/** * ClaudeCodeAdapterLive - Scoped live implementation for the Claude Code provider adapter. * * Wraps `@anthropic-ai/claude-agent-sdk` query sessions behind the generic * provider adapter contract and emits canonical runtime events. * * @module ClaudeCodeAdapterLive */import { type CanUseTool, query, type Options as ClaudeQueryOptions, type PermissionMode, type PermissionResult, type PermissionUpdate, type SDKMessage, type SDKResultMessage, type SDKUserMessage,} from "@anthropic-ai/claude-agent-sdk";import { ApprovalRequestId, type CanonicalItemType, type CanonicalRequestType, EventId, type ProviderApprovalDecision, ProviderItemId, type ProviderRuntimeEvent, type ProviderRuntimeTurnStatus, type ProviderSendTurnInput, type ProviderSession, RuntimeItemId, RuntimeRequestId, RuntimeTaskId, ThreadId, TurnId,} from "@t3tools/contracts";import { Cause, DateTime, Deferred, Effect, Layer, Queue, Random, Ref, Stream } from "effect"; import { ProviderAdapterProcessError, ProviderAdapterRequestError, ProviderAdapterSessionClosedError, ProviderAdapterSessionNotFoundError, ProviderAdapterValidationError, type ProviderAdapterError,} from "../Errors.ts";import { ClaudeCodeAdapter, type ClaudeCodeAdapterShape } from "../Services/ClaudeCodeAdapter.ts";import { type EventNdjsonLogger, makeEventNdjsonLogger } from "./EventNdjsonLogger.ts"; const PROVIDER = "claudeCode" as const; type PromptQueueItem = | { readonly type: "message"; readonly message: SDKUserMessage; } | { readonly type: "terminate"; }; interface ClaudeResumeState { readonly threadId?: ThreadId; readonly resume?: string; readonly resumeSessionAt?: string; readonly turnCount?: number;} interface ClaudeTurnState { readonly turnId: TurnId; readonly assistantItemId: string; readonly startedAt: string; readonly items: Array<unknown>; readonly messageCompleted: boolean; readonly emittedTextDelta: boolean; readonly fallbackAssistantText: string;} interface PendingApproval { readonly requestType: CanonicalRequestType; readonly detail?: string; readonly suggestions?: ReadonlyArray<PermissionUpdate>; readonly decision: Deferred.Deferred<ProviderApprovalDecision>;} interface ToolInFlight { readonly itemId: string; readonly itemType: CanonicalItemType; readonly toolName: string; readonly title: string; readonly detail?: string;} interface ClaudeSessionContext { session: ProviderSession; readonly promptQueue: Queue.Queue<PromptQueueItem>; readonly query: ClaudeQueryRuntime; readonly startedAt: string; resumeSessionId: string | undefined; readonly pendingApprovals: Map<ApprovalRequestId, PendingApproval>; readonly turns: Array<{ id: TurnId; items: Array<unknown>; }>; readonly inFlightTools: Map<number, ToolInFlight>; turnState: ClaudeTurnState | undefined; lastAssistantUuid: string | undefined; lastThreadStartedId: string | undefined; stopped: boolean;} interface ClaudeQueryRuntime extends AsyncIterable<SDKMessage> { readonly interrupt: () => Promise<void>; readonly setModel: (model?: string) => Promise<void>; readonly setPermissionMode: (mode: PermissionMode) => Promise<void>; readonly setMaxThinkingTokens: (maxThinkingTokens: number | null) => Promise<void>; readonly close: () => void;} export interface ClaudeCodeAdapterLiveOptions { readonly createQuery?: (input: { readonly prompt: AsyncIterable<SDKUserMessage>; readonly options: ClaudeQueryOptions; }) => ClaudeQueryRuntime; readonly nativeEventLogPath?: string; readonly nativeEventLogger?: EventNdjsonLogger;} function isUuid(value: string): boolean { return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);} function isSyntheticClaudeThreadId(value: string): boolean { return value.startsWith("claude-thread-");} function toMessage(cause: unknown, fallback: string): string { if (cause instanceof Error && cause.message.length > 0) { return cause.message; } return fallback;} function asRuntimeItemId(value: string): RuntimeItemId { return RuntimeItemId.makeUnsafe(value);} function asCanonicalTurnId(value: TurnId): TurnId { return value;} function asRuntimeRequestId(value: ApprovalRequestId): RuntimeRequestId { return RuntimeRequestId.makeUnsafe(value);} function toPermissionMode(value: unknown): PermissionMode | undefined { switch (value) { case "default": case "acceptEdits": case "bypassPermissions": case "plan": case "dontAsk": return value; default: return undefined; }} function readClaudeResumeState(resumeCursor: unknown): ClaudeResumeState | undefined { if (!resumeCursor || typeof resumeCursor !== "object") { return undefined; } const cursor = resumeCursor as { threadId?: unknown; resume?: unknown; sessionId?: unknown; resumeSessionAt?: unknown; turnCount?: unknown; }; const threadIdCandidate = typeof cursor.threadId === "string" ? cursor.threadId : undefined; const threadId = threadIdCandidate && !isSyntheticClaudeThreadId(threadIdCandidate) ? ThreadId.makeUnsafe(threadIdCandidate) : undefined; const resumeCandidate = typeof cursor.resume === "string" ? cursor.resume : typeof cursor.sessionId === "string" ? cursor.sessionId : undefined; const resume = resumeCandidate && isUuid(resumeCandidate) ? resumeCandidate : undefined; const resumeSessionAt = typeof cursor.resumeSessionAt === "string" ? cursor.resumeSessionAt : undefined; const turnCountValue = typeof cursor.turnCount === "number" ? cursor.turnCount : undefined; return { ...(threadId ? { threadId } : {}), ...(resume ? { resume } : {}), ...(resumeSessionAt ? { resumeSessionAt } : {}), ...(turnCountValue !== undefined && Number.isInteger(turnCountValue) && turnCountValue >= 0 ? { turnCount: turnCountValue } : {}), };} function classifyToolItemType(toolName: string): CanonicalItemType { const normalized = toolName.toLowerCase(); if ( normalized.includes("bash") || normalized.includes("command") || normalized.includes("shell") || normalized.includes("terminal") ) { return "command_execution"; } if ( normalized.includes("edit") || normalized.includes("write") || normalized.includes("file") || normalized.includes("patch") || normalized.includes("replace") || normalized.includes("create") || normalized.includes("delete") ) { return "file_change"; } if (normalized.includes("mcp")) { return "mcp_tool_call"; } return "dynamic_tool_call";} function classifyRequestType(toolName: string): CanonicalRequestType { const normalized = toolName.toLowerCase(); if (normalized === "read" || normalized.includes("read file") || normalized.includes("view")) { return "file_read_approval"; } return classifyToolItemType(toolName) === "command_execution" ? "command_execution_approval" : "file_change_approval";} function summarizeToolRequest(toolName: string, input: Record<string, unknown>): string { const commandValue = input.command ?? input.cmd; const command = typeof commandValue === "string" ? commandValue : undefined; if (command && command.trim().length > 0) { return `${toolName}: ${command.trim().slice(0, 400)}`; } const serialized = JSON.stringify(input); if (serialized.length <= 400) { return `${toolName}: ${serialized}`; } return `${toolName}: ${serialized.slice(0, 397)}...`;} function titleForTool(itemType: CanonicalItemType): string { switch (itemType) { case "command_execution": return "Command run"; case "file_change": return "File change"; case "mcp_tool_call": return "MCP tool call"; case "dynamic_tool_call": return "Tool call"; default: return "Item"; }} function buildUserMessage(input: ProviderSendTurnInput): SDKUserMessage { const fragments: string[] = []; if (input.input && input.input.trim().length > 0) { fragments.push(input.input.trim()); } for (const attachment of input.attachments ?? []) { if (attachment.type === "image") { fragments.push( `Attached image: ${attachment.name} (${attachment.mimeType}, ${attachment.sizeBytes} bytes).`, ); } } const text = fragments.join("\n\n"); return { type: "user", session_id: "", parent_tool_use_id: null, message: { role: "user", content: [{ type: "text", text }], }, } as SDKUserMessage;} function turnStatusFromResult(result: SDKResultMessage): ProviderRuntimeTurnStatus { if (result.subtype === "success") { return "completed"; } const errors = result.errors.join(" ").toLowerCase(); if (errors.includes("interrupt")) { return "interrupted"; } if (errors.includes("cancel")) { return "cancelled"; } return "failed";} function streamKindFromDeltaType(deltaType: string): "assistant_text" | "reasoning_text" { return deltaType.includes("thinking") ? "reasoning_text" : "assistant_text";} function providerThreadRef( context: ClaudeSessionContext,): { readonly providerThreadId: string } | {} { return context.resumeSessionId ? { providerThreadId: context.resumeSessionId } : {};} function extractAssistantText(message: SDKMessage): string { if (message.type !== "assistant") { return ""; } const content = (message.message as { content?: unknown } | undefined)?.content; if (!Array.isArray(content)) { return ""; } const fragments: string[] = []; for (const block of content) { if (!block || typeof block !== "object") { continue; } const candidate = block as { type?: unknown; text?: unknown }; if ( candidate.type === "text" && typeof candidate.text === "string" && candidate.text.length > 0 ) { fragments.push(candidate.text); } } return fragments.join("");} function toSessionError( threadId: ThreadId, cause: unknown,): ProviderAdapterSessionNotFoundError | ProviderAdapterSessionClosedError | undefined { const normalized = toMessage(cause, "").toLowerCase(); if (normalized.includes("unknown session") || normalized.includes("not found")) { return new ProviderAdapterSessionNotFoundError({ provider: PROVIDER, threadId, cause, }); } if (normalized.includes("closed")) { return new ProviderAdapterSessionClosedError({ provider: PROVIDER, threadId, cause, }); } return undefined;} function toRequestError(threadId: ThreadId, method: string, cause: unknown): ProviderAdapterError { const sessionError = toSessionError(threadId, cause); if (sessionError) { return sessionError; } return new ProviderAdapterRequestError({ provider: PROVIDER, method, detail: toMessage(cause, `${method} failed`), cause, });} function sdkMessageType(value: unknown): string | undefined { if (!value || typeof value !== "object") { return undefined; } const record = value as { type?: unknown }; return typeof record.type === "string" ? record.type : undefined;} function sdkMessageSubtype(value: unknown): string | undefined { if (!value || typeof value !== "object") { return undefined; } const record = value as { subtype?: unknown }; return typeof record.subtype === "string" ? record.subtype : undefined;} function sdkNativeMethod(message: SDKMessage): string { const subtype = sdkMessageSubtype(message); if (subtype) { return `claude/${message.type}/${subtype}`; } if (message.type === "stream_event") { const streamType = sdkMessageType(message.event); if (streamType) { const deltaType = streamType === "content_block_delta" ? sdkMessageType((message.event as { delta?: unknown }).delta) : undefined; if (deltaType) { return `claude/${message.type}/${streamType}/${deltaType}`; } return `claude/${message.type}/${streamType}`; } } return `claude/${message.type}`;} function sdkNativeItemId(message: SDKMessage): string | undefined { if (message.type === "assistant") { const maybeId = (message.message as { id?: unknown }).id; if (typeof maybeId === "string") { return maybeId; } return undefined; } if (message.type === "stream_event") { const event = message.event as { type?: unknown; content_block?: { id?: unknown }; }; if (event.type === "content_block_start" && typeof event.content_block?.id === "string") { return event.content_block.id; } } return undefined;} function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { return Effect.gen(function* () { const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== undefined ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native", }) : undefined); const createQuery = options?.createQuery ?? ((input: { readonly prompt: AsyncIterable<SDKUserMessage>; readonly options: ClaudeQueryOptions; }) => query({ prompt: input.prompt, options: input.options }) as ClaudeQueryRuntime); const sessions = new Map<ThreadId, ClaudeSessionContext>(); const runtimeEventQueue = yield* Queue.unbounded<ProviderRuntimeEvent>(); const nowIso = Effect.map(DateTime.now, DateTime.formatIso); const nextEventId = Effect.map(Random.nextUUIDv4, (id) => EventId.makeUnsafe(id)); const makeEventStamp = () => Effect.all({ eventId: nextEventId, createdAt: nowIso }); const offerRuntimeEvent = (event: ProviderRuntimeEvent): Effect.Effect<void> => Queue.offer(runtimeEventQueue, event).pipe(Effect.asVoid); const logNativeSdkMessage = ( context: ClaudeSessionContext, message: SDKMessage, ): Effect.Effect<void> => Effect.gen(function* () { if (!nativeEventLogger) { return; } const observedAt = new Date().toISOString(); const itemId = sdkNativeItemId(message); yield* nativeEventLogger.write( { observedAt, event: { id: "uuid" in message && typeof message.uuid === "string" ? message.uuid : crypto.randomUUID(), kind: "notification", provider: PROVIDER, createdAt: observedAt, method: sdkNativeMethod(message), ...(typeof message.session_id === "string"Lines 1–500 of 1863. Load more
/** * ClaudeCodeAdapterLive - Scoped live implementation for the Claude Code provider adapter. * * Wraps `@anthropic-ai/claude-agent-sdk` query sessions behind the generic * provider adapter contract and emits canonical runtime events. * * @module ClaudeCodeAdapterLive */ import { type CanUseTool, query, type Options as ClaudeQueryOptions, type PermissionMode, type PermissionResult, type PermissionUpdate, type SDKMessage, type SDKResultMessage, type SDKUserMessage, } from "@anthropic-ai/claude-agent-sdk"; import { ApprovalRequestId, type CanonicalItemType, type CanonicalRequestType, EventId, type ProviderApprovalDecision, ProviderItemId, type ProviderRuntimeEvent, type ProviderRuntimeTurnStatus, type ProviderSendTurnInput, type ProviderSession, RuntimeItemId, RuntimeRequestId, RuntimeTaskId, ThreadId, TurnId, } from "@t3tools/contracts"; import { Cause, DateTime, Deferred, Effect, Layer, Queue, Random, Ref, Stream } from "effect"; import { ProviderAdapterProcessError, ProviderAdapterRequestError, ProviderAdapterSessionClosedError, ProviderAdapterSessionNotFoundError, ProviderAdapterValidationError, type ProviderAdapterError, } from "../Errors.ts"; import { ClaudeCodeAdapter, type ClaudeCodeAdapterShape } from "../Services/ClaudeCodeAdapter.ts"; import { type EventNdjsonLogger, makeEventNdjsonLogger } from "./EventNdjsonLogger.ts"; const PROVIDER = "claudeCode" as const; type PromptQueueItem = | { readonly type: "message"; readonly message: SDKUserMessage; } | { readonly type: "terminate"; }; interface ClaudeResumeState { readonly threadId?: ThreadId; readonly resume?: string; readonly resumeSessionAt?: string; readonly turnCount?: number; } interface ClaudeTurnState { readonly turnId: TurnId; readonly assistantItemId: string; readonly startedAt: string; readonly items: Array<unknown>; readonly messageCompleted: boolean; readonly emittedTextDelta: boolean; readonly fallbackAssistantText: string; } interface PendingApproval { readonly requestType: CanonicalRequestType; readonly detail?: string; readonly suggestions?: ReadonlyArray<PermissionUpdate>; readonly decision: Deferred.Deferred<ProviderApprovalDecision>; } interface ToolInFlight { readonly itemId: string; readonly itemType: CanonicalItemType; readonly toolName: string; readonly title: string; readonly detail?: string; } interface ClaudeSessionContext { session: ProviderSession; readonly promptQueue: Queue.Queue<PromptQueueItem>; readonly query: ClaudeQueryRuntime; readonly startedAt: string; resumeSessionId: string | undefined; readonly pendingApprovals: Map<ApprovalRequestId, PendingApproval>; readonly turns: Array<{ id: TurnId; items: Array<unknown>; }>; readonly inFlightTools: Map<number, ToolInFlight>; turnState: ClaudeTurnState | undefined; lastAssistantUuid: string | undefined; lastThreadStartedId: string | undefined; stopped: boolean; } interface ClaudeQueryRuntime extends AsyncIterable<SDKMessage> { readonly interrupt: () => Promise<void>; readonly setModel: (model?: string) => Promise<void>; readonly setPermissionMode: (mode: PermissionMode) => Promise<void>; readonly setMaxThinkingTokens: (maxThinkingTokens: number | null) => Promise<void>; readonly close: () => void; } export interface ClaudeCodeAdapterLiveOptions { readonly createQuery?: (input: { readonly prompt: AsyncIterable<SDKUserMessage>; readonly options: ClaudeQueryOptions; }) => ClaudeQueryRuntime; readonly nativeEventLogPath?: string; readonly nativeEventLogger?: EventNdjsonLogger; } function isUuid(value: string): boolean { return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value); } function isSyntheticClaudeThreadId(value: string): boolean { return value.startsWith("claude-thread-"); } function toMessage(cause: unknown, fallback: string): string { if (cause instanceof Error && cause.message.length > 0) { return cause.message; } return fallback; } function asRuntimeItemId(value: string): RuntimeItemId { return RuntimeItemId.makeUnsafe(value); } function asCanonicalTurnId(value: TurnId): TurnId { return value; } function asRuntimeRequestId(value: ApprovalRequestId): RuntimeRequestId { return RuntimeRequestId.makeUnsafe(value); } function toPermissionMode(value: unknown): PermissionMode | undefined { switch (value) { case "default": case "acceptEdits": case "bypassPermissions": case "plan": case "dontAsk": return value; default: return undefined; } } function readClaudeResumeState(resumeCursor: unknown): ClaudeResumeState | undefined { if (!resumeCursor || typeof resumeCursor !== "object") { return undefined; } const cursor = resumeCursor as { threadId?: unknown; resume?: unknown; sessionId?: unknown; resumeSessionAt?: unknown; turnCount?: unknown; }; const threadIdCandidate = typeof cursor.threadId === "string" ? cursor.threadId : undefined; const threadId = threadIdCandidate && !isSyntheticClaudeThreadId(threadIdCandidate) ? ThreadId.makeUnsafe(threadIdCandidate) : undefined; const resumeCandidate = typeof cursor.resume === "string" ? cursor.resume : typeof cursor.sessionId === "string" ? cursor.sessionId : undefined; const resume = resumeCandidate && isUuid(resumeCandidate) ? resumeCandidate : undefined; const resumeSessionAt = typeof cursor.resumeSessionAt === "string" ? cursor.resumeSessionAt : undefined; const turnCountValue = typeof cursor.turnCount === "number" ? cursor.turnCount : undefined; return { ...(threadId ? { threadId } : {}), ...(resume ? { resume } : {}), ...(resumeSessionAt ? { resumeSessionAt } : {}), ...(turnCountValue !== undefined && Number.isInteger(turnCountValue) && turnCountValue >= 0 ? { turnCount: turnCountValue } : {}), }; } function classifyToolItemType(toolName: string): CanonicalItemType { const normalized = toolName.toLowerCase(); if ( normalized.includes("bash") || normalized.includes("command") || normalized.includes("shell") || normalized.includes("terminal") ) { return "command_execution"; } if ( normalized.includes("edit") || normalized.includes("write") || normalized.includes("file") || normalized.includes("patch") || normalized.includes("replace") || normalized.includes("create") || normalized.includes("delete") ) { return "file_change"; } if (normalized.includes("mcp")) { return "mcp_tool_call"; } return "dynamic_tool_call"; } function classifyRequestType(toolName: string): CanonicalRequestType { const normalized = toolName.toLowerCase(); if (normalized === "read" || normalized.includes("read file") || normalized.includes("view")) { return "file_read_approval"; } return classifyToolItemType(toolName) === "command_execution" ? "command_execution_approval" : "file_change_approval"; } function summarizeToolRequest(toolName: string, input: Record<string, unknown>): string { const commandValue = input.command ?? input.cmd; const command = typeof commandValue === "string" ? commandValue : undefined; if (command && command.trim().length > 0) { return `${toolName}: ${command.trim().slice(0, 400)}`; } const serialized = JSON.stringify(input); if (serialized.length <= 400) { return `${toolName}: ${serialized}`; } return `${toolName}: ${serialized.slice(0, 397)}...`; } function titleForTool(itemType: CanonicalItemType): string { switch (itemType) { case "command_execution": return "Command run"; case "file_change": return "File change"; case "mcp_tool_call": return "MCP tool call"; case "dynamic_tool_call": return "Tool call"; default: return "Item"; } } function buildUserMessage(input: ProviderSendTurnInput): SDKUserMessage { const fragments: string[] = []; if (input.input && input.input.trim().length > 0) { fragments.push(input.input.trim()); } for (const attachment of input.attachments ?? []) { if (attachment.type === "image") { fragments.push( `Attached image: ${attachment.name} (${attachment.mimeType}, ${attachment.sizeBytes} bytes).`, ); } } const text = fragments.join("\n\n"); return { type: "user", session_id: "", parent_tool_use_id: null, message: { role: "user", content: [{ type: "text", text }], }, } as SDKUserMessage; } function turnStatusFromResult(result: SDKResultMessage): ProviderRuntimeTurnStatus { if (result.subtype === "success") { return "completed"; } const errors = result.errors.join(" ").toLowerCase(); if (errors.includes("interrupt")) { return "interrupted"; } if (errors.includes("cancel")) { return "cancelled"; } return "failed"; } function streamKindFromDeltaType(deltaType: string): "assistant_text" | "reasoning_text" { return deltaType.includes("thinking") ? "reasoning_text" : "assistant_text"; } function providerThreadRef( context: ClaudeSessionContext, ): { readonly providerThreadId: string } | {} { return context.resumeSessionId ? { providerThreadId: context.resumeSessionId } : {}; } function extractAssistantText(message: SDKMessage): string { if (message.type !== "assistant") { return ""; } const content = (message.message as { content?: unknown } | undefined)?.content; if (!Array.isArray(content)) { return ""; } const fragments: string[] = []; for (const block of content) { if (!block || typeof block !== "object") { continue; } const candidate = block as { type?: unknown; text?: unknown }; if ( candidate.type === "text" && typeof candidate.text === "string" && candidate.text.length > 0 ) { fragments.push(candidate.text); } } return fragments.join(""); } function toSessionError( threadId: ThreadId, cause: unknown, ): ProviderAdapterSessionNotFoundError | ProviderAdapterSessionClosedError | undefined { const normalized = toMessage(cause, "").toLowerCase(); if (normalized.includes("unknown session") || normalized.includes("not found")) { return new ProviderAdapterSessionNotFoundError({ provider: PROVIDER, threadId, cause, }); } if (normalized.includes("closed")) { return new ProviderAdapterSessionClosedError({ provider: PROVIDER, threadId, cause, }); } return undefined; } function toRequestError(threadId: ThreadId, method: string, cause: unknown): ProviderAdapterError { const sessionError = toSessionError(threadId, cause); if (sessionError) { return sessionError; } return new ProviderAdapterRequestError({ provider: PROVIDER, method, detail: toMessage(cause, `${method} failed`), cause, }); } function sdkMessageType(value: unknown): string | undefined { if (!value || typeof value !== "object") { return undefined; } const record = value as { type?: unknown }; return typeof record.type === "string" ? record.type : undefined; } function sdkMessageSubtype(value: unknown): string | undefined { if (!value || typeof value !== "object") { return undefined; } const record = value as { subtype?: unknown }; return typeof record.subtype === "string" ? record.subtype : undefined; } function sdkNativeMethod(message: SDKMessage): string { const subtype = sdkMessageSubtype(message); if (subtype) { return `claude/${message.type}/${subtype}`; } if (message.type === "stream_event") { const streamType = sdkMessageType(message.event); if (streamType) { const deltaType = streamType === "content_block_delta" ? sdkMessageType((message.event as { delta?: unknown }).delta) : undefined; if (deltaType) { return `claude/${message.type}/${streamType}/${deltaType}`; } return `claude/${message.type}/${streamType}`; } } return `claude/${message.type}`; } function sdkNativeItemId(message: SDKMessage): string | undefined { if (message.type === "assistant") { const maybeId = (message.message as { id?: unknown }).id; if (typeof maybeId === "string") { return maybeId; } return undefined; } if (message.type === "stream_event") { const event = message.event as { type?: unknown; content_block?: { id?: unknown }; }; if (event.type === "content_block_start" && typeof event.content_block?.id === "string") { return event.content_block.id; } } return undefined; } function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { return Effect.gen(function* () { const nativeEventLogger = options?.nativeEventLogger ?? (options?.nativeEventLogPath !== undefined ? yield* makeEventNdjsonLogger(options.nativeEventLogPath, { stream: "native", }) : undefined); const createQuery = options?.createQuery ?? ((input: { readonly prompt: AsyncIterable<SDKUserMessage>; readonly options: ClaudeQueryOptions; }) => query({ prompt: input.prompt, options: input.options }) as ClaudeQueryRuntime); const sessions = new Map<ThreadId, ClaudeSessionContext>(); const runtimeEventQueue = yield* Queue.unbounded<ProviderRuntimeEvent>(); const nowIso = Effect.map(DateTime.now, DateTime.formatIso); const nextEventId = Effect.map(Random.nextUUIDv4, (id) => EventId.makeUnsafe(id)); const makeEventStamp = () => Effect.all({ eventId: nextEventId, createdAt: nowIso }); const offerRuntimeEvent = (event: ProviderRuntimeEvent): Effect.Effect<void> => Queue.offer(runtimeEventQueue, event).pipe(Effect.asVoid); const logNativeSdkMessage = ( context: ClaudeSessionContext, message: SDKMessage, ): Effect.Effect<void> => Effect.gen(function* () { if (!nativeEventLogger) { return; } const observedAt = new Date().toISOString(); const itemId = sdkNativeItemId(message); yield* nativeEventLogger.write( { observedAt, event: { id: "uuid" in message && typeof message.uuid === "string" ? message.uuid : crypto.randomUUID(), kind: "notification", provider: PROVIDER, createdAt: observedAt, method: sdkNativeMethod(message), ...(typeof message.session_id === "string"