Repository navigation
fix(chat): honor the configured steward across default entrypoints - #8677
huangruiteng wants to merge 1 commit into
Conversation
Signed-off-by: huangruiteng <huangrt01@163.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
评审提交 f8287cd。GitHub 目标与 merge base 为 eba8a7f,本轮读取的最新主干 7bb1b01 未改动这组变更路径。
[P2] 关闭与打开并发时,默认入口把已关闭会话报为恢复成功。 默认 manager POST 刚完成所选来源核验时,另一请求用现有 DELETE 入口关闭该空闲 Session,再让 POST 继续读取。 DELETE 已成功,候选仍返回 HTTP 200、resumed=true、status=closed、resumable=false。随后的发现 GET 返回 409,新的默认 POST 返回 400。 问题位置
动机 / Motivation
已把飞书原管家设为默认入口,想在 App 或本机 API 继续同一段对话的用户。 在基线,App 会继续飞书里的原记录,但走默认本机接口会打开另一段对话。本人登录失效时,界面只给出通用的不可用提示。 候选在正常情况下让两个入口打开同一个已验证的原会话。登录缺失时显示同一应用的重新登录指引,恢复后按重试即可回到原记录。 打包 Chat 使用合成身份和真实本地 HTTP、Core 与隔离 SQLite。实际飞书 OAuth、已安装 App 和独立概览交互仍待对应入口验证。
改动思路 / Approach
Core 仍拥有显式来源选择和原 Session 的授权。Python HTTP 接入复用该结果,前端展示登录原因和恢复路径。 沿用已核验的绑定会话结果,收拢候选新增的第二次读取,使两个默认入口共享同一可用性结论。 所选来源稳定时,默认 POST 可直接复用原 Session。发现失败时仍由原设置和重试入口处理。 绑定解析器
具体改动 / Changes
关键代码讲解
默认 POST 在 open_chat_session 中取得绑定与 Session ID,随后重读该 Session。这个新分支只判空。飞书适配器在应用身份已验证但本人登录缺失时发出类型化错误,GET 用 error_code 把原因交给两个页面入口。 默认打开 登录错误投影 前端读取
按 docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md 在 eba8a7f 的既有约束,原会话可用性仍有上述缺口。默认入口隔离已通过基线和候选的对照。登录恢复在打包页面验证通过。 已接受的验收依据
对主干的风险 / Risks
基线发现入口认得所选原会话,默认 manager POST 仍继续本机管家。 在同一套隔离 HTTP fixture 中,未选来源时两版都正常创建本机 Session。候选正常打开原 Session 时返回 ready。仅在实际关闭夹在两次读取间时,已关闭对象才被成功返回。 让默认入口从既有绑定解析器返回同一份经过校验的可用 Session,并在返回前拒绝已关闭或身份、选择已变化的结果。 扩展现有 HTTP/Core smoke,在发现和返回之间并发关闭原 Session,断言默认入口拒绝且保留历史,再核正常打开、恢复和显式清除。
语义与 CI 对齐
Chat 构建、现有 app-steward HTTP smoke、95 项身份与来源定向测试和独立浏览器重试通过。Standard premerge 六项直接检查、13 项选中检查均通过。 托管 CI 未查询。
我的整体评价 / Verdict
请求修改。默认入口复用正确,先把一次解析和成功返回之间的 Session 可用性对齐。 1200 × 900 和 390 × 900 的登录提示、重试和设置入口均在首屏,发送控件隐藏。重试回到含 14 条中英混合消息的原会话,两种宽度下正文可换行,输入区保留在下方。 打包 Chat 使用合成身份和真实本地 HTTP、Core 与隔离 SQLite。实际飞书 OAuth、已安装 App 和独立概览交互仍待对应入口验证。
English verdict: REQUEST_CHANGES. On f8287cd, the default manager POST can return resumed=true for a Session that the public close route has already closed.
| if target["binding_id"] is not None: | ||
| if mode != "resume_latest": | ||
| raise ValueError("Continue the selected original steward conversation; start a new conversation from its original source.") | ||
| session = controller.store.load_session(target["session_id"]) |
There was a problem hiding this comment.
[P2] 关闭与打开并发时,默认入口把已关闭会话报为恢复成功。 默认 manager POST 刚完成所选来源核验时,另一请求用现有 DELETE 入口关闭该空闲 Session,再让 POST 继续读取。 DELETE 已成功,候选仍返回 HTTP 200、resumed=true、status=closed、resumable=false。随后的发现 GET 返回 409,新的默认 POST 返回 400。 让默认入口从既有绑定解析器返回同一份经过校验的可用 Session,并在返回前拒绝已关闭或身份、选择已变化的结果。 扩展现有 HTTP/Core smoke,在发现和返回之间并发关闭原 Session,断言默认入口拒绝且保留历史,再核正常打开、恢复和显式清除。
Goal And Delivered Outcome
配置飞书原管家作为 App 默认来源后,前端会遵守选择,但直接调用
POST /api/chat/sessions的 manager 入口仍会打开独立本机管家。另一个问题是:机器人身份正常、本人登录缺失时,界面只报“会话不可用”,无法指出恢复步骤。本改动让默认 API 入口复用现有 Core 选择与原 Session。来源不可用时拒绝创建替代会话;新会话或不同模型的覆盖也不能绕过所选来源。本人登录缺失通过具体错误投影到聊天入口和概览输入框,恢复登录后继续原会话。已明确指定的历史 Session、未选择来源的本机入口及群授权规则保持原有边界。
app-conversation-and-async-inbox-v0original-conversation contract.mainateba8a7f95f54fe09cb3dcc28bb1f55443898bbed.Author Declaration
docs/architecture/rfcs/app-conversation-and-async-inbox-v0.mdat the base above; bilingual clarification included.open_chat_sessionreusesapp_steward_target; real HTTP/Core smokeScope And Continuation
Complete for default-entry consistency and actionable owner-login reporting. Account authorization remains with the original owner; this PR does not add an OAuth UI or migrate historical local conversations. No automatic selection among multiple configured stewards is introduced. The existing explicit App source configuration remains authoritative.
Bounded refactoring: reuse the existing typed source resolver and share the two UI failure messages. The provider error is an HTTP presentation distinction, not a new authorization state or a second decision owner.
Validation
f8287cd14f(same source bytes tested before commit).npm run smoke:app-steward: real HTTP/Core and isolated SQLite; default API reuse, owner-login recovery, stale/revoked source refusal, override refusal, explicit clear, no new model worknpm run build:chatincluding TypeScript; Ruff, diff check, bilingual RFC gateuv run --extra test python -m mypy: the sameno-any-returnat unchangedloopx/capabilities/decision_context/runtime.py:207reproduces on both baseeba8a7f95fand headf8287cd14f. CIkernel-contractsis therefore not green; no waiver or merge readiness is claimed.The first smoke attempt lacked the built Chat bundle; after building, a test incorrectly expected an existing local manager in a fixture that had none. Corrected that fixture expectation; the final smoke passed. Production provider delivery and OAuth are not established by these synthetic tests. No PostgreSQL or authority-store semantics change.
Frontend / Visual Evidence
UI impact: changed. The primary question is why a configured conversation cannot open. The existing recovery layout now gives the exact owner-login cause and preserves retry/settings actions; no new panels or repeated help blocks. The recovered transcript remains in its original bound route.
All attachments use synthetic state. Before: packaged
185e1e34ccgeneric source failure (same pre-change entry UI as main). After: packagedf8287cd14fowner-login failure, desktop and narrow. Existing layout and controls remain; no public live-data capture is included.Before
After
Type of Change
LoopX Area
Shared-authority RFC fixture impact
N/A: reuses the existing Core resolver; no storage promotion or new authority semantics.
Boundary Checklist