xai-org/xai-sdk-ts
TypeScript
Captured source
source ↗xai-org/xai-sdk-ts
Description: The official TypeScript SDK for the xAI API
Language: TypeScript
License: Apache-2.0
Stars: 0
Forks: 0
Open issues: 0
Created: 2026-08-26T16:09:05Z
Pushed: 2026-09-29T23:50:16Z
Default branch: main
Fork: no
Archived: no
README:
Use Grok from TypeScript with a typed, ESM client built on the xAI REST API. The SDK has no runtime dependencies and includes streaming, structured output, function tools, image input, image and video generation, file uploads, batch processing, text to speech and transcription, multi-turn conversations, and access to usage and HTTP metadata.
> Experimental. This SDK is in early development. It currently covers the Responses API, image and video generation, the Files, Batch, and Voice APIs, tokenization, and model and account lookup, and its interfaces may change between releases before 1.0. Pin an exact version and read the [changelog](./CHANGELOG.md) when upgrading. Feedback and bug reports are welcome in issues.
Requirements
- Node.js 22.13 or later
- An xAI API key
- An ESM project
Installation
Install the package with your preferred package manager:
npm install @xai-official/sdk
pnpm add @xai-official/sdk
Quickstart
Set your API key in the environment. The client reads XAI_API_KEY automatically.
export XAI_API_KEY="your-api-key"
import { xAI } from "@xai-official/sdk";
const client = new xAI();
const response = await client.responses.create({
model: "grok-4.7",
input: "Explain why the sky is blue in one sentence.",
});
console.log(response.toText());Keep API keys on the server. The SDK blocks browser and Worker use by default because shipping a secret key to client-side code exposes it to users.
Streaming
Set stream: true to receive output as it's generated. Listen for answer text with on("text"), then await stream.done() for the final response:
const stream = await client.responses.create({
model: "grok-4.7",
input: "Write a short story about a curious robot.",
stream: true,
});
const response = await stream
.on("text", (text) => process.stdout.write(text))
.done();
console.log(`\n${response.usage.total_tokens} tokens`);done() resolves to the same response object a non-streamed request returns. It rejects if the stream fails or closes before the response completes.
Besides "text", on() has helper events for the rest of a response:
"reasoning"for each chunk of reasoning text or reasoning summary"tool_call"for each tool call once its arguments are complete, whether your code or xAI runs it. Checkcall.typeto tell them apart"client_tool_call"for each call that your code runs: your function tools and shell commands"server_tool_call"for each call to a tool that xAI runs, such as web search or code execution"image"for each finished image generation call, with the base64 image inresult"citation"for each URL citation in the answer
Each tool call fires once, when its arguments are complete. For your function tools, that's when to run the function, since nothing has run it yet. To show that a call has started before its arguments arrive, listen for "response.output_item.added".
const response = await stream
.on("reasoning", (text) => process.stderr.write(text))
.on("text", (text) => process.stdout.write(text))
.on("tool_call", (call) => console.error(`\n${call.type} ${call.status}`))
.done();on() also takes any server-sent event type, such as "response.completed", and passes the listener the typed event. Events the SDK doesn't recognize arrive as "unknown", with the original payload in event.raw.
You can also iterate over the stream to handle events in a loop. After the loop, done() resolves right away with the final response:
for await (const event of stream) {
if (event.type === "response.function_call_arguments.delta") {
process.stdout.write(event.delta);
}
}
const response = await stream.done();
console.log(response.toText());stream.http has the HTTP status, headers, and request IDs as soon as create() returns.
If you stop consuming a stream early, call await stream.close() to cancel its response body.
Multi-turn conversations
Responses are not stored by default. Use toInput() to carry the model output, including encrypted reasoning content, into the next turn. Reuse one prompt_cache_key across the conversation to improve prompt cache routing:
import { randomUUID } from "node:crypto";
import { type InputItem, xAI } from "@xai-official/sdk";
const client = new xAI();
const promptCacheKey = `conversation:${randomUUID()}`;
const input: Array = [
{ role: "user", content: "My name is Ada. Remember it." },
];
const first = await client.responses.create({
model: "grok-4.7",
input,
prompt_cache_key: promptCacheKey,
});
const second = await client.responses.create({
model: "grok-4.7",
input: [
...input,
...first.toInput(),
{ role: "user", content: "What is my name?" },
],
prompt_cache_key: promptCacheKey,
});
console.log(second.toText());Use a different cache key for each unrelated conversation.
To continue a stored response by ID, opt in to storage:
const first = await client.responses.create({
model: "grok-4.7",
input: "My name is Ada. Remember it.",
store: true,
});
const second = await client.responses.create({
model: "grok-4.7",
input: "What is my name?",
previous_response_id: first.id,
store: true,
});Compacting long conversations
Every turn resends the whole conversation, so input tokens grow as it gets longer. Compact the conversation into a single encrypted item with responses.compact(), then start the next input with the compacted output. Continuing the toInput() example:
const compacted = await client.responses.compact({
model: "grok-4.7",
input: [
...input,
...first.toInput(),
{ role: "user", content: "What is my name?" },
...second.toInput(),
],
});
const third = await client.responses.create({
model: "grok-4.7",
input: [
...compacted.output,
{ role: "user", content: "Spell my name backwards." },
],
prompt_cache_key: promptCacheKey,
});
console.log(third.toText());Pass compacted.output unchanged and add new turns after it. The conversation must still fit in the model's context window when you compact it. compacted.usage reports the tokens the compaction used and...
Excerpt shown — open the source for the full document.