@witqq/agent-sdk 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-DxY68NZL.d.cts → agent-C6H2CgJA.d.cts} +2 -0
- package/dist/{agent-CW9XbmG_.d.ts → agent-F7oB6eKp.d.ts} +2 -0
- package/dist/backends/claude.cjs.map +1 -1
- package/dist/backends/claude.d.cts +2 -2
- package/dist/backends/claude.d.ts +2 -2
- package/dist/backends/claude.js.map +1 -1
- package/dist/backends/copilot.cjs +8 -15
- package/dist/backends/copilot.cjs.map +1 -1
- package/dist/backends/copilot.d.cts +2 -2
- package/dist/backends/copilot.d.ts +2 -2
- package/dist/backends/copilot.js +8 -15
- package/dist/backends/copilot.js.map +1 -1
- package/dist/backends/mock-llm.cjs +719 -0
- package/dist/backends/mock-llm.cjs.map +1 -0
- package/dist/backends/mock-llm.d.cts +37 -0
- package/dist/backends/mock-llm.d.ts +37 -0
- package/dist/backends/mock-llm.js +717 -0
- package/dist/backends/mock-llm.js.map +1 -0
- package/dist/backends/vercel-ai.cjs +8 -1
- package/dist/backends/vercel-ai.cjs.map +1 -1
- package/dist/backends/vercel-ai.d.cts +2 -2
- package/dist/backends/vercel-ai.d.ts +2 -2
- package/dist/backends/vercel-ai.js +8 -1
- package/dist/backends/vercel-ai.js.map +1 -1
- package/dist/backends-Cno0gZjy.d.cts +114 -0
- package/dist/backends-Cno0gZjy.d.ts +114 -0
- package/dist/chat/accumulator.cjs.map +1 -1
- package/dist/chat/accumulator.d.cts +2 -2
- package/dist/chat/accumulator.d.ts +2 -2
- package/dist/chat/accumulator.js.map +1 -1
- package/dist/chat/backends.cjs +350 -77
- package/dist/chat/backends.cjs.map +1 -1
- package/dist/chat/backends.d.cts +7 -7
- package/dist/chat/backends.d.ts +7 -7
- package/dist/chat/backends.js +349 -78
- package/dist/chat/backends.js.map +1 -1
- package/dist/chat/context.d.cts +2 -2
- package/dist/chat/context.d.ts +2 -2
- package/dist/chat/core.cjs +35 -25
- package/dist/chat/core.cjs.map +1 -1
- package/dist/chat/core.d.cts +15 -5
- package/dist/chat/core.d.ts +15 -5
- package/dist/chat/core.js +35 -26
- package/dist/chat/core.js.map +1 -1
- package/dist/chat/events.d.cts +2 -2
- package/dist/chat/events.d.ts +2 -2
- package/dist/chat/index.cjs +418 -122
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +7 -7
- package/dist/chat/index.d.ts +7 -7
- package/dist/chat/index.js +418 -124
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react.cjs +216 -12
- package/dist/chat/react.cjs.map +1 -1
- package/dist/chat/react.d.cts +78 -4
- package/dist/chat/react.d.ts +78 -4
- package/dist/chat/react.js +215 -13
- package/dist/chat/react.js.map +1 -1
- package/dist/chat/runtime.cjs +6 -2
- package/dist/chat/runtime.cjs.map +1 -1
- package/dist/chat/runtime.d.cts +2 -2
- package/dist/chat/runtime.d.ts +2 -2
- package/dist/chat/runtime.js +6 -2
- package/dist/chat/runtime.js.map +1 -1
- package/dist/chat/server.cjs +15 -5
- package/dist/chat/server.cjs.map +1 -1
- package/dist/chat/server.d.cts +3 -3
- package/dist/chat/server.d.ts +3 -3
- package/dist/chat/server.js +15 -5
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/sessions.cjs +39 -23
- package/dist/chat/sessions.cjs.map +1 -1
- package/dist/chat/sessions.d.cts +2 -2
- package/dist/chat/sessions.d.ts +2 -2
- package/dist/chat/sessions.js +40 -24
- package/dist/chat/sessions.js.map +1 -1
- package/dist/chat/sqlite.cjs +95 -0
- package/dist/chat/sqlite.cjs.map +1 -1
- package/dist/chat/sqlite.d.cts +39 -3
- package/dist/chat/sqlite.d.ts +39 -3
- package/dist/chat/sqlite.js +93 -1
- package/dist/chat/sqlite.js.map +1 -1
- package/dist/chat/state.d.cts +2 -2
- package/dist/chat/state.d.ts +2 -2
- package/dist/chat/storage.cjs +39 -23
- package/dist/chat/storage.cjs.map +1 -1
- package/dist/chat/storage.d.cts +7 -3
- package/dist/chat/storage.d.ts +7 -3
- package/dist/chat/storage.js +40 -24
- package/dist/chat/storage.js.map +1 -1
- package/dist/{in-process-transport-C1JnJGVR.d.ts → in-process-transport-7EIit9Xk.d.ts} +51 -17
- package/dist/{in-process-transport-C7DSqPyX.d.cts → in-process-transport-Ct9YcX8I.d.cts} +51 -17
- package/dist/index.cjs +14 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +13 -13
- package/dist/index.js.map +1 -1
- package/dist/testing.cjs +724 -0
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +14 -2
- package/dist/testing.d.ts +14 -2
- package/dist/testing.js +724 -0
- package/dist/testing.js.map +1 -1
- package/dist/{transport-Cdh3M0tS.d.cts → transport-DLWCN18G.d.cts} +1 -1
- package/dist/{transport-Ciap4PWK.d.ts → transport-DsuS-GeM.d.ts} +1 -1
- package/dist/{types-ajANVzf7.d.ts → types-DgtI1hzh.d.ts} +2 -1
- package/dist/{types-DRgd_9R7.d.cts → types-DkSXALKg.d.cts} +2 -1
- package/package.json +18 -7
- package/LICENSE +0 -21
- package/README.md +0 -1054
- package/dist/backends-BSrsBYFn.d.cts +0 -39
- package/dist/backends-BSrsBYFn.d.ts +0 -39
package/dist/chat/sqlite.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/chat/types.ts","../../src/errors.ts","../../src/chat/storage.ts","../../src/chat/sqlite/session-store.ts","../../src/chat/sqlite/provider-store.ts","../../src/chat/sqlite/token-store.ts","../../src/chat/sqlite/factory.ts"],"names":[],"mappings":"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","file":"sqlite.js","sourcesContent":["/**\n * @witqq/agent-sdk — Chat domain types\n *\n * All type definitions and interfaces for the chat layer.\n * Pure types + ChatId generation (tightly coupled to branded type).\n */\n\nimport type { UsageData, ToolDefinition, ErrorCode } from \"../types.js\";\nimport type { AuthToken } from \"../auth/types.js\";\n\n// ─── Unique ID ─────────────────────────────────────────────────\n\n/** Branded type for unique identifiers */\nexport type ChatId = string & { readonly __brand: \"ChatId\" };\n\n/**\n * Generate a new unique ChatId (crypto.randomUUID-based)\n * @returns Branded ChatId string\n */\nexport function createChatId(): ChatId {\n return crypto.randomUUID() as ChatId;\n}\n\n/** UUID v4 pattern for ChatId validation */\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/**\n * Cast a string to ChatId with UUID format validation.\n * Use this instead of manual `as ChatId` type assertions.\n *\n * @param value - String to validate and cast\n * @returns Branded ChatId\n * @throws {TypeError} If value is not a valid UUID v4 format\n */\nexport function toChatId(value: string): ChatId {\n if (!UUID_RE.test(value)) {\n throw new TypeError(`Invalid ChatId: \"${value}\" is not a valid UUID`);\n }\n return value as ChatId;\n}\n\n/**\n * Accepts either a plain string or branded ChatId for API convenience.\n * Use this in public API signatures so consumers don't need `as ChatId` casts.\n */\nexport type ChatIdLike = string | ChatId;\n\n// ─── Status Types ──────────────────────────────────────────────\n\n/** Lifecycle status of a message part (text, reasoning, etc.) */\nexport type PartStatus = \"pending\" | \"streaming\" | \"complete\" | \"error\";\n/** Lifecycle status of a tool call within a message */\nexport type ToolCallStatus = \"pending\" | \"running\" | \"requires_approval\" | \"complete\" | \"error\" | \"denied\";\n/** Lifecycle status of an entire message */\nexport type MessageStatus = \"pending\" | \"streaming\" | \"complete\" | \"error\" | \"cancelled\";\n/** Lifecycle status of a chat session */\nexport type SessionStatus = \"active\";\n/** Lifecycle status of the chat runtime */\nexport type RuntimeStatus = \"idle\" | \"streaming\" | \"error\" | \"disposed\";\n\n// ─── Message Parts (union) ─────────────────────────────────────\n\n/** Plain text content part */\nexport interface TextPart { type: \"text\"; text: string; status: PartStatus; }\n/** Model reasoning/thinking content part */\nexport interface ReasoningPart { type: \"reasoning\"; text: string; status: PartStatus; }\n/** Tool invocation part with call ID, arguments, optional result */\nexport interface ToolCallPart { type: \"tool_call\"; toolCallId: string; name: string; args: unknown; result?: unknown; status: ToolCallStatus; error?: string; }\n/** Source reference part (URL citation) */\nexport interface SourcePart { type: \"source\"; url: string; title?: string; status: PartStatus; }\n/** File attachment part (base64-encoded data) */\nexport interface FilePart { type: \"file\"; name: string; mimeType: string; data: string; status: PartStatus; }\n/** Union of all message part types */\nexport type MessagePart = TextPart | ReasoningPart | ToolCallPart | SourcePart | FilePart;\n\n// ─── Chat Message ──────────────────────────────────────────────\n\n/** Role of message author */\nexport type ChatRole = \"user\" | \"assistant\" | \"system\";\n\n/** Metadata attached to messages — useful preset for the TMetadata generic */\nexport interface ChatMessageMetadata {\n model?: string;\n backend?: string;\n usage?: UsageData;\n isSummary?: boolean;\n estimatedTokens?: number;\n custom?: Record<string, unknown>;\n}\n\n/** Message status */\nexport type ChatMessageStatus = MessageStatus;\n\n/** A single chat message — the fundamental unit of conversation */\nexport interface ChatMessage<TMetadata = unknown> {\n id: ChatId;\n role: ChatRole;\n parts: MessagePart[];\n metadata?: TMetadata;\n createdAt: string;\n updatedAt?: string;\n status: MessageStatus;\n}\n\n// ─── Supporting Types ──────────────────────────────────────────\n\n// ─── Chat Session ──────────────────────────────────────────────\n\n/** Session configuration snapshot */\nexport interface ChatSessionConfig {\n model: string;\n backend: string;\n systemPrompt?: string;\n temperature?: number;\n maxTokens?: number;\n}\n\n/**\n * Session metadata tracking usage statistics and custom extensions.\n *\n * Updated automatically by session stores on each `addMessage()` call.\n * The generic `TCustom` parameter allows type-safe application-specific\n * metadata via the `custom` field.\n *\n * @typeParam TCustom - Shape of the `custom` field (defaults to `Record<string, unknown>`)\n */\nexport interface ChatSessionMetadata<TCustom extends Record<string, unknown> = Record<string, unknown>> {\n /** Number of messages in the session (updated by session store) */\n messageCount: number;\n /** Total token count across all messages in the session */\n totalTokens: number;\n /** Optional tags for session categorization and filtering */\n tags?: string[];\n /** Application-specific metadata — typed via the TCustom generic parameter */\n custom?: TCustom;\n}\n\n/** Chat session — a conversation with ordered messages (pure serializable data) */\nexport interface ChatSession<TCustom extends Record<string, unknown> = Record<string, unknown>> {\n id: ChatId;\n title?: string;\n messages: ChatMessage[];\n config: ChatSessionConfig;\n metadata: ChatSessionMetadata<TCustom>;\n status: SessionStatus;\n createdAt: string;\n updatedAt: string;\n backendSessionId?: string;\n}\n\n/**\n * Reactive wrapper around ChatSession — provides subscribe/getSnapshot for\n * React useSyncExternalStore integration and lastMessage convenience getter.\n * Session stores may optionally return ObservableSession instances.\n */\nexport interface ObservableSession<TCustom extends Record<string, unknown> = Record<string, unknown>>\n extends ChatSession<TCustom> {\n /** Subscribe to session changes (for React useSyncExternalStore) */\n subscribe(callback: () => void): () => void;\n /** Get immutable snapshot of session state (for React useSyncExternalStore) */\n getSnapshot(): ChatSession<TCustom>;\n /** Last message in the session */\n readonly lastMessage: ChatMessage | undefined;\n}\n\n/** Lightweight session info for listing (without full message array) */\nexport interface SessionInfo {\n id: ChatId;\n title?: string;\n status: SessionStatus;\n messageCount: number;\n lastMessage?: ChatMessage;\n createdAt: string;\n updatedAt: string;\n}\n\n// ─── Chat Events ───────────────────────────────────────────────\n\n/** Events emitted during chat operation */\nexport type ChatEvent =\n | { type: \"message:start\"; messageId: ChatId; role: ChatRole }\n | { type: \"message:delta\"; messageId: ChatId; text: string }\n | { type: \"message:complete\"; messageId: ChatId; message: ChatMessage }\n | {\n type: \"tool:start\";\n messageId: ChatId;\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n }\n | {\n type: \"tool:complete\";\n messageId: ChatId;\n toolCallId: string;\n toolName: string;\n result: unknown;\n isError?: boolean;\n }\n | { type: \"thinking:start\"; messageId: ChatId }\n | { type: \"thinking:delta\"; messageId: ChatId; text: string }\n | { type: \"thinking:end\"; messageId: ChatId }\n | {\n type: \"permission:request\";\n messageId: ChatId;\n toolName: string;\n toolArgs: Record<string, unknown>;\n }\n | {\n type: \"permission:response\";\n messageId: ChatId;\n toolName: string;\n allowed: boolean;\n }\n | {\n type: \"usage\";\n promptTokens: number;\n completionTokens: number;\n model?: string;\n }\n | { type: \"session:created\"; sessionId: ChatId }\n | { type: \"session:updated\"; sessionId: ChatId }\n | {\n type: \"error\";\n error: string;\n recoverable: boolean;\n code?: ErrorCode;\n messageId?: ChatId;\n }\n | { type: \"typing:start\" }\n | { type: \"typing:end\" }\n | { type: \"heartbeat\" }\n | { type: \"done\"; finalOutput?: string };\n\n/** All possible ChatEvent type strings */\nexport type ChatEventType = ChatEvent[\"type\"];\n\n// ─── Chat Middleware ───────────────────────────────────────────\n\n/** Context passed to ChatMiddleware hooks */\nexport interface ChatMiddlewareContext {\n sessionId: ChatId;\n signal: AbortSignal;\n}\n\n/** Runtime-level middleware for the send/receive lifecycle.\n * Different from EventMiddleware which operates at the event bus level. */\nexport interface ChatMiddleware {\n /** Transform message before sending to backend. Return null to reject the send. */\n onBeforeSend?(message: ChatMessage, context: ChatMiddlewareContext): ChatMessage | null | Promise<ChatMessage | null>;\n /** Transform/intercept stream events */\n onEvent?(event: ChatEvent, context: ChatMiddlewareContext): ChatEvent | null | Promise<ChatEvent | null>;\n /** Transform completed message after receiving from backend */\n onAfterReceive?(message: ChatMessage, context: ChatMiddlewareContext): ChatMessage | Promise<ChatMessage>;\n /** Intercept errors — return null to suppress, return error to propagate */\n onError?(error: Error, context: ChatMiddlewareContext): Error | null | Promise<Error | null>;\n}\n\n// ─── Chat Provider Abstraction ─────────────────────────────────\n\n/** Options for sending a message to a provider */\nexport interface SendMessageOptions {\n signal?: AbortSignal;\n /** Model to use for this request. Required for server-side runtime.send(). */\n model?: string;\n /** Per-call system prompt override (forwarded to the backend agent) */\n systemPrompt?: string;\n context?: Record<string, unknown>;\n /** Additional tools to include in this request */\n tools?: ToolDefinition[];\n}\n\n/** Options for runtime.send() — requires backend routing info */\nexport interface RuntimeSendOptions {\n /** Backend to route this request to (key in backends map) */\n backend: string;\n /** Authentication credentials for the backend factory */\n credentials: AuthToken;\n /** Model to use for this request */\n model: string;\n /** Per-call system prompt override (forwarded to the backend agent) */\n systemPrompt?: string;\n /** Abort signal */\n signal?: AbortSignal;\n /** Request-scoped context */\n context?: Record<string, unknown>;\n /** Additional tools */\n tools?: ToolDefinition[];\n}\n\n/**\n * @deprecated IChatProvider has been inlined into IChatBackend.\n * Import IChatBackend from \"@witqq/agent-sdk/chat/backends\" instead.\n * Kept as type alias for backward compatibility.\n */\nexport type IChatProvider = import(\"./backends/types.js\").IChatBackend;\n\n// ─── Factory Functions ─────────────────────────────────────────\n\n/**\n * Create a simple text ChatMessage.\n *\n * @param text - Message text content\n * @param role - Message role (default: \"user\")\n * @returns A complete ChatMessage with a single TextPart\n */\nexport function createTextMessage(text: string, role: ChatRole = \"user\"): ChatMessage {\n return {\n id: createChatId(),\n role,\n parts: [{ type: \"text\", text, status: \"complete\" }],\n createdAt: new Date().toISOString(),\n status: \"complete\",\n };\n}\n\n/** Type guard: checks if a session has reactive API (subscribe/getSnapshot) */\nexport function isObservableSession<TCustom extends Record<string, unknown> = Record<string, unknown>>(\n session: ChatSession<TCustom>,\n): session is ObservableSession<TCustom> {\n return \"subscribe\" in session && typeof (session as ObservableSession<TCustom>).subscribe === \"function\"\n && \"getSnapshot\" in session && typeof (session as ObservableSession<TCustom>).getSnapshot === \"function\";\n}\n","import { ErrorCode } from \"./types/errors.js\";\n\n/** Options for constructing an AgentSDKError */\nexport interface AgentSDKErrorOptions extends ErrorOptions {\n /** Machine-readable error code */\n code?: string;\n /** Whether this error is retryable (default: false) */\n retryable?: boolean;\n /** HTTP status code hint (e.g. 401, 429, 500) */\n httpStatus?: number;\n}\n\n/** Base error class for agent-sdk.\n *\n * Use `AgentSDKError.is(err)` for reliable cross-module `instanceof` checks\n * (works across separately bundled entry points where `instanceof` may fail). */\nexport class AgentSDKError extends Error {\n /** @internal Marker for cross-bundle identity checks */\n readonly _agentSDKError = true as const;\n /** Machine-readable error code. Prefer values from the ErrorCode enum. */\n readonly code?: string;\n /** Whether this error is safe to retry */\n readonly retryable: boolean;\n /** HTTP status code hint for error classification */\n readonly httpStatus?: number;\n\n constructor(message: string, options?: AgentSDKErrorOptions) {\n super(message, options);\n this.name = \"AgentSDKError\";\n this.code = options?.code;\n this.retryable = options?.retryable ?? false;\n this.httpStatus = options?.httpStatus;\n }\n\n /** Check if an error is an AgentSDKError (works across bundled copies) */\n static is(error: unknown): error is AgentSDKError {\n return (\n error instanceof Error &&\n \"_agentSDKError\" in error &&\n (error as AgentSDKError)._agentSDKError === true\n );\n }\n}\n\n/** Thrown when agent.run() is called while already running (M8 re-entrancy guard) */\nexport class ReentrancyError extends AgentSDKError {\n constructor() {\n super(\"Agent is already running. Await the current run before starting another.\", {\n code: ErrorCode.REENTRANCY,\n });\n this.name = \"ReentrancyError\";\n }\n}\n\n/** Thrown when an operation is attempted on a disposed agent/service */\nexport class DisposedError extends AgentSDKError {\n constructor(entity: string) {\n super(`${entity} has been disposed and cannot be used.`, {\n code: ErrorCode.DISPOSED,\n });\n this.name = \"DisposedError\";\n }\n}\n\n/** Thrown when a backend is not found in the registry */\nexport class BackendNotFoundError extends AgentSDKError {\n constructor(backend: string) {\n super(\n `Unknown backend: \"${backend}\". ` +\n `Built-in: copilot, claude, vercel-ai. ` +\n `Custom: use registerBackend() first.`,\n { code: ErrorCode.BACKEND_NOT_INSTALLED },\n );\n this.name = \"BackendNotFoundError\";\n }\n}\n\n/** Thrown when a backend is already registered */\nexport class BackendAlreadyRegisteredError extends AgentSDKError {\n constructor(backend: string) {\n super(`Backend \"${backend}\" is already registered. Use a different name or unregister first.`);\n this.name = \"BackendAlreadyRegisteredError\";\n }\n}\n\n/** Thrown when subprocess management fails */\nexport class SubprocessError extends AgentSDKError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, { ...options, code: ErrorCode.DEPENDENCY_MISSING });\n this.name = \"SubprocessError\";\n }\n}\n\n/** Thrown when a required peer dependency is not installed */\nexport class DependencyError extends AgentSDKError {\n public readonly packageName: string;\n\n constructor(packageName: string) {\n super(`${packageName} is not installed. Install it: npm install ${packageName}`, {\n code: ErrorCode.DEPENDENCY_MISSING,\n });\n this.name = \"DependencyError\";\n this.packageName = packageName;\n }\n}\n\n/** Thrown when an agent run is aborted */\nexport class AbortError extends AgentSDKError {\n constructor() {\n super(\"Agent run was aborted.\", { code: ErrorCode.ABORTED });\n this.name = \"AbortError\";\n }\n}\n\n/** Thrown when a tool execution fails */\nexport class ToolExecutionError extends AgentSDKError {\n public readonly toolName: string;\n\n constructor(toolName: string, message: string, options?: ErrorOptions) {\n super(`Tool \"${toolName}\" failed: ${message}`, { ...options, code: ErrorCode.TOOL_EXECUTION });\n this.name = \"ToolExecutionError\";\n this.toolName = toolName;\n }\n}\n\n/** Thrown when a stream has no activity within the configured timeout */\nexport class ActivityTimeoutError extends AgentSDKError {\n constructor(timeoutMs: number) {\n super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {\n code: ErrorCode.TIMEOUT,\n retryable: true,\n });\n this.name = \"ActivityTimeoutError\";\n }\n}\n\n/** Thrown when structured output parsing fails */\nexport class StructuredOutputError extends AgentSDKError {\n constructor(message: string, options?: ErrorOptions) {\n super(`Structured output error: ${message}`, { ...options, code: ErrorCode.INVALID_RESPONSE });\n this.name = \"StructuredOutputError\";\n }\n}\n","/**\n * @witqq/agent-sdk/chat/storage\n *\n * Generic storage adapter layer with pluggable backends.\n * Provides CRUD operations for any data type via `IStorageAdapter<T>`.\n * Implementations: `InMemoryStorage` (Map-based) and `FileStorage` (JSON files).\n */\n\nimport { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { AgentSDKError } from \"../errors.js\";\nimport { ErrorCode } from \"../types/errors.js\";\n\n// ─── Storage Errors ────────────────────────────────────────────\n\n/**\n * Error thrown by storage operations.\n *\n * @example\n * ```typescript\n * try {\n * await store.get(\"missing-id\");\n * } catch (e) {\n * if (e instanceof StorageError && e.code === ErrorCode.STORAGE_NOT_FOUND) {\n * // handle missing item\n * }\n * }\n * ```\n */\nexport class StorageError extends AgentSDKError {\n /** Machine-readable error code from the unified ErrorCode enum */\n readonly code: StorageErrorCode;\n\n constructor(message: string, code: StorageErrorCode) {\n super(message);\n this.name = \"StorageError\";\n this.code = code;\n }\n}\n\n/** Storage-specific subset of ErrorCode */\nexport type StorageErrorCode =\n | ErrorCode.STORAGE_NOT_FOUND\n | ErrorCode.STORAGE_DUPLICATE_KEY\n | ErrorCode.STORAGE_IO_ERROR\n | ErrorCode.STORAGE_SERIALIZATION_ERROR;\n\n// ─── Storage Adapter Interface ─────────────────────────────────\n\n/**\n * Options for listing stored items.\n *\n * @typeParam T - The type of stored items\n */\nexport interface ListOptions<T> {\n /** Filter predicate — return `true` to include the item */\n filter?: (item: T) => boolean;\n /** Sort comparator — standard Array.sort semantics */\n sort?: (a: T, b: T) => number;\n /** Maximum number of items to return */\n limit?: number;\n /** Number of items to skip (for pagination) */\n offset?: number;\n}\n\n/**\n * Generic storage adapter for CRUD operations on any data type.\n * Items are identified by a string key.\n *\n * @typeParam T - The type of stored items\n *\n * @example\n * ```typescript\n * const store: IStorageAdapter<{ name: string }> = new InMemoryStorage();\n * await store.create(\"key1\", { name: \"Alice\" });\n * const item = await store.get(\"key1\"); // { name: \"Alice\" }\n * ```\n */\nexport interface IStorageAdapter<T> {\n /**\n * Retrieve an item by key.\n * @param key - Unique identifier\n * @returns The item, or `null` if not found\n */\n get(key: string): Promise<T | null>;\n\n /**\n * List items with optional filtering, sorting, and pagination.\n * @param options - Filter, sort, limit, offset options\n * @returns Array of matching items\n */\n list(options?: ListOptions<T>): Promise<T[]>;\n\n /**\n * Create a new item. Throws `StorageError` with code `DUPLICATE_KEY` if key exists.\n * @param key - Unique identifier\n * @param item - Data to store\n */\n create(key: string, item: T): Promise<void>;\n\n /**\n * Update an existing item. Throws `StorageError` with code `NOT_FOUND` if key missing.\n * @param key - Unique identifier\n * @param item - Updated data\n */\n update(key: string, item: T): Promise<void>;\n\n /**\n * Delete an item by key. Throws `StorageError` with code `NOT_FOUND` if key missing.\n * @param key - Unique identifier\n */\n delete(key: string): Promise<void>;\n\n /**\n * Check whether a key exists.\n * @param key - Unique identifier\n * @returns `true` if key exists\n */\n has(key: string): Promise<boolean>;\n\n /**\n * Return the number of stored items.\n * @returns Count of items\n */\n count(): Promise<number>;\n\n /**\n * Remove all items from storage.\n */\n clear(): Promise<void>;\n\n /**\n * Release any resources held by this adapter (DB connections, file handles).\n * Optional — adapters that don't hold resources need not implement this.\n */\n dispose?(): Promise<void>;\n}\n\n// ─── InMemoryStorage ───────────────────────────────────────────\n\n/**\n * In-memory storage adapter backed by a `Map`.\n * Suitable for development, testing, and short-lived processes.\n * Data is lost when the process exits.\n *\n * @typeParam T - The type of stored items\n *\n * @example\n * ```typescript\n * const store = new InMemoryStorage<{ name: string }>();\n * await store.create(\"k1\", { name: \"Alice\" });\n * await store.create(\"k2\", { name: \"Bob\" });\n * const items = await store.list({ filter: i => i.name.startsWith(\"A\") });\n * // [{ name: \"Alice\" }]\n * ```\n */\nexport class InMemoryStorage<T> implements IStorageAdapter<T> {\n private readonly data = new Map<string, T>();\n\n /** @inheritdoc */\n async get(key: string): Promise<T | null> {\n const item = this.data.get(key);\n return item !== undefined ? structuredClone(item) : null;\n }\n\n /** @inheritdoc */\n async list(options?: ListOptions<T>): Promise<T[]> {\n let items = Array.from(this.data.values()).map((item) => structuredClone(item));\n\n if (options?.filter) {\n items = items.filter(options.filter);\n }\n if (options?.sort) {\n items.sort(options.sort);\n }\n if (options?.offset !== undefined) {\n items = items.slice(options.offset);\n }\n if (options?.limit !== undefined) {\n items = items.slice(0, options.limit);\n }\n\n return items;\n }\n\n /** @inheritdoc */\n async create(key: string, item: T): Promise<void> {\n if (this.data.has(key)) {\n throw new StorageError(\n `Item with key \"${key}\" already exists`,\n ErrorCode.STORAGE_DUPLICATE_KEY,\n );\n }\n this.data.set(key, structuredClone(item));\n }\n\n /** @inheritdoc */\n async update(key: string, item: T): Promise<void> {\n if (!this.data.has(key)) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n this.data.set(key, structuredClone(item));\n }\n\n /** @inheritdoc */\n async delete(key: string): Promise<void> {\n if (!this.data.has(key)) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n this.data.delete(key);\n }\n\n /** @inheritdoc */\n async has(key: string): Promise<boolean> {\n return this.data.has(key);\n }\n\n /** @inheritdoc */\n async count(): Promise<number> {\n return this.data.size;\n }\n\n /** @inheritdoc */\n async clear(): Promise<void> {\n this.data.clear();\n }\n}\n\n// ─── FileStorage ───────────────────────────────────────────────\n\n/**\n * Options for configuring `FileStorage`.\n */\nexport interface FileStorageOptions {\n /** Directory path where JSON files are stored */\n directory: string;\n /** File extension (default: `.json`) */\n extension?: string;\n}\n\n/**\n * File-based storage adapter that persists each item as a JSON file.\n * Suitable for local applications, CLI tools, and development.\n * Creates the storage directory if it doesn't exist.\n *\n * @typeParam T - The type of stored items (must be JSON-serializable)\n *\n * @example\n * ```typescript\n * const store = new FileStorage<ChatSession>({\n * directory: \"./data/sessions\",\n * });\n * await store.create(\"session-1\", mySession);\n * ```\n */\nexport class FileStorage<T> implements IStorageAdapter<T> {\n private readonly directory: string;\n private readonly extension: string;\n\n constructor(options: FileStorageOptions) {\n this.directory = options.directory;\n this.extension = options.extension ?? \".json\";\n this.ensureDirectory();\n }\n\n /** @inheritdoc */\n async get(key: string): Promise<T | null> {\n const filePath = this.keyToPath(key);\n if (!existsSync(filePath)) {\n return null;\n }\n return this.readFile(filePath);\n }\n\n /** @inheritdoc */\n async list(options?: ListOptions<T>): Promise<T[]> {\n this.ensureDirectory();\n const files = readdirSync(this.directory).filter((f) =>\n f.endsWith(this.extension),\n );\n\n let items: T[] = [];\n for (const file of files) {\n const item = this.readFile(join(this.directory, file));\n items.push(item);\n }\n\n if (options?.filter) {\n items = items.filter(options.filter);\n }\n if (options?.sort) {\n items.sort(options.sort);\n }\n if (options?.offset !== undefined) {\n items = items.slice(options.offset);\n }\n if (options?.limit !== undefined) {\n items = items.slice(0, options.limit);\n }\n\n return items;\n }\n\n /** @inheritdoc */\n async create(key: string, item: T): Promise<void> {\n const filePath = this.keyToPath(key);\n if (existsSync(filePath)) {\n throw new StorageError(\n `Item with key \"${key}\" already exists`,\n ErrorCode.STORAGE_DUPLICATE_KEY,\n );\n }\n this.writeFile(filePath, item);\n }\n\n /** @inheritdoc */\n async update(key: string, item: T): Promise<void> {\n const filePath = this.keyToPath(key);\n if (!existsSync(filePath)) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n this.writeFile(filePath, item);\n }\n\n /** @inheritdoc */\n async delete(key: string): Promise<void> {\n const filePath = this.keyToPath(key);\n if (!existsSync(filePath)) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n unlinkSync(filePath);\n }\n\n /** @inheritdoc */\n async has(key: string): Promise<boolean> {\n return existsSync(this.keyToPath(key));\n }\n\n /** @inheritdoc */\n async count(): Promise<number> {\n this.ensureDirectory();\n return readdirSync(this.directory).filter((f) =>\n f.endsWith(this.extension),\n ).length;\n }\n\n /** @inheritdoc */\n async clear(): Promise<void> {\n this.ensureDirectory();\n const files = readdirSync(this.directory).filter((f) =>\n f.endsWith(this.extension),\n );\n for (const file of files) {\n unlinkSync(join(this.directory, file));\n }\n }\n\n private keyToPath(key: string): string {\n const safeKey = key.replace(/[^a-zA-Z0-9_-]/g, (c) =>\n \"%\" + c.charCodeAt(0).toString(16).padStart(2, \"0\"),\n );\n return join(this.directory, `${safeKey}${this.extension}`);\n }\n\n private ensureDirectory(): void {\n if (!existsSync(this.directory)) {\n mkdirSync(this.directory, { recursive: true });\n }\n }\n\n private readFile(filePath: string): T {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new StorageError(\n `Failed to parse file: ${filePath}`,\n ErrorCode.STORAGE_SERIALIZATION_ERROR,\n );\n }\n throw new StorageError(\n `Failed to read file: ${filePath}`,\n ErrorCode.STORAGE_IO_ERROR,\n );\n }\n }\n\n private writeFile(filePath: string, item: T): void {\n try {\n const content = JSON.stringify(item, null, 2);\n writeFileSync(filePath, content, \"utf-8\");\n } catch {\n throw new StorageError(\n `Failed to write file: ${filePath}`,\n ErrorCode.STORAGE_IO_ERROR,\n );\n }\n }\n}\n","/**\n * SQLite-backed session store implementing IChatSessionStore.\n *\n * Uses better-sqlite3 for synchronous database access wrapped in\n * async interface. Messages are stored with position ordering for\n * deterministic retrieval. Parts and metadata are JSON-serialized.\n *\n * Accepts a shared Database instance — multiple stores can share\n * a single SQLite file via the factory function.\n */\n\nimport type Database from \"better-sqlite3\";\nimport type { ChatSession, ChatMessage, ChatId, ChatSessionConfig, SessionStatus } from \"../core.js\";\nimport { createChatId } from \"../core.js\";\nimport type {\n IChatSessionStore,\n CreateSessionOptions,\n PaginatedMessages,\n SessionListOptions,\n SessionSearchOptions,\n} from \"../sessions.js\";\nimport { StorageError } from \"../storage.js\";\nimport { ErrorCode } from \"../../types/errors.js\";\n\n// ─── Schema ────────────────────────────────────────────────────\n\nconst CREATE_SESSIONS_TABLE = `\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n title TEXT,\n config TEXT NOT NULL,\n metadata TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'active',\n backend_session_id TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )\n`;\n\nconst CREATE_MESSAGES_TABLE = `\n CREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n role TEXT NOT NULL,\n parts TEXT NOT NULL,\n metadata TEXT,\n status TEXT NOT NULL DEFAULT 'complete',\n created_at TEXT NOT NULL,\n updated_at TEXT,\n position INTEGER NOT NULL,\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE\n )\n`;\n\nconst CREATE_MESSAGES_SESSION_IDX = `\n CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id, position)\n`;\n\n// ─── SQLiteSessionStore ────────────────────────────────────────\n\nexport class SQLiteSessionStore implements IChatSessionStore {\n private readonly db: Database.Database;\n\n constructor(db: Database.Database) {\n this.db = db;\n this.db.exec(CREATE_SESSIONS_TABLE);\n this.db.exec(CREATE_MESSAGES_TABLE);\n this.db.exec(CREATE_MESSAGES_SESSION_IDX);\n }\n\n async createSession(options: CreateSessionOptions = {}): Promise<ChatSession> {\n const id = createChatId();\n const now = new Date().toISOString();\n const config: ChatSessionConfig = {\n model: \"default\",\n backend: \"default\",\n ...options.config,\n };\n const metadata = {\n messageCount: 0,\n totalTokens: 0,\n tags: options.tags,\n custom: options.custom,\n };\n\n this.db.prepare(`\n INSERT INTO sessions (id, title, config, metadata, status, created_at, updated_at)\n VALUES (?, ?, ?, ?, 'active', ?, ?)\n `).run(id, options.title ?? null, JSON.stringify(config), JSON.stringify(metadata), now, now);\n\n return this.buildSession(id, options.title, config, metadata, \"active\", now, now, []);\n }\n\n async getSession(id: ChatId): Promise<ChatSession | null> {\n const row = this.db.prepare(\"SELECT * FROM sessions WHERE id = ?\").get(id) as SessionRow | undefined;\n if (!row) return null;\n\n const messages = this.loadAllMessages(row.id);\n return this.rowToSession(row, messages);\n }\n\n async listSessions(options?: SessionListOptions): Promise<ChatSession[]> {\n const rows = this.db.prepare(\"SELECT * FROM sessions ORDER BY updated_at DESC\").all() as SessionRow[];\n\n let sessions = rows.map((r) => this.rowToSession(r, []));\n\n if (options?.filter) sessions = sessions.filter(options.filter);\n if (options?.sort) sessions.sort(options.sort);\n if (options?.offset) sessions = sessions.slice(options.offset);\n if (options?.limit) sessions = sessions.slice(0, options.limit);\n\n return sessions;\n }\n\n async updateTitle(id: ChatId, title: string): Promise<void> {\n const result = this.db.prepare(\n \"UPDATE sessions SET title = ?, updated_at = ? WHERE id = ?\",\n ).run(title, new Date().toISOString(), id);\n if (result.changes === 0) throw new StorageError(`Session not found: ${id}`, ErrorCode.STORAGE_NOT_FOUND);\n }\n\n async updateConfig(id: ChatId, config: Partial<ChatSessionConfig>): Promise<void> {\n const row = this.db.prepare(\"SELECT config FROM sessions WHERE id = ?\").get(id) as { config: string } | undefined;\n if (!row) throw new StorageError(`Session not found: ${id}`, ErrorCode.STORAGE_NOT_FOUND);\n\n const merged = { ...JSON.parse(row.config), ...config };\n this.db.prepare(\n \"UPDATE sessions SET config = ?, updated_at = ? WHERE id = ?\",\n ).run(JSON.stringify(merged), new Date().toISOString(), id);\n }\n\n async deleteSession(id: ChatId): Promise<void> {\n const result = this.db.prepare(\"DELETE FROM sessions WHERE id = ?\").run(id);\n if (result.changes === 0) throw new StorageError(`Session not found: ${id}`, ErrorCode.STORAGE_NOT_FOUND);\n }\n\n async appendMessage(sessionId: ChatId, message: ChatMessage): Promise<void> {\n const session = this.db.prepare(\"SELECT id FROM sessions WHERE id = ?\").get(sessionId) as { id: string } | undefined;\n if (!session) throw new StorageError(`Session not found: ${sessionId}`, ErrorCode.STORAGE_NOT_FOUND);\n\n const position = this.getNextPosition(sessionId);\n\n this.db.prepare(`\n INSERT INTO messages (id, session_id, role, parts, metadata, status, created_at, updated_at, position)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n message.id,\n sessionId,\n message.role,\n JSON.stringify(message.parts),\n message.metadata ? JSON.stringify(message.metadata) : null,\n message.status,\n message.createdAt,\n message.updatedAt ?? null,\n position,\n );\n\n this.incrementMessageCount(sessionId);\n }\n\n async saveMessages(sessionId: ChatId, messages: ChatMessage[]): Promise<void> {\n if (messages.length === 0) return;\n\n const session = this.db.prepare(\"SELECT id FROM sessions WHERE id = ?\").get(sessionId) as { id: string } | undefined;\n if (!session) throw new StorageError(`Session not found: ${sessionId}`, ErrorCode.STORAGE_NOT_FOUND);\n\n const insertMsg = this.db.prepare(`\n INSERT INTO messages (id, session_id, role, parts, metadata, status, created_at, updated_at, position)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const tx = this.db.transaction(() => {\n let pos = this.getNextPosition(sessionId);\n for (const msg of messages) {\n insertMsg.run(\n msg.id, sessionId, msg.role,\n JSON.stringify(msg.parts),\n msg.metadata ? JSON.stringify(msg.metadata) : null,\n msg.status, msg.createdAt, msg.updatedAt ?? null, pos++,\n );\n }\n this.updateSessionMeta(sessionId, messages.length);\n });\n tx();\n }\n\n async loadMessages(\n sessionId: ChatId,\n options?: { limit?: number; offset?: number },\n ): Promise<PaginatedMessages> {\n const session = this.db.prepare(\"SELECT id FROM sessions WHERE id = ?\").get(sessionId) as { id: string } | undefined;\n if (!session) throw new StorageError(`Session not found: ${sessionId}`, ErrorCode.STORAGE_NOT_FOUND);\n\n const total = (this.db.prepare(\n \"SELECT COUNT(*) as cnt FROM messages WHERE session_id = ?\",\n ).get(sessionId) as { cnt: number }).cnt;\n\n const limit = options?.limit ?? 50;\n const offset = options?.offset ?? 0;\n\n const rows = this.db.prepare(\n \"SELECT * FROM messages WHERE session_id = ? ORDER BY position ASC LIMIT ? OFFSET ?\",\n ).all(sessionId, limit, offset) as MessageRow[];\n\n return {\n messages: rows.map(rowToMessage),\n total,\n hasMore: offset + limit < total,\n };\n }\n\n async searchSessions(options: SessionSearchOptions): Promise<ChatSession[]> {\n const pattern = `%${options.query}%`;\n const limit = options.limit ?? 20;\n\n const titleMatches = this.db.prepare(\n \"SELECT * FROM sessions WHERE title LIKE ? COLLATE NOCASE LIMIT ?\",\n ).all(pattern, limit) as SessionRow[];\n\n const contentMatches = this.db.prepare(`\n SELECT DISTINCT s.* FROM sessions s\n JOIN messages m ON m.session_id = s.id\n WHERE m.parts LIKE ? COLLATE NOCASE\n LIMIT ?\n `).all(pattern, limit) as SessionRow[];\n\n const seen = new Set<string>();\n const results: ChatSession[] = [];\n for (const row of [...titleMatches, ...contentMatches]) {\n if (!seen.has(row.id)) {\n seen.add(row.id);\n results.push(this.rowToSession(row, []));\n }\n }\n\n return results.slice(0, limit);\n }\n\n async count(): Promise<number> {\n return (this.db.prepare(\"SELECT COUNT(*) as cnt FROM sessions\").get() as { cnt: number }).cnt;\n }\n\n async clear(): Promise<void> {\n this.db.exec(\"DELETE FROM messages\");\n this.db.exec(\"DELETE FROM sessions\");\n }\n\n // ─── Private Helpers ─────────────────────────────────────────\n\n private getNextPosition(sessionId: string): number {\n const result = this.db.prepare(\n \"SELECT MAX(position) as maxPos FROM messages WHERE session_id = ?\",\n ).get(sessionId) as { maxPos: number | null };\n return (result.maxPos ?? -1) + 1;\n }\n\n private incrementMessageCount(sessionId: string): void {\n this.db.prepare(`\n UPDATE sessions\n SET metadata = json_set(metadata, '$.messageCount', json_extract(metadata, '$.messageCount') + 1),\n updated_at = ?\n WHERE id = ?\n `).run(new Date().toISOString(), sessionId);\n }\n\n private updateSessionMeta(sessionId: string, addedCount: number): void {\n this.db.prepare(`\n UPDATE sessions\n SET metadata = json_set(metadata, '$.messageCount', json_extract(metadata, '$.messageCount') + ?),\n updated_at = ?\n WHERE id = ?\n `).run(addedCount, new Date().toISOString(), sessionId);\n }\n\n private loadAllMessages(sessionId: string): ChatMessage[] {\n const rows = this.db.prepare(\n \"SELECT * FROM messages WHERE session_id = ? ORDER BY position ASC\",\n ).all(sessionId) as MessageRow[];\n return rows.map(rowToMessage);\n }\n\n private rowToSession(row: SessionRow, messages: ChatMessage[]): ChatSession {\n return this.buildSession(\n row.id as ChatId,\n row.title,\n JSON.parse(row.config),\n JSON.parse(row.metadata),\n row.status as SessionStatus,\n row.created_at,\n row.updated_at,\n messages,\n );\n }\n\n private buildSession(\n id: ChatId,\n title: string | undefined | null,\n config: ChatSessionConfig,\n metadata: ChatSession[\"metadata\"],\n status: SessionStatus,\n createdAt: string,\n updatedAt: string,\n messages: ChatMessage[],\n ): ChatSession {\n return {\n id,\n title: title ?? undefined,\n messages,\n config,\n metadata,\n status,\n createdAt,\n updatedAt,\n };\n }\n}\n\n// ─── Row Types ─────────────────────────────────────────────────\n\ninterface SessionRow {\n id: string;\n title: string | null;\n config: string;\n metadata: string;\n status: string;\n backend_session_id: string | null;\n created_at: string;\n updated_at: string;\n}\n\ninterface MessageRow {\n id: string;\n session_id: string;\n role: string;\n parts: string;\n metadata: string | null;\n status: string;\n created_at: string;\n updated_at: string | null;\n position: number;\n}\n\nfunction rowToMessage(row: MessageRow): ChatMessage {\n return {\n id: row.id as ChatId,\n role: row.role as ChatMessage[\"role\"],\n parts: JSON.parse(row.parts),\n metadata: row.metadata ? JSON.parse(row.metadata) : undefined,\n status: row.status as ChatMessage[\"status\"],\n createdAt: row.created_at,\n updatedAt: row.updated_at ?? undefined,\n };\n}\n","/**\n * SQLite-backed provider store implementing IProviderStore.\n *\n * Stores provider configurations in a `providers` table within\n * a shared SQLite database. Schema auto-created on construction.\n */\n\nimport type Database from \"better-sqlite3\";\nimport type { IProviderStore, ProviderConfig } from \"../provider-types.js\";\n\n// ─── Schema ────────────────────────────────────────────────────\n\nconst CREATE_PROVIDERS_TABLE = `\n CREATE TABLE IF NOT EXISTS providers (\n id TEXT PRIMARY KEY,\n backend TEXT NOT NULL,\n model TEXT NOT NULL,\n label TEXT NOT NULL,\n created_at INTEGER NOT NULL\n )\n`;\n\n// ─── SQLiteProviderStore ───────────────────────────────────────\n\nexport class SQLiteProviderStore implements IProviderStore {\n private readonly db: Database.Database;\n\n constructor(db: Database.Database) {\n this.db = db;\n this.db.exec(CREATE_PROVIDERS_TABLE);\n }\n\n async create(config: ProviderConfig): Promise<void> {\n this.db.prepare(`\n INSERT INTO providers (id, backend, model, label, created_at)\n VALUES (?, ?, ?, ?, ?)\n `).run(config.id, config.backend, config.model, config.label, config.createdAt);\n }\n\n async get(id: string): Promise<ProviderConfig | null> {\n const row = this.db.prepare(\"SELECT * FROM providers WHERE id = ?\").get(id) as ProviderRow | undefined;\n return row ? rowToProvider(row) : null;\n }\n\n async update(id: string, changes: Partial<Omit<ProviderConfig, \"id\" | \"createdAt\">>): Promise<void> {\n const existing = this.db.prepare(\"SELECT id FROM providers WHERE id = ?\").get(id) as { id: string } | undefined;\n if (!existing) throw new Error(`Provider \"${id}\" not found`);\n\n const sets: string[] = [];\n const values: unknown[] = [];\n if (changes.backend !== undefined) { sets.push(\"backend = ?\"); values.push(changes.backend); }\n if (changes.model !== undefined) { sets.push(\"model = ?\"); values.push(changes.model); }\n if (changes.label !== undefined) { sets.push(\"label = ?\"); values.push(changes.label); }\n\n if (sets.length > 0) {\n values.push(id);\n this.db.prepare(`UPDATE providers SET ${sets.join(\", \")} WHERE id = ?`).run(...values);\n }\n }\n\n async delete(id: string): Promise<void> {\n this.db.prepare(\"DELETE FROM providers WHERE id = ?\").run(id);\n }\n\n async list(): Promise<ProviderConfig[]> {\n const rows = this.db.prepare(\"SELECT * FROM providers ORDER BY created_at ASC\").all() as ProviderRow[];\n return rows.map(rowToProvider);\n }\n}\n\n// ─── Row Types ─────────────────────────────────────────────────\n\ninterface ProviderRow {\n id: string;\n backend: string;\n model: string;\n label: string;\n created_at: number;\n}\n\nfunction rowToProvider(row: ProviderRow): ProviderConfig {\n return {\n id: row.id,\n backend: row.backend,\n model: row.model,\n label: row.label,\n createdAt: row.created_at,\n };\n}\n","/**\n * SQLite-backed token store implementing ITokenStore.\n *\n * Stores auth tokens as JSON in a `tokens` table within\n * a shared SQLite database. Schema auto-created on construction.\n */\n\nimport type Database from \"better-sqlite3\";\nimport type { ITokenStore } from \"../server/token-store.js\";\nimport type { AuthToken } from \"../../auth/types.js\";\n\n// ─── Schema ────────────────────────────────────────────────────\n\nconst CREATE_TOKENS_TABLE = `\n CREATE TABLE IF NOT EXISTS tokens (\n provider TEXT PRIMARY KEY,\n token_json TEXT NOT NULL,\n saved_at INTEGER NOT NULL\n )\n`;\n\n// ─── SQLiteTokenStore ──────────────────────────────────────────\n\nexport class SQLiteTokenStore implements ITokenStore {\n private readonly db: Database.Database;\n\n constructor(db: Database.Database) {\n this.db = db;\n this.db.exec(CREATE_TOKENS_TABLE);\n }\n\n async save(provider: string, token: AuthToken): Promise<void> {\n this.db.prepare(`\n INSERT OR REPLACE INTO tokens (provider, token_json, saved_at)\n VALUES (?, ?, ?)\n `).run(provider, JSON.stringify(token), Date.now());\n }\n\n async load(provider: string): Promise<AuthToken | null> {\n const row = this.db.prepare(\"SELECT token_json FROM tokens WHERE provider = ?\").get(provider) as { token_json: string } | undefined;\n return row ? JSON.parse(row.token_json) as AuthToken : null;\n }\n\n async clear(provider: string): Promise<void> {\n this.db.prepare(\"DELETE FROM tokens WHERE provider = ?\").run(provider);\n }\n\n async clearAll(): Promise<void> {\n this.db.exec(\"DELETE FROM tokens\");\n }\n\n async list(): Promise<string[]> {\n const rows = this.db.prepare(\"SELECT provider FROM tokens ORDER BY saved_at ASC\").all() as { provider: string }[];\n return rows.map(r => r.provider);\n }\n}\n","/**\n * Factory function for creating all three SQLite stores from a single database path.\n *\n * @example\n * ```ts\n * import { createSQLiteStorage } from \"@witqq/agent-sdk/chat/sqlite\";\n *\n * const storage = createSQLiteStorage(\"/data/chat.db\");\n * // storage.sessionStore — IChatSessionStore\n * // storage.providerStore — IProviderStore\n * // storage.tokenStore — ITokenStore\n * // storage.db — raw Database instance\n * ```\n */\n\nimport { createRequire } from \"node:module\";\nimport type Database from \"better-sqlite3\";\nimport { SQLiteSessionStore } from \"./session-store.js\";\nimport { SQLiteProviderStore } from \"./provider-store.js\";\nimport { SQLiteTokenStore } from \"./token-store.js\";\nimport type { IChatSessionStore } from \"../sessions.js\";\nimport type { IProviderStore } from \"../provider-types.js\";\nimport type { ITokenStore } from \"../server/token-store.js\";\n\n// ─── Types ─────────────────────────────────────────────────────\n\nexport interface SQLiteStorageOptions {\n /** Path to SQLite database file. Use \":memory:\" for in-memory database. */\n dbPath: string;\n /** Optional pre-created Database instance. If provided, dbPath is ignored. */\n db?: Database.Database;\n}\n\nexport interface SQLiteStorage {\n /** The underlying better-sqlite3 Database instance */\n db: Database.Database;\n /** Session store for chat sessions and messages */\n sessionStore: IChatSessionStore;\n /** Provider store for provider configurations */\n providerStore: IProviderStore;\n /** Token store for auth tokens */\n tokenStore: ITokenStore;\n}\n\n// ─── Factory ───────────────────────────────────────────────────\n\n/**\n * Create all three SQLite stores sharing a single database.\n *\n * Requires `better-sqlite3` as a peer dependency.\n * Schema tables are auto-created on first use.\n *\n * @param pathOrOptions - Database file path string, or options object\n * @returns Object with db, sessionStore, providerStore, tokenStore\n *\n * @throws If better-sqlite3 is not installed\n */\nexport function createSQLiteStorage(pathOrOptions: string | SQLiteStorageOptions): SQLiteStorage {\n let db: Database.Database;\n\n if (typeof pathOrOptions === \"string\") {\n db = createDatabase(pathOrOptions);\n } else if (pathOrOptions.db) {\n db = pathOrOptions.db;\n } else {\n db = createDatabase(pathOrOptions.dbPath);\n }\n\n // Enable WAL + foreign keys once for the shared connection\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"foreign_keys = ON\");\n\n return {\n db,\n sessionStore: new SQLiteSessionStore(db),\n providerStore: new SQLiteProviderStore(db),\n tokenStore: new SQLiteTokenStore(db),\n };\n}\n\nfunction createDatabase(dbPath: string): Database.Database {\n try {\n // createRequire for ESM compatibility — better-sqlite3 is a CJS native addon\n const esmRequire = createRequire(import.meta.url);\n const BetterSqlite3 = esmRequire(\"better-sqlite3\") as typeof Database;\n return new BetterSqlite3(dbPath);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n if (message.includes(\"Cannot find module\") || message.includes(\"MODULE_NOT_FOUND\")) {\n throw new Error(\n \"better-sqlite3 is required for SQLite storage. Install it: npm install better-sqlite3\",\n );\n }\n throw err;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/chat/types.ts","../../src/errors.ts","../../src/chat/storage.ts","../../src/chat/sqlite/session-store.ts","../../src/chat/sqlite/provider-store.ts","../../src/chat/sqlite/token-store.ts","../../src/chat/sqlite/migrations.ts","../../src/chat/sqlite/factory.ts"],"names":[],"mappings":"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","file":"sqlite.js","sourcesContent":["/**\n * @witqq/agent-sdk — Chat domain types\n *\n * All type definitions and interfaces for the chat layer.\n * Pure types + ChatId generation (tightly coupled to branded type).\n */\n\nimport type { UsageData, ToolDefinition, ErrorCode } from \"../types.js\";\nimport type { AuthToken } from \"../auth/types.js\";\n\n// ─── Unique ID ─────────────────────────────────────────────────\n\n/** Branded type for unique identifiers */\nexport type ChatId = string & { readonly __brand: \"ChatId\" };\n\n/**\n * Generate a new unique ChatId (crypto.randomUUID-based)\n * @returns Branded ChatId string\n */\nexport function createChatId(): ChatId {\n return crypto.randomUUID() as ChatId;\n}\n\n/** UUID v4 pattern for ChatId validation */\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n/**\n * Cast a string to ChatId with UUID format validation.\n * Use this instead of manual `as ChatId` type assertions.\n *\n * @param value - String to validate and cast\n * @returns Branded ChatId\n * @throws {TypeError} If value is not a valid UUID v4 format\n */\nexport function toChatId(value: string): ChatId {\n if (!UUID_RE.test(value)) {\n throw new TypeError(`Invalid ChatId: \"${value}\" is not a valid UUID`);\n }\n return value as ChatId;\n}\n\n/**\n * Accepts either a plain string or branded ChatId for API convenience.\n * Use this in public API signatures so consumers don't need `as ChatId` casts.\n */\nexport type ChatIdLike = string | ChatId;\n\n// ─── Status Types ──────────────────────────────────────────────\n\n/** Lifecycle status of a message part (text, reasoning, etc.) */\nexport type PartStatus = \"pending\" | \"streaming\" | \"complete\" | \"error\";\n/** Lifecycle status of a tool call within a message */\nexport type ToolCallStatus = \"pending\" | \"running\" | \"requires_approval\" | \"complete\" | \"error\" | \"denied\";\n/** Lifecycle status of an entire message */\nexport type MessageStatus = \"pending\" | \"streaming\" | \"complete\" | \"error\" | \"cancelled\";\n/** Lifecycle status of a chat session */\nexport type SessionStatus = \"active\";\n/** Lifecycle status of the chat runtime */\nexport type RuntimeStatus = \"idle\" | \"streaming\" | \"error\" | \"disposed\";\n\n// ─── Message Parts (union) ─────────────────────────────────────\n\n/** Plain text content part */\nexport interface TextPart { type: \"text\"; text: string; status: PartStatus; }\n/** Model reasoning/thinking content part */\nexport interface ReasoningPart { type: \"reasoning\"; text: string; status: PartStatus; }\n/** Tool invocation part with call ID, arguments, optional result */\nexport interface ToolCallPart { type: \"tool_call\"; toolCallId: string; name: string; args: unknown; result?: unknown; status: ToolCallStatus; error?: string; }\n/** Source reference part (URL citation) */\nexport interface SourcePart { type: \"source\"; url: string; title?: string; status: PartStatus; }\n/** File attachment part (base64-encoded data) */\nexport interface FilePart { type: \"file\"; name: string; mimeType: string; data: string; status: PartStatus; }\n/** Union of all message part types */\nexport type MessagePart = TextPart | ReasoningPart | ToolCallPart | SourcePart | FilePart;\n\n// ─── Chat Message ──────────────────────────────────────────────\n\n/** Role of message author */\nexport type ChatRole = \"user\" | \"assistant\" | \"system\";\n\n/** Metadata attached to messages — useful preset for the TMetadata generic */\nexport interface ChatMessageMetadata {\n model?: string;\n backend?: string;\n usage?: UsageData;\n isSummary?: boolean;\n estimatedTokens?: number;\n custom?: Record<string, unknown>;\n}\n\n/** Message status */\nexport type ChatMessageStatus = MessageStatus;\n\n/** A single chat message — the fundamental unit of conversation */\nexport interface ChatMessage<TMetadata = unknown> {\n id: ChatId;\n role: ChatRole;\n parts: MessagePart[];\n metadata?: TMetadata;\n createdAt: string;\n updatedAt?: string;\n status: MessageStatus;\n}\n\n// ─── Supporting Types ──────────────────────────────────────────\n\n// ─── Chat Session ──────────────────────────────────────────────\n\n/** Session configuration snapshot */\nexport interface ChatSessionConfig {\n model: string;\n backend: string;\n systemPrompt?: string;\n temperature?: number;\n maxTokens?: number;\n}\n\n/**\n * Session metadata tracking usage statistics and custom extensions.\n *\n * Updated automatically by session stores on each `addMessage()` call.\n * The generic `TCustom` parameter allows type-safe application-specific\n * metadata via the `custom` field.\n *\n * @typeParam TCustom - Shape of the `custom` field (defaults to `Record<string, unknown>`)\n */\nexport interface ChatSessionMetadata<TCustom extends Record<string, unknown> = Record<string, unknown>> {\n /** Number of messages in the session (updated by session store) */\n messageCount: number;\n /** Total token count across all messages in the session */\n totalTokens: number;\n /** Optional tags for session categorization and filtering */\n tags?: string[];\n /** Application-specific metadata — typed via the TCustom generic parameter */\n custom?: TCustom;\n}\n\n/** Chat session — a conversation with ordered messages (pure serializable data) */\nexport interface ChatSession<TCustom extends Record<string, unknown> = Record<string, unknown>> {\n id: ChatId;\n title?: string;\n messages: ChatMessage[];\n config: ChatSessionConfig;\n metadata: ChatSessionMetadata<TCustom>;\n status: SessionStatus;\n createdAt: string;\n updatedAt: string;\n backendSessionId?: string;\n}\n\n/**\n * Reactive wrapper around ChatSession — provides subscribe/getSnapshot for\n * React useSyncExternalStore integration and lastMessage convenience getter.\n * Session stores may optionally return ObservableSession instances.\n */\nexport interface ObservableSession<TCustom extends Record<string, unknown> = Record<string, unknown>>\n extends ChatSession<TCustom> {\n /** Subscribe to session changes (for React useSyncExternalStore) */\n subscribe(callback: () => void): () => void;\n /** Get immutable snapshot of session state (for React useSyncExternalStore) */\n getSnapshot(): ChatSession<TCustom>;\n /** Last message in the session */\n readonly lastMessage: ChatMessage | undefined;\n}\n\n/** Lightweight session info for listing (without full message array) */\nexport interface SessionInfo {\n id: ChatId;\n title?: string;\n status: SessionStatus;\n messageCount: number;\n lastMessage?: ChatMessage;\n createdAt: string;\n updatedAt: string;\n}\n\n// ─── Chat Events ───────────────────────────────────────────────\n\n/** Events emitted during chat operation */\nexport type ChatEvent =\n | { type: \"message:start\"; messageId: ChatId; role: ChatRole }\n | { type: \"message:delta\"; messageId: ChatId; text: string }\n | { type: \"message:complete\"; messageId: ChatId; message: ChatMessage }\n | {\n type: \"tool:start\";\n messageId: ChatId;\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n }\n | {\n type: \"tool:complete\";\n messageId: ChatId;\n toolCallId: string;\n toolName: string;\n result: unknown;\n isError?: boolean;\n }\n | { type: \"thinking:start\"; messageId: ChatId }\n | { type: \"thinking:delta\"; messageId: ChatId; text: string }\n | { type: \"thinking:end\"; messageId: ChatId }\n | {\n type: \"permission:request\";\n messageId: ChatId;\n toolName: string;\n toolArgs: Record<string, unknown>;\n }\n | {\n type: \"permission:response\";\n messageId: ChatId;\n toolName: string;\n allowed: boolean;\n }\n | {\n type: \"usage\";\n promptTokens: number;\n completionTokens: number;\n model?: string;\n }\n | { type: \"session:created\"; sessionId: ChatId }\n | { type: \"session:updated\"; sessionId: ChatId }\n | {\n type: \"error\";\n error: string;\n recoverable: boolean;\n code?: ErrorCode;\n messageId?: ChatId;\n }\n | { type: \"typing:start\" }\n | { type: \"typing:end\" }\n | { type: \"heartbeat\" }\n | { type: \"done\"; finalOutput?: string; finishReason?: string };\n\n/** All possible ChatEvent type strings */\nexport type ChatEventType = ChatEvent[\"type\"];\n\n// ─── Chat Middleware ───────────────────────────────────────────\n\n/** Context passed to ChatMiddleware hooks */\nexport interface ChatMiddlewareContext {\n sessionId: ChatId;\n signal: AbortSignal;\n}\n\n/** Runtime-level middleware for the send/receive lifecycle.\n * Different from EventMiddleware which operates at the event bus level. */\nexport interface ChatMiddleware {\n /** Transform message before sending to backend. Return null to reject the send. */\n onBeforeSend?(message: ChatMessage, context: ChatMiddlewareContext): ChatMessage | null | Promise<ChatMessage | null>;\n /** Transform/intercept stream events */\n onEvent?(event: ChatEvent, context: ChatMiddlewareContext): ChatEvent | null | Promise<ChatEvent | null>;\n /** Transform completed message after receiving from backend */\n onAfterReceive?(message: ChatMessage, context: ChatMiddlewareContext): ChatMessage | Promise<ChatMessage>;\n /** Intercept errors — return null to suppress, return error to propagate */\n onError?(error: Error, context: ChatMiddlewareContext): Error | null | Promise<Error | null>;\n}\n\n// ─── Chat Provider Abstraction ─────────────────────────────────\n\n/** Options for sending a message to a provider */\nexport interface SendMessageOptions {\n signal?: AbortSignal;\n /** Model to use for this request. Required for server-side runtime.send(). */\n model?: string;\n /** Per-call system prompt override (forwarded to the backend agent) */\n systemPrompt?: string;\n context?: Record<string, unknown>;\n /** Additional tools to include in this request */\n tools?: ToolDefinition[];\n}\n\n/** Options for runtime.send() — requires backend routing info */\nexport interface RuntimeSendOptions {\n /** Backend to route this request to (key in backends map) */\n backend: string;\n /** Authentication credentials for the backend factory */\n credentials: AuthToken;\n /** Model to use for this request */\n model: string;\n /** Per-call system prompt override (forwarded to the backend agent) */\n systemPrompt?: string;\n /** Abort signal */\n signal?: AbortSignal;\n /** Request-scoped context */\n context?: Record<string, unknown>;\n /** Additional tools */\n tools?: ToolDefinition[];\n}\n\n/**\n * @deprecated IChatProvider has been inlined into IChatBackend.\n * Import IChatBackend from \"@witqq/agent-sdk/chat/backends\" instead.\n * Kept as type alias for backward compatibility.\n */\nexport type IChatProvider = import(\"./backends/types.js\").IChatBackend;\n\n// ─── Factory Functions ─────────────────────────────────────────\n\n/**\n * Create a simple text ChatMessage.\n *\n * @param text - Message text content\n * @param role - Message role (default: \"user\")\n * @returns A complete ChatMessage with a single TextPart\n */\nexport function createTextMessage(text: string, role: ChatRole = \"user\"): ChatMessage {\n return {\n id: createChatId(),\n role,\n parts: [{ type: \"text\", text, status: \"complete\" }],\n createdAt: new Date().toISOString(),\n status: \"complete\",\n };\n}\n\n/** Type guard: checks if a session has reactive API (subscribe/getSnapshot) */\nexport function isObservableSession<TCustom extends Record<string, unknown> = Record<string, unknown>>(\n session: ChatSession<TCustom>,\n): session is ObservableSession<TCustom> {\n return \"subscribe\" in session && typeof (session as ObservableSession<TCustom>).subscribe === \"function\"\n && \"getSnapshot\" in session && typeof (session as ObservableSession<TCustom>).getSnapshot === \"function\";\n}\n","import { ErrorCode } from \"./types/errors.js\";\n\n/** Options for constructing an AgentSDKError */\nexport interface AgentSDKErrorOptions extends ErrorOptions {\n /** Machine-readable error code */\n code?: string;\n /** Whether this error is retryable (default: false) */\n retryable?: boolean;\n /** HTTP status code hint (e.g. 401, 429, 500) */\n httpStatus?: number;\n}\n\n/** Base error class for agent-sdk.\n *\n * Use `AgentSDKError.is(err)` for reliable cross-module `instanceof` checks\n * (works across separately bundled entry points where `instanceof` may fail). */\nexport class AgentSDKError extends Error {\n /** @internal Marker for cross-bundle identity checks */\n readonly _agentSDKError = true as const;\n /** Machine-readable error code. Prefer values from the ErrorCode enum. */\n readonly code?: string;\n /** Whether this error is safe to retry */\n readonly retryable: boolean;\n /** HTTP status code hint for error classification */\n readonly httpStatus?: number;\n\n constructor(message: string, options?: AgentSDKErrorOptions) {\n super(message, options);\n this.name = \"AgentSDKError\";\n this.code = options?.code;\n this.retryable = options?.retryable ?? false;\n this.httpStatus = options?.httpStatus;\n }\n\n /** Check if an error is an AgentSDKError (works across bundled copies) */\n static is(error: unknown): error is AgentSDKError {\n return (\n error instanceof Error &&\n \"_agentSDKError\" in error &&\n (error as AgentSDKError)._agentSDKError === true\n );\n }\n}\n\n/** Thrown when agent.run() is called while already running (M8 re-entrancy guard) */\nexport class ReentrancyError extends AgentSDKError {\n constructor() {\n super(\"Agent is already running. Await the current run before starting another.\", {\n code: ErrorCode.REENTRANCY,\n });\n this.name = \"ReentrancyError\";\n }\n}\n\n/** Thrown when an operation is attempted on a disposed agent/service */\nexport class DisposedError extends AgentSDKError {\n constructor(entity: string) {\n super(`${entity} has been disposed and cannot be used.`, {\n code: ErrorCode.DISPOSED,\n });\n this.name = \"DisposedError\";\n }\n}\n\n/** Thrown when a backend is not found in the registry */\nexport class BackendNotFoundError extends AgentSDKError {\n constructor(backend: string) {\n super(\n `Unknown backend: \"${backend}\". ` +\n `Built-in: copilot, claude, vercel-ai. ` +\n `Custom: use registerBackend() first.`,\n { code: ErrorCode.BACKEND_NOT_INSTALLED },\n );\n this.name = \"BackendNotFoundError\";\n }\n}\n\n/** Thrown when a backend is already registered */\nexport class BackendAlreadyRegisteredError extends AgentSDKError {\n constructor(backend: string) {\n super(`Backend \"${backend}\" is already registered. Use a different name or unregister first.`);\n this.name = \"BackendAlreadyRegisteredError\";\n }\n}\n\n/** Thrown when subprocess management fails */\nexport class SubprocessError extends AgentSDKError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, { ...options, code: ErrorCode.DEPENDENCY_MISSING });\n this.name = \"SubprocessError\";\n }\n}\n\n/** Thrown when a required peer dependency is not installed */\nexport class DependencyError extends AgentSDKError {\n public readonly packageName: string;\n\n constructor(packageName: string) {\n super(`${packageName} is not installed. Install it: npm install ${packageName}`, {\n code: ErrorCode.DEPENDENCY_MISSING,\n });\n this.name = \"DependencyError\";\n this.packageName = packageName;\n }\n}\n\n/** Thrown when an agent run is aborted */\nexport class AbortError extends AgentSDKError {\n constructor() {\n super(\"Agent run was aborted.\", { code: ErrorCode.ABORTED });\n this.name = \"AbortError\";\n }\n}\n\n/** Thrown when a tool execution fails */\nexport class ToolExecutionError extends AgentSDKError {\n public readonly toolName: string;\n\n constructor(toolName: string, message: string, options?: ErrorOptions) {\n super(`Tool \"${toolName}\" failed: ${message}`, { ...options, code: ErrorCode.TOOL_EXECUTION });\n this.name = \"ToolExecutionError\";\n this.toolName = toolName;\n }\n}\n\n/** Thrown when a stream has no activity within the configured timeout */\nexport class ActivityTimeoutError extends AgentSDKError {\n constructor(timeoutMs: number) {\n super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {\n code: ErrorCode.TIMEOUT,\n retryable: true,\n });\n this.name = \"ActivityTimeoutError\";\n }\n}\n\n/** Thrown when structured output parsing fails */\nexport class StructuredOutputError extends AgentSDKError {\n constructor(message: string, options?: ErrorOptions) {\n super(`Structured output error: ${message}`, { ...options, code: ErrorCode.INVALID_RESPONSE });\n this.name = \"StructuredOutputError\";\n }\n}\n","/**\n * @witqq/agent-sdk/chat/storage\n *\n * Generic storage adapter layer with pluggable backends.\n * Provides CRUD operations for any data type via `IStorageAdapter<T>`.\n * Implementations: `InMemoryStorage` (Map-based) and `FileStorage` (JSON files).\n */\n\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { access, mkdir, readdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { AgentSDKError } from \"../errors.js\";\nimport { ErrorCode } from \"../types/errors.js\";\n\n// ─── Storage Errors ────────────────────────────────────────────\n\n/**\n * Error thrown by storage operations.\n *\n * @example\n * ```typescript\n * try {\n * await store.get(\"missing-id\");\n * } catch (e) {\n * if (e instanceof StorageError && e.code === ErrorCode.STORAGE_NOT_FOUND) {\n * // handle missing item\n * }\n * }\n * ```\n */\nexport class StorageError extends AgentSDKError {\n /** Machine-readable error code from the unified ErrorCode enum */\n readonly code: StorageErrorCode;\n\n constructor(message: string, code: StorageErrorCode) {\n super(message);\n this.name = \"StorageError\";\n this.code = code;\n }\n}\n\n/** Storage-specific subset of ErrorCode */\nexport type StorageErrorCode =\n | ErrorCode.STORAGE_NOT_FOUND\n | ErrorCode.STORAGE_DUPLICATE_KEY\n | ErrorCode.STORAGE_IO_ERROR\n | ErrorCode.STORAGE_SERIALIZATION_ERROR;\n\n// ─── Storage Adapter Interface ─────────────────────────────────\n\n/**\n * Options for listing stored items.\n *\n * @typeParam T - The type of stored items\n */\nexport interface ListOptions<T> {\n /** Filter predicate — return `true` to include the item */\n filter?: (item: T) => boolean;\n /** Sort comparator — standard Array.sort semantics */\n sort?: (a: T, b: T) => number;\n /** Maximum number of items to return */\n limit?: number;\n /** Number of items to skip (for pagination) */\n offset?: number;\n}\n\n/**\n * Generic storage adapter for CRUD operations on any data type.\n * Items are identified by a string key.\n *\n * @typeParam T - The type of stored items\n *\n * @example\n * ```typescript\n * const store: IStorageAdapter<{ name: string }> = new InMemoryStorage();\n * await store.create(\"key1\", { name: \"Alice\" });\n * const item = await store.get(\"key1\"); // { name: \"Alice\" }\n * ```\n */\nexport interface IStorageAdapter<T> {\n /**\n * Retrieve an item by key.\n * @param key - Unique identifier\n * @returns The item, or `null` if not found\n */\n get(key: string): Promise<T | null>;\n\n /**\n * List items with optional filtering, sorting, and pagination.\n * @param options - Filter, sort, limit, offset options\n * @returns Array of matching items\n */\n list(options?: ListOptions<T>): Promise<T[]>;\n\n /**\n * Create a new item. Throws `StorageError` with code `DUPLICATE_KEY` if key exists.\n * @param key - Unique identifier\n * @param item - Data to store\n */\n create(key: string, item: T): Promise<void>;\n\n /**\n * Update an existing item. Throws `StorageError` with code `NOT_FOUND` if key missing.\n * @param key - Unique identifier\n * @param item - Updated data\n */\n update(key: string, item: T): Promise<void>;\n\n /**\n * Delete an item by key. Throws `StorageError` with code `NOT_FOUND` if key missing.\n * @param key - Unique identifier\n */\n delete(key: string): Promise<void>;\n\n /**\n * Check whether a key exists.\n * @param key - Unique identifier\n * @returns `true` if key exists\n */\n has(key: string): Promise<boolean>;\n\n /**\n * Return the number of stored items.\n * @returns Count of items\n */\n count(): Promise<number>;\n\n /**\n * Remove all items from storage.\n */\n clear(): Promise<void>;\n\n /**\n * Release any resources held by this adapter (DB connections, file handles).\n * Optional — adapters that don't hold resources need not implement this.\n */\n dispose?(): Promise<void>;\n}\n\n// ─── InMemoryStorage ───────────────────────────────────────────\n\n/**\n * In-memory storage adapter backed by a `Map`.\n * Suitable for development, testing, and short-lived processes.\n * Data is lost when the process exits.\n *\n * @typeParam T - The type of stored items\n *\n * @example\n * ```typescript\n * const store = new InMemoryStorage<{ name: string }>();\n * await store.create(\"k1\", { name: \"Alice\" });\n * await store.create(\"k2\", { name: \"Bob\" });\n * const items = await store.list({ filter: i => i.name.startsWith(\"A\") });\n * // [{ name: \"Alice\" }]\n * ```\n */\nexport class InMemoryStorage<T> implements IStorageAdapter<T> {\n private readonly data = new Map<string, T>();\n\n /** @inheritdoc */\n async get(key: string): Promise<T | null> {\n const item = this.data.get(key);\n return item !== undefined ? structuredClone(item) : null;\n }\n\n /** @inheritdoc */\n async list(options?: ListOptions<T>): Promise<T[]> {\n let items = Array.from(this.data.values()).map((item) => structuredClone(item));\n\n if (options?.filter) {\n items = items.filter(options.filter);\n }\n if (options?.sort) {\n items.sort(options.sort);\n }\n if (options?.offset !== undefined) {\n items = items.slice(options.offset);\n }\n if (options?.limit !== undefined) {\n items = items.slice(0, options.limit);\n }\n\n return items;\n }\n\n /** @inheritdoc */\n async create(key: string, item: T): Promise<void> {\n if (this.data.has(key)) {\n throw new StorageError(\n `Item with key \"${key}\" already exists`,\n ErrorCode.STORAGE_DUPLICATE_KEY,\n );\n }\n this.data.set(key, structuredClone(item));\n }\n\n /** @inheritdoc */\n async update(key: string, item: T): Promise<void> {\n if (!this.data.has(key)) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n this.data.set(key, structuredClone(item));\n }\n\n /** @inheritdoc */\n async delete(key: string): Promise<void> {\n if (!this.data.has(key)) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n this.data.delete(key);\n }\n\n /** @inheritdoc */\n async has(key: string): Promise<boolean> {\n return this.data.has(key);\n }\n\n /** @inheritdoc */\n async count(): Promise<number> {\n return this.data.size;\n }\n\n /** @inheritdoc */\n async clear(): Promise<void> {\n this.data.clear();\n }\n}\n\n// ─── FileStorage ───────────────────────────────────────────────\n\n/**\n * Options for configuring `FileStorage`.\n */\nexport interface FileStorageOptions {\n /** Directory path where JSON files are stored */\n directory: string;\n /** File extension (default: `.json`) */\n extension?: string;\n}\n\n/**\n * File-based storage adapter that persists each item as a JSON file.\n * Suitable for local applications, CLI tools, and development.\n * Creates the storage directory if it doesn't exist.\n *\n * @typeParam T - The type of stored items (must be JSON-serializable)\n *\n * @example\n * ```typescript\n * const store = new FileStorage<ChatSession>({\n * directory: \"./data/sessions\",\n * });\n * await store.create(\"session-1\", mySession);\n * ```\n */\nexport class FileStorage<T> implements IStorageAdapter<T> {\n private readonly directory: string;\n private readonly extension: string;\n\n constructor(options: FileStorageOptions) {\n this.directory = options.directory;\n this.extension = options.extension ?? \".json\";\n this.ensureDirectorySync();\n }\n\n /** @inheritdoc */\n async get(key: string): Promise<T | null> {\n const filePath = this.keyToPath(key);\n if (!(await this.fileExists(filePath))) {\n return null;\n }\n return this.readJsonFile(filePath);\n }\n\n /** @inheritdoc */\n async list(options?: ListOptions<T>): Promise<T[]> {\n await this.ensureDirectoryAsync();\n const files = (await readdir(this.directory)).filter((f) =>\n f.endsWith(this.extension),\n );\n\n let items: T[] = [];\n for (const file of files) {\n const item = await this.readJsonFile(join(this.directory, file));\n items.push(item);\n }\n\n if (options?.filter) {\n items = items.filter(options.filter);\n }\n if (options?.sort) {\n items.sort(options.sort);\n }\n if (options?.offset !== undefined) {\n items = items.slice(options.offset);\n }\n if (options?.limit !== undefined) {\n items = items.slice(0, options.limit);\n }\n\n return items;\n }\n\n /** @inheritdoc */\n async create(key: string, item: T): Promise<void> {\n const filePath = this.keyToPath(key);\n if (await this.fileExists(filePath)) {\n throw new StorageError(\n `Item with key \"${key}\" already exists`,\n ErrorCode.STORAGE_DUPLICATE_KEY,\n );\n }\n await this.writeJsonFile(filePath, item);\n }\n\n /** @inheritdoc */\n async update(key: string, item: T): Promise<void> {\n const filePath = this.keyToPath(key);\n if (!(await this.fileExists(filePath))) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n await this.writeJsonFile(filePath, item);\n }\n\n /** @inheritdoc */\n async delete(key: string): Promise<void> {\n const filePath = this.keyToPath(key);\n if (!(await this.fileExists(filePath))) {\n throw new StorageError(\n `Item with key \"${key}\" not found`,\n ErrorCode.STORAGE_NOT_FOUND,\n );\n }\n await unlink(filePath);\n }\n\n /** @inheritdoc */\n async has(key: string): Promise<boolean> {\n return this.fileExists(this.keyToPath(key));\n }\n\n /** @inheritdoc */\n async count(): Promise<number> {\n await this.ensureDirectoryAsync();\n return (await readdir(this.directory)).filter((f) =>\n f.endsWith(this.extension),\n ).length;\n }\n\n /** @inheritdoc */\n async clear(): Promise<void> {\n await this.ensureDirectoryAsync();\n const files = (await readdir(this.directory)).filter((f) =>\n f.endsWith(this.extension),\n );\n for (const file of files) {\n await unlink(join(this.directory, file));\n }\n }\n\n private keyToPath(key: string): string {\n const safeKey = key.replace(/[^a-zA-Z0-9_-]/g, (c) =>\n \"%\" + c.charCodeAt(0).toString(16).padStart(2, \"0\"),\n );\n return join(this.directory, `${safeKey}${this.extension}`);\n }\n\n /** Sync directory init — used only in constructor (one-time). */\n private ensureDirectorySync(): void {\n if (!existsSync(this.directory)) {\n mkdirSync(this.directory, { recursive: true });\n }\n }\n\n /** Async directory init — used in operations. */\n private async ensureDirectoryAsync(): Promise<void> {\n if (!(await this.fileExists(this.directory))) {\n await mkdir(this.directory, { recursive: true });\n }\n }\n\n private async fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n }\n\n private async readJsonFile(filePath: string): Promise<T> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new StorageError(\n `Failed to parse file: ${filePath}`,\n ErrorCode.STORAGE_SERIALIZATION_ERROR,\n );\n }\n throw new StorageError(\n `Failed to read file: ${filePath}`,\n ErrorCode.STORAGE_IO_ERROR,\n );\n }\n }\n\n private async writeJsonFile(filePath: string, item: T): Promise<void> {\n try {\n const content = JSON.stringify(item, null, 2);\n await writeFile(filePath, content, \"utf-8\");\n } catch {\n throw new StorageError(\n `Failed to write file: ${filePath}`,\n ErrorCode.STORAGE_IO_ERROR,\n );\n }\n }\n}\n","/**\n * SQLite-backed session store implementing IChatSessionStore.\n *\n * Uses better-sqlite3 for synchronous database access wrapped in\n * async interface. Messages are stored with position ordering for\n * deterministic retrieval. Parts and metadata are JSON-serialized.\n *\n * Accepts a shared Database instance — multiple stores can share\n * a single SQLite file via the factory function.\n */\n\nimport type Database from \"better-sqlite3\";\nimport type { ChatSession, ChatMessage, ChatId, ChatSessionConfig, SessionStatus } from \"../core.js\";\nimport { createChatId } from \"../core.js\";\nimport type {\n IChatSessionStore,\n CreateSessionOptions,\n PaginatedMessages,\n SessionListOptions,\n SessionSearchOptions,\n} from \"../sessions.js\";\nimport { StorageError } from \"../storage.js\";\nimport { ErrorCode } from \"../../types/errors.js\";\n\n// ─── Schema ────────────────────────────────────────────────────\n\nconst CREATE_SESSIONS_TABLE = `\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n title TEXT,\n config TEXT NOT NULL,\n metadata TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'active',\n backend_session_id TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )\n`;\n\nconst CREATE_MESSAGES_TABLE = `\n CREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n role TEXT NOT NULL,\n parts TEXT NOT NULL,\n metadata TEXT,\n status TEXT NOT NULL DEFAULT 'complete',\n created_at TEXT NOT NULL,\n updated_at TEXT,\n position INTEGER NOT NULL,\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE\n )\n`;\n\nconst CREATE_MESSAGES_SESSION_IDX = `\n CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id, position)\n`;\n\n// ─── SQLiteSessionStore ────────────────────────────────────────\n\nexport class SQLiteSessionStore implements IChatSessionStore {\n private readonly db: Database.Database;\n\n constructor(db: Database.Database) {\n this.db = db;\n this.db.exec(CREATE_SESSIONS_TABLE);\n this.db.exec(CREATE_MESSAGES_TABLE);\n this.db.exec(CREATE_MESSAGES_SESSION_IDX);\n }\n\n async createSession(options: CreateSessionOptions = {}): Promise<ChatSession> {\n const id = createChatId();\n const now = new Date().toISOString();\n const config: ChatSessionConfig = {\n model: \"default\",\n backend: \"default\",\n ...options.config,\n };\n const metadata = {\n messageCount: 0,\n totalTokens: 0,\n tags: options.tags,\n custom: options.custom,\n };\n\n this.db.prepare(`\n INSERT INTO sessions (id, title, config, metadata, status, created_at, updated_at)\n VALUES (?, ?, ?, ?, 'active', ?, ?)\n `).run(id, options.title ?? null, JSON.stringify(config), JSON.stringify(metadata), now, now);\n\n return this.buildSession(id, options.title, config, metadata, \"active\", now, now, []);\n }\n\n async getSession(id: ChatId): Promise<ChatSession | null> {\n const row = this.db.prepare(\"SELECT * FROM sessions WHERE id = ?\").get(id) as SessionRow | undefined;\n if (!row) return null;\n\n const messages = this.loadAllMessages(row.id);\n return this.rowToSession(row, messages);\n }\n\n async listSessions(options?: SessionListOptions): Promise<ChatSession[]> {\n const rows = this.db.prepare(\"SELECT * FROM sessions ORDER BY updated_at DESC\").all() as SessionRow[];\n\n let sessions = rows.map((r) => this.rowToSession(r, []));\n\n if (options?.filter) sessions = sessions.filter(options.filter);\n if (options?.sort) sessions.sort(options.sort);\n if (options?.offset) sessions = sessions.slice(options.offset);\n if (options?.limit) sessions = sessions.slice(0, options.limit);\n\n return sessions;\n }\n\n async updateTitle(id: ChatId, title: string): Promise<void> {\n const result = this.db.prepare(\n \"UPDATE sessions SET title = ?, updated_at = ? WHERE id = ?\",\n ).run(title, new Date().toISOString(), id);\n if (result.changes === 0) throw new StorageError(`Session not found: ${id}`, ErrorCode.STORAGE_NOT_FOUND);\n }\n\n async updateConfig(id: ChatId, config: Partial<ChatSessionConfig>): Promise<void> {\n const row = this.db.prepare(\"SELECT config FROM sessions WHERE id = ?\").get(id) as { config: string } | undefined;\n if (!row) throw new StorageError(`Session not found: ${id}`, ErrorCode.STORAGE_NOT_FOUND);\n\n const merged = { ...JSON.parse(row.config), ...config };\n this.db.prepare(\n \"UPDATE sessions SET config = ?, updated_at = ? WHERE id = ?\",\n ).run(JSON.stringify(merged), new Date().toISOString(), id);\n }\n\n async deleteSession(id: ChatId): Promise<void> {\n const result = this.db.prepare(\"DELETE FROM sessions WHERE id = ?\").run(id);\n if (result.changes === 0) throw new StorageError(`Session not found: ${id}`, ErrorCode.STORAGE_NOT_FOUND);\n }\n\n async appendMessage(sessionId: ChatId, message: ChatMessage): Promise<void> {\n const session = this.db.prepare(\"SELECT id FROM sessions WHERE id = ?\").get(sessionId) as { id: string } | undefined;\n if (!session) throw new StorageError(`Session not found: ${sessionId}`, ErrorCode.STORAGE_NOT_FOUND);\n\n const position = this.getNextPosition(sessionId);\n\n this.db.prepare(`\n INSERT INTO messages (id, session_id, role, parts, metadata, status, created_at, updated_at, position)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n message.id,\n sessionId,\n message.role,\n JSON.stringify(message.parts),\n message.metadata ? JSON.stringify(message.metadata) : null,\n message.status,\n message.createdAt,\n message.updatedAt ?? null,\n position,\n );\n\n this.incrementMessageCount(sessionId);\n }\n\n async saveMessages(sessionId: ChatId, messages: ChatMessage[]): Promise<void> {\n if (messages.length === 0) return;\n\n const session = this.db.prepare(\"SELECT id FROM sessions WHERE id = ?\").get(sessionId) as { id: string } | undefined;\n if (!session) throw new StorageError(`Session not found: ${sessionId}`, ErrorCode.STORAGE_NOT_FOUND);\n\n const insertMsg = this.db.prepare(`\n INSERT INTO messages (id, session_id, role, parts, metadata, status, created_at, updated_at, position)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const tx = this.db.transaction(() => {\n let pos = this.getNextPosition(sessionId);\n for (const msg of messages) {\n insertMsg.run(\n msg.id, sessionId, msg.role,\n JSON.stringify(msg.parts),\n msg.metadata ? JSON.stringify(msg.metadata) : null,\n msg.status, msg.createdAt, msg.updatedAt ?? null, pos++,\n );\n }\n this.updateSessionMeta(sessionId, messages.length);\n });\n tx();\n }\n\n async loadMessages(\n sessionId: ChatId,\n options?: { limit?: number; offset?: number },\n ): Promise<PaginatedMessages> {\n const session = this.db.prepare(\"SELECT id FROM sessions WHERE id = ?\").get(sessionId) as { id: string } | undefined;\n if (!session) throw new StorageError(`Session not found: ${sessionId}`, ErrorCode.STORAGE_NOT_FOUND);\n\n const total = (this.db.prepare(\n \"SELECT COUNT(*) as cnt FROM messages WHERE session_id = ?\",\n ).get(sessionId) as { cnt: number }).cnt;\n\n const limit = options?.limit ?? 50;\n const offset = options?.offset ?? 0;\n\n const rows = this.db.prepare(\n \"SELECT * FROM messages WHERE session_id = ? ORDER BY position ASC LIMIT ? OFFSET ?\",\n ).all(sessionId, limit, offset) as MessageRow[];\n\n return {\n messages: rows.map(rowToMessage),\n total,\n hasMore: offset + limit < total,\n };\n }\n\n async searchSessions(options: SessionSearchOptions): Promise<ChatSession[]> {\n const pattern = `%${options.query}%`;\n const limit = options.limit ?? 20;\n\n const titleMatches = this.db.prepare(\n \"SELECT * FROM sessions WHERE title LIKE ? COLLATE NOCASE LIMIT ?\",\n ).all(pattern, limit) as SessionRow[];\n\n const contentMatches = this.db.prepare(`\n SELECT DISTINCT s.* FROM sessions s\n JOIN messages m ON m.session_id = s.id\n WHERE m.parts LIKE ? COLLATE NOCASE\n LIMIT ?\n `).all(pattern, limit) as SessionRow[];\n\n const seen = new Set<string>();\n const results: ChatSession[] = [];\n for (const row of [...titleMatches, ...contentMatches]) {\n if (!seen.has(row.id)) {\n seen.add(row.id);\n results.push(this.rowToSession(row, []));\n }\n }\n\n return results.slice(0, limit);\n }\n\n async count(): Promise<number> {\n return (this.db.prepare(\"SELECT COUNT(*) as cnt FROM sessions\").get() as { cnt: number }).cnt;\n }\n\n async clear(): Promise<void> {\n this.db.exec(\"DELETE FROM messages\");\n this.db.exec(\"DELETE FROM sessions\");\n }\n\n // ─── Private Helpers ─────────────────────────────────────────\n\n private getNextPosition(sessionId: string): number {\n const result = this.db.prepare(\n \"SELECT MAX(position) as maxPos FROM messages WHERE session_id = ?\",\n ).get(sessionId) as { maxPos: number | null };\n return (result.maxPos ?? -1) + 1;\n }\n\n private incrementMessageCount(sessionId: string): void {\n this.db.prepare(`\n UPDATE sessions\n SET metadata = json_set(metadata, '$.messageCount', json_extract(metadata, '$.messageCount') + 1),\n updated_at = ?\n WHERE id = ?\n `).run(new Date().toISOString(), sessionId);\n }\n\n private updateSessionMeta(sessionId: string, addedCount: number): void {\n this.db.prepare(`\n UPDATE sessions\n SET metadata = json_set(metadata, '$.messageCount', json_extract(metadata, '$.messageCount') + ?),\n updated_at = ?\n WHERE id = ?\n `).run(addedCount, new Date().toISOString(), sessionId);\n }\n\n private loadAllMessages(sessionId: string): ChatMessage[] {\n const rows = this.db.prepare(\n \"SELECT * FROM messages WHERE session_id = ? ORDER BY position ASC\",\n ).all(sessionId) as MessageRow[];\n return rows.map(rowToMessage);\n }\n\n private rowToSession(row: SessionRow, messages: ChatMessage[]): ChatSession {\n return this.buildSession(\n row.id as ChatId,\n row.title,\n JSON.parse(row.config),\n JSON.parse(row.metadata),\n row.status as SessionStatus,\n row.created_at,\n row.updated_at,\n messages,\n );\n }\n\n private buildSession(\n id: ChatId,\n title: string | undefined | null,\n config: ChatSessionConfig,\n metadata: ChatSession[\"metadata\"],\n status: SessionStatus,\n createdAt: string,\n updatedAt: string,\n messages: ChatMessage[],\n ): ChatSession {\n return {\n id,\n title: title ?? undefined,\n messages,\n config,\n metadata,\n status,\n createdAt,\n updatedAt,\n };\n }\n}\n\n// ─── Row Types ─────────────────────────────────────────────────\n\ninterface SessionRow {\n id: string;\n title: string | null;\n config: string;\n metadata: string;\n status: string;\n backend_session_id: string | null;\n created_at: string;\n updated_at: string;\n}\n\ninterface MessageRow {\n id: string;\n session_id: string;\n role: string;\n parts: string;\n metadata: string | null;\n status: string;\n created_at: string;\n updated_at: string | null;\n position: number;\n}\n\nfunction rowToMessage(row: MessageRow): ChatMessage {\n return {\n id: row.id as ChatId,\n role: row.role as ChatMessage[\"role\"],\n parts: JSON.parse(row.parts),\n metadata: row.metadata ? JSON.parse(row.metadata) : undefined,\n status: row.status as ChatMessage[\"status\"],\n createdAt: row.created_at,\n updatedAt: row.updated_at ?? undefined,\n };\n}\n","/**\n * SQLite-backed provider store implementing IProviderStore.\n *\n * Stores provider configurations in a `providers` table within\n * a shared SQLite database. Schema auto-created on construction.\n */\n\nimport type Database from \"better-sqlite3\";\nimport type { IProviderStore, ProviderConfig } from \"../provider-types.js\";\n\n// ─── Schema ────────────────────────────────────────────────────\n\nconst CREATE_PROVIDERS_TABLE = `\n CREATE TABLE IF NOT EXISTS providers (\n id TEXT PRIMARY KEY,\n backend TEXT NOT NULL,\n model TEXT NOT NULL,\n label TEXT NOT NULL,\n created_at INTEGER NOT NULL\n )\n`;\n\n// ─── SQLiteProviderStore ───────────────────────────────────────\n\nexport class SQLiteProviderStore implements IProviderStore {\n private readonly db: Database.Database;\n\n constructor(db: Database.Database) {\n this.db = db;\n this.db.exec(CREATE_PROVIDERS_TABLE);\n }\n\n async create(config: ProviderConfig): Promise<void> {\n this.db.prepare(`\n INSERT INTO providers (id, backend, model, label, created_at)\n VALUES (?, ?, ?, ?, ?)\n `).run(config.id, config.backend, config.model, config.label, config.createdAt);\n }\n\n async get(id: string): Promise<ProviderConfig | null> {\n const row = this.db.prepare(\"SELECT * FROM providers WHERE id = ?\").get(id) as ProviderRow | undefined;\n return row ? rowToProvider(row) : null;\n }\n\n async update(id: string, changes: Partial<Omit<ProviderConfig, \"id\" | \"createdAt\">>): Promise<void> {\n const existing = this.db.prepare(\"SELECT id FROM providers WHERE id = ?\").get(id) as { id: string } | undefined;\n if (!existing) throw new Error(`Provider \"${id}\" not found`);\n\n const sets: string[] = [];\n const values: unknown[] = [];\n if (changes.backend !== undefined) { sets.push(\"backend = ?\"); values.push(changes.backend); }\n if (changes.model !== undefined) { sets.push(\"model = ?\"); values.push(changes.model); }\n if (changes.label !== undefined) { sets.push(\"label = ?\"); values.push(changes.label); }\n\n if (sets.length > 0) {\n values.push(id);\n this.db.prepare(`UPDATE providers SET ${sets.join(\", \")} WHERE id = ?`).run(...values);\n }\n }\n\n async delete(id: string): Promise<void> {\n this.db.prepare(\"DELETE FROM providers WHERE id = ?\").run(id);\n }\n\n async list(): Promise<ProviderConfig[]> {\n const rows = this.db.prepare(\"SELECT * FROM providers ORDER BY created_at ASC\").all() as ProviderRow[];\n return rows.map(rowToProvider);\n }\n}\n\n// ─── Row Types ─────────────────────────────────────────────────\n\ninterface ProviderRow {\n id: string;\n backend: string;\n model: string;\n label: string;\n created_at: number;\n}\n\nfunction rowToProvider(row: ProviderRow): ProviderConfig {\n return {\n id: row.id,\n backend: row.backend,\n model: row.model,\n label: row.label,\n createdAt: row.created_at,\n };\n}\n","/**\n * SQLite-backed token store implementing ITokenStore.\n *\n * Stores auth tokens as JSON in a `tokens` table within\n * a shared SQLite database. Schema auto-created on construction.\n */\n\nimport type Database from \"better-sqlite3\";\nimport type { ITokenStore } from \"../server/token-store.js\";\nimport type { AuthToken } from \"../../auth/types.js\";\n\n// ─── Schema ────────────────────────────────────────────────────\n\nconst CREATE_TOKENS_TABLE = `\n CREATE TABLE IF NOT EXISTS tokens (\n provider TEXT PRIMARY KEY,\n token_json TEXT NOT NULL,\n saved_at INTEGER NOT NULL\n )\n`;\n\n// ─── SQLiteTokenStore ──────────────────────────────────────────\n\nexport class SQLiteTokenStore implements ITokenStore {\n private readonly db: Database.Database;\n\n constructor(db: Database.Database) {\n this.db = db;\n this.db.exec(CREATE_TOKENS_TABLE);\n }\n\n async save(provider: string, token: AuthToken): Promise<void> {\n this.db.prepare(`\n INSERT OR REPLACE INTO tokens (provider, token_json, saved_at)\n VALUES (?, ?, ?)\n `).run(provider, JSON.stringify(token), Date.now());\n }\n\n async load(provider: string): Promise<AuthToken | null> {\n const row = this.db.prepare(\"SELECT token_json FROM tokens WHERE provider = ?\").get(provider) as { token_json: string } | undefined;\n return row ? JSON.parse(row.token_json) as AuthToken : null;\n }\n\n async clear(provider: string): Promise<void> {\n this.db.prepare(\"DELETE FROM tokens WHERE provider = ?\").run(provider);\n }\n\n async clearAll(): Promise<void> {\n this.db.exec(\"DELETE FROM tokens\");\n }\n\n async list(): Promise<string[]> {\n const rows = this.db.prepare(\"SELECT provider FROM tokens ORDER BY saved_at ASC\").all() as { provider: string }[];\n return rows.map(r => r.provider);\n }\n}\n","/**\n * SQLite schema migration runner.\n *\n * Maintains a `schema_version` table and applies sequential migrations.\n * Each migration runs inside a transaction for atomicity.\n *\n * Individual stores keep `CREATE TABLE IF NOT EXISTS` for backward\n * compatibility when constructed directly. The migration runner is\n * responsible for schema evolution (ALTER TABLE, new indexes, etc.)\n * when used via `createSQLiteStorage()`.\n */\n\nimport type Database from \"better-sqlite3\";\n\n// ─── Types ─────────────────────────────────────────────────────\n\nexport interface Migration {\n /** Sequential version number (1-based) */\n version: number;\n /** Human-readable description */\n description: string;\n /** DDL statements to apply. Runs inside a transaction. */\n up: (db: Database.Database) => void;\n}\n\n// ─── Schema Version Table ──────────────────────────────────────\n\nconst CREATE_VERSION_TABLE = `\n CREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER PRIMARY KEY,\n applied_at TEXT NOT NULL,\n description TEXT\n )\n`;\n\n// ─── Migrations ────────────────────────────────────────────────\n\n/**\n * Migration registry. Append new migrations here.\n * Version numbers must be sequential (1, 2, 3, ...).\n */\nexport const migrations: readonly Migration[] = [\n {\n version: 1,\n description: \"Initial schema — sessions, messages, providers, tokens\",\n up: (db) => {\n // Tables are created by store constructors via IF NOT EXISTS.\n // This migration records that the baseline schema is version 1.\n // Future migrations will ALTER these tables.\n db.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n title TEXT,\n config TEXT NOT NULL,\n metadata TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'active',\n backend_session_id TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )\n `);\n db.exec(`\n CREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n role TEXT NOT NULL,\n parts TEXT NOT NULL,\n metadata TEXT,\n status TEXT NOT NULL DEFAULT 'complete',\n created_at TEXT NOT NULL,\n updated_at TEXT,\n position INTEGER NOT NULL,\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE\n )\n `);\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id, position)\n `);\n db.exec(`\n CREATE TABLE IF NOT EXISTS providers (\n id TEXT PRIMARY KEY,\n backend TEXT NOT NULL,\n model TEXT NOT NULL,\n label TEXT NOT NULL,\n created_at INTEGER NOT NULL\n )\n `);\n db.exec(`\n CREATE TABLE IF NOT EXISTS tokens (\n provider TEXT PRIMARY KEY,\n token_json TEXT NOT NULL,\n saved_at INTEGER NOT NULL\n )\n `);\n },\n },\n];\n\n// ─── Runner ────────────────────────────────────────────────────\n\n/** Get current schema version (0 if no migrations applied). */\nexport function getSchemaVersion(db: Database.Database): number {\n db.exec(CREATE_VERSION_TABLE);\n const row = db.prepare(\"SELECT MAX(version) as v FROM schema_version\").get() as\n | { v: number | null }\n | undefined;\n return row?.v ?? 0;\n}\n\n/**\n * Apply pending migrations sequentially. Each runs in a transaction.\n *\n * Safe to call multiple times — already-applied migrations are skipped.\n * For existing databases without schema_version table, detects current\n * tables and fast-forwards to the matching version.\n */\nexport function runMigrations(db: Database.Database): void {\n db.exec(CREATE_VERSION_TABLE);\n\n let current = getSchemaVersion(db);\n\n // Detect pre-migration databases: if sessions table exists but no version recorded,\n // fast-forward to version 1 to avoid re-running initial schema.\n if (current === 0 && tableExists(db, \"sessions\")) {\n const now = new Date().toISOString();\n db.prepare(\"INSERT INTO schema_version (version, applied_at, description) VALUES (?, ?, ?)\")\n .run(1, now, \"Initial schema (pre-existing database)\");\n current = 1;\n }\n\n const pending = migrations.filter((m) => m.version > current);\n if (pending.length === 0) return;\n\n for (const migration of pending) {\n const txn = db.transaction(() => {\n migration.up(db);\n const now = new Date().toISOString();\n db.prepare(\"INSERT INTO schema_version (version, applied_at, description) VALUES (?, ?, ?)\")\n .run(migration.version, now, migration.description);\n });\n txn();\n }\n}\n\nfunction tableExists(db: Database.Database, name: string): boolean {\n const row = db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name=?\")\n .get(name) as { name: string } | undefined;\n return !!row;\n}\n","/**\n * Factory function for creating all three SQLite stores from a single database path.\n *\n * @example\n * ```ts\n * import { createSQLiteStorage } from \"@witqq/agent-sdk/chat/sqlite\";\n *\n * const storage = createSQLiteStorage(\"/data/chat.db\");\n * // storage.sessionStore — IChatSessionStore\n * // storage.providerStore — IProviderStore\n * // storage.tokenStore — ITokenStore\n * // storage.db — raw Database instance\n * ```\n */\n\nimport { createRequire } from \"node:module\";\nimport type Database from \"better-sqlite3\";\nimport { SQLiteSessionStore } from \"./session-store.js\";\nimport { SQLiteProviderStore } from \"./provider-store.js\";\nimport { SQLiteTokenStore } from \"./token-store.js\";\nimport { runMigrations } from \"./migrations.js\";\nimport type { IChatSessionStore } from \"../sessions.js\";\nimport type { IProviderStore } from \"../provider-types.js\";\nimport type { ITokenStore } from \"../server/token-store.js\";\n\n// ─── Types ─────────────────────────────────────────────────────\n\nexport interface SQLiteStorageOptions {\n /** Path to SQLite database file. Use \":memory:\" for in-memory database. */\n dbPath: string;\n /** Optional pre-created Database instance. If provided, dbPath is ignored. */\n db?: Database.Database;\n}\n\nexport interface SQLiteStorage {\n /** The underlying better-sqlite3 Database instance */\n db: Database.Database;\n /** Session store for chat sessions and messages */\n sessionStore: IChatSessionStore;\n /** Provider store for provider configurations */\n providerStore: IProviderStore;\n /** Token store for auth tokens */\n tokenStore: ITokenStore;\n}\n\n// ─── Factory ───────────────────────────────────────────────────\n\n/**\n * Create all three SQLite stores sharing a single database.\n *\n * Requires `better-sqlite3` as a peer dependency.\n * Schema tables are auto-created on first use.\n *\n * @param pathOrOptions - Database file path string, or options object\n * @returns Object with db, sessionStore, providerStore, tokenStore\n *\n * @throws If better-sqlite3 is not installed\n */\nexport function createSQLiteStorage(pathOrOptions: string | SQLiteStorageOptions): SQLiteStorage {\n let db: Database.Database;\n\n if (typeof pathOrOptions === \"string\") {\n db = createDatabase(pathOrOptions);\n } else if (pathOrOptions.db) {\n db = pathOrOptions.db;\n } else {\n db = createDatabase(pathOrOptions.dbPath);\n }\n\n // Enable WAL + foreign keys once for the shared connection\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"foreign_keys = ON\");\n\n // Run schema migrations (creates/updates tables)\n runMigrations(db);\n\n return {\n db,\n sessionStore: new SQLiteSessionStore(db),\n providerStore: new SQLiteProviderStore(db),\n tokenStore: new SQLiteTokenStore(db),\n };\n}\n\nfunction createDatabase(dbPath: string): Database.Database {\n try {\n // createRequire for ESM compatibility — better-sqlite3 is a CJS native addon\n const esmRequire = createRequire(import.meta.url);\n const BetterSqlite3 = esmRequire(\"better-sqlite3\") as typeof Database;\n return new BetterSqlite3(dbPath);\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n if (message.includes(\"Cannot find module\") || message.includes(\"MODULE_NOT_FOUND\")) {\n throw new Error(\n \"better-sqlite3 is required for SQLite storage. Install it: npm install better-sqlite3\",\n );\n }\n throw err;\n }\n}\n"]}
|
package/dist/chat/state.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as MessageStatus, R as RuntimeStatus, T as ToolCallStatus } from '../types-
|
|
2
|
-
import '../agent-
|
|
1
|
+
import { M as MessageStatus, R as RuntimeStatus, T as ToolCallStatus } from '../types-DkSXALKg.cjs';
|
|
2
|
+
import '../agent-C6H2CgJA.cjs';
|
|
3
3
|
import 'zod';
|
|
4
4
|
import '../errors-C-so0M4t.cjs';
|
|
5
5
|
import '../types-4vbcmPTp.cjs';
|
package/dist/chat/state.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as MessageStatus, R as RuntimeStatus, T as ToolCallStatus } from '../types-
|
|
2
|
-
import '../agent-
|
|
1
|
+
import { M as MessageStatus, R as RuntimeStatus, T as ToolCallStatus } from '../types-DgtI1hzh.js';
|
|
2
|
+
import '../agent-F7oB6eKp.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
import '../errors-C-so0M4t.js';
|
|
5
5
|
import '../types-BxggH0Yh.js';
|
package/dist/chat/storage.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var fs = require('fs');
|
|
4
|
+
var promises = require('fs/promises');
|
|
4
5
|
var path = require('path');
|
|
5
6
|
|
|
6
7
|
// src/chat/storage.ts
|
|
@@ -111,25 +112,25 @@ var FileStorage = class {
|
|
|
111
112
|
constructor(options) {
|
|
112
113
|
this.directory = options.directory;
|
|
113
114
|
this.extension = options.extension ?? ".json";
|
|
114
|
-
this.
|
|
115
|
+
this.ensureDirectorySync();
|
|
115
116
|
}
|
|
116
117
|
/** @inheritdoc */
|
|
117
118
|
async get(key) {
|
|
118
119
|
const filePath = this.keyToPath(key);
|
|
119
|
-
if (!
|
|
120
|
+
if (!await this.fileExists(filePath)) {
|
|
120
121
|
return null;
|
|
121
122
|
}
|
|
122
|
-
return this.
|
|
123
|
+
return this.readJsonFile(filePath);
|
|
123
124
|
}
|
|
124
125
|
/** @inheritdoc */
|
|
125
126
|
async list(options) {
|
|
126
|
-
this.
|
|
127
|
-
const files =
|
|
127
|
+
await this.ensureDirectoryAsync();
|
|
128
|
+
const files = (await promises.readdir(this.directory)).filter(
|
|
128
129
|
(f) => f.endsWith(this.extension)
|
|
129
130
|
);
|
|
130
131
|
let items = [];
|
|
131
132
|
for (const file of files) {
|
|
132
|
-
const item = this.
|
|
133
|
+
const item = await this.readJsonFile(path.join(this.directory, file));
|
|
133
134
|
items.push(item);
|
|
134
135
|
}
|
|
135
136
|
if (options?.filter) {
|
|
@@ -149,55 +150,55 @@ var FileStorage = class {
|
|
|
149
150
|
/** @inheritdoc */
|
|
150
151
|
async create(key, item) {
|
|
151
152
|
const filePath = this.keyToPath(key);
|
|
152
|
-
if (
|
|
153
|
+
if (await this.fileExists(filePath)) {
|
|
153
154
|
throw new StorageError(
|
|
154
155
|
`Item with key "${key}" already exists`,
|
|
155
156
|
"STORAGE_DUPLICATE_KEY" /* STORAGE_DUPLICATE_KEY */
|
|
156
157
|
);
|
|
157
158
|
}
|
|
158
|
-
this.
|
|
159
|
+
await this.writeJsonFile(filePath, item);
|
|
159
160
|
}
|
|
160
161
|
/** @inheritdoc */
|
|
161
162
|
async update(key, item) {
|
|
162
163
|
const filePath = this.keyToPath(key);
|
|
163
|
-
if (!
|
|
164
|
+
if (!await this.fileExists(filePath)) {
|
|
164
165
|
throw new StorageError(
|
|
165
166
|
`Item with key "${key}" not found`,
|
|
166
167
|
"STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
|
|
167
168
|
);
|
|
168
169
|
}
|
|
169
|
-
this.
|
|
170
|
+
await this.writeJsonFile(filePath, item);
|
|
170
171
|
}
|
|
171
172
|
/** @inheritdoc */
|
|
172
173
|
async delete(key) {
|
|
173
174
|
const filePath = this.keyToPath(key);
|
|
174
|
-
if (!
|
|
175
|
+
if (!await this.fileExists(filePath)) {
|
|
175
176
|
throw new StorageError(
|
|
176
177
|
`Item with key "${key}" not found`,
|
|
177
178
|
"STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */
|
|
178
179
|
);
|
|
179
180
|
}
|
|
180
|
-
|
|
181
|
+
await promises.unlink(filePath);
|
|
181
182
|
}
|
|
182
183
|
/** @inheritdoc */
|
|
183
184
|
async has(key) {
|
|
184
|
-
return
|
|
185
|
+
return this.fileExists(this.keyToPath(key));
|
|
185
186
|
}
|
|
186
187
|
/** @inheritdoc */
|
|
187
188
|
async count() {
|
|
188
|
-
this.
|
|
189
|
-
return
|
|
189
|
+
await this.ensureDirectoryAsync();
|
|
190
|
+
return (await promises.readdir(this.directory)).filter(
|
|
190
191
|
(f) => f.endsWith(this.extension)
|
|
191
192
|
).length;
|
|
192
193
|
}
|
|
193
194
|
/** @inheritdoc */
|
|
194
195
|
async clear() {
|
|
195
|
-
this.
|
|
196
|
-
const files =
|
|
196
|
+
await this.ensureDirectoryAsync();
|
|
197
|
+
const files = (await promises.readdir(this.directory)).filter(
|
|
197
198
|
(f) => f.endsWith(this.extension)
|
|
198
199
|
);
|
|
199
200
|
for (const file of files) {
|
|
200
|
-
|
|
201
|
+
await promises.unlink(path.join(this.directory, file));
|
|
201
202
|
}
|
|
202
203
|
}
|
|
203
204
|
keyToPath(key) {
|
|
@@ -207,14 +208,29 @@ var FileStorage = class {
|
|
|
207
208
|
);
|
|
208
209
|
return path.join(this.directory, `${safeKey}${this.extension}`);
|
|
209
210
|
}
|
|
210
|
-
|
|
211
|
+
/** Sync directory init — used only in constructor (one-time). */
|
|
212
|
+
ensureDirectorySync() {
|
|
211
213
|
if (!fs.existsSync(this.directory)) {
|
|
212
214
|
fs.mkdirSync(this.directory, { recursive: true });
|
|
213
215
|
}
|
|
214
216
|
}
|
|
215
|
-
|
|
217
|
+
/** Async directory init — used in operations. */
|
|
218
|
+
async ensureDirectoryAsync() {
|
|
219
|
+
if (!await this.fileExists(this.directory)) {
|
|
220
|
+
await promises.mkdir(this.directory, { recursive: true });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
async fileExists(filePath) {
|
|
224
|
+
try {
|
|
225
|
+
await promises.access(filePath);
|
|
226
|
+
return true;
|
|
227
|
+
} catch {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async readJsonFile(filePath) {
|
|
216
232
|
try {
|
|
217
|
-
const content =
|
|
233
|
+
const content = await promises.readFile(filePath, "utf-8");
|
|
218
234
|
return JSON.parse(content);
|
|
219
235
|
} catch (error) {
|
|
220
236
|
if (error instanceof SyntaxError) {
|
|
@@ -229,10 +245,10 @@ var FileStorage = class {
|
|
|
229
245
|
);
|
|
230
246
|
}
|
|
231
247
|
}
|
|
232
|
-
|
|
248
|
+
async writeJsonFile(filePath, item) {
|
|
233
249
|
try {
|
|
234
250
|
const content = JSON.stringify(item, null, 2);
|
|
235
|
-
|
|
251
|
+
await promises.writeFile(filePath, content, "utf-8");
|
|
236
252
|
} catch {
|
|
237
253
|
throw new StorageError(
|
|
238
254
|
`Failed to write file: ${filePath}`,
|