TypeScript SDK
Required Configuration
All TypeScript snippets on this page use an API key that is validated at application startup:
Prerequisites
Step 1: Install
Source repository: joytoken-sdk-ts/client-sdk-ts
The package is distributed directly from GitHub and is not published to the npm registry. Pin a release tag or commit for reproducible production builds.
Step 2: Choose a Protocol
OpenAI
Anthropic
Non-streaming
Streaming
Orchestration responses
A model: "auto" request may be handled by an orchestrating gateway that plans and runs several sub-tasks (search, reasoning, and a final answer) before replying. The SDK aggregates this for you—it does not hand back a raw JSON string to parse.
Non-streaming
create() returns the final answer as plain text in choices[0].message.content, exactly like a normal completion. The full breakdown is attached separately on response.orchestration:
orchestrationis present only when the turn was orchestrated; a plain completion omits it.orchestration.planis the announced list of sub-tasks (when the gateway sent one).orchestration.stagesrecords every sub-task in arrival order, each with its own aggregatedcontent.
Streaming
On the wire the gateway first emits a planning event (a chunk whose orchestration.phase is planning, carrying the ordered plan) followed by the __planner__ metadata event, then delivers each sub-task’s full content as one chunk that carries an orchestration field (task_id, task_seq, task_status, title), each followed by a single standalone metadata event (one object, not an array). Rather than decode this raw shape yourself, use runStream() (below), which normalizes it into onOrchestrationEvent callbacks and filters onTextDelta down to the final answer. If you consume the raw stream() iterator, branch on the sentinel ORCHESTRATION_FINAL_TASK_ID from the aggregated result to isolate the user-facing answer.
Streaming with progress callbacks
runStream() filters text for you—onTextDelta receives only the final-answer text—while onOrchestrationEvent reports the plan announcement and per-sub-task lifecycle:
If the orchestration run fails, the gateway returns an error envelope ({ "error": { ... }, "choices": [] }). The SDK detects this on both streaming and non-streaming Chat paths and throws a JoyTokenAPIError instead of yielding an empty reply.
Choose an execution entry point
When no request tools and no Client-registered tools exist, create() may automatically run SDK default local tools. This is the only automatic tool execution allowed on a primitive method.
Tool ownership and precedence
Tool ownership depends on whether request.tools is undefined.
If a user tool has the same name as a default, the user declaration and user handler win. The SDK never falls back to a same-name default implementation.
Register and run a handler
Use create() instead when you want the returned tool_calls but will execute them elsewhere.
Preserve provider tool metadata
ToolCall.extra_content contains opaque, provider-specific extension data. SDK-managed run() / executeTools() loops and their streaming variants preserve it across Chat Completions, Responses, and Anthropic Messages continuations. For example, Gemini function calls can include extra_content.google.thought_signature; the SDK does not inspect, modify, or manufacture this value.
The SDK also captures a top-level thought_signature returned directly on the tool call as ToolCall.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; the SDK preserves it verbatim through Chat, Responses, Messages, streaming, and Agent tool loops, and it must be echoed back unchanged on the continuation turn or the provider rejects the request (previously surfaced as a 503).
If your application owns the tool loop, replay the complete assistant ToolCall, Responses function_call, or Messages tool_use item returned by the SDK. Rebuilding an item with only id and function can discard provider-required continuation metadata.
Default local tools
Defaults are selected only when request and Client tools are both absent.
Do not use a broad or sensitive workspace. Approval callbacks authorize one side effect; they do not replace process-level filesystem or OS isolation.
Responses hosted tools
Hosted tools are distinct from local function tools and are disabled by default.
Hosted file search requires explicit vector stores:
{ type: "function", name: "file_search", ... } is a local function declaration. { type: "file_search", vector_store_ids: [...] } is a hosted Responses tool. The SDK never creates vector store IDs.
Step 3: Model List
Use { locale: "zh" } for Chinese descriptions. Omitting locale leaves the API default of English. Catalog entries are in models.data.models.
