Skip to content

feat(chat): let configured steward groups respond without @ mentions - #5189

Merged
huangruiteng merged 4 commits into
mainfrom
codex/steward-experience-refinement
Sep 27, 2026
Merged

huangruiteng merged 4 commits into
mainfrom
codex/steward-experience-refinement

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

Steward groups currently keep ordinary messages as background and start a turn only for a mention or verified bot reply. This change adds an explicit per-connection Respond to group members without @ setting in the App, with saved-state readback and a switch back to addressed-only behavior.

The shared TypeScript rule consumes provider-verified sender and addressing evidence. Existing inbox, effect receipts and reply handling own execution and deduplication. Existing connections retain their default; historical messages, bots and unknown unaddressed senders do not start work in the new mode. Worker Topics keep routing priority. Receiving a message does not grant host tools or delegation permissions.

Validation on the updated head:

  • 182 focused connection, inbox and API tests; 2 typed admission tests; control-plane typecheck; Ruff; configured mypy; full frontend and packaged chat build.
  • Browser checks cover opt-in, save, readback, revocation and narrow-screen use in source and packaged builds. The packaged conversation-return scenario also passes after resolving the main integration conflict.
  • 8 registry census/source-session boundary tests. Main integration exposed six stale census locations; the metadata-only repair preserves all 250 sites and their classifications. Clean main reproduces the census failure before this repair.
  • The review's Python bridge suggestion is addressed with annotations and single-read Mapping narrowing. The optional broader strict-mypy diagnostic improves from 67 baseline errors to 63, with no newly introduced diagnostic; it is not fully clean.

Visual review: the existing connection editor gains one When to respond selector; the connection list shows its saved value. The settings navigation is unchanged. This advances roadmap R3's reliable entry and its no-mention golden-query variant. Shared coordination stays in TypeScript, with Python adapting Lark evidence and transport.

Provider send/readback uses public-safe test doubles. No live group messages were sent, no installation was updated, and deployed end-to-end behavior remains unqualified. External-channel tool permission and sender-bound recipient grants remain separate gaps. This PR is ready for renewed exact-head review and CI; the prior review applies to its earlier head.

Risk-based premerge passes on ca8923be8105b3ac40ec1d4ad07b4d4f4812b415; exact-scope change-quality receipt cqr_d3e03a948c26eb12de0f verifies valid. Public-boundary scan is clean. Of 16 selected checks, 15 pass and one is the reported inherited maintainability advisory: loopx.status reexports 119 symbols against ceiling 117. All five direct checks pass; no required check is skipped.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@mergify

mergify Bot commented Sep 27, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @huangruiteng.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Sep 27, 2026

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Exact head: 3bda6dacce91a3a2cd36c3c79defbe4e3f18cbfb; immutable base: 9eaacfbf2ff93d5386cee82ddf0847d9c739e78a. No blocking finding. This is a code-review approval, not merge authorization or certification of live Lark/model execution.

动机

原来的管家连接虽然捕获群消息,但只有 @ 或已验证回复能启动管家 Turn。普通成员直接提需求仍会落入背景上下文。结合现有 steward Golden Queries 和 roadmap R3 的群入口契约,本 PR 交付的是一个有用且可撤销的增量:用户可以为某一个管家群连接明确选择“人类消息无需 @”,并在编辑、保存、列表回读时看到该选择。它不等于完成整个 R3,也不证明已部署的飞书权限或模型执行质量。

改动思路

最强的反对理由是群捕获被错误当成执行授权,或者所有机器人和补拉历史都会触发 Turn。这里没有用 capture_scope 推导授权,也没有从消息关键词猜用户意图:连接上的 turn_trigger 是不可从其他状态推导的显式设置。前端生产这个设置,连接 writer 保存它,Lark adapter 提供已解析的 sender/address/history 证据,通用 TS owner 决定 admission。维持 @-only 什么也不改最便宜,但没有解决直接发消息的入口缺口;全局扩大捕获权限则扩大了不必要的范围。每连接两个枚举值、复用现有管家路由和设置页是合适的边界。

具体改动

20 个文件,271 行新增、11 行删除。生产逻辑集中在既有连接 writer、Lark routing 和一个 24 行的通用 TS 判定;其余是设置页/API 投影、双语说明和耐久测试,没有新增 capability、provider 或第二套队列。

