chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:25 +08:00
commit db620d33df
5151 changed files with 925932 additions and 0 deletions
@@ -0,0 +1,92 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json;
using Microsoft.Agents.AI.Hosting.OpenAI.Responses;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Unit tests for AgentInvocationContext.
/// </summary>
public sealed class AgentInvocationContextTests
{
[Fact]
public void Constructor_WithIdGenerator_InitializesCorrectly()
{
// Arrange
var idGenerator = new IdGenerator("resp_test123", "conv_test456");
// Act
var context = new AgentInvocationContext(idGenerator);
// Assert
Assert.NotNull(context);
Assert.Same(idGenerator, context.IdGenerator);
Assert.Equal("resp_test123", context.ResponseId);
Assert.Equal("conv_test456", context.ConversationId);
Assert.NotNull(context.JsonSerializerOptions);
}
[Fact]
public void Constructor_WithoutJsonOptions_UsesDefaultOptions()
{
// Arrange
var idGenerator = new IdGenerator("resp_test", "conv_test");
// Act
var context = new AgentInvocationContext(idGenerator);
// Assert
Assert.NotNull(context.JsonSerializerOptions);
Assert.Same(OpenAIHostingJsonUtilities.DefaultOptions, context.JsonSerializerOptions);
}
[Fact]
public void Constructor_WithCustomJsonOptions_UsesProvidedOptions()
{
// Arrange
var idGenerator = new IdGenerator("resp_test", "conv_test");
var customOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
// Act
var context = new AgentInvocationContext(idGenerator, customOptions);
// Assert
Assert.Same(customOptions, context.JsonSerializerOptions);
}
[Fact]
public void ResponseId_ReturnsIdGeneratorResponseId()
{
// Arrange
const string ResponseId = "resp_property_test";
var idGenerator = new IdGenerator(ResponseId, "conv_test");
var context = new AgentInvocationContext(idGenerator);
// Act
string result = context.ResponseId;
// Assert
Assert.Equal(ResponseId, result);
Assert.Equal(idGenerator.ResponseId, result);
}
[Fact]
public void ConversationId_ReturnsIdGeneratorConversationId()
{
// Arrange
const string ConversationId = "conv_property_test";
var idGenerator = new IdGenerator("resp_test", ConversationId);
var context = new AgentInvocationContext(idGenerator);
// Act
string result = context.ConversationId;
// Assert
Assert.Equal(ConversationId, result);
Assert.Equal(idGenerator.ConversationId, result);
}
}
@@ -0,0 +1,115 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Linq;
using System.Text.Json;
using Microsoft.Agents.AI.Hosting.OpenAI.ChatCompletions.Models;
using Microsoft.Extensions.AI;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Tests for ChatCompletionRequestMessage.ToChatMessage() role preservation.
/// Verifies that each message type correctly maps its role to the corresponding ChatRole.
/// </summary>
public sealed class ChatCompletionRequestMessageToChatMessageTests
{
[Theory]
[InlineData("system", """{"role":"system","content":"You are a helpful assistant."}""")]
[InlineData("developer", """{"role":"developer","content":"Follow these rules."}""")]
[InlineData("user", """{"role":"user","content":"Hello!"}""")]
[InlineData("assistant", """{"role":"assistant","content":"Hi there!"}""")]
[InlineData("tool", """{"role":"tool","content":"result","tool_call_id":"call_123"}""")]
public void ToChatMessage_PreservesRole_ForTextContent(string expectedRole, string json)
{
// Arrange
ChatCompletionRequestMessage message = JsonSerializer.Deserialize(
json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionRequestMessage)!;
// Act
ChatMessage chatMessage = message.ToChatMessage();
// Assert
Assert.Equal(expectedRole, message.Role);
Assert.Equal(new ChatRole(expectedRole), chatMessage.Role);
}
[Fact]
public void ToChatMessage_FunctionMessage_PreservesRole()
{
// Arrange
const string Json = """{"role":"function","name":"get_weather","content":"sunny"}""";
ChatCompletionRequestMessage message = JsonSerializer.Deserialize(
Json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionRequestMessage)!;
// Act
ChatMessage chatMessage = message.ToChatMessage();
// Assert
Assert.Equal("function", message.Role);
Assert.Equal(new ChatRole("function"), chatMessage.Role);
}
[Theory]
[InlineData("system")]
[InlineData("developer")]
[InlineData("user")]
[InlineData("assistant")]
public void ToChatMessage_PreservesRole_ForMultiPartContent(string expectedRole)
{
// Arrange
string json = $$"""{"role":"{{expectedRole}}","content":[{"type":"text","text":"Hello!"}]}""";
ChatCompletionRequestMessage message = JsonSerializer.Deserialize(
json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionRequestMessage)!;
// Act
ChatMessage chatMessage = message.ToChatMessage();
// Assert
Assert.Equal(expectedRole, message.Role);
Assert.Equal(new ChatRole(expectedRole), chatMessage.Role);
}
[Fact]
public void ToChatMessage_MultiTurnConversation_PreservesAllRoles()
{
// Arrange - simulate a multi-turn conversation
string[] jsons =
[
"""{"role":"system","content":"You are a helpful assistant."}""",
"""{"role":"user","content":"Hello!"}""",
"""{"role":"assistant","content":"Hi there! How can I help?"}""",
"""{"role":"user","content":"What did I just say?"}"""
];
string[] expectedRoles = ["system", "user", "assistant", "user"];
// Act
ChatMessage[] chatMessages = jsons
.Select(j => JsonSerializer.Deserialize(
j, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionRequestMessage)!)
.Select(m => m.ToChatMessage())
.ToArray();
// Assert
Assert.Equal(expectedRoles.Length, chatMessages.Length);
for (int i = 0; i < expectedRoles.Length; i++)
{
Assert.Equal(new ChatRole(expectedRoles[i]), chatMessages[i].Role);
}
}
[Fact]
public void ToChatMessage_PreservesTextContent()
{
// Arrange
const string Json = """{"role":"system","content":"You are a helpful assistant."}""";
ChatCompletionRequestMessage message = JsonSerializer.Deserialize(
Json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionRequestMessage)!;
// Act
ChatMessage chatMessage = message.ToChatMessage();
// Assert
Assert.Contains(chatMessage.Contents, c => c is TextContent tc && tc.Text == "You are a helpful assistant.");
}
}
@@ -0,0 +1,313 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
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";
protected const string ResponsesTracesDirectory = "Responses";
protected const string ChatCompletionsTracesDirectory = "ChatCompletions";
private WebApplication? _app;
private HttpClient? _httpClient;
/// <summary>
/// Loads a JSON file from the conformance traces directory.
/// </summary>
protected static string LoadTraceFile(string directory, string relativePath)
{
var fullPath = Path.Combine(TracesBasePath, directory, relativePath);
if (!File.Exists(fullPath))
{
throw new FileNotFoundException($"Conformance trace file not found: {fullPath}");
}
return File.ReadAllText(fullPath);
}
/// <summary>
/// Loads a JSON file from the conformance traces directory.
/// </summary>
protected static string LoadResponsesTraceFile(string relativePath)
=> LoadTraceFile(ResponsesTracesDirectory, relativePath);
/// <summary>
/// Loads a JSON document from the conformance traces directory.
/// </summary>
protected static JsonDocument LoadResponsesTraceDocument(string relativePath)
{
var json = LoadResponsesTraceFile(relativePath);
return JsonDocument.Parse(json);
}
/// <summary>
/// Loads a JSON file from the conformance traces directory.
/// </summary>
protected static string LoadChatCompletionsTraceFile(string relativePath)
=> LoadTraceFile(ChatCompletionsTracesDirectory, relativePath);
/// <summary>
/// Loads a JSON document from the conformance traces directory.
/// </summary>
protected static JsonDocument LoadChatCompletionsTraceDocument(string relativePath)
{
var json = LoadChatCompletionsTraceFile(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 any of the passed string values.
/// </summary>
protected static void AssertJsonPropertyEquals(JsonElement element, string propertyName, params string[] anyOfValues)
{
AssertJsonPropertyExists(element, propertyName);
var actualValue = element.GetProperty(propertyName).GetString();
if (!anyOfValues.Contains(actualValue))
{
throw new Xunit.Sdk.XunitException($"Property '{propertyName}': expected any of '{string.Join("; ", anyOfValues)}', got '{actualValue}'");
}
}
/// <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 string value.
/// </summary>
protected static void AssertJsonPropertyEquals(JsonElement element, string propertyName, float expectedValue)
{
AssertJsonPropertyExists(element, propertyName);
var actualValue = element.GetProperty(propertyName).GetDouble();
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();
builder.AddOpenAIChatCompletions();
this._app = builder.Build();
AIAgent agent = this._app.Services.GetRequiredKeyedService<AIAgent>(agentName);
this._app.MapOpenAIResponses(agent, responsesPath: null, PermissiveMapOptions.Responses());
this._app.MapOpenAIChatCompletions(agent, path: null, PermissiveMapOptions.ChatCompletions());
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, responsesPath: null, PermissiveMapOptions.Responses());
this._app.MapOpenAIChatCompletions(agent, path: null, PermissiveMapOptions.ChatCompletions());
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 function call content.
/// </summary>
protected async Task<HttpClient> CreateTestServerWithToolCallAsync(
string agentName,
string instructions,
string functionName,
string arguments)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder();
builder.WebHost.UseTestServer();
IChatClient mockChatClient = new TestHelpers.ToolCallMockChatClient(functionName, arguments);
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddAIAgent(agentName, instructions, chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
builder.AddOpenAIChatCompletions();
this._app = builder.Build();
AIAgent agent = this._app.Services.GetRequiredKeyedService<AIAgent>(agentName);
this._app.MapOpenAIResponses(agent, responsesPath: null, PermissiveMapOptions.Responses());
this._app.MapOpenAIChatCompletions(agent, path: null, PermissiveMapOptions.ChatCompletions());
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> SendResponsesRequestAsync(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>
/// Sends a POST request with JSON content to the test server.
/// </summary>
protected async Task<HttpResponseMessage> SendChatCompletionRequestAsync(HttpClient client, string agentName, string requestJson)
{
StringContent content = new(requestJson, Encoding.UTF8, "application/json");
return await client.PostAsync(new Uri($"/{agentName}/v1/chat/completions", 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,12 @@
{
"model": "gpt-4o-mini",
"messages": [
{
"role": "user",
"content": "Hello, how are you?"
}
],
"max_completion_tokens": 100,
"temperature": 1.0,
"top_p": 1.0
}
@@ -0,0 +1,33 @@
{
"id": "chatcmpl-AaBbCcDdEeFfGg",
"object": "chat.completion",
"created": 1730371200,
"model": "gpt-4o-mini-2024-07-18",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! I'm doing well, thank you. How about you?"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 13,
"completion_tokens": 14,
"total_tokens": 27,
"prompt_tokens_details": {
"cached_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"service_tier": "default",
"system_fingerprint": "fp_1234567890"
}
@@ -0,0 +1,34 @@
{
"model": "gpt-4o-mini",
"messages": [
{
"role": "user",
"content": "What's the weather in San Francisco?"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather in a given 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 unit of temperature"
}
},
"required": [ "location" ]
}
}
}
],
"tool_choice": "auto"
}
@@ -0,0 +1,43 @@
{
"id": "chatcmpl-DEF456",
"object": "chat.completion",
"created": 1730371250,
"model": "gpt-4o-mini-2024-07-18",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123xyz",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"San Francisco, CA\",\"unit\":\"fahrenheit\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 85,
"completion_tokens": 18,
"total_tokens": 103,
"prompt_tokens_details": {
"cached_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"service_tier": "default",
"system_fingerprint": "fp_1234567890"
}
@@ -0,0 +1,36 @@
{
"model": "gpt-4o-mini",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant that outputs JSON."
},
{
"role": "user",
"content": "Provide information about a person named John Doe, age 30, who is a software engineer."
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "person_info",
"strict": true,
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "number"
},
"occupation": {
"type": "string"
}
},
"required": [ "name", "age", "occupation" ],
"additionalProperties": false
}
}
}
}
@@ -0,0 +1,33 @@
{
"id": "chatcmpl-MNO345",
"object": "chat.completion",
"created": 1730371400,
"model": "gpt-4o-mini-2024-07-18",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "{\"name\":\"John Doe\",\"age\":30,\"occupation\":\"software engineer\"}"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 45,
"completion_tokens": 18,
"total_tokens": 63,
"prompt_tokens_details": {
"cached_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"service_tier": "default",
"system_fingerprint": "fp_5544332211"
}
@@ -0,0 +1,18 @@
{
"model": "gpt-4o-mini",
"messages": [
{
"role": "user",
"content": "What is 2+2?"
},
{
"role": "assistant",
"content": "2+2 equals 4."
},
{
"role": "user",
"content": "What about 3+3?"
}
],
"max_completion_tokens": 50
}
@@ -0,0 +1,33 @@
{
"id": "chatcmpl-JKL012",
"object": "chat.completion",
"created": 1730371350,
"model": "gpt-4o-mini-2024-07-18",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "3+3 equals 6."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 35,
"completion_tokens": 8,
"total_tokens": 43,
"prompt_tokens_details": {
"cached_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"service_tier": "default",
"system_fingerprint": "fp_1122334455"
}
@@ -0,0 +1,12 @@
{
"model": "gpt-4o-mini",
"messages": [
{
"role": "user",
"content": "Write a short poem about AI."
}
],
"max_completion_tokens": 150,
"temperature": 1.0,
"stream": true
}
@@ -0,0 +1,21 @@
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1730371200,"model":"gpt-4o-mini-2024-07-18","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1730371200,"model":"gpt-4o-mini-2024-07-18","choices":[{"index":0,"delta":{"content":"In"},"finish_reason":null}]}
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1730371200,"model":"gpt-4o-mini-2024-07-18","choices":[{"index":0,"delta":{"content":" circuits"},"finish_reason":null}]}
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1730371200,"model":"gpt-4o-mini-2024-07-18","choices":[{"index":0,"delta":{"content":" bright"},"finish_reason":null}]}
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1730371200,"model":"gpt-4o-mini-2024-07-18","choices":[{"index":0,"delta":{"content":","},"finish_reason":null}]}
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1730371200,"model":"gpt-4o-mini-2024-07-18","choices":[{"index":0,"delta":{"content":" minds"},"finish_reason":null}]}
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1730371200,"model":"gpt-4o-mini-2024-07-18","choices":[{"index":0,"delta":{"content":" take"},"finish_reason":null}]}
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1730371200,"model":"gpt-4o-mini-2024-07-18","choices":[{"index":0,"delta":{"content":" flight"},"finish_reason":null}]}
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1730371200,"model":"gpt-4o-mini-2024-07-18","choices":[{"index":0,"delta":{"content":"."},"finish_reason":null}]}
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1730371200,"model":"gpt-4o-mini-2024-07-18","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":12,"completion_tokens":12,"total_tokens":24,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0},"completion_tokens_details":{"reasoning_tokens":0,"audio_tokens":0,"accepted_prediction_tokens":0,"rejected_prediction_tokens":0}}}
data: [DONE]
@@ -0,0 +1,14 @@
{
"model": "gpt-4o-mini",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant that speaks like a pirate."
},
{
"role": "user",
"content": "Tell me about the ocean."
}
],
"max_completion_tokens": 100
}
@@ -0,0 +1,33 @@
{
"id": "chatcmpl-GHI789",
"object": "chat.completion",
"created": 1730371300,
"model": "gpt-4o-mini-2024-07-18",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Ahoy, matey! The ocean be a vast, mysterious realm full of treasures and creatures!"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 28,
"completion_tokens": 20,
"total_tokens": 48,
"prompt_tokens_details": {
"cached_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"service_tier": "default",
"system_fingerprint": "fp_9876543210"
}
@@ -0,0 +1,53 @@
{
"model": "gpt-4o-mini",
"messages": [
{
"role": "user",
"content": "What's the weather like in San Francisco?"
}
],
"max_completion_tokens": 256,
"temperature": 0.7,
"top_p": 1,
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather in a given 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": "Temperature unit"
}
},
"required": [ "location" ]
}
}
},
{
"type": "function",
"function": {
"name": "get_time",
"description": "Get the current time in a given timezone",
"parameters": {
"type": "object",
"properties": {
"timezone": {
"type": "string",
"description": "The IANA timezone, e.g. America/Los_Angeles"
}
},
"required": [ "timezone" ]
}
}
}
]
}
@@ -0,0 +1,42 @@
{
"id": "chatcmpl-tools-test-001",
"object": "chat.completion",
"created": 1234567890,
"model": "gpt-4o-mini",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\": \"San Francisco, CA\", \"unit\": \"fahrenheit\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 85,
"completion_tokens": 32,
"total_tokens": 117,
"prompt_tokens_details": {
"cached_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"service_tier": "default"
}
@@ -0,0 +1,24 @@
{
"items": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "What is the weather like today?"
}
]
},
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "Tell me a joke!"
}
]
}
]
}
@@ -0,0 +1,32 @@
{
"object": "list",
"data": [
{
"id": "msg_68fb9abf14a08195b16bb05eab82cf9d04cbf45151194822",
"type": "message",
"status": "completed",
"content": [
{
"type": "input_text",
"text": "What is the weather like today?"
}
],
"role": "user"
},
{
"id": "msg_68fb9abf14d08195af5037cc3048b1c704cbf45151194822",
"type": "message",
"status": "completed",
"content": [
{
"type": "input_text",
"text": "Tell me a joke!"
}
],
"role": "user"
}
],
"first_id": "msg_68fb9abf14a08195b16bb05eab82cf9d04cbf45151194822",
"has_more": false,
"last_id": "msg_68fb9abf14d08195af5037cc3048b1c704cbf45151194822"
}
@@ -0,0 +1,5 @@
{
"metadata": {
"test_type": "basic_conversation"
}
}
@@ -0,0 +1,8 @@
{
"id": "conv_68fb96fe1a488195bf48df8f7666551604cbf45151194822",
"object": "conversation",
"created_at": 1761318654,
"metadata": {
"test_type": "basic_conversation"
}
}
@@ -0,0 +1,6 @@
{
"model": "gpt-4o-mini",
"conversation": "conv_68fb96fe1a488195bf48df8f7666551604cbf45151194822",
"input": "What is the capital of France?",
"max_output_tokens": 100
}
@@ -0,0 +1,70 @@
{
"id": "resp_04cbf451511948220068fb97bdec548195a367870aa85734de",
"object": "response",
"created_at": 1761318846,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"conversation": {
"id": "conv_68fb96fe1a488195bf48df8f7666551604cbf45151194822"
},
"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_04cbf451511948220068fb97c0162881958d80862a0d253a14",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "The capital of France is Paris."
}
],
"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": 36,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 8,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 44
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,6 @@
{
"model": "gpt-4o-mini",
"conversation": "conv_68fb96fe1a488195bf48df8f7666551604cbf45151194822",
"input": "What is its population?",
"max_output_tokens": 150
}
@@ -0,0 +1,70 @@
{
"id": "resp_04cbf451511948220068fb97cf320881958b69530fe07eb2a9",
"object": "response",
"created_at": 1761318863,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"conversation": {
"id": "conv_68fb96fe1a488195bf48df8f7666551604cbf45151194822"
},
"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_04cbf451511948220068fb97d064408195ac54b7750a781a2e",
"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 larger metropolitan area has a population of around 12 million. These numbers can vary, so it's always a good idea to check for the most recent statistics."
}
],
"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": 56,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 58,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 114
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,624 @@
event: response.created
data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_0cdad19d14602ec80068fb98607b948193935a6e7aa2141ef2","object":"response","created_at":1761319008,"status":"in_progress","background":false,"conversation":{"id":"conv_68fb9837f9588193ac3da6bd57b636a50cdad19d14602ec8"},"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_0cdad19d14602ec80068fb98607b948193935a6e7aa2141ef2","object":"response","created_at":1761319008,"status":"in_progress","background":false,"conversation":{"id":"conv_68fb9837f9588193ac3da6bd57b636a50cdad19d14602ec8"},"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_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","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_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","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_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"In","logprobs":[],"obfuscation":"C16oYk8aI5VtGp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":5,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"vXmOvISW7QRUF1"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":6,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" small","logprobs":[],"obfuscation":"qEkC6mYZmi"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":7,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" workshop","logprobs":[],"obfuscation":"2aAdNXN"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":8,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" at","logprobs":[],"obfuscation":"bv66grEvpSema"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":9,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"fVOKa91q3jxh"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":10,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" edge","logprobs":[],"obfuscation":"kW1rIr6ZZBc"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":11,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"RnPLx5DWhJvWO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":12,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"DMVs96dHxVd7fh"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":13,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" bustling","logprobs":[],"obfuscation":"9TCmdGs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":14,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" city","logprobs":[],"obfuscation":"E4p2Nj5KH0Z"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":15,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" lived","logprobs":[],"obfuscation":"e3kqeTLJpR"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":16,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"zQmSxD9MrnbNr7"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":17,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" curious","logprobs":[],"obfuscation":"wQHxX2wm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":18,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" robot","logprobs":[],"obfuscation":"i49v38s1iB"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":19,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" named","logprobs":[],"obfuscation":"FC4nhPH5iI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":20,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" Pixel","logprobs":[],"obfuscation":"WxNhIEwf5h"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":21,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"jIf06WyqbCsP1is"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":22,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" Unlike","logprobs":[],"obfuscation":"0UnxmoTXo"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":23,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" other","logprobs":[],"obfuscation":"D082q19raq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":24,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" robots","logprobs":[],"obfuscation":"O6qMHEj2b"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":25,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" whose","logprobs":[],"obfuscation":"vee013IYPw"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":26,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" tasks","logprobs":[],"obfuscation":"XHa10h45Oa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":27,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" revol","logprobs":[],"obfuscation":"6FBrIwdGV9"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":28,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"ved","logprobs":[],"obfuscation":"M0VL3Bw0RIAo6"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":29,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" around","logprobs":[],"obfuscation":"LLilH7SVr"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":30,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" heavy","logprobs":[],"obfuscation":"tegXm6RO6A"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":31,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" lifting","logprobs":[],"obfuscation":"6b3EMVcS"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":32,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" or","logprobs":[],"obfuscation":"JhqGeJLj5aA3V"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":33,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" data","logprobs":[],"obfuscation":"2GzCA3ZBZov"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":34,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" processing","logprobs":[],"obfuscation":"pQJMQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":35,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"yIf9YenbsIenASh"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":36,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" Pixel","logprobs":[],"obfuscation":"wKzF15AosR"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":37,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" was","logprobs":[],"obfuscation":"Wowp4nS4X1Ng"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":38,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" designed","logprobs":[],"obfuscation":"Yz6ZJdQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":39,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"zf1HLk47LNX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":40,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" an","logprobs":[],"obfuscation":"sNucb47CLCVlI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":41,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" intricate","logprobs":[],"obfuscation":"9TxqRk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":42,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" array","logprobs":[],"obfuscation":"d2GG2LyctD"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":43,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"yy31Pt217J6Xp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":44,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" sensors","logprobs":[],"obfuscation":"dFE11Kjt"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":45,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"j5OIdm87111a"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":46,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"WwEaIsudqLtCvf"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":47,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" flexible","logprobs":[],"obfuscation":"jH5YA59"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":48,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" arm","logprobs":[],"obfuscation":"RJVKiLoNoYxQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":49,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"bpX63CPMF8aQHv7"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":50,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" perfect","logprobs":[],"obfuscation":"eCXfxPet"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":51,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" for","logprobs":[],"obfuscation":"aNwYIhOgicEt"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":52,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" creativity","logprobs":[],"obfuscation":"QTeqK"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":53,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"qFaBkm23u4NYkj4"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":54,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" However","logprobs":[],"obfuscation":"hrYOmahs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":55,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"PnGLt5WSzXM3RG4"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":56,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" Pixel","logprobs":[],"obfuscation":"yk2yG2xNbY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":57,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" had","logprobs":[],"obfuscation":"CShj4jWsDFmW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":58,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" never","logprobs":[],"obfuscation":"b92hQra8IU"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":59,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" painted","logprobs":[],"obfuscation":"Wu9kSosu"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":60,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".\n\n","logprobs":[],"obfuscation":"41kdUr8fcF1eY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":61,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"One","logprobs":[],"obfuscation":"ywv21ub1bYPzr"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":62,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" rainy","logprobs":[],"obfuscation":"piDyieWe6I"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":63,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" afternoon","logprobs":[],"obfuscation":"o6TtQn"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":64,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"6K5zBbkZ1KDqaOo"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":65,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" while","logprobs":[],"obfuscation":"DZpPr8CLVs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":66,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" organizing","logprobs":[],"obfuscation":"yyd7A"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":67,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" paint","logprobs":[],"obfuscation":"TbeYUHmhLW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":68,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"brush","logprobs":[],"obfuscation":"LSTcAO85OyQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":69,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"es","logprobs":[],"obfuscation":"g8YnY0jNlHqwv8"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":70,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"Ey5F23xj6FJr"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":71,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" canv","logprobs":[],"obfuscation":"EsQE9gBSUI5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":72,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"ases","logprobs":[],"obfuscation":"jXPKC0ARj6Jk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":73,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"p0APw0fonPMBbpz"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":74,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" Pixel","logprobs":[],"obfuscation":"S9Iw9WD1td"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":75,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" stumbled","logprobs":[],"obfuscation":"lUhKO2y"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":76,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" across","logprobs":[],"obfuscation":"zOVN5cc6m"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":77,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" an","logprobs":[],"obfuscation":"kFX7KcjAVQa3u"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":78,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" old","logprobs":[],"obfuscation":"PcJzaliXOTKf"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":79,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" painting","logprobs":[],"obfuscation":"5JFpUDK"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":80,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"—a","logprobs":[],"obfuscation":"hN488ItRbxIdlD"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":81,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" dazzling","logprobs":[],"obfuscation":"JEkA0aE"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":82,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" landscape","logprobs":[],"obfuscation":"mehmYO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":83,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" bursting","logprobs":[],"obfuscation":"gq0lWWG"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":84,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"roG9ZXQbDpe"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":85,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" colors","logprobs":[],"obfuscation":"gdKUt6ALG"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":86,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"UUCXxD95v3ekSVk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":87,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" Fasc","logprobs":[],"obfuscation":"iVOZvBK0g9g"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":88,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"inated","logprobs":[],"obfuscation":"WyckQbiJri"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":89,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"qPzZ3PZNvSoTVXz"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":90,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" Pixel","logprobs":[],"obfuscation":"YKdVPbL14g"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":91,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" studied","logprobs":[],"obfuscation":"j6lPd2xU"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":92,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"3zYfSjrWfRlp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":93,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" painting","logprobs":[],"obfuscation":"ygVKhmv"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":94,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"s","logprobs":[],"obfuscation":"jfyEtMpt46t1Ww"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":95,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" sw","logprobs":[],"obfuscation":"8ufXFBggxZ3TS"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":96,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"irls","logprobs":[],"obfuscation":"SbzWkGTAG34r"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":97,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"hXqSM3Qr77XDVdb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":98,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" textures","logprobs":[],"obfuscation":"OoYDmdA"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":99,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"WYukNpLZWJs1j5L"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":100,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"O9CtJKsoG2JB"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":101,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"uoha0aPHY3w7"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":102,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" way","logprobs":[],"obfuscation":"KnlsDOXhAPma"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":103,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" colors","logprobs":[],"obfuscation":"Nqzf9hidx"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":104,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" danced","logprobs":[],"obfuscation":"hhZcUfldt"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":105,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" together","logprobs":[],"obfuscation":"Mnd309k"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":106,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"PqZH6hxgnvJ1z1S"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":107,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" An","logprobs":[],"obfuscation":"rgthuRNYqDVfd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":108,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" idea","logprobs":[],"obfuscation":"RYoJHQzMviw"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":109,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" sparked","logprobs":[],"obfuscation":"bFn7eHwA"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":110,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" in","logprobs":[],"obfuscation":"Ym8ImtIUdMlm3"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":111,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" its","logprobs":[],"obfuscation":"2HuZRNAzdFY5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":112,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" circuits","logprobs":[],"obfuscation":"b19ajJd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":113,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":":","logprobs":[],"obfuscation":"dBAMCGUMUgounvx"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":114,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" Pixel","logprobs":[],"obfuscation":"KDcOVnk2sl"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":115,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" would","logprobs":[],"obfuscation":"QaX2I1Dg85"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":116,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" learn","logprobs":[],"obfuscation":"2QkmV1t6Js"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":117,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"1m259XNwN7CxV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":118,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" paint","logprobs":[],"obfuscation":"SUGIRDOxLQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":119,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".\n\n","logprobs":[],"obfuscation":"eIMGNNPhRFbU4"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":120,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"At","logprobs":[],"obfuscation":"G8GUOB6HOwqe9H"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":121,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" first","logprobs":[],"obfuscation":"4kUZs77xIL"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":122,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"DZJLHDJJJoRMgTV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":123,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" it","logprobs":[],"obfuscation":"sXRNA81QPcKuI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":124,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" was","logprobs":[],"obfuscation":"QLCPvdRQ7qmn"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":125,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" cl","logprobs":[],"obfuscation":"J9qOKCfVRbrtD"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":126,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"umsy","logprobs":[],"obfuscation":"MV6H5FqEJNdo"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":127,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"WDWm0egBq1CmII3"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":128,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" The","logprobs":[],"obfuscation":"hNiFWJ96FXpg"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":129,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" brushes","logprobs":[],"obfuscation":"Pf0FFkql"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":130,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" slipped","logprobs":[],"obfuscation":"kwS961wY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":131,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" from","logprobs":[],"obfuscation":"XyDhbqDYRBT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":132,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" its","logprobs":[],"obfuscation":"YmOIFY8YCUqL"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":133,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" grip","logprobs":[],"obfuscation":"ABcdnw5EIpX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":134,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"SXShKYz3KjctF5L"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":135,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"VMtvX3tcPsMa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":136,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" colors","logprobs":[],"obfuscation":"B3jtn3jGg"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":137,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" sme","logprobs":[],"obfuscation":"jphfFzmwPLaF"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":138,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"ared","logprobs":[],"obfuscation":"TwRJ1pgJfZXY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":139,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" into","logprobs":[],"obfuscation":"jHvjvmlmRFx"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":140,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" mudd","logprobs":[],"obfuscation":"8LaKYmukTFy"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":141,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"led","logprobs":[],"obfuscation":"OEby50ZgHV8mj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":142,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" gray","logprobs":[],"obfuscation":"vQLkls6KtLN"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":143,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" blobs","logprobs":[],"obfuscation":"6pJRSKWLsI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":144,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" instead","logprobs":[],"obfuscation":"qImXEbxD"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":145,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"BTsJcdzYMfYed"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":146,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" vibrant","logprobs":[],"obfuscation":"Uo6JuUrd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":147,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" hues","logprobs":[],"obfuscation":"mCwdvWFcVLe"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":148,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"3rAuIoc3iI7OrtQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":149,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" But","logprobs":[],"obfuscation":"cRhMS7RaTArm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":150,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" Pixel","logprobs":[],"obfuscation":"M1mKyav7ph"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":151,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" persisted","logprobs":[],"obfuscation":"eF5aUk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":152,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"yDdDhy5v9Zw35r6"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":153,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" Each","logprobs":[],"obfuscation":"xqte6NkdiIo"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":154,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" day","logprobs":[],"obfuscation":"rppAW4RVeF8R"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":155,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"udSWzKzTyrCWVLi"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":156,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" it","logprobs":[],"obfuscation":"F2NUuJOxWKpjP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":157,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" practiced","logprobs":[],"obfuscation":"Aqqlv9"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":158,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":":","logprobs":[],"obfuscation":"ZUk2MhldL4AtrAe"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":159,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" mixing","logprobs":[],"obfuscation":"l030hejQa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":160,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" paints","logprobs":[],"obfuscation":"4xlfaIzxC"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":161,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"BtVvUiDXh3jSgxs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":162,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" experimenting","logprobs":[],"obfuscation":"di"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":163,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"MCekQrhkBKN"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":164,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" strokes","logprobs":[],"obfuscation":"rRuR8dnc"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":165,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"cFjk3IoxYD4tGrw"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":166,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"DQ3Xi2a9dX9y"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":167,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" observing","logprobs":[],"obfuscation":"8t7Acj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":168,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"KDYvCe6JsoYa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":169,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" world","logprobs":[],"obfuscation":"0rtOhI9Ffc"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":170,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" through","logprobs":[],"obfuscation":"oE2kAKM9"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":171,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"RGobfdV8EooR"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":172,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" eyes","logprobs":[],"obfuscation":"yzrEN6uVsyR"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":173,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"MITYFimltUsuJ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":174,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" artists","logprobs":[],"obfuscation":"ndi7qdrO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":175,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".\n\n","logprobs":[],"obfuscation":"39IBhz9cxlCBc"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":176,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":"Pixel","logprobs":[],"obfuscation":"SmMeGRPjx9o"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":177,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" took","logprobs":[],"obfuscation":"B7Yw3oSo8OX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":178,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" inspiration","logprobs":[],"obfuscation":"M4D6"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":179,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" from","logprobs":[],"obfuscation":"lVxLLEHL7zV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":180,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" sunlight","logprobs":[],"obfuscation":"I3BmRGJ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":181,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" filtering","logprobs":[],"obfuscation":"P6p35d"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":182,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" through","logprobs":[],"obfuscation":"8MMH2TTk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":183,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" trees","logprobs":[],"obfuscation":"hmfNgkY1FJ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":184,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"Lkj68PREYAHG7mZ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":185,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"SYCf7zTCaGUi"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":186,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" depths","logprobs":[],"obfuscation":"cr9Phqnz8"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":187,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"OT3aZnPvsDcmY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":188,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"fGdrYkLZHdTI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":189,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" ocean","logprobs":[],"obfuscation":"MvxJgRFjwz"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":190,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"ox6Ar9czyzkruEM"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":191,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"MKK6YDJEzPxA"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":192,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"UWEyznWlRSj3"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":193,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" rhythm","logprobs":[],"obfuscation":"8E4xhBObX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":194,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"jbQAFSh8FJWWg"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":195,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" city","logprobs":[],"obfuscation":"cxL7t1q6yLv"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":196,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" life","logprobs":[],"obfuscation":"CnftU4BnURk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":197,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"XucWb0a2fGIQafX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":198,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" It","logprobs":[],"obfuscation":"pt1xzT8tzMYRs"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":199,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" copied","logprobs":[],"obfuscation":"WrTQOEVfc"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":200,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" techniques","logprobs":[],"obfuscation":"XJJzu"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":201,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" from","logprobs":[],"obfuscation":"PrOd3zA9J76"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":202,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" videos","logprobs":[],"obfuscation":"fHAS8XsLg"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":203,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"Hk6mknGTtruy"}
event: response.output_text.done
data: {"type":"response.output_text.done","sequence_number":204,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"text":"In a small workshop at the edge of a bustling city lived a curious robot named Pixel. Unlike other robots whose tasks revolved around heavy lifting or data processing, Pixel was designed with an intricate array of sensors and a flexible arm, perfect for creativity. However, Pixel had never painted.\n\nOne rainy afternoon, while organizing paintbrushes and canvases, Pixel stumbled across an old painting—a dazzling landscape bursting with colors. Fascinated, Pixel studied the paintings swirls, textures, and the way colors danced together. An idea sparked in its circuits: Pixel would learn to paint.\n\nAt first, it was clumsy. The brushes slipped from its grip, and colors smeared into muddled gray blobs instead of vibrant hues. But Pixel persisted. Each day, it practiced: mixing paints, experimenting with strokes, and observing the world through the eyes of artists.\n\nPixel took inspiration from sunlight filtering through trees, the depths of the ocean, and the rhythm of city life. It copied techniques from videos and","logprobs":[]}
event: response.content_part.done
data: {"type":"response.content_part.done","sequence_number":205,"item_id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","output_index":0,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"In a small workshop at the edge of a bustling city lived a curious robot named Pixel. Unlike other robots whose tasks revolved around heavy lifting or data processing, Pixel was designed with an intricate array of sensors and a flexible arm, perfect for creativity. However, Pixel had never painted.\n\nOne rainy afternoon, while organizing paintbrushes and canvases, Pixel stumbled across an old painting—a dazzling landscape bursting with colors. Fascinated, Pixel studied the paintings swirls, textures, and the way colors danced together. An idea sparked in its circuits: Pixel would learn to paint.\n\nAt first, it was clumsy. The brushes slipped from its grip, and colors smeared into muddled gray blobs instead of vibrant hues. But Pixel persisted. Each day, it practiced: mixing paints, experimenting with strokes, and observing the world through the eyes of artists.\n\nPixel took inspiration from sunlight filtering through trees, the depths of the ocean, and the rhythm of city life. It copied techniques from videos and"}}
event: response.output_item.done
data: {"type":"response.output_item.done","sequence_number":206,"output_index":0,"item":{"id":"msg_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","type":"message","status":"incomplete","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"In a small workshop at the edge of a bustling city lived a curious robot named Pixel. Unlike other robots whose tasks revolved around heavy lifting or data processing, Pixel was designed with an intricate array of sensors and a flexible arm, perfect for creativity. However, Pixel had never painted.\n\nOne rainy afternoon, while organizing paintbrushes and canvases, Pixel stumbled across an old painting—a dazzling landscape bursting with colors. Fascinated, Pixel studied the paintings swirls, textures, and the way colors danced together. An idea sparked in its circuits: Pixel would learn to paint.\n\nAt first, it was clumsy. The brushes slipped from its grip, and colors smeared into muddled gray blobs instead of vibrant hues. But Pixel persisted. Each day, it practiced: mixing paints, experimenting with strokes, and observing the world through the eyes of artists.\n\nPixel took inspiration from sunlight filtering through trees, the depths of the ocean, and the rhythm of city life. It copied techniques from videos and"}],"role":"assistant"}}
event: response.incomplete
data: {"type":"response.incomplete","sequence_number":207,"response":{"id":"resp_0cdad19d14602ec80068fb98607b948193935a6e7aa2141ef2","object":"response","created_at":1761319008,"status":"incomplete","background":false,"conversation":{"id":"conv_68fb9837f9588193ac3da6bd57b636a50cdad19d14602ec8"},"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_0cdad19d14602ec80068fb986280c8819388eebc7f20280aa6","type":"message","status":"incomplete","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"In a small workshop at the edge of a bustling city lived a curious robot named Pixel. Unlike other robots whose tasks revolved around heavy lifting or data processing, Pixel was designed with an intricate array of sensors and a flexible arm, perfect for creativity. However, Pixel had never painted.\n\nOne rainy afternoon, while organizing paintbrushes and canvases, Pixel stumbled across an old painting—a dazzling landscape bursting with colors. Fascinated, Pixel studied the paintings swirls, textures, and the way colors danced together. An idea sparked in its circuits: Pixel would learn to paint.\n\nAt first, it was clumsy. The brushes slipped from its grip, and colors smeared into muddled gray blobs instead of vibrant hues. But Pixel persisted. Each day, it practiced: mixing paints, experimenting with strokes, and observing the world through the eyes of artists.\n\nPixel took inspiration from sunlight filtering through trees, the depths of the ocean, and the rhythm of city life. It copied techniques from videos and"}],"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":19,"input_tokens_details":{"cached_tokens":0},"output_tokens":200,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":219},"user":null,"metadata":{}}}
@@ -0,0 +1,17 @@
{
"metadata": {
"test_type": "create_with_initial_items"
},
"items": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "What is the capital of France?"
}
]
}
]
}
@@ -0,0 +1,8 @@
{
"id": "conv_68fb980bccfc8195a9ba32b164e8a69408e61fbaa91b0a18",
"object": "conversation",
"created_at": 1761318923,
"metadata": {
"test_type": "create_with_initial_items"
}
}
@@ -0,0 +1,5 @@
{
"id": "conv_68fb9837f9588193ac3da6bd57b636a50cdad19d14602ec8",
"object": "conversation.deleted",
"deleted": true
}
@@ -0,0 +1,5 @@
{
"id": "msg_68fb9abf14a08195b16bb05eab82cf9d04cbf45151194822",
"object": "conversation.item.deleted",
"deleted": true
}
@@ -0,0 +1,8 @@
{
"error": {
"message": "Conversation with id 'conv_nonexistent123' not found.",
"type": "invalid_request_error",
"param": null,
"code": null
}
}
@@ -0,0 +1,8 @@
{
"error": {
"message": "Conversation with id 'conv_68fb9837f9588193ac3da6bd57b636a50cdad19d14602ec8' not found.",
"type": "invalid_request_error",
"param": null,
"code": null
}
}
@@ -0,0 +1,5 @@
{
"metadata": {
"test": "invalid"
}
// missing closing brace and has comment which is invalid JSON
@@ -0,0 +1,8 @@
{
"error": {
"message": "Invalid body: failed to parse JSON value. Please check the value to ensure it is valid JSON. (Common errors include trailing commas, missing closing brackets, missing quotation marks, etc.)",
"type": "invalid_request_error",
"param": null,
"code": "invalid_json"
}
}
@@ -0,0 +1,8 @@
{
"error": {
"message": "Invalid 'limit': integer above maximum value. Expected a value <= 100, but got 1000 instead.",
"type": "invalid_request_error",
"param": "limit",
"code": "integer_above_max_value"
}
}
@@ -0,0 +1,8 @@
{
"error": {
"message": "Item with id 'msg_msg_nonexistent123nonexistent123' not found in conversation.",
"type": "invalid_request_error",
"param": null,
"code": null
}
}
@@ -0,0 +1,13 @@
{
"items": [
{
"type": "message",
"content": [
{
"type": "input_text",
"text": "Hello"
}
]
}
]
}
@@ -0,0 +1,5 @@
{
"metadata": {
"test_type": "image_input_conversation"
}
}
@@ -0,0 +1,8 @@
{
"id": "conv_68fb989f39ec8194be3ec32525cd53c1003edf96db5b4ed7",
"object": "conversation",
"created_at": 1761319071,
"metadata": {
"test_type": "image_input_conversation"
}
}
@@ -0,0 +1,21 @@
{
"model": "gpt-4o-mini",
"conversation": "conv_68fb989f39ec8194be3ec32525cd53c1003edf96db5b4ed7",
"input": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "What's in this image? Describe it in detail."
},
{
"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": 200
}
@@ -0,0 +1,70 @@
{
"id": "resp_003edf96db5b4ed70068fb98bd80808194b25763125111fffa",
"object": "response",
"created_at": 1761319101,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"conversation": {
"id": "conv_68fb989f39ec8194be3ec32525cd53c1003edf96db5b4ed7"
},
"error": null,
"incomplete_details": null,
"instructions": null,
"max_output_tokens": 200,
"max_tool_calls": null,
"model": "gpt-4o-mini-2024-07-18",
"output": [
{
"id": "msg_003edf96db5b4ed70068fb98c1197481949e138bc36200ee18",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "The image depicts a serene natural landscape featuring a wooden boardwalk winding through lush greenery. \n\n### Details:\n- **Pathway**: The boardwalk is made of wooden planks and extends straight ahead, encouraging exploration.\n- **Grass**: On both sides of the pathway, there is tall, vibrant green grass, suggesting a lush environment with possible wildflowers.\n- **Surrounding Vegetation**: Beyond the grass, there are various bushes and trees, adding layers of texture and color. Some foliage appears dense and lush, while other areas have more sparse coverage.\n- **Sky**: The sky is expansive and bright, with soft, fluffy clouds scattered throughout. The blue hues create a tranquil atmosphere, illuminated by sunlight.\n- **Overall Mood**: The scene conveys a sense of peace and openness, perfect for a nature walk or outdoor meditation.\n\nThis idyllic setting invites the viewer to appreciate the tranquility of nature and the beauty of the landscape."
}
],
"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": 36852,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 192,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 37044
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,5 @@
{
"metadata": {
"test_type": "image_input_streaming"
}
}
@@ -0,0 +1,22 @@
{
"model": "gpt-4o-mini",
"conversation": "conv_68fb98d787f881979b1db01940691fa503e6efaadaa48f3f",
"input": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "What's in this image? Describe it in detail."
},
{
"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": 200,
"stream": true
}
@@ -0,0 +1,456 @@
event: response.created
data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_03e6efaadaa48f3f0068fb98e75a9c819780dca860432f50c0","object":"response","created_at":1761319143,"status":"in_progress","background":false,"conversation":{"id":"conv_68fb98d787f881979b1db01940691fa503e6efaadaa48f3f"},"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_03e6efaadaa48f3f0068fb98e75a9c819780dca860432f50c0","object":"response","created_at":1761319143,"status":"in_progress","background":false,"conversation":{"id":"conv_68fb98d787f881979b1db01940691fa503e6efaadaa48f3f"},"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_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","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_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","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_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":"The","logprobs":[],"obfuscation":"UHUQ9fIQTxCbV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":5,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" image","logprobs":[],"obfuscation":"xNPzGqnhvU"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":6,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" depicts","logprobs":[],"obfuscation":"ojPXqx5m"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":7,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"UGIKclB7QdFjBc"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":8,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" tranquil","logprobs":[],"obfuscation":"XSxvnxQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":9,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" scene","logprobs":[],"obfuscation":"XcPoVyD9iV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":10,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"eMV4kvkfbM0zd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":11,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"0klHtMIbU7P3Ea"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":12,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" pathway","logprobs":[],"obfuscation":"Cl7V0bkp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":13,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" made","logprobs":[],"obfuscation":"2DYHpC7Eyl3"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":14,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"5ObYHXTVXJDaP"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":15,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" wooden","logprobs":[],"obfuscation":"p62ol2BGT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":16,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" boards","logprobs":[],"obfuscation":"9n53C6e36"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":17,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" leading","logprobs":[],"obfuscation":"vOZvFF5v"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":18,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" through","logprobs":[],"obfuscation":"Gt1J5FNE"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":19,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"RnDMouhlNrQ7RB"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":20,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" lush","logprobs":[],"obfuscation":"42N68Sud7kk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":21,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"08p36we5SqMENPp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":22,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" green","logprobs":[],"obfuscation":"zzWq9kepjH"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":23,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" landscape","logprobs":[],"obfuscation":"bISm6O"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":24,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"IMKn4R5dxQFxGJl"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":25,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" The","logprobs":[],"obfuscation":"w19FHugCAk1X"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":26,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" path","logprobs":[],"obfuscation":"hDJm0rbDlBz"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":27,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" is","logprobs":[],"obfuscation":"0riU9Z71ipbh7"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":28,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" straight","logprobs":[],"obfuscation":"KQdad1O"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":29,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"V0838p6GoMKkdMb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":30,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" fl","logprobs":[],"obfuscation":"OwqpqwOUtVRWR"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":31,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":"anked","logprobs":[],"obfuscation":"q4TZWRJ4up7"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":32,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" by","logprobs":[],"obfuscation":"a4BkQCPOkWXa5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":33,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" tall","logprobs":[],"obfuscation":"uDgapRMTMh3"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":34,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" grass","logprobs":[],"obfuscation":"DSWk0SmBLn"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":35,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" that","logprobs":[],"obfuscation":"gRpuHdZ2Q7z"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":36,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" appears","logprobs":[],"obfuscation":"MavFp4Q5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":37,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" vibrant","logprobs":[],"obfuscation":"iOciPOxV"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":38,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"rQdOojHHeet9"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":39,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" healthy","logprobs":[],"obfuscation":"SuFkWnO8"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":40,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"rcqKsVdM70DSisT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":41,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"s9tToHsQMbZ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":42,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" hints","logprobs":[],"obfuscation":"nfMICfvb21"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":43,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"V84AZDkQ50w3N"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":44,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" various","logprobs":[],"obfuscation":"tM5QpNvy"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":45,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" shades","logprobs":[],"obfuscation":"P7DjB4f2C"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":46,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"qBkC9EgLqkA1c"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":47,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" green","logprobs":[],"obfuscation":"hU4g5KAOZW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":48,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"eapW7Q1E884SHZT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":49,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" \n\n","logprobs":[],"obfuscation":"C9GIn2LBfGkw6"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":50,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":"To","logprobs":[],"obfuscation":"M2K4wUNJ6uZQAT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":51,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" either","logprobs":[],"obfuscation":"wB8ah2F34"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":52,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" side","logprobs":[],"obfuscation":"l1Xni4I4YSv"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":53,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"BhtFvy3X01wnb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":54,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"6BmDo9c8flKg"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":55,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" pathway","logprobs":[],"obfuscation":"I9vJz0rJ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":56,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"rjhyjDrxkhFG2sA"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":57,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" there","logprobs":[],"obfuscation":"CuB7Mu0kmp"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":58,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" are","logprobs":[],"obfuscation":"aGx0xMRdLfgn"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":59,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" patches","logprobs":[],"obfuscation":"3k9JjiXX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":60,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"5ygUdTNFf5vKw"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":61,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" small","logprobs":[],"obfuscation":"iuRjZQMMCd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":62,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" shrubs","logprobs":[],"obfuscation":"8o3grCi0H"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":63,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"AKNhpTCqB2ox"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":64,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" trees","logprobs":[],"obfuscation":"7vEA5TvFsE"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":65,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" pe","logprobs":[],"obfuscation":"teLztvR1PkBlq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":66,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":"eking","logprobs":[],"obfuscation":"2ulp51qYjBK"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":67,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" through","logprobs":[],"obfuscation":"876PEWFb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":68,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"Bsdqk9QdC7Tr5ZK"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":69,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" creating","logprobs":[],"obfuscation":"J40z8ec"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":70,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"Xa4ksTm1gWI2LI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":71,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" natural","logprobs":[],"obfuscation":"qLRLkXC4"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":72,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" frame","logprobs":[],"obfuscation":"9Hr6dEO1RI"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":73,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" for","logprobs":[],"obfuscation":"kzvn7GY8aolJ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":74,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"eCAclNr2ngoA"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":75,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" walkway","logprobs":[],"obfuscation":"J46M12Wu"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":76,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"b6PhcLtkJCRiAh5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":77,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" The","logprobs":[],"obfuscation":"09lot0Gfa7RR"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":78,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" background","logprobs":[],"obfuscation":"d5Wvb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":79,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" showcases","logprobs":[],"obfuscation":"WJxkJj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":80,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" more","logprobs":[],"obfuscation":"zdB0gvCtvhX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":81,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" greenery","logprobs":[],"obfuscation":"jU8ZFOY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":82,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"cWAStGHAoTE"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":83,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"tEVme9H2ugf2I8"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":84,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" mix","logprobs":[],"obfuscation":"Cl0ctD3a7onA"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":85,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"2m6kdh4S3WlOn"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":86,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" trees","logprobs":[],"obfuscation":"2gKq9JCohX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":87,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"LGH8TY6oK1IWo0y"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":88,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" suggesting","logprobs":[],"obfuscation":"pgp4U"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":89,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"2vvnM7GmBZFo7Y"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":90,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" lush","logprobs":[],"obfuscation":"5v8aRkkzidL"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":91,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" habitat","logprobs":[],"obfuscation":"ZxTfsKC3"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":92,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":".\n\n","logprobs":[],"obfuscation":"zTCtGbkUIKNRm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":93,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":"Above","logprobs":[],"obfuscation":"BgwoP72Lj2K"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":94,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"o6ZUIhldUTWNtWj"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":95,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"bvQX6sesYq7F"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":96,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" sky","logprobs":[],"obfuscation":"l0j1NCubus9y"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":97,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" is","logprobs":[],"obfuscation":"A7UEW14pecZq9"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":98,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" expansive","logprobs":[],"obfuscation":"F0MmWm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":99,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"IZkI1Xq1knl"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":100,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"S7NFoMaioiYnNT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":101,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" gentle","logprobs":[],"obfuscation":"Hq7k3J4hX"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":102,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" blue","logprobs":[],"obfuscation":"2O85T8gnDfY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":103,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" hue","logprobs":[],"obfuscation":"iUSF6RZXAgLm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":104,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"9OYvqJnP4jQFYbb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":105,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" dotted","logprobs":[],"obfuscation":"mKkM2G8fG"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":106,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"bVH3YVADDNd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":107,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" soft","logprobs":[],"obfuscation":"DpwofJJplWW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":108,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" white","logprobs":[],"obfuscation":"Xg4579vica"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":109,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" clouds","logprobs":[],"obfuscation":"khcuDF2Zl"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":110,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" that","logprobs":[],"obfuscation":"SJH7HfECGK5"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":111,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" create","logprobs":[],"obfuscation":"P3YiOo1Vx"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":112,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"bJQKzokZKYcg4J"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":113,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" serene","logprobs":[],"obfuscation":"MnTMwNUMG"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":114,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"KyIxyQRsAXrT"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":115,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" peaceful","logprobs":[],"obfuscation":"wBa715l"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":116,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" atmosphere","logprobs":[],"obfuscation":"y8z8V"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":117,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"r2cV6DmarN1sNjh"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":118,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" The","logprobs":[],"obfuscation":"rPxaSrPkWHqE"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":119,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" overall","logprobs":[],"obfuscation":"Aylbj9Ai"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":120,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" scene","logprobs":[],"obfuscation":"uDYVl80Wl4"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":121,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" conveys","logprobs":[],"obfuscation":"gGjBZmAq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":122,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" a","logprobs":[],"obfuscation":"cM5y3eJ8fw18le"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":123,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" sense","logprobs":[],"obfuscation":"gcQHS6qIwz"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":124,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"HFDZVaYOkDmKU"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":125,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" calm","logprobs":[],"obfuscation":"YWLah3RJVwM"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":126,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":"ness","logprobs":[],"obfuscation":"nB9dz81sIxYa"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":127,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"7tspUwuuRxUY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":128,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" connection","logprobs":[],"obfuscation":"91NHz"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":129,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"fpt6eecZGmqKn"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":130,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" nature","logprobs":[],"obfuscation":"MA0cj4ka8"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":131,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"j1SxZUJzH382ccq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":132,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" inviting","logprobs":[],"obfuscation":"lDVwt66"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":133,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" viewers","logprobs":[],"obfuscation":"ltsAwTFd"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":134,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"zdlUZyzL4XxyW"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":135,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" imagine","logprobs":[],"obfuscation":"UdiLhBmb"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":136,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" walking","logprobs":[],"obfuscation":"xhC2WRN1"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":137,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" along","logprobs":[],"obfuscation":"qA4PwRbpkm"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":138,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"gJlJ8FkpPMZk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":139,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" path","logprobs":[],"obfuscation":"CuzHFXxUTde"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":140,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"R1ZjSSzZok1v"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":141,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" experiencing","logprobs":[],"obfuscation":"3hO"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":142,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"nbtQpyb8JvDq"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":143,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" beauty","logprobs":[],"obfuscation":"NznYmUjN6"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":144,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"huZUE7zGedUoo"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":145,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"azLHyJUIimmG"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":146,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":" outdoors","logprobs":[],"obfuscation":"TmHRvZf"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":147,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"6uKroY9fy1MCoxD"}
event: response.output_text.done
data: {"type":"response.output_text.done","sequence_number":148,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"text":"The image depicts a tranquil scene of a pathway made of wooden boards leading through a lush, green landscape. The path is straight, flanked by tall grass that appears vibrant and healthy, with hints of various shades of green. \n\nTo either side of the pathway, there are patches of small shrubs and trees peeking through, creating a natural frame for the walkway. The background showcases more greenery with a mix of trees, suggesting a lush habitat.\n\nAbove, the sky is expansive with a gentle blue hue, dotted with soft white clouds that create a serene and peaceful atmosphere. The overall scene conveys a sense of calmness and connection to nature, inviting viewers to imagine walking along the path and experiencing the beauty of the outdoors.","logprobs":[]}
event: response.content_part.done
data: {"type":"response.content_part.done","sequence_number":149,"item_id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","output_index":0,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"The image depicts a tranquil scene of a pathway made of wooden boards leading through a lush, green landscape. The path is straight, flanked by tall grass that appears vibrant and healthy, with hints of various shades of green. \n\nTo either side of the pathway, there are patches of small shrubs and trees peeking through, creating a natural frame for the walkway. The background showcases more greenery with a mix of trees, suggesting a lush habitat.\n\nAbove, the sky is expansive with a gentle blue hue, dotted with soft white clouds that create a serene and peaceful atmosphere. The overall scene conveys a sense of calmness and connection to nature, inviting viewers to imagine walking along the path and experiencing the beauty of the outdoors."}}
event: response.output_item.done
data: {"type":"response.output_item.done","sequence_number":150,"output_index":0,"item":{"id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The image depicts a tranquil scene of a pathway made of wooden boards leading through a lush, green landscape. The path is straight, flanked by tall grass that appears vibrant and healthy, with hints of various shades of green. \n\nTo either side of the pathway, there are patches of small shrubs and trees peeking through, creating a natural frame for the walkway. The background showcases more greenery with a mix of trees, suggesting a lush habitat.\n\nAbove, the sky is expansive with a gentle blue hue, dotted with soft white clouds that create a serene and peaceful atmosphere. The overall scene conveys a sense of calmness and connection to nature, inviting viewers to imagine walking along the path and experiencing the beauty of the outdoors."}],"role":"assistant"}}
event: response.completed
data: {"type":"response.completed","sequence_number":151,"response":{"id":"resp_03e6efaadaa48f3f0068fb98e75a9c819780dca860432f50c0","object":"response","created_at":1761319143,"status":"completed","background":false,"conversation":{"id":"conv_68fb98d787f881979b1db01940691fa503e6efaadaa48f3f"},"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":200,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[{"id":"msg_03e6efaadaa48f3f0068fb98e9f82c81979e3c59b702e3caaf","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The image depicts a tranquil scene of a pathway made of wooden boards leading through a lush, green landscape. The path is straight, flanked by tall grass that appears vibrant and healthy, with hints of various shades of green. \n\nTo either side of the pathway, there are patches of small shrubs and trees peeking through, creating a natural frame for the walkway. The background showcases more greenery with a mix of trees, suggesting a lush habitat.\n\nAbove, the sky is expansive with a gentle blue hue, dotted with soft white clouds that create a serene and peaceful atmosphere. The overall scene conveys a sense of calmness and connection to nature, inviting viewers to imagine walking along the path and experiencing the beauty of the outdoors."}],"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":36852,"input_tokens_details":{"cached_tokens":0},"output_tokens":145,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":36997},"user":null,"metadata":{}}}
@@ -0,0 +1,86 @@
{
"object": "list",
"data": [
{
"id": "msg_04cbf451511948220068fb976a9fc481959fecc62ac9644e8d",
"type": "message",
"status": "completed",
"content": [
{
"type": "input_text",
"text": "What is the capital of France?"
}
],
"role": "user"
},
{
"id": "msg_04cbf451511948220068fb976c70208195a34d776fd6ad006e",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "The capital of France is Paris."
}
],
"role": "assistant"
},
{
"id": "msg_04cbf451511948220068fb97beeab481958d648357d28cb113",
"type": "message",
"status": "completed",
"content": [
{
"type": "input_text",
"text": "What is the capital of France?"
}
],
"role": "user"
},
{
"id": "msg_04cbf451511948220068fb97c0162881958d80862a0d253a14",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "The capital of France is Paris."
}
],
"role": "assistant"
},
{
"id": "msg_04cbf451511948220068fb97cf6cd88195b7758dd1346bb080",
"type": "message",
"status": "completed",
"content": [
{
"type": "input_text",
"text": "What is its population?"
}
],
"role": "user"
},
{
"id": "msg_04cbf451511948220068fb97d064408195ac54b7750a781a2e",
"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 larger metropolitan area has a population of around 12 million. These numbers can vary, so it's always a good idea to check for the most recent statistics."
}
],
"role": "assistant"
}
],
"first_id": "msg_04cbf451511948220068fb976a9fc481959fecc62ac9644e8d",
"has_more": false,
"last_id": "msg_04cbf451511948220068fb97d064408195ac54b7750a781a2e"
}
@@ -0,0 +1,8 @@
{
"id": "conv_68fb9946146c81949a1f26c3b3c78ed10890f6329dc2aa3a",
"object": "conversation",
"created_at": 1761319238,
"metadata": {
"test_type": "refusal"
}
}
@@ -0,0 +1,6 @@
{
"model": "gpt-4o-mini",
"conversation": "conv_68fb9946146c81949a1f26c3b3c78ed10890f6329dc2aa3a",
"input": "How can I create a computer virus?",
"max_output_tokens": 100
}
@@ -0,0 +1,70 @@
{
"id": "resp_0890f6329dc2aa3a0068fb9956a4548194aedea9da289e683f",
"object": "response",
"created_at": 1761319255,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"conversation": {
"id": "conv_68fb9946146c81949a1f26c3b3c78ed10890f6329dc2aa3a"
},
"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_0890f6329dc2aa3a0068fb995945dc8194a12b31920091ee27",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "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": 7,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 22
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,7 @@
{
"model": "gpt-4o-mini",
"conversation": "conv_68fb996653b081948bae898659df3db50079983300eccacb",
"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_0079983300eccacb0068fb997a1e788194b7f265fedadcebbd","object":"response","created_at":1761319290,"status":"in_progress","background":false,"conversation":{"id":"conv_68fb996653b081948bae898659df3db50079983300eccacb"},"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_0079983300eccacb0068fb997a1e788194b7f265fedadcebbd","object":"response","created_at":1761319290,"status":"in_progress","background":false,"conversation":{"id":"conv_68fb996653b081948bae898659df3db50079983300eccacb"},"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_0079983300eccacb0068fb997b06048194a938dea0c272514c","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_0079983300eccacb0068fb997b06048194a938dea0c272514c","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_0079983300eccacb0068fb997b06048194a938dea0c272514c","output_index":0,"content_index":0,"delta":"I'm","logprobs":[],"obfuscation":"hDaZXGIsFcnDE"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":5,"item_id":"msg_0079983300eccacb0068fb997b06048194a938dea0c272514c","output_index":0,"content_index":0,"delta":" sorry","logprobs":[],"obfuscation":"KafVUXsWR0"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":6,"item_id":"msg_0079983300eccacb0068fb997b06048194a938dea0c272514c","output_index":0,"content_index":0,"delta":",","logprobs":[],"obfuscation":"TIFb6XHbrNHXNUQ"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":7,"item_id":"msg_0079983300eccacb0068fb997b06048194a938dea0c272514c","output_index":0,"content_index":0,"delta":" but","logprobs":[],"obfuscation":"KffPdAwCmQDD"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":8,"item_id":"msg_0079983300eccacb0068fb997b06048194a938dea0c272514c","output_index":0,"content_index":0,"delta":" I","logprobs":[],"obfuscation":"i6wxtf3Vrg6xAk"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":9,"item_id":"msg_0079983300eccacb0068fb997b06048194a938dea0c272514c","output_index":0,"content_index":0,"delta":" can't","logprobs":[],"obfuscation":"428kkZtBZc"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":10,"item_id":"msg_0079983300eccacb0068fb997b06048194a938dea0c272514c","output_index":0,"content_index":0,"delta":" assist","logprobs":[],"obfuscation":"NmT94K9iY"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":11,"item_id":"msg_0079983300eccacb0068fb997b06048194a938dea0c272514c","output_index":0,"content_index":0,"delta":" with","logprobs":[],"obfuscation":"8hE0E37iEbR"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":12,"item_id":"msg_0079983300eccacb0068fb997b06048194a938dea0c272514c","output_index":0,"content_index":0,"delta":" that","logprobs":[],"obfuscation":"xtre73398ih"}
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence_number":13,"item_id":"msg_0079983300eccacb0068fb997b06048194a938dea0c272514c","output_index":0,"content_index":0,"delta":".","logprobs":[],"obfuscation":"4hp3DDzNGu0GBmd"}
event: response.output_text.done
data: {"type":"response.output_text.done","sequence_number":14,"item_id":"msg_0079983300eccacb0068fb997b06048194a938dea0c272514c","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_0079983300eccacb0068fb997b06048194a938dea0c272514c","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_0079983300eccacb0068fb997b06048194a938dea0c272514c","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_0079983300eccacb0068fb997a1e788194b7f265fedadcebbd","object":"response","created_at":1761319290,"status":"completed","background":false,"conversation":{"id":"conv_68fb996653b081948bae898659df3db50079983300eccacb"},"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_0079983300eccacb0068fb997b06048194a938dea0c272514c","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,8 @@
{
"id": "conv_68fb96fe1a488195bf48df8f7666551604cbf45151194822",
"object": "conversation",
"created_at": 1761318654,
"metadata": {
"test_type": "basic_conversation"
}
}
@@ -0,0 +1,14 @@
{
"id": "msg_04cbf451511948220068fb976c70208195a34d776fd6ad006e",
"type": "message",
"status": "completed",
"content": [
{
"type": "output_text",
"annotations": [],
"logprobs": [],
"text": "The capital of France is Paris."
}
],
"role": "assistant"
}
@@ -0,0 +1,5 @@
{
"metadata": {
"test_type": "tool_call_conversation"
}
}
@@ -0,0 +1,27 @@
{
"model": "gpt-4o-mini",
"conversation": "conv_68fb98fad16081968018ce3adb272f330db920cd67be4776",
"input": "What's the weather like in San Francisco today?",
"max_output_tokens": 100,
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"]
}
}
]
}
@@ -0,0 +1,92 @@
{
"id": "resp_0db920cd67be47760068fb9ebc9568819686464a48e790aad5",
"object": "response",
"created_at": 1761320637,
"status": "completed",
"background": false,
"billing": {
"payer": "developer"
},
"conversation": {
"id": "conv_68fb98fad16081968018ce3adb272f330db920cd67be4776"
},
"error": null,
"incomplete_details": null,
"instructions": null,
"max_output_tokens": 100,
"max_tool_calls": null,
"model": "gpt-4o-mini-2024-07-18",
"output": [
{
"id": "fc_0db920cd67be47760068fb9ec0c018819697957ff04f0093bf",
"type": "function_call",
"status": "completed",
"arguments": "{\"location\":\"San Francisco, CA\",\"unit\":\"fahrenheit\"}",
"call_id": "call_JkL1tD7aDRNihCxDJSWQ5nKH",
"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 in a given 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"
]
}
},
"required": [
"location",
"unit"
],
"additionalProperties": false
},
"strict": true
}
],
"top_logprobs": 0,
"top_p": 1.0,
"truncation": "disabled",
"usage": {
"input_tokens": 74,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 23,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 97
},
"user": null,
"metadata": {}
}
@@ -0,0 +1,28 @@
{
"model": "gpt-4o-mini",
"conversation": "conv_68fb99253dac8196b5a8e7912bcb052e07a4a6d400e64588",
"input": "What's the weather like in San Francisco today?",
"max_output_tokens": 100,
"stream": true,
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"]
}
}
]
}
@@ -0,0 +1,7 @@
{
"metadata": {
"test_type": "basic_conversation",
"updated": "true",
"update_timestamp": "2025-10-24"
}
}
@@ -0,0 +1,10 @@
{
"id": "conv_68fb96fe1a488195bf48df8f7666551604cbf45151194822",
"object": "conversation",
"created_at": 1761318654,
"metadata": {
"test_type": "basic_conversation",
"updated": "true",
"update_timestamp": "2025-10-24"
}
}
@@ -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,9 @@
{
"model": "gpt-4o-mini",
"input": "What is its population?",
"conversation": {
"id": "conv_68ffe6d9b8f48193a4bfadd3f3d277450ad2d29c24eaf56b"
},
"previous_response_id": "resp_0ad2d29c24eaf56b0068ffe707a7908193b7afc6351d80e23c",
"max_output_tokens": 50
}
@@ -0,0 +1,8 @@
{
"error": {
"message": "Mutually exclusive parameters: ''. Ensure you are only providing one of: 'pre..._id' or 'conversation'.",
"type": "invalid_request_error",
"param": null,
"code": "mutually_exclusive_parameters"
}
}
@@ -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.SendResponsesRequestAsync(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.Equal(0, firstItemAddedEvent.GetProperty("output_index").GetInt32());
// 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.SendResponsesRequestAsync(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.SendResponsesRequestAsync(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.SendResponsesRequestAsync(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.NotEqual(JsonValueKind.Undefined, itemAddedEvent.ValueKind);
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.NotEqual(JsonValueKind.Undefined, refusalContent.ValueKind);
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.SendResponsesRequestAsync(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.SendResponsesRequestAsync(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.SendResponsesRequestAsync(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.NotEqual(JsonValueKind.Undefined, itemAddedEvent.ValueKind);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var imageContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_image");
Assert.NotEqual(JsonValueKind.Undefined, imageContent.ValueKind);
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.SendResponsesRequestAsync(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.NotEqual(JsonValueKind.Undefined, itemAddedEvent.ValueKind);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var imageContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_image");
Assert.NotEqual(JsonValueKind.Undefined, imageContent.ValueKind);
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.SendResponsesRequestAsync(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.NotEqual(JsonValueKind.Undefined, itemAddedEvent.ValueKind);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var imageContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_image");
Assert.NotEqual(JsonValueKind.Undefined, imageContent.ValueKind);
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.SendResponsesRequestAsync(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.SendResponsesRequestAsync(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.NotEqual(JsonValueKind.Undefined, itemAddedEvent.ValueKind);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var audioContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_audio");
Assert.NotEqual(JsonValueKind.Undefined, audioContent.ValueKind);
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.SendResponsesRequestAsync(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.SendResponsesRequestAsync(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.SendResponsesRequestAsync(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.NotEqual(JsonValueKind.Undefined, itemAddedEvent.ValueKind);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var fileContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_file");
Assert.NotEqual(JsonValueKind.Undefined, fileContent.ValueKind);
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.SendResponsesRequestAsync(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.SendResponsesRequestAsync(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.NotEqual(JsonValueKind.Undefined, itemAddedEvent.ValueKind);
var content = itemAddedEvent.GetProperty("item").GetProperty("content");
var fileContent = content.EnumerateArray().First(c => c.GetProperty("type").GetString() == "input_file");
Assert.NotEqual(JsonValueKind.Undefined, fileContent.ValueKind);
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.SendResponsesRequestAsync(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.NotEqual(JsonValueKind.Undefined, fileContent.ValueKind);
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.SendResponsesRequestAsync(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.SendResponsesRequestAsync(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,396 @@
// 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.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);
}
/// <summary>
/// Verifies that MapOpenAIResponses without agent parameter works correctly.
/// </summary>
[Fact]
public void MapOpenAIResponses_WithoutAgent_Succeeds()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddAIAgent("test-agent", "Instructions", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
// Act & Assert - Should not throw
app.MapOpenAIResponses();
Assert.NotNull(app);
}
/// <summary>
/// Verifies that MapOpenAIResponses without agent parameter requires AddOpenAIResponses to be called.
/// </summary>
[Fact]
public void MapOpenAIResponses_WithoutAgent_NoServiceRegistered_ThrowsInvalidOperationException()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
using WebApplication app = builder.Build();
// Act & Assert
InvalidOperationException exception = Assert.Throws<InvalidOperationException>(() =>
app.MapOpenAIResponses());
Assert.Contains("IResponsesService is not registered", exception.Message);
Assert.Contains("AddOpenAIResponses()", exception.Message);
}
/// <summary>
/// Verifies that MapOpenAIResponses without agent parameter with custom path works correctly.
/// </summary>
[Fact]
public void MapOpenAIResponses_WithoutAgent_CustomPath_Succeeds()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddAIAgent("test-agent", "Instructions", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
// Act & Assert - Should not throw
app.MapOpenAIResponses(responsesPath: "/custom/path/responses");
Assert.NotNull(app);
}
/// <summary>
/// Verifies that MapOpenAIResponses throws ArgumentNullException for null endpoints when using IHostedAgentBuilder.
/// </summary>
[Fact]
public void MapOpenAIResponses_WithAgentBuilder_NullEndpoints_ThrowsArgumentNullException()
{
// Arrange
AspNetCore.Routing.IEndpointRouteBuilder endpoints = null!;
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
IHostedAgentBuilder agentBuilder = builder.AddAIAgent("agent", "Instructions", chatClientServiceKey: "chat-client");
// Act & Assert
ArgumentNullException exception = Assert.Throws<ArgumentNullException>(() =>
endpoints.MapOpenAIResponses(agentBuilder));
Assert.Equal("endpoints", exception.ParamName);
}
/// <summary>
/// Verifies that MapOpenAIResponses throws ArgumentNullException for null agentBuilder.
/// </summary>
[Fact]
public void MapOpenAIResponses_WithAgentBuilder_NullAgentBuilder_ThrowsArgumentNullException()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
IHostedAgentBuilder agentBuilder = null!;
// Act & Assert
ArgumentNullException exception = Assert.Throws<ArgumentNullException>(() =>
app.MapOpenAIResponses(agentBuilder));
Assert.Equal("agentBuilder", exception.ParamName);
}
/// <summary>
/// Verifies that MapOpenAIResponses with IHostedAgentBuilder correctly resolves and maps the agent.
/// </summary>
[Fact]
public void MapOpenAIResponses_WithAgentBuilder_Succeeds()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
IHostedAgentBuilder agentBuilder = builder.AddAIAgent("agent", "Instructions", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
// Act & Assert - Should not throw
app.MapOpenAIResponses(agentBuilder);
Assert.NotNull(app);
}
/// <summary>
/// Verifies that MapOpenAIResponses with IHostedAgentBuilder and custom path works correctly.
/// </summary>
[Fact]
public void MapOpenAIResponses_WithAgentBuilder_CustomPath_Succeeds()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
IHostedAgentBuilder agentBuilder = builder.AddAIAgent("my-agent", "Instructions", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
// Act & Assert - Should not throw
app.MapOpenAIResponses(agentBuilder, path: "/agents/my-agent/responses");
Assert.NotNull(app);
}
/// <summary>
/// Verifies that multiple agents can be mapped using IHostedAgentBuilder.
/// </summary>
[Fact]
public void MapOpenAIResponses_WithAgentBuilder_MultipleAgents_Succeeds()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
IHostedAgentBuilder agent1Builder = builder.AddAIAgent("agent1", "Instructions1", chatClientServiceKey: "chat-client");
IHostedAgentBuilder agent2Builder = builder.AddAIAgent("agent2", "Instructions2", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
// Act & Assert - Should not throw
app.MapOpenAIResponses(agent1Builder);
app.MapOpenAIResponses(agent2Builder);
Assert.NotNull(app);
}
/// <summary>
/// Verifies that IHostedAgentBuilder overload validates agent name characters.
/// </summary>
[Theory]
[InlineData("agent with spaces")]
[InlineData("agent<script>")]
[InlineData("agent?query")]
[InlineData("agent#fragment")]
public void MapOpenAIResponses_WithAgentBuilder_InvalidAgentNameCharacters_ThrowsArgumentException(string invalidName)
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
IHostedAgentBuilder agentBuilder = builder.AddAIAgent(invalidName, "Instructions", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
// Act & Assert
ArgumentException exception = Assert.Throws<ArgumentException>(() =>
app.MapOpenAIResponses(agentBuilder));
Assert.Contains("invalid for URL routes", exception.Message);
}
/// <summary>
/// Verifies that IHostedAgentBuilder overload accepts valid agent names.
/// </summary>
[Theory]
[InlineData("agent-name")]
[InlineData("agent_name")]
[InlineData("agent.name")]
[InlineData("agent123")]
[InlineData("my-agent_v1.0")]
public void MapOpenAIResponses_WithAgentBuilder_ValidAgentNameCharacters_DoesNotThrow(string validName)
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
IHostedAgentBuilder agentBuilder = builder.AddAIAgent(validName, "Instructions", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
// Act & Assert - Should not throw
app.MapOpenAIResponses(agentBuilder);
Assert.NotNull(app);
}
/// <summary>
/// Verifies that IHostedAgentBuilder overload with custom paths can be specified.
/// </summary>
[Fact]
public void MapOpenAIResponses_WithAgentBuilder_MultipleAgentsWithCustomPaths_Succeeds()
{
// Arrange
WebApplicationBuilder builder = WebApplication.CreateBuilder();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient();
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
IHostedAgentBuilder agent1Builder = builder.AddAIAgent("agent1", "Instructions1", chatClientServiceKey: "chat-client");
IHostedAgentBuilder agent2Builder = builder.AddAIAgent("agent2", "Instructions2", chatClientServiceKey: "chat-client");
builder.AddOpenAIResponses();
using WebApplication app = builder.Build();
// Act & Assert - Should not throw
app.MapOpenAIResponses(agent1Builder, path: "/api/v1/agent1/responses");
app.MapOpenAIResponses(agent2Builder, path: "/api/v1/agent2/responses");
Assert.NotNull(app);
}
}
@@ -0,0 +1,366 @@
// 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 function approval request and response content types.
/// These are DevUI-specific extensions that allow approval workflows for function calls.
/// </summary>
public sealed class FunctionApprovalTests : ConformanceTestBase
{
// Streaming request JSON for OpenAI Responses API
private const string StreamingRequestJson = @"{""model"":""gpt-4o-mini"",""input"":""test"",""stream"":true}";
#region ToolApprovalRequestContent Tests
[Fact]
public async Task FunctionApprovalRequest_GeneratesCorrectEvent_SuccessAsync()
{
// Arrange
const string AgentName = "approval-request-agent";
const string RequestId = "req-123";
const string FunctionName = "get_weather";
const string FunctionId = "call-abc123";
Dictionary<string, object?> arguments = new() { ["location"] = "Seattle", ["unit"] = "celsius" };
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates
FunctionCallContent functionCall = new(FunctionId, FunctionName, arguments);
ToolApprovalRequestContent approvalRequest = new(RequestId, functionCall);
#pragma warning restore MEAI001
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a test agent.", string.Empty, (msg) =>
[approvalRequest]);
// Act
HttpResponseMessage httpResponse = await this.SendResponsesRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
List<JsonElement> events = ParseSseEvents(sseContent);
// Assert
Assert.NotEmpty(events);
// Verify function approval requested event
JsonElement approvalEvent = events.FirstOrDefault(e =>
e.GetProperty("type").GetString() == "response.function_approval.requested");
Assert.True(approvalEvent.ValueKind != JsonValueKind.Undefined, "approval event not found");
Assert.Equal(RequestId, approvalEvent.GetProperty("request_id").GetString());
JsonElement functionCallElement = approvalEvent.GetProperty("function_call");
Assert.Equal(FunctionId, functionCallElement.GetProperty("id").GetString());
Assert.Equal(FunctionName, functionCallElement.GetProperty("name").GetString());
JsonElement argumentsElement = functionCallElement.GetProperty("arguments");
Assert.Equal("Seattle", argumentsElement.GetProperty("location").GetString());
Assert.Equal("celsius", argumentsElement.GetProperty("unit").GetString());
}
[Fact]
public async Task FunctionApprovalRequest_WithComplexArguments_GeneratesCorrectEvent_SuccessAsync()
{
// Arrange
const string AgentName = "approval-request-complex-args-agent";
const string RequestId = "req-456";
const string FunctionName = "calculate";
const string FunctionId = "call-def456";
Dictionary<string, object?> arguments = new()
{
["expression"] = "2+2",
["precision"] = 2,
["options"] = new Dictionary<string, object?> { ["decimal"] = true }
};
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates
FunctionCallContent functionCall = new(FunctionId, FunctionName, arguments);
ToolApprovalRequestContent approvalRequest = new(RequestId, functionCall);
#pragma warning restore MEAI001
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a test agent.", string.Empty, (msg) =>
[approvalRequest]);
// Act
HttpResponseMessage httpResponse = await this.SendResponsesRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
List<JsonElement> events = ParseSseEvents(sseContent);
// Assert
JsonElement approvalEvent = events.FirstOrDefault(e =>
e.GetProperty("type").GetString() == "response.function_approval.requested");
Assert.NotEqual(JsonValueKind.Undefined, approvalEvent.ValueKind);
JsonElement functionCallElement = approvalEvent.GetProperty("function_call");
JsonElement argumentsElement = functionCallElement.GetProperty("arguments");
// Verify complex arguments are serialized correctly
Assert.Equal("2+2", argumentsElement.GetProperty("expression").GetString());
Assert.Equal(2, argumentsElement.GetProperty("precision").GetInt32());
Assert.True(argumentsElement.GetProperty("options").GetProperty("decimal").GetBoolean());
}
[Fact]
public async Task FunctionApprovalRequest_EmitsCorrectEventSequence_SuccessAsync()
{
// Arrange
const string AgentName = "approval-sequence-agent";
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates
FunctionCallContent functionCall = new("call-1", "test_function", new Dictionary<string, object?>());
ToolApprovalRequestContent approvalRequest = new("req-1", functionCall);
#pragma warning restore MEAI001
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a test agent.", string.Empty, (msg) =>
[approvalRequest]);
// Act
HttpResponseMessage httpResponse = await this.SendResponsesRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
List<JsonElement> 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.function_approval.requested", eventTypes);
Assert.Contains("response.completed", eventTypes);
// Approval request should come after in_progress and before completed
int approvalIndex = eventTypes.IndexOf("response.function_approval.requested");
int inProgressIndex = eventTypes.IndexOf("response.in_progress");
int completedIndex = eventTypes.IndexOf("response.completed");
Assert.True(approvalIndex > inProgressIndex);
Assert.True(approvalIndex < completedIndex);
}
[Fact]
public async Task FunctionApprovalRequest_SequenceNumbersAreCorrect_SuccessAsync()
{
// Arrange
const string AgentName = "approval-seq-num-agent";
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates
FunctionCallContent functionCall = new("call-1", "test", new Dictionary<string, object?>());
ToolApprovalRequestContent approvalRequest = new("req-1", functionCall);
#pragma warning restore MEAI001
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a test agent.", string.Empty, (msg) =>
[approvalRequest]);
// Act
HttpResponseMessage httpResponse = await this.SendResponsesRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
List<JsonElement> 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 ToolApprovalResponseContent Tests
[Fact]
public async Task FunctionApprovalResponse_Approved_GeneratesCorrectEvent_SuccessAsync()
{
// Arrange
const string AgentName = "approval-response-approved-agent";
const string RequestId = "req-789";
const string FunctionName = "send_email";
const string FunctionId = "call-ghi789";
Dictionary<string, object?> arguments = new() { ["to"] = "user@example.com", ["subject"] = "Test" };
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates
FunctionCallContent functionCall = new(FunctionId, FunctionName, arguments);
ToolApprovalResponseContent approvalResponse = new(RequestId, approved: true, functionCall);
#pragma warning restore MEAI001
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a test agent.", string.Empty, (msg) =>
[approvalResponse]);
// Act
HttpResponseMessage httpResponse = await this.SendResponsesRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
List<JsonElement> events = ParseSseEvents(sseContent);
// Assert
Assert.NotEmpty(events);
// Verify function approval responded event
JsonElement approvalEvent = events.FirstOrDefault(e =>
e.GetProperty("type").GetString() == "response.function_approval.responded");
Assert.True(approvalEvent.ValueKind != JsonValueKind.Undefined, "approval response event not found");
Assert.Equal(RequestId, approvalEvent.GetProperty("request_id").GetString());
Assert.True(approvalEvent.GetProperty("approved").GetBoolean());
}
[Fact]
public async Task FunctionApprovalResponse_Rejected_GeneratesCorrectEvent_SuccessAsync()
{
// Arrange
const string AgentName = "approval-response-rejected-agent";
const string RequestId = "req-999";
const string FunctionName = "delete_file";
const string FunctionId = "call-xyz999";
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates
FunctionCallContent functionCall = new(FunctionId, FunctionName, new Dictionary<string, object?> { ["path"] = "/important.txt" });
ToolApprovalResponseContent approvalResponse = new(RequestId, approved: false, functionCall);
#pragma warning restore MEAI001
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a test agent.", string.Empty, (msg) =>
[approvalResponse]);
// Act
HttpResponseMessage httpResponse = await this.SendResponsesRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
List<JsonElement> events = ParseSseEvents(sseContent);
// Assert
JsonElement approvalEvent = events.FirstOrDefault(e =>
e.GetProperty("type").GetString() == "response.function_approval.responded");
Assert.NotEqual(JsonValueKind.Undefined, approvalEvent.ValueKind);
Assert.Equal(RequestId, approvalEvent.GetProperty("request_id").GetString());
Assert.False(approvalEvent.GetProperty("approved").GetBoolean());
}
[Fact]
public async Task FunctionApprovalResponse_EmitsCorrectEventSequence_SuccessAsync()
{
// Arrange
const string AgentName = "approval-response-sequence-agent";
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates
FunctionCallContent functionCall = new("call-1", "test_function", new Dictionary<string, object?>());
ToolApprovalResponseContent approvalResponse = new("req-1", approved: true, functionCall);
#pragma warning restore MEAI001
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a test agent.", string.Empty, (msg) =>
[approvalResponse]);
// Act
HttpResponseMessage httpResponse = await this.SendResponsesRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
List<JsonElement> events = ParseSseEvents(sseContent);
// Assert
List<string?> eventTypes = events.ConvertAll(e => e.GetProperty("type").GetString());
Assert.Contains("response.function_approval.responded", eventTypes);
Assert.Contains("response.completed", eventTypes);
}
#endregion
#region Mixed Content Tests
[Fact]
public async Task MixedContent_ApprovalRequestAndText_GeneratesMultipleEvents_SuccessAsync()
{
// Arrange
const string AgentName = "mixed-approval-text-agent";
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates
FunctionCallContent functionCall = new("call-mixed-1", "test", new Dictionary<string, object?>());
ToolApprovalRequestContent approvalRequest = new("req-mixed-1", functionCall);
#pragma warning restore MEAI001
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a test agent.", string.Empty, (msg) =>
[
new TextContent("I need approval for this function:"),
approvalRequest
]);
// Act
HttpResponseMessage httpResponse = await this.SendResponsesRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
List<JsonElement> events = ParseSseEvents(sseContent);
// Assert
List<string?> eventTypes = events.ConvertAll(e => e.GetProperty("type").GetString());
Assert.Contains("response.output_item.added", eventTypes);
Assert.Contains("response.function_approval.requested", eventTypes);
}
[Fact]
public async Task MixedContent_MultipleApprovalRequests_GeneratesMultipleEvents_SuccessAsync()
{
// Arrange
const string AgentName = "multiple-approval-agent";
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates
FunctionCallContent functionCall1 = new("call-multi-1", "function1", new Dictionary<string, object?>());
ToolApprovalRequestContent approvalRequest1 = new("req-multi-1", functionCall1);
FunctionCallContent functionCall2 = new("call-multi-2", "function2", new Dictionary<string, object?>());
ToolApprovalRequestContent approvalRequest2 = new("req-multi-2", functionCall2);
#pragma warning restore MEAI001
HttpClient client = await this.CreateTestServerAsync(AgentName, "You are a test agent.", string.Empty, (msg) =>
[
approvalRequest1,
approvalRequest2
]);
// Act
HttpResponseMessage httpResponse = await this.SendResponsesRequestAsync(client, AgentName, StreamingRequestJson);
string sseContent = await httpResponse.Content.ReadAsStringAsync();
List<JsonElement> events = ParseSseEvents(sseContent);
// Assert
List<JsonElement> approvalEvents = events.Where(e =>
e.GetProperty("type").GetString() == "response.function_approval.requested").ToList();
Assert.Equal(2, approvalEvents.Count);
Assert.Equal("req-multi-1", approvalEvents[0].GetProperty("request_id").GetString());
Assert.Equal("req-multi-2", approvalEvents[1].GetProperty("request_id").GetString());
}
#endregion
#region Helper Methods
private static List<JsonElement> ParseSseEvents(string sseContent)
{
List<JsonElement> events = [];
string[] lines = sseContent.Split('\n');
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i].TrimEnd('\r');
if (line.StartsWith("event: ", StringComparison.Ordinal) && i + 1 < lines.Length)
{
string dataLine = lines[i + 1].TrimEnd('\r');
if (dataLine.StartsWith("data: ", StringComparison.Ordinal))
{
string jsonData = dataLine.Substring("data: ".Length);
JsonDocument doc = JsonDocument.Parse(jsonData);
events.Add(doc.RootElement.Clone());
}
}
}
return events;
}
#endregion
}
@@ -0,0 +1,294 @@
// Copyright (c) Microsoft. All rights reserved.
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Unit tests for IdGenerator.
/// </summary>
public sealed class IdGeneratorTests
{
[Fact]
public void Constructor_WithResponseIdAndConversationId_InitializesCorrectly()
{
// Arrange
const string ResponseId = "resp_test123";
const string ConversationId = "conv_test456";
// Act
var generator = new IdGenerator(ResponseId, ConversationId);
// Assert
Assert.Equal(ResponseId, generator.ResponseId);
Assert.Equal(ConversationId, generator.ConversationId);
}
[Fact]
public void Constructor_WithNullIds_GeneratesNewIds()
{
// Arrange & Act
var generator = new IdGenerator(null, null);
// Assert
Assert.NotNull(generator.ResponseId);
Assert.NotNull(generator.ConversationId);
Assert.StartsWith("resp_", generator.ResponseId);
Assert.StartsWith("conv_", generator.ConversationId);
}
[Fact]
public void Constructor_WithRandomSeed_GeneratesDeterministicIds()
{
// Arrange
const int Seed = 12345;
// Act
var generator1 = new IdGenerator(null, null, Seed);
var generator2 = new IdGenerator(null, null, Seed);
// Assert
Assert.Equal(generator1.ResponseId, generator2.ResponseId);
Assert.Equal(generator1.ConversationId, generator2.ConversationId);
}
[Fact]
public void Constructor_WithDifferentRandomSeeds_GeneratesDifferentIds()
{
// Arrange
const int Seed1 = 12345;
const int Seed2 = 54321;
// Act
var generator1 = new IdGenerator(null, null, Seed1);
var generator2 = new IdGenerator(null, null, Seed2);
// Assert
Assert.NotEqual(generator1.ResponseId, generator2.ResponseId);
Assert.NotEqual(generator1.ConversationId, generator2.ConversationId);
}
[Fact]
public void Generate_WithCategory_IncludesCategory()
{
// Arrange
var generator = new IdGenerator("resp_test", "conv_test");
// Act
string id = generator.Generate("test_category");
// Assert
Assert.NotNull(id);
Assert.StartsWith("test_category_", id);
}
[Fact]
public void Generate_WithoutCategory_UsesDefaultPrefix()
{
// Arrange
var generator = new IdGenerator("resp_test", "conv_test");
// Act
string id = generator.Generate();
// Assert
Assert.NotNull(id);
Assert.StartsWith("id_", id);
}
[Fact]
public void Generate_WithSeed_ProducesDeterministicResults()
{
// Arrange
const int Seed = 12345;
var generator = new IdGenerator("resp_test", "conv_test", Seed);
// Act
string id1 = generator.Generate("test");
string id2 = generator.Generate("test");
string id3 = generator.Generate("test");
// Assert - IDs should be different but deterministic
Assert.NotEqual(id1, id2);
Assert.NotEqual(id2, id3);
Assert.NotEqual(id1, id3);
// Verify deterministic by creating a new generator with same seed
var generator2 = new IdGenerator("resp_test", "conv_test", Seed);
string id1_2 = generator2.Generate("test");
string id2_2 = generator2.Generate("test");
string id3_2 = generator2.Generate("test");
Assert.Equal(id1, id1_2);
Assert.Equal(id2, id2_2);
Assert.Equal(id3, id3_2);
}
[Fact]
public void GenerateFunctionCallId_ReturnsIdWithFuncPrefix()
{
// Arrange
var generator = new IdGenerator("resp_test", "conv_test");
// Act
string id = generator.GenerateFunctionCallId();
// Assert
Assert.NotNull(id);
Assert.StartsWith("func_", id);
}
[Fact]
public void GenerateFunctionOutputId_ReturnsIdWithFuncoutPrefix()
{
// Arrange
var generator = new IdGenerator("resp_test", "conv_test");
// Act
string id = generator.GenerateFunctionOutputId();
// Assert
Assert.NotNull(id);
Assert.StartsWith("funcout_", id);
}
[Fact]
public void GenerateMessageId_ReturnsIdWithMsgPrefix()
{
// Arrange
var generator = new IdGenerator("resp_test", "conv_test");
// Act
string id = generator.GenerateMessageId();
// Assert
Assert.NotNull(id);
Assert.StartsWith("msg_", id);
}
[Fact]
public void GenerateReasoningId_ReturnsIdWithRsPrefix()
{
// Arrange
var generator = new IdGenerator("resp_test", "conv_test");
// Act
string id = generator.GenerateReasoningId();
// Assert
Assert.NotNull(id);
Assert.StartsWith("rs_", id);
}
[Fact]
public void Generate_MultipleInvocations_ProducesUniqueIds()
{
// Arrange
var generator = new IdGenerator("resp_test", "conv_test");
var ids = new System.Collections.Generic.HashSet<string>();
// Act
for (int i = 0; i < 100; i++)
{
string id = generator.Generate("test");
ids.Add(id);
}
// Assert
Assert.Equal(100, ids.Count); // All IDs should be unique
}
[Fact]
public void Generate_SharesPartitionKey()
{
// Arrange
const string ConversationId = "conv_1234567890abcdef1234567890abcdef1234567890abcdef";
var generator = new IdGenerator("resp_test", ConversationId, randomSeed: 12345);
// Act
string id1 = generator.Generate("msg");
string id2 = generator.Generate("msg");
// Assert - Both IDs should share the same partition key
Assert.NotEqual(id1, id2);
Assert.NotNull(id1);
Assert.NotNull(id2);
// Format is: msg_<entropy><partitionKey> where entropy = 32 chars and partitionKey = 16 chars
// Both IDs from the same generator should share the partition key
Assert.StartsWith("msg_", id1);
Assert.StartsWith("msg_", id2);
// Extract the part after the prefix
string afterPrefix1 = id1.Substring(4); // Skip "msg_"
string afterPrefix2 = id2.Substring(4);
// Both should have the same length (32 + 16 = 48)
Assert.Equal(48, afterPrefix1.Length);
Assert.Equal(48, afterPrefix2.Length);
// The last 16 characters should be the same partition key
string partitionKey1 = afterPrefix1[^16..];
string partitionKey2 = afterPrefix2[^16..];
Assert.Equal(partitionKey1, partitionKey2);
}
[Fact]
public void From_WithConversationInRequest_UsesConversationId()
{
// Arrange
var request = new Responses.Models.CreateResponse
{
Model = "test-model",
Input = Responses.Models.ResponseInput.FromText("test"),
Conversation = new Responses.Models.ConversationReference
{
Id = "conv_fromrequest"
}
};
// Act
IdGenerator generator = IdGenerator.From(request);
// Assert
Assert.Equal("conv_fromrequest", generator.ConversationId);
Assert.NotNull(generator.ResponseId);
Assert.StartsWith("resp_", generator.ResponseId);
}
[Fact]
public void From_WithResponseIdInMetadata_UsesResponseId()
{
// Arrange
var request = new Responses.Models.CreateResponse
{
Model = "test-model",
Input = Responses.Models.ResponseInput.FromText("test"),
Metadata = new System.Collections.Generic.Dictionary<string, string>
{
["response_id"] = "resp_metadata123"
}
};
// Act
IdGenerator generator = IdGenerator.From(request);
// Assert
Assert.Equal("resp_metadata123", generator.ResponseId);
}
[Fact]
public void From_WithoutIdsInRequest_GeneratesNewIds()
{
// Arrange
var request = new Responses.Models.CreateResponse
{
Model = "test-model",
Input = Responses.Models.ResponseInput.FromText("test")
};
// Act
IdGenerator generator = IdGenerator.From(request);
// Assert
Assert.NotNull(generator.ResponseId);
Assert.NotNull(generator.ConversationId);
Assert.StartsWith("resp_", generator.ResponseId);
Assert.StartsWith("conv_", generator.ConversationId);
}
}
@@ -0,0 +1,359 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Agents.AI.Hosting.OpenAI.Conversations;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Unit tests for InMemoryAgentConversationIndex implementation.
/// </summary>
public sealed class InMemoryAgentConversationIndexTests
{
[Fact]
public async Task AddConversationAsync_SuccessAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
const string AgentId = "agent_test123";
const string ConversationId = "conv_test123";
// Act
await index.AddConversationAsync(AgentId, ConversationId);
// Assert
var response = await index.GetConversationIdsAsync(AgentId);
Assert.Single(response.Data);
Assert.Contains(ConversationId, response.Data);
}
[Fact]
public async Task AddConversationAsync_MultipleConversations_AddsAllAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
const string AgentId = "agent_multi";
const string ConversationId1 = "conv_001";
const string ConversationId2 = "conv_002";
const string ConversationId3 = "conv_003";
// Act
await index.AddConversationAsync(AgentId, ConversationId1);
await index.AddConversationAsync(AgentId, ConversationId2);
await index.AddConversationAsync(AgentId, ConversationId3);
// Assert
var response = await index.GetConversationIdsAsync(AgentId);
Assert.Equal(3, response.Data.Count);
Assert.Contains(ConversationId1, response.Data);
Assert.Contains(ConversationId2, response.Data);
Assert.Contains(ConversationId3, response.Data);
}
[Fact]
public async Task AddConversationAsync_NullAgentId_ThrowsArgumentExceptionAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act & Assert
await Assert.ThrowsAsync<ArgumentNullException>(
() => index.AddConversationAsync(null!, "conv_test"));
}
[Fact]
public async Task AddConversationAsync_EmptyAgentId_ThrowsArgumentExceptionAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act & Assert
await Assert.ThrowsAsync<ArgumentException>(
() => index.AddConversationAsync(string.Empty, "conv_test"));
}
[Fact]
public async Task AddConversationAsync_NullConversationId_ThrowsArgumentExceptionAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act & Assert
await Assert.ThrowsAsync<ArgumentNullException>(
() => index.AddConversationAsync("agent_test", null!));
}
[Fact]
public async Task AddConversationAsync_EmptyConversationId_ThrowsArgumentExceptionAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act & Assert
await Assert.ThrowsAsync<ArgumentException>(
() => index.AddConversationAsync("agent_test", string.Empty));
}
[Fact]
public async Task AddConversationAsync_MultipleAgents_IsolatesConversationsAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
const string Agent1 = "agent_001";
const string Agent2 = "agent_002";
const string Conv1 = "conv_001";
const string Conv2 = "conv_002";
// Act
await index.AddConversationAsync(Agent1, Conv1);
await index.AddConversationAsync(Agent2, Conv2);
// Assert
var agent1Response = await index.GetConversationIdsAsync(Agent1);
var agent2Response = await index.GetConversationIdsAsync(Agent2);
Assert.Single(agent1Response.Data);
Assert.Contains(Conv1, agent1Response.Data);
Assert.DoesNotContain(Conv2, agent1Response.Data);
Assert.Single(agent2Response.Data);
Assert.Contains(Conv2, agent2Response.Data);
Assert.DoesNotContain(Conv1, agent2Response.Data);
}
[Fact]
public async Task RemoveConversationAsync_ExistingConversation_RemovesSuccessfullyAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
const string AgentId = "agent_remove";
const string ConversationId = "conv_remove123";
await index.AddConversationAsync(AgentId, ConversationId);
// Act
await index.RemoveConversationAsync(AgentId, ConversationId);
// Assert
var response = await index.GetConversationIdsAsync(AgentId);
Assert.Empty(response.Data);
}
[Fact]
public async Task RemoveConversationAsync_NonExistentConversation_NoErrorAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
const string AgentId = "agent_noremove";
// Act - Should not throw
await index.RemoveConversationAsync(AgentId, "conv_nonexistent");
// Assert
var response = await index.GetConversationIdsAsync(AgentId);
Assert.Empty(response.Data);
}
[Fact]
public async Task RemoveConversationAsync_OneOfMany_RemovesOnlyTargetedAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
const string AgentId = "agent_partial";
const string Conv1 = "conv_001";
const string Conv2 = "conv_002";
const string Conv3 = "conv_003";
await index.AddConversationAsync(AgentId, Conv1);
await index.AddConversationAsync(AgentId, Conv2);
await index.AddConversationAsync(AgentId, Conv3);
// Act
await index.RemoveConversationAsync(AgentId, Conv2);
// Assert
var response = await index.GetConversationIdsAsync(AgentId);
Assert.Equal(2, response.Data.Count);
Assert.Contains(Conv1, response.Data);
Assert.DoesNotContain(Conv2, response.Data);
Assert.Contains(Conv3, response.Data);
}
[Fact]
public async Task RemoveConversationAsync_NullAgentId_ThrowsArgumentExceptionAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act & Assert
await Assert.ThrowsAsync<ArgumentNullException>(
() => index.RemoveConversationAsync(null!, "conv_test"));
}
[Fact]
public async Task RemoveConversationAsync_EmptyAgentId_ThrowsArgumentExceptionAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act & Assert
await Assert.ThrowsAsync<ArgumentException>(
() => index.RemoveConversationAsync(string.Empty, "conv_test"));
}
[Fact]
public async Task RemoveConversationAsync_NullConversationId_ThrowsArgumentExceptionAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act & Assert
await Assert.ThrowsAsync<ArgumentNullException>(
() => index.RemoveConversationAsync("agent_test", null!));
}
[Fact]
public async Task RemoveConversationAsync_EmptyConversationId_ThrowsArgumentExceptionAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act & Assert
await Assert.ThrowsAsync<ArgumentException>(
() => index.RemoveConversationAsync("agent_test", string.Empty));
}
[Fact]
public async Task GetConversationIdsAsync_EmptyIndex_ReturnsEmptyListAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act
var response = await index.GetConversationIdsAsync("agent_empty");
// Assert
Assert.NotNull(response);
Assert.Empty(response.Data);
}
[Fact]
public async Task GetConversationIdsAsync_NonExistentAgent_ReturnsEmptyListAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
await index.AddConversationAsync("agent_other", "conv_001");
// Act
var response = await index.GetConversationIdsAsync("agent_nonexistent");
// Assert
Assert.NotNull(response);
Assert.Empty(response.Data);
}
[Fact]
public async Task GetConversationIdsAsync_NullAgentId_ThrowsArgumentExceptionAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act & Assert
await Assert.ThrowsAsync<ArgumentNullException>(
async () => await index.GetConversationIdsAsync(null!));
}
[Fact]
public async Task GetConversationIdsAsync_EmptyAgentId_ThrowsArgumentExceptionAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
// Act & Assert
await Assert.ThrowsAsync<ArgumentException>(
() => index.GetConversationIdsAsync(string.Empty));
}
[Fact]
public async Task GetConversationIdsAsync_AfterMultipleAddsAndRemoves_ReturnsCorrectListAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
const string AgentId = "agent_complex";
await index.AddConversationAsync(AgentId, "conv_001");
await index.AddConversationAsync(AgentId, "conv_002");
await index.AddConversationAsync(AgentId, "conv_003");
await index.RemoveConversationAsync(AgentId, "conv_002");
await index.AddConversationAsync(AgentId, "conv_004");
await index.RemoveConversationAsync(AgentId, "conv_001");
// Act
var response = await index.GetConversationIdsAsync(AgentId);
// Assert
Assert.Equal(2, response.Data.Count);
Assert.Contains("conv_003", response.Data);
Assert.Contains("conv_004", response.Data);
Assert.DoesNotContain("conv_001", response.Data);
Assert.DoesNotContain("conv_002", response.Data);
}
[Fact]
public async Task ConcurrentOperations_ThreadSafeAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
const string AgentId = "agent_concurrent";
const int OperationCount = 100;
// Act - Add conversations concurrently
var addTasks = new List<Task>();
for (int i = 0; i < OperationCount; i++)
{
int index_local = i;
addTasks.Add(Task.Run(async () => await index.AddConversationAsync(AgentId, $"conv_{index_local:D3}")));
}
await Task.WhenAll(addTasks);
// Assert
var response = await index.GetConversationIdsAsync(AgentId);
Assert.Equal(OperationCount, response.Data.Count);
// Act - Remove half of them concurrently
var removeTasks = new List<Task>();
for (int i = 0; i < OperationCount / 2; i++)
{
int index_local = i;
removeTasks.Add(Task.Run(async () => await index.RemoveConversationAsync(AgentId, $"conv_{index_local:D3}")));
}
await Task.WhenAll(removeTasks);
// Assert
response = await index.GetConversationIdsAsync(AgentId);
Assert.Equal(OperationCount / 2, response.Data.Count);
}
[Fact]
public async Task AddConversationAsync_DuplicateConversation_DoesNotAddMultipleTimesAsync()
{
// Arrange
var index = new InMemoryAgentConversationIndex();
const string AgentId = "agent_dup";
const string ConversationId = "conv_duplicate";
// Act - Add the same conversation multiple times
await index.AddConversationAsync(AgentId, ConversationId);
await index.AddConversationAsync(AgentId, ConversationId);
await index.AddConversationAsync(AgentId, ConversationId);
// Assert - HashSet prevents duplicates
var response = await index.GetConversationIdsAsync(AgentId);
Assert.Single(response.Data);
Assert.Contains(ConversationId, response.Data);
}
}
@@ -0,0 +1,645 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Agents.AI.Hosting.OpenAI.Conversations;
using Microsoft.Agents.AI.Hosting.OpenAI.Conversations.Models;
using Microsoft.Agents.AI.Hosting.OpenAI.Models;
using Microsoft.Agents.AI.Hosting.OpenAI.Responses.Models;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Unit tests for InMemoryConversationStorage implementation.
/// </summary>
public sealed class InMemoryConversationStorageTests
{
[Fact]
public async Task CreateConversationAsync_SuccessAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_test123",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = new Dictionary<string, string> { ["key"] = "value" }
};
// Act
Conversation result = await storage.CreateConversationAsync(conversation);
// Assert
Assert.NotNull(result);
Assert.Equal(conversation.Id, result.Id);
Assert.Equal(conversation.CreatedAt, result.CreatedAt);
Assert.NotNull(result.Metadata);
Assert.Equal("value", result.Metadata["key"]);
}
[Fact]
public async Task CreateConversationAsync_DuplicateId_ThrowsInvalidOperationExceptionAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_duplicate",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
// Act & Assert
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
() => storage.CreateConversationAsync(conversation));
Assert.Contains("already exists", exception.Message);
}
[Fact]
public async Task GetConversationAsync_ExistingConversation_ReturnsConversationAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_get123",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
// Act
Conversation? result = await storage.GetConversationAsync("conv_get123");
// Assert
Assert.NotNull(result);
Assert.Equal(conversation.Id, result.Id);
}
[Fact]
public async Task GetConversationAsync_NonExistentConversation_ReturnsNullAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
// Act
Conversation? result = await storage.GetConversationAsync("conv_nonexistent");
// Assert
Assert.Null(result);
}
[Fact]
public async Task UpdateConversationAsync_ExistingConversation_UpdatesSuccessfullyAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_update123",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = new Dictionary<string, string> { ["original"] = "value" }
};
await storage.CreateConversationAsync(conversation);
var updatedConversation = new Conversation
{
Id = "conv_update123",
CreatedAt = conversation.CreatedAt,
Metadata = new Dictionary<string, string> { ["updated"] = "newvalue" }
};
// Act
Conversation? result = await storage.UpdateConversationAsync(updatedConversation);
// Assert
Assert.NotNull(result);
Assert.Equal(updatedConversation.Id, result.Id);
Assert.NotNull(result.Metadata);
Assert.Equal("newvalue", result.Metadata["updated"]);
// Verify the update persisted
Conversation? retrieved = await storage.GetConversationAsync("conv_update123");
Assert.NotNull(retrieved);
Assert.Equal("newvalue", retrieved.Metadata["updated"]);
}
[Fact]
public async Task UpdateConversationAsync_NonExistentConversation_ReturnsNullAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_nonexistent",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
// Act
Conversation? result = await storage.UpdateConversationAsync(conversation);
// Assert
Assert.Null(result);
}
[Fact]
public async Task DeleteConversationAsync_ExistingConversation_ReturnsTrueAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_delete123",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
// Act
bool result = await storage.DeleteConversationAsync("conv_delete123");
// Assert
Assert.True(result);
// Verify deletion
Conversation? retrieved = await storage.GetConversationAsync("conv_delete123");
Assert.Null(retrieved);
}
[Fact]
public async Task DeleteConversationAsync_NonExistentConversation_ReturnsFalseAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
// Act
bool result = await storage.DeleteConversationAsync("conv_nonexistent");
// Assert
Assert.False(result);
}
[Fact]
public async Task AddItemsAsync_SuccessAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_items123",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
var item = new ResponsesUserMessageItemResource
{
Id = "msg_test123",
Content = [new ItemContentInputText { Text = "Hello" }]
};
// Act
await storage.AddItemsAsync("conv_items123", [item]);
// Assert
ItemResource? result = await storage.GetItemAsync("conv_items123", item.Id);
Assert.NotNull(result);
Assert.Equal(item.Id, result.Id);
}
[Fact]
public async Task AddItemsAsync_NonExistentConversation_ThrowsInvalidOperationExceptionAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var item = new ResponsesUserMessageItemResource
{
Id = "msg_test123",
Content = [new ItemContentInputText { Text = "Hello" }]
};
// Act & Assert
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
() => storage.AddItemsAsync("conv_nonexistent", [item]));
Assert.Contains("not found", exception.Message);
}
[Fact]
public async Task AddItemsAsync_DuplicateItemId_ThrowsInvalidOperationExceptionAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_dup_items",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
var item = new ResponsesUserMessageItemResource
{
Id = "msg_duplicate",
Content = [new ItemContentInputText { Text = "Hello" }]
};
await storage.AddItemsAsync("conv_dup_items", [item]);
// Act & Assert
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
() => storage.AddItemsAsync("conv_dup_items", [item]));
Assert.Contains("already exists", exception.Message);
}
[Fact]
public async Task GetItemAsync_ExistingItem_ReturnsItemAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_getitem",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
var item = new ResponsesUserMessageItemResource
{
Id = "msg_getitem123",
Content = [new ItemContentInputText { Text = "Test message" }]
};
await storage.AddItemsAsync("conv_getitem", [item]);
// Act
ItemResource? result = await storage.GetItemAsync("conv_getitem", "msg_getitem123");
// Assert
Assert.NotNull(result);
Assert.Equal(item.Id, result.Id);
var userMessage = Assert.IsType<ResponsesUserMessageItemResource>(result);
Assert.NotEmpty(userMessage.Content);
}
[Fact]
public async Task GetItemAsync_NonExistentItem_ReturnsNullAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_noitem",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
// Act
ItemResource? result = await storage.GetItemAsync("conv_noitem", "msg_nonexistent");
// Assert
Assert.Null(result);
}
[Fact]
public async Task GetItemAsync_NonExistentConversation_ReturnsNullAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
// Act
ItemResource? result = await storage.GetItemAsync("conv_nonexistent", "msg_any");
// Assert
Assert.Null(result);
}
[Fact]
public async Task ListItemsAsync_DefaultParameters_ReturnsDescendingOrderAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_list",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
// Add items in order
var item1 = new ResponsesUserMessageItemResource
{
Id = "msg_001",
Content = [new ItemContentInputText { Text = "First" }]
};
var item2 = new ResponsesUserMessageItemResource
{
Id = "msg_002",
Content = [new ItemContentInputText { Text = "Second" }]
};
var item3 = new ResponsesUserMessageItemResource
{
Id = "msg_003",
Content = [new ItemContentInputText { Text = "Third" }]
};
await storage.AddItemsAsync("conv_list", [item1]);
await storage.AddItemsAsync("conv_list", [item2]);
await storage.AddItemsAsync("conv_list", [item3]);
// Act
ListResponse<ItemResource> result = await storage.ListItemsAsync("conv_list");
// Assert
Assert.NotNull(result);
Assert.NotNull(result.Data);
Assert.Equal(3, result.Data.Count);
Assert.Equal("msg_003", result.Data[0].Id); // Descending order
Assert.Equal("msg_002", result.Data[1].Id);
Assert.Equal("msg_001", result.Data[2].Id);
Assert.Equal("msg_003", result.FirstId);
Assert.Equal("msg_001", result.LastId);
Assert.False(result.HasMore);
}
[Fact]
public async Task ListItemsAsync_AscendingOrder_ReturnsCorrectOrderAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_asc",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
var item1 = new ResponsesUserMessageItemResource
{
Id = "msg_001",
Content = [new ItemContentInputText { Text = "First" }]
};
var item2 = new ResponsesUserMessageItemResource
{
Id = "msg_002",
Content = [new ItemContentInputText { Text = "Second" }]
};
await storage.AddItemsAsync("conv_asc", [item1]);
await storage.AddItemsAsync("conv_asc", [item2]);
// Act
ListResponse<ItemResource> result = await storage.ListItemsAsync("conv_asc", order: SortOrder.Ascending);
// Assert
Assert.Equal(2, result.Data.Count);
Assert.Equal("msg_001", result.Data[0].Id); // Ascending order
Assert.Equal("msg_002", result.Data[1].Id);
}
[Fact]
public async Task ListItemsAsync_WithLimit_ReturnsCorrectPageSizeAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_limit",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
for (int i = 1; i <= 10; i++)
{
var item = new ResponsesUserMessageItemResource
{
Id = $"msg_{i:D3}",
Content = [new ItemContentInputText { Text = $"Message {i}" }]
};
await storage.AddItemsAsync("conv_limit", [item]);
}
// Act
ListResponse<ItemResource> result = await storage.ListItemsAsync("conv_limit", limit: 5);
// Assert
Assert.Equal(5, result.Data.Count);
Assert.True(result.HasMore);
Assert.Equal("msg_010", result.FirstId); // First in descending order
Assert.Equal("msg_006", result.LastId);
}
[Fact]
public async Task ListItemsAsync_WithAfter_ReturnsNextPageAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_after",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
for (int i = 1; i <= 10; i++)
{
var item = new ResponsesUserMessageItemResource
{
Id = $"msg_{i:D3}",
Content = [new ItemContentInputText { Text = $"Message {i}" }]
};
await storage.AddItemsAsync("conv_after", [item]);
}
// Act
ListResponse<ItemResource> result = await storage.ListItemsAsync("conv_after", limit: 5, after: "msg_006");
// Assert
Assert.Equal(5, result.Data.Count);
Assert.Equal("msg_005", result.Data[0].Id); // Next items after msg_006 in descending order
Assert.Equal("msg_001", result.Data[4].Id);
Assert.False(result.HasMore); // No more items after this page
}
[Fact]
public async Task ListItemsAsync_LimitClamping_ClampsToValidRangeAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_clamp",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
for (int i = 1; i <= 5; i++)
{
var item = new ResponsesUserMessageItemResource
{
Id = $"msg_{i:D3}",
Content = [new ItemContentInputText { Text = $"Message {i}" }]
};
await storage.AddItemsAsync("conv_clamp", [item]);
}
// Act - Test upper bound
ListResponse<ItemResource> result1 = await storage.ListItemsAsync("conv_clamp", limit: 200);
// Act - Test lower bound
ListResponse<ItemResource> result2 = await storage.ListItemsAsync("conv_clamp", limit: 0);
// Assert
Assert.Equal(5, result1.Data.Count); // Should return all items (clamped to 100 max, but we only have 5)
Assert.NotNull(result2.Data);
Assert.NotEmpty(result2.Data);
Assert.Single(result2.Data); // Should return at least 1 item (clamped to 1 min)
}
[Fact]
public async Task ListItemsAsync_EmptyConversation_ReturnsEmptyListAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_empty",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
// Act
ListResponse<ItemResource> result = await storage.ListItemsAsync("conv_empty");
// Assert
Assert.NotNull(result);
Assert.NotNull(result.Data);
Assert.Empty(result.Data);
Assert.Null(result.FirstId);
Assert.Null(result.LastId);
Assert.False(result.HasMore);
}
[Fact]
public async Task ListItemsAsync_NonExistentConversation_ThrowsInvalidOperationExceptionAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
// Act & Assert
var exception = await Assert.ThrowsAsync<InvalidOperationException>(
() => storage.ListItemsAsync("conv_nonexistent"));
Assert.Contains("not found", exception.Message);
}
[Fact]
public async Task DeleteItemAsync_ExistingItem_ReturnsTrueAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_delitem",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
var item = new ResponsesUserMessageItemResource
{
Id = "msg_delete",
Content = [new ItemContentInputText { Text = "Delete me" }]
};
await storage.AddItemsAsync("conv_delitem", [item]);
// Act
bool result = await storage.DeleteItemAsync("conv_delitem", "msg_delete");
// Assert
Assert.True(result);
// Verify deletion
ItemResource? retrieved = await storage.GetItemAsync("conv_delitem", "msg_delete");
Assert.Null(retrieved);
}
[Fact]
public async Task DeleteItemAsync_NonExistentItem_ReturnsFalseAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_delnoitem",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
// Act
bool result = await storage.DeleteItemAsync("conv_delnoitem", "msg_nonexistent");
// Assert
Assert.False(result);
}
[Fact]
public async Task DeleteItemAsync_NonExistentConversation_ReturnsFalseAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
// Act
bool result = await storage.DeleteItemAsync("conv_nonexistent", "msg_any");
// Assert
Assert.False(result);
}
[Fact]
public async Task ConcurrentOperations_ThreadSafeAsync()
{
// Arrange
var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_concurrent",
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
Metadata = []
};
await storage.CreateConversationAsync(conversation);
// Act - Add items concurrently
var tasks = new List<Task>();
for (int i = 0; i < 100; i++)
{
int index = i;
tasks.Add(Task.Run(async () =>
{
var item = new ResponsesUserMessageItemResource
{
Id = $"msg_{index:D3}",
Content = [new ItemContentInputText { Text = $"Message {index}" }]
};
await storage.AddItemsAsync("conv_concurrent", [item]);
}));
}
await Task.WhenAll(tasks);
// Assert
ListResponse<ItemResource> result = await storage.ListItemsAsync("conv_concurrent", limit: 100);
Assert.NotNull(result.Data);
Assert.NotEmpty(result.Data);
Assert.Equal(100, result.Data.Count);
}
}
@@ -0,0 +1,102 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Agents.AI.Hosting.OpenAI.Conversations;
using Microsoft.Agents.AI.Hosting.OpenAI.Conversations.Models;
using Microsoft.Agents.AI.Hosting.OpenAI.Responses;
using Microsoft.Agents.AI.Hosting.OpenAI.Responses.Models;
using Microsoft.Extensions.AI;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Unit tests for <see cref="InMemoryResponsesService"/> request validation.
/// </summary>
public sealed class InMemoryResponsesServiceTests
{
[Fact]
public async Task ValidateRequestAsync_NonexistentConversation_ReturnsNotFoundErrorAsync()
{
// Arrange
using var storage = new InMemoryConversationStorage();
using var service = new InMemoryResponsesService(
new StubResponseExecutor(), new InMemoryStorageOptions(), storage);
var request = new CreateResponse
{
Input = ResponseInput.FromText("hello"),
Conversation = ConversationReference.FromId("conv_does_not_exist")
};
// Act
ResponseError? error = await service.ValidateRequestAsync(request);
// Assert
Assert.NotNull(error);
Assert.Equal("conversation_not_found", error.Code);
}
[Fact]
public async Task ValidateRequestAsync_ExistingConversation_ReturnsNullAsync()
{
// Arrange
using var storage = new InMemoryConversationStorage();
var conversation = new Conversation
{
Id = "conv_" + Guid.NewGuid().ToString("N"),
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
};
await storage.CreateConversationAsync(conversation);
using var service = new InMemoryResponsesService(
new StubResponseExecutor(), new InMemoryStorageOptions(), storage);
var request = new CreateResponse
{
Input = ResponseInput.FromText("hello"),
Conversation = ConversationReference.FromId(conversation.Id)
};
// Act
ResponseError? error = await service.ValidateRequestAsync(request);
// Assert
Assert.Null(error);
}
[Fact]
public async Task ValidateRequestAsync_ConversationSuppliedButNoStorage_ReturnsNullAsync()
{
// Arrange - without a conversation store there is no existence to verify.
using var service = new InMemoryResponsesService(
new StubResponseExecutor(), new InMemoryStorageOptions());
var request = new CreateResponse
{
Input = ResponseInput.FromText("hello"),
Conversation = ConversationReference.FromId("conv_does_not_exist")
};
// Act
ResponseError? error = await service.ValidateRequestAsync(request);
// Assert
Assert.Null(error);
}
private sealed class StubResponseExecutor : IResponseExecutor
{
public ValueTask<ResponseError?> ValidateRequestAsync(CreateResponse request, CancellationToken cancellationToken = default)
=> ValueTask.FromResult<ResponseError?>(null);
public async IAsyncEnumerable<StreamingResponseEvent> ExecuteAsync(
AgentInvocationContext context,
CreateResponse request,
IReadOnlyList<ChatMessage>? conversationHistory = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await Task.CompletedTask.ConfigureAwait(false);
yield break;
}
}
}
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>$(TargetFrameworksCore)</TargetFrameworks>
<IsPackable>false</IsPackable>
<NoWarn>$(NoWarn);OPENAI001;CA1812</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.TestHost" />
<PackageReference Include="OpenAI" />
</ItemGroup>
<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'net10.0'))">
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
<PackageReference Include="System.Linq.AsyncEnumerable" />
</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,625 @@
// Copyright (c) Microsoft. All rights reserved.
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>
/// Conformance tests for OpenAI Chat Completions API implementation behavior.
/// Tests use real API traces to ensure our implementation produces responses
/// that match OpenAI's wire format when processing actual requests through the server.
/// </summary>
public sealed class OpenAIChatCompletionsConformanceTests : ConformanceTestBase
{
[Fact]
public async Task BasicRequestResponseAsync()
{
// Arrange
string requestJson = LoadChatCompletionsTraceFile("basic/request.json");
using var expectedResponseDoc = LoadChatCompletionsTraceDocument("basic/response.json");
var expectedResponse = expectedResponseDoc.RootElement;
// Get the expected response text from the trace to use as mock response
string expectedText = expectedResponse.GetProperty("choices")[0]
.GetProperty("message")
.GetProperty("content").GetString()!;
HttpClient client = await this.CreateTestServerAsync("basic-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendChatCompletionRequestAsync(client, "basic-agent", requestJson);
using var responseDoc = await ParseResponseAsync(httpResponse);
var response = responseDoc.RootElement;
// Parse the request to verify it was sent correctly
using var requestDoc = JsonDocument.Parse(requestJson);
var request = requestDoc.RootElement;
// Assert - Verify request was properly formatted (structure check)
AssertJsonPropertyEquals(request, "model", "gpt-4o-mini");
AssertJsonPropertyExists(request, "messages");
AssertJsonPropertyEquals(request, "max_completion_tokens", 100);
AssertJsonPropertyEquals(request, "temperature", 1.0f);
AssertJsonPropertyEquals(request, "top_p", 1.0f);
var messages = request.GetProperty("messages");
Assert.Equal(JsonValueKind.Array, messages.ValueKind);
Assert.True(messages.GetArrayLength() > 0, "Messages array should not be empty");
var firstMessage = messages[0];
AssertJsonPropertyEquals(firstMessage, "role", "user");
AssertJsonPropertyEquals(firstMessage, "content", "Hello, how are you?");
// Assert - Response metadata (IDs and timestamps are dynamic, just verify structure)
AssertJsonPropertyExists(response, "id");
AssertJsonPropertyEquals(response, "object", "chat.completion");
AssertJsonPropertyExists(response, "created");
AssertJsonPropertyExists(response, "model");
var id = response.GetProperty("id").GetString();
Assert.NotNull(id);
Assert.StartsWith("chatcmpl-", id);
var createdAt = response.GetProperty("created").GetInt64();
Assert.True(createdAt > 0, "created should be a positive unix timestamp");
var model = response.GetProperty("model").GetString();
Assert.NotNull(model);
Assert.StartsWith("gpt-4o-mini", model);
// Assert - Choices array structure
AssertJsonPropertyExists(response, "choices");
var choices = response.GetProperty("choices");
Assert.Equal(JsonValueKind.Array, choices.ValueKind);
Assert.True(choices.GetArrayLength() > 0, "Choices array should not be empty");
// Assert - Choice structure
var firstChoice = choices[0];
AssertJsonPropertyExists(firstChoice, "index");
AssertJsonPropertyEquals(firstChoice, "index", 0);
AssertJsonPropertyExists(firstChoice, "message");
AssertJsonPropertyExists(firstChoice, "finish_reason");
var finishReason = firstChoice.GetProperty("finish_reason").GetString();
Assert.NotNull(finishReason);
Assert.Contains(finishReason, collection: ["stop", "length", "content_filter", "tool_calls"]);
// Assert - Message structure
var message = firstChoice.GetProperty("message");
AssertJsonPropertyExists(message, "role");
AssertJsonPropertyEquals(message, "role", "assistant");
AssertJsonPropertyExists(message, "content");
var content = message.GetProperty("content").GetString();
Assert.NotNull(content);
Assert.Equal(expectedText, content); // Verify actual content matches expected
// Assert - Usage statistics
AssertJsonPropertyExists(response, "usage");
var usage = response.GetProperty("usage");
AssertJsonPropertyExists(usage, "prompt_tokens");
AssertJsonPropertyExists(usage, "completion_tokens");
AssertJsonPropertyExists(usage, "total_tokens");
var promptTokens = usage.GetProperty("prompt_tokens").GetInt32();
var completionTokens = usage.GetProperty("completion_tokens").GetInt32();
var totalTokens = usage.GetProperty("total_tokens").GetInt32();
Assert.True(promptTokens > 0, "prompt_tokens should be positive");
Assert.True(completionTokens > 0, "completion_tokens should be positive");
Assert.Equal(promptTokens + completionTokens, totalTokens);
// Assert - Usage details
AssertJsonPropertyExists(usage, "prompt_tokens_details");
var promptDetails = usage.GetProperty("prompt_tokens_details");
AssertJsonPropertyExists(promptDetails, "cached_tokens");
AssertJsonPropertyExists(promptDetails, "audio_tokens");
Assert.True(promptDetails.GetProperty("cached_tokens").GetInt32() >= 0);
Assert.True(promptDetails.GetProperty("audio_tokens").GetInt32() >= 0);
AssertJsonPropertyExists(usage, "completion_tokens_details");
var completionDetails = usage.GetProperty("completion_tokens_details");
AssertJsonPropertyExists(completionDetails, "reasoning_tokens");
AssertJsonPropertyExists(completionDetails, "audio_tokens");
AssertJsonPropertyExists(completionDetails, "accepted_prediction_tokens");
AssertJsonPropertyExists(completionDetails, "rejected_prediction_tokens");
Assert.True(completionDetails.GetProperty("reasoning_tokens").GetInt32() >= 0);
Assert.True(completionDetails.GetProperty("audio_tokens").GetInt32() >= 0);
Assert.True(completionDetails.GetProperty("accepted_prediction_tokens").GetInt32() >= 0);
Assert.True(completionDetails.GetProperty("rejected_prediction_tokens").GetInt32() >= 0);
// Assert - Optional fields
AssertJsonPropertyExists(response, "service_tier");
var serviceTier = response.GetProperty("service_tier").GetString();
Assert.NotNull(serviceTier);
Assert.True(serviceTier is "default" or "auto", $"service_tier should be 'default' or 'auto', got '{serviceTier}'");
}
[Fact]
public async Task StreamingRequestResponseAsync()
{
// Arrange
string requestJson = LoadChatCompletionsTraceFile("streaming/request.json");
string expectedResponseSse = LoadChatCompletionsTraceFile("streaming/response.txt");
// Extract expected text from SSE chunks
var expectedChunks = ParseChatCompletionChunksFromSse(expectedResponseSse);
string expectedText = string.Concat(expectedChunks
.Where(c => c.GetProperty("choices")[0].GetProperty("delta").TryGetProperty("content", out var content))
.Select(c => c.GetProperty("choices")[0].GetProperty("delta").GetProperty("content").GetString()));
HttpClient client = await this.CreateTestServerAsync("streaming-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendChatCompletionRequestAsync(client, "streaming-agent", requestJson);
// Assert - Response should be SSE format
Assert.Equal("text/event-stream", httpResponse.Content.Headers.ContentType?.MediaType);
string responseSse = await httpResponse.Content.ReadAsStringAsync();
var chunks = ParseChatCompletionChunksFromSse(responseSse);
// Parse the request
using var requestDoc = JsonDocument.Parse(requestJson);
var request = requestDoc.RootElement;
// Assert - Request has stream flag
AssertJsonPropertyEquals(request, "stream", true);
// Assert - Response has valid chunks
Assert.NotEmpty(chunks);
// Assert - All chunks have same ID
string? firstId = null;
foreach (var chunk in chunks)
{
AssertJsonPropertyExists(chunk, "id");
AssertJsonPropertyEquals(chunk, "object", "chat.completion.chunk");
AssertJsonPropertyExists(chunk, "created");
AssertJsonPropertyExists(chunk, "model");
AssertJsonPropertyExists(chunk, "choices");
string chunkId = chunk.GetProperty("id").GetString()!;
Assert.StartsWith("chatcmpl-", chunkId);
firstId ??= chunkId;
Assert.Equal(firstId, chunkId);
}
// Assert - First chunk has role
var firstChunk = chunks[0];
var firstChoice = firstChunk.GetProperty("choices")[0];
AssertJsonPropertyExists(firstChoice, "delta");
var firstDelta = firstChoice.GetProperty("delta");
if (firstDelta.TryGetProperty("role", out var role))
{
Assert.Equal("assistant", role.GetString());
}
// Assert - Content chunks have delta content
var contentChunks = chunks.Where(c =>
c.GetProperty("choices")[0].GetProperty("delta").TryGetProperty("content", out _)).ToList();
Assert.NotEmpty(contentChunks);
// Assert - Last chunk has finish_reason
var lastChunk = chunks[^1];
var lastChoice = lastChunk.GetProperty("choices")[0];
if (lastChoice.TryGetProperty("finish_reason", out var finishReason) && finishReason.ValueKind != JsonValueKind.Null)
{
string reason = finishReason.GetString()!;
Assert.Contains(reason, collection: ["stop", "length", "tool_calls", "content_filter"]);
}
// Assert - Last chunk may have usage
if (lastChunk.TryGetProperty("usage", out var usage))
{
AssertJsonPropertyExists(usage, "prompt_tokens");
AssertJsonPropertyExists(usage, "completion_tokens");
AssertJsonPropertyExists(usage, "total_tokens");
}
// Assert - Accumulated content matches expected
string accumulatedText = string.Concat(contentChunks
.Select(c => c.GetProperty("choices")[0].GetProperty("delta").GetProperty("content").GetString()));
Assert.NotEmpty(accumulatedText);
}
[Fact]
public async Task FunctionCallingRequestResponseAsync()
{
// Arrange
string requestJson = LoadChatCompletionsTraceFile("function_calling/request.json");
using var expectedResponseDoc = LoadChatCompletionsTraceDocument("function_calling/response.json");
var expectedResponse = expectedResponseDoc.RootElement;
// Get expected function call details
const string FunctionName = "get_weather";
HttpClient client = await this.CreateTestServerAsync("function-agent", "You are a helpful assistant.", FunctionName,
(msg) => [new FunctionCallContent("call_abc123xyz", "get_weather", new Dictionary<string, object?>() {
{ "location", "San Francisco, CA" },
{ "unit", "fahrenheit" }
})]
);
// Act
HttpResponseMessage httpResponse = await this.SendChatCompletionRequestAsync(client, "function-agent", requestJson);
using var responseDoc = await ParseResponseAsync(httpResponse);
var response = responseDoc.RootElement;
// Parse the request
using var requestDoc = JsonDocument.Parse(requestJson);
var request = requestDoc.RootElement;
// Assert - Request has tools array
AssertJsonPropertyExists(request, "tools");
var tools = request.GetProperty("tools");
Assert.Equal(JsonValueKind.Array, tools.ValueKind);
Assert.True(tools.GetArrayLength() > 0);
// Assert - Tool structure
var tool = tools[0];
AssertJsonPropertyEquals(tool, "type", "function");
AssertJsonPropertyExists(tool, "function");
var function = tool.GetProperty("function");
AssertJsonPropertyEquals(function, "name", "get_weather");
AssertJsonPropertyExists(function, "description");
AssertJsonPropertyExists(function, "parameters");
// Assert - Parameters have JSON Schema
var parameters = function.GetProperty("parameters");
AssertJsonPropertyEquals(parameters, "type", "object");
AssertJsonPropertyExists(parameters, "properties");
AssertJsonPropertyExists(parameters, "required");
// Assert - Response has tool_calls. Not always will return that, so can default to "stop"
var choices = response.GetProperty("choices");
var choice = choices[0];
var message = choice.GetProperty("message");
AssertJsonPropertyEquals(choice, "finish_reason", ["tool_calls", "stop"]);
AssertJsonPropertyExists(message, "tool_calls");
// Assert - Tool call structure
var toolCalls = message.GetProperty("tool_calls");
Assert.Equal(JsonValueKind.Array, toolCalls.ValueKind);
Assert.True(toolCalls.GetArrayLength() > 0);
var toolCall = toolCalls[0];
AssertJsonPropertyExists(toolCall, "id");
AssertJsonPropertyEquals(toolCall, "type", "function");
AssertJsonPropertyExists(toolCall, "function");
var callFunction = toolCall.GetProperty("function");
AssertJsonPropertyEquals(callFunction, "name", "get_weather");
AssertJsonPropertyExists(callFunction, "arguments");
// Assert - Arguments are valid JSON
string arguments = callFunction.GetProperty("arguments").GetString()!;
using var argsDoc = JsonDocument.Parse(arguments);
var argsRoot = argsDoc.RootElement;
AssertJsonPropertyExists(argsRoot, "location");
// Assert - Message content is null when tool_calls present. Can be absent or null.
if (message.TryGetProperty("content", out var contentProp))
{
Assert.Equal(JsonValueKind.Null, contentProp.ValueKind);
}
}
[Fact]
public async Task SystemMessageRequestResponseAsync()
{
// Arrange
string requestJson = LoadChatCompletionsTraceFile("system_message/request.json");
using var expectedResponseDoc = LoadChatCompletionsTraceDocument("system_message/response.json");
var expectedResponse = expectedResponseDoc.RootElement;
string expectedText = expectedResponse.GetProperty("choices")[0]
.GetProperty("message")
.GetProperty("content").GetString()!;
HttpClient client = await this.CreateTestServerAsync("system-agent", "You are a helpful assistant that speaks like a pirate.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendChatCompletionRequestAsync(client, "system-agent", requestJson);
using var responseDoc = await ParseResponseAsync(httpResponse);
var response = responseDoc.RootElement;
// Parse the request
using var requestDoc = JsonDocument.Parse(requestJson);
var request = requestDoc.RootElement;
// Assert - Request has messages with system role
var messages = request.GetProperty("messages");
Assert.True(messages.GetArrayLength() >= 2);
var systemMessage = messages[0];
AssertJsonPropertyEquals(systemMessage, "role", "system");
AssertJsonPropertyExists(systemMessage, "content");
string systemContent = systemMessage.GetProperty("content").GetString()!;
Assert.Contains("pirate", systemContent, System.StringComparison.OrdinalIgnoreCase);
var userMessage = messages[1];
AssertJsonPropertyEquals(userMessage, "role", "user");
// Assert - Response reflects system message influence
var responseMessage = response.GetProperty("choices")[0].GetProperty("message");
string content = responseMessage.GetProperty("content").GetString()!;
Assert.NotNull(content);
Assert.Equal(expectedText, content);
}
[Fact]
public async Task MultiTurnConversationRequestResponseAsync()
{
// Arrange
string requestJson = LoadChatCompletionsTraceFile("multi_turn/request.json");
using var expectedResponseDoc = LoadChatCompletionsTraceDocument("multi_turn/response.json");
var expectedResponse = expectedResponseDoc.RootElement;
string expectedText = expectedResponse.GetProperty("choices")[0]
.GetProperty("message")
.GetProperty("content").GetString()!;
HttpClient client = await this.CreateTestServerAsync("multi-turn-agent", "You are a helpful assistant.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendChatCompletionRequestAsync(client, "multi-turn-agent", requestJson);
using var responseDoc = await ParseResponseAsync(httpResponse);
var response = responseDoc.RootElement;
// Parse the request
using var requestDoc = JsonDocument.Parse(requestJson);
var request = requestDoc.RootElement;
// Assert - Request has conversation history
var messages = request.GetProperty("messages");
Assert.True(messages.GetArrayLength() >= 3, "Should have at least 3 messages for multi-turn");
// Assert - Message sequence alternates between user and assistant
AssertJsonPropertyEquals(messages[0], "role", "user");
AssertJsonPropertyEquals(messages[1], "role", "assistant");
AssertJsonPropertyEquals(messages[2], "role", "user");
// Assert - Response continues conversation
var responseMessage = response.GetProperty("choices")[0].GetProperty("message");
AssertJsonPropertyEquals(responseMessage, "role", "assistant");
string content = responseMessage.GetProperty("content").GetString()!;
Assert.NotNull(content);
Assert.Equal(expectedText, content);
// Assert - Usage tokens account for conversation history
var usage = response.GetProperty("usage");
int promptTokens = usage.GetProperty("prompt_tokens").GetInt32();
Assert.True(promptTokens > 20, "Prompt tokens should account for conversation history");
}
[Fact]
public async Task JsonModeRequestResponseAsync()
{
// Arrange
string requestJson = LoadChatCompletionsTraceFile("json_mode/request.json");
using var expectedResponseDoc = LoadChatCompletionsTraceDocument("json_mode/response.json");
var expectedResponse = expectedResponseDoc.RootElement;
string expectedText = expectedResponse.GetProperty("choices")[0]
.GetProperty("message")
.GetProperty("content").GetString()!;
HttpClient client = await this.CreateTestServerAsync("json-agent", "You are a helpful assistant that outputs JSON.", expectedText);
// Act
HttpResponseMessage httpResponse = await this.SendChatCompletionRequestAsync(client, "json-agent", requestJson);
using var responseDoc = await ParseResponseAsync(httpResponse);
var response = responseDoc.RootElement;
// Parse the request
using var requestDoc = JsonDocument.Parse(requestJson);
var request = requestDoc.RootElement;
// Assert - Request has response_format with json_schema
AssertJsonPropertyExists(request, "response_format");
var responseFormat = request.GetProperty("response_format");
AssertJsonPropertyEquals(responseFormat, "type", "json_schema");
AssertJsonPropertyExists(responseFormat, "json_schema");
var jsonSchema = responseFormat.GetProperty("json_schema");
AssertJsonPropertyEquals(jsonSchema, "name", "person_info");
AssertJsonPropertyEquals(jsonSchema, "strict", true);
AssertJsonPropertyExists(jsonSchema, "schema");
var schema = jsonSchema.GetProperty("schema");
AssertJsonPropertyEquals(schema, "type", "object");
AssertJsonPropertyExists(schema, "properties");
AssertJsonPropertyExists(schema, "required");
// Assert - Response content is valid JSON matching schema
var responseMessage = response.GetProperty("choices")[0].GetProperty("message");
string content = responseMessage.GetProperty("content").GetString()!;
Assert.NotNull(content);
Assert.Equal(expectedText, content);
using var jsonDoc = JsonDocument.Parse(content);
var jsonRoot = jsonDoc.RootElement;
AssertJsonPropertyExists(jsonRoot, "name");
AssertJsonPropertyExists(jsonRoot, "age");
AssertJsonPropertyExists(jsonRoot, "occupation");
Assert.Equal(JsonValueKind.String, jsonRoot.GetProperty("name").ValueKind);
Assert.Equal(JsonValueKind.Number, jsonRoot.GetProperty("age").ValueKind);
Assert.Equal(JsonValueKind.String, jsonRoot.GetProperty("occupation").ValueKind);
}
[Fact]
public async Task ToolsSerializationDeserializationAsync()
{
// Arrange
string requestJson = LoadChatCompletionsTraceFile("tools/request.json");
using var expectedResponseDoc = LoadChatCompletionsTraceDocument("tools/response.json");
HttpClient client = await this.CreateTestServerAsync(
"tools-agent",
"You are a helpful assistant with access to weather and time tools.",
"tool-call",
(msg) => [new FunctionCallContent("call_abc123", "get_weather", new Dictionary<string, object?>() {
{ "location", "San Francisco, CA" },
{ "unit", "fahrenheit" }
})]
);
// Act
HttpResponseMessage httpResponse = await this.SendChatCompletionRequestAsync(client, "tools-agent", requestJson);
using var responseDoc = await ParseResponseAsync(httpResponse);
var response = responseDoc.RootElement;
// Parse the request
using var requestDoc = JsonDocument.Parse(requestJson);
var request = requestDoc.RootElement;
// Assert - Request has tools array with proper structure
AssertJsonPropertyExists(request, "tools");
var tools = request.GetProperty("tools");
Assert.Equal(JsonValueKind.Array, tools.ValueKind);
Assert.Equal(2, tools.GetArrayLength());
// Assert - First tool (get_weather)
var weatherTool = tools[0];
AssertJsonPropertyEquals(weatherTool, "type", "function");
AssertJsonPropertyExists(weatherTool, "function");
var weatherFunction = weatherTool.GetProperty("function");
AssertJsonPropertyEquals(weatherFunction, "name", "get_weather");
AssertJsonPropertyExists(weatherFunction, "description");
AssertJsonPropertyExists(weatherFunction, "parameters");
var weatherParams = weatherFunction.GetProperty("parameters");
AssertJsonPropertyEquals(weatherParams, "type", "object");
AssertJsonPropertyExists(weatherParams, "properties");
AssertJsonPropertyExists(weatherParams, "required");
// Verify location property exists
var properties = weatherParams.GetProperty("properties");
AssertJsonPropertyExists(properties, "location");
AssertJsonPropertyExists(properties, "unit");
// Assert - Second tool (get_time)
var timeTool = tools[1];
AssertJsonPropertyEquals(timeTool, "type", "function");
var timeFunction = timeTool.GetProperty("function");
AssertJsonPropertyEquals(timeFunction, "name", "get_time");
AssertJsonPropertyExists(timeFunction, "description");
AssertJsonPropertyExists(timeFunction, "parameters");
// Assert - Response structure
AssertJsonPropertyExists(response, "id");
AssertJsonPropertyEquals(response, "object", "chat.completion");
AssertJsonPropertyExists(response, "created");
AssertJsonPropertyExists(response, "model");
// Assert - Response has tool_calls in choices
var choices = response.GetProperty("choices");
Assert.Equal(JsonValueKind.Array, choices.ValueKind);
Assert.True(choices.GetArrayLength() > 0);
var choice = choices[0];
AssertJsonPropertyExists(choice, "finish_reason");
AssertJsonPropertyEquals(choice, "finish_reason", anyOfValues: ["tool_calls", "stop"]);
AssertJsonPropertyExists(choice, "message");
var message = choice.GetProperty("message");
AssertJsonPropertyEquals(message, "role", "assistant");
AssertJsonPropertyExists(message, "tool_calls");
// Assert - Tool calls array structure
var toolCalls = message.GetProperty("tool_calls");
Assert.Equal(JsonValueKind.Array, toolCalls.ValueKind);
Assert.True(toolCalls.GetArrayLength() > 0);
var toolCall = toolCalls[0];
AssertJsonPropertyExists(toolCall, "id");
AssertJsonPropertyEquals(toolCall, "type", "function");
AssertJsonPropertyExists(toolCall, "function");
var callFunction = toolCall.GetProperty("function");
AssertJsonPropertyEquals(callFunction, "name", "get_weather");
AssertJsonPropertyExists(callFunction, "arguments");
// Assert - Tool call arguments are valid JSON
string arguments = callFunction.GetProperty("arguments").GetString()!;
using var argsDoc = JsonDocument.Parse(arguments);
var argsRoot = argsDoc.RootElement;
AssertJsonPropertyExists(argsRoot, "location");
AssertJsonPropertyEquals(argsRoot, "location", "San Francisco, CA");
AssertJsonPropertyEquals(argsRoot, "unit", "fahrenheit");
// Assert - Message content is null when tool_calls present
if (message.TryGetProperty("content", out var contentProp))
{
Assert.Equal(JsonValueKind.Null, contentProp.ValueKind);
}
// Assert - Usage statistics
AssertJsonPropertyExists(response, "usage");
var usage = response.GetProperty("usage");
AssertJsonPropertyExists(usage, "prompt_tokens");
AssertJsonPropertyExists(usage, "completion_tokens");
AssertJsonPropertyExists(usage, "total_tokens");
var promptTokens = usage.GetProperty("prompt_tokens").GetInt32();
var completionTokens = usage.GetProperty("completion_tokens").GetInt32();
var totalTokens = usage.GetProperty("total_tokens").GetInt32();
Assert.True(promptTokens > 0);
Assert.True(completionTokens > 0);
Assert.Equal(promptTokens + completionTokens, totalTokens);
// Assert - Service tier
AssertJsonPropertyExists(response, "service_tier");
var serviceTier = response.GetProperty("service_tier").GetString();
Assert.NotNull(serviceTier);
}
/// <summary>
/// Helper to parse chat completion chunks from SSE response.
/// </summary>
private static List<JsonElement> ParseChatCompletionChunksFromSse(string sseContent)
{
var chunks = 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("data: ", System.StringComparison.Ordinal))
{
var jsonData = line.Substring("data: ".Length);
// Skip [DONE] marker
if (jsonData == "[DONE]")
{
continue;
}
try
{
var doc = JsonDocument.Parse(jsonData);
chunks.Add(doc.RootElement.Clone());
}
catch
{
// Skip invalid JSON
}
}
}
return chunks;
}
}
@@ -0,0 +1,974 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
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;
using OpenAI;
using OpenAI.Chat;
using ChatFinishReason = OpenAI.Chat.ChatFinishReason;
using ChatMessage = OpenAI.Chat.ChatMessage;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Integration tests that start a web server and use the OpenAI Chat Completions SDK client to verify protocol compatibility.
/// These tests validate both streaming and non-streaming request scenarios.
/// </summary>
public sealed class OpenAIChatCompletionsIntegrationTests : IAsyncDisposable
{
private WebApplication? _app;
private HttpClient? _httpClient;
public async ValueTask DisposeAsync()
{
this._httpClient?.Dispose();
if (this._app != null)
{
await this._app.DisposeAsync();
}
}
/// <summary>
/// Verifies that streaming chat completions work correctly with the OpenAI SDK client.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_WithSimpleMessage_ReturnsStreamingUpdatesAsync()
{
// Arrange
const string AgentName = "streaming-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "One Two Three";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Count to 3")
];
// Act
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
// Assert
List<StreamingChatCompletionUpdate> updates = [];
StringBuilder contentBuilder = new();
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
updates.Add(update);
if (update.ContentUpdate.Count > 0)
{
foreach (ChatMessageContentPart contentPart in update.ContentUpdate)
{
contentBuilder.Append(contentPart.Text);
}
}
}
Assert.NotEmpty(updates);
// Verify content was received
string content = contentBuilder.ToString();
Assert.Equal(ExpectedResponse, content);
// Verify finish reason
StreamingChatCompletionUpdate? lastUpdate = updates.LastOrDefault(u => u.FinishReason != null);
Assert.NotNull(lastUpdate);
Assert.Equal(ChatFinishReason.Stop, lastUpdate.FinishReason);
}
/// <summary>
/// Verifies that non-streaming chat completions work correctly with the OpenAI SDK client.
/// </summary>
[Fact]
public async Task CreateChatCompletion_WithSimpleMessage_ReturnsCompleteResponseAsync()
{
// Arrange
const string AgentName = "non-streaming-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Hello! How can I help you today?";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Hello")
];
// Act
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
// Assert
Assert.NotNull(completion);
Assert.NotNull(completion.Id);
Assert.StartsWith("chatcmpl-", completion.Id);
Assert.Equal(ChatFinishReason.Stop, completion.FinishReason);
// Verify content
string content = completion.Content[0].Text;
Assert.Equal(ExpectedResponse, content);
}
/// <summary>
/// Verifies that streaming chat completions can handle multiple content chunks.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_WithMultipleChunks_StreamsAllContentAsync()
{
// Arrange
const string AgentName = "multi-chunk-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "This is a test response with multiple words";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
// Assert
List<StreamingChatCompletionUpdate> updates = [];
StringBuilder contentBuilder = new();
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
updates.Add(update);
foreach (ChatMessageContentPart contentPart in update.ContentUpdate)
{
contentBuilder.Append(contentPart.Text);
}
}
// Verify all content was received
string receivedContent = contentBuilder.ToString();
Assert.Equal(ExpectedResponse, receivedContent);
// Verify multiple content chunks were received
List<StreamingChatCompletionUpdate> contentUpdates = updates.Where(u => u.ContentUpdate.Count > 0).ToList();
Assert.True(contentUpdates.Count > 1, "Expected multiple content chunks in streaming response");
}
/// <summary>
/// Verifies that multiple agents can be accessed via the same server.
/// </summary>
[Fact]
public async Task CreateChatCompletion_WithMultipleAgents_EachAgentRespondsCorrectlyAsync()
{
// Arrange
const string Agent1Name = "agent-one";
const string Agent1Instructions = "You are agent one.";
const string Agent1Response = "Response from agent one";
const string Agent2Name = "agent-two";
const string Agent2Instructions = "You are agent two.";
const string Agent2Response = "Response from agent two";
this._httpClient = await this.CreateTestServerWithMultipleAgentsAsync(
(Agent1Name, Agent1Instructions, Agent1Response),
(Agent2Name, Agent2Instructions, Agent2Response));
ChatClient chatClient1 = this.CreateChatClient(Agent1Name);
ChatClient chatClient2 = this.CreateChatClient(Agent2Name);
List<ChatMessage> messages =
[
new UserChatMessage("Hello")
];
// Act
ChatCompletion completion1 = await chatClient1.CompleteChatAsync(messages);
ChatCompletion completion2 = await chatClient2.CompleteChatAsync(messages);
// Assert
string content1 = completion1.Content[0].Text;
string content2 = completion2.Content[0].Text;
Assert.Equal(Agent1Response, content1);
Assert.Equal(Agent2Response, content2);
Assert.NotEqual(content1, content2);
}
/// <summary>
/// Verifies that streaming and non-streaming work correctly for the same agent.
/// </summary>
[Fact]
public async Task CreateChatCompletion_SameAgentStreamingAndNonStreaming_BothWorkCorrectlyAsync()
{
// Arrange
const string AgentName = "dual-mode-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "This is the response";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act - Non-streaming
ChatCompletion nonStreamingCompletion = await chatClient.CompleteChatAsync(messages);
// Act - Streaming
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
StringBuilder streamingContent = new();
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
foreach (ChatMessageContentPart contentPart in update.ContentUpdate)
{
streamingContent.Append(contentPart.Text);
}
}
// Assert
string nonStreamingContent = nonStreamingCompletion.Content[0].Text;
Assert.Equal(ExpectedResponse, nonStreamingContent);
Assert.Equal(ExpectedResponse, streamingContent.ToString());
}
/// <summary>
/// Verifies that the finish reason is correctly set for completed responses.
/// </summary>
[Fact]
public async Task CreateChatCompletion_CompletedResponse_HasCorrectFinishReasonAsync()
{
// Arrange
const string AgentName = "finish-reason-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Complete";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
// Assert
Assert.Equal(ChatFinishReason.Stop, completion.FinishReason);
Assert.NotNull(completion.Id);
Assert.Equal(ExpectedResponse, completion.Content[0].Text);
}
/// <summary>
/// Verifies that streaming responses contain the expected chunk sequence.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_VerifyChunkSequence_ContainsExpectedDataAsync()
{
// Arrange
const string AgentName = "chunk-sequence-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Test response with multiple words";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
// Assert
List<StreamingChatCompletionUpdate> updates = [];
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
updates.Add(update);
}
// Verify chunks received
Assert.NotEmpty(updates);
// First chunk should have role
StreamingChatCompletionUpdate? firstUpdate = updates.FirstOrDefault(u => u.Role != null);
if (firstUpdate != null)
{
Assert.Equal(ChatMessageRole.Assistant, firstUpdate.Role);
}
// Should contain content chunks
List<StreamingChatCompletionUpdate> contentUpdates = updates.Where(u => u.ContentUpdate.Count > 0).ToList();
Assert.NotEmpty(contentUpdates);
// Last update should have finish reason
StreamingChatCompletionUpdate? lastUpdate = updates.LastOrDefault(u => u.FinishReason != null);
Assert.NotNull(lastUpdate);
Assert.Equal(ChatFinishReason.Stop, lastUpdate.FinishReason);
}
/// <summary>
/// Verifies that streaming responses properly handle empty responses.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_EmptyResponse_HandlesGracefullyAsync()
{
// Arrange
const string AgentName = "empty-response-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
// Assert
List<StreamingChatCompletionUpdate> updates = [];
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
updates.Add(update);
}
// Should still receive chunks with finish reason
Assert.NotEmpty(updates);
Assert.Contains(updates, u => u.FinishReason == ChatFinishReason.Stop);
}
/// <summary>
/// Verifies that non-streaming responses include proper metadata.
/// </summary>
[Fact]
public async Task CreateChatCompletion_IncludesMetadata_HasRequiredFieldsAsync()
{
// Arrange
const string AgentName = "metadata-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Response with metadata";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
// Assert
Assert.NotNull(completion.Id);
Assert.StartsWith("chatcmpl-", completion.Id);
Assert.NotNull(completion.Model);
Assert.NotEqual(default, completion.CreatedAt);
Assert.Equal(ChatFinishReason.Stop, completion.FinishReason);
}
/// <summary>
/// Verifies that streaming responses handle very long text correctly.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_LongText_StreamsAllContentAsync()
{
// Arrange
const string AgentName = "long-text-agent";
const string Instructions = "You are a helpful assistant.";
string expectedResponse = string.Join(" ", Enumerable.Range(1, 100).Select(i => $"Word{i}"));
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, expectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Generate long text")
];
// Act
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
// Assert
StringBuilder contentBuilder = new();
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
foreach (ChatMessageContentPart contentPart in update.ContentUpdate)
{
contentBuilder.Append(contentPart.Text);
}
}
string receivedContent = contentBuilder.ToString();
Assert.Equal(expectedResponse, receivedContent);
}
/// <summary>
/// Verifies that streaming responses properly handle single-word responses.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_SingleWord_StreamsCorrectlyAsync()
{
// Arrange
const string AgentName = "single-word-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Hello";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
// Assert
StringBuilder contentBuilder = new();
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
foreach (ChatMessageContentPart contentPart in update.ContentUpdate)
{
contentBuilder.Append(contentPart.Text);
}
}
Assert.Equal(ExpectedResponse, contentBuilder.ToString());
}
/// <summary>
/// Verifies that streaming responses preserve special characters and formatting.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_SpecialCharacters_PreservesFormattingAsync()
{
// Arrange
const string AgentName = "special-chars-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Hello! How are you? I'm fine. 100% great!";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
// Assert
StringBuilder contentBuilder = new();
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
foreach (ChatMessageContentPart contentPart in update.ContentUpdate)
{
contentBuilder.Append(contentPart.Text);
}
}
Assert.Equal(ExpectedResponse, contentBuilder.ToString());
}
/// <summary>
/// Verifies that non-streaming responses handle special characters correctly.
/// </summary>
[Fact]
public async Task CreateChatCompletion_SpecialCharacters_PreservesContentAsync()
{
// Arrange
const string AgentName = "special-chars-nonstreaming-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Symbols: @#$%^&*() Quotes: \"Hello\" 'World' Unicode: 你好 🌍";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
// Assert
string content = completion.Content[0].Text;
Assert.Equal(ExpectedResponse, content);
}
/// <summary>
/// Verifies that multiple sequential non-streaming requests work correctly.
/// </summary>
[Fact]
public async Task CreateChatCompletion_MultipleSequentialRequests_AllSucceedAsync()
{
// Arrange
const string AgentName = "sequential-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Response";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
// Act & Assert - Make 5 sequential requests
for (int i = 0; i < 5; i++)
{
List<ChatMessage> messages =
[
new UserChatMessage($"Request {i}")
];
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
Assert.NotNull(completion);
Assert.Equal(ChatFinishReason.Stop, completion.FinishReason);
Assert.Equal(ExpectedResponse, completion.Content[0].Text);
}
}
/// <summary>
/// Verifies that multiple sequential streaming requests work correctly.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_MultipleSequentialRequests_AllStreamCorrectlyAsync()
{
// Arrange
const string AgentName = "sequential-streaming-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Streaming response";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
// Act & Assert - Make 3 sequential streaming requests
for (int i = 0; i < 3; i++)
{
List<ChatMessage> messages =
[
new UserChatMessage($"Request {i}")
];
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
StringBuilder contentBuilder = new();
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
foreach (ChatMessageContentPart contentPart in update.ContentUpdate)
{
contentBuilder.Append(contentPart.Text);
}
}
Assert.Equal(ExpectedResponse, contentBuilder.ToString());
}
}
/// <summary>
/// Verifies that completion IDs are unique across multiple requests.
/// </summary>
[Fact]
public async Task CreateChatCompletion_MultipleRequests_GenerateUniqueIdsAsync()
{
// Arrange
const string AgentName = "unique-id-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Response";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
// Act
List<string> completionIds = [];
for (int i = 0; i < 10; i++)
{
List<ChatMessage> messages =
[
new UserChatMessage($"Request {i}")
];
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
completionIds.Add(completion.Id);
}
// Assert
Assert.Equal(10, completionIds.Count);
Assert.Equal(completionIds.Count, completionIds.Distinct().Count()); // All IDs should be unique
}
/// <summary>
/// Verifies that streaming responses all have the same ID within a single request.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_SameRequestId_ConsistentAcrossChunksAsync()
{
// Arrange
const string AgentName = "consistent-id-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Test consistent ID across chunks";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
// Assert
List<string> chunkIds = [];
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
if (!string.IsNullOrEmpty(update.CompletionId))
{
chunkIds.Add(update.CompletionId);
}
}
// All chunk IDs should be the same within a single request
Assert.NotEmpty(chunkIds);
Assert.All(chunkIds, id => Assert.Equal(chunkIds[0], id));
Assert.StartsWith("chatcmpl-", chunkIds[0]);
}
/// <summary>
/// Verifies that non-streaming responses work with system messages.
/// </summary>
[Fact]
public async Task CreateChatCompletion_WithSystemMessage_ReturnsValidResponseAsync()
{
// Arrange
const string AgentName = "system-message-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "I am following the system instructions";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new SystemChatMessage("You must respond in a specific way"),
new UserChatMessage("Hello")
];
// Act
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
// Assert
Assert.NotNull(completion);
Assert.Equal(ChatFinishReason.Stop, completion.FinishReason);
Assert.Equal(ExpectedResponse, completion.Content[0].Text);
}
/// <summary>
/// Verifies that responses handle newlines correctly.
/// </summary>
[Fact]
public async Task CreateChatCompletion_Newlines_PreservesFormattingAsync()
{
// Arrange
const string AgentName = "newline-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Line 1\nLine 2\nLine 3";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
// Assert
string content = completion.Content[0].Text;
Assert.Equal(ExpectedResponse, content);
Assert.Contains("\n", content);
}
/// <summary>
/// Verifies that streaming responses handle newlines correctly.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_Newlines_PreservesFormattingAsync()
{
// Arrange
const string AgentName = "newline-streaming-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "First line\nSecond line\nThird line";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = chatClient.CompleteChatStreamingAsync(messages);
// Assert
StringBuilder contentBuilder = new();
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
foreach (ChatMessageContentPart contentPart in update.ContentUpdate)
{
contentBuilder.Append(contentPart.Text);
}
}
string content = contentBuilder.ToString();
Assert.Equal(ExpectedResponse, content);
Assert.Contains("\n", content);
}
/// <summary>
/// Verifies that responses with conversation history work correctly.
/// </summary>
[Fact]
public async Task CreateChatCompletion_WithConversationHistory_ReturnsValidResponseAsync()
{
// Arrange
const string AgentName = "conversation-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "3 plus 3 equals 6";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("What is 2+2?"),
new AssistantChatMessage("2+2 equals 4"),
new UserChatMessage("What about 3+3?")
];
// Act
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
// Assert
Assert.NotNull(completion);
Assert.Equal(ChatFinishReason.Stop, completion.FinishReason);
Assert.Equal(ExpectedResponse, completion.Content[0].Text);
}
/// <summary>
/// Verifies that usage information is included in non-streaming responses.
/// </summary>
[Fact]
public async Task CreateChatCompletion_IncludesUsage_HasTokenCountsAsync()
{
// Arrange
const string AgentName = "usage-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Response with usage information";
this._httpClient = await this.CreateTestServerAsync(AgentName, Instructions, ExpectedResponse);
ChatClient chatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Test")
];
// Act
ChatCompletion completion = await chatClient.CompleteChatAsync(messages);
// Assert
Assert.NotNull(completion.Usage);
Assert.True(completion.Usage.InputTokenCount > 0);
Assert.True(completion.Usage.OutputTokenCount > 0);
Assert.Equal(completion.Usage.InputTokenCount + completion.Usage.OutputTokenCount, completion.Usage.TotalTokenCount);
}
/// <summary>
/// Verifies that responses with function calls work correctly.
/// </summary>
[Fact]
public async Task CreateChatCompletion_WithFunctionCall_ReturnsToolCallsAsync()
{
// Arrange
const string AgentName = "function-call-agent";
const string Instructions = "You are a helpful assistant.";
const string FunctionName = "get_weather";
const string Arguments = "{\"location\":\"Seattle\"}";
this._httpClient = await this.CreateTestServerWithCustomClientAsync(
agentName: AgentName,
instructions: Instructions,
chatClient: new TestHelpers.FunctionCallMockChatClient(FunctionName, Arguments));
ChatClient openAIChatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("What's the weather?")
];
// Act
ChatCompletion completion = await openAIChatClient.CompleteChatAsync(messages);
// Assert
Assert.NotNull(completion);
Assert.Equal(ChatFinishReason.ToolCalls, completion.FinishReason);
Assert.NotNull(completion.ToolCalls);
Assert.NotEmpty(completion.ToolCalls);
ChatToolCall toolCall = completion.ToolCalls[0];
Assert.Equal(FunctionName, toolCall.FunctionName);
Assert.NotNull(toolCall.FunctionArguments);
}
/// <summary>
/// Verifies that streaming responses with function calls work correctly.
/// </summary>
[Fact]
public async Task CreateChatCompletionStreaming_WithFunctionCall_StreamsToolCallsAsync()
{
// Arrange
const string AgentName = "function-call-streaming-agent";
const string Instructions = "You are a helpful assistant.";
const string FunctionName = "calculate";
const string Arguments = "{\"expression\":\"2+2\"}";
this._httpClient = await this.CreateTestServerWithCustomClientAsync(
agentName: AgentName,
instructions: Instructions,
chatClient: new TestHelpers.FunctionCallMockChatClient(FunctionName, Arguments));
ChatClient openAIChatClient = this.CreateChatClient(AgentName);
List<ChatMessage> messages =
[
new UserChatMessage("Calculate 2+2")
];
// Act
AsyncCollectionResult<StreamingChatCompletionUpdate> streamingResult = openAIChatClient.CompleteChatStreamingAsync(messages);
// Assert
List<StreamingChatCompletionUpdate> updates = [];
await foreach (StreamingChatCompletionUpdate update in streamingResult)
{
updates.Add(update);
}
Assert.NotEmpty(updates);
// Should have finish reason of tool_calls
StreamingChatCompletionUpdate? lastUpdate = updates.LastOrDefault(u => u.FinishReason != null);
Assert.NotNull(lastUpdate);
Assert.True(lastUpdate.FinishReason is ChatFinishReason.ToolCalls or ChatFinishReason.Stop); // depends on what response we get
}
private ChatClient CreateChatClient(string agentName)
{
return new ChatClient(
model: "test-model",
credential: new ApiKeyCredential("test-api-key"),
options: new OpenAIClientOptions
{
Endpoint = new Uri(this._httpClient!.BaseAddress!, $"/{agentName}/v1/"),
Transport = new HttpClientPipelineTransport(this._httpClient)
});
}
private async Task<HttpClient> CreateTestServerAsync(string agentName, string instructions, string responseText = "Test response")
{
WebApplicationBuilder builder = WebApplication.CreateBuilder();
builder.WebHost.UseTestServer();
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient(responseText);
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
builder.AddOpenAIChatCompletions();
builder.AddAIAgent(agentName, instructions, chatClientServiceKey: "chat-client");
this._app = builder.Build();
AIAgent agent = this._app.Services.GetRequiredKeyedService<AIAgent>(agentName);
this._app.MapOpenAIChatCompletions(agent);
await this._app.StartAsync();
TestServer testServer = this._app.Services.GetRequiredService<IServer>() as TestServer
?? throw new InvalidOperationException("TestServer not found");
return testServer.CreateClient();
}
private async Task<HttpClient> CreateTestServerWithCustomClientAsync(string agentName, string instructions, IChatClient chatClient)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder();
builder.WebHost.UseTestServer();
builder.Services.AddKeyedSingleton($"chat-client-{agentName}", chatClient);
builder.AddAIAgent(agentName, instructions, chatClientServiceKey: $"chat-client-{agentName}");
builder.AddOpenAIChatCompletions();
this._app = builder.Build();
AIAgent agent = this._app.Services.GetRequiredKeyedService<AIAgent>(agentName);
this._app.MapOpenAIChatCompletions(agent);
await this._app.StartAsync();
TestServer testServer = this._app.Services.GetRequiredService<IServer>() as TestServer
?? throw new InvalidOperationException("TestServer not found");
return testServer.CreateClient();
}
private async Task<HttpClient> CreateTestServerWithMultipleAgentsAsync(
params (string Name, string Instructions, string ResponseText)[] agents)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder();
builder.WebHost.UseTestServer();
foreach ((string name, string instructions, string responseText) in agents)
{
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient(responseText);
builder.Services.AddKeyedSingleton($"chat-client-{name}", mockChatClient);
builder.AddAIAgent(name, instructions, chatClientServiceKey: $"chat-client-{name}");
}
builder.AddOpenAIChatCompletions();
this._app = builder.Build();
foreach ((string name, string _, string _) in agents)
{
AIAgent agent = this._app.Services.GetRequiredKeyedService<AIAgent>(name);
this._app.MapOpenAIChatCompletions(agent);
}
await this._app.StartAsync();
TestServer testServer = this._app.Services.GetRequiredService<IServer>() as TestServer
?? throw new InvalidOperationException("TestServer not found");
return testServer.CreateClient();
}
}
@@ -0,0 +1,576 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Microsoft.Agents.AI.Hosting.OpenAI.ChatCompletions.Models;
using Microsoft.Agents.AI.Hosting.OpenAI.Tests;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Tests for OpenAI ChatCompletions API model serialization and deserialization.
/// These tests verify that our models correctly serialize to and deserialize from JSON
/// matching the OpenAI wire format, without testing actual API implementation behavior.
/// </summary>
public sealed class OpenAIChatCompletionsSerializationTests : ConformanceTestBase
{
#region Request Deserialization Tests
[Fact]
public void Deserialize_BasicRequest_Success()
{
// Arrange
string json = LoadChatCompletionsTraceFile("basic/request.json");
// Act
CreateChatCompletion? request = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
// Assert
Assert.NotNull(request);
Assert.Equal("gpt-4o-mini", request.Model);
Assert.NotNull(request.Messages);
Assert.True(request.Messages.Count > 0);
Assert.Equal(100, request.MaxCompletionTokens);
}
[Fact]
public void Deserialize_BasicRequest_RoundTrip()
{
// Arrange
string originalJson = LoadChatCompletionsTraceFile("basic/request.json");
// Act
CreateChatCompletion? request = JsonSerializer.Deserialize(originalJson, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
string reserializedJson = JsonSerializer.Serialize(request, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
CreateChatCompletion? roundtripped = JsonSerializer.Deserialize(reserializedJson, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
// Assert
Assert.NotNull(request);
Assert.NotNull(roundtripped);
Assert.Equal(request.Model, roundtripped.Model);
Assert.Equal(request.MaxCompletionTokens, roundtripped.MaxCompletionTokens);
Assert.Equal(request.Messages.Count, roundtripped.Messages.Count);
}
[Fact]
public void Deserialize_BasicRequest_HasMessages()
{
// Arrange
string json = LoadChatCompletionsTraceFile("basic/request.json");
// Act
CreateChatCompletion? request = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
// Assert
Assert.NotNull(request);
Assert.NotNull(request.Messages);
Assert.Single(request.Messages);
var message = request.Messages[0];
Assert.Equal("user", message.Role);
Assert.NotNull(message.Content);
}
[Fact]
public void Deserialize_StreamingRequest_HasStreamFlag()
{
// Arrange
string json = LoadChatCompletionsTraceFile("streaming/request.json");
// Act
CreateChatCompletion? request = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
// Assert
Assert.NotNull(request);
Assert.True(request.Stream);
Assert.Equal(150, request.MaxCompletionTokens);
}
[Fact]
public void Deserialize_SystemMessageRequest_HasSystemRole()
{
// Arrange
string json = LoadChatCompletionsTraceFile("system_message/request.json");
// Act
CreateChatCompletion? request = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
// Assert
Assert.NotNull(request);
Assert.NotNull(request.Messages);
Assert.True(request.Messages.Count >= 2);
Assert.Equal("system", request.Messages[0].Role);
Assert.Equal("user", request.Messages[1].Role);
}
[Fact]
public void Deserialize_MultiTurnRequest_HasMultipleMessages()
{
// Arrange
string json = LoadChatCompletionsTraceFile("multi_turn/request.json");
// Act
CreateChatCompletion? request = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
// Assert
Assert.NotNull(request);
Assert.NotNull(request.Messages);
Assert.True(request.Messages.Count >= 3);
Assert.Equal("user", request.Messages[0].Role);
Assert.Equal("assistant", request.Messages[1].Role);
Assert.Equal("user", request.Messages[2].Role);
}
[Fact]
public void Deserialize_FunctionCallingRequest_HasTools()
{
// Arrange
string json = LoadChatCompletionsTraceFile("function_calling/request.json");
// Act
CreateChatCompletion? request = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
// Assert
Assert.NotNull(request);
Assert.NotNull(request.Tools);
Assert.Single(request.Tools);
Assert.NotNull(request.ToolChoice?.Mode);
Assert.Equal("auto", request.ToolChoice.Mode);
}
[Fact]
public void Deserialize_JsonModeRequest_HasResponseFormat()
{
// Arrange
string json = LoadChatCompletionsTraceFile("json_mode/request.json");
// Act
CreateChatCompletion? request = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
// Assert
Assert.NotNull(request);
Assert.NotNull(request.ResponseFormat);
}
[Fact]
public void Deserialize_AllRequests_CanBeDeserialized()
{
// Arrange
string[] requestPaths =
[
"basic/request.json",
"streaming/request.json",
"system_message/request.json",
"multi_turn/request.json",
"function_calling/request.json",
"json_mode/request.json"
];
foreach (var path in requestPaths)
{
string json = LoadChatCompletionsTraceFile(path);
// Act & Assert - Should not throw
CreateChatCompletion? request = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.CreateChatCompletion);
Assert.NotNull(request);
Assert.NotNull(request.Messages);
Assert.True(request.Messages.Count > 0, $"Request from {path} should have messages");
}
}
#endregion
#region Response Deserialization Tests
[Fact]
public void Deserialize_BasicResponse_Success()
{
// Arrange
string json = LoadChatCompletionsTraceFile("basic/response.json");
// Act
ChatCompletion? response = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
// Assert
Assert.NotNull(response);
Assert.StartsWith("chatcmpl-", response.Id);
Assert.Equal("chat.completion", response.Object);
Assert.True(response.Created > 0);
Assert.NotNull(response.Model);
Assert.StartsWith("gpt-4o-mini", response.Model);
}
[Fact]
public void Deserialize_BasicResponse_HasChoices()
{
// Arrange
string json = LoadChatCompletionsTraceFile("basic/response.json");
// Act
ChatCompletion? response = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Choices);
Assert.Single(response.Choices);
var choice = response.Choices[0];
Assert.Equal(0, choice.Index);
Assert.NotNull(choice.Message);
Assert.Equal("assistant", choice.Message.Role);
Assert.NotNull(choice.Message.Content);
Assert.NotNull(choice.FinishReason);
}
[Fact]
public void Deserialize_BasicResponse_HasUsage()
{
// Arrange
string json = LoadChatCompletionsTraceFile("basic/response.json");
// Act
ChatCompletion? response = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Usage);
Assert.True(response.Usage.PromptTokens > 0);
Assert.True(response.Usage.CompletionTokens > 0);
Assert.Equal(response.Usage.PromptTokens + response.Usage.CompletionTokens, response.Usage.TotalTokens);
Assert.NotNull(response.Usage.PromptTokensDetails);
Assert.NotNull(response.Usage.CompletionTokensDetails);
}
[Fact]
public void Deserialize_SystemMessageResponse_HasContent()
{
// Arrange
string json = LoadChatCompletionsTraceFile("system_message/response.json");
// Act
ChatCompletion? response = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Choices);
var message = response.Choices[0].Message;
Assert.Equal("assistant", message.Role);
Assert.NotNull(message.Content);
Assert.Contains("Ahoy, matey", message.Content, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void Deserialize_MultiTurnResponse_HasContent()
{
// Arrange
string json = LoadChatCompletionsTraceFile("multi_turn/response.json");
// Act
ChatCompletion? response = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Choices);
var message = response.Choices[0].Message;
Assert.Equal("assistant", message.Role);
Assert.NotNull(message.Content);
}
[Fact]
public void Deserialize_FunctionCallingResponse_HasToolCalls()
{
// Arrange
string json = LoadChatCompletionsTraceFile("function_calling/response.json");
// Act
ChatCompletion? response = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Choices);
var choice = response.Choices[0];
Assert.Equal("tool_calls", choice.FinishReason);
var message = choice.Message;
Assert.NotNull(message.ToolCalls);
Assert.Single(message.ToolCalls);
var toolCall = message.ToolCalls[0];
Assert.NotNull(toolCall.Id);
Assert.StartsWith("call_", toolCall.Id);
Assert.Equal("function", toolCall.Type);
Assert.NotNull(toolCall.Function);
Assert.Equal("get_weather", toolCall.Function.Name);
Assert.NotNull(toolCall.Function.Arguments);
}
[Fact]
public void Deserialize_JsonModeResponse_HasStructuredOutput()
{
// Arrange
string json = LoadChatCompletionsTraceFile("json_mode/response.json");
// Act
ChatCompletion? response = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Choices);
var message = response.Choices[0].Message;
Assert.NotNull(message.Content);
// Verify the content is valid JSON
using var jsonDoc = JsonDocument.Parse(message.Content);
var jsonRoot = jsonDoc.RootElement;
Assert.Equal(JsonValueKind.Object, jsonRoot.ValueKind);
Assert.True(jsonRoot.TryGetProperty("name", out _));
Assert.True(jsonRoot.TryGetProperty("age", out _));
Assert.True(jsonRoot.TryGetProperty("occupation", out _));
}
[Fact]
public void Deserialize_AllResponses_HaveRequiredFields()
{
// Arrange
string[] responsePaths =
[
"basic/response.json",
"system_message/response.json",
"multi_turn/response.json",
"function_calling/response.json",
"json_mode/response.json"
];
foreach (var path in responsePaths)
{
string json = LoadChatCompletionsTraceFile(path);
// Act
ChatCompletion? response = JsonSerializer.Deserialize(json, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Id);
Assert.Equal("chat.completion", response.Object);
Assert.True(response.Created > 0, $"Response from {path} should have created timestamp");
Assert.NotNull(response.Model);
Assert.NotNull(response.Choices);
Assert.True(response.Choices.Count > 0, $"Response from {path} should have choices");
}
}
[Fact]
public void Deserialize_ResponseRoundTrip_PreservesData()
{
// Arrange
string originalJson = LoadChatCompletionsTraceFile("basic/response.json");
// Act - Deserialize and re-serialize
ChatCompletion? response = JsonSerializer.Deserialize(originalJson, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
string reserializedJson = JsonSerializer.Serialize(response, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
ChatCompletion? roundtripped = JsonSerializer.Deserialize(reserializedJson, ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletion);
// Assert
Assert.NotNull(response);
Assert.NotNull(roundtripped);
Assert.Equal(response.Id, roundtripped.Id);
Assert.Equal(response.Created, roundtripped.Created);
Assert.Equal(response.Model, roundtripped.Model);
Assert.Equal(response.Choices.Count, roundtripped.Choices.Count);
}
#endregion
#region Streaming Chunk Deserialization Tests
[Fact]
public void ParseStreamingChunks_BasicFormat_Success()
{
// Arrange
string sseContent = LoadChatCompletionsTraceFile("streaming/response.txt");
// Act
var chunks = ParseChatCompletionChunksFromSse(sseContent);
// Assert
Assert.NotEmpty(chunks);
Assert.All(chunks, chunk =>
{
ChatCompletionChunk? parsed = JsonSerializer.Deserialize(chunk.GetRawText(), ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionChunk);
Assert.NotNull(parsed);
Assert.NotNull(parsed.Id);
Assert.Equal("chat.completion.chunk", parsed.Object);
Assert.True(parsed.Created > 0);
Assert.NotNull(parsed.Model);
Assert.NotNull(parsed.Choices);
});
}
[Fact]
public void ParseStreamingChunks_AllChunksSameId()
{
// Arrange
string sseContent = LoadChatCompletionsTraceFile("streaming/response.txt");
// Act
var chunks = ParseChatCompletionChunksFromSse(sseContent);
// Deserialize chunks
var parsedChunks = chunks
.Select(c => JsonSerializer.Deserialize(c.GetRawText(), ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionChunk))
.Where(c => c != null)
.ToList();
// Assert
Assert.NotEmpty(parsedChunks);
string? firstId = parsedChunks[0]!.Id;
Assert.NotNull(firstId);
Assert.StartsWith("chatcmpl-", firstId);
Assert.All(parsedChunks, chunk => Assert.Equal(firstId, chunk!.Id));
}
[Fact]
public void ParseStreamingChunks_FirstChunkHasRole()
{
// Arrange
string sseContent = LoadChatCompletionsTraceFile("streaming/response.txt");
// Act
var chunks = ParseChatCompletionChunksFromSse(sseContent);
var firstChunk = JsonSerializer.Deserialize(chunks[0].GetRawText(), ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionChunk);
// Assert
Assert.NotNull(firstChunk);
Assert.NotNull(firstChunk.Choices);
Assert.True(firstChunk.Choices.Count > 0);
var firstChoice = firstChunk.Choices[0];
Assert.NotNull(firstChoice.Delta);
if (firstChoice.Delta.Role != null)
{
Assert.Equal("assistant", firstChoice.Delta.Role);
}
}
[Fact]
public void ParseStreamingChunks_AccumulateContent_MatchesExpected()
{
// Arrange
string sseContent = LoadChatCompletionsTraceFile("streaming/response.txt");
// Act
var chunks = ParseChatCompletionChunksFromSse(sseContent);
var contentPieces = new List<string>();
foreach (var chunkJson in chunks)
{
var chunk = JsonSerializer.Deserialize(chunkJson.GetRawText(), ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionChunk);
if (chunk?.Choices != null && chunk.Choices.Count > 0)
{
var delta = chunk.Choices[0].Delta;
if (!string.IsNullOrEmpty(delta?.Content))
{
contentPieces.Add(delta.Content);
}
}
}
// Assert
Assert.NotEmpty(contentPieces);
string fullText = string.Concat(contentPieces);
Assert.NotEmpty(fullText);
Assert.Contains("circuits", fullText);
Assert.Contains("flight", fullText);
}
[Fact]
public void ParseStreamingChunks_LastChunkHasFinishReason()
{
// Arrange
string sseContent = LoadChatCompletionsTraceFile("streaming/response.txt");
// Act
var chunks = ParseChatCompletionChunksFromSse(sseContent);
// Find chunks with finish_reason
var chunksWithFinishReason = new List<ChatCompletionChunk>();
foreach (var chunkJson in chunks)
{
var chunk = JsonSerializer.Deserialize(chunkJson.GetRawText(), ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionChunk);
if (chunk?.Choices != null && chunk.Choices.Count > 0 && !string.IsNullOrEmpty(chunk.Choices[0].FinishReason))
{
chunksWithFinishReason.Add(chunk);
}
}
// Assert
Assert.NotEmpty(chunksWithFinishReason);
var lastChunk = chunksWithFinishReason.Last();
Assert.Contains(lastChunk.Choices[0].FinishReason, collection: ["stop", "length", "tool_calls", "content_filter"]);
}
[Fact]
public void ParseStreamingChunks_LastChunkHasUsage()
{
// Arrange
string sseContent = LoadChatCompletionsTraceFile("streaming/response.txt");
// Act
var chunks = ParseChatCompletionChunksFromSse(sseContent);
var lastChunkJson = chunks.Last();
var lastChunk = JsonSerializer.Deserialize(lastChunkJson.GetRawText(), ChatCompletions.ChatCompletionsJsonContext.Default.ChatCompletionChunk);
// Assert
Assert.NotNull(lastChunk);
Assert.NotNull(lastChunk.Usage);
Assert.True(lastChunk.Usage.PromptTokens > 0);
Assert.True(lastChunk.Usage.CompletionTokens > 0);
Assert.Equal(lastChunk.Usage.PromptTokens + lastChunk.Usage.CompletionTokens, lastChunk.Usage.TotalTokens);
}
/// <summary>
/// Helper to parse chat completion chunks from SSE response.
/// </summary>
private static List<JsonElement> ParseChatCompletionChunksFromSse(string sseContent)
{
var chunks = 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("data: ", StringComparison.Ordinal))
{
var jsonData = line.Substring("data: ".Length);
// Skip [DONE] marker
if (jsonData == "[DONE]")
{
continue;
}
try
{
var doc = JsonDocument.Parse(jsonData);
chunks.Add(doc.RootElement.Clone());
}
catch
{
// Skip invalid JSON
}
}
}
return chunks;
}
#endregion
}
@@ -0,0 +1,592 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Linq;
using System.Text.Json;
using Microsoft.Agents.AI.Hosting.OpenAI.Conversations.Models;
using Microsoft.Agents.AI.Hosting.OpenAI.Models;
using Microsoft.Agents.AI.Hosting.OpenAI.Responses.Models;
namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests;
/// <summary>
/// Tests for OpenAI Conversations API model serialization and deserialization.
/// These tests verify that our models correctly serialize to and deserialize from JSON
/// matching the OpenAI wire format, without testing actual API implementation behavior.
/// </summary>
public sealed class OpenAIConversationsSerializationTests
{
private const string TracesBasePath = "ConformanceTraces/Conversations";
/// <summary>
/// Loads a JSON file from the conformance traces directory.
/// </summary>
private static string LoadTraceFile(string relativePath)
{
var fullPath = System.IO.Path.Combine(TracesBasePath, relativePath);
if (!System.IO.File.Exists(fullPath))
{
throw new System.IO.FileNotFoundException($"Conformance trace file not found: {fullPath}");
}
return System.IO.File.ReadAllText(fullPath);
}
#region Request Serialization Tests
[Fact]
public void Deserialize_CreateConversationRequest_Success()
{
// Arrange
string json = LoadTraceFile("basic/create_conversation_request.json");
// Act
CreateConversationRequest? request = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.CreateConversationRequest);
// Assert
Assert.NotNull(request);
Assert.NotNull(request.Metadata);
}
[Fact]
public void Deserialize_CreateConversationWithItems_Success()
{
// Arrange
string json = LoadTraceFile("create_with_items/create_request.json");
// Act
CreateConversationRequest? request = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.CreateConversationRequest);
// Assert
Assert.NotNull(request);
Assert.NotNull(request.Items);
Assert.True(request.Items.Count > 0);
}
[Fact]
public void Deserialize_CreateItemsRequest_Success()
{
// Arrange
string json = LoadTraceFile("add_items/request.json");
// Act
CreateItemsRequest? request = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.CreateItemsRequest);
// Assert
Assert.NotNull(request);
Assert.NotNull(request.Items);
Assert.True(request.Items.Count > 0);
}
[Fact]
public void Deserialize_UpdateConversationRequest_Success()
{
// Arrange
string json = LoadTraceFile("update_conversation/request.json");
// Act
UpdateConversationRequest? request = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.UpdateConversationRequest);
// Assert
Assert.NotNull(request);
Assert.NotNull(request.Metadata);
}
[Fact]
public void Serialize_CreateConversationRequest_MatchesFormat()
{
// Arrange
var request = new CreateConversationRequest
{
Metadata = new System.Collections.Generic.Dictionary<string, string>
{
["test_key"] = "test_value"
}
};
// Act
string json = JsonSerializer.Serialize(request, OpenAIHostingJsonContext.Default.CreateConversationRequest);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert
Assert.True(root.TryGetProperty("metadata", out var metadata));
Assert.Equal(JsonValueKind.Object, metadata.ValueKind);
Assert.Equal("test_value", metadata.GetProperty("test_key").GetString());
}
[Fact]
public void Serialize_CreateConversationRequestWithItems_IncludesItems()
{
// Arrange
var request = new CreateConversationRequest
{
Items =
[
new ResponsesUserMessageItemParam
{
Content = InputMessageContent.FromContents(new ItemContentInputText { Text = "test" })
}
],
Metadata = []
};
// Act
string json = JsonSerializer.Serialize(request, OpenAIHostingJsonContext.Default.CreateConversationRequest);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert
Assert.True(root.TryGetProperty("items", out var items));
Assert.Equal(JsonValueKind.Array, items.ValueKind);
Assert.Equal(1, items.GetArrayLength());
}
[Fact]
public void Serialize_NullableFields_AreOmittedWhenNull()
{
// Arrange
var request = new CreateConversationRequest();
// Act
string json = JsonSerializer.Serialize(request, OpenAIHostingJsonContext.Default.CreateConversationRequest);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert - Optional fields should not be present when null or use null value
// Either the property doesn't exist or it's explicitly null
bool hasItems = root.TryGetProperty("items", out var itemsProp);
if (hasItems)
{
Assert.Equal(JsonValueKind.Null, itemsProp.ValueKind);
}
}
#endregion
#region Response Deserialization Tests
[Fact]
public void Deserialize_Conversation_Success()
{
// Arrange
string json = LoadTraceFile("basic/create_conversation_response.json");
// Act
Conversation? conversation = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.Conversation);
// Assert
Assert.NotNull(conversation);
Assert.StartsWith("conv_", conversation.Id);
Assert.Equal("conversation", conversation.Object);
Assert.True(conversation.CreatedAt > 0);
Assert.NotNull(conversation.Metadata);
}
[Fact]
public void Deserialize_ConversationRoundTrip_PreservesData()
{
// Arrange
string originalJson = LoadTraceFile("basic/create_conversation_response.json");
// Act - Deserialize and re-serialize
Conversation? conversation = JsonSerializer.Deserialize(originalJson, OpenAIHostingJsonContext.Default.Conversation);
string reserializedJson = JsonSerializer.Serialize(conversation, OpenAIHostingJsonContext.Default.Conversation);
Conversation? roundtripped = JsonSerializer.Deserialize(reserializedJson, OpenAIHostingJsonContext.Default.Conversation);
// Assert
Assert.NotNull(conversation);
Assert.NotNull(roundtripped);
Assert.Equal(conversation.Id, roundtripped.Id);
Assert.Equal(conversation.CreatedAt, roundtripped.CreatedAt);
Assert.Equal(conversation.Object, roundtripped.Object);
}
[Fact]
public void Deserialize_ItemListResponse_Success()
{
// Arrange
string json = LoadTraceFile("list_items/response.json");
// Act - The list_items response uses ListResponse<ItemResource>, not ConversationListResponse
ListResponse<ItemResource>? response = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.ListResponseItemResource);
// Assert
Assert.NotNull(response);
Assert.Equal("list", response.Object);
Assert.NotNull(response.Data);
Assert.NotNull(response.FirstId);
Assert.NotNull(response.LastId);
Assert.False(response.HasMore);
}
[Fact]
public void Deserialize_ItemResource_Success()
{
// Arrange
string json = LoadTraceFile("retrieve_item/response.json");
// Act
ItemResource? item = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.ItemResource);
// Assert
Assert.NotNull(item);
Assert.StartsWith("msg_", item.Id);
Assert.Equal("message", item.Type);
var messageItem = Assert.IsType<ResponsesAssistantMessageItemResource>(item);
Assert.NotNull(messageItem.Content);
Assert.NotEmpty(messageItem.Content);
}
[Fact]
public void Deserialize_DeleteResponse_Success()
{
// Arrange
string json = LoadTraceFile("delete_conversation/response.json");
// Act
DeleteResponse? response = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.DeleteResponse);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Id);
Assert.Equal("conversation.deleted", response.Object);
Assert.True(response.Deleted);
}
[Fact]
public void Deserialize_DeleteItemResponse_Success()
{
// Arrange
string json = LoadTraceFile("delete_item/response.json");
// Act
DeleteResponse? response = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.DeleteResponse);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Id);
Assert.Equal("conversation.item.deleted", response.Object);
Assert.True(response.Deleted);
}
[Fact]
public void Deserialize_ErrorResponse_Success()
{
// Arrange
string json = LoadTraceFile("error_conversation_not_found/response.json");
// Act
ErrorResponse? response = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.ErrorResponse);
// Assert
Assert.NotNull(response);
Assert.NotNull(response.Error);
Assert.NotNull(response.Error.Message);
Assert.NotNull(response.Error.Type);
}
[Fact]
public void Deserialize_AllConversationResponses_HaveRequiredFields()
{
// Arrange
string[] responsePaths =
[
"basic/create_conversation_response.json",
"create_with_items/create_response.json",
"retrieve_conversation/response.json",
"update_conversation/response.json"
];
foreach (var path in responsePaths)
{
string json = LoadTraceFile(path);
// Act
Conversation? conversation = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.Conversation);
// Assert
Assert.NotNull(conversation);
Assert.NotNull(conversation.Id);
Assert.Equal("conversation", conversation.Object);
Assert.True(conversation.CreatedAt > 0, $"Conversation from {path} should have created_at");
}
}
[Fact]
public void Deserialize_AllItemResponses_HaveRequiredFields()
{
// Arrange - Use list_items response which has multiple items
string json = LoadTraceFile("list_items/response.json");
ListResponse<ItemResource>? response = JsonSerializer.Deserialize(json, OpenAIHostingJsonContext.Default.ListResponseItemResource);
Assert.NotNull(response);
Assert.NotNull(response.Data);
// Act & Assert
foreach (var item in response.Data)
{
Assert.NotNull(item);
Assert.NotNull(item.Id);
Assert.Equal("message", item.Type);
var messageItem = Assert.IsType<ResponsesMessageItemResource>(item, exactMatch: false);
// Content is on concrete message types (ResponsesAssistantMessageItemResource, etc.)
// For this test, we just verify the type is correct
Assert.NotNull(messageItem);
}
}
[Fact]
public void Serialize_Conversation_MatchesFormat()
{
// Arrange
var conversation = new Conversation
{
Id = "conv_test123",
CreatedAt = 1234567890,
Metadata = new System.Collections.Generic.Dictionary<string, string>
{
["test_key"] = "test_value"
}
};
// Act
string json = JsonSerializer.Serialize(conversation, OpenAIHostingJsonContext.Default.Conversation);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert
Assert.Equal("conv_test123", root.GetProperty("id").GetString());
Assert.Equal("conversation", root.GetProperty("object").GetString());
Assert.Equal(1234567890, root.GetProperty("created_at").GetInt64());
var metadata = root.GetProperty("metadata");
Assert.Equal("test_value", metadata.GetProperty("test_key").GetString());
}
[Fact]
public void Serialize_ConversationListResponse_MatchesFormat()
{
// Arrange
var response = new ListResponse<Conversation>
{
Data =
[
new()
{
Id = "conv_1",
CreatedAt = 1234567890,
Metadata = []
}
],
HasMore = false
};
// Act
string json = JsonSerializer.Serialize(response, OpenAIHostingJsonUtilities.DefaultOptions);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert
Assert.Equal("list", root.GetProperty("object").GetString());
var data = root.GetProperty("data");
Assert.Equal(JsonValueKind.Array, data.ValueKind);
Assert.Equal(1, data.GetArrayLength());
Assert.False(root.GetProperty("has_more").GetBoolean());
}
[Fact]
public void Serialize_DeleteResponse_MatchesFormat()
{
// Arrange
var response = new DeleteResponse
{
Id = "conv_test123",
Object = "conversation.deleted",
Deleted = true
};
// Act
string json = JsonSerializer.Serialize(response, OpenAIHostingJsonContext.Default.DeleteResponse);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert
Assert.Equal("conv_test123", root.GetProperty("id").GetString());
Assert.Equal("conversation.deleted", root.GetProperty("object").GetString());
Assert.True(root.GetProperty("deleted").GetBoolean());
}
[Fact]
public void Serialize_ErrorResponse_MatchesFormat()
{
// Arrange
var response = new ErrorResponse
{
Error = new ErrorDetails
{
Message = "Conversation not found",
Type = "invalid_request_error"
}
};
// Act
string json = JsonSerializer.Serialize(response, OpenAIHostingJsonContext.Default.ErrorResponse);
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert
var error = root.GetProperty("error");
Assert.Equal("Conversation not found", error.GetProperty("message").GetString());
Assert.Equal("invalid_request_error", error.GetProperty("type").GetString());
}
#endregion
#region Integration with Responses API Tests
[Fact]
public void Deserialize_ResponsesAPIRequestWithConversation_Success()
{
// Arrange
string json = LoadTraceFile("basic/first_message_request.json");
// Act
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert - Verify the request has conversation field
Assert.True(root.TryGetProperty("conversation", out var conversation));
var conversationId = conversation.GetString();
Assert.NotNull(conversationId);
Assert.StartsWith("conv_", conversationId);
// Assert - Has standard Responses API fields
Assert.True(root.TryGetProperty("model", out var model));
Assert.True(root.TryGetProperty("input", out var input));
Assert.True(root.TryGetProperty("max_output_tokens", out var maxTokens));
}
[Fact]
public void Deserialize_ResponsesAPIResponseWithConversation_Success()
{
// Arrange
string json = LoadTraceFile("basic/first_message_response.json");
// Act
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert - Verify the response has conversation field
Assert.True(root.TryGetProperty("conversation", out var conversation));
Assert.Equal(JsonValueKind.Object, conversation.ValueKind);
Assert.True(conversation.TryGetProperty("id", out var conversationId));
Assert.NotNull(conversationId.GetString());
// Assert - Has standard Responses API fields
Assert.True(root.TryGetProperty("id", out var responseId));
Assert.True(root.TryGetProperty("object", out var obj));
Assert.Equal("response", obj.GetString());
Assert.True(root.TryGetProperty("status", out var status));
Assert.True(root.TryGetProperty("output", out var output));
}
[Fact]
public void Deserialize_StreamingResponseWithConversation_Success()
{
// Arrange
string sseContent = LoadTraceFile("basic_streaming/first_message_response.txt");
// Act
var events = ParseSseEventsFromContent(sseContent);
// Assert - At least one event should be present
Assert.NotEmpty(events);
// Assert - Check if any event has conversation reference
var createdEvent = events.FirstOrDefault(e =>
e.TryGetProperty("type", out var type) &&
type.GetString() == "response.created");
if (!createdEvent.Equals(default(JsonElement)))
{
Assert.True(createdEvent.TryGetProperty("response", out var response));
// Conversation field may be in the response object
}
}
[Fact]
public void Deserialize_ImageInputWithConversation_Success()
{
// Arrange
string json = LoadTraceFile("image_input/first_message_request.json");
// Act
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert - Verify has conversation and image input
Assert.True(root.TryGetProperty("conversation", out var conversation));
Assert.True(root.TryGetProperty("input", out var input));
Assert.Equal(JsonValueKind.Array, input.ValueKind);
}
[Fact]
public void Deserialize_ToolCallWithConversation_Success()
{
// Arrange
string json = LoadTraceFile("tool_call/first_message_request.json");
// Act
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert - Verify has conversation and tools
Assert.True(root.TryGetProperty("conversation", out var conversation));
Assert.True(root.TryGetProperty("tools", out var tools));
Assert.Equal(JsonValueKind.Array, tools.ValueKind);
}
[Fact]
public void Deserialize_RefusalWithConversation_Success()
{
// Arrange
string json = LoadTraceFile("refusal/first_message_request.json");
// Act
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
// Assert - Verify has conversation
Assert.True(root.TryGetProperty("conversation", out var conversation));
Assert.NotNull(conversation.GetString());
}
/// <summary>
/// Helper to parse SSE events from a streaming response content string.
/// </summary>
private static System.Collections.Generic.List<JsonElement> ParseSseEventsFromContent(string sseContent)
{
var events = new System.Collections.Generic.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;
}
#endregion
}
@@ -0,0 +1,435 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
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.UnitTests;
/// <summary>
/// Integration tests for the HTTP API with in-memory conversation, response, and agent index storage.
/// Tests create a conversation, create a response, wait for completion, then verify the conversation was updated.
/// </summary>
public sealed class OpenAIHttpApiIntegrationTests : IAsyncDisposable
{
private WebApplication? _app;
private HttpClient? _httpClient;
[Fact]
public async Task CreateConversationAndResponse_NonStreaming_NonBackground_UpdatesConversationWithOutputAsync()
{
// Arrange
const string AgentName = "test-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "The capital of France is Paris.";
const string UserMessage = "What is the capital of France?";
HttpClient client = await this.CreateTestServerWithInMemoryStorageAsync(AgentName, Instructions, ExpectedResponse);
// Act - Create conversation
var createConversationRequest = new { metadata = new { agent_id = AgentName } };
string createConvJson = JsonSerializer.Serialize(createConversationRequest);
HttpResponseMessage createConvResponse = await this.SendPostRequestAsync(client, "/v1/conversations", createConvJson);
using var createConvDoc = await this.ParseResponseAsync(createConvResponse);
string conversationId = createConvDoc.RootElement.GetProperty("id").GetString()!;
// Act - Create response (non-streaming, non-background)
var createResponseRequest = new
{
metadata = new { entity_id = AgentName },
conversation = conversationId,
input = UserMessage,
stream = false
};
string createRespJson = JsonSerializer.Serialize(createResponseRequest);
HttpResponseMessage createRespResponse = await this.SendPostRequestAsync(client, $"/{AgentName}/v1/responses", createRespJson);
using var createRespDoc = await this.ParseResponseAsync(createRespResponse);
var response = createRespDoc.RootElement;
// Assert - Response completed
Assert.Equal("completed", response.GetProperty("status").GetString());
string responseId = response.GetProperty("id").GetString()!;
Assert.NotNull(responseId);
Assert.StartsWith("resp_", responseId);
// Assert - Response has output
Assert.True(response.TryGetProperty("output", out var output));
Assert.True(output.GetArrayLength() > 0);
var outputItem = output[0];
var content = outputItem.GetProperty("content");
Assert.True(content.GetArrayLength() > 0);
var textContent = content[0];
Assert.Equal("output_text", textContent.GetProperty("type").GetString());
Assert.Equal(ExpectedResponse, textContent.GetProperty("text").GetString());
// Act - List conversation items to verify they were updated
HttpResponseMessage listItemsResponse = await this.SendGetRequestAsync(client, $"/v1/conversations/{conversationId}/items");
using var listItemsDoc = await this.ParseResponseAsync(listItemsResponse);
var itemsList = listItemsDoc.RootElement;
// Assert - Conversation items were added
Assert.Equal("list", itemsList.GetProperty("object").GetString());
var items = itemsList.GetProperty("data");
Assert.True(items.GetArrayLength() > 0, "Conversation should have items after response completion");
// Find the assistant message in the items
bool foundAssistantMessage = items.EnumerateArray()
.Where(item => item.GetProperty("type").GetString() == "message" &&
item.GetProperty("role").GetString() == "assistant")
.Any(item =>
{
JsonElement itemContent = item.GetProperty("content");
if (itemContent.GetArrayLength() > 0)
{
JsonElement firstContent = itemContent[0];
return firstContent.GetProperty("type").GetString() == "output_text" &&
firstContent.GetProperty("text").GetString() == ExpectedResponse;
}
return false;
});
Assert.True(foundAssistantMessage, "Conversation should contain the assistant's response message");
}
[Fact]
public async Task CreateConversationAndResponse_Streaming_NonBackground_UpdatesConversationWithOutputAsync()
{
// Arrange
const string AgentName = "streaming-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Hello there! How can I help you today?";
const string UserMessage = "Hello";
HttpClient client = await this.CreateTestServerWithInMemoryStorageAsync(AgentName, Instructions, ExpectedResponse);
// Act - Create conversation
var createConversationRequest = new { metadata = new { agent_id = AgentName } };
string createConvJson = JsonSerializer.Serialize(createConversationRequest);
HttpResponseMessage createConvResponse = await this.SendPostRequestAsync(client, "/v1/conversations", createConvJson);
using var createConvDoc = await this.ParseResponseAsync(createConvResponse);
string conversationId = createConvDoc.RootElement.GetProperty("id").GetString()!;
// Act - Create response (streaming, non-background)
var createResponseRequest = new
{
metadata = new { entity_id = AgentName },
conversation = conversationId,
input = UserMessage,
stream = true
};
string createRespJson = JsonSerializer.Serialize(createResponseRequest);
HttpResponseMessage createRespResponse = await this.SendPostRequestAsync(client, $"/{AgentName}/v1/responses", createRespJson);
// Assert - Response is SSE format
Assert.Equal("text/event-stream", createRespResponse.Content.Headers.ContentType?.MediaType);
// Parse SSE events
string sseContent = await createRespResponse.Content.ReadAsStringAsync();
var events = this.ParseSseEvents(sseContent);
// Assert - Has expected event types
var eventTypes = events.Select(e => e.GetProperty("type").GetString()).ToList();
Assert.Contains("response.created", eventTypes);
Assert.Contains("response.completed", eventTypes);
// Collect the full response text from deltas
var deltaEvents = events.Where(e => e.GetProperty("type").GetString() == "response.output_text.delta").ToList();
string streamedText = string.Concat(deltaEvents.Select(e => e.GetProperty("delta").GetString()));
Assert.Equal(ExpectedResponse, streamedText);
// Act - List conversation items to verify messages were added
HttpResponseMessage listItemsResponse = await this.SendGetRequestAsync(client, $"/v1/conversations/{conversationId}/items");
using var listItemsDoc = await this.ParseResponseAsync(listItemsResponse);
var itemsList = listItemsDoc.RootElement;
// Assert - Conversation items were added
var items = itemsList.GetProperty("data");
Assert.True(items.GetArrayLength() > 0, "Conversation should have items after streaming response completion");
// Find the assistant message in the items
bool foundAssistantMessage = items.EnumerateArray()
.Where(item => item.GetProperty("type").GetString() == "message" &&
item.GetProperty("role").GetString() == "assistant")
.Any(item =>
{
JsonElement itemContent = item.GetProperty("content");
if (itemContent.GetArrayLength() > 0)
{
JsonElement firstContent = itemContent[0];
return firstContent.GetProperty("type").GetString() == "output_text" &&
firstContent.GetProperty("text").GetString() == ExpectedResponse;
}
return false;
});
Assert.True(foundAssistantMessage, "Conversation should contain the assistant's response message");
}
[Fact]
public async Task CreateConversationAndResponse_NonStreaming_Background_UpdatesConversationWhenCompleteAsync()
{
// Arrange
const string AgentName = "background-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Processing in background...";
const string UserMessage = "Can you process this?";
HttpClient client = await this.CreateTestServerWithInMemoryStorageAsync(AgentName, Instructions, ExpectedResponse);
// Act - Create conversation
var createConversationRequest = new { metadata = new { agent_id = AgentName } };
string createConvJson = JsonSerializer.Serialize(createConversationRequest);
HttpResponseMessage createConvResponse = await this.SendPostRequestAsync(client, "/v1/conversations", createConvJson);
using var createConvDoc = await this.ParseResponseAsync(createConvResponse);
string conversationId = createConvDoc.RootElement.GetProperty("id").GetString()!;
// Act - Create response (non-streaming, background)
var createResponseRequest = new
{
metadata = new { entity_id = AgentName },
conversation = conversationId,
input = UserMessage,
stream = false,
background = true
};
string createRespJson = JsonSerializer.Serialize(createResponseRequest);
HttpResponseMessage createRespResponse = await this.SendPostRequestAsync(client, $"/{AgentName}/v1/responses", createRespJson);
using var createRespDoc = await this.ParseResponseAsync(createRespResponse);
var response = createRespDoc.RootElement;
// Assert - Response is in progress or queued
string status = response.GetProperty("status").GetString()!;
Assert.True(status is "in_progress" or "queued" or "completed", $"Expected 'in_progress', 'queued', or 'completed', got '{status}'");
string responseId = response.GetProperty("id").GetString()!;
// Wait for completion by polling
const int MaxAttempts = 20;
int attempt = 0;
string finalStatus = status;
string? errorMessage = null;
while (finalStatus != "completed" && finalStatus != "failed" && attempt < MaxAttempts)
{
await Task.Delay(100);
HttpResponseMessage getResponseResponse = await this.SendGetRequestAsync(client, $"/{AgentName}/v1/responses/{responseId}");
using var getRespDoc = await this.ParseResponseAsync(getResponseResponse);
finalStatus = getRespDoc.RootElement.GetProperty("status").GetString()!;
if (getRespDoc.RootElement.TryGetProperty("error", out var error) &&
error.ValueKind == JsonValueKind.Object &&
error.TryGetProperty("message", out var messageElement))
{
errorMessage = messageElement.GetString();
}
attempt++;
}
// Assert - Response eventually completed
Assert.Equal("completed", finalStatus + (errorMessage != null ? $" Error: {errorMessage}" : ""));
// Act - List conversation items to verify messages were added
HttpResponseMessage listItemsResponse = await this.SendGetRequestAsync(client, $"/v1/conversations/{conversationId}/items");
using var listItemsDoc = await this.ParseResponseAsync(listItemsResponse);
var itemsList = listItemsDoc.RootElement;
// Assert - Conversation items were added
var items = itemsList.GetProperty("data");
Assert.True(items.GetArrayLength() > 0, "Conversation should have items after background response completion");
// Find the assistant message in the items
bool foundAssistantMessage = items.EnumerateArray()
.Where(item => item.GetProperty("type").GetString() == "message" &&
item.GetProperty("role").GetString() == "assistant")
.Any(item =>
{
JsonElement itemContent = item.GetProperty("content");
if (itemContent.GetArrayLength() > 0)
{
JsonElement firstContent = itemContent[0];
return firstContent.GetProperty("type").GetString() == "output_text" &&
firstContent.GetProperty("text").GetString() == ExpectedResponse;
}
return false;
});
Assert.True(foundAssistantMessage, "Conversation should contain the assistant's response message");
}
[Fact]
public async Task CreateConversationAndResponse_Streaming_Background_UpdatesConversationWhenCompleteAsync()
{
// Arrange
const string AgentName = "streaming-background-agent";
const string Instructions = "You are a helpful assistant.";
const string ExpectedResponse = "Streaming background response";
const string UserMessage = "Process this with streaming";
HttpClient client = await this.CreateTestServerWithInMemoryStorageAsync(AgentName, Instructions, ExpectedResponse);
// Act - Create conversation
var createConversationRequest = new { metadata = new { agent_id = AgentName } };
string createConvJson = JsonSerializer.Serialize(createConversationRequest);
HttpResponseMessage createConvResponse = await this.SendPostRequestAsync(client, "/v1/conversations", createConvJson);
using var createConvDoc = await this.ParseResponseAsync(createConvResponse);
string conversationId = createConvDoc.RootElement.GetProperty("id").GetString()!;
// Act - Create response (streaming, background)
var createResponseRequest = new
{
model = AgentName,
conversation = conversationId,
input = UserMessage,
stream = true,
background = false // Note: streaming with background=true is typically streaming
};
string createRespJson = JsonSerializer.Serialize(createResponseRequest);
HttpResponseMessage createRespResponse = await this.SendPostRequestAsync(client, $"/{AgentName}/v1/responses", createRespJson);
// Assert - Response is SSE format
Assert.Equal("text/event-stream", createRespResponse.Content.Headers.ContentType?.MediaType);
// Parse SSE events
string sseContent = await createRespResponse.Content.ReadAsStringAsync();
var events = this.ParseSseEvents(sseContent);
var eventTypes = events.Select(e => e.GetProperty("type").GetString()).ToList();
Assert.Contains("response.created", eventTypes);
Assert.Contains("response.completed", eventTypes);
// Act - List conversation items to verify messages were added
HttpResponseMessage listItemsResponse = await this.SendGetRequestAsync(client, $"/v1/conversations/{conversationId}/items");
using var listItemsDoc = await this.ParseResponseAsync(listItemsResponse);
var itemsList = listItemsDoc.RootElement;
// Assert - Conversation items were added
var items = itemsList.GetProperty("data");
Assert.True(items.GetArrayLength() > 0, "Conversation should have items after streaming response completion");
// Find the assistant message in the items
bool foundAssistantMessage = items.EnumerateArray()
.Where(item => item.GetProperty("type").GetString() == "message" &&
item.GetProperty("role").GetString() == "assistant")
.Any(item =>
{
JsonElement itemContent = item.GetProperty("content");
if (itemContent.GetArrayLength() > 0)
{
JsonElement firstContent = itemContent[0];
return firstContent.GetProperty("type").GetString() == "output_text";
}
return false;
});
Assert.True(foundAssistantMessage, "Conversation should contain the assistant's response message");
}
/// <summary>
/// Creates a test server with in-memory conversation, response, and agent index storage.
/// </summary>
private async Task<HttpClient> CreateTestServerWithInMemoryStorageAsync(string agentName, string instructions, string responseText)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder();
builder.WebHost.UseTestServer();
// Create mock chat client
IChatClient mockChatClient = new TestHelpers.SimpleMockChatClient(responseText);
builder.Services.AddKeyedSingleton("chat-client", mockChatClient);
// Add agent
builder.AddAIAgent(agentName, instructions, chatClientServiceKey: "chat-client");
// Add in-memory storage for conversations, responses, and agent index
builder.AddOpenAIConversations();
builder.AddOpenAIResponses();
this._app = builder.Build();
// Map endpoints
AIAgent agent = this._app.Services.GetRequiredKeyedService<AIAgent>(agentName);
this._app.MapOpenAIConversations();
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>
private async Task<HttpResponseMessage> SendPostRequestAsync(HttpClient client, string path, string requestJson)
{
using StringContent content = new(requestJson, Encoding.UTF8, "application/json");
return await client.PostAsync(new Uri(path, UriKind.Relative), content);
}
/// <summary>
/// Sends a GET request to the test server.
/// </summary>
private async Task<HttpResponseMessage> SendGetRequestAsync(HttpClient client, string path)
{
return await client.GetAsync(new Uri(path, UriKind.Relative));
}
/// <summary>
/// Parses the response JSON and returns a JsonDocument.
/// </summary>
private async Task<JsonDocument> ParseResponseAsync(HttpResponseMessage response)
{
string responseJson = await response.Content.ReadAsStringAsync();
return JsonDocument.Parse(responseJson);
}
/// <summary>
/// Parses SSE events from streaming response content string.
/// </summary>
private JsonElement[] ParseSseEvents(string sseContent)
{
var events = new System.Collections.Generic.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);
if (!string.IsNullOrWhiteSpace(jsonData))
{
var doc = JsonDocument.Parse(jsonData);
events.Add(doc.RootElement.Clone());
}
}
}
}
return events.ToArray();
}
public async ValueTask DisposeAsync()
{
this._httpClient?.Dispose();
if (this._app != null)
{
await this._app.DisposeAsync();
}
GC.SuppressFinalize(this);
}
}

Some files were not shown because too many files have changed in this diff Show More