AgentHub uses UniConfig, UniMessage, and UniEvent to represent request options, conversation history, and streamed outputs across providers.
UniConfig is the request config for streamingResponse and streamingResponseStateful. All fields are optional.
const config = {
max_tokens: 1024,
temperature: 1.0,
tools: [{
name: "get_weather",
description: "Get weather.",
parameters: {
type: "object",
properties: { location: { type: "string", description: "City name." } },
required: ["location"],
},
}],
tool_choice: "auto",
thinking_summary: true,
thinking_level: ThinkingLevel.HIGH,
system_prompt: "You are helpful.",
prompt_caching: PromptCaching.ENABLE,
image_config: { aspect_ratio: "4:3", image_size: "1K" },
tts_config: [{ voice: "Kore" }],
embedding_config: { dimensions: 768 },
trace_id: "agent1/conversation_001",
};Fields:
max_tokens(number): Output token limit.temperature(number): Sampling temperature; support varies by model.tools(ToolSchema[]): Tools withname,description, and optional JSON Schemaparameters.thinking_summary(boolean): Request a thinking summary when supported.thinking_level(ThinkingLevel):NONE,LOW,MEDIUM,HIGH, orXHIGH.tool_choice(ToolChoice):auto,required,none, or a list of tool names; support varies by model.system_prompt(string): System instruction text.prompt_caching(PromptCaching):ENABLE,DISABLE, orENHANCE.image_config(ImageConfig):aspect_ratio(1:1,2:3,3:2,3:4,4:3,9:16,16:9,21:9) andimage_size(1K,2K).tts_config(SpeakerConfig[]): Voice config; each item hasvoiceand optionalspeaker.embedding_config(EmbeddingConfig): Embedding config, currentlydimensions.trace_id(string): Stable ID for tracer output.
UniMessage is the durable message shape used in history.
const message = {
role: "user",
content_items: [
{ type: "text", text: "Hello", fidelity: { phase: "commentary" } },
{ type: "image_url", image_url: "https://example.com/image.jpg" },
{ type: "inline_data", data: Buffer.from("..."), mime_type: "image/png", fidelity: { signature: "sig" } },
{ type: "thinking", thinking: "Reasoning", fidelity: { signature: "sig" } },
{ type: "inline_thinking", data: Buffer.from("..."), mime_type: "image/png", fidelity: { signature: "sig" } },
{ type: "tool_call", name: "get_weather", arguments: { location: "Paris" }, tool_call_id: "call_1", fidelity: { signature: "sig" } },
{ type: "tool_result", text: "22 C", tool_call_id: "call_1" },
{ type: "embedding", embedding: [0.1, 0.2] },
],
};Fields:
role(Role):userorassistant.content_items(ContentItem[]): Message payload.usage_metadata(UsageMetadata | null): Optional token counts on completed assistant messages.finish_reason(FinishReason | null):stop,length,tool_call,unknown, ornull.created_at(number): Unix milliseconds.
Content items:
text: Text chunk; may carryfidelity.image_url: Image URL or data URI.inline_data: Inline media bytes with MIME type; may carryfidelity.thinking: Text reasoning content; may carryfidelity.inline_thinking: Binary reasoning artifact; may carryfidelity.tool_call: Complete model tool request with name, args, ID, and optionalfidelity.tool_result: Tool output text for atool_call_id; may include image URLs.embedding: Numeric embedding vector.
fidelity is an arbitrary JSON object of wire-level data the client recorded to reproduce the original message on replay — thinking signatures, phase labels, the upstream reasoning field name, and the like. It is opaque: pass it back unchanged, never modify or drop it.
UniEvent is the streamed output shape. Read token counts from usage_metadata here.
const event = {
role: "assistant",
event_type: "delta",
content_items: [
{ type: "partial_tool_call", name: "get_weather", arguments: "{\"location\":\"Par", tool_call_id: "call_1" },
],
usage_metadata: { cached_tokens: 0, prompt_tokens: 10, thoughts_tokens: null, response_tokens: 1 },
finish_reason: null,
created_at: 1694502400000,
};Fields:
role(Role):userorassistant.event_type(EventType):start,delta,stop, orunused.content_items(PartialContentItem[]): Stream payload; includesContentItempluspartial_tool_call.usage_metadata(UsageMetadata | null): Token counts:cached_tokens,prompt_tokens,thoughts_tokens,response_tokens. Token math:input = cached_tokens + prompt_tokens;output = thoughts_tokens + response_tokens; treatnullas0.finish_reason(FinishReason | null):stop,length,tool_call,unknown, ornull.created_at(number): Unix milliseconds.
Event-only content item:
partial_tool_call: Streaming tool-call fragment withname, partial JSONarguments, andtool_call_id.
Across providers a tool call streams as the same ordered sequence of events, so consumers handle every model the same way:
- Announce (name + id first). The first event for a tool call carries a
partial_tool_callwhosenameandtool_call_idare non-empty and whoseargumentsis a JSON string fragment (often""). The tool's identity arrives no later than the first argument bytes. - Argument deltas. Zero or more
deltaevents follow, each carrying apartial_tool_callwhoseargumentsis the next fragment of the arguments JSON string (nameandtool_call_idare empty""). Concatenate the fragments in order. - Complete call (last). One final event carries a complete
tool_callitem:name,tool_call_id, andargumentsparsed into an object. Read tool calls from thesetool_callitems; treat thepartial_tool_callfragments as live progress only.
The final arguments value must parse to a JSON object. If the streamed JSON is malformed, truncated, or parses to a non-object value such as an array, AgentHub raises ToolCallArgumentParseError instead of yielding a complete tool_call. The error carries client, toolName, toolCallId, rawArgumentsLength, and rawArgumentsPreview so the caller can log the bad model output and retry or re-prompt without executing a tool from partial arguments.
For consecutive or parallel tool calls, each new call restarts at step 1 with its own name and tool_call_id, so one call's arguments never bleed into the next. Send each tool result back with the exact tool_call_id from its tool_call.
Errors thrown by AgentHub inherit AgentHubError, an Error subclass:
ToolCallArgumentParseError— streamed tool-call arguments were malformed or not a JSON object. It carriesclient,toolName,toolCallId,rawArgumentsLength, andrawArgumentsPreview.EmptyResponseError— the response finished with thinking content only, which fails with a 400 error when sent back on the next turn. It carriesclientandfinishReason.