fix(desktop): create bot sessions without invalid explore-at-create - #4040
fix(desktop): create bot sessions without invalid explore-at-create#4040ennian001 wants to merge 3 commits into
Conversation
Bot incoming adapters passed permissionMode=explore at session create time, but Runtime Host rejects explore without a declared SessionStartMode. Pin explore after create via updateSessionConfiguration instead. Generated-by: Cursor Co-authored-by: Cursor <cursoragent@cursor.com>
|
This is a synthesis of the independent blind review by @Sol-404ARE at exact head What I checked myself:
Findings from Sol's review (file:line anchored, durability defect shared across axes but counted per-axis): Standards — NO-GO — 2×P2 + 1×P3 (worst P2)
Spec — NO-GO — 1×P2 (worst P2)
The Standards durability P2 and Spec P2 are the same underlying defect viewed through the two axes — each count is preserved per Sol's seal. What was proven green: the happy-path fix is correct (create omits invalid explore-at-create and a successful update correctly pins explore); normal revision conflicts are retried; deep-research mode is intentionally not appropriate here. What I did not judge: a full Gate: Standards 2×P2 + Spec 1×P2 remain;
|
… Sessions The post-create permission update now verifies commit_outcome_unknown against the stable Session id instead of rethrowing blind: a lost response that did pin explore binds the existing Session, while a definite failure (or an unverified outcome) archives the unbound default-ask Session so the next inbound message cannot fork a sibling conversation. Also re-encodes the PR screenshot as actual PNG data to match its extension.
|
Thanks for the detailed review. All three findings are addressed in 23c6e66:
Local verification at 23c6e66: |
Astro-Han
left a comment
There was a problem hiding this comment.
Reviewed at exact head 23c6e6635e0292b1ad0e0e1c8e215535c0cc8c6f. Approving with comments (P2/P3 only).
The follow-up fixes the prior first-message leak. Create omits permissionMode: 'explore' (Host prepareCreate only rejects explicit explore-without-mode). The pin uses the same session.configuration.update as prepareSession. On pin commit_outcome_unknown, getSession on the stable id binds only a non-archived explore projection; otherwise the unbound default-ask Session is archived and the error is rethrown. Inbound botConversationSessions.set runs only after createSession resolves, and same-conversation traffic is queued, so a throw does not bind and cannot race a sibling create.
[P2] Create-unknown reconcile does not mirror this pin path: getSession(sessionId) in the create catch has no .catch, and a failed catalog read does not abandonUnusableBotSession. After this PR, a successful create is Host-default (typically ask). If that create committed and the follow-up get throws (persistence_failed / catalog_unstable), the ask row leaks and the next inbound IM mints another Session.
[P3] Tests still skip the production create-unknown → ask → pin sequence (the existing reconcile case stubs getSession as already-explore, so the pin branch is never entered). Also uncovered: pin-unknown getSession throw, update committed but still ask, inbound create throw leaving the conversation map empty.
Kicking CI on this SHA separately (fork action_required gate).
| // stable id before deciding the Session is unusable — otherwise the | ||
| // next inbound message forks another conversation. | ||
| const reconciled = isCommitOutcomeUnknown(error) | ||
| ? await deps.client.getSession(session.id).catch(() => null) |
There was a problem hiding this comment.
[P2] This is the right pin-unknown pattern. The create-unknown getSession(sessionId) a few lines above does not mirror it (no .catch, no abandon). After this PR that create is Host-default ask, so a catalog-read throw leaks an unbound ask row and the next inbound IM mints a sibling. Please use getSession(...).catch(() => null) and abandon if it is not verified explore, then rethrow the original error.
…ion pin The candidate connection harness never implemented session.configuration.update, so after the bot adapter began pinning explore post-create, the Host-backed Bot turn test died on the unexpected-operation guard and hung awaiting turnStarted until the CI runner timeout (882s). Commit the explore pin like the real Host would; the suite is back to 19/19 in ~300ms.
|
Follow-up for the CI failure on 23c6e66: Root cause: that suite's connection harness never implemented Fix in cedc98f: the harness now commits the explore pin ( |
Summary
English: IM bot conversations (Feishu/Lark and other platforms) failed on the first inbound message. The bot adapter created sessions with
permissionMode: 'explore'at create time, but Runtime Host rejects explore unless a declaredSessionStartMode(e.g.deep_research) is also provided. Session creation failed; users only saw the sanitized Feishu reply: “Maka 暂时无法处理这条消息:机器人对话处理失败”.This PR creates bot sessions with the Host default permission mode, then pins
exploreviaupdateSessionConfiguration—the same pathprepareSessionalready uses for existing bindings.中文: IM 机器人(飞书/Lark 等)在收到第一条消息时会失败。Bot 适配器在 创建 Session 时直接传了
permissionMode: 'explore',但 Runtime Host 规定:创建时若要用explore,必须同时声明SessionStartMode(如deep_research)。Bot 对话不属于该模式,因此创建被拒;飞书侧只看到脱敏后的 「Maka 暂时无法处理这条消息:机器人对话处理失败」。本 PR 改为:先用 Host 默认权限创建 Session,再通过
updateSessionConfiguration切到explore(与已有会话的prepareSession路径一致)。Reproduction / 复现步骤
Before / 修复前
npm run dev).hi).Symptom / 现象
Also in repo:
docs/images/pr/bot-feishu-explore-session-create/feishu-bot-dialogue-failed.pngRoot cause / 根因
runtime-host-bot-session-adapter.tspassedpermissionMode: 'explore'tocreateSession. Host rule insession-catalog-coordinator.ts:After / 修复后
Same steps → bot session is created, explore mode is applied post-create, turn proceeds and Feishu receives the agent reply.
Verification
npm ci npm run build node --test apps/desktop/dist/main/__tests__/runtime-host-bot-session-adapter.test.js \ apps/desktop/dist/main/__tests__/bot-incoming-session-lifecycle.test.jsResult: 13/13 tests passed locally (10 at the original head; 3 added by the follow-up commit covering the explore-pin reconciliation and abandonment paths).
Did not run full
npm test(large monorepo suite); focused on bot adapter + lifecycle tests that cover this path.AI use
Tool(s) and scope: Cursor — bug diagnosis from local repro, patch, test update, PR text, and reproduction screenshot packaging.
Checklist
npm run build)Does this PR entail a change in behavior?
Made with Cursor