first commit
This commit is contained in:
136
src/Agent/AgentRunner.php
Normal file
136
src/Agent/AgentRunner.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Agent;
|
||||
|
||||
use App\Context\ContextService;
|
||||
use App\Context\UrlAnalyzer;
|
||||
use App\Infrastructure\OllamaClient;
|
||||
use App\Knowledge\Retrieval\RetrieverInterface;
|
||||
use Generator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
use App\Agent\StreamChunker;
|
||||
|
||||
final readonly class AgentRunner
|
||||
{
|
||||
public function __construct(
|
||||
private PromptBuilder $promptBuilder,
|
||||
private ThinkSuppressor $thinkSuppressor,
|
||||
private ContextService $contextService,
|
||||
private UrlAnalyzer $urlAnalyzer,
|
||||
private RetrieverInterface $retriever,
|
||||
private OllamaClient $ollamaClient,
|
||||
private LoggerInterface $agentLogger,
|
||||
private bool $debug,
|
||||
private bool $logPrompt,
|
||||
private bool $logContext,
|
||||
) {}
|
||||
|
||||
public function run(string $prompt, string $userId): Generator
|
||||
{
|
||||
$prompt = trim($prompt);
|
||||
|
||||
if ($prompt === '') {
|
||||
yield '❌ Empty prompt.';
|
||||
return;
|
||||
}
|
||||
|
||||
$this->agentLogger->info('Agent run started', [
|
||||
'userId' => $userId,
|
||||
]);
|
||||
|
||||
try {
|
||||
// ---------------------------------------------------------
|
||||
// 1) Context strategy
|
||||
// ---------------------------------------------------------
|
||||
$includeFullContext = false;
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 2) Extract URL content (if present)
|
||||
// ---------------------------------------------------------
|
||||
$urlContent = $this->urlAnalyzer->extractContentFromPrompt($prompt);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 3) Retrieve RAG knowledge
|
||||
// ---------------------------------------------------------
|
||||
$knowledgeChunks = $this->retriever->retrieve($prompt);
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 4) Build final prompt
|
||||
// ---------------------------------------------------------
|
||||
$finalPrompt = $this->promptBuilder->build(
|
||||
prompt: $prompt,
|
||||
userId: $userId,
|
||||
urlContent: $urlContent,
|
||||
knowledgeChunks: $knowledgeChunks,
|
||||
fullContext: $includeFullContext
|
||||
);
|
||||
|
||||
if ($this->debug && $this->logPrompt) {
|
||||
$this->agentLogger->debug($finalPrompt);
|
||||
}
|
||||
|
||||
if ($this->debug && $this->logContext) {
|
||||
$this->agentLogger->debug('Conversation context snapshot', [
|
||||
'context' => $this->contextService->buildUserContext(
|
||||
$userId,
|
||||
$includeFullContext
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 5) Stream tokens from the LLM backend (chunked streaming)
|
||||
// ---------------------------------------------------------
|
||||
$fullOutput = '';
|
||||
$chunker = new StreamChunker();
|
||||
|
||||
foreach ($this->ollamaClient->stream($finalPrompt) as $token) {
|
||||
$cleanToken = $this->thinkSuppressor->filter($token);
|
||||
|
||||
if ($cleanToken === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Vollständige Antwort weiter sammeln (für History)
|
||||
$fullOutput .= $cleanToken;
|
||||
|
||||
// ⬇️ Token in Chunker geben
|
||||
$chunk = $chunker->push($cleanToken);
|
||||
if ($chunk !== null) {
|
||||
yield $chunk;
|
||||
}
|
||||
}
|
||||
|
||||
// ⬇️ Rest flushen
|
||||
$finalChunk = $chunker->flush();
|
||||
if ($finalChunk !== null) {
|
||||
yield $finalChunk;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 6) Persist conversation history
|
||||
// ---------------------------------------------------------
|
||||
$this->contextService->appendHistory(
|
||||
$userId,
|
||||
$prompt,
|
||||
$fullOutput
|
||||
);
|
||||
|
||||
$this->agentLogger->info('Agent run finished', [
|
||||
'userId' => $userId,
|
||||
'outputLength' => mb_strlen($fullOutput),
|
||||
'contextMode' => 'recent',
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
$this->agentLogger->error('Agent run failed', [
|
||||
'userId' => $userId,
|
||||
'exception' => $e,
|
||||
]);
|
||||
|
||||
yield "\n❌ An internal error occurred while processing the request.";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user