feat: phase3 sub-project 7 — agent protocol + sqlite storage#175
Open
blove wants to merge 28 commits into
Open
feat: phase3 sub-project 7 — agent protocol + sqlite storage#175blove wants to merge 28 commits into
blove wants to merge 28 commits into
Conversation
Spec for AP-compatible HTTP endpoints + Dawn-native SQLite checkpointer. Single @dawn-ai/sqlite-storage package using node:sqlite directly. One SQLite per concern: checkpoints.sqlite + threads.sqlite + existing permissions.json. Replaces ad-hoc /runs/stream with thread-keyed AP shape. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
16 tasks covering @dawn-ai/sqlite-storage package, agent-adapter rewiring, AP HTTP routes, chat-example proxy updates, harness packing, and restart-persistence integration test. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements getTuple, list, put, putWrites, and deleteThread against node:sqlite via the existing openDb/runMigrations infrastructure. Adds @langchain/core as peer+devDep so RunnableConfig resolves at compile time. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tics Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds optional BaseCheckpointSaver + ThreadsStore fields so applications can inject custom persistence. CLI runtime instantiates sqlite-backed defaults when these are unset (T10). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove the module-level MemorySaver singleton from agent-adapter and require callers to supply a BaseCheckpointSaver via AgentOptions.checkpointer (and materializeAgentGraph options). Tests supply new MemorySaver() explicitly, keeping the "tests own their dependencies" pattern intact. T10 will wire the SQLite-backed checkpointer from the CLI runtime. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire @dawn-ai/sqlite-storage into execute-route: prepareRouteExecution now loads dawn.config and creates sqliteCheckpointer (checkpoints.sqlite) and createThreadsStore (threads.sqlite) under .dawn/ by default, or uses user-provided values from dawn.config. The checkpointer is passed to every executeAgent/streamAgent call site. A new resolveThreadsStore() helper is exported so the HTTP server layer (T11+) can obtain the same store. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace ad-hoc /runs/stream and /runs/wait routes with thread-keyed Agent Protocol routes: POST/GET/DELETE /threads/:id, POST /threads/:id/runs/stream and /threads/:id/runs/wait (SSE + blocking), GET /threads/:id/state (checkpoint read), POST /threads/:id/resume (interrupt resolution). Adds resolveCheckpointer + invokeResolvedRoute exports to execute-route.ts and threads-store lifecycle (busy/idle) around each run. Updates dev-command tests to the new AP shape. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update /api/chat to POST to /threads/:thread_id/runs/stream with the new AP body shape (input + route). The permission-resume proxy already targets /threads/:thread_id/resume and required no changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add @dawn-ai/sqlite-storage to all packing manifests and dependency- rewrite blocks so the verification harnesses can install it from a local tarball rather than the (unpublished) npm registry. Also add as a direct dependency (not just pnpm.overrides) because pnpm cannot apply overrides for packages that have never been published to the registry — it requires a metadata lookup to succeed first. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update execute-route-server.ts and test harnesses to use the thread-keyed
AP URL shape (POST /threads/:id/runs/wait with {input, route} body) that
replaced the legacy /runs/wait endpoint in T11+T12. Suppress Node's
node:sqlite ExperimentalWarning in spawned child processes via
NODE_NO_WARNINGS=1 so non-empty stderr no longer trips the harness's
stderr-clean check.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds test/runtime/run-agent-protocol.test.ts which proves that LangGraph checkpoint state written via POST /threads/:id/runs/wait survives a Dawn dev-server kill and restart on a fresh port, by reading GET /threads/:id/state from the new process and asserting that messages and config.configurable match the pre-restart capture. The echo-agent overlay is a zero-LLM LangGraph StateGraph compiled against the same .dawn/checkpoints.sqlite path that Dawn uses; no real model calls are made. The vitest.config.ts include list is updated to run both runtime test files under pnpm test:runtime. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-fix from biome after T11+T12 AP route updates. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Fake agent servers in run-command + test-command match /threads/:id/runs/wait
- run-command body assertion updated to {input, route} shape
- typegen-command packs @dawn-ai/sqlite-storage tarball
- check + typegen subprocesses set NODE_NO_WARNINGS=1 to silence
node:sqlite experimental warning
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…d resume input
- Remove the resume loop from streamFromRunnable; after yielding interrupt
envelopes the stream returns cleanly (no Promise parking)
- Handle Command({resume}) input directly in streamAgent — passed verbatim
to streamEvents instead of wrapped in {messages:[...]}
- Remove imports/exports of pending-interrupts from agent-adapter and index
- Add DAWN_DEBUG_INTERRUPTS=1 runtime assertion at interrupt yield site (Option F)
- Update agent-adapter-interrupt tests: resume is now a separate streamAgent
call with Command input rather than resolving an in-process Promise
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Replace in-memory pendingByThread lookup with checkpointer.getTuple()
to validate interrupt_id against pendingWrites on channel __interrupt__
- handleResumeRequest now reads from SQLite checkpoint: 404 if no tuple,
409 if no matching write, else opens a new SSE stream with Command resume
- Track threadRouteMap (thread_id → routeKey) in buildRouteTable closure
so the resume handler knows which route to re-invoke
- Add resumeDecision option to streamResolvedRoute; execute-route constructs
Command({resume}) internally (keeping Command import in @dawn-ai/langchain)
- Update resume-endpoint tests to test the new state-based behavior
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- permission-resume route.ts now proxies the upstream SSE stream instead
of returning {ok: true} JSON — the resume endpoint opens a new SSE stream
- page.tsx: factor SSE reader logic into readSseInto() helper shared between
send() and resolveInterrupt()
- resolveInterrupt now streams the resume response into setEvents, matching
the send() flow so continuation tokens/tool calls appear in the log
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Delete packages/langchain/src/pending-interrupts.ts — no longer imported by agent-adapter or re-exported from index; in-memory Promise parking was replaced by the state-based checkpoint resume in the prior commits - Reduce packages/cli/src/lib/runtime/pending-interrupts.ts to a tombstone comment; the cli runtime-server no longer imports from it Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ct round-trip
JsonPlusSerializer (the default serde inherited from BaseCheckpointSaver) handles
LangChain's `lc` constructor protocol so BaseMessage subclasses survive the SQLite
round-trip as class instances. The naive JSON.stringify in our previous serde.ts
left them as plain objects, which ToolNode rejected on resume with "ToolNode only
accepts BaseMessage[] or { messages: BaseMessage[] } as input."
This unblocks the state-based resume path from the prior commits — verified
end-to-end via permission interrupt → resume → tool execution → done.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds end-to-end integration tests for the HITL permission interrupt + resume cycle, exercising the state-based resume path (fc75e4c) and the JsonPlusSerializer serde fix. Three new tests in the 'agent protocol permission interrupt + resume' describe block: - 'resume with unknown interrupt_id returns 409' — negative CI test, no LLM - 'resume on unknown thread returns 404' — negative CI test, no LLM - 'permission interrupt survives server restart and resumes to completion' — full LLM test (skipIf !OPENAI_API_KEY) with gpt-4o-mini; kills server A after interrupt fires, restarts server B on a new port, POSTs resume (with route key for restart durability), asserts tool_result=1, done=1, ToolNode-errors=0, and ToolMessage in persisted state Also extends handleResumeRequest to accept an optional `route` field in the resume body so clients can resume after a server restart without the in-memory threadRouteMap. Fixes a pre-existing biome formatting issue in sqlite-storage/saver.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r-restart The in-memory threadRouteMap is empty after a server restart, which forced clients to re-send the route key in the resume body. Now runs/stream and runs/wait persist the route into thread metadata (SQLite), so the resume endpoint resolves it automatically: in-memory map → thread metadata → body override. The web client no longer needs to send route on resume. Adds ThreadsStore.updateMetadata (shallow-merge) + unit tests. The restart-durability integration test now resumes WITHOUT a body route, proving the metadata fallback works end-to-end. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@dawn-ai/sqlite-storagepackage: Dawn-nativeBaseCheckpointSaver+ threads store on Node 22's built-innode:sqlite(no native deps)./threads,/threads/{id}/runs/stream,/threads/{id}/runs/wait,/threads/{id}/state,/threads/{id}/resume.MemorySaverremoved from@dawn-ai/langchain; checkpointer is now pluggable viadawn.config.ts.checkpointerand.threadsStore, with SQLite-backed defaults at.dawn/checkpoints.sqlite+.dawn/threads.sqlite.test/runtime/run-agent-protocol.test.ts.Test plan
@dawn-ai/sqlite-storage)run-agent-protocol.test.ts)/threads/{id}/resumeURL (existingresume-endpoint.test.ts)@dawn-ai/sqlite-storageSpec:
docs/superpowers/specs/2026-05-22-phase3-agent-protocol-design.mdPlan:
docs/superpowers/plans/2026-05-22-phase3-agent-protocol.md🤖 Generated with Claude Code