llmist 1.2.0 → 1.3.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/gadgets/validation.ts","../src/testing/gadget-testing.ts","../src/testing/mock-manager.ts","../src/testing/mock-stream.ts","../src/testing/mock-adapter.ts","../src/testing/mock-builder.ts","../src/testing/mock-client.ts","../src/testing/mock-gadget.ts","../src/testing/stream-helpers.ts","../src/testing/conversation-fixtures.ts","../src/testing/mock-conversation.ts","../src/testing/cli-helpers.ts"],"sourcesContent":["/**\n * Validation utilities for gadget parameters.\n *\n * Provides standalone validation with Zod schema support, including\n * default application and formatted error output.\n *\n * @module gadgets/validation\n */\n\nimport type { ZodTypeAny } from \"zod\";\nimport type { BaseGadget } from \"./gadget.js\";\n\n/**\n * Individual validation issue with path and message.\n */\nexport interface ValidationIssue {\n /** Dot-separated path to the invalid field (e.g., \"user.email\") */\n path: string;\n /** Human-readable error message */\n message: string;\n}\n\n/**\n * Result of parameter validation.\n * Discriminated union based on `success` field.\n */\nexport type ValidationResult<T = Record<string, unknown>> =\n | {\n success: true;\n /** Validated and transformed data with defaults applied */\n data: T;\n }\n | {\n success: false;\n /** Formatted error message */\n error: string;\n /** Individual validation issues */\n issues: ValidationIssue[];\n };\n\n/**\n * Validate parameters against a Zod schema and apply defaults/transformations.\n *\n * This replicates the validation behavior from GadgetExecutor, making it\n * available for direct use in tests and other contexts.\n *\n * @param schema - Zod schema to validate against\n * @param params - Raw parameters to validate\n * @returns ValidationResult with either validated data or error details\n *\n * @example\n * ```typescript\n * import { validateAndApplyDefaults } from 'llmist';\n * import { z } from 'zod';\n *\n * const schema = z.object({\n * delay: z.number().default(100),\n * retries: z.number().int().min(0).default(3),\n * });\n *\n * const result = validateAndApplyDefaults(schema, { delay: 50 });\n * if (result.success) {\n * console.log(result.data); // { delay: 50, retries: 3 }\n * }\n * ```\n */\nexport function validateAndApplyDefaults<T = Record<string, unknown>>(\n schema: ZodTypeAny,\n params: Record<string, unknown>,\n): ValidationResult<T> {\n const result = schema.safeParse(params);\n\n if (result.success) {\n return {\n success: true,\n data: result.data as T,\n };\n }\n\n const issues: ValidationIssue[] = result.error.issues.map((issue) => ({\n path: issue.path.join(\".\") || \"root\",\n message: issue.message,\n }));\n\n const formattedError = `Invalid parameters: ${issues.map((i) => `${i.path}: ${i.message}`).join(\"; \")}`;\n\n return {\n success: false,\n error: formattedError,\n issues,\n };\n}\n\n/**\n * Validate gadget parameters using the gadget's schema.\n *\n * Convenience wrapper that extracts the schema from a gadget instance.\n * If the gadget has no schema, validation always succeeds with the\n * original parameters.\n *\n * @param gadget - Gadget instance with optional parameterSchema\n * @param params - Raw parameters to validate\n * @returns ValidationResult with either validated data or error details\n *\n * @example\n * ```typescript\n * import { validateGadgetParams, createGadget } from 'llmist';\n * import { z } from 'zod';\n *\n * const calculator = createGadget({\n * description: 'Add numbers',\n * schema: z.object({\n * a: z.number(),\n * b: z.number().default(0),\n * }),\n * execute: ({ a, b }) => String(a + b),\n * });\n *\n * const result = validateGadgetParams(calculator, { a: 5 });\n * if (result.success) {\n * console.log(result.data); // { a: 5, b: 0 }\n * }\n * ```\n */\nexport function validateGadgetParams(\n gadget: BaseGadget,\n params: Record<string, unknown>,\n): ValidationResult {\n if (!gadget.parameterSchema) {\n return {\n success: true,\n data: params,\n };\n }\n\n return validateAndApplyDefaults(gadget.parameterSchema, params);\n}\n","/**\n * Testing utilities for gadgets.\n *\n * Provides helpers for testing gadgets with schema validation without\n * requiring full executor setup.\n *\n * @module testing/gadget-testing\n */\n\nimport type { BaseGadget } from \"../gadgets/gadget.js\";\nimport { type ValidationResult, validateGadgetParams } from \"../gadgets/validation.js\";\n\n/**\n * Result of testing a gadget.\n */\nexport interface TestGadgetResult {\n /** Result string if execution succeeded */\n result?: string;\n /** Error message if validation or execution failed */\n error?: string;\n /** Parameters after validation and default application */\n validatedParams?: Record<string, unknown>;\n}\n\n/**\n * Options for testGadget.\n */\nexport interface TestGadgetOptions {\n /**\n * If true, skip schema validation.\n * Useful for testing gadget behavior with invalid parameters.\n */\n skipValidation?: boolean;\n}\n\n/**\n * Test a gadget with schema validation and default application.\n *\n * This helper replicates the validation behavior from GadgetExecutor.execute(),\n * making it easy to test gadgets in isolation without setting up a full\n * registry and executor.\n *\n * @param gadget - Gadget instance to test\n * @param params - Raw parameters (before validation)\n * @param options - Test options\n * @returns Promise resolving to test result\n *\n * @example\n * ```typescript\n * import { testGadget } from 'llmist/testing';\n * import { createGadget } from 'llmist';\n * import { z } from 'zod';\n *\n * const calculator = createGadget({\n * description: 'Add numbers',\n * schema: z.object({\n * a: z.number(),\n * b: z.number().default(0),\n * }),\n * execute: ({ a, b }) => String(a + b),\n * });\n *\n * // Test with defaults applied\n * const result = await testGadget(calculator, { a: 5 });\n * expect(result.result).toBe('5');\n * expect(result.validatedParams).toEqual({ a: 5, b: 0 });\n *\n * // Test validation errors\n * const invalid = await testGadget(calculator, { a: 'not a number' });\n * expect(invalid.error).toContain('Invalid parameters');\n *\n * // Test with validation skipped\n * const skipped = await testGadget(calculator, { a: 5 }, { skipValidation: true });\n * expect(skipped.validatedParams).toEqual({ a: 5 }); // No defaults applied\n * ```\n */\nexport async function testGadget(\n gadget: BaseGadget,\n params: Record<string, unknown>,\n options?: TestGadgetOptions,\n): Promise<TestGadgetResult> {\n let validatedParams = params;\n\n // Apply validation if schema exists and not skipped\n if (!options?.skipValidation) {\n const validationResult: ValidationResult = validateGadgetParams(gadget, params);\n\n if (!validationResult.success) {\n return {\n error: validationResult.error,\n validatedParams: params,\n };\n }\n\n validatedParams = validationResult.data;\n }\n\n // Execute the gadget\n try {\n const result = await Promise.resolve(gadget.execute(validatedParams));\n return {\n result,\n validatedParams,\n };\n } catch (error) {\n return {\n error: error instanceof Error ? error.message : String(error),\n validatedParams,\n };\n }\n}\n\n/**\n * Test multiple parameter sets against a gadget.\n *\n * Convenience helper for running the same gadget with different inputs.\n *\n * @param gadget - Gadget instance to test\n * @param paramSets - Array of parameter sets to test\n * @param options - Test options applied to all tests\n * @returns Promise resolving to array of test results\n *\n * @example\n * ```typescript\n * const results = await testGadgetBatch(calculator, [\n * { a: 1, b: 2 },\n * { a: 5 },\n * { a: 'invalid' },\n * ]);\n *\n * expect(results[0].result).toBe('3');\n * expect(results[1].result).toBe('5');\n * expect(results[2].error).toBeDefined();\n * ```\n */\nexport async function testGadgetBatch(\n gadget: BaseGadget,\n paramSets: Record<string, unknown>[],\n options?: TestGadgetOptions,\n): Promise<TestGadgetResult[]> {\n return Promise.all(paramSets.map((params) => testGadget(gadget, params, options)));\n}\n","import type { ILogObj, Logger } from \"tslog\";\nimport { createLogger } from \"../logging/logger.js\";\nimport type {\n MockMatcherContext,\n MockOptions,\n MockRegistration,\n MockResponse,\n MockStats,\n} from \"./mock-types.js\";\n\n/**\n * Global singleton instance for managing LLM mocks.\n * This allows mocks to be registered once and used across the application.\n */\nexport class MockManager {\n private static instance: MockManager | null = null;\n private mocks: Map<string, MockRegistration> = new Map();\n private stats: Map<string, MockStats> = new Map();\n private options: Required<MockOptions>;\n private logger: Logger<ILogObj>;\n private nextId = 1;\n\n private constructor(options: MockOptions = {}) {\n this.options = {\n strictMode: options.strictMode ?? false,\n debug: options.debug ?? false,\n recordStats: options.recordStats ?? true,\n };\n this.logger = createLogger({ name: \"MockManager\", minLevel: this.options.debug ? 2 : 3 });\n }\n\n /**\n * Get the global MockManager instance.\n * Creates one if it doesn't exist.\n */\n static getInstance(options?: MockOptions): MockManager {\n if (!MockManager.instance) {\n MockManager.instance = new MockManager(options);\n } else if (options) {\n // Warn if options are provided after initialization\n console.warn(\n \"MockManager.getInstance() called with options, but instance already exists. \" +\n \"Options are ignored. Use setOptions() to update options or reset() to reinitialize.\",\n );\n }\n return MockManager.instance;\n }\n\n /**\n * Reset the global instance (useful for testing).\n */\n static reset(): void {\n MockManager.instance = null;\n }\n\n /**\n * Register a new mock.\n *\n * @param registration - The mock registration configuration\n * @returns The ID of the registered mock\n *\n * @example\n * const manager = MockManager.getInstance();\n * const mockId = manager.register({\n * label: 'GPT-4 mock',\n * matcher: (ctx) => ctx.modelName.includes('gpt-4'),\n * response: { text: 'Mocked response' }\n * });\n */\n register(registration: Omit<MockRegistration, \"id\"> & { id?: string }): string {\n const id = registration.id ?? `mock-${this.nextId++}`;\n const mock: MockRegistration = {\n id,\n matcher: registration.matcher,\n response: registration.response,\n label: registration.label,\n once: registration.once,\n };\n\n this.mocks.set(id, mock);\n\n if (this.options.recordStats) {\n this.stats.set(id, { matchCount: 0 });\n }\n\n this.logger.debug(\n `Registered mock: ${id}${mock.label ? ` (${mock.label})` : \"\"}${mock.once ? \" [once]\" : \"\"}`,\n );\n\n return id;\n }\n\n /**\n * Unregister a mock by ID.\n */\n unregister(id: string): boolean {\n const deleted = this.mocks.delete(id);\n if (deleted) {\n this.stats.delete(id);\n this.logger.debug(`Unregistered mock: ${id}`);\n }\n return deleted;\n }\n\n /**\n * Clear all registered mocks.\n */\n clear(): void {\n this.mocks.clear();\n this.stats.clear();\n this.logger.debug(\"Cleared all mocks\");\n }\n\n /**\n * Find and return a matching mock for the given context.\n * Returns the mock response if found, null otherwise.\n */\n async findMatch(context: MockMatcherContext): Promise<MockResponse | null> {\n this.logger.debug(\n `Finding match for: ${context.provider}:${context.modelName} (${this.mocks.size} mocks registered)`,\n );\n\n for (const [id, mock] of this.mocks.entries()) {\n let matches = false;\n\n try {\n matches = await Promise.resolve(mock.matcher(context));\n } catch (error) {\n // Matcher errors are caught - a matcher that throws simply doesn't match\n this.logger.warn(`Error in matcher ${id}:`, error);\n // In strict mode, re-throw matcher errors to help catch bugs\n if (this.options.strictMode) {\n throw new Error(`Matcher error in mock ${id}: ${error}`);\n }\n continue; // Skip to next mock\n }\n\n if (matches) {\n this.logger.debug(`Mock matched: ${id}${mock.label ? ` (${mock.label})` : \"\"}`);\n\n // Record stats\n if (this.options.recordStats) {\n const stats = this.stats.get(id);\n if (stats) {\n stats.matchCount++;\n stats.lastUsed = new Date();\n }\n }\n\n // Remove if once\n if (mock.once) {\n this.mocks.delete(id);\n this.stats.delete(id);\n this.logger.debug(`Removed one-time mock: ${id}`);\n }\n\n // Resolve response (could be a function)\n // Response errors are NOT caught - they should propagate to the caller\n const response =\n typeof mock.response === \"function\"\n ? await Promise.resolve(mock.response(context))\n : mock.response;\n\n return response;\n }\n }\n\n // No match found\n this.logger.debug(\"No mock matched\");\n\n if (this.options.strictMode) {\n throw new Error(\n `No mock registered for ${context.provider}:${context.modelName}. ` +\n `Register a mock using MockManager.getInstance().register() or disable strictMode.`,\n );\n }\n\n // Return empty response in non-strict mode\n return {\n text: \"\",\n usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },\n finishReason: \"stop\",\n };\n }\n\n /**\n * Get statistics for a specific mock.\n */\n getStats(id: string): MockStats | undefined {\n return this.stats.get(id);\n }\n\n /**\n * Get all registered mock IDs.\n */\n getMockIds(): string[] {\n return Array.from(this.mocks.keys());\n }\n\n /**\n * Get the number of registered mocks.\n */\n getCount(): number {\n return this.mocks.size;\n }\n\n /**\n * Update the mock manager options.\n */\n setOptions(options: Partial<MockOptions>): void {\n this.options = { ...this.options, ...options };\n this.logger = createLogger({ name: \"MockManager\", minLevel: this.options.debug ? 2 : 3 });\n }\n}\n\n/**\n * Helper function to get the global mock manager instance.\n */\nexport function getMockManager(options?: MockOptions): MockManager {\n return MockManager.getInstance(options);\n}\n","import { GADGET_ARG_PREFIX, GADGET_END_PREFIX, GADGET_START_PREFIX } from \"../core/constants.js\";\nimport type { LLMStream, LLMStreamChunk } from \"../core/options.js\";\nimport type { MockResponse } from \"./mock-types.js\";\n\n/**\n * Utility to sleep for a given duration.\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Generate a unique invocation ID for gadget calls.\n */\nfunction generateInvocationId(): string {\n return `inv-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * Split text into chunks for streaming simulation.\n * Tries to split on word boundaries for more realistic streaming.\n */\nfunction splitIntoChunks(text: string, minChunkSize = 5, maxChunkSize = 30): string[] {\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n // Determine chunk size\n const chunkSize = Math.min(\n Math.floor(Math.random() * (maxChunkSize - minChunkSize + 1)) + minChunkSize,\n remaining.length,\n );\n\n // Try to split on word boundary\n let chunk: string;\n if (chunkSize < remaining.length) {\n const substr = remaining.substring(0, chunkSize);\n const lastSpace = substr.lastIndexOf(\" \");\n if (lastSpace > minChunkSize / 2) {\n chunk = substr.substring(0, lastSpace + 1);\n } else {\n chunk = substr;\n }\n } else {\n chunk = remaining;\n }\n\n chunks.push(chunk);\n remaining = remaining.substring(chunk.length);\n }\n\n return chunks;\n}\n\n/**\n * Serialize an object to block format parameters with !!!ARG: markers.\n *\n * Example:\n * { operation: \"add\", a: 5, config: { timeout: 30 } }\n * becomes:\n * !!!ARG:operation\n * add\n * !!!ARG:a\n * 5\n * !!!ARG:config/timeout\n * 30\n */\nfunction serializeToBlockFormat(obj: Record<string, unknown>, prefix = \"\"): string {\n let result = \"\";\n\n for (const [key, value] of Object.entries(obj)) {\n const pointer = prefix ? `${prefix}/${key}` : key;\n\n if (value === null || value === undefined) {\n continue;\n }\n\n if (Array.isArray(value)) {\n // Serialize array elements with numeric indices\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n const itemPointer = `${pointer}/${i}`;\n\n if (typeof item === \"object\" && item !== null && !Array.isArray(item)) {\n // Nested object in array\n result += serializeToBlockFormat(item as Record<string, unknown>, itemPointer);\n } else if (Array.isArray(item)) {\n // Nested array - serialize recursively\n for (let j = 0; j < item.length; j++) {\n result += `${GADGET_ARG_PREFIX}${itemPointer}/${j}\\n${String(item[j])}\\n`;\n }\n } else {\n result += `${GADGET_ARG_PREFIX}${itemPointer}\\n${String(item)}\\n`;\n }\n }\n } else if (typeof value === \"object\") {\n // Nested object - recurse\n result += serializeToBlockFormat(value as Record<string, unknown>, pointer);\n } else {\n // Primitive value\n result += `${GADGET_ARG_PREFIX}${pointer}\\n${String(value)}\\n`;\n }\n }\n\n return result;\n}\n\n/**\n * Convert gadget calls in MockResponse to their text representation.\n * Formats them using block format: !!!GADGET_START:name\\n!!!ARG:...\\n!!!GADGET_END\n */\nfunction formatGadgetCalls(gadgetCalls: NonNullable<MockResponse[\"gadgetCalls\"]>): {\n text: string;\n calls: Array<{ name: string; invocationId: string }>;\n} {\n let text = \"\";\n const calls: Array<{ name: string; invocationId: string }> = [];\n\n for (const call of gadgetCalls) {\n const invocationId = call.invocationId ?? generateInvocationId();\n calls.push({ name: call.gadgetName, invocationId });\n\n // Format parameters using block format with !!!ARG: markers\n const blockParams = serializeToBlockFormat(call.parameters);\n\n // Format using the gadget marker format\n text += `\\n${GADGET_START_PREFIX}${call.gadgetName}\\n${blockParams}${GADGET_END_PREFIX}`;\n }\n\n return { text, calls };\n}\n\n/**\n * Create a mock LLM stream from a mock response.\n * This simulates the streaming behavior of real LLM providers.\n *\n * @param response - The mock response configuration\n * @returns An async iterable that yields LLMStreamChunks\n */\nexport async function* createMockStream(response: MockResponse): LLMStream {\n // Initial delay (simulate network latency)\n if (response.delayMs) {\n await sleep(response.delayMs);\n }\n\n const streamDelay = response.streamDelayMs ?? 0;\n let fullText = response.text ?? \"\";\n\n // Add gadget calls to the text if provided\n if (response.gadgetCalls && response.gadgetCalls.length > 0) {\n const { text: gadgetText } = formatGadgetCalls(response.gadgetCalls);\n fullText += gadgetText;\n }\n\n // Stream the text in chunks\n if (fullText.length > 0) {\n const chunks = streamDelay > 0 ? splitIntoChunks(fullText) : [fullText];\n\n for (let i = 0; i < chunks.length; i++) {\n const isLast = i === chunks.length - 1;\n\n const chunk: LLMStreamChunk = {\n text: chunks[i],\n };\n\n // Add finish reason and usage on the last chunk\n if (isLast) {\n if (response.finishReason !== undefined) {\n chunk.finishReason = response.finishReason;\n }\n if (response.usage) {\n chunk.usage = response.usage;\n }\n }\n\n yield chunk;\n\n // Delay between chunks\n if (streamDelay > 0 && !isLast) {\n await sleep(streamDelay);\n }\n }\n } else {\n // Empty response - still yield a final chunk with metadata\n yield {\n text: \"\",\n finishReason: response.finishReason ?? \"stop\",\n usage: response.usage ?? { inputTokens: 0, outputTokens: 0, totalTokens: 0 },\n };\n }\n}\n\n/**\n * Create a simple text-only mock stream.\n * Convenience helper for quickly creating mock responses.\n *\n * @param text - The text to stream\n * @param options - Optional streaming configuration\n *\n * @example\n * const stream = createTextMockStream('Hello, world!');\n * for await (const chunk of stream) {\n * console.log(chunk.text);\n * }\n */\nexport function createTextMockStream(\n text: string,\n options?: {\n delayMs?: number;\n streamDelayMs?: number;\n usage?: MockResponse[\"usage\"];\n },\n): LLMStream {\n return createMockStream({\n text,\n delayMs: options?.delayMs,\n streamDelayMs: options?.streamDelayMs,\n usage: options?.usage,\n finishReason: \"stop\",\n });\n}\n","import type { LLMMessage } from \"../core/messages.js\";\nimport type { LLMGenerationOptions, LLMStream, ModelDescriptor } from \"../core/options.js\";\nimport { ModelIdentifierParser } from \"../core/options.js\";\nimport type { ProviderAdapter } from \"../providers/provider.js\";\nimport { getMockManager, type MockManager } from \"./mock-manager.js\";\nimport { createMockStream } from \"./mock-stream.js\";\nimport type { MockMatcherContext, MockOptions } from \"./mock-types.js\";\n\n/**\n * Provider adapter that serves mock responses instead of making real LLM API calls.\n * This is useful for testing applications that use llmist without incurring API costs.\n *\n * The MockProviderAdapter has high priority (100) and is always checked before\n * real providers when both are registered. This enables selective mocking where\n * some models use mocks while others use real providers. If no matching mock is\n * found and strictMode is disabled, requests return an empty response.\n *\n * @example\n * ```typescript\n * import { LLMist, createMockAdapter, mockLLM } from 'llmist/testing';\n *\n * // Use with real providers for selective mocking\n * const client = new LLMist({\n * adapters: [createMockAdapter()],\n * autoDiscoverProviders: true // Also loads real OpenAI, Anthropic, etc.\n * });\n *\n * // Register mocks for specific models\n * mockLLM()\n * .forModel('gpt-5-nano')\n * .returns('Test response')\n * .register();\n *\n * // gpt-5-nano uses mock, other models use real providers\n * const stream = client.stream({\n * model: 'openai:gpt-5-nano',\n * messages: [{ role: 'user', content: 'test' }]\n * });\n * ```\n */\nexport class MockProviderAdapter implements ProviderAdapter {\n readonly providerId = \"mock\";\n readonly priority = 100; // High priority: check mocks before real providers\n private readonly mockManager: MockManager;\n\n constructor(options?: MockOptions) {\n this.mockManager = getMockManager(options);\n }\n\n supports(descriptor: ModelDescriptor): boolean {\n // Support any provider when using mock adapter\n // This allows tests to use \"openai:gpt-4\", \"anthropic:claude\", etc.\n return true;\n }\n\n stream(\n options: LLMGenerationOptions,\n descriptor: ModelDescriptor,\n // spec is unused for mocks\n // biome-ignore lint/correctness/noUnusedVariables: spec parameter required by interface\n spec?: unknown,\n ): LLMStream {\n // Create matcher context\n const context: MockMatcherContext = {\n model: options.model,\n provider: descriptor.provider,\n modelName: descriptor.name,\n options,\n messages: options.messages,\n };\n\n // Find matching mock (async operation)\n // We need to handle this in the stream generator\n return this.createMockStreamFromContext(context);\n }\n\n private async *createMockStreamFromContext(context: MockMatcherContext): LLMStream {\n try {\n // Find matching mock\n const mockResponse = await this.mockManager.findMatch(context);\n\n if (!mockResponse) {\n // This should not happen if MockManager is configured correctly\n // but handle it gracefully\n yield {\n text: \"\",\n finishReason: \"stop\",\n usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },\n };\n return;\n }\n\n // Stream the mock response\n yield* createMockStream(mockResponse);\n } catch (error) {\n // If an error occurs (e.g., strictMode with no match), we need to handle it\n throw error;\n }\n }\n}\n\n/**\n * Create a mock provider adapter instance.\n * This is a convenience factory function.\n *\n * @param options - Optional configuration for the mock system\n * @returns A configured MockProviderAdapter\n *\n * @example\n * ```typescript\n * const adapter = createMockAdapter({ strictMode: true, debug: true });\n * const client = new LLMist([adapter]);\n * ```\n */\nexport function createMockAdapter(options?: MockOptions): MockProviderAdapter {\n return new MockProviderAdapter(options);\n}\n","import type { LLMMessage } from \"../core/messages.js\";\nimport { getMockManager } from \"./mock-manager.js\";\nimport type {\n MockMatcher,\n MockMatcherContext,\n MockRegistration,\n MockResponse,\n} from \"./mock-types.js\";\n\n/**\n * Fluent builder for creating mock responses and registrations.\n * Provides a convenient API for common mocking scenarios.\n *\n * @example\n * ```typescript\n * import { mockLLM } from 'llmist';\n *\n * // Simple text mock\n * mockLLM()\n * .forModel('gpt-5')\n * .returns('Hello, world!')\n * .register();\n *\n * // Mock with gadget calls\n * mockLLM()\n * .forProvider('anthropic')\n * .whenMessageContains('calculate')\n * .returnsGadgetCalls([\n * { gadgetName: 'calculator', parameters: { operation: 'add', a: 1, b: 2 } }\n * ])\n * .register();\n *\n * // Complex conditional mock\n * mockLLM()\n * .when((ctx) => ctx.messages.length > 5)\n * .returns('This conversation is getting long!')\n * .once()\n * .register();\n * ```\n */\nexport class MockBuilder {\n private matchers: MockMatcher[] = [];\n private response:\n | MockResponse\n | ((context: MockMatcherContext) => MockResponse | Promise<MockResponse>) = {};\n private label?: string;\n private isOnce = false;\n private id?: string;\n\n /**\n * Match calls to a specific model (by name, supports partial matching).\n *\n * @example\n * mockLLM().forModel('gpt-5')\n * mockLLM().forModel('claude') // matches any Claude model\n */\n forModel(modelName: string): this {\n if (!modelName || modelName.trim() === \"\") {\n throw new Error(\"Model name cannot be empty\");\n }\n this.matchers.push((ctx) => ctx.modelName.includes(modelName));\n return this;\n }\n\n /**\n * Match calls to any model.\n * Useful when you want to mock responses regardless of the model used.\n *\n * @example\n * mockLLM().forAnyModel()\n */\n forAnyModel(): this {\n this.matchers.push(() => true);\n return this;\n }\n\n /**\n * Match calls to a specific provider.\n *\n * @example\n * mockLLM().forProvider('openai')\n * mockLLM().forProvider('anthropic')\n */\n forProvider(provider: string): this {\n if (!provider || provider.trim() === \"\") {\n throw new Error(\"Provider name cannot be empty\");\n }\n this.matchers.push((ctx) => ctx.provider === provider);\n return this;\n }\n\n /**\n * Match calls to any provider.\n * Useful when you want to mock responses regardless of the provider used.\n *\n * @example\n * mockLLM().forAnyProvider()\n */\n forAnyProvider(): this {\n this.matchers.push(() => true);\n return this;\n }\n\n /**\n * Match when any message contains the given text (case-insensitive).\n *\n * @example\n * mockLLM().whenMessageContains('hello')\n */\n whenMessageContains(text: string): this {\n this.matchers.push((ctx) =>\n ctx.messages.some((msg) => msg.content?.toLowerCase().includes(text.toLowerCase())),\n );\n return this;\n }\n\n /**\n * Match when the last message contains the given text (case-insensitive).\n *\n * @example\n * mockLLM().whenLastMessageContains('goodbye')\n */\n whenLastMessageContains(text: string): this {\n this.matchers.push((ctx) => {\n const lastMsg = ctx.messages[ctx.messages.length - 1];\n return lastMsg?.content?.toLowerCase().includes(text.toLowerCase()) ?? false;\n });\n return this;\n }\n\n /**\n * Match when any message matches the given regex.\n *\n * @example\n * mockLLM().whenMessageMatches(/calculate \\d+/)\n */\n whenMessageMatches(regex: RegExp): this {\n this.matchers.push((ctx) => ctx.messages.some((msg) => regex.test(msg.content ?? \"\")));\n return this;\n }\n\n /**\n * Match when a message with a specific role contains text.\n *\n * @example\n * mockLLM().whenRoleContains('system', 'You are a helpful assistant')\n */\n whenRoleContains(role: LLMMessage[\"role\"], text: string): this {\n this.matchers.push((ctx) =>\n ctx.messages.some(\n (msg) => msg.role === role && msg.content?.toLowerCase().includes(text.toLowerCase()),\n ),\n );\n return this;\n }\n\n /**\n * Match based on the number of messages in the conversation.\n *\n * @example\n * mockLLM().whenMessageCount((count) => count > 10)\n */\n whenMessageCount(predicate: (count: number) => boolean): this {\n this.matchers.push((ctx) => predicate(ctx.messages.length));\n return this;\n }\n\n /**\n * Add a custom matcher function.\n * This provides full control over matching logic.\n *\n * @example\n * mockLLM().when((ctx) => {\n * return ctx.options.temperature > 0.8;\n * })\n */\n when(matcher: MockMatcher): this {\n this.matchers.push(matcher);\n return this;\n }\n\n /**\n * Set the text response to return.\n * Can be a static string or a function that returns a string dynamically.\n *\n * @example\n * mockLLM().returns('Hello, world!')\n * mockLLM().returns(() => `Response at ${Date.now()}`)\n * mockLLM().returns((ctx) => `You said: ${ctx.messages[0]?.content}`)\n */\n returns(text: string | ((context: MockMatcherContext) => string | Promise<string>)): this {\n if (typeof text === \"function\") {\n // Convert function to full response generator\n // Use Promise.resolve().then() to properly handle both sync and async errors\n this.response = async (ctx) => {\n const resolvedText = await Promise.resolve().then(() => text(ctx));\n return { text: resolvedText };\n };\n } else {\n if (typeof this.response === \"function\") {\n throw new Error(\"Cannot use returns() after withResponse() with a function\");\n }\n this.response.text = text;\n }\n return this;\n }\n\n /**\n * Set gadget calls to include in the response.\n *\n * @example\n * mockLLM().returnsGadgetCalls([\n * { gadgetName: 'calculator', parameters: { op: 'add', a: 1, b: 2 } }\n * ])\n */\n returnsGadgetCalls(\n calls: Array<{\n gadgetName: string;\n parameters: Record<string, unknown>;\n invocationId?: string;\n }>,\n ): this {\n if (typeof this.response === \"function\") {\n throw new Error(\"Cannot use returnsGadgetCalls() after withResponse() with a function\");\n }\n this.response.gadgetCalls = calls;\n return this;\n }\n\n /**\n * Add a single gadget call to the response.\n *\n * @example\n * mockLLM()\n * .returnsGadgetCall('calculator', { op: 'add', a: 1, b: 2 })\n * .returnsGadgetCall('logger', { message: 'Done!' })\n */\n returnsGadgetCall(gadgetName: string, parameters: Record<string, unknown>): this {\n if (typeof this.response === \"function\") {\n throw new Error(\"Cannot use returnsGadgetCall() after withResponse() with a function\");\n }\n if (!this.response.gadgetCalls) {\n this.response.gadgetCalls = [];\n }\n this.response.gadgetCalls.push({ gadgetName, parameters });\n return this;\n }\n\n /**\n * Set the complete mock response object.\n * This allows full control over all response properties.\n * Can also be a function that generates the response dynamically based on context.\n *\n * @example\n * // Static response\n * mockLLM().withResponse({\n * text: 'Hello',\n * usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 },\n * finishReason: 'stop'\n * })\n *\n * @example\n * // Dynamic response\n * mockLLM().withResponse((ctx) => ({\n * text: `You said: ${ctx.messages[ctx.messages.length - 1]?.content}`,\n * usage: { inputTokens: 10, outputTokens: 5, totalTokens: 15 }\n * }))\n */\n withResponse(\n response:\n | MockResponse\n | ((context: MockMatcherContext) => MockResponse | Promise<MockResponse>),\n ): this {\n this.response = response;\n return this;\n }\n\n /**\n * Set simulated token usage.\n *\n * @example\n * mockLLM().withUsage({ inputTokens: 100, outputTokens: 50, totalTokens: 150 })\n */\n withUsage(usage: { inputTokens: number; outputTokens: number; totalTokens: number }): this {\n if (typeof this.response === \"function\") {\n throw new Error(\"Cannot use withUsage() after withResponse() with a function\");\n }\n if (usage.inputTokens < 0 || usage.outputTokens < 0 || usage.totalTokens < 0) {\n throw new Error(\"Token counts cannot be negative\");\n }\n if (usage.totalTokens !== usage.inputTokens + usage.outputTokens) {\n throw new Error(\"totalTokens must equal inputTokens + outputTokens\");\n }\n this.response.usage = usage;\n return this;\n }\n\n /**\n * Set the finish reason.\n *\n * @example\n * mockLLM().withFinishReason('stop')\n * mockLLM().withFinishReason('length')\n */\n withFinishReason(reason: string): this {\n if (typeof this.response === \"function\") {\n throw new Error(\"Cannot use withFinishReason() after withResponse() with a function\");\n }\n this.response.finishReason = reason;\n return this;\n }\n\n /**\n * Set initial delay before streaming starts (simulates network latency).\n *\n * @example\n * mockLLM().withDelay(100) // 100ms delay\n */\n withDelay(ms: number): this {\n if (typeof this.response === \"function\") {\n throw new Error(\"Cannot use withDelay() after withResponse() with a function\");\n }\n if (ms < 0) {\n throw new Error(\"Delay must be non-negative\");\n }\n this.response.delayMs = ms;\n return this;\n }\n\n /**\n * Set delay between stream chunks (simulates realistic streaming).\n *\n * @example\n * mockLLM().withStreamDelay(10) // 10ms between chunks\n */\n withStreamDelay(ms: number): this {\n if (typeof this.response === \"function\") {\n throw new Error(\"Cannot use withStreamDelay() after withResponse() with a function\");\n }\n if (ms < 0) {\n throw new Error(\"Stream delay must be non-negative\");\n }\n this.response.streamDelayMs = ms;\n return this;\n }\n\n /**\n * Set a label for this mock (useful for debugging).\n *\n * @example\n * mockLLM().withLabel('greeting mock')\n */\n withLabel(label: string): this {\n this.label = label;\n return this;\n }\n\n /**\n * Set a specific ID for this mock.\n *\n * @example\n * mockLLM().withId('my-custom-mock-id')\n */\n withId(id: string): this {\n this.id = id;\n return this;\n }\n\n /**\n * Mark this mock as one-time use (will be removed after first match).\n *\n * @example\n * mockLLM().once()\n */\n once(): this {\n this.isOnce = true;\n return this;\n }\n\n /**\n * Build the mock registration without registering it.\n * Useful if you want to register it manually later.\n *\n * @returns The built MockRegistration object (without id if not specified)\n */\n build(): Omit<MockRegistration, \"id\"> & { id?: string } {\n // Guard against empty matchers\n if (this.matchers.length === 0) {\n throw new Error(\n \"Mock must have at least one matcher. Use .when(), .forModel(), .forProvider(), etc.\",\n );\n }\n\n // Combine all matchers with AND logic\n const combinedMatcher: MockMatcher = async (ctx) => {\n for (const matcher of this.matchers) {\n const matches = await Promise.resolve(matcher(ctx));\n if (!matches) return false;\n }\n return true;\n };\n\n return {\n id: this.id,\n matcher: combinedMatcher,\n response: this.response,\n label: this.label,\n once: this.isOnce,\n };\n }\n\n /**\n * Register this mock with the global MockManager.\n * Returns the ID of the registered mock.\n *\n * @example\n * const mockId = mockLLM().forModel('gpt-5').returns('Hello!').register();\n * // Later: getMockManager().unregister(mockId);\n */\n register(): string {\n const mockManager = getMockManager();\n const registration = this.build();\n return mockManager.register(registration);\n }\n}\n\n/**\n * Create a new MockBuilder instance.\n * This is the main entry point for the fluent mock API.\n *\n * @example\n * ```typescript\n * import { mockLLM } from 'llmist';\n *\n * mockLLM()\n * .forModel('gpt-5')\n * .whenMessageContains('hello')\n * .returns('Hello there!')\n * .register();\n * ```\n */\nexport function mockLLM(): MockBuilder {\n return new MockBuilder();\n}\n","import { LLMist } from \"../core/client.js\";\nimport { MockProviderAdapter } from \"./mock-adapter.js\";\nimport type { MockOptions } from \"./mock-types.js\";\n\n/**\n * Create a preconfigured LLMist client with mock adapter.\n * This is a convenience function for testing scenarios.\n *\n * @param options - Optional configuration for the mock system\n * @returns A LLMist instance configured to use mocks\n *\n * @example\n * ```typescript\n * import { createMockClient, getMockManager } from 'llmist';\n *\n * // Setup\n * const client = createMockClient({ strictMode: true });\n * const mockManager = getMockManager();\n *\n * // Register mocks\n * mockManager.register({\n * matcher: (ctx) => ctx.modelName === 'gpt-4',\n * response: { text: 'Mocked response' }\n * });\n *\n * // Use in tests\n * const stream = client.stream({\n * model: 'mock:gpt-4',\n * messages: [{ role: 'user', content: 'test' }]\n * });\n * ```\n */\nexport function createMockClient(options?: MockOptions): LLMist {\n return new LLMist({\n adapters: [new MockProviderAdapter(options)],\n autoDiscoverProviders: false,\n defaultProvider: \"mock\",\n });\n}\n","/**\n * Mock gadget utilities for testing.\n *\n * Provides helpers for creating mock gadgets with configurable behavior\n * and call tracking.\n *\n * @module testing/mock-gadget\n */\n\nimport type { ZodType } from \"zod\";\nimport { BaseGadget } from \"../gadgets/gadget.js\";\n\n/**\n * Recorded gadget call for tracking.\n */\nexport interface RecordedCall {\n /** Parameters passed to execute() */\n params: Record<string, unknown>;\n /** When the call was made */\n timestamp: number;\n}\n\n/**\n * Mock gadget with call tracking capabilities.\n */\nexport interface MockGadget extends BaseGadget {\n /** Get all recorded calls */\n getCalls(): RecordedCall[];\n /** Get number of times the gadget was executed */\n getCallCount(): number;\n /** Reset call history */\n resetCalls(): void;\n /** Check if gadget was called with specific params (partial match) */\n wasCalledWith(params: Partial<Record<string, unknown>>): boolean;\n /** Get the last call's parameters */\n getLastCall(): RecordedCall | undefined;\n}\n\n/**\n * Configuration for creating a mock gadget.\n */\nexport interface MockGadgetConfig<TSchema extends ZodType = ZodType> {\n /** Gadget name (required) */\n name: string;\n /** Gadget description */\n description?: string;\n /** Parameter schema */\n schema?: TSchema;\n /** Static result to return */\n result?: string;\n /** Dynamic result based on parameters */\n resultFn?: (params: Record<string, unknown>) => string | Promise<string>;\n /** Error to throw on execution */\n error?: Error | string;\n /** Enable call tracking (default: true) */\n trackCalls?: boolean;\n /** Execution delay in ms */\n delayMs?: number;\n /** Gadget timeout setting */\n timeoutMs?: number;\n}\n\n/**\n * Implementation of MockGadget.\n */\nclass MockGadgetImpl extends BaseGadget implements MockGadget {\n override name: string;\n override description: string;\n override parameterSchema?: ZodType;\n override timeoutMs?: number;\n\n private calls: RecordedCall[] = [];\n private readonly resultValue?: string;\n private readonly resultFn?: (params: Record<string, unknown>) => string | Promise<string>;\n private readonly errorToThrow?: Error;\n private readonly delayMs: number;\n private readonly shouldTrackCalls: boolean;\n\n constructor(config: MockGadgetConfig) {\n super();\n this.name = config.name;\n this.description = config.description ?? `Mock gadget: ${config.name}`;\n this.parameterSchema = config.schema;\n this.resultValue = config.result;\n this.resultFn = config.resultFn;\n this.delayMs = config.delayMs ?? 0;\n this.shouldTrackCalls = config.trackCalls ?? true;\n this.timeoutMs = config.timeoutMs;\n\n if (config.error) {\n this.errorToThrow = typeof config.error === \"string\" ? new Error(config.error) : config.error;\n }\n }\n\n async execute(params: Record<string, unknown>): Promise<string> {\n if (this.shouldTrackCalls) {\n this.calls.push({ params: { ...params }, timestamp: Date.now() });\n }\n\n if (this.delayMs > 0) {\n await new Promise((resolve) => setTimeout(resolve, this.delayMs));\n }\n\n if (this.errorToThrow) {\n throw this.errorToThrow;\n }\n\n if (this.resultFn) {\n return this.resultFn(params);\n }\n\n return this.resultValue ?? \"mock result\";\n }\n\n getCalls(): RecordedCall[] {\n return [...this.calls];\n }\n\n getCallCount(): number {\n return this.calls.length;\n }\n\n resetCalls(): void {\n this.calls = [];\n }\n\n wasCalledWith(params: Partial<Record<string, unknown>>): boolean {\n return this.calls.some((call) =>\n Object.entries(params).every(([key, value]) => call.params[key] === value),\n );\n }\n\n getLastCall(): RecordedCall | undefined {\n return this.calls.length > 0 ? this.calls[this.calls.length - 1] : undefined;\n }\n}\n\n/**\n * Create a mock gadget for testing.\n *\n * @param config - Mock gadget configuration\n * @returns MockGadget instance with call tracking\n *\n * @example\n * ```typescript\n * import { createMockGadget } from 'llmist/testing';\n * import { z } from 'zod';\n *\n * const calculator = createMockGadget({\n * name: 'Calculator',\n * schema: z.object({ a: z.number(), b: z.number() }),\n * resultFn: ({ a, b }) => String(Number(a) + Number(b)),\n * });\n *\n * // Use in tests\n * const registry = new GadgetRegistry();\n * registry.registerByClass(calculator);\n *\n * // After running agent...\n * expect(calculator.getCallCount()).toBe(1);\n * expect(calculator.wasCalledWith({ a: 5 })).toBe(true);\n * ```\n */\nexport function createMockGadget<TSchema extends ZodType>(\n config: MockGadgetConfig<TSchema>,\n): MockGadget {\n return new MockGadgetImpl(config);\n}\n\n/**\n * Fluent builder for creating mock gadgets.\n *\n * @example\n * ```typescript\n * import { mockGadget } from 'llmist/testing';\n * import { z } from 'zod';\n *\n * const mock = mockGadget()\n * .withName('Weather')\n * .withDescription('Get weather for a city')\n * .withSchema(z.object({ city: z.string() }))\n * .returns('Sunny, 72F')\n * .trackCalls()\n * .build();\n *\n * // Or for error testing\n * const errorMock = mockGadget()\n * .withName('Unstable')\n * .throws('Service unavailable')\n * .build();\n * ```\n */\nexport class MockGadgetBuilder {\n private config: MockGadgetConfig = { name: \"MockGadget\" };\n\n /**\n * Set the gadget name.\n */\n withName(name: string): this {\n this.config.name = name;\n return this;\n }\n\n /**\n * Set the gadget description.\n */\n withDescription(description: string): this {\n this.config.description = description;\n return this;\n }\n\n /**\n * Set the parameter schema.\n */\n withSchema<T extends ZodType>(schema: T): MockGadgetBuilder {\n this.config.schema = schema;\n return this;\n }\n\n /**\n * Set a static result to return.\n */\n returns(result: string): this {\n this.config.result = result;\n this.config.resultFn = undefined;\n return this;\n }\n\n /**\n * Set a dynamic result function.\n */\n returnsAsync(resultFn: (params: Record<string, unknown>) => string | Promise<string>): this {\n this.config.resultFn = resultFn;\n this.config.result = undefined;\n return this;\n }\n\n /**\n * Make the gadget throw an error on execution.\n */\n throws(error: Error | string): this {\n this.config.error = error;\n return this;\n }\n\n /**\n * Add execution delay.\n */\n withDelay(ms: number): this {\n this.config.delayMs = ms;\n return this;\n }\n\n /**\n * Set timeout for the gadget.\n */\n withTimeout(ms: number): this {\n this.config.timeoutMs = ms;\n return this;\n }\n\n /**\n * Enable call tracking (enabled by default).\n */\n trackCalls(): this {\n this.config.trackCalls = true;\n return this;\n }\n\n /**\n * Disable call tracking.\n */\n noTracking(): this {\n this.config.trackCalls = false;\n return this;\n }\n\n /**\n * Build the mock gadget.\n */\n build(): MockGadget {\n return createMockGadget(this.config);\n }\n}\n\n/**\n * Create a fluent builder for mock gadgets.\n *\n * @returns New MockGadgetBuilder instance\n *\n * @example\n * ```typescript\n * const mock = mockGadget()\n * .withName('Search')\n * .withSchema(z.object({ query: z.string() }))\n * .returnsAsync(async ({ query }) => {\n * return `Results for: ${query}`;\n * })\n * .build();\n * ```\n */\nexport function mockGadget(): MockGadgetBuilder {\n return new MockGadgetBuilder();\n}\n","/**\n * Stream testing utilities for llmist.\n * Provides helpers for creating and consuming test streams.\n */\n\nimport type { LLMStream, LLMStreamChunk } from \"../core/options.js\";\n\n/**\n * Create an async iterable stream from an array of chunks.\n * Useful for creating deterministic test streams.\n *\n * @param chunks - Array of chunks to yield\n * @returns An async iterable that yields the chunks in order\n *\n * @example\n * ```typescript\n * const stream = createTestStream([\n * { text: \"Hello \" },\n * { text: \"world\", finishReason: \"stop\", usage: { inputTokens: 10, outputTokens: 5 } }\n * ]);\n * ```\n */\nexport function createTestStream(chunks: LLMStreamChunk[]): LLMStream {\n return (async function* () {\n for (const chunk of chunks) {\n yield chunk;\n }\n })();\n}\n\n/**\n * Create a stream that yields text in specified chunks.\n * Automatically adds finishReason and usage to the final chunk.\n *\n * @param text - The full text to stream\n * @param options - Configuration options\n * @returns An async iterable stream\n *\n * @example\n * ```typescript\n * const stream = createTextStream(\"Hello, world!\", { chunkSize: 5 });\n * // Yields: \"Hello\", \", wor\", \"ld!\"\n * ```\n */\nexport function createTextStream(\n text: string,\n options?: {\n /** Size of each chunk (default: entire text as one chunk) */\n chunkSize?: number;\n /** Delay before starting the stream in ms */\n delayMs?: number;\n /** Delay between chunks in ms */\n chunkDelayMs?: number;\n /** Custom usage stats */\n usage?: { inputTokens: number; outputTokens: number; totalTokens: number };\n /** Custom finish reason (default: \"stop\") */\n finishReason?: string;\n },\n): LLMStream {\n return (async function* () {\n if (options?.delayMs) {\n await sleep(options.delayMs);\n }\n\n const chunkSize = options?.chunkSize ?? text.length;\n const chunks: string[] = [];\n\n for (let i = 0; i < text.length; i += chunkSize) {\n chunks.push(text.slice(i, i + chunkSize));\n }\n\n for (let i = 0; i < chunks.length; i++) {\n const isLast = i === chunks.length - 1;\n\n const chunk: LLMStreamChunk = { text: chunks[i] };\n\n if (isLast) {\n chunk.finishReason = options?.finishReason ?? \"stop\";\n // Simplified token estimation heuristic (~4 chars per token) for testing only.\n // For accurate token counts, provide explicit usage in options.\n const inputTokens = Math.ceil(text.length / 4);\n const outputTokens = Math.ceil(text.length / 4);\n chunk.usage = options?.usage ?? {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n };\n }\n\n yield chunk;\n\n if (options?.chunkDelayMs && !isLast) {\n await sleep(options.chunkDelayMs);\n }\n }\n })();\n}\n\n/**\n * Collect all chunks from a stream into an array.\n * Useful for asserting on stream output in tests.\n *\n * @param stream - The stream to collect from\n * @returns Array of all chunks from the stream\n *\n * @example\n * ```typescript\n * const chunks = await collectStream(myStream);\n * expect(chunks).toHaveLength(3);\n * expect(chunks[2].finishReason).toBe(\"stop\");\n * ```\n */\nexport async function collectStream(stream: LLMStream): Promise<LLMStreamChunk[]> {\n const chunks: LLMStreamChunk[] = [];\n for await (const chunk of stream) {\n chunks.push(chunk);\n }\n return chunks;\n}\n\n/**\n * Collect all text from a stream into a single string.\n *\n * @param stream - The stream to collect from\n * @returns Concatenated text from all chunks\n *\n * @example\n * ```typescript\n * const text = await collectStreamText(myStream);\n * expect(text).toBe(\"Hello, world!\");\n * ```\n */\nexport async function collectStreamText(stream: LLMStream): Promise<string> {\n let text = \"\";\n for await (const chunk of stream) {\n text += chunk.text ?? \"\";\n }\n return text;\n}\n\n/**\n * Get the final chunk from a stream (containing finishReason and usage).\n *\n * @param stream - The stream to consume\n * @returns The final chunk from the stream\n */\nexport async function getStreamFinalChunk(stream: LLMStream): Promise<LLMStreamChunk | undefined> {\n let lastChunk: LLMStreamChunk | undefined;\n for await (const chunk of stream) {\n lastChunk = chunk;\n }\n return lastChunk;\n}\n\n/**\n * Create an empty stream that yields nothing.\n * Useful for testing edge cases.\n */\nexport function createEmptyStream(): LLMStream {\n return (async function* () {\n // Empty stream\n })();\n}\n\n/**\n * Create a stream that throws an error after yielding some chunks.\n * Useful for testing error handling.\n *\n * @param chunksBeforeError - Chunks to yield before throwing\n * @param error - The error to throw\n */\nexport function createErrorStream(\n chunksBeforeError: LLMStreamChunk[],\n error: Error,\n): LLMStream {\n return (async function* () {\n for (const chunk of chunksBeforeError) {\n yield chunk;\n }\n throw error;\n })();\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * Conversation fixture generators for testing.\n * Provides utilities for creating test conversation data.\n */\n\nimport type { LLMMessage } from \"../core/messages.js\";\n\n/**\n * Create a conversation with a specified number of turns.\n * Each turn consists of a user message and an assistant response.\n *\n * @param turnCount - Number of conversation turns to generate\n * @param options - Configuration options\n * @returns Array of LLMMessages representing the conversation\n *\n * @example\n * ```typescript\n * const messages = createConversation(5);\n * // Creates 10 messages: 5 user + 5 assistant\n * ```\n */\nexport function createConversation(\n turnCount: number,\n options?: {\n /** Prefix for user messages (default: \"User message\") */\n userPrefix?: string;\n /** Prefix for assistant messages (default: \"Assistant response\") */\n assistantPrefix?: string;\n /** Base content length per message (default: 100 chars) */\n contentLength?: number;\n },\n): LLMMessage[] {\n const messages: LLMMessage[] = [];\n const userPrefix = options?.userPrefix ?? \"User message\";\n const assistantPrefix = options?.assistantPrefix ?? \"Assistant response\";\n const contentLength = options?.contentLength ?? 100;\n\n for (let i = 0; i < turnCount; i++) {\n // Generate content to fill approximate length\n const padding = \" \".repeat(Math.max(0, contentLength - 30));\n\n messages.push({\n role: \"user\",\n content: `${userPrefix} ${i + 1}: This is turn ${i + 1} of the conversation.${padding}`,\n });\n\n messages.push({\n role: \"assistant\",\n content: `${assistantPrefix} ${i + 1}: I acknowledge turn ${i + 1}.${padding}`,\n });\n }\n\n return messages;\n}\n\n/**\n * Create a conversation with gadget calls interspersed.\n * Simulates an agent conversation with tool usage.\n *\n * @param turnCount - Number of conversation turns\n * @param gadgetCallsPerTurn - Number of gadget calls per assistant turn\n * @returns Array of LLMMessages including gadget call/result pairs\n *\n * @example\n * ```typescript\n * const messages = createConversationWithGadgets(3, 2);\n * // Creates: user, assistant+gadget, gadget-result, assistant+gadget, gadget-result, assistant (per turn)\n * ```\n */\nexport function createConversationWithGadgets(\n turnCount: number,\n gadgetCallsPerTurn: number = 1,\n options?: {\n /** Gadget names to cycle through (default: [\"search\", \"calculate\", \"read\"]) */\n gadgetNames?: string[];\n /** Content length for messages */\n contentLength?: number;\n },\n): LLMMessage[] {\n const messages: LLMMessage[] = [];\n const gadgetNames = options?.gadgetNames ?? [\"search\", \"calculate\", \"read\"];\n const contentLength = options?.contentLength ?? 50;\n let gadgetIndex = 0;\n\n for (let turn = 0; turn < turnCount; turn++) {\n // User message\n messages.push({\n role: \"user\",\n content: `User request ${turn + 1}${\"x\".repeat(contentLength)}`,\n });\n\n // Assistant with gadget calls\n for (let g = 0; g < gadgetCallsPerTurn; g++) {\n const gadgetName = gadgetNames[gadgetIndex % gadgetNames.length];\n gadgetIndex++;\n\n // Gadget call (assistant message)\n messages.push({\n role: \"assistant\",\n content: `!!!GADGET_START:${gadgetName}\\n!!!ARG:query\\ntest query ${turn}-${g}\\n!!!GADGET_END`,\n });\n\n // Gadget result (user message)\n messages.push({\n role: \"user\",\n content: `Result: Gadget ${gadgetName} returned result for query ${turn}-${g}`,\n });\n }\n\n // Final assistant response for this turn\n messages.push({\n role: \"assistant\",\n content: `Final response for turn ${turn + 1}${\"y\".repeat(contentLength)}`,\n });\n }\n\n return messages;\n}\n\n/**\n * Estimate token count for a message array.\n * Uses a simple 4-characters-per-token heuristic.\n *\n * @param messages - Messages to estimate tokens for\n * @returns Estimated token count\n *\n * @example\n * ```typescript\n * const messages = createConversation(10);\n * const tokens = estimateTokens(messages);\n * // Returns approximate token count\n * ```\n */\nexport function estimateTokens(messages: LLMMessage[]): number {\n return Math.ceil(\n messages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4,\n );\n}\n\n/**\n * Create a single user message.\n */\nexport function createUserMessage(content: string): LLMMessage {\n return { role: \"user\", content };\n}\n\n/**\n * Create a single assistant message.\n */\nexport function createAssistantMessage(content: string): LLMMessage {\n return { role: \"assistant\", content };\n}\n\n/**\n * Create a system message.\n */\nexport function createSystemMessage(content: string): LLMMessage {\n return { role: \"system\", content };\n}\n\n/**\n * Create a minimal conversation for quick tests.\n * Returns a single turn: one user message and one assistant response.\n */\nexport function createMinimalConversation(): LLMMessage[] {\n return [\n { role: \"user\", content: \"Hello\" },\n { role: \"assistant\", content: \"Hi there!\" },\n ];\n}\n\n/**\n * Create a conversation that exceeds a target token count.\n * Useful for testing compaction triggers.\n *\n * @param targetTokens - Minimum token count to exceed\n * @param options - Configuration options\n * @returns Conversation with at least targetTokens tokens\n */\nexport function createLargeConversation(\n targetTokens: number,\n options?: {\n /** Average tokens per turn (default: 200) */\n tokensPerTurn?: number;\n },\n): LLMMessage[] {\n const tokensPerTurn = options?.tokensPerTurn ?? 200;\n const turnsNeeded = Math.ceil(targetTokens / tokensPerTurn);\n\n // Each character is ~0.25 tokens, so multiply by 4 for chars\n const charsPerMessage = Math.floor((tokensPerTurn * 4) / 2); // Divide by 2 for user + assistant\n\n return createConversation(turnsNeeded, {\n contentLength: charsPerMessage,\n });\n}\n","/**\n * Mock ConversationManager for testing compaction and agent components.\n * Implements IConversationManager interface with test-friendly features.\n */\n\nimport type { LLMMessage } from \"../core/messages.js\";\nimport type { IConversationManager } from \"../agent/interfaces.js\";\n\n/**\n * A mock implementation of IConversationManager for testing.\n * Tracks all operations and allows inspection of state changes.\n *\n * @example\n * ```typescript\n * const mockConvo = new MockConversationManager([\n * { role: \"user\", content: \"Hello\" },\n * { role: \"assistant\", content: \"Hi!\" }\n * ]);\n *\n * // Use in compaction tests\n * compactionManager.checkAndCompact(mockConvo, 1);\n *\n * // Assert on state changes\n * expect(mockConvo.wasReplaceHistoryCalled()).toBe(true);\n * expect(mockConvo.getReplacementHistory()).toHaveLength(2);\n * ```\n */\nexport class MockConversationManager implements IConversationManager {\n private history: LLMMessage[];\n private readonly baseMessages: LLMMessage[];\n private replacementHistory: LLMMessage[] | undefined;\n private replaceHistoryCallCount = 0;\n private addedMessages: LLMMessage[] = [];\n\n constructor(\n history: LLMMessage[] = [],\n baseMessages: LLMMessage[] = [],\n ) {\n this.history = [...history];\n this.baseMessages = [...baseMessages];\n }\n\n addUserMessage(content: string): void {\n const msg: LLMMessage = { role: \"user\", content };\n this.history.push(msg);\n this.addedMessages.push(msg);\n }\n\n addAssistantMessage(content: string): void {\n const msg: LLMMessage = { role: \"assistant\", content };\n this.history.push(msg);\n this.addedMessages.push(msg);\n }\n\n addGadgetCall(gadgetName: string, parameters: Record<string, unknown>, result: string): void {\n // Simplified gadget call format for testing\n const assistantMsg: LLMMessage = {\n role: \"assistant\",\n content: `!!!GADGET_START:${gadgetName}\\n${JSON.stringify(parameters)}\\n!!!GADGET_END`,\n };\n const resultMsg: LLMMessage = {\n role: \"user\",\n content: `Result: ${result}`,\n };\n\n this.history.push(assistantMsg);\n this.history.push(resultMsg);\n this.addedMessages.push(assistantMsg);\n this.addedMessages.push(resultMsg);\n }\n\n getMessages(): LLMMessage[] {\n return [...this.baseMessages, ...this.history];\n }\n\n getHistoryMessages(): LLMMessage[] {\n return [...this.history];\n }\n\n getBaseMessages(): LLMMessage[] {\n return [...this.baseMessages];\n }\n\n replaceHistory(newHistory: LLMMessage[]): void {\n this.replacementHistory = [...newHistory];\n this.history = [...newHistory];\n this.replaceHistoryCallCount++;\n }\n\n // ============================================\n // Test Helper Methods\n // ============================================\n\n /**\n * Check if replaceHistory was called.\n */\n wasReplaceHistoryCalled(): boolean {\n return this.replaceHistoryCallCount > 0;\n }\n\n /**\n * Get the number of times replaceHistory was called.\n */\n getReplaceHistoryCallCount(): number {\n return this.replaceHistoryCallCount;\n }\n\n /**\n * Get the most recent history passed to replaceHistory.\n * Returns undefined if replaceHistory was never called.\n */\n getReplacementHistory(): LLMMessage[] | undefined {\n return this.replacementHistory;\n }\n\n /**\n * Get all messages that were added via add* methods.\n */\n getAddedMessages(): LLMMessage[] {\n return [...this.addedMessages];\n }\n\n /**\n * Reset all tracking state while preserving the conversation.\n */\n resetTracking(): void {\n this.replacementHistory = undefined;\n this.replaceHistoryCallCount = 0;\n this.addedMessages = [];\n }\n\n /**\n * Completely reset the mock to initial state.\n * Note: baseMessages cannot be changed after construction.\n */\n reset(history: LLMMessage[] = []): void {\n this.history = [...history];\n this.resetTracking();\n }\n\n /**\n * Set the history directly (for test setup).\n */\n setHistory(messages: LLMMessage[]): void {\n this.history = [...messages];\n }\n\n /**\n * Get the current history length.\n */\n getHistoryLength(): number {\n return this.history.length;\n }\n\n /**\n * Get total message count (base + history).\n */\n getTotalMessageCount(): number {\n return this.baseMessages.length + this.history.length;\n }\n}\n\n/**\n * Create a mock conversation manager with a pre-populated conversation.\n *\n * @param turnCount - Number of conversation turns\n * @param baseMessages - Optional base messages (system prompts)\n * @returns Configured MockConversationManager\n */\nexport function createMockConversationManager(\n turnCount: number,\n baseMessages: LLMMessage[] = [],\n): MockConversationManager {\n const history: LLMMessage[] = [];\n\n for (let i = 0; i < turnCount; i++) {\n history.push({\n role: \"user\",\n content: `User message ${i + 1}: This is turn ${i + 1} of the conversation.`,\n });\n history.push({\n role: \"assistant\",\n content: `Assistant response ${i + 1}: I acknowledge turn ${i + 1}.`,\n });\n }\n\n return new MockConversationManager(history, baseMessages);\n}\n","/**\n * CLI testing utilities for llmist.\n * Provides helpers for testing CLI commands without real I/O.\n */\n\nimport { PassThrough, Readable, Writable } from \"node:stream\";\n\n/**\n * Options for creating a test environment.\n */\nexport interface TestEnvironmentOptions {\n /** Input to provide via stdin (string or line array) */\n stdin?: string | string[];\n /** Whether stdin is a TTY (default: false) */\n isTTY?: boolean;\n /** Environment variables to set */\n env?: Record<string, string>;\n /** Command line arguments (default: [\"node\", \"llmist\"]) */\n argv?: string[];\n}\n\n/**\n * A test environment with captured I/O streams.\n */\nexport interface TestEnvironment {\n /** Stdin readable stream */\n stdin: Readable;\n /** Stdout writable stream (PassThrough for capturing) */\n stdout: PassThrough;\n /** Stderr writable stream (PassThrough for capturing) */\n stderr: PassThrough;\n /** Whether stdin is TTY */\n isTTY: boolean;\n /** Command line arguments */\n argv: string[];\n /** Environment variables */\n env: Record<string, string>;\n /** Exit code if set */\n exitCode?: number;\n /** Function to set exit code */\n setExitCode: (code: number) => void;\n}\n\n/**\n * Create a test environment with mocked I/O streams.\n *\n * @param options - Configuration options\n * @returns A test environment with captured streams\n *\n * @example\n * ```typescript\n * const env = createTestEnvironment({\n * stdin: '{\"param\": \"value\"}',\n * isTTY: false\n * });\n *\n * // Pass to CLI command\n * await executeCommand(env);\n *\n * // Check output\n * const output = await collectOutput(env.stdout);\n * expect(output).toContain(\"Success\");\n * ```\n */\nexport function createTestEnvironment(options: TestEnvironmentOptions = {}): TestEnvironment {\n const stdin = createMockReadable(options.stdin);\n const stdout = new PassThrough();\n const stderr = new PassThrough();\n\n let exitCode: number | undefined;\n\n return {\n stdin,\n stdout,\n stderr,\n isTTY: options.isTTY ?? false,\n argv: options.argv ?? [\"node\", \"llmist\"],\n env: { ...filterDefinedEnv(process.env), ...options.env },\n get exitCode() {\n return exitCode;\n },\n setExitCode: (code: number) => {\n exitCode = code;\n },\n };\n}\n\n/**\n * Create a readable stream from a string or array of lines.\n *\n * @param input - String content or array of lines\n * @returns A Readable stream\n *\n * @example\n * ```typescript\n * const stream = createMockReadable(\"line1\\nline2\\n\");\n * // or\n * const stream = createMockReadable([\"line1\", \"line2\"]);\n * ```\n */\nexport function createMockReadable(input?: string | string[]): Readable {\n if (!input) {\n // Empty stream that ends immediately\n const stream = new Readable({ read() {} });\n stream.push(null);\n return stream;\n }\n\n const content = Array.isArray(input) ? `${input.join(\"\\n\")}\\n` : input;\n\n const stream = new Readable({ read() {} });\n stream.push(content);\n stream.push(null);\n return stream;\n}\n\n/**\n * Create a writable stream that collects all written data.\n *\n * @returns A writable stream with getData() method\n */\nexport function createMockWritable(): Writable & { getData(): string } {\n const chunks: Buffer[] = [];\n\n const stream = new Writable({\n write(chunk, _encoding, callback) {\n chunks.push(Buffer.from(chunk));\n callback();\n },\n }) as Writable & { getData(): string };\n\n stream.getData = () => Buffer.concat(chunks).toString(\"utf8\");\n\n return stream;\n}\n\n/**\n * Collect all output from a PassThrough stream.\n * Waits for the stream to end before returning.\n *\n * @param stream - The stream to collect from\n * @param timeout - Maximum time to wait in ms (default: 5000)\n * @returns All data written to the stream\n *\n * @example\n * ```typescript\n * const output = await collectOutput(env.stdout);\n * expect(output).toContain(\"Expected text\");\n * ```\n */\nexport async function collectOutput(stream: PassThrough, timeout = 5000): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n\n const timeoutId = setTimeout(() => {\n // Return what we have so far if timeout\n resolve(Buffer.concat(chunks).toString(\"utf8\"));\n }, timeout);\n\n stream.on(\"data\", (chunk) => {\n chunks.push(Buffer.from(chunk));\n });\n\n stream.on(\"end\", () => {\n clearTimeout(timeoutId);\n resolve(Buffer.concat(chunks).toString(\"utf8\"));\n });\n\n stream.on(\"error\", (err) => {\n clearTimeout(timeoutId);\n reject(err);\n });\n });\n}\n\n/**\n * Collect output without waiting for stream end.\n * Returns immediately with whatever has been written.\n *\n * @param stream - The stream to read from\n * @returns Currently buffered data\n */\nexport function getBufferedOutput(stream: PassThrough): string {\n const chunks: Buffer[] = [];\n\n // Read all available data\n for (;;) {\n const chunk = stream.read() as Buffer | null;\n if (chunk === null) break;\n chunks.push(chunk);\n }\n\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\n/**\n * Create a mock prompt function for testing interactive input.\n *\n * @param responses - Array of responses to return in order\n * @returns A prompt function that returns the next response\n *\n * @example\n * ```typescript\n * const prompt = createMockPrompt([\"yes\", \"no\", \"maybe\"]);\n * expect(await prompt(\"Question 1?\")).toBe(\"yes\");\n * expect(await prompt(\"Question 2?\")).toBe(\"no\");\n * ```\n */\nexport function createMockPrompt(\n responses: string[],\n): (question: string) => Promise<string> {\n let index = 0;\n\n return async (_question: string): Promise<string> => {\n if (index >= responses.length) {\n throw new Error(`Mock prompt exhausted: no response for question ${index + 1}`);\n }\n return responses[index++];\n };\n}\n\n/**\n * Mock prompt that records questions and returns configured responses.\n */\nexport class MockPromptRecorder {\n private responses: string[];\n private index = 0;\n private questions: string[] = [];\n\n constructor(responses: string[]) {\n this.responses = responses;\n }\n\n /**\n * The prompt function to use in tests.\n */\n prompt = async (question: string): Promise<string> => {\n this.questions.push(question);\n if (this.index >= this.responses.length) {\n throw new Error(`Mock prompt exhausted after ${this.index} questions`);\n }\n return this.responses[this.index++];\n };\n\n /**\n * Get all questions that were asked.\n */\n getQuestions(): string[] {\n return [...this.questions];\n }\n\n /**\n * Get the number of questions asked.\n */\n getQuestionCount(): number {\n return this.questions.length;\n }\n\n /**\n * Reset the recorder state.\n */\n reset(newResponses?: string[]): void {\n this.index = 0;\n this.questions = [];\n if (newResponses) {\n this.responses = newResponses;\n }\n }\n}\n\n/**\n * Wait for a condition to be true, with timeout.\n * Useful for async testing scenarios.\n *\n * @param condition - Function that returns true when condition is met\n * @param timeout - Maximum time to wait in ms (default: 5000)\n * @param interval - Check interval in ms (default: 50)\n */\nexport async function waitFor(\n condition: () => boolean,\n timeout = 5000,\n interval = 50,\n): Promise<void> {\n const startTime = Date.now();\n\n while (!condition()) {\n if (Date.now() - startTime > timeout) {\n throw new Error(`waitFor timed out after ${timeout}ms`);\n }\n await sleep(interval);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction filterDefinedEnv(env: NodeJS.ProcessEnv): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n if (value !== undefined) {\n result[key] = value;\n }\n }\n return result;\n}\n"],"mappings":"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","names":["sleep","stream","sleep"]}