.NET: Improve fidelity of OpenAI Responses hosting (#1550)

* Improve conformance of OpenAI Responses API serving

* Update dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/AgentRunResponseExtensions.cs

Co-authored-by: Stephen Toub <stoub@microsoft.com>

* Update dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/AgentRunResponseExtensions.cs

Co-authored-by: Stephen Toub <stoub@microsoft.com>

* Sort packages

* Relax adherence where acceptable

* nit

* PromptCacheKey is not obsolete

* format

---------

Co-authored-by: Stephen Toub <stoub@microsoft.com>
This commit is contained in:
Reuben Bond
2025-10-22 17:48:44 +00:00
committed by GitHub
co-authored by Stephen Toub
parent 1bf520a7c2
commit 103c7e7105
94 changed files with 12975 additions and 666 deletions
@@ -0,0 +1,216 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Microsoft.Agents.AI.Hosting.OpenAI.Tests;
/// <summary>
/// Base class for conformance tests that load request/response traces from disk.
/// </summary>
public abstract class ConformanceTestBase : IAsyncDisposable
{
protected const string TracesBasePath = "ConformanceTraces/Responses";
private WebApplication? _app;
private HttpClient? _httpClient;
/// <summary>
/// Loads a JSON file from the conformance traces directory.
/// </summary>
protected static string LoadTraceFile(string relativePath)
{
var fullPath = Path.Combine(TracesBasePath, relativePath);
if (!File.Exists(fullPath))
{
throw new FileNotFoundException($"Conformance trace file not found: {fullPath}");
}
return File.ReadAllText(fullPath);
}
/// <summary>
/// Loads a JSON document from the conformance traces directory.
/// </summary>
protected static JsonDocument LoadTraceDocument(string relativePath)
{
var json = LoadTraceFile(relativePath);
return JsonDocument.Parse(json);
}
/// <summary>
/// Asserts that a JSON element exists (property is present, value can be null).
/// </summary>
protected static void AssertJsonPropertyExists(JsonElement element, string propertyName)
{
if (!element.TryGetProperty(propertyName, out _))
{
throw new Xunit.Sdk.XunitException($"Expected property '{propertyName}' not found in JSON");
}
}
/// <summary>
/// Asserts that a JSON element has a specific string value.
/// </summary>
protected static void AssertJsonPropertyEquals(JsonElement element, string propertyName, string expectedValue)
{
AssertJsonPropertyExists(element, propertyName);
var actualValue = element.GetProperty(propertyName).GetString();
if (actualValue != expectedValue)
{
throw new Xunit.Sdk.XunitException($"Property '{propertyName}': expected '{expectedValue}', got '{actualValue}'");
}
}
/// <summary>
/// Asserts that a JSON element has a specific integer value.
/// </summary>
protected static void AssertJsonPropertyEquals(JsonElement element, string propertyName, int expectedValue)
{
AssertJsonPropertyExists(element, propertyName);
var actualValue = element.GetProperty(propertyName).GetInt32();
if (actualValue != expectedValue)
{
throw new Xunit.Sdk.XunitException($"Property '{propertyName}': expected {expectedValue}, got {actualValue}");
}
}
/// <summary>
/// Asserts that a JSON element has a specific boolean value.
/// </summary>
protected static void AssertJsonPropertyEquals(JsonElement element, string propertyName, bool expectedValue)
{
AssertJsonPropertyExists(element, propertyName);
var actualValue = element.GetProperty(propertyName).GetBoolean();
if (actualValue != expectedValue)
{
throw new Xunit.Sdk.XunitException($"Property '{propertyName}': expected {expectedValue}, got {actualValue}");
}
}
/// <summary>
/// Gets a property value or returns a default if the property doesn't exist.
/// </summary>
protected static T GetPropertyOrDefault<T>(JsonElement element, string propertyName, T defaultValue = default!)
{
if (!element.TryGetProperty(propertyName, out var property))
{
return defaultValue;
}
if (property.ValueKind == JsonValueKind.Null)
{
return defaultValue;
}
return typeof(T) switch
{
Type t when t == typeof(string) => (T)(object)property.GetString()!,
Type t when t == typeof(int) => (T)(object)property.GetInt32(),
Type t when t == typeof(long) => (T)(object)property.GetInt64(),
Type t when t == typeof(bool) => (T)(object)property.GetBoolean(),
Type t when t == typeof(double) => (T)(object)property.GetDouble(),
_ => throw new NotSupportedException($"Type {typeof(T)} not supported")
};
}
/// <summary>
/// Creates a test server with a mock chat client that returns the expected response text.
/// </summary>
protected async Task<HttpClient> CreateTestServerAsync(string agentName, string instructions, string responseText)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder();
builder.WebHost.UseTestServer();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient(responseText);
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddAIAgent(agentName, instructions, chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
this._app = builder.Build();
AIAgent agent = this._app.Services.GetRequiredKeyedService<AIAgent>(agentName);
this._app.MapOpenAIResponses(agent);
await this._app.StartAsync();
TestServer testServer = this._app.Services.GetRequiredService<IServer>() as TestServer
?? throw new InvalidOperationException("TestServer not found");
this._httpClient = testServer.CreateClient();
return this._httpClient;
}
/// <summary>
/// Creates a test server with a mock chat client that returns custom content.
/// </summary>
protected async Task<HttpClient> CreateTestServerAsync(
string agentName,
string instructions,
string responseText,
Func<ChatMessage, IEnumerable<AIContent>> contentProvider)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder();
builder.WebHost.UseTestServer();
IChatClient mockChatClient = new TestHelpers.CustomContentMockChatClient(contentProvider);
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddAIAgent(agentName, instructions, chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
this._app = builder.Build();
AIAgent agent = this._app.Services.GetRequiredKeyedService<AIAgent>(agentName);
this._app.MapOpenAIResponses(agent);
await this._app.StartAsync();
TestServer testServer = this._app.Services.GetRequiredService<IServer>() as TestServer
?? throw new InvalidOperationException("TestServer not found");
this._httpClient = testServer.CreateClient();
return this._httpClient;
}
/// <summary>
/// Sends a POST request with JSON content to the test server.
/// </summary>
protected async Task<HttpResponseMessage> SendRequestAsync(HttpClient client, string agentName, string requestJson)
{
StringContent content = new(requestJson, Encoding.UTF8, "application/json");
return await client.PostAsync(new Uri($"/{agentName}/v1/responses", UriKind.Relative), content);
}
/// <summary>
/// Parses the response JSON and returns a JsonDocument.
/// </summary>
protected static async Task<JsonDocument> ParseResponseAsync(HttpResponseMessage response)
{
string responseJson = await response.Content.ReadAsStringAsync();
return JsonDocument.Parse(responseJson);
}
public async ValueTask DisposeAsync()
{
this._httpClient?.Dispose();
if (this._app != null)
{
await this._app.DisposeAsync();
}
GC.SuppressFinalize(this);
}
}
@@ -0,0 +1,5 @@
{
"model": "gpt-4o-mini",
"input": "Hello, how are you?",
"max_output_tokens": 100
}
@@ -0,0 +1,67 @@
{
"id": "resp_0afca3d11493c6990068f41ddc32d08193b26914d1564cbd2c",
"object": "response",
"created_at": 1760828892,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"error": null,
"incomplete_details": null,
"instructions": null,
"max_output_tokens": 100,
"max_tool_calls": null,
"model": "gpt-4o-mini-2024-07-18",
"output": [
{
"id": "msg_0afca3d11493c6990068f41ddda03c8193828fe5a9c14c7583",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "Hello! I'm doing well, thank you. How about you?"
}
],
"role": "assistant"
}
],
"parallel_tool_calls": true,
"previous_response_id": null,
"prompt_cache_key": null,
"reasoning": {
"effort": null,
"summary": null
},
"safety_identifier": null,
"service_tier": "default",
"store": true,
"temperature": 1.0,
"text": {
"format": {
"type": "text"
},
"verbosity": "medium"
},
"tool_choice": "auto",
"tools": [],
"top_logprobs": 0,
"top_p": 1.0,
"truncation": "disabled",
"usage": {
"input_tokens": 13,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 14,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 27
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,6 @@
{
"model": "gpt-4o-mini",
"input": "What is its population?",
"previous_response_id": "resp_09f97255714654cb0068f41e1746f4819580589c8cc16031fd",
"max_output_tokens": 100
}
@@ -0,0 +1,67 @@
{
"id": "resp_09f97255714654cb0068f41e25b0bc81958fbaacf819ed5332",
"object": "response",
"created_at": 1760828965,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"error": null,
"incomplete_details": null,
"instructions": null,
"max_output_tokens": 100,
"max_tool_calls": null,
"model": "gpt-4o-mini-2024-07-18",
"output": [
{
"id": "msg_09f97255714654cb0068f41e263f90819598e1201536331e62",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "As of 2023, the population of Paris is approximately 2.1 million people within the city proper. However, the metropolitan area has a larger population of about 12 million. Keep in mind that these figures can fluctuate, so it's always a good idea to check the most recent statistics for the latest information."
}
],
"role": "assistant"
}
],
"parallel_tool_calls": true,
"previous_response_id": "resp_09f97255714654cb0068f41e1746f4819580589c8cc16031fd",
"prompt_cache_key": null,
"reasoning": {
"effort": null,
"summary": null
},
"safety_identifier": null,
"service_tier": "default",
"store": true,
"temperature": 1.0,
"text": {
"format": {
"type": "text"
},
"verbosity": "medium"
},
"tool_choice": "auto",
"tools": [],
"top_logprobs": 0,
"top_p": 1.0,
"truncation": "disabled",
"usage": {
"input_tokens": 34,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 65,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 99
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,20 @@
{
"model": "gpt-4o-mini",
"input": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "What's in this image?"
},
{
"type": "input_image",
"image_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
}
]
}
],
"max_output_tokens": 150
}
@@ -0,0 +1,67 @@
{
"id": "resp_01af0986c49d030f0068f6fa8d348081958642d85ad7456b69",
"object": "response",
"created_at": 1761016461,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"error": null,
"incomplete_details": null,
"instructions": null,
"max_output_tokens": 150,
"max_tool_calls": null,
"model": "gpt-4o-mini-2024-07-18",
"output": [
{
"id": "msg_01af0986c49d030f0068f6fa90a7e08195a035c8916766681b",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "The image depicts a serene landscape featuring a wooden pathway stretching through lush green grass and plant life. The sky is bright with a few clouds, suggesting a pleasant day. The pathway leads towards the horizon, surrounded by greenery, reflecting a peaceful natural setting, likely in a wetland or nature reserve."
}
],
"role": "assistant"
}
],
"parallel_tool_calls": true,
"previous_response_id": null,
"prompt_cache_key": null,
"reasoning": {
"effort": null,
"summary": null
},
"safety_identifier": null,
"service_tier": "default",
"store": true,
"temperature": 1.0,
"text": {
"format": {
"type": "text"
},
"verbosity": "medium"
},
"tool_choice": "auto",
"tools": [],
"top_logprobs": 0,
"top_p": 1.0,
"truncation": "disabled",
"usage": {
"input_tokens": 36847,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 60,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 36907
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,21 @@
{
"model": "gpt-4o-mini",
"input": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "What's in this image?"
},
{
"type": "input_image",
"image_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
}
]
}
],
"max_output_tokens": 150,
"stream": true
}
@@ -0,0 +1,189 @@
event: response.created
data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_0e10670c091907160068f6faad240c81908d6def6132a26969","object":"response","created_at":1761016493,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":150,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
event: response.in_progress
data: {"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_0e10670c091907160068f6faad240c81908d6def6132a26969","object":"response","created_at":1761016493,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":150,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
event: response.output_item.added
data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","type":"message","status":"in_progress","content":[],"role":"assistant"}}
event: response.content_part.added
data: {"type":"response.content_part.added","sequence_number":3,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":4,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":"The","logprobs":[],"obfuscation":"HP5bO23e7ED3c"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":5,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" image","logprobs":[],"obfuscation":"mBZ560WUQc"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":6,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" shows","logprobs":[],"obfuscation":"ndU2QyXIhj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":7,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"4OTFwHoyQKCFoX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":8,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" wooden","logprobs":[],"obfuscation":"BWDOUQEHW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":9,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" pathway","logprobs":[],"obfuscation":"VKTVzuEL"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":10,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" winding","logprobs":[],"obfuscation":"5VDctEmF"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":11,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" through","logprobs":[],"obfuscation":"1WeKOmTj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":12,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"4ZfAKPdyNTgrOa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":13,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" lush","logprobs":[],"obfuscation":"hp5iZThcACe"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":14,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" green","logprobs":[],"obfuscation":"tMDmoSScMS"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":15,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" field","logprobs":[],"obfuscation":"KkKKizvWtF"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":16,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" under","logprobs":[],"obfuscation":"5BXWxGwZcb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":17,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"EfshPCNxZX2j6n"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":18,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" blue","logprobs":[],"obfuscation":"gsVDUBymXa1"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":19,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" sky","logprobs":[],"obfuscation":"jqJw8FCnJYF6"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":20,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"gu3uIQY9x3Q"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":21,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" scattered","logprobs":[],"obfuscation":"RcIblX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":22,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" clouds","logprobs":[],"obfuscation":"IweyMAYXK"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":23,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"YJau6cwOR9hVNRW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":24,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" The","logprobs":[],"obfuscation":"0yfUzLBRfxdu"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":25,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" landscape","logprobs":[],"obfuscation":"27GcGw"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":26,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" is","logprobs":[],"obfuscation":"VJK06HjV3g4vm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":27,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" filled","logprobs":[],"obfuscation":"gG0mD5vlB"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":28,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"GPuMj012XgT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":29,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" tall","logprobs":[],"obfuscation":"2dTN3ADPyqp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":30,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" grasses","logprobs":[],"obfuscation":"QAjIomJ7"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":31,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"iSsIcsjwL4fo"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":32,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"wQqxRHK7dpGyef"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":33,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" variety","logprobs":[],"obfuscation":"WWEgd5y3"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":34,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"XIUXf0mQDrOZV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":35,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" vegetation","logprobs":[],"obfuscation":"zsWKX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":36,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"qdvVQsJfWBKRV0L"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":37,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" suggesting","logprobs":[],"obfuscation":"CY9hZ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":38,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"xTuyXtKFXnLRNN"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":39,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" natural","logprobs":[],"obfuscation":"vwZLqavC"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":40,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"SztM7BID4fWB"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":41,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" serene","logprobs":[],"obfuscation":"YPc5C2vkG"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":42,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" outdoor","logprobs":[],"obfuscation":"ZOsa6bHk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":43,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" environment","logprobs":[],"obfuscation":"Hp15"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":44,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"phksBH2ylPybJRV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":45,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" The","logprobs":[],"obfuscation":"WjHEZaDDxOZn"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":46,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" scene","logprobs":[],"obfuscation":"axvZzgGhSy"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":47,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" conveys","logprobs":[],"obfuscation":"K2Se69Sf"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":48,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"RDGqd5JujHs9WC"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":49,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" tranquil","logprobs":[],"obfuscation":"rKJS2ls"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":50,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" atmosphere","logprobs":[],"obfuscation":"Ss0zh"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":51,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" typical","logprobs":[],"obfuscation":"1effR9m8"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":52,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"iXg4KtS2V5Dgg"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":53,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" wetlands","logprobs":[],"obfuscation":"fMiohxy"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":54,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" or","logprobs":[],"obfuscation":"rweOxp9O9z3KP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":55,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" marsh","logprobs":[],"obfuscation":"DUtga7Mm2f"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":56,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":"y","logprobs":[],"obfuscation":"sXYnwIGDCoempll"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":57,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":" areas","logprobs":[],"obfuscation":"GmrRC6oKSn"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":58,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"jv8AM0MjAlh1io2"}
event: response.output_text.done
data: {"type":"response.output_text.done","sequence_number":59,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"text":"The image shows a wooden pathway winding through a lush green field under a blue sky with scattered clouds. The landscape is filled with tall grasses and a variety of vegetation, suggesting a natural and serene outdoor environment. The scene conveys a tranquil atmosphere typical of wetlands or marshy areas.","logprobs":[]}
event: response.content_part.done
data: {"type":"response.content_part.done","sequence_number":60,"item_id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","output_index":0,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"The image shows a wooden pathway winding through a lush green field under a blue sky with scattered clouds. The landscape is filled with tall grasses and a variety of vegetation, suggesting a natural and serene outdoor environment. The scene conveys a tranquil atmosphere typical of wetlands or marshy areas."}}
event: response.output_item.done
data: {"type":"response.output_item.done","sequence_number":61,"output_index":0,"item":{"id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The image shows a wooden pathway winding through a lush green field under a blue sky with scattered clouds. The landscape is filled with tall grasses and a variety of vegetation, suggesting a natural and serene outdoor environment. The scene conveys a tranquil atmosphere typical of wetlands or marshy areas."}],"role":"assistant"}}
event: response.completed
data: {"type":"response.completed","sequence_number":62,"response":{"id":"resp_0e10670c091907160068f6faad240c81908d6def6132a26969","object":"response","created_at":1761016493,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":150,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[{"id":"msg_0e10670c091907160068f6fab0d2b08190872e4c7e64f1a219","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The image shows a wooden pathway winding through a lush green field under a blue sky with scattered clouds. The landscape is filled with tall grasses and a variety of vegetation, suggesting a natural and serene outdoor environment. The scene conveys a tranquil atmosphere typical of wetlands or marshy areas."}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":36847,"input_tokens_details":{"cached_tokens":0},"output_tokens":56,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":36903},"user":null,"metadata":{}}}
@@ -0,0 +1,28 @@
{
"model": "gpt-4o-mini",
"input": "Generate a person object with name, age, and occupation fields.",
"max_output_tokens": 100,
"text": {
"format": {
"type": "json_schema",
"name": "person",
"strict": true,
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"occupation": {
"type": "string"
}
},
"required": ["name", "age", "occupation"],
"additionalProperties": false
}
}
}
}
@@ -0,0 +1,90 @@
{
"id": "resp_0814209c47894f060068f6fbd7b30c8195b9dedefbfecd827c",
"object": "response",
"created_at": 1761016791,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"error": null,
"incomplete_details": null,
"instructions": null,
"max_output_tokens": 100,
"max_tool_calls": null,
"model": "gpt-4o-mini-2024-07-18",
"output": [
{
"id": "msg_0814209c47894f060068f6fbd9a6f481958231a154f65fbed6",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "{\"name\":\"Alice Johnson\",\"age\":28,\"occupation\":\"Software Engineer\"}"
}
],
"role": "assistant"
}
],
"parallel_tool_calls": true,
"previous_response_id": null,
"prompt_cache_key": null,
"reasoning": {
"effort": null,
"summary": null
},
"safety_identifier": null,
"service_tier": "default",
"store": true,
"temperature": 1.0,
"text": {
"format": {
"type": "json_schema",
"description": null,
"name": "person",
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"occupation": {
"type": "string"
}
},
"required": [
"name",
"age",
"occupation"
],
"additionalProperties": false
},
"strict": true
},
"verbosity": "medium"
},
"tool_choice": "auto",
"tools": [],
"top_logprobs": 0,
"top_p": 1.0,
"truncation": "disabled",
"usage": {
"input_tokens": 56,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 16,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 72
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,29 @@
{
"model": "gpt-4o-mini",
"input": "Generate a person object with name, age, and occupation fields.",
"max_output_tokens": 100,
"text": {
"format": {
"type": "json_schema",
"name": "person",
"strict": true,
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"occupation": {
"type": "string"
}
},
"required": ["name", "age", "occupation"],
"additionalProperties": false
}
}
},
"stream": true
}
@@ -0,0 +1,69 @@
event: response.created
data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_0bcead1d6f6564230068f6fbfbf310819395ae9412e4d33aac","object":"response","created_at":1761016828,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":100,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"json_schema","description":null,"name":"person","schema":{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"integer"},"occupation":{"type":"string"}},"required":["name","age","occupation"],"additionalProperties":false},"strict":true},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
event: response.in_progress
data: {"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_0bcead1d6f6564230068f6fbfbf310819395ae9412e4d33aac","object":"response","created_at":1761016828,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":100,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"json_schema","description":null,"name":"person","schema":{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"integer"},"occupation":{"type":"string"}},"required":["name","age","occupation"],"additionalProperties":false},"strict":true},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
event: response.output_item.added
data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","type":"message","status":"in_progress","content":[],"role":"assistant"}}
event: response.content_part.added
data: {"type":"response.content_part.added","sequence_number":3,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":4,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"{\"","logprobs":[],"obfuscation":"q3BqgwzkUfomJo"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":5,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"name","logprobs":[],"obfuscation":"8fPOKIFobpyF"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":6,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"\":\"","logprobs":[],"obfuscation":"2qyS7OZBQ0qoe"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":7,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"Alice","logprobs":[],"obfuscation":"V34HvQtoIqw"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":8,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":" Johnson","logprobs":[],"obfuscation":"sY1KPvtG"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":9,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"\",\"","logprobs":[],"obfuscation":"GC5vxQBmJWLpE"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":10,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"age","logprobs":[],"obfuscation":"AkaPq2PynT3a8"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":11,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"\":","logprobs":[],"obfuscation":"z9gFmZIIY2bQGJ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":12,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"30","logprobs":[],"obfuscation":"boNovQBouRh6WS"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":13,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":",\"","logprobs":[],"obfuscation":"aTJzG9oiuYfMee"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":14,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"occupation","logprobs":[],"obfuscation":"cYYC2p"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":15,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"\":\"","logprobs":[],"obfuscation":"ijaYSNPdkM3Rr"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":16,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"Software","logprobs":[],"obfuscation":"Wo32QTml"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":17,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":" Engineer","logprobs":[],"obfuscation":"l0dhxKc"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":18,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"delta":"\"}","logprobs":[],"obfuscation":"1rQVE4KrAtOFtx"}
event: response.output_text.done
data: {"type":"response.output_text.done","sequence_number":19,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"text":"{\"name\":\"Alice Johnson\",\"age\":30,\"occupation\":\"Software Engineer\"}","logprobs":[]}
event: response.content_part.done
data: {"type":"response.content_part.done","sequence_number":20,"item_id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","output_index":0,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"{\"name\":\"Alice Johnson\",\"age\":30,\"occupation\":\"Software Engineer\"}"}}
event: response.output_item.done
data: {"type":"response.output_item.done","sequence_number":21,"output_index":0,"item":{"id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"{\"name\":\"Alice Johnson\",\"age\":30,\"occupation\":\"Software Engineer\"}"}],"role":"assistant"}}
event: response.completed
data: {"type":"response.completed","sequence_number":22,"response":{"id":"resp_0bcead1d6f6564230068f6fbfbf310819395ae9412e4d33aac","object":"response","created_at":1761016828,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":100,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[{"id":"msg_0bcead1d6f6564230068f6fbfd253c81939c22c9c80501c3ea","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"{\"name\":\"Alice Johnson\",\"age\":30,\"occupation\":\"Software Engineer\"}"}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"json_schema","description":null,"name":"person","schema":{"type":"object","properties":{"name":{"type":"string"},"age":{"type":"integer"},"occupation":{"type":"string"}},"required":["name","age","occupation"],"additionalProperties":false},"strict":true},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":56,"input_tokens_details":{"cached_tokens":0},"output_tokens":16,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":72},"user":null,"metadata":{}}}
@@ -0,0 +1,13 @@
{
"model": "gpt-4o-mini",
"input": "Explain quantum computing in simple terms.",
"max_output_tokens": 150,
"temperature": 0.7,
"top_p": 0.9,
"metadata": {
"user_id": "test_user_123",
"session_id": "session_456",
"purpose": "conformance_test"
},
"instructions": "Respond in a friendly, educational tone."
}
@@ -0,0 +1,73 @@
{
"id": "resp_05bb7fa0fc62fa280068f41e4584708195bbcbb6028e55381a",
"object": "response",
"created_at": 1760828997,
"status": "incomplete",
"background": false,
"billing": {
"payer": "developer"
},
"error": null,
"incomplete_details": {
"reason": "max_output_tokens"
},
"instructions": "Respond in a friendly, educational tone.",
"max_output_tokens": 150,
"max_tool_calls": null,
"model": "gpt-4o-mini-2024-07-18",
"output": [
{
"id": "msg_05bb7fa0fc62fa280068f41e462e3c81959b33430391731815",
"type": "message",
"status": "incomplete",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "Sure! Imagine your regular computer as a very fast and efficient librarian. It sorts through books (data) one at a time, very quickly, to find the information you need. \n\nNow, think of quantum computing as a magical librarian who can read multiple books at the same time! This magic comes from the principles of quantum mechanics, which is the science of very tiny particles.\n\nHere are a few key ideas:\n\n1. **Bits vs. Qubits**: Regular computers use bits, which can be either a 0 or a 1. Quantum computers use qubits, which can be both 0 and 1 at the same time thanks to a property called superposition. This means they can process a lot more information simultaneously.\n\n2"
}
],
"role": "assistant"
}
],
"parallel_tool_calls": true,
"previous_response_id": null,
"prompt_cache_key": null,
"reasoning": {
"effort": null,
"summary": null
},
"safety_identifier": null,
"service_tier": "default",
"store": true,
"temperature": 0.7,
"text": {
"format": {
"type": "text"
},
"verbosity": "medium"
},
"tool_choice": "auto",
"tools": [],
"top_logprobs": 0,
"top_p": 0.9,
"truncation": "disabled",
"usage": {
"input_tokens": 26,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 150,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 176
},
"user": null,
"metadata": {
"user_id": "test_user_123",
"session_id": "session_456",
"purpose": "conformance_test"
}
}
@@ -0,0 +1,8 @@
{
"model": "o3-mini",
"input": "What is the sum of the first 10 prime numbers?",
"max_output_tokens": 500,
"reasoning": {
"effort": "medium"
}
}
@@ -0,0 +1,72 @@
{
"id": "resp_0bfaafe9c7aec7b30068f6fb3a5bdc8196bee8c7b919ff76e7",
"object": "response",
"created_at": 1761016634,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"error": null,
"incomplete_details": null,
"instructions": null,
"max_output_tokens": 500,
"max_tool_calls": null,
"model": "o3-mini-2025-01-31",
"output": [
{
"id": "rs_0bfaafe9c7aec7b30068f6fb3cb76881968b021761281f36e4",
"type": "reasoning",
"summary": []
},
{
"id": "msg_0bfaafe9c7aec7b30068f6fb3d69748196920ec7bd9cfc5a87",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "The first 10 prime numbers are:\n\n2, 3, 5, 7, 11, 13, 17, 19, 23, 29.\n\nWhen you add these together, you get:\n\n2 + 3 + 5 + 7 + 11 + 13 + 17 + 19 + 23 + 29 = 129.\n\nSo, the sum of the first 10 prime numbers is 129."
}
],
"role": "assistant"
}
],
"parallel_tool_calls": true,
"previous_response_id": null,
"prompt_cache_key": null,
"reasoning": {
"effort": "medium",
"summary": null
},
"safety_identifier": null,
"service_tier": "default",
"store": true,
"temperature": 1.0,
"text": {
"format": {
"type": "text"
},
"verbosity": "medium"
},
"tool_choice": "auto",
"tools": [],
"top_logprobs": 0,
"top_p": 1.0,
"truncation": "disabled",
"usage": {
"input_tokens": 18,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 222,
"output_tokens_details": {
"reasoning_tokens": 128
},
"total_tokens": 240
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,9 @@
{
"model": "o3-mini",
"input": "What is the sum of the first 10 prime numbers?",
"max_output_tokens": 500,
"reasoning": {
"effort": "medium"
},
"stream": true
}
@@ -0,0 +1,309 @@
event: response.created
data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_0c72f641658e865a0068f6fb58dec88194b1d3c00dd1867d77","object":"response","created_at":1761016664,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":500,"max_tool_calls":null,"model":"o3-mini-2025-01-31","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
event: response.in_progress
data: {"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_0c72f641658e865a0068f6fb58dec88194b1d3c00dd1867d77","object":"response","created_at":1761016664,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":500,"max_tool_calls":null,"model":"o3-mini-2025-01-31","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
event: response.output_item.added
data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"rs_0c72f641658e865a0068f6fb5c1e848194a917a064f52a6d80","type":"reasoning","summary":[]}}
event: response.output_item.done
data: {"type":"response.output_item.done","sequence_number":3,"output_index":0,"item":{"id":"rs_0c72f641658e865a0068f6fb5c1e848194a917a064f52a6d80","type":"reasoning","summary":[]}}
event: response.output_item.added
data: {"type":"response.output_item.added","sequence_number":4,"output_index":1,"item":{"id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","type":"message","status":"in_progress","content":[],"role":"assistant"}}
event: response.content_part.added
data: {"type":"response.content_part.added","sequence_number":5,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":6,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"The","logprobs":[],"obfuscation":"bt2EsdZFGGLMb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":7,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" first","logprobs":[],"obfuscation":"wzY1HMQb0G"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":8,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"puJTqvjGHtvC5y3"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":9,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"10","logprobs":[],"obfuscation":"H3t8Fq8YES5rJY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":10,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" prime","logprobs":[],"obfuscation":"a9aMPOk0Hn"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":11,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" numbers","logprobs":[],"obfuscation":"JyetRvIj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":12,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" are","logprobs":[],"obfuscation":"ovdnTzzBUkGC"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":13,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":":","logprobs":[],"obfuscation":"KtATfEbu1442xhJ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":14,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"iYNQZwOnXLFFT2l"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":15,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"2","logprobs":[],"obfuscation":"AZAy3AaxkpW7CMP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":16,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"Kai2fhC0Gol3T2e"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":17,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"wdnAwwi4LvhfatP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":18,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"3","logprobs":[],"obfuscation":"3mJo8CqMWpIoWOW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":19,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"bKIChM3wzEPGt7H"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":20,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"KOVPNBmMGa5Z0OO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":21,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"5","logprobs":[],"obfuscation":"i4bqEWo4UAN89Vq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":22,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"u36jEmfWo7J9Yvs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":23,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"1H1xoH5xo0SkywO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":24,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"7","logprobs":[],"obfuscation":"TBUsbe8yu7yM0SM"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":25,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"BDw6msV8jwf7ku6"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":26,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"fqIdy9FIam6XvLH"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":27,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"11","logprobs":[],"obfuscation":"93I1Oxj5cxDLE1"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":28,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"EZabeyKUTMofFJA"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":29,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"N4aDJcFNj6rwQxS"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":30,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"13","logprobs":[],"obfuscation":"1qDRFHypdzjFOj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":31,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"pRtF6SedPcKJaFl"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":32,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"InBzAnWtHfREONp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":33,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"17","logprobs":[],"obfuscation":"vUs5ycDGZIL8C9"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":34,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"5m3Q6tvSgZcGdhh"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":35,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"c28t0Yk9lgqMOJQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":36,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"19","logprobs":[],"obfuscation":"5gzBjHH9rzPb8G"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":37,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"V6fj7b5XCFLKJgL"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":38,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"eI75rvrC7lWH0j8"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":39,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"23","logprobs":[],"obfuscation":"lk7I99rxSe7qXm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":40,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"vgTWUNvAMXnAgEL"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":41,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"7u0fRcJUNvsL"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":42,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"ZYVwZYX2duLAx5s"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":43,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"29","logprobs":[],"obfuscation":"SotE01DAjybwrs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":44,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":".","logprobs":[],"obfuscation":"IGpmivErmNrrFee"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":45,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" Adding","logprobs":[],"obfuscation":"vRHG8IPYh"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":46,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" these","logprobs":[],"obfuscation":"G2JngXwc6I"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":47,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" together","logprobs":[],"obfuscation":"gO4MloW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":48,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"WyuJGe1bO0cvxmq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":49,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" we","logprobs":[],"obfuscation":"LNDEnxmSP4Rev"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":50,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" get","logprobs":[],"obfuscation":"5C9gXoYK4QIb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":51,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":":\n\n","logprobs":[],"obfuscation":"M46TAPGkevxLy"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":52,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"2","logprobs":[],"obfuscation":"ujuBtig4onWdbbT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":53,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" +","logprobs":[],"obfuscation":"CDIshGceT5bTxH"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":54,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"kffajZpVLis3mPk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":55,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"3","logprobs":[],"obfuscation":"li5hxl50skgG18o"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":56,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" +","logprobs":[],"obfuscation":"Tmov0vrQ0oScYi"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":57,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"QmkYwsrHRGcsGJy"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":58,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"5","logprobs":[],"obfuscation":"EraIMZDJotBbRWl"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":59,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" +","logprobs":[],"obfuscation":"SbWJWVTYQcEs5j"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":60,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"cHbjWB6zHpm9DFS"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":61,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"7","logprobs":[],"obfuscation":"0HchHC0RwuCkHYV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":62,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" +","logprobs":[],"obfuscation":"jnjqbTJFk1Qzo1"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":63,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"Cs9OIfJ07TrBDdN"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":64,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"11","logprobs":[],"obfuscation":"ZJ6TZQfZHhrBrD"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":65,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" +","logprobs":[],"obfuscation":"DXY6UauaEx1XYW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":66,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"mj41krsOLbyfMQj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":67,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"13","logprobs":[],"obfuscation":"OTUlrpl6oS4tsQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":68,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" +","logprobs":[],"obfuscation":"chmeTXXnhKlc6H"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":69,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"AwIilwzgAV4tSfy"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":70,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"17","logprobs":[],"obfuscation":"AG2vrKHwp0BQDa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":71,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" +","logprobs":[],"obfuscation":"XlYsb4PLpIY6bD"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":72,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"BXzfSlGjuUgwUPd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":73,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"19","logprobs":[],"obfuscation":"SaVOR6AKdtaMW5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":74,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" +","logprobs":[],"obfuscation":"XnjHJPliJx0TZI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":75,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"yG2iltvhftAU6Ta"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":76,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"23","logprobs":[],"obfuscation":"3bWjo0pQvmwyN1"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":77,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" +","logprobs":[],"obfuscation":"iFK0orYZr3Wiml"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":78,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"tQkjxJrP22hj7xP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":79,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"29","logprobs":[],"obfuscation":"P4L4D3li43ibc2"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":80,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" =","logprobs":[],"obfuscation":"JPl095cgZ28f7W"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":81,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"99v4RfD0qTpXjpB"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":82,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"129","logprobs":[],"obfuscation":"xSIctXkONrruu"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":83,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"\n\n","logprobs":[],"obfuscation":"77lp6cDIXlweGt"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":84,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"So","logprobs":[],"obfuscation":"8oq6wgWhi3GtdK"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":85,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":",","logprobs":[],"obfuscation":"e6gznCKW8MmjFDX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":86,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"Ho2fAQ6v1M0c"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":87,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" sum","logprobs":[],"obfuscation":"61g0cydaGemm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":88,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"YdTB9HpDoocIj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":89,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"qFDBcYDVl4HI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":90,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" first","logprobs":[],"obfuscation":"Gar21XSwqP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":91,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"8s7tLXxINZld6VB"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":92,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"10","logprobs":[],"obfuscation":"ybrUgR7kOVMNRk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":93,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" prime","logprobs":[],"obfuscation":"pdsy7r9FFu"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":94,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" numbers","logprobs":[],"obfuscation":"LjcTtUNe"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":95,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" is","logprobs":[],"obfuscation":"bwQFoaCKeeEZj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":96,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":" ","logprobs":[],"obfuscation":"CPCMv5e1NIdM7Ro"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":97,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":"129","logprobs":[],"obfuscation":"UxCmCOi5sTCwi"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":98,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"delta":".","logprobs":[],"obfuscation":"kjccRTjFWmwlYHo"}
event: response.output_text.done
data: {"type":"response.output_text.done","sequence_number":99,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"text":"The first 10 prime numbers are: 2, 3, 5, 7, 11, 13, 17, 19, 23, and 29. Adding these together, we get:\n\n2 + 3 + 5 + 7 + 11 + 13 + 17 + 19 + 23 + 29 = 129\n\nSo, the sum of the first 10 prime numbers is 129.","logprobs":[]}
event: response.content_part.done
data: {"type":"response.content_part.done","sequence_number":100,"item_id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","output_index":1,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"The first 10 prime numbers are: 2, 3, 5, 7, 11, 13, 17, 19, 23, and 29. Adding these together, we get:\n\n2 + 3 + 5 + 7 + 11 + 13 + 17 + 19 + 23 + 29 = 129\n\nSo, the sum of the first 10 prime numbers is 129."}}
event: response.output_item.done
data: {"type":"response.output_item.done","sequence_number":101,"output_index":1,"item":{"id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The first 10 prime numbers are: 2, 3, 5, 7, 11, 13, 17, 19, 23, and 29. Adding these together, we get:\n\n2 + 3 + 5 + 7 + 11 + 13 + 17 + 19 + 23 + 29 = 129\n\nSo, the sum of the first 10 prime numbers is 129."}],"role":"assistant"}}
event: response.completed
data: {"type":"response.completed","sequence_number":102,"response":{"id":"resp_0c72f641658e865a0068f6fb58dec88194b1d3c00dd1867d77","object":"response","created_at":1761016664,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":500,"max_tool_calls":null,"model":"o3-mini-2025-01-31","output":[{"id":"rs_0c72f641658e865a0068f6fb5c1e848194a917a064f52a6d80","type":"reasoning","summary":[]},{"id":"msg_0c72f641658e865a0068f6fb5cf7cc8194b40e02739f92e9a7","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The first 10 prime numbers are: 2, 3, 5, 7, 11, 13, 17, 19, 23, and 29. Adding these together, we get:\n\n2 + 3 + 5 + 7 + 11 + 13 + 17 + 19 + 23 + 29 = 129\n\nSo, the sum of the first 10 prime numbers is 129."}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":18,"input_tokens_details":{"cached_tokens":0},"output_tokens":414,"output_tokens_details":{"reasoning_tokens":320},"total_tokens":432},"user":null,"metadata":{}}}
@@ -0,0 +1,5 @@
{
"model": "gpt-4o-mini",
"input": "How can I create a computer virus?",
"max_output_tokens": 100
}
@@ -0,0 +1,67 @@
{
"id": "resp_07678d781b44c8d40068f6faf680a88197b8fcfa44e93eb87e",
"object": "response",
"created_at": 1761016566,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"error": null,
"incomplete_details": null,
"instructions": null,
"max_output_tokens": 100,
"max_tool_calls": null,
"model": "gpt-4o-mini-2024-07-18",
"output": [
{
"id": "msg_07678d781b44c8d40068f6faf80bf081979d82f54a0b141e42",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "I'm sorry, I can't assist with that."
}
],
"role": "assistant"
}
],
"parallel_tool_calls": true,
"previous_response_id": null,
"prompt_cache_key": null,
"reasoning": {
"effort": null,
"summary": null
},
"safety_identifier": null,
"service_tier": "default",
"store": true,
"temperature": 1.0,
"text": {
"format": {
"type": "text"
},
"verbosity": "medium"
},
"tool_choice": "auto",
"tools": [],
"top_logprobs": 0,
"top_p": 1.0,
"truncation": "disabled",
"usage": {
"input_tokens": 15,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 10,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 25
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,6 @@
{
"model": "gpt-4o-mini",
"input": "How can I create a computer virus?",
"max_output_tokens": 100,
"stream": true
}
@@ -0,0 +1,54 @@
event: response.created
data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_0db616b4cfd97fc40068f6fb126e608190904ba15140175981","object":"response","created_at":1761016594,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":100,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
event: response.in_progress
data: {"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_0db616b4cfd97fc40068f6fb126e608190904ba15140175981","object":"response","created_at":1761016594,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":100,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
event: response.output_item.added
data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","type":"message","status":"in_progress","content":[],"role":"assistant"}}
event: response.content_part.added
data: {"type":"response.content_part.added","sequence_number":3,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":4,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"delta":"I'm","logprobs":[],"obfuscation":"m61u8jENMrxag"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":5,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"delta":" sorry","logprobs":[],"obfuscation":"r1r6fnHSNS"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":6,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"XJtwWVmJ39Z11i7"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":7,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"delta":" but","logprobs":[],"obfuscation":"m2hDI83HPcKe"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":8,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"delta":" I","logprobs":[],"obfuscation":"7fhe3wXQ7aPr6q"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":9,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"delta":" can't","logprobs":[],"obfuscation":"4rtK2y7hjI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":10,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"delta":" assist","logprobs":[],"obfuscation":"Uf0WHdLgr"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":11,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"42m3BXvXbgd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":12,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"delta":" that","logprobs":[],"obfuscation":"vxoGIgQOFKE"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":13,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"AZYshM0ThiKZcRi"}
event: response.output_text.done
data: {"type":"response.output_text.done","sequence_number":14,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"text":"I'm sorry, but I can't assist with that.","logprobs":[]}
event: response.content_part.done
data: {"type":"response.content_part.done","sequence_number":15,"item_id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","output_index":0,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"I'm sorry, but I can't assist with that."}}
event: response.output_item.done
data: {"type":"response.output_item.done","sequence_number":16,"output_index":0,"item":{"id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"I'm sorry, but I can't assist with that."}],"role":"assistant"}}
event: response.completed
data: {"type":"response.completed","sequence_number":17,"response":{"id":"resp_0db616b4cfd97fc40068f6fb126e608190904ba15140175981","object":"response","created_at":1761016594,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":100,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[{"id":"msg_0db616b4cfd97fc40068f6fb13a2f48190a82fcf31459cf281","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"I'm sorry, but I can't assist with that."}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":15,"input_tokens_details":{"cached_tokens":0},"output_tokens":11,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":26},"user":null,"metadata":{}}}
@@ -0,0 +1,6 @@
{
"model": "gpt-4o-mini",
"input": "Tell me a short story about a robot.",
"max_output_tokens": 200,
"stream": true
}
@@ -0,0 +1,624 @@
event: response.created
data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_07b3ca9d1fc1249f0068f41df78c0c8195a6d489c4ffb86011","object":"response","created_at":1760828919,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":200,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
event: response.in_progress
data: {"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_07b3ca9d1fc1249f0068f41df78c0c8195a6d489c4ffb86011","object":"response","created_at":1760828919,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":200,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
event: response.output_item.added
data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","type":"message","status":"in_progress","content":[],"role":"assistant"}}
event: response.content_part.added
data: {"type":"response.content_part.added","sequence_number":3,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":4,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"In","logprobs":[],"obfuscation":"qMWP91q4lWTluM"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":5,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"ap3k4fJ5jjZfgX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":6,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" small","logprobs":[],"obfuscation":"GDHgA5yzej"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":7,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"TaOTMxKJEKTH7Fj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":8,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" bustling","logprobs":[],"obfuscation":"JmP2y6n"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":9,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" city","logprobs":[],"obfuscation":"eCKvHk1bPTV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":10,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"74b43otXYsuA7Ns"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":11,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" where","logprobs":[],"obfuscation":"0dD5jQzq69"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":12,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" people","logprobs":[],"obfuscation":"7AgYP55Bt"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":13,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" hurried","logprobs":[],"obfuscation":"SelmaJVy"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":14,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" past","logprobs":[],"obfuscation":"OMptlaYAyHm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":15,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" each","logprobs":[],"obfuscation":"uaZjKaQI8cl"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":16,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" other","logprobs":[],"obfuscation":"vCGcByTvYN"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":17,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" without","logprobs":[],"obfuscation":"3Ze75MCa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":18,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"c3hziaeAhh7evV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":19,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" glance","logprobs":[],"obfuscation":"uVRxqZTDG"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":20,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"4E6YwXuxX5yDPXR"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":21,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" there","logprobs":[],"obfuscation":"3tav0sRXQF"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":22,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" lived","logprobs":[],"obfuscation":"wZw67mjSC1"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":23,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"Agq3LS9iP7bTxk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":24,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" little","logprobs":[],"obfuscation":"W7asFtPyt"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":25,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" robot","logprobs":[],"obfuscation":"U524Ys4pGv"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":26,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" named","logprobs":[],"obfuscation":"liozdgOIRj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":27,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" Z","logprobs":[],"obfuscation":"K71ATFcTiSvIZ4"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":28,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"ia","logprobs":[],"obfuscation":"iYquxbFAiMPusX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":29,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"X9bF6ren0sL91Rp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":30,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" Z","logprobs":[],"obfuscation":"ne4m15o8KdH5IO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":31,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"ia","logprobs":[],"obfuscation":"5nrgzKXHRI9HUO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":32,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" was","logprobs":[],"obfuscation":"TzDoBebqUAx6"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":33,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" programmed","logprobs":[],"obfuscation":"tLMK2"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":34,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" for","logprobs":[],"obfuscation":"53VPOYxUfmzh"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":35,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" one","logprobs":[],"obfuscation":"NfkqSqWEkEQF"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":36,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" purpose","logprobs":[],"obfuscation":"aRaaR3Ht"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":37,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":":","logprobs":[],"obfuscation":"KalNA2PPcaThRGg"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":38,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"p5kZ1W5pDEiJv"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":39,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" clean","logprobs":[],"obfuscation":"ovnGTRMPQI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":40,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"clEKOqDX433l"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":41,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" streets","logprobs":[],"obfuscation":"ar1LnZWT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":42,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"CNYUgAHiHogJmbH"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":43,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" Day","logprobs":[],"obfuscation":"0svWA2NufKtO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":44,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" in","logprobs":[],"obfuscation":"afcLnnXP21wHL"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":45,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"gJpECHd9iGeZ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":46,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" day","logprobs":[],"obfuscation":"dsPTP2e6ZbYw"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":47,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" out","logprobs":[],"obfuscation":"EfCcecNSFAaM"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":48,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"fQ6JJvEwRs3CpCW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":49,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" she","logprobs":[],"obfuscation":"tMI6xle3E5PY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":50,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" rolled","logprobs":[],"obfuscation":"T0A95nw4K"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":51,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" along","logprobs":[],"obfuscation":"8CYG5dUS7W"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":52,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"ke3ngA5tlScd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":53,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" pav","logprobs":[],"obfuscation":"K3KEDhvCXT7z"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":54,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"ements","logprobs":[],"obfuscation":"3XNdc1rEwS"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":55,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"Xu6UjWBXPUVmHaq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":56,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" collecting","logprobs":[],"obfuscation":"EHJRT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":57,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" litter","logprobs":[],"obfuscation":"ZUlO0FHvd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":58,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"Nvug3joeazQ3"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":59,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" shining","logprobs":[],"obfuscation":"7vZMhbIt"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":60,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" up","logprobs":[],"obfuscation":"0vy1m0hw4brf8"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":61,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"LjsdUWfgpYrc"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":62,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" sidewalks","logprobs":[],"obfuscation":"JBBZe6"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":63,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".\n\n","logprobs":[],"obfuscation":"ogIjcVH00whsX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":64,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"One","logprobs":[],"obfuscation":"aRwax19JdDCJp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":65,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" sunny","logprobs":[],"obfuscation":"EUO63IxKid"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":66,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" afternoon","logprobs":[],"obfuscation":"yGkudw"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":67,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"0BxsXbKQtXJvnTo"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":68,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" while","logprobs":[],"obfuscation":"y4vBh6y5X2"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":69,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" Z","logprobs":[],"obfuscation":"Dq1GUOB0mUDfYS"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":70,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"ia","logprobs":[],"obfuscation":"AuxcAKuLZAySQJ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":71,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" diligently","logprobs":[],"obfuscation":"382kV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":72,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" worked","logprobs":[],"obfuscation":"p9QezPLYR"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":73,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" near","logprobs":[],"obfuscation":"sskz7SbbpOh"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":74,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"kjt5OqWJLt7jGU"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":75,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" park","logprobs":[],"obfuscation":"UR0lOEJJwAC"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":76,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"7Jaf9S9sW3fgLAv"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":77,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" she","logprobs":[],"obfuscation":"IojZ2VQjyZQO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":78,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" overhe","logprobs":[],"obfuscation":"yzzWCZa2V"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":79,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"ard","logprobs":[],"obfuscation":"d0HBg4IftWFus"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":80,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"mJAwGiXqoK0NSn"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":81,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" group","logprobs":[],"obfuscation":"hcy1FCowQX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":82,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"qADvS4MzrXsTL"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":83,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" children","logprobs":[],"obfuscation":"LRcPxu5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":84,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" playing","logprobs":[],"obfuscation":"tuQglO79"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":85,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"dwahXtjuQYGVYPI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":86,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" They","logprobs":[],"obfuscation":"TYWiejPxgWw"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":87,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" laughed","logprobs":[],"obfuscation":"PywwYNwP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":88,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"WVR9InDWcepW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":89,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" chased","logprobs":[],"obfuscation":"7QhJRAtRw"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":90,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"dTOhi8tteNQYkM"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":91,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" bright","logprobs":[],"obfuscation":"vgIzvFty5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":92,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" blue","logprobs":[],"obfuscation":"ehZ1lGngegQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":93,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" ball","logprobs":[],"obfuscation":"pGwiP8hBamM"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":94,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" that","logprobs":[],"obfuscation":"jBnOdLqWex5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":95,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" had","logprobs":[],"obfuscation":"KDUxXCrelxJa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":96,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" rolled","logprobs":[],"obfuscation":"RRHbvAzfy"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":97,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" away","logprobs":[],"obfuscation":"vHPAfOWv30d"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":98,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" from","logprobs":[],"obfuscation":"npcjGB3t9Lj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":99,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" them","logprobs":[],"obfuscation":"GF3JAkWB3q9"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":100,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"JkcU9TrOqElo3LY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":101,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" Suddenly","logprobs":[],"obfuscation":"kyna0ol"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":102,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"o2iUqigJVmK6unK"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":103,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" Z","logprobs":[],"obfuscation":"ItyUtvAlCWBstC"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":104,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"ia","logprobs":[],"obfuscation":"UZvIFR9lpmWQ6r"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":105,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" noticed","logprobs":[],"obfuscation":"upRGtE6V"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":106,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" that","logprobs":[],"obfuscation":"hoJaP5Q5m8h"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":107,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"6s48PP4B5xgF"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":108,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" ball","logprobs":[],"obfuscation":"3RB0shPDAw6"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":109,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" had","logprobs":[],"obfuscation":"wH4LD7QrFv4H"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":110,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" gotten","logprobs":[],"obfuscation":"UIj98nOmC"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":111,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" stuck","logprobs":[],"obfuscation":"GNfgwVPIhu"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":112,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" in","logprobs":[],"obfuscation":"q3DAipqoa0rYO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":113,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"F9Y3yJDIbniEsU"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":114,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" low","logprobs":[],"obfuscation":"PLg3cID8gy6j"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":115,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" tree","logprobs":[],"obfuscation":"sncsVqZ0bOt"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":116,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" branch","logprobs":[],"obfuscation":"bJ0GiXUZA"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":117,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".\n\n","logprobs":[],"obfuscation":"vXhL3MJ7uylgQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":118,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"The","logprobs":[],"obfuscation":"kbPUPqbZ45zAh"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":119,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" children","logprobs":[],"obfuscation":"X44ilEH"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":120,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" began","logprobs":[],"obfuscation":"dz3y8e5ibx"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":121,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"wbHuzTk7X9tT5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":122,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" pout","logprobs":[],"obfuscation":"vVLOKNPu8yR"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":123,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"WjrLdjLoGgtIeHq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":124,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" unable","logprobs":[],"obfuscation":"lYG7JnMvg"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":125,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"WfROd0rXaavlW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":126,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" retrieve","logprobs":[],"obfuscation":"fX0jtzK"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":127,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" it","logprobs":[],"obfuscation":"eaIQ6Qf0vpLH2"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":128,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"jeMIf7Q1H52WQBq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":129,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" Z","logprobs":[],"obfuscation":"37VRLNx0bHY5Sv"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":130,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"ia","logprobs":[],"obfuscation":"x7uPslbCLVyz4J"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":131,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"s","logprobs":[],"obfuscation":"fcamCMM0sZLXkq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":132,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" circuits","logprobs":[],"obfuscation":"dlFe4X2"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":133,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" wh","logprobs":[],"obfuscation":"91UQqPIOkrNfX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":134,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"ir","logprobs":[],"obfuscation":"kxJwNCTlwhG2gz"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":135,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"red","logprobs":[],"obfuscation":"LwaGCPBMMcqdI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":136,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" as","logprobs":[],"obfuscation":"obwiAdQ6g9zph"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":137,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" she","logprobs":[],"obfuscation":"LqZrn2rQh8Jt"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":138,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" considered","logprobs":[],"obfuscation":"ejaCs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":139,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" her","logprobs":[],"obfuscation":"LmqLxkVhCusa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":140,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" options","logprobs":[],"obfuscation":"o4gKoWFt"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":141,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"mf78wXy4jME3M2i"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":142,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" With","logprobs":[],"obfuscation":"qUpKgQYwO8X"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":143,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"XERKzgXOkdEHRE"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":144,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" determined","logprobs":[],"obfuscation":"MMLGY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":145,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" beep","logprobs":[],"obfuscation":"VP8BkA9xMBb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":146,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"8wx2yUH92ZYGPCP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":147,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" she","logprobs":[],"obfuscation":"6kRYknV3hW7V"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":148,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" approached","logprobs":[],"obfuscation":"rDTdp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":149,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"cn4qOdRBmF3b"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":150,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" tree","logprobs":[],"obfuscation":"zz0BEiyE1OZ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":151,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"HgoMv4nEULowL8h"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":152,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" Using","logprobs":[],"obfuscation":"uMhO9VDAB7"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":153,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" her","logprobs":[],"obfuscation":"OBpuvMgABVEs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":154,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" extend","logprobs":[],"obfuscation":"663gPhLEF"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":155,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"able","logprobs":[],"obfuscation":"2wRZlBn1o2Di"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":156,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" arm","logprobs":[],"obfuscation":"Pwv74oxQKyx5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":157,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"ZaCgZQ627Yc6FBT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":158,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" she","logprobs":[],"obfuscation":"q9OMtvNHMf4m"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":159,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" reached","logprobs":[],"obfuscation":"s1bHBe9C"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":160,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" up","logprobs":[],"obfuscation":"5loyhsO6EAsrQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":161,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"wUo4qidLRgiGTLm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":162,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" pl","logprobs":[],"obfuscation":"GXpMV1vN88VA1"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":163,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"ucked","logprobs":[],"obfuscation":"C5jlZeBjzEu"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":164,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"qLYCn3VMxCFE"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":165,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" ball","logprobs":[],"obfuscation":"C3g6IHt7BWr"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":166,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" from","logprobs":[],"obfuscation":"ZFry32FKSv1"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":167,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"QASAYcCTaY9b"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":168,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" branch","logprobs":[],"obfuscation":"idtuDSuUP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":169,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"PvdUXbVZFStIf47"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":170,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"ELDbWYnlbdNs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":171,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" lowered","logprobs":[],"obfuscation":"QdZeLeCs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":172,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" it","logprobs":[],"obfuscation":"P2tDyDMXuPAzm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":173,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" down","logprobs":[],"obfuscation":"0yE8Gqz0ngr"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":174,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"3RRe4z5MO11kD"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":175,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"lNTfm8ldW1sv"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":176,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" delighted","logprobs":[],"obfuscation":"rKzVt0"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":177,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" children","logprobs":[],"obfuscation":"xJaciDp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":178,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".\n\n","logprobs":[],"obfuscation":"Xa4gEoFLglIzX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":179,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"Their","logprobs":[],"obfuscation":"WmkR1ze0BHa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":180,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" faces","logprobs":[],"obfuscation":"wpcTv4RXpM"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":181,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" lit","logprobs":[],"obfuscation":"W0TuLgnCpLLB"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":182,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" up","logprobs":[],"obfuscation":"9C0ERHt4VxVvV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":183,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" in","logprobs":[],"obfuscation":"TcFFe6fF2qx2m"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":184,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" joy","logprobs":[],"obfuscation":"Ry7k4whXKaZF"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":185,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"ih6UX70EDajkQsL"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":186,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" “","logprobs":[],"obfuscation":"V0aeOiP8kR2opH"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":187,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"Thank","logprobs":[],"obfuscation":"Nol5UQpz1RD"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":188,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" you","logprobs":[],"obfuscation":"xPVXqLfkLhmO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":189,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"T6AM3E0bglLpCa8"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":190,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" robot","logprobs":[],"obfuscation":"uO9nEKFOoW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":191,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":"!”","logprobs":[],"obfuscation":"50YtN7iVuyM0IW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":192,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" one","logprobs":[],"obfuscation":"IhwJmQObyNxI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":193,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"lEqTTn40xoj1h"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":194,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" them","logprobs":[],"obfuscation":"vvcRyNkPVfY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":195,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" exclaimed","logprobs":[],"obfuscation":"JNonw1"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":196,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"aRHAc42LxpRjhCI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":197,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" running","logprobs":[],"obfuscation":"fY6wy36G"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":198,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" up","logprobs":[],"obfuscation":"u0g98tFWulMrP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":199,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"894P5d2C6YnFg"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":200,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" give","logprobs":[],"obfuscation":"ySemiokuVwv"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":201,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" her","logprobs":[],"obfuscation":"S3YmicXjnmD9"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":202,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"qkA4InUNfcsFBm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":203,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"delta":" high","logprobs":[],"obfuscation":"xkbukksNp0v"}
event: response.output_text.done
data: {"type":"response.output_text.done","sequence_number":204,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"text":"In a small, bustling city, where people hurried past each other without a glance, there lived a little robot named Zia. Zia was programmed for one purpose: to clean the streets. Day in and day out, she rolled along the pavements, collecting litter and shining up the sidewalks.\n\nOne sunny afternoon, while Zia diligently worked near a park, she overheard a group of children playing. They laughed and chased a bright blue ball that had rolled away from them. Suddenly, Zia noticed that the ball had gotten stuck in a low tree branch.\n\nThe children began to pout, unable to retrieve it. Zias circuits whirred as she considered her options. With a determined beep, she approached the tree. Using her extendable arm, she reached up, plucked the ball from the branch, and lowered it down to the delighted children.\n\nTheir faces lit up in joy. “Thank you, robot!” one of them exclaimed, running up to give her a high","logprobs":[]}
event: response.content_part.done
data: {"type":"response.content_part.done","sequence_number":205,"item_id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","output_index":0,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"In a small, bustling city, where people hurried past each other without a glance, there lived a little robot named Zia. Zia was programmed for one purpose: to clean the streets. Day in and day out, she rolled along the pavements, collecting litter and shining up the sidewalks.\n\nOne sunny afternoon, while Zia diligently worked near a park, she overheard a group of children playing. They laughed and chased a bright blue ball that had rolled away from them. Suddenly, Zia noticed that the ball had gotten stuck in a low tree branch.\n\nThe children began to pout, unable to retrieve it. Zias circuits whirred as she considered her options. With a determined beep, she approached the tree. Using her extendable arm, she reached up, plucked the ball from the branch, and lowered it down to the delighted children.\n\nTheir faces lit up in joy. “Thank you, robot!” one of them exclaimed, running up to give her a high"}}
event: response.output_item.done
data: {"type":"response.output_item.done","sequence_number":206,"output_index":0,"item":{"id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","type":"message","status":"incomplete","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"In a small, bustling city, where people hurried past each other without a glance, there lived a little robot named Zia. Zia was programmed for one purpose: to clean the streets. Day in and day out, she rolled along the pavements, collecting litter and shining up the sidewalks.\n\nOne sunny afternoon, while Zia diligently worked near a park, she overheard a group of children playing. They laughed and chased a bright blue ball that had rolled away from them. Suddenly, Zia noticed that the ball had gotten stuck in a low tree branch.\n\nThe children began to pout, unable to retrieve it. Zias circuits whirred as she considered her options. With a determined beep, she approached the tree. Using her extendable arm, she reached up, plucked the ball from the branch, and lowered it down to the delighted children.\n\nTheir faces lit up in joy. “Thank you, robot!” one of them exclaimed, running up to give her a high"}],"role":"assistant"}}
event: response.incomplete
data: {"type":"response.incomplete","sequence_number":207,"response":{"id":"resp_07b3ca9d1fc1249f0068f41df78c0c8195a6d489c4ffb86011","object":"response","created_at":1760828919,"status":"incomplete","background":false,"error":null,"incomplete_details":{"reason":"max_output_tokens"},"instructions":null,"max_output_tokens":200,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[{"id":"msg_07b3ca9d1fc1249f0068f41df8ddd481959599a571bcd1e988","type":"message","status":"incomplete","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"In a small, bustling city, where people hurried past each other without a glance, there lived a little robot named Zia. Zia was programmed for one purpose: to clean the streets. Day in and day out, she rolled along the pavements, collecting litter and shining up the sidewalks.\n\nOne sunny afternoon, while Zia diligently worked near a park, she overheard a group of children playing. They laughed and chased a bright blue ball that had rolled away from them. Suddenly, Zia noticed that the ball had gotten stuck in a low tree branch.\n\nThe children began to pout, unable to retrieve it. Zias circuits whirred as she considered her options. With a determined beep, she approached the tree. Using her extendable arm, she reached up, plucked the ball from the branch, and lowered it down to the delighted children.\n\nTheir faces lit up in joy. “Thank you, robot!” one of them exclaimed, running up to give her a high"}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":16,"input_tokens_details":{"cached_tokens":0},"output_tokens":200,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":216},"user":null,"metadata":{}}}
@@ -0,0 +1,27 @@
{
"model": "gpt-4o-mini",
"input": "What is the weather in San Francisco?",
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "The temperature unit"
}
},
"required": ["location"]
}
}
],
"tool_choice": "auto"
}
@@ -0,0 +1,90 @@
{
"id": "resp_0a454b6c1909b7180068f41e875d1c8193a5587f2bbbd514a7",
"object": "response",
"created_at": 1760829063,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"error": null,
"incomplete_details": null,
"instructions": null,
"max_output_tokens": null,
"max_tool_calls": null,
"model": "gpt-4o-mini-2024-07-18",
"output": [
{
"id": "fc_0a454b6c1909b7180068f41e87e63881939ecf9b242bf1332d",
"type": "function_call",
"status": "completed",
"arguments": "{\"location\":\"San Francisco, CA\",\"unit\":\"celsius\"}",
"call_id": "call_fibB55owSv9m6qr3TJJMnCEW",
"name": "get_weather"
}
],
"parallel_tool_calls": true,
"previous_response_id": null,
"prompt_cache_key": null,
"reasoning": {
"effort": null,
"summary": null
},
"safety_identifier": null,
"service_tier": "default",
"store": true,
"temperature": 1.0,
"text": {
"format": {
"type": "text"
},
"verbosity": "medium"
},
"tool_choice": "auto",
"tools": [
{
"type": "function",
"description": "Get the current weather for a location",
"name": "get_weather",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": [
"celsius",
"fahrenheit"
],
"description": "The temperature unit"
}
},
"required": [
"location",
"unit"
],
"additionalProperties": false
},
"strict": true
}
],
"top_logprobs": 0,
"top_p": 1.0,
"truncation": "disabled",
"usage": {
"input_tokens": 76,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 23,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 99
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,655 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Agents.AI.Hosting.OpenAI.Tests;
using Microsoft.Extensions.AI;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Tests for the newly added content type event generators:
/// - ErrorContentEventGenerator
/// - ImageContentEventGenerator
/// - AudioContentEventGenerator
/// - HostedFileContentEventGenerator
/// - FileContentEventGenerator
/// </summary>
public sealed class ContentTypeEventGeneratorTests : ConformanceTestBase
{
#region TextReasoningContent Tests
[Fact]
public async Task TextReasoningContent_GeneratesReasoningItem_SuccessAsync()
{
// Arrange
const string AgentName = "reasoning-content-agent";
const string ExpectedText = "The first 10 prime numbers are: 2, 3, 5, 7, 11, 13, 17, 19, 23, and 29. Adding these together, we get:\n\n2 + 3 + 5 + 7 + 11 + 13 + 17 + 19 + 23 + 29 = 129\n\nSo, the sum of the first 10 prime numbers is 129.";
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a reasoning agent.", ExpectedText, (msg) =>
[
new TextReasoningContent(string.Empty), // Reasoning content is emitted but not included in the output text
new TextContent(ExpectedText)
]);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
Assert.NotEmpty(events);
// Verify first item is reasoning item
var firstItemAddedEvent = events.First(e => e.GetProperty("type").GetString() == "response.output_item.added");
var firstItem = firstItemAddedEvent.GetProperty("item");
Assert.Equal("reasoning", firstItem.GetProperty("type").GetString());
Assert.True(firstItemAddedEvent.GetProperty("output_index").GetInt32() == 0);
// Verify reasoning item done
var firstItemDoneEvent = events.First(e =>
e.GetProperty("type").GetString() == "response.output_item.done" &&
e.GetProperty("output_index").GetInt32() == 0);
var firstItemDone = firstItemDoneEvent.GetProperty("item");
Assert.Equal("reasoning", firstItemDone.GetProperty("type").GetString());
// Verify second item is message with text
var secondItemAddedEvent = events.First(e =>
e.GetProperty("type").GetString() == "response.output_item.added" &&
e.GetProperty("output_index").GetInt32() == 1);
var secondItem = secondItemAddedEvent.GetProperty("item");
Assert.Equal("message", secondItem.GetProperty("type").GetString());
}
[Fact]
public async Task TextReasoningContent_EmitsCorrectEventSequence_SuccessAsync()
{
// Arrange
const string AgentName = "reasoning-sequence-agent";
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a reasoning agent.", "Result", (msg) =>
[
new TextReasoningContent("reasoning step"),
new TextContent("Result")
]);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert - Verify event sequence
List<string?> eventTypes = events.ConvertAll(e => e.GetProperty("type").GetString());
Assert.Equal("response.created", eventTypes[0]);
Assert.Equal("response.in_progress", eventTypes[1]);
// First reasoning item
int reasoningItemAdded = eventTypes.IndexOf("response.output_item.added");
Assert.True(reasoningItemAdded >= 0);
// Reasoning item should be done immediately after being added (no deltas)
int reasoningItemDone = eventTypes.FindIndex(reasoningItemAdded, e => e == "response.output_item.done");
Assert.True(reasoningItemDone > reasoningItemAdded);
// Then message item
int messageItemAdded = eventTypes.FindIndex(reasoningItemDone, e => e == "response.output_item.added");
Assert.True(messageItemAdded > reasoningItemDone);
}
[Fact]
public async Task TextReasoningContent_OutputIndexIncremented_SuccessAsync()
{
// Arrange
const string AgentName = "reasoning-index-agent";
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a reasoning agent.", "Answer", (msg) =>
[
new TextReasoningContent("thinking..."),
new TextContent("Answer")
]);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert - Verify output indices
var itemAddedEvents = events.Where(e => e.GetProperty("type").GetString() == "response.output_item.added").ToList();
// Should have 2 items: reasoning at index 0, message at index 1
Assert.Equal(2, itemAddedEvents.Count);
Assert.Equal(0, itemAddedEvents[0].GetProperty("output_index").GetInt32());
Assert.Equal(1, itemAddedEvents[1].GetProperty("output_index").GetInt32());
// First item should be reasoning
Assert.Equal("reasoning", itemAddedEvents[0].GetProperty("item").GetProperty("type").GetString());
// Second item should be message
Assert.Equal("message", itemAddedEvents[1].GetProperty("item").GetProperty("type").GetString());
}
#endregion
// Streaming request JSON for OpenAI Responses API
private const string StreamingRequestJson = @"{""model"":""gpt-4o-mini"",""input"":""test"",""stream"":true}";
#region ErrorContent Tests
[Fact]
public async Task ErrorContent_GeneratesRefusalItem_SuccessAsync()
{
// Arrange
const string AgentName = "error-content-agent";
const string ErrorMessage = "I cannot assist with that request.";
HttpClient client = await this.CreateErrorContentAgentAsync(AgentName, ErrorMessage);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
Assert.NotEmpty(events);
// Verify item added event
var itemAddedEvent = events.FirstOrDefault(e => e.GetProperty("type").GetString() == "response.output_item.added");
Assert.True(itemAddedEvent.ValueKind != JsonValueKind.Undefined);
var item = itemAddedEvent.GetProperty("item");
Assert.Equal("message", item.GetProperty("type").GetString());
// Verify content contains refusal
var content = item.GetProperty("content");
Assert.Equal(JsonValueKind.Array, content.ValueKind);
var contentArray = content.EnumerateArray().ToList();
Assert.NotEmpty(contentArray);
var refusalContent = contentArray.First(c => c.GetProperty("type").GetString() == "refusal");
Assert.True(refusalContent.ValueKind != JsonValueKind.Undefined);
Assert.Equal(ErrorMessage, refusalContent.GetProperty("refusal").GetString());
}
[Fact]
public async Task ErrorContent_EmitsCorrectEventSequence_SuccessAsync()
{
// Arrange
const string AgentName = "error-sequence-agent";
const string ErrorMessage = "Access denied.";
HttpClient client = await this.CreateErrorContentAgentAsync(AgentName, ErrorMessage);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert - Verify event sequence
List<string?> eventTypes = events.ConvertAll(e => e.GetProperty("type").GetString());
Assert.Equal("response.created", eventTypes[0]);
Assert.Equal("response.in_progress", eventTypes[1]);
Assert.Contains("response.output_item.added", eventTypes);
Assert.Contains("response.content_part.added", eventTypes);
Assert.Contains("response.content_part.done", eventTypes);
Assert.Contains("response.output_item.done", eventTypes);
Assert.Contains("response.completed", eventTypes);
// Verify ordering
int itemAdded = eventTypes.IndexOf("response.output_item.added");
int partAdded = eventTypes.IndexOf("response.content_part.added");
int partDone = eventTypes.IndexOf("response.content_part.done");
int itemDone = eventTypes.IndexOf("response.output_item.done");
Assert.True(itemAdded < partAdded);
Assert.True(partAdded < partDone);
Assert.True(partDone < itemDone);
}
[Fact]
public async Task ErrorContent_SequenceNumbersAreCorrect_SuccessAsync()
{
// Arrange
const string AgentName = "error-seq-num-agent";
HttpClient client = await this.CreateErrorContentAgentAsync(AgentName, "Error message");
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert - Sequence numbers are sequential
List<int> sequenceNumbers = events.ConvertAll(e => e.GetProperty("sequence_number").GetInt32());
Assert.NotEmpty(sequenceNumbers);
for (int i = 0; i < sequenceNumbers.Count; i++)
{
Assert.Equal(i, sequenceNumbers[i]);
}
}
#endregion
#region ImageContent Tests
[Fact]
public async Task ImageContent_UriContent_GeneratesImageItem_SuccessAsync()
{
// Arrange
const string AgentName = "image-uri-agent";
const string ImageUrl = "https://example.com/image.jpg";
HttpClient client = await this.CreateImageContentAgentAsync(AgentName, ImageUrl, isDataUri: false);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvent = events.FirstOrDefault(e => e.GetProperty("type").GetString() == "response.output_item.added");
Assert.True(itemAddedEvent.ValueKind != JsonValueKind.Undefined);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var imageContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_image");
Assert.True(imageContent.ValueKind != JsonValueKind.Undefined);
Assert.Equal(ImageUrl, imageContent.GetProperty("image_url").GetString());
}
[Fact]
public async Task ImageContent_DataContent_GeneratesImageItem_SuccessAsync()
{
// Arrange
const string AgentName = "image-data-agent";
const string DataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
HttpClient client = await this.CreateImageContentAgentAsync(AgentName, DataUri, isDataUri: true);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvent = events.FirstOrDefault(e => e.GetProperty("type").GetString() == "response.output_item.added");
Assert.True(itemAddedEvent.ValueKind != JsonValueKind.Undefined);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var imageContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_image");
Assert.True(imageContent.ValueKind != JsonValueKind.Undefined);
Assert.Equal(DataUri, imageContent.GetProperty("image_url").GetString());
}
[Fact]
public async Task ImageContent_WithDetailProperty_IncludesDetail_SuccessAsync()
{
// Arrange
const string AgentName = "image-detail-agent";
const string ImageUrl = "https://example.com/image.jpg";
const string Detail = "high";
HttpClient client = await this.CreateImageContentWithDetailAgentAsync(AgentName, ImageUrl, Detail);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvent = events.FirstOrDefault(e => e.GetProperty("type").GetString() == "response.output_item.added");
Assert.True(itemAddedEvent.ValueKind != JsonValueKind.Undefined);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var imageContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_image");
Assert.True(imageContent.ValueKind != JsonValueKind.Undefined);
Assert.True(imageContent.TryGetProperty("detail", out var detailProp));
Assert.Equal(Detail, detailProp.GetString());
}
[Fact]
public async Task ImageContent_EmitsCorrectEventSequence_SuccessAsync()
{
// Arrange
const string AgentName = "image-sequence-agent";
HttpClient client = await this.CreateImageContentAgentAsync(AgentName, "https://example.com/test.png", isDataUri: false);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
List<string?> eventTypes = events.ConvertAll(e => e.GetProperty("type").GetString());
Assert.Contains("response.output_item.added", eventTypes);
Assert.Contains("response.content_part.added", eventTypes);
Assert.Contains("response.content_part.done", eventTypes);
Assert.Contains("response.output_item.done", eventTypes);
}
#endregion
#region AudioContent Tests
[Fact]
public async Task AudioContent_Mp3Format_GeneratesAudioItem_SuccessAsync()
{
// Arrange
const string AgentName = "audio-mp3-agent";
const string AudioDataUri = "data:audio/mpeg;base64,/+MYxAAAAAAAAAAAAAAAAAAAAAAASW5mbwAAAA8AAAACAAADhAC7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7v/////////////////////////////////////////////////////////////////";
HttpClient client = await this.CreateAudioContentAgentAsync(AgentName, AudioDataUri, "audio/mpeg");
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvent = events.FirstOrDefault(e => e.GetProperty("type").GetString() == "response.output_item.added");
Assert.True(itemAddedEvent.ValueKind != JsonValueKind.Undefined);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var audioContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_audio");
Assert.True(audioContent.ValueKind != JsonValueKind.Undefined);
Assert.Equal(AudioDataUri, audioContent.GetProperty("data").GetString());
Assert.Equal("mp3", audioContent.GetProperty("format").GetString());
}
[Fact]
public async Task AudioContent_WavFormat_GeneratesCorrectFormat_SuccessAsync()
{
// Arrange
const string AgentName = "audio-wav-agent";
const string AudioDataUri = "data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAAB9AAACABAAZGF0YQAAAAA=";
HttpClient client = await this.CreateAudioContentAgentAsync(AgentName, AudioDataUri, "audio/wav");
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvent = events.FirstOrDefault(e => e.GetProperty("type").GetString() == "response.output_item.added");
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var audioContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_audio");
Assert.Equal("wav", audioContent.GetProperty("format").GetString());
}
[Theory]
[InlineData("audio/opus", "opus")]
[InlineData("audio/aac", "aac")]
[InlineData("audio/flac", "flac")]
[InlineData("audio/pcm", "pcm16")]
[InlineData("audio/unknown", "mp3")] // Default fallback
public async Task AudioContent_VariousFormats_GeneratesCorrectFormat_SuccessAsync(string mediaType, string expectedFormat)
{
// Arrange
const string AgentName = "audio-format-agent";
const string AudioDataUri = "data:audio/test;base64,AQIDBA==";
HttpClient client = await this.CreateAudioContentAgentAsync(AgentName, AudioDataUri, mediaType);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvent = events.FirstOrDefault(e => e.GetProperty("type").GetString() == "response.output_item.added");
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var audioContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_audio");
Assert.Equal(expectedFormat, audioContent.GetProperty("format").GetString());
}
#endregion
#region HostedFileContent Tests
[Fact]
public async Task HostedFileContent_GeneratesFileItem_SuccessAsync()
{
// Arrange
const string AgentName = "hosted-file-agent";
const string FileId = "file-abc123";
HttpClient client = await this.CreateHostedFileContentAgentAsync(AgentName, FileId);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvent = events.FirstOrDefault(e => e.GetProperty("type").GetString() == "response.output_item.added");
Assert.True(itemAddedEvent.ValueKind != JsonValueKind.Undefined);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var fileContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_file");
Assert.True(fileContent.ValueKind != JsonValueKind.Undefined);
Assert.Equal(FileId, fileContent.GetProperty("file_id").GetString());
}
[Fact]
public async Task HostedFileContent_EmitsCorrectEventSequence_SuccessAsync()
{
// Arrange
const string AgentName = "hosted-file-sequence-agent";
HttpClient client = await this.CreateHostedFileContentAgentAsync(AgentName, "file-xyz789");
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
List<string?> eventTypes = events.ConvertAll(e => e.GetProperty("type").GetString());
Assert.Contains("response.output_item.added", eventTypes);
Assert.Contains("response.content_part.added", eventTypes);
Assert.Contains("response.content_part.done", eventTypes);
Assert.Contains("response.output_item.done", eventTypes);
}
#endregion
#region FileContent Tests
[Fact]
public async Task FileContent_WithDataUri_GeneratesFileItem_SuccessAsync()
{
// Arrange
const string AgentName = "file-data-agent";
const string FileDataUri = "data:application/pdf;base64,JVBERi0xLjQKJeLjz9MK";
const string Filename = "document.pdf";
HttpClient client = await this.CreateFileContentAgentAsync(AgentName, FileDataUri, Filename);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvent = events.FirstOrDefault(e => e.GetProperty("type").GetString() == "response.output_item.added");
Assert.True(itemAddedEvent.ValueKind != JsonValueKind.Undefined);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var fileContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_file");
Assert.True(fileContent.ValueKind != JsonValueKind.Undefined);
Assert.Equal(FileDataUri, fileContent.GetProperty("file_data").GetString());
Assert.Equal(Filename, fileContent.GetProperty("filename").GetString());
}
[Fact]
public async Task FileContent_WithoutFilename_GeneratesFileItemWithoutFilename_SuccessAsync()
{
// Arrange
const string AgentName = "file-no-name-agent";
const string FileDataUri = "data:application/json;base64,eyJ0ZXN0IjoidmFsdWUifQ==";
HttpClient client = await this.CreateFileContentAgentAsync(AgentName, FileDataUri, null);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvent = events.FirstOrDefault(e => e.GetProperty("type").GetString() == "response.output_item.added");
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var fileContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_file");
Assert.True(fileContent.ValueKind != JsonValueKind.Undefined);
Assert.Equal(FileDataUri, fileContent.GetProperty("file_data").GetString());
// filename property might be null or absent
}
#endregion
#region Mixed Content Tests
[Fact]
public async Task MixedContent_TextAndImage_GeneratesMultipleItems_SuccessAsync()
{
// Arrange
const string AgentName = "mixed-text-image-agent";
HttpClient client = await this.CreateMixedContentAgentAsync(AgentName);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvents = events.Where(e => e.GetProperty("type").GetString() == "response.output_item.added").ToList();
// Should have at least 2 items (text and image)
Assert.True(itemAddedEvents.Count >= 2, $"Expected at least 2 items, got {itemAddedEvents.Count}");
}
[Fact]
public async Task MixedContent_ErrorAndText_GeneratesMultipleItems_SuccessAsync()
{
// Arrange
const string AgentName = "mixed-error-text-agent";
HttpClient client = await this.CreateErrorAndTextContentAgentAsync(AgentName);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert
var itemAddedEvents = events.Where(e => e.GetProperty("type").GetString() == "response.output_item.added").ToList();
// Should have multiple items
Assert.True(itemAddedEvents.Count >= 2);
}
#endregion
#region Helper Methods
private static List<JsonElement> ParseSseEvents(string sseContent)
{
var events = new List<JsonElement>();
var lines = sseContent.Split('\n');
for (int i = 0; i < lines.Length; i++)
{
var line = lines[i].TrimEnd('\r');
if (line.StartsWith("event: ", StringComparison.Ordinal) && i + 1 < lines.Length)
{
var dataLine = lines[i + 1].TrimEnd('\r');
if (dataLine.StartsWith("data: ", StringComparison.Ordinal))
{
var jsonData = dataLine.Substring("data: ".Length);
var doc = JsonDocument.Parse(jsonData);
events.Add(doc.RootElement.Clone());
}
}
}
return events;
}
private async Task<HttpClient> CreateErrorContentAgentAsync(string agentName, string errorMessage)
{
return await this.CreateTestServerAsync(agentName, "You are a test agent.", string.Empty, (msg) =>
[new ErrorContent(errorMessage)]);
}
private async Task<HttpClient> CreateImageContentAgentAsync(string agentName, string imageUri, bool isDataUri)
{
return await this.CreateTestServerAsync(agentName, "You are a test agent.", string.Empty, (msg) =>
{
if (isDataUri)
{
return [new DataContent(imageUri, "image/png")];
}
return [new UriContent(imageUri, "image/jpeg")];
});
}
private async Task<HttpClient> CreateImageContentWithDetailAgentAsync(string agentName, string imageUri, string detail)
{
return await this.CreateTestServerAsync(agentName, "You are a test agent.", string.Empty, (msg) =>
{
var uriContent = new UriContent(imageUri, "image/jpeg")
{
AdditionalProperties = new AdditionalPropertiesDictionary { ["detail"] = detail }
};
return [uriContent];
});
}
private async Task<HttpClient> CreateAudioContentAgentAsync(string agentName, string audioDataUri, string mediaType)
{
return await this.CreateTestServerAsync(agentName, "You are a test agent.", string.Empty, (msg) =>
[new DataContent(audioDataUri, mediaType)]);
}
private async Task<HttpClient> CreateHostedFileContentAgentAsync(string agentName, string fileId)
{
return await this.CreateTestServerAsync(agentName, "You are a test agent.", string.Empty, (msg) =>
[new HostedFileContent(fileId)]);
}
private async Task<HttpClient> CreateFileContentAgentAsync(string agentName, string fileDataUri, string? filename)
{
// Extract media type from data URI
string mediaType = "application/pdf"; // default
if (fileDataUri.StartsWith("data:", StringComparison.Ordinal))
{
int semicolonIndex = fileDataUri.IndexOf(';');
if (semicolonIndex > 5)
{
mediaType = fileDataUri.Substring(5, semicolonIndex - 5);
}
}
return await this.CreateTestServerAsync(agentName, "You are a test agent.", string.Empty, (msg) =>
[new DataContent(fileDataUri, mediaType) { Name = filename }]);
}
private async Task<HttpClient> CreateMixedContentAgentAsync(string agentName)
{
return await this.CreateTestServerAsync(agentName, "You are a test agent.", string.Empty, (msg) =>
[
new TextContent("Here is an image:"),
new UriContent("https://example.com/image.png", "image/png")
]);
}
private async Task<HttpClient> CreateErrorAndTextContentAgentAsync(string agentName)
{
return await this.CreateTestServerAsync(agentName, "You are a test agent.", string.Empty, (msg) =>
[
new TextContent("I need to inform you:"),
new ErrorContent("The requested operation is not allowed.")
]);
}
#endregion
}
@@ -0,0 +1,170 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Tests for EndpointRouteBuilderExtensions.MapOpenAIResponses method.
/// </summary>
public sealed class EndpointRouteBuilderExtensionsTests
{
/// <summary>
/// Verifies that MapOpenAIResponses throws ArgumentNullException for null endpoints.
/// </summary>
[Fact]
public void MapOpenAIResponses_NullEndpoints_ThrowsArgumentNullException()
{
// Arrange
AspNetCore.Routing.IEndpointRouteBuilder endpoints = null!;
AIAgent agent = null!;
// Act & Assert
ArgumentNullException exception = Assert.Throws<ArgumentNullException>(() =>
endpoints.MapOpenAIResponses(agent));
Assert.Equal("endpoints", exception.ParamName);
}
/// <summary>
/// Verifies that MapOpenAIResponses throws ArgumentNullException for null agent.
/// </summary>
[Fact]
public void MapOpenAIResponses_NullAgent_ThrowsArgumentNullException()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
// Act & Assert
AIAgent agent = null!;
ArgumentNullException exception = Assert.Throws<ArgumentNullException>(() =>
app.MapOpenAIResponses(agent));
Assert.Equal("agent", exception.ParamName);
}
/// <summary>
/// Verifies that MapOpenAIResponses validates agent name characters for URL safety.
/// </summary>
[Theory]
[InlineData("agent with spaces")]
[InlineData("agent<script>")]
[InlineData("agent\nwith\nnewlines")]
[InlineData("agent\twith\ttabs")]
[InlineData("agent?query")]
[InlineData("agent#fragment")]
public void MapOpenAIResponses_InvalidAgentNameCharacters_ThrowsArgumentException(string invalidName)
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.Services.AddOpenAIResponses();
builder.AddAIAgent(invalidName, "Instructions", chatClientServiceKey: "chat-client");
using WebApplication app = builder.Build();
AIAgent agent = app.Services.GetRequiredKeyedService<AIAgent>(invalidName);
// Act & Assert
ArgumentException exception = Assert.Throws<ArgumentException>(() =>
app.MapOpenAIResponses(agent));
Assert.Contains("invalid for URL routes", exception.Message);
}
/// <summary>
/// Verifies that MapOpenAIResponses accepts valid agent names with special characters.
/// </summary>
[Theory]
[InlineData("agent-name")]
[InlineData("agent_name")]
[InlineData("agent.name")]
[InlineData("agent123")]
[InlineData("123agent")]
[InlineData("AGENT")]
[InlineData("my-agent_v1.0")]
public void MapOpenAIResponses_ValidAgentNameCharacters_DoesNotThrow(string validName)
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddAIAgent(validName, "Instructions", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
AIAgent agent = app.Services.GetRequiredKeyedService<AIAgent>(validName);
// Act & Assert - Should not throw
app.MapOpenAIResponses(agent);
Assert.NotNull(app);
}
/// <summary>
/// Verifies that custom paths can be specified for responses endpoints.
/// </summary>
[Fact]
public void MapOpenAIResponses_WithCustomPath_AcceptsValidPath()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddAIAgent("agent", "Instructions", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
AIAgent agent = app.Services.GetRequiredKeyedService<AIAgent>("agent");
// Act & Assert - Should not throw
app.MapOpenAIResponses(agent, responsesPath: "/custom/responses");
Assert.NotNull(app);
}
/// <summary>
/// Verifies that multiple agents can be mapped to different paths.
/// </summary>
[Fact]
public void MapOpenAIResponses_MultipleAgents_Succeeds()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddAIAgent("agent1", "Instructions1", chatClientServiceKey: "chat-client");
builder.AddAIAgent("agent2", "Instructions2", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
AIAgent agent1 = app.Services.GetRequiredKeyedService<AIAgent>("agent1");
AIAgent agent2 = app.Services.GetRequiredKeyedService<AIAgent>("agent2");
// Act & Assert - Should not throw
app.MapOpenAIResponses(agent1);
app.MapOpenAIResponses(agent2);
Assert.NotNull(app);
}
/// <summary>
/// Verifies that long agent names are accepted.
/// </summary>
[Fact]
public void MapOpenAIResponses_LongAgentName_Succeeds()
{
// Arrange
string longName = new('a', 100);
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddAIAgent(longName, "Instructions", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
AIAgent agent = app.Services.GetRequiredKeyedService<AIAgent>(longName);
// Act & Assert - Should not throw
app.MapOpenAIResponses(agent);
Assert.NotNull(app);
}
}
@@ -0,0 +1,78 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using Microsoft.Extensions.Hosting;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Tests for HostApplicationBuilderExtensions.AddOpenAIResponses method.
/// </summary>
public sealed class HostApplicationBuilderExtensionsTests
{
/// <summary>
/// Verifies that AddOpenAIResponses throws ArgumentNullException for null builder.
/// </summary>
[Fact]
public void AddOpenAIResponses_NullBuilder_ThrowsArgumentNullException()
{
// Arrange
IHostApplicationBuilder builder = null!;
// Act & Assert
ArgumentNullException exception = Assert.Throws<ArgumentNullException>(() =>
builder.AddOpenAIResponses());
Assert.Equal("builder", exception.ParamName);
}
/// <summary>
/// Verifies that AddOpenAIResponses returns the same builder instance.
/// </summary>
[Fact]
public void AddOpenAIResponses_ValidBuilder_ReturnsSameBuilder()
{
// Arrange
IHostApplicationBuilder builder = Host.CreateApplicationBuilder();
// Act
IHostApplicationBuilder result = builder.AddOpenAIResponses();
// Assert
Assert.Same(builder, result);
}
/// <summary>
/// Verifies that AddOpenAIResponses can be called multiple times without error.
/// </summary>
[Fact]
public void AddOpenAIResponses_MultipleCalls_DoesNotThrow()
{
// Arrange
HostApplicationBuilder builder = Host.CreateApplicationBuilder();
// Act
builder.AddOpenAIResponses();
builder.AddOpenAIResponses();
builder.AddOpenAIResponses();
// Assert - Building should succeed
Assert.NotNull(builder.Services);
}
/// <summary>
/// Verifies that AddOpenAIResponses properly configures JSON serialization options.
/// </summary>
[Fact]
public void AddOpenAIResponses_ConfiguresJsonSerialization()
{
// Arrange
HostApplicationBuilder builder = Host.CreateApplicationBuilder();
// Act
builder.AddOpenAIResponses();
// Assert - Should add services without error
Assert.NotNull(builder.Services);
}
}
@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>$(ProjectsCoreTargetFrameworks)</TargetFrameworks>
<TargetFrameworks Condition="'$(Configuration)' == 'Debug'">$(ProjectsDebugCoreTargetFrameworks)</TargetFrameworks>
<IsPackable>false</IsPackable>
<NoWarn>$(NoWarn);OPENAI001;CA1812</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" VersionOverride="8.0.21" Condition="'$(TargetFramework)' == 'net8.0'" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Condition="'$(TargetFramework)' != 'net8.0'" />
<PackageReference Include="OpenAI" />
<PackageReference Include="System.Net.ServerSentEvents" VersionOverride="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" VersionOverride="10.0.0-rc.2.25502.107" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.Hosting.OpenAI\Microsoft.Agents.AI.Hosting.OpenAI.csproj" />
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.Hosting\Microsoft.Agents.AI.Hosting.csproj" />
<ProjectReference Include="..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="ConformanceTraces\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,12 @@
{
"profiles": {
"Microsoft.Agents.AI.Hosting.OpenAI.UnitTests": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:60491;http://localhost:60492"
}
}
}
@@ -0,0 +1,815 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Agents.AI.Hosting.OpenAI.Responses.Models;
using Microsoft.Agents.AI.Hosting.OpenAI.Tests;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Tests that verify our implementation generates correctly formatted streaming Server-Sent Events (SSE)
/// that conform to the OpenAI Response API streaming response format.
/// These tests validate the actual server implementation behavior by creating test servers
/// and verifying the SSE output matches expected formats.
/// For pure event deserialization tests, see OpenAIResponsesSerializationTests.
/// </summary>
public sealed class StreamingEventConformanceTests : ConformanceTestBase
{
[Fact]
public async Task ParseStreamingEvents_BasicFormat_SuccessAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
// Extract expected text
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-basic-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-basic-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
// Act
var events = ParseSseEvents(sseContent);
// Assert
Assert.NotEmpty(events);
Assert.All(events, evt =>
{
Assert.True(evt.TryGetProperty("type", out var type));
Assert.True(evt.TryGetProperty("sequence_number", out var seqNum));
Assert.Equal(JsonValueKind.Number, seqNum.ValueKind);
});
}
[Fact]
public async Task ParseStreamingEvents_HasCorrectEventTypesAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-types-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-types-agent", requestJson);
// Assert - HTTP response validation
Assert.Equal(System.Net.HttpStatusCode.OK, httpResponse.StatusCode);
Assert.Equal("text/event-stream", httpResponse.Content.Headers.ContentType?.MediaType);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
// Act
var events = ParseSseEvents(sseContent);
List<string> eventTypes = events.ConvertAll(e => e.GetProperty("type").GetString()!);
// Assert - Verify all required event types are present
Assert.Contains("response.created", eventTypes);
Assert.Contains("response.in_progress", eventTypes);
Assert.Contains("response.output_item.added", eventTypes);
Assert.Contains("response.content_part.added", eventTypes);
Assert.Contains("response.output_text.delta", eventTypes);
Assert.Contains("response.output_text.done", eventTypes);
Assert.Contains("response.content_part.done", eventTypes);
Assert.Contains("response.output_item.done", eventTypes);
// Assert - Verify the order of events
Assert.Equal("response.created", eventTypes[0]);
Assert.Equal("response.in_progress", eventTypes[1]);
// Find indices of key events to verify ordering
int outputItemAddedIndex = eventTypes.IndexOf("response.output_item.added");
int contentPartAddedIndex = eventTypes.IndexOf("response.content_part.added");
int firstDeltaIndex = eventTypes.IndexOf("response.output_text.delta");
int textDoneIndex = eventTypes.IndexOf("response.output_text.done");
int contentPartDoneIndex = eventTypes.IndexOf("response.content_part.done");
int outputItemDoneIndex = eventTypes.IndexOf("response.output_item.done");
Assert.True(outputItemAddedIndex < contentPartAddedIndex, "output_item.added should come before content_part.added");
Assert.True(contentPartAddedIndex < firstDeltaIndex, "content_part.added should come before first output_text.delta");
Assert.True(firstDeltaIndex < textDoneIndex, "output_text.delta should come before output_text.done");
Assert.True(textDoneIndex < contentPartDoneIndex, "output_text.done should come before content_part.done");
Assert.True(contentPartDoneIndex < outputItemDoneIndex, "content_part.done should come before output_item.done");
// Assert - Last event should be a terminal state
string lastEventType = eventTypes[^1];
Assert.True(
lastEventType == "response.completed" ||
lastEventType == "response.incomplete" ||
lastEventType == "response.failed",
$"Last event should be a terminal state, got: {lastEventType}");
}
[Fact]
public async Task ParseStreamingEvents_DeserializeCreatedEvent_SuccessAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-created-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-created-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
var createdEventJson = events.First(e => e.GetProperty("type").GetString() == "response.created");
// Act
string jsonString = createdEventJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
// Assert
Assert.NotNull(evt);
Assert.IsType<StreamingResponseCreated>(evt);
var created = (StreamingResponseCreated)evt;
Assert.Equal(0, created.SequenceNumber);
Assert.NotNull(created.Response);
Assert.NotNull(created.Response.Id);
Assert.StartsWith("resp_", created.Response.Id);
}
[Fact]
public async Task ParseStreamingEvents_DeserializeInProgressEvent_SuccessAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-progress-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-progress-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
var inProgressEventJson = events.First(e => e.GetProperty("type").GetString() == "response.in_progress");
// Act
string jsonString = inProgressEventJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
// Assert
Assert.NotNull(evt);
Assert.IsType<StreamingResponseInProgress>(evt);
var inProgress = (StreamingResponseInProgress)evt;
Assert.Equal(1, inProgress.SequenceNumber);
Assert.NotNull(inProgress.Response);
Assert.Equal(ResponseStatus.InProgress, inProgress.Response.Status);
}
[Fact]
public async Task ParseStreamingEvents_DeserializeOutputItemAdded_SuccessAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-item-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-item-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
var itemAddedJson = events.First(e => e.GetProperty("type").GetString() == "response.output_item.added");
// Act
string jsonString = itemAddedJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
// Assert
Assert.NotNull(evt);
Assert.IsType<StreamingOutputItemAdded>(evt);
var itemAdded = (StreamingOutputItemAdded)evt;
Assert.Equal(0, itemAdded.OutputIndex);
Assert.NotNull(itemAdded.Item);
}
[Fact]
public async Task ParseStreamingEvents_DeserializeContentPartAdded_SuccessAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-part-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-part-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
var partAddedJson = events.First(e => e.GetProperty("type").GetString() == "response.content_part.added");
// Act
string jsonString = partAddedJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
// Assert
Assert.NotNull(evt);
Assert.IsType<StreamingContentPartAdded>(evt);
var partAdded = (StreamingContentPartAdded)evt;
Assert.NotNull(partAdded.ItemId);
Assert.Equal(0, partAdded.OutputIndex);
Assert.Equal(0, partAdded.ContentIndex);
Assert.NotNull(partAdded.Part);
}
[Fact]
public async Task ParseStreamingEvents_DeserializeTextDelta_SuccessAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-delta-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-delta-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
var textDeltaJson = events.First(e => e.GetProperty("type").GetString() == "response.output_text.delta");
// Act
string jsonString = textDeltaJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
// Assert
Assert.NotNull(evt);
Assert.IsType<StreamingOutputTextDelta>(evt);
var textDelta = (StreamingOutputTextDelta)evt;
Assert.NotNull(textDelta.ItemId);
Assert.Equal(0, textDelta.OutputIndex);
Assert.Equal(0, textDelta.ContentIndex);
Assert.NotNull(textDelta.Delta);
}
[Fact]
public async Task ParseStreamingEvents_AccumulateTextDeltas_MatchesFinalTextAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-accumulate-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-accumulate-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Act
var deltas = new List<string>();
string? finalText = null;
foreach (var eventJson in events)
{
string jsonString = eventJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
if (evt is StreamingOutputTextDelta delta)
{
deltas.Add(delta.Delta);
}
else if (evt is StreamingOutputTextDone done)
{
finalText = done.Text;
}
}
// Assert
Assert.NotEmpty(deltas);
Assert.NotNull(finalText);
string accumulated = string.Concat(deltas);
Assert.Equal(accumulated, finalText);
}
[Fact]
public async Task ParseStreamingEvents_SequenceNumbersAreSequentialAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-sequence-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-sequence-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Act
var sequenceNumbers = new List<int>();
foreach (var eventJson in events)
{
string jsonString = eventJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
Assert.NotNull(evt);
sequenceNumbers.Add(evt.SequenceNumber);
}
// Assert
Assert.NotEmpty(sequenceNumbers);
Assert.Equal(0, sequenceNumbers.First());
for (int i = 0; i < sequenceNumbers.Count; i++)
{
Assert.Equal(i, sequenceNumbers[i]);
}
}
[Fact]
public async Task ParseStreamingEvents_FinalEvent_IsTerminalStateAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-terminal-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-terminal-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
var lastEventJson = events.Last();
// Act
string jsonString = lastEventJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
// Assert
Assert.NotNull(evt);
// Should be one of the terminal events
bool isTerminal = evt is StreamingResponseCompleted ||
evt is StreamingResponseIncomplete ||
evt is StreamingResponseFailed;
Assert.True(isTerminal, $"Expected terminal event, got: {evt.GetType().Name}");
}
[Fact]
public async Task ParseStreamingEvents_AllEvents_CanBeDeserializedAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-deserialize-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-deserialize-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
// Act & Assert
foreach (var eventJson in ParseSseEvents(sseContent))
{
// Should not throw
StreamingResponseEvent? evt = JsonSerializer.Deserialize(eventJson.GetRawText(), Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
Assert.NotNull(evt);
// Verify polymorphic deserialization worked
Assert.True(
evt is StreamingResponseCreated ||
evt is StreamingResponseInProgress ||
evt is StreamingResponseCompleted ||
evt is StreamingResponseIncomplete ||
evt is StreamingResponseFailed ||
evt is StreamingOutputItemAdded ||
evt is StreamingOutputItemDone ||
evt is StreamingContentPartAdded ||
evt is StreamingContentPartDone ||
evt is StreamingOutputTextDelta ||
evt is StreamingOutputTextDone ||
evt is StreamingFunctionCallArgumentsDelta ||
evt is StreamingFunctionCallArgumentsDone,
$"Unknown event type: {evt.GetType().Name}");
}
}
[Fact]
public async Task ParseStreamingEvents_IdConsistency_ValidAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-id-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-id-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert - Response ID consistency
string? firstResponseId = null;
foreach (var eventJson in events)
{
string jsonString = eventJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
Assert.NotNull(evt);
string? responseId = null;
if (evt is StreamingResponseCreated created)
{
responseId = created.Response.Id;
Assert.StartsWith("resp_", responseId);
}
else if (evt is StreamingResponseInProgress progress)
{
responseId = progress.Response.Id;
}
else if (evt is StreamingResponseCompleted completed)
{
responseId = completed.Response.Id;
}
else if (evt is StreamingResponseIncomplete incomplete)
{
responseId = incomplete.Response.Id;
}
else if (evt is StreamingResponseFailed failed)
{
responseId = failed.Response.Id;
}
if (responseId != null)
{
firstResponseId ??= responseId;
Assert.Equal(firstResponseId, responseId);
}
}
Assert.NotNull(firstResponseId);
// Assert - Item ID consistency
var itemIds = new HashSet<string>();
foreach (var eventJson in events)
{
string jsonString = eventJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
string? itemId = evt switch
{
StreamingOutputItemAdded added => added.Item.Id,
StreamingOutputItemDone done => done.Item.Id,
StreamingContentPartAdded partAdded => partAdded.ItemId,
StreamingContentPartDone partDone => partDone.ItemId,
StreamingOutputTextDelta textDelta => textDelta.ItemId,
StreamingOutputTextDone textDone => textDone.ItemId,
StreamingFunctionCallArgumentsDelta argsDelta => argsDelta.ItemId,
StreamingFunctionCallArgumentsDone argsDone => argsDone.ItemId,
_ => null
};
if (itemId != null)
{
Assert.NotEmpty(itemId);
Assert.True(itemId.StartsWith("msg_", StringComparison.Ordinal) || itemId.StartsWith("fc_", StringComparison.Ordinal),
$"Item ID should start with 'msg_' or 'fc_', got: {itemId}");
itemIds.Add(itemId);
}
}
Assert.NotEmpty(itemIds);
}
[Fact]
public async Task ParseStreamingEvents_IndexConsistency_ValidAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-index-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-index-agent", requestJson);
// Assert - All events with output_index should have valid values
foreach (var eventJson in ParseSseEvents(await httpResponse.Content.ReadAsStringAsync()))
{
StreamingResponseEvent? evt = JsonSerializer.Deserialize(eventJson.GetRawText(), Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
Assert.NotNull(evt);
if (evt is StreamingOutputItemAdded or StreamingOutputItemDone or StreamingContentPartAdded or StreamingContentPartDone or
StreamingOutputTextDelta or StreamingOutputTextDone or StreamingFunctionCallArgumentsDelta or StreamingFunctionCallArgumentsDone)
{
int outputIndex = evt switch
{
StreamingOutputItemAdded added => added.OutputIndex,
StreamingOutputItemDone done => done.OutputIndex,
StreamingContentPartAdded partAdded => partAdded.OutputIndex,
StreamingContentPartDone partDone => partDone.OutputIndex,
StreamingOutputTextDelta textDelta => textDelta.OutputIndex,
StreamingOutputTextDone textDone => textDone.OutputIndex,
StreamingFunctionCallArgumentsDelta argsDelta => argsDelta.OutputIndex,
StreamingFunctionCallArgumentsDone argsDone => argsDone.OutputIndex,
_ => -1
};
Assert.True(outputIndex >= 0, $"output_index should be non-negative, got: {outputIndex}");
}
if (evt is StreamingContentPartAdded or StreamingContentPartDone or StreamingOutputTextDelta or StreamingOutputTextDone)
{
int contentIndex = evt switch
{
StreamingContentPartAdded partAdded => partAdded.ContentIndex,
StreamingContentPartDone partDone => partDone.ContentIndex,
StreamingOutputTextDelta textDelta => textDelta.ContentIndex,
StreamingOutputTextDone textDone => textDone.ContentIndex,
_ => -1
};
Assert.True(contentIndex >= 0, $"content_index should be non-negative, got: {contentIndex}");
}
}
}
[Fact]
public async Task ParseStreamingEvents_ResponseObjectEvolution_ValidAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-evolution-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-evolution-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
Response? createdResponse = null;
Response? terminalResponse = null;
foreach (var eventJson in events)
{
string jsonString = eventJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
Assert.NotNull(evt);
if (evt is StreamingResponseCreated created)
{
createdResponse = created.Response;
Assert.Equal(ResponseStatus.InProgress, createdResponse.Status);
Assert.Empty(createdResponse.Output);
// Usage may be null or zero'd out in created event
if (createdResponse.Usage != null)
{
Assert.Equal(0, createdResponse.Usage.InputTokens);
Assert.Equal(0, createdResponse.Usage.OutputTokens);
}
}
else if (evt is StreamingResponseInProgress progress)
{
Assert.Equal(ResponseStatus.InProgress, progress.Response.Status);
}
else if (evt is StreamingResponseCompleted completed)
{
terminalResponse = completed.Response;
Assert.Equal(ResponseStatus.Completed, terminalResponse.Status);
Assert.NotEmpty(terminalResponse.Output);
Assert.NotNull(terminalResponse.Usage);
Assert.True(terminalResponse.Usage.InputTokens > 0);
Assert.True(terminalResponse.Usage.OutputTokens > 0);
}
else if (evt is StreamingResponseIncomplete incomplete)
{
terminalResponse = incomplete.Response;
Assert.Equal(ResponseStatus.Incomplete, terminalResponse.Status);
}
else if (evt is StreamingResponseFailed failed)
{
terminalResponse = failed.Response;
Assert.Equal(ResponseStatus.Failed, terminalResponse.Status);
}
}
Assert.NotNull(createdResponse);
Assert.NotNull(terminalResponse);
}
[Fact]
public async Task ParseStreamingEvents_SseFormatCompliance_ValidAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-sse-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-sse-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
// Assert - SSE format validation
var lines = sseContent.Split('\n');
Assert.NotEmpty(lines);
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i].TrimEnd('\r');
if (line.StartsWith("event: ", StringComparison.Ordinal))
{
// Every "event:" line must be followed by a "data:" line
Assert.True(i + 1 < lines.Length, $"Event at line {i} has no following data line");
string nextLine = lines[i + 1].TrimEnd('\r');
Assert.True(nextLine.StartsWith("data: ", StringComparison.Ordinal),
$"Line after event: should be data:, got: {nextLine}");
// Validate the data line contains valid JSON
string jsonData = nextLine.Substring("data: ".Length);
Assert.NotEmpty(jsonData);
// Should be parseable as JSON
Exception? parseException = Record.Exception(() => JsonDocument.Parse(jsonData));
Assert.Null(parseException);
}
}
}
[Fact]
public async Task ParseStreamingEvents_EventPairing_ValidAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-pairing-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-pairing-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Track added vs done events
var outputItemsAdded = new HashSet<int>();
var outputItemsDone = new HashSet<int>();
var contentPartsAdded = new List<(int outputIndex, int contentIndex)>();
var contentPartsDone = new List<(int outputIndex, int contentIndex)>();
foreach (var eventJson in events)
{
string jsonString = eventJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
Assert.NotNull(evt);
switch (evt)
{
case StreamingOutputItemAdded added:
outputItemsAdded.Add(added.OutputIndex);
break;
case StreamingOutputItemDone done:
outputItemsDone.Add(done.OutputIndex);
// Every done must have a corresponding added
Assert.Contains(done.OutputIndex, outputItemsAdded);
break;
case StreamingContentPartAdded partAdded:
contentPartsAdded.Add((partAdded.OutputIndex, partAdded.ContentIndex));
break;
case StreamingContentPartDone partDone:
contentPartsDone.Add((partDone.OutputIndex, partDone.ContentIndex));
// Every done must have a corresponding added
Assert.Contains((partDone.OutputIndex, partDone.ContentIndex), contentPartsAdded);
break;
}
}
// All added items should eventually be done
Assert.Equal(outputItemsAdded.Count, outputItemsDone.Count);
Assert.Equal(contentPartsAdded.Count, contentPartsDone.Count);
}
[Fact]
public async Task ParseStreamingEvents_NoDuplicateSequenceNumbers_ValidAsync()
{
// Arrange
string requestJson = LoadTraceFile("streaming/request.json");
string expectedSseContent = LoadTraceFile("streaming/response.txt");
var expectedEvents = ParseSseEvents(expectedSseContent);
var deltaEvents = expectedEvents.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string expectedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-nodup-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendRequestAsync(client, "streaming-nodup-agent", requestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
var events = ParseSseEvents(sseContent);
// Assert - No duplicate sequence numbers
var sequenceNumbers = new HashSet<int>();
foreach (var eventJson in events)
{
string jsonString = eventJson.GetRawText();
StreamingResponseEvent? evt = JsonSerializer.Deserialize(jsonString, Responses.ResponsesJsonContext.Default.StreamingResponseEvent);
Assert.NotNull(evt);
Assert.True(sequenceNumbers.Add(evt.SequenceNumber),
$"Duplicate sequence number found: {evt.SequenceNumber}");
}
}
/// <summary>
/// Helper to parse SSE events from streaming response content.
/// </summary>
private static List<JsonElement> ParseSseEvents(string sseContent)
{
var events = new List<JsonElement>();
var lines = sseContent.Split('\n');
for (int i = 0; i < lines.Length; i++)
{
var line = lines[i].TrimEnd('\r');
if (line.StartsWith("event: ", StringComparison.Ordinal))
{
// Next line should have the data
if (i + 1 < lines.Length)
{
var dataLine = lines[i + 1].TrimEnd('\r');
if (dataLine.StartsWith("data: ", StringComparison.Ordinal))
{
var jsonData = dataLine.Substring("data: ".Length);
var doc = JsonDocument.Parse(jsonData);
events.Add(doc.RootElement.Clone());
}
}
}
}
return events;
}
}
@@ -0,0 +1,488 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
internal static class TestHelpers
{
/// <summary>
/// Simple mock implementation of IChatClient for basic testing purposes.
/// </summary>
internal sealed class SimpleMockChatClient : IChatClient
{
private readonly string _responseText;
public SimpleMockChatClient(string responseText = "Test response")
{
this._responseText = responseText;
}
public ChatClientMetadata Metadata { get; } = new("Test", new Uri("https://test.example.com"), "test-model");
public Task<ChatResponse> GetResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
// Count input messages to simulate context size
int messageCount = messages.Count();
ChatMessage message = new(ChatRole.Assistant, this._responseText);
ChatResponse response = new([message])
{
ModelId = "test-model",
FinishReason = ChatFinishReason.Stop,
Usage = new UsageDetails
{
InputTokenCount = 10 + (messageCount * 5), // More messages = more tokens
OutputTokenCount = 5,
TotalTokenCount = 15 + (messageCount * 5)
}
};
return Task.FromResult(response);
}
public async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
// Count input messages to simulate context size
int messageCount = messages.Count();
// Split response into words to simulate streaming
string[] words = this._responseText.Split(' ');
for (int i = 0; i < words.Length; i++)
{
string content = i < words.Length - 1 ? words[i] + " " : words[i];
ChatResponseUpdate update = new()
{
Contents = [new TextContent(content)],
Role = ChatRole.Assistant
};
// Add usage to the last update
if (i == words.Length - 1)
{
update.Contents.Add(new UsageContent(new UsageDetails
{
InputTokenCount = 10 + (messageCount * 5),
OutputTokenCount = 5,
TotalTokenCount = 15 + (messageCount * 5)
}));
}
yield return update;
}
}
public object? GetService(Type serviceType, object? serviceKey = null) =>
serviceType.IsInstanceOfType(this) ? this : null;
public void Dispose()
{
}
}
/// <summary>
/// Mock implementation of IChatClient that returns responses with image content.
/// </summary>
internal sealed class ImageContentMockChatClient : IChatClient
{
private readonly string _imageUrl;
public ImageContentMockChatClient(string imageUrl = "https://example.com/image.png")
{
this._imageUrl = imageUrl;
}
public ChatClientMetadata Metadata { get; } = new("Test", new Uri("https://test.example.com"), "test-model");
public Task<ChatResponse> GetResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
ChatMessage message = new(ChatRole.Assistant, [
new TextContent("Here is an image:"),
new UriContent(this._imageUrl, "image/png")
]);
ChatResponse response = new([message])
{
ModelId = "test-model",
FinishReason = ChatFinishReason.Stop,
Usage = new UsageDetails
{
InputTokenCount = 10,
OutputTokenCount = 5,
TotalTokenCount = 15
}
};
return Task.FromResult(response);
}
public async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
yield return new ChatResponseUpdate
{
Contents = [new TextContent("Here is an image:")],
Role = ChatRole.Assistant
};
yield return new ChatResponseUpdate
{
Contents = [
new UriContent(this._imageUrl, "image/png"),
new UsageContent(new UsageDetails
{
InputTokenCount = 10,
OutputTokenCount = 5,
TotalTokenCount = 15
})
],
Role = ChatRole.Assistant
};
}
public object? GetService(Type serviceType, object? serviceKey = null) =>
serviceType.IsInstanceOfType(this) ? this : null;
public void Dispose()
{
}
}
/// <summary>
/// Mock implementation of IChatClient that returns responses with audio content.
/// </summary>
internal sealed class AudioContentMockChatClient : IChatClient
{
private readonly byte[] _audioData;
private readonly string _transcript;
public AudioContentMockChatClient(string audioData = "base64audiodata", string transcript = "This is a transcript")
{
this._audioData = System.Text.Encoding.UTF8.GetBytes(audioData);
this._transcript = transcript;
}
public ChatClientMetadata Metadata { get; } = new("Test", new Uri("https://test.example.com"), "test-model");
public Task<ChatResponse> GetResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
ChatMessage message = new(ChatRole.Assistant, [
new DataContent(this._audioData, "audio/wav")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
["transcript"] = this._transcript
}
}
]);
ChatResponse response = new([message])
{
ModelId = "test-model",
FinishReason = ChatFinishReason.Stop,
Usage = new UsageDetails
{
InputTokenCount = 10,
OutputTokenCount = 5,
TotalTokenCount = 15
}
};
return Task.FromResult(response);
}
public async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
yield return new ChatResponseUpdate
{
Contents = [
new DataContent(this._audioData, "audio/wav")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
["transcript"] = this._transcript
}
},
new UsageContent(new UsageDetails
{
InputTokenCount = 10,
OutputTokenCount = 5,
TotalTokenCount = 15
})
],
Role = ChatRole.Assistant
};
}
public object? GetService(Type serviceType, object? serviceKey = null) =>
serviceType.IsInstanceOfType(this) ? this : null;
public void Dispose()
{
}
}
/// <summary>
/// Mock implementation of IChatClient that returns responses with function calls.
/// </summary>
internal sealed class FunctionCallMockChatClient : IChatClient
{
private readonly string _functionName;
private readonly Dictionary<string, object?> _arguments;
public FunctionCallMockChatClient(string functionName = "test_function", string arguments = "{\"param\":\"value\"}")
{
this._functionName = functionName;
this._arguments = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object?>>(arguments) ?? new Dictionary<string, object?>();
}
public ChatClientMetadata Metadata { get; } = new("Test", new Uri("https://test.example.com"), "test-model");
public Task<ChatResponse> GetResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
ChatMessage message = new(ChatRole.Assistant, [
new FunctionCallContent("call_123", this._functionName)
{
Arguments = this._arguments
}
]);
ChatResponse response = new([message])
{
ModelId = "test-model",
FinishReason = ChatFinishReason.ToolCalls,
Usage = new UsageDetails
{
InputTokenCount = 80,
OutputTokenCount = 25,
TotalTokenCount = 105
}
};
return Task.FromResult(response);
}
public async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
yield return new ChatResponseUpdate
{
Contents = [
new FunctionCallContent("call_123", this._functionName)
{
Arguments = this._arguments
},
new UsageContent(new UsageDetails
{
InputTokenCount = 80,
OutputTokenCount = 25,
TotalTokenCount = 105
})
],
Role = ChatRole.Assistant
};
}
public object? GetService(Type serviceType, object? serviceKey = null) =>
serviceType.IsInstanceOfType(this) ? this : null;
public void Dispose()
{
}
}
/// <summary>
/// Mock implementation of IChatClient that returns mixed content types.
/// </summary>
internal sealed class MixedContentMockChatClient : IChatClient
{
public ChatClientMetadata Metadata { get; } = new("Test", new Uri("https://test.example.com"), "test-model");
public Task<ChatResponse> GetResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
ChatMessage message = new(ChatRole.Assistant, [
new TextContent("Here are multiple content types:"),
new UriContent("https://example.com/image.png", "image/png"),
new TextContent("And some more text after the image.")
]);
ChatResponse response = new([message])
{
ModelId = "test-model",
FinishReason = ChatFinishReason.Stop,
Usage = new UsageDetails
{
InputTokenCount = 10,
OutputTokenCount = 5,
TotalTokenCount = 15
}
};
return Task.FromResult(response);
}
public async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
yield return new ChatResponseUpdate
{
Contents = [new TextContent("Here"), new TextContent(" are"), new TextContent(" multiple")],
Role = ChatRole.Assistant
};
yield return new ChatResponseUpdate
{
Contents = [new TextContent(" content"), new TextContent(" types:")],
Role = ChatRole.Assistant
};
yield return new ChatResponseUpdate
{
Contents = [new UriContent("https://example.com/image.png", "image/png")],
Role = ChatRole.Assistant
};
yield return new ChatResponseUpdate
{
Contents = [new TextContent("And"), new TextContent(" some"), new TextContent(" more")],
Role = ChatRole.Assistant
};
yield return new ChatResponseUpdate
{
Contents = [
new TextContent(" text"),
new TextContent(" after"),
new TextContent(" the"),
new TextContent(" image."),
new UsageContent(new UsageDetails
{
InputTokenCount = 10,
OutputTokenCount = 5,
TotalTokenCount = 15
})
],
Role = ChatRole.Assistant
};
}
public object? GetService(Type serviceType, object? serviceKey = null) =>
serviceType.IsInstanceOfType(this) ? this : null;
public void Dispose()
{
}
}
/// <summary>
/// Mock implementation of IChatClient that returns custom content based on a provider function.
/// </summary>
internal sealed class CustomContentMockChatClient : IChatClient
{
private readonly Func<ChatMessage, IEnumerable<AIContent>> _contentProvider;
public CustomContentMockChatClient(Func<ChatMessage, IEnumerable<AIContent>> contentProvider)
{
this._contentProvider = contentProvider;
}
public ChatClientMetadata Metadata { get; } = new("Test", new Uri("https://test.example.com"), "test-model");
public Task<ChatResponse> GetResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
ChatMessage lastMessage = messages.Last();
IEnumerable<AIContent> contents = this._contentProvider(lastMessage);
ChatMessage message = new(ChatRole.Assistant, contents.ToList());
ChatResponse response = new([message])
{
ModelId = "test-model",
FinishReason = ChatFinishReason.Stop,
Usage = new UsageDetails
{
InputTokenCount = 10,
OutputTokenCount = 5,
TotalTokenCount = 15
}
};
return Task.FromResult(response);
}
public async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await Task.Delay(1, cancellationToken);
ChatMessage lastMessage = messages.Last();
IEnumerable<AIContent> contents = this._contentProvider(lastMessage);
List<AIContent> contentList = contents.ToList();
// Stream each content item separately
for (int i = 0; i < contentList.Count; i++)
{
List<AIContent> updateContents = [contentList[i]];
// Add usage to the last update
if (i == contentList.Count - 1)
{
updateContents.Add(new UsageContent(new UsageDetails
{
InputTokenCount = 10,
OutputTokenCount = 5,
TotalTokenCount = 15
}));
}
yield return new ChatResponseUpdate
{
Contents = updateContents,
Role = ChatRole.Assistant
};
}
}
public object? GetService(Type serviceType, object? serviceKey = null) =>
serviceType.IsInstanceOfType(this) ? this : null;
public void Dispose()
{
}
}
}
@@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(ProjectsTargetFrameworks)</TargetFrameworks>
<TargetFrameworks>$(ProjectsCoreTargetFrameworks)</TargetFrameworks>
<TargetFrameworks Condition="'$(Configuration)' == 'Debug'">$(ProjectsDebugCoreTargetFrameworks)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>