Skip to content

feat: emit session recovery events - #107

Merged
divo12 merged 43 commits into
mainfrom
feat/session-recovery-events
Aug 16, 2026
Merged

divo12 merged 43 commits into
mainfrom
feat/session-recovery-events

Conversation

@divo12

@divo12 divo12 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

User description

Summary

  • emit role.session.recovered when Dream resets or bypasses an unreadable persisted role session
  • distinguish the active session_id from the failed requested_session_id
  • render the recovery in the stdio observer without changing existing fallback behavior

Tests

  • pytest tests/test_runner/test_role_session_resume.py tests/test_runner/test_observer.py -q
  • ruff check src/dream/runner/_role_session.py src/dream/runner/_observer.py tests/test_runner/test_role_session_resume.py tests/test_runner/test_observer.py
  • mypy src/dream/runner/_role_session.py src/dream/runner/_observer.py
  • full pytest -q with the venv on PATH

Notes

  • TDD: reset and workspace-bypass observer cases were added before implementation
  • independent review finding about session correlation/order was addressed before publication
  • no new Any annotations

CodeAnt-AI Description

Report when a role session is recovered after a resume failure

What Changed

  • Emits a recovery event when a corrupt session is reset or a session from another workspace is bypassed
  • Includes the affected session, failure reason, recovery action, and whether the saved snapshot was preserved
  • Displays recovery details in the standard output observer between session open and close messages
  • Keeps corrupted sessions resumable under the same ID while protecting snapshots owned by another workspace

Impact

✅ Clearer session recovery status
✅ Fewer stranded role sessions
✅ Protected cross-workspace session history

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@codeant-ai

codeant-ai Bot commented Aug 9, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR 1bdd915 Aug 09, 2026 · 14:08 14:10

@codeant-ai

codeant-ai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@greptile-apps greptile-apps 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.

divo12 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Aug 9, 2026
Comment thread src/dream/runner/_role_session.py Outdated

@greptile-apps greptile-apps 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.

divo12 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps 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.

divo12 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@greptile-apps greptile-apps 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.

divo12 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

divo12 and others added 15 commits August 10, 2026 12:41
Address CodeAnt: the return contract includes evaluation, with explicit
None when the evaluator is disabled.

Co-authored-by: Cursor <cursoragent@cursor.com>
feat(context): expose typed evaluator carryover and hook roles
Move planner/generator/evaluator protocol into packaged standing orders
selected by session role; load employee craft from .harness/AGENTS.md in
the context tier; slim head intents to data envelopes.

Co-authored-by: Cursor <cursoragent@cursor.com>
Omit packaged standing orders when a role manifest requests replace so
subagent isolation and custom roles keep their contract.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep gen/eval user turns as data-only beat packets, share format_sprint_beat,
retire oracle into verification, align planner SO with read-only tools, harden
ask_until_parsed for session reuse, and surface retry/skip/escalate in StdioObserver.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace dict[str, Any] observer payloads with frozen event classes, merge
tiny modules into a readable layout, and drop getattr/setattr colour hacks.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop event.kind / content_preview / usage_from_event, store typed
handoff artefacts, bare-JSON evaluator parse, and collapse thin prompt
block wrappers. Net ~270 lines shorter.

Co-authored-by: Cursor <cursoragent@cursor.com>
Evaluator verifies in-session via bash; run_oracle had no production
callers. Keep run_verification as the real shell runner.

Co-authored-by: Cursor <cursoragent@cursor.com>
Evaluator verifies in-session via bash; the Spec 12c runner/report/UI
seam and tech-debt filer had no production callers.

Co-authored-by: Cursor <cursoragent@cursor.com>
List available subagents in the system-prompt brief like skills. Keep
spawn_subagent wire schema as a typed enum only; spawn usage policy moves
into Dream standing orders.

Co-authored-by: Cursor <cursoragent@cursor.com>
Wire ToolCatalogue from the same role-filtered tool set as the request
tools array (builtin, per-repo, MCP) so the brief matches the callable
surface. Schemas stay on the provider wire.

Co-authored-by: Cursor <cursoragent@cursor.com>
Split tool brief into Tool definitions vs MCP & dynamic tools by
ToolSource; rename Skills and Subagent definitions headers. Park
deferred load_tool wire work for a follow-up PR.

Co-authored-by: Cursor <cursoragent@cursor.com>
… green)

- dream.runner now re-exports UsageMeter so Chorus's
  dream_beat.py import keeps working after _usage.py removal
