@columenlabs/lumen-ai

中文文档
0.1.219发布于 2026/11/09MITTypeScriptES Module近 30 天下载 4万

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

中文使用文档
文档目录11 节
  1. 安装
  2. 服务 MCP 服务器
  3. 出口
  4. 版本数
  5. 一个聊天助手
  6. 命令 :, @ 财务报告和审定财务报表 #
  7. 轴心
  8. 查找:一个问题,一个查询
  9. 云花盘思维的代理
  10. 工作空间: 食谱上的标签, 按要求再次运行
  11. Web 数据并按下数据集( 没有服务器代码运行)

校对:soup

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

安装

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

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

服务 MCP 服务器

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

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。 。 。 .

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芯片,其结果会回溯到下一条消息(Uoutcomes) (中文(简体) ). 没有什么能通过移动来挽救.
  • 背景工作情况 用于个人运行的应用程序(分数、摘要)是 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} 替换为名称后(或函数返回的)的词. 应用指令取自内置名.

    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); 页面在显示时添加自己的页面 :

    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毫秒,当它晚到或者抛出其行被忽略.

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:它的行是最接近的几行,而不是每一行相合的行,因此模型从不引用它们作为数个相配.
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)或预算背景步骤(持久目标)中,从未提出要求。 在索引存在之前,单词会回落到一个纯文本匹配,结果也这么说,所以代码可以在它的迁移之前运出.

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

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 并停止提供重试。 服务器上没有任何变化:重审后的消息是普通的消息.

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);失败的运行保留了最后一行并说原因.

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 共发布 183 个版本,首次发布于 2026/10/25;过去 12 个月发布了 183 个版本。

版本发布日期距今
0.1.219latest2026/11/091 天前
0.1.2182026/11/091 天前
0.1.2172026/11/091 天前
0.1.2162026/11/091 天前
0.1.2152026/11/091 天前
0.1.2142026/11/091 天前

关于 @columenlabs/lumen-ai 的常见问题

@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 和提交记录判断。