|
6 | 6 | use Prism\Prism\Enums\FinishReason; |
7 | 7 | use Prism\Prism\Exceptions\PrismException; |
8 | 8 | use Prism\Prism\Streaming\Adapters\DataProtocolAdapter; |
| 9 | +use Prism\Prism\Streaming\Events\ArtifactEvent; |
9 | 10 | use Prism\Prism\Streaming\Events\ErrorEvent; |
10 | 11 | use Prism\Prism\Streaming\Events\StreamEndEvent; |
11 | 12 | use Prism\Prism\Streaming\Events\StreamEvent; |
|
19 | 20 | use Prism\Prism\Streaming\Events\ToolCallEvent; |
20 | 21 | use Prism\Prism\Streaming\Events\ToolResultEvent; |
21 | 22 | use Prism\Prism\Text\PendingRequest; |
| 23 | +use Prism\Prism\ValueObjects\Artifact; |
22 | 24 | use Prism\Prism\ValueObjects\ToolCall; |
23 | 25 | use Prism\Prism\ValueObjects\ToolResult; |
24 | 26 | use Prism\Prism\ValueObjects\Usage; |
@@ -527,3 +529,62 @@ function createThrowingGenerator(array $eventsBeforeError, Throwable $exception) |
527 | 529 | fclose($outputBuffer); |
528 | 530 | } |
529 | 531 | }); |
| 532 | + |
| 533 | +it('formats artifact events using data- prefix convention', function (): void { |
| 534 | + $artifact = new Artifact( |
| 535 | + data: 'iVBORw0KGgo=', |
| 536 | + mimeType: 'image/png', |
| 537 | + metadata: ['width' => 512], |
| 538 | + id: 'artifact-123', |
| 539 | + ); |
| 540 | + |
| 541 | + $events = [ |
| 542 | + new ArtifactEvent('evt-1', 1640995200, $artifact, 'tool-call-456', 'generate_image', 'msg-789'), |
| 543 | + ]; |
| 544 | + |
| 545 | + $adapter = new DataProtocolAdapter; |
| 546 | + $response = ($adapter)(createDataEventGenerator($events)); |
| 547 | + $callback = $response->getCallback(); |
| 548 | + |
| 549 | + $outputBuffer = fopen('php://memory', 'r+'); |
| 550 | + ob_start(function ($buffer) use ($outputBuffer): string { |
| 551 | + fwrite($outputBuffer, $buffer); |
| 552 | + |
| 553 | + return ''; |
| 554 | + }); |
| 555 | + |
| 556 | + try { |
| 557 | + $callback(); |
| 558 | + ob_end_flush(); |
| 559 | + |
| 560 | + rewind($outputBuffer); |
| 561 | + $capturedOutput = stream_get_contents($outputBuffer); |
| 562 | + |
| 563 | + // Verify data- prefix convention is used (not bare "artifact") |
| 564 | + expect($capturedOutput)->toContain('data: {"type":"data-artifact"'); |
| 565 | + expect($capturedOutput)->not->toContain('"type":"artifact"'); |
| 566 | + |
| 567 | + // Verify payload is nested under "data" key |
| 568 | + expect($capturedOutput)->toContain('"data":{'); |
| 569 | + expect($capturedOutput)->toContain('"toolCallId":"tool-call-456"'); |
| 570 | + expect($capturedOutput)->toContain('"toolName":"generate_image"'); |
| 571 | + expect($capturedOutput)->toContain('"mimeType":"image\/png"'); |
| 572 | + expect($capturedOutput)->toContain('"id":"artifact-123"'); |
| 573 | + |
| 574 | + // Parse the JSON to verify structure |
| 575 | + $lines = explode("\n", trim($capturedOutput)); |
| 576 | + $dataLines = array_filter($lines, fn (string $line): bool => str_starts_with($line, 'data: ') && $line !== 'data: [DONE]'); |
| 577 | + $artifactLine = array_values($dataLines)[0]; |
| 578 | + $json = json_decode(substr($artifactLine, 6), true); |
| 579 | + |
| 580 | + expect($json['type'])->toBe('data-artifact'); |
| 581 | + expect($json['data']['toolCallId'])->toBe('tool-call-456'); |
| 582 | + expect($json['data']['toolName'])->toBe('generate_image'); |
| 583 | + expect($json['data']['artifact']['id'])->toBe('artifact-123'); |
| 584 | + expect($json['data']['artifact']['mimeType'])->toBe('image/png'); |
| 585 | + expect($json['data']['artifact']['data'])->toBe('iVBORw0KGgo='); |
| 586 | + expect($json['data']['artifact']['metadata'])->toBe(['width' => 512]); |
| 587 | + } finally { |
| 588 | + fclose($outputBuffer); |
| 589 | + } |
| 590 | +}); |
0 commit comments