Skip to content

Integrate session ownership and state routing / 集成会话归属与状态路由#4250

Merged
esengine merged 1 commit into
esengine:main-v2from
SivanCola:fix/integrate-session-ownership
Jun 13, 2026
Merged

Integrate session ownership and state routing / 集成会话归属与状态路由#4250
esengine merged 1 commit into
esengine:main-v2from
SivanCola:fix/integrate-session-ownership

Conversation

@SivanCola

Copy link
Copy Markdown
Collaborator

Summary

This maintainer integration PR uses #4215 as the foundation and folds in compatible state-routing fixes from #4073 and #3935.

The combined change keeps session-owned runtime state aligned across Desktop and controller paths:

  • Scope subagent transcripts and background jobs to the owning parent session.
  • Prevent background job output, lifecycle notices, completion notes, and kill/wait/output operations from crossing session boundaries.
  • Cancel and suppress late writeback when a session is cleared, deleted, or moved to trash.
  • Route memory storage and the Desktop memory panel through the correct global/workspace scope.
  • Preserve approved plan execution across pause/resume while coexisting with the session-scoped controller lifecycle.

Credits / Attribution

This integration PR builds on prior contributor work:

Not included in this integration PR:

Verification

  • gofmt -l $(git diff --name-only origin/main-v2...HEAD -- '*.go') produced no output
  • git diff --check origin/main-v2...HEAD passed
  • go test ./internal/jobs ./internal/control ./internal/agent ./internal/boot ./internal/tool/builtin ./internal/memory passed
  • go test ./... passed
  • go test ./... in desktop/ passed
  • go vet ./... passed
  • go vet ./... in desktop/ passed
  • pnpm --dir desktop/frontend check:css passed
  • pnpm --dir desktop/frontend typecheck passed after generating Wails bindings with Wails 2.12.0
  • pnpm --dir desktop/frontend build passed after generating Wails bindings with Wails 2.12.0

