Skip to content

Node.js 后端接入

安装

bash
npm install @blade-hq/agent-kit@0.5.11

Node.js 项目必须使用 ESM:package.json 设置 "type": "module"。只用 /client 入口,不需要 React。

json
{
  "type": "module",
  "dependencies": {
    "@blade-hq/agent-kit": "0.5.11"
  }
}

常见错误

ts
// 错误:不要从包根导入
import { BladeClient } from "@blade-hq/agent-kit"
// 错误:不要用 require
const { BladeClient } = require("@blade-hq/agent-kit")
// 错误:不存在 createClient
import { createClient } from "@blade-hq/agent-kit/client"

创建 Client

ts
import { BladeClient } from "@blade-hq/agent-kit/client"

const client = new BladeClient({
  baseUrl: process.env.BLADE_AGENT_URL,  // 后端 origin,不带 pathname
  token: process.env.BLADE_AGENT_TOKEN,  // sk-blade-v2-...
})

创建会话与发送消息

ts
const { session_id } = await client.sessions.createSession("用户任务")

const socket = client.socket()
socket.on("turn:start", (p) => console.log("开始:", p.role))
socket.on("turn:patch", (p) => { /* 增量更新 */ })
socket.on("turn:end", (p) => console.log("结束:", p.role))
socket.on("chat:end", (p) => {
  console.log("完成:", p.status) // completed / failed
  socket.disconnect()
})
socket.on("system:error", (p) => console.error(p.message))

socket.connect()
socket.emit("session:subscribe", { session_id })
socket.emit("chat:send", { session_id, message: "你好", mode: "executing" })

离开时清理:

ts
socket.emit("session:unsubscribe", { session_id })
socket.disconnect()

Headless 一次性问答

最省事的后端入口,自动建会话、跑完、返回结果:

ts
// 纯文本
const reply = await client.headless.run("用一句话介绍你自己")
console.log(reply) // string

// 结构化结果
const data = await client.headless.run("提取公司名和金额:...", {
  schema: {
    type: "object",
    properties: {
      company: { type: "string" },
      amount: { type: "number" },
    },
    required: ["company", "amount"],
  },
})
console.log(data.company, data.amount)

// 必须断开 socket,否则 Node 进程不会退出
client.socket().disconnect()

WARNING

headless.run 内部会建立 Socket.IO 长连接。Node 脚本拿到结果后,必须调用 client.socket().disconnect()process.exit(0),否则进程会一直挂住。

headless.run(prompt, options) 的 options:

参数类型说明
schemaJSON Schema 对象返回结构化数据
modelstring模型 ID
timeoutMsnumber超时,默认 300000

会话管理(REST)

ts
const { session_id } = await client.sessions.createSession("用户任务")
const detail = await client.sessions.getSession(session_id)
const sessions = await client.sessions.listSessions()
const turns = await client.sessions.getSessionTurns(session_id)   // 渲染用的投影
const history = await client.sessions.getSessionHistory(session_id) // 原始历史树
await client.sessions.deleteSession(session_id)

Express SSE 包装示例

将 Socket.IO 事件转为 HTTP SSE 流:

ts
import express from "express"
import { BladeClient } from "@blade-hq/agent-kit/client"

const app = express()
app.use(express.json())

app.post("/api/sessions/:session_id/chat", async (req, res) => {
  const { session_id } = req.params
  const { message } = req.body
  const client = new BladeClient({
    baseUrl: process.env.BLADE_AGENT_URL!,
    token: process.env.BLADE_AGENT_TOKEN!,
  })
  const socket = client.socket()

  res.writeHead(200, {
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache, no-transform",
    Connection: "keep-alive",
  })
  res.write(`event: connected\ndata: {"ok":true}\n\n`)

  const send = (event: string, data: unknown) => {
    res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`)
  }
  const heartbeat = setInterval(() => send("heartbeat", { ts: Date.now() }), 15000)
  const cleanup = () => {
    clearInterval(heartbeat)
    socket.emit("session:unsubscribe", { session_id })
    socket.disconnect()
  }
  const finish = () => { cleanup(); if (!res.writableEnded) res.end() }

  res.on("close", cleanup)
  socket.on("connect", () => {
    socket.emit("session:subscribe", { session_id })
    socket.emit("chat:send", { session_id, message, mode: "executing" })
  })
  socket.on("connect_error", (err) => { send("error", { message: err.message }); finish() })
  socket.on("turn:start", (p) => send("turn:start", p))
  socket.on("turn:patch", (p) => send("turn:patch", p))
  socket.on("turn:end", (p) => send("turn:end", p))
  socket.on("chat:end", (p) => { send("chat:end", p); finish() })
  socket.on("system:error", (p) => { send("error", p); finish() })
  socket.connect()
})