Skip to content

feat: D1 Durable Dana Conversation — restart-resumable ACP agent#27

Open
ngoclam9415 wants to merge 11 commits into
developfrom
feat/acp-agent-session-kernel
Open

feat: D1 Durable Dana Conversation — restart-resumable ACP agent#27
ngoclam9415 wants to merge 11 commits into
developfrom
feat/acp-agent-session-kernel

Conversation

@ngoclam9415

Copy link
Copy Markdown
Contributor

Summary

Dana now streams multi-turn text conversations through dana-acp and automatically resumes the same session after the ACP process restarts. This is the first delivery (D1) of the ACP AgentSession kernel — a Session Journal backed by SQLite/PostgreSQL is the sole durable authority for every turn.

What shipped

Area Files
Journal models dana/core/session/{models,protected_state}.pyOwnerScope, JournalFact, FactType, ProtectedStateCodec (AES-GCM + HKDF + AAD)
DB adapters dana/core/session/journal/{sqlite,postgres,protocol,schema,models}.py — one contract, two real databases, optimistic concurrency
Projections dana/core/session/projections/{conversation,host_events}.py — ConversationView (committed-turn gating) + HostEvent stream
AgentSession dana/core/session/agent_session.py — serialized text turns, streaming seam, bounded flush, crash-safe journaling
Crash recovery + migration dana/core/session/legacy_timeline_migration.py — interrupted-turn detection + idempotent legacy Timeline import
ACP stdio agent dana/apps/acp/initialize, session/new, session/load, session/resume, session/prompt, session/cancel
Health checks dana/core/session/health.py — redacted operational report
Docs Architecture, ACP config, storage/migration/rollback, briefing, changelog

Key invariants

  • Input durability: TURN_STARTED + USER_CONTENT_FINAL appended before the model call
  • One terminal per turn: ASSISTANT_CONTENT_FINAL + terminal in one atomic batch
  • No post-terminal mutation: nothing appended after the terminal fact
  • Same-session concurrency: second prompt while active returns busy
  • Interrupted turns: partial output host-visible but excluded from ConversationView
  • ACP isolation: acp.* imports confined to dana/apps/acp/; STAR core untouched

Test results

  • Session + integration: 210 passed, 16 skipped (PostgreSQL without DSN)
  • Full unit suite: 2087 passed, 0 failures
  • Ruff: clean on all new code

Dependencies added

  • agent-client-protocol>=0.10,<0.11
  • aiosqlite>=0.20.0
  • asyncpg>=0.30.0

What's NOT changed

  • dana-code, adana, dana-repl CLIs remain on legacy Timeline (incremental migration)
  • Existing STARAgent.query() / aquery() source-compatible
  • Tools, permissions, model switching, MCP, attachments — deferred to D2–D6

Console companion PR

Branch feat/acp-agent-session-restart in dana-console adds sessionStorage session-ID persistence + session/load resume on reconnect.

Design spec

Approved at docs/superpowers/specs/2026-07-07-acp-star-adapter-design.md.

Add DanaACPAgent implementing the ACP Agent protocol over stdio JSON-RPC,
enabling dana-console to connect to Dana as a Custom ACP Agent.

- dana/apps/acp/agent.py: DanaACPAgent translating ACP calls (initialize,
  session/new, session/load, session/resume, session/prompt, session/cancel)
  to AgentSession operations, streaming HostEvents back as session_update
  notifications
- dana/apps/acp/translation.py: HostEvent → ACP update chunk translation
  (ACP types never enter STAR core)
- dana/apps/acp/__main__.py: entry point with stderr-only logging
- dana/__init__/init_environment.py: redirect structlog to stderr so stdout
  stays clean for JSON-RPC frames
- pyproject.toml: dana-acp console script entry point
- tests/integration/test_acp_agent.py: 14 in-process + subprocess tests
  covering load capability, replay-before-return, chunk streaming, burst
  ordering, busy, cancel, malformed content, stderr/stdout discipline
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