Integrates the session ownership foundation from PR esengine#4215 and compatible state-routing fixes from PR esengine#4073 and PR esengine#3935. Contributor attribution and verification details are documented in the pull request body.
@github-actions github-actions Bot added v2 Go rewrite (1.x) — main-v2 branch, active development desktop Wails desktop app (desktop/**) skills Skill system (internal/skill, internal/tool) agent Core agent loop (internal/agent, internal/control) config Configuration & setup (internal/config) labels Jun 13, 2026
@SivanCola SivanCola marked this pull request as ready for review June 13, 2026 05:19
@SivanCola SivanCola requested a review from esengine as a code owner June 13, 2026 05:20
@SivanCola SivanCola enabled auto-merge June 13, 2026 05:37

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c4aa0fd84

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/memory/store.go
Comment on lines +2977 to +2981
for i := len(msgs) - 1; i >= start; i-- {
for j := len(msgs[i].ToolCalls) - 1; j >= 0; j-- {
tc := msgs[i].ToolCalls[j]
if tc.Name == "todo_write" {
return tc.Arguments, true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Account for complete_step when ending approval bypass

When an approved plan follows the documented workflow (an initial todo_write followed by complete_step sign-offs, with no final todo_write), this scan keeps returning the initial incomplete todo list; the host-advanced state from complete_step is recorded in the agent ledger/events rather than as a todo_write in Session().Messages. That leaves approvedPlanActive true after the plan is actually complete, so a later user message such as “continue” can still bypass writer approvals for work no longer covered by the approved plan.

Useful? React with 👍 / 👎.

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.

This path was already addressed on main-v2 by #4266, which removed the phrase-matched approved-plan continuation state that kept the bypass active. #4273 leaves that controller path unchanged and re-runs go test ./internal/control -run TestApprovedPlan for coverage.

Comment thread internal/jobs/jobs.go
Comment on lines +1081 to +1082
value={selectedTabId ?? ""}
onChange={(e) => setSelectedTabId(e.target.value || null)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Scope suggestions to the selected memory tab

This selector is also shown on the Suggestions subtab, but refreshSuggestions, AcceptMemorySuggestion, and AcceptSkillSuggestion still call the active-tab APIs. When the user selects a non-active project here and generates or accepts a suggestion, the candidate is based on and written to the active project instead, while the panel reloads the selected project and makes the save appear to disappear.

Useful? React with 👍 / 👎.

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.

Addressed in #4273 with tab-scoped MemorySuggestionsForTab, AcceptMemorySuggestionForTab, and AcceptSkillSuggestionForTab APIs, plus frontend routing from the selected Memory panel tab. Covered by TestMemorySuggestionsForTabUsesSelectedTab.

Comment thread internal/memory/store.go
Comment on lines 198 to +201
if err := os.WriteFile(path, []byte(render(m, name)), 0o644); err != nil {
return "", err
}
if err := s.reindex(name, m); err != nil {
if err := reindexIn(dir, name, m); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Remove stale copies when a memory changes scope

If a saved memory already exists in the other directory and is updated with the same name but a type routed to this dir (for example a global user memory is later saved as project), this write leaves the old copy and its index line behind. Because Index, List, and Path read GlobalDir first and dedupe by name, the stale global copy continues to be shown and read, so the apparent overwrite silently does not take effect.

Useful? React with 👍 / 👎.

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.

Addressed in #4273 by archiving/removing stale active copies from the other memory scope after saving the new scoped copy, and by flushing the old scope index. Covered by TestStoreSaveRemovesStaleCopyWhenScopeChanges.

@esengine esengine merged commit b99e893 into esengine:main-v2 Jun 13, 2026
14 checks passed
@esengine

Copy link
Copy Markdown
Owner

Merged after a full read + local verification (root build/vet/staticcheck/tests clean; desktop build/vet/tests pass aside from two failures that reproduce identically on main-v2 — a Windows TempDir cleanup flake and a test picking up a real ~/.agents/skills on the dev box, neither a regression and neither present on Linux CI). The session-scoping, destroy-window/late-writeback suppression, and memory global/project routing all hold up, and the approved-plan marker + job notes correctly ride the turn text rather than the cache-stable prefix.

Two non-blocking observations left as-is, flagged for the record rather than changed here since they're judgment calls:

  1. isApprovedPlanContinuation is an exact-phrase whitelist (继续 / continue / proceed / …). It's a small intent heuristic, which we've generally moved away from. The failure mode is safe — a non-match just falls back to per-tool approval and deny rules still bite — so the blast radius is bounded to one turn of an already-approved plan. Leaving it; worth revisiting if the phrase set starts drifting.
  2. Store.Index() now merges global+project and sorts by stem. For existing users this shifts the cached system-prefix once (insertion order → alphabetical, plus any global memories folded in) and drops non-index lines from MEMORY.md. One-time, deterministic thereafter — fine, just noting the one-time cache turnover.

Tiny lint nit the new desktop test introduced (emitReady(nil) → SA1012) cleaned up in #4263.

esengine added a commit that referenced this pull request Jun 13, 2026
emitReady returns before touching ctx when a readyHook is set, so the
test behaves identically — this only silences staticcheck SA1012 (do not
pass a nil Context). Follow-up to #4250, which added the test.
esengine added a commit that referenced this pull request Jun 13, 2026
)

#4250 carried an approved plan's writer auto-approval across a user pause
when the next turn matched a fixed phrase whitelist (继续 / continue / …).
That is the brittle intent-detection the project removed elsewhere, and a
false positive silently widens auto-approval. Auto-approval now covers the
execution turn only; any later turn — including "continue" — returns to the
normal per-tool approval posture (ask/auto/yolo still govern it). The plan
still seeds todos and avoids clobbering the model's own todo_write.

Removes approvedPlanActive/approvedPlanContinuationTurn, the execution
marker, and isApprovedPlanContinuation.
esengine pushed a commit that referenced this pull request Jun 13, 2026
Follow-up to #4250: flush stale MEMORY.md entries when the active file is absent, archive the old active copy + stale index line on cross-scope save, wait on already-killed-but-unwinding jobs in DestroySession, and route memory suggestion generation/acceptance through the selected Memory panel tab. Each fix has a regression test.

Co-authored-by: lifu963 <56394323+lifu963@users.noreply.github.com>
Co-authored-by: ashishexee <144021866+ashishexee@users.noreply.github.com>
Co-authored-by: AresNing <49557311+AresNing@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Core agent loop (internal/agent, internal/control) config Configuration & setup (internal/config) desktop Wails desktop app (desktop/**) skills Skill system (internal/skill, internal/tool) v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants