# @astralform/js 中文文档

规范地址：https://npmcn.com/package/%40astralform/js/

版本：9\.13\.0
npm 元数据更新时间：2026-10-25T11:44:41.544Z
中文译文更新时间：2026-11-07T01:28:12.545Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40astralform/js
原文对照：https://npmcn.com/package/%40astralform/js/?lang=original
项目主页：https://github.com/astralform-ai/Astralform-JS-SDK#readme
源码仓库：https://github.com/astralform-ai/Astralform-JS-SDK

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：1.5 MB，8 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=18
- 运行依赖：0 个
- 首次发布：2026-03-16T16:10:58.154Z
- 最新版本发布：2026-10-25T11:44:41.159Z
- 近 30 天下载量：2220（2026-10-07 至 2026-11-05，npm 官方下载统计）
- 已发布版本数：66（近 12 个月 66 个）

## 中文简介

Astralform JS SDK - 在WebMCP支持下的AI代理管弦乐

## 安装

```sh
npm install @astralform/js
```

也可以使用：`pnpm add @astralform/js`、`yarn add @astralform/js`、`bun add @astralform/js`

## README

# @ astralform/js (英语)

Java脚本/ Type脚本 SDK 用于 [星状](https://astralform.ai/) ——AI代理管弦乐与SSE流和客户端-侧工具执行.

## 安装

```bash
npm install @astralform/js
```

## 快速启动

```ts
import { ChatSession } from "@astralform/js";

const session = new ChatSession({
  apiKey: "your-api-key",
  userId: "user-123",
});

session.on((event) => {
  switch (event.type) {
    case "block_delta":
      if (event.delta.channel === "text") {
        process.stdout.write(event.delta.text);
      }
      break;
    case "message_stop":
      console.log("\nDone!");
      break;
    case "error":
      console.error(`${event.code}: ${event.message}`);
      break;
  }
});

await session.connect();

// A conversation's first message names its model — one the agent's team has
// connected. Later messages in the same conversation may omit it and reuse the
// conversation's model.
const models = await session.client.getModels(); // the list backs a model picker
const model = models[0];
if (!model) throw new Error("Connect a model provider for this agent first.");
await session.send("What is the capital of France?", {
  provider: model.provider,
  model: model.model,
});
session.disconnect();
```

以下示例略去 `provider` 财务报告和审定财务报表 `model` 简洁。 第一次谈话时 消息,如上所示: 更新的 Astralform 服务器拒绝一个新的对话 没有名号,每个服务器都接受一个名号.

## 特征

-   **SSE 流线** ——通过Server-Sent Evolutions实时按键响应
-   **客户端工具** —— LLM 可以调用, 在您的应用程序中本地执行的注册工具
-   **核准工具** - 答复 `tool_approval_requested` 执行前的事件
-   **UI 协议** – MCP 风格嵌入式资源的可插件渲染器(A2UI等)
-   **多代理人** ——给特定代理人的路由信息或让主管选择
-   **对话管理** ——创建,切换,删除并恢复对话
-   **事件重播** - 将持续的电讯事件转换成 `ChatEvent`编号
-   **无依赖** - 仅使用本地API(`fetch`, (中文(简体) ), `ReadableStream`, (中文(简体) ), `crypto`(中文(简体) )
-   **通用** ——无害环境管理+CJS,在浏览器和节点18+工作

## 配置

```ts
import { ChatSession } from "@astralform/js";

const session = new ChatSession({
  apiKey: "your-api-key",   // Required — Astralform agent API key
  userId: "user-123",       // Required — identifies the end user
  baseURL: "http://localhost:8000", // Optional — defaults to https://api.astralform.ai
  fetch: customFetch,       // Optional — custom fetch implementation
  timeoutMs: 30_000,        // Optional — REST request deadline, defaults to 30s
});
```

`timeoutMs` 将每个 REST 请求结束到结束 —— 连接、 信头和 正文读取 - 用 `ConnectionError` 当它过期。 文件上传和 sSE 溪流是免责的:两者都是设计上的长期运行,而溪流也是免责的 自己携带 `AbortSignal`。 。 。 .

## 活动

订阅事件 `.on()`,它返回一个未订阅的函数。 SDK 向前键入 `ChatEvent` 每起电线事件——消费者从溪流中建立自己的块/消息状态.

```ts
const unsubscribe = session.on((event) => {
  switch (event.type) {
    case "connected":
      // Session connected, agent status and tools loaded
      break;

    // --- Turn lifecycle ---
    case "message_start":
      // New turn: event.turnId, event.model, event.agentDisplayName
      break;
    case "block_start":
      // A content block opened: event.kind ("text" | "thinking" | "tool_use" | ...)
      break;
    case "block_delta":
      // Streaming chunk. Narrow by event.delta.channel:
      //   - "text": event.delta.text
      //   - "thinking": event.delta.text
      //   - "input" / "input_arg": partial tool input
      //   - "output": interpreter stdout/stderr/progress
      //   - "status": "executing" | "awaiting_client_result" | "awaiting_approval" | "denied"
      break;
    case "block_stop":
      // Block finished. event.status === "awaiting_client_result" means
      // a client-side tool is ready to run (see "Client-Side Tools" below).
      break;
    case "message_stop":
      // Turn complete: event.stopReason, event.usage, event.totalMs, event.jobId
      break;

    // --- Custom events (typed variants) ---
    case "subagent_start":
    case "subagent_stop":
      // event.agent (AgentIdentity), event.taskCallId
      break;
    case "todo_update":
      // event.todos (TodoItem[])
      break;
    case "title_generated":
      // event.title
      break;
    case "context_warning":
      // event.severity, event.utilizationPct, event.remainingTokens, ...
      break;
    case "memory_recall":
    case "memory_update":
      // Backend memory subsystem surfaced to the UI
      break;
    case "tool_approval_requested":
      // Respond via client.submitToolApproval(...)
      break;
    case "asset_created":
    case "attachment_staged":
    case "workspace_ready":
    case "desktop_stream":
      // Workspace / asset pipeline events
      break;
    case "state_changed":
      // event.state ("queued" | "running" | "waiting_for_tool" | ...)
      break;
    case "custom":
      // Unknown custom event — forward-compat passthrough
      break;

    // --- Transport / errors ---
    case "retry":
    case "stall":
    case "keepalive":
      break;
    case "error":
      // event.code, event.message, event.blockPath
      break;
    case "disconnected":
      break;
  }
});

// Later: unsubscribe()
```

## 客户端工具

LLM可以引用的注册工具. 工具名称 **必须** 开始 `mcp_` 所以后端会把它们传送到客户端执行.

```ts
session.toolRegistry.registerTool(
  "mcp_get_current_time",
  "Get the current date and time",
  {
    type: "object",
    properties: {
      timezone: {
        type: "string",
        description: "IANA timezone (e.g. America/New_York)",
      },
    },
  },
  async (args) => {
    const tz = (args.timezone as string) || "UTC";
    return new Date().toLocaleString("en-US", { timeZone: tz });
  },
);

await session.send("What time is it in Tokyo?");
// The LLM calls mcp_get_current_time → SDK executes it → result sent back → LLM responds
```

工具执行流程被自动处理 :

1.  LLM 请求客户端工具( 有线 : `block_start(kind="tool_use")`,然后流出 `block_delta(channel="input")`(中文(简体) )
2.  后端信号准备运行 `block_stop(status="awaiting_client_result")` —— 说 `final.call_id`, (中文(简体) ), `final.tool_name`,以及 `final.input` 带解析参数
3.  SDK 本地引用注册处理器
4.  SDK将结果张贴到 `/v1/tool-result`
5.  SDK 为 LLM 的最终响应继续SSE流

观察者可以通过观看来显示“运行...” UIs `block_start(kind="tool_use")` 财务报告和审定财务报表 `block_stop(status="awaiting_client_result")` 直接说.

### 核准工具

当一个工具需要用户批准时,后端会发出 a `tool_approval_requested` 事件,而不是开始 `awaiting_client_result`。响应 `client.submitToolApproval(...)`数字 :

```ts
session.on(async (event) => {
  if (event.type === "tool_approval_requested") {
    const ok = confirm(`Allow ${event.toolName}? (${event.reason ?? ""})`);
    await session.client.submitToolApproval({
      job_id: session.currentJobId ?? "",
      call_id: event.callId,
      decision: ok ? "allow" : "deny",
      scope: "once", // "once" | "conversation" | "always"
    });
  }
});
```

## UI 协议

当后端使丰富的UI表面(今天的A2UI,将来的其他协议),工具输出会以MCP风格的嵌入资源包裹而来. 按 MIME 类型键登记一个框架特定渲染器 :

```ts
import { ChatSession, parseEmbeddedResource } from "@astralform/js";

await session.connect();

// Gate registration on the agent's configured protocol.
if (session.agentStatus?.uiComponents.enabled) {
  session.protocols.register({
    mimeType: session.agentStatus.uiComponents.mimeType!,
    render: (payload) => {
      /* framework-specific render */
    },
  });
}

// Inside your tool-result block handler:
session.on((event) => {
  if (event.type === "block_stop" && event.final) {
    const resource = parseEmbeddedResource(event.final.output);
    if (resource) {
      const adapter = session.protocols.get(resource.mimeType);
      adapter?.render(resource.payload);
    }
  }
});
```

SDK从未进口出一个渲染器——适配器是消费者在读取上收缩的不透明的手柄. 适配器被丢弃 `disconnect()`。 。 。 .

## 多代理人

向特定代理发送消息 :

```ts
await session.connect();

// List available agents
console.log(session.agents);

// Send to a specific agent
await session.send("Help me debug this", { agentName: "debugger" });
```

## 对话管理

```ts
// Create a new conversation
const id = await session.createNewConversation();

// Switch to an existing conversation (loads messages from backend)
await session.switchConversation("conversation-id");

// Delete a conversation. Rejects if the server refused it — a 404 counts as
// already deleted and resolves, anything else leaves the conversation in place.
try {
  await session.deleteConversation("conversation-id");
} catch (err) {
  // Still there: tell the user rather than removing it from your own UI.
}

// Edit and resend from a checkpoint
await session.resendFromCheckpoint("message-id", "Updated message");

// Access state
session.conversationId;   // Current conversation ID
session.conversations;    // All conversations
session.messages;         // Messages in current conversation
```

## 启用客户端工具

客户工具通过 `session.toolRegistry.registerTool(...)` 仅在会话启用集中其名称时运行 :

```ts
// Enable / disable a registered client tool
session.toggleClientTool("mcp_get_current_time"); // returns true if now enabled

// Inspect the enabled set
session.enabledClientTools; // Set<string>
```

平台层面的功能(如计划模式)通过 `send` 选项。 Web搜索不需要选项:当代理搜索功能启用服务器侧时,代理决定每个任务是否搜索.

```ts
await session.send("Research the latest on WebGPU", {
  planMode: true,
});
```

## 低级客户端

对于没有会话状态管理的直接 API 访问 :

```ts
import { AstralformClient } from "@astralform/js";

const client = new AstralformClient({
  apiKey: "your-api-key",
  userId: "user-123",
});

// REST endpoints
const status = await client.getAgentStatus();
const conversations = await client.getConversations();
const messages = await client.getMessages("conversation-id");
const agents = await client.getAgents();
const skills = await client.getSkills();
const commands = await client.listSkillCommands();

// Job-based streaming
const job = await client.createJob({
  message: "Hello",
  provider: "anthropic", // a new conversation names its model
  model: "claude-sonnet-5",
});
for await (const event of client.streamJobEvents(job.job_id)) {
  const data = JSON.parse(event.data);
  if (data.type === "block_delta" && data.delta.channel === "text") {
    process.stdout.write(data.delta.text);
  }
}
```

## 自定义存储

SDK默认使用内存存储. 执行 `ChatStorage` 持久性:

```ts
import { ChatSession, type ChatStorage } from "@astralform/js";

const myStorage: ChatStorage = {
  fetchConversations: async () => { /* ... */ },
  fetchConversation: async (id) => { /* ... */ },
  createConversation: async (id, title) => { /* ... */ },
  updateConversationTitle: async (id, title) => { /* ... */ },
  deleteConversation: async (id) => { /* ... */ },
  fetchMessages: async (conversationId) => { /* ... */ },
  addMessage: async (message, conversationId) => { /* ... */ },
  updateMessageStatus: async (id, status) => { /* ... */ },
  deleteMessage: async (id) => { /* ... */ },
};

const session = new ChatSession(config, myStorage);
```

## 处理错误

HTTP 呼叫 (`connect`, (中文(简体) ), `submitToolApproval`, (中文(简体) ), `createJob`,.) 抛出打出的错误:

```ts
import {
  AuthenticationError, // 401 — invalid API key
  RateLimitError, // 429 — rate limit exceeded
  LLMNotConfiguredError, // LLM provider not set up
  ServerError, // 5xx or unexpected errors — carries `status` when it came from a response
  ConnectionError, // Network failures
  StreamAbortedError, // Stream cancelled via disconnect()
} from "@astralform/js";

try {
  await session.connect();
} catch (err) {
  if (err instanceof AuthenticationError) {
    // Redirect to login
  }
}
```

以打字方式从 SSE 流火中到达的错误 `error` 结构形状的事件——无 `Error` 实例被包裹 :

```ts
session.on((event) => {
  if (event.type === "error") {
    // event.code, event.message, event.blockPath
    if (event.code === "rate_limit_exceeded") {
      // Show backoff UI
    }
  }
});
```

## 框架整合

SDK是无头的——它与任何UI框架合作. 以下是反应的例子:

```tsx
import { ChatSession, type ChatEvent } from "@astralform/js";
import { useEffect, useRef, useState } from "react";

function useChat(apiKey: string, userId: string) {
  const sessionRef = useRef<ChatSession>();
  const [messages, setMessages] = useState<string[]>([]);
  const [streaming, setStreaming] = useState("");

  useEffect(() => {
    const session = new ChatSession({ apiKey, userId });
    sessionRef.current = session;

    session.on((event: ChatEvent) => {
      switch (event.type) {
        case "block_delta":
          if (event.delta.channel === "text") {
            setStreaming((s) => s + event.delta.text);
          }
          break;
        case "message_stop":
          setStreaming((s) => {
            setMessages((m) => [...m, s]);
            return "";
          });
          break;
      }
    });

    session.connect();
    return () => session.disconnect();
  }, [apiKey, userId]);

  const send = (text: string) => sessionRef.current?.send(text);

  return { messages, streaming, send };
}
```

## 发展

```bash
npm install        # Install dependencies
npm run build      # Build ESM + CJS + types
npm test           # Run tests
npm run typecheck  # Type check
```

## 许可证

麻省理工学院

## 常见问题

### @astralform/js 是什么？

Astralform JS SDK - 在WebMCP支持下的AI代理管弦乐

### 如何安装 @astralform/js？

在项目目录运行 npm install @astralform/js，或使用 pnpm add / yarn add / bun add。

### @astralform/js 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @astralform/js 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @astralform/js 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @astralform/js 可以商用吗？

@astralform/js 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @astralform/js 的下载量有多少？

根据 npm 官方下载统计，@astralform/js 在 2026/10/07 – 2026/11/05 这 30 天内被下载 2,220 次，日均约 74 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @astralform/js 还在维护吗？

最新版本 9\.13\.0 发布于 2026/10/25（13 天前）；至今共发布 66 个版本，其中过去 12 个月发布了 66 个；首次发布于 2026/03/17。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

