-
-
Notifications
You must be signed in to change notification settings - Fork 102
Description
I'm trying to use symfony/ai as a backend for https://ai-sdk.dev. ai-sdk requires the backend to send the content in a structured way (also when streaming). This allows the frontend to display status information, internal tool calling, reasoning etc. (like in le chat or chat-gpt).
Basic content streaming of one text part works well, by wrapping each chunk of the content response in a small envelope:
$result = $defaultAgent->call($messages, ['stream' => true]);
$response = new StreamedResponse(function () use ($result) {
$send = function (string $type, array $data = []) {
echo 'data: ' . json_encode(array_merge(['type' => $type], $data), JSON_UNESCAPED_SLASHES) . "\n\n";
@ob_flush(); @flush();
};
$send('start');
$textId = (string) new Ulid();
$send('text-start', ['id' => $textId]);
foreach ($result->getContent() as $part) {
$send('text-delta', ['id' => $textId, 'delta' => $part]);
}
$send('text-end', ['id' => $textId]);
$send('finish');
echo "data: [DONE]\n\n";
@ob_flush();
@flush();
}
However when i want to stream tool calling status or internal reasoning, things are getting more complicated.
I tried to implement a custom OutputProcessor, however the internal agentic flow breaks, when replacing tool_calling result with a custom envenlope.
The best result I got, was writing to the output-stream directly from an output-processor, however this is not very elegant or maintanable.
Basically what I need would be:
- a better $result->getResultPart()s generator, that will not return simple content, but instances of
ResultInterface
or mybe a newFinalResultInterface
? - A new TextChunkResult to not get a mixture of string and
ResultInterface
objects. This would allow me to add my envelopes in the$result->getResultParts()
loop depending on the part class.
I tink this would be a very nice feature for any UI that wants to display whats going on inside one agent call.