@mikesaintsg/core 0.0.1 → 0.0.2
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/README.md +175 -365
- package/dist/index.d.ts +26 -433
- package/dist/index.js +164 -746
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/types.ts","../src/errors.ts","../src/helpers.ts","../src/constants.ts","../src/adapters/embeddings/openai.ts","../src/adapters/embeddings/anthropic.ts","../src/adapters/embeddings/batched.ts","../src/adapters/embeddings/cache.ts","../src/adapters/tools/formatters/openai.ts","../src/adapters/tools/formatters/anthropic.ts","../src/adapters/persistence/vectorstore/indexeddb.ts","../src/adapters/persistence/vectorstore/opfs.ts","../src/adapters/persistence/vectorstore/http.ts","../src/bridges/tool-call.ts","../src/bridges/retrieval-tool.ts","../src/bridges/form-dirty-guard.ts","../src/bridges/session-persistence.ts"],"sourcesContent":["/**\n * @mikesaintsg/core\n *\n * Type definitions for the core library.\n * All public types and interfaces are defined here as the SOURCE OF TRUTH.\n */\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/** Cleanup function returned by event subscriptions */\nexport type Unsubscribe = () => void\n\n/** Converts subscription methods to hook callbacks for options */\nexport type SubscriptionToHook<T> = {\n\t[K in keyof T]?: T[K] extends (callback: infer CB) => Unsubscribe ? CB : never\n}\n\n/** Origin of state change */\nexport type ChangeSource = 'local' | 'remote'\n\n/** Cancellable operation options */\nexport interface AbortableOptions {\n\treadonly signal?: AbortSignal\n}\n\n// ============================================================================\n// Content Hashing Types (Shared across packages)\n// ============================================================================\n\n/** Content hash for deduplication (SHA-256 hex string) */\nexport type ContentHash = string\n\n// ============================================================================\n// Result Pattern\n// ============================================================================\n\n/** Success result */\nexport interface Ok<T> {\n\treadonly ok: true\n\treadonly value: T\n}\n\n/** Failure result */\nexport interface Err<E> {\n\treadonly ok: false\n\treadonly error: E\n}\n\n/** Result union */\nexport type Result<T, E> = Ok<T> | Err<E>\n\n// ============================================================================\n// Embedding Types (Shared between inference, vectorstore)\n// ============================================================================\n\n/** Embedding vector */\nexport type Embedding = Float32Array\n\n/** Embedding model info */\nexport interface EmbeddingModelMetadata {\n\treadonly provider: string\n\treadonly model: string\n\treadonly dimensions: number\n}\n\n/** Embedding generation contract */\nexport interface EmbeddingAdapterInterface {\n\tembed(texts: readonly string[], options?: AbortableOptions): Promise<readonly Embedding[]>\n\tgetModelMetadata(): EmbeddingModelMetadata\n}\n\n// ============================================================================\n// Tool Types (Shared between inference, contextprotocol)\n// ============================================================================\n\n/** Tool call from LLM response */\nexport interface ToolCall {\n\treadonly id: string\n\treadonly name: string\n\treadonly arguments: Record<string, unknown>\n}\n\n/** Tool execution result */\nexport interface ToolResult {\n\treadonly callId: string\n\treadonly name: string\n\treadonly success: boolean\n\treadonly value?: unknown\n\treadonly error?: string\n}\n\n/** Tool schema definition */\nexport interface ToolSchema {\n\treadonly name: string\n\treadonly description: string\n\treadonly parameters: JSONSchema7\n\treadonly returns?: JSONSchema7\n}\n\n/** JSON Schema 7 subset for tool parameters */\nexport interface JSONSchema7 {\n\treadonly type?: string | readonly string[]\n\treadonly properties?: Readonly<Record<string, JSONSchema7>>\n\treadonly items?: JSONSchema7 | readonly JSONSchema7[]\n\treadonly required?: readonly string[]\n\treadonly enum?: readonly unknown[]\n\treadonly const?: unknown\n\treadonly format?: string\n\treadonly minimum?: number\n\treadonly maximum?: number\n\treadonly minLength?: number\n\treadonly maxLength?: number\n\treadonly pattern?: string\n\treadonly description?: string\n\treadonly default?: unknown\n\treadonly additionalProperties?: boolean | JSONSchema7\n\treadonly anyOf?: readonly JSONSchema7[]\n\treadonly oneOf?: readonly JSONSchema7[]\n\treadonly allOf?: readonly JSONSchema7[]\n\treadonly $ref?: string\n\treadonly definitions?: Readonly<Record<string, JSONSchema7>>\n}\n\n// ============================================================================\n// Scored Result Types (Shared between vectorstore, contextbuilder)\n// ============================================================================\n\n/** Scored result from similarity search or retrieval */\nexport interface ScoredResult {\n\treadonly id: string\n\treadonly content: string\n\treadonly score: number\n\treadonly metadata?: Readonly<Record<string, unknown>>\n\treadonly embedding?: Embedding\n}\n\n// ============================================================================\n// Context Frame Types (Shared between contextbuilder, inference)\n// ============================================================================\n\n/** Frame type discriminator */\nexport type FrameType =\n\t| 'system'\n\t| 'instruction'\n\t| 'section'\n\t| 'file'\n\t| 'document'\n\t| 'example'\n\t| 'tool'\n\t| 'memory'\n\t| 'retrieval'\n\t| 'custom'\n\n/** Frame priority levels */\nexport type FramePriority = 'critical' | 'high' | 'normal' | 'low' | 'optional'\n\n/** Context frame - atomic unit of context */\nexport interface ContextFrame {\n\treadonly id: string\n\treadonly type: FrameType\n\treadonly content: string\n\treadonly contentHash: ContentHash\n\treadonly priority: FramePriority\n\treadonly tokenEstimate: number\n\treadonly createdAt: number\n\treadonly metadata?: FrameMetadata\n}\n\n/** Frame metadata */\nexport interface FrameMetadata {\n\treadonly sectionId?: string\n\treadonly filePath?: string\n\treadonly fileVersion?: number\n\treadonly toolName?: string\n\treadonly score?: number\n\treadonly tags?: readonly string[]\n\treadonly expiresAt?: number\n\treadonly source?: string\n}\n\n// ============================================================================\n// Token Budget Types (Shared between contextbuilder, inference)\n// ============================================================================\n\n/** Token budget level */\nexport type TokenBudgetLevel = 'ok' | 'warning' | 'critical' | 'exceeded'\n\n/** Token budget state */\nexport interface TokenBudgetState {\n\treadonly used: number\n\treadonly available: number\n\treadonly reserved: number\n\treadonly max: number\n\treadonly usage: number\n\treadonly level: TokenBudgetLevel\n}\n\n// ============================================================================\n// Built Context Types (Shared between contextbuilder, inference)\n// ============================================================================\n\n/** Deduplication result summary */\nexport interface DeduplicationResult {\n\treadonly originalCount: number\n\treadonly deduplicatedCount: number\n\treadonly removedFrames: readonly ContextFrame[]\n\treadonly mergedFrames: readonly ContextFrame[]\n\treadonly tokensSaved: number\n}\n\n/** Truncation strategy */\nexport type TruncationStrategy =\n\t| 'priority'\n\t| 'fifo'\n\t| 'lifo'\n\t| 'score'\n\t| 'custom'\n\n/** Why a frame was truncated */\nexport type TruncationReason =\n\t| 'budget_exceeded'\n\t| 'priority_too_low'\n\t| 'expired'\n\t| 'deduplicated'\n\t| 'manual'\n\n/** Frame summary for reporting */\nexport interface FrameSummary {\n\treadonly id: string\n\treadonly type: FrameType\n\treadonly tokenEstimate: number\n\treadonly reason: TruncationReason\n}\n\n/** Truncation information */\nexport interface TruncationInfo {\n\treadonly originalFrameCount: number\n\treadonly keptFrameCount: number\n\treadonly removedFrames: readonly FrameSummary[]\n\treadonly strategy: TruncationStrategy\n}\n\n/** Assembled context ready for inference */\nexport interface BuiltContext {\n\treadonly frames: readonly ContextFrame[]\n\treadonly totalTokens: number\n\treadonly budget: TokenBudgetState\n\treadonly truncated: boolean\n\treadonly truncationInfo?: TruncationInfo\n\treadonly deduplication?: DeduplicationResult\n\treadonly timestamp: number\n}\n\n// ============================================================================\n// Embedding Batching Types (Shared optimization infrastructure)\n// ============================================================================\n\n/** Embedding cache entry */\nexport interface EmbeddingCacheEntry {\n\treadonly embedding: Embedding\n\treadonly contentHash: ContentHash\n\treadonly modelId: string\n\treadonly createdAt: number\n\treadonly hitCount: number\n}\n\n/** Embedding cache statistics */\nexport interface EmbeddingCacheStats {\n\treadonly entries: number\n\treadonly hits: number\n\treadonly misses: number\n\treadonly hitRate: number\n\treadonly estimatedBytes: number\n}\n\n/** Embedding cache interface */\nexport interface EmbeddingCacheInterface {\n\tget(contentHash: ContentHash): Embedding | undefined\n\tset(contentHash: ContentHash, embedding: Embedding): void\n\thas(contentHash: ContentHash): boolean\n\tremove(contentHash: ContentHash): boolean\n\tclear(): void\n\tgetStats(): EmbeddingCacheStats\n}\n\n/** LRU cache eviction options */\nexport interface EmbeddingCacheOptions {\n\treadonly maxEntries?: number\n\treadonly maxBytes?: number\n\treadonly ttlMs?: number\n\treadonly onEvict?: (contentHash: ContentHash, embedding: Embedding) => void\n}\n\n/** Factory function for creating embedding cache */\nexport type CreateEmbeddingCache = (options?: EmbeddingCacheOptions) => EmbeddingCacheInterface\n\n/** Embedding batch options */\nexport interface EmbeddingBatchOptions {\n\treadonly maxBatchSize?: number\n\treadonly flushDelayMs?: number\n\treadonly deduplicate?: boolean\n\treadonly cache?: EmbeddingCacheInterface\n}\n\n/** Batched embedding adapter interface - extends base with batching */\nexport interface BatchedEmbeddingAdapterInterface extends EmbeddingAdapterInterface {\n\tqueue(text: string, options?: AbortableOptions): Promise<Embedding>\n\tqueueBatch(texts: readonly string[], options?: AbortableOptions): Promise<readonly Embedding[]>\n\tflush(): Promise<void>\n\tgetPendingCount(): number\n\tgetCache(): EmbeddingCacheInterface | undefined\n}\n\n/** In-memory embedding cache options */\nexport interface InMemoryEmbeddingCacheOptions {\n\treadonly maxEntries?: number\n\treadonly ttlMs?: number\n}\n\n// ============================================================================\n// Persistence Types (Shared across packages)\n// ============================================================================\n\n/** Prune result information */\nexport interface PruneResult {\n\treadonly prunedCount: number\n\treadonly remainingCount: number\n}\n\n// ============================================================================\n// Storage Types (Shared between indexeddb, filesystem)\n// ============================================================================\n\n/** Storage information (quota and usage) */\nexport interface StorageInfo {\n\treadonly usage: number\n\treadonly quota: number\n\treadonly available: number\n\treadonly percentUsed: number\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * Generic error data interface for package-specific errors.\n * Use this as a base for error data interfaces in packages.\n *\n * @example\n * ```ts\n * export type MyErrorCode = 'NOT_FOUND' | 'INVALID' | 'TIMEOUT'\n * export interface MyErrorData extends PackageErrorData<MyErrorCode> {\n * readonly extra?: string\n * }\n * ```\n */\nexport interface PackageErrorData<TCode extends string> {\n\treadonly code: TCode\n\treadonly cause?: Error\n}\n\n/** Base ecosystem error */\nexport abstract class EcosystemError extends Error {\n\tabstract readonly code: string\n\toverride readonly cause: Error | undefined\n}\n\n/** Type guard for ecosystem errors */\nexport function isEcosystemError(error: unknown): error is EcosystemError {\n\treturn error instanceof EcosystemError\n}\n\n/** Extract error code type */\nexport type ErrorCode<T extends EcosystemError> = T['code']\n\n// ============================================================================\n// Minimal Cross-Package Interfaces\n// ============================================================================\n\n/**\n * Minimal database access interface for cross-package adapters.\n * Used by vectorstore persistence adapters to access IndexedDB without\n * creating a hard dependency on the indexeddb package.\n */\nexport interface MinimalDatabaseAccess<T = unknown> {\n\tstore<S extends T>(name: string): MinimalStoreAccess<S>\n}\n\n/**\n * Minimal store access interface for cross-package adapters.\n * Provides only the operations needed by persistence adapters.\n */\nexport interface MinimalStoreAccess<T> {\n\tget(key: IDBValidKey): Promise<T | undefined>\n\tset(value: T, key?: IDBValidKey): Promise<IDBValidKey>\n\tremove(key: IDBValidKey): Promise<void>\n\tall(): Promise<readonly T[]>\n\tclear(): Promise<void>\n}\n\n/**\n * Minimal directory access interface for cross-package adapters.\n * Used by vectorstore OPFS persistence adapters without creating\n * a hard dependency on the filesystem package.\n */\nexport interface MinimalDirectoryAccess {\n\tgetFile(name: string): Promise<MinimalFileAccess | undefined>\n\tcreateFile(name: string): Promise<MinimalFileAccess>\n\thasFile(name: string): Promise<boolean>\n\tremoveFile(name: string): Promise<void>\n\tlistFiles(): Promise<readonly MinimalFileAccess[]>\n}\n\n/**\n * Minimal file access interface for cross-package adapters.\n */\nexport interface MinimalFileAccess {\n\tgetName(): string\n\tgetText(): Promise<string>\n\tgetArrayBuffer(): Promise<ArrayBuffer>\n\twrite(data: string | ArrayBuffer): Promise<void>\n}\n\n// ============================================================================\n// Provider Adapter Types (for inference package integration)\n// ============================================================================\n\n/** Provider capabilities information */\nexport interface ProviderCapabilities {\n\treadonly supportsTools: boolean\n\treadonly supportsStreaming: boolean\n\treadonly supportsVision: boolean\n\treadonly supportsFunctions: boolean\n\treadonly models: readonly string[]\n}\n\n/** Generation defaults for provider adapters */\nexport interface GenerationDefaults {\n\treadonly temperature?: number\n\treadonly maxTokens?: number\n\treadonly topP?: number\n\treadonly stop?: readonly string[]\n}\n\n/**\n * Provider adapter interface for LLM providers.\n * Implemented by OpenAI, Anthropic, and other provider adapters.\n */\nexport interface ProviderAdapterInterface {\n\tgetId(): string\n\tsupportsTools(): boolean\n\tsupportsStreaming(): boolean\n\tgetCapabilities(): ProviderCapabilities\n}\n\n/** OpenAI provider adapter options */\nexport interface OpenAIProviderAdapterOptions {\n\treadonly apiKey: string\n\treadonly model?: string\n\treadonly baseURL?: string\n\treadonly organization?: string\n\treadonly defaultOptions?: GenerationDefaults\n}\n\n/** Anthropic provider adapter options */\nexport interface AnthropicProviderAdapterOptions {\n\treadonly apiKey: string\n\treadonly model?: string\n\treadonly baseURL?: string\n\treadonly defaultOptions?: GenerationDefaults\n}\n\n// ============================================================================\n// Embedding Adapter Options\n// ============================================================================\n\n/** OpenAI embedding adapter options */\nexport interface OpenAIEmbeddingAdapterOptions {\n\treadonly apiKey: string\n\treadonly model?: string\n\treadonly baseURL?: string\n\treadonly dimensions?: number\n}\n\n/** Anthropic embedding adapter options */\nexport interface AnthropicEmbeddingAdapterOptions {\n\treadonly apiKey: string\n\treadonly model?: string\n\treadonly baseURL?: string\n}\n\n// ============================================================================\n// Tool Format Adapter Types (for contextprotocol integration)\n// ============================================================================\n\n/**\n * Tool format adapter interface.\n * Converts between internal tool representations and provider-specific formats.\n */\nexport interface ToolFormatAdapterInterface {\n\tformatSchemas(schemas: readonly ToolSchema[]): unknown\n\tparseToolCalls(response: unknown): readonly ToolCall[]\n\tformatResult(result: ToolResult): unknown\n}\n\n/** OpenAI tool format adapter options */\nexport interface OpenAIToolFormatAdapterOptions {\n\treadonly toolChoice?: 'auto' | 'none' | 'required' | { readonly name: string }\n}\n\n/** Anthropic tool format adapter options */\nexport interface AnthropicToolFormatAdapterOptions {\n\treadonly toolChoice?: 'auto' | 'any' | { readonly name: string }\n}\n\n// ============================================================================\n// VectorStore Persistence Types (for vectorstore integration)\n// ============================================================================\n\n/** Stored document for persistence */\nexport interface StoredDocument {\n\treadonly id: string\n\treadonly content: string\n\treadonly embedding: Embedding\n\treadonly metadata?: Readonly<Record<string, unknown>>\n\treadonly contentHash?: ContentHash\n\treadonly createdAt?: number\n\treadonly updatedAt?: number\n}\n\n/** VectorStore metadata for persistence */\nexport interface VectorStoreMetadata {\n\treadonly dimensions: number\n\treadonly model: string\n\treadonly provider: string\n\treadonly documentCount: number\n\treadonly createdAt: number\n\treadonly updatedAt: number\n}\n\n/**\n * VectorStore persistence adapter interface.\n * Implemented by IndexedDB, OPFS, and HTTP adapters.\n */\nexport interface VectorStorePersistenceAdapterInterface {\n\tload(): Promise<readonly StoredDocument[]>\n\tloadMetadata(): Promise<VectorStoreMetadata | undefined>\n\tsave(docs: StoredDocument | readonly StoredDocument[]): Promise<void>\n\tsaveMetadata(metadata: VectorStoreMetadata): Promise<void>\n\tremove(ids: string | readonly string[]): Promise<void>\n\tclear(): Promise<void>\n\tisAvailable(): Promise<boolean>\n}\n\n/** IndexedDB VectorStore persistence options */\nexport interface IndexedDBVectorStorePersistenceOptions {\n\treadonly database: MinimalDatabaseAccess\n\treadonly documentsStore?: string\n\treadonly metadataStore?: string\n}\n\n/** OPFS VectorStore persistence options */\nexport interface OPFSVectorStorePersistenceOptions {\n\treadonly directory: MinimalDirectoryAccess\n\treadonly chunkSize?: number\n}\n\n/** HTTP persistence options */\nexport interface HTTPPersistenceOptions {\n\treadonly baseURL: string\n\treadonly headers?: Readonly<Record<string, string>>\n\treadonly timeout?: number\n}\n\n// ============================================================================\n// Internal Cache Types\n// ============================================================================\n\n/** Internal LRU cache entry with access tracking */\nexport interface LRUCacheEntry {\n\treadonly embedding: Embedding\n\treadonly createdAt: number\n\thitCount: number\n\tlastAccess: number\n}\n\n/** Pending embedding request in batch queue */\nexport interface PendingEmbeddingRequest {\n\treadonly text: string\n\treadonly contentHash: ContentHash\n\tresolve: (embedding: Embedding) => void\n\treject: (error: unknown) => void\n}\n\n// ============================================================================\n// OpenAI API Types\n// ============================================================================\n\n/** OpenAI embedding API response */\nexport interface OpenAIEmbeddingResponse {\n\treadonly object: 'list'\n\treadonly data: readonly OpenAIEmbeddingData[]\n\treadonly model: string\n\treadonly usage: OpenAIEmbeddingUsage\n}\n\n/** OpenAI embedding data item */\nexport interface OpenAIEmbeddingData {\n\treadonly object: 'embedding'\n\treadonly index: number\n\treadonly embedding: readonly number[]\n}\n\n/** OpenAI embedding usage stats */\nexport interface OpenAIEmbeddingUsage {\n\treadonly prompt_tokens: number\n\treadonly total_tokens: number\n}\n\n/** OpenAI tool schema format */\nexport interface OpenAITool {\n\treadonly type: 'function'\n\treadonly function: OpenAIToolFunction\n}\n\n/** OpenAI tool function definition */\nexport interface OpenAIToolFunction {\n\treadonly name: string\n\treadonly description: string\n\treadonly parameters: unknown\n}\n\n/** OpenAI tool call from response */\nexport interface OpenAIToolCall {\n\treadonly id: string\n\treadonly type: 'function'\n\treadonly function: OpenAIToolCallFunction\n}\n\n/** OpenAI tool call function */\nexport interface OpenAIToolCallFunction {\n\treadonly name: string\n\treadonly arguments: string\n}\n\n// ============================================================================\n// Voyage AI (Anthropic) API Types\n// ============================================================================\n\n/** Voyage AI embedding API response */\nexport interface VoyageEmbeddingResponse {\n\treadonly object: 'list'\n\treadonly data: readonly VoyageEmbeddingData[]\n\treadonly model: string\n\treadonly usage: VoyageEmbeddingUsage\n}\n\n/** Voyage AI embedding data item */\nexport interface VoyageEmbeddingData {\n\treadonly object: 'embedding'\n\treadonly index: number\n\treadonly embedding: readonly number[]\n}\n\n/** Voyage AI embedding usage stats */\nexport interface VoyageEmbeddingUsage {\n\treadonly total_tokens: number\n}\n\n/** Anthropic tool schema format */\nexport interface AnthropicTool {\n\treadonly name: string\n\treadonly description: string\n\treadonly input_schema: unknown\n}\n\n/** Anthropic tool use content block */\nexport interface AnthropicToolUse {\n\treadonly type: 'tool_use'\n\treadonly id: string\n\treadonly name: string\n\treadonly input: Readonly<Record<string, unknown>>\n}\n\n// ============================================================================\n// Bridge Types - Tool Call Bridge\n// ============================================================================\n\n/**\n * Minimal tool registry interface for bridge functions.\n * Avoids hard dependency on contextprotocol package.\n */\nexport interface ToolRegistryMinimal {\n\thas(name: string): boolean\n\texecute(name: string, args: Readonly<Record<string, unknown>>): Promise<unknown>\n}\n\n/** Tool call bridge options */\nexport interface ToolCallBridgeOptions {\n\treadonly registry: ToolRegistryMinimal\n\treadonly timeout?: number\n\treadonly onError?: (error: unknown, toolCall: ToolCall) => void\n\treadonly onBeforeExecute?: (toolCall: ToolCall) => void\n\treadonly onAfterExecute?: (toolCall: ToolCall, result: unknown) => void\n}\n\n/**\n * Tool call bridge interface.\n * Connects inference tool calls to contextprotocol tool registry.\n */\nexport interface ToolCallBridgeInterface {\n\texecute(toolCall: ToolCall): Promise<ToolResult>\n\texecuteAll(toolCalls: readonly ToolCall[]): Promise<readonly ToolResult[]>\n\thasTool(name: string): boolean\n}\n\n// ============================================================================\n// Bridge Types - Retrieval Tool\n// ============================================================================\n\n/**\n * Minimal vectorstore interface for bridge functions.\n * Avoids hard dependency on vectorstore package.\n */\nexport interface VectorStoreMinimal<TMetadata = unknown> {\n\tsearch(query: string, options?: VectorStoreSearchOptions<TMetadata>): Promise<readonly ScoredResult[]>\n}\n\n/** VectorStore search options */\nexport interface VectorStoreSearchOptions<TMetadata = unknown> {\n\treadonly limit?: number\n\treadonly filter?: TMetadata\n}\n\n/** Retrieval tool factory options */\nexport interface RetrievalToolOptions<TMetadata = unknown> {\n\treadonly vectorStore: VectorStoreMinimal<TMetadata>\n\treadonly name: string\n\treadonly description: string\n\treadonly defaultLimit?: number\n\treadonly maxLimit?: number\n\treadonly scoreThreshold?: number\n\treadonly formatResult?: (result: ScoredResult) => unknown\n\treadonly extendParameters?: Readonly<Record<string, JSONSchema7>>\n\treadonly buildFilter?: (params: Readonly<Record<string, unknown>>) => TMetadata | undefined\n}\n\n/** Retrieval tool created by factory */\nexport interface RetrievalToolCreated {\n\treadonly schema: ToolSchema\n\treadonly handler: (args: Readonly<Record<string, unknown>>) => Promise<readonly unknown[]>\n}\n\n// ============================================================================\n// Bridge Types - Form Dirty Guard\n// ============================================================================\n\n/**\n * Minimal form interface for bridge functions.\n * Avoids hard dependency on form packages.\n */\nexport interface FormMinimal<_TFormData = unknown> {\n\tisDirty(): boolean\n}\n\n/**\n * Navigation guard function type.\n * Returns true to allow navigation, false to block.\n */\nexport type NavigationGuard<TPage extends string = string> = (\n\tto: TPage,\n\tfrom: TPage\n) => Promise<boolean> | boolean\n\n/** Form dirty guard options */\nexport interface FormDirtyGuardOptions<TFormData = unknown, TPage extends string = string> {\n\treadonly form: FormMinimal<TFormData>\n\treadonly confirmFn: (message: string) => Promise<boolean> | boolean\n\treadonly message?: string\n\treadonly excludePages?: readonly TPage[]\n\treadonly onlyFromPages?: readonly TPage[]\n}\n\n// ============================================================================\n// Bridge Types - Session Persistence\n// ============================================================================\n\n/** Serialized message for persistence */\nexport interface SerializedMessage {\n\treadonly role: 'user' | 'assistant' | 'system' | 'tool'\n\treadonly content: string\n\treadonly toolCalls?: readonly ToolCall[]\n\treadonly toolResult?: ToolResult\n}\n\n/** Session metadata for persistence */\nexport interface SessionMetadata {\n\treadonly model: string\n\treadonly provider: string\n\treadonly createdAt: number\n\treadonly system?: string\n}\n\n/**\n * Minimal session interface for serialization.\n * Avoids hard dependency on inference package.\n */\nexport interface SerializableSession {\n\tgetMessages(): readonly SerializedMessage[]\n\tgetMetadata(): SessionMetadata\n}\n\n/** Serialized session for storage */\nexport interface SerializedSession {\n\treadonly id: string\n\treadonly messages: readonly SerializedMessage[]\n\treadonly metadata: SessionMetadata\n\treadonly updatedAt: number\n}\n\n/** Session persistence options */\nexport interface SessionPersistenceOptions {\n\treadonly database: MinimalDatabaseAccess\n\treadonly storeName: string\n\treadonly autoprune?: number\n\treadonly onSaveError?: (error: unknown, sessionId: string) => void\n}\n\n/**\n * Session persistence interface.\n * Connects inference sessions to IndexedDB storage.\n */\nexport interface SessionPersistenceInterface {\n\tsave(id: string, session: SerializableSession): Promise<void>\n\tload(id: string): Promise<SerializedSession | undefined>\n\tdelete(id: string): Promise<void>\n\tlist(): Promise<readonly string[]>\n\tprune(maxAgeMs: number): Promise<number>\n}\n","/**\n * @mikesaintsg/core\n *\n * Error utilities and re-exports.\n */\n\n// Re-export error types and guards from types.ts\n// These are the canonical exports for error handling\nexport { EcosystemError, isEcosystemError } from './types.js'\nexport type { PackageErrorData, ErrorCode } from './types.js'\n\n// ============================================================================\n// Core Error Codes\n// ============================================================================\n\n/** Core package error codes */\nexport type CoreErrorCode =\n\t| 'ADAPTER_ERROR'\n\t| 'BRIDGE_ERROR'\n\t| 'VALIDATION_ERROR'\n\t| 'NOT_FOUND'\n\t| 'TIMEOUT'\n\t| 'ABORTED'\n\n// ============================================================================\n// Core Error Class\n// ============================================================================\n\n/**\n * Core package error.\n *\n * @example\n * ```ts\n * throw new CoreError('ADAPTER_ERROR', 'Failed to connect to OpenAI')\n * ```\n */\nexport class CoreError extends Error {\n\treadonly code: CoreErrorCode\n\toverride readonly cause: Error | undefined\n\n\tconstructor(code: CoreErrorCode, message: string, cause?: Error) {\n\t\tsuper(message)\n\t\tthis.name = 'CoreError'\n\t\tthis.code = code\n\t\tthis.cause = cause\n\t}\n}\n\n/**\n * Type guard to check if an error is a CoreError.\n *\n * @param error - The value to check\n * @returns True if the error is a CoreError\n *\n * @example\n * ```ts\n * try {\n * await adapter.embed(['text'])\n * } catch (error) {\n * if (isCoreError(error)) {\n * console.log('Code:', error.code)\n * }\n * }\n * ```\n */\nexport function isCoreError(error: unknown): error is CoreError {\n\treturn error instanceof CoreError\n}\n","/**\n * @mikesaintsg/core\n *\n * Helper functions and type guards.\n */\n\nimport type { Ok, Err, Result, ContentHash, StoredDocument, Embedding } from './types.js'\n\n// ============================================================================\n// Result Pattern Helpers\n// ============================================================================\n\n/**\n * Create a success result.\n *\n * @param value - The success value\n * @returns An Ok result containing the value\n *\n * @example\n * ```ts\n * const result = ok(42)\n * // result.ok === true\n * // result.value === 42\n * ```\n */\nexport function ok<T>(value: T): Ok<T> {\n\treturn { ok: true, value }\n}\n\n/**\n * Create a failure result.\n *\n * @param error - The error value\n * @returns An Err result containing the error\n *\n * @example\n * ```ts\n * const result = err('NOT_FOUND')\n * // result.ok === false\n * // result.error === 'NOT_FOUND'\n * ```\n */\nexport function err<E>(error: E): Err<E> {\n\treturn { ok: false, error }\n}\n\n/**\n * Check if a result is a success.\n *\n * @param result - The result to check\n * @returns True if the result is Ok, false otherwise\n *\n * @example\n * ```ts\n * const result: Result<number, string> = ok(42)\n * if (isOk(result)) {\n * console.log(result.value) // TypeScript knows result is Ok<number>\n * }\n * ```\n */\nexport function isOk<T, E>(result: Result<T, E>): result is Ok<T> {\n\treturn result.ok === true\n}\n\n/**\n * Check if a result is a failure.\n *\n * @param result - The result to check\n * @returns True if the result is Err, false otherwise\n *\n * @example\n * ```ts\n * const result: Result<number, string> = err('NOT_FOUND')\n * if (isErr(result)) {\n * console.log(result.error) // TypeScript knows result is Err<string>\n * }\n * ```\n */\nexport function isErr<T, E>(result: Result<T, E>): result is Err<E> {\n\treturn !result.ok\n}\n\n/**\n * Unwrap a result, returning the value or a default.\n *\n * @param result - The result to unwrap\n * @param defaultValue - Value to return if result is an error\n * @returns The success value or the default value\n *\n * @example\n * ```ts\n * const value = unwrap(ok(42), 0) // 42\n * const fallback = unwrap(err('oops'), 0) // 0\n * ```\n */\nexport function unwrap<T, E>(result: Result<T, E>, defaultValue: T): T {\n\treturn result.ok ? result.value : defaultValue\n}\n\n/**\n * Unwrap a result, throwing if it's an error.\n *\n * @param result - The result to unwrap\n * @returns The success value\n * @throws The error if result is Err\n *\n * @example\n * ```ts\n * const value = unwrapOrThrow(ok(42)) // 42\n * unwrapOrThrow(err(new Error('oops'))) // throws Error('oops')\n * ```\n */\nexport function unwrapOrThrow<T, E>(result: Result<T, E>): T {\n\tif (result.ok) {\n\t\treturn result.value\n\t}\n\tif (result.error instanceof Error) {\n\t\tthrow result.error\n\t}\n\tthrow new Error(String(result.error))\n}\n\n/**\n * Map a function over a success value.\n *\n * @param result - The result to map over\n * @param fn - Function to apply to the success value\n * @returns A new result with the mapped value, or the original error\n *\n * @example\n * ```ts\n * const doubled = map(ok(5), x => x * 2) // ok(10)\n * const failed = map(err('oops'), x => x * 2) // err('oops')\n * ```\n */\nexport function map<T, U, E>(\n\tresult: Result<T, E>,\n\tfn: (value: T) => U,\n): Result<U, E> {\n\treturn result.ok ? ok(fn(result.value)) : result\n}\n\n/**\n * Map a function over an error value.\n *\n * @param result - The result to map over\n * @param fn - Function to apply to the error value\n * @returns A new result with the mapped error, or the original value\n *\n * @example\n * ```ts\n * const wrapped = mapErr(err('oops'), e => new Error(e)) // err(Error('oops'))\n * const unchanged = mapErr(ok(42), e => new Error(e)) // ok(42)\n * ```\n */\nexport function mapErr<T, E, F>(\n\tresult: Result<T, E>,\n\tfn: (error: E) => F,\n): Result<T, F> {\n\treturn result.ok ? result : err(fn(result.error))\n}\n\n/**\n * Chain results (flatMap). Apply a function that returns a Result to a success value.\n *\n * @param result - The result to chain\n * @param fn - Function returning a new Result\n * @returns The result of applying fn, or the original error\n *\n * @example\n * ```ts\n * const parsed = chain(ok('42'), s => {\n * const n = parseInt(s, 10)\n * return isNaN(n) ? err('PARSE_ERROR') : ok(n)\n * })\n * // parsed = ok(42)\n * ```\n */\nexport function chain<T, U, E>(\n\tresult: Result<T, E>,\n\tfn: (value: T) => Result<U, E>,\n): Result<U, E> {\n\treturn result.ok ? fn(result.value) : result\n}\n\n// ============================================================================\n// Content Hashing Helpers\n// ============================================================================\n\n/**\n * Compute a SHA-256 content hash for text.\n *\n * @param text - The text to hash\n * @returns A hex string content hash\n *\n * @example\n * ```ts\n * const hash = await computeContentHash('Hello, world!')\n * // hash = 'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e'\n * ```\n */\nexport async function computeContentHash(text: string): Promise<ContentHash> {\n\tconst encoder = new TextEncoder()\n\tconst data = encoder.encode(text)\n\tconst hashBuffer = await crypto.subtle.digest('SHA-256', data)\n\tconst hashArray = Array.from(new Uint8Array(hashBuffer))\n\treturn hashArray.map(b => b.toString(16).padStart(2, '0')).join('')\n}\n\n// ============================================================================\n// Document Serialization Helpers\n// ============================================================================\n\n/**\n * Serialize a stored document for JSON storage.\n * Converts Float32Array embeddings to regular arrays.\n *\n * @param doc - The document to serialize\n * @returns A plain object suitable for JSON.stringify\n *\n * @example\n * ```ts\n * const serialized = serializeStoredDocument(doc)\n * const json = JSON.stringify(serialized)\n * ```\n */\nexport function serializeStoredDocument(doc: StoredDocument): Record<string, unknown> {\n\treturn {\n\t\t...doc,\n\t\tembedding: Array.from(doc.embedding),\n\t}\n}\n\n/**\n * Deserialize a stored document from JSON storage.\n * Converts array embeddings back to Float32Array.\n *\n * @param data - The plain object from JSON.parse\n * @returns A StoredDocument with proper Float32Array embedding\n *\n * @example\n * ```ts\n * const data = JSON.parse(json)\n * const doc = deserializeStoredDocument(data)\n * ```\n */\nexport function deserializeStoredDocument(data: Record<string, unknown>): StoredDocument {\n\tconst embedding = data.embedding\n\treturn {\n\t\t...data,\n\t\tembedding: new Float32Array(embedding as number[]),\n\t} as StoredDocument\n}\n\n// ============================================================================\n// Embedding Helpers\n// ============================================================================\n\n/**\n * Estimate the byte size of an embedding.\n *\n * @param embedding - The embedding to measure\n * @returns The byte length of the embedding\n */\nexport function estimateEmbeddingBytes(embedding: Embedding): number {\n\treturn embedding.byteLength\n}\n","/**\n * @mikesaintsg/core\n *\n * Shared constants for the core library.\n */\n\n// ============================================================================\n// OpenAI Constants\n// ============================================================================\n\n/** Default OpenAI embedding model */\nexport const OPENAI_DEFAULT_EMBEDDING_MODEL = 'text-embedding-3-small'\n\n/** Default dimensions for OpenAI text-embedding-3-small */\nexport const OPENAI_DEFAULT_EMBEDDING_DIMENSIONS = 1536\n\n/** OpenAI API base URL */\nexport const OPENAI_API_BASE_URL = 'https://api.openai.com/v1'\n\n// ============================================================================\n// Voyage AI (Anthropic) Constants\n// ============================================================================\n\n/** Default Voyage AI embedding model (recommended by Anthropic) */\nexport const VOYAGE_DEFAULT_EMBEDDING_MODEL = 'voyage-2'\n\n/** Default dimensions for Voyage AI voyage-2 */\nexport const VOYAGE_DEFAULT_EMBEDDING_DIMENSIONS = 1024\n\n/** Voyage AI API base URL */\nexport const VOYAGE_API_BASE_URL = 'https://api.voyageai.com/v1'\n\n// ============================================================================\n// Embedding Cache Constants\n// ============================================================================\n\n/** Default maximum entries for embedding cache */\nexport const EMBEDDING_CACHE_DEFAULT_MAX_ENTRIES = 1000\n\n// ============================================================================\n// Batching Constants\n// ============================================================================\n\n/** Default maximum batch size for embedding requests */\nexport const EMBEDDING_BATCH_DEFAULT_MAX_SIZE = 100\n\n/** Default flush delay in milliseconds for batched embeddings */\nexport const EMBEDDING_BATCH_DEFAULT_FLUSH_DELAY_MS = 50\n\n// ============================================================================\n// Persistence Constants\n// ============================================================================\n\n/** Default documents store name for IndexedDB persistence */\nexport const INDEXEDDB_DEFAULT_DOCUMENTS_STORE = 'documents'\n\n/** Default metadata store name for IndexedDB persistence */\nexport const INDEXEDDB_DEFAULT_METADATA_STORE = 'metadata'\n\n/** Metadata key for VectorStore in persistence */\nexport const VECTORSTORE_METADATA_KEY = 'vectorstore_metadata'\n\n/** Default chunk size for OPFS persistence */\nexport const OPFS_DEFAULT_CHUNK_SIZE = 100\n\n/** Metadata file name for OPFS persistence */\nexport const OPFS_METADATA_FILE = '_metadata.json'\n\n/** Documents file name prefix for OPFS persistence */\nexport const OPFS_DOCUMENTS_PREFIX = 'chunk_'\n\n/** Default timeout for HTTP persistence requests in milliseconds */\nexport const HTTP_DEFAULT_TIMEOUT = 30000\n\n// ============================================================================\n// Bridge Constants\n// ============================================================================\n\n/** Default timeout for bridge operations in milliseconds */\nexport const BRIDGE_DEFAULT_TIMEOUT = 30000\n\n/** Default retrieval limit for retrieval tool */\nexport const RETRIEVAL_DEFAULT_LIMIT = 10\n\n/** Maximum retrieval limit for retrieval tool */\nexport const RETRIEVAL_MAX_LIMIT = 100\n\n/** Default form dirty guard message */\nexport const FORM_DIRTY_DEFAULT_MESSAGE = 'You have unsaved changes. Are you sure you want to leave?'\n","/**\n * @mikesaintsg/core\n *\n * OpenAI embedding adapter for generating text embeddings.\n */\n\nimport type {\n\tAbortableOptions,\n\tEmbedding,\n\tEmbeddingAdapterInterface,\n\tEmbeddingModelMetadata,\n\tOpenAIEmbeddingAdapterOptions,\n\tOpenAIEmbeddingResponse,\n} from '../../types.js'\nimport { CoreError } from '../../errors.js'\nimport {\n\tOPENAI_DEFAULT_EMBEDDING_MODEL,\n\tOPENAI_DEFAULT_EMBEDDING_DIMENSIONS,\n\tOPENAI_API_BASE_URL,\n} from '../../constants.js'\n\n/**\n * Create an OpenAI embedding adapter.\n *\n * @param options - OpenAI adapter configuration\n * @returns An embedding adapter for OpenAI\n *\n * @example\n * ```ts\n * const adapter = createOpenAIEmbeddingAdapter({\n * apiKey: process.env.OPENAI_API_KEY,\n * model: 'text-embedding-3-small',\n * })\n *\n * const embeddings = await adapter.embed(['Hello, world!'])\n * ```\n */\nexport function createOpenAIEmbeddingAdapter(\n\toptions: OpenAIEmbeddingAdapterOptions,\n): EmbeddingAdapterInterface {\n\tconst {\n\t\tapiKey,\n\t\tmodel = OPENAI_DEFAULT_EMBEDDING_MODEL,\n\t\tbaseURL = OPENAI_API_BASE_URL,\n\t\tdimensions = OPENAI_DEFAULT_EMBEDDING_DIMENSIONS,\n\t} = options\n\n\tif (!apiKey) {\n\t\tthrow new CoreError('ADAPTER_ERROR', 'OpenAI API key is required')\n\t}\n\n\tconst metadata: EmbeddingModelMetadata = {\n\t\tprovider: 'openai',\n\t\tmodel,\n\t\tdimensions,\n\t}\n\n\treturn {\n\t\tasync embed(texts: readonly string[], options?: AbortableOptions): Promise<readonly Embedding[]> {\n\t\t\tif (texts.length === 0) {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\tconst url = `${baseURL}/embeddings`\n\n\t\t\tconst fetchOptions: RequestInit = {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t'Authorization': `Bearer ${apiKey}`,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tinput: texts,\n\t\t\t\t\tmodel,\n\t\t\t\t\tdimensions,\n\t\t\t\t}),\n\t\t\t}\n\n\t\t\tif (options?.signal) {\n\t\t\t\tfetchOptions.signal = options.signal\n\t\t\t}\n\n\t\t\tconst response = await fetch(url, fetchOptions)\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorText = await response.text().catch(() => 'Unknown error')\n\t\t\t\tthrow new CoreError(\n\t\t\t\t\t'ADAPTER_ERROR',\n\t\t\t\t\t`OpenAI API error (${response.status}): ${errorText}`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst data = await response.json() as OpenAIEmbeddingResponse\n\n\t\t\t// Sort by index to ensure correct order\n\t\t\tconst sortedData = [...data.data].sort((a, b) => a.index - b.index)\n\n\t\t\t// Convert to Float32Array\n\t\t\treturn sortedData.map(item => new Float32Array(item.embedding))\n\t\t},\n\n\t\tgetModelMetadata(): EmbeddingModelMetadata {\n\t\t\treturn metadata\n\t\t},\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * Anthropic embedding adapter for generating text embeddings.\n * Note: Anthropic does not currently offer a public embedding API.\n * This adapter uses Voyage AI (recommended by Anthropic) as the backend.\n */\n\nimport type {\n\tAbortableOptions,\n\tEmbedding,\n\tEmbeddingAdapterInterface,\n\tEmbeddingModelMetadata,\n\tAnthropicEmbeddingAdapterOptions,\n\tVoyageEmbeddingResponse,\n} from '../../types.js'\nimport { CoreError } from '../../errors.js'\nimport {\n\tVOYAGE_DEFAULT_EMBEDDING_MODEL,\n\tVOYAGE_DEFAULT_EMBEDDING_DIMENSIONS,\n\tVOYAGE_API_BASE_URL,\n} from '../../constants.js'\n\n/**\n * Create an Anthropic-compatible embedding adapter.\n *\n * Note: Anthropic recommends Voyage AI for embeddings, so this adapter\n * uses the Voyage AI API. The apiKey should be a Voyage AI API key.\n *\n * @param options - Adapter configuration\n * @returns An embedding adapter for Anthropic/Voyage\n *\n * @example\n * ```ts\n * const adapter = createAnthropicEmbeddingAdapter({\n * apiKey: process.env.VOYAGE_API_KEY,\n * model: 'voyage-2',\n * })\n *\n * const embeddings = await adapter.embed(['Hello, world!'])\n * ```\n */\nexport function createAnthropicEmbeddingAdapter(\n\toptions: AnthropicEmbeddingAdapterOptions,\n): EmbeddingAdapterInterface {\n\tconst {\n\t\tapiKey,\n\t\tmodel = VOYAGE_DEFAULT_EMBEDDING_MODEL,\n\t\tbaseURL = VOYAGE_API_BASE_URL,\n\t} = options\n\n\tif (!apiKey) {\n\t\tthrow new CoreError('ADAPTER_ERROR', 'Voyage AI API key is required')\n\t}\n\n\tconst metadata: EmbeddingModelMetadata = {\n\t\tprovider: 'anthropic',\n\t\tmodel,\n\t\tdimensions: VOYAGE_DEFAULT_EMBEDDING_DIMENSIONS,\n\t}\n\n\treturn {\n\t\tasync embed(texts: readonly string[], options?: AbortableOptions): Promise<readonly Embedding[]> {\n\t\t\tif (texts.length === 0) {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\tconst url = `${baseURL}/embeddings`\n\n\t\t\tconst fetchOptions: RequestInit = {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t'Authorization': `Bearer ${apiKey}`,\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tinput: texts,\n\t\t\t\t\tmodel,\n\t\t\t\t}),\n\t\t\t}\n\n\t\t\tif (options?.signal) {\n\t\t\t\tfetchOptions.signal = options.signal\n\t\t\t}\n\n\t\t\tconst response = await fetch(url, fetchOptions)\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorText = await response.text().catch(() => 'Unknown error')\n\t\t\t\tthrow new CoreError(\n\t\t\t\t\t'ADAPTER_ERROR',\n\t\t\t\t\t`Voyage AI API error (${response.status}): ${errorText}`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst data = await response.json() as VoyageEmbeddingResponse\n\n\t\t\t// Sort by index to ensure correct order\n\t\t\tconst sortedData = [...data.data].sort((a, b) => a.index - b.index)\n\n\t\t\t// Convert to Float32Array\n\t\t\treturn sortedData.map(item => new Float32Array(item.embedding))\n\t\t},\n\n\t\tgetModelMetadata(): EmbeddingModelMetadata {\n\t\t\treturn metadata\n\t\t},\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * Batched embedding adapter that wraps any embedding adapter with\n * automatic batching, deduplication, and caching.\n */\n\nimport type {\n\tAbortableOptions,\n\tBatchedEmbeddingAdapterInterface,\n\tContentHash,\n\tEmbedding,\n\tEmbeddingAdapterInterface,\n\tEmbeddingBatchOptions,\n\tEmbeddingCacheInterface,\n\tEmbeddingModelMetadata,\n\tPendingEmbeddingRequest,\n} from '../../types.js'\nimport { computeContentHash } from '../../helpers.js'\nimport {\n\tEMBEDDING_BATCH_DEFAULT_MAX_SIZE,\n\tEMBEDDING_BATCH_DEFAULT_FLUSH_DELAY_MS,\n} from '../../constants.js'\n\n/**\n * Create a batched embedding adapter that wraps any embedding adapter.\n *\n * @param adapter - The base embedding adapter to wrap\n * @param options - Batching configuration options\n * @returns A batched embedding adapter instance\n *\n * @example\n * ```ts\n * const baseAdapter = createOpenAIEmbeddingAdapter({ apiKey: '...' })\n * const cache = createEmbeddingCache({ maxEntries: 1000 })\n *\n * const batched = createBatchedEmbeddingAdapter(baseAdapter, {\n * maxBatchSize: 100,\n * flushDelayMs: 50,\n * deduplicate: true,\n * cache,\n * })\n *\n * // These will be batched together\n * const [e1, e2] = await Promise.all([\n * batched.queue('text 1'),\n * batched.queue('text 2'),\n * ])\n * ```\n */\nexport function createBatchedEmbeddingAdapter(\n\tadapter: EmbeddingAdapterInterface,\n\toptions: EmbeddingBatchOptions = {},\n): BatchedEmbeddingAdapterInterface {\n\tconst {\n\t\tmaxBatchSize = EMBEDDING_BATCH_DEFAULT_MAX_SIZE,\n\t\tflushDelayMs = EMBEDDING_BATCH_DEFAULT_FLUSH_DELAY_MS,\n\t\tdeduplicate = true,\n\t\tcache,\n\t} = options\n\n\tconst pendingRequests: PendingEmbeddingRequest[] = []\n\tlet flushTimeout: ReturnType<typeof setTimeout> | undefined\n\n\t/** Schedule a flush after the delay */\n\tfunction scheduleFlush(): void {\n\t\tif (flushTimeout !== undefined) return\n\n\t\tflushTimeout = setTimeout(() => {\n\t\t\tflushTimeout = undefined\n\t\t\tvoid flushInternal()\n\t\t}, flushDelayMs)\n\t}\n\n\t/** Internal flush implementation */\n\tasync function flushInternal(): Promise<void> {\n\t\tif (pendingRequests.length === 0) return\n\n\t\t// Take all current requests\n\t\tconst requests = pendingRequests.splice(0, pendingRequests.length)\n\n\t\t// Group by unique content hash for deduplication\n\t\tconst uniqueTexts: string[] = []\n\t\tconst hashToRequests = new Map<ContentHash, PendingEmbeddingRequest[]>()\n\n\t\tfor (const request of requests) {\n\t\t\tconst existing = hashToRequests.get(request.contentHash)\n\t\t\tif (existing) {\n\t\t\t\tif (deduplicate) {\n\t\t\t\t\texisting.push(request)\n\t\t\t\t} else {\n\t\t\t\t\tuniqueTexts.push(request.text)\n\t\t\t\t\thashToRequests.set(request.contentHash + '_' + uniqueTexts.length, [request])\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tuniqueTexts.push(request.text)\n\t\t\t\thashToRequests.set(request.contentHash, [request])\n\t\t\t}\n\t\t}\n\n\t\t// Check cache for already computed embeddings\n\t\tconst textsToEmbed: string[] = []\n\t\tconst hashesForEmbedding: ContentHash[] = []\n\t\tconst cachedResults = new Map<ContentHash, Embedding>()\n\n\t\tfor (const request of requests) {\n\t\t\tif (cachedResults.has(request.contentHash)) continue\n\n\t\t\tconst cached = cache?.get(request.contentHash)\n\t\t\tif (cached) {\n\t\t\t\tcachedResults.set(request.contentHash, cached)\n\t\t\t} else if (!hashesForEmbedding.includes(request.contentHash)) {\n\t\t\t\ttextsToEmbed.push(request.text)\n\t\t\t\thashesForEmbedding.push(request.contentHash)\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Call the base adapter for uncached texts\n\t\t\tlet embeddings: readonly Embedding[] = []\n\t\t\tif (textsToEmbed.length > 0) {\n\t\t\t\tembeddings = await adapter.embed(textsToEmbed)\n\n\t\t\t\t// Cache the results\n\t\t\t\tfor (let i = 0; i < embeddings.length; i++) {\n\t\t\t\t\tconst hash = hashesForEmbedding[i]\n\t\t\t\t\tconst embedding = embeddings[i]\n\t\t\t\t\tif (hash !== undefined && embedding !== undefined) {\n\t\t\t\t\t\tcache?.set(hash, embedding)\n\t\t\t\t\t\tcachedResults.set(hash, embedding)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Resolve all pending requests\n\t\t\tfor (const request of requests) {\n\t\t\t\tconst embedding = cachedResults.get(request.contentHash)\n\t\t\t\tif (embedding) {\n\t\t\t\t\trequest.resolve(embedding)\n\t\t\t\t} else {\n\t\t\t\t\trequest.reject(new Error(`No embedding found for content hash: ${request.contentHash}`))\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Reject all pending requests on error\n\t\t\tfor (const request of requests) {\n\t\t\t\trequest.reject(error)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\t// Passthrough methods from base adapter\n\t\tasync embed(texts: readonly string[], options?: AbortableOptions): Promise<readonly Embedding[]> {\n\t\t\treturn adapter.embed(texts, options)\n\t\t},\n\n\t\tgetModelMetadata(): EmbeddingModelMetadata {\n\t\t\treturn adapter.getModelMetadata()\n\t\t},\n\n\t\t// Batched methods\n\t\tasync queue(text: string, _options?: AbortableOptions): Promise<Embedding> {\n\t\t\tconst contentHash = await computeContentHash(text)\n\n\t\t\t// Check cache first\n\t\t\tconst cached = cache?.get(contentHash)\n\t\t\tif (cached) {\n\t\t\t\treturn cached\n\t\t\t}\n\n\t\t\treturn new Promise<Embedding>((resolve, reject) => {\n\t\t\t\tpendingRequests.push({\n\t\t\t\t\ttext,\n\t\t\t\t\tcontentHash,\n\t\t\t\t\tresolve,\n\t\t\t\t\treject,\n\t\t\t\t})\n\n\t\t\t\t// Flush immediately if we hit max batch size\n\t\t\t\tif (pendingRequests.length >= maxBatchSize) {\n\t\t\t\t\tif (flushTimeout !== undefined) {\n\t\t\t\t\t\tclearTimeout(flushTimeout)\n\t\t\t\t\t\tflushTimeout = undefined\n\t\t\t\t\t}\n\t\t\t\t\tvoid flushInternal()\n\t\t\t\t} else {\n\t\t\t\t\tscheduleFlush()\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\tasync queueBatch(texts: readonly string[], options?: AbortableOptions): Promise<readonly Embedding[]> {\n\t\t\tconst promises = texts.map(text => this.queue(text, options))\n\t\t\treturn Promise.all(promises)\n\t\t},\n\n\t\tasync flush(): Promise<void> {\n\t\t\tif (flushTimeout !== undefined) {\n\t\t\t\tclearTimeout(flushTimeout)\n\t\t\t\tflushTimeout = undefined\n\t\t\t}\n\t\t\tawait flushInternal()\n\t\t},\n\n\t\tgetPendingCount(): number {\n\t\t\treturn pendingRequests.length\n\t\t},\n\n\t\tgetCache(): EmbeddingCacheInterface | undefined {\n\t\t\treturn cache\n\t\t},\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * In-memory embedding cache with LRU eviction and TTL support.\n */\n\nimport type {\n\tContentHash,\n\tEmbedding,\n\tEmbeddingCacheInterface,\n\tEmbeddingCacheOptions,\n\tEmbeddingCacheStats,\n\tLRUCacheEntry,\n} from '../../types.js'\nimport { estimateEmbeddingBytes } from '../../helpers.js'\nimport { EMBEDDING_CACHE_DEFAULT_MAX_ENTRIES } from '../../constants.js'\n\n/**\n * Create an in-memory embedding cache with LRU eviction.\n *\n * @param options - Cache configuration options\n * @returns An embedding cache instance\n *\n * @example\n * ```ts\n * const cache = createEmbeddingCache({\n * maxEntries: 1000,\n * ttlMs: 60 * 60 * 1000, // 1 hour\n * })\n *\n * cache.set('hash123', embedding)\n * const cached = cache.get('hash123')\n * ```\n */\nexport function createEmbeddingCache(\n\toptions: EmbeddingCacheOptions = {},\n): EmbeddingCacheInterface {\n\tconst {\n\t\tmaxEntries = EMBEDDING_CACHE_DEFAULT_MAX_ENTRIES,\n\t\tmaxBytes,\n\t\tttlMs,\n\t\tonEvict,\n\t} = options\n\n\tconst cache = new Map<ContentHash, LRUCacheEntry>()\n\tlet hits = 0\n\tlet misses = 0\n\n\t/** Get total estimated bytes */\n\tfunction getTotalBytes(): number {\n\t\tlet total = 0\n\t\tfor (const entry of cache.values()) {\n\t\t\ttotal += estimateEmbeddingBytes(entry.embedding)\n\t\t}\n\t\treturn total\n\t}\n\n\t/** Check if entry is expired */\n\tfunction isExpired(entry: LRUCacheEntry): boolean {\n\t\tif (ttlMs === undefined) return false\n\t\treturn Date.now() - entry.createdAt > ttlMs\n\t}\n\n\t/** Evict oldest entries until under limits */\n\tfunction evictIfNeeded(): void {\n\t\t// Evict by max entries\n\t\twhile (cache.size > maxEntries) {\n\t\t\tevictLRU()\n\t\t}\n\n\t\t// Evict by max bytes\n\t\tif (maxBytes !== undefined) {\n\t\t\twhile (getTotalBytes() > maxBytes && cache.size > 0) {\n\t\t\t\tevictLRU()\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Evict least recently used entry */\n\tfunction evictLRU(): void {\n\t\tlet oldestKey: ContentHash | undefined\n\t\tlet oldestAccess = Infinity\n\n\t\tfor (const [key, entry] of cache.entries()) {\n\t\t\tif (entry.lastAccess < oldestAccess) {\n\t\t\t\toldestAccess = entry.lastAccess\n\t\t\t\toldestKey = key\n\t\t\t}\n\t\t}\n\n\t\tif (oldestKey !== undefined) {\n\t\t\tconst entry = cache.get(oldestKey)\n\t\t\tcache.delete(oldestKey)\n\t\t\tif (entry && onEvict) {\n\t\t\t\tonEvict(oldestKey, entry.embedding)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tget(contentHash: ContentHash): Embedding | undefined {\n\t\t\tconst entry = cache.get(contentHash)\n\n\t\t\tif (!entry) {\n\t\t\t\tmisses++\n\t\t\t\treturn undefined\n\t\t\t}\n\n\t\t\tif (isExpired(entry)) {\n\t\t\t\tcache.delete(contentHash)\n\t\t\t\tif (onEvict) {\n\t\t\t\t\tonEvict(contentHash, entry.embedding)\n\t\t\t\t}\n\t\t\t\tmisses++\n\t\t\t\treturn undefined\n\t\t\t}\n\n\t\t\tentry.hitCount++\n\t\t\tentry.lastAccess = Date.now()\n\t\t\thits++\n\t\t\treturn entry.embedding\n\t\t},\n\n\t\tset(contentHash: ContentHash, embedding: Embedding): void {\n\t\t\tconst now = Date.now()\n\n\t\t\tcache.set(contentHash, {\n\t\t\t\tembedding,\n\t\t\t\tcreatedAt: now,\n\t\t\t\thitCount: 0,\n\t\t\t\tlastAccess: now,\n\t\t\t})\n\n\t\t\tevictIfNeeded()\n\t\t},\n\n\t\thas(contentHash: ContentHash): boolean {\n\t\t\tconst entry = cache.get(contentHash)\n\t\t\tif (!entry) return false\n\t\t\tif (isExpired(entry)) {\n\t\t\t\tcache.delete(contentHash)\n\t\t\t\tif (onEvict) {\n\t\t\t\t\tonEvict(contentHash, entry.embedding)\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn true\n\t\t},\n\n\t\tremove(contentHash: ContentHash): boolean {\n\t\t\tconst entry = cache.get(contentHash)\n\t\t\tif (entry && onEvict) {\n\t\t\t\tonEvict(contentHash, entry.embedding)\n\t\t\t}\n\t\t\treturn cache.delete(contentHash)\n\t\t},\n\n\t\tclear(): void {\n\t\t\tif (onEvict) {\n\t\t\t\tfor (const [key, entry] of cache.entries()) {\n\t\t\t\t\tonEvict(key, entry.embedding)\n\t\t\t\t}\n\t\t\t}\n\t\t\tcache.clear()\n\t\t\thits = 0\n\t\t\tmisses = 0\n\t\t},\n\n\t\tgetStats(): EmbeddingCacheStats {\n\t\t\tconst entries = cache.size\n\t\t\tconst total = hits + misses\n\t\t\treturn {\n\t\t\t\tentries,\n\t\t\t\thits,\n\t\t\t\tmisses,\n\t\t\t\thitRate: total > 0 ? hits / total : 0,\n\t\t\t\testimatedBytes: getTotalBytes(),\n\t\t\t}\n\t\t},\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * OpenAI tool format adapter.\n * Converts between internal tool representations and OpenAI's format.\n */\n\nimport type {\n\tToolCall,\n\tToolResult,\n\tToolSchema,\n\tToolFormatAdapterInterface,\n\tOpenAIToolFormatAdapterOptions,\n\tOpenAITool,\n\tOpenAIToolCall,\n} from '../../../types.js'\n\n/**\n * Create an OpenAI tool format adapter.\n *\n * @param options - Adapter options\n * @returns A tool format adapter for OpenAI\n *\n * @example\n * ```ts\n * const adapter = createOpenAIToolFormatAdapter({\n * toolChoice: 'auto',\n * })\n *\n * const formatted = adapter.formatSchemas(schemas)\n * const calls = adapter.parseToolCalls(response)\n * ```\n */\nexport function createOpenAIToolFormatAdapter(\n\t_options: OpenAIToolFormatAdapterOptions = {},\n): ToolFormatAdapterInterface {\n\treturn {\n\t\tformatSchemas(schemas: readonly ToolSchema[]): readonly OpenAITool[] {\n\t\t\treturn schemas.map(schema => ({\n\t\t\t\ttype: 'function' as const,\n\t\t\t\tfunction: {\n\t\t\t\t\tname: schema.name,\n\t\t\t\t\tdescription: schema.description,\n\t\t\t\t\tparameters: schema.parameters,\n\t\t\t\t},\n\t\t\t}))\n\t\t},\n\n\t\tparseToolCalls(response: unknown): readonly ToolCall[] {\n\t\t\tif (!response || typeof response !== 'object') {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\t// Handle OpenAI response format\n\t\t\tconst resp = response as {\n\t\t\t\tchoices?: readonly {\n\t\t\t\t\tmessage?: {\n\t\t\t\t\t\ttool_calls?: readonly OpenAIToolCall[]\n\t\t\t\t\t}\n\t\t\t\t}[]\n\t\t\t}\n\n\t\t\tconst toolCalls = resp.choices?.[0]?.message?.tool_calls\n\t\t\tif (!toolCalls || !Array.isArray(toolCalls)) {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\tconst result: ToolCall[] = []\n\n\t\t\tfor (const call of toolCalls as readonly OpenAIToolCall[]) {\n\t\t\t\tif (!call || typeof call !== 'object') continue\n\t\t\t\tif (!('id' in call) || !('function' in call)) continue\n\n\t\t\t\tconst fn = call.function\n\t\t\t\tif (!fn || typeof fn !== 'object') continue\n\t\t\t\tif (!('name' in fn) || !('arguments' in fn)) continue\n\n\t\t\t\tlet args: Record<string, unknown> = {}\n\t\t\t\ttry {\n\t\t\t\t\tconst parsed = JSON.parse(String(fn.arguments)) as unknown\n\t\t\t\t\tif (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n\t\t\t\t\t\targs = parsed as Record<string, unknown>\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Keep empty args on parse failure\n\t\t\t\t}\n\n\t\t\t\tresult.push({\n\t\t\t\t\tid: String(call.id),\n\t\t\t\t\tname: String(fn.name),\n\t\t\t\t\targuments: args,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\treturn result\n\t\t},\n\n\t\tformatResult(result: ToolResult): unknown {\n\t\t\treturn {\n\t\t\t\ttool_call_id: result.callId,\n\t\t\t\trole: 'tool',\n\t\t\t\tcontent: result.success\n\t\t\t\t\t? JSON.stringify(result.value)\n\t\t\t\t\t: JSON.stringify({ error: result.error }),\n\t\t\t}\n\t\t},\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * Anthropic tool format adapter.\n * Converts between internal tool representations and Anthropic's format.\n */\n\nimport type {\n\tToolCall,\n\tToolResult,\n\tToolSchema,\n\tToolFormatAdapterInterface,\n\tAnthropicToolFormatAdapterOptions,\n\tAnthropicTool,\n} from '../../../types.js'\n\n/**\n * Create an Anthropic tool format adapter.\n *\n * @param options - Adapter options\n * @returns A tool format adapter for Anthropic\n *\n * @example\n * ```ts\n * const adapter = createAnthropicToolFormatAdapter({\n * toolChoice: 'auto',\n * })\n *\n * const formatted = adapter.formatSchemas(schemas)\n * const calls = adapter.parseToolCalls(response)\n * ```\n */\nexport function createAnthropicToolFormatAdapter(\n\t_options: AnthropicToolFormatAdapterOptions = {},\n): ToolFormatAdapterInterface {\n\treturn {\n\t\tformatSchemas(schemas: readonly ToolSchema[]): readonly AnthropicTool[] {\n\t\t\treturn schemas.map(schema => ({\n\t\t\t\tname: schema.name,\n\t\t\t\tdescription: schema.description,\n\t\t\t\tinput_schema: schema.parameters,\n\t\t\t}))\n\t\t},\n\n\t\tparseToolCalls(response: unknown): readonly ToolCall[] {\n\t\t\tif (!response || typeof response !== 'object') {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\t// Handle Anthropic response format\n\t\t\tconst resp = response as {\n\t\t\t\tcontent?: readonly unknown[]\n\t\t\t}\n\n\t\t\tif (!resp.content || !Array.isArray(resp.content)) {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\tconst toolCalls: ToolCall[] = []\n\n\t\t\tfor (const block of resp.content) {\n\t\t\t\tif (!block || typeof block !== 'object') continue\n\t\t\t\tif (!('type' in block)) continue\n\n\t\t\t\tconst typedBlock = block as { type: unknown }\n\t\t\t\tif (typedBlock.type !== 'tool_use') continue\n\t\t\t\tif (!('id' in block) || !('name' in block) || !('input' in block)) continue\n\n\t\t\t\t// Type assertion after validation\n\t\t\t\tconst toolUse = block as { id: unknown; name: unknown; input: unknown }\n\t\t\t\tconst id = toolUse.id\n\t\t\t\tconst name = toolUse.name\n\t\t\t\tconst input = toolUse.input\n\n\t\t\t\tif (typeof id !== 'string' || typeof name !== 'string') continue\n\t\t\t\tif (!input || typeof input !== 'object' || Array.isArray(input)) continue\n\n\t\t\t\ttoolCalls.push({\n\t\t\t\t\tid,\n\t\t\t\t\tname,\n\t\t\t\t\targuments: input as Record<string, unknown>,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\treturn toolCalls\n\t\t},\n\n\t\tformatResult(result: ToolResult): unknown {\n\t\t\treturn {\n\t\t\t\ttype: 'tool_result',\n\t\t\t\ttool_use_id: result.callId,\n\t\t\t\tcontent: result.success\n\t\t\t\t\t? JSON.stringify(result.value)\n\t\t\t\t\t: JSON.stringify({ error: result.error }),\n\t\t\t\tis_error: !result.success,\n\t\t\t}\n\t\t},\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * IndexedDB persistence adapter for VectorStore.\n * Uses the MinimalDatabaseAccess interface to avoid hard dependency on indexeddb package.\n */\n\nimport type {\n\tIndexedDBVectorStorePersistenceOptions,\n\tStoredDocument,\n\tVectorStoreMetadata,\n\tVectorStorePersistenceAdapterInterface,\n} from '../../../types.js'\nimport {\n\tINDEXEDDB_DEFAULT_DOCUMENTS_STORE,\n\tINDEXEDDB_DEFAULT_METADATA_STORE,\n\tVECTORSTORE_METADATA_KEY,\n} from '../../../constants.js'\n\n/**\n * Create an IndexedDB persistence adapter for VectorStore.\n *\n * @param options - Adapter configuration\n * @returns A persistence adapter using IndexedDB\n *\n * @example\n * ```ts\n * import { createDatabase } from '@mikesaintsg/indexeddb'\n *\n * const db = await createDatabase({ name: 'vectors' })\n * const adapter = createIndexedDBVectorStorePersistence({\n * database: db,\n * documentsStore: 'embeddings',\n * })\n *\n * await adapter.save({ id: 'doc1', content: 'hello', embedding: new Float32Array([...]) })\n * ```\n */\nexport function createIndexedDBVectorStorePersistence(\n\toptions: IndexedDBVectorStorePersistenceOptions,\n): VectorStorePersistenceAdapterInterface {\n\tconst {\n\t\tdatabase,\n\t\tdocumentsStore = INDEXEDDB_DEFAULT_DOCUMENTS_STORE,\n\t\tmetadataStore = INDEXEDDB_DEFAULT_METADATA_STORE,\n\t} = options\n\n\tconst docs = database.store<StoredDocument>(documentsStore)\n\tconst meta = database.store<VectorStoreMetadata>(metadataStore)\n\n\treturn {\n\t\tasync load(): Promise<readonly StoredDocument[]> {\n\t\t\treturn docs.all()\n\t\t},\n\n\t\tasync loadMetadata(): Promise<VectorStoreMetadata | undefined> {\n\t\t\treturn meta.get(VECTORSTORE_METADATA_KEY)\n\t\t},\n\n\t\tasync save(documents: StoredDocument | readonly StoredDocument[]): Promise<void> {\n\t\t\tconst docsArray: readonly StoredDocument[] = Array.isArray(documents) ? documents : [documents]\n\t\t\tfor (const doc of docsArray) {\n\t\t\t\tawait docs.set(doc, doc.id)\n\t\t\t}\n\t\t},\n\n\t\tasync saveMetadata(metadata: VectorStoreMetadata): Promise<void> {\n\t\t\tawait meta.set(metadata, VECTORSTORE_METADATA_KEY)\n\t\t},\n\n\t\tasync remove(ids: string | readonly string[]): Promise<void> {\n\t\t\tconst idsArray: readonly string[] = Array.isArray(ids) ? ids : [ids]\n\t\t\tfor (const id of idsArray) {\n\t\t\t\tawait docs.remove(id)\n\t\t\t}\n\t\t},\n\n\t\tasync clear(): Promise<void> {\n\t\t\tawait docs.clear()\n\t\t\tawait meta.clear()\n\t\t},\n\n\t\tasync isAvailable(): Promise<boolean> {\n\t\t\ttry {\n\t\t\t\t// Try a simple read to verify the database is accessible\n\t\t\t\tawait docs.all()\n\t\t\t\treturn true\n\t\t\t} catch {\n\t\t\t\treturn false\n\t\t\t}\n\t\t},\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * OPFS persistence adapter for VectorStore.\n * Uses the MinimalDirectoryAccess interface to avoid hard dependency on filesystem package.\n */\n\nimport type {\n\tOPFSVectorStorePersistenceOptions,\n\tStoredDocument,\n\tVectorStoreMetadata,\n\tVectorStorePersistenceAdapterInterface,\n} from '../../../types.js'\nimport {\n\tserializeStoredDocument,\n\tdeserializeStoredDocument,\n} from '../../../helpers.js'\nimport {\n\tOPFS_DEFAULT_CHUNK_SIZE,\n\tOPFS_METADATA_FILE,\n\tOPFS_DOCUMENTS_PREFIX,\n} from '../../../constants.js'\n\n/**\n * Create an OPFS persistence adapter for VectorStore.\n *\n * @param options - Adapter configuration\n * @returns A persistence adapter using OPFS\n *\n * @example\n * ```ts\n * import { createDirectory } from '@mikesaintsg/filesystem'\n *\n * const dir = await createDirectory({ name: 'vectors' })\n * const adapter = createOPFSVectorStorePersistence({\n * directory: dir,\n * chunkSize: 50,\n * })\n *\n * await adapter.save({ id: 'doc1', content: 'hello', embedding: new Float32Array([...]) })\n * ```\n */\nexport function createOPFSVectorStorePersistence(\n\toptions: OPFSVectorStorePersistenceOptions,\n): VectorStorePersistenceAdapterInterface {\n\tconst {\n\t\tdirectory,\n\t\tchunkSize = OPFS_DEFAULT_CHUNK_SIZE,\n\t} = options\n\n\treturn {\n\t\tasync load(): Promise<readonly StoredDocument[]> {\n\t\t\tconst files = await directory.listFiles()\n\t\t\tconst documents: StoredDocument[] = []\n\n\t\t\tfor (const file of files) {\n\t\t\t\tconst name = file.getName()\n\t\t\t\tif (!name.startsWith(OPFS_DOCUMENTS_PREFIX)) continue\n\n\t\t\t\ttry {\n\t\t\t\t\tconst text = await file.getText()\n\t\t\t\t\tconst chunk = JSON.parse(text) as Record<string, unknown>[]\n\t\t\t\t\tfor (const data of chunk) {\n\t\t\t\t\t\tdocuments.push(deserializeStoredDocument(data))\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Skip corrupt chunks\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn documents\n\t\t},\n\n\t\tasync loadMetadata(): Promise<VectorStoreMetadata | undefined> {\n\t\t\tconst file = await directory.getFile(OPFS_METADATA_FILE)\n\t\t\tif (!file) return undefined\n\n\t\t\ttry {\n\t\t\t\tconst text = await file.getText()\n\t\t\t\treturn JSON.parse(text) as VectorStoreMetadata\n\t\t\t} catch {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t},\n\n\t\tasync save(documents: StoredDocument | readonly StoredDocument[]): Promise<void> {\n\t\t\tconst docsArray: readonly StoredDocument[] = Array.isArray(documents) ? documents : [documents]\n\t\t\tif (docsArray.length === 0) return\n\n\t\t\t// Load existing documents\n\t\t\tconst existing = await this.load()\n\t\t\tconst existingMap = new Map<string, StoredDocument>(existing.map(d => [d.id, d]))\n\n\t\t\t// Merge new documents\n\t\t\tfor (const doc of docsArray) {\n\t\t\t\texistingMap.set(doc.id, doc)\n\t\t\t}\n\n\t\t\t// Clear existing chunks\n\t\t\tconst files = await directory.listFiles()\n\t\t\tfor (const file of files) {\n\t\t\t\tif (file.getName().startsWith(OPFS_DOCUMENTS_PREFIX)) {\n\t\t\t\t\tawait directory.removeFile(file.getName())\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Write new chunks\n\t\t\tconst allDocs = Array.from(existingMap.values())\n\t\t\tfor (let i = 0; i < allDocs.length; i += chunkSize) {\n\t\t\t\tconst chunk = allDocs.slice(i, i + chunkSize)\n\t\t\t\tconst chunkIndex = Math.floor(i / chunkSize)\n\t\t\t\tconst fileName = `${OPFS_DOCUMENTS_PREFIX}${chunkIndex}.json`\n\n\t\t\t\tconst file = await directory.createFile(fileName)\n\t\t\t\tawait file.write(JSON.stringify(chunk.map(serializeStoredDocument)))\n\t\t\t}\n\t\t},\n\n\t\tasync saveMetadata(metadata: VectorStoreMetadata): Promise<void> {\n\t\t\tconst file = await directory.createFile(OPFS_METADATA_FILE)\n\t\t\tawait file.write(JSON.stringify(metadata))\n\t\t},\n\n\t\tasync remove(ids: string | readonly string[]): Promise<void> {\n\t\t\tconst idsArray: readonly string[] = Array.isArray(ids) ? ids : [ids]\n\t\t\tconst idsSet = new Set(idsArray)\n\n\t\t\t// Load, filter, and re-save\n\t\t\tconst existing = await this.load()\n\t\t\tconst filtered = existing.filter(d => !idsSet.has(d.id))\n\n\t\t\t// Clear and rewrite\n\t\t\tawait this.clear()\n\t\t\tif (filtered.length > 0) {\n\t\t\t\tawait this.save(filtered)\n\t\t\t}\n\t\t},\n\n\t\tasync clear(): Promise<void> {\n\t\t\tconst files = await directory.listFiles()\n\t\t\tfor (const file of files) {\n\t\t\t\tawait directory.removeFile(file.getName())\n\t\t\t}\n\t\t},\n\n\t\tasync isAvailable(): Promise<boolean> {\n\t\t\ttry {\n\t\t\t\t// Try to check if OPFS is available by testing file operations\n\t\t\t\tawait directory.listFiles()\n\t\t\t\treturn true\n\t\t\t} catch {\n\t\t\t\treturn false\n\t\t\t}\n\t\t},\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * HTTP persistence adapter for VectorStore.\n * Persists documents to a remote HTTP endpoint.\n */\n\nimport type {\n\tHTTPPersistenceOptions,\n\tStoredDocument,\n\tVectorStoreMetadata,\n\tVectorStorePersistenceAdapterInterface,\n} from '../../../types.js'\nimport { CoreError } from '../../../errors.js'\nimport {\n\tserializeStoredDocument,\n\tdeserializeStoredDocument,\n} from '../../../helpers.js'\nimport { HTTP_DEFAULT_TIMEOUT } from '../../../constants.js'\n\n/**\n * Create an HTTP persistence adapter for VectorStore.\n *\n * @param options - Adapter configuration\n * @returns A persistence adapter using HTTP\n *\n * @example\n * ```ts\n * const adapter = createHTTPVectorStorePersistence({\n * baseURL: 'https://api.example.com/vectors',\n * headers: { 'Authorization': 'Bearer token' },\n * })\n *\n * await adapter.save({ id: 'doc1', content: 'hello', embedding: new Float32Array([...]) })\n * ```\n */\nexport function createHTTPVectorStorePersistence(\n\toptions: HTTPPersistenceOptions,\n): VectorStorePersistenceAdapterInterface {\n\tconst {\n\t\tbaseURL,\n\t\theaders = {},\n\t\ttimeout = HTTP_DEFAULT_TIMEOUT,\n\t} = options\n\n\t/** Make a fetch request with timeout */\n\tasync function fetchWithTimeout(\n\t\turl: string,\n\t\tinit: RequestInit,\n\t): Promise<Response> {\n\t\tconst controller = new AbortController()\n\t\tconst timeoutId = setTimeout(() => controller.abort(), timeout)\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, {\n\t\t\t\t...init,\n\t\t\t\tsignal: controller.signal,\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t...headers,\n\t\t\t\t\t...init.headers,\n\t\t\t\t},\n\t\t\t})\n\t\t\treturn response\n\t\t} finally {\n\t\t\tclearTimeout(timeoutId)\n\t\t}\n\t}\n\n\treturn {\n\t\tasync load(): Promise<readonly StoredDocument[]> {\n\t\t\tconst response = await fetchWithTimeout(`${baseURL}/documents`, {\n\t\t\t\tmethod: 'GET',\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new CoreError(\n\t\t\t\t\t'ADAPTER_ERROR',\n\t\t\t\t\t`HTTP load failed (${response.status})`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst data = await response.json() as Record<string, unknown>[]\n\t\t\treturn data.map(deserializeStoredDocument)\n\t\t},\n\n\t\tasync loadMetadata(): Promise<VectorStoreMetadata | undefined> {\n\t\t\ttry {\n\t\t\t\tconst response = await fetchWithTimeout(`${baseURL}/metadata`, {\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t})\n\n\t\t\t\tif (response.status === 404) {\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new CoreError(\n\t\t\t\t\t\t'ADAPTER_ERROR',\n\t\t\t\t\t\t`HTTP loadMetadata failed (${response.status})`,\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\treturn await response.json() as VectorStoreMetadata\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof CoreError) throw error\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t},\n\n\t\tasync save(documents: StoredDocument | readonly StoredDocument[]): Promise<void> {\n\t\t\tconst docsArray: readonly StoredDocument[] = Array.isArray(documents) ? documents : [documents]\n\n\t\t\tconst response = await fetchWithTimeout(`${baseURL}/documents`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\tbody: JSON.stringify(docsArray.map(serializeStoredDocument)),\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new CoreError(\n\t\t\t\t\t'ADAPTER_ERROR',\n\t\t\t\t\t`HTTP save failed (${response.status})`,\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\n\t\tasync saveMetadata(metadata: VectorStoreMetadata): Promise<void> {\n\t\t\tconst response = await fetchWithTimeout(`${baseURL}/metadata`, {\n\t\t\t\tmethod: 'PUT',\n\t\t\t\tbody: JSON.stringify(metadata),\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new CoreError(\n\t\t\t\t\t'ADAPTER_ERROR',\n\t\t\t\t\t`HTTP saveMetadata failed (${response.status})`,\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\n\t\tasync remove(ids: string | readonly string[]): Promise<void> {\n\t\t\tconst idsArray = Array.isArray(ids) ? ids : [ids]\n\n\t\t\tconst response = await fetchWithTimeout(`${baseURL}/documents`, {\n\t\t\t\tmethod: 'DELETE',\n\t\t\t\tbody: JSON.stringify({ ids: idsArray }),\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new CoreError(\n\t\t\t\t\t'ADAPTER_ERROR',\n\t\t\t\t\t`HTTP remove failed (${response.status})`,\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\n\t\tasync clear(): Promise<void> {\n\t\t\tconst response = await fetchWithTimeout(`${baseURL}/documents`, {\n\t\t\t\tmethod: 'DELETE',\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new CoreError(\n\t\t\t\t\t'ADAPTER_ERROR',\n\t\t\t\t\t`HTTP clear failed (${response.status})`,\n\t\t\t\t)\n\t\t\t}\n\t\t},\n\n\t\tasync isAvailable(): Promise<boolean> {\n\t\t\ttry {\n\t\t\t\tconst response = await fetchWithTimeout(`${baseURL}/health`, {\n\t\t\t\t\tmethod: 'GET',\n\t\t\t\t})\n\t\t\t\treturn response.ok\n\t\t\t} catch {\n\t\t\t\treturn false\n\t\t\t}\n\t\t},\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * Tool call bridge that connects inference tool calls to contextprotocol tool registry.\n */\n\nimport type {\n\tToolCall,\n\tToolResult,\n\tToolCallBridgeOptions,\n\tToolCallBridgeInterface,\n} from '../types.js'\nimport { BRIDGE_DEFAULT_TIMEOUT } from '../constants.js'\n\n/**\n * Create a tool call bridge.\n *\n * @param options - Bridge configuration options\n * @returns A tool call bridge instance\n *\n * @example\n * ```ts\n * import { createToolRegistry } from '@mikesaintsg/contextprotocol'\n * import { createToolCallBridge } from '@mikesaintsg/core'\n *\n * const registry = createToolRegistry()\n * registry.register(weatherTool)\n *\n * const bridge = createToolCallBridge({\n * registry,\n * timeout: 30000,\n * onError: (error, toolCall) => console.error(`Tool ${toolCall.name} failed:`, error),\n * })\n *\n * // Execute tool calls from LLM response\n * const results = await bridge.executeAll(response.toolCalls)\n * ```\n */\nexport function createToolCallBridge(\n\toptions: ToolCallBridgeOptions,\n): ToolCallBridgeInterface {\n\tconst {\n\t\tregistry,\n\t\ttimeout = BRIDGE_DEFAULT_TIMEOUT,\n\t\tonError,\n\t\tonBeforeExecute,\n\t\tonAfterExecute,\n\t} = options\n\n\t/**\n\t * Execute a single tool call with timeout.\n\t */\n\tasync function executeWithTimeout(\n\t\ttoolCall: ToolCall,\n\t): Promise<ToolResult> {\n\t\t// Check if tool exists\n\t\tif (!registry.has(toolCall.name)) {\n\t\t\tconst result: ToolResult = {\n\t\t\t\tcallId: toolCall.id,\n\t\t\t\tname: toolCall.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `Tool not found: ${toolCall.name}`,\n\t\t\t}\n\t\t\treturn result\n\t\t}\n\n\t\t// Call lifecycle hook\n\t\tonBeforeExecute?.(toolCall)\n\n\t\ttry {\n\t\t\t// Create timeout promise\n\t\t\tconst timeoutPromise = new Promise<never>((_, reject) => {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\treject(new Error(`Tool execution timed out after ${timeout}ms`))\n\t\t\t\t}, timeout)\n\t\t\t})\n\n\t\t\t// Execute tool with timeout\n\t\t\tconst value = await Promise.race([\n\t\t\t\tregistry.execute(toolCall.name, toolCall.arguments),\n\t\t\t\ttimeoutPromise,\n\t\t\t])\n\n\t\t\t// Call lifecycle hook\n\t\t\tonAfterExecute?.(toolCall, value)\n\n\t\t\treturn {\n\t\t\t\tcallId: toolCall.id,\n\t\t\t\tname: toolCall.name,\n\t\t\t\tsuccess: true,\n\t\t\t\tvalue,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Call error hook\n\t\t\tonError?.(error, toolCall)\n\n\t\t\tconst errorMessage = error instanceof Error\n\t\t\t\t? error.message\n\t\t\t\t: String(error)\n\n\t\t\treturn {\n\t\t\t\tcallId: toolCall.id,\n\t\t\t\tname: toolCall.name,\n\t\t\t\tsuccess: false,\n\t\t\t\terror: errorMessage,\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tasync execute(toolCall: ToolCall): Promise<ToolResult> {\n\t\t\treturn executeWithTimeout(toolCall)\n\t\t},\n\n\t\tasync executeAll(toolCalls: readonly ToolCall[]): Promise<readonly ToolResult[]> {\n\t\t\t// Execute all tool calls in parallel\n\t\t\tconst results = await Promise.all(\n\t\t\t\ttoolCalls.map(toolCall => executeWithTimeout(toolCall)),\n\t\t\t)\n\t\t\treturn results\n\t\t},\n\n\t\thasTool(name: string): boolean {\n\t\t\treturn registry.has(name)\n\t\t},\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * Retrieval tool factory that connects vectorstore to contextprotocol.\n */\n\nimport type {\n\tRetrievalToolOptions,\n\tRetrievalToolCreated,\n\tToolSchema,\n\tJSONSchema7,\n\tScoredResult,\n} from '../types.js'\nimport {\n\tRETRIEVAL_DEFAULT_LIMIT,\n\tRETRIEVAL_MAX_LIMIT,\n} from '../constants.js'\n\n/**\n * Create a retrieval tool for use with contextprotocol tool registry.\n *\n * @param options - Retrieval tool configuration options\n * @returns A tool schema and handler for registration\n *\n * @example\n * ```ts\n * import { createVectorStore } from '@mikesaintsg/vectorstore'\n * import { createToolRegistry } from '@mikesaintsg/contextprotocol'\n * import { createRetrievalTool } from '@mikesaintsg/core'\n *\n * const vectorStore = createVectorStore({ ... })\n * const registry = createToolRegistry()\n *\n * const { schema, handler } = createRetrievalTool({\n * vectorStore,\n * name: 'search_docs',\n * description: 'Search documentation for relevant information',\n * defaultLimit: 5,\n * scoreThreshold: 0.7,\n * })\n *\n * registry.register({ ...schema, execute: handler })\n * ```\n */\nexport function createRetrievalTool<TMetadata = unknown>(\n\toptions: RetrievalToolOptions<TMetadata>,\n): RetrievalToolCreated {\n\tconst {\n\t\tvectorStore,\n\t\tname,\n\t\tdescription,\n\t\tdefaultLimit = RETRIEVAL_DEFAULT_LIMIT,\n\t\tmaxLimit = RETRIEVAL_MAX_LIMIT,\n\t\tscoreThreshold,\n\t\tformatResult = defaultFormatResult,\n\t\textendParameters = {},\n\t\tbuildFilter,\n\t} = options\n\n\t// Build tool schema parameters\n\tconst parameters: JSONSchema7 = {\n\t\ttype: 'object',\n\t\tproperties: {\n\t\t\tquery: {\n\t\t\t\ttype: 'string',\n\t\t\t\tdescription: 'The search query to find relevant documents',\n\t\t\t},\n\t\t\tlimit: {\n\t\t\t\ttype: 'integer',\n\t\t\t\tdescription: `Maximum number of results to return (default: ${defaultLimit}, max: ${maxLimit})`,\n\t\t\t\tminimum: 1,\n\t\t\t\tmaximum: maxLimit,\n\t\t\t\tdefault: defaultLimit,\n\t\t\t},\n\t\t\t...extendParameters,\n\t\t},\n\t\trequired: ['query'],\n\t}\n\n\tconst schema: ToolSchema = {\n\t\tname,\n\t\tdescription,\n\t\tparameters,\n\t}\n\n\tasync function handler(\n\t\targs: Readonly<Record<string, unknown>>,\n\t): Promise<readonly unknown[]> {\n\t\tconst query = args.query\n\t\tif (typeof query !== 'string' || query.length === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\tconst requestedLimit = args.limit\n\t\tlet limit = defaultLimit\n\t\tif (typeof requestedLimit === 'number' && Number.isInteger(requestedLimit)) {\n\t\t\tlimit = Math.min(Math.max(1, requestedLimit), maxLimit)\n\t\t}\n\n\t\t// Build filter if provided\n\t\tconst filter = buildFilter?.(args)\n\n\t\t// Search vectorstore - only include filter if defined\n\t\tconst searchOptions = filter !== undefined\n\t\t\t? { limit, filter }\n\t\t\t: { limit }\n\t\tconst results = await vectorStore.search(query, searchOptions)\n\n\t\t// Filter by score threshold\n\t\tlet filteredResults = results\n\t\tif (scoreThreshold !== undefined) {\n\t\t\tfilteredResults = results.filter(r => r.score >= scoreThreshold)\n\t\t}\n\n\t\t// Format results\n\t\treturn filteredResults.map(formatResult)\n\t}\n\n\treturn { schema, handler }\n}\n\n/**\n * Default result formatter - returns content and metadata.\n */\nfunction defaultFormatResult(result: ScoredResult): unknown {\n\treturn {\n\t\tcontent: result.content,\n\t\tscore: result.score,\n\t\tmetadata: result.metadata,\n\t}\n}\n","/**\n * @mikesaintsg/core\n *\n * Form dirty guard that prevents navigation when form has unsaved changes.\n */\n\nimport type {\n\tFormDirtyGuardOptions,\n\tNavigationGuard,\n} from '../types.js'\nimport { FORM_DIRTY_DEFAULT_MESSAGE } from '../constants.js'\n\n/**\n * Create a navigation guard that prevents leaving when form is dirty.\n *\n * @param options - Form dirty guard configuration options\n * @returns A navigation guard function\n *\n * @example\n * ```ts\n * import { createForm } from '@mikesaintsg/form'\n * import { createFormDirtyGuard } from '@mikesaintsg/core'\n *\n * const form = createForm({ ... })\n *\n * const guard = createFormDirtyGuard({\n * form,\n * confirmFn: (message) => window.confirm(message),\n * message: 'You have unsaved changes. Continue?',\n * excludePages: ['settings'],\n * })\n *\n * // Use with router\n * router.beforeNavigate(guard)\n * ```\n */\nexport function createFormDirtyGuard<TFormData = unknown, TPage extends string = string>(\n\toptions: FormDirtyGuardOptions<TFormData, TPage>,\n): NavigationGuard<TPage> {\n\tconst {\n\t\tform,\n\t\tconfirmFn,\n\t\tmessage = FORM_DIRTY_DEFAULT_MESSAGE,\n\t\texcludePages = [],\n\t\tonlyFromPages,\n\t} = options\n\n\treturn async function guard(to: TPage, from: TPage): Promise<boolean> {\n\t\t// Check if we should skip guard for this navigation\n\t\tif (shouldSkipGuard(to, from, excludePages, onlyFromPages)) {\n\t\t\treturn true\n\t\t}\n\n\t\t// If form is not dirty, allow navigation\n\t\tif (!form.isDirty()) {\n\t\t\treturn true\n\t\t}\n\n\t\t// Form is dirty, ask for confirmation\n\t\tconst confirmed = await Promise.resolve(confirmFn(message))\n\t\treturn confirmed\n\t}\n}\n\n/**\n * Determine if guard should be skipped for this navigation.\n */\nfunction shouldSkipGuard<TPage extends string>(\n\tto: TPage,\n\tfrom: TPage,\n\texcludePages: readonly TPage[],\n\tonlyFromPages: readonly TPage[] | undefined,\n): boolean {\n\t// Skip if navigating to excluded page\n\tif (excludePages.includes(to)) {\n\t\treturn true\n\t}\n\n\t// Skip if from page is not in onlyFromPages (if specified)\n\tif (onlyFromPages !== undefined && !onlyFromPages.includes(from)) {\n\t\treturn true\n\t}\n\n\treturn false\n}\n","/**\n * @mikesaintsg/core\n *\n * Session persistence bridge that connects inference sessions to IndexedDB storage.\n */\n\nimport type {\n\tSessionPersistenceOptions,\n\tSessionPersistenceInterface,\n\tSerializableSession,\n\tSerializedSession,\n} from '../types.js'\n\n/**\n * Create a session persistence adapter for storing inference sessions.\n *\n * @param options - Session persistence configuration options\n * @returns A session persistence instance\n *\n * @example\n * ```ts\n * import { createDatabase } from '@mikesaintsg/indexeddb'\n * import { createSessionPersistence } from '@mikesaintsg/core'\n *\n * const db = await createDatabase({ name: 'sessions' })\n * const persistence = createSessionPersistence({\n * database: db,\n * storeName: 'chat_sessions',\n * autoprune: 7 * 24 * 60 * 60 * 1000, // 7 days\n * })\n *\n * // Save session\n * await persistence.save('session-1', session)\n *\n * // Load session\n * const savedSession = await persistence.load('session-1')\n * ```\n */\nexport function createSessionPersistence(\n\toptions: SessionPersistenceOptions,\n): SessionPersistenceInterface {\n\tconst {\n\t\tdatabase,\n\t\tstoreName,\n\t\tautoprune,\n\t\tonSaveError,\n\t} = options\n\n\tconst store = database.store<SerializedSession>(storeName)\n\n\t// Auto-prune on creation if configured\n\tif (autoprune !== undefined && autoprune > 0) {\n\t\tvoid pruneOldSessions(autoprune)\n\t}\n\n\t/**\n\t * Prune sessions older than maxAgeMs.\n\t */\n\tasync function pruneOldSessions(maxAgeMs: number): Promise<number> {\n\t\tconst now = Date.now()\n\t\tconst cutoff = now - maxAgeMs\n\n\t\tconst allSessions = await store.all()\n\t\tlet prunedCount = 0\n\n\t\tfor (const session of allSessions) {\n\t\t\tif (session.updatedAt < cutoff) {\n\t\t\t\tawait store.remove(session.id)\n\t\t\t\tprunedCount++\n\t\t\t}\n\t\t}\n\n\t\treturn prunedCount\n\t}\n\n\treturn {\n\t\tasync save(id: string, session: SerializableSession): Promise<void> {\n\t\t\ttry {\n\t\t\t\tconst serialized: SerializedSession = {\n\t\t\t\t\tid,\n\t\t\t\t\tmessages: [...session.getMessages()],\n\t\t\t\t\tmetadata: session.getMetadata(),\n\t\t\t\t\tupdatedAt: Date.now(),\n\t\t\t\t}\n\n\t\t\t\tawait store.set(serialized, id)\n\t\t\t} catch (error) {\n\t\t\t\tonSaveError?.(error, id)\n\t\t\t\tthrow error\n\t\t\t}\n\t\t},\n\n\t\tasync load(id: string): Promise<SerializedSession | undefined> {\n\t\t\treturn store.get(id)\n\t\t},\n\n\t\tasync delete(id: string): Promise<void> {\n\t\t\tawait store.remove(id)\n\t\t},\n\n\t\tasync list(): Promise<readonly string[]> {\n\t\t\tconst allSessions = await store.all()\n\t\t\treturn allSessions.map(s => s.id)\n\t\t},\n\n\t\tasync prune(maxAgeMs: number): Promise<number> {\n\t\t\treturn pruneOldSessions(maxAgeMs)\n\t\t},\n\t}\n}\n"],"names":["EcosystemError","isEcosystemError","error","CoreError","code","message","cause","isCoreError","ok","value","err","isOk","result","isErr","unwrap","defaultValue","unwrapOrThrow","map","fn","mapErr","chain","computeContentHash","text","data","hashBuffer","b","serializeStoredDocument","doc","deserializeStoredDocument","embedding","estimateEmbeddingBytes","OPENAI_DEFAULT_EMBEDDING_MODEL","OPENAI_DEFAULT_EMBEDDING_DIMENSIONS","OPENAI_API_BASE_URL","VOYAGE_DEFAULT_EMBEDDING_MODEL","VOYAGE_DEFAULT_EMBEDDING_DIMENSIONS","VOYAGE_API_BASE_URL","EMBEDDING_CACHE_DEFAULT_MAX_ENTRIES","EMBEDDING_BATCH_DEFAULT_MAX_SIZE","EMBEDDING_BATCH_DEFAULT_FLUSH_DELAY_MS","INDEXEDDB_DEFAULT_DOCUMENTS_STORE","INDEXEDDB_DEFAULT_METADATA_STORE","VECTORSTORE_METADATA_KEY","OPFS_DEFAULT_CHUNK_SIZE","OPFS_METADATA_FILE","OPFS_DOCUMENTS_PREFIX","HTTP_DEFAULT_TIMEOUT","BRIDGE_DEFAULT_TIMEOUT","RETRIEVAL_DEFAULT_LIMIT","RETRIEVAL_MAX_LIMIT","FORM_DIRTY_DEFAULT_MESSAGE","createOpenAIEmbeddingAdapter","options","apiKey","model","baseURL","dimensions","metadata","texts","url","fetchOptions","response","errorText","a","item","createAnthropicEmbeddingAdapter","createBatchedEmbeddingAdapter","adapter","maxBatchSize","flushDelayMs","deduplicate","cache","pendingRequests","flushTimeout","scheduleFlush","flushInternal","requests","uniqueTexts","hashToRequests","request","existing","textsToEmbed","hashesForEmbedding","cachedResults","cached","embeddings","i","hash","_options","contentHash","resolve","reject","promises","createEmbeddingCache","maxEntries","maxBytes","ttlMs","onEvict","hits","misses","getTotalBytes","total","entry","isExpired","evictIfNeeded","evictLRU","oldestKey","oldestAccess","key","now","entries","createOpenAIToolFormatAdapter","schemas","schema","toolCalls","call","args","parsed","createAnthropicToolFormatAdapter","resp","block","toolUse","id","name","input","createIndexedDBVectorStorePersistence","database","documentsStore","metadataStore","docs","meta","documents","docsArray","ids","idsArray","createOPFSVectorStorePersistence","directory","chunkSize","files","file","chunk","existingMap","d","allDocs","chunkIndex","fileName","idsSet","filtered","createHTTPVectorStorePersistence","headers","timeout","fetchWithTimeout","init","controller","timeoutId","createToolCallBridge","registry","onError","onBeforeExecute","onAfterExecute","executeWithTimeout","toolCall","timeoutPromise","_","errorMessage","createRetrievalTool","vectorStore","description","defaultLimit","maxLimit","scoreThreshold","formatResult","defaultFormatResult","extendParameters","buildFilter","parameters","handler","query","requestedLimit","limit","filter","searchOptions","results","filteredResults","r","createFormDirtyGuard","form","confirmFn","excludePages","onlyFromPages","to","from","shouldSkipGuard","createSessionPersistence","storeName","autoprune","onSaveError","store","pruneOldSessions","maxAgeMs","cutoff","allSessions","prunedCount","session","serialized","s"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/errors.ts","../src/helpers.ts","../src/constants.ts","../src/bridges/tool-call.ts","../src/bridges/retrieval-tool.ts","../src/bridges/form-dirty-guard.ts","../src/bridges/session-persistence.ts"],"sourcesContent":["/**\r\n * @mikesaintsg/core\r\n *\r\n * Error utilities and re-exports.\r\n */\r\n\r\n// ============================================================================\r\n// Base Ecosystem Error\r\n// ============================================================================\r\n\r\nimport { CoreErrorCode } from './types'\r\n\r\n/**\r\n * Base error class for all ecosystem errors.\r\n * All package-specific errors should extend this class.\r\n */\r\nexport abstract class EcosystemError extends Error {\r\n\tabstract readonly code: string\r\n\toverride readonly cause: Error | undefined\r\n\r\n\tconstructor(message: string, cause?: Error) {\r\n\t\tsuper(message)\r\n\t\tthis.name = this.constructor.name\r\n\t\tthis.cause = cause\r\n\t}\r\n}\r\n\r\n/**\r\n * Type guard for ecosystem errors.\r\n *\r\n * @param error - The value to check\r\n * @returns True if the error is an EcosystemError\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await someOperation()\r\n * } catch (error) {\r\n * if (isEcosystemError(error)) {\r\n * console.log('Code:', error.code)\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isEcosystemError(error: unknown): error is EcosystemError {\r\n\treturn error instanceof EcosystemError\r\n}\r\n\r\n// ============================================================================\r\n// Core Error Class\r\n// ============================================================================\r\n\r\n/**\r\n * Core package error.\r\n *\r\n * @example\r\n * ```ts\r\n * throw new CoreError('ADAPTER_ERROR', 'Failed to connect to OpenAI')\r\n * ```\r\n */\r\nexport class CoreError extends Error {\r\n\treadonly code: CoreErrorCode\r\n\toverride readonly cause: Error | undefined\r\n\r\n\tconstructor(code: CoreErrorCode, message: string, cause?: Error) {\r\n\t\tsuper(message)\r\n\t\tthis.name = 'CoreError'\r\n\t\tthis.code = code\r\n\t\tthis.cause = cause\r\n\t}\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is a CoreError.\r\n *\r\n * @param error - The value to check\r\n * @returns True if the error is a CoreError\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await adapter.embed(['text'])\r\n * } catch (error) {\r\n * if (isCoreError(error)) {\r\n * console.log('Code:', error.code)\r\n * }\r\n * }\r\n * ```\r\n */\r\nexport function isCoreError(error: unknown): error is CoreError {\r\n\treturn error instanceof CoreError\r\n}\r\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Helper functions and type guards.\r\n */\r\n\r\nimport type { Ok, Err, Result, ContentHash } from './types.js'\r\n\r\n// ============================================================================\r\n// Result Pattern Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Create a success result.\r\n *\r\n * @param value - The success value\r\n * @returns An Ok result containing the value\r\n *\r\n * @example\r\n * ```ts\r\n * const result = ok(42)\r\n * // result.ok === true\r\n * // result.value === 42\r\n * ```\r\n */\r\nexport function ok<T>(value: T): Ok<T> {\r\n\treturn { ok: true, value }\r\n}\r\n\r\n/**\r\n * Create a failure result.\r\n *\r\n * @param error - The error value\r\n * @returns An Err result containing the error\r\n *\r\n * @example\r\n * ```ts\r\n * const result = err('NOT_FOUND')\r\n * // result.ok === false\r\n * // result.error === 'NOT_FOUND'\r\n * ```\r\n */\r\nexport function err<E>(error: E): Err<E> {\r\n\treturn { ok: false, error }\r\n}\r\n\r\n/**\r\n * Check if a result is a success.\r\n *\r\n * @param result - The result to check\r\n * @returns True if the result is Ok, false otherwise\r\n *\r\n * @example\r\n * ```ts\r\n * const result: Result<number, string> = ok(42)\r\n * if (isOk(result)) {\r\n * console.log(result.value) // TypeScript knows result is Ok<number>\r\n * }\r\n * ```\r\n */\r\nexport function isOk<T, E>(result: Result<T, E>): result is Ok<T> {\r\n\treturn result.ok === true\r\n}\r\n\r\n/**\r\n * Check if a result is a failure.\r\n *\r\n * @param result - The result to check\r\n * @returns True if the result is Err, false otherwise\r\n *\r\n * @example\r\n * ```ts\r\n * const result: Result<number, string> = err('NOT_FOUND')\r\n * if (isErr(result)) {\r\n * console.log(result.error) // TypeScript knows result is Err<string>\r\n * }\r\n * ```\r\n */\r\nexport function isErr<T, E>(result: Result<T, E>): result is Err<E> {\r\n\treturn !result.ok\r\n}\r\n\r\n/**\r\n * Unwrap a result, returning the value or a default.\r\n *\r\n * @param result - The result to unwrap\r\n * @param defaultValue - Value to return if result is an error\r\n * @returns The success value or the default value\r\n *\r\n * @example\r\n * ```ts\r\n * const value = unwrap(ok(42), 0) // 42\r\n * const fallback = unwrap(err('oops'), 0) // 0\r\n * ```\r\n */\r\nexport function unwrap<T, E>(result: Result<T, E>, defaultValue: T): T {\r\n\treturn result.ok ? result.value : defaultValue\r\n}\r\n\r\n/**\r\n * Unwrap a result, throwing if it's an error.\r\n *\r\n * @param result - The result to unwrap\r\n * @returns The success value\r\n * @throws The error if result is Err\r\n *\r\n * @example\r\n * ```ts\r\n * const value = unwrapOrThrow(ok(42)) // 42\r\n * unwrapOrThrow(err(new Error('oops'))) // throws Error('oops')\r\n * ```\r\n */\r\nexport function unwrapOrThrow<T, E>(result: Result<T, E>): T {\r\n\tif (result.ok) {\r\n\t\treturn result.value\r\n\t}\r\n\tif (result.error instanceof Error) {\r\n\t\tthrow result.error\r\n\t}\r\n\tthrow new Error(String(result.error))\r\n}\r\n\r\n/**\r\n * Map a function over a success value.\r\n *\r\n * @param result - The result to map over\r\n * @param fn - Function to apply to the success value\r\n * @returns A new result with the mapped value, or the original error\r\n *\r\n * @example\r\n * ```ts\r\n * const doubled = map(ok(5), x => x * 2) // ok(10)\r\n * const failed = map(err('oops'), x => x * 2) // err('oops')\r\n * ```\r\n */\r\nexport function map<T, U, E>(\r\n\tresult: Result<T, E>,\r\n\tfn: (value: T) => U,\r\n): Result<U, E> {\r\n\treturn result.ok ? ok(fn(result.value)) : result\r\n}\r\n\r\n/**\r\n * Map a function over an error value.\r\n *\r\n * @param result - The result to map over\r\n * @param fn - Function to apply to the error value\r\n * @returns A new result with the mapped error, or the original value\r\n *\r\n * @example\r\n * ```ts\r\n * const wrapped = mapErr(err('oops'), e => new Error(e)) // err(Error('oops'))\r\n * const unchanged = mapErr(ok(42), e => new Error(e)) // ok(42)\r\n * ```\r\n */\r\nexport function mapErr<T, E, F>(\r\n\tresult: Result<T, E>,\r\n\tfn: (error: E) => F,\r\n): Result<T, F> {\r\n\treturn result.ok ? result : err(fn(result.error))\r\n}\r\n\r\n/**\r\n * Chain results (flatMap). Apply a function that returns a Result to a success value.\r\n *\r\n * @param result - The result to chain\r\n * @param fn - Function returning a new Result\r\n * @returns The result of applying fn, or the original error\r\n *\r\n * @example\r\n * ```ts\r\n * const parsed = chain(ok('42'), s => {\r\n * const n = parseInt(s, 10)\r\n * return isNaN(n) ? err('PARSE_ERROR') : ok(n)\r\n * })\r\n * // parsed = ok(42)\r\n * ```\r\n */\r\nexport function chain<T, U, E>(\r\n\tresult: Result<T, E>,\r\n\tfn: (value: T) => Result<U, E>,\r\n): Result<U, E> {\r\n\treturn result.ok ? fn(result.value) : result\r\n}\r\n\r\n// ============================================================================\r\n// Content Hashing Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Compute a SHA-256 content hash for text.\r\n *\r\n * @param text - The text to hash\r\n * @returns A hex string content hash\r\n *\r\n * @example\r\n * ```ts\r\n * const hash = await computeContentHash('Hello, world!')\r\n * // hash = 'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e'\r\n * ```\r\n */\r\nexport async function computeContentHash(text: string): Promise<ContentHash> {\r\n\tconst encoder = new TextEncoder()\r\n\tconst data = encoder.encode(text)\r\n\tconst hashBuffer = await crypto.subtle.digest('SHA-256', data)\r\n\tconst hashArray = Array.from(new Uint8Array(hashBuffer))\r\n\treturn hashArray.map(b => b.toString(16).padStart(2, '0')).join('')\r\n}\r\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Shared constants for the core library.\r\n */\r\n\r\n// ============================================================================\r\n// Bridge Constants\r\n// ============================================================================\r\n\r\n/** Default timeout for bridge operations in milliseconds */\r\nexport const BRIDGE_DEFAULT_TIMEOUT = 30000\r\n\r\n/** Default retrieval limit for retrieval tool */\r\nexport const RETRIEVAL_DEFAULT_LIMIT = 10\r\n\r\n/** Maximum retrieval limit for retrieval tool */\r\nexport const RETRIEVAL_MAX_LIMIT = 100\r\n\r\n/** Default form dirty guard message */\r\nexport const FORM_DIRTY_DEFAULT_MESSAGE = 'You have unsaved changes. Are you sure you want to leave?'\r\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Tool call bridge that connects inference tool calls to contextprotocol tool registry.\r\n */\r\n\r\nimport type {\r\n\tToolCall,\r\n\tToolResult,\r\n\tToolCallBridgeOptions,\r\n\tToolCallBridgeInterface,\r\n} from '../types.js'\r\nimport { BRIDGE_DEFAULT_TIMEOUT } from '../constants.js'\r\n\r\n/**\r\n * Create a tool call bridge.\r\n *\r\n * @param options - Bridge configuration options\r\n * @returns A tool call bridge instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createToolRegistry } from '@mikesaintsg/contextprotocol'\r\n * import { createToolCallBridge } from '@mikesaintsg/core'\r\n *\r\n * const registry = createToolRegistry()\r\n * registry.register(weatherTool)\r\n *\r\n * const bridge = createToolCallBridge({\r\n * registry,\r\n * timeout: 30000,\r\n * onError: (error, toolCall) => console.error(`Tool ${toolCall.name} failed:`, error),\r\n * })\r\n *\r\n * // Execute tool calls from LLM response\r\n * const results = await bridge.executeAll(response.toolCalls)\r\n * ```\r\n */\r\nexport function createToolCallBridge(\r\n\toptions: ToolCallBridgeOptions,\r\n): ToolCallBridgeInterface {\r\n\tconst {\r\n\t\tregistry,\r\n\t\ttimeout = BRIDGE_DEFAULT_TIMEOUT,\r\n\t\tonError,\r\n\t\tonBeforeExecute,\r\n\t\tonAfterExecute,\r\n\t} = options\r\n\r\n\t/**\r\n\t * Execute a single tool call with timeout.\r\n\t */\r\n\tasync function executeWithTimeout(\r\n\t\ttoolCall: ToolCall,\r\n\t): Promise<ToolResult> {\r\n\t\t// Check if tool exists\r\n\t\tif (!registry.has(toolCall.name)) {\r\n\t\t\tconst result: ToolResult = {\r\n\t\t\t\tcallId: toolCall.id,\r\n\t\t\t\tname: toolCall.name,\r\n\t\t\t\tsuccess: false,\r\n\t\t\t\terror: `Tool not found: ${toolCall.name}`,\r\n\t\t\t}\r\n\t\t\treturn result\r\n\t\t}\r\n\r\n\t\t// Call lifecycle hook\r\n\t\tonBeforeExecute?.(toolCall)\r\n\r\n\t\ttry {\r\n\t\t\t// Create timeout promise\r\n\t\t\tconst timeoutPromise = new Promise<never>((_, reject) => {\r\n\t\t\t\tsetTimeout(() => {\r\n\t\t\t\t\treject(new Error(`Tool execution timed out after ${timeout}ms`))\r\n\t\t\t\t}, timeout)\r\n\t\t\t})\r\n\r\n\t\t\t// Execute tool with timeout\r\n\t\t\tconst value = await Promise.race([\r\n\t\t\t\tregistry.execute(toolCall.name, toolCall.arguments),\r\n\t\t\t\ttimeoutPromise,\r\n\t\t\t])\r\n\r\n\t\t\t// Call lifecycle hook\r\n\t\t\tonAfterExecute?.(toolCall, value)\r\n\r\n\t\t\treturn {\r\n\t\t\t\tcallId: toolCall.id,\r\n\t\t\t\tname: toolCall.name,\r\n\t\t\t\tsuccess: true,\r\n\t\t\t\tvalue,\r\n\t\t\t}\r\n\t\t} catch (error) {\r\n\t\t\t// Call error hook\r\n\t\t\tonError?.(error, toolCall)\r\n\r\n\t\t\tconst errorMessage = error instanceof Error\r\n\t\t\t\t? error.message\r\n\t\t\t\t: String(error)\r\n\r\n\t\t\treturn {\r\n\t\t\t\tcallId: toolCall.id,\r\n\t\t\t\tname: toolCall.name,\r\n\t\t\t\tsuccess: false,\r\n\t\t\t\terror: errorMessage,\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn {\r\n\t\tasync execute(toolCall: ToolCall): Promise<ToolResult> {\r\n\t\t\treturn executeWithTimeout(toolCall)\r\n\t\t},\r\n\r\n\t\tasync executeAll(toolCalls: readonly ToolCall[]): Promise<readonly ToolResult[]> {\r\n\t\t\t// Execute all tool calls in parallel\r\n\t\t\tconst results = await Promise.all(\r\n\t\t\t\ttoolCalls.map(toolCall => executeWithTimeout(toolCall)),\r\n\t\t\t)\r\n\t\t\treturn results\r\n\t\t},\r\n\r\n\t\thasTool(name: string): boolean {\r\n\t\t\treturn registry.has(name)\r\n\t\t},\r\n\t}\r\n}\r\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Retrieval tool factory that connects vectorstore to contextprotocol.\r\n */\r\n\r\nimport type {\r\n\tRetrievalToolOptions,\r\n\tRetrievalToolCreated,\r\n\tToolSchema,\r\n\tJSONSchema7,\r\n\tScoredResult,\r\n} from '../types.js'\r\nimport {\r\n\tRETRIEVAL_DEFAULT_LIMIT,\r\n\tRETRIEVAL_MAX_LIMIT,\r\n} from '../constants.js'\r\n\r\n/**\r\n * Create a retrieval tool for use with contextprotocol tool registry.\r\n *\r\n * @param options - Retrieval tool configuration options\r\n * @returns A tool schema and handler for registration\r\n *\r\n * @example\r\n * ```ts\r\n * import { createVectorStore } from '@mikesaintsg/vectorstore'\r\n * import { createToolRegistry } from '@mikesaintsg/contextprotocol'\r\n * import { createRetrievalTool } from '@mikesaintsg/core'\r\n *\r\n * const vectorStore = createVectorStore({ ... })\r\n * const registry = createToolRegistry()\r\n *\r\n * const { schema, handler } = createRetrievalTool({\r\n * vectorStore,\r\n * name: 'search_docs',\r\n * description: 'Search documentation for relevant information',\r\n * defaultLimit: 5,\r\n * scoreThreshold: 0.7,\r\n * })\r\n *\r\n * registry.register({ ...schema, execute: handler })\r\n * ```\r\n */\r\nexport function createRetrievalTool<TMetadata = unknown>(\r\n\toptions: RetrievalToolOptions<TMetadata>,\r\n): RetrievalToolCreated {\r\n\tconst {\r\n\t\tvectorStore,\r\n\t\tname,\r\n\t\tdescription,\r\n\t\tdefaultLimit = RETRIEVAL_DEFAULT_LIMIT,\r\n\t\tmaxLimit = RETRIEVAL_MAX_LIMIT,\r\n\t\tscoreThreshold,\r\n\t\tformatResult = defaultFormatResult,\r\n\t\textendParameters = {},\r\n\t\tbuildFilter,\r\n\t} = options\r\n\r\n\t// Build tool schema parameters\r\n\tconst parameters: JSONSchema7 = {\r\n\t\ttype: 'object',\r\n\t\tproperties: {\r\n\t\t\tquery: {\r\n\t\t\t\ttype: 'string',\r\n\t\t\t\tdescription: 'The search query to find relevant documents',\r\n\t\t\t},\r\n\t\t\tlimit: {\r\n\t\t\t\ttype: 'integer',\r\n\t\t\t\tdescription: `Maximum number of results to return (default: ${defaultLimit}, max: ${maxLimit})`,\r\n\t\t\t\tminimum: 1,\r\n\t\t\t\tmaximum: maxLimit,\r\n\t\t\t\tdefault: defaultLimit,\r\n\t\t\t},\r\n\t\t\t...extendParameters,\r\n\t\t},\r\n\t\trequired: ['query'],\r\n\t}\r\n\r\n\tconst schema: ToolSchema = {\r\n\t\tname,\r\n\t\tdescription,\r\n\t\tparameters,\r\n\t}\r\n\r\n\tasync function handler(\r\n\t\targs: Readonly<Record<string, unknown>>,\r\n\t): Promise<readonly unknown[]> {\r\n\t\tconst query = args.query\r\n\t\tif (typeof query !== 'string' || query.length === 0) {\r\n\t\t\treturn []\r\n\t\t}\r\n\r\n\t\tconst requestedLimit = args.limit\r\n\t\tlet limit = defaultLimit\r\n\t\tif (typeof requestedLimit === 'number' && Number.isInteger(requestedLimit)) {\r\n\t\t\tlimit = Math.min(Math.max(1, requestedLimit), maxLimit)\r\n\t\t}\r\n\r\n\t\t// Build filter if provided\r\n\t\tconst filter = buildFilter?.(args)\r\n\r\n\t\t// Search vectorstore - only include filter if defined\r\n\t\tconst searchOptions = filter !== undefined\r\n\t\t\t? { limit, filter }\r\n\t\t\t: { limit }\r\n\t\tconst results = await vectorStore.search(query, searchOptions)\r\n\r\n\t\t// Filter by score threshold\r\n\t\tlet filteredResults = results\r\n\t\tif (scoreThreshold !== undefined) {\r\n\t\t\tfilteredResults = results.filter(r => r.score >= scoreThreshold)\r\n\t\t}\r\n\r\n\t\t// Format results\r\n\t\treturn filteredResults.map(formatResult)\r\n\t}\r\n\r\n\treturn { schema, handler }\r\n}\r\n\r\n/**\r\n * Default result formatter - returns content and metadata.\r\n */\r\nfunction defaultFormatResult(result: ScoredResult): unknown {\r\n\treturn {\r\n\t\tcontent: result.content,\r\n\t\tscore: result.score,\r\n\t\tmetadata: result.metadata,\r\n\t}\r\n}\r\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Form dirty guard that prevents navigation when form has unsaved changes.\r\n */\r\n\r\nimport type {\r\n\tFormDirtyGuardOptions,\r\n\tNavigationGuard,\r\n} from '../types.js'\r\nimport { FORM_DIRTY_DEFAULT_MESSAGE } from '../constants.js'\r\n\r\n/**\r\n * Create a navigation guard that prevents leaving when form is dirty.\r\n *\r\n * @param options - Form dirty guard configuration options\r\n * @returns A navigation guard function\r\n *\r\n * @example\r\n * ```ts\r\n * import { createForm } from '@mikesaintsg/form'\r\n * import { createFormDirtyGuard } from '@mikesaintsg/core'\r\n *\r\n * const form = createForm({ ... })\r\n *\r\n * const guard = createFormDirtyGuard({\r\n * form,\r\n * confirmFn: (message) => window.confirm(message),\r\n * message: 'You have unsaved changes. Continue?',\r\n * excludePages: ['settings'],\r\n * })\r\n *\r\n * // Use with router\r\n * router.beforeNavigate(guard)\r\n * ```\r\n */\r\nexport function createFormDirtyGuard<TFormData = unknown, TPage extends string = string>(\r\n\toptions: FormDirtyGuardOptions<TFormData, TPage>,\r\n): NavigationGuard<TPage> {\r\n\tconst {\r\n\t\tform,\r\n\t\tconfirmFn,\r\n\t\tmessage = FORM_DIRTY_DEFAULT_MESSAGE,\r\n\t\texcludePages = [],\r\n\t\tonlyFromPages,\r\n\t} = options\r\n\r\n\treturn async function guard(to: TPage, from: TPage): Promise<boolean> {\r\n\t\t// Check if we should skip guard for this navigation\r\n\t\tif (shouldSkipGuard(to, from, excludePages, onlyFromPages)) {\r\n\t\t\treturn true\r\n\t\t}\r\n\r\n\t\t// If form is not dirty, allow navigation\r\n\t\tif (!form.isDirty()) {\r\n\t\t\treturn true\r\n\t\t}\r\n\r\n\t\t// Form is dirty, ask for confirmation\r\n\t\tconst confirmed = await Promise.resolve(confirmFn(message))\r\n\t\treturn confirmed\r\n\t}\r\n}\r\n\r\n/**\r\n * Determine if guard should be skipped for this navigation.\r\n */\r\nfunction shouldSkipGuard<TPage extends string>(\r\n\tto: TPage,\r\n\tfrom: TPage,\r\n\texcludePages: readonly TPage[],\r\n\tonlyFromPages: readonly TPage[] | undefined,\r\n): boolean {\r\n\t// Skip if navigating to excluded page\r\n\tif (excludePages.includes(to)) {\r\n\t\treturn true\r\n\t}\r\n\r\n\t// Skip if from page is not in onlyFromPages (if specified)\r\n\tif (onlyFromPages !== undefined && !onlyFromPages.includes(from)) {\r\n\t\treturn true\r\n\t}\r\n\r\n\treturn false\r\n}\r\n","/**\r\n * @mikesaintsg/core\r\n *\r\n * Session persistence bridge that connects inference sessions to IndexedDB storage.\r\n */\r\n\r\nimport type {\r\n\tSessionPersistenceOptions,\r\n\tSessionPersistenceInterface,\r\n\tSerializableSession,\r\n\tSerializedSession,\r\n} from '../types.js'\r\n\r\n/**\r\n * Create a session persistence adapter for storing inference sessions.\r\n *\r\n * @param options - Session persistence configuration options\r\n * @returns A session persistence instance\r\n *\r\n * @example\r\n * ```ts\r\n * import { createDatabase } from '@mikesaintsg/indexeddb'\r\n * import { createSessionPersistence } from '@mikesaintsg/core'\r\n *\r\n * const db = await createDatabase({ name: 'sessions' })\r\n * const persistence = createSessionPersistence({\r\n * database: db,\r\n * storeName: 'chat_sessions',\r\n * autoprune: 7 * 24 * 60 * 60 * 1000, // 7 days\r\n * })\r\n *\r\n * // Save session\r\n * await persistence.save('session-1', session)\r\n *\r\n * // Load session\r\n * const savedSession = await persistence.load('session-1')\r\n * ```\r\n */\r\nexport function createSessionPersistence(\r\n\toptions: SessionPersistenceOptions,\r\n): SessionPersistenceInterface {\r\n\tconst {\r\n\t\tdatabase,\r\n\t\tstoreName,\r\n\t\tautoprune,\r\n\t\tonSaveError,\r\n\t} = options\r\n\r\n\tconst store = database.store<SerializedSession>(storeName)\r\n\r\n\t// Auto-prune on creation if configured\r\n\tif (autoprune !== undefined && autoprune > 0) {\r\n\t\tvoid pruneOldSessions(autoprune)\r\n\t}\r\n\r\n\t/**\r\n\t * Prune sessions older than maxAgeMs.\r\n\t */\r\n\tasync function pruneOldSessions(maxAgeMs: number): Promise<number> {\r\n\t\tconst now = Date.now()\r\n\t\tconst cutoff = now - maxAgeMs\r\n\r\n\t\tconst allSessions = await store.all()\r\n\t\tlet prunedCount = 0\r\n\r\n\t\tfor (const session of allSessions) {\r\n\t\t\tif (session.updatedAt < cutoff) {\r\n\t\t\t\tawait store.remove(session.id)\r\n\t\t\t\tprunedCount++\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn prunedCount\r\n\t}\r\n\r\n\treturn {\r\n\t\tasync save(id: string, session: SerializableSession): Promise<void> {\r\n\t\t\ttry {\r\n\t\t\t\tconst serialized: SerializedSession = {\r\n\t\t\t\t\tid,\r\n\t\t\t\t\tmessages: [...session.getMessages()],\r\n\t\t\t\t\tmetadata: session.getMetadata(),\r\n\t\t\t\t\tupdatedAt: Date.now(),\r\n\t\t\t\t}\r\n\r\n\t\t\t\tawait store.set(serialized, id)\r\n\t\t\t} catch (error) {\r\n\t\t\t\tonSaveError?.(error, id)\r\n\t\t\t\tthrow error\r\n\t\t\t}\r\n\t\t},\r\n\r\n\t\tasync load(id: string): Promise<SerializedSession | undefined> {\r\n\t\t\treturn store.get(id)\r\n\t\t},\r\n\r\n\t\tasync delete(id: string): Promise<void> {\r\n\t\t\tawait store.remove(id)\r\n\t\t},\r\n\r\n\t\tasync list(): Promise<readonly string[]> {\r\n\t\t\tconst allSessions = await store.all()\r\n\t\t\treturn allSessions.map(s => s.id)\r\n\t\t},\r\n\r\n\t\tasync prune(maxAgeMs: number): Promise<number> {\r\n\t\t\treturn pruneOldSessions(maxAgeMs)\r\n\t\t},\r\n\t}\r\n}\r\n"],"names":["EcosystemError","message","cause","isEcosystemError","error","CoreError","code","isCoreError","ok","value","err","isOk","result","isErr","unwrap","defaultValue","unwrapOrThrow","map","fn","mapErr","chain","computeContentHash","text","data","hashBuffer","b","BRIDGE_DEFAULT_TIMEOUT","RETRIEVAL_DEFAULT_LIMIT","RETRIEVAL_MAX_LIMIT","FORM_DIRTY_DEFAULT_MESSAGE","createToolCallBridge","options","registry","timeout","onError","onBeforeExecute","onAfterExecute","executeWithTimeout","toolCall","timeoutPromise","_","reject","errorMessage","toolCalls","name","createRetrievalTool","vectorStore","description","defaultLimit","maxLimit","scoreThreshold","formatResult","defaultFormatResult","extendParameters","buildFilter","parameters","schema","handler","args","query","requestedLimit","limit","filter","searchOptions","results","filteredResults","r","createFormDirtyGuard","form","confirmFn","excludePages","onlyFromPages","to","from","shouldSkipGuard","createSessionPersistence","database","storeName","autoprune","onSaveError","store","pruneOldSessions","maxAgeMs","cutoff","allSessions","prunedCount","session","id","serialized","s"],"mappings":"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"}
|