- remove worktree_root passthrough that make_evaluator_head no longer accepts
- merge split observe import in test (ruff I001)
feat(prompts): centralize cache-stable session prompt assembly
divo12 and others added 22 commits August 11, 2026 19:58
Add dream.context.breakdown with Hermes-compatible categories and
Session.context_breakdown() for a future REPL /context command.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bound skills/memory sections, read system prompt and tools from the
engine contract, and use the shared 200k window fallback.

Co-authored-by: Cursor <cursoragent@cursor.com>
…text

Rewrite the context breakdown to consume typed objects end-to-end instead
of re-parsing the raw provider wire:

- Introduce PromptSurfaces (StablePromptBlock / ContextPromptBlock / role
  instructions / AdvertisedTool tuple) held on the QueryEngine; the engine
  no longer needs a raw system_prompt string plus tools_wire dicts.
- AdvertisedTool carries a token estimate of its own OpenAI tools wire
  entry plus ToolSource provenance, so MCP tools split out without name
  sniffing; only subagent-named builtins need the small name set.
- compute_context_breakdown reads the typed prompt blocks and delegates
  transcript tokenization to estimate_conversation_tokens (shared with the
  compactor), splitting [Compaction summary...] messages into their own
  bucket. No Any, dicts, getattr, or regex over rendered text.
- Build the typed surfaces once in _build_session_engine (replacing the
  private _assemble_system_prompt string-only helper) and render the same
  string the streamer needs from them.
- session.context_breakdown() now returns ContextBreakdown | None straight
  off the engine's prompt_surfaces (no getattr), and tests exercise the
  typed API with a real compaction-summary conversation.
feat(context): Cursor-style context breakdown pie
Rebase onto main (keep #112 context breakdown). Drop the PR's
reimplemented context pie and getattr session wiring. Apply ≤4
ephemeral breakpoints via frozen OpenAIChatMessage envelopes when
ProviderCapabilities.prompt_cache is set.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace to_wire dict helpers with OpenAIChatMessage.to_json_object /
encode_openai_messages at the HTTP boundary only.

Co-authored-by: Cursor <cursoragent@cursor.com>
Compaction shares Dream-owned common standing orders via
CompactionPromptParts / OpenAIChatMessage envelopes (workspace context
stays on the user message). Stacked on cleaned #113; no context pie
reimplementation.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop unused JsonValue alias, move assistant tool_calls wire encoding
into the OpenAI adapter, and inline message JSON at call sites.

Co-authored-by: Cursor <cursoragent@cursor.com>
Narrow OpenAIChatMessage list before apply_cache_control and align
httpx stream callable message param with StreamChatCompletion.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use live stable_block.render() for compact cache prefix alignment,
restrict workspace context to skill/memory catalogues only, add typed
OpenAIAssistantToolMessage wire types, CompactionChatRequest, and
validate summariser JSON payloads before parsing.

Co-authored-by: Cursor <cursoragent@cursor.com>
feat(compact): reuse stable+context assembler prefix
feat(prompts): Hermes-style cache_control + stable tool prefix
Ship explore/plan/verify builtins, wire model/overlay/spawned_by/isolation on
the live path, add delegation poll/stop for background spawns, and keep sync
as the beat default with a host tool blocklist.

Co-authored-by: Cursor <cursoragent@cursor.com>
Scope asynchronous delegation to its owning session and make overlays and worktree execution fail closed so the lean subagent catalog is safe to expose.

Co-authored-by: Cursor <cursoragent@cursor.com>
feat(subagents): lean Hermes+Claude catalog with wired isolation
Carry typed tool result metadata through RunTaskObserver so downstream adapters can consume structured evidence without parsing text.

Co-authored-by: Cursor <cursoragent@cursor.com>
fix(runner): preserve structured tool results in events
Seal session and trace JSON into public typed immutable values so control-plane readers cannot mutate captured execution state.

Co-authored-by: Cursor <cursoragent@cursor.com>
feat(observability): expose immutable runtime snapshots
Preserve snapshot truth across resume races and expose recovery actions without allowing observers to control session lifecycle.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the reviewed current-main implementation while joining the original PR branch without rewriting remote history.
@greptile-apps

greptile-apps Bot commented Aug 16, 2026

Copy link
Copy Markdown

Too many files changed for review (128 files, 100 file limit).

Bypass the limit by tagging @greptile-apps to review.

@codeant-ai

codeant-ai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Skipping CodeAnt AI review — this PR changes more than 100 files, which usually means a migration, codemod, or vendored drop. Line-level review on diffs this large produces duplicate findings on the same rewrite pattern and drowns out anything that actually matters.

If you still want a review, comment @codeant-ai : review. For better signal, consider splitting the PR into smaller chunks.

@divo12
divo12 merged commit be642b1 into main Aug 16, 2026
4 checks passed
@divo12
divo12 deleted the feat/session-recovery-events branch August 16, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant