用于javascript和typescript的ai推理API
官方javascript/typescript SDK inference.sh -无服务器ai推理的ai代理运行时。
运行ai模型,构建ai代理,并使用简单的api部署生成ai应用程序。访问模型包括通量,稳定扩散,LLMS (claude, gpt, gemini),视频生成(veo, seedance)等。
安装
npm install @inferencesh/sdk
# or
yarn add @inferencesh/sdk
# or
pnpm add @inferencesh/sdk
获取API密钥
获取API密钥 inference.sh仪表板.
快速入门
import { inference, TaskStatusCompleted } from '@inferencesh/sdk';
const client = inference({ apiKey: 'your-api-key' });
// Run a task and wait for the result
const result = await client.tasks.run({
app: 'your-app',
input: {
prompt: 'Hello, world!'
}
});
if (result.status === TaskStatusCompleted) {
console.log(result.output);
}
使用
基本用法
import { inference, TaskStatusCompleted } from '@inferencesh/sdk';
const client = inference({ apiKey: 'your-api-key' });
// Wait for result (default behavior)
const result = await client.tasks.run({
app: 'my-app',
input: { prompt: 'Generate something amazing' }
});
if (result.status === TaskStatusCompleted) {
console.log('Output:', result.output);
}
使用设置参数
设置参数配置应用实例(例如,模型选择)。具有匹配设置的工人是“温暖”和跳过设置:
const result = await client.tasks.run({
app: 'my-app',
setup: { model: 'schnell' }, // Setup parameters
input: { prompt: 'hello' }
});
火灾和遗忘
// Get task info immediately without waiting
const task = await client.tasks.run(
{ app: 'my-app', input: { prompt: 'hello' } },
{ wait: false }
);
console.log('Task ID:', task.id);
console.log('Status:', task.status);
实时状态更新
默认情况下,客户端通过NDJSON (/tasks/{id}/stream)并调用 onUpdate 随着任务的变化。使用 onPartialUpdate 当你只需要部分流负载中的特定字段时:
const result = await client.run(
{ app: 'my-app', input: { prompt: 'hello' } },
{
onUpdate: (update) => {
console.log('Status:', update.status);
console.log('Progress:', update.logs);
},
onPartialUpdate: (update, fields) => {
console.log('Changed fields:', fields, update.status);
},
}
);
流媒体vs轮询
SSE/NDJSON流是默认的。对于不能保持长时间连接打开的边缘运行时(凸动作,Cloudflare Workers等),禁用流并使用轻量级状态轮询:
const client = inference({
apiKey: 'your-api-key',
stream: false, // poll /tasks/{id}/status instead of streaming
pollIntervalMs: 2000, // default: 2000
});
// Per-call override
const result = await client.run(
{ app: 'my-app', input: { prompt: 'hello' } },
{ stream: false, onUpdate: (u) => console.log(u.status) }
);
轮询模式下,由SDK进行检查 /tasks/{id}/status 并在状态改变时获取完整的任务。如果状态转换后取回失败, run() 拒绝使用基础错误。
批处理
async function processImages(images: string[]) {
const results = [];
for (const image of images) {
const result = await client.tasks.run({
app: 'image-processor',
input: { image }
}, {
onUpdate: (update) => console.log(`Processing: ${update.status}`)
});
results.push(result);
}
return results;
}
文件上传
// Upload from base64
const file = await client.files.upload('data:image/png;base64,...', {
filename: 'image.png',
contentType: 'image/png'
});
// Use the uploaded file in a task
const result = await client.tasks.run({
app: 'image-app',
input: { image: file.uri }
});
取消任务
const task = await client.tasks.run(
{ app: 'long-running-app', input: {} },
{ wait: false }
);
// Cancel if needed
await client.tasks.cancel(task.id);
流函数(Live Sockets)
流函数在任务的生命周期内保持套接字与其调用者打开:帧在调用者关闭或应用程序返回之前都是双向的。 client.live 启动任务并拨打其套接字;run响应携带要拨号的地方(task.socket)。
const { task, session } = await client.live(
{ app: 'infsh/voice-loop', function: 'stream', input: { effect: 'robot' } },
{
onState: (state) => console.log(state), // connecting → waiting → live → ended
onBinary: (pcm) => speaker.write(new Int16Array(pcm)),
onPatch: (patch) => console.log(patch), // e.g. { frames: 120 }
}
);
session.sendBinary(micFrame); // one item of the input's binary live field
session.sendPatch({ effect: 'echo' }); // change an ordinary input while it runs
session.close(); // the function returns and the task completes
await session.ended;
会议是 waiting 直到应用程序的第一帧(冷启动可能需要一分钟),如果任务在此之前结束,则放弃。当它下面的中继重新启动时,它使用一个新的凭据再次拨号。 client.sockets.open(taskOrId, handlers) 重新连接到正在运行的任务的套接字,例如在页面重新加载后。
函数的套接字所携带的内容在其模式中:活字段是 {"type": "array", "format": "stream", "items": ...}. splitLiveSchema(schema) 将普通字段(请求体)与活动字段分开,并且 pcmFormat(field.media) 读取PCM音频场的采样率。
在Node 18-21上没有全局变量 WebSocket:从 ws 包作为 { webSocket: WebSocket }.
会话(有状态执行)
会话允许您跨多个任务调用维护状态。worker在调用之间保持温暖,保留已加载的模型和内存状态。
// Start a new session
const result = await client.tasks.run({
app: 'my-stateful-app',
input: { prompt: 'hello' },
session: 'new'
});
const sessionId = result.session_id;
console.log('Session ID:', sessionId);
// Continue the session with another call
const result2 = await client.tasks.run({
app: 'my-stateful-app',
input: { prompt: 'remember what I said?' },
session: sessionId
});
自定义会话超时时间
缺省情况下,会话在60秒后失效。您可以使用 session_timeout (1 - 3600秒):
// Create a session with 5-minute idle timeout
const result = await client.tasks.run({
app: 'my-stateful-app',
input: { prompt: 'hello' },
session: 'new',
session_timeout: 300 // 5 minutes
});
// Session stays alive for 5 minutes after each call
注:
session_timeout仅在以下情况下有效session: 'new'- 最小超时时间:1秒
- 最大超时时间:3600秒(1小时)
- 每次呼叫成功都会重置空闲计时器
会话管理API
不运行任务直接管理会话:
// Inspect a session
const info = await client.sessions.get(sessionId);
console.log(info.status, info.expires_at, info.call_count);
// List active sessions
const sessions = await client.sessions.list();
// Extend idle timeout without a task call (sliding window)
await client.sessions.keepalive(sessionId);
// Release the worker immediately
await client.sessions.end(sessionId);
会话的错误
import {
SessionNotFoundError,
SessionExpiredError,
SessionEndedError,
} from '@inferencesh/sdk';
try {
await client.tasks.run({
app: 'my-stateful-app',
input: { prompt: 'hello' },
session: sessionId,
});
} catch (error) {
if (
error instanceof SessionNotFoundError ||
error instanceof SessionExpiredError ||
error instanceof SessionEndedError
) {
// Start a new session and retry
const result = await client.tasks.run({
app: 'my-stateful-app',
input: { prompt: 'hello' },
session: 'new',
});
} else {
throw error;
}
}
有关完整的会话文档,包括错误处理、最佳实践和高级模式,请参阅 会议开发者指南.
代理聊天
聊天与人工智能代理使用 client.agents.create().
使用模板代理
使用工作区中的现有代理 namespace/name@shortid:
import { inference } from '@inferencesh/sdk';
const client = inference({ apiKey: 'your-api-key' });
// Create agent from template
const agent = client.agents.create('my-org/assistant@abc123');
// Send a message with streaming
await agent.sendMessage('Hello!', {
onMessage: (msg) => {
if (msg.content) {
for (const c of msg.content) {
if (c.type === 'text' && c.text) {
process.stdout.write(c.text);
}
}
}
}
});
// Clean up
agent.disconnect();
创建Ad-Hoc代理
即时创建代理,无需保存到工作区:
import { inference, tool, string } from '@inferencesh/sdk';
const client = inference({ apiKey: 'your-api-key' });
// Create ad-hoc agent (config uses API field names: core_app, system_prompt)
const weatherTool = tool('get_weather')
.describe('Get current weather')
.param('city', string('City name'))
.build();
const agent = client.agents.create({
core_app: { ref: 'infsh/claude-sonnet-4@abc123' },
system_prompt: 'You are a helpful assistant.',
tools: [weatherTool], // only schemas are sent to the API; handlers stay client-side
});
await agent.sendMessage('What is the weather in Paris?', {
onMessage: (msg) => console.log(msg),
onToolCall: async (call) => {
const result = await runMyClientTool(call.name, call.args);
await agent.submitToolResult(call.id, result);
},
});
对于多回合聊天,SDK在发送下一条消息之前打开聊天流,因此不会错过更新。使用 stopChat() 取消机上发电(POST /chats/{id}/stop), reset() 清除当前聊天并重新开始。
工具构建器
使用流畅构建器来定义 AgentTool 模式。客户端工具(tool)运行在你的应用程序通过 onToolCall;服务器端工具在inference.sh上运行。
| 建设者 | 运行在 | 描述 |
|---|---|---|
tool(name) | 客户端 | 当地处理程序;只有模式被发送到API |
appTool(name, appRef) | 服务器 | 调用另一个推理应用程序 |
agentTool(name, agentRef) | 服务器 | 委托给子代理 |
httpTool(name, url) / callTool(name, url) | 服务器 | 带凭据注入的HTTP请求(优先于 webhookTool) |
webhookTool(name, url) | 服务器 | Unsigned webhook (legacy httpTool 对于新工具) |
mcpTool(name, { server, toolName }) | 服务器 | 调用MCP服务器上的工具(通过段塞),使用运行者自己与服务器提供程序的连接进行登录 |
internalTools() | 服务器 | 内置工具:计划、记忆、小部件、完成、技能、元、远程、知识、工件、代理 |
import {
inference,
tool,
appTool,
httpTool,
mcpTool,
internalTools,
string,
CredentialProviderGoogle,
} from '@inferencesh/sdk';
const clientTool = tool('get_weather')
.describe('Get current weather')
.param('city', string('City name'))
.build();
// HTTP tool authenticated with a connected account (token injected server-side)
const gmailSend = httpTool('gmail_send', 'https://gmail.googleapis.com/gmail/v1/users/me/messages/send')
.describe('Send an email via Gmail')
.method('POST')
.auth({ credential: CredentialProviderGoogle })
.build();
// API key or bearer auth
const fetchData = httpTool('fetch', 'https://api.example.com/data')
.method('GET')
.auth({ apiKey: 'YOUR_KEY', header: 'X-API-Key' }) // default header: X-API-Key
.header('Accept', 'application/json')
.build();
const bearerFetch = httpTool('bearer_fetch', 'https://api.example.com')
.auth({ bearer: 'YOUR_TOKEN' })
.build();
const imageGen = appTool('generate_image', 'infsh/flux-schnell@abc123')
.param('prompt', string('Image description'))
.requireApproval()
.build();
// MCP server by slug; the runner's connection to its provider signs the call
const mcpSearch = mcpTool('notion_search', { server: 'notion', toolName: 'search' })
.describe('Search Notion pages')
.param('query', string('Search query'))
.build();
const agent = client.agents.create({
core_app: { ref: 'infsh/claude-sonnet-4@latest' },
system_prompt: 'You are helpful.',
tools: [clientTool, gmailSend, imageGen, mcpSearch],
internal_tools: internalTools().memory().build(),
});
callTool 的别名 httpTool。运行 npx tsx examples/tool-builder.ts 查看更多模式示例(不需要API键)。
生命周期的钩子
使用 lifecycleHook() 将钩子附加到代理事件。Hooks可以调用webhook或作为任务委托给另一个代理:
import { inference, lifecycleHook, HookEventTurnStart, HookEventToolCall } from '@inferencesh/sdk';
const client = inference({ apiKey: 'your-api-key' });
const agent = client.agents.create({
core_app: { ref: 'openrouter/claude-sonnet-4@abc' },
hooks: [
lifecycleHook(HookEventTurnStart)
.webhook('https://example.com/on-turn')
.timeout(10)
.build(),
lifecycleHook(HookEventToolCall)
.task('my-org/approval-agent')
.async(true)
.build(),
],
});
消息排队
sendMessage 当代理忙于处理上一条消息时自动排队。队列消息显示时带有 queued 状态,直到座席接机。
要在处理队列消息之前取消该消息,请使用 cancelMessage 在React提供程序或 chats.cancelMessage 在API客户端上:
// Via the API client
await client.chats.cancelMessage(messageId);
文件附件
传入文件 sendMessage 选项。 Blob 首先上传值;带有 uri (已上载至 client.files.upload)按原样附上:
const uploaded = await client.files.upload(imageBlob, {
filename: 'photo.png',
contentType: 'image/png',
});
await agent.sendMessage('Describe this image', {
files: [imageBlob, uploaded], // Blob uploads; FileDTO reuses uri
onMessage: (msg) => console.log(msg),
});
结构化输出
使用 output_schema 获取结构化JSON响应:
const agent = client.agents.create({
core_app: { ref: 'infsh/claude-sonnet-4@latest' },
output_schema: {
type: 'object',
properties: {
summary: { type: 'string' },
sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] },
confidence: { type: 'number' },
},
required: ['summary', 'sentiment', 'confidence'],
},
internal_tools: { finish: true },
});
const output = await agent.run('Analyze: Great product!');
agent.run() 发送带有轮询的消息(没有SSE),等待聊天空闲,然后返回 chat.output (解析后的成品-工具结果,或 null 如果没有)。
剂的方法
| 方法 | 描述 |
|---|---|
sendMessage(text, options?) | 发送消息;流或轮询,直到空闲时回调或 stream: false |
run(text, options?) | 结构化发送和返回 chat.output (总是使用轮询) |
getChat(chatId?) | 获取当前或指定的聊天记录(chat_messages 在返回的聊天中) |
stopChat() | 停止当前聊天的生成(如果没有活动聊天,则不进行操作) |
submitToolResult(toolId, resultOrAction) | 提交客户端工具的结果(字符串或 {action, form_data}) |
startStreaming(options?) | 手动连接到 /chats/{id}/stream 对于当前聊天 |
disconnect() | 停止活动流/轮询连接 |
reset() | 断开并清除聊天状态,以便下一条消息开始新的聊天 |
通过渠道整合(Slack、Telegram、可穿戴设备)到达的信息可以携带 channel_context 因此,回复以同样的方式发送回来。API在它第一次看到它的时候记录在聊天中,所以以后的turn继承它:
await agent.sendMessage(text, {
channel_context: { channel_type: 'slack', channel_metadata: { channel: 'C123', thread_ts: '1700000000.000100' } },
});
API参考
inference(config)
创建一个新的推断客户端。
| 参数 | 类型 | 要求 | 描述 |
|---|---|---|---|
config.apiKey | string | 是 | 您的inference.sh API密钥 |
config.baseUrl | string | 否 | 自定义API URL(默认: https://api.inference.sh) |
config.stream | boolean | 否 | 使用NDJSON流(true,默认)或状态轮询(false) |
config.pollIntervalMs | number | 否 | 轮询间隔 stream: false (默认值: 2000) |
config.proxyUrl | string | 否 | 前端应用的代理基础URL(将API密钥保存在服务器端) |
client.tasks.run(params, options?)
在inference.sh上运行任务。
参数:
| 参数 | 类型 | 要求 | 描述 |
|---|---|---|---|
params.app | string | 是 | App标识符(例如: 'username/app-name') |
params.input | object | 是 | 输入应用程序的参数 |
params.setup | object | 否 | 设置参数(影响工人热情/调度) |
params.infra | string | 否 | 基础设施: 'cloud' 或者 'private' |
params.session | string | 否 | 会话ID或 'new' 开始一个新的会话 |
params.session_timeout | number | 否 | 会话超时时间,单位为秒(1-3600) session: 'new') |
选项:
| 选项 | 类型 | 默认的 | 描述 |
|---|---|---|---|
wait | boolean | true | 等待任务完成 |
stream | boolean | 客户端默认 | 使用NDJSON流或状态轮询 |
pollIntervalMs | number | 客户端默认 | 轮询间隔 stream: false |
onUpdate | function | - | 回调任务更新(在轮询时对状态更改进行完整获取) |
onPartialUpdate | function | - | 部分NDJSON流更新的回调 (task, fields) |
maxReconnects | number | 5 | 最大轮询重试时 stream: false |
client.tasks.get(taskId)
按ID获取任务。
client.tasks.cancel(taskId)
取消正在运行的任务。
client.files.upload(data, options?)
上传文件到inference.sh。
参数:
| 参数 | 类型 | 描述 |
|---|---|---|
data | string | Blob | Base64字符串、数据URI或Blob |
options.filename | string | 文件名 |
options.contentType | string | MIME类型 |
options.public | boolean | 使文件可公开访问 |
client.agents.create(templateOrConfig) / client.agent(...)
从模板或临时配置创建代理实例。 client.agent(...) 的别名 client.agents.create(...).
sendMessage 选项: onMessage, onChat, onToolCall, files, stream, pollIntervalMs。带有状态的客户端工具 awaiting_input 每个调用ID通过 onToolCall.
模板模式:
const agent = client.agents.create('namespace/name@version');
特别的模式:
const agent = client.agents.create({
core_app: { ref: 'infsh/claude-sonnet-4@abc123' },
system_prompt: 'You are helpful.',
tools: [...],
});
client.sessions
| 方法 | HTTP | 描述 |
|---|---|---|
get(sessionId) | GET /sessions/{id} | 会话元数据(status, expires_at, call_count,……) |
list() | GET /sessions | 所有会话(如果没有则为空数组) |
keepalive(sessionId) | POST /sessions/{id}/keepalive | 重置空闲过期 |
end(sessionId) | DELETE /sessions/{id} | 结束会话并释放工作人员 |
client.sockets
| 方法 | HTTP | 描述 |
|---|---|---|
open(taskOrId, handlers?, options?) | - - - - - - | 调用流任务的套接字;返回一个 LiveSession |
get(socketId) | GET /sockets/{id} | 插座和它的寿命 |
forTask(taskId) | POST /sockets/list | 任务的套接字,或null |
access(socketId) | POST /sockets/{id}/access | 呼叫方的新凭证 |
delete(socketId) | DELETE /sockets/{id} | 删除记录 |
client.live(params, handlers?, options?) 是 tasks.run(params, { wait: false }) 紧随其后的是 sockets.open.
任务状态常量
import {
TaskStatusQueued,
TaskStatusRunning,
TaskStatusCompleted,
TaskStatusFailed,
TaskStatusCancelled
} from '@inferencesh/sdk';
if (task.status === TaskStatusCompleted) {
console.log('Done!');
}
凭据常量
CredentialDTO 字段(provider, type, status)使用导出为常量的类型化字符串联合:
import type { CredentialDTO } from '@inferencesh/sdk';
import {
CredentialProviderGoogle,
CredentialTypeOAuth,
CredentialStatusConnected,
CredentialStatusDisconnected,
CredentialStatusExpired,
CredentialStatusError,
RequirementTypeCredential,
isRequirementsNotMetException,
} from '@inferencesh/sdk';
function isGoogleConnected(credential: CredentialDTO): boolean {
return (
credential.provider === CredentialProviderGoogle &&
credential.status === CredentialStatusConnected
);
}
// HTTP 412 when an app requires a missing secret, credential, or scope
try {
await client.run({ app: 'my-app', input: {} });
} catch (error) {
if (isRequirementsNotMetException(error)) {
for (const req of error.errors) {
if (req.type === RequirementTypeCredential && req.action?.provider === CredentialProviderGoogle) {
// User must connect Google — see https://inference.sh/docs/extend/credentials
}
}
}
}
| 恒集团 | 值 |
|---|---|
CredentialProvider* | google, google-sa, slack, notion, github, x, microsoft, salesforce, discord, gcp, reddit |
CredentialType* | service_account, oauth, api_key, wif |
CredentialStatus* | connected, disconnected, expired, error |
实例状态常量
使用引擎实例api时使用(InstanceDTO.status):
import {
InstanceStatusCreating,
InstanceStatusPendingProvider,
InstanceStatusPending,
InstanceStatusActive,
InstanceStatusError,
InstanceStatusDeleting,
InstanceStatusDeleted,
} from '@inferencesh/sdk';
工具参数类型
在构建 AgentTool 模式手动(在工具构建器之外),使用 ToolParamType* 用于JSON模式 type 字段:
import {
ToolParamTypeObject,
ToolParamTypeString,
ToolParamTypeInteger,
ToolParamTypeNumber,
ToolParamTypeBoolean,
ToolParamTypeArray,
ToolParamTypeNull,
} from '@inferencesh/sdk';
const schema = {
type: ToolParamTypeObject,
properties: {
city: { type: ToolParamTypeString, description: 'City name' },
},
required: ['city'],
};
流畅的工具构建器(string(), number(), object())自动推断这些类型。
打印稿的支持
这个SDK是用TypeScript编写的,包含完整的类型定义。导出所有类型:
import type {
Task,
ApiAppRunRequest,
RunOptions,
CredentialDTO,
AgentTool,
} from '@inferencesh/sdk';
要求
- Node.js 18.0.0或更高版本
- 现代浏览器
fetch支持
资源
许可证
麻省理工学院© inference.sh