# @chamvi/core 中文文档

规范地址：https://npmcn.com/package/%40chamvi/core/

版本：0\.8\.0
npm 元数据更新时间：2026-11-08T20:17:45.212Z
中文译文更新时间：2026-11-09T10:08:32.469Z
软件包许可：Apache-2\.0

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

原始 npm 页面：https://www.npmjs.com/package/%40chamvi/core
原文对照：https://npmcn.com/package/%40chamvi/core/?lang=original
项目主页：https://chamvi.dev/
源码仓库：https://github.com/chamvi/chamvi

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

- 包体积（解压后）：1.2 MB，12 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=26\.0\.0
- 运行依赖：6 个
- peer 依赖：ai ^7
- 首次发布：2026-10-25T08:42:03.555Z
- 最新版本发布：2026-11-08T20:17:44.883Z
- 近 30 天下载量：5279（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：15（近 12 个月 15 个）

## 中文简介

用于自发托管,触发驱动的AI代理的核心引擎:代理,触发和可持久运行.

## 安装

```sh
npm install @chamvi/core
```

也可以使用：`pnpm add @chamvi/core`、`yarn add @chamvi/core`、`bun add @chamvi/core`

## README

![@chamvi/core](https://raw.githubusercontent.com/chamvi/chamvi/master/.github/assets/logo.svg)

# @ chamvi/ 核心

**自发主机,频道驱动AI代理机的核心引擎:代理机,频道和可持久运行.**  
你用AI SDK给特工写信 引擎排队运行, 检查每一个步骤,  
暂停批准和中断的接头又在平坦的节点过程中运行.

[![npm version](https://img.shields.io/npm/v/@chamvi/core)](https://www.npmjs.com/package/@chamvi/core) [![CI](https://github.com/chamvi/chamvi/actions/workflows/ci.yml/badge.svg)](https://github.com/chamvi/chamvi/actions/workflows/ci.yml) [![License](https://img.shields.io/npm/l/@chamvi/core)](https://github.com/chamvi/chamvi/blob/master/packages/core/LICENSE)

[**安装**](https://npmcn.com/package/%40chamvi/core/#readme-installation) • 妇女 [使用量](https://npmcn.com/package/%40chamvi/core/#readme-usage) • 妇女 [选项](https://npmcn.com/package/%40chamvi/core/#readme-options) • 妇女 [API 密码](https://npmcn.com/package/%40chamvi/core/#readme-api) • 妇女 [页:1](https://npmcn.com/package/%40chamvi/core/#readme-notes)

* * *

## 为什么?

AI SDK运行模型及其工具回路,并站在那里. 一个对webhooks和日程表作出反应的代理商也需要一个工作排队的地方,一个在跑道上半程重启的被吊舱生存的方法,一个在重试后两次发出相同评论的戒备,以及一个等待人类批准呼叫的一天的方法. 这通常是指主机管弦乐手,或者很多胶相编码.

`@chamvi/core` 该图层作为库,没有管弦乐服务器,也没有Redis:

| 关切 | AI SDK 独自行动 | @ chamvi/ 核心 |
| --- | --- | --- |
| **摄入量** | 你打电话 `generateText` 从您的处理器 | `dispatch()` 存储 a `queued` 运行; a `idempotencyKey` 将重交付转换为当前运行 |
| **货币** | 两个同一期的网友互相比赛 | 每跑一次一次 `concurrencyKey`,通过复制品的商店执行 |
| **重复性** | 撞车会失去对话 | 每一步后都有一个检查站;从最近一个检查站恢复运行 |
| **副作用** | 重审工具呼叫帖 | `defineEffectTool()` 记录每个效果键的每个结果,并可以在动作前检查远程系统 |
| **核准** | 你建起暂停,存储和召回 | `await approve(ctx, { title })` 在工具中暂停运行 `waiting`,跨越重启; `engine.approve()` 或者说 `resume(token, decision)` 答案和电话随决定重播 |
| **限制** | `stopWhen` 每个呼叫 | `maxSteps`, (中文(简体) ), `maxTokens` 财务报告和审定财务报表 `timeoutMs` 每跑一次,以 `completed` 或者说 `failed` |
| **关闭** | 运行随进程而死 | `drain()` 等待飞行,然后标记其余部分 `interrupted` 用于另一个复制 |

模型、消息和工具保留AI SDK类型: `defineModelAgent()` 使用一个 `LanguageModel` (或 a 个) `'<provider>/<model id>'` 串起引擎解决 `EngineOptions.models`和一个平地 `ToolSet` (与 `tool()`,或 `defineTool()` 用于读取运行上下文的工具),而没有任何东西被chamvi类型所包裹.

![dispatch() stores a queued run, deduplicated by idempotency key. The engine claims it and runs it: every LLM or tool step is followed by a checkpoint in the store. A run ends completed, failed or cancelled. A tool that awaits approve() pauses the run in waiting; approving or denying it requeues the run, and the call runs again with the decision. drain() or a crashed process leaves a run interrupted or with an expired claim; recover() requeues it, and the next execution continues from the latest checkpoint.](https://raw.githubusercontent.com/chamvi/chamvi/master/.github/assets/run-lifecycle.svg)

**目录**

-   [安装](https://npmcn.com/package/%40chamvi/core/#readme-installation)
-   [使用量](https://npmcn.com/package/%40chamvi/core/#readme-usage)
    -   [代理人和渠道](https://npmcn.com/package/%40chamvi/core/#readme-agents-and-channels)
    -   [效果工具](https://npmcn.com/package/%40chamvi/core/#readme-effect-tools)
    -   [核准](https://npmcn.com/package/%40chamvi/core/#readme-approvals)
    -   [代理状态](https://npmcn.com/package/%40chamvi/core/#readme-agent-state)
    -   [储存和储存库](https://npmcn.com/package/%40chamvi/core/#readme-stores-and-repositories)
-   [选项](https://npmcn.com/package/%40chamvi/core/#readme-options)
-   [API 密码](https://npmcn.com/package/%40chamvi/core/#readme-api)
-   [页:1](https://npmcn.com/package/%40chamvi/core/#readme-notes)
-   [许可证](https://npmcn.com/package/%40chamvi/core/#readme-license)

## 安装

```bash
npm install @chamvi/core ai --save
```

仅限无害环境管理,节点.js `>=26.0.0`。 。 。 . `ai@^7` (Vercel AI SDK)是一个对等依赖; 添加您的模型的提供者包, 例如 `@ai-sdk/anthropic`。 。 。 .

## 使用量

一个代理商、一个内存商店、一个开发控制台频道和一个手动发送的运行,其答案来自:

```typescript
import type { LanguageModel } from 'ai';
import { z } from 'zod';
import {
    Engine,
    consoleChannel,
    createMemoryStore,
    defineEffectTool,
    defineModelAgent,
} from '@chamvi/core';

export async function triageIssue(model: LanguageModel) {
    const labels: string[] = [];
    const lines: string[] = [];

    const triage = defineModelAgent({
        name: 'triage',
        model,
        instructions: 'Label the issue in the trigger payload as bug, feature or question.',
        budget: { maxSteps: 5 },
        tools: {
            // the result is recorded per (run, tool, input): a resumed run reuses it
            addLabel: defineEffectTool({
                description: 'Adds a label to the issue.',
                inputSchema: z.object({ label: z.enum(['bug', 'feature', 'question']) }),
                execute: async ({ label }, { context }) => {
                    labels.push(label);
                    // answers where the run came from, at most once per message
                    await context.channels.findOne()?.emit({ body: `Labelled as ${label}.` });

                    return { added: label };
                },
            }),
        },
    });

    const engine = new Engine({
        store: createMemoryStore(),
        agents: [triage],
        channels: [consoleChannel({
            write: (line) => {
                lines.push(line);
            },
        })],
    });

    await engine.start();

    const { runId } = await engine.dispatch({
        agent: 'triage',
        trigger: 'manual',
        channel: 'console',
        address: 'issue-1',
        payload: { title: 'App crashes on start' },
    });

    await engine.idle();
    await engine.stop();

    return {
        run: await engine.getRun(runId),
        labels,
        lines,
    };
}
```

跑步解决了 `completed`,以及 `output` 是模型最后答案的文本(结构化为 `output`,解析值;控制台频道已写入 `Labelled as bug.` 一次 一次吗 这是代码 [`test/fixtures/readme-example.ts`](https://npmcn.com/package/%40chamvi/core/test/fixtures/readme-example.ts),测试套房运行 与脚本模型.

### 代理人和渠道

-   `defineModelAgent()` 检查名称( n)`^[a-z0-9]+(-[a-z0-9]+)*$`,最多64个字符),且订阅代号是独一无二的,并填写默认预算(`maxSteps: 20`, (中文(简体) ), `timeoutMs: 900_000`) (中文(简体) ).
-   `tools` 一个简单的AI SDK `ToolSet`,在模块范围或工厂中定义一次 `(ctx) => ToolSet` 用于动态集(称为每次执行一次)。 工具构建 `defineTool()` (或 `defineEffectTool()`)将运行上下文读取为 `context` 内 `execute`数字 : `run` (单位:千美元)`runId`, (中文(简体) ), `agent`, (中文(简体) ), `trigger`, (中文(简体) ), `signal`),经纪人的 `state` 和运行 `artifacts`每一次执行一次,每个呼叫和工厂都有一个上下文;视之为不可改变.

```typescript
const lookup = defineTool({
    inputSchema: z.object({ issue: z.number() }),
    execute: async ({ issue }, { context }) => fetchIssue(issue, { signal: context.run.signal }),
});
```

-   只有工具,他们 `contextSchema` 是查姆维的 `toolContextSchema` 获取背景。 具有自身能力的第三方工具 `contextSchema` 获得代理的输入 `toolsContext`,通过参考。 输入工具的计程器失败运行 `validation_error`,而不记录值。 命名一个 chamvi 工具或没有工具的条目是一个 `InvalidAgentDefinitionError` (推着) `defineModelAgent()` 对于一个平地的集, 一个工厂失败运行.

```typescript
tools: { search: searchTool },
toolsContext: { search: { apiKey: process.env.SEARCH_KEY } },
```

-   一个频道( A)`IChannel`数字 : `name`选项 `defaultAddress`, (中文(简体) ), `start`, (中文(简体) ), `stop`, (中文(简体) ), `in`, (中文(简体) ), `out`任何来自跑步或交谈的事物; `new Engine({ channels })` 注册它们(名称遵循代理名称规则,每个引擎独有). `start()` 第一次恢复后启动每个频道(`start({ channels: false })` 开始无, `drain()` 财务报告和审定财务报表 `stop()` 先拦住他们 代理用户通过 `channels: ChannelSubscription[]`,每个指定一个注册频道(拒绝一个未知频道)。 一个频道通过其 `ChannelContext`,设置 `channel` 以自己的名义.
-   出道由工具驱动:引擎从未发出自己的信息. 在一个工具, `ctx.channels.findOne(name)` 返回注册频道上的控件 `out`,或 `undefined`;没有名称,它是运行的源频道,与其源地址相接. `ctx.channels.findOneOrFail(name?)` 掷出 `ChannelNotFoundError` (单位:千美元)`channel_not_found`改为 `undefined`,以及 `ctx.channels.find()` 返回每个频道 `out`。 。 。 . `handle.emit({ title?, body, key? }, address?)` 通过频道发送 `out`;地址默认为源频道上的源地址,否则为频道的 `defaultAddress` (单位:千美元)`consoleChannel()` 有它的名称, OpenClaw 频道 `deliver.to`) ;没有两者皆是 `validation_error` 工具错误。 发射是一种效应:其关键(`<runId>:emit:<channel>:<sha256 of address and message>`时,或您的 `key`)被记录在效应商店中,所以在一次坠机发送后,一个步骤和一个步骤的再发音相同 `out` 把它当作 `message.key` 打开; 扔出 `out` 没有记录,而且是一个工具错误. `emit` 在工具调用( 在工具厂) 外抛出 `InvalidRunStateError`。 。 。 .
-   `consoleChannel({ name?, write? })` 是开发通道( 仅退出, 默认名称) `console`默认值 `write` `console.log`:每条消息有一条标题行,车体行并需要批准,直到它等待的时候;它从不扔.
-   触发信封(频道、订阅代号、有效载荷); `address` )成为了运行的第一个用户消息,作为JSON块.
-   `dispatch({ ..., attachments: [{ mediaType, filename?, data }] })` 启动带有文件的运行: 在运行创建之前, 每个运行被存储为运行的一件文物( 复制的发送存储什么也没有) , 它的元数据登陆 `run.trigger.attachments` (单位:美元) `<runId>.0000`, (中文(简体) ), `<runId>.0001`,...,所以列表会保持输入顺序,模型会得到字节作为第一个消息的文件部分. 检查点保留一个引用, 绝不是字节; 丢失的文物失败 `artifact_not_found`。 。 。 .
-   工具上下文(也是工厂的论点) `artifacts`,范围为运行: `put({ mediaType, filename?, data })`, (中文(简体) ), `get(id)` 财务报告和审定财务报表 `list()`。 。 。 . `put()` 本身没有效果 `defineEffectTool` 保存文件一次.
-   `output` 取一个AI SDK `Output` (例如:. `Output.object({ schema })`: 完成运行 `output` 然后是解析的数值而不是文本,最后一个不解析的答案会以 `validation_error` (引用的原因被切为500个字符;整个答案留在 `llm` 步骤)。 在输出符号限制下断掉的答案, 或者在工具上结束的回路, 没有执行, 失败了 `incomplete_response`。 。 。 .
-   引擎流 每一个模型调用: `engine.on('run.delta', ({ delta }) => ...)` 获得 `{ runId, step, kind: 'text' | 'reasoning', text }` 在模特儿写的时候 德尔塔从未被存储,并且在执行运行的过程中只接触到听众.
-   一个失败的模型调用 中流仍然结束其步骤: `llm` 步数( 到目前为止的文本, 结束原因) `error`),并写出一个检查点,然后运行会随着模型的错误而失败. 一个没有提供者完成部分的流关闭失败运行 `incomplete_response` 从不运行该步骤的工具呼叫.

### 效果工具

```typescript
const comment = defineEffectTool({
    inputSchema: z.object({ issue: z.number(), body: z.string() }),
    effectKey: ({ issue }, ctx) => `${ctx.run.runId}:comment:${issue}`,
    // finds a comment an earlier, crashed attempt already posted
    alreadyApplied: async (key, { issue }) => findComment(issue, effectMarker(key)),
    execute: async ({ issue, body }, { context }) => postComment(
        issue,
        `${body}\n${effectMarker(`${context.run.runId}:comment:${issue}`)}`,
    ),
});

const agent = defineModelAgent({
    name: 'responder',
    model,
    instructions: 'Answer new issues.',
    tools: { comment },
});
```

-   效果密钥默认为 `${ctx.run.runId}:${toolName}:${sha256(input)}`· ; `effectKey(input, ctx)` 替换它. `effectKey` 财务报告和审定财务报表 `alreadyApplied` 获取与 `execute` (单位:千美元)`ctx.run`, (中文(简体) ), `ctx.state`, (中文(简体) ), `ctx.artifacts`)在核心0.1中,他们得到了运行上下文,所以 `ctx.runId` 现在 `ctx.run.runId`。 。 。 .
-   每次通话时,引擎先尝试记录结果,然后 `alreadyApplied`,则 `execute`之后记录结果 `execute` 返回。 扔东西 `execute` 没有记录,所以可以重试.
-   `effectMarker(key)` 是一个隐藏的 HTML 注释,以嵌入工具创建的内容,这样 `alreadyApplied` 还能再找到它.

### 核准

```typescript
const deploy = defineTool({
    description: 'Deploy a version.',
    inputSchema: z.object({ version: z.string() }),
    execute: async ({ version }, { context }) => {
        // pauses the run until the owner answers; the call then runs again and gets the decision
        const decision = await approve(context, { title: `Deploy ${version}?`, timeoutMs: 60 * 60 * 1000 });
        if (!decision.approved) return `Not deployed: ${decision.reason ?? 'denied'}`;
        return deployVersion(version);
    },
});

const deployer = defineModelAgent({
    name: 'deployer',
    model,
    instructions: 'Deploy the requested version.',
    tools: { deploy },
});

const engine = new Engine({
    store,
    agents: [deployer],
});

// later, from the owner's answer to run.waiting
await engine.approve(runId, { approvalId, approved: true });
```

-   `approve(ctx, { title, body?, timeoutMs? })` 在一个工具调用内运行( 它 `execute` 或代理人的 `hooks`) (中文(简体) ). 它把跑步进入 `waiting` (单位:千美元)`run.waiting` 请注明批准日期, `<stepIndex>:<toolCallId>:<n>`),并放出其槽;批准存活了重启. 一旦回了电话 电话就从头开始 `approve()` 返回时 `{ approved, reason?, approver? }`代码之前,它必须是一能。 要求采取同样步骤以保持其成果的其他要求.
-   `ctx.channels.findOneOrFail(name).approve({ title, address? })` 同样的,请求是通过该渠道提出的.
-   要打开一个您没有写的工具, 请打电话 `approve()` 在经纪人的 `beforeToolExecution` 钩子和掷出 `ToolDeniedError` 为拒绝.
-   `engine.approve(runId, { approvalId, approved, reason?, approver? })` 回答当前等待点, 对于一个给批准者本身授权的呼叫者。 答案是单用.
-   批准书未在其 `timeoutMs` (默认24小时)被拒绝的原因 `approval timed out`。 。 。 .

### 内容不可信

工具可以声明 `trust: { taint: true, guardWhenTainted: true }` 打开 `defineTool()` 或者说 `defineEffectTool()`。 。 。 . `taint` 在结果或执行错误暴露于模型之前标记运行; `guardWhenTainted` 要求批准或拒绝在运行已被污染时执行。 每个旗帜接受布尔或 `(input, ctx) => boolean | Promise<boolean>` 上观相. 频道与 `untrusted: true` 开始被污染的跑道。 第三方工具默认可信; 用代理工具的名称分类 `trust.tools` 超载.

```typescript
trust: {
    onTainted: 'approve', // default; use 'deny' to refuse outbound calls
    tools: {
        externalSearch: { taint: true },
        publish: { guardWhenTainted: true },
    },
},
```

第一次接触持续存在,因为 `run.taint: { at: Date, source: string }` 在结果到达模型之前 它在检查站存活下来并重新开始运行;被派遣的运行继承它,等待被污染儿童的父母在结果达到其模式之前被玷污,谈话保守地玷污了接收运行。 自定义商店必须保存此可选字段 。 数据库的迁移也标志着先前存在的未完成的行经被污染了,因为它们的检查站可能已经包含外部内容.

**用停机时间升级,而不是滚动部署 :** 停止所有老入侵者,工人和批准人 在每个复制品和预定工作, 等待他们离开, 然后迁移/回填, 然后只开始新的二进制。 不要在同一家商店混合新旧运行时间 。 旧的传票人可以向其源道透露出一个新的自动审批的自有争辩体;旧的工人可以在一次性回填后创建出未被污染的跑道. 仅靠处决是不够的。 自定义商店需要相同的停止/回填/启动序列. 见 [多个复制品](https://chamvi.dev/deployment/replicas#upgrading-to-untrusted-content-gates)。 。 。 .

曝光后,出行工具需要持久的批准(或被拒绝). 门运行在最后验证的输入后 `beforeToolExecution`,在效果检查之前;改变参数需要新的决定。 完整的论证保留在批准信箱/API中. 自动源渠道通知只包含一个通用审查请求. 直接通道的出入口也被封入,除了发送到同一通道的源地址或由代码配置的默认地址. 这些是 **固定目的地例外**,不能保证信息体.

`extract(ctx, { schema, content, instructions?, model? })` 调用结构化输出且没有工具的单独模型。 在可信任的工具代码中获取原始内容并只返回提取;一个普通的不可信读取后再取取不会去除纹章. 只有保守的受约束的策略可以避免 ta:字面常数(包括: `null`),布林斯/null,数字,固定的enum,被关闭的对象,数组被绑定为10个项,而图案字符串被绑定为200个字符. 自由文本、参考文献、梳理器和未知的图案特性会给运行造成影响。 结果有效果;提取从未清除出已存在的污点。 呼叫者仍然拥有对所提取值的授权和语义验证.

**限制 :** 这不是一个快速注射防沙箱。 被启用的 shell 执行可以绕出出道工具门,包括通过脚本和嵌入过程. Shell命令政策和可选权限分类器是单独的工作. 国家出处、供应商执行的工具、沙盒网络入侵和向模型提供者披露信息都不属于这一界限。 来源答复/默认地址发送和未分类的第三方工具仍然是可信赖的能力。 GitHub 读取工具将模式选择的查询、路径和校对发送到 GitHub API , 但没有出入口; 将这些工具归类为出入口 `trust.tools` 如果API操作员或其日志未经批准不得接收任意运行的数据.

### 输入器和工具访问

跑跑可以携带起跑者:谁发动跑跑跑,作为认证者解决跑跑跑(英语:`@chamvi/http` 由请求的委托人提供). `toolPolicy` 决定每个工具运行是否可以使用;不向模型提供被拒绝的工具.

```typescript
const ops = defineModelAgent({
    name: 'ops',
    model,
    instructions: 'Operate the service.',
    tools: { deploy, rollback },
    // offers a tool only when the invoker holds tool:ops:<tool>; cron and webhook runs get none
    toolPolicy: requireToolPermission(),
    hooks: {
        // release managers deploy without asking
        async beforeToolExecution({ toolName, input }, ctx) {
            const { invoker } = ctx.run.trigger;
            if (toolName !== 'deploy' || (invoker && hasPermission(invoker.permissions, 'release:manage'))) return input;
            const decision = await approve(ctx, { title: 'Deploy?' });
            if (!decision.approved) throw new ToolDeniedError('Deploy denied.');
            return input;
        },
    },
});

const { runId } = await engine.dispatch({
    agent: 'ops',
    trigger: 'http',
    channel: 'http',
    payload: {},
    invoker: { id: 'u-42', kind: 'user', permissions: ['tool:ops:deploy'] },
});

// later, once the run waits: the approver is recorded on the run's wait step
const { approvalId } = (await engine.getRun(runId))!.waiting!;
await engine.approve(runId, { approvalId, approved: true, approver: { id: 'u-7', kind: 'user', permissions: [] } });
```

-   援引者(`{ id, kind, name?, permissions }`)是即时拍摄的快照. 运行会贯穿审批和重启;取消赠款不会达到已经持有的运行.
-   与援引者 `idempotencyKey` 范围包括:`<agent>:<channel>:<kind>:<id>`:只有同一引用者的重试被去重复,另一个具有相同密钥的引用者得到自己的运行.
-   工具代码视其为 `context.run.trigger.invoker` 在工具和工厂 `ctx.run.trigger.invoker` 实际上,钩和代理钩.
-   该政策还包括国家工具。 给一个仍作为工具出错到达的被拒绝工具的呼叫失败, 运行继续进行: 步骤将其记录为 `tool_not_allowed` (单位:千美元)`ToolNotAllowedError`),无论是该型号总称它(该型号看到AI SDK的不可用工具出错),还是一个来自更古老历史的经批准的呼叫到达了引擎的再检查.
-   权限是 `:`\- 分开的: `*` 单是给一切,a `*` 区段匹配一个区段,区段计数必须匹配. `requireToolPermission({ withoutInvoker: 'allow' })` 让运行时没有引用器使用每个工具.

### 代理状态

```typescript
const digest = defineModelAgent({
    name: 'digest',
    model,
    instructions: 'Track open loops across days.',
    state: { loops: z.object({ title: z.string(), due: z.string().optional() }) },
    tools: ({ state }) => ({
        countLoops: tool({
            inputSchema: z.object({}),
            execute: async () => (await state.collection('loops').list()).length,
        }),
    }),
});
```

-   `state.get` 财务报告和审定财务报表 `state.set` 是每个代理商的密钥价值商店。 每个申报的集合都持有文件,并经过其标准Schema关于上升的验证.
-   模型还获得每个收藏作为 `state_<collection>_list`, (中文(简体) ), `state_<collection>_upsert` 财务报告和审定财务报表 `state_<collection>_remove` 工具; 更新和去除是效果工具.

### 储存和储存库

`createMemoryStore()` 将一切保存在过程中的记忆中,用于开发和测试. 工厂将独立的容量储存库(运行、台阶、检查站、一能钥匙、锁、效果、状态、文物、代理修改和可选对话)装入平地 `IStore` 汇总,而不是带有转发方法的外表,并证明他们与共用合同套房的合同来自 [`@chamvi/test-kit`](https://npmcn.com/package/%40chamvi/test-kit)数字 :

```typescript
import { describeRepositoryContract } from '@chamvi/test-kit';

describeRepositoryContract((clock) => createMemoryStore({ clock }));
```

工厂收到 `ControllableClock` 并且必须使用它 每一个过期决定。 该套房运行于维特.

仓库查询的使用 `findOne` 财务报告和审定财务报表 `find`匹配 `findOneOrFail` 财务报告和审定财务报表 `findOrFail` 方法,当缺席应该抛出。 收集结果保持现有形状: `runs.find` 返回时 `{ data, total }`时 `artifacts.find` 返回数组. `OrFail` 检查所选结果, 所以一个空页即使其总计为非零也会丢出 。 国家价值观,例如: `null`, (中文(简体) ), `false` 财务报告和审定财务报表 `0` 在场。 域突变保留其具体名称,例如: `claim` 财务报告和审定财务报表 `beginTurn`。 。 。 .

### A. 背景情况

一个工具通过打出键而不是关闭到达共享实例(API客户端,GitHub App,工作空间管理器). 发动机以参考方式保持其价值; `inject(ctx, key)` 在工具的读取它 `execute`,在工具厂和效应钩中,任何规定的都从未储存或序列化(`ToolContext` 实值 `{ run, state, artifacts, channels }` 并且没有给定值的字段.

```ts
import { defineContextKey, defineTool, inject } from '@chamvi/core';

const DEPLOY = defineContextKey<IDeployClient>('deploy');

const deploy = defineTool({
    description: 'Deploys a version.',
    inputSchema: z.object({ version: z.string() }),
    execute: async ({ version }, { context }) => inject(context, DEPLOY).deploy(version),
});

engine.provide(DEPLOY, client); // once per key, after new Engine()
```

缺少值抛出 `ContextNotProvidedError` (单位:千美元)`context_not_provided`,只命名密钥:在 `execute` 和效果钩,一个失败的运行(在任何型号呼叫之前) 在工具厂. `tryInject(ctx, key)` 返回时 `undefined` 换句话说. `provide` 拒绝 `undefined`键,不是来自 `defineContextKey()` 一个键的第二个值.

## 选项

`new Engine(options)`数字 :

| 选项 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `store` | `IStore` | 所需经费 | 跑道、台阶、检查站和国家 |
| `agents` | `Agent[]` | 所需经费 | 这个引擎运行的代理商 |
| `channels` | `IChannel[]` | `[]` | 频道由独有的名称开始 `start()` 然后先停下来 `drain()`编号 :`stop()`; 工具通过 `ctx.channels` |
| `concurrencyMaxRuns` | `number` | `4` | 在此过程中立即执行 |
| `model` | `ModelRef` | 无 | 没有代理的模型; 检查字符串 `models` 建筑业 |
| `models` | `IModelResolver` | 无 | 决定: `'<provider>/<model id>'` 字符串; 注册检查每个字符串校对通过它; 没有它,字符串校正是一个 `InvalidAgentDefinitionError` (通过a) `LanguageModel` 对象) |
| `claimTtlMs` | `number` | `60_000` | 租一次跑步,每次续约 `claimTtlMs / 3`;新工作的民意调查,过期的审批和被废弃的运行使用相同的间隔 |
| `owner` | `string` | `` `${hostname}-${pid}` `` | 索赔中该复制品的身份 |
| `clock` | `IClock` | `systemClock` | 时间源,可在测试中替换 |
| `onError` | `(error, run?) => void` | `console.error` | 没有呼叫器可丢的错误, 如租赁丢失 |

`defineModelAgent(definition)`数字 :

| 外地 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- |
| `name` | `string` | 所需经费 | 每个应用程序独有, 小写单词由 `-` |
| `model` | `ModelRef` | `EngineOptions.model` | A 类 `'<provider>/<model id>'` 字符串解析通过 `EngineOptions.models`,或任何AI SDK `LanguageModel` |
| `instructions` | `AgentInstructions` | 所需经费 | 本地系统/ 用户/ 协助信件的字符串或只命令重读的数组 |
| `channels` | `ChannelSubscription[]` | 无 | 订阅引擎注册的频道 |
| `tools` | `ToolSet | (ctx) => ToolSet` | 无 | 一个简单的工具集,或者一个工厂要求每次执行 |
| `toolsContext` | `Record<string, unknown>` | 无 | 每个工具名,不是 chamvi 的工具的上下文,通过引用传递 |
| `state` | `Record<string, StandardSchemaV1>` | 无 | 输入状态收藏 |
| `toolPolicy` | `(toolName, { run }) => boolean` | 无 | 运行可能使用的工具,例如:. `requireToolPermission()` |
| `budget` | `{ maxSteps, maxTokens?, timeoutMs? }` | `{ maxSteps: 20, timeoutMs: 900_000 }` | 每次运行; 超时适用于每次执行 |
| `hooks` | `AgentHooks` | 无 | `beforeToolExecution` 编号 : `afterToolExecution` 环绕每个工具调用: 重写输入或输出, 闸门工具 `approve()` |
| `output` | `Output` | 无 | AI SDK 结构输出; 已完成运行 `output` 是解析值 |

## 结构化指令

一个系统消息的字符串仍然是简写. 本地信件类型可以从核心直接获取 :

```ts
import { defineModelAgent } from '@chamvi/core';
import type { AgentInstructions, SystemModelMessage, UserModelMessage } from '@chamvi/core';

const policy: SystemModelMessage = { role: 'system', content: 'Summarize the report.' };
const example: UserModelMessage = { role: 'user', content: [{ type: 'text', text: 'All checks passed.' }] };
const instructions: AgentInstructions = [policy, example, { role: 'assistant', content: 'Ready to release.' }];
const agent = defineModelAgent({ name: 'reporter', instructions });
```

系统内容是一个字符串; 用户/助理内容和 `providerOptions` 使用本地的 SDK 类型 。 引导系统块通过 SDK `instructions`;剩余消息在运行记录之前会保持顺序,包括任何后期的系统块. 一级技能附加一个单独的元数据系统块. 这些被配置的信息是短暂的:它们为模型/工具上下文提供水分的文物标记,远离检查站和对话历史,永远不会成为等待重播的电话。 重新回顾的对话信息遵循这个已配置的前缀,批准恢复使用被捕获的对话快照. 恢复处决从目前的定义中重建。 存储的誊本系统角色在重放/模型工作前被拒绝. 手动 `SkillCatalog.instructions` 仍然是明确构成的字符串.

见 [指南](https://chamvi.dev/guide/agents#instructions) 用于输入的示例和特定角色的内容限制.

## API 密码

| 导出 | 仁爱 | 目的 |
| --- | --- | --- |
| `AgentInstruction`, (中文(简体) ), `AgentInstructions` | 类型 | 原生系统/用户/助理信息联盟和字符串/只读阵列配置 |
| `SystemModelMessage`, (中文(简体) ), `UserModelMessage`, (中文(简体) ), `AssistantModelMessage`, (中文(简体) ), `ModelMessage` | 类型 | 保存本地 SDK 信件类型 |
| `UserContent`, (中文(简体) ), `AssistantContent`, (中文(简体) ), `TextPart`, (中文(简体) ), `ImagePart`, (中文(简体) ), `FilePart` | 类型 | 原始 SDK 内容和部分类型 |
| `defineModelAgent` | 函数 | 验证代理定义并应用默认值 |
| `DEFAULT_MAX_STEPS`, (中文(简体) ), `DEFAULT_TIMEOUT_MS` | 常数 | 默认预算 : `20` 步骤, `900_000` 分钟 |
| `Engine` | 类 | `store`, (中文(简体) ), `clock`, (中文(简体) ), `getAgent`, (中文(简体) ), `listAgents`, (中文(简体) ), `putAgent`, (中文(简体) ), `removeAgent`, (中文(简体) ), `getChannel`, (中文(简体) ), `listChannels`, (中文(简体) ), `provide`, (中文(简体) ), `start`, (中文(简体) ), `dispatch`, (中文(简体) ), `getRun`, (中文(简体) ), `on`, (中文(简体) ), `approve`, (中文(简体) ), `cancel`, (中文(简体) ), `recover`, (中文(简体) ), `tick`, (中文(简体) ), `idle`, (中文(简体) ), `stop`, (中文(简体) ), `drain` |
| `createMemoryStore()` | 函数 | 包括对话在内的独立内存集合 |
| `defineTool` | 函数 | 一个AI SDK `tool()` 谁 `execute` 得到运行 `ToolContext` 作为 `context` |
| `defineContextKey`, (中文(简体) ), `inject`, (中文(简体) ), `tryInject` | 函数 | 键入上下文键,从 a 读取引擎上提供的值 `ToolContext` |
| `toolContextSchema` | 对象 | 这个 `contextSchema` 这标志着一个chamvi工具 |
| `defineEffectTool`, (中文(简体) ), `effectMarker` | 函数 | 记录的副作用工具及其隐藏标记 |
| `EFFECT` | 符号 | 标记创建的工具 `defineEffectTool()` |
| `wrapToolsForRun` | 函数 | `wrapToolsForRun(tools, ctx, store, { allow?, hooks? })`: 应用效果记录和代理钩对 a `ToolSet` 在引擎外,有一个 `ToolContext`; 可选 `allow(toolName)` 重新检查每次呼叫( 拒绝的呼叫) `ToolNotAllowedError`(中文(简体) ) |
| `approve` | 函数 | `approve(ctx, { title, body?, timeoutMs? })`: 从工具调用内部持久批准 |
| `DEFAULT_APPROVAL_TIMEOUT_MS`, (中文(简体) ), `APPROVAL_TIMEOUT_MAX_MS` | 常数 | `86_400_000` (24小时), `2_147_483_647` |
| `createAgentState`, (中文(简体) ), `createStateTools` | 函数 | 国家API在商店,和 `createStateTools(schema)`,生成状态工具(它们读取 `context.state`(中文(简体) ) |
| `hasPermission`, (中文(简体) ), `matchesPermission`, (中文(简体) ), `toolPermission` | 函数 | 权限匹配和 `tool:<agent>:<tool>` 权限 |
| `requireToolPermission` | 函数 | A 类 `toolPolicy` 检查引用者的权限 |
| `consoleChannel` | 函数 | `consoleChannel({ name?, write? })`: 开发通道, 仅输出, 记录每个消息( 默认名称) `console`默认值 `write` `console.log`(中文(简体) ) |
| `assertTriggerKey`, (中文(简体) ), `normalizeEnvelope` | 函数 | 信封密钥和地址的255个字符,无 NUL 规则;在频道之前存储的信封的回读(`source`, (中文(简体) ), `thread`用于存储执行 |
| `isArtifactMediaType` | 函数 | 关于附件和文物的媒体类型规则(`type/subtype`,无参数) |
| `artifactFilePart` | 函数 | 文件项为工具 `toModelOutput` 返回一件文物:步骤和检查站的标记,模型的字节 |
| `ChamviError` | 类 | 下面每个错误的基准类 |
| `InvalidAgentDefinitionError`, (中文(简体) ), `InvalidRunStateError`, (中文(简体) ), `RunNotFoundError`, (中文(简体) ), `ArtifactNotFoundError` | 类 | 拒绝定义和引擎呼叫 |
| `BudgetExceededError`, (中文(简体) ), `FatalToolError`, (中文(简体) ), `IncompleteResponseError`, (中文(简体) ), `LeaseLostError`, (中文(简体) ), `TimeoutError`, (中文(简体) ), `ValidationError` | 类 | 运行失败和报告的条件; `ValidationError.issues` 保留有效问题 |
| `ContextNotProvidedError` | 类 | `inject()` 找不到密钥的值( e)`context_not_provided`(中文(简体) ) |
| `ChannelNotFoundError` | 类 | `ctx.channels.findOneOrFail()` 指定一个频道,引擎没有或没有 `out` (单位:千美元)`channel_not_found`(中文(简体) ) |
| `ToolNotAllowedError` | 类 | 用于调用工具的工具错误记录 `toolPolicy` 拒绝 |
| `ToolDeniedError` | 类 | 大门(例如: `beforeToolExecution` hook)拒绝一个工具呼叫(`tool_denied`); 工具出错,绝不致命 |
| `SandboxError` | 类 | 沙盒工作空间或提供者失败( S)`@chamvi/sandbox` 及其提供者; 工具出错, 从未失败运行 |
| `ErrorCode` | 对象 | 这个 `code` 上方每个错误 |
| `systemClock` | 对象 | 默认 `IClock` |

类型 : `Agent`, (中文(简体) ), `AgentDefinition`, (中文(简体) ), `ToolContext`, (中文(简体) ), `ContextKey`, (中文(简体) ), `IContextProvider`, (中文(简体) ), `ToolPolicy`, (中文(简体) ), `AgentHooks`, (中文(简体) ), `ToolCallInfo`, (中文(简体) ), `TriggerEnvelope`, (中文(简体) ), `Invoker`, (中文(简体) ), `Run`, (中文(简体) ), `RunStatus`, (中文(简体) ), `Step`, (中文(简体) ), `Checkpoint`, (中文(简体) ), `WaitPoint`, (中文(简体) ), `Budget`, (中文(简体) ), `Usage`, (中文(简体) ), `ApprovalRequestInput`, (中文(简体) ), `ApprovalDecision`, (中文(简体) ), `ApprovalAnswer`, (中文(简体) ), `IStore` 及其能力接口, `MemoryStoreOptions`, (中文(简体) ), `Artifact`, (中文(简体) ), `ArtifactInput`, (中文(简体) ), `IRunArtifacts`, (中文(简体) ), `IChannel`, (中文(简体) ), `ChannelSubscription`, (中文(简体) ), `ChannelContext`, (中文(简体) ), `ChannelMessage`, (中文(简体) ), `ChannelSendOptions`, (中文(简体) ), `ChannelHandle`, (中文(简体) ), `EmitMessage`, (中文(简体) ), `ConsoleChannelOptions`, (中文(简体) ), `IAgentState`, (中文(简体) ), `RunEvent`, (中文(简体) ), `EngineOptions`, (中文(简体) ), `ModelRef`, (中文(简体) ), `IModelResolver`, (中文(简体) ), `IClock`。 。 。 .

测试助手( E)`ControllableClock`, (中文(简体) ), `describeRepositoryContract`住在这里 [`@chamvi/test-kit`](https://npmcn.com/package/%40chamvi/test-kit)。 。 。 .

## 页:1

`EngineOptions.skills` 每个代理设备的供应缺省; `AgentDefinition.skills` 增加范围外加. 两个都接受通用 `SkillInput` 协议从核心。 导入技能数据类型, `gitSkills`, (中文(简体) ), `loadSkillBundle`,自定义适配器(`defineSkill`, (中文(简体) ), `defineSkillSource`和可选目录 [`@chamvi/skills`](https://npmcn.com/package/%40chamvi/skills/README.md)。它的工厂值自动带有运行时间,没有模块注册。 核心坐标准备,取消和普通的贡献工具执行;可选软件包拥有验证,内容,目录和缓存. 核心工作没有安装技能.

-   **工具错误不会失败运行 .** 它作为工具出错的结果回到模型. 掷出 `FatalToolError` 以失败运行; 步骤预算上限重试循环.
-   **预算结算.** 跑步经过 `maxSteps` 或者说 `maxTokens` 当模型仍然想要调用工具时, 代码失败 `BudgetExceeded`; 点击其超时的运行失败 `Timeout`。 。 。 .
-   **效果会在发生后记录下来.** 工具的副作用和商店写入之间发生相撞, 重复恢复时的效果, 除非 `alreadyApplied` 发现它.
-   **一步一步的几项批准是一次处理的.** 跑步按呼叫顺序在第一个等待;另一个被暂停的呼叫在恢复后继续等待,并在任何进一步的型号呼叫之前再次询问.
-   **`createMemoryStore()` 不持久.** 一切随过程而去;使用一长串商店来活下来重启或运行复制品.
-   **`stop()` 停止投票 和渠道.** 一旦每个频道停止运行,它就会解决 `drain()` 关闭.

## 许可证

原载 [Apache 许可证 2.0](https://npmcn.com/package/%40chamvi/core/LICENSE)。 。 。 .

## 常见问题

### @chamvi/core 是什么？

用于自发托管,触发驱动的AI代理的核心引擎:代理,触发和可持久运行\.

### 如何安装 @chamvi/core？

在项目目录运行 npm install @chamvi/core，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：ai（^7）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @chamvi/core 支持 TypeScript 吗？

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

### @chamvi/core 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

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

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

### @chamvi/core 可以商用吗？

@chamvi/core 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @chamvi/core 的下载量有多少？

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

### @chamvi/core 还在维护吗？

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

