拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

IronClaw 通道适配器契约重构:Reply 与 Delivery 双轴输出模型的设计与源码落地

IronClaw 通道适配器契约重构:Reply 与 Delivery 双轴输出模型的设计与源码落地 人工智能AI 应用交互助手AI Agent【免费下载链接】ironclawIronClaw is an Agent OS focused on privacy, security and extensibility项目地址https://gitcode.com/gh_mirrors/iro/ironclaw点击查看免费下载导读本文基于 IronClaw 仓库中的设计文档 2026-08-11-channel-adapter-contract.md 展开剖析一次关键契约重构把旧ChannelAdapter上「回复」与「通知」混为一体的词汇拆分为Reply回复与Delivery投递两条正交轴并重塑了 manifest 声明、核心类型、分发器、适配器 trait 与 enrollment 归属。读完本文你将理解这一设计如何让「流式回复 浏览器推送」这类组合变得可表达、如何消灭「按意图分发导致通知丢失」的缺陷类别以及仓库源码ironclaw_extension_contracts、ironclaw_assistant、各通道 manifest中与之对应的真实实现细节。1. 背景统一通道模型之后契约成了最后的瓶颈此前发布的统一通道模型设计2026-08-10-unified-channel-model.md让所有通道共用一条入站核心、一个投递协调器delivery coordinator和一套通知设置面但它没有触碰这些路径真正调用的 trait。当时的ChannelAdapter携带十一个方法activate · cleanup · inbound · fetch_attachment · fetch_conversation_context deliver · deliver_notification · notification_setup_status enable_notifications · disable_notifications · list_targets设计文档在当时的分支上实测了三个通道的实现情况方法slacktelegramweb-appactivate/cleanup默认no-op已重写默认no-opinbound是是不支持host 侧 actor 权威deliver是是是渲染推送deliver_notification默认 →deliver默认 →deliver默认 →deliver通知设置 ×3不支持不支持已实现只有deliver被三个通道全部实现——这个 trait 本质上是各通道需求的并集而不是一份真正的契约。但设计文档明确指出表面积只是症状根本问题在于两个相互独立的概念被折叠进同一套词汇而 §1 的「双轴模型」是所有后续改动的出发点。2. 核心模型Reply 与 Delivery 是两条不同的轴设计文档给出的轴定义如下Reply回复Delivery投递本质回答本次 run 的输入在带外触达某人路由源路由source-routed——回到输入来源处目标解析target-resolved——host 配置或模型选择没有 run 时是否存在从不是web-app流式推送到已订阅客户端浏览器推送slack / telegram线程里的一条消息一条消息两者是正交关系而非二选一的替代关系。一次 run 可以同时做两件事答案流式进入你打开的标签页reply同时如果你没在看一条浏览器推送通知你结果已到达delivery。而在旧模型里「回复」和「通知」是同一决策下的竞争分支这种组合很难表达。2.1 为什么按轴切分而不是按意图切分旧代码按意图FinalReply、GatePrompt、BackgroundRunNotice等分发这在当时分支上已经制造了一个真实缺陷一个审批提示gate prompt当人类正坐在 Slack 线程里时是reply当凌晨 3 点一个 routine 被阻塞、现场无人时则是delivery。同样的意图、同样的内容不同的轴。以意图为键来决定流式与否静默丢掉了第二种情况——被阻塞 routine 的推送消失了。该缺陷由 blocked-fire journey 测试捕获修复方式是把键改为路由。这一思想已原样落进源码在 delivery_coordinator.rs 中OutboundRoute的文档注释明确写道这个类型之所以存在是因为按DeliveryIntent而非按轴分发已经上线过一个缺陷。……显式命名轴使这类 bug 变得不可表达内容永远不会隐含路由。源码中OutboundRoute::for_policy正是「一次决策」的实现RequestedOutbound一律是DeliveryRunNotification若解析到LiveSourceRoute人类在线则是Reply否则是Delivery。for_notice()则规定 notice 类发送恒为Reply——它们的目标本身就是发起会话。2.2 为什么叫 delivery而不是 reach / notification「Delivery」在这套代码里本来就意味着 target-resolveddelivery targets、delivery attempts、delivery coordinator、builtin.outbound_deliver都是既有词汇沿用零学习成本。「Notification」过于狭窄它排除模型主动选择发送到某通道的场景而新造「reach」只会给已有两个词的概念再加第三个词。这一命名同时合并了两个今天彼此分离的概念——通知与带外投递——因为它们本已共享机制BackgroundRunNotice与ModelDelivery都是 policy 类、都解析一个已验证目标、都持久化一次 attempt。它们只是同一台机器上的两个标签。2.3 投递内部唯一必须保持分离的东西谁选择了目标。用户配置host 解析了用户的通知通道。可信。模型请求builtin.outbound_deliver模型点名了一个目标。不可信——必须针对用户实际授权的内容做校验。统一传输与 attempt 记录但目标授权必须保留为独立阶段、带两个入口。折叠两者会让模型选择的目标继承用户配置目标的信任。3. Manifest三个小节描述通道能力新 manifest 以三个小节分别描述三条轴缺席即表示不支持[channel.ingress] # 输入如何到达今天已存在 verification { kind hmac_sha256, … } [channel.reply] # run 的答案如何返回 transport stream # | message [channel.delivery] # 如何在 run 之外触达用户 transport push # | message requires_enrollment true # 每个用户先完成设置才能投递整个 web-app 与 Slack 的差异被压缩为两行数据# web-app # slack / telegram [channel.reply] [channel.reply] transport stream transport message [channel.delivery] [channel.delivery] transport push transport message requires_enrollment true这套声明淘汰了inbound/outbound/notifications三个布尔量——它们只说明通道「能做某事」却不说明「怎么做」。在真实仓库里可以对照三个包的实际 manifestslack/manifest.toml[channel.reply] transport message与[channel.delivery] transport message文件注释解释了「message出现两次是传输机制的巧合不是同一个概念」[channel.ingress]声明了hmac_sha256签名校验X-Slack-Signature、max_age_seconds 300。telegram/manifest.toml与 Slack 同构。web-app/manifest.toml[channel.reply] transport stream注释明确stream 意味着 host 发布、该包完全不实现 reply 半体、[channel.delivery] transport push且requires_enrollment true、[channel.ingress] verification.kind authenticated_session浏览器请求永不进入 webhook 命名空间信任来自 host 传输层的会话认证。对应类型定义在 channel.rsReplyTransportStream/Message与DeliveryTransportPush/Message是两个独立枚举ChannelReplyDescriptor只有一个transport字段ChannelDeliveryDescriptor则有transport与带#[serde(default)]的requires_enrollment。两点值得注意的边界provider 消息长度限制故意不进 manifest 策略。Slack 与 Telegram 的计量单位不同例如 Telegram 按 UTF-16 code unit因此每个 adapter 在出站前按自己协议权威的长度限制自行渲染与分块。滚动兼容保留 v3。公开写入端只输出上述三个小节轴ChannelDescriptor 的 serde 边界上单独保留了对 v3 布尔量与旧展示层max_message_chars的私有只读字段会话式outbound true归一化为 message reply message delivery唯一部署过的notifications true形态归一化为需要 enrollment 的 push delivery。这是受清单约束的桥梁而非 v4 或通用迁移层安全敏感的嵌套配方仍保持严格未知字段拒绝。桥梁仅前向读取——当前写入端不重发已退役布尔量因此把已重写的 manifest 行回滚到拆分前的二进制需要恢复旧 manifest 行或重装旧包而不是引入第二套永久双分类法。4. 核心类型OutboundRoute 与两个传输枚举/// Where an outbound thing is going — the axis, decided once, by the router. enum OutboundRoute { /// Back to the conversation/session the run came from. The request /// already carries its run and source binding. Reply, /// To a resolved target, with no assumption that a run exists. The /// delivery resolution already carries its target and authorization. Delivery, } enum ReplyTransport { Stream, Message } enum DeliveryTransport { Push, Message }两个传输枚举是有意为之。Stream对 delivery 无意义、Push对 reply 无意义分离类型让这些荒谬组合不可表示。Slack 的Message同时出现在两个枚举里不是重复——它恰好说明对 Slack 而言两条轴碰巧共享同一机制而这也正是「直到 web-app 出现之前这个区分始终不可见」的原因。源码 channel.rs 的注释与之一致并补充了第三个传输的扩展路径一个「自己不能订阅、需要 host 向其中推块」的通道会以新枚举变体加入而非重构。5. 分发器一个地方、两个入口impl OutboundCoordinator { async fn reply(self, run: Run, content: ReplyContent) - Outcome; async fn deliver(self, spec: DeliverySpec, content: Content) - VecOutcome; }两个入口都持久化一次 delivery attempt都返回证据都不存在静默跳过。在仓库中这一职责落在 delivery_coordinator.rs 注释所描述的通用协调器发送一条消息被分解为「语义与可靠性」目标解析、授权、attempt 持久化、重试、崩溃恢复——对所有通道一致、归协调器所有与「厂商机制」渲染、拆分、API 选择、错误映射——归各扩展的ChannelDelivery::deliver。规则包括任何用户可见的通道输出都是语义DeliveryIntent发射方永远不知道用户在哪个通道OUT-1attempt 在厂商出站之前持久化OUT-3崩溃恢复标记Unknown且绝不盲目重发OUT-6多部分投递中已发送部分之后的重试性失败是终态的OUT-7。5.1 证据是对称的transport返回的证据Message/Push厂商vendor message idStream该回复可见处的 projection cursor两者都提供持久化的传输证据消息/推送的厂商接受标识或证明流式回复已提交的投影游标。两者都不是「人类客户端真的渲染了结果」的证明——那需要单独的客户端确认契约。这堵住了一个真实漏洞过去浏览器回复根本不产生任何 delivery 记录用户答案的持久可用性没有统一的审计轨迹web-app 在投递审计中不可见。5.2 真实存在的不对称以及它住在哪里Message/Push在完成时投递一次Stream在回合期间持续投递。这是客户端固有属性不是需要设计掉的缺陷。分发器对两者都在同一时刻运行完成时对Stream那次调用是seal封口——「回合结束、最终状态在游标 N 处持久化」——而不是用户第一次看到任何内容。增量流是该传输的特征正如 4096 字符分块是 Telegram 的特征。5.3 projection stream 保持共享基础设施它按线程per thread键控而非按通道键控且已有多个读者WebUI 的 SSE 路由和OpenAI-compat。Stream从它读取以获得游标但不拥有它。通道真正拥有的是自己的reader——订阅并向前转发帧给客户端的传输——而今天恰恰是这个部分没有归属所以浏览器那一半活在 WebUI 前端里。5.4 决策验证而非拥有2026-08-11 修订——定为 verify。StreamDelivered记录回合管线已经写入的投影游标。投递协调器验证并报告这一持久的projection-commit证据它不接管 transcript/projection 持久化也不扰动 replay。历史变体名并不断言某个已订阅浏览器收到了帧不存在客户端确认契约调用方不得把游标当作客户端收讫的证明。「Stream 应该验证追加读取回合已写入的游标还是拥有它把 assistant 消息追加移出回合管线」拥有在概念上更纯粹——单一写者、与 push 对称——但意味着对 turn/timeline 持久化的外科手术而这会波及 replay。建议先验证。它带来同样性质保证而不动摇 replay且即使写操作日后移动接口也不变。仓库里的实现正是如此stream_delivery_cursor 在已有 envelope 中寻找「同一 state 里同时包含 finalized 的 transcript 文本与 completed 的 run 状态」的真实游标——进程局部的实时文本在任何早期 envelope 中都不能满足这个 seal。6. 适配器 trait11 个方法 → 三个 trait2026-08-11 修订——一致性现在是被强制执行的而非仅仅可能。把 trait 与 manifest 小节配对本身并不能阻止ChannelSurfaces选项漂移。check_binding现在在激活时逐轴检查vendor/webhook 入站要求ChannelIngressmessage 回复要求ChannelReply投递要求ChannelDeliveryauthenticated-session 入站与 stream 回复要求对应 adapter 半体缺席因为 host 拥有它们。回归由ironclaw_extension_host::entrypoint::tests::each_channel_section_must_have_exactly_its_implementing_half钉住host 拥有时的缺席情形由a_stream_reply_and_session_ingress_must_bind_no_half钉住。trait ChannelIngress { async fn receive(self, verified, restricted_egress) - InboundOutcome; } trait ChannelReply { async fn send_reply(self, envelope, egress) - Report; } trait ChannelDelivery { async fn deliver(self, envelope, egress) - Report; }落地实现见 channel_adapter.rsChannelIngress::receive把一条 host 已验证的厂商请求翻译为完整归一化结果任何附件字节或厂商侧会话上下文都在返回前经 manifest 限制的 egress 解析完毕host 永远不会回调 adapter 去补完半归一化消息。ChannelReply::send_reply渲染并发回一条 run 答案负责厂商格式、provider 特定分拆、目标语法与安全错误映射从不触碰投递存储附带的supports_private_delivery()默认false让依赖隐私的 host 决策如共享会话中是否可携带设置链接issue #7681对所有未声明能力的 adapter 关闭fail closed而投递本身仍 fail-open。ChannelDelivery::deliver向一个已解析、已授权的目标发送带外投递可选provision_direct_target是类型化的直接目标开通钩子默认Unsupported。ChannelSurfaceschannel_adapter.rs以三个OptionArcdyn ...字段承载「一个扩展的通道面实际实现了哪些半体」——None是 host 拥有模式authenticated_session入站、stream回复的必需事实check_binding在激活时证明每个 manifest 轴与其实现一致。这正是 web-app 只实现ChannelDelivery的原因authenticated_session意味着 host 归一化入站transport stream意味着 host 发布回复两个缺失半体都是有意义的而不是谜团。三通道的完整矩阵可查 extensions/AGENTS.mdslack 与 telegram 为 webhook 入站 message reply message deliveryweb-app 为 host 拥有的 session 入站与 stream 回复 push deliveryVAPID 在[admin_configuration]下自动播种。7. 决策删除activate/cleanup只有 Telegram 实现了它们而其内容不过是setWebhook/deleteWebhook——告诉厂商往哪里 POST。这是入站注册而每条输入都已为 host 所知host 拥有 webhook 路由因此也拥有 URL。它变成又一条 recipe[channel.ingress.registration] method post path /bot{credential}/setWebhook body { url {webhook_url}, secret_token {ingress_secret} } [channel.ingress.deregistration] method post path /bot{credential}/deleteWebhookhost 替换占位符经由既有的受限 egress 与既有凭据注入执行。两个方法体变为零manifest 字段不会再与其实现漂移。无需注册的通道Slack——其 events URL 在厂商应用内配置web-app——没有 webhook直接省略该小节这正是「默认 no-op」的含义只是少了 trait 表面积。被否决的方案把它们挪进一个SurfaceLifecycletrait——那只是搬运债务而非消除债务且为零个调用方购买通用性。若真有通道需要命令式的激活钩子届时再添加且必须有真实的第二个实现者。8. 被取代的提案receive异步化与附件预确认含修订定案2026-08-11 修订——完整消息方案胜出。所有者测量了线上路径后否决了 refs/post-ack 设计。两条旧 adapter 回调本来就在持久化接受提交之前运行因此在receive内解析附件并不会把 provider I/O 引入一个此前是 post-commit 的 pre-ack 窗口。实际顺序是校验/约束请求并构造 manifest 限制的 egressChannelIngress::receive经该 egress 解析并解析附件字节及任何会话上下文host 消毒上下文、验证 descriptor/字节精确一致性与预算、运行入站策略host 持久化接受消息幂等、绑定、turn 提交、附件落盘然后路由器返回 2xx。旧的fetch_attachment/fetch_conversation_context回调同样占据步骤 2位于 parse 与accept_prepared_user_message之间。ack-after-commit 与重试语义不变。评审中发现的第二处修订提交边界不变但与产品账本 replay 预检的相对顺序不同。退役路径先解析事件 id、检查 replay 是否已settled、然后才抓取附件字节。完整消息receive必须在产品看到该 id 之前抓取因此厂商精确重投可能重复凭据读取且即使原始事件已settled重复抓取失败也可能返回 503。恢复该优化需要单独一个 host 拥有的持久化已验证请求 replay 守卫绝不能实现为又一个 adapter parse/fetch 回调那会重建本决策移除的部分契约。这是后续风险而非声称当前顺序在每一方面都不变。[channel.attachments]被删除因为两个已上线的传输都不是通用请求模板Telegram 执行getFile再下载响应派生的、路径校验过的后缀Slack 跟随 payload 派生的绝对 URL 且必须拒绝 HTTP 200 返回的 HTML 错误体。两者实现的大部分都在校验不可信的厂商响应。把这些协议——尤其是 Telegram 的路径穿越防御——编码为 TOML 校验 DSL会比留在包内 Rust 更不可审查、更不安全。会话上下文也不类似附件引用上下文就是内容本身。没有可先提交的廉价 ref且在接收后再抓取它会让当前回合在没有共享消息的情况下作答——而正是这些共享消息让「你能查一下吗」这类问题有意义。因此它同样由receive完成。原文保留了 post-ack 提案及其论证作为决策历史并附有 §7.1–7.3 的完整推理值得在此保留8.1 为什么不能简单地先 ack入站路由器刻意在提交之后 ack// Durable dedupe admission commit (idempotency ledger keyed by// installation external event fingerprint) plus identity/// conversation binding and turn submission — synchronous, so the// routers 2xx is ack-after-commit.—— extension_ingress.rs这里的「commit」指持久化写入而非 git幂等账本条目与已提交的 turn。这是at-least-once契约。先 ack 再写失败厂商会认为消息已送达而永不重试——静默丢消息。提前 ack 会把 at-least-once 变成 at-most-once。8.2 真正的问题提交依赖抓取let attachments self.resolve_inbound_attachments(...).await?; // ← 网络 self.accept_prepared_user_message(prepared, envelope, attachments) // ← 持久化写入抓到的字节是写入的参数因此厂商往返不可避免地落在 pre-ack 窗口内。这是对「提交包含什么」的选择而非对顺序的选择——顺序本来就是正确的提交内容抓取发生今天消息连同落盘字节提交前 → ack 前目标消息仅含 refsack 后两者都是 commit-then-ack第二种提交更廉价的东西——ref 已在解析后的 payload 里无需网络——消息立即持久化、随即 ack、然后才拉字节。8.3 原决策已被修订取代原方案是让receive异步但不抓取抓取变成 host 在post-ack运行的声明式 recipe[channel.attachments] fetch { method get, path /files/{external_file_id} }无 adapter 方法——与 §7 一致通道特有数据、通用执行。无法声明式表达的通道回退为outcome 携带一个 deferred handle 由 host 在 post-ack 调用。receive内联抓取被彻底否决——它把往返提前到提交之前。fetch_conversation_context同样分析。8.4 已无悬念不存在未解析附件窗口2026-08-11 修订。因为receive返回完整附件、且持久化接受仍将其字节与消息原子落盘所以原提案中那个「未解析窗口」不存在。无需 wait/backfill 行为。原提案担忧的是字节在提交之后才到turn 必须容忍短暂未解析的附件——ref 已提交所以失败不丢东西但模型可能看到字节尚不可用的消息loop 需要为该窗口定义行为等待、继续并回填、或失败。9. 决策enrollment 移到 host且没有adapter 方法旧模型里 adapter 拥有 enrollment 存储并暴露三个方法。后果不止是表面积host 无法回答「这个用户设置好了吗」——这正是投递前没有护栏的原因无订阅时发送只会在 adapter 处失败。一个推送订阅endpoint keys按用户、可撤销、在设置中列出本质上就是一条按用户的投递注册。目标模型host 存储按用户的投递注册一个不透明的、有大小上限的 blob键为(tenant, user, extension_id)。存储前唯一的 security 相关检查是通用的endpoint 必须指向[[channel.egress]]中声明的 host。否则 enrollment 就是一个让 host 向攻击者 URL POST 的 SSRF 原语。host 拥有该 allowlist所以由 host 执行检查大小上限同样在 host 侧。其余一切在使用处校验——adapter 在投递时解析 blob反正那时它就需要 endpoint 与密钥。畸形记录使该次投递失败并在同一路径上被修剪该路径本就会修剪 404/410。每条存储行有 host 铸造的不透明注册 idprovider 寻址包括推送 endpoint永远不会成为其身份。既有 Web Push 文档以其原始subscription_id保持可读写入端同时携带规范records与私有、结构化扁平化的subscriptions回滚投影通用存储生成该投影时不解释不透明文档。回滚的写入端丢弃未知的规范投影下次上线再次读取旧投影无需重键记录。因此没有validate_enrollment也没有任何设置方法。客户端引导数据浏览器订阅所需的 VAPID 公钥是 host 已拥有的凭据的公开一半按声明种类注入——host 通用地发布它而非通道暴露定制状态文档。结果注册变成delivery targets与 outbound 目标目录统一协调器获得真正的闸门——向零注册通道投递在任何 adapter 调用之前就是一个可解析的「无目标」结果而不是在厂商路径内部才发现失败。这一设计在 channel_adapter.rs 的DeliveryRegistration中落地为「两个字段、两个信任故事」endpoint有意 host 可见存储前对照通道声明 egress host 检查document通道不透明host 只限大小、绝不解释。NoDeliveryRegistrationsdelivery_coordinator.rs则提供了「无注册」这一真实答案的占位实现让无法回答「该用户是否已注册」的协调器也必须回答它。10. 变更清单today → becomes今天变为inbound: bool[channel.ingress]小节存在outbound: bool[channel.reply]/[channel.delivery]小节存在notifications: bool[channel.delivery]小节存在notifications_require_setup[channel.delivery].requires_enrollmentreply_mode streaming\|batched[channel.reply].transport stream\|messagedeliver()按轴调用send_reply()或deliver()deliver_notification()deliver()从DeliveryIntent推断路由两臂OutboundRoute内容与授权留在各自属主请求类型中流式的NoDeliveryDelivered { via: Projection, cursor }activate/cleanup[channel.ingress.registration]recipefetch_attachment/fetch_conversation_context回调一个完整的异步ChannelIngress::receive提交前经受限 egress3 个通知设置方法host 拥有的注册对照 entrypoint.rs 的激活检查如[channel.delivery] needs an adapter half to send out of band与 deployment_channels.rs 的[channel.delivery] must not enter the deployment registry without ChannelDelivery可以看到这些规则如何被编码为可执行的激活期断言。11. 开放问题与已定案开放问题§5.1 审计形态Stream投递用完整 attempt 行还是浏览器高频路径上的更轻量标记第三种传输一个能流式但无法自行订阅的通道host 向其中推块的第三方 websocket需要PushStreaming。现在不构建枚举形状保证新增它不是重写。已定案2026-08-11 更新至 2026-08-12prompt/reaction/retraction 保持为内容而非路由分类法路由器只存两臂 reply/delivery 轴§2.1。两个传输枚举而非一个§4。流式证据验证既有投影游标§5.4。完整入站附件/上下文保持提交前§7/§8 修订。投递注册落在ironclaw_auth而非ironclaw_outbound——两个候选属主本就可从所有消费者到达决胜因素是出站边缘adapter 面向的注册视图属于ironclaw_extension_contractsauth 已依赖它、outbound 不依赖语义上一条按用户、可撤销、在设置中列出的投递授权是凭据形态的。12. 实施顺序每一项都可独立交付且都不属于 unified-channel-model PR——那个 PR 统一管线本设计重塑契约混在一起会让两者都无法审查#变更规模风险1OutboundRouteStream的终态 outcome§4、§5小低——堵住审计漏洞、消灭 no-op2删除activate/cleanup→ ingress-registration recipe§7小低——仅一个通道受影响3manifest 小节取代布尔量§3中低——机械、有门禁检查4异步receive返回完整附件/上下文§8 修订中中——厂商 I/O 留在既有 pre-ack 窗口5host 拥有的注册§9大中——持久化数据迁移6拆分为三个 trait§6机械低——在 1–5 之后结语从「方法并集」到「轴声明」这次重构的本质是把路由决策从内容推断中解放出来轴由路由器决定一次内容永远不需要暗示路由。对读者而言最值得带走的三点manifest 的三小节声明是通道能力的唯一权威缺席即不支持OutboundRoute使「同一意图、不同轴」的缺陷类不可表达enrollment 归 host 后协调器在碰厂商之前就能回答「该用户是否已设置」。相关实现细节可继续深入 channel_adapter.rs、channel.rs、delivery_coordinator.rs 与三个通道包的 manifest前序设计的完整上下文则在 2026-08-10-unified-channel-model.md。赞分享人工智能AI 应用交互助手AI Agent【免费下载链接】ironclawIronClaw is an Agent OS focused on privacy, security and extensibility项目地址https://gitcode.com/gh_mirrors/iro/ironclaw点击查看免费下载相关推荐Ice 菜单栏管理完整指南3 步用免费 Mac 工具快速整理图标Ice 菜单栏管理完整指南3 步用免费 Mac 工具快速整理图标 屏幕右上角的 Wi Fi、电池和一堆状态图标越积越多投屏时甚至被刘海直接挡住——这正是 I桌面应用IronClaw 附件落地机制解析ironclaw_attachments 的通道无关落盘、端口契约与预算治理IronClaw 附件落地机制解析ironclaw_attachments 的通道无关落盘、端口契约与预算治理 IronClaw 是一个以隐私、安全与可扩展性人工智能AI 应用交互助手AI Agent深入解析 ghost-storage-baseGhost 存储适配器基类的设计契约与落地实践深入解析 ghost storage baseGhost 存储适配器基类的设计契约与落地实践 ghost storage base 是 Ghost 官方为文件CMS后端前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表