OpenAI Responses: Wires

This commit is contained in:
Enrico Ros
2025-06-24 19:18:01 -07:00
parent f58eae623a
commit d4e158a8b6
@@ -863,3 +863,602 @@ export namespace OpenAIWire_API_Moderations_Create {
});
}
// Chat > Responses API
export namespace OpenAIWire_Responses_InputTypes {
// Input Parts
const InputTextPart_schema = z.object({
type: z.literal('input_text'),
text: z.string(),
});
const InputImagePart_schema = z.object({
type: z.literal('input_image'),
detail: z.enum(['auto', 'low', 'high']).optional(), // defaults to 'auto'
image_url: z.string().optional(), // URL or base64 encoded image in a data URL.
file_id: z.string().optional(),
});
const InputFilePart_schema = z.object({
type: z.literal('input_file'),
file_data: z.string().optional(), // content of the file
file_id: z.string().optional(), // ID of the file
filename: z.string().optional(), // name of the file
});
// Output Parts
export const ContentPartText_schema = z.object({
type: z.literal('output_text'),
text: z.string(),
// NOTE: this could also be file_citation, container_file_citation, file_path
annotations: z.array(z.object({
type: z.literal('url_citation'),
url: z.string(),
title: z.string(),
start_index: z.number().optional(),
end_index: z.number().optional(),
})).optional(),
// Log Probabilities are ignored on purpose
});
export const ContentPartRefusal_schema = z.object({
type: z.literal('refusal'),
refusal: z.string(), // explanation
});
export const ContentPartTextOrRefusal_schema = z.union([
ContentPartText_schema,
ContentPartRefusal_schema,
]);
export const ReasoningPartSummaryText_schema = z.object({
type: z.literal('summary_text'),
text: z.string(), // summary text
});
// Request 'Input' Item
const _InputItem_schema = z.object({
status: z.enum(['incomplete', 'in_progress', 'completed']).optional(),
});
export type UserItemMessage = z.infer<typeof UserItemMessage_schema>;
const UserItemMessage_schema = _InputItem_schema.extend({
type: z.literal('message'),
role: z.enum(['user', 'system', 'developer']),
content: z.array(z.union([
InputTextPart_schema,
InputImagePart_schema,
InputFilePart_schema,
])),
});
// export type ModelItemMessage = z.infer<typeof ModelItemMessage_schema>;
const ModelItemMessage_schema = _InputItem_schema.extend({
type: z.literal('message'),
id: z.string(), // unique ID of the output message
role: z.literal('assistant'),
content: z.array(ContentPartTextOrRefusal_schema),
});
const ReasoningItemMessage_schema = _InputItem_schema.extend({
type: z.literal('reasoning'),
id: z.string(), // unique ID of the reasoning content
summary: z.array(ReasoningPartSummaryText_schema),
encrypted_content: z.string().nullish(),
});
export type FunctionToolCall = z.infer<typeof FunctionToolCall_schema>;
const FunctionToolCall_schema = _InputItem_schema.extend({
type: z.literal('function_call'),
id: z.string().optional(), // unique ID of the function call
call_id: z.string().optional(), // unique ID of the function call generated by the model
name: z.string(), // the name of the function that was requested to run
arguments: z.string().optional(), // JSON string of the arguments to pass to the function
});
export type FunctionToolCallOutput = z.infer<typeof FunctionToolCallOutput_schema>;
const FunctionToolCallOutput_schema = _InputItem_schema.extend({
type: z.literal('function_call_output'),
id: z.string().optional(), // The unique ID of the function tool call output. Populated when this item is returned via API.
output: z.string(), // a JSON string of the output of the function call
call_id: z.string(), // unique ID of the function tool call generated by the model.
});
// Ignoring for now:
// - type: 'file_search_call'
// - type: 'computer_call'
// - type: 'web_search_call'
// - type: 'image_generation_call'
// - type: 'code_interpreter_call'
// - type: 'local_shell_call'
// - type: 'local_shell_call_output'
// - type: 'mcp_list_tools'
// - type: 'mcp_approval_request'
// - type: 'mcp_approval_response'
// - type: 'mcp_call'
/**
* Old-style Item Message, used for compatibility with older APIs.
*
* NOTE: Over time we will move to the 'Item' type below, but it requires tracking lots
* of 3rd party IDs (to messages, reasoning items, calls, etc.), which will be a vendor
* lock-in potentially.
*
* In the meantime this is a way out of that.
*/
const InputMessage_Compat_schema = z.object({
type: z.literal('message'),
role: z.enum(['user', 'assistant', 'system', 'developer']),
content: z.array(z.union([
InputTextPart_schema,
InputImagePart_schema,
InputFilePart_schema,
])),
});
export type InputMessage_Compat = z.infer<typeof InputMessage_Compat_schema>;
// Input Item (combined)
export type InputItem = z.infer<typeof InputItem_schema>;
export const InputItem_schema = z.union([
// Old-style Item Message
InputMessage_Compat_schema,
// Item:
UserItemMessage_schema,
ModelItemMessage_schema,
ReasoningItemMessage_schema,
FunctionToolCall_schema,
FunctionToolCallOutput_schema,
// Item Reference (not used yet):
z.object({
type: z.literal('item_reference'),
id: z.string(), // ID of the item to reference
}),
]);
}
export namespace OpenAIWire_Responses_Tools {
// Custom tool definitions
const CustomFunctionTool_schema = z.object({
type: z.literal('function'),
name: z.string().regex(/^[a-zA-Z0-9_-]{1,64}$/),
description: z.string(), // Used by the model to determine whether or not to call the function.
parameters: z.object({
type: z.literal('object'),
/**
* For stricter validation, use the OpenAPI_Schema.Object_schema
*/
properties: z.record(z.any()).optional(),
required: z.array(z.string()).optional(),
}).optional(),
strict: z.boolean().optional(), // enforce strict parameter validation
});
// Hosted tools definitions
const WebSearchTool_schema = z.object({
type: z.enum(['web_search_preview', 'web_search_preview_2025_03_11']),
search_context_size: z.enum(['low', 'medium', 'high']).optional(),
user_location: z.object({
type: z.literal('approximate'),
city: z.string().optional(),
country: z.string().optional(),
region: z.string().optional(),
timezone: z.string().optional(),
}).optional(),
});
// Combined tools
export type Tool = z.infer<typeof Tool_schema>;
export const Tool_schema = z.union([
// custom function tools
CustomFunctionTool_schema,
// hosted tools
WebSearchTool_schema,
// CodeInterpreterTool_schema,
// ComputerUseTool_schema,
// FileSearchTool_schema,
// ImageGenerationTool_schema,
// LocalShellTool_schema,
// MCPTool_schema,
]);
export const ToolChoice_schema = z.union([
z.literal('none'), // do not call any tool
z.literal('auto'), // pick between generating a message or calling 1+ tools
z.literal('required'), // must call 1+ tools
z.object({ // function tool
type: z.literal('function'),
name: z.string(),
}),
z.object({ // hosted tool
type: z.enum([
// 'file_search',
'web_search_preview',
// 'computer_use_preview',
// 'code_interpreter',
// 'mcp',
// 'image_generation',
// 'local_shell' ?
]),
}),
]);
}
export namespace OpenAIWire_API_Responses {
/// Request
export type Request = z.infer<typeof Request_schema>;
export const Request_schema = z.object({
// Input
input: z.array(OpenAIWire_Responses_InputTypes.InputItem_schema),
instructions: z.string().nullish(),
// Model configuration
model: z.string(),
max_output_tokens: z.number().int().positive().nullish(),
temperature: z.number().min(0).nullish(), // [OpenAI] Defaults to 1, max: 2
top_p: z.number().min(0).nullish(), // [OpenAI] Defaults to 1, max: 1
// Tools
tools: z.array(OpenAIWire_Responses_Tools.Tool_schema).optional(),
tool_choice: OpenAIWire_Responses_Tools.ToolChoice_schema.optional(),
parallel_tool_calls: z.boolean().nullish(),
// configure text output
text: z.object({
format: z.union([
z.object({ type: z.literal('text') }),
z.object({
type: z.literal('json_schema'),
name: z.string(), // The name of the response format. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.
description: z.string().optional(), // A description of what the response format is for, used by the model to determine how to respond in the format.
schema: z.record(z.any()), // JSON Schema object
strict: z.boolean().nullish(), // only a subset of JSON Schema is supported when strict is true
}),
// z.object({ type: z.literal('json_object') }), // deprecated
]).optional(),
}).optional(),
// configure reasoning
reasoning: z.object({
effort: z.enum(['low', 'medium', 'high']).nullish(), // defaults to 'medium'
summary: z.enum(['auto', 'concise', 'detailed']).nullish(),
}).nullish(),
// State management (we won't use this for stateless)
// store: z.boolean().nullish(),
// previous_response_id: z.string().nullish(),
// API options
stream: z.boolean().nullish(),
background: z.boolean().nullish(),
truncation: z.enum(['auto', 'disabled']).nullish(), // defaults to 'disabled', 'auto' drops input items in the middle of the conversation.
user: z.string().optional(), // stable identifier for your end-users
// Unused
// include: z.array(z.string()).nullish(), // additional output to include in the response: 'file_search_call.results', 'message.input_image.image_url', 'computer_call_output.output.image_url', 'reasoning.encrypted_content', 'code_interpreter_call.outputs'
// metadata: z.record(z.any()).optional(), // set of 16 key-value pairs that can be attached to an object
// service_tier: z.enum(['auto', 'default', 'flex', 'priority']).nullish(),
// prompt: z.object({
// id: z.string(),
// version: z.string().optional(),
// variables: z.record(z.any()).optional(),
// }).optional(),
});
/// Response - NS
const _OutputItemStatus_schema = z.enum(['in_progress', 'completed', 'incomplete']);
const MessageItemOutput_schema = z.object({
type: z.literal('message'),
id: z.string(), // unique ID of the output item
role: z.literal('assistant'),
content: z.array(OpenAIWire_Responses_InputTypes.ContentPartTextOrRefusal_schema),
status: _OutputItemStatus_schema.optional(),
});
const ReasoningItemOutput_schema = z.object({
type: z.literal('reasoning'),
id: z.string(), // unique ID of the output item
summary: z.array(OpenAIWire_Responses_InputTypes.ReasoningPartSummaryText_schema).nullish(), // summary of the reasoning
encrypted_content: z.string().nullish(), // populated when a response is generated with reasoning.encrypted_content in the include
status: _OutputItemStatus_schema.optional(),
});
const FunctionCallOutput_schema = z.object({
type: z.literal('function_call'),
id: z.string(), // unique ID of the function tool call (output item ID)
arguments: z.string(), // JSON string of the arguments to pass to the function
call_id: z.string(), // unique ID of the function tool call -- same as ID? verify
name: z.string(), // name of the function to call
status: _OutputItemStatus_schema.optional(),
});
const ImageGenerationCallOutput_schema = z.object({
type: z.literal('image_generation_call'),
id: z.string(), // unique ID of the image generation call (output item ID)
result: z.string().nullish(), // base64 image data
status: _OutputItemStatus_schema.optional(),
});
// NS combined output
const OutputItem_schema = z.union([
MessageItemOutput_schema,
ReasoningItemOutput_schema,
FunctionCallOutput_schema,
ImageGenerationCallOutput_schema,
// FileSearchCallOutput_schema,
// WebSearchCallOutput_schema,
// ComputerUseCallOutput_schema,
// CodeInterpreterCallOutput_schema,
// LocalShellCallOutput_schema,
// MCPToolCallOutput_schema,
// MCPListToolsOutput_schema,
// MCPApprovalRequestOutput_schema,
]);
export type ResponseNS = z.infer<typeof ResponseNS_schema>;
export const ResponseNS_schema = z.object({
object: z.literal('response'),
id: z.string(), // unique ID for this response
created_at: z.number(), // unix timestamp (in seconds)
status: z.enum(['completed', 'failed', 'in_progress', 'cancelled', 'queued', 'incomplete']),
incomplete_details: z.object({ reason: z.string() }).nullish(), // why the response is incomplete
error: z.object({ code: z.string(), message: z.string() }).nullish(),
model: z.string(), // model used for the response
output: z.array(OutputItem_schema),
usage: z.object({
input_tokens: z.number(),
output_tokens: z.number(),
total_tokens: z.number(),
input_tokens_details: z.object({
cached_tokens: z.number().optional(),
}).optional(),
output_tokens_details: z.object({
reasoning_tokens: z.number().optional(),
}).optional(),
}).optional(),
// NOTE: the following fields seem an exact echo of what's in the request - let's ignore these for now
// background: ...
// instructions: ...
// max_output_tokens: ...
// metadata: ...
// parallel_tool_calls: ...
// previous_response_id: ...
// prompt: ...
// reasoning: ...
// service_tier: ...
// temperature: ...
// text: ...
// tool_choice: ...
// tools: ...
// top_p: ...
// truncation: ...
// user: ...
});
// Response - Streaming Events
const _BaseEvent_schema = z.object({
sequence_number: z.number(),
});
// Streaming > Response lifecycle
const ResponseCreatedEvent_schema = _BaseEvent_schema.extend({
type: z.literal('response.created'),
response: ResponseNS_schema,
});
const ResponseInProgress_schema = _BaseEvent_schema.extend({
type: z.literal('response.in_progress'),
response: ResponseNS_schema,
});
const ResponseCompletedEvent_schema = _BaseEvent_schema.extend({
type: z.literal('response.completed'),
response: ResponseNS_schema,
});
// finishes as failed
const ResponseFailedEvent_schema = _BaseEvent_schema.extend({
type: z.literal('response.failed'),
response: ResponseNS_schema,
});
// finishes as incomplete
const ResponseIncompleteEvent_schema = _BaseEvent_schema.extend({
type: z.literal('response.incomplete'),
response: ResponseNS_schema,
});
// Streaming > Output item
const _OutputItemEvent_schema = _BaseEvent_schema.extend({
output_index: z.number(), // identifies the output item in the response
});
const OutputItemAddedEvent_schema = _OutputItemEvent_schema.extend({
type: z.literal('response.output_item.added'),
item: OutputItem_schema,
});
const OutputItemDoneEvent_schema = _OutputItemEvent_schema.extend({
type: z.literal('response.output_item.done'),
item: OutputItem_schema,
});
const _OutputIndexedEvent_schema = _OutputItemEvent_schema.extend({
item_id: z.string(), // items[output_index].id
});
// Streaming > Output Item > Content Part
const _PartIndexedEvent_schema = _OutputIndexedEvent_schema.extend({
content_index: z.number(), // identifies the content part in the output item
});
const ContentPartAddedEvent_schema = _PartIndexedEvent_schema.extend({
type: z.literal('response.content_part.added'),
part: OpenAIWire_Responses_InputTypes.ContentPartTextOrRefusal_schema,
});
const ContentPartDoneEvent_schema = _PartIndexedEvent_schema.extend({
type: z.literal('response.content_part.done'),
part: OpenAIWire_Responses_InputTypes.ContentPartTextOrRefusal_schema,
});
const OutputTextDeltaEvent_schema = _PartIndexedEvent_schema.extend({
type: z.literal('response.output_text.delta'),
delta: z.string(),
});
const OutputTextDoneEvent_schema = _PartIndexedEvent_schema.extend({
type: z.literal('response.output_text.done'),
text: z.string(),
});
const OutputRefusalDeltaEvent_schema = _PartIndexedEvent_schema.extend({
type: z.literal('response.output_refusal.delta'),
delta: z.string(),
});
const OutputRefusalDoneEvent_schema = _PartIndexedEvent_schema.extend({
type: z.literal('response.output_refusal.done'),
refusal: z.string(),
});
const OutputTextAnnotationAddedEvent_schema = _PartIndexedEvent_schema.extend({
type: z.literal('response.output_text_annotation.added'),
annotation_index: z.number(),
annotation: z.any(), // will spec later
});
const OutputResponseReasoningDeltaEvent_schema = _PartIndexedEvent_schema.extend({
type: z.literal('response.reasoning.delta'),
delta: z.any(), // will spec later - seems { text: string } from the spec? smells
});
const OutputResponseReasoningDoneEvent_schema = _PartIndexedEvent_schema.extend({
type: z.literal('response.reasoning.done'),
text: z.string(), // finalized reasoning text
});
// Streaming > Output Item > Reasoning Summary
const _SummaryIndexedEvent_schema = _OutputIndexedEvent_schema.extend({
summary_index: z.number(), // identifies the reasoning summary in the output item
});
const OutputReasoningSummaryDeltaEvent_schema = _SummaryIndexedEvent_schema.extend({
type: z.literal('response.reasoning_summary.delta'),
delta: z.any(), // object // will spec later
});
const OutputReasoningSummaryDoneEvent_schema = _SummaryIndexedEvent_schema.extend({
type: z.literal('response.reasoning_summary.done'),
text: z.string(), // finalized reasoning summary text.
});
const OutputReasoningSummaryPartAddedEvent_schema = _SummaryIndexedEvent_schema.extend({
type: z.literal('response.reasoning_summary_part.added'),
part: OpenAIWire_Responses_InputTypes.ReasoningPartSummaryText_schema,
});
const OutputReasoningSummaryPartDoneEvent_schema = _SummaryIndexedEvent_schema.extend({
type: z.literal('response.reasoning_summary_part.done'),
part: OpenAIWire_Responses_InputTypes.ReasoningPartSummaryText_schema,
});
const OutputReasoningSummaryTextDeltaEvent_schema = _SummaryIndexedEvent_schema.extend({
type: z.literal('response.reasoning_summary_text.delta'),
delta: z.string(),
});
const OutputReasoningSummaryTextDoneEvent_schema = _SummaryIndexedEvent_schema.extend({
type: z.literal('response.reasoning_summary_text.done'),
text: z.string(), // final summary text
});
// Streaming > Output Item: Function Call Arguments
const FunctionCallArgumentsDeltaEvent_schema = _OutputIndexedEvent_schema.extend({
type: z.literal('response.function_call_arguments.delta'),
delta: z.string(),
});
const FunctionCallArgumentsDoneEvent_schema = _OutputIndexedEvent_schema.extend({
type: z.literal('response.function_call_arguments.done'),
arguments: z.string(), // JSON string of the arguments to pass to the function
});
// Streaming > Output Item: Ignoring:
// - file_search_call.*
// - web_search_call.*
// - image_generation_call.*
// - mcp_call.*, mcp_list_tools.*
// - code_interpreter_call.*, code_interpreter_call_code.*
// Error event
const ErrorEvent_schema = _BaseEvent_schema.extend({
type: z.literal('error'),
code: z.string().nullish(),
message: z.string(),
param: z.string().nullish(),
});
// Combined streaming event
export type StreamingEvent = z.infer<typeof StreamingEvent_schema>;
export const StreamingEvent_schema = z.discriminatedUnion('type', [
ResponseCreatedEvent_schema,
ResponseInProgress_schema,
ResponseCompletedEvent_schema,
ResponseFailedEvent_schema,
ResponseIncompleteEvent_schema,
OutputItemAddedEvent_schema,
OutputItemDoneEvent_schema,
ContentPartAddedEvent_schema,
ContentPartDoneEvent_schema,
OutputTextDeltaEvent_schema,
OutputTextDoneEvent_schema,
OutputRefusalDeltaEvent_schema,
OutputRefusalDoneEvent_schema,
OutputTextAnnotationAddedEvent_schema,
OutputResponseReasoningDeltaEvent_schema,
OutputResponseReasoningDoneEvent_schema,
OutputReasoningSummaryDeltaEvent_schema,
OutputReasoningSummaryDoneEvent_schema,
OutputReasoningSummaryPartAddedEvent_schema,
OutputReasoningSummaryPartDoneEvent_schema,
OutputReasoningSummaryTextDeltaEvent_schema,
OutputReasoningSummaryTextDoneEvent_schema,
FunctionCallArgumentsDeltaEvent_schema,
FunctionCallArgumentsDoneEvent_schema,
ErrorEvent_schema,
]);
}