# @columenlabs/lumen-ai 中文文档

规范地址：https://npmcn.com/package/%40columenlabs/lumen-ai/

版本：0\.1\.219
npm 元数据更新时间：2026-11-09T05:44:05.024Z
中文译文更新时间：2026-11-10T11:36:54.150Z
软件包许可：MIT

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

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

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

- 包体积（解压后）：413 kB，62 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：11 个
- peer 依赖：@modelcontextprotocol/sdk ^1\.29\.0
- 首次发布：2026-10-24T21:47:22.700Z
- 最新版本发布：2026-11-09T05:44:04.857Z
- 近 30 天下载量：39995（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：183（近 12 个月 183 个）

## 中文简介

卢门的助手和代理部件:一个聊天助手的服务器(Claude levels,工具通过MCP,网络,手接,花盖),服务于一个来自Worker的MCP服务器,只读工具集和调用分解工具.

## 安装

```sh
npm install @columenlabs/lumen-ai
```

也可以使用：`pnpm add @columenlabs/lumen-ai`、`yarn add @columenlabs/lumen-ai`、`bun add @columenlabs/lumen-ai`

## README

# 校对:soup

Cloudflare工人应用软件的助手和代理部件. 从 Worker 服务 MCP 服务器, 只保留只读调用器的读取工具, 测量每个工具调用, 以及聊天助理的服务器侧(`@columenlabs/lumen-ai/assistant`) (中文(简体) ).

## 安装

```sh
bun add @columenlabs/lumen-ai @columenlabs/lumen-ops @modelcontextprotocol/sdk
```

切换 `@columenlabs/lumen-*` 软件包到相同的准确版本. `@modelcontextprotocol/sdk` 是一个对等点: 应用程序自己的副本构建服务器 .

## 服务 MCP 服务器

为您已检查的呼叫者创建一个服务器, 然后将请求交给它 。 每项请求都是单独提出的(无法说明的可流式HTTP、JSON答复),因为一个工人在请求之间没有任何关系.

```ts
import { jsonResult, keepReadTools, meterTools, serveMcp } from '@columenlabs/lumen-ai';
import { setToolSink } from '@columenlabs/lumen-ops/tools';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';

setToolSink(env.TOOL_CALLS); // once per isolate; tool calls are metered only when it is set

function build(person: string) {
  const mcp = new McpServer({ name: 'my-app', version: '1.0.0' });
  mcp.registerTool(
    'account_list',
    { description: 'Accounts and balances', annotations: { readOnlyHint: true } },
    async () => jsonResult(await accounts(person)),
  );
  return mcp;
}

app.all('/mcp', async (c) => {
  const server = meterTools(build(c.get('person')), { app: 'my-app' });
  if (c.get('viewOnly')) keepReadTools(server);
  return serveMcp(server, c.req.raw, { onRequest: ({ tool }) => c.set('tool', tool) });
});
```

## 出口

| 导出 | 它会做什么 |
| --- | --- |
| `serveMcp(server, request, opts?)` | 答复一个MCP请求并关闭服务器; `onRequest` 先听到方法和工具 |
| `jsonResult(value)` | 一个工具结果将一个 JSON 值作为文本 |
| `keepReadTools(server, isRead?)` | 删除每个写入的工具;默认情况下,当工具被读取时只读 `readOnlyHint` 设定 |
| `meterTools(server, opts)` | 环绕每个注册工具, 因此每个调用是一个工具调用点: 墙上时间、 结果、 JSON 列表的行、 输入和输出大小 |
| `registeredTools(server)` | 服务器上的每个工具, 按名称 |
| `mcpCallOf(body)` | JSON-RPC机构要求的方法和工具 |

`meterTools` 写入 `@columenlabs/lumen-ops/tools`; 查看其列的读取.

## 版本数

每次合并到 `main` 立即发布每个 Lumen 软件包的下一条补丁 .

## 一个聊天助手

`@columenlabs/lumen-ai/assistant` 是聊天侧面板背后的服务器: Claude 或 OpenAI 模型在应用程序自己的分级, 应用程序的工具来自任何 MCP 服务器, 网络, 起草人物保存, 交给更高分级, 建议, 以及每月每人开支上限 。 面板和设置部分 `@columenlabs/lumen-ui`';共享类型是 `@columenlabs/lumen-ui-types/assistant`。 。 。 .

```ts
import {
  assistantRoutes,
  createAssistant,
  doSql,
  mcpServerTools,
  sqlAssistantStore,
} from '@columenlabs/lumen-ai/assistant';

const assistant = createAssistant({
  name: 'Helper',
  system: 'You help people with their notes. Use the notes tools for facts.',
  // Smallest first. The app names them; a person picks each tier's model and effort.
  tiers: [
    { id: 'fast', label: 'Fast', about: 'Quick lookups', model: 'claude-haiku-5-5' },
    { id: 'steady', label: 'Steady', about: 'Most work', model: 'claude-sonnet-5-5' },
    { id: 'deep', label: 'Deep', about: 'Hard judgement', model: 'claude-opus-5-5' },
  ],
  groups: [
    { id: 'notes', label: 'Notes', about: 'Read and edit notes', tools: (caller) => mcpServerTools(() => notesServer(caller.id)) },
  ],
  web: { fetch: { blockHosts: ['app.example.com'] }, scrapeql: { url: 'https://scrapeql.example.com/mcp' } },
  store: sqlAssistantStore(doSql(ctx.storage.sql)), // or d1Sql(env.DB); { table } names another table
  sealer, // the app's own sealing: keys and chats are stored sealed
  // A provider's key when none is set in Settings.
  appKey: async (provider) => (provider === 'openai' ? env.OPENAI_API_KEY : env.ANTHROPIC_API_KEY),
});

const routes = assistantRoutes(assistant, {
  base: '/api/assistant',
  caller: (req) => ({ id: personId(req), admin: isAdmin(req) }),
});
app.all('/api/assistant/*', (c) => routes(c.req.raw));
```

-   **供养者.** 级别运行任意模型 `models` (克劳德和OpenAI默认, `CLAUDE_MODELS`, (中文(简体) ), `OPENAI_MODELS`:克洛德通过Anthropic's Messages API,OpenAI通过反应API,拥有相同的工具,草稿,停放和盖. XAI的Grok模型(`XAI_MODELS`)选择在: 列出它们的应用程序在 Model 提供者中获得一行 xAI (一个 API 密钥, `xai-…`);它们运行在同一个响应客户端在 `XAI_BASE_URL` (单位:千美元)`https://api.x.ai/v1`. xAI没有其他应用程序的公开登录,因此Grok只取了一把钥匙. 交接可能交叉供货商. 顾问和快活的死记号是克劳德的.
-   **钥匙.** 每个供应商都有自己的钥匙(`?provider=anthropic|openai|xai` 在关键路线上。 一个管理员粘贴每个人使用的共享关键字(`PUT /key`;在保存之前通过一个免费呼叫进行测试,然后被封住,没有路线返回. 一个人可以增加自己的(第1款)`PUT /my-key`),在自己的密钥上加了1个月盖(`PUT /my-key/cap`) (中文(简体) ).
-   **ChatGPT登录.** 代替自己的OpenAI密钥,一个人可以签入他们的ChatGPT计划(ChatGPT)`POST /my-signin`,则 `POST /my-signin/finish {url}`: 登录在新标签中打开并结束于 `http://127.0.0.1:1455/auth/callback`,不装入的一页,其地址被贴回。 道具被封为自己的钥匙,在用完之前被刷新;计划上的答案数了道具,没有美元.
-   **谁付.** 个人的取出(默认情况下的共享密钥),而其拥有一个关卡提供者的密钥和本月在其封顶下留下的钱(一个管理员设定了共享密钥的每人封顶, `PUT /app`而不是另一个.
-   **工具 来.** 每组为Off,Read,Read + reader + Read + Ready + Ready 每人. 工具是读取其 MCP `readOnlyHint` 已经设定。 在Read + 草稿时,写作只起草一张卡片,并在再次检查访问后按下 Save 时作为个人运行. 一组 `readOnly: true` 仅提供阅读工具。 读取 + 写只提供给一组 `writes: true`:它一时运行 `undo` 设定聊天中每个人的行有 Undo, 它调用 `undo(caller, { tool, args, result })`; 模型被告知什么被撤销。 卡片逐一起草,作为"保存"的一叠. 使用 `mcpServerTools` (一个SDK) `McpServer`, (中文(简体) ), `mcpFetchTools` (一个服务器担任取取处理器,任何SDK), `remoteMcpTools` 或者说 `plainTools`。 。 。 .
-   **腾讯网.** `fetch` 是一个普通的从工作人( 10 s, 2 MB, 从来不是应用程序自己的主机或私人地址) 。 ScrapeQL 自己的工具一旦管理员粘贴了 Cloudflare 访问服务标志( Cloudflare Access service service service services),就加入到它的MCP API上(`PUT /web/scrapeql`) (中文(简体) ). 一个在ScrapeQL自己的Cloudflare账户上的工人 转而通过服务约束, `scrapeql: { url: 'https://scrapeql/mcp', fetch: env.SCRAPEQL.fetch.bind(env.SCRAPEQL) }`: 不存储任何令牌, 工具总是打开, 设置显示一个测试的链接 。 每个网络步骤都带 `web` (单位:千美元)`StepWeb`: 一个搜索 `query` 财务报告和审定财务报表 `results`,或者页面 `read`),因此面板会在其行下折叠一个搜索结果,并在答案下读取每页的数字为"源芯片";模型用这些数字(\[1\])来标记事实.
-   **手取出并劝.** 这个 `escalate` 工具将一个任务交给一个更高的级别(下一级、任意或仅在被问及时); Anthropic 的顾问工具让一个更高的级别发送一个计划,最多两个答案.
-   **聊天** 运行于代理( e)`./agent`, (中文(简体) ), `LumenAgent`应用程序路线 `POST /chat` 每次聊天都会给自己的经纪人读取卡片和复出 `assistantRoutes` 答题 `POST /chat` 含410个 `moved`。通过旧转弯循环保存的聊天可以读取(`GET /chats`, (中文(简体) ), `GET|DELETE /chats/:id`直至 `assistant.purge()` 在他们最后的消息发出30天后.
-   **屏幕移动**:在人物设置 QQ Screen 移动(默认)时,面板会发送其页面映射(`AssistantMessage.screen`: 路由、导航页面、设置区域、屏幕上的卡片、要打开的行)和 `LumenAgent` 给模型一个 `screen` 工具 (`./agent` `screen.ts`) (中文(简体) ). 每个呼叫的动作(去,设置,图表,打开,点)与地图对照检查,保存在聊天中并流出为一 `screen` 事件; 面板通过 `AssistantScreenProvider` (计有: `LumenShell`) 带有Uddo芯片,其结果会回溯到下一条消息(U`outcomes`) (中文(简体) ). 没有什么能通过移动来挽救.
-   **背景工作情况** 用于个人运行的应用程序(分数、摘要)是 `assistant.complete(caller, { task, system, prompt, images?, maxTokens })`: 关于任务的层级的答案( :`tasks`,因此此人在 Sets QQ模型中选择其模型,没有聊天和工具(`images`, base64 及其介质类型, 阅读时提示: 扫描页, 截图 , 向付款人计费, 并在开支和津贴中计费, 如聊天转折. `maxTokens` (默认值1,000)升至 `COMPLETE_MAX_TOKENS` (32,000,包括思考) 答案是流出而来,所以一个长长的连接 `cut: true` 表示在结束前就停止了(应用程序可以再次询问,缩短或继续). 它会扔 `AssistantError` `not_connected`, (中文(简体) ), `app_cap` 或者说 `own_cap` 当没人付得起钱,所以打电话者等待,然后尝试。 它还原了答案 `usd`, (中文(简体) ), `model` 财务报告和审定财务报表 `usage` (键入,缓存读出,每个模型). `run: { id, title }` 发出共享的呼叫 `id` 一个人的用法历史的一行(每轮重建);没有它,一天的任务呼叫共享一行.
-   **用地历史.** 每次聊天( E)`agentTurn` 与 `chat`),每跑一行背景工作是个人月份的一行(`usage:YYYY-MM`,最新的300:其标题,第一和最后使用,符号,成本及其每层和每型号的零件. `GET /usage?month=YYYY-MM` 在月花和月花之外还原; `LumenAssistant`'页脚显示这个月的总和并打开它(`UsageHistoryView`) (中文(简体) ).

### 命令 :, `@` 财务报告和审定财务报表 `#`

面板的作曲者列出了在被打出时可以跟随三个键的. 套件自己的条目是每个应用程序的;一个应用程序只添加自己的.

-   **`/` 命令.** 内建于: `/compact` (总结聊天), `/clear` (一个新的聊天), `/model <tier>` (从现在开始对另一层进行回答)和 `/escalate <task>` (把一个任务交给下一层) 应用程序在服务器上添加了自己的功能 `commands`: 聊天显示打字人和模型得到的 `prompt`,与 `{args}` 替换为名称后(或函数返回的)的词. 应用指令取自内置名.
    
    ```ts
    createAssistant({
      // ...
      commands: [
        { name: 'story', about: 'Find stories for a question', args: '<question>',
          prompt: 'Search my stories for: {args}. List the best three with why each fits.' },
        { name: 'prep', about: 'Prep for an interview', args: '<company>',
          prompt: async (company, caller) => prepPrompt(caller.id, company) },
      ],
    });
    ```
    
    一个在浏览器中起作用的命令(打开一页,设置过滤器)会放在面板上: `LumenAssistant` (或 `useLumenAssistantDock`获取 `commands`,每个 `{ name, about, args?, options?, run }`· ; `run` 返回要发送的文本, 或当它自己采取行动时不发送,以及 `options` 列出输入时其单词的选择.
    
-   **`#` a 等级.** `#` 列出应用程序的分级; 选择是一个芯片, 只随该消息去取(`tier`) (中文(简体) ). 一个更高层次把它当作自己聊天部分的任务;同一个或一个更低层次的回答.
    
-   **`@` 东西.** `@` 列出个人可以指向的,每个源的一组;每个取出是芯片,并随消息作为参考(`kind`, (中文(简体) ), `label` 无论发现什么 模型在消息之前读到的 常备消息来源进入小组`sources`); 页面在显示时添加自己的页面 :
    
    ```tsx
    import { useAssistantSource } from '@columenlabs/lumen-ui/assistant';
    
    useAssistantSource({
      id: 'page',
      label: 'On this page',
      items: (q) =>
        rows
          .filter((r) => r.title.toLowerCase().includes(q.toLowerCase()))
          .map((r) => ({ id: r.id, label: r.title, target: `card:${r.id}`, ref: { kind: 'story', label: r.title, id: r.id } })),
    });
    ```
    
    `target` 在屏幕上点亮它的行被徘徊。 页面的源头取代了相同的站台 `id`。 。 。 .
    
    文本 页面上人物的亮点首先在 `@` (所选的文本),它从最近的地方坐在那里 `data-assistant-where` 属性。 要交接页面上的亮点,请询问按钮 `composeAssistant({ refs: [selectionRef({ text, where })], text: '' })` (或任何参考和文本):面板会用作曲中的芯片打开,专注供人物完成.
    

### 轴心

模型得到的每个消息都从几行轴承开始:现在的人行区的时间(面板发送浏览器的时间),UTC,聊天的最后消息和app的名字还有多久. 他们走在消息中,而不是系统即时,所以即时缓存持有. 应用程序添加自己的行 `bearings`;每通电话得到300毫秒,当它晚到或者抛出其行被忽略.

```ts
createAssistant({
  // ...
  app: 'Notes',
  timeZone: 'America/Los_Angeles', // when the browser sends none
  bearings: ({ now, at, span }) => `Next backup: ${at(nextBackup(now))} (in ${span(nextBackup(now) - now)})`,
});
```

拥有自己的助手循环的应用程序会创建一个相同的块 `bearings({ timeZone, lastAt, app, extras })` 并把它摆在信息之前.

### 查找:一个问题,一个查询

搜索应用程序记录的标准方式(Columen's canonical setup, 2026-10-28):每个显示助手收藏的应用程序都会给它一个找取工具,从没有列表加上一所记录读取. 一个呼叫将问题变成一个运行在行所居住的查询(D1或持久对象的SQLite). 模型只取回相匹配行和所要的字段,并自行作最后调用.

-   **过滤器** (tag,数字和日期范围)是准确的SQL.
-   **单词** 与FTS5指数相匹配(`porter unicode61`,所以"蛋"发现"蛋": `any`, (中文(简体) ), `all`, (中文(简体) ), `none` (放出:"不吃牛奶"),和 `in` 说出哪块地值得看.
-   **含义** 来源于矢量化,选择每个应用程序: `like` ("某事光为一热天") 问出最近的行的索引,相同的过滤器和词来修剪.
-   **工作领域**: 数字,日期或标记字段可能是应用程序在行上自有的SQL(`sql: 'json_array_length(t.steps)'`)而不是一栏.
-   **计数**: 结果带有 `count` (所有匹配), `returned` 财务报告和审定财务报表 `same_name` (不同行同名),所以模型说出正确的数字. 按意义进行搜索 `nearest: true` 没有 `count`:它的行是最接近的几行,而不是每一行相合的行,因此模型从不引用它们作为数个相配.

```ts
import { d1Sql, defineFind, findSql, findTool } from '@columenlabs/lumen-ai/assistant';

export const notesFind = defineFind({
  name: 'notes', label: 'note', table: 'notes', key: 'id',
  where: 'deleted = 0',          // the app's own SQL, always applied
  order: 'updated_at DESC',      // with no words to rank by
  fields: {
    title: { kind: 'text' },
    body: { kind: 'text', show: false },     // searchable, returned only when asked
    tags: { kind: 'text', json: true },      // a JSON column, returned parsed
    folder: { kind: 'tag' },                 // exact filter; its values are listed to the model
    updated_at: { kind: 'date' },            // updated_at_from, updated_at_to
  },
});

// In a group's tool source, per answer (a Durable Object passes doSql(ctx.storage.sql)):
plainTools([await findTool(notesFind, d1Sql(env.DB))]);
```

-   `findTool` 制造 `<name>_find` 带有平面输入图案(每个提供者都使用),并读取每个标记字段的值一次以列出它们. 助理告诉模特儿把一个问题放在一个寻人电话里.
-   `runFind(def, sql, query)` 是没有工具的相同的查询:只绑定参数,从不模型写入SQL. 3秒后就放弃了.
-   `findSql(def)` 给出索引的 SQL. `create` 是一个外部内容 FTS5 表格外加触发器, 使其与每个插入, 更新和删除, 不管是谁写的 . `fill` 索引已经在那里的行,和 `drop` 把它都拿出来。 打开 `create` 财务报告和审定财务报表 `fill` 在迁移(D1)或预算背景步骤(持久目标)中,从未提出要求。 在索引存在之前,单词会回落到一个纯文本匹配,结果也这么说,所以代码可以在它的迁移之前运出.

意思是,对于人们要求松散的应用软件(一本食谱书,一份职业日志;而不是像卡片福利那样的准确记录):

```ts
import { meaningStep, vectorMeaning, workersEmbed } from '@columenlabs/lumen-ai/assistant';

// On the definition: what a row means, and the column every write moves.
meaning: { fields: ['title', 'body', 'tags'], changed: 'updated_at' },

const embed = workersEmbed(env.AI);              // bge-base-en-v1.5: a 768-dimension cosine index
await findTool(notesFind, d1Sql(env.DB), { meaning: vectorMeaning({ embed, index: env.NOTES_INDEX }) });

// Off the request path (waitUntil after a write and when the tool opens, an alarm, a queue):
ctx.waitUntil(meaningStep({ def: notesFind, sql: d1Sql(env.DB), embed, index: env.NOTES_INDEX, mark }));
```

-   `meaningStep` 仅嵌入其 `changed` 栏移动到其书签上(`mark`: 得到并放置, 由应用程序保存), 最多50个步骤在一个嵌入调用和一个上升 `where`)出于指数. 恢复停放地点,一次安全运行两次; `done` 在行左行时是虚假的.
-   一个人的行得到一个 `namespace` 每一个`vectorMeaning` 财务报告和审定财务报表 `meaningStep` 因此,一个指数服务于一个应用.
-   当指数不能回答 3 s, `like` 其余的搜索结果都是这样.

## 云花盘思维的代理

`@columenlabs/lumen-ai/agent` 作为 Cloudflare 思维代理运行一个聊天(`@cloudflare/think`,实验性),在应用的分级,键和工具组. 思考保持了循环,消息,流传,恢复和收缩;套件在付款人的钥匙上添加了模型,个人访问时的工具,花帽和用法. 这将取代 `./assistant`自己的循环.

| 导出 | 它会做什么 |
| --- | --- |
| `LumenAgent` | 一个抽象的思维代理人. 应用程序回答 `plan(turn)` (模型、钥匙、努力、指示、工具来源、剩余资金) `settle(end)` (结果、使用部分、上下文大小、时间) |
| `aiModel(model, key, opts?)` | AI SDK模型用于API密钥上的分级,或用于ChatGPT计划上签名的分级(`key.plan`,通过 `planFetch`(中文(简体) ) |
| `planFetch(fetch?, name?)` | 重写计划登录规则的响应: 一个命名空间中的工具, 没有输出封顶, 强制调用是唯一的工具 |
| `planFallback(primary, fallback, onSwitch)` | 一个计划模型 接通电话, 和其余的转弯 `fallback` 当计划达到使用限值时(在任何输出前为429或用法代码) |
| `turnSettings(model, opts)` | 供货商使用时输出上限和努力 |
| `openAiTools(sources, opts)` | 该应用程序的工具组作为 AI SDK 工具:通过访问读取、起草和写作,结果切入为 16k 字符 |
| `UsageMeter`, (中文(简体) ), `tokenUsage(u)` | 将每个步骤的代号(读写、推理)定价为一个用法部分 |

ChatGPT计划签入程序免费(`priced` 与 `free`) (中文(简体) ). 计划用完后 转弯 `fallback` (单位:千美元)`agentTurn` 设定应用程序的第一个 Claude 在同一付款人的 Anthropic 密钥上 ) 的答案,而不是在限制错误中结束,它使用自己的部分. 这里没有钥匙或标志:应用程序每转一转就通过.

附带一个应用程序 `Assistant` 从它得到整个计划: `assistant.agentTurn(caller, { message, tier?, context?, refs?, time_zone? })` 返回时 `{ plan, settle }` 人物的等级和型号 在谁付费,工具组 在他们的访问,工具包的规则,轴承和页面 在消息之前, `escalate` 和克劳德的顾问. `settle` 将支出加到付款人的月份 并报告转弯 `onStep`。它抛出 `AssistantError` 当没有人能支付.

草稿和写作是聊天中自己存储的卡片(`lumen_cards` 在代理的 SQLite 中。 写一个人的访问只写出草稿,就可以开出一张卡片,而不会改变任何东西. `saveCard(id)` 通过应用程序运行 `applyDraft`,以及 `dismissCard(id)` 放下枪 一次写作保存 `undoCard(id)` 通过应用程序 `undoWrite`。 。 。 . `cards()` 列出牌。 接下来的答案是,每张卡是如何结束的,什么被取消。 与一个 `Assistant`, (中文(简体) ), `applyDraft` 实值 `assistant.runDraft(caller, card)` 财务报告和审定财务报表 `undoWrite` 实值 `assistant.undoChange(caller, card)`。思考压缩聊天的过去 `COMPACT_AT` (150k令牌) 在最后一个答案的模型和密钥上,这种花被添加到下一个答案中.

**连接器.** 一个人在聊天时添加一个 MCP 服务器 `addConnector(name, url)`。地址必须是https。 服务器通过 Think 的 MCP 客户端使用自己的 OAuth 签名, 答案包含 `authUrl` 当它问. `connectors()` 列出他们和 `removeConnector(id)` 掉一个 认为永远不要 合并自己的工具(`includeMcpTools` (这是虚假的)。 转一圈打开那些 `plan.connectors` 列表, 应用程序在访问时按组给出每个列表 `mcp_<id>`。“读取”保留仅读取服务器标记的工具。 阅读 + 草稿 制作休息卡 `saveCard` 在服务器上运行。 读取 + 写入 一次运行它们, 没有撤消 。 一个连接器的文本是不信任的数据.

**懒活的工具.** 过去 `LAZY_AT` (30) 工具,转而发送模型的核心工具和 `tool_search`,在指令中每组有一个目录行。 默认核心工具是应用程序的发现,关闭的手和顾问. `plan.lazy` 套装 `{ at, core }`。一个搜索匹配工具名称和描述中的单词,然后从下一步开始打开最多8个工具.

**图像.** `AskInput.images` (基数64 PNG、JPEG、WebP或GIF;最多 `ASSISTANT_IMAGES_MAX` (四)和 `ASSISTANT_IMAGE_CHARS` 一起)作为文件部分(`imageParts`),所以模型看到它们,聊天会再次显示它们. `LumenAssistant images` 让人物粘贴 (Cmd+V) 或将图像放入框上; 作曲家在长边上分别缩放到1568 px. 一个应用 `POST /chat` 通过 `images` 编号 `AskInput`。 。 。 .

**那个面板.** `LumenAssistant` 读取 想着聊天,没有变化. `ask(input, sink)` 运行一个答案并发送面板本身的事件( q)`AssistantEvent`:聊天、文字、每个工具行、卡片、交接部分、建议、使用)至 `sink`应用程序 `POST /chat` 返回时 `askResponse((sink) => chat.ask(input, sink), { signal, stop: () => chat.stop() })`,相同的服务器发送事件 `assistantRoutes` 发送. `view()` 作为面板项目提供存储聊天,以及 `usage()` 到现在为止 聊天还是有用的 一张卡的ID是它的工具呼叫, 所以面板的保存, 解散和撤消去 `saveCard`, (中文(简体) ), `dismissCard` 财务报告和审定财务报表 `undoCard`. 该应用保留了聊天列表,每个聊天都是自己的代理,例如个人商店的一面. `chunkEvents` 财务报告和审定财务报表 `itemsOf` 是绘图, 对于一个应用 流出一些其他方式.

**阶行.** 只有一个答案最多 `plan.maxSteps` 模式调用`MAX_STEPS`最后一个没有工具 `LAST_STEP_NOTE`,所以一个答案总是用词来结束:它找到了什么,当任务不合适时剩下的是什么.

**引导和排队.** 当一个答案运行时,面板的框会保持打开: Enter 将消息引导到答案中( E)`steer(message)` 代理; 应用程序路径 `POST /chats/:id/steer` `{ message }` 对它和答案 `{ steered }`),Alt+Enter为它排队。 一个方向盘在答案的下一步, 在它的工具之后,与 `STEER_NOTE` 用于模型; 面板显示它在那里标记了方向(活动) `steered`),以及 `view()` 保持原样`SteerNote`,在信息下,答案是). 方向盘在读出前结束 `unsteered` 并排在队列中第一. `plan.steer: false` 关闭它作为模型;没有路径的应用程序(404)只显示队列. 被排队的消息在答案结束前分别作为自己的消息去发;每个消息现在都有指向,编辑和去除.

**重试.** 以出错结束的转弯显示在Copy旁边的重试图标(QQ),总是可见,而没有答案运行,有人可以支付(`status.wait` 未设置; 隐藏在其它处, 永不禁用). 它发出转弯的话, `@` 组件, `#` 等级和图像再次作为新消息( e)`chat.retry(at, user, extra)` 内 `useAssistantChat`),在气泡上方标记;旧错误变为灰色(`retried` 并停止提供重试。 服务器上没有任何变化:重审后的消息是普通的消息.

```ts
class Chat extends LumenAgent<Env> {
  #settle?: (end: AgentTurnEnd) => Promise<void>;
  async plan(turn: TurnContext) {
    // this.input: what the person sent (message, page, refs, tier, time zone).
    // chat: this chat's id, so its use is one line of the person's usage history.
    const { plan, settle } = await assistant.agentTurn(caller, { ...(this.input ?? { message: '' }), chat: this.name });
    this.#settle = settle;
    return plan;
  }
  settle(end: AgentTurnEnd) { return this.#settle?.(end) ?? Promise.resolve(); }
  protected applyDraft(card: AgentCard) { return assistant.runDraft(caller, card); }
  protected undoWrite(card: AgentCard) { return assistant.undoChange(caller, card); }
}
```

## 工作空间: 食谱上的标签, 按要求再次运行

`@columenlabs/lumen-ai/workspaces` 是工具箱的服务器 `WorkspacesSection` 财务报告和审定财务报表 `WorkspacePage` 电话 工作空间是个人的标签页; 每个标签是一个表格, 超过一个 **边框**: 第一组 **食谱** 拉出,食谱本身 和人的手编辑。 食谱是对产品读取工具之一的调用(`{kind: 'call', fn: 'jobs.list', args}`),所以再次运行它不需要模型. 没有在计时器上运行:在标签上运行它的食谱,在页眉中,每个标签一个接一个地运行,每个标签在15秒之内(15秒)`RUN_MS`);失败的运行保留了最后一行并说原因.

```ts
import { createWorkspaces, doSql, workspaceMigrations, workspaceRoutes } from '@columenlabs/lumen-ai/workspaces';

// In the store that holds the person's data (a Durable Object's SQLite, or D1 with d1Sql):
for (const q of workspaceMigrations({ spaces: 'app_ws_spaces', frames: 'app_ws_frames' })) sql.exec(q);
const store = createWorkspaces({
  db: doSql(sql),
  tables: { spaces: 'app_ws_spaces', frames: 'app_ws_frames' },
  run: (recipe, { owner, signal }) => callReadTool(owner, recipe, signal), // the product's own tools, as the person
});

// In the Worker, at the assistant's api:
const routes = workspaceRoutes({ base: '/api/assistant', owner: callerOf, store: () => store });
```

预算:一帧为一行(最多为一行1.5MB,一行一万一行,五十列),所以一跑会写一行;每读一行有一行LIMIT(30个工作空间,12个分页,100个分页). 列从它们的值(数字,日期,文本)中打出;一个单词列表,或从一个小集中取出短文本,成为了标记列(chips). 装备箱 `WorkspacesProvider` 带 `recipes` 从标签栏中的食谱中提供 + 新的标签.

### Web 数据并按下数据集( 没有服务器代码运行)

还有三种方式

-   **获取食谱** (单位:千美元)`{kind: 'fetch', requests: [{url, method?, key?}], each?: {values}, rows?, pick?}`:声明网读出产品运行在其服务器上. `{field}` 从每个值的 URL 填充中的孔 `each` (文字填写) `{value}`(三); `fetchCalls` 扩展( 最多) `FETCH_CALLS`, 50 a run))和 (英语: `fetchedRows` 将答案转换成行 `each` 值的字段,然后是 `pick`'被点出的道路 (`current.temperature_2m`) (中文(简体) ). 一个数据密钥被命名( A)`key`),从未发送:产品添加其服务器侧.
-   **浏览器脚本** (单位:千美元)`{kind: 'script', runtime: 'browser', code, requests?}`:在人物页面上运行的JavaScript. 装备箱 `runBrowserFrame` 负载 `<base>/sandbox` (这个包裹) `SANDBOX_HTML`,服务于 `SANDBOX_CSP`数字 : `connect-src 'none'`在一个框中 `sandbox="allow-scripts"`,在网络工作员中运行代码(停止于 `BROWSER_RUN_MS`, 30 s),并保存其返回的内容 `PUT /frames/:id/rows` (一作一出,取出相框盖. 密码是 `async (fetched, hub) => rows`数字 : `fetched` 拥有答案 `requests`, (中文(简体) ), `hub.fetch(url, {key})` 通过产品的代用读取(`fetch` 内 `workspaceRoutes`, (中文(简体) ), `POST <base>/fetch`) (中文(简体) ). 服务器从未运行过 : `refresh` 拒绝(409美元) `refreshAll` 将此类标签列表为 `browser`。 。 。 .
-   **已按下数据集** (单位:千美元)`store.pushFrame(owner, {name, rows, mode, by, key?})`: 行外代理 wronged (一个 CSV 解析 : `parseCsv`最多 `CSV_BYTES` 一个电话,其余的作为 `append` 部件; 与 `key`,后面的一行用键替换。 来源 `harness`没有食谱; `by` 指定代理和标签的状态栏 读作"4分钟前被克洛德代码压住". `frameTab(owner, workspace, {name, frame})` 在标签中显示一个( 不运行) ; `removeFrame` 删除带有标签的标签.

`workspaceRoutes` 让我们 `call`, (中文(简体) ), `fetch` 浏览器 `script` 菜谱通过产品 `allow`; 服务器 `sql` 财务报告和审定财务报表 `script` 拒绝.

## 常见问题

### @columenlabs/lumen-ai 是什么？

卢门的助手和代理部件:一个聊天助手的服务器\(Claude levels,工具通过MCP,网络,手接,花盖\),服务于一个来自Worker的MCP服务器,只读工具集和调用分解工具\.

### 如何安装 @columenlabs/lumen-ai？

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

### @columenlabs/lumen-ai 支持 TypeScript 吗？

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

### @columenlabs/lumen-ai 支持 ESM 还是 CommonJS？

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

### @columenlabs/lumen-ai 可以商用吗？

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

### @columenlabs/lumen-ai 的下载量有多少？

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

### @columenlabs/lumen-ai 还在维护吗？

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

