Skip to content

[Agent] Unable to access sources metadata with streaming #833

@JorrinKievit

Description

@JorrinKievit

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();
    }

Metadata

Metadata

Assignees

Labels

AgentIssues & PRs about the AI Agent componentBugSomething isn't workingStatus: Needs Review

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions