iii codegen 的 Worker 与 CLI 双入口设计:单一 Rust 二进制如何驱动类型代码生成流水线 📅 发布时间:2026/9/15 22:20:43 👁 浏览次数: iii codegen 的 Worker 与 CLI 双入口设计单一 Rust 二进制如何驱动类型代码生成流水线【免费下载链接】iiiEffortlessly compose, extend, and observe every service in real-time for the first time ever.项目地址: https://gitcode.com/GitHub_Trending/mo/iii本指南围绕iii项目中 codegen 工作者的打包与对外接口展开它把「一个 Rust 二进制、两扇门」的架构落地为clap命令行与codegen::*注册函数二者共享同一条select → discover → map → emit → write生成流水线。读完你将掌握 codegen 的全部 CLI 参数、三个可调用函数的请求/响应协议、iii.worker.yaml部署清单、依赖选型逻辑与三层测试策略并能理解其 v1 明确划定的边界。一个二进制两个入口codegen 的设计核心是一句话一个 Rust 二进制两个前端入口共享同一条核心流水线详见 技术规格 README。两条入口分别是clapCLI供本地开发与 CI 使用典型调用是codegen generate --config codegen.ymlcodegen::*注册函数供其他 worker 与 Agent 通过引擎调用典型调用是codegen::generate/codegen::preview/codegen::languages。两条入口行为完全一致都以**瞬时 workertransient worker**身份连接引擎跑一遍流水线然后以完全相同的报告格式返回结果。CLI 模式下连接完成后即断开worker 模式下连接保持打开每次codegen::generate被调用时按需重跑流水线。选择 Rust 作为实现语言并非偶然codegen 必须在任意语言的项目内TypeScript、Python、甚至 Go 仓库以单一自包含二进制运行不需要为目标项目安装任何语言运行时——这正是规格中引用的deploy: binary模型。这一点与它产出什么语言无关发射器emitter永远只输出 TS/JS/Rust/Python 代码。文件布局镜像 binary-worker SOPworkers/codegen/的目录结构刻意镜像了 binary-worker 标准流程与coder工作者的既有约定workers/codegen/ Cargo.toml # [[bin]] name codegen iii.worker.yaml # deploy: binary, multi-target src/ main.rs # clap CLI; dispatches subcommands lib.rs # the pipeline, re-used by CLI and worker config.rs # codegen.yml parse validate (serde_yaml) catalog.rs # discovery: engine::* calls → in-memory catalog select.rs # glob selection (globset) schema/ # JSON Schema → IR (intermediate representation) mod.rs # parse, $defs collection, $ref resolution emit/ mod.rs # shared skeleton naming typescript.rs javascript.rs rust.rs python.rs worker.rs # register codegen::generate / ::preview / ::languages manifest.rs # build_manifest() for --manifest tests/ golden/ # fixture catalogs expected outputs (see Testing)结构上值得注意的分工main.rs只负责 CLI 分发真正的流水线放在lib.rs中以便 CLI 与 worker 模式复用config.rs用serde_yaml解析并校验codegen.ymlcatalog.rs负责通过engine::*调用构建内存目录schema/与emit/分别处理 JSON Schema 到中间表示IR的转换以及按语言发射最终源码。规格同时说明该布局遵循仓库内的 binary-worker SOP见 docs 下的标准流程说明 所对应的仓库约定并与coder工作者的结构保持一致。CLI 表面generate / preview / languages / --manifestclapderive 构建命令行形态沿用coder的--url/--manifest约定codegen generate --config path [--url ws] [--only path]... [--check] [--watch] codegen preview --config path [--url ws] --output path # prints code to stdout, writes nothing codegen languages # prints supported languages status codegen --manifest # prints the worker manifest JSON, exits参数表Flag默认值含义--config./codegen.yml配置文件路径--url$III_URL其次ws://127.0.0.1:49134引擎地址--only全部限制只处理特定输出路径可重复传入--checkoff只计算输出、不写盘若有任何文件会变化则退出码为 1参见 emitters 的确定性说明--watchoff监听codegen.yml变化以及引擎的engine::functions::available目录变更触发器变化时重跑注意--url的取值优先级显式--url参数优先于$III_URL环境变量最后兜底ws://127.0.0.1:49134。引擎地址永远不写进codegen.yml这一约定与仓库中其他所有 worker 一致规格引用workers/coder/src/main.rs:14-49作为先例。退出码契约0成功全部写入或保持不变1--check模式下发现至少一个文件会变化2配置错误或连接错误。面向人的输出与 worker 函数返回的 per-output 报告相同只是渲染成表格。Worker 函数表面三个类型化函数函数 id 遵循 kebab-case 的worker::verb规范codegen::generate、codegen::preview、codegen::languages绝不用 snake_case且只注册类型化处理器——每个函数都使用派生JsonSchema的具体输入/输出结构体绝不使用裸serde_json::Value处理器。codegen::generate运行流水线并写盘路径相对于cwd若给定base_dir则相对它。// request { config_path: string?, // path to codegen.yml — OR — config: { /* inline GenerationConfig, same schema as the file */ }, base_dir: string?, // resolve output paths against this (default: cwd) only: [string], // optional subset of output paths check: false // dry-run; write nothing, report would-change } // exactly one of config_path / config is required // response { outputs: [ { path: src/types/codegen/harness.ts, language: typescript, functions: 7, triggers: 2, types: 11, bytes: 4210, status: written } // written | unchanged | would-change ], warnings: [functions glob harness::* matched nothing — is harness running?] }内联config会经过与配置文件完全相同的 JSON Schema 校验见 configuration 的配置 Schema 一节并且该 Schema 被发布为这个函数的request_format——也就是说无论走文件路径还是内联对象校验规则是一致的。codegen::preview请求体与codegen::generate完全相同但绝不写盘——返回生成的源码文本供想在提交前查看或 diff 输出的 Agent 与工具使用。// response { outputs: [ { path: …, language: …, code: generated source } ], warnings: [ … ] }codegen::languages能力探测当前构建能发射哪些语言。// request: {} // response { languages: [ { id: typescript, status: stable, modes: [types,functions,triggers] }, { id: javascript, status: stable, modes: [types,functions,triggers] }, { id: rust, status: stable, modes: [types,functions,triggers] }, { id: python, status: stable, modes: [types,functions,triggers] }, { id: go, status: planned, modes: [] } ] }注意go的状态是planned且modes为空——这与下文「边界与非目标」中的E_LANG_UNSUPPORTED拒绝逻辑互相印证。部署清单iii.worker.yaml与coder的清单同构deploy: binary、多目标平台iii: v1 name: codegen language: rust deploy: binary manifest: Cargo.toml bin: codegen description: Generates typed client code (types, function wrappers, trigger handlers) in TS/JS/Rust/Python from the engines live function catalog. targets: - x86_64-apple-darwin - aarch64-apple-darwin - x86_64-unknown-linux-gnu - x86_64-unknown-linux-musl - aarch64-unknown-linux-gnu runtime: kind: rust scripts: install: cargo build start: cargo run要点deploy: binary声明二进制分发模型manifest: Cargo.toml让引擎从 Cargo 清单推导元信息bin: codegen指定可执行文件名targets覆盖 macOS 与 Linux 的主流架构其中同时包含 glibcgnu与静态链接musl两个 Linux 目标以适配不同宿主环境。依赖选型每个 crate 的职责Crate用途iii-sdkregister_worker、IIIClient、TriggerRequest、register_functionworker 模式clapderive, envCLI 与--url/$III_URL绑定serde、serde_json目录/Schema 的Value表示与 worker 函数 I/Oserde_yaml解析codegen.ymlschemars为 codegen自身的codegen::*函数 I/O 派生 JSON Schemaglobset选择 globconfiguration 的选择语义convert_case命名推导中的标识符大小写转换tokio异步运行时SDK 是异步的notify--watch可选feature 门控值得强调的实现选择发射器是手写的字符串构建器不是模板引擎。因为输出必须是结构化、字节确定性、预格式化pre-formatted的直接控制字符串拼接比引入模板 DSL 更可靠。测试策略三层防护codegen 是典型的「bug 是静默的」工具——类型错误、optionality 差一错误都要等到下游消费者编译失败才暴露因此测试分两层加一个现场集成验证Golden 测试tests/golden/一组 fixture 目录——这些 JSON 文件是从真实 workerharness、email捕获的、逐字不变的FunctionDetail/TriggerTypeDetail响应外加手工构造的边界用例$defs递归、oneOf、nullable、无类型Value、路径风格 id。每个 fixture 都配有一份每种语言的期望生成文件。mapper/emitter 在离线状态下直接对 fixtures 运行无需引擎输出做字节级比对。新增行为 新增 fixture这也是确定性/幂等性的回归网。下游编译检查CIgolden fixtures 生成的 TS/Rust/Python 分别喂给tsc --noEmit、cargo check、pyright配合pydantic。这证明发射出的代码不只是字符串稳定而是在各自目标工具链中真正有效且类型正确——这才是最关键的属性。现场集成测试启动引擎挂载todo-worker对其实跑codegen generate断言生成的 wrapper 调用了正确的function_id——覆盖 golden 测试跳过的 discovery/连接路径。从源码看目录与 Schema 的来路规格文档中反复出现的「活目录live catalog」与「JSON Schema 即真相」都有源码佐证引擎内置发现函数engine::functions::list在 engine/src/workers/engine_fn/mod.rs#L1571 附近实现默认隐藏engine::内部函数与标记metadata.internal true的处理器除非显式传include_internal: true——这正是 codegen 生成产物中不泄漏引擎内部 handler 的原因。FunctionSummary/FunctionDetail结构体定义在 同一文件的 L218 / L243 附近FunctionDetail携带request_schema/response_schema两个 JSON Schema 字段OptionValue为 None 表示该侧无类型。Rust worker 的#[function]宏在注册时通过schemars::schema_for!(Input)/schema_for!(Output)生成请求/响应 Schema见 engine/function-macros/src/lib.rs#L350-L376引擎将其存入Function的request_format/response_format见 engine/src/function.rs#L32-L40。也就是说codegen 不发明任何 Schema它只是把引擎已经持有的 JSON Schema 投射成语言类型与 SDK 调用点。Node SDK 侧triggerTInput, TOutput(request: TriggerRequestTInput): PromiseTOutput与registerFunction/registerTrigger分别在 sdk/packages/node/iii/src/types.ts#L180、#L140、#L106Rust SDK 侧IIIClient与pub async fn trigger(...)在 sdk/packages/rust/iii/src/iii.rs#L953 与 #L1534。生成代码的每个 wrapper 最终都塌缩为这唯一的调用原语trigger({ function_id, payload })。边界与非目标v1规格明确列出 v1 不做的事理解这些边界有助于正确使用v1 无 Go 发射器。language: go被保留但拒绝报E_LANG_UNSUPPORTEDcodegen::languages将其报告为planned。仅客户端表面。codegen 只生成类型化的调用方、类型与类型化的触发器订阅辅助函数它不脚手架化 worker 实现、函数体或iii.worker.yaml——Schema 与行为归属注册它们的 worker。不是 Schema 编写工具。codegen 从不发明或编辑 Schema它是engine::*::info输出的纯投射pure projection。v1 只认活目录。生成要求目标 worker 已连接见 discovery 的「目录是活的」。从签入的目录快照生成让 CI 不必启动每个 worker是 v2 的主要计划项codegen generate --from catalog.json。v1 无自定义模板/插件。graphql-codegen的插件模型是可能的未来方向v1 只带四个内置发射器。读多写少、受限写入。唯一的文件系统变更就是写声明过的输出路径codegen 从不删除文件也从不写到解析出的输出集合之外。这套「CLI worker 双入口、单一共享流水线」的打包模式让 codegen 既能作为开发者的本地/CI 命令使用又能作为引擎内的可编程函数被其他 worker 与 Agent 编排调用而两者的正确性由同一份 golden 下游编译 现场集成三层测试共同背书。【免费下载链接】iiiEffortlessly compose, extend, and observe every service in real-time for the first time ever.项目地址: https://gitcode.com/GitHub_Trending/mo/iii创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考