iterate

中文文档
0.4.1-main.20261103T213652Z-98a2f20发布于 2026/11/04Apache-2.0TypeScriptES Module

用于迭代的SDK和CLI

中文使用文档
文档目录10 节
  1. SDK/平台行
  2. 每个符号一条路径
  3. 从加载的代码到达上下文
  4. 谁写了一个事件
  5. 测试处理器
  6. 多步跑
  7. 节点连接
  8. 事件类型
  9. 名称空间
  10. 事件名称

迭代

迭代的SDKcore/os):上下文api、流处理器、响应式客户端、React 绑定和OAuth应用会话 iterate/*. 包在此导出源代码 工作空间,并在打包时使用声明编译JavaScript。它的 iterate bin是命令行 (src / cli / README.md).

SDK/平台行

SDK保存了用户代码运行或说话的内容,平台是它的第一个用户:核心/操作系统构建 自己的实体 iterate/sdk,第一方应用程序的代码只使用 iterate/*. 每一个 子路径的 package.json的 exports 是一个公共模块;没有其他东西是可进口的。

  • 当用户代码运行或调用它时,模块就属于这里:一个加载的worker、一个facet、一个 处理器、浏览器或Node客户端,或者它们和平台之间的有线契约。它 当只有平台的Worker运行时,它属于core/os;当有更多的Worker运行时,它属于packages/shared 一个应用程序需要它,而用户代码永远不需要。
  • 在core/os之外,没有任何包和应用程序导入core/os。 import-js/no-restricted-paths 在 .oxlintrc.json 解析下的每个导入 packages/** 和 internal-packages/** 到一个文件,所以键入 进口,再出口,动态 import() 以及之后添加的应用程序 lint/oxlintrc-platform-line.test.ts 别针。该平台的测试在 test/,这 该规则没有涵盖:它们可以导入core/os,而core/os只保留简单的单元测试。
  • 没有私有的核心包背后一个薄 iterate: core/os将会导入模块的用户代码 不能,而且SDK的类型无论如何都必须被捆绑或发布。

决定的原因,以及如何工作,代理SDK,凸, Supabase、tRPC、Hono和Wrangler划一条线:决策记录 docs/2026-09-24-sdk-platform-line.md 在迭代/迭代# 3018。

每个符号一条路径

平台为项目加载的代码(重写规则背后的配置入口点、面、工作器) 从一个路径中导入每个符号,然后加载器将其链接到这个部署自己的构建中:

路径它包含什么
iterate/sdk工人主持: IterateConfigEntrypoint, FacetDurableObject, StreamProcessorDurableObject,它们的类型,以及capnweb的构造函数
iterate/stream/processor处理机表面: StreamProcessor, defineProcessorContract, LiveState,事件和合同类型。它也在Node中运行
iterate/stream/contractdefineProcessorContract 单是合同类型 iterate/stream/processor 再出口。浏览器加载的代码会导入引擎需要的代码 node:async_hooks
iterate/email这个 email 方面的合同, email/received 和 email/sent 还有它们折叠成的线
iterate/agents代理应用程序的两个类,其中一个是配置 agents.ts 再出口; iterate/agents/install 安装它(其自述)
zod每个隔离一个副本,所以SDK检查的是模式用户代码生成的那个
import { StreamProcessorDurableObject } from "iterate/sdk";
import { StreamProcessor, defineProcessorContract } from "iterate/stream/processor";
import { z } from "zod";

const Contract = defineProcessorContract({
  slug: "hoarder",
  version: "1.0.0",
  description: "keeps every blob it reduces",
  stateSchema: z.object({ blobs: z.array(z.string()).default([]) }),
  consumes: ["blob"],
  emits: [],
});
class Hoarder extends StreamProcessor {
  contract = Contract;
  reduce({ event, state }) {
    return { blobs: [...state.blobs, event.payload.blob] };
  }
}
export class HoarderDurableObject extends StreamProcessorDurableObject {
  processor = new Hoarder();
}

从加载的代码到达上下文

加载的代码到达它的上下文 using itx = this.getItx():当块结束时,作用域; 通过它发出的每个调用和它等待的每个句柄都被释放。每一个加载 WorkerEntrypoint 有 getItx, SDK的主机(IterateConfigEntrypoint, FacetDurableObject, StreamProcessorDurableObject).

import { IterateConfigEntrypoint } from "iterate/sdk";

export default class extends IterateConfigEntrypoint {
  async fetch() {
    using itx = this.getItx();
    const { projectSlug } = await itx.whoami();
    return new Response(`Homepage of ${projectSlug}`);
  }
}

将每个作用域与 using 在保存调用的最小块中,等待内部的每个调用 它,和手数据,而不是句柄,从它:一个保留作用域,步骤或句柄保留上下文,和任何 Facet持有它,在项目闲置后驻留。需要到达的对象取An 访问器(() => this.getItx()),而不是作用域;调用之后的工作在a下运行 处理器的 runInBackground 索赔。棉绒拒绝生毛 ITX.get() 和一个 getItx() 否 using 绑定在此存储库中(iterate/no-raw-itx-get).

配置工作者的 getItx() 根的作用域是谁调用它:每个上下文链接到 根继承根的规则,所以脚本在 /child 调用 itx.voice.setupVoiceAgent(…) 作为根运行worker。在任何方法中 fetch, this.callerPath() 命名上下文 电话来自(/child),因为平台标记了它,所以worker为调用者创建了什么 不能比呼叫者拥有更多的东西;

async setupVoiceAgent({ streamPath }) {
  using itx = this.getItx();
  await itx.agents.at(this.callerPath()).create(streamPath); // linked to the caller, not to `/`
}

谁写了一个事件

项目中的任何人都可以将任何事件附加到任何上下文,并且每个事件都说明它来自何处。 月台邮票 source.origin,代码或会话编写它的上下文 source.principal (成员)及 source.platform. 作家自己的价值观被抛弃了。一个 一个作家所拥有的领域 source.processor,即处理器为其编写的引擎标签。

// A script in /agents/a:
await itx.cd("/agents/b").append({
  type: "events.iterate.com/agent/context-added",
  payload: { role: "user", content: "hello" },
});
// Stamped { origin: "/agents/a" }. Agent b's model reads "[from /agents/a] hello",
// and the same from `itx.agents.get("/agents/b").message("hello")`.

单词 / (一个成员的会话,破折号)作为一个人的,没有发送者。 origin 是 运行代码的上下文,而不是谁要求它运行的上下文(core/os) caller.ts stampCaller 说为什么会这样 这是建议)。批写道: append(...events) 是一个提交,不管它包含多少事件。

失控反应自行停止:代码对其他代码的输出进行一轮又一轮的反应 两个代理相互应答,一个处理程序附加它所处理的内容,在几个之后停止 以一个错误命名开始反应链,上下文记录一个 itx/loop-limit 的事实。阅读仍然有效。

例外是监狱,一个带有裸的上下文 itx ⇒ null 行加上它旁边的授予权。一个光秃秃的 监狱是双向封闭的:它的代码没有附加到任何地方,也没有代码附加到它里面。赋予其 itx.append 每个上下文都可以附加到它里面;它自己的代码仍然不能解除null。一个 Jail限制的是运行在其中的代码,而不是它通过授权创建的上下文。

测试处理器

iterate/stream/test-support (Node)是SDK自己的引擎测试使用的线束:

import { reduceProcessor } from "iterate/stream/test-support";

// test/helpers/presence/processor.test.ts: durable ticks are reduced, ephemeral pokes are not
const state = reduceProcessor(new PresenceProcessor(), [{ type: "tick" }, { type: "poke" }]);
// state.ticks === 1

memoryStream, memoryStorage 和 settle 全程驾驶 ProcessorEngine 针对一个 内存日志(src/stream/processor.test.ts 显示)。

多步跑

其工作执行步骤(运行部署、创建项目)的处理器仍然是一个 契约,一个国家,一个 reduce 和一个 processEvent. 核心/ os src/deployment/ 工作顺利吗? 的例子。

  1. 这个要求是事实。 动词追加 <x>-requested 然后回答它的偏移量,也就是 运行的id。fact保存运行所需的每个输入,或者命名facet为其保存的内容 它自己的存储(部署的配置):下一个化身读取日志和存储, 从来没有电话。
  2. 每一步都有一个事实,由请求的偏移量和尝试次数来指定 (<slug>/<fact>:<requestOffset>:<attempt>),所以重复的追加操作只着陆一次。键控有效载荷 不保存值为的键 undefined:流将重复的追加对象与存储的追加对象进行比较 JSON,它没有这样的键。
  3. 州政府说了跑路的位置: 请求、尝试、最后一步和偏移量 它的事实。 snapshot() 显示它,页面可以实时观看它。
  4. processEvent 来自国家的预付款。 在 delivery.caughtUp没有工作的跑步 这个化身的驱动器只有一个司机 runInBackground. 司机的索赔使 Facet,如果Facet死亡。中途发现的跑步失去了它的化身,或者它的司机自己的事实 没有着陆,所以司机立即开始下一次尝试:如果出了什么问题,工作是 再次运行。
  5. 重复每一步都是安全的。 一次尝试从第一步重新开始,每一步都有效果 接受自己早期的成功。事实记录进步;他们不会跳过那些与死亡相伴的工作 化身(/tmp(开放式计划)。
  6. 尝试是以事实计算的,并且是有限制的。 一个 attempt-started 事实摆在每个人面前 尝试。无论结果如何,结束的尝试立即解决了运行:没有重试等待 在处理器内部,调用者再次运行它。只有一次尝试在解决问题之前就结束了 Run(游戏邦注:它的化身已经死亡)将在引擎的5次下再次运行 死亡,这样一场尝试都失败了的赛跑还能复活下来。
  7. 最后一个事实是, <x>-settled { requestOffset, status, error? },按要求输入。它的 status 是四个中的一个: succeeded; refused,预期结果; failed,任何其他错误 (再运行一次); unavailable,平台故障(再次运行)。未打开运行的请求被解决 refused 当它被处理时,在 blockProcessorWhile:没有状态会记住请求,所以没有 过一会儿就可以解决了。来电者接以下语句 waitForEvent({ type, payload: { requestOffset }, afterOffset })。
  8. 测试它作为表: 事件通过 reduceProcessor,通过 processEvent 带着假的 对假时钟的影响,和一个重减行。

节点连接

iterate/node 为Iterate脚本和live公开一个连接所有者 提供者。它使用与CLI相同的协议和清理:

import { connectIterate } from "iterate/node";

using connection = await connectIterate({
  baseUrl: "https://os.iterate.com",
  auth: { type: "bearer", token: process.env.ITERATE_BEARER_TOKEN },
});
using project = await connection.session.projects.get("my-project");
console.log(await project.run("async (itx) => await itx.whoami()"));

事件类型

平台事件类型为 events.iterate.com/<namespace>/<event>:一个命名空间段和一个 事件段,都是小写的kebab-case,没有第三段。

下面的每种类型 events.iterate.com/ 遵循这些规则,包括测试类型。没有的类型 该前缀属于附加它的人,并且对平台不透明:测试使用类似的类型 demo/ping 并且一个项目可以使用它自己的域(events.garple.com/sales/…).

名称空间

  • itx 保存上下文引擎自己的事件:核心契约的一切 (core/os/src/stream/core-processor.ts)减少,验证或拒绝,加上记录 流、上下文持久对象和SDK处理器主机自己编写。其中模式 reduce live决定它,而不是哪个上下文持有事件:fetch路由和顶点 入口目标是核心状态,所以它们是 itx 即使只读取项目根目录的副本。 域处理器可以使用一个 itx 事件(代理使用) itx/run-*、项目 处理器 itx/ingress-configured); 它在它的 processorDeps 而不是 定义事件本身。核心的检查点是 core:它是一个存储键,而不是类型 前缀。
  • 域命名空间 事件日志所属的上下文类型的单数名称 To,当有一个时,它是定义合同的段格: account, organization, project, repo, workspace, sandbox, deployment, secret, agent, voice-agent. 一个事实 交叉发布到另一个日志保留自己的命名空间: repo/created 在 / 仍然是回购事实。
  • 一个集成 例如,使用自己的名称作为名称空间 chrome, slack, google, github。
  • test 保存仅测试追加的类型。产品代码永远不匹配 test/* 类型。一个 测试契约可以保留自己的段(counter),但它的事件却悄无声息 test/. 测试必须 不要为不存在的类型借用生产名称空间。

事件名称

  • 事实是过去时: <object>-<verb-ed>,或裸露的 <verb-ed> 当对象是 命名空间本身的主题(itx/created 是上下文, agent/paused 是代理)。的对象 出现在前面并且是单数。
  • 把单词拼出来。 不允许使用缩略词(spk); 一个真正的词是(mic), an也是如此 API的首字母缩写是(llm, rpc, itx).
  • 提问和回答。 <x>-requested 请求,其偏移量标识请求。答案 取三种形状之一:
    • <x>-settled 是请求程序读取结果时的一个终端事实。它的名字 requestOffset 并携带结果:成功、失败或取消、状态或错误。 例子: itx/run-*, agent/llm-request-*, project/hostname-add-*, deployment/run-*。
    • <verb-ed> 或 <verb>-failed 当成功是其他日志等待的事实时使用,例如 证书: create-requested → created 或 create-failed, delete-requested → deleted, hostname-remove-requested → hostname-removed. 重试失败,而不是失败 报告没有 -failed 的事实。
    • 这个答案本身就是一个事实,它的答案就是提问者的答案:助手的答案 agent/context-added 带着 llmRequestOffset 的 llm-request-requested 它的答案。
  • 一种变化对应一组动词:
    • added / removed 对于集合中的成员: organization/member-added, organization/project-added主机名。
    • created / deleted 对于具有生命周期的实体:项目、仓库、工作区、沙盒、 部署,代理。
    • set / deleted 对于键值: secret/*。
    • set / cancelled 对于时间表: itx/schedule-*. 每次出现都是 fired 或 failed。
    • -configured 用于设置一行或清除一行的一个事实 null (itx/subscription-configured, itx/rewrite-rule-configured, itx/fetch-route-configured), 设置一个单例(itx/ingress-configured),或者合并部分配置 (agent/configured:省略的键保留其值)。
  • 平台自己做的事情 是关于物体的简单事实: itx/schedule-fired, itx/schedule-failed, itx/subscription-delivery-halted。
  • 短暂的事件。 记录发生的事情的短暂事件与其他事件一样被命名 事实: itx/rpc-stub-attached, itx/live-state-changed, chrome/navigated. 可能有三种 单数名词:直播流的一个序列片段是a <stream>-frame (voice-agent/mic-frame, agent/llm-response-frame),心跳(voice-agent/keepalive), 诊断记录(itx/alarm-trace). 持久事件从来不是名词。
  • 家庭和前缀。 代码通过前缀匹配某些家族: …/itx/run-, …/itx/subscription-, …/itx/schedule-, …/project/hostname-. 在命名新类型之前,请进行检查 它加入这些家庭不是偶然的。从来没有匹配 …/itx/ 作为一个整体:它不是 权限边界,它捕获实时状态delta、存根存在和子节点 公告。
  • 代码遵循类型。 从类型构建的常量、模式、测试fixture或等幂键 它的名字(itx/child-created:<path>). 更广泛的概念、模块和工人日志 事件名称保持他们的:流,计划追加, core, scheduled-append.completed。
  • 重命名。 重新命名必须符合这些规则之一,而不是口味。类之外存储类型 平台的持久对象(设备固件、发布的SDK、项目的配置repo); 仅在迁移该存储的更改中重命名它。
名称空间中定义的
itxcore/os/src/stream/core-processor.ts (及其叶事件目录), stream.ts, scheduled-appends.ts, subscription-delivery.ts, core/os/src/context/built-ins.ts, core/os/src/fetch-routes.ts, core/os/src/iterate-context-durable-object.ts, core/lib/src/stream/{run,processor}.ts
account, organization, project, repo, workspace, sandbox, deployment, secretcore/os/src/<name>/contract.ts (repo,工作区,沙盒和部署也使用 project/entity-lifecycle.ts)
agentcore/lib/src/agents/contract.ts
voice-agentpackages/voice/src/voice-agent.ts, packages/voice/src/events.ts
chromepackages/browser-extension/public/panel.js
emailcore/lib/src/email.ts
integrationcore/lib/src/integrations.ts (项目的包写入的注册表;它的文件夹是 core/os/src/integrations/registry.ts)
test只测试

note/added 只是Agents composer中的一个例子;没有合同定义 note。

版本与发布记录

iterate 共发布 72 个版本,首次发布于 2012/07/23;过去 12 个月发布了 68 个版本。

版本发布日期距今
0.4.1-main.20261103T213652Z-98a2f20latest2026/11/041 天前
0.4.1-main.20261103T133631Z-bb7505b2026/11/031 天前
0.4.1-main.20261103T135500Z-56c2d5d2026/11/031 天前
0.4.1-main.20261102T141235Z-57ab9592026/11/022 天前
0.4.1-main.20261102T141207Z-d7cc69f2026/11/022 天前
0.4.1-main.20261021T154646Z-f6d80ff2026/10/2214 天前

其他发布通道:canary → 0.4.1-canary.20261003T073032000Z-17b7b90c4bafa98b212095a2636442b6435f0960。

关于 iterate 的常见问题

iterate 是什么?

用于迭代的SDK和CLI

如何安装 iterate?

在项目目录运行 npm install iterate,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 iterate,可以用 npx iterate 直接运行。

iterate 支持 TypeScript 吗?

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

iterate 支持 ESM 还是 CommonJS?

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

iterate 需要什么版本的 Node.js?

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

iterate 可以商用吗?

iterate 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

iterate 还在维护吗?

最新版本 0.4.1-main.20261103T213652Z-98a2f20 发布于 2026/11/04(1 天前);至今共发布 72 个版本,其中过去 12 个月发布了 68 个;首次发布于 2012/07/23。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。