-
-
Notifications
You must be signed in to change notification settings - Fork 114
Open
Labels
AgentIssues & PRs about the AI Agent componentIssues & PRs about the AI Agent componentBugSomething isn't workingSomething isn't workingStatus: Needs Review
Description
I am implementing the Symfony AI Agent in combination with the ai-sdk. I want to display the used sources in the UI, so I want to dispatch these in an event stream using the ai-sdk Data Stream Protocol. However, during streaming, the metadata seems to reset and sources are always null. Without the stream option this works fine.
Should this be done in a different order? The sources are present at some point, but seem to reset while actually streaming the content back.
This is basically all that I am doing:
public function __invoke(ChatRequest $request): StreamedResponse
{
$platform = PlatformFactory::create(env('OPENAI_API_KEY'), HttpClient::create());
$toolBox = new ToolBox([
new RandomTool(),
]);
$processor = new AgentProcessor($toolBox, includeSources: true);
$agent = new Agent($platform, 'gpt-4o-mini', [$processor], [$processor]);
$messages = new MessageBag();
foreach ($request->messages() as $message) {
foreach ($message['parts'] as $part) {
if ($part['type'] !== 'text') {
continue;
}
$messages->add(Message::ofUser($part['text']));
}
}
$result = $agent->call($messages, [
'stream' => true
]);
$response = new StreamedResponse(function () use ($result) {
$messageId = 'msg_' . bin2hex(random_bytes(16));
$textBlockId = 'text_' . bin2hex(random_bytes(16));
$this->sendSSE(['type' => 'start', 'messageId' => $messageId]);
$this->sendSSE(['type' => 'text-start', 'id' => $textBlockId]);
foreach ($result->getContent() as $chunk) {
$text = (string)$chunk;
if ($text !== '') {
$this->sendSSE([
'type' => 'text-delta',
'id' => $textBlockId,
'delta' => $text
]);
}
}
$this->sendSSE(['type' => 'text-end', 'id' => $textBlockId]);
// This is always null
$sources = $result->getMetadata()->get('sources', []);
foreach ($sources as $source) {
if (!$source instanceof Source) {
continue;
}
$this->sendSSE([
'type' => 'source-url',
'sourceId' => $source->getReference(),
'url' => $source->getReference(),
'title' => $source->getName()
]);
}
$this->sendSSE(['type' => 'finish']);
echo "data: [DONE]\n\n";
flush();
});
$response->headers->set('Content-Type', 'text/event-stream');
$response->headers->set('Cache-Control', 'no-cache');
$response->headers->set('Connection', 'keep-alive');
$response->headers->set('X-Accel-Buffering', 'no');
$response->headers->set('x-vercel-ai-ui-message-stream', 'v1');
return $response;
}
private function sendSSE(array $data): void
{
echo 'data: ' . json_encode($data, JSON_UNESCAPED_UNICODE) . "\n\n";
flush();
}Copilot
Metadata
Metadata
Assignees
Labels
AgentIssues & PRs about the AI Agent componentIssues & PRs about the AI Agent componentBugSomething isn't workingSomething isn't workingStatus: Needs Review