feat: Claude Agent SDK backend + clean-room PostgresSessionStore (v2.7.5)
Lands the lean-SDK direction (boocode_code_review_v2 §1 #9) behind a flag. Adds @anthropic-ai/claude-agent-sdk@0.3.159 (Commercial Terms, runtime dep). - PostgresSessionStore: clean-room impl of the SDK's real SessionStore type over a new claude_session_entries table. Typechecks against the SDK type; 8 DB-integration tests. - ClaudeSdkBackend (implements AgentBackend): one warm query() per (chat,claude) in streaming-input mode via a pushable async-iterable pump, sessionStore + resume continuity, pure mapSdkMessage->AgentEvent, session_id from init, usage/cost onto agent_sessions (backend CHECK gains 'claude_sdk'). - Routing env-gated by CLAUDE_SDK_BACKEND (default off) -> PTY path UNCHANGED. - Built against real SDK 0.3.159 types (install paid off: partial=stream_event needing includePartialMessages, MessageParam, result error arm). - Fix latent test-infra deadlock: serialize DB suites (fileParallelism:false). Coder 269 passing default / 290 with DB; tsc clean vs SDK types; builds clean. LIVE pump + resume + actual claude turn need a host smoke (CLAUDE_SDK_BACKEND=1 + claude binary + auth). zod peer-dep wants ^4 (workspace 3.25). Builds on v2.7.4. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
38
apps/coder/src/services/backends/claude-sdk-routing.ts
Normal file
38
apps/coder/src/services/backends/claude-sdk-routing.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* claude-sdk-sessionstore #9 (Part 2) — claude-SDK-vs-PTY routing predicate.
|
||||
*
|
||||
* Sibling to `shouldUseWarmBackend` (warm-acp-routing.ts). The warm Claude-SDK
|
||||
* backend keys its persistent `query()` on (chat_id, agent) — exactly like the
|
||||
* warm-ACP / opencode-server backends — so a task only routes to it when it carries
|
||||
* BOTH a `session_id` and a `chat_id` (a real chat tab).
|
||||
*
|
||||
* CRUCIALLY this is ALSO gated behind the `CLAUDE_SDK_BACKEND` env flag (default
|
||||
* OFF). While off — the production default — claude always falls through to the
|
||||
* existing one-shot PTY `runExternalAgent` path, UNCHANGED. The live SDK streaming
|
||||
* pump + cross-turn resume need a host smoke against the real `claude` binary, so
|
||||
* we keep the working PTY path as the default until that lands. Flip the env var
|
||||
* on a host (any truthy value) to opt a deployment into the SDK backend.
|
||||
*
|
||||
* Pure (env read injected) so it's unit-testable; the dispatcher consumes it.
|
||||
*/
|
||||
|
||||
/** True iff the `CLAUDE_SDK_BACKEND` env flag is set to a truthy value. */
|
||||
export function claudeSdkBackendEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
|
||||
const v = env.CLAUDE_SDK_BACKEND;
|
||||
if (v == null) return false;
|
||||
const s = v.trim().toLowerCase();
|
||||
return s !== '' && s !== '0' && s !== 'false' && s !== 'off' && s !== 'no';
|
||||
}
|
||||
|
||||
export function shouldUseClaudeSdk(
|
||||
task: {
|
||||
agent: string | null;
|
||||
session_id: string | null;
|
||||
chat_id: string | null;
|
||||
},
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): boolean {
|
||||
if (!claudeSdkBackendEnabled(env)) return false;
|
||||
if (task.agent !== 'claude') return false;
|
||||
return task.session_id != null && task.chat_id != null;
|
||||
}
|
||||
Reference in New Issue
Block a user