Go SDK
Prerequisites
Step 1: Install
Source repository: joytoken-sdk-go
The module is distributed directly from GitHub. Pin a release tag for reproducible production builds.
The examples below assume these imports:
Create a context inside the calling function:
Step 2: Choose a Protocol Interface
OpenAI
Anthropic
WithAPIBaseURL derives <base>/openai/v1. Use WithOpenAIBaseURL only when the model API URL must be overridden.
Chat Completions
Chat SSE may include a metadata/usage-only event with no choices. The SDK
preserves it and normalizes chunk.Choices to an empty slice. Iterate as
above or check len(chunk.Choices) before indexing; never access
chunk.Choices[0] unconditionally. If protocol-level usage is absent, token
counts fall back to metadata.billing.
Responses
CreateResponse and StreamResponse preserve native Responses output items and events.
The explicit non-nil empty Tools slice keeps these connectivity examples tool-free. Remove it to enable SDK fallback tools, or replace it with your own exact declarations.
Orchestration responses
A model: "auto" request may be handled in orchestration (multi-task planning) mode. The SDK returns the raw gateway shape, so branch on it:
Choices[0].Message.Contentis a JSON-encoded array of per-task outputs ({ "title", "content" }), not a plain string.json.Unmarshalit before rendering; the top-levelplanfield confirms orchestration mode.metadatais an array with one entry per task (including reserved__planner__/__final__). Sumbilling.credits_usedacross entries for total cost, rather than reading a singlemetadata.billingobject.- When streaming, a planning event arrives first (a chunk whose
orchestration.phaseisplanning, carrying the orderedplan), followed by the__planner__metadata event. Then each task’s full content arrives as a chunk that carries anorchestrationfield (task_id,task_seq,task_status,title), each followed by one standalone metadata event (a single object, not an array).
See Examples → Orchestration for full parsing code and Routing for the field reference.
Step 3: List models
Use joytoken.ModelLocaleZH for Chinese descriptions. ListModels(ctx) leaves locale unset, so the API defaults to English. Catalog entries are in models.Data.Models.
Tool calling
The SDK keeps caller-owned tools separate from its fallback tools. It resolves exactly one source for each request:
An explicit empty slice means send no tools. Registered tools replace defaults; they are not merged. Continuation turns carry the same resolved declarations exactly once.
Choose a method
Primitive Create* methods automatically continue only when priority 3 selected SDK-owned defaults. Passing request tools or registering Client tools keeps Create* single-pass.
Request-level declarations contain no Go handler. To execute one through Run*, also register a handler with the same function name. A missing handler is returned to the model as a structured tool error; the SDK never guesses or invokes arbitrary code.
Register and execute a tool
Register tools with joytoken.WithToolHandler (or joytoken.WithTools) when constructing the client:
Default fallback tools
When no caller-owned tools exist, the SDK offers seven local tools:
Hosted Responses tools run upstream rather than in Go. WithDefaultBuiltinTools(true) opts into web_search_preview only and is disabled by default. Hosted file_search is never synthesized because it requires caller-provided vector_store_ids.
A successful hosted search includes a web_search_call output item. Check the returned output items rather than treating HTTP success alone as confirmation that a hosted tool ran.
Send exact tool types supported by the Gateway. Do not send web_search, web_search_20250305, and web_search_preview together as aliases; an unknown type may be rejected before model routing.
Side-effecting tools are gated
file_write and shell are always declared to the model but never run without host approval. Install a permission callback to make them runnable; with none configured, the model sees the capability yet every invocation is refused at execution time (fail-safe).
If you never need a tool at all, you can remove it from the default set entirely (rather than just gating it):
WithoutDefaultTools never filters caller-registered tools.
Loop results and diagnostics
RunChatResult reports FinalText, Messages, per-turn Steps, StoppedBy, and a provider-neutral FinishReason. malformed_function_call identifies a model that repeatedly emitted invalid tool-call payloads instead of a clean empty answer. Run loops keep the resolved tools on continuation turns and relax a forced ToolChoice to auto after the first tool call so the model can finish naturally.
Provider tool metadata
Some providers attach opaque metadata to a tool call that must be returned unchanged on the next turn. JoyToken Go SDK v0.1.3 and later exposes it as ToolCall.ExtraContent and preserves it through Chat, Responses, Messages, streaming, and Agent tool loops. For example, Gemini function calls may carry extra_content.google.thought_signature.
The SDK also captures a top-level thought_signature returned directly on the tool call as ToolCall.ThoughtSignature (serialized as thought_signature), distinct from the nested extra_content form. Gemini via the gateway Chat Completions endpoint returns it at the top level of the tool_call; it must be echoed back verbatim on the continuation turn or the provider rejects the request (previously surfaced as a 503).
The automatic Run* methods preserve this field without interpreting it. In a manual loop, append the complete assistant message or returned ToolCall; do not rebuild a call from only ID, Type, and Function.
If a later model turn fails, every explicit Run* method returns both the error and a non-nil partial result. Inspect its completed Steps and accumulated Messages or Input before deciding whether to retry or resume.
For production diagnostics, log the Gateway request ID, response metadata, tool source (request / Client / default), tool name, step, and stop reason. Never log API keys or unredacted sensitive tool inputs.
Read request IDs with response.RequestID(), chunk.RequestID(), or
joytoken.RequestIDFromMetadata(metadata). The SDK preserves body
metadata.request_id and uses a successful response header as a fallback when
one is available. Chat, Responses, and Messages also derive missing token usage
from metadata.billing; an explicit protocol usage object always wins.
Timeouts and retries
Requests and streams time out after 60 seconds by default. WithTimeout changes the whole-operation timeout; a non-positive duration disables it.
Automatic retries are disabled by default because model POSTs are not inherently idempotent. WithMaxRetries(n) opts into retries for HTTP 429, 5xx, and transport failures with bounded backoff, jitter, and Retry-After support. Enable it only when duplicate execution or billing risk is acceptable.
