StreamedChatMessageIterator buffer corrupts HTML when consuming streamed responses server-side (relative URLs split mid-attribute)
>>> [!note] Migrated issue
<!-- Drupal.org comment -->
<!-- Migrated from issue #3579967. -->
Reported by: [increweb21](https://www.drupal.org/user/3651601)
Related to !1328
>>>
<p>[Tracker]<br>
<strong>Update Summary: </strong>Buffer flushes mid-attribute on relative URLs, corrupting HTML in server-side consumers<br>
<strong>Short Description: </strong>StreamedChatMessageIterator buffer corrupts HTML when consuming streamed responses server-side (relative URLs split mid-attribute)<br>
<strong>Check-in Date: </strong>03/18/2026<br>
<em>Metadata is used by the <a href="https://www.drupalstarforge.ai/" title="AI Tracker">AI Tracker.</a> Docs and additional fields <a href="https://www.drupalstarforge.ai/ai-dashboard/docs" title="AI Issue Tracker Documentation">here</a>.</em><br>
[/Tracker]</p>
<h3 id="summary-problem-motivation">Problem/Motivation</h3>
<p>When using the AI module's Chat operation type to process HTML-rich content server-side (e.g. via <code>ai_integration_eca</code> or any server-side batch consumer), the output HTML is consistently corrupted. Attributes are split mid-value, tags are broken, table structures are destroyed, and <code>src</code>/<code>href</code> URLs are truncated.</p>
<p>The root cause is in <code>StreamedChatMessageIterator</code>, where the buffer flushes when <code>$maxBufferSize</code> (100 characters) is reached or on every newline. This causes the buffer to flush mid-attribute when processing HTML content with relative URLs like <code>src="/sites/default/files/..."</code>.</p>
<p><strong>Note:</strong> as of Drupal 11.3, Fibers are supported and any AI provider call runs in streaming mode — including server-side consumers like <code>ai_integration_eca</code>. There is no way to avoid this code path.</p>
<h4 id="summary-steps-reproduce">Steps to reproduce (required for bugs, not feature requests)</h4>
<ol>
<li>Install Drupal 11.3+ with the AI module and <code>ai_integration_eca</code></li>
<li>Configure an ECA Chat action that processes a node body field containing images with relative URLs (<code>src="/sites/default/files/..."</code>), HTML tables, and links</li>
<li>Trigger the ECA model</li>
<li>Observe the output — HTML attributes are split, tags are broken, table structure is destroyed</li>
</ol>
<h4>Example of corruption observed</h4>
<p>Debugging with Xdebug inside <code>flushInternal()</code>, two consecutive flushes were observed:</p>
<p>Flush 1 (buffer limit reached mid-attribute):<br>
<code>src="/sites/default"</code></p>
<p>Flush 2 (rest of the URL):<br>
<code>/files/inline-images/image.png" width="2816" height="1536"></code></p>
<p>Resulting in broken HTML with the rest of the URL orphaned outside the tag.</p>
<h3 id="summary-proposed-resolution">Proposed resolution</h3>
<ol>
<li>Fix the regex in <code>shouldFlush()</code> to protect relative URLs starting with <code>/</code>:</li>
</ol>
<pre>// Before — only protects absolute URLs<br>if (preg_match('/"(?:http|\/\/:)[^"]*$/', $this->buffer)...<br><br>// After — also protects relative URLs<br>if (preg_match('/"(?:http|\/)[^"]*$/', $this->buffer)...</pre><ol start="2">
<li>Consider increasing <code>$maxBufferSize</code> or making it configurable to reduce the risk of mid-attribute flushes on long attribute values.</li>
</ol>
<h3 id="summary-remaining-tasks">Remaining tasks</h3>
<ul>
<li>Fix the regex in <code>shouldFlush()</code> to protect relative URLs</li>
<li>Add kernel test that verifies HTML with relative URLs is not corrupted when consuming the iterator server-side</li>
</ul>
<h3 id="summary-user-interface-changes">User interface changes</h3>
<p>None.</p>
<h3 id="summary-api-changes">API changes</h3>
<p>None.</p>
<h3 id="summary-data-model-changes">Data model changes</h3>
<p>None.</p>
<h3 id="summary-release-notes-snippet">Release notes snippet</h3>
<p>Fixed HTML corruption in <code>StreamedChatMessageIterator</code> when processing content with relative URLs server-side (e.g. via ECA or batch processing).</p>
issue