@ cygnuxlabs/ tracekit (中文(简体) )
实验: 客户端及其 Vercel AI SDK 集成工作并经过测试,但可能会改变并减少 硬化超过 稳定核心核查者 (单位:千美元)
src/verify/)是稳定的.
TypeScript 和 JavaScript 代理的 Tracekit: 每个工具调用由 Tracekit 签名器在运行和运行前决定 模型反应成为签名证据。 客户端直接与签名人交谈; 它不需要 Python 在运行时( 当没有运行时, 用 Python 启动同一用户的 dev 签名) .
安装
18号或更新型的:
npm install @cygnuxlabs/tracekit
npm 也为您的平台安装了签名包(@cygnuxlabs/tracekit-signer-<platform>: 苹果硅
macOS, Linux x64 和 arm64 有 glibc, Windows x64 , 它捆绑一个 Python, 所以 npx @cygnuxlabs/tracekit up 开始 a
德夫签名者无一. 在一个信息Mac或高山没有: pip install tracekit-ai。 。 。 .
或从检查中建出,并安装它制作的文件:
cd sdk/typescript && npm ci && npm run build && npm pack # writes cygnuxlabs-tracekit-<version>.tgz
cd /path/to/your/app && npm install /path/to/Tracekit/sdk/typescript/cygnuxlabs-tracekit-*.tgz
签名客户端( E)@cygnuxlabs/tracekit(中文(简体) )
V2 签名器的本地客户端 RPC 没有运行时的依赖性(仅Node \\ 18 内置,没有 Python 桥)
导出为 @cygnuxlabs/tracekit/v2。 。 。 .
import { Client, withRun, currentRun } from "@cygnuxlabs/tracekit";
const client = new Client(); // or new Client({ signer: "https://signer:8443" })
const run = await client.registerRun("research-bot");
const d = await run.decide(call.id, "Bash", call.function.arguments); // the raw model string, or a parsed value
if (d.decision === "allow") {
if ((await run.approvalConsume(call.id, "Bash", call.function.arguments)).ok) // never throws: ok false means it doesn't run
await run.complete(call.id, "ok", { result: await runShell(call) }); // never throws: a recording failure is a warning
} else if (d.decision === "ask") {
const { approval_id } = await run.approvalRequest(call.id);
const { state } = await run.approvalWait(approval_id, 300_000); // on a connection of its own
if (state === "approved" && (await run.approvalConsume(call.id, "Bash", call.function.arguments, approval_id)).ok)
await run.complete(call.id, "ok", { result: await runShell(call) });
}
await run.close();
await client.close(); // waits for what is in flight
- 签名者 :
$TRACEKIT_SIGNER命名 Unix 套接字,tcp://127.0.0.1:port(与$TRACEKIT_SIGNER_TOKEN; 双方 证明他们握住它, 它从来没有走在线上)或https://host:port(单位:千美元)$TRACEKIT_SIGNER_TOKEN_FILE: 无记名符号 每一电话重读;$TRACEKIT_SIGNER_CERT编号 :_KEY: mTLS; (中文(简体) );$TRACEKIT_SIGNER_CA:签名人CA. 在系统模式 由 root 拥有的签名符命名/etc/tracekit/client.json使用和不同的$TRACEKIT_SIGNER被拒绝. 否则会找到同一用户的dev签名器,或者从tracekit up --json数字 :$TRACEKIT_PYTHON -m tracekit若为 设定, 否则设置了tracekit在PATH上, 否则Python捆绑在这个平台上@cygnuxlabs/tracekit-signer-<platform>软件包.npx @cygnuxlabs/tracekit up|down|status|view|verify|signer运行 同样的命令. - 议定书:
hello首先;拒绝使用不讲客户端的 RPC 版本的签名器Incompatible。 。 。 . 请求在发送、处理一次连接并答复之前,对RPC计划进行验证 命令; 连接下降的电话被同一种人讨厌request_id。每个手柄的事件都带有客户的stream(单位:千美元)client_seq每次运行. - 失败模式 : 只有在无法联系到签名者时才会
decide返回工具类的运行失败模式 (单位:千美元)fields.tool_class_hint从register_run是因为fail_modes关闭)unavailable: true拒绝 以示否认者发誓RPCError从来没有允许. - 无服务器 :
client.waitUntil(promise)财务报告和审定财务报表await client.flush()在主机冻结进程之前. withRun(run, fn)制造run页:1currentRun()所有东西fn等待( 本地同步) .argsDigest(tool, args), (中文(简体) ),canonicalize, (中文(简体) ),strictParse:JCS(RFC 8785)和严格的同义词 共享向量上的 Python 客户端tests/vectors/jcs.jsonl。 。 。 .
校验捆绑( E)@cygnuxlabs/tracekit/verify(中文(简体) )
V2捆绑的独立核查人(.tkb),从 文件/格式v2.md 测试到
同意派斯核查员的意见 无依赖关系: Web Crypto 和 DecompressionStream,所以节点 \ 20.12 和当前
浏览器.
npx @cygnuxlabs/tracekit verify run.tkb --trust trust.json [--json] [--strict]
0 出口已核实, 1 失败, 2 无法使用或无法核实, 3 a 警告 --strict报告 --json 这些是
联 合 国 tracekit verify在代码、节点或浏览器中:
import { verify, formatReport } from "@cygnuxlabs/tracekit/verify";
const bundle = new Uint8Array(await (await fetch("run.tkb")).arrayBuffer());
const trust = new Uint8Array(await (await fetch("trust.json")).arrayBuffer()); // your own pinned trust config
const { report, code } = await verify(bundle, trust);
console.log(report.integrity, report.assurance); // e.g. "VERIFIED", "witnessed; records ed25519; ..."
它不检查 SLH-DSA 检查线, Rekor 锚或认证的记录密钥: 依赖于一个的捆绑是
UNVERIFIABLE (not checked by this verifier: ...)永远 VERIFIED。监测报告、撤销和v1格式
桥需要Python验证器.
verify(bundle, null),没有信任配置,运行所有不需要被绑定的密钥的检查,永远不会 VERIFIED(单位:千美元)
更改的记录仍然失败, 一个完整的捆绑是 UNVERIFIABLE (no trust config: ...)。 。 。 .
在浏览器中 : dist/verify.html 在此包中(和发行资产)是作为自成一页的这个验证符.
丢入捆绑及其信任配置; 其内容安全政策允许它加载并发送任何信息, 所以两个文件都没有
离开浏览器( e)在浏览器中校验) (中文(简体) ). make verify-page 正在建设
从退票.
v2 框架适配器
一个呼叫注册一个运行( 如果没有答案, Dev 签名器将启动), 当进程即将退出时关闭它,
然后,你们交接他们 tracekit last 出口、指针和核实运行情况:
import { instrument } from "@cygnuxlabs/tracekit";
const tk = await instrument(); // the same on a second call
const model = wrapLanguageModel({ model: openai("gpt-5"), middleware: tk.ai.middleware }); // Vercel AI SDK
const r = await generateText({ model, tools: tk.ai.tools({ pay }), toolApproval: tk.ai.toolApproval, messages });
const agent = new Agent({ name: "payer", tools: [tk.agents.tool(tool, { name: "pay", description, parameters, execute })] }); // OpenAI Agents JS
ES模块不能从外部补丁,所以与Python不同 tracekit.instrument() 适配器传递到
由您编写.
每个适配器打开每个工具 通过签名器: 它传递调用ID,它的尝试和模型的生
参数,签名人决定,a ask 等待一个人( 在框架允许的钩子中持有, 否则暂停)
每一次通话,允许或批准, 只在签字人之后进行 approval_consume - 同意 - 同意吗? A 类 deny
随工具出错结果到达模型,运行继续. 运行失败模式( T)register_run是因为 fail_modes(中文(简体) )
只有在下列情况下适用:签字人无法在裁决时达成;拒绝;或等待批准时失败,
从来没有让电话运行。 记录完成的呼叫从不扔出,也从不改变结果(失败是
TracekitWarning) (中文(简体) ). 框架是可选的对等依赖:适配器不导入,客户端
没有运行时间依赖。 没有适配器包装一个提供者客户端,所以SDKs自己的 APIPromise (单位:千美元).withResponse()(中文(简体) )
和溪流(messages.stream(), (中文(简体) ), streamText工作没有 Tracekit。 离线示例 : examples/v2_*.mjs,以及
a 马斯特拉工作流程 暂停被传唤,经批准恢复.
- 服务器:每次对话运行一次. 每次谈话都要注册一次运行,并让每次请求都与
withRun(run, () => runner.run(...)):每个适配器决定它内部在运行中发出的呼叫(它完成和 批准遵从呼吁),并使用它用其他方式建造的跑道.instrument()自己的运行替换为 a 新的(警告,链接为parent_run旧的已关闭了),而签署者在它闲置后关闭了它. - 离开.
instrument()关闭运行beforeExit,并在SIGINT或SIGTERM上,当没有其他处理 信号(然后该信号的默认动作运行). 您的应用程序或库控件留给它(@openai/agentssIGINT/SIGTERM上的出口 : 关闭您自己处理器中的运行(await tk.run.close()在你离开之前。 跑步会留下 (a) 在批准时等待某人或经批准恢复。 批准并恢复另一个进程, 保持运行runId财务报告和审定财务报表runToken与框架的保存状态和重排:new RunHandle(new Client(), { run_id, run_token }); 完成后关闭客户端 (单位:千美元)run.client.close()),或每一次通过一个共享客户端重排.process.exit()跳过所有这一切: 关闭 先说 这个 离线 Vercel AI 恢复示例 保存运行和信件, 打印 批准命令,并在第二个程序中恢复. - LLM网关. 用信头指向提供者, 例如 OpenAI 代理
setDefaultOpenAIClient(new OpenAI({ baseURL, apiKey: <gateway token>, defaultHeaders: { "X-Tracekit-Run":${run.runId}. ${run.runToken} (韩语)} })), Vercel AI 软件createOpenAI({ baseURL, apiKey, headers })。将运行注册为 网关中继器的身份(TRACEKIT_SIGNER=https://…并给予这种身份 适配者用来配他,approval_list列入限制) (中文(简体) ). 适配器自己的型号 然后事件是可选的:网关记录每个交换.
OpenAI 代理服务器 SDK (单位:千美元)@cygnuxlabs/tracekit/v2/openai-agents(中文(简体) )
import { Agent, Runner, tool } from "@openai/agents";
import { TracekitAgents } from "@cygnuxlabs/tracekit/v2/openai-agents";
const tk = new TracekitAgents(await new Client().registerRun("payer"));
const agent = new Agent({ name: "payer", tools: [tk.tool(tool, { name: "pay", description, parameters, execute })] });
let result = await runner.run(agent, "pay acct-42 $15", { context: {} }); // the context must be an object
if (result.interruptions.length) { // an `ask`: once decided in the signer
await tk.applyDecisions(result.state);
result = await runner.run(agent, result.state);
}
await tk.recordResponses(result.rawResponses, "gpt-5");
tk.tool(tool, options) 用 SDK 构建工具 tool(): 签名人的政策取代 needsApproval,则a
工具输入护栏(在您自己之后)打开其原始参数的调用。 批准id只在运行州行驶
作为提示( e)context.tracekit.approvals签字人检查过了 离开 toolExecution.preApprovalInputGuardrails 关闭 :
戴着它 护栏在中断之前运行 每一个 ask 立即拒绝.
本地 MCP 服务器( NameMCPServerStdio,SSE,可流式HTTP)通过其工具护栏被入门:
new MCPServerStdio({ name: "filesystem", ..., ...tk.mcp("filesystem") }) 决定每次呼吁为:
mcp:filesystem/<tool>时 ask 在看守所,直到一个人决定, 并完成电话与
服务器输出 。 通过服务器自己的 name: 与 mcpConfig.includeServerInToolNames 这个模型的
mcp_<server>__<tool> 改为 mcp:<server>/<tool> 从它。 一个叫自己的输入式护栏 拒绝是
记录为被拒绝。 没有它,当地MCP电话
没有门。 用作工具的子剂(agent.asTool())也不设闸门,其模型反应也没有
外层 rawResponses: 打开它自己的工具 tk.tool,并记录其答复customOutputExtractor 获得
或运行 LLM 网关。 也没有门禁,被列为被揭发的工具:主机工具(网络和文件搜索,
代码解释器,主机MCP,主机外壳, shell, application patch 和计算机工具,以及交接(在
保险单 handoffs: 故他们要和解. recordResponses 将它们(T3)记录在每个响应的签名模型事件上.
维塞尔 AI SDK v7 (单位:千美元)@cygnuxlabs/tracekit/v2/vercel-ai(中文(简体) )
import { generateText, wrapLanguageModel } from "ai";
import { tracekitAI } from "@cygnuxlabs/tracekit/v2/vercel-ai";
const tk = tracekitAI(await new Client().registerRun("assistant"));
const model = wrapLanguageModel({ model: openai("gpt-5"), middleware: tk.middleware });
const r = await generateText({ model, tools: tk.tools({ pay }), toolApproval: tk.toolApproval, messages });
// asks end the step with tool-approval-request parts; once decided in the signer:
messages.push(...r.response.messages, { role: "tool", content: await tk.approvalResponses(r.content) });
同样的选择适用于 streamText 财务报告和审定财务报表 ToolLoopAgent。 。 。 . tk.middleware 记录每个模型响应(V3使用,
并保留每个呼叫的原始参数 toolCallId 为了决定. tk.toolApproval 地图
deny 改为 denied 财务报告和审定财务报表 ask 改为 user-approval没有它 ask 被拒绝. tk.tools() 每个包 execute,所以一个
伪造或重放 tool-approval-response 运行什么. experimental_toolApprovalSecret (SDK的HMAC 超越了自己)
批准申请)也可以设置;它不会取代签注人的支票. 来自 @ai-sdk/otel 是遥测,不是
证据:签名的记录是中间软件和适配器的. 没有工具 execute 和提供者执行的工具
没有门;它们出现在记录的模型答复中.
MCP工具(@ai-sdk/mcp: tk.tools(await client.tools(), { mcp: "filesystem" }) 决定如下:
mcp:filesystem/<tool>。自定义 toolApproval (一个函数,或每个工具名一个)与符号的:
toolApproval: tk.toolApprovalWith(mine) 首先询问政策, 您的答案仅适用于电话 政策
允许(你所否认的召唤,将被记录为被拒绝的;你应答的) user-approval 然后在自己的UI中否认
决定未完成); tk.toolApproval 单枪匹马取代你的.
克劳德探员SDK (单位:千美元)@cygnuxlabs/tracekit/v2/claude-agent-sdk(中文(简体) )
import { query } from "@anthropic-ai/claude-agent-sdk";
import { tracekitHooks, tracekitSessionStore } from "@cygnuxlabs/tracekit/v2/claude-agent-sdk";
const run = await new Client().registerRun("my-agent");
query({ prompt, options: { hooks: tracekitHooks(run), sessionStore: tracekitSessionStore(myStore, run) } });
大门是 PreToolUse 钩子(每一次呼叫都使用; canUseTool 已跳过 CLI 的许可模式
允许)。 一个 ask (a) 在钩子内最多持有540 s,低于它规定的钩子超时(600 s)
然后被封锁. PostToolUse编号 :PostToolUseFailure 完成呼叫, SessionEnd 关闭运行。 会话库
包装将每个保存的文字记录作为 state_write 上一个被锁了起来 所以在店里编辑了笔录
在两个字之间出现签名 state_tamper 间隙.
从v1 移动
V1 SDK (英语:Tracekit驾驶 python -m tracekit.bridge)在0.5.0中被折旧并去除. 在此之前,它停留在
@cygnuxlabs/tracekit/v1· ; Tracekit.start 每个进程发出一次警告(DeprecationWarning代码 TRACEKIT_V1和桥
打印 stderr 上的匹配通知; TRACEKIT_NO_DEPRECATION=1 都安静 导入为
import { Tracekit } from "@cygnuxlabs/tracekit/v1"。 。 。 .
v1 (单数)@cygnuxlabs/tracekit/v1(中文(简体) ) | v2 (英语:@cygnuxlabs/tracekit(中文(简体) ) |
|---|---|
await Tracekit.start({ agent }) | const client = new Client(); const run = await client.registerRun(agent) |
await tk.tool(name, args, fn, { toolUseId }) | await run.decide(toolUseId, name, args)运行 fn 打开 allow,则 await run.complete(toolUseId, "ok", { result }) |
TracekitDenied | d.decision === "deny" (单位:千美元)d.rule_ids被签人拒绝的 RPCError |
内部核准 tk.tool | d.decision === "ask"数字 : run.approvalRequest(id),则 run.approvalWait(approval_id) |
instrumentOpenAI 编号 : instrumentAnthropic, (中文(简体) ), tk.modelBegin 编号 : tk.modelEnd | run.modelEvent(provider, model, "response", { stop_reason, usage, tool_uses }),或下面的框架适配器 |
tracekitMiddleware(tk) | tracekitAI(run).middleware 从 @cygnuxlabs/tracekit/v2/vercel-ai,与 tools 财务报告和审定财务报表 toolApproval |
tk.prompt 编号 : tk.say 编号 : tk.think | 未被 v2 签名符记录 |
tk.end(reason) | await run.close(reason); await client.close() |
// v1
import { Tracekit, TracekitDenied } from "@cygnuxlabs/tracekit/v1";
const tk = await Tracekit.start({ agent: "research-bot" });
try {
out = await tk.tool("Bash", args, () => runShell(args), { toolUseId: call.id });
} catch (e) {
if (!(e instanceof TracekitDenied)) throw e;
}
await tk.end();
// v2
import { Client } from "@cygnuxlabs/tracekit";
const client = new Client();
const run = await client.registerRun("research-bot");
const d = await run.decide(call.id, "Bash", call.function.arguments);
if (d.decision === "allow") {
out = await runShell(args);
await run.complete(call.id, "ok", { result: out });
}
await run.close();
await client.close();
v1 SDK (折旧, @cygnuxlabs/tracekit/v1(中文(简体) )
于0.5.0中被删除;见上文迁移. 工具调用通过 Tracekit 的政策门 在运行前,和模型调用 成为与Python SDK相同的分类账和格式的签名证据.
import OpenAI from "openai";
import { Tracekit, TracekitDenied, instrumentOpenAI } from "@cygnuxlabs/tracekit/v1";
const tk = await Tracekit.start({ agent: "research-bot" });
const openai = instrumentOpenAI(new OpenAI(), tk); // also: instrumentAnthropic(client, tk), tracekitMiddleware(tk) for the Vercel AI SDK
const r = await openai.chat.completions.create({ model: "gpt-4o", messages, tools });
for (const call of r.choices[0].message.tool_calls ?? []) {
await tk.tool("Bash", JSON.parse(call.function.arguments), () => runShell(call), { toolUseId: call.id }); // TracekitDenied if blocked
}
await tk.end();
tk.tool(name, args, fn):在作出政策决定之前签署fn运行; 被拒绝( 或持有, 未获批准) 呼叫掷出TracekitDenied财务报告和审定财务报表fn从不跑 通过模型的调用 id作为toolUseId连接请求和执行.instrumentOpenAI(聊天结束,答复),instrumentAnthropic(消息):在 发送调用,并发送一个带有模型、完成理由、请求的工具调用、符号使用、错误、状态和 时间第一块。 流被记录在结束, 失败或被废弃时: SDK 取代流的 async 安装了录音机;在供应商SDK返回时,非流式的回复会回来。 这个 包起来create是一个async函数,所以它返回一个简单的承诺: SDK 自身承诺对象上的帮助者(例如 作为.withResponse()无法通过它获取。 提供者错误被记录并重写 。 请求活动是 在呼叫发出前写出: 如果桥上报出错误或出错, 则会抛出错误, 不发出呼叫; 如果 桥已出道,fail_mode: closed掷出TracekitDenied财务报告和审定财务报表fail_mode: open发送无记录的呼叫 在 Stderr 上发出警告。 无法记录已完成的电话,请写成 Stderr 并计入tk.recordFailures;它永远不会取代呼叫的结果.tracekitMiddleware(tk)数字 :wrapLanguageModel({ model, middleware: tracekitMiddleware(tk) })在 Vercel AI SDK 中 (v4和v5结果形状).
如何是通义. SDK开始 python -m tracekit.bridge 和它说话 通过stdio, 所以政策评估,秘密
编辑,签名客户端和事件格式是Tracekit自己的Python代码,而不是第二个执行. 这需要
页:1 tracekit Python 软件包和一个签名器(tracekit init --dev页:1 TRACEKIT_PYTHON 选择翻译.
测试(npm test: test/sdk.test.mjs 使用真实的 OpenAI 和 Anthropic SDK 运行 v1 SDK 对被嘲笑的获取器和真正的签名器, 然后验证
捆绑; test/adapters.test.mjs 运行每个适配器的适配器合同,通过小站台运行
框架的钩子和中间软件接口,与测试中的假签名符和(带有 Python 和签名符额外)
真实的.