first commit

This commit is contained in:
team 1
2026-02-11 14:15:08 +01:00
parent a4742c2c38
commit aa7d362bc3
58 changed files with 9999 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
namespace App\Agent;
/**
* ThinkSuppressor
*
* Robust streaming-safe suppressor for internal <think>...</think> sections.
*
* Key properties:
* - Handles token fragmentation (partial tags across tokens)
* - Stateful per stream, stateless per request
* - Does not buffer full responses
* - Deterministic and predictable
*/
final class ThinkSuppressor
{
/** Indicates whether the stream is currently inside a <think> block. */
private bool $insideThink = false;
/** Indicates whether the think section has been fully closed. */
private bool $thinkSectionCompleted = false;
/**
* Rolling buffer for detecting fragmented tags across tokens.
*/
private string $rollingBuffer = '';
/**
* Maximum buffer length needed to safely detect tags.
*/
private int $maxBufferLength = 32;
/**
* Filters a single token from the LLM stream.
*
* @param string $token Raw token from the LLM
* @return string Cleaned token safe for user output
*/
public function filter(string $token): string
{
// Append to rolling buffer
$this->rollingBuffer .= $token;
if (strlen($this->rollingBuffer) > $this->maxBufferLength) {
$this->rollingBuffer = substr($this->rollingBuffer, -$this->maxBufferLength);
}
// If think section is already completed, just strip stray closing tags
if ($this->thinkSectionCompleted) {
return str_replace('</think>', '', $token);
}
// Detect fragmented opening <think> tag
if (!$this->insideThink && str_contains($this->rollingBuffer, '<think>')) {
$this->insideThink = true;
return '';
}
// Detect fragmented closing </think> tag
if ($this->insideThink && str_contains($this->rollingBuffer, '</think>')) {
$this->insideThink = false;
$this->thinkSectionCompleted = true;
// Emit a single line break after think section ends
return "\n";
}
// Suppress all content while inside <think>...</think>
if ($this->insideThink) {
return '';
}
return $token;
}
/**
* Resets the suppressor state.
* Must be called before starting a new stream.
*/
public function reset(): void
{
$this->insideThink = false;
$this->thinkSectionCompleted = false;
$this->rollingBuffer = '';
}
}