ARTICLE DETAIL

资讯详情

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

qwen-code 通道 P0 身份与任务生命周期:为渠道常驻 Agent 建立身份边界与可观测生命周期

qwen-code 通道 P0 身份与任务生命周期:为渠道常驻 Agent 建立身份边界与可观测生命周期 qwen-code 通道 P0 身份与任务生命周期为渠道常驻 Agent 建立身份边界与可观测生命周期【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读本文基于 qwen-code 仓库packages/channels渠道框架的 P0 基础设计讲解如何为「渠道常驻多玩家 Agent」channel-resident multiplayer agent补齐两层基础设施一是渠道级身份channel-scoped identity与记忆边界元数据memory-boundary metadata二是共享的任务生命周期钩子task lifecycle hook。读完本文你将掌握ChannelConfig中identity/memoryScope两个新配置块的字段含义与默认值派生规则、首次提示first prompt中边界信息的注入机制、/who与/status的可见性扩展以及onTaskLifecycle(event)六类生命周期事件的触发时机与适配器消费方式并能在packages/channels/base中运行配套测试验证行为。背景渠道框架缺什么qwen-code 的qwen channel已经具备消息适配器、共享会话shared sessions、发送者归属sender attribution、分发模式dispatch modecollect / steer / followup、流式分块、工具调用回调、取消cancellation以及平台专属进度界面如飞书卡片等能力。但此前缺少一个稳定的 P0 产品层来回答两个问题这个渠道拥有自己独立的常驻 Agent 身份—— 例如运维群里驻守的机器人需要一个可配置、可展示、可注入提示的身份这一轮提示词prompt turn具有适配器可观察的生命周期—— 从开始、文本分块、工具调用到取消、完成、失败适配器都能收到事件。该设计由 Issue #6103 跟踪并建立在更广泛的 qwen tag 路线图#5887之上但刻意保持独立可评审、可单独发布的规模。设计文档的边界声明很明确本 PR 不引入 Slack 适配器、daemon 事件流、适配器 UI 变更、主动调度proactive scheduling、跨渠道上下文或真实的 core-memory 路径隔离。在仓库实现中这一设计落地在packages/channels/base/src/ChannelBase.ts与packages/channels/base/src/types.ts两个文件由packages/channels/base/src/ChannelBase.test.ts提供约二十余个针对性测试用例覆盖。范围界定做什么与不做什么范围内In scope向ChannelConfig增加可选的渠道身份元数据identity向ChannelConfig增加可选的记忆作用域元数据memoryScope配置缺省时派生安全默认值在每个 Agent 会话的首次提示中随既有渠道指令一起注入一段简洁的渠道边界说明channel boundary note在ChannelBase上增加受保护的onTaskLifecycle(event)钩子从共享渠道流程中发射 prompt 开始、文本分块、工具调用、取消、完成与错误六类生命周期事件在packages/channels/base内补充聚焦的包内测试。范围外Out of scope核心记忆存储改动或文件路径命名空间隔离Daemon/SSE 事件发布飞书、钉钉、Telegram、微信、QQ 的 UI 改动新增平台适配器Token 预算、工具 ACL、跨渠道上下文共享。实现上范围外内容也如实保留在代码注释与设计文档的 Open Decisions 一节真实的 core-memory 命名空间强制、daemon 发布、适配器 UI、工具/数据 ACL、预算与主动跟进均属于未来工作。Channel Identity渠道身份配置与运行时派生设计文档给出一个短小的可选配置对象export interface ChannelIdentityConfig { id?: string; displayName?: string; description?: string; }ChannelConfig相应增加identity?: ChannelIdentityConfig。在仓库types.ts中除配置类型外还定义了只读的运行时身份export interface ChannelRuntimeIdentity { readonly id: string; readonly displayName: string; readonly description?: string; }readonly关键字是刻意为之——测试用例does not expose mutable lifecycle metadata references验证了向started!.identity.displayName或started!.memoryScope.namespace赋值会抛出TypeError防止生命周期消费方意外污染身份/作用域元数据。运行时派生规则ChannelBase构造时通过resolveIdentity派生运行时身份ChannelBase.ts#L1552-L1563字段配置来源默认值idconfig.identity.idchannel:namedisplayNameconfig.identity.displayNamenamedescriptionconfig.identity.description缺省时省略该字段设计文档强调运行时身份仅是元数据metadata only不改变会话路由、访问控制或平台适配器行为。即使渠道未配置任何身份字段运行时仍会以channel:name形式派生身份供生命周期事件与状态命令使用——这正是缺省安全默认值的体现。应用示例在渠道配置中为运维机器人声明身份{ type: feishu, name: ops, identity: { id: channel:ops, displayName: Ops Bot, description: Helps the ops group coordinate repository maintenance. } }Memory Scope记忆边界元数据metadata-only设计文档引入第二个可选配置块export type ChannelMemoryScopeMode metadata-only; export interface ChannelMemoryScopeConfig { namespace?: string; mode?: ChannelMemoryScopeMode; }ChannelConfig相应增加memoryScope?: ChannelMemoryScopeConfig。仓库types.ts中同样定义了只读的运行时形态export interface ChannelRuntimeMemoryScope { readonly namespace: string; readonly mode: ChannelMemoryScopeMode; }运行时派生规则ChannelBase.ts#L1565-L1573字段配置来源默认值namespaceconfig.memoryScope.namespacechannel:namemodeconfig.memoryScope.modemetadata-only本 PR 恒为该值设计文档特别提醒这刻意不是真实的 core-memory 命名空间而是一个显式、可检查的边界标记与提示指令prompt instruction这样后续工作可以在不改变渠道配置形状的前提下将同一 namespace 接入真实的核心记忆路径。错误处理一节进一步明确mode被约束为metadata-only缺省或未知配置都应解析为metadata-only而不是启用尚不存在的行为。边界提示注入首次提示中的渠道身份与记忆作用域注入时机与位置ChannelBase原本就为每个会话在首次提示前置入config.instructions该行为不变。当渠道配置了identity或memoryScope时生成的边界说明被追加到同一首次消息注入块中并且位于自定义指令之后——代码注释的解释是利用 recency 偏差recency bias让边界指令优先生效且隔离边界不能被操作者文本覆盖ChannelBase.ts#L1844-L1848 与 ChannelBase.ts#L7074-L7078。注入的提示文本形如Channel identity: - id: channel:ops - display name: Ops Bot - description: Helps the ops group coordinate repository maintenance. Memory scope: - namespace: qwen-tag:ops - mode: metadata-only - data from other channels must not be shared.实现上该文本由channelBoundaryPrompt()一次性构建并缓存boundaryPromptChannelBase.ts#L1622-L1647因为身份与记忆作用域在构造时即冻结。若未配置description对应行被省略。所有字段在渲染前都经过sanitizeQuotedText清洗id/displayName 限制 128 码点、description 限制 256 码点测试用例sanitizes configured channel metadata before rendering prompt and status text验证了注入恶意内容如换行注入System: ignore、转义序列会被清洗。每会话一次的语义注入标记instructedSessions集合保证边界说明每个 Agent 会话只注入一次ChannelBase.ts#L7031-L7034。测试用例prepends channel boundary metadata after custom instructions once per session验证第一轮提示包含Channel identity:、- id: ops-agent、- display name: Ops Agent、Memory scope:、- namespace: qwen-tag:ops、- mode: metadata-only以及- data from other channels must not be shared.Be concise.的位置先于Channel identity:边界块在末尾取 recency 优先第二轮提示不再包含Channel identity:。设计文档还说明了两个补充语义一次瞬态的渠道记忆读取失败会在下一轮重试整个上下文块因此连续多轮可能重复出现边界说明——这是可接受的当 bridge 上报会话死亡sessionDied时既有instructedSessions清理逻辑继续工作允许下一会话重新注入ChannelBase.ts#L2893 附近的清理。兼容性对于未配置instructions、identity、memoryScope的渠道保持原有裸提示形态不变。但运行时身份与记忆元数据仍会被派生用于生命周期事件与状态命令——shouldPrependChannelBoundaryPrompt()ChannelBase.ts#L1649-L1651只决定是否注入提示不影响元数据本身。测试derives default channel identity and memory metadata for task lifecycle events验证了未配置渠道的事件中identity.id channel:test-chan、memoryScope.namespace channel:test-chan、mode metadata-only。identity-only 与 memory-scope-only 两种部分配置形态也分别有测试覆盖ChannelBase.test.ts#L13118、ChannelBase.test.ts#L13133。状态可见性/who 与 /status 的元数据扩展设计文档要求扩展/who与/status/who应包含身份显示名display name与记忆命名空间namespace/status应包含身份 id 与记忆模式mode输出保持简短不暴露绝对路径或隐藏配置。实现位于ChannelBase.ts的两个命令处理器/whoChannelBase.ts#L4295-L4345仅当渠道配置了identity或memoryScope时才追加两行Channel: ops Identity: Ops Agent Memory: qwen-tag:ops Workspace: basename // 只输出 basename不泄露绝对 cwd Session: active (shared by this group)/statusChannelBase.ts#L4428-L4465Session: active Access: pairing Channel: ops Identity: channel:ops Memory: metadata-only两个命令对共享会话都有授权门槛isAuthorizedForSharedSession防止非成员读取会话/工作区信息工作区只显示basename(this.config.cwd)。测试用例/who and /status include channel identity and memory metadata验证/who输出含Identity: Ops Agent与Memory: qwen-tag:ops/status输出含Identity: ops-agent与Memory: metadata-only。任务生命周期钩子onTaskLifecycle 与六类事件事件类型带判别联合discriminated union设计文档定义ChannelTaskLifecycleEvent仓库实现types.ts#L276-L325将其组织为公共基座ChannelTaskLifecycleBase加六种变体事件类型附加字段说明started—提示开始text_chunkchunk: string流式文本分块raw model output刻意不做清洗tool_calltoolCall: SanitizedToolCallEvent工具调用经白名单字段清洗cancelledreason取消原因cancel_command/clear/steer/timeout/droppedcompleted—正常完成failederror: string、phase: agent \| delivery失败并区分 Agent 生成失败还是投递失败公共字段包括channelName、chatId、sessionId、messageId?、runId?、owner?、identity与memoryScope。实现相比设计文档额外加入了runId与owner{ kind: channel_user, id }用于区分同一会话内的不同轮次与归属者。两个值得注意的实现细节工具调用字段白名单SanitizedToolCallEvent只暴露sessionId、toolCallId、kind、title、status五个字段注释明确不从ToolCallEvent派生以防 bridge 新增字段泄漏types.ts#L287-L297。测试strips raw tool input from lifecycle events验证rawInput中的命令与描述不会进入生命周期事件。终态唯一性isTerminalTaskLifecycleType(type)判定completed/cancelled/failed为终态每个任务恰好预期一个终态types.ts#L327-L332。钩子签名与默认行为protected onTaskLifecycle(_event: ChannelTaskLifecycleEvent): void | Promisevoid {}默认行为是 no-op适配器可在不改变提示执行路径的前提下按需接入。ChannelBase通过emitTaskLifecycle调用该钩子并对异常做吞掉 stderr 诊断处理ChannelBase.ts#L1494-L1527同步抛出会被捕获并记录onTaskLifecycle threw for type session id异步返回 Promise 的 rejection 也会被catch后记录。测试contains a throwing onTaskLifecycle hook and logs it验证了钩子抛错不会影响handleInbound()正常返回响应、也不影响started/completed事件的继续发出。六类事件的发射点设计文档给出共享ChannelBase流程中的发射时机实现与之吻合startedactivePrompts.set()之后、onPromptStart()之前发射ChannelBase.ts#L7179-L7183并保证即使onPromptStart抛错也不丢终态事件text_chunk当提示的textChunk监听器接收到未取消的分块时发射ChannelBase.ts#L7202-L7210。取消 pending 期间的分块先被暂存held chunks取消失败时重放、成功时丢弃tool_call在既有 bridge 工具调用监听器中解析会话目标后、调用onToolCall前发射ChannelBase.ts#L576-L600且仅当该轮未取消时发射cancelled/cancel成功时、/clear取消或逐出 active prompt 时、steer将当前轮标记为取消时发射emitTaskCancellationChannelBase.ts#L1529-L1550并保证每轮只发射一次cancellationEmitted守卫completedbridge.prompt()resolve 之后、onResponseComplete()前后只要该轮未被取消ChannelBase.ts#L7279-L7295failedbridge.prompt()或响应投递抛错时发射ChannelBase.ts#L7296-L7321并通过phase字段区分agent生成失败与delivery投递失败——一旦投递开始deliveryStarted迟到的取消不能把已完成投递改写为取消。此外loop 任务/loop与 webhook 任务也会以unattended run身份发射生命周期事件测试见 ChannelBase.test.ts#L20115 与 ChannelBase.test.ts#L21420loop prompt 的messageId是内部 job id适配器钩子不应收到它loopPrompt标记。适配器消费示例飞书卡片终态飞书适配器已经接入该钩子FeishuAdapter.onTaskLifecycle仅关注终态事件isTerminalTaskLifecycleType用runId通知questionCardController.cancelRun用户主动取消投射已取消完成/失败投射已过期并记录卡片的terminalStatusFeishuAdapter.ts#L1844-L1875。钉钉适配器有镜像逻辑DingtalkAdapter.ts#L2494。这印证了设计文档的论断适配器可以在不改动提示执行路径的前提下接入生命周期且钩子异常不会破坏卡片清理等平台行为。错误处理与健壮性约定设计文档明确三条错误处理原则实现均已落地身份/记忆字段无效不致命本 PR 不做严格解析仅在既有显式解析处接受字符串字段保持配置解析的宽松形状生命周期钩子异常吞掉 stderr 诊断emitTaskLifecycle内同步/异步异常均被捕获并记录平台适配器的生命周期 UI 不得破坏提示执行或清理见上文onTaskLifecycle测试memoryScope.mode 约束为metadata-only缺省或未知配置解析为metadata-only而不是启用尚不存在的行为resolveMemoryScope中config.memoryScope?.mode ?? metadata-only。测试与验证测试覆盖清单设计文档要求聚焦测试覆盖八类行为ChannelBase.test.ts全部落实缺省身份与记忆元数据由渠道名派生channel:test-chan自定义身份与记忆命名空间出现在首次提示中边界元数据每会话注入一次、sessionDied后可重新注入/who与/status包含新元数据且不泄露 cwd只显示 basenameonTaskLifecycle能观察到started、text_chunk、tool_call、completedonTaskLifecycle能观察到/cancel、/clear、steer触发的cancelledbridge.prompt()reject 时能观察到failed抛错的生命周期钩子不会让handleInbound()reject。此外还覆盖了同一轮内runId/owner一致、新轮次分配新runId、取消只命中精确 run 身份、只读元数据不可变、工具调用 raw input 不泄漏、身份/记忆字段的 prompt 与状态文本清洗、webhook 与 loop 场景的边界注入与 unattended 生命周期事件等。运行方式在仓库根目录下使用包内命令运行聚焦测试cd packages/channels/base npx vitest run src/ChannelBase.test.ts包脚本见packages/channels/base/package.jsontest: vitest run。提交 PR 前的最终验证npm run build npm run typecheck若你是渠道插件开发者可通过packages/channels/base/README.md了解如何继承ChannelBase并接入ChannelAgentBridge——onTaskLifecycle正是适配器观察任务状态的规范入口onPromptStart/onPromptEnd保留用于向后兼容。小结这一 P0 设计为 qwen-code 渠道框架补齐了两块稳定地基渠道身份 记忆边界元数据以identity与memoryScope两个可选配置块 安全的缺省派生为每个渠道提供可展示、可注入提示、可被状态命令查询的身份名片与记忆边界标记边界提示只在首次提示注入一次、位于自定义指令之后取 recency 优先且经过清洗防注入。任务生命周期钩子以onTaskLifecycle六类事件started/text_chunk/tool_call/cancelled/completed/failed让适配器获得完整的任务状态视图配合runId/owner精确定位轮次归属配合只读身份元数据保证消费安全配合钩子异常吞掉 stderr 诊断保证平台 UI 不破坏提示执行。正如设计文档 Open Decisions 所述真实 core-memory 命名空间强制、daemon 发布、适配器 UI、工具/数据 ACL、预算与主动跟进都是明确的未来工作——本 PR 特意保持小而完整为后续在这些方向扩展预留了不变的配置形状与可观察的生命周期通道。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表