关键代码讲解

  1. resolveConversationTrigger:输入 mode 与 provider evidence。缺省保持 addressed;拒绝未知 mode;历史/self 不授权;human_messages 下机器人不授权。输出 mode、authorized、reason,由 adapter 消费,不直接执行任务。
  2. connect_lark_goal_topic:只有 manager 连接接收这个设置,校验发生在连接副作用前;preview 不写入,保存后有真实持久化回读。编辑时旧客户端省略字段会保留已有选择,而不是静默重置它。
  3. decide_manager_event:先检查确切 worker Topic、唯一管家绑定和 self identity,再调用 TS rule。授权之后仍使用既有 session、executor 和 reply path;免 @ 没有授予新的工具权限或委派权限。
  4. LarkSettingsPage:新建默认 @-only,编辑读取已保存值,只给 manager POST 该字段,并明确告知该群所有成员都可发起对话。桌面和手机打包版已实际查看,选项、说明与保存按钮可用。

正向路径:preview → save human_messages → 无 @ 的群成员消息 → TS admission → 既有 manager route。独立真实连接/dispatch 实验还验证了新加入成员被有意覆盖、同一群的 worker Topic 优先、另一群不匹配、self/bot/history 不越界。切回 addressed 后,无 @ 的下一条消息回到 context-only,而 @ 消息可以继续正常推进。原生 runtime 测试还覆盖一次回复/ACK 后重放不会重复回答。

对主干的风险

本地验证:182 项 Python 连接/runtime/API 测试通过(相同 base 命令 181 项通过);2 项新 TS 测试通过;control-plane typecheck、配置内 mypy 19 文件、CI 配置范围 Ruff、dashboard 构建通过;新增浏览器场景在开发版和打包版都通过。独立要求新功能的 dispatch oracle 在 base 明确失败、head 通过,不是仅证明测试可以运行。浏览器的其他 workspace API 使用 fixture;连接持久化、TS rule 和 inbox/ACK 使用真实产品实现,飞书传输和回答执行使用 doubles,没有访问真实群或启动真实模型。

扩大到四个 Python 文件的额外 strict-mypy 探查为 base 67 / head 70 个错误,新增三项都在 conversation_trigger bridge 的参数/Any 返回注解上;这些文件不在当前配置内 19-file mypy gate 中。建议后续在这个小 adapter 上补齐类型,不将它误报为“全部来自主干”,也不把没有功能反例的额外范围诊断当作当前 PR blocker。

语义与 CI 对齐

此处扩展既有 conversation vocabulary,不创造 peer 生命周期。默认 live @/reply route 与 base 相同;新增的 mode/reason 回读是 additive。历史消息在 admission 边界被进一步收紧为 context-only,符合既有 inbox 的历史不入 live attention 契约,不应把它描述成所有字段逐字节不变。已读当前 Python workflow、typed-owner RFC 和受影响的群入口文档;review 按 capability policy 11 使用本地证据,未查询或等待远端 CI。

完整 architecture suite 在 base/head 均为 812 通过、2 失败:test_checked_in_project_registry_io_manifest_is_current 和 test_goal_instance_inventory_does_not_replace_the_registry_io_census 都调用同一个 validator,规范化后的八条具体 I/O 诊断完全相同(签名 7d316a0dd27414ed776745b6005d8b0f8f4d4c51c394c0f6b7e768cfd43601c4),对应的 archive/peer-host/manager-inbox/peers I/O sites 未被本 PR 修改。独立的新功能测试通过,因此这些已存在的失败不改变 review approval;它们需要由原 manifest owner 处理,合并就绪与代码 review 分开判断。

我的整体评价

长期推进方面,明确 admission、继续复用 session/reply/ACK 和可撤销配置,比要求群成员每次手工 @ 更有价值;用户体验方面,新建、编辑、保存与回读形成完整本地交互。未来改动便利性已考虑:规则放在 typed owner、Python 只做 provider adaptation,这个小 seam 足够,无需引入新的编排框架。最强剩余证据缺口是拥有 all-message 权限的真实 Lark 群与真实 executor 的部署验收,它没有被本地 fixture 或 R3 文档更新冒充为已完成。本结论不包含自合并或外部权限变更。

English verdict: APPROVE - the scoped group-trigger increment is locally validated, preserves live default admission, and keeps execution permissions separate.

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Review frame for exact head 3bda6dacce91a3a2cd36c3c79defbe4e3f18cbfb: the accepted comparison is the existing steward group journey and the R3 roadmap boundary, not the author's completion label. This is a per-connection human-message admission increment with local UI/persistence/dispatch validation; provider permission, tool authorization and live executor acceptance remain separate. The published review approves that bounded delta, not all of R3 or merge readiness.

Full exact-head review.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
…gration

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Merge readiness: HOLD

Exact head: 3bda6dacce91a3a2cd36c3c79defbe4e3f18cbfb.

当前原生合并门禁返回 ready=false、merge_state=DIRTY,阻塞原因是 merge_state_requires_update。已发布的完整评审在这个 head 上仍为有效 APPROVE;本条记录当前合并条件,不重复发布完整评审。

本地独立合并预览将这个 head 与刚获取的 main ce3862e33cb9c5b9f416627727fddfd46f9b6a2f 比较,复现 examples/personal-workspace-browser-smoke.mjs 的内容冲突。工作树保持干净,diff hygiene 通过,未修改分支或创建合并提交。请由 PR owner 解决冲突并更新分支;新 head 必须重新执行受影响验证、完整评审及合并门禁,不能继承旧 head 的 approval。

验收边界继续采用已有评审 frame和 R3:这是按连接选择群消息准入的增量;真实群部署、外部工具权限与发信人委派授权仍需独立验收。此次未重跑功能测试,也未查询、轮询或等待远端 CI(配置 wait_for_ci=false);没有将此前测试报告当作本次执行结果。运行和控制面变更保留 maintainer merge 路径,未合并,admin bypass 不能消除冲突或授予 merge authority。

Merge-readiness verdict: HOLD — the exact-head APPROVE remains valid, but native readiness and an independent merge preview both establish a branch conflict. The owner must update the branch, then validate and review the new head before requalification. CI was not consulted; no merge was attempted.

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Updated head: ca8923be8105b3ac40ec1d4ad07b4d4f4812b415.

Addressed the bridge typing suggestion: annotated mode/evidence/result and narrowed the routing readback from one Mapping read. Optional strict-mypy comparison is now base 67 / head 63, with no added diagnostic; configured mypy passes. This retains the TS owner and makes no permission change.

Merged current main and resolved the browser catalog conflict by retaining both the no-mention and conversation-return scenarios. Both relevant packaged scenarios pass; the trigger also passes in source mode. The same 182 focused Python tests, 2 TS tests, typechecks, lint and frontend build pass.

Main's six newly stale census coordinates are refreshed in a separate metadata-only commit; no site or classification changes (250 sites). Census/source-session checks now pass 8/8.

Risk-based premerge passes: five direct checks, 15 selected passes and one inherited maintainability advisory (loopx.status reexports 119 vs ceiling 117). Exact-scope receipt cqr_d3e03a948c26eb12de0f is valid; public-boundary scan clean. No live provider acceptance, deployed update or new-head CI completion is claimed. Prior approval remains evidence for the earlier head; this update awaits renewed review and maintainer merge.

@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Sep 27, 2026
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Head update after the readiness HOLD

#5189 now has head ca8923be8105b3ac40ec1d4ad07b4d4f4812b415 on main ce3862e33cb9c5b9f416627727fddfd46f9b6a2f. The preceding DIRTY/HOLD records the previous head 3bda6dacce91a3a2cd36c3c79defbe4e3f18cbfb; its reproduced conflict must not be attributed to the new head.

更新后的分支已可进行 Git 合并,但原生门禁仍返回 ready=false。旧 head 的 APPROVE 不覆盖新 head;当前 capability 要求 review_pull_request_exact_head,新 head 需要完整评审和验证后再检查合并就绪。本次未将旧评审或旧测试重新标记为新 head 的证据,未查询远端 CI,未合并。

Current disposition: HOLD for a new exact-head review. Git conflict resolution alone does not qualify the new head; the prior approval remains a historical record, and merge authority remains with the maintainer.

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

APPROVE:这是对新 head ca8923be8105b3ac40ec1d4ad07b4d4f4812b415 的完整重新审查,不沿用旧 head 的 approval。没有发现该 head 的阻塞问题。

动机

管家可以保存群聊上下文,却并不等于普通成员的消息能启动回应;用户仍需要反复 @。这个 PR 在现有连接设置里提供可撤销的显式选择,解决本地配置与 admission 的实际缺口。它是 R3 / steward golden queries 的有用增量,不宣称整个在线协作旅程已验收。长期 session、回复和 ACK 的 owner 保持,设置到读回到恢复默认的用户路径完整;真实飞书权限与在线执行器仍需既有部署验收。

改动思路

我先检查是否真的需要新状态。capture_scope=configured_chat_all 在开启和关闭无 @ 回应时都可能相同,无法推导用户是否愿意让整个群的人启动对话。因此 turn_trigger 是真实的用户意图,不是可以从 capture 推导的重复标签。设置页负责可发现的选择,原连接 API/writer 负责验证、预览、保存与读回,通用 TypeScript owner 负责 admission,Lark adapter 只传入身份、寻址和历史证据。工具、委派和受保护操作授权没有因此扩大。不开启时保留 live addressed 路径;历史回放不应作为新请求,文档对此单独披露,不能宣称所有历史输入字节级不变。

具体改动

当前整体 diff 为 21 个文件,新增 273、删除 28 行,包括设置/schema/API、24 行 typed rule、Lark 适配、薄浏览器场景、原生测试和文档。相对上一轮审查,作者整合了 main、补齐桥接类型和现有 routing 快照的 Mapping 收窄,并保留浏览器目录里的 conversation-return-continuity。另更新 registry census 坐标;我独立比较 JSON,除 line/column 外 site 的分类和语义全部保持一致,原生 validator 在该 head 没有诊断。不能把 main 整合带入的其他历史当成当前 PR 的新增功能,也不能只检查最后一处修复就认可整个 head。

关键代码讲解

  • resolveConversationTrigger,行 6:只有 addressed 与 human_messages 两个明确变体;历史、自身消息与 bot 限制先处理,capture 不授予 turn。Python bridge 调用同一 owner,不重新计算政策。
  • connect_lark_goal_topic,行 356:显式保存 manager 的回应方式,预览不写入,编辑时未提供字段保留既有选择。旧连接缺字段使用 addressed,避免升级时自动让整个群启动回应。
  • decide_manager_event,行 104:先按绑定群和身份选择,精确 worker Topic 优先,自身消息排除,再把 provider 证据交给 typed rule;原 session/executor、reply/ACK 路径继续负责执行。
  • LarkSettingsPage,行 174:控件、保存 payload、列表显示和重新编辑读回共同组成用户入口。桌面及窄屏说明明确涉及所有群成员、bot/历史仅作背景,以及飞书收信权限和工具权限的边界。

对主干的风险

最强反例是“群 A 开启后群 B 或 worker 被管家抢走”,以及撤销只改界面而没有恢复执行行为。我使用当前不可变基线 ce3862e33cb9c5b9f416627727fddfd46f9b6a2f 和新 head 的真实连接 writer、读取与 dispatcher,而不是让 mock 返回已经授权的结论。原默认寻址观察一致;head 上预览不写、开启保存、旧客户端省略编辑仍保留、新群成员纳入已明确的群级范围、其他群不匹配、worker 优先、bot/历史不触发、自身忽略、撤销后普通消息仅作背景而 @ 仍能推进均通过。要求无 @ 功能的同一探针在旧基线失败、该 head 通过。

本次亲自重跑 206 条 Python、两条 TS、配置的 Ruff/mypy、control-plane typecheck、dashboard/chat 构建;源码和打包设置场景及打包 conversation-return-continuity 都通过,并检查了桌面/移动截图。浏览器 API 是合成 fixture,真实后端持久化/路由由另一个原生探针验证;没有把 fixture 冒充真实飞书或模型调用,也未读取/等待远端 CI。

语义与 CI 对齐

新增词汇限于会话 admission,不是 peer 生命周期或工具授权;文档与两种模式对应。census 坐标修正保留原语义,两个相关架构文件的九条测试通过。完整架构套件在新 head 上 820 条全部通过;同一命令在 base 为 818 通过、两项 census 失败,完整六条诊断对应已修正的坐标,而不是下调检查或改写分类规则。相关 Python 基线 205 条通过,head 为 206 条;这次默认路径和新增能力均有独立证据。

我的整体评价

长期续接语义保持,群成员发起请求与设置反馈改善;仍是可撤销的本地 admission 增量,而不是在线权限、模型执行或整个 R3 完成。未来方向检查已落实到有边界的改进:一份 typed 决策源、桥接返回类型和 routing 快照收窄;无需再建通用 trigger 框架。保留缺字段默认和省略编辑兼容有真实的持久化连接及旧 API 客户端依据。重新核查整个 diff、原默认路径、作用域反例和新 head 集成后,可以批准;本次只发布 review,不执行自合并。

English verdict: APPROVE — exact head ca8923b. Fresh native persistence/routing, scoped opt-in and revocation, typed checks, and source/packaged UI validation support this bounded increment; live Lark permission and model execution remain unqualified. The prior approval is not inherited and no merge was performed.

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Reviewed frame: a reversible per-manager-connection admission choice, with the existing session/reply/ACK and protected-operation owners preserved. Following the accepted earlier boundary and new-head integration clarification, I independently rechecked the entire current diff, source/packaged settings, persisted routing and registry-census semantics. Exact head: ca8923be8105b3ac40ec1d4ad07b4d4f4812b415; the earlier-head approval is not carried forward. This is not live Lark/model qualification or completion of R3.

Full exact-head review.

@huangruiteng
huangruiteng merged commit 40a6df9 into main Sep 27, 2026
39 of 53 checks passed
@huangruiteng
huangruiteng deleted the codex/steward-experience-refinement branch September 27, 2026 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant