llmist 6.2.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/constants.ts","../src/core/input-content.ts","../src/core/model-shortcuts.ts","../src/gadgets/schema-validator.ts","../src/gadgets/registry.ts","../src/core/execution-tree.ts","../src/core/prompt-config.ts","../src/core/messages.ts","../src/gadgets/media-store.ts","../src/gadgets/exceptions.ts","../src/logging/logger.ts","../src/gadgets/schema-to-json.ts","../src/gadgets/gadget.ts","../src/gadgets/create-gadget.ts","../src/gadgets/output-viewer.ts","../src/agent/agent-internal-key.ts","../src/agent/compaction/config.ts","../src/agent/compaction/strategy.ts","../src/agent/compaction/strategies/sliding-window.ts","../src/agent/compaction/strategies/summarization.ts","../src/agent/compaction/strategies/hybrid.ts","../src/agent/compaction/strategies/index.ts","../src/agent/compaction/manager.ts","../src/agent/conversation-manager.ts","../src/agent/event-handlers.ts","../src/agent/gadget-output-store.ts","../src/agent/hook-validators.ts","../src/providers/anthropic-models.ts","../src/providers/base-provider.ts","../src/providers/constants.ts","../src/providers/utils.ts","../src/providers/anthropic.ts","../src/providers/gemini-image-models.ts","../src/providers/gemini-models.ts","../src/providers/gemini-speech-models.ts","../src/providers/gemini.ts","../src/providers/openai-image-models.ts","../src/providers/openai-models.ts","../src/providers/openai-speech-models.ts","../src/providers/openai.ts","../src/providers/discovery.ts","../src/core/model-registry.ts","../src/core/namespaces/image.ts","../src/core/namespaces/speech.ts","../src/core/quick-methods.ts","../src/core/namespaces/text.ts","../src/core/namespaces/vision.ts","../src/core/options.ts","../src/core/client.ts","../src/gadgets/schema-introspector.ts","../src/gadgets/block-params.ts","../src/gadgets/cost-reporting-client.ts","../src/gadgets/error-formatter.ts","../src/gadgets/parser.ts","../src/gadgets/typed-gadget.ts","../src/gadgets/executor.ts","../src/agent/stream-processor.ts","../src/agent/agent.ts","../src/agent/builder.ts","../src/cli/constants.ts","../src/cli/program.ts","../package.json","../src/cli/agent-command.ts","../src/core/errors.ts","../src/cli/builtin-gadgets.ts","../src/cli/subagent-config.ts","../src/cli/config.ts","../src/cli/templates.ts","../src/cli/docker/types.ts","../src/cli/docker/docker-config.ts","../src/cli/docker/docker-wrapper.ts","../src/cli/docker/dockerfile.ts","../src/cli/docker/image-manager.ts","../src/cli/file-utils.ts","../src/cli/gadgets.ts","../src/cli/builtins/filesystem/edit-file.ts","../src/index.ts","../src/agent/compaction/index.ts","../src/agent/index.ts","../src/agent/hints.ts","../src/gadgets/helpers.ts","../src/testing/cli-helpers.ts","../src/testing/mock-manager.ts","../src/testing/mock-stream.ts","../src/testing/mock-builder.ts","../src/testing/mock-client.ts","../src/testing/mock-gadget.ts","../src/cli/builtins/filesystem/utils.ts","../src/cli/builtins/filesystem/list-directory.ts","../src/cli/builtins/filesystem/read-file.ts","../src/cli/builtins/filesystem/write-file.ts","../src/cli/builtins/run-command.ts","../src/cli/builtins/index.ts","../src/cli/external-gadgets.ts","../src/cli/llm-logging.ts","../src/cli/utils.ts","../src/cli/ui/formatters.ts","../src/cli/option-helpers.ts","../src/cli/tui/screen.ts","../src/cli/tui/layout.ts","../src/cli/tui/status-bar.ts","../src/cli/tui/input-handler.ts","../src/cli/tui/block-renderer.ts","../src/cli/ui/block-formatters.ts","../src/cli/tui/approval-dialog.ts","../src/cli/tui/raw-viewer.ts","../src/cli/tui/index.ts","../src/cli/complete-command.ts","../src/cli/init-command.ts","../src/cli/environment.ts","../src/cli/custom-command.ts","../src/cli/gadget-command.ts","../src/cli/gadget-prompts.ts","../src/cli/image-command.ts","../src/cli/models-command.ts","../src/cli/speech-command.ts","../src/cli/vision-command.ts","../src/cli.ts"],"sourcesContent":["// Gadget marker constants\nexport const GADGET_START_PREFIX = \"!!!GADGET_START:\";\nexport const GADGET_END_PREFIX = \"!!!GADGET_END\";\nexport const GADGET_ARG_PREFIX = \"!!!ARG:\";\n\n// Default configuration values\nexport const DEFAULT_MAX_TOKENS = 1024;\nexport const DEFAULT_MAX_ITERATIONS = 10;\n\n// Gadget output limiting defaults\n/** Default: gadget output limiting is enabled */\nexport const DEFAULT_GADGET_OUTPUT_LIMIT = true;\n\n/** Default: limit gadget output to 15% of context window */\nexport const DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT = 15;\n\n/** Approximate characters per token for limit calculation */\nexport const CHARS_PER_TOKEN = 4;\n\n/** Fallback context window size if model is not in registry */\nexport const FALLBACK_CONTEXT_WINDOW = 128_000;\n","/**\n * Types and interfaces for multimodal input content.\n *\n * These types define the structure for sending images, audio, and other\n * media alongside text in LLM messages. They complement the output types\n * in media-types.ts.\n */\n\n// ============================================================================\n// MIME Types\n// ============================================================================\n\n/**\n * Supported image MIME types for input.\n * All major providers support these formats.\n */\nexport type ImageMimeType = \"image/jpeg\" | \"image/png\" | \"image/gif\" | \"image/webp\";\n\n/**\n * Supported audio MIME types for input.\n * Currently only Gemini supports audio input.\n */\nexport type AudioMimeType =\n | \"audio/mp3\"\n | \"audio/mpeg\"\n | \"audio/wav\"\n | \"audio/webm\"\n | \"audio/ogg\"\n | \"audio/flac\";\n\n// ============================================================================\n// Content Part Types\n// ============================================================================\n\n/**\n * Base interface for all content parts.\n */\nexport interface BaseContentPart {\n type: string;\n}\n\n/**\n * Text content part.\n */\nexport interface TextContentPart extends BaseContentPart {\n type: \"text\";\n text: string;\n}\n\n/**\n * Image content part.\n */\nexport interface ImageContentPart extends BaseContentPart {\n type: \"image\";\n source: ImageSource;\n}\n\n/**\n * Audio content part.\n * Currently only supported by Gemini.\n */\nexport interface AudioContentPart extends BaseContentPart {\n type: \"audio\";\n source: AudioSource;\n}\n\n/**\n * Union of all supported content part types.\n */\nexport type ContentPart = TextContentPart | ImageContentPart | AudioContentPart;\n\n// ============================================================================\n// Source Types\n// ============================================================================\n\n/**\n * Image can come from base64 data or a URL.\n */\nexport type ImageSource = ImageBase64Source | ImageUrlSource;\n\n/**\n * Base64-encoded image data.\n * Supported by all providers.\n */\nexport interface ImageBase64Source {\n type: \"base64\";\n mediaType: ImageMimeType;\n data: string;\n}\n\n/**\n * Image URL reference.\n * Only supported by OpenAI.\n */\nexport interface ImageUrlSource {\n type: \"url\";\n url: string;\n}\n\n/**\n * Audio source (base64 only).\n * URL sources are not currently supported for audio.\n */\nexport interface AudioSource {\n type: \"base64\";\n mediaType: AudioMimeType;\n data: string;\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Check if a content part is a text part.\n */\nexport function isTextPart(part: ContentPart): part is TextContentPart {\n return part.type === \"text\";\n}\n\n/**\n * Check if a content part is an image part.\n */\nexport function isImagePart(part: ContentPart): part is ImageContentPart {\n return part.type === \"image\";\n}\n\n/**\n * Check if a content part is an audio part.\n */\nexport function isAudioPart(part: ContentPart): part is AudioContentPart {\n return part.type === \"audio\";\n}\n\n/**\n * Check if an image source is base64.\n */\nexport function isBase64ImageSource(source: ImageSource): source is ImageBase64Source {\n return source.type === \"base64\";\n}\n\n/**\n * Check if an image source is a URL.\n */\nexport function isUrlImageSource(source: ImageSource): source is ImageUrlSource {\n return source.type === \"url\";\n}\n\n// ============================================================================\n// Helper Functions - Content Part Creation\n// ============================================================================\n\n/**\n * Create a text content part.\n *\n * @example\n * ```typescript\n * const part = text(\"What's in this image?\");\n * ```\n */\nexport function text(content: string): TextContentPart {\n return { type: \"text\", text: content };\n}\n\n/**\n * Create an image content part from base64-encoded data.\n *\n * @param data - Base64-encoded image data\n * @param mediaType - MIME type of the image\n *\n * @example\n * ```typescript\n * const part = imageFromBase64(base64Data, \"image/jpeg\");\n * ```\n */\nexport function imageFromBase64(data: string, mediaType: ImageMimeType): ImageContentPart {\n return {\n type: \"image\",\n source: { type: \"base64\", mediaType, data },\n };\n}\n\n/**\n * Create an image content part from a URL.\n * Note: Only supported by OpenAI.\n *\n * @param url - URL to the image (must be accessible)\n *\n * @example\n * ```typescript\n * const part = imageFromUrl(\"https://example.com/image.jpg\");\n * ```\n */\nexport function imageFromUrl(url: string): ImageContentPart {\n return {\n type: \"image\",\n source: { type: \"url\", url },\n };\n}\n\n/**\n * Magic bytes for detecting image MIME types.\n */\nconst IMAGE_MAGIC_BYTES: Array<{ bytes: number[]; mimeType: ImageMimeType }> = [\n { bytes: [0xff, 0xd8, 0xff], mimeType: \"image/jpeg\" },\n { bytes: [0x89, 0x50, 0x4e, 0x47], mimeType: \"image/png\" },\n { bytes: [0x47, 0x49, 0x46, 0x38], mimeType: \"image/gif\" },\n // WebP starts with RIFF....WEBP\n { bytes: [0x52, 0x49, 0x46, 0x46], mimeType: \"image/webp\" },\n];\n\n/**\n * Magic bytes for detecting audio MIME types.\n */\nconst AUDIO_MAGIC_BYTES: Array<{ bytes: number[]; mimeType: AudioMimeType }> = [\n // MP3 frame sync\n { bytes: [0xff, 0xfb], mimeType: \"audio/mp3\" },\n { bytes: [0xff, 0xfa], mimeType: \"audio/mp3\" },\n // ID3 tag (MP3)\n { bytes: [0x49, 0x44, 0x33], mimeType: \"audio/mp3\" },\n // OGG\n { bytes: [0x4f, 0x67, 0x67, 0x53], mimeType: \"audio/ogg\" },\n // WAV (RIFF)\n { bytes: [0x52, 0x49, 0x46, 0x46], mimeType: \"audio/wav\" },\n // WebM\n { bytes: [0x1a, 0x45, 0xdf, 0xa3], mimeType: \"audio/webm\" },\n // FLAC (fLaC)\n { bytes: [0x66, 0x4c, 0x61, 0x43], mimeType: \"audio/flac\" },\n];\n\n/**\n * Detect the MIME type of image data from magic bytes.\n *\n * @param data - Raw image data\n * @returns Detected MIME type or null if unknown\n */\nexport function detectImageMimeType(data: Buffer | Uint8Array): ImageMimeType | null {\n const bytes = data instanceof Buffer ? data : Buffer.from(data);\n\n for (const { bytes: magic, mimeType } of IMAGE_MAGIC_BYTES) {\n if (bytes.length >= magic.length) {\n let matches = true;\n for (let i = 0; i < magic.length; i++) {\n if (bytes[i] !== magic[i]) {\n matches = false;\n break;\n }\n }\n if (matches) {\n // Special case: RIFF could be WebP or WAV, check for WEBP marker\n if (mimeType === \"image/webp\") {\n // RIFF....WEBP - check bytes 8-11\n if (bytes.length >= 12) {\n const webpMarker =\n bytes[8] === 0x57 && bytes[9] === 0x45 && bytes[10] === 0x42 && bytes[11] === 0x50;\n if (!webpMarker) continue; // Not WebP, try next pattern\n }\n }\n return mimeType;\n }\n }\n }\n return null;\n}\n\n/**\n * Detect the MIME type of audio data from magic bytes.\n *\n * @param data - Raw audio data\n * @returns Detected MIME type or null if unknown\n */\nexport function detectAudioMimeType(data: Buffer | Uint8Array): AudioMimeType | null {\n const bytes = data instanceof Buffer ? data : Buffer.from(data);\n\n for (const { bytes: magic, mimeType } of AUDIO_MAGIC_BYTES) {\n if (bytes.length >= magic.length) {\n let matches = true;\n for (let i = 0; i < magic.length; i++) {\n if (bytes[i] !== magic[i]) {\n matches = false;\n break;\n }\n }\n if (matches) {\n // Special case: RIFF could be WAV or WebP, check for WAVE marker\n if (mimeType === \"audio/wav\") {\n // RIFF....WAVE - check bytes 8-11\n if (bytes.length >= 12) {\n const waveMarker =\n bytes[8] === 0x57 && bytes[9] === 0x41 && bytes[10] === 0x56 && bytes[11] === 0x45;\n if (!waveMarker) continue; // Not WAV, try next pattern\n }\n }\n return mimeType;\n }\n }\n }\n return null;\n}\n\n/**\n * Convert data to base64 string.\n *\n * @param data - Data to encode (Buffer, Uint8Array, or already base64 string)\n * @returns Base64-encoded string\n */\nexport function toBase64(data: Buffer | Uint8Array | string): string {\n if (typeof data === \"string\") {\n return data; // Assume already base64\n }\n return Buffer.from(data).toString(\"base64\");\n}\n\n/**\n * Create an image content part from a Buffer or Uint8Array.\n * Automatically detects the MIME type if not provided.\n *\n * @param buffer - Image data\n * @param mediaType - Optional MIME type (auto-detected if not provided)\n *\n * @example\n * ```typescript\n * const imageData = await fs.readFile(\"photo.jpg\");\n * const part = imageFromBuffer(imageData); // Auto-detects JPEG\n * ```\n */\nexport function imageFromBuffer(\n buffer: Buffer | Uint8Array,\n mediaType?: ImageMimeType,\n): ImageContentPart {\n const detectedType = mediaType ?? detectImageMimeType(buffer);\n if (!detectedType) {\n throw new Error(\n \"Could not detect image MIME type. Please provide the mediaType parameter explicitly.\",\n );\n }\n return {\n type: \"image\",\n source: {\n type: \"base64\",\n mediaType: detectedType,\n data: toBase64(buffer),\n },\n };\n}\n\n/**\n * Create an audio content part from base64-encoded data.\n *\n * @param data - Base64-encoded audio data\n * @param mediaType - MIME type of the audio\n *\n * @example\n * ```typescript\n * const part = audioFromBase64(base64Audio, \"audio/mp3\");\n * ```\n */\nexport function audioFromBase64(data: string, mediaType: AudioMimeType): AudioContentPart {\n return {\n type: \"audio\",\n source: { type: \"base64\", mediaType, data },\n };\n}\n\n/**\n * Create an audio content part from a Buffer or Uint8Array.\n * Automatically detects the MIME type if not provided.\n *\n * @param buffer - Audio data\n * @param mediaType - Optional MIME type (auto-detected if not provided)\n *\n * @example\n * ```typescript\n * const audioData = await fs.readFile(\"audio.mp3\");\n * const part = audioFromBuffer(audioData); // Auto-detects MP3\n * ```\n */\nexport function audioFromBuffer(\n buffer: Buffer | Uint8Array,\n mediaType?: AudioMimeType,\n): AudioContentPart {\n const detectedType = mediaType ?? detectAudioMimeType(buffer);\n if (!detectedType) {\n throw new Error(\n \"Could not detect audio MIME type. Please provide the mediaType parameter explicitly.\",\n );\n }\n return {\n type: \"audio\",\n source: {\n type: \"base64\",\n mediaType: detectedType,\n data: toBase64(buffer),\n },\n };\n}\n\n// ============================================================================\n// Data URL Utilities\n// ============================================================================\n\n/**\n * Check if a string is a data URL.\n *\n * @param input - String to check\n * @returns True if it's a data URL\n */\nexport function isDataUrl(input: string): boolean {\n return input.startsWith(\"data:\");\n}\n\n/**\n * Parse a data URL into its components.\n *\n * @param url - Data URL to parse\n * @returns Parsed components or null if invalid\n *\n * @example\n * ```typescript\n * const result = parseDataUrl(\"data:image/jpeg;base64,/9j/4AAQ...\");\n * // { mimeType: \"image/jpeg\", data: \"/9j/4AAQ...\" }\n * ```\n */\nexport function parseDataUrl(url: string): { mimeType: string; data: string } | null {\n const match = url.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) return null;\n return { mimeType: match[1], data: match[2] };\n}\n","/**\n * Model shortcuts and aliases for more expressive DX.\n *\n * This module provides convenient aliases for common model names,\n * allowing developers to use short, memorable names instead of\n * verbose provider:model-id formats.\n *\n * @example\n * ```typescript\n * // Instead of:\n * model: \"openai:gpt-5-nano\"\n *\n * // You can use:\n * model: \"gpt5-nano\"\n * // or even:\n * model: \"gpt-5-nano\" // Auto-detects provider\n * ```\n */\n\n/**\n * Map of common model aliases to their full provider:model-id format.\n */\nexport const MODEL_ALIASES: Record<string, string> = {\n // OpenAI aliases\n gpt4: \"openai:gpt-4o\",\n gpt4o: \"openai:gpt-4o\",\n gpt5: \"openai:gpt-5\",\n \"gpt5-mini\": \"openai:gpt-5-mini\",\n \"gpt5-nano\": \"openai:gpt-5-nano\",\n\n // Anthropic aliases\n sonnet: \"anthropic:claude-sonnet-4-5\",\n \"claude-sonnet\": \"anthropic:claude-sonnet-4-5\",\n haiku: \"anthropic:claude-haiku-4-5\",\n \"claude-haiku\": \"anthropic:claude-haiku-4-5\",\n opus: \"anthropic:claude-opus-4-5\",\n \"claude-opus\": \"anthropic:claude-opus-4-5\",\n\n // Gemini aliases\n flash: \"gemini:gemini-2.0-flash\",\n \"gemini-flash\": \"gemini:gemini-2.0-flash\",\n \"gemini-pro\": \"gemini:gemini-2.5-pro\",\n pro: \"gemini:gemini-2.5-pro\",\n};\n\n/**\n * Options for resolveModel function.\n */\nexport interface ResolveModelOptions {\n /**\n * If true, throw an error for unknown model names instead of falling back to OpenAI.\n * This helps catch typos like \"gp4\" instead of \"gpt4\".\n * Default: false\n */\n strict?: boolean;\n\n /**\n * If true, suppress warnings for unknown model names.\n * Default: false\n */\n silent?: boolean;\n}\n\n/**\n * Known model name patterns for validation.\n * These patterns help detect typos and unknown models.\n */\nconst KNOWN_MODEL_PATTERNS = [\n /^gpt-?\\d/i, // gpt-4, gpt-3.5, gpt4, etc.\n /^claude-?\\d/i, // claude-3, claude-2, etc.\n /^gemini-?(\\d|pro|flash)/i, // gemini-2.0, gemini-pro, gemini-flash, etc.\n /^o\\d/i, // OpenAI o1, o3, etc.\n];\n\n/**\n * Check if a model name matches known patterns.\n *\n * @param model - Model name to check\n * @returns True if the model matches a known pattern\n */\nfunction isKnownModelPattern(model: string): boolean {\n const normalized = model.toLowerCase();\n\n // Check if it's a known alias\n if (MODEL_ALIASES[normalized]) {\n return true;\n }\n\n // Check against known patterns\n return KNOWN_MODEL_PATTERNS.some((pattern) => pattern.test(model));\n}\n\n/**\n * Resolves a model name to its full provider:model format.\n *\n * Supports:\n * - Direct aliases: 'gpt5', 'sonnet', 'flash'\n * - Auto-detection: 'gpt-5-nano' → 'openai:gpt-5-nano'\n * - Pass-through: 'openai:gpt-5' → 'openai:gpt-5'\n *\n * Warnings:\n * - Logs a warning when an unknown model name falls back to OpenAI\n * - Use { strict: true } to throw an error instead\n * - Use { silent: true } to suppress warnings\n *\n * @param model - Model name or alias\n * @param options - Resolution options\n * @returns Full provider:model-id string\n *\n * @example\n * ```typescript\n * resolveModel('gpt5') // → 'openai:gpt-5'\n * resolveModel('sonnet') // → 'anthropic:claude-sonnet-4-5'\n * resolveModel('gpt-5-nano') // → 'openai:gpt-5-nano'\n * resolveModel('openai:gpt-5') // → 'openai:gpt-5' (passthrough)\n * resolveModel('claude-3-5-sonnet') // → 'anthropic:claude-3-5-sonnet'\n *\n * // Typo detection\n * resolveModel('gp5') // ⚠️ Warning: Unknown model 'gp5', falling back to 'openai:gp5'\n *\n * // Strict mode (throws on typos)\n * resolveModel('gp5', { strict: true }) // ❌ Error: Unknown model 'gp5'\n * ```\n */\nexport function resolveModel(model: string, options: ResolveModelOptions = {}): string {\n // Already has provider prefix - pass through\n if (model.includes(\":\")) {\n return model;\n }\n\n // Check if it's a known alias\n const normalized = model.toLowerCase();\n if (MODEL_ALIASES[normalized]) {\n return MODEL_ALIASES[normalized];\n }\n\n // Smart detection by model name patterns\n const modelLower = model.toLowerCase();\n\n // OpenAI models start with 'gpt'\n if (modelLower.startsWith(\"gpt\")) {\n return `openai:${model}`;\n }\n\n // Anthropic models start with 'claude'\n if (modelLower.startsWith(\"claude\")) {\n return `anthropic:${model}`;\n }\n\n // Gemini models start with 'gemini'\n if (modelLower.startsWith(\"gemini\")) {\n return `gemini:${model}`;\n }\n\n // OpenAI o-series models (o1, o3, etc.)\n if (modelLower.match(/^o\\d/)) {\n return `openai:${model}`;\n }\n\n // Unknown model: validate and warn/error\n if (!isKnownModelPattern(model)) {\n if (options.strict) {\n throw new Error(\n `Unknown model '${model}'. Did you mean one of: gpt4, sonnet, haiku, flash? ` +\n `Use explicit provider prefix like 'openai:${model}' to bypass this check.`,\n );\n }\n\n if (!options.silent) {\n console.warn(\n `⚠️ Unknown model '${model}', falling back to 'openai:${model}'. ` +\n `This might be a typo. Did you mean: gpt4, gpt5, gpt5-nano, sonnet, haiku, flash? ` +\n `Use { strict: true } to error on unknown models, or { silent: true } to suppress this warning.`,\n );\n }\n }\n\n // Default: assume OpenAI for unknown models\n // This provides a reasonable fallback for most cases\n return `openai:${model}`;\n}\n\n/**\n * Check if a model string is already in provider:model format.\n *\n * @param model - Model string to check\n * @returns True if the model has a provider prefix\n *\n * @example\n * ```typescript\n * hasProviderPrefix('openai:gpt-4o') // → true\n * hasProviderPrefix('gpt4') // → false\n * hasProviderPrefix('claude-3-5-sonnet') // → false\n * ```\n */\nexport function hasProviderPrefix(model: string): boolean {\n return model.includes(\":\");\n}\n\n/**\n * Extract the provider from a full model string.\n *\n * @param model - Full model string (provider:model-id)\n * @returns Provider name, or undefined if no prefix\n *\n * @example\n * ```typescript\n * getProvider('openai:gpt-4o') // → 'openai'\n * getProvider('anthropic:claude') // → 'anthropic'\n * getProvider('gpt4') // → undefined\n * ```\n */\nexport function getProvider(model: string): string | undefined {\n const separatorIndex = model.indexOf(\":\");\n if (separatorIndex === -1) {\n return undefined;\n }\n return model.slice(0, separatorIndex);\n}\n\n/**\n * Extract the model ID from a full model string.\n *\n * @param model - Full model string (provider:model-id)\n * @returns Model ID, or the original string if no prefix\n *\n * @example\n * ```typescript\n * getModelId('openai:gpt-4o') // → 'gpt-4o'\n * getModelId('anthropic:claude') // → 'claude'\n * getModelId('gpt4') // → 'gpt4'\n * ```\n */\nexport function getModelId(model: string): string {\n const separatorIndex = model.indexOf(\":\");\n if (separatorIndex === -1) {\n return model;\n }\n return model.slice(separatorIndex + 1);\n}\n","import type { ZodTypeAny } from \"zod\";\nimport * as z from \"zod\";\n\n/**\n * Validates that a Zod schema doesn't contain z.unknown() which produces\n * incomplete JSON schemas without type information.\n *\n * @param schema - The Zod schema to validate\n * @param gadgetName - Name of the gadget (for error messages)\n * @throws Error if z.unknown() is detected with helpful suggestions\n */\nexport function validateGadgetSchema(schema: ZodTypeAny, gadgetName: string): void {\n let jsonSchema;\n try {\n jsonSchema = z.toJSONSchema(schema, { target: \"draft-7\" });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Gadget \"${gadgetName}\" has a schema that cannot be serialized to JSON Schema.\\n` +\n `This usually happens with unsupported patterns like:\\n` +\n `- z.record() - use z.object({}).passthrough() instead\\n` +\n `- Complex transforms or custom refinements\\n` +\n `- Circular references\\n` +\n `\\n` +\n `Original error: ${errorMessage}\\n` +\n `\\n` +\n `Only use schema patterns that Zod v4's native toJSONSchema() supports.`,\n );\n }\n const issues = findUnknownTypes(jsonSchema);\n\n if (issues.length > 0) {\n const fieldList = issues.join(\", \");\n throw new Error(\n `Gadget \"${gadgetName}\" uses z.unknown() which produces incomplete schemas.\\n` +\n `Problematic fields: ${fieldList}\\n` +\n `\\n` +\n `z.unknown() doesn't generate type information in JSON Schema, making it unclear\\n` +\n `to the LLM what data structure to provide.\\n` +\n `\\n` +\n `Suggestions:\\n` +\n `- Use z.object({}).passthrough() for flexible objects\\n` +\n `- Use z.record(z.string()) for key-value objects with string values\\n` +\n `- Define specific structure if possible\\n` +\n `\\n` +\n `Example fixes:\\n` +\n ` // ❌ Bad\\n` +\n ` content: z.unknown()\\n` +\n `\\n` +\n ` // ✅ Good\\n` +\n ` content: z.object({}).passthrough() // for flexible objects\\n` +\n ` content: z.record(z.string()) // for key-value objects\\n` +\n ` content: z.array(z.string()) // for arrays of strings\\n`,\n );\n }\n}\n\n/**\n * Recursively searches a JSON Schema for properties without type information,\n * which indicates z.unknown() usage.\n *\n * @param schema - JSON Schema object to search\n * @param path - Current path in schema (for error reporting)\n * @returns Array of problematic field paths\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction findUnknownTypes(schema: any, path: string[] = []): string[] {\n const issues: string[] = [];\n\n if (!schema || typeof schema !== \"object\") {\n return issues;\n }\n\n // Check if we're in a definitions block\n if (schema.definitions) {\n for (const defSchema of Object.values(schema.definitions)) {\n issues.push(...findUnknownTypes(defSchema, []));\n }\n }\n\n // Check properties of objects\n if (schema.properties) {\n for (const [propName, propSchema] of Object.entries(schema.properties)) {\n const propPath = [...path, propName];\n\n // Check if this property has no type information\n if (hasNoType(propSchema)) {\n issues.push(propPath.join(\".\") || propName);\n }\n\n // Recursively check nested properties\n issues.push(...findUnknownTypes(propSchema, propPath));\n }\n }\n\n // Check array items\n if (schema.items) {\n const itemPath = [...path, \"[]\"];\n if (hasNoType(schema.items)) {\n issues.push(itemPath.join(\".\"));\n }\n issues.push(...findUnknownTypes(schema.items, itemPath));\n }\n\n // Check anyOf/oneOf/allOf unions\n if (schema.anyOf) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema.anyOf.forEach((subSchema: any, index: number) => {\n issues.push(...findUnknownTypes(subSchema, [...path, `anyOf[${index}]`]));\n });\n }\n\n if (schema.oneOf) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema.oneOf.forEach((subSchema: any, index: number) => {\n issues.push(...findUnknownTypes(subSchema, [...path, `oneOf[${index}]`]));\n });\n }\n\n if (schema.allOf) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema.allOf.forEach((subSchema: any, index: number) => {\n issues.push(...findUnknownTypes(subSchema, [...path, `allOf[${index}]`]));\n });\n }\n\n return issues;\n}\n\n/**\n * Checks if a schema property has no type information.\n * This indicates z.unknown() usage.\n *\n * A property has \"no type\" if it:\n * - Is an object\n * - Has no \"type\" field\n * - Has no \"$ref\" (reference to definition)\n * - Has no \"anyOf\", \"oneOf\", or \"allOf\" (union types)\n * - Has only \"description\" or is empty\n *\n * @param prop - Property schema to check\n * @returns true if property has no type information\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction hasNoType(prop: any): boolean {\n if (!prop || typeof prop !== \"object\") {\n return false;\n }\n\n const hasType = prop.type !== undefined;\n const hasRef = prop.$ref !== undefined;\n const hasUnion = prop.anyOf !== undefined || prop.oneOf !== undefined || prop.allOf !== undefined;\n\n // If it has any type information, it's fine\n if (hasType || hasRef || hasUnion) {\n return false;\n }\n\n // Check if it only has description and/or other non-type metadata\n const keys = Object.keys(prop);\n const metadataKeys = [\"description\", \"title\", \"default\", \"examples\"];\n const hasOnlyMetadata = keys.every((key) => metadataKeys.includes(key));\n\n // If it only has metadata or is empty (besides metadata), it's missing type info\n return hasOnlyMetadata || keys.length === 0;\n}\n","import type { AbstractGadget } from \"./gadget.js\";\nimport { validateGadgetSchema } from \"./schema-validator.js\";\n\n// Type for gadget constructor\nexport type GadgetClass = new (...args: unknown[]) => AbstractGadget;\n\n// Type for gadget or gadget class\nexport type GadgetOrClass = AbstractGadget | GadgetClass;\n\nexport class GadgetRegistry {\n private readonly gadgets = new Map<string, AbstractGadget>();\n\n /**\n * Creates a registry from an array of gadget classes or instances,\n * or an object mapping names to gadgets.\n *\n * @param gadgets - Array of gadgets/classes or object with custom names\n * @returns New GadgetRegistry with all gadgets registered\n *\n * @example\n * ```typescript\n * // From array of classes\n * const registry = GadgetRegistry.from([Calculator, Weather]);\n *\n * // From array of instances\n * const registry = GadgetRegistry.from([new Calculator(), new Weather()]);\n *\n * // From object with custom names\n * const registry = GadgetRegistry.from({\n * calc: Calculator,\n * weather: new Weather({ apiKey: \"...\" })\n * });\n * ```\n */\n static from(gadgets: GadgetOrClass[] | Record<string, GadgetOrClass>): GadgetRegistry {\n const registry = new GadgetRegistry();\n\n if (Array.isArray(gadgets)) {\n // Array of gadgets or classes\n registry.registerMany(gadgets);\n } else {\n // Object with custom names\n for (const [name, gadget] of Object.entries(gadgets)) {\n const instance = typeof gadget === \"function\" ? new gadget() : gadget;\n registry.register(name, instance);\n }\n }\n\n return registry;\n }\n\n /**\n * Registers multiple gadgets at once from an array.\n *\n * @param gadgets - Array of gadget instances or classes\n * @returns This registry for chaining\n *\n * @example\n * ```typescript\n * registry.registerMany([Calculator, Weather, Email]);\n * registry.registerMany([new Calculator(), new Weather()]);\n * ```\n */\n registerMany(gadgets: GadgetOrClass[]): this {\n for (const gadget of gadgets) {\n const instance = typeof gadget === \"function\" ? new gadget() : gadget;\n this.registerByClass(instance);\n }\n return this;\n }\n\n // Register a gadget by name\n register(name: string, gadget: AbstractGadget): void {\n const normalizedName = name.toLowerCase();\n if (this.gadgets.has(normalizedName)) {\n throw new Error(`Gadget '${name}' is already registered`);\n }\n\n // Validate schema if present\n if (gadget.parameterSchema) {\n validateGadgetSchema(gadget.parameterSchema, name);\n }\n\n this.gadgets.set(normalizedName, gadget);\n }\n\n // Register a gadget using its name property or class name\n registerByClass(gadget: AbstractGadget): void {\n const name = gadget.name ?? gadget.constructor.name;\n this.register(name, gadget);\n }\n\n // Get gadget by name (case-insensitive)\n get(name: string): AbstractGadget | undefined {\n return this.gadgets.get(name.toLowerCase());\n }\n\n // Check if gadget exists (case-insensitive)\n has(name: string): boolean {\n return this.gadgets.has(name.toLowerCase());\n }\n\n // Get all registered gadget names\n getNames(): string[] {\n return Array.from(this.gadgets.keys());\n }\n\n // Get all gadgets for instruction generation\n getAll(): AbstractGadget[] {\n return Array.from(this.gadgets.values());\n }\n\n // Unregister gadget (useful for testing, case-insensitive)\n unregister(name: string): boolean {\n return this.gadgets.delete(name.toLowerCase());\n }\n\n // Clear all gadgets (useful for testing)\n clear(): void {\n this.gadgets.clear();\n }\n}\n","/**\n * First-class Execution Tree model for nested subagent support.\n *\n * The ExecutionTree is THE single source of truth for execution state.\n * All nodes (including nested subagent nodes) live in one tree.\n * Events are projections of tree changes.\n *\n * @module core/execution-tree\n */\n\nimport type { GadgetMediaOutput } from \"../gadgets/types.js\";\nimport type { LLMMessage } from \"./messages.js\";\nimport type { TokenUsage } from \"./options.js\";\n\n// =============================================================================\n// Node Identifiers\n// =============================================================================\n\n/**\n * Unique identifier for any execution node.\n * Format examples: \"llm_1\", \"gadget_abc123\", \"llm_1_2\" (nested)\n */\nexport type NodeId = string;\n\n/**\n * Node type discriminator.\n */\nexport type ExecutionNodeType = \"llm_call\" | \"gadget\";\n\n// =============================================================================\n// Execution Node Types\n// =============================================================================\n\n/**\n * Base properties shared by all execution nodes.\n */\ninterface BaseExecutionNode {\n /** Unique identifier for this node */\n id: NodeId;\n /** Node type discriminator */\n type: ExecutionNodeType;\n /** Parent node ID (null for root nodes) */\n parentId: NodeId | null;\n /** Nesting depth (0 = root, 1 = child of gadget, etc.) */\n depth: number;\n /** Path from root to this node: [\"llm_1\", \"gadget_abc\", \"llm_1_1\"] */\n path: NodeId[];\n /** Creation timestamp */\n createdAt: number;\n /** Completion timestamp (null if in progress) */\n completedAt: number | null;\n}\n\n/**\n * LLM call execution node.\n */\nexport interface LLMCallNode extends BaseExecutionNode {\n type: \"llm_call\";\n /** Iteration number within the agent loop (1-indexed for display) */\n iteration: number;\n /** Model identifier */\n model: string;\n /** Request messages (set when call starts) */\n request?: LLMMessage[];\n /** Accumulated response text */\n response: string;\n /** Token usage (set on completion) */\n usage?: TokenUsage;\n /** Finish reason from LLM */\n finishReason?: string | null;\n /** Cost in USD */\n cost?: number;\n /** Child node IDs (gadgets spawned by this LLM call) */\n children: NodeId[];\n}\n\n/**\n * Gadget execution state.\n */\nexport type GadgetState = \"pending\" | \"running\" | \"completed\" | \"failed\" | \"skipped\";\n\n/**\n * Gadget execution node.\n */\nexport interface GadgetNode extends BaseExecutionNode {\n type: \"gadget\";\n /** Invocation ID (LLM-generated or auto) */\n invocationId: string;\n /** Gadget name */\n name: string;\n /** Parameters passed to the gadget */\n parameters: Record<string, unknown>;\n /** Dependencies (other invocation IDs this gadget waits for) */\n dependencies: string[];\n /** Execution state */\n state: GadgetState;\n /** Result string (if completed successfully) */\n result?: string;\n /** Error message (if failed or skipped) */\n error?: string;\n /** Failed dependency invocation ID (if skipped due to dependency) */\n failedDependency?: string;\n /** Execution time in milliseconds */\n executionTimeMs?: number;\n /** Cost in USD */\n cost?: number;\n /** Media outputs from this gadget */\n media?: GadgetMediaOutput[];\n /** Child node IDs (nested LLM calls for subagent gadgets) */\n children: NodeId[];\n /** Whether this gadget is a subagent (has nested LLM calls) */\n isSubagent: boolean;\n}\n\n/**\n * Union of all execution node types.\n */\nexport type ExecutionNode = LLMCallNode | GadgetNode;\n\n// =============================================================================\n// Node Creation Parameters\n// =============================================================================\n\nexport interface AddLLMCallParams {\n /** Iteration number (1-indexed) */\n iteration: number;\n /** Model identifier */\n model: string;\n /** Request messages */\n request?: LLMMessage[];\n /** Parent node ID (for subagent LLM calls) */\n parentId?: NodeId | null;\n}\n\nexport interface AddGadgetParams {\n /** Invocation ID */\n invocationId: string;\n /** Gadget name */\n name: string;\n /** Parameters */\n parameters: Record<string, unknown>;\n /** Dependencies */\n dependencies?: string[];\n /** Parent LLM call node ID */\n parentId?: NodeId | null;\n}\n\nexport interface CompleteLLMCallParams {\n /** Accumulated response text */\n response?: string;\n /** Token usage */\n usage?: TokenUsage;\n /** Finish reason */\n finishReason?: string | null;\n /** Cost in USD */\n cost?: number;\n}\n\nexport interface CompleteGadgetParams {\n /** Result string */\n result?: string;\n /** Error message */\n error?: string;\n /** Failed dependency (for skipped gadgets) */\n failedDependency?: string;\n /** Execution time in ms */\n executionTimeMs?: number;\n /** Cost in USD */\n cost?: number;\n /** Media outputs */\n media?: GadgetMediaOutput[];\n}\n\n// =============================================================================\n// Event Types (imported from execution-events.ts)\n// =============================================================================\n\n// Forward declaration - actual types in execution-events.ts\nimport type { ExecutionEvent, ExecutionEventType } from \"./execution-events.js\";\n\nexport type { ExecutionEvent, ExecutionEventType };\n\n// =============================================================================\n// Event Listener Types\n// =============================================================================\n\n/** Event listener function type */\ntype EventListener = (event: ExecutionEvent) => void;\n\n// =============================================================================\n// ExecutionTree Class\n// =============================================================================\n\n/**\n * The Execution Tree - single source of truth for all execution state.\n *\n * Features:\n * - Stores all nodes (LLM calls, gadgets) in a hierarchical structure\n * - Emits events on mutations\n * - Provides query methods for aggregation (costs, media, descendants)\n * - Supports single shared tree model for nested subagents\n *\n * @example\n * ```typescript\n * const tree = new ExecutionTree();\n *\n * // Add root LLM call\n * const llmNode = tree.addLLMCall({ iteration: 1, model: \"sonnet\" });\n *\n * // Add gadget under the LLM call\n * const gadgetNode = tree.addGadget({\n * invocationId: \"gc_1\",\n * name: \"ReadFile\",\n * parameters: { path: \"/foo.txt\" },\n * parentId: llmNode.id,\n * });\n *\n * // Complete the gadget\n * tree.completeGadget(gadgetNode.id, { result: \"file contents\", executionTimeMs: 50 });\n *\n * // Query total cost\n * console.log(tree.getTotalCost());\n * ```\n */\nexport class ExecutionTree {\n private nodes = new Map<NodeId, ExecutionNode>();\n private rootIds: NodeId[] = [];\n private eventListeners = new Map<ExecutionEventType, Set<EventListener>>();\n private eventIdCounter = 0;\n private invocationIdToNodeId = new Map<string, NodeId>();\n\n // For async event streaming\n private eventQueue: ExecutionEvent[] = [];\n private eventWaiters: Array<(event: ExecutionEvent) => void> = [];\n private isCompleted = false;\n\n /**\n * Base depth for all nodes in this tree.\n * Used when this tree is a subagent's view into a parent tree.\n */\n public readonly baseDepth: number;\n\n /**\n * Parent node ID for subagent trees.\n * All root nodes in this tree will have this as their parentId.\n */\n public readonly parentNodeId: NodeId | null;\n\n constructor(options?: { baseDepth?: number; parentNodeId?: NodeId | null }) {\n this.baseDepth = options?.baseDepth ?? 0;\n this.parentNodeId = options?.parentNodeId ?? null;\n }\n\n // ===========================================================================\n // Node ID Generation\n // ===========================================================================\n\n private generateLLMCallId(iteration: number, parentId: NodeId | null): NodeId {\n if (parentId) {\n // Subagent LLM call: include parent info for uniqueness\n return `llm_${parentId}_${iteration}`;\n }\n return `llm_${iteration}`;\n }\n\n private gadgetIdCounter = 0;\n private generateGadgetId(invocationId: string): NodeId {\n return `gadget_${invocationId}_${++this.gadgetIdCounter}`;\n }\n\n // ===========================================================================\n // Event Emission\n // ===========================================================================\n\n private emit(event: ExecutionEvent): void {\n // Notify sync listeners\n const listeners = this.eventListeners.get(event.type);\n if (listeners) {\n for (const listener of listeners) {\n try {\n listener(event);\n } catch (error) {\n console.error(`Error in event listener for ${event.type}:`, error);\n }\n }\n }\n\n // Also emit to \"all\" listeners\n const allListeners = this.eventListeners.get(\"*\");\n if (allListeners) {\n for (const listener of allListeners) {\n try {\n listener(event);\n } catch (error) {\n console.error(\"Error in wildcard event listener:\", error);\n }\n }\n }\n\n // Push to async queue\n if (this.eventWaiters.length > 0) {\n const waiter = this.eventWaiters.shift();\n if (waiter) waiter(event);\n } else {\n this.eventQueue.push(event);\n }\n }\n\n private createBaseEventProps(node: ExecutionNode): {\n eventId: number;\n timestamp: number;\n nodeId: NodeId;\n parentId: NodeId | null;\n depth: number;\n path: NodeId[];\n } {\n return {\n eventId: ++this.eventIdCounter,\n timestamp: Date.now(),\n nodeId: node.id,\n parentId: node.parentId,\n depth: node.depth,\n path: node.path,\n };\n }\n\n // ===========================================================================\n // Node Creation\n // ===========================================================================\n\n /**\n * Add a new LLM call node to the tree.\n */\n addLLMCall(params: AddLLMCallParams): LLMCallNode {\n const parentId = params.parentId ?? this.parentNodeId;\n const parent = parentId ? this.nodes.get(parentId) : null;\n\n const depth = parent ? parent.depth + 1 : this.baseDepth;\n const path = parent ? [...parent.path] : [];\n\n const id = this.generateLLMCallId(params.iteration, parentId);\n path.push(id);\n\n const node: LLMCallNode = {\n id,\n type: \"llm_call\",\n parentId,\n depth,\n path,\n createdAt: Date.now(),\n completedAt: null,\n iteration: params.iteration,\n model: params.model,\n request: params.request,\n response: \"\",\n children: [],\n };\n\n this.nodes.set(id, node);\n\n if (!parentId) {\n this.rootIds.push(id);\n } else if (parent) {\n parent.children.push(id);\n }\n\n this.emit({\n type: \"llm_call_start\",\n ...this.createBaseEventProps(node),\n iteration: node.iteration,\n model: node.model,\n request: node.request,\n });\n\n return node;\n }\n\n /**\n * Add text to an LLM call's response (for streaming).\n */\n appendLLMResponse(nodeId: NodeId, chunk: string): void {\n const node = this.nodes.get(nodeId);\n if (!node || node.type !== \"llm_call\") {\n throw new Error(`LLM call node not found: ${nodeId}`);\n }\n\n (node as LLMCallNode).response += chunk;\n\n this.emit({\n type: \"llm_call_stream\",\n ...this.createBaseEventProps(node),\n chunk,\n });\n }\n\n /**\n * Complete an LLM call node.\n */\n completeLLMCall(nodeId: NodeId, params: CompleteLLMCallParams): void {\n const node = this.nodes.get(nodeId);\n if (!node || node.type !== \"llm_call\") {\n throw new Error(`LLM call node not found: ${nodeId}`);\n }\n\n const llmNode = node as LLMCallNode;\n llmNode.completedAt = Date.now();\n if (params.response !== undefined) llmNode.response = params.response;\n if (params.usage) llmNode.usage = params.usage;\n if (params.finishReason !== undefined) llmNode.finishReason = params.finishReason;\n if (params.cost !== undefined) llmNode.cost = params.cost;\n\n this.emit({\n type: \"llm_call_complete\",\n ...this.createBaseEventProps(node),\n response: llmNode.response,\n usage: llmNode.usage,\n finishReason: llmNode.finishReason,\n cost: llmNode.cost,\n });\n }\n\n /**\n * Mark an LLM call as failed.\n */\n failLLMCall(nodeId: NodeId, error: Error, recovered: boolean): void {\n const node = this.nodes.get(nodeId);\n if (!node || node.type !== \"llm_call\") {\n throw new Error(`LLM call node not found: ${nodeId}`);\n }\n\n const llmNode = node as LLMCallNode;\n llmNode.completedAt = Date.now();\n\n this.emit({\n type: \"llm_call_error\",\n ...this.createBaseEventProps(node),\n error,\n recovered,\n });\n }\n\n /**\n * Add a new gadget node to the tree.\n */\n addGadget(params: AddGadgetParams): GadgetNode {\n const parentId = params.parentId ?? this.getCurrentLLMCallId() ?? this.parentNodeId;\n const parent = parentId ? this.nodes.get(parentId) : null;\n\n const depth = parent ? parent.depth + 1 : this.baseDepth;\n const path = parent ? [...parent.path] : [];\n\n const id = this.generateGadgetId(params.invocationId);\n path.push(id);\n\n const node: GadgetNode = {\n id,\n type: \"gadget\",\n parentId,\n depth,\n path,\n createdAt: Date.now(),\n completedAt: null,\n invocationId: params.invocationId,\n name: params.name,\n parameters: params.parameters,\n dependencies: params.dependencies ?? [],\n state: \"pending\",\n children: [],\n isSubagent: false,\n };\n\n this.nodes.set(id, node);\n this.invocationIdToNodeId.set(params.invocationId, id);\n\n if (parent) {\n parent.children.push(id);\n }\n\n this.emit({\n type: \"gadget_call\",\n ...this.createBaseEventProps(node),\n invocationId: node.invocationId,\n name: node.name,\n parameters: node.parameters,\n dependencies: node.dependencies,\n });\n\n return node;\n }\n\n /**\n * Mark a gadget as started (running).\n */\n startGadget(nodeId: NodeId): void {\n const node = this.nodes.get(nodeId);\n if (!node || node.type !== \"gadget\") {\n throw new Error(`Gadget node not found: ${nodeId}`);\n }\n\n const gadgetNode = node as GadgetNode;\n gadgetNode.state = \"running\";\n\n this.emit({\n type: \"gadget_start\",\n ...this.createBaseEventProps(node),\n invocationId: gadgetNode.invocationId,\n name: gadgetNode.name,\n });\n }\n\n /**\n * Complete a gadget node successfully.\n */\n completeGadget(nodeId: NodeId, params: CompleteGadgetParams): void {\n const node = this.nodes.get(nodeId);\n if (!node || node.type !== \"gadget\") {\n throw new Error(`Gadget node not found: ${nodeId}`);\n }\n\n const gadgetNode = node as GadgetNode;\n gadgetNode.completedAt = Date.now();\n gadgetNode.state = params.error ? \"failed\" : \"completed\";\n if (params.result !== undefined) gadgetNode.result = params.result;\n if (params.error) gadgetNode.error = params.error;\n if (params.executionTimeMs !== undefined) gadgetNode.executionTimeMs = params.executionTimeMs;\n if (params.cost !== undefined) gadgetNode.cost = params.cost;\n if (params.media) gadgetNode.media = params.media;\n\n // Mark as subagent if it has child LLM calls\n gadgetNode.isSubagent = gadgetNode.children.some((childId) => {\n const child = this.nodes.get(childId);\n return child?.type === \"llm_call\";\n });\n\n if (params.error) {\n this.emit({\n type: \"gadget_error\",\n ...this.createBaseEventProps(node),\n invocationId: gadgetNode.invocationId,\n name: gadgetNode.name,\n error: params.error,\n executionTimeMs: params.executionTimeMs ?? 0,\n });\n } else {\n this.emit({\n type: \"gadget_complete\",\n ...this.createBaseEventProps(node),\n invocationId: gadgetNode.invocationId,\n name: gadgetNode.name,\n result: params.result ?? \"\",\n executionTimeMs: params.executionTimeMs ?? 0,\n cost: params.cost,\n media: params.media,\n });\n }\n }\n\n /**\n * Mark a gadget as skipped due to dependency failure.\n */\n skipGadget(\n nodeId: NodeId,\n failedDependency: string,\n failedDependencyError: string,\n reason: \"dependency_failed\" | \"controller_skip\",\n ): void {\n const node = this.nodes.get(nodeId);\n if (!node || node.type !== \"gadget\") {\n throw new Error(`Gadget node not found: ${nodeId}`);\n }\n\n const gadgetNode = node as GadgetNode;\n gadgetNode.completedAt = Date.now();\n gadgetNode.state = \"skipped\";\n gadgetNode.failedDependency = failedDependency;\n gadgetNode.error = failedDependencyError;\n\n // Build error message combining reason and dependency error\n const error =\n reason === \"controller_skip\"\n ? \"Skipped by controller\"\n : `Dependency ${failedDependency} failed: ${failedDependencyError}`;\n\n this.emit({\n type: \"gadget_skipped\",\n ...this.createBaseEventProps(node),\n invocationId: gadgetNode.invocationId,\n name: gadgetNode.name,\n reason,\n error,\n failedDependency,\n failedDependencyError,\n });\n }\n\n // ===========================================================================\n // Text Events (pure notifications, not tree nodes)\n // ===========================================================================\n\n /**\n * Emit a text event (notification only, not stored in tree).\n */\n emitText(content: string, llmCallNodeId: NodeId): void {\n const node = this.nodes.get(llmCallNodeId);\n if (!node) {\n throw new Error(`Node not found: ${llmCallNodeId}`);\n }\n\n this.emit({\n type: \"text\",\n ...this.createBaseEventProps(node),\n content,\n });\n }\n\n // ===========================================================================\n // Query Methods\n // ===========================================================================\n\n /**\n * Get a node by ID.\n */\n getNode(id: NodeId): ExecutionNode | undefined {\n return this.nodes.get(id);\n }\n\n /**\n * Get a gadget node by invocation ID.\n */\n getNodeByInvocationId(invocationId: string): GadgetNode | undefined {\n const nodeId = this.invocationIdToNodeId.get(invocationId);\n if (!nodeId) return undefined;\n const node = this.nodes.get(nodeId);\n return node?.type === \"gadget\" ? (node as GadgetNode) : undefined;\n }\n\n /**\n * Get all root nodes (depth 0 for this tree).\n */\n getRoots(): ExecutionNode[] {\n return this.rootIds\n .map((id) => this.nodes.get(id))\n .filter((node): node is ExecutionNode => node !== undefined);\n }\n\n /**\n * Get children of a node.\n */\n getChildren(id: NodeId): ExecutionNode[] {\n const node = this.nodes.get(id);\n if (!node) return [];\n return node.children\n .map((childId) => this.nodes.get(childId))\n .filter((child): child is ExecutionNode => child !== undefined);\n }\n\n /**\n * Get ancestors of a node (from root to parent).\n */\n getAncestors(id: NodeId): ExecutionNode[] {\n const node = this.nodes.get(id);\n if (!node) return [];\n\n const ancestors: ExecutionNode[] = [];\n let currentId = node.parentId;\n while (currentId) {\n const ancestor = this.nodes.get(currentId);\n if (ancestor) {\n ancestors.unshift(ancestor);\n currentId = ancestor.parentId;\n } else {\n break;\n }\n }\n return ancestors;\n }\n\n /**\n * Get all descendants of a node.\n */\n getDescendants(id: NodeId, type?: ExecutionNodeType): ExecutionNode[] {\n const node = this.nodes.get(id);\n if (!node) return [];\n\n const descendants: ExecutionNode[] = [];\n const stack = [...node.children];\n\n while (stack.length > 0) {\n const childId = stack.pop()!;\n const child = this.nodes.get(childId);\n if (child) {\n if (!type || child.type === type) {\n descendants.push(child);\n }\n stack.push(...child.children);\n }\n }\n\n return descendants;\n }\n\n /**\n * Get the current (most recent incomplete) LLM call node.\n */\n getCurrentLLMCallId(): NodeId | undefined {\n // Find the most recent root LLM call that's not complete\n for (let i = this.rootIds.length - 1; i >= 0; i--) {\n const node = this.nodes.get(this.rootIds[i]);\n if (node?.type === \"llm_call\" && !node.completedAt) {\n return node.id;\n }\n }\n return undefined;\n }\n\n // ===========================================================================\n // Aggregation Methods (for subagent support)\n // ===========================================================================\n\n /**\n * Get total cost for entire tree.\n */\n getTotalCost(): number {\n let total = 0;\n for (const node of this.nodes.values()) {\n if (node.type === \"llm_call\" && (node as LLMCallNode).cost) {\n total += (node as LLMCallNode).cost!;\n } else if (node.type === \"gadget\" && (node as GadgetNode).cost) {\n total += (node as GadgetNode).cost!;\n }\n }\n return total;\n }\n\n /**\n * Get total cost for a subtree (node and all descendants).\n */\n getSubtreeCost(nodeId: NodeId): number {\n const node = this.nodes.get(nodeId);\n if (!node) return 0;\n\n let total = 0;\n\n // Add node's own cost\n if (node.type === \"llm_call\" && (node as LLMCallNode).cost) {\n total += (node as LLMCallNode).cost!;\n } else if (node.type === \"gadget\" && (node as GadgetNode).cost) {\n total += (node as GadgetNode).cost!;\n }\n\n // Add descendants' costs\n for (const descendant of this.getDescendants(nodeId)) {\n if (descendant.type === \"llm_call\" && (descendant as LLMCallNode).cost) {\n total += (descendant as LLMCallNode).cost!;\n } else if (descendant.type === \"gadget\" && (descendant as GadgetNode).cost) {\n total += (descendant as GadgetNode).cost!;\n }\n }\n\n return total;\n }\n\n /**\n * Get token usage for entire tree.\n */\n getTotalTokens(): { input: number; output: number; cached: number } {\n let input = 0;\n let output = 0;\n let cached = 0;\n\n for (const node of this.nodes.values()) {\n if (node.type === \"llm_call\") {\n const llmNode = node as LLMCallNode;\n if (llmNode.usage) {\n input += llmNode.usage.inputTokens;\n output += llmNode.usage.outputTokens;\n cached += llmNode.usage.cachedInputTokens ?? 0;\n }\n }\n }\n\n return { input, output, cached };\n }\n\n /**\n * Get token usage for a subtree.\n */\n getSubtreeTokens(nodeId: NodeId): { input: number; output: number; cached: number } {\n const node = this.nodes.get(nodeId);\n if (!node) return { input: 0, output: 0, cached: 0 };\n\n let input = 0;\n let output = 0;\n let cached = 0;\n\n const nodesToProcess = [node, ...this.getDescendants(nodeId)];\n\n for (const n of nodesToProcess) {\n if (n.type === \"llm_call\") {\n const llmNode = n as LLMCallNode;\n if (llmNode.usage) {\n input += llmNode.usage.inputTokens;\n output += llmNode.usage.outputTokens;\n cached += llmNode.usage.cachedInputTokens ?? 0;\n }\n }\n }\n\n return { input, output, cached };\n }\n\n /**\n * Collect all media from a subtree.\n */\n getSubtreeMedia(nodeId: NodeId): GadgetMediaOutput[] {\n const node = this.nodes.get(nodeId);\n if (!node) return [];\n\n const media: GadgetMediaOutput[] = [];\n const nodesToProcess: ExecutionNode[] = node.type === \"gadget\" ? [node] : [];\n nodesToProcess.push(...this.getDescendants(nodeId, \"gadget\"));\n\n for (const n of nodesToProcess) {\n if (n.type === \"gadget\") {\n const gadgetNode = n as GadgetNode;\n if (gadgetNode.media) {\n media.push(...gadgetNode.media);\n }\n }\n }\n\n return media;\n }\n\n /**\n * Check if a subtree is complete (all nodes finished).\n */\n isSubtreeComplete(nodeId: NodeId): boolean {\n const node = this.nodes.get(nodeId);\n if (!node) return true;\n if (!node.completedAt) return false;\n\n for (const descendant of this.getDescendants(nodeId)) {\n if (!descendant.completedAt) return false;\n }\n\n return true;\n }\n\n /**\n * Get node counts.\n */\n getNodeCount(): { llmCalls: number; gadgets: number } {\n let llmCalls = 0;\n let gadgets = 0;\n\n for (const node of this.nodes.values()) {\n if (node.type === \"llm_call\") llmCalls++;\n else if (node.type === \"gadget\") gadgets++;\n }\n\n return { llmCalls, gadgets };\n }\n\n // ===========================================================================\n // Event Subscription\n // ===========================================================================\n\n /**\n * Subscribe to events of a specific type.\n * Returns unsubscribe function.\n *\n * @param type - Event type to subscribe to (use \"*\" for all events)\n * @param listener - Callback function that receives matching events\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = tree.on(\"gadget_complete\", (event) => {\n * if (event.type === \"gadget_complete\") {\n * console.log(`Gadget ${event.name} completed`);\n * }\n * });\n * ```\n */\n on(type: ExecutionEventType, listener: EventListener): () => void {\n if (!this.eventListeners.has(type)) {\n this.eventListeners.set(type, new Set());\n }\n const listeners = this.eventListeners.get(type)!;\n listeners.add(listener);\n\n return () => {\n listeners.delete(listener);\n };\n }\n\n /**\n * Subscribe to all events.\n */\n onAll(listener: EventListener): () => void {\n return this.on(\"*\", listener);\n }\n\n /**\n * Get async iterable of all events.\n * Events are yielded as they occur.\n */\n async *events(): AsyncGenerator<ExecutionEvent> {\n while (!this.isCompleted) {\n // Drain queue first\n while (this.eventQueue.length > 0) {\n yield this.eventQueue.shift()!;\n }\n\n if (this.isCompleted) break;\n\n // Wait for next event\n const event = await new Promise<ExecutionEvent>((resolve) => {\n // Check queue again in case events arrived while setting up\n if (this.eventQueue.length > 0) {\n resolve(this.eventQueue.shift()!);\n } else {\n this.eventWaiters.push(resolve);\n }\n });\n\n yield event;\n }\n\n // Drain remaining events\n while (this.eventQueue.length > 0) {\n yield this.eventQueue.shift()!;\n }\n }\n\n /**\n * Mark the tree as complete (no more events will be emitted).\n */\n complete(): void {\n this.isCompleted = true;\n // Wake up any waiters with a dummy event that signals completion\n for (const waiter of this.eventWaiters) {\n // Push a completion marker so waiters can exit\n }\n this.eventWaiters = [];\n }\n\n /**\n * Check if the tree is complete.\n */\n isComplete(): boolean {\n return this.isCompleted;\n }\n}\n","/**\n * Context provided to prompt template functions for rendering dynamic content.\n */\nexport interface PromptContext {\n /** Custom gadget start prefix */\n startPrefix: string;\n /** Custom gadget end prefix */\n endPrefix: string;\n /** Custom argument prefix for block format */\n argPrefix: string;\n /** Number of gadgets being registered */\n gadgetCount: number;\n /** Names of all gadgets */\n gadgetNames: string[];\n}\n\n/**\n * Context provided to hint template functions for rendering dynamic hints.\n */\nexport interface HintContext {\n /** Current iteration (1-based for readability) */\n iteration: number;\n /** Maximum iterations allowed */\n maxIterations: number;\n /** Iterations remaining (maxIterations - iteration) */\n remaining: number;\n /** Number of gadget calls in the current response */\n gadgetCallCount?: number;\n}\n\n/**\n * Template that can be either a static string or a function that renders based on context.\n */\nexport type PromptTemplate = string | ((context: PromptContext) => string);\n\n/**\n * Template for hints that can be either a static string or a function that renders based on hint context.\n */\nexport type HintTemplate = string | ((context: HintContext) => string);\n\n/**\n * Configuration for customizing all prompts used internally by llmist.\n *\n * Each field can be either a string (static text) or a function that receives\n * context and returns a string (for dynamic content).\n *\n * @example\n * ```typescript\n * const customConfig: PromptTemplateConfig = {\n * mainInstruction: \"USE ONLY THE GADGET MARKERS BELOW:\",\n * criticalUsage: \"Important: Follow the exact format shown.\",\n * rules: (ctx) => [\n * \"Always use the markers to invoke gadgets\",\n * \"Never use function calling\",\n * `You have ${ctx.gadgetCount} gadgets available`\n * ]\n * };\n * ```\n */\nexport interface PromptTemplateConfig {\n /**\n * Main instruction block that appears at the start of the gadget system prompt.\n * Default emphasizes using text markers instead of function calling.\n */\n mainInstruction?: PromptTemplate;\n\n /**\n * Critical usage instruction that appears in the usage section.\n * Default emphasizes the exact format requirement.\n */\n criticalUsage?: PromptTemplate;\n\n /**\n * Format description for the block parameter format.\n * Default uses the configured argPrefix dynamically.\n */\n formatDescription?: PromptTemplate;\n\n /**\n * Rules that appear in the rules section.\n * Can be an array of strings or a function that returns an array.\n * Default includes rules about not using function calling.\n */\n rules?: PromptTemplate | string[] | ((context: PromptContext) => string[]);\n\n /**\n * Custom examples to show in the examples section.\n * If provided, replaces the default examples entirely.\n * Should be a function that returns formatted example strings.\n */\n customExamples?: (context: PromptContext) => string;\n\n // ============================================================================\n // HINT TEMPLATES\n // ============================================================================\n\n /**\n * Hint shown when LLM uses only one gadget per response.\n * Encourages parallel gadget usage for efficiency.\n */\n parallelGadgetsHint?: HintTemplate;\n\n /**\n * Template for iteration progress hint.\n * Informs the LLM about remaining iterations to help plan work.\n *\n * When using a string template, supports placeholders:\n * - {iteration}: Current iteration (1-based)\n * - {maxIterations}: Maximum iterations allowed\n * - {remaining}: Iterations remaining\n */\n iterationProgressHint?: HintTemplate;\n}\n\n/**\n * Default hint templates used by llmist.\n */\nexport const DEFAULT_HINTS = {\n parallelGadgetsHint: \"Tip: You can call multiple gadgets in a single response for efficiency.\",\n\n iterationProgressHint: \"[Iteration {iteration}/{maxIterations}] Plan your actions accordingly.\",\n} as const;\n\n/**\n * Default prompt templates used by llmist.\n */\nexport const DEFAULT_PROMPTS: Required<\n Omit<\n PromptTemplateConfig,\n \"rules\" | \"customExamples\" | \"parallelGadgetsHint\" | \"iterationProgressHint\"\n > & {\n rules: (context: PromptContext) => string[];\n customExamples: null;\n }\n> = {\n mainInstruction: [\n \"⚠️ CRITICAL: RESPOND ONLY WITH GADGET INVOCATIONS\",\n \"DO NOT use function calling or tool calling\",\n \"You must output the exact text markers shown below in plain text.\",\n \"EACH MARKER MUST START WITH A NEWLINE.\",\n ].join(\"\\n\"),\n\n criticalUsage: \"INVOKE gadgets using the markers - do not describe what you want to do.\",\n\n formatDescription: (ctx) =>\n `Parameters using ${ctx.argPrefix}name markers (value on next line(s), no escaping needed)`,\n\n rules: () => [\n \"Output ONLY plain text with the exact markers - never use function/tool calling\",\n \"You can invoke multiple gadgets in a single response\",\n \"Gadgets without dependencies execute immediately (in parallel if multiple)\",\n \"Use :invocation_id:dep1,dep2 syntax when a gadget needs results from prior gadgets\",\n \"If any dependency fails, dependent gadgets are automatically skipped\",\n ],\n\n customExamples: null,\n};\n\n/**\n * Resolve a prompt template to a string using the given context.\n */\nexport function resolvePromptTemplate(\n template: PromptTemplate | undefined,\n defaultValue: PromptTemplate,\n context: PromptContext,\n): string {\n const resolved = template ?? defaultValue;\n return typeof resolved === \"function\" ? resolved(context) : resolved;\n}\n\n/**\n * Resolve rules template to an array of strings.\n */\nexport function resolveRulesTemplate(\n rules: PromptTemplateConfig[\"rules\"] | undefined,\n context: PromptContext,\n): string[] {\n const resolved = rules ?? DEFAULT_PROMPTS.rules;\n\n if (Array.isArray(resolved)) {\n return resolved;\n }\n\n if (typeof resolved === \"function\") {\n const result = resolved(context);\n return Array.isArray(result) ? result : [result];\n }\n\n return [resolved];\n}\n\n/**\n * Resolve a hint template to a string using the given context.\n * Supports both function templates and string templates with placeholders.\n *\n * @param template - The hint template to resolve\n * @param defaultValue - Default value if template is undefined\n * @param context - Context for rendering the template\n * @returns The resolved hint string\n */\nexport function resolveHintTemplate(\n template: HintTemplate | undefined,\n defaultValue: string,\n context: HintContext,\n): string {\n const resolved = template ?? defaultValue;\n\n if (typeof resolved === \"function\") {\n return resolved(context);\n }\n\n // Replace placeholders in string template\n return resolved\n .replace(/\\{iteration\\}/g, String(context.iteration))\n .replace(/\\{maxIterations\\}/g, String(context.maxIterations))\n .replace(/\\{remaining\\}/g, String(context.remaining));\n}\n","import type { AbstractGadget } from \"../gadgets/gadget.js\";\nimport type { GadgetMediaOutput } from \"../gadgets/types.js\";\nimport { GADGET_ARG_PREFIX, GADGET_END_PREFIX, GADGET_START_PREFIX } from \"./constants.js\";\nimport type {\n AudioMimeType,\n ContentPart,\n ImageMimeType,\n TextContentPart,\n} from \"./input-content.js\";\nimport {\n audioFromBase64,\n audioFromBuffer,\n detectImageMimeType,\n imageFromBase64,\n imageFromBuffer,\n imageFromUrl,\n text,\n toBase64,\n} from \"./input-content.js\";\nimport type { PromptTemplateConfig } from \"./prompt-config.js\";\nimport { DEFAULT_PROMPTS, resolvePromptTemplate, resolveRulesTemplate } from \"./prompt-config.js\";\n\nexport type MessageRole = \"system\" | \"user\" | \"assistant\";\n\n/**\n * Message content can be a simple string (text only) or an array of content parts (multimodal).\n * Using a string is simpler for text-only messages, while arrays support images and audio.\n */\nexport type MessageContent = string | ContentPart[];\n\nexport interface LLMMessage {\n role: MessageRole;\n content: MessageContent;\n name?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Normalize message content to an array of content parts.\n * Converts string content to a single text part.\n *\n * @param content - Message content (string or ContentPart[])\n * @returns Array of content parts\n */\nexport function normalizeMessageContent(content: MessageContent): ContentPart[] {\n if (typeof content === \"string\") {\n return [{ type: \"text\", text: content }];\n }\n return content;\n}\n\n/**\n * Extract text from message content.\n * Concatenates all text parts in the content.\n *\n * @param content - Message content (string or ContentPart[])\n * @returns Combined text from all text parts\n */\nexport function extractMessageText(content: MessageContent): string {\n if (typeof content === \"string\") {\n return content;\n }\n return content\n .filter((part): part is TextContentPart => part.type === \"text\")\n .map((part) => part.text)\n .join(\"\");\n}\n\nexport class LLMMessageBuilder {\n private readonly messages: LLMMessage[] = [];\n private startPrefix: string = GADGET_START_PREFIX;\n private endPrefix: string = GADGET_END_PREFIX;\n private argPrefix: string = GADGET_ARG_PREFIX;\n private promptConfig: PromptTemplateConfig;\n\n constructor(promptConfig?: PromptTemplateConfig) {\n this.promptConfig = promptConfig ?? {};\n }\n\n /**\n * Set custom prefixes for gadget markers.\n * Used to configure history builder to match system prompt markers.\n */\n withPrefixes(startPrefix: string, endPrefix: string, argPrefix?: string): this {\n this.startPrefix = startPrefix;\n this.endPrefix = endPrefix;\n if (argPrefix) {\n this.argPrefix = argPrefix;\n }\n return this;\n }\n\n addSystem(content: string, metadata?: Record<string, unknown>): this {\n this.messages.push({ role: \"system\", content, metadata });\n return this;\n }\n\n addGadgets(\n gadgets: AbstractGadget[],\n options?: { startPrefix?: string; endPrefix?: string; argPrefix?: string },\n ): this {\n // Store custom prefixes for later use in addGadgetCall\n if (options?.startPrefix) {\n this.startPrefix = options.startPrefix;\n }\n if (options?.endPrefix) {\n this.endPrefix = options.endPrefix;\n }\n if (options?.argPrefix) {\n this.argPrefix = options.argPrefix;\n }\n\n const context = {\n startPrefix: this.startPrefix,\n endPrefix: this.endPrefix,\n argPrefix: this.argPrefix,\n gadgetCount: gadgets.length,\n gadgetNames: gadgets.map((g) => g.name ?? g.constructor.name),\n };\n\n const parts: string[] = [];\n\n // Use configurable main instruction\n const mainInstruction = resolvePromptTemplate(\n this.promptConfig.mainInstruction,\n DEFAULT_PROMPTS.mainInstruction,\n context,\n );\n parts.push(mainInstruction);\n\n parts.push(this.buildGadgetsSection(gadgets));\n parts.push(this.buildUsageSection(context));\n\n this.messages.push({ role: \"system\", content: parts.join(\"\") });\n return this;\n }\n\n private buildGadgetsSection(gadgets: AbstractGadget[]): string {\n const parts: string[] = [];\n parts.push(\"\\n\\nAVAILABLE GADGETS\");\n parts.push(\"\\n=================\\n\");\n\n for (const gadget of gadgets) {\n const gadgetName = gadget.name ?? gadget.constructor.name;\n const instruction = gadget.getInstruction(this.argPrefix);\n\n // Parse instruction to separate description and schema\n const schemaMarker = \"\\n\\nInput Schema (BLOCK):\";\n const schemaIndex = instruction.indexOf(schemaMarker);\n\n const description = (\n schemaIndex !== -1 ? instruction.substring(0, schemaIndex) : instruction\n ).trim();\n const schema =\n schemaIndex !== -1 ? instruction.substring(schemaIndex + schemaMarker.length).trim() : \"\";\n\n parts.push(`\\nGADGET: ${gadgetName}`);\n parts.push(`\\n${description}`);\n if (schema) {\n parts.push(`\\n\\nPARAMETERS (BLOCK):\\n${schema}`);\n }\n parts.push(\"\\n\\n---\");\n }\n\n return parts.join(\"\");\n }\n\n private buildUsageSection(context: {\n startPrefix: string;\n endPrefix: string;\n argPrefix: string;\n gadgetCount: number;\n gadgetNames: string[];\n }): string {\n const parts: string[] = [];\n\n // Use configurable format description\n const formatDescription = resolvePromptTemplate(\n this.promptConfig.formatDescription,\n DEFAULT_PROMPTS.formatDescription,\n context,\n );\n\n parts.push(\"\\n\\nHOW TO INVOKE GADGETS\");\n parts.push(\"\\n=====================\\n\");\n\n // Use configurable critical usage instruction\n const criticalUsage = resolvePromptTemplate(\n this.promptConfig.criticalUsage,\n DEFAULT_PROMPTS.criticalUsage,\n context,\n );\n parts.push(`\\nCRITICAL: ${criticalUsage}\\n`);\n\n // Format section\n parts.push(\"\\nFORMAT:\");\n parts.push(`\\n 1. Start marker: ${this.startPrefix}gadget_name`);\n parts.push(`\\n With ID: ${this.startPrefix}gadget_name:my_id`);\n parts.push(`\\n With dependencies: ${this.startPrefix}gadget_name:my_id:dep1,dep2`);\n parts.push(`\\n 2. ${formatDescription}`);\n parts.push(`\\n 3. End marker: ${this.endPrefix}`);\n\n parts.push(this.buildExamplesSection(context));\n parts.push(this.buildRulesSection(context));\n\n parts.push(\"\\n\");\n\n return parts.join(\"\");\n }\n\n private buildExamplesSection(context: {\n startPrefix: string;\n endPrefix: string;\n argPrefix: string;\n gadgetCount: number;\n gadgetNames: string[];\n }): string {\n // Allow custom examples to completely replace default examples\n if (this.promptConfig.customExamples) {\n return this.promptConfig.customExamples(context);\n }\n\n const parts: string[] = [];\n\n // Single gadget example\n const singleExample = `${this.startPrefix}translate\n${this.argPrefix}from\nEnglish\n${this.argPrefix}to\nPolish\n${this.argPrefix}content\nParis is the capital of France: a beautiful city.\n${this.endPrefix}`;\n\n parts.push(`\\n\\nEXAMPLE (Single Gadget):\\n\\n${singleExample}`);\n\n // Multiple gadget example with multiline content\n const multipleExample = `${this.startPrefix}translate\n${this.argPrefix}from\nEnglish\n${this.argPrefix}to\nPolish\n${this.argPrefix}content\nParis is the capital of France: a beautiful city.\n${this.endPrefix}\n${this.startPrefix}analyze\n${this.argPrefix}type\neconomic_analysis\n${this.argPrefix}matter\nPolish Economy\n${this.argPrefix}question\nAnalyze the following:\n- Polish arms exports 2025\n- Economic implications\n${this.endPrefix}`;\n\n parts.push(`\\n\\nEXAMPLE (Multiple Gadgets):\\n\\n${multipleExample}`);\n\n // Dependency example\n const dependencyExample = `${this.startPrefix}fetch_data:fetch_1\n${this.argPrefix}url\nhttps://api.example.com/users\n${this.endPrefix}\n${this.startPrefix}fetch_data:fetch_2\n${this.argPrefix}url\nhttps://api.example.com/orders\n${this.endPrefix}\n${this.startPrefix}merge_data:merge_1:fetch_1,fetch_2\n${this.argPrefix}format\njson\n${this.endPrefix}`;\n\n parts.push(`\\n\\nEXAMPLE (With Dependencies):\nmerge_1 waits for fetch_1 AND fetch_2 to complete.\nIf either fails, merge_1 is automatically skipped.\n\n${dependencyExample}`);\n\n // Block format syntax guide\n parts.push(`\n\nBLOCK FORMAT SYNTAX:\nBlock format uses ${this.argPrefix}name markers. Values are captured verbatim until the next marker.\n\n${this.argPrefix}filename\ncalculator.ts\n${this.argPrefix}code\nclass Calculator {\n private history: string[] = [];\n\n add(a: number, b: number): number {\n const result = a + b;\n this.history.push(\\`\\${a} + \\${b} = \\${result}\\`);\n return result;\n }\n}\n\nBLOCK FORMAT RULES:\n- Each parameter starts with ${this.argPrefix}parameterName on its own line\n- The value starts on the NEXT line after the marker\n- Value ends when the next ${this.argPrefix} or ${this.endPrefix} appears\n- NO escaping needed - write values exactly as they should appear\n- Perfect for code, JSON, markdown, or any content with special characters\n\nNESTED OBJECTS (use / separator):\n${this.argPrefix}config/timeout\n30\n${this.argPrefix}config/retries\n3\nProduces: { \"config\": { \"timeout\": \"30\", \"retries\": \"3\" } }\n\nARRAYS (use numeric indices):\n${this.argPrefix}items/0\nfirst\n${this.argPrefix}items/1\nsecond\nProduces: { \"items\": [\"first\", \"second\"] }`);\n\n return parts.join(\"\");\n }\n\n private buildRulesSection(context: {\n startPrefix: string;\n endPrefix: string;\n argPrefix: string;\n gadgetCount: number;\n gadgetNames: string[];\n }): string {\n const parts: string[] = [];\n parts.push(\"\\n\\nRULES:\");\n\n // Use configurable rules\n const rules = resolveRulesTemplate(this.promptConfig.rules, context);\n\n for (const rule of rules) {\n parts.push(`\\n - ${rule}`);\n }\n\n return parts.join(\"\");\n }\n\n /**\n * Add a user message.\n * Content can be a string (text only) or an array of content parts (multimodal).\n *\n * @param content - Message content\n * @param metadata - Optional metadata\n *\n * @example\n * ```typescript\n * // Text only\n * builder.addUser(\"Hello!\");\n *\n * // Multimodal\n * builder.addUser([\n * text(\"What's in this image?\"),\n * imageFromBuffer(imageData),\n * ]);\n * ```\n */\n addUser(content: MessageContent, metadata?: Record<string, unknown>): this {\n this.messages.push({ role: \"user\", content, metadata });\n return this;\n }\n\n addAssistant(content: string, metadata?: Record<string, unknown>): this {\n this.messages.push({ role: \"assistant\", content, metadata });\n return this;\n }\n\n /**\n * Add a user message with an image attachment.\n *\n * @param textContent - Text prompt\n * @param imageData - Image data (Buffer, Uint8Array, or base64 string)\n * @param mimeType - Optional MIME type (auto-detected if not provided)\n *\n * @example\n * ```typescript\n * builder.addUserWithImage(\n * \"What's in this image?\",\n * await fs.readFile(\"photo.jpg\"),\n * \"image/jpeg\" // Optional - auto-detected\n * );\n * ```\n */\n addUserWithImage(\n textContent: string,\n imageData: Buffer | Uint8Array | string,\n mimeType?: ImageMimeType,\n ): this {\n const imageBuffer =\n typeof imageData === \"string\" ? Buffer.from(imageData, \"base64\") : imageData;\n const detectedMime = mimeType ?? detectImageMimeType(imageBuffer);\n\n if (!detectedMime) {\n throw new Error(\n \"Could not detect image MIME type. Please provide the mimeType parameter explicitly.\",\n );\n }\n\n const content: ContentPart[] = [\n text(textContent),\n {\n type: \"image\",\n source: {\n type: \"base64\",\n mediaType: detectedMime,\n data: toBase64(imageBuffer),\n },\n },\n ];\n\n this.messages.push({ role: \"user\", content });\n return this;\n }\n\n /**\n * Add a user message with an image URL (OpenAI only).\n *\n * @param textContent - Text prompt\n * @param imageUrl - URL to the image\n *\n * @example\n * ```typescript\n * builder.addUserWithImageUrl(\n * \"What's in this image?\",\n * \"https://example.com/image.jpg\"\n * );\n * ```\n */\n addUserWithImageUrl(textContent: string, imageUrl: string): this {\n const content: ContentPart[] = [text(textContent), imageFromUrl(imageUrl)];\n this.messages.push({ role: \"user\", content });\n return this;\n }\n\n /**\n * Add a user message with an audio attachment (Gemini only).\n *\n * @param textContent - Text prompt\n * @param audioData - Audio data (Buffer, Uint8Array, or base64 string)\n * @param mimeType - Optional MIME type (auto-detected if not provided)\n *\n * @example\n * ```typescript\n * builder.addUserWithAudio(\n * \"Transcribe this audio\",\n * await fs.readFile(\"recording.mp3\"),\n * \"audio/mp3\" // Optional - auto-detected\n * );\n * ```\n */\n addUserWithAudio(\n textContent: string,\n audioData: Buffer | Uint8Array | string,\n mimeType?: AudioMimeType,\n ): this {\n const audioBuffer =\n typeof audioData === \"string\" ? Buffer.from(audioData, \"base64\") : audioData;\n\n const content: ContentPart[] = [text(textContent), audioFromBuffer(audioBuffer, mimeType)];\n this.messages.push({ role: \"user\", content });\n return this;\n }\n\n /**\n * Add a user message with multiple content parts.\n * Provides full flexibility for complex multimodal messages.\n *\n * @param parts - Array of content parts\n *\n * @example\n * ```typescript\n * builder.addUserMultimodal([\n * text(\"Compare these images:\"),\n * imageFromBuffer(image1),\n * imageFromBuffer(image2),\n * ]);\n * ```\n */\n addUserMultimodal(parts: ContentPart[]): this {\n this.messages.push({ role: \"user\", content: parts });\n return this;\n }\n\n /**\n * Record a gadget execution result in the message history.\n * Creates an assistant message with the gadget invocation and a user message with the result.\n *\n * The invocationId is shown to the LLM so it can reference previous calls when building dependencies.\n *\n * @param gadget - Name of the gadget that was executed\n * @param parameters - Parameters that were passed to the gadget\n * @param result - Text result from the gadget execution\n * @param invocationId - Invocation ID (shown to LLM so it can reference for dependencies)\n * @param media - Optional media outputs from the gadget\n * @param mediaIds - Optional IDs for the media outputs\n */\n addGadgetCallResult(\n gadget: string,\n parameters: Record<string, unknown>,\n result: string,\n invocationId: string,\n media?: GadgetMediaOutput[],\n mediaIds?: string[],\n ) {\n const paramStr = this.formatBlockParameters(parameters, \"\");\n\n // Assistant message with gadget markers and invocation ID\n this.messages.push({\n role: \"assistant\",\n content: `${this.startPrefix}${gadget}:${invocationId}\\n${paramStr}\\n${this.endPrefix}`,\n });\n\n // User message with result, including invocation ID so LLM can reference it\n if (media && media.length > 0 && mediaIds && mediaIds.length > 0) {\n // Build text with ID references (include kind for clarity)\n const idRefs = media.map((m, i) => `[Media: ${mediaIds[i]} (${m.kind})]`).join(\"\\n\");\n const textWithIds = `Result (${invocationId}): ${result}\\n${idRefs}`;\n\n // Build multimodal content: text + media content parts\n const parts: ContentPart[] = [text(textWithIds)];\n for (const item of media) {\n // Convert based on media kind\n if (item.kind === \"image\") {\n parts.push(imageFromBase64(item.data, item.mimeType as ImageMimeType));\n } else if (item.kind === \"audio\") {\n parts.push(audioFromBase64(item.data, item.mimeType as AudioMimeType));\n }\n // Note: video and file types are stored but not included in LLM context\n // as most providers don't support them yet\n }\n this.messages.push({ role: \"user\", content: parts });\n } else {\n // Simple text result\n this.messages.push({\n role: \"user\",\n content: `Result (${invocationId}): ${result}`,\n });\n }\n\n return this;\n }\n\n /**\n * Format parameters as Block format with JSON Pointer paths.\n * Uses the configured argPrefix for consistency with system prompt.\n */\n private formatBlockParameters(params: Record<string, unknown>, prefix: string): string {\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(params)) {\n const fullPath = prefix ? `${prefix}/${key}` : key;\n\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n const itemPath = `${fullPath}/${index}`;\n if (typeof item === \"object\" && item !== null) {\n lines.push(this.formatBlockParameters(item as Record<string, unknown>, itemPath));\n } else {\n lines.push(`${this.argPrefix}${itemPath}`);\n lines.push(String(item));\n }\n });\n } else if (typeof value === \"object\" && value !== null) {\n lines.push(this.formatBlockParameters(value as Record<string, unknown>, fullPath));\n } else {\n lines.push(`${this.argPrefix}${fullPath}`);\n lines.push(String(value));\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n build(): LLMMessage[] {\n return [...this.messages];\n }\n}\n\nexport const isLLMMessage = (value: unknown): value is LLMMessage => {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n\n const message = value as Partial<LLMMessage>;\n const validRole =\n message.role === \"system\" || message.role === \"user\" || message.role === \"assistant\";\n const validContent = typeof message.content === \"string\" || Array.isArray(message.content);\n\n return validRole && validContent;\n};\n","/**\n * MediaStore: Session-scoped storage for gadget media outputs.\n *\n * This module provides an abstraction layer between gadgets and the filesystem.\n * Instead of exposing raw file paths, it assigns unique IDs to stored media\n * that can be shared with the LLM and user.\n *\n * @example\n * ```typescript\n * const store = new MediaStore();\n *\n * // Store an image, get back ID\n * const stored = await store.store({\n * kind: \"image\",\n * data: base64EncodedPng,\n * mimeType: \"image/png\",\n * description: \"Screenshot\"\n * }, \"Screenshot\");\n *\n * console.log(stored.id); // \"media_a1b2c3\"\n * console.log(stored.path); // \"/tmp/llmist-media-xxx/Screenshot_001.png\"\n *\n * // Later: retrieve by ID\n * const retrieved = store.get(\"media_a1b2c3\");\n * ```\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { mkdir, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { GadgetMediaOutput, MediaKind, StoredMedia } from \"./types.js\";\n\n// Re-export StoredMedia for convenience\nexport type { StoredMedia };\n\n/**\n * Get the llmist temp directory path.\n * Uses ~/.llmist/tmp for user-scoped storage.\n */\nfunction getLlmistTmpDir(): string {\n return join(homedir(), \".llmist\", \"tmp\");\n}\n\n/**\n * Common MIME type to file extension mapping.\n */\nconst MIME_TO_EXTENSION: Record<string, string> = {\n // Images\n \"image/png\": \".png\",\n \"image/jpeg\": \".jpg\",\n \"image/gif\": \".gif\",\n \"image/webp\": \".webp\",\n \"image/svg+xml\": \".svg\",\n \"image/bmp\": \".bmp\",\n \"image/tiff\": \".tiff\",\n // Audio\n \"audio/mp3\": \".mp3\",\n \"audio/mpeg\": \".mp3\",\n \"audio/wav\": \".wav\",\n \"audio/webm\": \".webm\",\n \"audio/ogg\": \".ogg\",\n \"audio/flac\": \".flac\",\n \"audio/aac\": \".aac\",\n // Video\n \"video/mp4\": \".mp4\",\n \"video/webm\": \".webm\",\n \"video/ogg\": \".ogv\",\n \"video/quicktime\": \".mov\",\n \"video/x-msvideo\": \".avi\",\n // Documents\n \"application/pdf\": \".pdf\",\n \"application/json\": \".json\",\n \"text/plain\": \".txt\",\n \"text/html\": \".html\",\n \"text/css\": \".css\",\n \"text/javascript\": \".js\",\n};\n\n/**\n * Session-scoped media storage with ID abstraction.\n *\n * Each MediaStore instance manages media for a single agent session.\n * Media files are stored in a temporary directory and referenced by\n * short, unique IDs rather than file paths.\n */\nexport class MediaStore {\n private readonly items = new Map<string, StoredMedia>();\n private readonly outputDir: string;\n private counter = 0;\n private initialized = false;\n\n /**\n * Create a new MediaStore.\n *\n * @param sessionId - Optional session ID for the output directory.\n * If not provided, a random ID is generated.\n */\n constructor(sessionId?: string) {\n const id = sessionId ?? randomBytes(8).toString(\"hex\");\n this.outputDir = join(getLlmistTmpDir(), `media-${id}`);\n }\n\n /**\n * Get the output directory path.\n */\n getOutputDir(): string {\n return this.outputDir;\n }\n\n /**\n * Ensure the output directory exists.\n * @throws Error if directory creation fails\n */\n private async ensureDir(): Promise<void> {\n if (this.initialized) return;\n\n try {\n await mkdir(this.outputDir, { recursive: true });\n this.initialized = true;\n } catch (error) {\n throw new Error(\n `MediaStore: Failed to create directory ${this.outputDir}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n /**\n * Generate a unique media ID.\n * Format: \"media_\" + 6 random alphanumeric characters\n */\n private generateId(): string {\n const chars = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n let id = \"media_\";\n const bytes = randomBytes(6);\n for (let i = 0; i < 6; i++) {\n id += chars[bytes[i] % chars.length];\n }\n return id;\n }\n\n /**\n * Get file extension from MIME type.\n */\n private getExtension(mimeType: string): string {\n return MIME_TO_EXTENSION[mimeType] ?? \".bin\";\n }\n\n /**\n * Store media and return stored metadata with ID.\n *\n * @param media - The media output from a gadget\n * @param gadgetName - Name of the gadget that created this media\n * @returns Stored media information including generated ID\n * @throws Error if file write fails\n */\n async store(media: GadgetMediaOutput, gadgetName: string): Promise<StoredMedia> {\n await this.ensureDir();\n\n const id = this.generateId();\n const ext = this.getExtension(media.mimeType);\n // Use provided fileName or generate one\n const filename =\n media.fileName ?? `${gadgetName}_${String(++this.counter).padStart(3, \"0\")}${ext}`;\n const filePath = join(this.outputDir, filename);\n\n // Decode base64 and write to file\n const buffer = Buffer.from(media.data, \"base64\");\n\n try {\n await writeFile(filePath, buffer);\n } catch (error) {\n throw new Error(\n `MediaStore: Failed to write media file ${filePath}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n const stored: StoredMedia = {\n id,\n kind: media.kind,\n path: filePath,\n mimeType: media.mimeType,\n sizeBytes: buffer.length,\n description: media.description,\n metadata: media.metadata,\n gadgetName,\n createdAt: new Date(),\n };\n\n this.items.set(id, stored);\n return stored;\n }\n\n /**\n * Get stored media by ID.\n *\n * @param id - The media ID (e.g., \"media_a1b2c3\")\n * @returns The stored media or undefined if not found\n */\n get(id: string): StoredMedia | undefined {\n return this.items.get(id);\n }\n\n /**\n * Get the actual file path for a media ID.\n * Convenience method for gadgets that need the raw path.\n *\n * @param id - The media ID\n * @returns The file path or undefined if not found\n */\n getPath(id: string): string | undefined {\n return this.items.get(id)?.path;\n }\n\n /**\n * List all stored media, optionally filtered by kind.\n *\n * @param kind - Optional media kind to filter by\n * @returns Array of stored media items\n */\n list(kind?: MediaKind): StoredMedia[] {\n const all = Array.from(this.items.values());\n if (kind) {\n return all.filter((item) => item.kind === kind);\n }\n return all;\n }\n\n /**\n * Get the count of stored media items.\n */\n get size(): number {\n return this.items.size;\n }\n\n /**\n * Check if a media ID exists.\n */\n has(id: string): boolean {\n return this.items.has(id);\n }\n\n /**\n * Clear in-memory store without deleting files.\n * Resets the counter but leaves files on disk.\n */\n clear(): void {\n this.items.clear();\n this.counter = 0;\n }\n\n /**\n * Delete all stored files and clear memory.\n * Removes the entire session directory.\n */\n async cleanup(): Promise<void> {\n if (this.initialized) {\n try {\n await rm(this.outputDir, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors (directory may already be deleted)\n }\n this.initialized = false;\n }\n this.clear();\n }\n}\n","/**\n * Signal that a gadget throws to indicate task completion and agent termination.\n *\n * When a gadget throws this signal, the agent loop will:\n * 1. Complete the current iteration\n * 2. Return the signal message as the gadget's result\n * 3. Exit the loop instead of continuing to the next iteration\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * class FinishGadget extends Gadget({\n * name: 'Finish',\n * description: 'Signals task completion',\n * schema: z.object({\n * message: z.string().optional(),\n * }),\n * }) {\n * execute(params: this['params']): string {\n * const message = params.message || 'Task completed';\n * throw new TaskCompletionSignal(message);\n * }\n * }\n * ```\n */\nexport class TaskCompletionSignal extends Error {\n constructor(message?: string) {\n super(message ?? \"Agent loop terminated by gadget\");\n this.name = \"TaskCompletionSignal\";\n }\n}\n\n/**\n * Exception that gadgets can throw to request human input during execution.\n *\n * When a gadget throws this exception, the agent loop will:\n * 1. Pause execution and wait for human input\n * 2. If `requestHumanInput` callback is provided, call it and await the answer\n * 3. Return the user's answer as the gadget's result\n * 4. Continue the loop with the answer added to conversation history\n *\n * If no callback is provided, the loop will yield a `human_input_required` event\n * and the caller must handle it externally.\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * class AskUserGadget extends Gadget({\n * name: 'AskUser',\n * description: 'Ask the user a question and get their answer',\n * schema: z.object({\n * question: z.string().min(1, 'Question is required'),\n * }),\n * }) {\n * execute(params: this['params']): string {\n * throw new HumanInputRequiredException(params.question);\n * }\n * }\n * ```\n */\nexport class HumanInputRequiredException extends Error {\n public readonly question: string;\n\n constructor(question: string) {\n super(`Human input required: ${question}`);\n this.name = \"HumanInputRequiredException\";\n this.question = question;\n }\n}\n\n/**\n * Exception thrown when a gadget execution exceeds its timeout limit.\n *\n * When a gadget's execution time exceeds either:\n * - The gadget's own `timeoutMs` property, or\n * - The global `defaultGadgetTimeoutMs` configured in runtime/agent loop options\n *\n * The executor will automatically throw this exception and return it as an error.\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n *\n * class SlowApiGadget extends Gadget({\n * name: 'SlowApi',\n * description: 'Calls a slow external API',\n * timeoutMs: 5000, // 5 second timeout\n * schema: z.object({\n * endpoint: z.string(),\n * }),\n * }) {\n * async execute(params: this['params']): Promise<string> {\n * // If this takes longer than 5 seconds, execution will be aborted\n * const response = await fetch(params.endpoint);\n * return await response.text();\n * }\n * }\n * ```\n */\nexport class TimeoutException extends Error {\n public readonly timeoutMs: number;\n public readonly gadgetName: string;\n\n constructor(gadgetName: string, timeoutMs: number) {\n super(`Gadget '${gadgetName}' execution exceeded timeout of ${timeoutMs}ms`);\n this.name = \"TimeoutException\";\n this.gadgetName = gadgetName;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Exception thrown when gadget execution is aborted.\n *\n * Gadgets can throw this exception when they detect the abort signal has been\n * triggered. This is typically used via the `throwIfAborted()` helper method\n * on the Gadget base class.\n *\n * @example\n * ```typescript\n * class LongRunningGadget extends Gadget({\n * name: 'LongRunning',\n * description: 'Performs a long operation with checkpoints',\n * schema: z.object({ data: z.string() }),\n * }) {\n * async execute(params: this['params'], ctx: ExecutionContext): Promise<string> {\n * // Check at key points - throws AbortException if aborted\n * this.throwIfAborted(ctx);\n *\n * await this.doPartOne(params.data);\n *\n * this.throwIfAborted(ctx);\n *\n * await this.doPartTwo(params.data);\n *\n * return 'completed';\n * }\n * }\n * ```\n */\nexport class AbortException extends Error {\n constructor(message?: string) {\n super(message || \"Gadget execution was aborted\");\n this.name = \"AbortException\";\n }\n}\n\n","import { createWriteStream, mkdirSync, type WriteStream } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { type ILogObj, Logger } from \"tslog\";\n\nconst LEVEL_NAME_TO_ID: Record<string, number> = {\n silly: 0,\n trace: 1,\n debug: 2,\n info: 3,\n warn: 4,\n error: 5,\n fatal: 6,\n};\n\nfunction parseLogLevel(value?: string): number | undefined {\n if (!value) {\n return undefined;\n }\n\n const normalized = value.trim().toLowerCase();\n\n if (normalized === \"\") {\n return undefined;\n }\n\n const numericLevel = Number(normalized);\n if (Number.isFinite(numericLevel)) {\n return Math.max(0, Math.min(6, Math.floor(numericLevel)));\n }\n\n return LEVEL_NAME_TO_ID[normalized];\n}\n\n/**\n * Logger configuration options for the library.\n */\nexport interface LoggerOptions {\n /**\n * Log level: 0=silly, 1=trace, 2=debug, 3=info, 4=warn, 5=error, 6=fatal\n * @default 4 (warn)\n */\n minLevel?: number;\n\n /**\n * Output type: 'pretty' for development, 'json' for production\n * @default 'pretty'\n */\n type?: \"pretty\" | \"json\" | \"hidden\";\n\n /**\n * Logger name (appears in logs)\n */\n name?: string;\n\n /**\n * When true, reset (truncate) the log file instead of appending.\n * Useful for getting clean logs per session.\n * @default false\n */\n logReset?: boolean;\n}\n\n/**\n * Parses a boolean environment variable.\n */\nfunction parseEnvBoolean(value?: string): boolean | undefined {\n if (!value) return undefined;\n const normalized = value.trim().toLowerCase();\n if (normalized === \"true\" || normalized === \"1\") return true;\n if (normalized === \"false\" || normalized === \"0\") return false;\n return undefined;\n}\n\n/**\n * Create a new logger instance for the library.\n *\n * @param options - Logger configuration options\n * @returns Configured Logger instance\n *\n * @example\n * ```typescript\n * // Development logger with pretty output\n * const logger = createLogger({ type: 'pretty', minLevel: 2 });\n *\n * // Production logger with JSON output\n * const logger = createLogger({ type: 'json', minLevel: 3 });\n *\n * // Silent logger for tests\n * const logger = createLogger({ type: 'hidden' });\n * ```\n */\nexport function createLogger(options: LoggerOptions = {}): Logger<ILogObj> {\n const envMinLevel = parseLogLevel(process.env.LLMIST_LOG_LEVEL);\n const envLogFile = process.env.LLMIST_LOG_FILE?.trim() ?? \"\";\n const envLogReset = parseEnvBoolean(process.env.LLMIST_LOG_RESET);\n\n const minLevel = options.minLevel ?? envMinLevel ?? 4;\n const defaultType = options.type ?? \"pretty\";\n const name = options.name ?? \"llmist\";\n // Priority: options > env var > default (false = append)\n const logReset = options.logReset ?? envLogReset ?? false;\n\n let logFileStream: WriteStream | undefined;\n let finalType = defaultType;\n\n if (envLogFile) {\n try {\n mkdirSync(dirname(envLogFile), { recursive: true });\n // Use \"w\" (write/truncate) when logReset is true, \"a\" (append) otherwise\n const flags = logReset ? \"w\" : \"a\";\n logFileStream = createWriteStream(envLogFile, { flags });\n finalType = \"hidden\";\n } catch (error) {\n console.error(\"Failed to initialize LLMIST_LOG_FILE output:\", error);\n }\n }\n\n const logger = new Logger<ILogObj>({\n name,\n minLevel,\n type: finalType,\n // Optimize for production\n hideLogPositionForProduction: finalType !== \"pretty\",\n // Pretty output settings\n prettyLogTemplate:\n finalType === \"pretty\"\n ? \"{{yyyy}}-{{mm}}-{{dd}} {{hh}}:{{MM}}:{{ss}}:{{ms}} {{logLevelName}} [{{name}}] \"\n : undefined,\n });\n\n if (logFileStream) {\n logger.attachTransport((logObj) => {\n logFileStream?.write(`${JSON.stringify(logObj)}\\n`);\n });\n }\n\n return logger;\n}\n\n/**\n * Default logger instance for the library.\n * Users can replace this with their own configured logger.\n */\nexport const defaultLogger = createLogger();\n","/**\n * Zod schema to JSON Schema conversion with instance mismatch detection.\n *\n * When consumers use their own `import { z } from \"zod\"` instead of\n * `import { z } from \"llmist\"`, the `.describe()` metadata can be lost\n * because Zod stores metadata on schema instances and `toJSONSchema()`\n * only reads from schemas created by the same Zod module instance.\n *\n * This module provides a `schemaToJSONSchema()` function that:\n * 1. Converts Zod schema to JSON Schema using the standard API\n * 2. Detects if descriptions were lost due to instance mismatch\n * 3. Logs a warning recommending `import { z } from \"llmist\"`\n * 4. Falls back to extracting descriptions from `schema._def`\n *\n * @module gadgets/schema-to-json\n */\n\nimport type { ZodTypeAny } from \"zod\";\nimport * as z from \"zod\";\nimport { defaultLogger } from \"../logging/logger.js\";\n\n/**\n * Convert a Zod schema to JSON Schema with description fallback.\n *\n * If descriptions exist in schema._def but are missing from the generated\n * JSON Schema (indicating a Zod instance mismatch), this function:\n * 1. Logs a warning recommending `import { z } from \"llmist\"`\n * 2. Extracts descriptions from _def and merges them into the JSON Schema\n *\n * @param schema - Zod schema to convert\n * @param options - Conversion options (target JSON Schema version)\n * @returns JSON Schema object with descriptions preserved\n *\n * @example\n * ```typescript\n * import { schemaToJSONSchema } from './schema-to-json.js';\n * import { z } from 'zod';\n *\n * const schema = z.object({\n * name: z.string().describe('User name'),\n * });\n *\n * const jsonSchema = schemaToJSONSchema(schema);\n * // { type: 'object', properties: { name: { type: 'string', description: 'User name' } } }\n * ```\n */\nexport function schemaToJSONSchema(\n schema: ZodTypeAny,\n options?: { target?: \"draft-7\" | \"draft-2020-12\" },\n): Record<string, unknown> {\n const jsonSchema = z.toJSONSchema(schema, options ?? { target: \"draft-7\" });\n\n // Check for instance mismatch by comparing _def descriptions with JSON schema\n const mismatches = detectDescriptionMismatch(schema, jsonSchema);\n\n if (mismatches.length > 0) {\n defaultLogger.warn(\n `Zod instance mismatch detected: ${mismatches.length} description(s) lost. ` +\n `For best results, use: import { z } from \"llmist\"`,\n );\n\n // Merge descriptions from _def into JSON schema\n return mergeDescriptions(schema, jsonSchema);\n }\n\n return jsonSchema;\n}\n\n/**\n * Detect if schema._def contains descriptions that are missing from JSON schema.\n * Returns array of paths where descriptions were lost.\n */\nfunction detectDescriptionMismatch(\n schema: ZodTypeAny,\n jsonSchema: Record<string, unknown>,\n): string[] {\n const mismatches: string[] = [];\n\n function checkSchema(zodSchema: ZodTypeAny, json: unknown, path: string): void {\n if (!zodSchema || typeof zodSchema !== \"object\") return;\n\n const def = zodSchema._def as unknown as Record<string, unknown> | undefined;\n const jsonObj = json as Record<string, unknown> | undefined;\n\n // Check if _def has description but JSON schema doesn't\n if (def?.description && !jsonObj?.description) {\n mismatches.push(path || \"root\");\n }\n\n // Recursively check object properties\n if (def?.typeName === \"ZodObject\" && def?.shape) {\n const shape =\n typeof def.shape === \"function\"\n ? (def.shape as () => Record<string, ZodTypeAny>)()\n : def.shape;\n for (const [key, fieldSchema] of Object.entries(shape as Record<string, ZodTypeAny>)) {\n const properties = jsonObj?.properties as Record<string, unknown> | undefined;\n const jsonProp = properties?.[key];\n checkSchema(fieldSchema, jsonProp, path ? `${path}.${key}` : key);\n }\n }\n\n // Check array items\n if (def?.typeName === \"ZodArray\" && def?.type) {\n checkSchema(def.type as ZodTypeAny, jsonObj?.items, path ? `${path}[]` : \"[]\");\n }\n\n // Check optional/nullable wrapped types\n if ((def?.typeName === \"ZodOptional\" || def?.typeName === \"ZodNullable\") && def?.innerType) {\n checkSchema(def.innerType as ZodTypeAny, json, path);\n }\n\n // Check default wrapped types\n if (def?.typeName === \"ZodDefault\" && def?.innerType) {\n checkSchema(def.innerType as ZodTypeAny, json, path);\n }\n }\n\n checkSchema(schema, jsonSchema, \"\");\n return mismatches;\n}\n\n/**\n * Merge descriptions from schema._def into JSON schema.\n * Returns a new JSON schema object with descriptions filled in from _def.\n */\nfunction mergeDescriptions(\n schema: ZodTypeAny,\n jsonSchema: Record<string, unknown>,\n): Record<string, unknown> {\n function merge(zodSchema: ZodTypeAny, json: unknown): unknown {\n if (!json || typeof json !== \"object\") return json;\n\n const def = zodSchema._def as unknown as Record<string, unknown> | undefined;\n const jsonObj = json as Record<string, unknown>;\n const merged: Record<string, unknown> = { ...jsonObj };\n\n // Copy description from _def if missing in JSON\n if (def?.description && !jsonObj.description) {\n merged.description = def.description;\n }\n\n // Recursively merge object properties\n if (def?.typeName === \"ZodObject\" && def?.shape && jsonObj.properties) {\n const shape =\n typeof def.shape === \"function\"\n ? (def.shape as () => Record<string, ZodTypeAny>)()\n : def.shape;\n const properties = jsonObj.properties as Record<string, unknown>;\n merged.properties = { ...properties };\n for (const [key, fieldSchema] of Object.entries(shape as Record<string, ZodTypeAny>)) {\n if (properties[key]) {\n (merged.properties as Record<string, unknown>)[key] = merge(fieldSchema, properties[key]);\n }\n }\n }\n\n // Merge array items\n if (def?.typeName === \"ZodArray\" && def?.type && jsonObj.items) {\n merged.items = merge(def.type as ZodTypeAny, jsonObj.items);\n }\n\n // Handle optional/nullable wrapped types\n if ((def?.typeName === \"ZodOptional\" || def?.typeName === \"ZodNullable\") && def?.innerType) {\n return merge(def.innerType as ZodTypeAny, json);\n }\n\n // Handle default wrapped types\n if (def?.typeName === \"ZodDefault\" && def?.innerType) {\n return merge(def.innerType as ZodTypeAny, json);\n }\n\n return merged;\n }\n\n return merge(schema, jsonSchema) as Record<string, unknown>;\n}\n","import type { ZodTypeAny } from \"zod\";\n\nimport { GADGET_ARG_PREFIX, GADGET_END_PREFIX, GADGET_START_PREFIX } from \"../core/constants.js\";\nimport { AbortException } from \"./exceptions.js\";\nimport { schemaToJSONSchema } from \"./schema-to-json.js\";\nimport { validateGadgetSchema } from \"./schema-validator.js\";\nimport type { ExecutionContext, GadgetExample, GadgetExecuteReturn } from \"./types.js\";\n\n/**\n * Format parameters object as Block format for use in examples.\n * Uses JSON Pointer paths for nested structures.\n *\n * @param params - The parameters object to format\n * @param prefix - Path prefix for nested structures (internal use)\n * @param argPrefix - The argument prefix marker (defaults to GADGET_ARG_PREFIX)\n */\nfunction formatParamsForBlockExample(\n params: Record<string, unknown>,\n prefix: string = \"\",\n argPrefix: string = GADGET_ARG_PREFIX,\n): string {\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(params)) {\n const fullPath = prefix ? `${prefix}/${key}` : key;\n\n if (Array.isArray(value)) {\n // Arrays: use numeric indices\n value.forEach((item, index) => {\n const itemPath = `${fullPath}/${index}`;\n if (typeof item === \"object\" && item !== null) {\n // Nested object in array\n lines.push(formatParamsForBlockExample(item as Record<string, unknown>, itemPath, argPrefix));\n } else {\n lines.push(`${argPrefix}${itemPath}`);\n lines.push(String(item));\n }\n });\n } else if (typeof value === \"object\" && value !== null) {\n // Nested objects: recurse with path prefix\n lines.push(formatParamsForBlockExample(value as Record<string, unknown>, fullPath, argPrefix));\n } else {\n // Simple values\n lines.push(`${argPrefix}${fullPath}`);\n lines.push(String(value));\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format a single parameter line with type info and description.\n * Helper function for formatSchemaAsPlainText.\n */\nfunction formatParamLine(\n key: string,\n propObj: Record<string, unknown>,\n isRequired: boolean,\n indent = \"\",\n): string {\n const type = propObj.type as string;\n const description = propObj.description as string | undefined;\n const enumValues = propObj.enum as string[] | undefined;\n\n let line = `${indent}- ${key}`;\n\n // Add type info\n if (type === \"array\") {\n const items = propObj.items as Record<string, unknown> | undefined;\n const itemType = items?.type || \"any\";\n line += ` (array of ${itemType})`;\n } else if (type === \"object\" && propObj.properties) {\n line += \" (object)\";\n } else {\n line += ` (${type})`;\n }\n\n // Add required marker only for nested objects (not at root level where sections indicate this)\n if (isRequired && indent !== \"\") {\n line += \" [required]\";\n }\n\n // Add description\n if (description) {\n line += `: ${description}`;\n }\n\n // Add enum values if present\n if (enumValues) {\n line += ` - one of: ${enumValues.map((v) => `\"${v}\"`).join(\", \")}`;\n }\n\n return line;\n}\n\n/**\n * Format JSON Schema as plain text description.\n * This presents parameters in a neutral, human-readable format\n * that complements the block format used for gadget invocation.\n */\nfunction formatSchemaAsPlainText(\n schema: Record<string, unknown>,\n indent = \"\",\n atRoot = true,\n): string {\n const lines: string[] = [];\n const properties = (schema.properties || {}) as Record<string, unknown>;\n const required = (schema.required || []) as string[];\n\n // At root level: split required/optional\n if (atRoot && indent === \"\") {\n const requiredProps: [string, unknown][] = [];\n const optionalProps: [string, unknown][] = [];\n\n for (const [key, prop] of Object.entries(properties)) {\n if (required.includes(key)) {\n requiredProps.push([key, prop]);\n } else {\n optionalProps.push([key, prop]);\n }\n }\n\n const reqCount = requiredProps.length;\n const optCount = optionalProps.length;\n\n // Add count summary\n if (reqCount > 0 || optCount > 0) {\n const parts: string[] = [];\n if (reqCount > 0) parts.push(`${reqCount} required`);\n if (optCount > 0) parts.push(`${optCount} optional`);\n lines.push(parts.join(\", \"));\n lines.push(\"\"); // Blank line\n }\n\n // Render REQUIRED section\n if (reqCount > 0) {\n lines.push(\"REQUIRED Parameters:\");\n for (const [key, prop] of requiredProps) {\n lines.push(formatParamLine(key, prop as Record<string, unknown>, true, \"\"));\n // Handle nested objects\n const propObj = prop as Record<string, unknown>;\n if (propObj.type === \"object\" && propObj.properties) {\n lines.push(formatSchemaAsPlainText(propObj, \" \", false));\n }\n }\n }\n\n // Render OPTIONAL section\n if (optCount > 0) {\n if (reqCount > 0) lines.push(\"\"); // Blank line between sections\n lines.push(\"OPTIONAL Parameters:\");\n for (const [key, prop] of optionalProps) {\n lines.push(formatParamLine(key, prop as Record<string, unknown>, false, \"\"));\n // Handle nested objects\n const propObj = prop as Record<string, unknown>;\n if (propObj.type === \"object\" && propObj.properties) {\n lines.push(formatSchemaAsPlainText(propObj, \" \", false));\n }\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n // Nested objects: use current behavior (no split)\n for (const [key, prop] of Object.entries(properties)) {\n const isRequired = required.includes(key);\n lines.push(formatParamLine(key, prop as Record<string, unknown>, isRequired, indent));\n\n const propObj = prop as Record<string, unknown>;\n if (propObj.type === \"object\" && propObj.properties) {\n lines.push(formatSchemaAsPlainText(propObj, indent + \" \", false));\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Abstract base class for gadgets. Most users should use the `Gadget()` factory\n * or `createGadget()` function instead, as they provide better type safety\n * and simpler APIs.\n *\n * Extend this class directly only when you need advanced control over gadget behavior.\n */\nexport abstract class AbstractGadget {\n /**\n * The name of the gadget. Used for identification when LLM calls it.\n * If not provided, defaults to the class name.\n */\n name?: string;\n\n /**\n * Human-readable description of what the gadget does.\n */\n abstract description: string;\n\n /**\n * Optional Zod schema describing the expected input payload. When provided,\n * it will be validated before execution and transformed into a JSON Schema\n * representation that is surfaced to the LLM as part of the instructions.\n */\n parameterSchema?: ZodTypeAny;\n\n /**\n * Optional timeout in milliseconds for gadget execution.\n * If execution exceeds this timeout, a TimeoutException will be thrown.\n * If not set, the global defaultGadgetTimeoutMs from runtime options will be used.\n * Set to 0 or undefined to disable timeout for this gadget.\n */\n timeoutMs?: number;\n\n /**\n * Optional usage examples to help LLMs understand proper invocation.\n * Examples are rendered in getInstruction() alongside the schema.\n *\n * Note: Uses broader `unknown` type to allow typed examples from subclasses\n * while maintaining runtime compatibility.\n */\n examples?: GadgetExample<unknown>[];\n\n /**\n * Execute the gadget with the given parameters.\n * Can be synchronous or asynchronous.\n *\n * @param params - Parameters passed from the LLM\n * @param ctx - Optional execution context for cost reporting and LLM access\n * @returns Result as a string, or an object with result and optional cost\n *\n * @example\n * ```typescript\n * // Simple string return (free gadget)\n * execute(params) {\n * return \"result\";\n * }\n *\n * // Object return with cost tracking\n * execute(params) {\n * return { result: \"data\", cost: 0.001 };\n * }\n *\n * // Using context for callback-based cost reporting\n * execute(params, ctx) {\n * ctx.reportCost(0.001);\n * return \"result\";\n * }\n *\n * // Using wrapped LLMist for automatic cost tracking\n * async execute(params, ctx) {\n * const summary = await ctx.llmist.complete('Summarize: ' + params.text);\n * return summary;\n * }\n * ```\n */\n abstract execute(\n params: Record<string, unknown>,\n ctx?: ExecutionContext,\n ): GadgetExecuteReturn | Promise<GadgetExecuteReturn>;\n\n /**\n * Throws an AbortException if the execution has been aborted.\n *\n * Call this at key checkpoints in long-running gadgets to allow early exit\n * when the gadget has been cancelled (e.g., due to timeout). This enables\n * resource cleanup and prevents unnecessary work after cancellation.\n *\n * @param ctx - The execution context containing the abort signal\n * @throws AbortException if ctx.signal.aborted is true\n *\n * @example\n * ```typescript\n * class DataProcessor extends Gadget({\n * description: 'Processes data in multiple steps',\n * schema: z.object({ items: z.array(z.string()) }),\n * }) {\n * async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {\n * const results: string[] = [];\n *\n * for (const item of params.items) {\n * // Check before each expensive operation\n * this.throwIfAborted(ctx);\n *\n * results.push(await this.processItem(item));\n * }\n *\n * return results.join(', ');\n * }\n * }\n * ```\n */\n throwIfAborted(ctx?: ExecutionContext): void {\n if (ctx?.signal?.aborted) {\n throw new AbortException();\n }\n }\n\n /**\n * Register a cleanup function to run when execution is aborted (timeout or cancellation).\n * The cleanup function is called immediately if the signal is already aborted.\n * Errors thrown by the cleanup function are silently ignored.\n *\n * Use this to clean up resources like browser instances, database connections,\n * or child processes when the gadget is cancelled due to timeout.\n *\n * @param ctx - The execution context containing the abort signal\n * @param cleanup - Function to run on abort (can be sync or async)\n *\n * @example\n * ```typescript\n * class BrowserGadget extends Gadget({\n * description: 'Fetches web page content',\n * schema: z.object({ url: z.string() }),\n * }) {\n * async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {\n * const browser = await chromium.launch();\n * this.onAbort(ctx, () => browser.close());\n *\n * const page = await browser.newPage();\n * this.onAbort(ctx, () => page.close());\n *\n * await page.goto(params.url);\n * const content = await page.content();\n *\n * await browser.close();\n * return content;\n * }\n * }\n * ```\n */\n onAbort(ctx: ExecutionContext | undefined, cleanup: () => void | Promise<void>): void {\n if (!ctx?.signal) return;\n\n const safeCleanup = () => {\n try {\n const result = cleanup();\n if (result && typeof result === \"object\" && \"catch\" in result) {\n (result as Promise<void>).catch(() => {});\n }\n } catch {\n // Swallow synchronous errors\n }\n };\n\n if (ctx.signal.aborted) {\n // Already aborted, run cleanup immediately\n safeCleanup();\n return;\n }\n\n ctx.signal.addEventListener(\"abort\", safeCleanup, { once: true });\n }\n\n /**\n * Create an AbortController linked to the execution context's signal.\n * When the parent signal aborts, the returned controller also aborts with the same reason.\n *\n * Useful for passing abort signals to child operations like fetch() while still\n * being able to abort them independently if needed.\n *\n * @param ctx - The execution context containing the parent abort signal\n * @returns A new AbortController linked to the parent signal\n *\n * @example\n * ```typescript\n * class FetchGadget extends Gadget({\n * description: 'Fetches data from URL',\n * schema: z.object({ url: z.string() }),\n * }) {\n * async execute(params: this['params'], ctx?: ExecutionContext): Promise<string> {\n * const controller = this.createLinkedAbortController(ctx);\n *\n * // fetch() will automatically abort when parent times out\n * const response = await fetch(params.url, { signal: controller.signal });\n * return response.text();\n * }\n * }\n * ```\n */\n createLinkedAbortController(ctx?: ExecutionContext): AbortController {\n const controller = new AbortController();\n\n if (ctx?.signal) {\n if (ctx.signal.aborted) {\n controller.abort(ctx.signal.reason);\n } else {\n ctx.signal.addEventListener(\n \"abort\",\n () => {\n controller.abort(ctx.signal.reason);\n },\n { once: true },\n );\n }\n }\n\n return controller;\n }\n\n /**\n * Auto-generated instruction text for the LLM.\n * Combines name, description, and parameter schema into a formatted instruction.\n * @deprecated Use getInstruction() instead\n */\n get instruction(): string {\n return this.getInstruction();\n }\n\n /**\n * Generate instruction text for the LLM.\n * Combines name, description, and parameter schema into a formatted instruction.\n *\n * @param optionsOrArgPrefix - Optional custom prefixes for examples, or just argPrefix string for backwards compatibility\n * @returns Formatted instruction string\n */\n getInstruction(\n optionsOrArgPrefix?: string | { argPrefix?: string; startPrefix?: string; endPrefix?: string },\n ): string {\n // Handle backwards compatibility: if string is passed, treat it as argPrefix\n const options =\n typeof optionsOrArgPrefix === \"string\"\n ? { argPrefix: optionsOrArgPrefix }\n : optionsOrArgPrefix;\n const parts: string[] = [];\n\n // Add description\n parts.push(this.description);\n\n if (this.parameterSchema) {\n // Validate that the schema doesn't use z.unknown() and can be serialized\n const gadgetName = this.name ?? this.constructor.name;\n validateGadgetSchema(this.parameterSchema, gadgetName);\n\n const jsonSchema = schemaToJSONSchema(this.parameterSchema, {\n target: \"draft-7\",\n });\n\n // Use plain text schema description\n parts.push(\"\\n\\nParameters:\");\n parts.push(formatSchemaAsPlainText(jsonSchema));\n }\n\n // Render examples if present\n if (this.examples && this.examples.length > 0) {\n parts.push(\"\\n\\nExamples:\");\n\n // Use custom prefixes if provided, otherwise use defaults\n const effectiveArgPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;\n const effectiveStartPrefix = options?.startPrefix ?? GADGET_START_PREFIX;\n const effectiveEndPrefix = options?.endPrefix ?? GADGET_END_PREFIX;\n const gadgetName = this.name || this.constructor.name;\n\n this.examples.forEach((example, index) => {\n // Add horizontal rule between examples (but not before the first one)\n if (index > 0) {\n parts.push(\"\");\n parts.push(\"---\");\n parts.push(\"\");\n }\n\n // Add comment if provided\n if (example.comment) {\n parts.push(`# ${example.comment}`);\n }\n\n // Add GADGET_START marker\n parts.push(`${effectiveStartPrefix}${gadgetName}`);\n\n // Render params in block format\n parts.push(\n formatParamsForBlockExample(example.params as Record<string, unknown>, \"\", effectiveArgPrefix),\n );\n\n // Add GADGET_END marker\n parts.push(effectiveEndPrefix);\n\n // Render output if provided\n if (example.output !== undefined) {\n parts.push(\"\"); // Blank line before output\n parts.push(\"Expected Output:\");\n parts.push(example.output);\n }\n });\n }\n\n return parts.join(\"\\n\");\n }\n}\n\n","/**\n * Function-based gadget creation helper.\n *\n * For simple gadgets, use createGadget() instead of defining a class.\n * Parameters are automatically typed from the Zod schema.\n *\n * @example\n * ```typescript\n * const calculator = createGadget({\n * description: \"Performs arithmetic operations\",\n * schema: z.object({\n * operation: z.enum([\"add\", \"subtract\"]),\n * a: z.number(),\n * b: z.number(),\n * }),\n * execute: ({ operation, a, b }) => {\n * // Automatically typed!\n * return operation === \"add\" ? String(a + b) : String(a - b);\n * },\n * });\n * ```\n */\n\nimport type { ZodType } from \"zod\";\nimport { AbstractGadget } from \"./gadget.js\";\nimport type { ExecutionContext, GadgetExample, GadgetExecuteReturn } from \"./types.js\";\n\n/**\n * Infer the TypeScript type from a Zod schema.\n */\ntype InferSchema<T> = T extends ZodType<infer U> ? U : never;\n\n/**\n * Configuration for creating a function-based gadget.\n */\nexport interface CreateGadgetConfig<TSchema extends ZodType> {\n /** Optional custom name (defaults to \"FunctionGadget\") */\n name?: string;\n\n /** Human-readable description of what the gadget does */\n description: string;\n\n /** Zod schema for parameter validation */\n schema: TSchema;\n\n /**\n * Execution function with typed parameters.\n * Can return string or { result, cost? }.\n * Optionally receives ExecutionContext for callback-based cost reporting.\n */\n execute: (\n params: InferSchema<TSchema>,\n ctx?: ExecutionContext,\n ) => GadgetExecuteReturn | Promise<GadgetExecuteReturn>;\n\n /** Optional timeout in milliseconds */\n timeoutMs?: number;\n\n /** Optional usage examples to help LLMs understand proper invocation */\n examples?: GadgetExample<InferSchema<TSchema>>[];\n}\n\n/**\n * Creates a gadget from a function (simpler than class-based approach).\n *\n * This is perfect for simple gadgets where you don't need the full\n * power of a class. Parameters are automatically typed from the schema.\n *\n * @param config - Configuration with execute function and schema\n * @returns Gadget instance ready to be registered\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n * import { createGadget } from 'llmist';\n *\n * // Simple calculator gadget\n * const calculator = createGadget({\n * description: \"Performs arithmetic operations\",\n * schema: z.object({\n * operation: z.enum([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n * a: z.number().describe(\"First number\"),\n * b: z.number().describe(\"Second number\"),\n * }),\n * execute: ({ operation, a, b }) => {\n * // Parameters are automatically typed!\n * switch (operation) {\n * case \"add\": return String(a + b);\n * case \"subtract\": return String(a - b);\n * case \"multiply\": return String(a * b);\n * case \"divide\": return String(a / b);\n * }\n * },\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Async gadget with custom name and timeout\n * const weather = createGadget({\n * name: \"weather\",\n * description: \"Fetches current weather for a city\",\n * schema: z.object({\n * city: z.string().min(1).describe(\"City name\"),\n * }),\n * timeoutMs: 10000,\n * execute: async ({ city }) => {\n * const response = await fetch(`https://api.weather.com/${city}`);\n * const data = await response.json();\n * return `Weather in ${city}: ${data.description}, ${data.temp}°C`;\n * },\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Use with agent\n * const agent = LLMist.createAgent()\n * .withGadgets(calculator, weather)\n * .ask(\"What's the weather in Paris and what's 10 + 5?\");\n * ```\n */\nexport function createGadget<TSchema extends ZodType>(\n config: CreateGadgetConfig<TSchema>,\n): AbstractGadget {\n class DynamicGadget extends AbstractGadget {\n name = config.name;\n description = config.description;\n parameterSchema = config.schema;\n timeoutMs = config.timeoutMs;\n examples = config.examples;\n\n execute(\n params: Record<string, unknown>,\n ctx?: ExecutionContext,\n ): GadgetExecuteReturn | Promise<GadgetExecuteReturn> {\n // Cast to inferred type and call user's function with context\n return config.execute(params as InferSchema<TSchema>, ctx);\n }\n }\n\n return new DynamicGadget();\n}\n","/**\n * GadgetOutputViewer - Browse stored outputs from gadgets that exceeded the size limit.\n *\n * When a gadget returns too much data, the output is stored and can be browsed\n * using this gadget with grep-like pattern filtering and line limiting.\n */\n\nimport { z } from \"zod\";\nimport type { GadgetOutputStore } from \"../agent/gadget-output-store.js\";\nimport { createGadget } from \"./create-gadget.js\";\n\n/**\n * Pattern filter configuration.\n */\ninterface PatternFilter {\n /** Regular expression to match */\n regex: string;\n /** true = keep matches, false = exclude matches */\n include: boolean;\n /** Context lines before match (like grep -B) */\n before: number;\n /** Context lines after match (like grep -A) */\n after: number;\n}\n\n/**\n * Apply a single pattern filter to lines.\n *\n * For include=true: keeps lines that match (with before/after context).\n * For include=false: removes lines that match.\n */\nfunction applyPattern(lines: string[], pattern: PatternFilter): string[] {\n const regex = new RegExp(pattern.regex);\n\n if (!pattern.include) {\n // Exclude mode: remove matching lines\n return lines.filter((line) => !regex.test(line));\n }\n\n // Include mode: keep matching lines with context\n const matchIndices = new Set<number>();\n\n // Find all matching line indices\n for (let i = 0; i < lines.length; i++) {\n if (regex.test(lines[i])) {\n // Add the matching line and its context\n const start = Math.max(0, i - pattern.before);\n const end = Math.min(lines.length - 1, i + pattern.after);\n for (let j = start; j <= end; j++) {\n matchIndices.add(j);\n }\n }\n }\n\n // Return lines at matching indices (preserving order)\n return lines.filter((_, index) => matchIndices.has(index));\n}\n\n/**\n * Apply multiple pattern filters in sequence (like piping through grep commands).\n */\nfunction applyPatterns(lines: string[], patterns: PatternFilter[]): string[] {\n let result = lines;\n for (const pattern of patterns) {\n result = applyPattern(result, pattern);\n }\n return result;\n}\n\n/**\n * Parse and apply a line limit string.\n *\n * Formats:\n * - \"100-\" → first 100 lines (slice 0 to 100)\n * - \"-25\" → last 25 lines (slice -25)\n * - \"50-100\" → lines 50-100 (1-indexed, so slice 49 to 100)\n */\nfunction applyLineLimit(lines: string[], limit: string): string[] {\n const trimmed = limit.trim();\n\n // Format: \"100-\" (first N lines)\n if (trimmed.endsWith(\"-\") && !trimmed.startsWith(\"-\")) {\n const n = parseInt(trimmed.slice(0, -1), 10);\n if (!isNaN(n) && n > 0) {\n return lines.slice(0, n);\n }\n }\n\n // Format: \"-25\" (last N lines)\n if (trimmed.startsWith(\"-\") && !trimmed.includes(\"-\", 1)) {\n const n = parseInt(trimmed, 10);\n if (!isNaN(n) && n < 0) {\n return lines.slice(n);\n }\n }\n\n // Format: \"50-100\" (range, 1-indexed)\n const rangeMatch = trimmed.match(/^(\\d+)-(\\d+)$/);\n if (rangeMatch) {\n const start = parseInt(rangeMatch[1], 10);\n const end = parseInt(rangeMatch[2], 10);\n if (!isNaN(start) && !isNaN(end) && start > 0 && end >= start) {\n // Convert from 1-indexed to 0-indexed\n return lines.slice(start - 1, end);\n }\n }\n\n // Invalid format - return unchanged\n return lines;\n}\n\n/**\n * Schema for pattern filter objects.\n */\nconst patternSchema = z.object({\n regex: z.string().describe(\"Regular expression to match\"),\n include: z\n .boolean()\n .default(true)\n .describe(\"true = keep matching lines, false = exclude matching lines\"),\n before: z\n .number()\n .int()\n .min(0)\n .default(0)\n .describe(\"Context lines before each match (like grep -B)\"),\n after: z\n .number()\n .int()\n .min(0)\n .default(0)\n .describe(\"Context lines after each match (like grep -A)\"),\n});\n\n/** Default max output in characters (~19k tokens at 4 chars/token) */\nconst DEFAULT_MAX_OUTPUT_CHARS = 76_800;\n\n/**\n * Create a GadgetOutputViewer gadget instance bound to a specific output store.\n *\n * This is a factory function because the gadget needs access to the output store,\n * which is created per-agent-run.\n *\n * @param store - The GadgetOutputStore to read outputs from\n * @param maxOutputChars - Maximum characters to return (default: 76,800 = ~19k tokens)\n * @returns A GadgetOutputViewer gadget instance\n *\n * @example\n * ```typescript\n * const store = new GadgetOutputStore();\n * const viewer = createGadgetOutputViewer(store, 76_800);\n * registry.register(\"GadgetOutputViewer\", viewer);\n * ```\n */\nexport function createGadgetOutputViewer(\n store: GadgetOutputStore,\n maxOutputChars: number = DEFAULT_MAX_OUTPUT_CHARS,\n) {\n return createGadget({\n name: \"GadgetOutputViewer\",\n description:\n \"View stored output from gadgets that returned too much data. \" +\n \"Use patterns to filter lines (like grep) and limit to control output size. \" +\n \"Patterns are applied first in order, then the limit is applied to the result.\",\n schema: z.object({\n id: z.string().describe(\"ID of the stored output (from the truncation message)\"),\n patterns: z\n .array(patternSchema)\n .optional()\n .describe(\n \"Filter patterns applied in order (like piping through grep). \" +\n \"Each pattern can include or exclude lines with optional before/after context.\",\n ),\n limit: z\n .string()\n .optional()\n .describe(\n \"Line range to return after filtering. \" +\n \"Formats: '100-' (first 100), '-25' (last 25), '50-100' (lines 50-100)\",\n ),\n }),\n examples: [\n {\n comment: \"View first 50 lines of stored output\",\n params: { id: \"Search_abc12345\", limit: \"50-\" },\n },\n {\n comment: \"Filter for error lines with context\",\n params: {\n id: \"Search_abc12345\",\n patterns: [{ regex: \"error|Error|ERROR\", include: true, before: 2, after: 5 }],\n },\n },\n {\n comment: \"Exclude blank lines, then show first 100\",\n params: {\n id: \"Search_abc12345\",\n patterns: [{ regex: \"^\\\\s*$\", include: false, before: 0, after: 0 }],\n limit: \"100-\",\n },\n },\n {\n comment: \"Chain filters: find TODOs, exclude tests, limit to 50 lines\",\n params: {\n id: \"Search_abc12345\",\n patterns: [\n { regex: \"TODO\", include: true, before: 1, after: 1 },\n { regex: \"test|spec\", include: false, before: 0, after: 0 },\n ],\n limit: \"50-\",\n },\n },\n ],\n execute: ({ id, patterns, limit }) => {\n const stored = store.get(id);\n if (!stored) {\n return `Error: No stored output with id \"${id}\". Available IDs: ${store.getIds().join(\", \") || \"(none)\"}`;\n }\n\n let lines = stored.content.split(\"\\n\");\n\n // Step 1: Apply patterns in order (like piping through grep)\n if (patterns && patterns.length > 0) {\n lines = applyPatterns(\n lines,\n patterns.map((p) => ({\n regex: p.regex,\n include: p.include ?? true,\n before: p.before ?? 0,\n after: p.after ?? 0,\n })),\n );\n }\n\n // Step 2: Apply line limit AFTER all patterns\n if (limit) {\n lines = applyLineLimit(lines, limit);\n }\n\n // Step 3: Build output string\n let output = lines.join(\"\\n\");\n const totalLines = stored.lineCount;\n const returnedLines = lines.length;\n\n if (returnedLines === 0) {\n return `No lines matched the filters. Original output had ${totalLines} lines.`;\n }\n\n // Step 4: Apply output size limit to prevent context explosion\n let truncatedBySize = false;\n let linesIncluded = returnedLines;\n if (output.length > maxOutputChars) {\n truncatedBySize = true;\n let truncatedOutput = \"\";\n linesIncluded = 0;\n\n for (const line of lines) {\n if (truncatedOutput.length + line.length + 1 > maxOutputChars) break;\n truncatedOutput += line + \"\\n\";\n linesIncluded++;\n }\n\n output = truncatedOutput;\n }\n\n // Build header with appropriate messaging\n let header: string;\n if (truncatedBySize) {\n const remainingLines = returnedLines - linesIncluded;\n header =\n `[Showing ${linesIncluded} of ${totalLines} lines (truncated due to size limit)]\\n` +\n `[... ${remainingLines.toLocaleString()} more lines. Use limit parameter to paginate, e.g., limit: \"${linesIncluded + 1}-${linesIncluded + 200}\"]\\n`;\n } else if (returnedLines < totalLines) {\n header = `[Showing ${returnedLines} of ${totalLines} lines]\\n`;\n } else {\n header = `[Showing all ${totalLines} lines]\\n`;\n }\n\n return header + output;\n },\n });\n}\n\n// Export helpers for testing\nexport { applyPattern, applyPatterns, applyLineLimit };\n","/**\n * Internal key for Agent instantiation.\n * This Symbol is used to ensure only AgentBuilder can create Agent instances.\n *\n * @internal\n */\nexport const AGENT_INTERNAL_KEY = Symbol(\"AGENT_INTERNAL_KEY\");\n\n/**\n * Type guard to check if the key is the correct internal key\n * @internal\n */\nexport function isValidAgentKey(key: unknown): key is typeof AGENT_INTERNAL_KEY {\n return key === AGENT_INTERNAL_KEY;\n}\n","/**\n * Configuration types for the context compaction system.\n *\n * Context compaction automatically manages conversation history to prevent\n * context window overflow in long-running agent conversations.\n */\n\nimport type { CompactionStrategy } from \"./strategy.js\";\n\n/**\n * Event emitted when compaction occurs.\n * This is included in StreamEvent for UI visibility.\n */\nexport interface CompactionEvent {\n /** The strategy that performed the compaction */\n strategy: string;\n /** Token count before compaction */\n tokensBefore: number;\n /** Token count after compaction */\n tokensAfter: number;\n /** Number of messages before compaction */\n messagesBefore: number;\n /** Number of messages after compaction */\n messagesAfter: number;\n /** Summary text if summarization was used */\n summary?: string;\n /** Agent iteration when compaction occurred */\n iteration: number;\n}\n\n/**\n * Statistics about compaction activity.\n */\nexport interface CompactionStats {\n /** Total number of compactions performed */\n totalCompactions: number;\n /** Total tokens saved across all compactions */\n totalTokensSaved: number;\n /** Current context usage */\n currentUsage: {\n tokens: number;\n percent: number;\n };\n /** Model's context window size */\n contextWindow: number;\n}\n\n/**\n * Configuration for the context compaction system.\n *\n * @example\n * ```typescript\n * // Custom configuration\n * const agent = await LLMist.createAgent()\n * .withModel('sonnet')\n * .withCompaction({\n * triggerThresholdPercent: 70,\n * targetPercent: 40,\n * preserveRecentTurns: 10,\n * })\n * .ask('...');\n *\n * // Disable compaction\n * const agent = await LLMist.createAgent()\n * .withModel('sonnet')\n * .withoutCompaction()\n * .ask('...');\n * ```\n */\nexport interface CompactionConfig {\n /**\n * Enable or disable compaction.\n * @default true\n */\n enabled?: boolean;\n\n /**\n * The compaction strategy to use.\n * - 'sliding-window': Fast, drops oldest turns (no LLM call)\n * - 'summarization': LLM-based compression of old messages\n * - 'hybrid': Summarizes old messages + keeps recent turns (recommended)\n * - Or provide a custom CompactionStrategy instance\n * @default 'hybrid'\n */\n strategy?: \"sliding-window\" | \"summarization\" | \"hybrid\" | CompactionStrategy;\n\n /**\n * Context usage percentage that triggers compaction.\n * When token count exceeds this percentage of the context window,\n * compaction is performed before the next LLM call.\n * @default 80\n */\n triggerThresholdPercent?: number;\n\n /**\n * Target context usage percentage after compaction.\n * The compaction will aim to reduce tokens to this percentage.\n * @default 50\n */\n targetPercent?: number;\n\n /**\n * Number of recent turns to preserve during compaction.\n * A \"turn\" is a user message + assistant response pair.\n * Recent turns are kept verbatim while older ones are summarized/dropped.\n * @default 5\n */\n preserveRecentTurns?: number;\n\n /**\n * Model to use for summarization.\n * If not specified, uses the agent's model.\n * @default undefined (uses agent's model)\n */\n summarizationModel?: string;\n\n /**\n * Custom system prompt for summarization.\n * If not specified, uses a default prompt optimized for context preservation.\n */\n summarizationPrompt?: string;\n\n /**\n * Callback invoked when compaction occurs.\n * Useful for logging or analytics.\n */\n onCompaction?: (event: CompactionEvent) => void;\n}\n\n/**\n * Default configuration values for compaction.\n * Compaction is enabled by default with the hybrid strategy.\n */\nexport const DEFAULT_COMPACTION_CONFIG: Required<\n Omit<CompactionConfig, \"summarizationModel\" | \"summarizationPrompt\" | \"onCompaction\">\n> = {\n enabled: true,\n strategy: \"hybrid\",\n triggerThresholdPercent: 80,\n targetPercent: 50,\n preserveRecentTurns: 5,\n};\n\n/**\n * Default prompt used for summarization strategy.\n */\nexport const DEFAULT_SUMMARIZATION_PROMPT = `Summarize this conversation history concisely, preserving:\n1. Key decisions made and their rationale\n2. Important facts and data discovered\n3. Errors encountered and how they were resolved\n4. Current task context and goals\n\nFormat as a brief narrative paragraph, not bullet points.\nPrevious conversation:`;\n\n/**\n * Resolved configuration with all defaults applied.\n */\nexport interface ResolvedCompactionConfig {\n enabled: boolean;\n strategy: \"sliding-window\" | \"summarization\" | \"hybrid\";\n triggerThresholdPercent: number;\n targetPercent: number;\n preserveRecentTurns: number;\n summarizationModel?: string;\n summarizationPrompt: string;\n onCompaction?: (event: CompactionEvent) => void;\n}\n\n/**\n * Resolves partial configuration with defaults.\n */\nexport function resolveCompactionConfig(config: CompactionConfig = {}): ResolvedCompactionConfig {\n const trigger =\n config.triggerThresholdPercent ?? DEFAULT_COMPACTION_CONFIG.triggerThresholdPercent;\n const target = config.targetPercent ?? DEFAULT_COMPACTION_CONFIG.targetPercent;\n\n // Warn about potentially misconfigured thresholds\n if (target >= trigger) {\n console.warn(\n `[llmist/compaction] targetPercent (${target}) should be less than triggerThresholdPercent (${trigger}) to be effective.`,\n );\n }\n\n // Handle custom strategy instances vs string names\n const strategy = config.strategy ?? DEFAULT_COMPACTION_CONFIG.strategy;\n const strategyName =\n typeof strategy === \"object\" && \"name\" in strategy\n ? (strategy.name as \"sliding-window\" | \"summarization\" | \"hybrid\")\n : strategy;\n\n return {\n enabled: config.enabled ?? DEFAULT_COMPACTION_CONFIG.enabled,\n strategy: strategyName,\n triggerThresholdPercent: trigger,\n targetPercent: target,\n preserveRecentTurns:\n config.preserveRecentTurns ?? DEFAULT_COMPACTION_CONFIG.preserveRecentTurns,\n summarizationModel: config.summarizationModel,\n summarizationPrompt: config.summarizationPrompt ?? DEFAULT_SUMMARIZATION_PROMPT,\n onCompaction: config.onCompaction,\n };\n}\n","/**\n * Strategy interface for context compaction.\n *\n * Strategies define how conversation history is compressed to fit within\n * context window limits. Different strategies trade off between:\n * - Speed (LLM calls vs local processing)\n * - Context preservation (summary quality vs simple truncation)\n * - Cost (summarization model usage)\n */\n\nimport type { LLMist } from \"../../core/client.js\";\nimport type { LLMMessage } from \"../../core/messages.js\";\nimport type { ModelLimits } from \"../../core/model-catalog.js\";\nimport type { ResolvedCompactionConfig } from \"./config.js\";\n\n/**\n * Context provided to compaction strategies.\n */\nexport interface CompactionContext {\n /** Current token count of the conversation */\n currentTokens: number;\n /** Target token count after compaction */\n targetTokens: number;\n /** Model's context window limits */\n modelLimits: ModelLimits;\n /** LLMist client for summarization calls */\n client: LLMist;\n /** Model identifier for token counting and summarization */\n model: string;\n}\n\n/**\n * Result of a compaction operation.\n */\nexport interface CompactionResult {\n /** Compacted messages to replace history with */\n messages: LLMMessage[];\n /** Summary text if summarization was used */\n summary?: string;\n /** The name of the strategy that was ultimately executed */\n strategyName: string;\n /** Metadata about the compaction */\n metadata: {\n /** Number of messages before compaction */\n originalCount: number;\n /** Number of messages after compaction */\n compactedCount: number;\n /** Estimated tokens before compaction */\n tokensBefore: number;\n /** Estimated tokens after compaction */\n tokensAfter: number;\n };\n}\n\n/**\n * Interface for compaction strategy implementations.\n *\n * Strategies receive the conversation history (excluding base messages like\n * system prompt and gadget instructions) and must return a compacted version.\n *\n * @example\n * ```typescript\n * class MyCustomStrategy implements CompactionStrategy {\n * readonly name = 'my-custom';\n *\n * async compact(\n * messages: LLMMessage[],\n * config: ResolvedCompactionConfig,\n * context: CompactionContext\n * ): Promise<CompactionResult> {\n * // Custom compaction logic\n * return {\n * messages: compactedMessages,\n * metadata: { ... }\n * };\n * }\n * }\n * ```\n */\nexport interface CompactionStrategy {\n /** Human-readable name of the strategy */\n readonly name: string;\n\n /**\n * Compact the given messages to fit within target token count.\n *\n * @param messages - Conversation history messages (excludes system/gadget base)\n * @param config - Resolved compaction configuration\n * @param context - Context including token counts and LLM client\n * @returns Compacted messages with metadata\n */\n compact(\n messages: LLMMessage[],\n config: ResolvedCompactionConfig,\n context: CompactionContext,\n ): Promise<CompactionResult>;\n}\n\n/**\n * Utility to group messages into logical conversation turns.\n *\n * A \"turn\" is typically a user message followed by an assistant response.\n * Gadget calls are grouped with the preceding assistant message.\n */\nexport interface MessageTurn {\n /** Messages in this turn (user + assistant + any gadget results) */\n messages: LLMMessage[];\n /** Estimated token count for this turn */\n tokenEstimate: number;\n}\n\n/**\n * Groups messages into logical conversation turns.\n *\n * Rules:\n * - A turn starts with a user message\n * - A turn includes all subsequent assistant messages until the next user message\n * - The first message(s) before any user message are considered \"preamble\"\n *\n * @param messages - Array of conversation messages\n * @returns Array of message turns\n */\nexport function groupIntoTurns(messages: LLMMessage[]): MessageTurn[] {\n const turns: MessageTurn[] = [];\n let currentTurn: LLMMessage[] = [];\n\n for (const msg of messages) {\n if (msg.role === \"user\" && currentTurn.length > 0) {\n // Start new turn - save current one\n turns.push({\n messages: currentTurn,\n tokenEstimate: estimateTurnTokens(currentTurn),\n });\n currentTurn = [msg];\n } else {\n currentTurn.push(msg);\n }\n }\n\n // Don't forget the last turn\n if (currentTurn.length > 0) {\n turns.push({\n messages: currentTurn,\n tokenEstimate: estimateTurnTokens(currentTurn),\n });\n }\n\n return turns;\n}\n\n/**\n * Rough token estimation for a turn (4 chars per token).\n */\nfunction estimateTurnTokens(messages: LLMMessage[]): number {\n return Math.ceil(messages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4);\n}\n\n/**\n * Flattens turns back into a message array.\n */\nexport function flattenTurns(turns: MessageTurn[]): LLMMessage[] {\n return turns.flatMap((turn) => turn.messages);\n}\n","/**\n * Sliding Window Compaction Strategy\n *\n * A fast, no-LLM-call strategy that simply keeps the most recent N turns\n * and drops older ones. Best for:\n * - Long-running conversations where older context becomes irrelevant\n * - Scenarios requiring minimal latency\n * - As a fallback when summarization is too slow\n */\n\nimport type { LLMMessage } from \"../../../core/messages.js\";\nimport type { ResolvedCompactionConfig } from \"../config.js\";\nimport {\n type CompactionContext,\n type CompactionResult,\n type CompactionStrategy,\n flattenTurns,\n groupIntoTurns,\n} from \"../strategy.js\";\n\n/**\n * Marker message inserted to indicate truncation.\n */\nconst TRUNCATION_MARKER_TEMPLATE =\n \"[Previous conversation truncated. Removed {count} turn(s) to fit context window.]\";\n\n/**\n * Sliding window strategy - keeps recent turns, drops older ones.\n *\n * This strategy:\n * 1. Groups messages into logical turns (user + assistant pairs)\n * 2. Keeps the `preserveRecentTurns` most recent turns\n * 3. Inserts a truncation marker at the beginning\n * 4. Requires no LLM call - very fast\n */\nexport class SlidingWindowStrategy implements CompactionStrategy {\n readonly name = \"sliding-window\";\n\n async compact(\n messages: LLMMessage[],\n config: ResolvedCompactionConfig,\n context: CompactionContext,\n ): Promise<CompactionResult> {\n const turns = groupIntoTurns(messages);\n const preserveCount = Math.min(config.preserveRecentTurns, turns.length);\n\n // If we have fewer turns than the preserve count, nothing to compact\n if (turns.length <= preserveCount) {\n return {\n messages,\n strategyName: this.name,\n metadata: {\n originalCount: messages.length,\n compactedCount: messages.length,\n tokensBefore: context.currentTokens,\n tokensAfter: context.currentTokens,\n },\n };\n }\n\n // Keep only the most recent turns\n const turnsToKeep = turns.slice(-preserveCount);\n const turnsRemoved = turns.length - preserveCount;\n\n // Create truncation marker\n const truncationMarker: LLMMessage = {\n role: \"user\",\n content: TRUNCATION_MARKER_TEMPLATE.replace(\"{count}\", turnsRemoved.toString()),\n };\n\n // Build compacted message list\n const compactedMessages: LLMMessage[] = [truncationMarker, ...flattenTurns(turnsToKeep)];\n\n // Estimate new token count\n const tokensAfter = Math.ceil(\n compactedMessages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4,\n );\n\n return {\n messages: compactedMessages,\n strategyName: this.name,\n metadata: {\n originalCount: messages.length,\n compactedCount: compactedMessages.length,\n tokensBefore: context.currentTokens,\n tokensAfter,\n },\n };\n }\n}\n","/**\n * Summarization Compaction Strategy\n *\n * Uses an LLM to summarize older conversation messages into a concise summary.\n * Best for:\n * - Tasks where historical context matters\n * - Complex multi-step reasoning\n * - When accuracy is more important than speed\n */\n\nimport type { LLMMessage } from \"../../../core/messages.js\";\nimport type { ResolvedCompactionConfig } from \"../config.js\";\nimport {\n type CompactionContext,\n type CompactionResult,\n type CompactionStrategy,\n flattenTurns,\n groupIntoTurns,\n} from \"../strategy.js\";\n\n/**\n * Summarization strategy - uses LLM to compress conversation history.\n *\n * This strategy:\n * 1. Groups messages into logical turns\n * 2. Keeps recent turns intact\n * 3. Summarizes older turns using LLM\n * 4. Returns summary + recent turns\n */\nexport class SummarizationStrategy implements CompactionStrategy {\n readonly name = \"summarization\";\n\n async compact(\n messages: LLMMessage[],\n config: ResolvedCompactionConfig,\n context: CompactionContext,\n ): Promise<CompactionResult> {\n const turns = groupIntoTurns(messages);\n const preserveCount = Math.min(config.preserveRecentTurns, turns.length);\n\n // If we have fewer turns than the preserve count, nothing to compact\n if (turns.length <= preserveCount) {\n return {\n messages,\n strategyName: this.name,\n metadata: {\n originalCount: messages.length,\n compactedCount: messages.length,\n tokensBefore: context.currentTokens,\n tokensAfter: context.currentTokens,\n },\n };\n }\n\n // Split into turns to summarize and turns to keep\n const turnsToSummarize = turns.slice(0, -preserveCount);\n const turnsToKeep = turns.slice(-preserveCount);\n\n // Build conversation text to summarize\n const conversationToSummarize = this.formatTurnsForSummary(flattenTurns(turnsToSummarize));\n\n // Generate summary using LLM\n const summary = await this.generateSummary(conversationToSummarize, config, context);\n\n // Create summary message\n const summaryMessage: LLMMessage = {\n role: \"user\",\n content: `[Previous conversation summary]\\n${summary}\\n[End of summary - conversation continues below]`,\n };\n\n // Build compacted message list\n const compactedMessages: LLMMessage[] = [summaryMessage, ...flattenTurns(turnsToKeep)];\n\n // Estimate new token count\n const tokensAfter = Math.ceil(\n compactedMessages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4,\n );\n\n return {\n messages: compactedMessages,\n summary,\n strategyName: this.name,\n metadata: {\n originalCount: messages.length,\n compactedCount: compactedMessages.length,\n tokensBefore: context.currentTokens,\n tokensAfter,\n },\n };\n }\n\n /**\n * Formats messages into a readable conversation format for summarization.\n */\n private formatTurnsForSummary(messages: LLMMessage[]): string {\n return messages\n .map((msg) => {\n const role = msg.role.charAt(0).toUpperCase() + msg.role.slice(1);\n return `${role}: ${msg.content}`;\n })\n .join(\"\\n\\n\");\n }\n\n /**\n * Generates a summary using the configured LLM.\n */\n private async generateSummary(\n conversation: string,\n config: ResolvedCompactionConfig,\n context: CompactionContext,\n ): Promise<string> {\n const model = config.summarizationModel ?? context.model;\n const prompt = `${config.summarizationPrompt}\\n\\n${conversation}`;\n\n // Use the LLMist client's complete method for summarization\n const response = await context.client.complete(prompt, {\n model,\n temperature: 0.3, // Low temperature for factual summarization\n });\n\n return response.trim();\n }\n}\n","/**\n * Hybrid Compaction Strategy\n *\n * Combines sliding window and summarization for the best of both worlds:\n * 1. Identifies which turns to compact vs keep (like sliding window)\n * 2. Summarizes the older turns (like summarization)\n * 3. Returns summary + recent turns intact\n *\n * Falls back to sliding window if there are too few turns to summarize.\n */\n\nimport type { LLMMessage } from \"../../../core/messages.js\";\nimport type { ResolvedCompactionConfig } from \"../config.js\";\nimport {\n type CompactionContext,\n type CompactionResult,\n type CompactionStrategy,\n groupIntoTurns,\n} from \"../strategy.js\";\nimport { SlidingWindowStrategy } from \"./sliding-window.js\";\nimport { SummarizationStrategy } from \"./summarization.js\";\n\n/**\n * Minimum turns needed to make summarization worthwhile.\n * Below this threshold, we fall back to sliding window.\n */\nconst MIN_TURNS_FOR_SUMMARIZATION = 3;\n\n/**\n * Hybrid strategy - summarizes old turns + keeps recent turns.\n *\n * This is the recommended default strategy as it:\n * - Preserves important historical context via summarization\n * - Keeps recent conversation turns verbatim for continuity\n * - Falls back gracefully to sliding window when appropriate\n */\nexport class HybridStrategy implements CompactionStrategy {\n readonly name = \"hybrid\";\n\n private readonly slidingWindow = new SlidingWindowStrategy();\n private readonly summarization = new SummarizationStrategy();\n\n async compact(\n messages: LLMMessage[],\n config: ResolvedCompactionConfig,\n context: CompactionContext,\n ): Promise<CompactionResult> {\n const turns = groupIntoTurns(messages);\n const preserveCount = Math.min(config.preserveRecentTurns, turns.length);\n\n // If we have fewer turns than the preserve count, nothing to compact\n if (turns.length <= preserveCount) {\n return {\n messages,\n strategyName: this.name,\n metadata: {\n originalCount: messages.length,\n compactedCount: messages.length,\n tokensBefore: context.currentTokens,\n tokensAfter: context.currentTokens,\n },\n };\n }\n\n // Calculate how many turns would be summarized\n const turnsToSummarize = turns.length - preserveCount;\n\n // If there are too few turns to summarize, use sliding window instead\n if (turnsToSummarize < MIN_TURNS_FOR_SUMMARIZATION) {\n // Delegate to sliding window - propagate its strategyName for accurate reporting\n return this.slidingWindow.compact(messages, config, context);\n }\n\n // Use summarization for older turns - propagate its strategyName\n return this.summarization.compact(messages, config, context);\n }\n}\n","/**\n * Compaction Strategy Implementations\n *\n * Available strategies:\n * - SlidingWindowStrategy: Fast, drops oldest turns (no LLM call)\n * - SummarizationStrategy: LLM-based compression\n * - HybridStrategy: Summarizes old + keeps recent (recommended)\n */\n\nexport { HybridStrategy } from \"./hybrid.js\";\nexport { SlidingWindowStrategy } from \"./sliding-window.js\";\nexport { SummarizationStrategy } from \"./summarization.js\";\n","/**\n * CompactionManager - Central orchestrator for context compaction.\n *\n * Monitors token usage and coordinates compaction strategies to keep\n * conversation context within model limits.\n */\n\nimport type { LLMist } from \"../../core/client.js\";\nimport type { LLMMessage } from \"../../core/messages.js\";\nimport type { ModelLimits } from \"../../core/model-catalog.js\";\nimport type { IConversationManager } from \"../interfaces.js\";\nimport {\n type CompactionConfig,\n type CompactionEvent,\n type CompactionStats,\n type ResolvedCompactionConfig,\n resolveCompactionConfig,\n} from \"./config.js\";\nimport {\n HybridStrategy,\n SlidingWindowStrategy,\n SummarizationStrategy,\n} from \"./strategies/index.js\";\nimport type { CompactionStrategy } from \"./strategy.js\";\n\n/**\n * Pre-computed token counts to avoid redundant counting.\n * Passed from checkAndCompact to compact for efficiency.\n */\ninterface PrecomputedTokens {\n historyMessages: LLMMessage[];\n baseMessages: LLMMessage[];\n historyTokens: number;\n baseTokens: number;\n currentTokens: number;\n}\n\n/**\n * Creates a strategy instance from a strategy name.\n */\nfunction createStrategy(name: string): CompactionStrategy {\n switch (name) {\n case \"sliding-window\":\n return new SlidingWindowStrategy();\n case \"summarization\":\n return new SummarizationStrategy();\n case \"hybrid\":\n return new HybridStrategy();\n default:\n throw new Error(`Unknown compaction strategy: ${name}`);\n }\n}\n\n/**\n * CompactionManager orchestrates context compaction for an agent.\n *\n * It:\n * - Monitors token usage before each LLM call\n * - Triggers compaction when threshold is exceeded\n * - Coordinates with ConversationManager to update history\n * - Tracks statistics for observability\n */\nexport class CompactionManager {\n private readonly client: LLMist;\n private readonly model: string;\n private readonly config: ResolvedCompactionConfig;\n private readonly strategy: CompactionStrategy;\n private modelLimits?: ModelLimits;\n\n // Statistics\n private totalCompactions = 0;\n private totalTokensSaved = 0;\n private lastTokenCount = 0;\n\n constructor(client: LLMist, model: string, config: CompactionConfig = {}) {\n this.client = client;\n this.model = model;\n this.config = resolveCompactionConfig(config);\n\n // Create strategy instance (support both string name and custom instance)\n if (typeof config.strategy === \"object\" && \"compact\" in config.strategy) {\n this.strategy = config.strategy as CompactionStrategy;\n } else {\n this.strategy = createStrategy(this.config.strategy);\n }\n }\n\n /**\n * Check if compaction is needed and perform it if so.\n *\n * @param conversation - The conversation manager to compact\n * @param iteration - Current agent iteration (for event metadata)\n * @returns CompactionEvent if compaction was performed, null otherwise\n */\n async checkAndCompact(\n conversation: IConversationManager,\n iteration: number,\n ): Promise<CompactionEvent | null> {\n if (!this.config.enabled) {\n return null;\n }\n\n // Get model limits (cached after first call)\n if (!this.modelLimits) {\n this.modelLimits = this.client.modelRegistry.getModelLimits(this.model);\n if (!this.modelLimits) {\n // Model not found in registry, skip compaction silently\n // This is not an error - it just means we can't determine context limits\n return null;\n }\n }\n\n // Count current tokens (skip if client doesn't support token counting)\n if (!this.client.countTokens) {\n return null;\n }\n const messages = conversation.getMessages();\n const currentTokens = await this.client.countTokens(this.model, messages);\n this.lastTokenCount = currentTokens;\n\n // Calculate usage percentage\n const usagePercent = (currentTokens / this.modelLimits.contextWindow) * 100;\n\n // Check if we need to compact\n if (usagePercent < this.config.triggerThresholdPercent) {\n return null;\n }\n\n // Perform compaction with precomputed token counts to avoid redundant counting\n const historyMessages = conversation.getHistoryMessages();\n const baseMessages = conversation.getBaseMessages();\n const historyTokens = await this.client.countTokens(this.model, historyMessages);\n const baseTokens = await this.client.countTokens(this.model, baseMessages);\n\n return this.compact(conversation, iteration, {\n historyMessages,\n baseMessages,\n historyTokens,\n baseTokens,\n currentTokens: historyTokens + baseTokens,\n });\n }\n\n /**\n * Force compaction regardless of threshold.\n *\n * @param conversation - The conversation manager to compact\n * @param iteration - Current agent iteration (for event metadata). Use -1 for manual compaction.\n * @param precomputed - Optional pre-computed token counts (passed from checkAndCompact for efficiency)\n * @returns CompactionEvent with compaction details\n */\n async compact(\n conversation: IConversationManager,\n iteration: number,\n precomputed?: PrecomputedTokens,\n ): Promise<CompactionEvent | null> {\n if (!this.modelLimits) {\n this.modelLimits = this.client.modelRegistry.getModelLimits(this.model);\n if (!this.modelLimits) {\n return null;\n }\n }\n\n // Use precomputed values if available, otherwise compute them\n const historyMessages = precomputed?.historyMessages ?? conversation.getHistoryMessages();\n const baseMessages = precomputed?.baseMessages ?? conversation.getBaseMessages();\n const historyTokens =\n precomputed?.historyTokens ?? (await this.client.countTokens(this.model, historyMessages));\n const baseTokens =\n precomputed?.baseTokens ?? (await this.client.countTokens(this.model, baseMessages));\n const currentTokens = precomputed?.currentTokens ?? historyTokens + baseTokens;\n\n // Calculate target tokens for history (leaving room for base messages and output)\n const targetTotalTokens = Math.floor(\n (this.modelLimits.contextWindow * this.config.targetPercent) / 100,\n );\n const targetHistoryTokens = Math.max(0, targetTotalTokens - baseTokens);\n\n // Run the compaction strategy\n const result = await this.strategy.compact(historyMessages, this.config, {\n currentTokens: historyTokens,\n targetTokens: targetHistoryTokens,\n modelLimits: this.modelLimits,\n client: this.client,\n model: this.config.summarizationModel ?? this.model,\n });\n\n // Replace the conversation history\n conversation.replaceHistory(result.messages);\n\n // Count tokens after compaction\n const afterTokens = await this.client.countTokens(this.model, conversation.getMessages());\n const tokensSaved = currentTokens - afterTokens;\n\n // Update statistics\n this.totalCompactions++;\n this.totalTokensSaved += tokensSaved;\n this.lastTokenCount = afterTokens;\n\n // Create event - use result.strategyName for accurate reporting (e.g., when hybrid falls back to sliding-window)\n const event: CompactionEvent = {\n strategy: result.strategyName,\n tokensBefore: currentTokens,\n tokensAfter: afterTokens,\n messagesBefore: historyMessages.length + baseMessages.length,\n messagesAfter: result.messages.length + baseMessages.length,\n summary: result.summary,\n iteration,\n };\n\n // Call onCompaction callback if provided\n if (this.config.onCompaction) {\n try {\n this.config.onCompaction(event);\n } catch (err) {\n console.warn(\"[llmist/compaction] onCompaction callback error:\", err);\n }\n }\n\n return event;\n }\n\n /**\n * Get compaction statistics.\n */\n getStats(): CompactionStats {\n const contextWindow = this.modelLimits?.contextWindow ?? 0;\n return {\n totalCompactions: this.totalCompactions,\n totalTokensSaved: this.totalTokensSaved,\n currentUsage: {\n tokens: this.lastTokenCount,\n percent: contextWindow > 0 ? (this.lastTokenCount / contextWindow) * 100 : 0,\n },\n contextWindow,\n };\n }\n\n /**\n * Check if compaction is enabled.\n */\n isEnabled(): boolean {\n return this.config.enabled;\n }\n}\n","/**\n * ConversationManager handles conversation state and message building.\n * Extracted from AgentLoop to follow Single Responsibility Principle.\n */\n\nimport type { MessageContent } from \"../core/messages.js\";\nimport { extractMessageText, type LLMMessage, LLMMessageBuilder } from \"../core/messages.js\";\nimport type { GadgetMediaOutput } from \"../gadgets/types.js\";\nimport type { IConversationManager } from \"./interfaces.js\";\n\n/**\n * Options for ConversationManager constructor.\n */\nexport interface ConversationManagerOptions {\n /** Custom gadget start marker prefix */\n startPrefix?: string;\n /** Custom gadget end marker prefix */\n endPrefix?: string;\n /** Custom argument prefix for block format */\n argPrefix?: string;\n}\n\n/**\n * Default implementation of IConversationManager.\n * Manages conversation history by building on top of base messages (system prompt, gadget instructions).\n */\nexport class ConversationManager implements IConversationManager {\n private readonly baseMessages: LLMMessage[];\n private readonly initialMessages: LLMMessage[];\n private historyBuilder: LLMMessageBuilder;\n private readonly startPrefix?: string;\n private readonly endPrefix?: string;\n private readonly argPrefix?: string;\n\n constructor(\n baseMessages: LLMMessage[],\n initialMessages: LLMMessage[],\n options: ConversationManagerOptions = {},\n ) {\n this.baseMessages = baseMessages;\n this.initialMessages = initialMessages;\n this.historyBuilder = new LLMMessageBuilder();\n\n // Store prefixes for history replacement\n this.startPrefix = options.startPrefix;\n this.endPrefix = options.endPrefix;\n this.argPrefix = options.argPrefix;\n\n // Apply custom prefixes if provided (must match system prompt markers)\n if (options.startPrefix && options.endPrefix) {\n this.historyBuilder.withPrefixes(options.startPrefix, options.endPrefix, options.argPrefix);\n }\n }\n\n addUserMessage(content: MessageContent): void {\n this.historyBuilder.addUser(content);\n }\n\n addAssistantMessage(content: string): void {\n this.historyBuilder.addAssistant(content);\n }\n\n addGadgetCallResult(\n gadgetName: string,\n parameters: Record<string, unknown>,\n result: string,\n invocationId: string,\n media?: GadgetMediaOutput[],\n mediaIds?: string[],\n ): void {\n this.historyBuilder.addGadgetCallResult(gadgetName, parameters, result, invocationId, media, mediaIds);\n }\n\n getMessages(): LLMMessage[] {\n return [...this.baseMessages, ...this.initialMessages, ...this.historyBuilder.build()];\n }\n\n getHistoryMessages(): LLMMessage[] {\n return this.historyBuilder.build();\n }\n\n getBaseMessages(): LLMMessage[] {\n return [...this.baseMessages, ...this.initialMessages];\n }\n\n replaceHistory(newHistory: LLMMessage[]): void {\n // Create a new builder with the same prefixes\n this.historyBuilder = new LLMMessageBuilder();\n if (this.startPrefix && this.endPrefix) {\n this.historyBuilder.withPrefixes(this.startPrefix, this.endPrefix, this.argPrefix);\n }\n\n // Add each message from the new history\n for (const msg of newHistory) {\n if (msg.role === \"user\") {\n this.historyBuilder.addUser(msg.content);\n } else if (msg.role === \"assistant\") {\n // Assistant messages are always text, extract if multimodal\n this.historyBuilder.addAssistant(extractMessageText(msg.content));\n }\n // System messages are not added to history (they're in baseMessages)\n }\n }\n}\n","/**\n * Event handler sugar for cleaner event processing.\n *\n * Instead of verbose if/else chains, use named handlers\n * for each event type.\n *\n * @example\n * ```typescript\n * await agent.runWith({\n * onText: (content) => console.log(\"LLM:\", content),\n * onGadgetResult: (result) => console.log(\"Result:\", result.result),\n * });\n * ```\n */\n\nimport type { StreamEvent } from \"../gadgets/types.js\";\n\n/**\n * Named event handlers for different event types.\n */\nexport interface EventHandlers {\n /** Called when text is generated by the LLM */\n onText?: (content: string) => void | Promise<void>;\n\n /** Called when a gadget is about to be executed */\n onGadgetCall?: (call: {\n gadgetName: string;\n invocationId: string;\n parameters?: Record<string, unknown>;\n parametersRaw: string;\n dependencies: string[];\n }) => void | Promise<void>;\n\n /** Called when a gadget execution completes */\n onGadgetResult?: (result: {\n gadgetName: string;\n invocationId: string;\n result?: string;\n error?: string;\n parameters: Record<string, unknown>;\n }) => void | Promise<void>;\n\n /** Called when human input is required */\n onHumanInputRequired?: (data: { question: string; gadgetName: string }) => void | Promise<void>;\n\n /** Called for any other event type */\n onOther?: (event: StreamEvent) => void | Promise<void>;\n}\n\n/**\n * Helper to run an agent with named event handlers.\n *\n * @param agentGenerator - Agent's run() async generator\n * @param handlers - Named event handlers\n *\n * @example\n * ```typescript\n * await runWithHandlers(agent.run(), {\n * onText: (text) => console.log(\"LLM:\", text),\n * onGadgetResult: (result) => console.log(\"Result:\", result.result),\n * });\n * ```\n */\nexport async function runWithHandlers(\n agentGenerator: AsyncGenerator<StreamEvent>,\n handlers: EventHandlers,\n): Promise<void> {\n for await (const event of agentGenerator) {\n switch (event.type) {\n case \"text\":\n if (handlers.onText) {\n await handlers.onText(event.content);\n }\n break;\n\n case \"gadget_call\":\n if (handlers.onGadgetCall) {\n await handlers.onGadgetCall({\n gadgetName: event.call.gadgetName,\n invocationId: event.call.invocationId,\n parameters: event.call.parameters,\n parametersRaw: event.call.parametersRaw,\n dependencies: event.call.dependencies,\n });\n }\n break;\n\n case \"gadget_result\":\n if (handlers.onGadgetResult) {\n await handlers.onGadgetResult(event.result);\n }\n break;\n\n case \"human_input_required\":\n if (handlers.onHumanInputRequired) {\n await handlers.onHumanInputRequired({\n question: event.question,\n gadgetName: event.gadgetName,\n });\n }\n break;\n\n default:\n if (handlers.onOther) {\n await handlers.onOther(event);\n }\n break;\n }\n }\n}\n\n/**\n * Helper to collect events by type.\n *\n * @param agentGenerator - Agent's run() async generator\n * @param collect - Object specifying which event types to collect\n * @returns Object with collected events\n *\n * @example\n * ```typescript\n * const { text, gadgetResults } = await collectEvents(agent.run(), {\n * text: true,\n * gadgetResults: true,\n * });\n *\n * console.log(\"Full response:\", text.join(\"\"));\n * console.log(\"Gadget calls:\", gadgetResults.length);\n * ```\n */\nexport async function collectEvents(\n agentGenerator: AsyncGenerator<StreamEvent>,\n collect: {\n text?: boolean;\n gadgetCalls?: boolean;\n gadgetResults?: boolean;\n },\n): Promise<{\n text: string[];\n gadgetCalls: Array<{ gadgetName: string; parameters: Record<string, unknown> }>;\n gadgetResults: Array<{\n gadgetName: string;\n result?: string;\n error?: string;\n parameters: Record<string, unknown>;\n }>;\n}> {\n const result = {\n text: [] as string[],\n gadgetCalls: [] as Array<{ gadgetName: string; parameters: Record<string, unknown> }>,\n gadgetResults: [] as Array<{\n gadgetName: string;\n result?: string;\n error?: string;\n parameters: Record<string, unknown>;\n }>,\n };\n\n for await (const event of agentGenerator) {\n switch (event.type) {\n case \"text\":\n if (collect.text) {\n result.text.push(event.content);\n }\n break;\n\n case \"gadget_call\":\n if (collect.gadgetCalls && event.call.parameters) {\n result.gadgetCalls.push({\n gadgetName: event.call.gadgetName,\n parameters: event.call.parameters,\n });\n }\n break;\n\n case \"gadget_result\":\n if (collect.gadgetResults) {\n result.gadgetResults.push(event.result);\n }\n break;\n }\n }\n\n return result;\n}\n\n/**\n * Helper to collect only text from an agent run.\n *\n * @param agentGenerator - Agent's run() async generator\n * @returns Combined text response\n *\n * @example\n * ```typescript\n * const response = await collectText(agent.run());\n * console.log(response);\n * ```\n */\nexport async function collectText(agentGenerator: AsyncGenerator<StreamEvent>): Promise<string> {\n const chunks: string[] = [];\n\n for await (const event of agentGenerator) {\n if (event.type === \"text\") {\n chunks.push(event.content);\n }\n }\n\n return chunks.join(\"\");\n}\n","/**\n * Storage for large gadget outputs that exceed the configured limit.\n *\n * When a gadget returns more data than the configured limit, the output\n * is stored here and can be browsed later using GadgetOutputViewer.\n */\n\nimport { randomBytes } from \"node:crypto\";\n\n/**\n * Metadata and content for a stored gadget output.\n */\nexport interface StoredOutput {\n /** Unique identifier (e.g., \"Search_d34db33f\") */\n id: string;\n /** Name of the gadget that produced this output */\n gadgetName: string;\n /** Full output content */\n content: string;\n /** Size in bytes */\n byteSize: number;\n /** Number of lines */\n lineCount: number;\n /** When the output was stored */\n timestamp: Date;\n}\n\n/**\n * In-memory store for large gadget outputs.\n *\n * Outputs are stored with generated IDs in the format `{GadgetName}_{hex8}`.\n * The store is tied to an agent run and cleared when the agent completes.\n *\n * @example\n * ```typescript\n * const store = new GadgetOutputStore();\n * const id = store.store(\"Search\", largeOutput);\n * // id = \"Search_a1b2c3d4\"\n *\n * const stored = store.get(id);\n * console.log(stored?.lineCount); // 4200\n * ```\n */\nexport class GadgetOutputStore {\n private outputs = new Map<string, StoredOutput>();\n\n /**\n * Store a gadget output and return its ID.\n *\n * @param gadgetName - Name of the gadget that produced the output\n * @param content - Full output content to store\n * @returns Generated ID for retrieving the output later\n */\n store(gadgetName: string, content: string): string {\n const id = this.generateId(gadgetName);\n const encoder = new TextEncoder();\n\n const stored: StoredOutput = {\n id,\n gadgetName,\n content,\n byteSize: encoder.encode(content).length,\n lineCount: content.split(\"\\n\").length,\n timestamp: new Date(),\n };\n\n this.outputs.set(id, stored);\n return id;\n }\n\n /**\n * Retrieve a stored output by ID.\n *\n * @param id - The output ID (e.g., \"Search_d34db33f\")\n * @returns The stored output or undefined if not found\n */\n get(id: string): StoredOutput | undefined {\n return this.outputs.get(id);\n }\n\n /**\n * Check if an output exists.\n *\n * @param id - The output ID to check\n * @returns True if the output exists\n */\n has(id: string): boolean {\n return this.outputs.has(id);\n }\n\n /**\n * Get all stored output IDs.\n *\n * @returns Array of output IDs\n */\n getIds(): string[] {\n return Array.from(this.outputs.keys());\n }\n\n /**\n * Get the number of stored outputs.\n */\n get size(): number {\n return this.outputs.size;\n }\n\n /**\n * Clear all stored outputs.\n * Called when the agent run completes.\n */\n clear(): void {\n this.outputs.clear();\n }\n\n /**\n * Generate a unique ID for a stored output.\n * Format: {GadgetName}_{8 hex chars}\n */\n private generateId(gadgetName: string): string {\n const hex = randomBytes(4).toString(\"hex\");\n return `${gadgetName}_${hex}`;\n }\n}\n","/**\n * Runtime validators for hook action types.\n *\n * These validators ensure that controllers return valid action objects,\n * catching common mistakes like missing required fields.\n */\n\nimport type {\n AfterGadgetExecutionAction,\n AfterLLMCallAction,\n AfterLLMErrorAction,\n BeforeGadgetExecutionAction,\n BeforeLLMCallAction,\n} from \"./hooks.js\";\n\nexport class HookValidationError extends Error {\n constructor(hookName: string, message: string) {\n super(`Invalid action from ${hookName}: ${message}`);\n this.name = \"HookValidationError\";\n }\n}\n\n/**\n * Validate beforeLLMCall action.\n */\nexport function validateBeforeLLMCallAction(action: BeforeLLMCallAction): void {\n if (!action || typeof action !== \"object\" || !(\"action\" in action)) {\n throw new HookValidationError(\n \"beforeLLMCall\",\n \"Must return an action object with an 'action' field\",\n );\n }\n\n const actionType = action.action;\n if (actionType !== \"proceed\" && actionType !== \"skip\") {\n throw new HookValidationError(\n \"beforeLLMCall\",\n `Invalid action type: ${actionType}. Must be 'proceed' or 'skip'`,\n );\n }\n\n if (actionType === \"skip\" && !action.syntheticResponse) {\n throw new HookValidationError(\n \"beforeLLMCall\",\n \"When action is 'skip', syntheticResponse is required\",\n );\n }\n}\n\n/**\n * Validate afterLLMCall action.\n */\nexport function validateAfterLLMCallAction(action: AfterLLMCallAction): void {\n if (!action || typeof action !== \"object\" || !(\"action\" in action)) {\n throw new HookValidationError(\n \"afterLLMCall\",\n \"Must return an action object with an 'action' field\",\n );\n }\n\n const actionType = action.action;\n const validActions = [\"continue\", \"append_messages\", \"modify_and_continue\", \"append_and_modify\"];\n if (!validActions.includes(actionType)) {\n throw new HookValidationError(\n \"afterLLMCall\",\n `Invalid action type: ${actionType}. Must be one of: ${validActions.join(\", \")}`,\n );\n }\n\n if (actionType === \"append_messages\" || actionType === \"append_and_modify\") {\n if (!(\"messages\" in action) || !action.messages || !Array.isArray(action.messages)) {\n throw new HookValidationError(\n \"afterLLMCall\",\n `When action is '${actionType}', messages array is required`,\n );\n }\n\n if (action.messages.length === 0) {\n throw new HookValidationError(\n \"afterLLMCall\",\n `When action is '${actionType}', messages array must not be empty`,\n );\n }\n\n // Validate each message\n for (let i = 0; i < action.messages.length; i++) {\n const msg = action.messages[i];\n if (!msg || typeof msg !== \"object\") {\n throw new HookValidationError(\"afterLLMCall\", `Message at index ${i} must be an object`);\n }\n if (!msg.role || !msg.content) {\n throw new HookValidationError(\n \"afterLLMCall\",\n `Message at index ${i} must have 'role' and 'content' fields`,\n );\n }\n if (![\"system\", \"user\", \"assistant\"].includes(msg.role)) {\n throw new HookValidationError(\n \"afterLLMCall\",\n `Message at index ${i} has invalid role: ${msg.role}`,\n );\n }\n }\n }\n\n if (actionType === \"modify_and_continue\" || actionType === \"append_and_modify\") {\n if (!(\"modifiedMessage\" in action) || !action.modifiedMessage) {\n throw new HookValidationError(\n \"afterLLMCall\",\n `When action is '${actionType}', modifiedMessage is required`,\n );\n }\n }\n}\n\n/**\n * Validate afterLLMError action.\n */\nexport function validateAfterLLMErrorAction(action: AfterLLMErrorAction): void {\n if (!action || typeof action !== \"object\" || !(\"action\" in action)) {\n throw new HookValidationError(\n \"afterLLMError\",\n \"Must return an action object with an 'action' field\",\n );\n }\n\n const actionType = action.action;\n if (actionType !== \"rethrow\" && actionType !== \"recover\") {\n throw new HookValidationError(\n \"afterLLMError\",\n `Invalid action type: ${actionType}. Must be 'rethrow' or 'recover'`,\n );\n }\n\n if (actionType === \"recover\" && !action.fallbackResponse) {\n throw new HookValidationError(\n \"afterLLMError\",\n \"When action is 'recover', fallbackResponse is required\",\n );\n }\n}\n\n/**\n * Validate beforeGadgetExecution action.\n */\nexport function validateBeforeGadgetExecutionAction(action: BeforeGadgetExecutionAction): void {\n if (!action || typeof action !== \"object\" || !(\"action\" in action)) {\n throw new HookValidationError(\n \"beforeGadgetExecution\",\n \"Must return an action object with an 'action' field\",\n );\n }\n\n const actionType = action.action;\n if (actionType !== \"proceed\" && actionType !== \"skip\") {\n throw new HookValidationError(\n \"beforeGadgetExecution\",\n `Invalid action type: ${actionType}. Must be 'proceed' or 'skip'`,\n );\n }\n\n if (actionType === \"skip\" && !action.syntheticResult) {\n throw new HookValidationError(\n \"beforeGadgetExecution\",\n \"When action is 'skip', syntheticResult is required\",\n );\n }\n}\n\n/**\n * Validate afterGadgetExecution action.\n */\nexport function validateAfterGadgetExecutionAction(action: AfterGadgetExecutionAction): void {\n if (!action || typeof action !== \"object\" || !(\"action\" in action)) {\n throw new HookValidationError(\n \"afterGadgetExecution\",\n \"Must return an action object with an 'action' field\",\n );\n }\n\n const actionType = action.action;\n if (actionType !== \"continue\" && actionType !== \"recover\") {\n throw new HookValidationError(\n \"afterGadgetExecution\",\n `Invalid action type: ${actionType}. Must be 'continue' or 'recover'`,\n );\n }\n\n if (actionType === \"recover\" && !action.fallbackResult) {\n throw new HookValidationError(\n \"afterGadgetExecution\",\n \"When action is 'recover', fallbackResult is required\",\n );\n }\n}\n","/**\n * Anthropic Claude Model Specifications\n *\n * Model data for Anthropic Claude models including Sonnet and Opus variants\n * with their specifications, pricing, and capabilities.\n */\n\nimport type { ModelSpec } from \"../core/model-catalog.js\";\n\nexport const ANTHROPIC_MODELS: ModelSpec[] = [\n {\n provider: \"anthropic\",\n modelId: \"claude-sonnet-4-5-20250929\",\n displayName: \"Claude Sonnet 4.5\",\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n pricing: {\n input: 3.0,\n output: 15.0,\n cachedInput: 0.3,\n cacheWriteInput: 3.75,\n },\n knowledgeCutoff: \"2025-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n },\n metadata: {\n family: \"Claude 4\",\n releaseDate: \"2025-09-29\",\n notes: \"Smartest model for complex agents and coding. Extended thinking. 1M context in beta.\",\n },\n },\n {\n provider: \"anthropic\",\n modelId: \"claude-haiku-4-5-20251001\",\n displayName: \"Claude Haiku 4.5\",\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n pricing: {\n input: 1.0,\n output: 5.0,\n cachedInput: 0.1,\n cacheWriteInput: 1.25,\n },\n knowledgeCutoff: \"2025-02\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n },\n metadata: {\n family: \"Claude 4\",\n releaseDate: \"2025-10-01\",\n notes:\n \"Fastest model with near-frontier intelligence. Excellent for coding (73.3% SWE-bench).\",\n },\n },\n {\n provider: \"anthropic\",\n modelId: \"claude-sonnet-4-20250514\",\n displayName: \"Claude Sonnet 4\",\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n pricing: {\n input: 3.0,\n output: 15.0,\n cachedInput: 0.3,\n cacheWriteInput: 3.75,\n },\n knowledgeCutoff: \"2025-03\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n },\n metadata: {\n family: \"Claude 4\",\n releaseDate: \"2025-05-14\",\n notes: \"High performance with vision and extended thinking\",\n },\n },\n {\n provider: \"anthropic\",\n modelId: \"claude-3-7-sonnet-20250219\",\n displayName: \"Claude Sonnet 3.7\",\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n pricing: {\n input: 3.0,\n output: 15.0,\n cachedInput: 0.3,\n cacheWriteInput: 3.75,\n },\n knowledgeCutoff: \"2024-11\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n },\n metadata: {\n family: \"Claude 3\",\n releaseDate: \"2025-02-19\",\n notes: \"Legacy model - consider upgrading to Claude 4 family\",\n },\n },\n {\n provider: \"anthropic\",\n modelId: \"claude-opus-4-1-20250805\",\n displayName: \"Claude Opus 4.1\",\n contextWindow: 200_000,\n maxOutputTokens: 32_000,\n pricing: {\n input: 15.0,\n output: 75.0,\n cachedInput: 1.5,\n cacheWriteInput: 18.75,\n },\n knowledgeCutoff: \"2025-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n },\n metadata: {\n family: \"Claude 4\",\n releaseDate: \"2025-08-05\",\n notes: \"Exceptional for specialized reasoning tasks. Extended thinking support.\",\n },\n },\n {\n provider: \"anthropic\",\n modelId: \"claude-opus-4-20250514\",\n displayName: \"Claude Opus 4\",\n contextWindow: 200_000,\n maxOutputTokens: 32_000,\n pricing: {\n input: 15.0,\n output: 75.0,\n cachedInput: 1.5,\n cacheWriteInput: 18.75,\n },\n knowledgeCutoff: \"2025-03\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n },\n metadata: {\n family: \"Claude 4\",\n releaseDate: \"2025-05-14\",\n notes: \"Legacy Opus model - consider Opus 4.1 for improved reasoning\",\n },\n },\n {\n provider: \"anthropic\",\n modelId: \"claude-3-5-haiku-20241022\",\n displayName: \"Claude Haiku 3.5\",\n contextWindow: 200_000,\n maxOutputTokens: 8_192,\n pricing: {\n input: 0.8,\n output: 4.0,\n cachedInput: 0.08,\n cacheWriteInput: 1.0,\n },\n knowledgeCutoff: \"2024-07\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n },\n metadata: {\n family: \"Claude 3\",\n releaseDate: \"2024-10-22\",\n notes: \"Legacy model - upgrade to Haiku 4.5 for better performance\",\n },\n },\n {\n provider: \"anthropic\",\n modelId: \"claude-3-haiku-20240307\",\n displayName: \"Claude Haiku 3\",\n contextWindow: 200_000,\n maxOutputTokens: 4_096,\n pricing: {\n input: 0.25,\n output: 1.25,\n cachedInput: 0.025,\n cacheWriteInput: 0.3125,\n },\n knowledgeCutoff: \"2023-08\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n },\n metadata: {\n family: \"Claude 3\",\n releaseDate: \"2024-03-07\",\n notes: \"Legacy model - upgrade to Haiku 4.5 for better performance\",\n },\n },\n // Modern aliases (recommended by Anthropic)\n {\n provider: \"anthropic\",\n modelId: \"claude-haiku-4-5\",\n displayName: \"Claude Haiku 4.5\",\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n pricing: {\n input: 1.0,\n output: 5.0,\n cachedInput: 0.1,\n cacheWriteInput: 1.25,\n },\n knowledgeCutoff: \"2025-02\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n },\n metadata: {\n family: \"Claude 4\",\n releaseDate: \"2025-10-01\",\n notes: \"Alias for claude-haiku-4-5-20251001. Fastest model with near-frontier intelligence.\",\n },\n },\n {\n provider: \"anthropic\",\n modelId: \"claude-sonnet-4-5\",\n displayName: \"Claude Sonnet 4.5\",\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n pricing: {\n input: 3.0,\n output: 15.0,\n cachedInput: 0.3,\n cacheWriteInput: 3.75,\n },\n knowledgeCutoff: \"2025-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n },\n metadata: {\n family: \"Claude 4\",\n releaseDate: \"2025-09-29\",\n notes: \"Alias for claude-sonnet-4-5-20250929. Smartest model for complex agents and coding.\",\n },\n },\n {\n provider: \"anthropic\",\n modelId: \"claude-opus-4-5\",\n displayName: \"Claude Opus 4.5\",\n contextWindow: 200_000,\n maxOutputTokens: 64_000,\n pricing: {\n input: 5.0,\n output: 25.0,\n cachedInput: 0.5,\n cacheWriteInput: 6.25,\n },\n knowledgeCutoff: \"2025-03\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n },\n metadata: {\n family: \"Claude 4\",\n releaseDate: \"2025-11-24\",\n notes: \"Alias for claude-opus-4-5-20251124. Most powerful model for coding and computer use.\",\n },\n },\n];\n","/**\n * Base Provider Adapter\n *\n * Abstract base class for provider adapters that implements the Template Method pattern.\n * This class defines the skeleton of the streaming algorithm, leaving provider-specific\n * details to be implemented by concrete subclasses.\n *\n * The streaming workflow consists of four main steps:\n * 1. Prepare messages (optional transformation for provider-specific requirements)\n * 2. Build the request payload (provider-specific formatting)\n * 3. Execute the stream request (call the provider's SDK)\n * 4. Wrap the stream (transform provider-specific chunks into universal format)\n */\n\nimport type { LLMMessage } from \"../core/messages.js\";\nimport type { ModelSpec } from \"../core/model-catalog.js\";\nimport type { LLMGenerationOptions, LLMStream, ModelDescriptor } from \"../core/options.js\";\nimport type { ProviderAdapter } from \"./provider.js\";\n\nexport abstract class BaseProviderAdapter implements ProviderAdapter {\n abstract readonly providerId: string;\n\n constructor(protected readonly client: unknown) {}\n\n abstract supports(descriptor: ModelDescriptor): boolean;\n\n /**\n * Optionally provide model specifications for this provider.\n * This allows the model registry to discover available models and their capabilities.\n */\n getModelSpecs?(): ModelSpec[];\n\n /**\n * Template method that defines the skeleton of the streaming algorithm.\n * This orchestrates the four-step process without dictating provider-specific details.\n */\n async *stream(\n options: LLMGenerationOptions,\n descriptor: ModelDescriptor,\n spec?: ModelSpec,\n ): LLMStream {\n // Step 1: Prepare messages (can be overridden for special cases like Gemini)\n const preparedMessages = this.prepareMessages(options.messages);\n\n // Step 2: Build the provider-specific request payload\n const payload = this.buildApiRequest(options, descriptor, spec, preparedMessages);\n\n // Step 3: Execute the stream request using the provider's SDK (with optional abort signal)\n const rawStream = await this.executeStreamRequest(payload, options.signal);\n\n // Step 4: Normalize provider-specific stream into universal format\n yield* this.normalizeProviderStream(rawStream);\n }\n\n /**\n * Prepare messages for the request.\n * Default implementation returns messages unchanged.\n * Override this to implement provider-specific message transformations\n * (e.g., Gemini's consecutive message merging, Anthropic's system message extraction).\n *\n * @param messages - The input messages\n * @returns Prepared messages\n */\n protected prepareMessages(messages: LLMMessage[]): LLMMessage[] {\n return messages;\n }\n\n /**\n * Build the provider-specific API request.\n * This method must be implemented by each concrete provider.\n *\n * @param options - The generation options\n * @param descriptor - The model descriptor\n * @param spec - Optional model specification with metadata\n * @param messages - The prepared messages\n * @returns Provider-specific request object ready for the API call\n */\n protected abstract buildApiRequest(\n options: LLMGenerationOptions,\n descriptor: ModelDescriptor,\n spec: ModelSpec | undefined,\n messages: LLMMessage[],\n ): unknown;\n\n /**\n * Execute the stream request using the provider's SDK.\n * This method must be implemented by each concrete provider.\n *\n * @param payload - The provider-specific payload\n * @param signal - Optional abort signal for cancelling the request\n * @returns An async iterable of provider-specific chunks\n */\n protected abstract executeStreamRequest(\n payload: unknown,\n signal?: AbortSignal,\n ): Promise<AsyncIterable<unknown>>;\n\n /**\n * Normalize the provider-specific stream into the universal LLMStream format.\n * This method must be implemented by each concrete provider.\n *\n * @param rawStream - The provider-specific stream\n * @returns Universal LLMStream\n */\n protected abstract normalizeProviderStream(rawStream: AsyncIterable<unknown>): LLMStream;\n}\n","/**\n * Provider-specific constants and default values.\n *\n * This file centralizes magic numbers and hardcoded defaults to improve\n * maintainability and documentation. Each constant includes a comment\n * explaining its purpose and rationale.\n */\n\n/**\n * Default maximum output tokens for Anthropic models.\n *\n * Rationale: Most Anthropic models (Claude 3 Opus, Sonnet, Haiku) support\n * at least 4096 output tokens. This is used as a fallback when:\n * - The user doesn't specify maxTokens explicitly\n * - The model spec doesn't define maxOutputTokens\n *\n * Note: Anthropic's API requires the max_tokens parameter, unlike OpenAI\n * which can infer it from the context window. This default ensures the API\n * call succeeds while allowing substantial output.\n *\n * Reference: https://docs.anthropic.com/en/docs/about-claude/models\n */\nexport const ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS = 4096;\n\n/**\n * Character-to-token ratio for fallback token estimation.\n *\n * Rationale: When native token counting APIs fail, we estimate tokens using\n * a rough heuristic of 4 characters per token. This is based on empirical\n * observations across multiple LLM providers:\n * - OpenAI's GPT models average ~4 chars/token for English text\n * - Anthropic's Claude models have similar characteristics\n * - Gemini models also approximate this ratio\n *\n * This is intentionally conservative to avoid underestimating token usage.\n * While not perfectly accurate, it provides a reasonable fallback when\n * precise tokenization is unavailable.\n *\n * Reference: https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them\n */\nexport const FALLBACK_CHARS_PER_TOKEN = 4;\n\n/**\n * OpenAI message structure overhead in tokens.\n *\n * Rationale: OpenAI's chat completion format adds tokens for message\n * boundaries and structure. Each message follows the pattern:\n * <im_start>{role/name}\\n{content}<im_end>\\n\n *\n * This overhead accounts for:\n * - <im_start> token\n * - Role/name field tokens\n * - Newline and separator tokens\n * - <im_end> token\n *\n * The value of 4 tokens per message is based on OpenAI's official\n * tokenization examples and testing.\n *\n * Reference: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb\n */\nexport const OPENAI_MESSAGE_OVERHEAD_TOKENS = 4;\n\n/**\n * OpenAI reply priming overhead in tokens.\n *\n * Rationale: Every OpenAI assistant reply is primed with the tokens:\n * <im_start>assistant\\n\n *\n * This adds 2 tokens to the total input token count before the actual\n * response generation begins. This is part of OpenAI's message formatting\n * and must be accounted for in accurate token counting.\n *\n * Reference: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb\n */\nexport const OPENAI_REPLY_PRIMING_TOKENS = 2;\n\n/**\n * OpenAI name field overhead in tokens.\n *\n * Rationale: When a message includes a \"name\" field (for identifying the\n * speaker in multi-party conversations), OpenAI's format adds 1 extra\n * token beyond the name's actual token count.\n *\n * This accounts for the separator between the role and name fields.\n *\n * Reference: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb\n */\nexport const OPENAI_NAME_FIELD_OVERHEAD_TOKENS = 1;\n","/**\n * Common utility functions shared across provider implementations\n */\n\n/**\n * Safely read an environment variable\n * @param key - The environment variable key to read\n * @returns The value if found and valid, undefined otherwise\n */\nexport function readEnvVar(key: string): string | undefined {\n if (typeof process === \"undefined\" || typeof process.env === \"undefined\") {\n return undefined;\n }\n const value = process.env[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\n/**\n * Check if a value is a non-empty string\n * @param value - The value to check\n * @returns true if the value is a non-empty string, false otherwise\n */\nexport function isNonEmpty(value: string | undefined): value is string {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n\n/**\n * Generic factory function for creating provider instances from environment variables\n * @param envVarName - Name of the environment variable containing the API key\n * @param ClientClass - Constructor for the SDK client\n * @param ProviderClass - Constructor for the provider adapter\n * @param clientOptions - Optional additional options to pass to the client constructor\n * @returns Provider instance or null if API key is not set\n */\nexport function createProviderFromEnv<TClient, TProvider>(\n envVarName: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ClientClass: new (config: any) => TClient,\n ProviderClass: new (client: TClient) => TProvider,\n clientOptions?: Record<string, unknown>,\n): TProvider | null {\n const apiKey = readEnvVar(envVarName);\n if (!isNonEmpty(apiKey)) {\n return null;\n }\n\n // Create client with API key and optional config\n const client = new ClientClass({ apiKey: apiKey.trim(), ...clientOptions });\n\n return new ProviderClass(client);\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type {\n ContentBlockParam,\n ImageBlockParam,\n MessageCreateParamsStreaming,\n MessageStreamEvent,\n TextBlockParam,\n} from \"@anthropic-ai/sdk/resources/messages\";\nimport type { ContentPart, ImageContentPart, ImageMimeType } from \"../core/input-content.js\";\nimport type { LLMMessage, MessageContent } from \"../core/messages.js\";\nimport { extractMessageText, normalizeMessageContent } from \"../core/messages.js\";\nimport type { ModelSpec } from \"../core/model-catalog.js\";\nimport type { LLMGenerationOptions, LLMStream, ModelDescriptor } from \"../core/options.js\";\nimport { ANTHROPIC_MODELS } from \"./anthropic-models.js\";\nimport { BaseProviderAdapter } from \"./base-provider.js\";\nimport { ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS, FALLBACK_CHARS_PER_TOKEN } from \"./constants.js\";\nimport { createProviderFromEnv } from \"./utils.js\";\n\nexport class AnthropicMessagesProvider extends BaseProviderAdapter {\n readonly providerId = \"anthropic\" as const;\n\n supports(descriptor: ModelDescriptor): boolean {\n return descriptor.provider === this.providerId;\n }\n\n getModelSpecs() {\n return ANTHROPIC_MODELS;\n }\n\n // =========================================================================\n // Image Generation (Not Supported)\n // =========================================================================\n\n supportsImageGeneration(_modelId: string): boolean {\n return false;\n }\n\n async generateImage(): Promise<never> {\n throw new Error(\n \"Anthropic does not support image generation. Use OpenAI (DALL-E, GPT Image) or Google Gemini (Imagen) instead.\",\n );\n }\n\n // =========================================================================\n // Speech Generation (Not Supported)\n // =========================================================================\n\n supportsSpeechGeneration(_modelId: string): boolean {\n return false;\n }\n\n async generateSpeech(): Promise<never> {\n throw new Error(\n \"Anthropic does not support speech generation. Use OpenAI (TTS) or Google Gemini (TTS) instead.\",\n );\n }\n\n protected buildApiRequest(\n options: LLMGenerationOptions,\n descriptor: ModelDescriptor,\n spec: ModelSpec | undefined,\n messages: LLMMessage[],\n ): MessageCreateParamsStreaming {\n const systemMessages = messages.filter((message) => message.role === \"system\");\n\n // System message as array of text blocks with cache_control on last block\n // This enables Anthropic's prompt caching for the system prompt\n // System messages are always text-only\n const system =\n systemMessages.length > 0\n ? systemMessages.map((m, index) => ({\n type: \"text\" as const,\n text: extractMessageText(m.content),\n // Add cache_control to the LAST system message block\n ...(index === systemMessages.length - 1\n ? { cache_control: { type: \"ephemeral\" as const } }\n : {}),\n }))\n : undefined;\n\n const nonSystemMessages = messages.filter(\n (message): message is LLMMessage & { role: \"user\" | \"assistant\" } =>\n message.role !== \"system\",\n );\n\n // Find index of last user message for cache breakpoint\n const lastUserIndex = nonSystemMessages.reduce(\n (lastIdx, msg, idx) => (msg.role === \"user\" ? idx : lastIdx),\n -1,\n );\n\n // Build conversation with multimodal content support\n // Cache_control is added to the last part of the last user message\n const conversation = nonSystemMessages.map((message, index) => ({\n role: message.role,\n content: this.convertToAnthropicContent(\n message.content,\n message.role === \"user\" && index === lastUserIndex,\n ),\n }));\n\n // Anthropic requires max_tokens, so use a smart default if not specified\n // Use model's max from the passed spec, or fall back to the default constant\n const defaultMaxTokens = spec?.maxOutputTokens ?? ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS;\n\n const payload: MessageCreateParamsStreaming = {\n model: descriptor.name,\n system,\n messages: conversation,\n max_tokens: options.maxTokens ?? defaultMaxTokens,\n temperature: options.temperature,\n top_p: options.topP,\n stop_sequences: options.stopSequences,\n stream: true,\n ...options.extra,\n };\n\n return payload;\n }\n\n /**\n * Convert llmist content to Anthropic's content block format.\n * Handles text, images (base64 only), and applies cache_control.\n */\n private convertToAnthropicContent(\n content: MessageContent,\n addCacheControl: boolean,\n ): ContentBlockParam[] {\n const parts = normalizeMessageContent(content);\n\n return parts.map((part, index) => {\n const isLastPart = index === parts.length - 1;\n const cacheControl =\n addCacheControl && isLastPart ? { cache_control: { type: \"ephemeral\" as const } } : {};\n\n if (part.type === \"text\") {\n return {\n type: \"text\" as const,\n text: part.text,\n ...cacheControl,\n } as TextBlockParam;\n }\n\n if (part.type === \"image\") {\n return this.convertImagePart(part, cacheControl);\n }\n\n if (part.type === \"audio\") {\n throw new Error(\n \"Anthropic does not support audio input. Use Google Gemini for audio processing.\",\n );\n }\n\n throw new Error(`Unsupported content type: ${(part as ContentPart).type}`);\n });\n }\n\n /**\n * Convert an image content part to Anthropic's image block format.\n */\n private convertImagePart(\n part: ImageContentPart,\n cacheControl: { cache_control?: { type: \"ephemeral\" } },\n ): ImageBlockParam {\n if (part.source.type === \"url\") {\n throw new Error(\n \"Anthropic does not support image URLs. Please provide base64-encoded image data instead.\",\n );\n }\n\n return {\n type: \"image\" as const,\n source: {\n type: \"base64\" as const,\n media_type: part.source.mediaType as ImageMimeType,\n data: part.source.data,\n },\n ...cacheControl,\n };\n }\n\n protected async executeStreamRequest(\n payload: MessageCreateParamsStreaming,\n signal?: AbortSignal,\n ): Promise<AsyncIterable<MessageStreamEvent>> {\n const client = this.client as Anthropic;\n // Pass abort signal to SDK via request options\n const stream = await client.messages.create(payload, signal ? { signal } : undefined);\n return stream as unknown as AsyncIterable<MessageStreamEvent>;\n }\n\n protected async *normalizeProviderStream(iterable: AsyncIterable<unknown>): LLMStream {\n const stream = iterable as AsyncIterable<MessageStreamEvent>;\n let inputTokens = 0;\n let cachedInputTokens = 0;\n let cacheCreationInputTokens = 0;\n\n for await (const event of stream) {\n // Track and yield input tokens from message_start event\n // Anthropic returns cache_read_input_tokens and cache_creation_input_tokens\n if (event.type === \"message_start\") {\n const usage = event.message.usage as {\n input_tokens: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n // Total input tokens includes uncached + cached reads + cache writes\n cachedInputTokens = usage.cache_read_input_tokens ?? 0;\n cacheCreationInputTokens = usage.cache_creation_input_tokens ?? 0;\n inputTokens = usage.input_tokens + cachedInputTokens + cacheCreationInputTokens;\n // Yield early so hooks can access input tokens before text streams\n yield {\n text: \"\",\n usage: {\n inputTokens,\n outputTokens: 0,\n totalTokens: inputTokens,\n cachedInputTokens,\n cacheCreationInputTokens,\n },\n rawEvent: event,\n };\n continue;\n }\n\n if (event.type === \"content_block_delta\" && event.delta.type === \"text_delta\") {\n yield { text: event.delta.text ?? \"\", rawEvent: event };\n continue;\n }\n\n if (event.type === \"message_delta\") {\n const usage = event.usage\n ? {\n inputTokens,\n outputTokens: event.usage.output_tokens,\n totalTokens: inputTokens + event.usage.output_tokens,\n cachedInputTokens,\n cacheCreationInputTokens,\n }\n : undefined;\n\n if (event.delta.stop_reason || usage) {\n yield {\n text: \"\",\n finishReason: event.delta.stop_reason ?? undefined,\n usage,\n rawEvent: event,\n };\n }\n continue;\n }\n\n if (event.type === \"message_stop\") {\n yield { text: \"\", finishReason: \"stop\", rawEvent: event };\n }\n }\n }\n\n /**\n * Count tokens in messages using Anthropic's native token counting API.\n *\n * This method provides accurate token estimation for Anthropic models by:\n * - Using the native messages.countTokens() API\n * - Properly handling system messages and conversation structure\n * - Transforming messages to Anthropic's expected format\n *\n * @param messages - The messages to count tokens for\n * @param descriptor - Model descriptor containing the model name\n * @param _spec - Optional model specification (currently unused)\n * @returns Promise resolving to the estimated input token count\n *\n * @throws Never throws - falls back to character-based estimation (4 chars/token) on error\n *\n * @example\n * ```typescript\n * const count = await provider.countTokens(\n * [{ role: \"user\", content: \"Hello!\" }],\n * { provider: \"anthropic\", name: \"claude-3-5-sonnet-20241022\" }\n * );\n * ```\n */\n async countTokens(\n messages: LLMMessage[],\n descriptor: ModelDescriptor,\n _spec?: ModelSpec,\n ): Promise<number> {\n const client = this.client as Anthropic;\n\n // Extract system messages and conversation messages\n const systemMessages = messages.filter((message) => message.role === \"system\");\n const system =\n systemMessages.length > 0\n ? systemMessages.map((m) => extractMessageText(m.content)).join(\"\\n\\n\")\n : undefined;\n\n // Convert messages to Anthropic format, handling multimodal content\n const conversation = messages\n .filter(\n (message): message is LLMMessage & { role: \"user\" | \"assistant\" } =>\n message.role !== \"system\",\n )\n .map((message) => ({\n role: message.role,\n content: this.convertToAnthropicContent(message.content, false),\n }));\n\n try {\n // Use the native token counting API\n const response = await client.messages.countTokens({\n model: descriptor.name,\n messages: conversation,\n ...(system ? { system } : {}),\n });\n\n return response.input_tokens;\n } catch (error) {\n // Log the error for debugging\n console.warn(\n `Token counting failed for ${descriptor.name}, using fallback estimation:`,\n error,\n );\n // Fallback to rough estimation if API fails\n // For multimodal, extract text and estimate; images add ~1000 tokens\n let totalChars = 0;\n let imageCount = 0;\n for (const msg of messages) {\n const parts = normalizeMessageContent(msg.content);\n for (const part of parts) {\n if (part.type === \"text\") {\n totalChars += part.text.length;\n } else if (part.type === \"image\") {\n imageCount++;\n }\n }\n }\n // Anthropic charges ~1000 tokens per image (rough estimate).\n // Source: https://docs.anthropic.com/en/docs/build-with-claude/vision\n // Actual cost depends on image size, but this provides a reasonable fallback.\n return Math.ceil(totalChars / FALLBACK_CHARS_PER_TOKEN) + imageCount * 1000;\n }\n }\n}\n\nexport function createAnthropicProviderFromEnv(): AnthropicMessagesProvider | null {\n return createProviderFromEnv(\"ANTHROPIC_API_KEY\", Anthropic, AnthropicMessagesProvider);\n}\n","/**\n * Google Gemini Image Generation Model Catalog\n *\n * Pricing as of December 2025:\n *\n * Imagen 4 Family (standalone image generation):\n * - imagen-4.0-fast-generate-001: $0.02 per image\n * - imagen-4.0-generate-001: $0.04 per image\n * - imagen-4.0-ultra-generate-001: $0.06 per image\n *\n * Gemini Native Image Generation (multimodal):\n * - gemini-2.5-flash-image: $0.039 per output image\n * - gemini-3-pro-image-preview: ~$0.134 per 1K/2K image, $0.24 per 4K\n *\n * @see https://ai.google.dev/gemini-api/docs/pricing\n * @see https://ai.google.dev/gemini-api/docs/imagen\n */\n\nimport type { ImageModelSpec } from \"../core/media-types.js\";\n\n/** Imagen 4 supported aspect ratios */\nexport const IMAGEN4_ASPECT_RATIOS = [\"1:1\", \"3:4\", \"4:3\", \"9:16\", \"16:9\"] as const;\nexport type Imagen4AspectRatio = (typeof IMAGEN4_ASPECT_RATIOS)[number];\n\n/** Gemini native image supported aspect ratios */\nexport const GEMINI_IMAGE_ASPECT_RATIOS = [\"1:1\", \"3:4\", \"4:3\", \"9:16\", \"16:9\"] as const;\n\n/**\n * Google Image Model Specifications\n */\nexport const geminiImageModels: ImageModelSpec[] = [\n // Imagen 4 Family (standalone image generation)\n {\n provider: \"gemini\",\n modelId: \"imagen-4.0-fast-generate-001\",\n displayName: \"Imagen 4 Fast\",\n pricing: {\n perImage: 0.02,\n },\n supportedSizes: [...IMAGEN4_ASPECT_RATIOS],\n maxImages: 4,\n defaultSize: \"1:1\",\n features: {\n textRendering: true,\n },\n },\n {\n provider: \"gemini\",\n modelId: \"imagen-4.0-generate-001\",\n displayName: \"Imagen 4\",\n pricing: {\n perImage: 0.04,\n },\n supportedSizes: [...IMAGEN4_ASPECT_RATIOS],\n maxImages: 4,\n defaultSize: \"1:1\",\n features: {\n textRendering: true,\n },\n },\n {\n provider: \"gemini\",\n modelId: \"imagen-4.0-ultra-generate-001\",\n displayName: \"Imagen 4 Ultra\",\n pricing: {\n perImage: 0.06,\n },\n supportedSizes: [...IMAGEN4_ASPECT_RATIOS],\n maxImages: 4,\n defaultSize: \"1:1\",\n features: {\n textRendering: true,\n },\n },\n // Preview versions\n {\n provider: \"gemini\",\n modelId: \"imagen-4.0-generate-preview-06-06\",\n displayName: \"Imagen 4 (Preview)\",\n pricing: {\n perImage: 0.04,\n },\n supportedSizes: [...IMAGEN4_ASPECT_RATIOS],\n maxImages: 4,\n defaultSize: \"1:1\",\n features: {\n textRendering: true,\n },\n },\n {\n provider: \"gemini\",\n modelId: \"imagen-4.0-ultra-generate-preview-06-06\",\n displayName: \"Imagen 4 Ultra (Preview)\",\n pricing: {\n perImage: 0.06,\n },\n supportedSizes: [...IMAGEN4_ASPECT_RATIOS],\n maxImages: 4,\n defaultSize: \"1:1\",\n features: {\n textRendering: true,\n },\n },\n // Gemini Native Image Generation (multimodal models)\n {\n provider: \"gemini\",\n modelId: \"gemini-2.5-flash-image\",\n displayName: \"Gemini 2.5 Flash Image\",\n pricing: {\n perImage: 0.039,\n },\n supportedSizes: [...GEMINI_IMAGE_ASPECT_RATIOS],\n maxImages: 1,\n defaultSize: \"1:1\",\n features: {\n conversational: true,\n textRendering: true,\n },\n },\n {\n provider: \"gemini\",\n modelId: \"gemini-2.5-flash-image-preview\",\n displayName: \"Gemini 2.5 Flash Image (Preview)\",\n pricing: {\n perImage: 0.039,\n },\n supportedSizes: [...GEMINI_IMAGE_ASPECT_RATIOS],\n maxImages: 1,\n defaultSize: \"1:1\",\n features: {\n conversational: true,\n textRendering: true,\n },\n },\n {\n provider: \"gemini\",\n modelId: \"gemini-3-pro-image-preview\",\n displayName: \"Gemini 3 Pro Image (Preview)\",\n pricing: {\n // Token-based: ~$0.134 per 1K/2K image, $0.24 per 4K\n // Using 2K as default\n bySize: {\n \"1K\": 0.134,\n \"2K\": 0.134,\n \"4K\": 0.24,\n },\n },\n supportedSizes: [\"1K\", \"2K\", \"4K\"],\n maxImages: 1,\n defaultSize: \"2K\",\n features: {\n conversational: true,\n textRendering: true,\n },\n },\n // Alias: nano-banana-pro-preview is gemini-3-pro-image-preview\n {\n provider: \"gemini\",\n modelId: \"nano-banana-pro-preview\",\n displayName: \"Nano Banana Pro (Gemini 3 Pro Image)\",\n pricing: {\n bySize: {\n \"1K\": 0.134,\n \"2K\": 0.134,\n \"4K\": 0.24,\n },\n },\n supportedSizes: [\"1K\", \"2K\", \"4K\"],\n maxImages: 1,\n defaultSize: \"2K\",\n features: {\n conversational: true,\n textRendering: true,\n },\n },\n];\n\n/**\n * Get image model spec by model ID.\n */\nexport function getGeminiImageModelSpec(modelId: string): ImageModelSpec | undefined {\n return geminiImageModels.find((m) => m.modelId === modelId);\n}\n\n/**\n * Check if a model ID is a Gemini image model.\n */\nexport function isGeminiImageModel(modelId: string): boolean {\n return geminiImageModels.some((m) => m.modelId === modelId);\n}\n\n/**\n * Calculate cost for image generation.\n *\n * @param modelId - The model ID\n * @param size - Image size (for models with size-based pricing)\n * @param n - Number of images\n * @returns Cost in USD, or undefined if model not found\n */\nexport function calculateGeminiImageCost(modelId: string, size = \"1:1\", n = 1): number | undefined {\n const spec = getGeminiImageModelSpec(modelId);\n if (!spec) return undefined;\n\n // Simple per-image pricing (Imagen 4, Gemini Flash Image)\n if (spec.pricing.perImage !== undefined) {\n return spec.pricing.perImage * n;\n }\n\n // Size-based pricing (Gemini 3 Pro Image)\n if (spec.pricing.bySize) {\n const sizePrice = spec.pricing.bySize[size];\n if (typeof sizePrice === \"number\") {\n return sizePrice * n;\n }\n }\n\n return undefined;\n}\n","/**\n * Google Gemini Model Specifications\n *\n * Model data for Google Gemini models including 3.0, 2.5 and 2.0 series\n * with their specifications, pricing (Standard Paid tier), and capabilities.\n *\n * Pricing source: https://ai.google.dev/gemini-api/docs/pricing\n * Last updated: 2025-11-29\n */\n\nimport type { ModelSpec } from \"../core/model-catalog.js\";\n\nexport const GEMINI_MODELS: ModelSpec[] = [\n // Gemini 3 Pro (Preview)\n {\n provider: \"gemini\",\n modelId: \"gemini-3-pro-preview\",\n displayName: \"Gemini 3 Pro (Preview)\",\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n pricing: {\n input: 2.0, // $2.00 for prompts <= 200k, $4.00 for > 200k (using lower tier)\n output: 12.0, // $12.00 for prompts <= 200k, $18.00 for > 200k\n cachedInput: 0.2, // $0.20 for prompts <= 200k\n },\n knowledgeCutoff: \"2025-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n structuredOutputs: true,\n },\n metadata: {\n family: \"Gemini 3\",\n releaseDate: \"2025-11-18\",\n notes:\n \"Best model for multimodal understanding, agentic and vibe-coding. Deep Think mode available.\",\n },\n },\n\n // Gemini 2.5 Pro\n {\n provider: \"gemini\",\n modelId: \"gemini-2.5-pro\",\n displayName: \"Gemini 2.5 Pro\",\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n pricing: {\n input: 1.25, // $1.25 for prompts <= 200k, $2.50 for > 200k\n output: 10.0, // $10.00 for prompts <= 200k, $15.00 for > 200k\n cachedInput: 0.125, // $0.125 for prompts <= 200k\n },\n knowledgeCutoff: \"2025-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n structuredOutputs: true,\n },\n metadata: {\n family: \"Gemini 2.5\",\n releaseDate: \"2025-06\",\n notes: \"State-of-the-art multipurpose model. Excels at coding and complex reasoning.\",\n },\n },\n\n // Gemini 2.5 Flash\n {\n provider: \"gemini\",\n modelId: \"gemini-2.5-flash\",\n displayName: \"Gemini 2.5 Flash\",\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n pricing: {\n input: 0.3, // $0.30 for text/image/video, $1.00 for audio\n output: 2.5,\n cachedInput: 0.03, // $0.03 for text/image/video\n },\n knowledgeCutoff: \"2025-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n structuredOutputs: true,\n },\n metadata: {\n family: \"Gemini 2.5\",\n releaseDate: \"2025-06\",\n notes: \"First hybrid reasoning model with 1M context and thinking budgets.\",\n },\n },\n\n // Gemini 2.5 Flash-Lite\n {\n provider: \"gemini\",\n modelId: \"gemini-2.5-flash-lite\",\n displayName: \"Gemini 2.5 Flash-Lite\",\n contextWindow: 1_048_576,\n maxOutputTokens: 65_536,\n pricing: {\n input: 0.1, // $0.10 for text/image/video, $0.30 for audio\n output: 0.4,\n cachedInput: 0.01, // $0.01 for text/image/video\n },\n knowledgeCutoff: \"2025-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n structuredOutputs: true,\n },\n metadata: {\n family: \"Gemini 2.5\",\n releaseDate: \"2025-06\",\n notes: \"Smallest and most cost effective model, built for at scale usage.\",\n },\n },\n\n // Gemini 2.0 Flash\n {\n provider: \"gemini\",\n modelId: \"gemini-2.0-flash\",\n displayName: \"Gemini 2.0 Flash\",\n contextWindow: 1_048_576,\n maxOutputTokens: 8_192,\n pricing: {\n input: 0.1, // $0.10 for text/image/video, $0.70 for audio\n output: 0.4,\n cachedInput: 0.025, // $0.025 for text/image/video\n },\n knowledgeCutoff: \"2024-08\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n structuredOutputs: true,\n },\n metadata: {\n family: \"Gemini 2.0\",\n notes: \"Balanced multimodal model with 1M context, built for the era of Agents.\",\n },\n },\n\n // Gemini 2.0 Flash-Lite\n {\n provider: \"gemini\",\n modelId: \"gemini-2.0-flash-lite\",\n displayName: \"Gemini 2.0 Flash-Lite\",\n contextWindow: 1_048_576,\n maxOutputTokens: 8_192,\n pricing: {\n input: 0.075,\n output: 0.3,\n // No context caching available for 2.0-flash-lite\n },\n knowledgeCutoff: \"2024-08\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n structuredOutputs: true,\n },\n metadata: {\n family: \"Gemini 2.0\",\n notes: \"Smallest and most cost effective 2.0 model for at scale usage.\",\n },\n },\n];\n","/**\n * Google Gemini Speech (TTS) Model Catalog\n *\n * Pricing as of December 2025 (per 1M tokens):\n *\n * Gemini 2.5 Flash Preview TTS:\n * - Input (text): $0.50\n * - Output (audio): $10.00\n *\n * Gemini 2.5 Pro Preview TTS:\n * - Input (text): $1.00\n * - Output (audio): $20.00\n *\n * @see https://ai.google.dev/gemini-api/docs/pricing\n * @see https://ai.google.dev/gemini-api/docs/speech-generation\n */\n\nimport type { AudioFormat, SpeechModelSpec } from \"../core/media-types.js\";\n\n/**\n * Gemini TTS voices (30 prebuilt voices)\n * Each has distinct characteristics like \"Bright\", \"Upbeat\", \"Breathy\", \"Warm\", etc.\n */\nexport const GEMINI_TTS_VOICES = [\n \"Zephyr\", // Bright\n \"Puck\", // Upbeat\n \"Charon\", // Informative\n \"Kore\", // Firm\n \"Fenrir\", // Excitable\n \"Leda\", // Youthful\n \"Orus\", // Firm\n \"Aoede\", // Breezy\n \"Callirrhoe\", // Easy-going\n \"Autonoe\", // Bright\n \"Enceladus\", // Breathy\n \"Iapetus\", // Clear\n \"Umbriel\", // Easy-going\n \"Algieba\", // Smooth\n \"Despina\", // Smooth\n \"Erinome\", // Clear\n \"Algenib\", // Gravelly\n \"Rasalgethi\", // Informative\n \"Laomedeia\", // Upbeat\n \"Achernar\", // Soft\n \"Alnilam\", // Firm\n \"Schedar\", // Even\n \"Gacrux\", // Mature\n \"Pulcherrima\", // Forward\n \"Achird\", // Friendly\n \"Zubenelgenubi\", // Casual\n \"Vindemiatrix\", // Gentle\n \"Sadachbia\", // Lively\n \"Sadaltager\", // Knowledgeable\n \"Sulafat\", // Warm\n] as const;\n\nexport type GeminiTTSVoice = (typeof GEMINI_TTS_VOICES)[number];\n\n/** Gemini TTS supported audio format (PCM only, converted to WAV) */\nexport const GEMINI_TTS_FORMATS: AudioFormat[] = [\"pcm\", \"wav\"];\n\n/**\n * Gemini Speech Model Specifications\n */\nexport const geminiSpeechModels: SpeechModelSpec[] = [\n {\n provider: \"gemini\",\n modelId: \"gemini-2.5-flash-preview-tts\",\n displayName: \"Gemini 2.5 Flash TTS (Preview)\",\n pricing: {\n // $0.50 per 1M input tokens = $0.0000005 per token\n perInputToken: 0.0000005,\n // $10.00 per 1M audio output tokens = $0.00001 per token\n perAudioOutputToken: 0.00001,\n // Rough estimate: ~$0.01 per minute of audio\n perMinute: 0.01,\n },\n voices: [...GEMINI_TTS_VOICES],\n formats: GEMINI_TTS_FORMATS,\n maxInputLength: 8000, // bytes (text + prompt combined)\n defaultVoice: \"Zephyr\",\n defaultFormat: \"wav\",\n features: {\n multiSpeaker: true,\n languages: 24,\n voiceInstructions: true,\n },\n },\n {\n provider: \"gemini\",\n modelId: \"gemini-2.5-pro-preview-tts\",\n displayName: \"Gemini 2.5 Pro TTS (Preview)\",\n pricing: {\n // $1.00 per 1M input tokens = $0.000001 per token\n perInputToken: 0.000001,\n // $20.00 per 1M audio output tokens = $0.00002 per token\n perAudioOutputToken: 0.00002,\n // Rough estimate: ~$0.02 per minute of audio\n perMinute: 0.02,\n },\n voices: [...GEMINI_TTS_VOICES],\n formats: GEMINI_TTS_FORMATS,\n maxInputLength: 8000, // bytes\n defaultVoice: \"Zephyr\",\n defaultFormat: \"wav\",\n features: {\n multiSpeaker: true,\n languages: 24,\n voiceInstructions: true,\n },\n },\n];\n\n/**\n * Get speech model spec by model ID.\n */\nexport function getGeminiSpeechModelSpec(modelId: string): SpeechModelSpec | undefined {\n return geminiSpeechModels.find((m) => m.modelId === modelId);\n}\n\n/**\n * Check if a model ID is a Gemini speech model.\n */\nexport function isGeminiSpeechModel(modelId: string): boolean {\n return geminiSpeechModels.some((m) => m.modelId === modelId);\n}\n\n/**\n * Calculate cost for speech generation.\n *\n * Uses per-minute approximation since exact token counts are hard to predict.\n *\n * @param modelId - The model ID\n * @param characterCount - Number of characters in the input\n * @param estimatedMinutes - Optional: estimated audio duration\n * @returns Cost in USD, or undefined if model not found\n */\nexport function calculateGeminiSpeechCost(\n modelId: string,\n characterCount: number,\n estimatedMinutes?: number,\n): number | undefined {\n const spec = getGeminiSpeechModelSpec(modelId);\n if (!spec) return undefined;\n\n // Use per-minute approximation\n if (spec.pricing.perMinute !== undefined) {\n if (estimatedMinutes !== undefined) {\n return estimatedMinutes * spec.pricing.perMinute;\n }\n // Fallback: rough estimate based on ~150 words/min, ~5 chars/word\n // ~750 chars/min of audio\n const approxMinutes = characterCount / 750;\n return approxMinutes * spec.pricing.perMinute;\n }\n\n return undefined;\n}\n","import { FunctionCallingConfigMode, GoogleGenAI, Modality } from \"@google/genai\";\nimport type { ContentPart } from \"../core/input-content.js\";\nimport type {\n ImageGenerationOptions,\n ImageGenerationResult,\n ImageModelSpec,\n SpeechGenerationOptions,\n SpeechGenerationResult,\n SpeechModelSpec,\n} from \"../core/media-types.js\";\nimport type { LLMMessage, MessageContent } from \"../core/messages.js\";\nimport { extractMessageText, normalizeMessageContent } from \"../core/messages.js\";\nimport type { ModelSpec } from \"../core/model-catalog.js\";\nimport type { LLMGenerationOptions, LLMStream, ModelDescriptor } from \"../core/options.js\";\nimport { BaseProviderAdapter } from \"./base-provider.js\";\nimport { FALLBACK_CHARS_PER_TOKEN } from \"./constants.js\";\nimport {\n calculateGeminiImageCost,\n geminiImageModels,\n getGeminiImageModelSpec,\n isGeminiImageModel,\n} from \"./gemini-image-models.js\";\nimport { GEMINI_MODELS } from \"./gemini-models.js\";\nimport {\n calculateGeminiSpeechCost,\n geminiSpeechModels,\n getGeminiSpeechModelSpec,\n isGeminiSpeechModel,\n} from \"./gemini-speech-models.js\";\nimport { createProviderFromEnv } from \"./utils.js\";\n\n/**\n * Gemini content part - can be text or inline data (images/audio).\n */\ntype GeminiPart = { text: string } | { inlineData: { mimeType: string; data: string } };\n\n/**\n * Gemini content with role and multimodal parts.\n */\ntype GeminiContent = {\n role: string;\n parts: GeminiPart[];\n};\n\ntype GeminiChunk = {\n text?: () => string;\n candidates?: Array<{\n content?: {\n parts?: Array<{ text?: string }>;\n };\n finishReason?: string;\n }>;\n usageMetadata?: {\n promptTokenCount?: number;\n candidatesTokenCount?: number;\n totalTokenCount?: number;\n cachedContentTokenCount?: number;\n };\n};\n\nconst GEMINI_ROLE_MAP: Record<LLMMessage[\"role\"], \"user\" | \"model\"> = {\n system: \"user\",\n user: \"user\",\n assistant: \"model\",\n};\n\n/**\n * Wraps raw PCM audio data in a WAV file container.\n *\n * WAV format structure:\n * - RIFF header (12 bytes)\n * - fmt chunk (24 bytes) - describes audio format\n * - data chunk (8 bytes + audio data)\n *\n * @param pcmData - Raw PCM audio samples\n * @param sampleRate - Sample rate in Hz (e.g., 24000)\n * @param bitsPerSample - Bits per sample (e.g., 16)\n * @param numChannels - Number of audio channels (1 = mono, 2 = stereo)\n * @returns ArrayBuffer containing valid WAV file\n */\nfunction wrapPcmInWav(\n pcmData: Uint8Array,\n sampleRate: number,\n bitsPerSample: number,\n numChannels: number,\n): ArrayBuffer {\n const byteRate = (sampleRate * numChannels * bitsPerSample) / 8;\n const blockAlign = (numChannels * bitsPerSample) / 8;\n const dataSize = pcmData.length;\n const headerSize = 44;\n const fileSize = headerSize + dataSize - 8; // File size minus RIFF header\n\n const buffer = new ArrayBuffer(headerSize + dataSize);\n const view = new DataView(buffer);\n const uint8 = new Uint8Array(buffer);\n\n // RIFF header\n view.setUint32(0, 0x52494646, false); // \"RIFF\"\n view.setUint32(4, fileSize, true); // File size - 8\n view.setUint32(8, 0x57415645, false); // \"WAVE\"\n\n // fmt chunk\n view.setUint32(12, 0x666d7420, false); // \"fmt \"\n view.setUint32(16, 16, true); // fmt chunk size (16 for PCM)\n view.setUint16(20, 1, true); // Audio format (1 = PCM)\n view.setUint16(22, numChannels, true); // Number of channels\n view.setUint32(24, sampleRate, true); // Sample rate\n view.setUint32(28, byteRate, true); // Byte rate\n view.setUint16(32, blockAlign, true); // Block align\n view.setUint16(34, bitsPerSample, true); // Bits per sample\n\n // data chunk\n view.setUint32(36, 0x64617461, false); // \"data\"\n view.setUint32(40, dataSize, true); // Data size\n\n // Copy PCM data\n uint8.set(pcmData, headerSize);\n\n return buffer;\n}\n\nexport class GeminiGenerativeProvider extends BaseProviderAdapter {\n readonly providerId = \"gemini\" as const;\n\n supports(descriptor: ModelDescriptor): boolean {\n return descriptor.provider === this.providerId;\n }\n\n getModelSpecs() {\n return GEMINI_MODELS;\n }\n\n // =========================================================================\n // Image Generation\n // =========================================================================\n\n getImageModelSpecs(): ImageModelSpec[] {\n return geminiImageModels;\n }\n\n supportsImageGeneration(modelId: string): boolean {\n return isGeminiImageModel(modelId);\n }\n\n async generateImage(options: ImageGenerationOptions): Promise<ImageGenerationResult> {\n const client = this.client as GoogleGenAI;\n const spec = getGeminiImageModelSpec(options.model);\n const isImagenModel = options.model.startsWith(\"imagen\");\n\n const aspectRatio = options.size ?? spec?.defaultSize ?? \"1:1\";\n const n = options.n ?? 1;\n\n if (isImagenModel) {\n // Use Imagen API for imagen models\n // Note: safetyFilterLevel and personGeneration can be configured for less restrictive filtering\n // Valid safetyFilterLevel values: \"BLOCK_NONE\" | \"BLOCK_ONLY_HIGH\" | \"BLOCK_MEDIUM_AND_ABOVE\" | \"BLOCK_LOW_AND_ABOVE\"\n // Valid personGeneration values: \"ALLOW_ALL\" | \"ALLOW_ADULT\" | \"DONT_ALLOW\"\n const response = await client.models.generateImages({\n model: options.model,\n prompt: options.prompt,\n config: {\n numberOfImages: n,\n aspectRatio: aspectRatio,\n outputMimeType: options.responseFormat === \"b64_json\" ? \"image/png\" : \"image/jpeg\",\n },\n });\n\n const images = response.generatedImages ?? [];\n const cost = calculateGeminiImageCost(options.model, aspectRatio, images.length);\n\n return {\n // Gemini's imageBytes is already base64 encoded, so use it directly\n images: images.map((img) => ({\n b64Json: img.image?.imageBytes ?? undefined,\n })),\n model: options.model,\n usage: {\n imagesGenerated: images.length,\n size: aspectRatio,\n quality: \"standard\",\n },\n cost,\n };\n }\n // Use native Gemini image generation for gemini-* models\n const response = await client.models.generateContent({\n model: options.model,\n contents: [{ role: \"user\", parts: [{ text: options.prompt }] }],\n config: {\n responseModalities: [Modality.IMAGE, Modality.TEXT],\n },\n });\n\n // Extract images from response\n const images: Array<{ b64Json?: string; url?: string }> = [];\n const candidate = response.candidates?.[0];\n if (candidate?.content?.parts) {\n for (const part of candidate.content.parts) {\n if (\"inlineData\" in part && part.inlineData) {\n images.push({\n b64Json: part.inlineData.data,\n });\n }\n }\n }\n\n const cost = calculateGeminiImageCost(options.model, aspectRatio, images.length);\n\n return {\n images,\n model: options.model,\n usage: {\n imagesGenerated: images.length,\n size: aspectRatio,\n quality: \"standard\",\n },\n cost,\n };\n }\n\n // =========================================================================\n // Speech Generation\n // =========================================================================\n\n getSpeechModelSpecs(): SpeechModelSpec[] {\n return geminiSpeechModels;\n }\n\n supportsSpeechGeneration(modelId: string): boolean {\n return isGeminiSpeechModel(modelId);\n }\n\n async generateSpeech(options: SpeechGenerationOptions): Promise<SpeechGenerationResult> {\n const client = this.client as GoogleGenAI;\n const spec = getGeminiSpeechModelSpec(options.model);\n\n const voice = options.voice ?? spec?.defaultVoice ?? \"Zephyr\";\n\n // Gemini TTS uses speech configuration\n const response = await client.models.generateContent({\n model: options.model,\n contents: [\n {\n role: \"user\",\n parts: [{ text: options.input }],\n },\n ],\n config: {\n responseModalities: [Modality.AUDIO],\n speechConfig: {\n voiceConfig: {\n prebuiltVoiceConfig: {\n voiceName: voice,\n },\n },\n },\n },\n });\n\n // Extract audio from response\n let pcmData: Uint8Array | undefined;\n const candidate = response.candidates?.[0];\n if (candidate?.content?.parts) {\n for (const part of candidate.content.parts) {\n if (\"inlineData\" in part && part.inlineData?.data) {\n // Convert base64 to Uint8Array\n const base64 = part.inlineData.data;\n const binary = atob(base64);\n pcmData = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n pcmData[i] = binary.charCodeAt(i);\n }\n break;\n }\n }\n }\n\n if (!pcmData) {\n throw new Error(\"No audio data in Gemini TTS response\");\n }\n\n // Wrap raw PCM data in WAV headers (Gemini returns 24kHz, 16-bit, mono PCM)\n const audioData = wrapPcmInWav(pcmData, 24000, 16, 1);\n\n const cost = calculateGeminiSpeechCost(options.model, options.input.length);\n\n return {\n audio: audioData,\n model: options.model,\n usage: {\n characterCount: options.input.length,\n },\n cost,\n format: spec?.defaultFormat ?? \"wav\",\n };\n }\n\n protected buildApiRequest(\n options: LLMGenerationOptions,\n descriptor: ModelDescriptor,\n _spec: ModelSpec | undefined,\n messages: LLMMessage[],\n ): {\n model: string;\n contents: GeminiContent[];\n config: Record<string, unknown>;\n } {\n // Convert messages to Gemini format (system messages become user+model exchanges)\n const contents = this.convertMessagesToContents(messages);\n const generationConfig = this.buildGenerationConfig(options);\n\n // Build the config object for the new SDK\n const config: Record<string, unknown> = {\n // Note: systemInstruction removed - it doesn't work with countTokens()\n // System messages are now included in contents as user+model exchanges\n ...(generationConfig ? { ...generationConfig } : {}),\n // Explicitly disable function calling to prevent UNEXPECTED_TOOL_CALL errors\n toolConfig: {\n functionCallingConfig: {\n mode: FunctionCallingConfigMode.NONE,\n },\n },\n ...options.extra,\n };\n\n return {\n model: descriptor.name,\n contents,\n config,\n };\n }\n\n protected async executeStreamRequest(\n payload: {\n model: string;\n contents: GeminiContent[];\n config: Record<string, unknown>;\n },\n signal?: AbortSignal,\n ): Promise<AsyncIterable<GeminiChunk>> {\n const client = this.client as GoogleGenAI;\n // Gemini SDK uses abortSignal in the config object\n const streamResponse = await client.models.generateContentStream({\n ...payload,\n config: {\n ...payload.config,\n ...(signal ? { abortSignal: signal } : {}),\n },\n });\n return streamResponse as unknown as AsyncIterable<GeminiChunk>;\n }\n\n /**\n * Convert LLM messages to Gemini contents format.\n *\n * For Gemini, we convert system messages to user+model exchanges instead of\n * using systemInstruction, because:\n * 1. systemInstruction doesn't work with countTokens() API\n * 2. This approach gives perfect token counting accuracy (0% error)\n * 3. The model receives and follows system instructions identically\n *\n * System message: \"You are a helpful assistant\"\n * Becomes:\n * - User: \"You are a helpful assistant\"\n * - Model: \"Understood.\"\n */\n private convertMessagesToContents(messages: LLMMessage[]): GeminiContent[] {\n const expandedMessages: Array<{ role: LLMMessage[\"role\"]; content: MessageContent }> = [];\n\n for (const message of messages) {\n if (message.role === \"system\") {\n // Convert system message to user+model exchange\n // System messages are always text-only\n expandedMessages.push({\n role: \"user\",\n content: extractMessageText(message.content),\n });\n expandedMessages.push({\n role: \"assistant\",\n content: \"Understood.\",\n });\n } else {\n expandedMessages.push({\n role: message.role,\n content: message.content,\n });\n }\n }\n\n return this.mergeConsecutiveMessages(expandedMessages);\n }\n\n /**\n * Merge consecutive messages with the same role (required by Gemini).\n * Handles multimodal content by converting to Gemini's part format.\n */\n private mergeConsecutiveMessages(\n messages: Array<{ role: LLMMessage[\"role\"]; content: MessageContent }>,\n ): GeminiContent[] {\n if (messages.length === 0) {\n return [];\n }\n\n const result: GeminiContent[] = [];\n let currentGroup: GeminiContent | null = null;\n\n for (const message of messages) {\n const geminiRole = GEMINI_ROLE_MAP[message.role];\n const geminiParts = this.convertToGeminiParts(message.content);\n\n if (currentGroup && currentGroup.role === geminiRole) {\n // Merge into current group\n currentGroup.parts.push(...geminiParts);\n } else {\n // Start new group\n if (currentGroup) {\n result.push(currentGroup);\n }\n currentGroup = {\n role: geminiRole,\n parts: geminiParts,\n };\n }\n }\n\n // Push the last group\n if (currentGroup) {\n result.push(currentGroup);\n }\n\n return result;\n }\n\n /**\n * Convert llmist content to Gemini's part format.\n * Handles text, images, and audio (Gemini supports all three).\n */\n private convertToGeminiParts(content: MessageContent): GeminiPart[] {\n const parts = normalizeMessageContent(content);\n\n return parts.map((part) => {\n if (part.type === \"text\") {\n return { text: part.text };\n }\n\n if (part.type === \"image\") {\n if (part.source.type === \"url\") {\n throw new Error(\n \"Gemini does not support image URLs directly. Please provide base64-encoded image data.\",\n );\n }\n return {\n inlineData: {\n mimeType: part.source.mediaType,\n data: part.source.data,\n },\n };\n }\n\n if (part.type === \"audio\") {\n return {\n inlineData: {\n mimeType: part.source.mediaType,\n data: part.source.data,\n },\n };\n }\n\n throw new Error(`Unsupported content type: ${(part as ContentPart).type}`);\n });\n }\n\n private buildGenerationConfig(options: LLMGenerationOptions) {\n const config: Record<string, unknown> = {};\n\n // Only set maxOutputTokens if explicitly provided\n // Otherwise let Gemini use \"as much as fits\" in the context window\n if (typeof options.maxTokens === \"number\") {\n config.maxOutputTokens = options.maxTokens;\n }\n\n if (typeof options.temperature === \"number\") {\n config.temperature = options.temperature;\n }\n if (typeof options.topP === \"number\") {\n config.topP = options.topP;\n }\n if (options.stopSequences?.length) {\n config.stopSequences = options.stopSequences;\n }\n\n return Object.keys(config).length > 0 ? config : null;\n }\n\n protected async *normalizeProviderStream(iterable: AsyncIterable<unknown>): LLMStream {\n const stream = iterable as AsyncIterable<GeminiChunk>;\n for await (const chunk of stream) {\n const text = this.extractMessageText(chunk);\n if (text) {\n yield { text, rawEvent: chunk };\n }\n\n const finishReason = this.extractFinishReason(chunk);\n const usage = this.extractUsage(chunk);\n\n if (finishReason || usage) {\n yield { text: \"\", finishReason, usage, rawEvent: chunk };\n }\n }\n }\n\n private extractMessageText(chunk: GeminiChunk): string {\n if (!chunk?.candidates) {\n return \"\";\n }\n\n return chunk.candidates\n .flatMap((candidate) => candidate.content?.parts ?? [])\n .map((part) => part.text ?? \"\")\n .join(\"\");\n }\n\n private extractFinishReason(chunk: GeminiChunk): string | null {\n const candidate = chunk?.candidates?.find((item) => item.finishReason);\n return candidate?.finishReason ?? null;\n }\n\n private extractUsage(\n chunk: GeminiChunk,\n ):\n | { inputTokens: number; outputTokens: number; totalTokens: number; cachedInputTokens?: number }\n | undefined {\n const usageMetadata = chunk?.usageMetadata;\n if (!usageMetadata) {\n return undefined;\n }\n\n return {\n inputTokens: usageMetadata.promptTokenCount ?? 0,\n outputTokens: usageMetadata.candidatesTokenCount ?? 0,\n totalTokens: usageMetadata.totalTokenCount ?? 0,\n // Gemini returns cached token count in cachedContentTokenCount\n cachedInputTokens: usageMetadata.cachedContentTokenCount ?? 0,\n };\n }\n\n /**\n * Count tokens in messages using Gemini's native token counting API.\n *\n * This method provides accurate token estimation for Gemini models by:\n * - Using the SDK's countTokens() method\n * - Converting system messages to user+model exchanges (same as in generation)\n * - This gives perfect token counting accuracy (0% error vs actual usage)\n *\n * @param messages - The messages to count tokens for\n * @param descriptor - Model descriptor containing the model name\n * @param _spec - Optional model specification (currently unused)\n * @returns Promise resolving to the estimated input token count\n *\n * @throws Never throws - falls back to character-based estimation (4 chars/token) on error\n *\n * @example\n * ```typescript\n * const count = await provider.countTokens(\n * [{ role: \"user\", content: \"Hello!\" }],\n * { provider: \"gemini\", name: \"gemini-1.5-pro\" }\n * );\n * ```\n */\n async countTokens(\n messages: LLMMessage[],\n descriptor: ModelDescriptor,\n _spec?: ModelSpec,\n ): Promise<number> {\n const client = this.client as GoogleGenAI;\n\n // Convert messages to Gemini format (same as buildRequestPayload)\n // This now handles multimodal content\n const contents = this.convertMessagesToContents(messages);\n\n // Return 0 for empty messages - Gemini API requires non-empty contents\n if (!contents || contents.length === 0) {\n return 0;\n }\n\n try {\n // Use Gemini's count_tokens method\n const response = await client.models.countTokens({\n model: descriptor.name,\n contents,\n // Note: systemInstruction not used - it's not supported by countTokens()\n // and would cause a 2100% token counting error\n });\n return response.totalTokens ?? 0;\n } catch (error) {\n // Log the error for debugging\n console.warn(\n `Token counting failed for ${descriptor.name}, using fallback estimation:`,\n error,\n );\n // Fallback to rough estimation if API fails\n // For multimodal, extract text and estimate; images/audio add tokens\n let totalChars = 0;\n let mediaCount = 0;\n for (const msg of messages) {\n const parts = normalizeMessageContent(msg.content);\n for (const part of parts) {\n if (part.type === \"text\") {\n totalChars += part.text.length;\n } else if (part.type === \"image\" || part.type === \"audio\") {\n mediaCount++;\n }\n }\n }\n // Gemini charges ~258 tokens per image/audio (for standard size).\n // Source: https://ai.google.dev/gemini-api/docs/tokens\n // Actual cost varies by media type and dimensions.\n return Math.ceil(totalChars / FALLBACK_CHARS_PER_TOKEN) + mediaCount * 258;\n }\n }\n}\n\nexport function createGeminiProviderFromEnv(): GeminiGenerativeProvider | null {\n return createProviderFromEnv(\"GEMINI_API_KEY\", GoogleGenAI, GeminiGenerativeProvider);\n}\n","/**\n * OpenAI Image Generation Model Catalog\n *\n * Pricing as of December 2025:\n *\n * GPT Image 1 (flagship):\n * - Low quality: ~$0.011 per image\n * - Medium quality: ~$0.04 per image\n * - High quality: ~$0.17 per image\n *\n * GPT Image 1 Mini (cost-effective):\n * - Low quality: ~$0.005 per image\n * - Medium quality: ~$0.02 per image\n * - High quality: ~$0.052 per image\n *\n * DALL-E 3:\n * - 1024x1024: $0.040 (standard), $0.080 (hd)\n * - 1024x1792: $0.080 (standard), $0.120 (hd)\n * - 1792x1024: $0.080 (standard), $0.120 (hd)\n *\n * DALL-E 2 (legacy):\n * - 256x256: $0.016\n * - 512x512: $0.018\n * - 1024x1024: $0.020\n *\n * @see https://platform.openai.com/docs/guides/images\n */\n\nimport type { ImageModelSpec } from \"../core/media-types.js\";\n\n/** GPT Image 1 supported sizes */\nexport const GPT_IMAGE_SIZES = [\"1024x1024\", \"1024x1536\", \"1536x1024\"] as const;\nexport type GptImageSize = (typeof GPT_IMAGE_SIZES)[number];\n\n/** GPT Image quality levels */\nexport const GPT_IMAGE_QUALITIES = [\"low\", \"medium\", \"high\"] as const;\nexport type GptImageQuality = (typeof GPT_IMAGE_QUALITIES)[number];\n\n/** DALL-E 3 supported sizes */\nexport const DALLE3_SIZES = [\"1024x1024\", \"1024x1792\", \"1792x1024\"] as const;\nexport type DallE3Size = (typeof DALLE3_SIZES)[number];\n\n/** DALL-E 3 quality levels */\nexport const DALLE3_QUALITIES = [\"standard\", \"hd\"] as const;\nexport type DallE3Quality = (typeof DALLE3_QUALITIES)[number];\n\n/** DALL-E 2 supported sizes */\nexport const DALLE2_SIZES = [\"256x256\", \"512x512\", \"1024x1024\"] as const;\nexport type DallE2Size = (typeof DALLE2_SIZES)[number];\n\n/**\n * OpenAI Image Model Specifications\n */\nexport const openaiImageModels: ImageModelSpec[] = [\n // GPT Image 1 Family (flagship)\n {\n provider: \"openai\",\n modelId: \"gpt-image-1\",\n displayName: \"GPT Image 1\",\n pricing: {\n bySize: {\n \"1024x1024\": { low: 0.011, medium: 0.04, high: 0.17 },\n \"1024x1536\": { low: 0.016, medium: 0.06, high: 0.25 },\n \"1536x1024\": { low: 0.016, medium: 0.06, high: 0.25 },\n },\n },\n supportedSizes: [...GPT_IMAGE_SIZES],\n supportedQualities: [...GPT_IMAGE_QUALITIES],\n maxImages: 1,\n defaultSize: \"1024x1024\",\n defaultQuality: \"medium\",\n features: {\n textRendering: true,\n transparency: true,\n },\n },\n {\n provider: \"openai\",\n modelId: \"gpt-image-1-mini\",\n displayName: \"GPT Image 1 Mini\",\n pricing: {\n bySize: {\n \"1024x1024\": { low: 0.005, medium: 0.02, high: 0.052 },\n \"1024x1536\": { low: 0.0075, medium: 0.03, high: 0.078 },\n \"1536x1024\": { low: 0.0075, medium: 0.03, high: 0.078 },\n },\n },\n supportedSizes: [...GPT_IMAGE_SIZES],\n supportedQualities: [...GPT_IMAGE_QUALITIES],\n maxImages: 1,\n defaultSize: \"1024x1024\",\n defaultQuality: \"medium\",\n features: {\n textRendering: true,\n transparency: true,\n },\n },\n // DALL-E Family\n {\n provider: \"openai\",\n modelId: \"dall-e-3\",\n displayName: \"DALL-E 3\",\n pricing: {\n bySize: {\n \"1024x1024\": { standard: 0.04, hd: 0.08 },\n \"1024x1792\": { standard: 0.08, hd: 0.12 },\n \"1792x1024\": { standard: 0.08, hd: 0.12 },\n },\n },\n supportedSizes: [...DALLE3_SIZES],\n supportedQualities: [...DALLE3_QUALITIES],\n maxImages: 1, // DALL-E 3 only supports n=1\n defaultSize: \"1024x1024\",\n defaultQuality: \"standard\",\n features: {\n textRendering: true,\n },\n },\n {\n provider: \"openai\",\n modelId: \"dall-e-2\",\n displayName: \"DALL-E 2 (Legacy)\",\n pricing: {\n bySize: {\n \"256x256\": 0.016,\n \"512x512\": 0.018,\n \"1024x1024\": 0.02,\n },\n },\n supportedSizes: [...DALLE2_SIZES],\n maxImages: 10,\n defaultSize: \"1024x1024\",\n },\n];\n\n/**\n * Get image model spec by model ID.\n */\nexport function getOpenAIImageModelSpec(modelId: string): ImageModelSpec | undefined {\n return openaiImageModels.find((m) => m.modelId === modelId);\n}\n\n/**\n * Check if a model ID is an OpenAI image model.\n */\nexport function isOpenAIImageModel(modelId: string): boolean {\n return openaiImageModels.some((m) => m.modelId === modelId);\n}\n\n/**\n * Calculate cost for image generation.\n *\n * @param modelId - The model ID (dall-e-3 or dall-e-2)\n * @param size - Image size\n * @param quality - Quality level (for DALL-E 3)\n * @param n - Number of images\n * @returns Cost in USD, or undefined if model not found\n */\nexport function calculateOpenAIImageCost(\n modelId: string,\n size: string,\n quality = \"standard\",\n n = 1,\n): number | undefined {\n const spec = getOpenAIImageModelSpec(modelId);\n if (!spec) return undefined;\n\n // Get price for this size\n const sizePrice = spec.pricing.bySize?.[size];\n if (sizePrice === undefined) return undefined;\n\n let pricePerImage: number;\n\n if (typeof sizePrice === \"number\") {\n // Flat pricing (DALL-E 2)\n pricePerImage = sizePrice;\n } else {\n // Quality-based pricing (DALL-E 3)\n pricePerImage = sizePrice[quality];\n if (pricePerImage === undefined) return undefined;\n }\n\n return pricePerImage * n;\n}\n","/**\n * OpenAI Model Specifications\n *\n * Model data for OpenAI models including GPT-5, GPT-4.1, GPT-4o, and o-series\n * with their specifications, pricing (Standard tier), and capabilities.\n *\n * Pricing source: https://openai.com/api/pricing (Standard tier)\n * Last updated: 2025-11-29\n */\n\nimport type { ModelSpec } from \"../core/model-catalog.js\";\n\nexport const OPENAI_MODELS: ModelSpec[] = [\n // GPT-5 Family\n {\n provider: \"openai\",\n modelId: \"gpt-5.1\",\n displayName: \"GPT-5.1\",\n contextWindow: 128_000,\n maxOutputTokens: 32_768,\n pricing: {\n input: 1.25,\n output: 10.0,\n cachedInput: 0.125,\n },\n knowledgeCutoff: \"2024-09-30\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n structuredOutputs: true,\n fineTuning: true,\n },\n metadata: {\n family: \"GPT-5\",\n releaseDate: \"2025-11-12\",\n notes: \"Latest GPT-5 with improved instruction following. 2-3x faster than GPT-5.\",\n supportsTemperature: false,\n },\n },\n {\n provider: \"openai\",\n modelId: \"gpt-5\",\n displayName: \"GPT-5\",\n contextWindow: 272_000,\n maxOutputTokens: 128_000,\n pricing: {\n input: 1.25,\n output: 10.0,\n cachedInput: 0.125,\n },\n knowledgeCutoff: \"2024-09-30\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n structuredOutputs: true,\n fineTuning: true,\n },\n metadata: {\n family: \"GPT-5\",\n releaseDate: \"2025-08-07\",\n notes:\n \"Best model for coding and agentic tasks. Adaptive reasoning with 90% caching discount.\",\n supportsTemperature: false,\n },\n },\n {\n provider: \"openai\",\n modelId: \"gpt-5-mini\",\n displayName: \"GPT-5 Mini\",\n contextWindow: 272_000,\n maxOutputTokens: 32_768,\n pricing: {\n input: 0.25,\n output: 2.0,\n cachedInput: 0.025,\n },\n knowledgeCutoff: \"2024-06-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n structuredOutputs: true,\n fineTuning: true,\n },\n metadata: {\n family: \"GPT-5\",\n notes: \"Fast and cost-efficient with adaptive reasoning\",\n supportsTemperature: false,\n },\n },\n {\n provider: \"openai\",\n modelId: \"gpt-5-nano\",\n displayName: \"GPT-5 Nano\",\n contextWindow: 272_000,\n maxOutputTokens: 32_768,\n pricing: {\n input: 0.05,\n output: 0.4,\n cachedInput: 0.005,\n },\n knowledgeCutoff: \"2024-05-31\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n structuredOutputs: true,\n fineTuning: true,\n },\n metadata: {\n family: \"GPT-5\",\n notes: \"Fastest, most cost-efficient version for well-defined tasks\",\n supportsTemperature: false,\n },\n },\n {\n provider: \"openai\",\n modelId: \"gpt-5-pro\",\n displayName: \"GPT-5 Pro\",\n contextWindow: 272_000,\n maxOutputTokens: 128_000,\n pricing: {\n input: 15.0,\n output: 120.0,\n // No cached input pricing for gpt-5-pro\n },\n knowledgeCutoff: \"2024-09-30\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n structuredOutputs: true,\n },\n metadata: {\n family: \"GPT-5\",\n notes: \"Premium tier with enhanced capabilities. Does not support prompt caching.\",\n supportsTemperature: false,\n },\n },\n\n // GPT-4.1 Family\n {\n provider: \"openai\",\n modelId: \"gpt-4.1\",\n displayName: \"GPT-4.1\",\n contextWindow: 128_000,\n maxOutputTokens: 32_768,\n pricing: {\n input: 2.0,\n output: 8.0,\n cachedInput: 0.5,\n },\n knowledgeCutoff: \"2024-04-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n structuredOutputs: true,\n fineTuning: true,\n },\n metadata: {\n family: \"GPT-4.1\",\n notes: \"Improved GPT-4 with better instruction following\",\n },\n },\n {\n provider: \"openai\",\n modelId: \"gpt-4.1-mini\",\n displayName: \"GPT-4.1 Mini\",\n contextWindow: 128_000,\n maxOutputTokens: 32_768,\n pricing: {\n input: 0.4,\n output: 1.6,\n cachedInput: 0.1,\n },\n knowledgeCutoff: \"2024-04-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n structuredOutputs: true,\n fineTuning: true,\n },\n metadata: {\n family: \"GPT-4.1\",\n notes: \"Cost-efficient GPT-4.1 variant\",\n },\n },\n {\n provider: \"openai\",\n modelId: \"gpt-4.1-nano\",\n displayName: \"GPT-4.1 Nano\",\n contextWindow: 128_000,\n maxOutputTokens: 32_768,\n pricing: {\n input: 0.1,\n output: 0.4,\n cachedInput: 0.025,\n },\n knowledgeCutoff: \"2024-04-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n structuredOutputs: true,\n fineTuning: true,\n },\n metadata: {\n family: \"GPT-4.1\",\n notes: \"Fastest GPT-4.1 variant for simple tasks\",\n },\n },\n\n // GPT-4o Family\n {\n provider: \"openai\",\n modelId: \"gpt-4o\",\n displayName: \"GPT-4o\",\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n pricing: {\n input: 2.5,\n output: 10.0,\n cachedInput: 1.25,\n },\n knowledgeCutoff: \"2024-04-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n structuredOutputs: true,\n fineTuning: true,\n },\n metadata: {\n family: \"GPT-4o\",\n notes: \"Multimodal model optimized for speed\",\n },\n },\n {\n provider: \"openai\",\n modelId: \"gpt-4o-mini\",\n displayName: \"GPT-4o Mini\",\n contextWindow: 128_000,\n maxOutputTokens: 16_384,\n pricing: {\n input: 0.15,\n output: 0.6,\n cachedInput: 0.075,\n },\n knowledgeCutoff: \"2024-04-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n structuredOutputs: true,\n fineTuning: true,\n },\n metadata: {\n family: \"GPT-4o\",\n notes: \"Fast and affordable multimodal model\",\n },\n },\n\n // o-series (Reasoning models)\n {\n provider: \"openai\",\n modelId: \"o1\",\n displayName: \"o1\",\n contextWindow: 200_000,\n maxOutputTokens: 100_000,\n pricing: {\n input: 15.0,\n output: 60.0,\n cachedInput: 7.5,\n },\n knowledgeCutoff: \"2024-12-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n structuredOutputs: true,\n },\n metadata: {\n family: \"o-series\",\n notes: \"Advanced reasoning model with chain-of-thought\",\n supportsTemperature: false,\n },\n },\n {\n provider: \"openai\",\n modelId: \"o3\",\n displayName: \"o3\",\n contextWindow: 200_000,\n maxOutputTokens: 100_000,\n pricing: {\n input: 2.0,\n output: 8.0,\n cachedInput: 0.5,\n },\n knowledgeCutoff: \"2025-01-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n structuredOutputs: true,\n },\n metadata: {\n family: \"o-series\",\n notes: \"Next-gen reasoning model, more efficient than o1\",\n supportsTemperature: false,\n },\n },\n {\n provider: \"openai\",\n modelId: \"o4-mini\",\n displayName: \"o4 Mini\",\n contextWindow: 200_000,\n maxOutputTokens: 100_000,\n pricing: {\n input: 1.1,\n output: 4.4,\n cachedInput: 0.275,\n },\n knowledgeCutoff: \"2025-04-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n structuredOutputs: true,\n fineTuning: true,\n },\n metadata: {\n family: \"o-series\",\n notes: \"Cost-efficient reasoning model\",\n supportsTemperature: false,\n },\n },\n {\n provider: \"openai\",\n modelId: \"o3-mini\",\n displayName: \"o3 Mini\",\n contextWindow: 200_000,\n maxOutputTokens: 100_000,\n pricing: {\n input: 1.1,\n output: 4.4,\n cachedInput: 0.55,\n },\n knowledgeCutoff: \"2025-01-01\",\n features: {\n streaming: true,\n functionCalling: true,\n vision: true,\n reasoning: true,\n structuredOutputs: true,\n },\n metadata: {\n family: \"o-series\",\n notes: \"Compact reasoning model for cost-sensitive applications\",\n supportsTemperature: false,\n },\n },\n];\n","/**\n * OpenAI Speech (TTS) Model Catalog\n *\n * Pricing as of December 2025:\n * - tts-1: $15.00 per 1M characters\n * - tts-1-hd: $30.00 per 1M characters\n * - gpt-4o-mini-tts: $0.60/1M input tokens + $12/1M audio output tokens (~$0.015/min)\n *\n * @see https://platform.openai.com/docs/guides/text-to-speech\n */\n\nimport type { AudioFormat, SpeechModelSpec } from \"../core/media-types.js\";\n\n/** OpenAI TTS voices for standard models (tts-1, tts-1-hd) */\nexport const OPENAI_TTS_VOICES = [\"alloy\", \"echo\", \"fable\", \"onyx\", \"nova\", \"shimmer\"] as const;\n\n/** Additional voices available in gpt-4o-mini-tts */\nexport const OPENAI_TTS_EXTENDED_VOICES = [\n ...OPENAI_TTS_VOICES,\n \"ash\",\n \"ballad\",\n \"coral\",\n \"sage\",\n \"verse\",\n] as const;\n\nexport type OpenAITTSVoice = (typeof OPENAI_TTS_VOICES)[number];\nexport type OpenAITTSExtendedVoice = (typeof OPENAI_TTS_EXTENDED_VOICES)[number];\n\n/** OpenAI supported audio formats */\nexport const OPENAI_TTS_FORMATS: AudioFormat[] = [\"mp3\", \"opus\", \"aac\", \"flac\", \"wav\", \"pcm\"];\n\n/**\n * OpenAI Speech Model Specifications\n */\nexport const openaiSpeechModels: SpeechModelSpec[] = [\n // Standard TTS models (character-based pricing)\n {\n provider: \"openai\",\n modelId: \"tts-1\",\n displayName: \"TTS-1\",\n pricing: {\n // $15 per 1M characters = $0.000015 per character\n perCharacter: 0.000015,\n },\n voices: [...OPENAI_TTS_VOICES],\n formats: OPENAI_TTS_FORMATS,\n maxInputLength: 4096,\n defaultVoice: \"alloy\",\n defaultFormat: \"mp3\",\n features: {\n voiceInstructions: false,\n },\n },\n {\n provider: \"openai\",\n modelId: \"tts-1-1106\",\n displayName: \"TTS-1 (Nov 2023)\",\n pricing: {\n perCharacter: 0.000015,\n },\n voices: [...OPENAI_TTS_VOICES],\n formats: OPENAI_TTS_FORMATS,\n maxInputLength: 4096,\n defaultVoice: \"alloy\",\n defaultFormat: \"mp3\",\n features: {\n voiceInstructions: false,\n },\n },\n {\n provider: \"openai\",\n modelId: \"tts-1-hd\",\n displayName: \"TTS-1 HD\",\n pricing: {\n // $30 per 1M characters = $0.00003 per character\n perCharacter: 0.00003,\n },\n voices: [...OPENAI_TTS_VOICES],\n formats: OPENAI_TTS_FORMATS,\n maxInputLength: 4096,\n defaultVoice: \"alloy\",\n defaultFormat: \"mp3\",\n features: {\n voiceInstructions: false,\n },\n },\n {\n provider: \"openai\",\n modelId: \"tts-1-hd-1106\",\n displayName: \"TTS-1 HD (Nov 2023)\",\n pricing: {\n perCharacter: 0.00003,\n },\n voices: [...OPENAI_TTS_VOICES],\n formats: OPENAI_TTS_FORMATS,\n maxInputLength: 4096,\n defaultVoice: \"alloy\",\n defaultFormat: \"mp3\",\n features: {\n voiceInstructions: false,\n },\n },\n // Token-based TTS model with voice instructions support\n {\n provider: \"openai\",\n modelId: \"gpt-4o-mini-tts\",\n displayName: \"GPT-4o Mini TTS\",\n pricing: {\n // $0.60 per 1M input tokens = $0.0000006 per token\n perInputToken: 0.0000006,\n // $12 per 1M audio output tokens = $0.000012 per token\n perAudioOutputToken: 0.000012,\n // ~$0.015 per minute of audio\n perMinute: 0.015,\n },\n voices: [...OPENAI_TTS_EXTENDED_VOICES],\n formats: OPENAI_TTS_FORMATS,\n maxInputLength: 2000, // tokens, not characters\n defaultVoice: \"alloy\",\n defaultFormat: \"mp3\",\n features: {\n voiceInstructions: true,\n },\n },\n];\n\n/**\n * Get speech model spec by model ID.\n */\nexport function getOpenAISpeechModelSpec(modelId: string): SpeechModelSpec | undefined {\n return openaiSpeechModels.find((m) => m.modelId === modelId);\n}\n\n/**\n * Check if a model ID is an OpenAI speech model.\n */\nexport function isOpenAISpeechModel(modelId: string): boolean {\n return openaiSpeechModels.some((m) => m.modelId === modelId);\n}\n\n/**\n * Calculate cost for speech generation.\n *\n * For character-based models (tts-1, tts-1-hd): cost = characters * perCharacter\n * For token-based models (gpt-4o-mini-tts): uses perMinute approximation\n *\n * @param modelId - The model ID\n * @param characterCount - Number of characters in the input\n * @param estimatedMinutes - Optional: estimated audio duration for token-based models\n * @returns Cost in USD, or undefined if model not found\n */\nexport function calculateOpenAISpeechCost(\n modelId: string,\n characterCount: number,\n estimatedMinutes?: number,\n): number | undefined {\n const spec = getOpenAISpeechModelSpec(modelId);\n if (!spec) return undefined;\n\n // Character-based pricing (tts-1, tts-1-hd)\n if (spec.pricing.perCharacter !== undefined) {\n return characterCount * spec.pricing.perCharacter;\n }\n\n // Token-based pricing (gpt-4o-mini-tts) - use per-minute approximation\n if (spec.pricing.perMinute !== undefined && estimatedMinutes !== undefined) {\n return estimatedMinutes * spec.pricing.perMinute;\n }\n\n // Fallback: rough estimate based on ~150 words/min, ~5 chars/word\n // ~750 chars/min of audio\n if (spec.pricing.perMinute !== undefined) {\n const approxMinutes = characterCount / 750;\n return approxMinutes * spec.pricing.perMinute;\n }\n\n return undefined;\n}\n","import OpenAI from \"openai\";\nimport type {\n ChatCompletionChunk,\n ChatCompletionContentPart,\n ChatCompletionMessageParam,\n} from \"openai/resources/chat/completions\";\nimport { encoding_for_model, type TiktokenModel } from \"tiktoken\";\nimport type { ContentPart, ImageContentPart } from \"../core/input-content.js\";\nimport type {\n ImageGenerationOptions,\n ImageGenerationResult,\n ImageModelSpec,\n SpeechGenerationOptions,\n SpeechGenerationResult,\n SpeechModelSpec,\n} from \"../core/media-types.js\";\nimport type { LLMMessage, MessageContent } from \"../core/messages.js\";\nimport { extractMessageText, normalizeMessageContent } from \"../core/messages.js\";\nimport type { ModelSpec } from \"../core/model-catalog.js\";\nimport type { LLMGenerationOptions, LLMStream, ModelDescriptor } from \"../core/options.js\";\nimport { BaseProviderAdapter } from \"./base-provider.js\";\nimport {\n FALLBACK_CHARS_PER_TOKEN,\n OPENAI_MESSAGE_OVERHEAD_TOKENS,\n OPENAI_NAME_FIELD_OVERHEAD_TOKENS,\n OPENAI_REPLY_PRIMING_TOKENS,\n} from \"./constants.js\";\nimport {\n calculateOpenAIImageCost,\n getOpenAIImageModelSpec,\n isOpenAIImageModel,\n openaiImageModels,\n} from \"./openai-image-models.js\";\nimport { OPENAI_MODELS } from \"./openai-models.js\";\nimport {\n calculateOpenAISpeechCost,\n getOpenAISpeechModelSpec,\n isOpenAISpeechModel,\n openaiSpeechModels,\n} from \"./openai-speech-models.js\";\nimport { createProviderFromEnv } from \"./utils.js\";\n\nconst ROLE_MAP: Record<LLMMessage[\"role\"], \"system\" | \"user\" | \"assistant\"> = {\n system: \"system\",\n user: \"user\",\n assistant: \"assistant\",\n};\n\n// Note: Temperature support is now determined from the ModelSpec passed to stream()\n// instead of being hardcoded at module level\n\nfunction sanitizeExtra(\n extra: Record<string, unknown> | undefined,\n allowTemperature: boolean,\n): Record<string, unknown> | undefined {\n if (!extra) {\n return undefined;\n }\n\n if (allowTemperature || !Object.hasOwn(extra, \"temperature\")) {\n return extra;\n }\n\n return Object.fromEntries(Object.entries(extra).filter(([key]) => key !== \"temperature\"));\n}\n\nexport class OpenAIChatProvider extends BaseProviderAdapter {\n readonly providerId = \"openai\" as const;\n\n supports(descriptor: ModelDescriptor): boolean {\n return descriptor.provider === this.providerId;\n }\n\n getModelSpecs() {\n return OPENAI_MODELS;\n }\n\n // =========================================================================\n // Image Generation\n // =========================================================================\n\n getImageModelSpecs(): ImageModelSpec[] {\n return openaiImageModels;\n }\n\n supportsImageGeneration(modelId: string): boolean {\n return isOpenAIImageModel(modelId);\n }\n\n async generateImage(options: ImageGenerationOptions): Promise<ImageGenerationResult> {\n const client = this.client as OpenAI;\n const spec = getOpenAIImageModelSpec(options.model);\n\n const size = options.size ?? spec?.defaultSize ?? \"1024x1024\";\n const quality = options.quality ?? spec?.defaultQuality ?? \"standard\";\n const n = options.n ?? 1;\n\n // Determine which parameters to include based on model capabilities\n const isDallE2 = options.model === \"dall-e-2\";\n const isGptImage = options.model.startsWith(\"gpt-image\");\n\n // Build request payload conditionally\n // - DALL-E 2: no quality parameter, no response_format\n // - GPT Image: quality uses low/medium/high, no response_format (uses output_format)\n // - DALL-E 3: supports quality (standard/hd) and response_format\n const requestParams: Parameters<typeof client.images.generate>[0] = {\n model: options.model,\n prompt: options.prompt,\n size: size as \"1024x1024\" | \"1024x1792\" | \"1792x1024\" | \"256x256\" | \"512x512\",\n n,\n };\n\n // Only DALL-E 3 supports the quality parameter with standard/hd values\n if (!isDallE2 && !isGptImage) {\n requestParams.quality = quality as \"standard\" | \"hd\";\n }\n\n // GPT Image models use output_format instead of response_format\n if (isGptImage) {\n // GPT Image supports: png, webp, jpeg\n // Map b64_json to the default format (png) since GPT Image API is different\n // For now, we'll always return URLs for GPT Image models\n // Note: GPT Image API uses different response structure\n } else if (!isDallE2) {\n // DALL-E 3 supports response_format\n requestParams.response_format = options.responseFormat ?? \"url\";\n }\n\n const response = await client.images.generate(requestParams);\n\n const cost = calculateOpenAIImageCost(options.model, size, quality, n);\n // Type assertion: we're not using streaming, so response is ImagesResponse\n const images = (response as OpenAI.Images.ImagesResponse).data ?? [];\n\n return {\n images: images.map((img) => ({\n url: img.url,\n b64Json: img.b64_json,\n revisedPrompt: img.revised_prompt,\n })),\n model: options.model,\n usage: {\n imagesGenerated: images.length,\n size,\n quality,\n },\n cost,\n };\n }\n\n // =========================================================================\n // Speech Generation\n // =========================================================================\n\n getSpeechModelSpecs(): SpeechModelSpec[] {\n return openaiSpeechModels;\n }\n\n supportsSpeechGeneration(modelId: string): boolean {\n return isOpenAISpeechModel(modelId);\n }\n\n async generateSpeech(options: SpeechGenerationOptions): Promise<SpeechGenerationResult> {\n const client = this.client as OpenAI;\n const spec = getOpenAISpeechModelSpec(options.model);\n\n const format = options.responseFormat ?? spec?.defaultFormat ?? \"mp3\";\n const voice = options.voice ?? spec?.defaultVoice ?? \"alloy\";\n\n const response = await client.audio.speech.create({\n model: options.model,\n input: options.input,\n voice: voice as \"alloy\" | \"echo\" | \"fable\" | \"onyx\" | \"nova\" | \"shimmer\",\n response_format: format,\n speed: options.speed ?? 1.0,\n });\n\n const audioBuffer = await response.arrayBuffer();\n const cost = calculateOpenAISpeechCost(options.model, options.input.length);\n\n return {\n audio: audioBuffer,\n model: options.model,\n usage: {\n characterCount: options.input.length,\n },\n cost,\n format,\n };\n }\n\n protected buildApiRequest(\n options: LLMGenerationOptions,\n descriptor: ModelDescriptor,\n spec: ModelSpec | undefined,\n messages: LLMMessage[],\n ): Parameters<OpenAI[\"chat\"][\"completions\"][\"create\"]>[0] {\n const { maxTokens, temperature, topP, stopSequences, extra } = options;\n\n // Use spec metadata to determine temperature support, defaulting to true if spec is unavailable\n const supportsTemperature = spec?.metadata?.supportsTemperature !== false;\n const shouldIncludeTemperature = typeof temperature === \"number\" && supportsTemperature;\n const sanitizedExtra = sanitizeExtra(extra, shouldIncludeTemperature);\n\n return {\n model: descriptor.name,\n messages: messages.map((message) => this.convertToOpenAIMessage(message)),\n // Only set max_completion_tokens if explicitly provided\n // Otherwise let the API use \"as much as fits\" in the context window\n ...(maxTokens !== undefined ? { max_completion_tokens: maxTokens } : {}),\n top_p: topP,\n stop: stopSequences,\n stream: true,\n stream_options: { include_usage: true },\n ...(sanitizedExtra ?? {}),\n ...(shouldIncludeTemperature ? { temperature } : {}),\n };\n }\n\n /**\n * Convert an LLMMessage to OpenAI's ChatCompletionMessageParam.\n * Handles role-specific content type requirements:\n * - system/assistant: string content only\n * - user: string or multimodal array content\n */\n private convertToOpenAIMessage(message: LLMMessage): ChatCompletionMessageParam {\n const role = ROLE_MAP[message.role];\n\n // User messages support multimodal content\n if (role === \"user\") {\n const content = this.convertToOpenAIContent(message.content);\n return {\n role: \"user\",\n content,\n ...(message.name ? { name: message.name } : {}),\n };\n }\n\n // System and assistant messages only support string content\n const textContent =\n typeof message.content === \"string\" ? message.content : extractMessageText(message.content);\n\n if (role === \"system\") {\n return {\n role: \"system\",\n content: textContent,\n ...(message.name ? { name: message.name } : {}),\n };\n }\n\n // Assistant role\n return {\n role: \"assistant\",\n content: textContent,\n ...(message.name ? { name: message.name } : {}),\n };\n }\n\n /**\n * Convert llmist content to OpenAI's content format.\n * Optimizes by returning string for text-only content, array for multimodal.\n */\n private convertToOpenAIContent(content: MessageContent): string | ChatCompletionContentPart[] {\n // Optimization: keep simple string content as-is\n if (typeof content === \"string\") {\n return content;\n }\n\n // Convert array content to OpenAI format\n return content.map((part) => {\n if (part.type === \"text\") {\n return { type: \"text\" as const, text: part.text };\n }\n\n if (part.type === \"image\") {\n return this.convertImagePart(part);\n }\n\n if (part.type === \"audio\") {\n throw new Error(\n \"OpenAI chat completions do not support audio input. Use Whisper for transcription or Gemini for audio understanding.\",\n );\n }\n\n throw new Error(`Unsupported content type: ${(part as ContentPart).type}`);\n });\n }\n\n /**\n * Convert an image content part to OpenAI's image_url format.\n * Supports both URLs and base64 data URLs.\n */\n private convertImagePart(part: ImageContentPart): ChatCompletionContentPart {\n if (part.source.type === \"url\") {\n return {\n type: \"image_url\" as const,\n image_url: { url: part.source.url },\n };\n }\n\n // Convert base64 to data URL format\n return {\n type: \"image_url\" as const,\n image_url: {\n url: `data:${part.source.mediaType};base64,${part.source.data}`,\n },\n };\n }\n\n protected async executeStreamRequest(\n payload: Parameters<OpenAI[\"chat\"][\"completions\"][\"create\"]>[0],\n signal?: AbortSignal,\n ): Promise<AsyncIterable<ChatCompletionChunk>> {\n const client = this.client as OpenAI;\n // Pass abort signal to SDK via request options\n const stream = await client.chat.completions.create(payload, signal ? { signal } : undefined);\n return stream as unknown as AsyncIterable<ChatCompletionChunk>;\n }\n\n protected async *normalizeProviderStream(iterable: AsyncIterable<unknown>): LLMStream {\n const stream = iterable as AsyncIterable<ChatCompletionChunk>;\n for await (const chunk of stream) {\n const text = chunk.choices.map((choice) => choice.delta?.content ?? \"\").join(\"\");\n if (text) {\n yield { text, rawEvent: chunk };\n }\n\n const finishReason = chunk.choices.find((choice) => choice.finish_reason)?.finish_reason;\n\n // Extract token usage if available (typically in the final chunk)\n // OpenAI returns cached token count in prompt_tokens_details.cached_tokens\n const usage = chunk.usage\n ? {\n inputTokens: chunk.usage.prompt_tokens,\n outputTokens: chunk.usage.completion_tokens,\n totalTokens: chunk.usage.total_tokens,\n cachedInputTokens:\n (chunk.usage as { prompt_tokens_details?: { cached_tokens?: number } })\n .prompt_tokens_details?.cached_tokens ?? 0,\n }\n : undefined;\n\n if (finishReason || usage) {\n yield { text: \"\", finishReason, usage, rawEvent: chunk };\n }\n }\n }\n\n /**\n * Count tokens in messages using OpenAI's tiktoken library.\n *\n * This method provides accurate token estimation for OpenAI models by:\n * - Using the model-specific tokenizer encoding\n * - Accounting for message formatting overhead\n * - Falling back to gpt-4o encoding for unknown models\n *\n * @param messages - The messages to count tokens for\n * @param descriptor - Model descriptor containing the model name\n * @param _spec - Optional model specification (currently unused)\n * @returns Promise resolving to the estimated input token count\n *\n * @throws Never throws - falls back to character-based estimation (4 chars/token) on error\n *\n * @example\n * ```typescript\n * const count = await provider.countTokens(\n * [{ role: \"user\", content: \"Hello!\" }],\n * { provider: \"openai\", name: \"gpt-4\" }\n * );\n * ```\n */\n async countTokens(\n messages: LLMMessage[],\n descriptor: ModelDescriptor,\n _spec?: ModelSpec,\n ): Promise<number> {\n try {\n // Map model names to tiktoken models\n // For models not directly supported, use a reasonable default\n const modelName = descriptor.name as TiktokenModel;\n let encoding;\n\n try {\n encoding = encoding_for_model(modelName);\n } catch {\n // If the specific model isn't supported, fall back to gpt-4o which uses cl100k_base\n encoding = encoding_for_model(\"gpt-4o\");\n }\n\n try {\n let tokenCount = 0;\n let imageCount = 0;\n\n // Count tokens per message with proper formatting\n // OpenAI's format adds tokens for message boundaries and roles\n // Token overhead based on OpenAI's message formatting\n // See: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb\n for (const message of messages) {\n // Every message follows <im_start>{role/name}\\n{content}<im_end>\\n\n tokenCount += OPENAI_MESSAGE_OVERHEAD_TOKENS;\n\n const roleText = ROLE_MAP[message.role];\n tokenCount += encoding.encode(roleText).length;\n\n // Handle multimodal content\n const textContent = extractMessageText(message.content);\n tokenCount += encoding.encode(textContent).length;\n\n // Count images for estimation (each image ~85 tokens base + variable)\n const parts = normalizeMessageContent(message.content);\n for (const part of parts) {\n if (part.type === \"image\") {\n imageCount++;\n }\n }\n\n if (message.name) {\n tokenCount += encoding.encode(message.name).length;\n tokenCount += OPENAI_NAME_FIELD_OVERHEAD_TOKENS;\n }\n }\n\n tokenCount += OPENAI_REPLY_PRIMING_TOKENS;\n // Add ~765 tokens per image (low detail mode).\n // Source: https://platform.openai.com/docs/guides/vision\n // High detail mode varies by image size (510-1105 tokens per 512px tile + 85 base).\n tokenCount += imageCount * 765;\n\n return tokenCount;\n } finally {\n // Always free the encoding to prevent memory leaks\n encoding.free();\n }\n } catch (error) {\n // Log the error for debugging\n console.warn(\n `Token counting failed for ${descriptor.name}, using fallback estimation:`,\n error,\n );\n // If tiktoken fails, provide a rough estimate\n let totalChars = 0;\n let imageCount = 0;\n for (const msg of messages) {\n const parts = normalizeMessageContent(msg.content);\n for (const part of parts) {\n if (part.type === \"text\") {\n totalChars += part.text.length;\n } else if (part.type === \"image\") {\n imageCount++;\n }\n }\n }\n // Use same image token estimate as tiktoken path (765 tokens per image).\n return Math.ceil(totalChars / FALLBACK_CHARS_PER_TOKEN) + imageCount * 765;\n }\n }\n}\n\nexport function createOpenAIProviderFromEnv(): OpenAIChatProvider | null {\n return createProviderFromEnv(\"OPENAI_API_KEY\", OpenAI, OpenAIChatProvider);\n}\n","import { createAnthropicProviderFromEnv } from \"./anthropic.js\";\nimport { createGeminiProviderFromEnv } from \"./gemini.js\";\nimport { createOpenAIProviderFromEnv } from \"./openai.js\";\nimport type { ProviderAdapter } from \"./provider.js\";\n\nexport type ProviderDiscoverer = () => ProviderAdapter | null | undefined;\n\nconst DISCOVERERS: ProviderDiscoverer[] = [\n createOpenAIProviderFromEnv,\n createAnthropicProviderFromEnv,\n createGeminiProviderFromEnv,\n];\n\nexport function discoverProviderAdapters(): ProviderAdapter[] {\n const adapters: ProviderAdapter[] = [];\n\n for (const discover of DISCOVERERS) {\n const adapter = discover();\n if (adapter) {\n adapters.push(adapter);\n }\n }\n\n return adapters;\n}\n","/**\n * Model Registry\n *\n * Centralized registry for querying LLM model specifications,\n * validating configurations, and estimating costs.\n *\n * Model data is provided by ProviderAdapter implementations and\n * automatically populated when providers are registered.\n */\n\nimport type { ProviderAdapter } from \"../providers/provider.js\";\nimport type { CostEstimate, ModelLimits, ModelSpec } from \"./model-catalog.js\";\n\nexport class ModelRegistry {\n private modelSpecs: ModelSpec[] = [];\n private providerMap = new Map<string, ModelSpec[]>();\n\n /**\n * Register a provider and collect its model specifications\n */\n registerProvider(provider: ProviderAdapter): void {\n const specs = provider.getModelSpecs?.() ?? [];\n\n if (specs.length > 0) {\n this.modelSpecs.push(...specs);\n this.providerMap.set(provider.providerId, specs);\n }\n }\n\n /**\n * Register a custom model specification at runtime\n *\n * Use this to add models that aren't in the built-in catalog, such as:\n * - Fine-tuned models with custom pricing\n * - New models not yet supported by llmist\n * - Custom deployments with different configurations\n *\n * @param spec - Complete model specification\n * @throws {Error} If spec is missing required fields\n *\n * @example\n * ```ts\n * client.modelRegistry.registerModel({\n * provider: \"openai\",\n * modelId: \"ft:gpt-4o-2024-08-06:my-org:custom:abc123\",\n * displayName: \"My Fine-tuned GPT-4o\",\n * contextWindow: 128_000,\n * maxOutputTokens: 16_384,\n * pricing: { input: 7.5, output: 30.0 },\n * knowledgeCutoff: \"2024-08\",\n * features: { streaming: true, functionCalling: true, vision: true }\n * });\n * ```\n */\n registerModel(spec: ModelSpec): void {\n // Validate required fields\n if (!spec.modelId || !spec.provider) {\n throw new Error(\"ModelSpec must have modelId and provider\");\n }\n\n // Check for duplicates\n const existing = this.getModelSpec(spec.modelId);\n if (existing) {\n console.warn(\n `[llmist] Overwriting existing model spec for \"${spec.modelId}\". ` +\n `Previous: ${existing.displayName}, New: ${spec.displayName}`,\n );\n // Remove old spec from arrays\n const index = this.modelSpecs.findIndex((m) => m.modelId === spec.modelId);\n if (index !== -1) {\n this.modelSpecs.splice(index, 1);\n }\n // Remove from provider map\n const providerSpecs = this.providerMap.get(spec.provider);\n if (providerSpecs) {\n const providerIndex = providerSpecs.findIndex((m) => m.modelId === spec.modelId);\n if (providerIndex !== -1) {\n providerSpecs.splice(providerIndex, 1);\n }\n }\n }\n\n // Add to registry\n this.modelSpecs.push(spec);\n\n // Update provider map\n const providerSpecs = this.providerMap.get(spec.provider) ?? [];\n providerSpecs.push(spec);\n this.providerMap.set(spec.provider, providerSpecs);\n }\n\n /**\n * Register multiple custom model specifications at once\n *\n * @param specs - Array of complete model specifications\n *\n * @example\n * ```ts\n * client.modelRegistry.registerModels([\n * { provider: \"openai\", modelId: \"gpt-5\", ... },\n * { provider: \"openai\", modelId: \"gpt-5-mini\", ... }\n * ]);\n * ```\n */\n registerModels(specs: ModelSpec[]): void {\n for (const spec of specs) {\n this.registerModel(spec);\n }\n }\n\n /**\n * Get model specification by model ID\n * @param modelId - Full model identifier (e.g., 'gpt-5', 'claude-sonnet-4-5-20250929')\n * @returns ModelSpec if found, undefined otherwise\n */\n getModelSpec(modelId: string): ModelSpec | undefined {\n return this.modelSpecs.find((model) => model.modelId === modelId);\n }\n\n /**\n * List all models, optionally filtered by provider\n * @param providerId - Optional provider ID to filter by (e.g., 'openai', 'anthropic')\n * @returns Array of ModelSpec objects\n */\n listModels(providerId?: string): ModelSpec[] {\n if (!providerId) {\n return [...this.modelSpecs];\n }\n\n return this.providerMap.get(providerId) ?? [];\n }\n\n /**\n * Get context window and output limits for a model\n * @param modelId - Full model identifier\n * @returns ModelLimits if model found, undefined otherwise\n */\n getModelLimits(modelId: string): ModelLimits | undefined {\n const spec = this.getModelSpec(modelId);\n if (!spec) return undefined;\n\n return {\n contextWindow: spec.contextWindow,\n maxOutputTokens: spec.maxOutputTokens,\n };\n }\n\n /**\n * Estimate API cost for a given model and token usage\n * @param modelId - Full model identifier\n * @param inputTokens - Number of input tokens (total, including cached and cache creation)\n * @param outputTokens - Number of output tokens\n * @param cachedInputTokens - Number of cached input tokens (subset of inputTokens)\n * @param cacheCreationInputTokens - Number of cache creation tokens (subset of inputTokens, Anthropic only)\n * @returns CostEstimate if model found, undefined otherwise\n */\n estimateCost(\n modelId: string,\n inputTokens: number,\n outputTokens: number,\n cachedInputTokens = 0,\n cacheCreationInputTokens = 0,\n ): CostEstimate | undefined {\n const spec = this.getModelSpec(modelId);\n if (!spec) return undefined;\n\n // Pricing is per 1M tokens, so convert to actual cost\n // Cached tokens are charged at a lower rate (or same rate if no cached pricing)\n // Cache creation tokens are charged at a higher rate (Anthropic: 1.25x input)\n const cachedRate = spec.pricing.cachedInput ?? spec.pricing.input;\n const cacheWriteRate = spec.pricing.cacheWriteInput ?? spec.pricing.input;\n const uncachedInputTokens = inputTokens - cachedInputTokens - cacheCreationInputTokens;\n\n const uncachedInputCost = (uncachedInputTokens / 1_000_000) * spec.pricing.input;\n const cachedInputCost = (cachedInputTokens / 1_000_000) * cachedRate;\n const cacheCreationCost = (cacheCreationInputTokens / 1_000_000) * cacheWriteRate;\n const inputCost = uncachedInputCost + cachedInputCost + cacheCreationCost;\n const outputCost = (outputTokens / 1_000_000) * spec.pricing.output;\n const totalCost = inputCost + outputCost;\n\n return {\n inputCost,\n cachedInputCost,\n cacheCreationCost,\n outputCost,\n totalCost,\n currency: \"USD\",\n };\n }\n\n /**\n * Validate that requested token count fits within model limits\n * @param modelId - Full model identifier\n * @param requestedTokens - Total tokens requested (input + output)\n * @returns true if valid, false if model not found or exceeds limits\n */\n validateModelConfig(modelId: string, requestedTokens: number): boolean {\n const limits = this.getModelLimits(modelId);\n if (!limits) return false;\n\n return requestedTokens <= limits.contextWindow;\n }\n\n /**\n * Check if a model supports a specific feature\n * @param modelId - Full model identifier\n * @param feature - Feature to check ('streaming', 'functionCalling', 'vision', etc.)\n * @returns true if model supports feature, false otherwise\n */\n supportsFeature(modelId: string, feature: keyof ModelSpec[\"features\"]): boolean {\n const spec = this.getModelSpec(modelId);\n if (!spec) return false;\n\n return spec.features[feature] === true;\n }\n\n /**\n * Get all models that support a specific feature\n * @param feature - Feature to filter by\n * @param providerId - Optional provider ID to filter by\n * @returns Array of ModelSpec objects that support the feature\n */\n getModelsByFeature(feature: keyof ModelSpec[\"features\"], providerId?: string): ModelSpec[] {\n const models = this.listModels(providerId);\n return models.filter((model) => model.features[feature] === true);\n }\n\n /**\n * Get the most cost-effective model for a given provider and token budget\n * @param inputTokens - Expected input tokens\n * @param outputTokens - Expected output tokens\n * @param providerId - Optional provider ID to filter by\n * @returns ModelSpec with lowest total cost, or undefined if no models found\n */\n getCheapestModel(\n inputTokens: number,\n outputTokens: number,\n providerId?: string,\n ): ModelSpec | undefined {\n const models = this.listModels(providerId);\n if (models.length === 0) return undefined;\n\n let cheapest: { model: ModelSpec; cost: number } | undefined;\n\n for (const model of models) {\n const estimate = this.estimateCost(model.modelId, inputTokens, outputTokens);\n if (!estimate) continue;\n\n if (!cheapest || estimate.totalCost < cheapest.cost) {\n cheapest = { model, cost: estimate.totalCost };\n }\n }\n\n return cheapest?.model;\n }\n}\n","/**\n * Image Generation Namespace\n *\n * Provides image generation methods.\n *\n * @example\n * ```typescript\n * const llmist = new LLMist();\n *\n * const result = await llmist.image.generate({\n * model: \"dall-e-3\",\n * prompt: \"A cat in space\",\n * size: \"1024x1024\",\n * quality: \"hd\",\n * });\n *\n * console.log(result.images[0].url);\n * console.log(\"Cost:\", result.cost);\n * ```\n */\n\nimport type { ProviderAdapter } from \"../../providers/provider.js\";\nimport type {\n ImageGenerationOptions,\n ImageGenerationResult,\n ImageModelSpec,\n} from \"../media-types.js\";\n\nexport class ImageNamespace {\n constructor(\n private readonly adapters: ProviderAdapter[],\n private readonly defaultProvider: string,\n ) {}\n\n /**\n * Generate images from a text prompt.\n *\n * @param options - Image generation options\n * @returns Promise resolving to the generation result with images and cost\n * @throws Error if the provider doesn't support image generation\n */\n async generate(options: ImageGenerationOptions): Promise<ImageGenerationResult> {\n const modelId = options.model;\n\n // Find an adapter that supports this image model\n const adapter = this.findImageAdapter(modelId);\n if (!adapter || !adapter.generateImage) {\n throw new Error(\n `No provider supports image generation for model \"${modelId}\". ` +\n `Available image models: ${this.listModels()\n .map((m) => m.modelId)\n .join(\", \")}`,\n );\n }\n\n return adapter.generateImage(options);\n }\n\n /**\n * List all available image generation models.\n */\n listModels(): ImageModelSpec[] {\n const models: ImageModelSpec[] = [];\n for (const adapter of this.adapters) {\n if (adapter.getImageModelSpecs) {\n models.push(...adapter.getImageModelSpecs());\n }\n }\n return models;\n }\n\n /**\n * Check if a model is supported for image generation.\n */\n supportsModel(modelId: string): boolean {\n return this.findImageAdapter(modelId) !== undefined;\n }\n\n private findImageAdapter(modelId: string): ProviderAdapter | undefined {\n return this.adapters.find((adapter) => adapter.supportsImageGeneration?.(modelId) ?? false);\n }\n}\n","/**\n * Speech Generation Namespace\n *\n * Provides text-to-speech generation methods.\n *\n * @example\n * ```typescript\n * const llmist = new LLMist();\n *\n * const result = await llmist.speech.generate({\n * model: \"tts-1-hd\",\n * input: \"Hello, world!\",\n * voice: \"nova\",\n * });\n *\n * // Save the audio\n * fs.writeFileSync(\"output.mp3\", Buffer.from(result.audio));\n * console.log(\"Cost:\", result.cost);\n * ```\n */\n\nimport type { ProviderAdapter } from \"../../providers/provider.js\";\nimport type {\n SpeechGenerationOptions,\n SpeechGenerationResult,\n SpeechModelSpec,\n} from \"../media-types.js\";\n\nexport class SpeechNamespace {\n constructor(\n private readonly adapters: ProviderAdapter[],\n private readonly defaultProvider: string,\n ) {}\n\n /**\n * Generate speech audio from text.\n *\n * @param options - Speech generation options\n * @returns Promise resolving to the generation result with audio and cost\n * @throws Error if the provider doesn't support speech generation\n */\n async generate(options: SpeechGenerationOptions): Promise<SpeechGenerationResult> {\n const modelId = options.model;\n\n // Find an adapter that supports this speech model\n const adapter = this.findSpeechAdapter(modelId);\n if (!adapter || !adapter.generateSpeech) {\n throw new Error(\n `No provider supports speech generation for model \"${modelId}\". ` +\n `Available speech models: ${this.listModels()\n .map((m) => m.modelId)\n .join(\", \")}`,\n );\n }\n\n return adapter.generateSpeech(options);\n }\n\n /**\n * List all available speech generation models.\n */\n listModels(): SpeechModelSpec[] {\n const models: SpeechModelSpec[] = [];\n for (const adapter of this.adapters) {\n if (adapter.getSpeechModelSpecs) {\n models.push(...adapter.getSpeechModelSpecs());\n }\n }\n return models;\n }\n\n /**\n * Check if a model is supported for speech generation.\n */\n supportsModel(modelId: string): boolean {\n return this.findSpeechAdapter(modelId) !== undefined;\n }\n\n private findSpeechAdapter(modelId: string): ProviderAdapter | undefined {\n return this.adapters.find((adapter) => adapter.supportsSpeechGeneration?.(modelId) ?? false);\n }\n}\n","/**\n * Quick execution methods for simple use cases.\n *\n * These methods provide convenient shortcuts for common operations\n * without requiring full agent setup.\n *\n * @example\n * ```typescript\n * // Quick completion\n * const answer = await llmist.complete(\"What is 2+2?\");\n *\n * // Quick streaming\n * for await (const chunk of llmist.stream(\"Tell me a story\")) {\n * process.stdout.write(chunk);\n * }\n * ```\n */\n\nimport type { LLMist } from \"./client.js\";\nimport { LLMMessageBuilder } from \"./messages.js\";\nimport { resolveModel } from \"./model-shortcuts.js\";\n\n/**\n * Options for text generation methods (complete/stream).\n */\nexport interface TextGenerationOptions {\n /** Model to use (supports aliases like \"gpt4\", \"sonnet\", \"flash\") */\n model?: string;\n\n /** Temperature (0-1) */\n temperature?: number;\n\n /** System prompt */\n systemPrompt?: string;\n\n /** Max tokens to generate */\n maxTokens?: number;\n}\n\n/**\n * Quick completion - returns final text response.\n *\n * @param client - LLMist client instance\n * @param prompt - User prompt\n * @param options - Optional configuration\n * @returns Complete text response\n *\n * @example\n * ```typescript\n * const client = new LLMist();\n * const answer = await complete(client, \"What is 2+2?\");\n * console.log(answer); // \"4\" or \"2+2 equals 4\"\n * ```\n */\nexport async function complete(\n client: LLMist,\n prompt: string,\n options: TextGenerationOptions = {},\n): Promise<string> {\n const model = resolveModel(options.model ?? \"gpt-5-nano\");\n\n const builder = new LLMMessageBuilder();\n if (options.systemPrompt) {\n builder.addSystem(options.systemPrompt);\n }\n builder.addUser(prompt);\n\n let fullResponse = \"\";\n for await (const chunk of client.stream({\n model,\n messages: builder.build(),\n temperature: options.temperature,\n maxTokens: options.maxTokens,\n })) {\n fullResponse += chunk.text;\n }\n\n return fullResponse.trim();\n}\n\n/**\n * Quick streaming - returns async generator of text chunks.\n *\n * @param client - LLMist client instance\n * @param prompt - User prompt\n * @param options - Optional configuration\n * @returns Async generator yielding text chunks\n *\n * @example\n * ```typescript\n * const client = new LLMist();\n *\n * for await (const chunk of stream(client, \"Tell me a story\")) {\n * process.stdout.write(chunk);\n * }\n * ```\n */\nexport async function* stream(\n client: LLMist,\n prompt: string,\n options: TextGenerationOptions = {},\n): AsyncGenerator<string> {\n const model = resolveModel(options.model ?? \"gpt-5-nano\");\n\n const builder = new LLMMessageBuilder();\n if (options.systemPrompt) {\n builder.addSystem(options.systemPrompt);\n }\n builder.addUser(prompt);\n\n for await (const chunk of client.stream({\n model,\n messages: builder.build(),\n temperature: options.temperature,\n maxTokens: options.maxTokens,\n })) {\n yield chunk.text;\n }\n}\n","/**\n * Text Generation Namespace\n *\n * Provides text completion and streaming methods.\n * Replaces the deprecated llmist.complete() and llmist.stream() methods.\n *\n * @example\n * ```typescript\n * const llmist = new LLMist();\n *\n * // Complete\n * const answer = await llmist.text.complete(\"What is 2+2?\");\n *\n * // Stream\n * for await (const chunk of llmist.text.stream(\"Tell me a story\")) {\n * process.stdout.write(chunk);\n * }\n * ```\n */\n\nimport type { LLMist } from \"../client.js\";\nimport { complete, type TextGenerationOptions, stream } from \"../quick-methods.js\";\n\nexport class TextNamespace {\n constructor(private readonly client: LLMist) {}\n\n /**\n * Generate a complete text response.\n *\n * @param prompt - User prompt\n * @param options - Optional configuration\n * @returns Complete text response\n */\n async complete(prompt: string, options?: TextGenerationOptions): Promise<string> {\n return complete(this.client, prompt, options);\n }\n\n /**\n * Stream text chunks.\n *\n * @param prompt - User prompt\n * @param options - Optional configuration\n * @returns Async generator yielding text chunks\n */\n stream(prompt: string, options?: TextGenerationOptions): AsyncGenerator<string> {\n return stream(this.client, prompt, options);\n }\n}\n","/**\n * Vision Analysis Namespace\n *\n * Provides one-shot image analysis without agent setup.\n * Useful for quick image understanding tasks.\n *\n * @example\n * ```typescript\n * const llmist = new LLMist();\n *\n * const description = await llmist.vision.analyze({\n * model: \"gpt-4o\",\n * image: await readFile(\"photo.jpg\"),\n * prompt: \"Describe this image in detail\",\n * });\n *\n * console.log(description);\n * ```\n */\n\nimport type { LLMist } from \"../client.js\";\nimport type { ImageMimeType } from \"../input-content.js\";\nimport {\n detectImageMimeType,\n imageFromBuffer,\n imageFromUrl,\n isDataUrl,\n parseDataUrl,\n text,\n} from \"../input-content.js\";\nimport { LLMMessageBuilder } from \"../messages.js\";\n\n/**\n * Options for vision analysis.\n */\nexport interface VisionAnalyzeOptions {\n /** Model to use (must support vision, e.g., \"gpt-4o\", \"claude-sonnet-4-20250514\", \"gemini-2.5-flash\") */\n model: string;\n\n /** Image data: Buffer, Uint8Array, base64 string, data URL, or HTTPS URL */\n image: string | Buffer | Uint8Array;\n\n /** Analysis prompt describing what to do with the image */\n prompt: string;\n\n /** MIME type (auto-detected if not provided for Buffer/Uint8Array) */\n mimeType?: ImageMimeType;\n\n /** System prompt for analysis context */\n systemPrompt?: string;\n\n /** Max tokens for response */\n maxTokens?: number;\n\n /** Temperature (0-1) */\n temperature?: number;\n}\n\n/**\n * Result of vision analysis.\n */\nexport interface VisionAnalyzeResult {\n /** The analysis text */\n text: string;\n\n /** Model used */\n model: string;\n\n /** Token usage if available */\n usage?: {\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n };\n}\n\nexport class VisionNamespace {\n constructor(private readonly client: LLMist) {}\n\n /**\n * Build a message builder with the image content attached.\n * Handles URLs, data URLs, base64 strings, and binary buffers.\n */\n private buildImageMessage(options: VisionAnalyzeOptions): LLMMessageBuilder {\n const builder = new LLMMessageBuilder();\n\n if (options.systemPrompt) {\n builder.addSystem(options.systemPrompt);\n }\n\n // Handle different image source types\n if (typeof options.image === \"string\") {\n if (options.image.startsWith(\"http://\") || options.image.startsWith(\"https://\")) {\n // URL - only supported by OpenAI\n builder.addUserWithImageUrl(options.prompt, options.image);\n } else if (isDataUrl(options.image)) {\n // Data URL - parse and use\n const parsed = parseDataUrl(options.image);\n if (!parsed) {\n throw new Error(\"Invalid data URL format\");\n }\n builder.addUserWithImage(options.prompt, parsed.data, parsed.mimeType as ImageMimeType);\n } else {\n // Assume base64 string\n const buffer = Buffer.from(options.image, \"base64\");\n builder.addUserWithImage(options.prompt, buffer, options.mimeType);\n }\n } else {\n // Buffer or Uint8Array\n builder.addUserWithImage(options.prompt, options.image, options.mimeType);\n }\n\n return builder;\n }\n\n /**\n * Stream the response and collect text and usage information.\n */\n private async streamAndCollect(\n options: VisionAnalyzeOptions,\n builder: LLMMessageBuilder,\n ): Promise<{ text: string; usage?: VisionAnalyzeResult[\"usage\"] }> {\n let response = \"\";\n let finalUsage: VisionAnalyzeResult[\"usage\"] | undefined;\n\n for await (const chunk of this.client.stream({\n model: options.model,\n messages: builder.build(),\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n })) {\n response += chunk.text;\n if (chunk.usage) {\n finalUsage = {\n inputTokens: chunk.usage.inputTokens,\n outputTokens: chunk.usage.outputTokens,\n totalTokens: chunk.usage.totalTokens,\n };\n }\n }\n\n return { text: response.trim(), usage: finalUsage };\n }\n\n /**\n * Analyze an image with a vision-capable model.\n * Returns the analysis as a string.\n *\n * @param options - Vision analysis options\n * @returns Promise resolving to the analysis text\n * @throws Error if the image format is unsupported or model doesn't support vision\n *\n * @example\n * ```typescript\n * // From file\n * const result = await llmist.vision.analyze({\n * model: \"gpt-4o\",\n * image: await fs.readFile(\"photo.jpg\"),\n * prompt: \"What's in this image?\",\n * });\n *\n * // From URL (OpenAI only)\n * const result = await llmist.vision.analyze({\n * model: \"gpt-4o\",\n * image: \"https://example.com/image.jpg\",\n * prompt: \"Describe this image\",\n * });\n * ```\n */\n async analyze(options: VisionAnalyzeOptions): Promise<string> {\n const builder = this.buildImageMessage(options);\n const { text } = await this.streamAndCollect(options, builder);\n return text;\n }\n\n /**\n * Analyze an image and return detailed result with usage info.\n *\n * @param options - Vision analysis options\n * @returns Promise resolving to the analysis result with usage info\n */\n async analyzeWithUsage(options: VisionAnalyzeOptions): Promise<VisionAnalyzeResult> {\n const builder = this.buildImageMessage(options);\n const { text, usage } = await this.streamAndCollect(options, builder);\n\n return {\n text,\n model: options.model,\n usage,\n };\n }\n\n /**\n * Check if a model supports vision/image input.\n *\n * @param modelId - Model ID to check\n * @returns True if the model supports vision\n */\n supportsModel(modelId: string): boolean {\n const spec = this.client.modelRegistry.getModelSpec(modelId);\n return spec?.features?.vision === true;\n }\n\n /**\n * List all models that support vision.\n *\n * @returns Array of model IDs that support vision\n */\n listModels(): string[] {\n return this.client.modelRegistry\n .listModels()\n .filter((spec) => spec.features?.vision === true)\n .map((spec) => spec.modelId);\n }\n}\n","import type { LLMMessage } from \"./messages.js\";\n\nexport interface LLMGenerationOptions {\n model: string;\n messages: LLMMessage[];\n maxTokens?: number;\n temperature?: number;\n topP?: number;\n stopSequences?: string[];\n responseFormat?: \"text\";\n metadata?: Record<string, unknown>;\n extra?: Record<string, unknown>;\n /**\n * Optional abort signal for cancelling the request mid-flight.\n *\n * When the signal is aborted, the provider will attempt to cancel\n * the underlying HTTP request and the stream will terminate with\n * an abort error. Use `isAbortError()` from `@/core/errors` to\n * detect cancellation in error handling.\n *\n * @example\n * ```typescript\n * const controller = new AbortController();\n *\n * const stream = client.stream({\n * model: \"claude-3-5-sonnet-20241022\",\n * messages: [{ role: \"user\", content: \"Tell me a long story\" }],\n * signal: controller.signal,\n * });\n *\n * // Cancel after 5 seconds\n * setTimeout(() => controller.abort(), 5000);\n *\n * try {\n * for await (const chunk of stream) {\n * process.stdout.write(chunk.text);\n * }\n * } catch (error) {\n * if (isAbortError(error)) {\n * console.log(\"\\nRequest was cancelled\");\n * } else {\n * throw error;\n * }\n * }\n * ```\n */\n signal?: AbortSignal;\n}\n\nexport interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n /** Number of input tokens served from cache (subset of inputTokens) */\n cachedInputTokens?: number;\n /** Number of input tokens written to cache (subset of inputTokens, Anthropic only) */\n cacheCreationInputTokens?: number;\n}\n\nexport interface LLMStreamChunk {\n text: string;\n /**\n * Indicates that the provider has finished producing output and includes the reason if available.\n */\n finishReason?: string | null;\n /**\n * Token usage information, typically available in the final chunk when the stream completes.\n */\n usage?: TokenUsage;\n /**\n * Provider specific payload emitted at the same time as the text chunk. This is useful for debugging and tests.\n */\n rawEvent?: unknown;\n}\n\nexport interface LLMStream extends AsyncIterable<LLMStreamChunk> {}\n\nexport type ProviderIdentifier = string;\n\nexport interface ModelDescriptor {\n provider: string;\n name: string;\n}\n\nexport class ModelIdentifierParser {\n constructor(private readonly defaultProvider: string = \"openai\") {}\n\n parse(identifier: string): ModelDescriptor {\n const trimmed = identifier.trim();\n if (!trimmed) {\n throw new Error(\"Model identifier cannot be empty\");\n }\n\n const [maybeProvider, ...rest] = trimmed.split(\":\");\n if (rest.length === 0) {\n return { provider: this.defaultProvider, name: maybeProvider };\n }\n\n const provider = maybeProvider;\n const name = rest.join(\":\");\n if (!name) {\n throw new Error(\"Model name cannot be empty\");\n }\n\n return { provider, name };\n }\n}\n","import { AgentBuilder } from \"../agent/builder.js\";\nimport { discoverProviderAdapters } from \"../providers/discovery.js\";\nimport type { ProviderAdapter } from \"../providers/provider.js\";\nimport type { LLMMessage } from \"./messages.js\";\nimport type { ModelSpec } from \"./model-catalog.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { ImageNamespace } from \"./namespaces/image.js\";\nimport { SpeechNamespace } from \"./namespaces/speech.js\";\nimport { TextNamespace } from \"./namespaces/text.js\";\nimport { VisionNamespace } from \"./namespaces/vision.js\";\nimport type { LLMGenerationOptions, LLMStream, ModelDescriptor } from \"./options.js\";\nimport { ModelIdentifierParser } from \"./options.js\";\nimport {\n complete as completeHelper,\n type TextGenerationOptions,\n stream as streamHelper,\n} from \"./quick-methods.js\";\n\nexport interface LLMistOptions {\n /**\n * Provider adapters to register manually.\n */\n adapters?: ProviderAdapter[];\n /**\n * Default provider prefix applied when a model identifier omits it.\n */\n defaultProvider?: string;\n /**\n * Automatically discover built-in providers based on environment configuration.\n * Enabled by default.\n */\n autoDiscoverProviders?: boolean;\n /**\n * Custom model specifications to register at initialization.\n * Use this to define models not in the built-in catalog, such as:\n * - Fine-tuned models with custom pricing\n * - New models not yet supported by llmist\n * - Custom deployments with different configurations\n *\n * @example\n * ```ts\n * new LLMist({\n * customModels: [{\n * provider: \"openai\",\n * modelId: \"ft:gpt-4o-2024-08-06:my-org:custom:abc123\",\n * displayName: \"My Fine-tuned GPT-4o\",\n * contextWindow: 128_000,\n * maxOutputTokens: 16_384,\n * pricing: { input: 7.5, output: 30.0 },\n * knowledgeCutoff: \"2024-08\",\n * features: { streaming: true, functionCalling: true, vision: true }\n * }]\n * });\n * ```\n */\n customModels?: ModelSpec[];\n}\n\nexport class LLMist {\n private readonly parser: ModelIdentifierParser;\n private readonly defaultProvider: string;\n readonly modelRegistry: ModelRegistry;\n private readonly adapters: ProviderAdapter[];\n\n // Namespaces for different generation types\n readonly text: TextNamespace;\n readonly image: ImageNamespace;\n readonly speech: SpeechNamespace;\n readonly vision: VisionNamespace;\n\n constructor();\n constructor(adapters: ProviderAdapter[]);\n constructor(adapters: ProviderAdapter[], defaultProvider: string);\n constructor(options: LLMistOptions);\n constructor(...args: [] | [ProviderAdapter[]] | [ProviderAdapter[], string] | [LLMistOptions]) {\n let adapters: ProviderAdapter[] = [];\n let defaultProvider: string | undefined;\n let autoDiscoverProviders = true;\n let customModels: ModelSpec[] = [];\n\n if (args.length === 0) {\n // Use defaults\n } else if (Array.isArray(args[0])) {\n adapters = args[0];\n if (args.length > 1) {\n defaultProvider = args[1];\n }\n } else if (typeof args[0] === \"object\" && args[0] !== null) {\n const options = args[0];\n adapters = options.adapters ?? [];\n defaultProvider = options.defaultProvider;\n customModels = options.customModels ?? [];\n if (typeof options.autoDiscoverProviders === \"boolean\") {\n autoDiscoverProviders = options.autoDiscoverProviders;\n }\n }\n\n const discoveredAdapters = autoDiscoverProviders ? discoverProviderAdapters() : [];\n const combinedAdapters: ProviderAdapter[] = [...adapters];\n for (const adapter of discoveredAdapters) {\n if (!combinedAdapters.some((existing) => existing.providerId === adapter.providerId)) {\n combinedAdapters.push(adapter);\n }\n }\n\n if (combinedAdapters.length === 0) {\n throw new Error(\n \"No LLM providers available. Provide adapters explicitly or set provider API keys in the environment.\",\n );\n }\n\n const resolvedDefaultProvider = defaultProvider ?? combinedAdapters[0]?.providerId ?? \"openai\";\n\n // Sort by priority (descending: higher priority first)\n // Use stable sort to preserve order for equal priorities\n this.adapters = [...combinedAdapters].sort((a, b) => {\n const priorityA = a.priority ?? 0;\n const priorityB = b.priority ?? 0;\n return priorityB - priorityA;\n });\n this.defaultProvider = resolvedDefaultProvider;\n this.parser = new ModelIdentifierParser(resolvedDefaultProvider);\n this.modelRegistry = new ModelRegistry();\n\n // Register all providers with the model registry\n for (const adapter of this.adapters) {\n this.modelRegistry.registerProvider(adapter);\n }\n\n // Register custom models if provided\n if (customModels.length > 0) {\n this.modelRegistry.registerModels(customModels);\n }\n\n // Initialize generation namespaces\n this.text = new TextNamespace(this);\n this.image = new ImageNamespace(this.adapters, this.defaultProvider);\n this.speech = new SpeechNamespace(this.adapters, this.defaultProvider);\n this.vision = new VisionNamespace(this);\n }\n\n stream(options: LLMGenerationOptions): LLMStream {\n const descriptor = this.parser.parse(options.model);\n const spec = this.modelRegistry.getModelSpec(descriptor.name);\n const adapter = this.resolveAdapter(descriptor);\n return adapter.stream(options, descriptor, spec);\n }\n\n /**\n * Count tokens in messages for a given model.\n *\n * Uses provider-specific token counting methods for accurate estimation:\n * - OpenAI: tiktoken library with model-specific encodings\n * - Anthropic: Native messages.countTokens() API\n * - Gemini: SDK's countTokens() method\n *\n * Falls back to character-based estimation (4 chars/token) if the provider\n * doesn't support native token counting or if counting fails.\n *\n * This is useful for:\n * - Pre-request cost estimation\n * - Context window management\n * - Request batching optimization\n *\n * @param model - Model identifier (e.g., \"openai:gpt-4\", \"anthropic:claude-3-5-sonnet-20241022\")\n * @param messages - Array of messages to count tokens for\n * @returns Promise resolving to the estimated input token count\n *\n * @example\n * ```typescript\n * const client = new LLMist();\n * const messages = [\n * { role: 'system', content: 'You are a helpful assistant.' },\n * { role: 'user', content: 'Hello!' }\n * ];\n *\n * const tokenCount = await client.countTokens('openai:gpt-4', messages);\n * console.log(`Estimated tokens: ${tokenCount}`);\n * ```\n */\n async countTokens(model: string, messages: LLMMessage[]): Promise<number> {\n const descriptor = this.parser.parse(model);\n const spec = this.modelRegistry.getModelSpec(descriptor.name);\n const adapter = this.resolveAdapter(descriptor);\n\n // Check if the provider supports token counting\n if (adapter.countTokens) {\n return adapter.countTokens(messages, descriptor, spec);\n }\n\n // Fallback: rough character-based estimation (4 chars per token)\n const totalChars = messages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0);\n return Math.ceil(totalChars / 4);\n }\n\n private resolveAdapter(descriptor: ModelDescriptor): ProviderAdapter {\n const adapter = this.adapters.find((item) => item.supports(descriptor));\n if (!adapter) {\n throw new Error(`No adapter registered for provider ${descriptor.provider}`);\n }\n\n return adapter;\n }\n\n /**\n * Quick completion - returns final text response.\n * Convenient for simple queries without needing agent setup.\n *\n * @param prompt - User prompt\n * @param options - Optional configuration\n * @returns Complete text response\n *\n * @example\n * ```typescript\n * const answer = await LLMist.complete(\"What is 2+2?\");\n * console.log(answer); // \"4\" or \"2+2 equals 4\"\n *\n * const answer = await LLMist.complete(\"Tell me a joke\", {\n * model: \"sonnet\",\n * temperature: 0.9\n * });\n * ```\n */\n static async complete(prompt: string, options?: TextGenerationOptions): Promise<string> {\n const client = new LLMist();\n return completeHelper(client, prompt, options);\n }\n\n /**\n * Quick streaming - returns async generator of text chunks.\n * Convenient for streaming responses without needing agent setup.\n *\n * @param prompt - User prompt\n * @param options - Optional configuration\n * @returns Async generator yielding text chunks\n *\n * @example\n * ```typescript\n * for await (const chunk of LLMist.stream(\"Tell me a story\")) {\n * process.stdout.write(chunk);\n * }\n *\n * // With options\n * for await (const chunk of LLMist.stream(\"Generate code\", {\n * model: \"gpt4\",\n * systemPrompt: \"You are a coding assistant\"\n * })) {\n * process.stdout.write(chunk);\n * }\n * ```\n */\n static stream(prompt: string, options?: TextGenerationOptions): AsyncGenerator<string> {\n const client = new LLMist();\n return streamHelper(client, prompt, options);\n }\n\n /**\n * Instance method: Quick completion using this client instance.\n *\n * @param prompt - User prompt\n * @param options - Optional configuration\n * @returns Complete text response\n */\n async complete(prompt: string, options?: TextGenerationOptions): Promise<string> {\n return completeHelper(this, prompt, options);\n }\n\n /**\n * Instance method: Quick streaming using this client instance.\n *\n * @param prompt - User prompt\n * @param options - Optional configuration\n * @returns Async generator yielding text chunks\n */\n streamText(prompt: string, options?: TextGenerationOptions): AsyncGenerator<string> {\n return streamHelper(this, prompt, options);\n }\n\n /**\n * Create a fluent agent builder.\n * Provides a chainable API for configuring and creating agents.\n *\n * @returns AgentBuilder instance for chaining\n *\n * @example\n * ```typescript\n * const agent = LLMist.createAgent()\n * .withModel(\"sonnet\")\n * .withSystem(\"You are a helpful assistant\")\n * .withGadgets(Calculator, Weather)\n * .ask(\"What's the weather in Paris?\");\n *\n * for await (const event of agent.run()) {\n * // handle events\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Quick one-liner for simple queries\n * const answer = await LLMist.createAgent()\n * .withModel(\"gpt4-mini\")\n * .askAndCollect(\"What is 2+2?\");\n * ```\n */\n static createAgent(): AgentBuilder {\n return new AgentBuilder();\n }\n\n /**\n * Create agent builder with this client instance.\n * Useful when you want to reuse a configured client.\n *\n * @returns AgentBuilder instance using this client\n *\n * @example\n * ```typescript\n * const client = new LLMist({ ... });\n *\n * const agent = client.createAgent()\n * .withModel(\"sonnet\")\n * .ask(\"Hello\");\n * ```\n */\n createAgent(): AgentBuilder {\n return new AgentBuilder(this);\n }\n}\n","import type { ZodTypeAny } from \"zod\";\n\n/**\n * Helper to safely access Zod's internal _def structure.\n * Zod's _def is not publicly typed, so we cast through unknown.\n */\nfunction getDef(schema: ZodTypeAny): Record<string, unknown> {\n return schema._def as unknown as Record<string, unknown>;\n}\n\n/**\n * Type hints that guide value coercion.\n * - 'string': Keep the value as a string, no coercion\n * - 'number': Coerce to number if possible\n * - 'boolean': Coerce to boolean if possible\n * - 'unknown': Use default auto-coercion logic (backwards compatible)\n */\nexport type TypeHint = \"string\" | \"number\" | \"boolean\" | \"unknown\";\n\n/**\n * Get the type name from a Zod schema's _def.\n * Handles both Zod v3 (typeName) and Zod v4 (type) structures.\n * Note: We cast _def to any since Zod's internal structure isn't publicly typed.\n */\nfunction getTypeName(schema: ZodTypeAny): string | undefined {\n const def = getDef(schema);\n // Zod v4 uses _def.type, Zod v3 uses _def.typeName\n return (def?.type ?? def?.typeName) as string | undefined;\n}\n\n/**\n * Get the shape from a Zod object schema's _def.\n * Handles both Zod v3 (shape()) and Zod v4 (shape) structures.\n * Note: We cast _def to any since Zod's internal structure isn't publicly typed.\n */\nfunction getShape(schema: ZodTypeAny): Record<string, ZodTypeAny> | undefined {\n const def = getDef(schema);\n // Zod v4 uses _def.shape directly, Zod v3 uses _def.shape()\n if (typeof def?.shape === \"function\") {\n return (def.shape as () => Record<string, ZodTypeAny>)();\n }\n return def?.shape as Record<string, ZodTypeAny> | undefined;\n}\n\n/**\n * Introspects Zod schemas to determine expected types at JSON pointer paths.\n *\n * This enables schema-aware type coercion - instead of blindly converting\n * \"1\" to a number, the parser can check if the schema expects a string\n * and preserve the original value.\n *\n * Design decisions:\n * - Union types prefer string over other primitives (preserves LLM intent)\n * - Transform/effect schemas return 'unknown' (let Zod handle transformation)\n * - Invalid paths return 'unknown' (fall back to auto-coercion)\n *\n * @example\n * ```typescript\n * const schema = z.object({\n * id: z.string(),\n * count: z.number(),\n * config: z.object({ timeout: z.number() })\n * });\n *\n * const introspector = new SchemaIntrospector(schema);\n * introspector.getTypeAtPath(\"id\"); // 'string'\n * introspector.getTypeAtPath(\"count\"); // 'number'\n * introspector.getTypeAtPath(\"config/timeout\"); // 'number'\n * introspector.getTypeAtPath(\"unknown\"); // 'unknown'\n * ```\n */\nexport class SchemaIntrospector {\n private readonly schema: ZodTypeAny;\n private readonly cache = new Map<string, TypeHint>();\n\n constructor(schema: ZodTypeAny) {\n this.schema = schema;\n }\n\n /**\n * Get the expected type at a JSON pointer path.\n *\n * @param pointer - JSON pointer path without leading / (e.g., \"config/timeout\", \"items/0\")\n * @returns Type hint for coercion decision\n */\n getTypeAtPath(pointer: string): TypeHint {\n // Check cache first\n const cached = this.cache.get(pointer);\n if (cached !== undefined) {\n return cached;\n }\n\n const result = this.resolveTypeAtPath(pointer);\n this.cache.set(pointer, result);\n return result;\n }\n\n /**\n * Internal method to resolve type at path without caching.\n */\n private resolveTypeAtPath(pointer: string): TypeHint {\n // Empty pointer means the root - shouldn't happen for parameters\n if (!pointer) {\n return this.getBaseType(this.schema);\n }\n\n const segments = pointer.split(\"/\");\n let current: ZodTypeAny = this.schema;\n\n for (const segment of segments) {\n // Unwrap any wrapper types (optional, default, nullable, etc.)\n current = this.unwrapSchema(current);\n\n // Navigate based on schema type\n const typeName = getTypeName(current);\n\n if (typeName === \"object\" || typeName === \"ZodObject\") {\n // Navigate into object property\n const shape = getShape(current);\n if (!shape || !(segment in shape)) {\n return \"unknown\"; // Property doesn't exist in schema\n }\n current = shape[segment];\n } else if (typeName === \"array\" || typeName === \"ZodArray\") {\n // For array indices, get element type\n if (!/^\\d+$/.test(segment)) {\n return \"unknown\"; // Not a numeric index\n }\n // Zod v4 uses _def.element, Zod v3 uses _def.type\n const def = getDef(current);\n const elementType = (def?.element ?? def?.type) as ZodTypeAny | undefined;\n if (!elementType) {\n return \"unknown\";\n }\n current = elementType;\n } else if (typeName === \"tuple\" || typeName === \"ZodTuple\") {\n // For tuples, get element at specific index\n if (!/^\\d+$/.test(segment)) {\n return \"unknown\";\n }\n const index = parseInt(segment, 10);\n const def = getDef(current);\n const items = def?.items as ZodTypeAny[] | undefined;\n if (!items || index >= items.length) {\n return \"unknown\";\n }\n current = items[index];\n } else if (typeName === \"record\" || typeName === \"ZodRecord\") {\n // For records, all values have the same type\n // Zod v4 uses _def.valueType, Zod v3 uses _def.valueType\n const def = getDef(current);\n const valueType = def?.valueType as ZodTypeAny | undefined;\n if (!valueType) {\n return \"unknown\";\n }\n current = valueType;\n } else {\n // Can't navigate further (e.g., trying to access property on a string)\n return \"unknown\";\n }\n }\n\n // Get the base type of the final schema\n return this.getBaseType(current);\n }\n\n /**\n * Unwrap schema modifiers (optional, default, nullable, branded, etc.)\n * to get to the underlying type.\n */\n private unwrapSchema(schema: ZodTypeAny): ZodTypeAny {\n let current = schema;\n let iterations = 0;\n const maxIterations = 20; // Prevent infinite loops\n\n while (iterations < maxIterations) {\n const typeName = getTypeName(current);\n\n // Check for wrapper types (both Zod v3 and v4 naming)\n const wrapperTypes = [\n \"optional\",\n \"nullable\",\n \"default\",\n \"catch\",\n \"branded\",\n \"readonly\",\n \"pipeline\",\n \"ZodOptional\",\n \"ZodNullable\",\n \"ZodDefault\",\n \"ZodCatch\",\n \"ZodBranded\",\n \"ZodReadonly\",\n \"ZodPipeline\",\n ];\n\n if (typeName && wrapperTypes.includes(typeName)) {\n const def = getDef(current);\n const inner = (def?.innerType ?? def?.in ?? def?.type) as ZodTypeAny | undefined;\n if (!inner || inner === current) break;\n current = inner;\n iterations++;\n continue;\n }\n\n break;\n }\n\n return current;\n }\n\n /**\n * Get the primitive type hint from an unwrapped schema.\n */\n private getBaseType(schema: ZodTypeAny): TypeHint {\n const unwrapped = this.unwrapSchema(schema);\n const typeName = getTypeName(unwrapped);\n\n // Map both Zod v3 (ZodString) and v4 (string) type names\n switch (typeName) {\n // Primitive types\n case \"string\":\n case \"ZodString\":\n return \"string\";\n case \"number\":\n case \"ZodNumber\":\n case \"bigint\":\n case \"ZodBigInt\":\n return \"number\";\n case \"boolean\":\n case \"ZodBoolean\":\n return \"boolean\";\n\n // Literal types - check the literal value type\n case \"literal\":\n case \"ZodLiteral\": {\n // Zod v4 uses _def.values (array), Zod v3 uses _def.value\n const def = getDef(unwrapped);\n const values = def?.values as unknown[] | undefined;\n const value = values?.[0] ?? def?.value;\n if (typeof value === \"string\") return \"string\";\n if (typeof value === \"number\" || typeof value === \"bigint\") return \"number\";\n if (typeof value === \"boolean\") return \"boolean\";\n return \"unknown\";\n }\n\n // Enum - always string keys\n case \"enum\":\n case \"ZodEnum\":\n case \"nativeEnum\":\n case \"ZodNativeEnum\":\n return \"string\";\n\n // Union - return 'unknown' to let auto-coercion decide\n // Since multiple types are valid, we can't definitively say what the LLM intended\n // Auto-coercion will handle common cases (numbers, booleans) appropriately\n case \"union\":\n case \"ZodUnion\":\n return \"unknown\";\n\n // Discriminated union - complex, return unknown\n case \"discriminatedUnion\":\n case \"ZodDiscriminatedUnion\":\n return \"unknown\";\n\n // Intersection - check both sides\n case \"intersection\":\n case \"ZodIntersection\": {\n const def = getDef(unwrapped);\n const left = def?.left as ZodTypeAny | undefined;\n const right = def?.right as ZodTypeAny | undefined;\n if (!left || !right) return \"unknown\";\n\n const leftType = this.getBaseType(left);\n const rightType = this.getBaseType(right);\n\n // If both are the same type, return it\n if (leftType === rightType) return leftType;\n // If one is string, prefer string\n if (leftType === \"string\" || rightType === \"string\") return \"string\";\n // Otherwise return unknown (complex intersection)\n return \"unknown\";\n }\n\n // Effects/transforms - return unknown to let Zod handle it\n case \"effects\":\n case \"ZodEffects\":\n // ZodEffects wraps transforms, refinements, etc.\n // The transform expects input in original format, so don't coerce\n return \"unknown\";\n\n // Lazy - can't resolve without evaluating\n case \"lazy\":\n case \"ZodLazy\":\n return \"unknown\";\n\n // Complex types - return unknown\n case \"object\":\n case \"ZodObject\":\n case \"array\":\n case \"ZodArray\":\n case \"tuple\":\n case \"ZodTuple\":\n case \"record\":\n case \"ZodRecord\":\n case \"map\":\n case \"ZodMap\":\n case \"set\":\n case \"ZodSet\":\n case \"function\":\n case \"ZodFunction\":\n case \"promise\":\n case \"ZodPromise\":\n case \"date\":\n case \"ZodDate\":\n return \"unknown\";\n\n // Unknown/any/never/void/undefined/null\n case \"unknown\":\n case \"ZodUnknown\":\n case \"any\":\n case \"ZodAny\":\n case \"never\":\n case \"ZodNever\":\n case \"void\":\n case \"ZodVoid\":\n case \"undefined\":\n case \"ZodUndefined\":\n case \"null\":\n case \"ZodNull\":\n return \"unknown\";\n\n default:\n return \"unknown\";\n }\n }\n}\n","import type { ZodTypeAny } from \"zod\";\nimport { GADGET_ARG_PREFIX } from \"../core/constants.js\";\nimport { SchemaIntrospector, type TypeHint } from \"./schema-introspector.js\";\n\nexport interface BlockParseOptions {\n /** Prefix that declares an argument. Default: \"!!!ARG:\" */\n argPrefix?: string;\n /** Optional Zod schema for schema-aware type coercion */\n schema?: ZodTypeAny;\n}\n\n/**\n * Parse block format parameters into an object.\n *\n * Block format uses !!!ARG:pointer syntax where pointer is a JSON Pointer\n * path (without leading /) that defines where to place the value.\n *\n * Example input:\n * ```\n * !!!ARG:filename\n * calculator.ts\n * !!!ARG:config/timeout\n * 30\n * !!!ARG:items/0\n * first\n * ```\n *\n * Produces:\n * ```json\n * {\n * \"filename\": \"calculator.ts\",\n * \"config\": { \"timeout\": 30 },\n * \"items\": [\"first\"]\n * }\n * ```\n *\n * Single-line values are automatically coerced:\n * - \"true\" / \"false\" → boolean\n * - Numeric strings → number\n * - Multiline values always stay as strings (for code/content)\n *\n * @param content - Raw parameter content (after gadget name line, before end marker)\n * @param options - Parser options\n * @returns Parsed parameters object with coerced values\n * @throws Error if duplicate pointers or invalid array indices\n */\nexport function parseBlockParams(\n content: string,\n options?: BlockParseOptions,\n): Record<string, unknown> {\n const argPrefix = options?.argPrefix ?? GADGET_ARG_PREFIX;\n const result: Record<string, unknown> = {};\n const seenPointers = new Set<string>();\n\n // Create schema introspector if schema is provided\n const introspector = options?.schema ? new SchemaIntrospector(options.schema) : undefined;\n\n // Split content by arg prefix to get individual arg entries\n // First element will be empty or whitespace before first arg\n const parts = content.split(argPrefix);\n\n for (let i = 1; i < parts.length; i++) {\n const part = parts[i];\n\n // Find the pointer (first line) and value (rest)\n const newlineIndex = part.indexOf(\"\\n\");\n if (newlineIndex === -1) {\n // Arg with no value (just the pointer line)\n const pointer = part.trim();\n if (pointer) {\n if (seenPointers.has(pointer)) {\n throw new Error(`Duplicate pointer: ${pointer}`);\n }\n seenPointers.add(pointer);\n setByPointer(result, pointer, \"\", introspector);\n }\n continue;\n }\n\n const pointer = part.substring(0, newlineIndex).trim();\n let value = part.substring(newlineIndex + 1);\n\n // Strip single trailing newline if present (per spec)\n if (value.endsWith(\"\\n\")) {\n value = value.slice(0, -1);\n }\n\n if (!pointer) {\n continue; // Skip empty pointers\n }\n\n if (seenPointers.has(pointer)) {\n throw new Error(`Duplicate pointer: ${pointer}`);\n }\n seenPointers.add(pointer);\n\n setByPointer(result, pointer, value, introspector);\n }\n\n return result;\n}\n\n/**\n * Coerce a string value to its appropriate primitive type.\n *\n * When an `expectedType` hint is provided (from schema introspection), the coercion\n * respects the schema's expected type:\n * - 'string': Keep value as string, no coercion\n * - 'number': Coerce to number if valid\n * - 'boolean': Coerce to boolean if \"true\"/\"false\"\n * - 'unknown': Use auto-coercion logic (backwards compatible)\n *\n * Without a type hint (undefined), uses auto-coercion:\n * - \"true\" / \"false\" → boolean\n * - Numeric strings → number\n * - Everything else stays string\n *\n * Multiline values are never coerced (likely code/content).\n *\n * @param value - The string value to coerce\n * @param expectedType - Optional type hint from schema introspection\n * @returns Coerced value\n */\nfunction coerceValue(value: string, expectedType?: TypeHint): string | number | boolean {\n // Don't coerce multiline values - they're likely code/content\n if (value.includes(\"\\n\")) {\n return value;\n }\n\n const trimmed = value.trim();\n\n // If schema provides a type hint, respect it\n if (expectedType === \"string\") {\n // Keep as string - no coercion at all\n return value;\n }\n\n if (expectedType === \"boolean\") {\n // Only coerce recognized boolean strings\n if (trimmed === \"true\") return true;\n if (trimmed === \"false\") return false;\n // Invalid boolean - keep as string for Zod to report error\n return value;\n }\n\n if (expectedType === \"number\") {\n // Attempt to coerce to number\n const num = Number(trimmed);\n if (!isNaN(num) && isFinite(num) && trimmed !== \"\") {\n return num;\n }\n // Invalid number - keep as string for Zod to report error\n return value;\n }\n\n // expectedType === 'unknown' or undefined: use auto-coercion logic\n // This maintains backwards compatibility when no schema is provided\n // or when schema introspection can't determine the type\n\n // Boolean coercion\n if (trimmed === \"true\") return true;\n if (trimmed === \"false\") return false;\n\n // Number coercion - only for values that look clearly numeric\n // Avoid coercing things like \"123abc\" or empty strings\n if (trimmed !== \"\" && /^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\n const num = Number(trimmed);\n if (!isNaN(num) && isFinite(num)) {\n return num;\n }\n }\n\n return value;\n}\n\n/**\n * Set a value in an object using a JSON Pointer path (without leading /).\n *\n * Handles:\n * - Simple keys: \"name\" → { name: value }\n * - Nested paths: \"config/timeout\" → { config: { timeout: value } }\n * - Array indices: \"items/0\" → { items: [value] }\n *\n * Values are coerced based on the schema's expected type when an introspector\n * is provided. Without a schema, falls back to auto-coercion (backwards compatible).\n *\n * @param obj - Target object to modify\n * @param pointer - JSON Pointer path without leading /\n * @param value - Value to set (string that may be coerced)\n * @param introspector - Optional schema introspector for type-aware coercion\n * @throws Error if array index gaps detected\n */\nfunction setByPointer(\n obj: Record<string, unknown>,\n pointer: string,\n value: string,\n introspector?: SchemaIntrospector,\n): void {\n const segments = pointer.split(\"/\");\n let current: Record<string, unknown> | unknown[] = obj;\n\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i];\n const nextSegment = segments[i + 1];\n const nextIsArrayIndex = /^\\d+$/.test(nextSegment);\n\n if (Array.isArray(current)) {\n const index = parseInt(segment, 10);\n if (isNaN(index) || index < 0) {\n throw new Error(`Invalid array index: ${segment}`);\n }\n // Validate no gaps\n if (index > current.length) {\n throw new Error(`Array index gap: expected ${current.length}, got ${index}`);\n }\n if (current[index] === undefined) {\n current[index] = nextIsArrayIndex ? [] : {};\n }\n current = current[index] as Record<string, unknown> | unknown[];\n } else {\n // current is an object\n const rec = current as Record<string, unknown>;\n if (rec[segment] === undefined) {\n rec[segment] = nextIsArrayIndex ? [] : {};\n }\n current = rec[segment] as Record<string, unknown> | unknown[];\n }\n }\n\n // Set the final value\n const lastSegment = segments[segments.length - 1];\n\n // Get expected type from schema if available, then coerce accordingly\n const expectedType = introspector?.getTypeAtPath(pointer);\n const coercedValue = coerceValue(value, expectedType);\n\n if (Array.isArray(current)) {\n const index = parseInt(lastSegment, 10);\n if (isNaN(index) || index < 0) {\n throw new Error(`Invalid array index: ${lastSegment}`);\n }\n // Validate no gaps\n if (index > current.length) {\n throw new Error(`Array index gap: expected ${current.length}, got ${index}`);\n }\n current[index] = coercedValue;\n } else {\n (current as Record<string, unknown>)[lastSegment] = coercedValue;\n }\n}\n","/**\n * LLMist client wrapper that automatically reports LLM costs via callback.\n *\n * Used internally by ExecutionContext to provide ctx.llmist for gadgets.\n * All LLM calls made through this wrapper will have their costs automatically\n * tracked and reported via the provided callback.\n *\n * @module gadgets/cost-reporting-client\n */\n\nimport type { LLMist } from \"../core/client.js\";\nimport type {\n ImageGenerationOptions,\n ImageGenerationResult,\n SpeechGenerationOptions,\n SpeechGenerationResult,\n} from \"../core/media-types.js\";\nimport type { ModelRegistry } from \"../core/model-registry.js\";\nimport { resolveModel } from \"../core/model-shortcuts.js\";\nimport type { LLMGenerationOptions, LLMStream, LLMStreamChunk } from \"../core/options.js\";\nimport type { TextGenerationOptions } from \"../core/quick-methods.js\";\nimport type {\n CostReportingImageNamespace,\n CostReportingLLMist,\n CostReportingSpeechNamespace,\n} from \"./types.js\";\n\n/**\n * Callback type for reporting costs.\n */\nexport type CostReporter = (amount: number) => void;\n\n/**\n * LLMist client wrapper that automatically reports LLM costs.\n *\n * This wrapper intercepts all LLM calls, tracks token usage from responses,\n * calculates costs using ModelRegistry, and reports them via the callback.\n *\n * @example\n * ```typescript\n * let totalCost = 0;\n * const wrapper = new CostReportingLLMistWrapper(client, (cost) => {\n * totalCost += cost;\n * });\n *\n * // LLM cost automatically reported after completion\n * const result = await wrapper.complete(\"Hello\");\n * console.log(`Cost: $${totalCost}`);\n * ```\n */\nexport class CostReportingLLMistWrapper implements CostReportingLLMist {\n readonly image: CostReportingImageNamespace;\n readonly speech: CostReportingSpeechNamespace;\n\n constructor(\n private readonly client: LLMist,\n private readonly reportCost: CostReporter,\n ) {\n // Initialize image namespace with cost reporting\n this.image = {\n generate: async (options: ImageGenerationOptions): Promise<ImageGenerationResult> => {\n const result = await this.client.image.generate(options);\n // Report cost if available in the result\n if (result.cost !== undefined && result.cost > 0) {\n this.reportCost(result.cost);\n }\n return result;\n },\n };\n\n // Initialize speech namespace with cost reporting\n this.speech = {\n generate: async (options: SpeechGenerationOptions): Promise<SpeechGenerationResult> => {\n const result = await this.client.speech.generate(options);\n // Report cost if available in the result\n if (result.cost !== undefined && result.cost > 0) {\n this.reportCost(result.cost);\n }\n return result;\n },\n };\n }\n\n /**\n * Access to model registry for cost estimation.\n */\n get modelRegistry(): ModelRegistry {\n return this.client.modelRegistry;\n }\n\n /**\n * Quick completion with automatic cost reporting.\n *\n * Streams internally to track token usage, then reports the calculated cost.\n *\n * @param prompt - User prompt\n * @param options - Optional configuration (model, temperature, etc.)\n * @returns Complete text response\n */\n async complete(prompt: string, options?: TextGenerationOptions): Promise<string> {\n const model = resolveModel(options?.model ?? \"haiku\");\n let result = \"\";\n let inputTokens = 0;\n let outputTokens = 0;\n let cachedInputTokens = 0;\n let cacheCreationInputTokens = 0;\n\n const messages = [\n ...(options?.systemPrompt\n ? [{ role: \"system\" as const, content: options.systemPrompt }]\n : []),\n { role: \"user\" as const, content: prompt },\n ];\n\n for await (const chunk of this.client.stream({\n model,\n messages,\n temperature: options?.temperature,\n maxTokens: options?.maxTokens,\n })) {\n result += chunk.text ?? \"\";\n if (chunk.usage) {\n inputTokens = chunk.usage.inputTokens;\n outputTokens = chunk.usage.outputTokens;\n cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;\n cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;\n }\n }\n\n this.reportCostFromUsage(\n model,\n inputTokens,\n outputTokens,\n cachedInputTokens,\n cacheCreationInputTokens,\n );\n return result;\n }\n\n /**\n * Quick streaming with automatic cost reporting when stream completes.\n *\n * Yields text chunks as they arrive, then reports cost in finally block.\n *\n * @param prompt - User prompt\n * @param options - Optional configuration (model, temperature, etc.)\n * @returns Async generator yielding text chunks\n */\n async *streamText(prompt: string, options?: TextGenerationOptions): AsyncGenerator<string> {\n const model = resolveModel(options?.model ?? \"haiku\");\n let inputTokens = 0;\n let outputTokens = 0;\n let cachedInputTokens = 0;\n let cacheCreationInputTokens = 0;\n\n const messages = [\n ...(options?.systemPrompt\n ? [{ role: \"system\" as const, content: options.systemPrompt }]\n : []),\n { role: \"user\" as const, content: prompt },\n ];\n\n try {\n for await (const chunk of this.client.stream({\n model,\n messages,\n temperature: options?.temperature,\n maxTokens: options?.maxTokens,\n })) {\n if (chunk.text) {\n yield chunk.text;\n }\n if (chunk.usage) {\n inputTokens = chunk.usage.inputTokens;\n outputTokens = chunk.usage.outputTokens;\n cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;\n cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;\n }\n }\n } finally {\n // Report cost when stream ends (success or early exit)\n this.reportCostFromUsage(\n model,\n inputTokens,\n outputTokens,\n cachedInputTokens,\n cacheCreationInputTokens,\n );\n }\n }\n\n /**\n * Low-level stream access with automatic cost reporting.\n *\n * Returns a wrapped stream that reports costs when iteration completes.\n *\n * @param options - Full LLM generation options\n * @returns Wrapped LLM stream that auto-reports costs\n */\n stream(options: LLMGenerationOptions): LLMStream {\n return this.createCostReportingStream(options);\n }\n\n /**\n * Creates a wrapped stream that tracks usage and reports costs on completion.\n */\n private createCostReportingStream(options: LLMGenerationOptions): LLMStream {\n const innerStream = this.client.stream(options);\n const reportCostFromUsage = this.reportCostFromUsage.bind(this);\n const model = options.model;\n\n async function* costReportingWrapper(): AsyncGenerator<LLMStreamChunk> {\n let inputTokens = 0;\n let outputTokens = 0;\n let cachedInputTokens = 0;\n let cacheCreationInputTokens = 0;\n\n try {\n for await (const chunk of innerStream) {\n if (chunk.usage) {\n inputTokens = chunk.usage.inputTokens;\n outputTokens = chunk.usage.outputTokens;\n cachedInputTokens = chunk.usage.cachedInputTokens ?? 0;\n cacheCreationInputTokens = chunk.usage.cacheCreationInputTokens ?? 0;\n }\n yield chunk;\n }\n } finally {\n // Report cost when stream completes (success or early exit)\n if (inputTokens > 0 || outputTokens > 0) {\n reportCostFromUsage(\n model,\n inputTokens,\n outputTokens,\n cachedInputTokens,\n cacheCreationInputTokens,\n );\n }\n }\n }\n\n return costReportingWrapper();\n }\n\n /**\n * Calculates and reports cost from token usage.\n */\n private reportCostFromUsage(\n model: string,\n inputTokens: number,\n outputTokens: number,\n cachedInputTokens = 0,\n cacheCreationInputTokens = 0,\n ): void {\n if (inputTokens === 0 && outputTokens === 0) return;\n\n // Extract model name from provider:model format\n const modelName = model.includes(\":\") ? model.split(\":\")[1] : model;\n\n const estimate = this.client.modelRegistry.estimateCost(\n modelName,\n inputTokens,\n outputTokens,\n cachedInputTokens,\n cacheCreationInputTokens,\n );\n\n if (estimate && estimate.totalCost > 0) {\n this.reportCost(estimate.totalCost);\n }\n }\n}\n","import type { ZodError } from \"zod\";\nimport { GADGET_ARG_PREFIX, GADGET_END_PREFIX, GADGET_START_PREFIX } from \"../core/constants.js\";\nimport type { AbstractGadget } from \"./gadget.js\";\n\nexport interface ErrorFormatterOptions {\n /** Custom argument prefix for block format examples. Default: \"!!!ARG:\" */\n argPrefix?: string;\n /** Custom start prefix for block format examples. Default: \"!!!GADGET_START:\" */\n startPrefix?: string;\n /** Custom end prefix for block format examples. Default: \"!!!GADGET_END\" */\n endPrefix?: string;\n}\n\n/**\n * Formats gadget execution errors with helpful context for LLM self-correction.\n *\n * This class generates error messages that include:\n * - Clear error description\n * - Full gadget usage instructions (via getInstruction())\n * - Block format reference for parse errors\n *\n * The goal is to help LLMs self-correct on subsequent invocation attempts.\n */\nexport class GadgetExecutionErrorFormatter {\n private readonly argPrefix: string;\n private readonly startPrefix: string;\n private readonly endPrefix: string;\n\n constructor(options: ErrorFormatterOptions = {}) {\n this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;\n this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;\n this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;\n }\n\n /**\n * Format a Zod validation error with full gadget instructions.\n *\n * @param gadgetName - Name of the gadget that was called\n * @param zodError - The Zod validation error\n * @param gadget - The gadget instance (for generating instructions)\n * @returns Formatted error message with usage instructions\n */\n formatValidationError(gadgetName: string, zodError: ZodError, gadget: AbstractGadget): string {\n const parts: string[] = [];\n\n // Error header\n parts.push(`Error: Invalid parameters for '${gadgetName}':`);\n\n // Format each validation issue\n for (const issue of zodError.issues) {\n const path = issue.path.join(\".\") || \"root\";\n parts.push(` - ${path}: ${issue.message}`);\n }\n\n // Add gadget usage instructions\n parts.push(\"\");\n parts.push(\"Gadget Usage:\");\n parts.push(gadget.getInstruction(this.argPrefix));\n\n return parts.join(\"\\n\");\n }\n\n /**\n * Format a parse error with block format reference.\n *\n * @param gadgetName - Name of the gadget that was called\n * @param parseError - The parse error message\n * @param gadget - The gadget instance if found (for generating instructions)\n * @returns Formatted error message with format reference\n */\n formatParseError(gadgetName: string, parseError: string, gadget: AbstractGadget | undefined): string {\n const parts: string[] = [];\n\n // Error header\n parts.push(`Error: Failed to parse parameters for '${gadgetName}':`);\n parts.push(` ${parseError}`);\n\n // Add gadget usage instructions if gadget exists\n if (gadget) {\n parts.push(\"\");\n parts.push(\"Gadget Usage:\");\n parts.push(gadget.getInstruction(this.argPrefix));\n }\n\n // Always add block format reference\n parts.push(\"\");\n parts.push(\"Block Format Reference:\");\n parts.push(` ${this.startPrefix}${gadgetName}`);\n parts.push(` ${this.argPrefix}parameterName`);\n parts.push(\" parameter value here\");\n parts.push(` ${this.endPrefix}`);\n\n return parts.join(\"\\n\");\n }\n\n /**\n * Format a registry error (gadget not found) with available gadgets list.\n *\n * @param gadgetName - Name of the gadget that was not found\n * @param availableGadgets - List of available gadget names\n * @returns Formatted error message with available gadgets\n */\n formatRegistryError(gadgetName: string, availableGadgets: string[]): string {\n const parts: string[] = [];\n\n // Error header\n parts.push(`Error: Gadget '${gadgetName}' not found.`);\n\n // List available gadgets\n if (availableGadgets.length > 0) {\n parts.push(\"\");\n parts.push(`Available gadgets: ${availableGadgets.join(\", \")}`);\n } else {\n parts.push(\"\");\n parts.push(\"No gadgets are currently registered.\");\n }\n\n return parts.join(\"\\n\");\n }\n}\n\n/**\n * Create a pre-configured error formatter instance.\n *\n * @param options - Formatter options\n * @returns Configured GadgetExecutionErrorFormatter instance\n */\nexport function createErrorFormatter(\n options: ErrorFormatterOptions = {},\n): GadgetExecutionErrorFormatter {\n return new GadgetExecutionErrorFormatter(options);\n}\n","import { GADGET_ARG_PREFIX, GADGET_END_PREFIX, GADGET_START_PREFIX } from \"../core/constants.js\";\nimport { parseBlockParams } from \"./block-params.js\";\nimport type { StreamEvent } from \"./types.js\";\n\nexport type ParameterFormat = \"block\";\n\n/**\n * Strip markdown code fences from parameter content.\n * LLMs sometimes wrap their parameters in ```toml, ```yaml, ```json, or plain ``` blocks.\n * This function removes those fences to allow successful parsing.\n *\n * @internal Exported for testing only\n */\nexport function stripMarkdownFences(content: string): string {\n let cleaned = content.trim();\n\n // Pattern: ```toml, ```yaml, ```json, or just ``` at start (case-insensitive)\n const openingFence = /^```(?:toml|yaml|json)?\\s*\\n/i;\n // Pattern: ``` at end (with optional preceding newline)\n const closingFence = /\\n?```\\s*$/;\n\n // Strip opening fence if present\n cleaned = cleaned.replace(openingFence, \"\");\n // Strip closing fence if present\n cleaned = cleaned.replace(closingFence, \"\");\n\n return cleaned.trim();\n}\n\nexport interface StreamParserOptions {\n startPrefix?: string;\n endPrefix?: string;\n /** Prefix for block format arguments. Default: \"!!!ARG:\" */\n argPrefix?: string;\n}\n\n// Global counter for generating unique invocation IDs across all parser instances\nlet globalInvocationCounter = 0;\n\n/**\n * Reset the global invocation counter. Only use this in tests!\n * @internal\n */\nexport function resetGlobalInvocationCounter(): void {\n globalInvocationCounter = 0;\n}\n\n/**\n * Parser for extracting gadget invocations from LLM text output.\n * Processes text chunks incrementally and emits events for text and gadget calls.\n */\nexport class GadgetCallParser {\n private buffer = \"\";\n private lastEmittedTextOffset = 0;\n private readonly startPrefix: string;\n private readonly endPrefix: string;\n private readonly argPrefix: string;\n\n constructor(options: StreamParserOptions = {}) {\n this.startPrefix = options.startPrefix ?? GADGET_START_PREFIX;\n this.endPrefix = options.endPrefix ?? GADGET_END_PREFIX;\n this.argPrefix = options.argPrefix ?? GADGET_ARG_PREFIX;\n }\n\n /**\n * Extract and consume text up to the given index.\n * Returns undefined if no meaningful text to emit.\n */\n private extractTextSegment(index: number): string | undefined {\n if (index <= this.lastEmittedTextOffset) {\n return undefined;\n }\n\n const segment = this.buffer.slice(this.lastEmittedTextOffset, index);\n this.lastEmittedTextOffset = index;\n\n return segment.trim().length > 0 ? segment : undefined;\n }\n\n /**\n * Parse gadget invocation metadata from the header line.\n *\n * Supported formats:\n * - `GadgetName` - Auto-generate ID, no dependencies\n * - `GadgetName:my_id` - Explicit ID, no dependencies\n * - `GadgetName:my_id:dep1,dep2` - Explicit ID with dependencies\n *\n * Dependencies must be comma-separated invocation IDs.\n */\n private parseInvocationMetadata(headerLine: string): {\n gadgetName: string;\n invocationId: string;\n dependencies: string[];\n } {\n const parts = headerLine.split(\":\");\n\n if (parts.length === 1) {\n // Just name: GadgetName\n return {\n gadgetName: parts[0],\n invocationId: `gadget_${++globalInvocationCounter}`,\n dependencies: [],\n };\n } else if (parts.length === 2) {\n // Name + ID: GadgetName:calc_1\n return {\n gadgetName: parts[0],\n invocationId: parts[1].trim(),\n dependencies: [],\n };\n } else {\n // Name + ID + deps: GadgetName:calc_1:dep1,dep2\n const deps = parts[2]\n .split(\",\")\n .map((d) => d.trim())\n .filter((d) => d.length > 0);\n return {\n gadgetName: parts[0],\n invocationId: parts[1].trim(),\n dependencies: deps,\n };\n }\n }\n\n /**\n * Extract the error message from a parse error.\n * Preserves full message since the error formatter adds contextual help\n * that benefits from precise, detailed error information.\n */\n private extractParseError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n }\n\n /**\n * Parse parameter string using block format\n */\n private parseParameters(raw: string): {\n parameters?: Record<string, unknown>;\n parseError?: string;\n } {\n // Strip markdown code fences if LLM wrapped the parameters\n const cleaned = stripMarkdownFences(raw);\n\n try {\n return { parameters: parseBlockParams(cleaned, { argPrefix: this.argPrefix }) };\n } catch (error) {\n return { parseError: this.extractParseError(error) };\n }\n }\n\n // Feed a chunk of text and get parsed events\n *feed(chunk: string): Generator<StreamEvent> {\n this.buffer += chunk;\n\n let startIndex = 0;\n while (true) {\n // Find next gadget start marker\n const partStartIndex = this.buffer.indexOf(this.startPrefix, startIndex);\n if (partStartIndex === -1) break;\n\n // Yield any text before the gadget\n const textBefore = this.extractTextSegment(partStartIndex);\n if (textBefore !== undefined) {\n yield { type: \"text\", content: textBefore };\n }\n\n // Extract gadget metadata from header line\n const metadataStartIndex = partStartIndex + this.startPrefix.length;\n const metadataEndIndex = this.buffer.indexOf(\"\\n\", metadataStartIndex);\n if (metadataEndIndex === -1) break; // Wait for more data\n\n const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();\n const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);\n\n const contentStartIndex = metadataEndIndex + 1;\n\n let partEndIndex: number;\n let endMarkerLength = 0;\n\n // Look for end marker OR next start marker (implicit end)\n // If a next gadget starts BEFORE an end marker, use that as implicit terminator\n\n // Look for next gadget start (potential implicit end)\n const nextStartPos = this.buffer.indexOf(this.startPrefix, contentStartIndex);\n\n // Look for end marker\n const endPos = this.buffer.indexOf(this.endPrefix, contentStartIndex);\n\n // Decide which terminator to use:\n // - If next start comes before end marker, use next start (implicit end)\n // - Otherwise use the end marker if found\n if (nextStartPos !== -1 && (endPos === -1 || nextStartPos < endPos)) {\n // Found next gadget start before any end marker - implicit end\n partEndIndex = nextStartPos;\n endMarkerLength = 0; // Don't consume the next start marker\n } else if (endPos !== -1) {\n // Found proper end marker\n partEndIndex = endPos;\n endMarkerLength = this.endPrefix.length;\n } else {\n // Neither end marker nor next start found - wait for more data\n break;\n }\n\n // Extract parameters\n const parametersRaw = this.buffer.substring(contentStartIndex, partEndIndex).trim();\n\n // Parse parameters according to configured format\n const { parameters, parseError } = this.parseParameters(parametersRaw);\n\n yield {\n type: \"gadget_call\",\n call: {\n gadgetName,\n invocationId,\n parametersRaw,\n parameters,\n parseError,\n dependencies,\n },\n };\n\n // Move past this gadget\n startIndex = partEndIndex + endMarkerLength;\n\n this.lastEmittedTextOffset = startIndex;\n }\n\n // Keep unprocessed data in buffer\n if (startIndex > 0) {\n this.buffer = this.buffer.substring(startIndex);\n this.lastEmittedTextOffset = 0;\n }\n }\n\n // Finalize parsing and return remaining text or incomplete gadgets\n *finalize(): Generator<StreamEvent> {\n // Check if there's an incomplete gadget in the buffer\n const startIndex = this.buffer.indexOf(this.startPrefix, this.lastEmittedTextOffset);\n\n if (startIndex !== -1) {\n // There's an incomplete gadget - try to parse it\n const textBefore = this.extractTextSegment(startIndex);\n if (textBefore !== undefined) {\n yield { type: \"text\", content: textBefore };\n }\n\n // Extract gadget metadata from header line\n const metadataStartIndex = startIndex + this.startPrefix.length;\n const metadataEndIndex = this.buffer.indexOf(\"\\n\", metadataStartIndex);\n\n if (metadataEndIndex !== -1) {\n const headerLine = this.buffer.substring(metadataStartIndex, metadataEndIndex).trim();\n const { gadgetName, invocationId, dependencies } = this.parseInvocationMetadata(headerLine);\n const contentStartIndex = metadataEndIndex + 1;\n\n // Extract parameters (everything after the newline to end of buffer)\n const parametersRaw = this.buffer.substring(contentStartIndex).trim();\n\n const { parameters, parseError } = this.parseParameters(parametersRaw);\n\n yield {\n type: \"gadget_call\",\n call: {\n gadgetName,\n invocationId,\n parametersRaw: parametersRaw,\n parameters,\n parseError,\n dependencies,\n },\n };\n\n return;\n }\n }\n\n // No incomplete gadget - just emit remaining text\n const remainingText = this.extractTextSegment(this.buffer.length);\n if (remainingText !== undefined) {\n yield { type: \"text\", content: remainingText };\n }\n }\n\n // Reset parser state (note: global invocation counter is NOT reset to ensure unique IDs)\n reset(): void {\n this.buffer = \"\";\n this.lastEmittedTextOffset = 0;\n }\n}\n\n","/**\n * Type-safe gadget factory with automatic parameter inference.\n *\n * Gadget eliminates the need for manual type assertions\n * by automatically inferring parameter types from the Zod schema.\n *\n * @example\n * ```typescript\n * class Calculator extends Gadget({\n * description: \"Performs arithmetic operations\",\n * schema: z.object({\n * operation: z.enum([\"add\", \"subtract\"]),\n * a: z.number(),\n * b: z.number(),\n * }),\n * }) {\n * // ✨ params is automatically typed!\n * execute(params: this['params']): string {\n * const { operation, a, b } = params; // All typed!\n * return operation === \"add\" ? String(a + b) : String(a - b);\n * }\n * }\n * ```\n */\n\nimport type { ZodType } from \"zod\";\nimport { AbstractGadget } from \"./gadget.js\";\nimport type { ExecutionContext, GadgetExample, GadgetExecuteReturn } from \"./types.js\";\n\n/**\n * Infer the TypeScript type from a Zod schema.\n */\ntype InferSchema<T> = T extends ZodType<infer U> ? U : never;\n\n/**\n * Configuration for creating a typed gadget.\n */\nexport interface GadgetConfig<TSchema extends ZodType> {\n /** Human-readable description of what the gadget does */\n description: string;\n\n /** Zod schema for parameter validation */\n schema: TSchema;\n\n /** Optional custom name (defaults to class name) */\n name?: string;\n\n /** Optional timeout in milliseconds */\n timeoutMs?: number;\n\n /** Optional usage examples to help LLMs understand proper invocation */\n examples?: GadgetExample<InferSchema<TSchema>>[];\n}\n\n/**\n * Factory function to create a typed gadget base class.\n *\n * The returned class automatically infers parameter types from the Zod schema,\n * eliminating the need for manual type assertions in the execute method.\n *\n * @param config - Configuration with description and schema\n * @returns Base class to extend with typed execute method\n *\n * @example\n * ```typescript\n * import { z } from 'zod';\n * import { Gadget } from 'llmist';\n *\n * class Calculator extends Gadget({\n * description: \"Performs arithmetic operations\",\n * schema: z.object({\n * operation: z.enum([\"add\", \"subtract\", \"multiply\", \"divide\"]),\n * a: z.number().describe(\"First number\"),\n * b: z.number().describe(\"Second number\"),\n * }),\n * }) {\n * execute(params: this['params']): string {\n * // params is automatically typed as:\n * // { operation: \"add\" | \"subtract\" | \"multiply\" | \"divide\"; a: number; b: number }\n * const { operation, a, b } = params;\n *\n * switch (operation) {\n * case \"add\": return String(a + b);\n * case \"subtract\": return String(a - b);\n * case \"multiply\": return String(a * b);\n * case \"divide\": return String(a / b);\n * }\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // With async execution\n * class WeatherGadget extends Gadget({\n * description: \"Fetches weather for a city\",\n * schema: z.object({\n * city: z.string().min(1).describe(\"City name\"),\n * }),\n * timeoutMs: 10000,\n * }) {\n * async execute(params: this['params']): Promise<string> {\n * const { city } = params; // Automatically typed as { city: string }\n * const weather = await fetchWeather(city);\n * return `Weather in ${city}: ${weather}`;\n * }\n * }\n * ```\n */\nexport function Gadget<TSchema extends ZodType>(config: GadgetConfig<TSchema>) {\n abstract class GadgetBase extends AbstractGadget {\n description = config.description;\n parameterSchema = config.schema;\n name = config.name;\n timeoutMs = config.timeoutMs;\n examples = config.examples;\n\n /**\n * Type helper property for accessing inferred parameter type.\n * This is used in the execute method signature: `execute(params: this['params'])`\n *\n * Note: This is just for type inference - the actual params in execute()\n * will be Record<string, unknown> which you can safely cast to this['params']\n */\n readonly params!: InferSchema<TSchema>;\n\n /**\n * Execute the gadget. Subclasses should cast params to this['params'].\n *\n * @param params - Validated parameters from the LLM\n * @param ctx - Optional execution context for cost reporting and LLM access\n * @returns Result as a string, or an object with result and optional cost\n *\n * @example\n * ```typescript\n * // Simple string return (free gadget)\n * execute(params: this['params']) {\n * return String(params.a + params.b);\n * }\n *\n * // Using context for callback-based cost reporting\n * execute(params: this['params'], ctx) {\n * ctx.reportCost(0.001);\n * return \"result\";\n * }\n *\n * // Using wrapped LLMist for automatic cost tracking\n * async execute(params: this['params'], ctx) {\n * return ctx.llmist.complete('Summarize: ' + params.text);\n * }\n * ```\n */\n abstract execute(\n params: Record<string, unknown>,\n ctx?: ExecutionContext,\n ): GadgetExecuteReturn | Promise<GadgetExecuteReturn>;\n }\n\n return GadgetBase as {\n new (): GadgetBase & { params: InferSchema<TSchema> };\n };\n}\n","import type { ILogObj, Logger } from \"tslog\";\nimport { z } from \"zod\";\nimport { AgentBuilder } from \"../agent/builder.js\";\nimport { LLMist } from \"../core/client.js\";\nimport { GADGET_ARG_PREFIX } from \"../core/constants.js\";\nimport { ExecutionTree, type NodeId } from \"../core/execution-tree.js\";\nimport { createLogger } from \"../logging/logger.js\";\nimport { parseBlockParams } from \"./block-params.js\";\nimport { CostReportingLLMistWrapper } from \"./cost-reporting-client.js\";\nimport { createGadget } from \"./create-gadget.js\";\nimport { type ErrorFormatterOptions, GadgetExecutionErrorFormatter } from \"./error-formatter.js\";\nimport {\n AbortException,\n HumanInputRequiredException,\n TaskCompletionSignal,\n TimeoutException,\n} from \"./exceptions.js\";\nimport type { MediaStore } from \"./media-store.js\";\nimport { stripMarkdownFences } from \"./parser.js\";\nimport type { GadgetRegistry } from \"./registry.js\";\nimport { Gadget } from \"./typed-gadget.js\";\nimport type {\n AgentContextConfig,\n ExecutionContext,\n GadgetExecuteResult,\n GadgetExecuteResultWithMedia,\n GadgetExecutionResult,\n GadgetMediaOutput,\n HostExports,\n ParsedGadgetCall,\n SubagentConfigMap,\n SubagentEvent,\n} from \"./types.js\";\n\n/**\n * Lazily create host exports to avoid circular dependency issues.\n * Cached after first call.\n */\nlet cachedHostExports: HostExports | undefined;\nfunction getHostExportsInternal(): HostExports {\n if (!cachedHostExports) {\n cachedHostExports = {\n AgentBuilder,\n Gadget,\n createGadget,\n ExecutionTree,\n LLMist,\n z,\n };\n }\n return cachedHostExports;\n}\n\nexport class GadgetExecutor {\n private readonly logger: Logger<ILogObj>;\n private readonly errorFormatter: GadgetExecutionErrorFormatter;\n private readonly argPrefix: string;\n\n constructor(\n private readonly registry: GadgetRegistry,\n private readonly requestHumanInput?: (question: string) => Promise<string>,\n logger?: Logger<ILogObj>,\n private readonly defaultGadgetTimeoutMs?: number,\n errorFormatterOptions?: ErrorFormatterOptions,\n private readonly client?: LLMist,\n private readonly mediaStore?: MediaStore,\n private readonly agentConfig?: AgentContextConfig,\n private readonly subagentConfig?: SubagentConfigMap,\n private readonly onSubagentEvent?: (event: SubagentEvent) => void,\n // Execution Tree context for gadget execution\n private readonly tree?: ExecutionTree,\n private readonly parentNodeId?: NodeId | null,\n private readonly baseDepth?: number,\n ) {\n this.logger = logger ?? createLogger({ name: \"llmist:executor\" });\n this.errorFormatter = new GadgetExecutionErrorFormatter(errorFormatterOptions);\n this.argPrefix = errorFormatterOptions?.argPrefix ?? GADGET_ARG_PREFIX;\n }\n\n /**\n * Creates a promise that rejects with a TimeoutException after the specified timeout.\n * Aborts the provided AbortController before rejecting, allowing gadgets to clean up.\n * Returns both the promise and a cancel function to clear the timeout when no longer needed.\n */\n private createTimeoutPromise(\n gadgetName: string,\n timeoutMs: number,\n abortController: AbortController,\n ): { promise: Promise<never>; cancel: () => void } {\n let timeoutId: ReturnType<typeof setTimeout>;\n\n const promise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n const timeoutError = new TimeoutException(gadgetName, timeoutMs);\n // Signal abort FIRST so gadgets can clean up before exception is thrown\n // Pass the timeout message as reason for better debugging context\n abortController.abort(timeoutError.message);\n reject(timeoutError);\n }, timeoutMs);\n });\n\n return {\n promise,\n cancel: () => clearTimeout(timeoutId),\n };\n }\n\n /**\n * Unify gadget execute result to consistent internal format.\n * Handles string returns (backwards compat), object returns with cost,\n * and object returns with media.\n */\n private unifyExecuteResult(\n raw: string | GadgetExecuteResult | GadgetExecuteResultWithMedia,\n ): { result: string; media?: GadgetMediaOutput[]; cost: number } {\n if (typeof raw === \"string\") {\n return { result: raw, cost: 0 };\n }\n // Check if it has media property (GadgetExecuteResultWithMedia)\n if (\"media\" in raw && raw.media) {\n return { result: raw.result, media: raw.media, cost: raw.cost ?? 0 };\n }\n return { result: raw.result, cost: raw.cost ?? 0 };\n }\n\n // Execute a gadget call asynchronously\n async execute(call: ParsedGadgetCall): Promise<GadgetExecutionResult> {\n const startTime = Date.now();\n\n this.logger.debug(\"Executing gadget\", {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: call.parameters,\n });\n\n const rawParameters: Record<string, unknown> = call.parameters ?? {};\n let validatedParameters: Record<string, unknown> = rawParameters;\n\n try {\n // Check if gadget exists\n const gadget = this.registry.get(call.gadgetName);\n if (!gadget) {\n this.logger.error(\"Gadget not found\", { gadgetName: call.gadgetName });\n const availableGadgets = this.registry.getNames();\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: call.parameters ?? {},\n error: this.errorFormatter.formatRegistryError(call.gadgetName, availableGadgets),\n executionTimeMs: Date.now() - startTime,\n };\n }\n\n // Check for parse errors\n if (call.parseError || !call.parameters) {\n this.logger.error(\"Gadget parameter parse error\", {\n gadgetName: call.gadgetName,\n parseError: call.parseError,\n rawParameters: call.parametersRaw,\n });\n const parseErrorMessage = call.parseError ?? \"Failed to parse parameters\";\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: {},\n error: this.errorFormatter.formatParseError(call.gadgetName, parseErrorMessage, gadget),\n executionTimeMs: Date.now() - startTime,\n };\n }\n\n // Re-parse parameters with schema for type-aware coercion (Approach B)\n // This allows the parser to use the schema to determine correct types\n // (e.g., keeping \"1\" as string when schema expects z.string())\n // Only re-parse if:\n // 1. The raw content is in block format (contains configured arg prefix)\n // 2. Parameters weren't modified by an interceptor (compare with initial parse)\n let schemaAwareParameters: Record<string, unknown> = rawParameters;\n const hasBlockFormat = call.parametersRaw?.includes(this.argPrefix);\n if (gadget.parameterSchema && hasBlockFormat) {\n try {\n const cleanedRaw = stripMarkdownFences(call.parametersRaw);\n\n // First, parse without schema to get what initial parse would produce\n const initialParse = parseBlockParams(cleanedRaw, { argPrefix: this.argPrefix });\n\n // Check if parameters were modified by an interceptor\n // by comparing current parameters with what initial parse produces\n const parametersWereModified = !this.deepEquals(rawParameters, initialParse);\n\n if (parametersWereModified) {\n // Parameters were modified by an interceptor - keep the modifications\n this.logger.debug(\"Parameters modified by interceptor, skipping re-parse\", {\n gadgetName: call.gadgetName,\n });\n schemaAwareParameters = rawParameters;\n } else {\n // Re-parse with schema for type-aware coercion\n schemaAwareParameters = parseBlockParams(cleanedRaw, {\n argPrefix: this.argPrefix,\n schema: gadget.parameterSchema,\n });\n this.logger.debug(\"Re-parsed parameters with schema\", {\n gadgetName: call.gadgetName,\n original: rawParameters,\n schemaAware: schemaAwareParameters,\n });\n }\n } catch (error) {\n // If re-parsing fails, fall back to original parameters\n // This shouldn't happen if initial parse succeeded, but be safe\n this.logger.warn(\"Schema-aware re-parsing failed, using original parameters\", {\n gadgetName: call.gadgetName,\n error: error instanceof Error ? error.message : String(error),\n });\n schemaAwareParameters = rawParameters;\n }\n }\n\n if (gadget.parameterSchema) {\n const validationResult = gadget.parameterSchema.safeParse(schemaAwareParameters);\n if (!validationResult.success) {\n const validationError = this.errorFormatter.formatValidationError(\n call.gadgetName,\n validationResult.error,\n gadget,\n );\n this.logger.error(\"Gadget parameter validation failed\", {\n gadgetName: call.gadgetName,\n issueCount: validationResult.error.issues.length,\n });\n\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: schemaAwareParameters,\n error: validationError,\n executionTimeMs: Date.now() - startTime,\n };\n }\n\n validatedParameters = validationResult.data as Record<string, unknown>;\n } else {\n // No schema - use the schema-aware parameters (which are same as raw if no schema)\n validatedParameters = schemaAwareParameters;\n }\n\n // Determine the timeout for this gadget\n // Priority: gadget's own timeoutMs > defaultGadgetTimeoutMs > no timeout\n const timeoutMs = gadget.timeoutMs ?? this.defaultGadgetTimeoutMs;\n\n // Create AbortController for cancellation support\n // Signal is always provided to gadgets, even without timeout\n const abortController = new AbortController();\n\n // Create execution context with cost accumulator and abort signal\n let callbackCost = 0;\n const reportCost = (amount: number) => {\n if (amount > 0) {\n callbackCost += amount;\n this.logger.debug(\"Gadget reported cost via callback\", {\n gadgetName: call.gadgetName,\n amount,\n totalCallbackCost: callbackCost,\n });\n }\n };\n\n // Build execution context with abort signal, agent config, and tree access\n // Look up the gadget's own node ID from the tree (not the parent LLM call's ID)\n const gadgetNodeId = this.tree?.getNodeByInvocationId(call.invocationId)?.id;\n const gadgetDepth = gadgetNodeId\n ? this.tree?.getNode(gadgetNodeId)?.depth ?? this.baseDepth\n : this.baseDepth;\n\n const ctx: ExecutionContext = {\n reportCost,\n llmist: this.client ? new CostReportingLLMistWrapper(this.client, reportCost) : undefined,\n signal: abortController.signal,\n agentConfig: this.agentConfig,\n subagentConfig: this.subagentConfig,\n invocationId: call.invocationId,\n onSubagentEvent: this.onSubagentEvent,\n // Tree context for subagent support - use gadget's own node ID\n tree: this.tree,\n nodeId: gadgetNodeId,\n depth: gadgetDepth,\n // Host exports for external gadgets to use host's llmist classes\n hostExports: getHostExportsInternal(),\n };\n\n // Execute gadget (handle both sync and async)\n let rawResult: string | GadgetExecuteResult;\n if (timeoutMs && timeoutMs > 0) {\n // Execute with timeout - abort signal will be triggered before timeout rejection\n this.logger.debug(\"Executing gadget with timeout\", {\n gadgetName: call.gadgetName,\n timeoutMs,\n });\n const timeout = this.createTimeoutPromise(call.gadgetName, timeoutMs, abortController);\n try {\n rawResult = await Promise.race([\n Promise.resolve(gadget.execute(validatedParameters, ctx)),\n timeout.promise,\n ]);\n } finally {\n // Always cancel the timeout to prevent it from keeping the event loop alive\n timeout.cancel();\n }\n } else {\n // Execute without timeout\n rawResult = await Promise.resolve(gadget.execute(validatedParameters, ctx));\n }\n\n // Normalize result: handle string returns (legacy), object returns with cost, and media\n const { result, media, cost: returnCost } = this.unifyExecuteResult(rawResult);\n\n // Sum callback costs + return costs\n const totalCost = callbackCost + returnCost;\n\n // Store media in MediaStore if present\n let mediaIds: string[] | undefined;\n let storedMedia: import(\"./types.js\").StoredMedia[] | undefined;\n if (media && media.length > 0 && this.mediaStore) {\n storedMedia = await Promise.all(\n media.map((item) => this.mediaStore!.store(item, call.gadgetName)),\n );\n mediaIds = storedMedia.map((m) => m.id);\n this.logger.debug(\"Stored media outputs\", {\n gadgetName: call.gadgetName,\n mediaIds,\n count: media.length,\n });\n }\n\n const executionTimeMs = Date.now() - startTime;\n this.logger.info(\"Gadget executed successfully\", {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n executionTimeMs,\n cost: totalCost > 0 ? totalCost : undefined,\n callbackCost: callbackCost > 0 ? callbackCost : undefined,\n returnCost: returnCost > 0 ? returnCost : undefined,\n mediaCount: media?.length,\n });\n\n this.logger.debug(\"Gadget result\", {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: validatedParameters,\n result,\n cost: totalCost,\n executionTimeMs,\n mediaIds,\n });\n\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: validatedParameters,\n result,\n executionTimeMs,\n cost: totalCost,\n media,\n mediaIds,\n storedMedia,\n };\n } catch (error) {\n // Check if this is a TaskCompletionSignal\n if (error instanceof TaskCompletionSignal) {\n this.logger.info(\"Gadget requested loop termination\", {\n gadgetName: call.gadgetName,\n message: error.message,\n });\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: validatedParameters,\n result: error.message,\n breaksLoop: true,\n executionTimeMs: Date.now() - startTime,\n };\n }\n\n // Check if this is a TimeoutException\n if (error instanceof TimeoutException) {\n this.logger.error(\"Gadget execution timed out\", {\n gadgetName: call.gadgetName,\n timeoutMs: error.timeoutMs,\n executionTimeMs: Date.now() - startTime,\n });\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: validatedParameters,\n error: error.message,\n executionTimeMs: Date.now() - startTime,\n };\n }\n\n // Check if this is an AbortException (thrown by gadgets when they detect abort signal)\n if (error instanceof AbortException) {\n this.logger.info(\"Gadget execution was aborted\", {\n gadgetName: call.gadgetName,\n executionTimeMs: Date.now() - startTime,\n });\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: validatedParameters,\n error: error.message,\n executionTimeMs: Date.now() - startTime,\n };\n }\n\n // Check if this is a HumanInputRequiredException\n if (error instanceof HumanInputRequiredException) {\n this.logger.info(\"Gadget requested human input\", {\n gadgetName: call.gadgetName,\n question: error.question,\n });\n\n // If callback is provided, call it and wait for answer\n if (this.requestHumanInput) {\n try {\n const answer = await this.requestHumanInput(error.question);\n this.logger.debug(\"Human input received\", {\n gadgetName: call.gadgetName,\n answerLength: answer.length,\n });\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: validatedParameters,\n result: answer,\n executionTimeMs: Date.now() - startTime,\n };\n } catch (inputError) {\n this.logger.error(\"Human input callback error\", {\n gadgetName: call.gadgetName,\n error: inputError instanceof Error ? inputError.message : String(inputError),\n });\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: validatedParameters,\n error: inputError instanceof Error ? inputError.message : String(inputError),\n executionTimeMs: Date.now() - startTime,\n };\n }\n }\n\n // No callback - return error since we can't get human input\n this.logger.warn(\"Human input required but no callback provided\", {\n gadgetName: call.gadgetName,\n });\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: validatedParameters,\n error: \"Human input required but not available (stdin is not interactive)\",\n executionTimeMs: Date.now() - startTime,\n };\n }\n\n const executionTimeMs = Date.now() - startTime;\n this.logger.error(\"Gadget execution failed\", {\n gadgetName: call.gadgetName,\n error: error instanceof Error ? error.message : String(error),\n executionTimeMs,\n });\n\n return {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: validatedParameters,\n error: error instanceof Error ? error.message : String(error),\n executionTimeMs,\n };\n }\n }\n\n // Execute multiple gadget calls in parallel\n async executeAll(calls: ParsedGadgetCall[]): Promise<GadgetExecutionResult[]> {\n return Promise.all(calls.map((call) => this.execute(call)));\n }\n\n /**\n * Deep equality check for objects/arrays.\n * Used to detect if parameters were modified by an interceptor.\n */\n private deepEquals(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n\n if (typeof a !== \"object\") return a === b;\n\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((val, i) => this.deepEquals(val, b[i]));\n }\n\n const aObj = a as Record<string, unknown>;\n const bObj = b as Record<string, unknown>;\n\n const aKeys = Object.keys(aObj);\n const bKeys = Object.keys(bObj);\n\n if (aKeys.length !== bKeys.length) return false;\n\n return aKeys.every((key) => this.deepEquals(aObj[key], bObj[key]));\n }\n}\n","/**\n * StreamProcessor: The heart of the new hooks architecture.\n *\n * Replaces the complex wiring between Agent, ResponseProcessor, and GadgetRuntime.\n * Owns ALL stream processing and hook coordination with a clean, predictable flow.\n */\n\nimport type { ILogObj, Logger } from \"tslog\";\nimport type { LLMist } from \"../core/client.js\";\nimport type { ExecutionTree, NodeId } from \"../core/execution-tree.js\";\nimport type { LLMStreamChunk, TokenUsage } from \"../core/options.js\";\nimport { GadgetExecutor } from \"../gadgets/executor.js\";\nimport type { MediaStore } from \"../gadgets/media-store.js\";\nimport { GadgetCallParser } from \"../gadgets/parser.js\";\nimport type { GadgetRegistry } from \"../gadgets/registry.js\";\nimport type {\n AgentContextConfig,\n GadgetExecutionResult,\n GadgetSkippedEvent,\n ParsedGadgetCall,\n StreamCompletionEvent,\n StreamEvent,\n SubagentConfigMap,\n SubagentEvent,\n} from \"../gadgets/types.js\";\nimport { createLogger } from \"../logging/logger.js\";\nimport {\n validateAfterGadgetExecutionAction,\n validateBeforeGadgetExecutionAction,\n} from \"./hook-validators.js\";\nimport type {\n AfterGadgetExecutionAction,\n AfterGadgetExecutionControllerContext,\n AgentHooks,\n BeforeGadgetExecutionAction,\n ChunkInterceptorContext,\n DependencySkipAction,\n DependencySkipControllerContext,\n GadgetExecutionControllerContext,\n GadgetParameterInterceptorContext,\n GadgetResultInterceptorContext,\n MessageInterceptorContext,\n ObserveChunkContext,\n ObserveGadgetCompleteContext,\n ObserveGadgetSkippedContext,\n ObserveGadgetStartContext,\n} from \"./hooks.js\";\n\n/**\n * Configuration for the StreamProcessor.\n */\nexport interface StreamProcessorOptions {\n /** Current iteration number */\n iteration: number;\n\n /** Gadget registry for execution */\n registry: GadgetRegistry;\n\n /** Custom gadget start prefix */\n gadgetStartPrefix?: string;\n\n /** Custom gadget end prefix */\n gadgetEndPrefix?: string;\n\n /** Custom argument prefix for block format */\n gadgetArgPrefix?: string;\n\n /** Hooks for lifecycle events */\n hooks?: AgentHooks;\n\n /** Logger instance */\n logger?: Logger<ILogObj>;\n\n /** Callback for requesting human input during execution */\n requestHumanInput?: (question: string) => Promise<string>;\n\n /** Default gadget timeout */\n defaultGadgetTimeoutMs?: number;\n\n /** LLMist client for ExecutionContext.llmist */\n client?: LLMist;\n\n /** MediaStore for storing gadget media outputs */\n mediaStore?: MediaStore;\n\n /** Parent agent configuration for subagents to inherit */\n agentConfig?: AgentContextConfig;\n\n /** Subagent-specific configuration overrides */\n subagentConfig?: SubagentConfigMap;\n\n /** Callback for subagent gadgets to report subagent events to parent */\n onSubagentEvent?: (event: SubagentEvent) => void;\n\n // ==========================================================================\n // Execution Tree Context (for tree-based tracking)\n // ==========================================================================\n\n /** Execution tree for tracking LLM calls and gadget executions */\n tree?: ExecutionTree;\n\n /** Parent node ID (for gadget nodes created by this processor) */\n parentNodeId?: NodeId | null;\n\n /** Base depth for nodes created by this processor */\n baseDepth?: number;\n}\n\n/**\n * Result of stream processing.\n */\nexport interface StreamProcessingResult {\n /** All emitted events */\n outputs: StreamEvent[];\n\n /** Whether the loop should break */\n shouldBreakLoop: boolean;\n\n /** Whether any gadgets were executed */\n didExecuteGadgets: boolean;\n\n /** LLM finish reason */\n finishReason: string | null;\n\n /** Token usage (including cached token counts when available) */\n usage?: TokenUsage;\n\n /** The raw accumulated response text */\n rawResponse: string;\n\n /** The final message (after interceptors) */\n finalMessage: string;\n}\n\n/**\n * StreamProcessor: Coordinates all stream processing and hook execution.\n *\n * Execution order:\n * 1. Raw chunk arrives from LLM\n * 2. Interceptor: interceptRawChunk (transform raw text)\n * 3. Observer: onStreamChunk (logging)\n * 4. Parse for gadgets\n * 5. If gadget found:\n * a. Interceptor: interceptGadgetParameters (transform params)\n * b. Controller: beforeGadgetExecution (can skip)\n * c. Observer: onGadgetExecutionStart\n * d. Execute gadget\n * e. Interceptor: interceptGadgetResult (transform result)\n * f. Controller: afterGadgetExecution (can provide fallback)\n * g. Observer: onGadgetExecutionComplete\n * 6. If text chunk:\n * a. Interceptor: interceptTextChunk (transform display text)\n * b. Yield to user\n * 7. Stream complete\n * 8. Interceptor: interceptAssistantMessage (transform final message)\n */\nexport class StreamProcessor {\n private readonly iteration: number;\n private readonly registry: GadgetRegistry;\n private readonly hooks: AgentHooks;\n private readonly logger: Logger<ILogObj>;\n private readonly parser: GadgetCallParser;\n private readonly executor: GadgetExecutor;\n\n // Execution Tree context\n private readonly tree?: ExecutionTree;\n private readonly parentNodeId: NodeId | null;\n private readonly baseDepth: number;\n\n private responseText = \"\";\n private observerFailureCount = 0;\n\n // Dependency tracking for gadget execution DAG\n /** Gadgets waiting for their dependencies to complete */\n private gadgetsAwaitingDependencies: Map<string, ParsedGadgetCall> = new Map();\n /** Completed gadget results, keyed by invocation ID */\n private completedResults: Map<string, GadgetExecutionResult> = new Map();\n /** Invocation IDs of gadgets that have failed (error or skipped due to dependency) */\n private failedInvocations: Set<string> = new Set();\n /** Promises for independent gadgets currently executing (fire-and-forget) */\n private inFlightExecutions: Map<string, Promise<void>> = new Map();\n /** Queue of completed gadget results ready to be yielded (for real-time streaming) */\n private completedResultsQueue: StreamEvent[] = [];\n\n constructor(options: StreamProcessorOptions) {\n this.iteration = options.iteration;\n this.registry = options.registry;\n this.hooks = options.hooks ?? {};\n this.logger = options.logger ?? createLogger({ name: \"llmist:stream-processor\" });\n\n // Initialize tree context\n this.tree = options.tree;\n this.parentNodeId = options.parentNodeId ?? null;\n this.baseDepth = options.baseDepth ?? 0;\n\n this.parser = new GadgetCallParser({\n startPrefix: options.gadgetStartPrefix,\n endPrefix: options.gadgetEndPrefix,\n argPrefix: options.gadgetArgPrefix,\n });\n\n // Wrap onSubagentEvent to also push to completedResultsQueue for real-time streaming\n // during parallel gadget execution. This ensures subagent events are yielded\n // while waiting for gadgets to complete, not batched at the end.\n const wrappedOnSubagentEvent = options.onSubagentEvent\n ? (event: SubagentEvent) => {\n // Push to queue for real-time streaming during parallel execution\n this.completedResultsQueue.push({\n type: \"subagent_event\",\n subagentEvent: event,\n });\n // Also call the original callback (for Agent's queue and hooks)\n options.onSubagentEvent?.(event);\n }\n : undefined;\n\n this.executor = new GadgetExecutor(\n options.registry,\n options.requestHumanInput,\n this.logger.getSubLogger({ name: \"executor\" }),\n options.defaultGadgetTimeoutMs,\n { argPrefix: options.gadgetArgPrefix },\n options.client,\n options.mediaStore,\n options.agentConfig,\n options.subagentConfig,\n wrappedOnSubagentEvent,\n // Tree context for gadget execution\n options.tree,\n options.parentNodeId,\n options.baseDepth,\n );\n }\n\n /**\n * Process an LLM stream and yield events in real-time.\n *\n * This is an async generator that yields events immediately as they occur:\n * - Text events are yielded as text is streamed from the LLM\n * - gadget_call events are yielded immediately when a gadget call is parsed\n * - gadget_result events are yielded when gadget execution completes\n *\n * The final event is always a StreamCompletionEvent containing metadata.\n */\n async *process(stream: AsyncIterable<LLMStreamChunk>): AsyncGenerator<StreamEvent> {\n let finishReason: string | null = null;\n let usage: TokenUsage | undefined;\n let didExecuteGadgets = false;\n let shouldBreakLoop = false;\n\n // Process stream chunks\n for await (const chunk of stream) {\n // Capture metadata\n if (chunk.finishReason) finishReason = chunk.finishReason;\n if (chunk.usage) usage = chunk.usage;\n\n // Process text content if present\n let processedChunk = \"\";\n if (chunk.text) {\n // Step 1: Interceptor - Transform raw chunk\n processedChunk = chunk.text;\n if (this.hooks.interceptors?.interceptRawChunk) {\n const context: ChunkInterceptorContext = {\n iteration: this.iteration,\n accumulatedText: this.responseText,\n logger: this.logger,\n };\n const intercepted = this.hooks.interceptors.interceptRawChunk(processedChunk, context);\n if (intercepted === null) {\n // Chunk suppressed\n processedChunk = \"\";\n } else {\n processedChunk = intercepted;\n }\n }\n\n // Accumulate text\n if (processedChunk) {\n this.responseText += processedChunk;\n }\n }\n\n // Step 2: Observer - Observe chunk (called for text OR usage updates)\n if (this.hooks.observers?.onStreamChunk && (processedChunk || chunk.usage)) {\n const chunkObservers: Array<() => void | Promise<void>> = [];\n chunkObservers.push(async () => {\n const context: ObserveChunkContext = {\n iteration: this.iteration,\n rawChunk: processedChunk,\n accumulatedText: this.responseText,\n usage,\n logger: this.logger,\n };\n await this.hooks.observers?.onStreamChunk?.(context);\n });\n await this.runObserversInParallel(chunkObservers);\n }\n\n // Skip further processing if no text\n if (!processedChunk) {\n continue;\n }\n\n // Step 3: Parse and process events - yield immediately\n for (const event of this.parser.feed(processedChunk)) {\n for await (const processedEvent of this.processEventGenerator(event)) {\n yield processedEvent;\n\n // Track gadget execution\n if (processedEvent.type === \"gadget_result\") {\n didExecuteGadgets = true;\n if (processedEvent.result.breaksLoop) {\n shouldBreakLoop = true;\n }\n }\n }\n }\n\n // Step 4: Drain completed parallel gadget results (real-time streaming)\n // This yields results from gadgets that completed during this chunk processing\n for (const evt of this.drainCompletedResults()) {\n yield evt;\n\n if (evt.type === \"gadget_result\") {\n didExecuteGadgets = true;\n if (evt.result.breaksLoop) {\n shouldBreakLoop = true;\n }\n }\n }\n }\n\n // Finalize parsing\n for (const event of this.parser.finalize()) {\n for await (const processedEvent of this.processEventGenerator(event)) {\n yield processedEvent;\n\n if (processedEvent.type === \"gadget_result\") {\n didExecuteGadgets = true;\n if (processedEvent.result.breaksLoop) {\n shouldBreakLoop = true;\n }\n }\n }\n }\n\n // Wait for all in-flight parallel gadgets to complete, yielding events in real-time\n // This enables subagent events to be displayed during long-running gadget execution\n for await (const evt of this.waitForInFlightExecutions()) {\n yield evt;\n\n if (evt.type === \"gadget_result\") {\n didExecuteGadgets = true;\n if (evt.result.breaksLoop) {\n shouldBreakLoop = true;\n }\n }\n }\n\n // Drain any remaining completed results (stragglers that finished after final poll)\n for (const evt of this.drainCompletedResults()) {\n yield evt;\n\n if (evt.type === \"gadget_result\") {\n didExecuteGadgets = true;\n if (evt.result.breaksLoop) {\n shouldBreakLoop = true;\n }\n }\n }\n\n // Final pass to process any remaining pending gadgets\n // This handles cases where the last gadgets in the stream have dependencies\n // (now that in-flight gadgets have completed, their dependents can execute)\n for await (const evt of this.processPendingGadgetsGenerator()) {\n yield evt;\n\n if (evt.type === \"gadget_result\") {\n didExecuteGadgets = true;\n if (evt.result.breaksLoop) {\n shouldBreakLoop = true;\n }\n }\n }\n\n // Step 4: Interceptor - Transform final message\n let finalMessage = this.responseText;\n if (this.hooks.interceptors?.interceptAssistantMessage) {\n const context: MessageInterceptorContext = {\n iteration: this.iteration,\n rawResponse: this.responseText,\n logger: this.logger,\n };\n finalMessage = this.hooks.interceptors.interceptAssistantMessage(finalMessage, context);\n }\n\n // Yield completion event with all metadata\n const completionEvent: StreamCompletionEvent = {\n type: \"stream_complete\",\n shouldBreakLoop,\n didExecuteGadgets,\n finishReason,\n usage,\n rawResponse: this.responseText,\n finalMessage,\n };\n yield completionEvent;\n }\n\n /**\n * Process a single parsed event, yielding events in real-time.\n */\n private async *processEventGenerator(event: StreamEvent): AsyncGenerator<StreamEvent> {\n if (event.type === \"text\") {\n // processTextEvent is async - need to await the result before iterating\n for (const e of await this.processTextEvent(event)) {\n yield e;\n }\n } else if (event.type === \"gadget_call\") {\n for await (const e of this.processGadgetCallGenerator(event.call)) {\n yield e;\n }\n } else {\n yield event;\n }\n }\n\n /**\n * Process a text event through interceptors.\n */\n private async processTextEvent(event: { type: \"text\"; content: string }): Promise<StreamEvent[]> {\n let content = event.content;\n\n // Interceptor: Transform text chunk\n if (this.hooks.interceptors?.interceptTextChunk) {\n const context: ChunkInterceptorContext = {\n iteration: this.iteration,\n accumulatedText: this.responseText,\n logger: this.logger,\n };\n const intercepted = this.hooks.interceptors.interceptTextChunk(content, context);\n if (intercepted === null) {\n // Chunk suppressed\n return [];\n }\n content = intercepted;\n }\n\n return [{ type: \"text\", content }];\n }\n\n /**\n * Process a gadget call through the full lifecycle, handling dependencies.\n *\n * Gadgets without dependencies (or with all dependencies satisfied) execute immediately.\n * Gadgets with unsatisfied dependencies are queued for later execution.\n * After each execution, pending gadgets are checked to see if they can now run.\n */\n private async processGadgetCall(call: ParsedGadgetCall): Promise<StreamEvent[]> {\n const events: StreamEvent[] = [];\n\n // Emit gadget call event immediately (even if execution is deferred)\n events.push({ type: \"gadget_call\", call });\n\n // Check for dependencies\n if (call.dependencies.length > 0) {\n // Check for self-referential dependency (circular to self)\n if (call.dependencies.includes(call.invocationId)) {\n this.logger.warn(\"Gadget has self-referential dependency (depends on itself)\", {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n });\n this.failedInvocations.add(call.invocationId);\n const skipEvent: GadgetSkippedEvent = {\n type: \"gadget_skipped\",\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: call.parameters ?? {},\n failedDependency: call.invocationId,\n failedDependencyError: `Gadget \"${call.invocationId}\" cannot depend on itself (self-referential dependency)`,\n };\n events.push(skipEvent);\n return events;\n }\n\n // Check if any dependency has failed\n const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));\n if (failedDep) {\n // Dependency failed - handle skip\n const skipEvents = await this.handleFailedDependency(call, failedDep);\n events.push(...skipEvents);\n return events;\n }\n\n // Check if all dependencies are satisfied\n const unsatisfied = call.dependencies.filter((dep) => !this.completedResults.has(dep));\n if (unsatisfied.length > 0) {\n // Queue for later execution\n this.logger.debug(\"Queueing gadget for later - waiting on dependencies\", {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n waitingOn: unsatisfied,\n });\n this.gadgetsAwaitingDependencies.set(call.invocationId, call);\n return events; // Return call event only, execution deferred\n }\n }\n\n // All dependencies satisfied (or no dependencies) - execute now\n const executeEvents = await this.executeGadgetWithHooks(call);\n events.push(...executeEvents);\n\n // Check if any pending gadgets can now execute\n const triggeredEvents = await this.processPendingGadgets();\n events.push(...triggeredEvents);\n\n return events;\n }\n\n /**\n * Process a gadget call, yielding events in real-time.\n *\n * Key difference from processGadgetCall: yields gadget_call event IMMEDIATELY\n * when parsed (before execution), enabling real-time UI feedback.\n */\n private async *processGadgetCallGenerator(call: ParsedGadgetCall): AsyncGenerator<StreamEvent> {\n // Yield gadget_call IMMEDIATELY (real-time feedback before execution)\n yield { type: \"gadget_call\", call };\n\n // Add gadget to execution tree\n if (this.tree) {\n this.tree.addGadget({\n invocationId: call.invocationId,\n name: call.gadgetName,\n parameters: call.parameters ?? {},\n dependencies: call.dependencies,\n parentId: this.parentNodeId,\n });\n }\n\n // Check for dependencies\n if (call.dependencies.length > 0) {\n // Check for self-referential dependency (circular to self)\n if (call.dependencies.includes(call.invocationId)) {\n this.logger.warn(\"Gadget has self-referential dependency (depends on itself)\", {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n });\n this.failedInvocations.add(call.invocationId);\n const skipEvent: GadgetSkippedEvent = {\n type: \"gadget_skipped\",\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: call.parameters ?? {},\n failedDependency: call.invocationId,\n failedDependencyError: `Gadget \"${call.invocationId}\" cannot depend on itself (self-referential dependency)`,\n };\n yield skipEvent;\n return;\n }\n\n // Check if any dependency has failed\n const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));\n if (failedDep) {\n // Dependency failed - handle skip\n const skipEvents = await this.handleFailedDependency(call, failedDep);\n for (const evt of skipEvents) {\n yield evt;\n }\n return;\n }\n\n // Check if all dependencies are satisfied\n const unsatisfied = call.dependencies.filter((dep) => !this.completedResults.has(dep));\n if (unsatisfied.length > 0) {\n // Queue for later execution - gadget_call already yielded above\n this.logger.debug(\"Queueing gadget for later - waiting on dependencies\", {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n waitingOn: unsatisfied,\n });\n this.gadgetsAwaitingDependencies.set(call.invocationId, call);\n return; // Execution deferred, gadget_call already yielded\n }\n\n // All dependencies satisfied - execute synchronously (dependency already complete)\n for await (const evt of this.executeGadgetGenerator(call)) {\n yield evt;\n }\n\n // Check if any pending gadgets can now execute\n for await (const evt of this.processPendingGadgetsGenerator()) {\n yield evt;\n }\n return;\n }\n\n // NO dependencies - start immediately (parallel execution)\n // Results are pushed to completedResultsQueue and yielded during stream processing\n const executionPromise = this.executeGadgetAndCollect(call);\n this.inFlightExecutions.set(call.invocationId, executionPromise);\n // DON'T await - continue processing stream immediately\n }\n\n /**\n * Execute a gadget through the full hook lifecycle.\n * This is the core execution logic, extracted from processGadgetCall.\n * @deprecated Use executeGadgetGenerator for real-time streaming\n */\n private async executeGadgetWithHooks(call: ParsedGadgetCall): Promise<StreamEvent[]> {\n const events: StreamEvent[] = [];\n\n // Log parse errors if present (execution continues - errors are part of the result)\n if (call.parseError) {\n this.logger.warn(\"Gadget has parse error\", {\n gadgetName: call.gadgetName,\n error: call.parseError,\n rawParameters: call.parametersRaw,\n });\n }\n\n // Step 1: Interceptor - Transform parameters\n let parameters = call.parameters ?? {};\n if (this.hooks.interceptors?.interceptGadgetParameters) {\n const context: GadgetParameterInterceptorContext = {\n iteration: this.iteration,\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n logger: this.logger,\n };\n parameters = this.hooks.interceptors.interceptGadgetParameters(parameters, context);\n }\n\n // Update call with intercepted parameters\n call.parameters = parameters;\n\n // Step 2: Controller - Before execution\n let shouldSkip = false;\n let syntheticResult: string | undefined;\n\n if (this.hooks.controllers?.beforeGadgetExecution) {\n const context: GadgetExecutionControllerContext = {\n iteration: this.iteration,\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters,\n logger: this.logger,\n };\n const action: BeforeGadgetExecutionAction =\n await this.hooks.controllers.beforeGadgetExecution(context);\n\n // Validate the action\n validateBeforeGadgetExecutionAction(action);\n\n if (action.action === \"skip\") {\n shouldSkip = true;\n syntheticResult = action.syntheticResult;\n this.logger.info(\"Controller skipped gadget execution\", {\n gadgetName: call.gadgetName,\n });\n }\n }\n\n // Step 3: Observer - Execution start\n const startObservers: Array<() => void | Promise<void>> = [];\n if (this.hooks.observers?.onGadgetExecutionStart) {\n startObservers.push(async () => {\n const context: ObserveGadgetStartContext = {\n iteration: this.iteration,\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters,\n logger: this.logger,\n };\n await this.hooks.observers?.onGadgetExecutionStart?.(context);\n });\n }\n await this.runObserversInParallel(startObservers);\n\n // Step 4: Execute or use synthetic result\n let result: GadgetExecutionResult;\n if (shouldSkip) {\n result = {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters,\n result: syntheticResult ?? \"Execution skipped\",\n executionTimeMs: 0,\n };\n } else {\n result = await this.executor.execute(call);\n }\n\n // Capture the raw result before any hook transformations.\n // Used in onGadgetExecutionComplete to provide both pre-hook (originalResult)\n // and post-hook (finalResult) values for observers that need to audit changes.\n const originalResult = result.result;\n\n // Step 5: Interceptor - Transform result (modifies result.result)\n if (result.result && this.hooks.interceptors?.interceptGadgetResult) {\n const context: GadgetResultInterceptorContext = {\n iteration: this.iteration,\n gadgetName: result.gadgetName,\n invocationId: result.invocationId,\n parameters,\n executionTimeMs: result.executionTimeMs,\n logger: this.logger,\n };\n result.result = this.hooks.interceptors.interceptGadgetResult(result.result, context);\n }\n\n // Step 6: Controller - After execution (can further modify result)\n if (this.hooks.controllers?.afterGadgetExecution) {\n const context: AfterGadgetExecutionControllerContext = {\n iteration: this.iteration,\n gadgetName: result.gadgetName,\n invocationId: result.invocationId,\n parameters,\n result: result.result,\n error: result.error,\n executionTimeMs: result.executionTimeMs,\n logger: this.logger,\n };\n const action: AfterGadgetExecutionAction =\n await this.hooks.controllers.afterGadgetExecution(context);\n\n // Validate the action\n validateAfterGadgetExecutionAction(action);\n\n if (action.action === \"recover\" && result.error) {\n this.logger.info(\"Controller recovered from gadget error\", {\n gadgetName: result.gadgetName,\n originalError: result.error,\n });\n result = {\n ...result,\n error: undefined,\n result: action.fallbackResult,\n };\n }\n }\n\n // Step 7: Observer - Execution complete\n const completeObservers: Array<() => void | Promise<void>> = [];\n if (this.hooks.observers?.onGadgetExecutionComplete) {\n completeObservers.push(async () => {\n const context: ObserveGadgetCompleteContext = {\n iteration: this.iteration,\n gadgetName: result.gadgetName,\n invocationId: result.invocationId,\n parameters,\n originalResult,\n finalResult: result.result,\n error: result.error,\n executionTimeMs: result.executionTimeMs,\n breaksLoop: result.breaksLoop,\n cost: result.cost,\n logger: this.logger,\n };\n await this.hooks.observers?.onGadgetExecutionComplete?.(context);\n });\n }\n await this.runObserversInParallel(completeObservers);\n\n // Track completion for dependency resolution\n this.completedResults.set(result.invocationId, result);\n if (result.error) {\n this.failedInvocations.add(result.invocationId);\n }\n\n // Emit result event\n events.push({ type: \"gadget_result\", result });\n\n return events;\n }\n\n /**\n * Execute a gadget and yield the result event.\n * Generator version that yields gadget_result immediately when execution completes.\n */\n private async *executeGadgetGenerator(call: ParsedGadgetCall): AsyncGenerator<StreamEvent> {\n // Log parse errors if present (execution continues - errors are part of the result)\n if (call.parseError) {\n this.logger.warn(\"Gadget has parse error\", {\n gadgetName: call.gadgetName,\n error: call.parseError,\n rawParameters: call.parametersRaw,\n });\n }\n\n // Step 1: Interceptor - Transform parameters\n let parameters = call.parameters ?? {};\n if (this.hooks.interceptors?.interceptGadgetParameters) {\n const context: GadgetParameterInterceptorContext = {\n iteration: this.iteration,\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n logger: this.logger,\n };\n parameters = this.hooks.interceptors.interceptGadgetParameters(parameters, context);\n }\n\n // Update call with intercepted parameters\n call.parameters = parameters;\n\n // Step 2: Controller - Before execution\n let shouldSkip = false;\n let syntheticResult: string | undefined;\n\n if (this.hooks.controllers?.beforeGadgetExecution) {\n const context: GadgetExecutionControllerContext = {\n iteration: this.iteration,\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters,\n logger: this.logger,\n };\n const action: BeforeGadgetExecutionAction =\n await this.hooks.controllers.beforeGadgetExecution(context);\n\n // Validate the action\n validateBeforeGadgetExecutionAction(action);\n\n if (action.action === \"skip\") {\n shouldSkip = true;\n syntheticResult = action.syntheticResult;\n this.logger.info(\"Controller skipped gadget execution\", {\n gadgetName: call.gadgetName,\n });\n }\n }\n\n // Step 3: Observer - Execution start\n const startObservers: Array<() => void | Promise<void>> = [];\n if (this.hooks.observers?.onGadgetExecutionStart) {\n startObservers.push(async () => {\n const context: ObserveGadgetStartContext = {\n iteration: this.iteration,\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters,\n logger: this.logger,\n };\n await this.hooks.observers?.onGadgetExecutionStart?.(context);\n });\n }\n await this.runObserversInParallel(startObservers);\n\n // Mark gadget as running in execution tree\n if (this.tree) {\n const gadgetNode = this.tree.getNodeByInvocationId(call.invocationId);\n if (gadgetNode) {\n this.tree.startGadget(gadgetNode.id);\n }\n }\n\n // Step 4: Execute or use synthetic result\n let result: GadgetExecutionResult;\n if (shouldSkip) {\n result = {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters,\n result: syntheticResult ?? \"Execution skipped\",\n executionTimeMs: 0,\n };\n } else {\n result = await this.executor.execute(call);\n }\n\n // Capture the raw result before any hook transformations.\n // Used in onGadgetExecutionComplete to provide both pre-hook (originalResult)\n // and post-hook (finalResult) values for observers that need to audit changes.\n const originalResult = result.result;\n\n // Step 5: Interceptor - Transform result (modifies result.result)\n if (result.result && this.hooks.interceptors?.interceptGadgetResult) {\n const context: GadgetResultInterceptorContext = {\n iteration: this.iteration,\n gadgetName: result.gadgetName,\n invocationId: result.invocationId,\n parameters,\n executionTimeMs: result.executionTimeMs,\n logger: this.logger,\n };\n result.result = this.hooks.interceptors.interceptGadgetResult(result.result, context);\n }\n\n // Step 6: Controller - After execution (can further modify result)\n if (this.hooks.controllers?.afterGadgetExecution) {\n const context: AfterGadgetExecutionControllerContext = {\n iteration: this.iteration,\n gadgetName: result.gadgetName,\n invocationId: result.invocationId,\n parameters,\n result: result.result,\n error: result.error,\n executionTimeMs: result.executionTimeMs,\n logger: this.logger,\n };\n const action: AfterGadgetExecutionAction =\n await this.hooks.controllers.afterGadgetExecution(context);\n\n // Validate the action\n validateAfterGadgetExecutionAction(action);\n\n if (action.action === \"recover\" && result.error) {\n this.logger.info(\"Controller recovered from gadget error\", {\n gadgetName: result.gadgetName,\n originalError: result.error,\n });\n result = {\n ...result,\n error: undefined,\n result: action.fallbackResult,\n };\n }\n }\n\n // Step 7: Observer - Execution complete\n const completeObservers: Array<() => void | Promise<void>> = [];\n if (this.hooks.observers?.onGadgetExecutionComplete) {\n completeObservers.push(async () => {\n const context: ObserveGadgetCompleteContext = {\n iteration: this.iteration,\n gadgetName: result.gadgetName,\n invocationId: result.invocationId,\n parameters,\n originalResult,\n finalResult: result.result,\n error: result.error,\n executionTimeMs: result.executionTimeMs,\n breaksLoop: result.breaksLoop,\n cost: result.cost,\n logger: this.logger,\n };\n await this.hooks.observers?.onGadgetExecutionComplete?.(context);\n });\n }\n await this.runObserversInParallel(completeObservers);\n\n // Complete gadget in execution tree\n if (this.tree) {\n const gadgetNode = this.tree.getNodeByInvocationId(result.invocationId);\n if (gadgetNode) {\n if (result.error) {\n this.tree.completeGadget(gadgetNode.id, {\n error: result.error,\n executionTimeMs: result.executionTimeMs,\n cost: result.cost,\n });\n } else {\n this.tree.completeGadget(gadgetNode.id, {\n result: result.result,\n executionTimeMs: result.executionTimeMs,\n cost: result.cost,\n media: result.media,\n });\n }\n }\n }\n\n // Track completion for dependency resolution\n this.completedResults.set(result.invocationId, result);\n if (result.error) {\n this.failedInvocations.add(result.invocationId);\n }\n\n // Yield result event immediately\n yield { type: \"gadget_result\", result };\n }\n\n /**\n * Execute a gadget and push events to the completed results queue (non-blocking).\n * Used for fire-and-forget parallel execution of independent gadgets.\n * Results are pushed to completedResultsQueue for real-time streaming to the caller.\n */\n private async executeGadgetAndCollect(call: ParsedGadgetCall): Promise<void> {\n for await (const evt of this.executeGadgetGenerator(call)) {\n // Push each event to the queue as it's produced for real-time streaming\n this.completedResultsQueue.push(evt);\n }\n // NOTE: Don't delete from inFlightExecutions here - it creates a race condition\n // where fast-completing gadgets are removed before waitForInFlightExecutions runs.\n // The map is cleared in waitForInFlightExecutions after all promises are awaited.\n }\n\n /**\n * Drain all completed results from the queue.\n * Used to yield results as they complete during stream processing.\n * @returns Generator that yields all events currently in the queue\n */\n private *drainCompletedResults(): Generator<StreamEvent> {\n while (this.completedResultsQueue.length > 0) {\n yield this.completedResultsQueue.shift()!;\n }\n }\n\n /**\n * Wait for all in-flight gadget executions to complete, yielding events in real-time.\n * Called at stream end to ensure all parallel executions finish.\n * Results and subagent events are pushed to completedResultsQueue during execution.\n * This generator yields queued events while polling, enabling real-time display\n * of subagent activity (LLM calls, nested gadgets) during long-running gadgets.\n * Clears the inFlightExecutions map after all gadgets complete.\n */\n private async *waitForInFlightExecutions(): AsyncGenerator<StreamEvent> {\n if (this.inFlightExecutions.size === 0) {\n return;\n }\n\n this.logger.debug(\"Waiting for in-flight gadget executions\", {\n count: this.inFlightExecutions.size,\n invocationIds: Array.from(this.inFlightExecutions.keys()),\n });\n\n // Create a combined promise that resolves when all gadgets complete\n const allDone = Promise.all(this.inFlightExecutions.values()).then(() => \"done\" as const);\n\n // Poll interval for draining queue (100ms provides responsive updates)\n const POLL_INTERVAL_MS = 100;\n\n // Poll loop: yield queued events while waiting for gadgets to complete\n while (true) {\n // Race between: all gadgets completing OR poll timeout\n const result = await Promise.race([\n allDone,\n new Promise<\"poll\">((resolve) => setTimeout(() => resolve(\"poll\"), POLL_INTERVAL_MS)),\n ]);\n\n // Yield any events that accumulated in the queue\n yield* this.drainCompletedResults();\n\n if (result === \"done\") {\n // All gadgets complete - exit loop\n break;\n }\n // result === \"poll\" - continue polling\n }\n\n // Clear the map after all promises have completed\n this.inFlightExecutions.clear();\n }\n\n /**\n * Handle a gadget that cannot execute because a dependency failed.\n * Calls the onDependencySkipped controller to allow customization.\n */\n private async handleFailedDependency(\n call: ParsedGadgetCall,\n failedDep: string,\n ): Promise<StreamEvent[]> {\n const events: StreamEvent[] = [];\n const depResult = this.completedResults.get(failedDep);\n const depError = depResult?.error ?? \"Dependency failed\";\n\n // Call controller to allow customization of skip behavior\n let action: DependencySkipAction = { action: \"skip\" };\n if (this.hooks.controllers?.onDependencySkipped) {\n const context: DependencySkipControllerContext = {\n iteration: this.iteration,\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: call.parameters ?? {},\n failedDependency: failedDep,\n failedDependencyError: depError,\n logger: this.logger,\n };\n action = await this.hooks.controllers.onDependencySkipped(context);\n }\n\n if (action.action === \"skip\") {\n // Mark as failed so downstream dependents also skip\n this.failedInvocations.add(call.invocationId);\n\n // Skip gadget in execution tree\n if (this.tree) {\n const gadgetNode = this.tree.getNodeByInvocationId(call.invocationId);\n if (gadgetNode) {\n this.tree.skipGadget(gadgetNode.id, failedDep, depError, \"dependency_failed\");\n }\n }\n\n // Emit skip event\n const skipEvent: GadgetSkippedEvent = {\n type: \"gadget_skipped\",\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: call.parameters ?? {},\n failedDependency: failedDep,\n failedDependencyError: depError,\n };\n events.push(skipEvent);\n\n // Call observer\n if (this.hooks.observers?.onGadgetSkipped) {\n const observeContext: ObserveGadgetSkippedContext = {\n iteration: this.iteration,\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: call.parameters ?? {},\n failedDependency: failedDep,\n failedDependencyError: depError,\n logger: this.logger,\n };\n await this.safeObserve(() => this.hooks.observers?.onGadgetSkipped?.(observeContext));\n }\n\n this.logger.info(\"Gadget skipped due to failed dependency\", {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n failedDependency: failedDep,\n });\n } else if (action.action === \"execute_anyway\") {\n // Execute despite failed dependency\n this.logger.info(\"Executing gadget despite failed dependency (controller override)\", {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n failedDependency: failedDep,\n });\n const executeEvents = await this.executeGadgetWithHooks(call);\n events.push(...executeEvents);\n } else if (action.action === \"use_fallback\") {\n // Use fallback result without executing\n const fallbackResult: GadgetExecutionResult = {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n parameters: call.parameters ?? {},\n result: action.fallbackResult,\n executionTimeMs: 0,\n };\n this.completedResults.set(call.invocationId, fallbackResult);\n events.push({ type: \"gadget_result\", result: fallbackResult });\n\n this.logger.info(\"Using fallback result for gadget with failed dependency\", {\n gadgetName: call.gadgetName,\n invocationId: call.invocationId,\n failedDependency: failedDep,\n });\n }\n\n return events;\n }\n\n /**\n * Process pending gadgets whose dependencies are now satisfied.\n * Executes ready gadgets in parallel and continues until no more can be triggered.\n */\n private async processPendingGadgets(): Promise<StreamEvent[]> {\n const events: StreamEvent[] = [];\n let progress = true;\n\n while (progress && this.gadgetsAwaitingDependencies.size > 0) {\n progress = false;\n\n // Find all gadgets that are ready to execute\n const readyToExecute: ParsedGadgetCall[] = [];\n const readyToSkip: Array<{ call: ParsedGadgetCall; failedDep: string }> = [];\n\n for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {\n // Check for failed dependency\n const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));\n if (failedDep) {\n readyToSkip.push({ call, failedDep });\n continue;\n }\n\n // Check if all dependencies are satisfied\n const allSatisfied = call.dependencies.every((dep) => this.completedResults.has(dep));\n if (allSatisfied) {\n readyToExecute.push(call);\n }\n }\n\n // Handle skipped gadgets\n for (const { call, failedDep } of readyToSkip) {\n this.gadgetsAwaitingDependencies.delete(call.invocationId);\n const skipEvents = await this.handleFailedDependency(call, failedDep);\n events.push(...skipEvents);\n progress = true;\n }\n\n // Execute ready gadgets in parallel\n if (readyToExecute.length > 0) {\n this.logger.debug(\"Executing ready gadgets in parallel\", {\n count: readyToExecute.length,\n invocationIds: readyToExecute.map((c) => c.invocationId),\n });\n\n // Remove from pending before executing\n for (const call of readyToExecute) {\n this.gadgetsAwaitingDependencies.delete(call.invocationId);\n }\n\n // Execute all ready gadgets in parallel\n const executePromises = readyToExecute.map((call) => this.executeGadgetWithHooks(call));\n const results = await Promise.all(executePromises);\n\n // Collect all events\n for (const executeEvents of results) {\n events.push(...executeEvents);\n }\n\n progress = true;\n }\n }\n\n // Warn about any remaining unresolved gadgets (circular or missing dependencies)\n if (this.gadgetsAwaitingDependencies.size > 0) {\n // Collect all pending invocation IDs to detect circular dependencies\n const pendingIds = new Set(this.gadgetsAwaitingDependencies.keys());\n\n for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {\n const missingDeps = call.dependencies.filter((dep) => !this.completedResults.has(dep));\n\n // Categorize the dependency issue\n const circularDeps = missingDeps.filter((dep) => pendingIds.has(dep));\n const trulyMissingDeps = missingDeps.filter((dep) => !pendingIds.has(dep));\n\n let errorMessage: string;\n let logLevel: \"warn\" | \"error\" = \"warn\";\n\n if (circularDeps.length > 0 && trulyMissingDeps.length > 0) {\n errorMessage = `Dependencies unresolvable: circular=[${circularDeps.join(\", \")}], missing=[${trulyMissingDeps.join(\", \")}]`;\n logLevel = \"error\";\n } else if (circularDeps.length > 0) {\n errorMessage = `Circular dependency detected: \"${invocationId}\" depends on \"${circularDeps[0]}\" which also depends on \"${invocationId}\" (directly or indirectly)`;\n } else {\n errorMessage = `Dependency \"${missingDeps[0]}\" was never executed - check that the invocation ID exists and is spelled correctly`;\n }\n\n this.logger[logLevel](\"Gadget has unresolvable dependencies\", {\n gadgetName: call.gadgetName,\n invocationId,\n circularDependencies: circularDeps,\n missingDependencies: trulyMissingDeps,\n });\n\n // Mark as failed and emit skip event\n this.failedInvocations.add(invocationId);\n const skipEvent: GadgetSkippedEvent = {\n type: \"gadget_skipped\",\n gadgetName: call.gadgetName,\n invocationId,\n parameters: call.parameters ?? {},\n failedDependency: missingDeps[0],\n failedDependencyError: errorMessage,\n };\n events.push(skipEvent);\n }\n this.gadgetsAwaitingDependencies.clear();\n }\n\n return events;\n }\n\n /**\n * Process pending gadgets, yielding events in real-time.\n * Generator version that yields events as gadgets complete.\n *\n * Note: Gadgets are still executed in parallel for efficiency,\n * but results are yielded as they become available.\n */\n private async *processPendingGadgetsGenerator(): AsyncGenerator<StreamEvent> {\n let progress = true;\n\n while (progress && this.gadgetsAwaitingDependencies.size > 0) {\n progress = false;\n\n // Find all gadgets that are ready to execute\n const readyToExecute: ParsedGadgetCall[] = [];\n const readyToSkip: Array<{ call: ParsedGadgetCall; failedDep: string }> = [];\n\n for (const [_invocationId, call] of this.gadgetsAwaitingDependencies) {\n // Check for failed dependency\n const failedDep = call.dependencies.find((dep) => this.failedInvocations.has(dep));\n if (failedDep) {\n readyToSkip.push({ call, failedDep });\n continue;\n }\n\n // Check if all dependencies are satisfied\n const allSatisfied = call.dependencies.every((dep) => this.completedResults.has(dep));\n if (allSatisfied) {\n readyToExecute.push(call);\n }\n }\n\n // Handle skipped gadgets\n for (const { call, failedDep } of readyToSkip) {\n this.gadgetsAwaitingDependencies.delete(call.invocationId);\n const skipEvents = await this.handleFailedDependency(call, failedDep);\n for (const evt of skipEvents) {\n yield evt;\n }\n progress = true;\n }\n\n // Execute ready gadgets in parallel\n if (readyToExecute.length > 0) {\n this.logger.debug(\"Executing ready gadgets in parallel\", {\n count: readyToExecute.length,\n invocationIds: readyToExecute.map((c) => c.invocationId),\n });\n\n // Remove from pending before executing\n for (const call of readyToExecute) {\n this.gadgetsAwaitingDependencies.delete(call.invocationId);\n }\n\n // Execute all ready gadgets in parallel, collect events, then yield\n const eventSets = await Promise.all(\n readyToExecute.map(async (call) => {\n const events: StreamEvent[] = [];\n for await (const evt of this.executeGadgetGenerator(call)) {\n events.push(evt);\n }\n return events;\n }),\n );\n\n // Yield all events from parallel execution\n for (const events of eventSets) {\n for (const evt of events) {\n yield evt;\n }\n }\n\n progress = true;\n }\n }\n\n // Warn about any remaining unresolved gadgets (circular or missing dependencies)\n if (this.gadgetsAwaitingDependencies.size > 0) {\n // Collect all pending invocation IDs to detect circular dependencies\n const pendingIds = new Set(this.gadgetsAwaitingDependencies.keys());\n\n for (const [invocationId, call] of this.gadgetsAwaitingDependencies) {\n const missingDeps = call.dependencies.filter((dep) => !this.completedResults.has(dep));\n\n // Categorize the dependency issue\n const circularDeps = missingDeps.filter((dep) => pendingIds.has(dep));\n const trulyMissingDeps = missingDeps.filter((dep) => !pendingIds.has(dep));\n\n let errorMessage: string;\n let logLevel: \"warn\" | \"error\" = \"warn\";\n\n if (circularDeps.length > 0 && trulyMissingDeps.length > 0) {\n errorMessage = `Dependencies unresolvable: circular=[${circularDeps.join(\", \")}], missing=[${trulyMissingDeps.join(\", \")}]`;\n logLevel = \"error\";\n } else if (circularDeps.length > 0) {\n errorMessage = `Circular dependency detected: \"${invocationId}\" depends on \"${circularDeps[0]}\" which also depends on \"${invocationId}\" (directly or indirectly)`;\n } else {\n errorMessage = `Dependency \"${missingDeps[0]}\" was never executed - check that the invocation ID exists and is spelled correctly`;\n }\n\n this.logger[logLevel](\"Gadget has unresolvable dependencies\", {\n gadgetName: call.gadgetName,\n invocationId,\n circularDependencies: circularDeps,\n missingDependencies: trulyMissingDeps,\n });\n\n // Mark as failed and emit skip event\n this.failedInvocations.add(invocationId);\n const skipEvent: GadgetSkippedEvent = {\n type: \"gadget_skipped\",\n gadgetName: call.gadgetName,\n invocationId,\n parameters: call.parameters ?? {},\n failedDependency: missingDeps[0],\n failedDependencyError: errorMessage,\n };\n yield skipEvent;\n }\n this.gadgetsAwaitingDependencies.clear();\n }\n }\n\n /**\n * Safely execute an observer, catching and logging any errors.\n * Observers are non-critical, so errors are logged but don't crash the system.\n */\n private async safeObserve(fn: () => void | Promise<void>): Promise<void> {\n try {\n await fn();\n } catch (error) {\n this.observerFailureCount++;\n this.logger.error(\"Observer threw error (ignoring)\", {\n error: error instanceof Error ? error.message : String(error),\n failureCount: this.observerFailureCount,\n });\n }\n }\n\n /**\n * Execute multiple observers in parallel.\n * All observers run concurrently and failures are tracked but don't crash.\n */\n private async runObserversInParallel(\n observers: Array<() => void | Promise<void>>,\n ): Promise<void> {\n if (observers.length === 0) return;\n\n const results = await Promise.allSettled(\n observers.map((observer) => this.safeObserve(observer)),\n );\n\n // All errors are already logged in safeObserve, no need to handle rejected promises\n // This just ensures we wait for all observers to complete\n }\n}\n","/**\n * Agent: Lean orchestrator using the clean hooks architecture.\n *\n * The Agent delegates ALL stream processing and hook coordination to StreamProcessor,\n * making it a simple loop orchestrator with clear responsibilities.\n */\n\nimport type { ILogObj, Logger } from \"tslog\";\nimport type { LLMist } from \"../core/client.js\";\nimport {\n CHARS_PER_TOKEN,\n DEFAULT_GADGET_OUTPUT_LIMIT,\n DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT,\n FALLBACK_CONTEXT_WINDOW,\n} from \"../core/constants.js\";\nimport { ExecutionTree, type NodeId } from \"../core/execution-tree.js\";\nimport type { ContentPart } from \"../core/input-content.js\";\nimport type { MessageContent } from \"../core/messages.js\";\nimport { extractMessageText, LLMMessageBuilder } from \"../core/messages.js\";\nimport { resolveModel } from \"../core/model-shortcuts.js\";\nimport type { LLMGenerationOptions } from \"../core/options.js\";\nimport type { PromptTemplateConfig } from \"../core/prompt-config.js\";\nimport { MediaStore } from \"../gadgets/media-store.js\";\nimport { createGadgetOutputViewer } from \"../gadgets/output-viewer.js\";\nimport type { GadgetRegistry } from \"../gadgets/registry.js\";\nimport type {\n AgentContextConfig,\n LLMCallInfo,\n StreamCompletionEvent,\n StreamEvent,\n SubagentConfigMap,\n SubagentEvent,\n TextOnlyHandler,\n} from \"../gadgets/types.js\";\nimport { createLogger } from \"../logging/logger.js\";\nimport { type AGENT_INTERNAL_KEY, isValidAgentKey } from \"./agent-internal-key.js\";\nimport type { CompactionConfig, CompactionEvent, CompactionStats } from \"./compaction/config.js\";\nimport { CompactionManager } from \"./compaction/manager.js\";\nimport { ConversationManager } from \"./conversation-manager.js\";\nimport { type EventHandlers, runWithHandlers } from \"./event-handlers.js\";\nimport { GadgetOutputStore } from \"./gadget-output-store.js\";\nimport {\n validateAfterLLMCallAction,\n validateAfterLLMErrorAction,\n validateBeforeLLMCallAction,\n} from \"./hook-validators.js\";\nimport type {\n AfterLLMCallAction,\n AfterLLMCallControllerContext,\n AfterLLMErrorAction,\n AgentHooks,\n BeforeLLMCallAction,\n GadgetResultInterceptorContext,\n LLMCallControllerContext,\n LLMErrorControllerContext,\n ObserveAbortContext,\n ObserveLLMCallContext,\n ObserveLLMCallReadyContext,\n ObserveLLMCompleteContext,\n ObserveLLMErrorContext,\n} from \"./hooks.js\";\nimport { StreamProcessor } from \"./stream-processor.js\";\n\n/**\n * Configuration options for the Agent.\n */\nexport interface AgentOptions {\n /** The LLM client */\n client: LLMist;\n\n /** The model ID */\n model: string;\n\n /** System prompt */\n systemPrompt?: string;\n\n /** Initial user prompt (optional if using build()). Can be text or multimodal content. */\n userPrompt?: string | ContentPart[];\n\n /** Maximum iterations */\n maxIterations?: number;\n\n /** Temperature */\n temperature?: number;\n\n /** Gadget registry */\n registry: GadgetRegistry;\n\n /** Logger */\n logger?: Logger<ILogObj>;\n\n /** Clean hooks system */\n hooks?: AgentHooks;\n\n /** Callback for requesting human input during execution */\n requestHumanInput?: (question: string) => Promise<string>;\n\n /** Custom gadget start prefix */\n gadgetStartPrefix?: string;\n\n /** Custom gadget end prefix */\n gadgetEndPrefix?: string;\n\n /** Custom gadget argument prefix for block format parameters */\n gadgetArgPrefix?: string;\n\n /** Initial messages. User messages support multimodal content. */\n initialMessages?: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: MessageContent }>;\n\n /** Text-only handler */\n textOnlyHandler?: TextOnlyHandler;\n\n /**\n * Handler for text content that appears alongside gadget calls.\n * When set, text accompanying gadgets will be wrapped as a synthetic gadget call.\n */\n textWithGadgetsHandler?: {\n /** Name of the gadget to use for wrapping text */\n gadgetName: string;\n /** Maps text content to gadget parameters */\n parameterMapping: (text: string) => Record<string, unknown>;\n /** Maps text content to the result string (optional, defaults to text) */\n resultMapping?: (text: string) => string;\n };\n\n /** Default gadget timeout */\n defaultGadgetTimeoutMs?: number;\n\n /** Custom prompt configuration for gadget system prompts */\n promptConfig?: PromptTemplateConfig;\n\n /** Enable gadget output limiting (default: true) */\n gadgetOutputLimit?: boolean;\n\n /** Max gadget output as % of model context window (default: 15) */\n gadgetOutputLimitPercent?: number;\n\n /** Context compaction configuration (enabled by default) */\n compactionConfig?: CompactionConfig;\n\n /** Optional abort signal for cancelling requests mid-flight */\n signal?: AbortSignal;\n\n /** Subagent-specific configuration overrides (from CLI config) */\n subagentConfig?: SubagentConfigMap;\n\n /** Callback for subagent gadgets to report subagent events to parent */\n onSubagentEvent?: (event: SubagentEvent) => void;\n\n // ==========================================================================\n // Execution Tree Context (for shared tree model with subagents)\n // ==========================================================================\n\n /**\n * Shared execution tree for tracking all LLM calls and gadget executions.\n * If provided (by a parent subagent), nodes are added to this tree.\n * If not provided, the Agent creates its own tree.\n */\n parentTree?: ExecutionTree;\n\n /**\n * Parent node ID in the tree (when this agent is a subagent).\n * Used to set parentId on all nodes created by this agent.\n */\n parentNodeId?: NodeId;\n\n /**\n * Base depth for nodes created by this agent.\n * Root agents use 0; subagents use (parentDepth + 1).\n */\n baseDepth?: number;\n}\n\n/**\n * Agent: Lean orchestrator that delegates to StreamProcessor.\n *\n * Responsibilities:\n * - Run the main agent loop\n * - Call LLM API\n * - Delegate stream processing to StreamProcessor\n * - Coordinate conversation management\n * - Execute top-level lifecycle controllers\n *\n * NOT responsible for:\n * - Stream parsing (StreamProcessor)\n * - Hook coordination (StreamProcessor)\n * - Gadget execution (StreamProcessor -> GadgetExecutor)\n */\nexport class Agent {\n private readonly client: LLMist;\n private readonly model: string;\n private readonly maxIterations: number;\n private readonly temperature?: number;\n private readonly logger: Logger<ILogObj>;\n private readonly hooks: AgentHooks;\n private readonly conversation: ConversationManager;\n private readonly registry: GadgetRegistry;\n private readonly gadgetStartPrefix?: string;\n private readonly gadgetEndPrefix?: string;\n private readonly gadgetArgPrefix?: string;\n private readonly requestHumanInput?: (question: string) => Promise<string>;\n private readonly textOnlyHandler: TextOnlyHandler;\n private readonly textWithGadgetsHandler?: {\n gadgetName: string;\n parameterMapping: (text: string) => Record<string, unknown>;\n resultMapping?: (text: string) => string;\n };\n private readonly defaultGadgetTimeoutMs?: number;\n private readonly defaultMaxTokens?: number;\n private hasUserPrompt: boolean;\n\n // Gadget output limiting\n private readonly outputStore: GadgetOutputStore;\n private readonly outputLimitEnabled: boolean;\n private readonly outputLimitCharLimit: number;\n\n // Context compaction\n private readonly compactionManager?: CompactionManager;\n\n // Media storage (for gadgets returning images, audio, etc.)\n private readonly mediaStore: MediaStore;\n\n // Cancellation\n private readonly signal?: AbortSignal;\n\n // Subagent configuration\n private readonly agentContextConfig: AgentContextConfig;\n private readonly subagentConfig?: SubagentConfigMap;\n\n // Subagent event callback for subagent gadgets\n private readonly userSubagentEventCallback?: (event: SubagentEvent) => void;\n // Internal queue for yielding subagent events in run()\n private readonly pendingSubagentEvents: SubagentEvent[] = [];\n // Combined callback that queues events AND calls user callback\n private readonly onSubagentEvent: (event: SubagentEvent) => void;\n // Counter for generating synthetic invocation IDs for wrapped text content\n private syntheticInvocationCounter = 0;\n\n // Execution Tree - first-class model for nested subagent support\n private readonly tree: ExecutionTree;\n private readonly parentNodeId: NodeId | null;\n private readonly baseDepth: number;\n\n /**\n * Creates a new Agent instance.\n * @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.\n */\n constructor(key: typeof AGENT_INTERNAL_KEY, options: AgentOptions) {\n if (!isValidAgentKey(key)) {\n throw new Error(\n \"Agent cannot be instantiated directly. Use LLMist.createAgent() or new AgentBuilder() instead.\",\n );\n }\n\n this.client = options.client;\n this.model = resolveModel(options.model);\n this.maxIterations = options.maxIterations ?? 10;\n this.temperature = options.temperature;\n this.logger = options.logger ?? createLogger({ name: \"llmist:agent\" });\n this.registry = options.registry;\n this.gadgetStartPrefix = options.gadgetStartPrefix;\n this.gadgetEndPrefix = options.gadgetEndPrefix;\n this.gadgetArgPrefix = options.gadgetArgPrefix;\n this.requestHumanInput = options.requestHumanInput;\n this.textOnlyHandler = options.textOnlyHandler ?? \"terminate\";\n this.textWithGadgetsHandler = options.textWithGadgetsHandler;\n this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;\n this.defaultMaxTokens = this.resolveMaxTokensFromCatalog(options.model);\n\n // Initialize gadget output limiting\n this.outputLimitEnabled = options.gadgetOutputLimit ?? DEFAULT_GADGET_OUTPUT_LIMIT;\n this.outputStore = new GadgetOutputStore();\n\n // Initialize media storage for gadgets returning images, audio, etc.\n this.mediaStore = new MediaStore();\n\n // Calculate character limit from model context window\n const limitPercent = options.gadgetOutputLimitPercent ?? DEFAULT_GADGET_OUTPUT_LIMIT_PERCENT;\n const limits = this.client.modelRegistry.getModelLimits(this.model);\n const contextWindow = limits?.contextWindow ?? FALLBACK_CONTEXT_WINDOW;\n this.outputLimitCharLimit = Math.floor(contextWindow * (limitPercent / 100) * CHARS_PER_TOKEN);\n\n // Auto-register GadgetOutputViewer when limiting is enabled\n // Pass the same character limit so viewer output is also bounded\n if (this.outputLimitEnabled) {\n this.registry.register(\n \"GadgetOutputViewer\",\n createGadgetOutputViewer(this.outputStore, this.outputLimitCharLimit),\n );\n }\n\n // Chain output limiter interceptor with user hooks\n this.hooks = this.chainOutputLimiterWithUserHooks(options.hooks);\n\n // Build conversation\n const baseBuilder = new LLMMessageBuilder(options.promptConfig);\n if (options.systemPrompt) {\n baseBuilder.addSystem(options.systemPrompt);\n }\n\n baseBuilder.addGadgets(this.registry.getAll(), {\n startPrefix: options.gadgetStartPrefix,\n endPrefix: options.gadgetEndPrefix,\n argPrefix: options.gadgetArgPrefix,\n });\n const baseMessages = baseBuilder.build();\n\n const initialMessages = (options.initialMessages ?? []).map((message) => ({\n role: message.role,\n content: message.content,\n }));\n\n this.conversation = new ConversationManager(baseMessages, initialMessages, {\n startPrefix: options.gadgetStartPrefix,\n endPrefix: options.gadgetEndPrefix,\n argPrefix: options.gadgetArgPrefix,\n });\n this.hasUserPrompt = !!options.userPrompt;\n if (options.userPrompt) {\n this.conversation.addUserMessage(options.userPrompt);\n }\n\n // Initialize context compaction (enabled by default)\n const compactionEnabled = options.compactionConfig?.enabled ?? true;\n if (compactionEnabled) {\n this.compactionManager = new CompactionManager(\n this.client,\n this.model,\n options.compactionConfig,\n );\n }\n\n // Store abort signal for cancellation\n this.signal = options.signal;\n\n // Build agent context config for subagents to inherit\n this.agentContextConfig = {\n model: this.model,\n temperature: this.temperature,\n };\n this.subagentConfig = options.subagentConfig;\n\n // Initialize Execution Tree\n // If a parent tree is provided (subagent case), share it; otherwise create a new tree\n this.tree = options.parentTree ?? new ExecutionTree();\n this.parentNodeId = options.parentNodeId ?? null;\n this.baseDepth = options.baseDepth ?? 0;\n\n // Store user callback and create combined callback that:\n // 1. Queues events for yielding in run()\n // 2. Calls user callback if provided\n // 3. Fires hooks with subagentContext for consistent event handling\n this.userSubagentEventCallback = options.onSubagentEvent;\n this.onSubagentEvent = (event: SubagentEvent) => {\n this.pendingSubagentEvents.push(event);\n this.userSubagentEventCallback?.(event);\n\n // Fire the SAME hooks with subagentContext - enables consistent hook-based handling\n const subagentContext = {\n parentGadgetInvocationId: event.gadgetInvocationId,\n depth: event.depth,\n };\n\n // Fire hooks asynchronously but don't block\n if (event.type === \"llm_call_start\") {\n const info = event.event as LLMCallInfo;\n void this.hooks?.observers?.onLLMCallStart?.({\n iteration: info.iteration,\n options: { model: info.model, messages: [] },\n logger: this.logger,\n subagentContext,\n });\n } else if (event.type === \"llm_call_end\") {\n const info = event.event as LLMCallInfo;\n // Use full usage object if available (preserves cached tokens), fallback to basic reconstruction\n const usage = info.usage ?? (info.outputTokens\n ? {\n inputTokens: info.inputTokens ?? 0,\n outputTokens: info.outputTokens,\n totalTokens: (info.inputTokens ?? 0) + info.outputTokens,\n }\n : undefined);\n void this.hooks?.observers?.onLLMCallComplete?.({\n iteration: info.iteration,\n options: { model: info.model, messages: [] },\n finishReason: info.finishReason ?? null,\n usage,\n rawResponse: \"\",\n finalMessage: \"\",\n logger: this.logger,\n subagentContext,\n });\n } else if (event.type === \"gadget_call\") {\n const gadgetEvent = event.event as { call: { invocationId: string; gadgetName: string; parameters?: Record<string, unknown> } };\n void this.hooks?.observers?.onGadgetExecutionStart?.({\n iteration: 0,\n gadgetName: gadgetEvent.call.gadgetName,\n invocationId: gadgetEvent.call.invocationId,\n parameters: gadgetEvent.call.parameters ?? {},\n logger: this.logger,\n subagentContext,\n });\n } else if (event.type === \"gadget_result\") {\n const resultEvent = event.event as { result: { invocationId: string; gadgetName?: string; executionTimeMs?: number } };\n void this.hooks?.observers?.onGadgetExecutionComplete?.({\n iteration: 0,\n gadgetName: resultEvent.result.gadgetName ?? \"unknown\",\n invocationId: resultEvent.result.invocationId,\n parameters: {},\n executionTimeMs: resultEvent.result.executionTimeMs ?? 0,\n logger: this.logger,\n subagentContext,\n });\n }\n };\n }\n\n /**\n * Flush pending subagent events as StreamEvents.\n * Called from run() to yield queued subagent events from subagent gadgets.\n */\n private *flushPendingSubagentEvents(): Generator<StreamEvent> {\n while (this.pendingSubagentEvents.length > 0) {\n const event = this.pendingSubagentEvents.shift();\n if (event) {\n yield { type: \"subagent_event\", subagentEvent: event };\n }\n }\n }\n\n /**\n * Get the gadget registry for this agent.\n *\n * Useful for inspecting registered gadgets in tests or advanced use cases.\n *\n * @returns The GadgetRegistry instance\n *\n * @example\n * ```typescript\n * const agent = new AgentBuilder()\n * .withModel(\"sonnet\")\n * .withGadgets(Calculator, Weather)\n * .build();\n *\n * // Inspect registered gadgets\n * console.log(agent.getRegistry().getNames()); // ['Calculator', 'Weather']\n * ```\n */\n getRegistry(): GadgetRegistry {\n return this.registry;\n }\n\n /**\n * Get the media store for this agent session.\n *\n * The media store holds all media outputs (images, audio, etc.) produced by gadgets\n * during this agent's execution. Use this to:\n * - Access stored media files by ID\n * - List all stored media\n * - Clean up temporary files after execution\n *\n * @returns The MediaStore instance for this agent\n *\n * @example\n * ```typescript\n * const agent = new AgentBuilder()\n * .withModel(\"sonnet\")\n * .build();\n *\n * // After execution, access stored media\n * const store = agent.getMediaStore();\n * for (const media of store.list()) {\n * console.log(`${media.id}: ${media.path}`);\n * }\n *\n * // Clean up when done\n * await store.cleanup();\n * ```\n */\n getMediaStore(): MediaStore {\n return this.mediaStore;\n }\n\n /**\n * Get the execution tree for this agent.\n *\n * The execution tree provides a first-class model of all LLM calls and gadget executions,\n * including nested subagent activity. Use this to:\n * - Query execution state: `tree.getNode(id)`\n * - Get total cost: `tree.getTotalCost()`\n * - Get subtree cost/media/tokens: `tree.getSubtreeCost(nodeId)`\n * - Subscribe to events: `tree.on(\"llm_call_complete\", handler)`\n * - Stream all events: `for await (const event of tree.events())`\n *\n * For subagents (created with `withParentContext`), the tree is shared with the parent,\n * enabling unified tracking and real-time visibility across all nesting levels.\n *\n * @returns The ExecutionTree instance\n *\n * @example\n * ```typescript\n * const agent = LLMist.createAgent()\n * .withModel(\"sonnet\")\n * .withGadgets(BrowseWeb)\n * .ask(\"Research topic X\");\n *\n * for await (const event of agent.run()) {\n * // Process events...\n * }\n *\n * // After execution, query the tree\n * const tree = agent.getTree();\n * console.log(`Total cost: $${tree.getTotalCost().toFixed(4)}`);\n *\n * // Inspect all LLM calls\n * for (const node of tree.getAllNodes()) {\n * if (node.type === \"llm_call\") {\n * console.log(`LLM #${node.iteration}: ${node.model}`);\n * }\n * }\n * ```\n */\n getTree(): ExecutionTree {\n return this.tree;\n }\n\n /**\n * Manually trigger context compaction.\n *\n * Forces compaction regardless of threshold. Useful for:\n * - Pre-emptive context management before expected long operations\n * - Testing compaction behavior\n *\n * @returns CompactionEvent if compaction was performed, null if not configured or no history\n *\n * @example\n * ```typescript\n * const agent = await LLMist.createAgent()\n * .withModel('sonnet')\n * .withCompaction()\n * .ask('...');\n *\n * // Manually compact before a long operation\n * const event = await agent.compact();\n * if (event) {\n * console.log(`Saved ${event.tokensBefore - event.tokensAfter} tokens`);\n * }\n * ```\n */\n async compact(): Promise<CompactionEvent | null> {\n if (!this.compactionManager) {\n return null;\n }\n // Use -1 to indicate manual (out-of-band) compaction, not part of the normal iteration cycle\n return this.compactionManager.compact(this.conversation, -1);\n }\n\n /**\n * Get compaction statistics.\n *\n * @returns CompactionStats if compaction is enabled, null otherwise\n *\n * @example\n * ```typescript\n * const stats = agent.getCompactionStats();\n * if (stats) {\n * console.log(`Total compactions: ${stats.totalCompactions}`);\n * console.log(`Tokens saved: ${stats.totalTokensSaved}`);\n * console.log(`Current usage: ${stats.currentUsage.percent.toFixed(1)}%`);\n * }\n * ```\n */\n getCompactionStats(): CompactionStats | null {\n return this.compactionManager?.getStats() ?? null;\n }\n\n /**\n * Run the agent loop.\n * Clean, simple orchestration - all complexity is in StreamProcessor.\n *\n * @throws {Error} If no user prompt was provided (when using build() without ask())\n */\n async *run(): AsyncGenerator<StreamEvent> {\n if (!this.hasUserPrompt) {\n throw new Error(\n \"No user prompt provided. Use .ask(prompt) instead of .build(), or call agent.run() after providing a prompt.\",\n );\n }\n\n let currentIteration = 0;\n\n this.logger.info(\"Starting agent loop\", {\n model: this.model,\n maxIterations: this.maxIterations,\n });\n\n while (currentIteration < this.maxIterations) {\n // Check abort signal at start of each iteration for immediate termination\n if (this.signal?.aborted) {\n this.logger.info(\"Agent loop terminated by abort signal\", {\n iteration: currentIteration,\n reason: this.signal.reason,\n });\n\n // Observer: Notify abort\n await this.safeObserve(async () => {\n if (this.hooks.observers?.onAbort) {\n const context: ObserveAbortContext = {\n iteration: currentIteration,\n reason: this.signal?.reason,\n logger: this.logger,\n };\n await this.hooks.observers.onAbort(context);\n }\n });\n\n return; // Clean exit from generator\n }\n\n this.logger.debug(\"Starting iteration\", { iteration: currentIteration });\n\n try {\n // Check and perform context compaction if needed\n if (this.compactionManager) {\n const compactionEvent = await this.compactionManager.checkAndCompact(\n this.conversation,\n currentIteration,\n );\n if (compactionEvent) {\n this.logger.info(\"Context compacted\", {\n strategy: compactionEvent.strategy,\n tokensBefore: compactionEvent.tokensBefore,\n tokensAfter: compactionEvent.tokensAfter,\n });\n yield { type: \"compaction\", event: compactionEvent } as StreamEvent;\n\n // Observer: Compaction occurred\n await this.safeObserve(async () => {\n if (this.hooks.observers?.onCompaction) {\n await this.hooks.observers.onCompaction({\n iteration: currentIteration,\n event: compactionEvent,\n // biome-ignore lint/style/noNonNullAssertion: compactionManager exists if compactionEvent is truthy\n stats: this.compactionManager!.getStats(),\n logger: this.logger,\n });\n }\n });\n }\n }\n\n // Prepare LLM call options\n let llmOptions: LLMGenerationOptions = {\n model: this.model,\n messages: this.conversation.getMessages(),\n temperature: this.temperature,\n maxTokens: this.defaultMaxTokens,\n signal: this.signal,\n };\n\n // Observer: LLM call start\n await this.safeObserve(async () => {\n if (this.hooks.observers?.onLLMCallStart) {\n const context: ObserveLLMCallContext = {\n iteration: currentIteration,\n options: llmOptions,\n logger: this.logger,\n };\n await this.hooks.observers.onLLMCallStart(context);\n }\n });\n\n // Controller: Before LLM call\n if (this.hooks.controllers?.beforeLLMCall) {\n const context: LLMCallControllerContext = {\n iteration: currentIteration,\n maxIterations: this.maxIterations,\n options: llmOptions,\n logger: this.logger,\n };\n const action: BeforeLLMCallAction = await this.hooks.controllers.beforeLLMCall(context);\n\n // Validate the action\n validateBeforeLLMCallAction(action);\n\n if (action.action === \"skip\") {\n this.logger.info(\"Controller skipped LLM call, using synthetic response\");\n // Add synthetic response to conversation\n this.conversation.addAssistantMessage(action.syntheticResponse);\n // Yield as text event\n yield { type: \"text\", content: action.syntheticResponse };\n break;\n } else if (action.action === \"proceed\" && action.modifiedOptions) {\n llmOptions = { ...llmOptions, ...action.modifiedOptions };\n }\n }\n\n // Observer: LLM call ready (after controller modifications)\n // This is the ideal point for logging the exact request being sent to the LLM\n await this.safeObserve(async () => {\n if (this.hooks.observers?.onLLMCallReady) {\n const context: ObserveLLMCallReadyContext = {\n iteration: currentIteration,\n maxIterations: this.maxIterations,\n options: llmOptions,\n logger: this.logger,\n };\n await this.hooks.observers.onLLMCallReady(context);\n }\n });\n\n // Call LLM\n this.logger.info(\"Calling LLM\", { model: this.model });\n this.logger.silly(\"LLM request details\", {\n model: llmOptions.model,\n temperature: llmOptions.temperature,\n maxTokens: llmOptions.maxTokens,\n messageCount: llmOptions.messages.length,\n messages: llmOptions.messages,\n });\n\n // Add LLM call to execution tree\n const llmNode = this.tree.addLLMCall({\n iteration: currentIteration,\n model: llmOptions.model,\n parentId: this.parentNodeId,\n request: llmOptions.messages,\n });\n const currentLLMNodeId = llmNode.id;\n\n const stream = this.client.stream(llmOptions);\n\n // Process stream - ALL complexity delegated to StreamProcessor\n const processor = new StreamProcessor({\n iteration: currentIteration,\n registry: this.registry,\n gadgetStartPrefix: this.gadgetStartPrefix,\n gadgetEndPrefix: this.gadgetEndPrefix,\n gadgetArgPrefix: this.gadgetArgPrefix,\n hooks: this.hooks,\n logger: this.logger.getSubLogger({ name: \"stream-processor\" }),\n requestHumanInput: this.requestHumanInput,\n defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,\n client: this.client,\n mediaStore: this.mediaStore,\n agentConfig: this.agentContextConfig,\n subagentConfig: this.subagentConfig,\n onSubagentEvent: this.onSubagentEvent,\n // Tree context for execution tracking\n tree: this.tree,\n parentNodeId: currentLLMNodeId, // Gadgets are children of this LLM call\n baseDepth: this.baseDepth,\n });\n\n // Consume the stream processor generator, yielding events in real-time\n // The final event is a StreamCompletionEvent containing metadata\n let streamMetadata: StreamCompletionEvent | null = null;\n let gadgetCallCount = 0;\n\n // Track outputs for conversation history (since we stream instead of batch)\n const textOutputs: string[] = [];\n const gadgetResults: StreamEvent[] = [];\n\n for await (const event of processor.process(stream)) {\n if (event.type === \"stream_complete\") {\n // Completion event - extract metadata, don't yield to consumer\n streamMetadata = event;\n continue;\n }\n\n // Track outputs for later conversation history updates\n if (event.type === \"text\") {\n textOutputs.push(event.content);\n } else if (event.type === \"gadget_result\") {\n gadgetCallCount++;\n gadgetResults.push(event);\n }\n\n // Yield event to consumer in real-time\n yield event;\n\n // Yield any subagent events that accumulated during gadget execution\n // This enables real-time display of subagent activity (Navigate, Screenshot, etc.)\n yield* this.flushPendingSubagentEvents();\n }\n\n // Ensure we received the completion metadata\n if (!streamMetadata) {\n throw new Error(\"Stream processing completed without metadata event\");\n }\n\n // Use streamMetadata as the result for remaining logic\n const result = streamMetadata;\n\n this.logger.info(\"LLM response completed\", {\n finishReason: result.finishReason,\n usage: result.usage,\n didExecuteGadgets: result.didExecuteGadgets,\n });\n this.logger.silly(\"LLM response details\", {\n rawResponse: result.rawResponse,\n });\n\n // Observer: LLM call complete\n await this.safeObserve(async () => {\n if (this.hooks.observers?.onLLMCallComplete) {\n const context: ObserveLLMCompleteContext = {\n iteration: currentIteration,\n options: llmOptions,\n finishReason: result.finishReason,\n usage: result.usage,\n rawResponse: result.rawResponse,\n finalMessage: result.finalMessage,\n logger: this.logger,\n };\n await this.hooks.observers.onLLMCallComplete(context);\n }\n });\n\n // Complete LLM call in execution tree\n this.tree.completeLLMCall(currentLLMNodeId, {\n response: result.rawResponse,\n usage: result.usage,\n finishReason: result.finishReason,\n });\n\n // Controller: After LLM call\n let finalMessage = result.finalMessage;\n if (this.hooks.controllers?.afterLLMCall) {\n // gadgetCallCount was tracked during the streaming loop above\n const context: AfterLLMCallControllerContext = {\n iteration: currentIteration,\n maxIterations: this.maxIterations,\n options: llmOptions,\n finishReason: result.finishReason,\n usage: result.usage,\n finalMessage: result.finalMessage,\n gadgetCallCount,\n logger: this.logger,\n };\n const action: AfterLLMCallAction = await this.hooks.controllers.afterLLMCall(context);\n\n // Validate the action\n validateAfterLLMCallAction(action);\n\n if (action.action === \"modify_and_continue\" || action.action === \"append_and_modify\") {\n finalMessage = action.modifiedMessage;\n }\n\n if (action.action === \"append_messages\" || action.action === \"append_and_modify\") {\n for (const msg of action.messages) {\n if (msg.role === \"user\") {\n this.conversation.addUserMessage(msg.content);\n } else if (msg.role === \"assistant\") {\n // Assistant messages are always text, extract if multimodal\n this.conversation.addAssistantMessage(extractMessageText(msg.content));\n } else if (msg.role === \"system\") {\n // System messages can't be added mid-conversation, treat as user\n this.conversation.addUserMessage(`[System] ${extractMessageText(msg.content)}`);\n }\n }\n }\n }\n\n // Add gadget results to conversation (if any were executed)\n if (result.didExecuteGadgets) {\n // If configured, wrap accompanying text as a synthetic gadget call (before actual gadgets)\n if (this.textWithGadgetsHandler) {\n // Use tracked textOutputs from streaming loop (replaces result.outputs filtering)\n const textContent = textOutputs.join(\"\");\n\n if (textContent.trim()) {\n const { gadgetName, parameterMapping, resultMapping } = this.textWithGadgetsHandler;\n // Generate synthetic invocation ID for wrapped text\n const syntheticId = `gc_text_${++this.syntheticInvocationCounter}`;\n this.conversation.addGadgetCallResult(\n gadgetName,\n parameterMapping(textContent),\n resultMapping ? resultMapping(textContent) : textContent,\n syntheticId,\n );\n }\n }\n\n // Extract and add all gadget results to conversation\n // Use tracked gadgetResults from streaming loop (replaces result.outputs iteration)\n for (const output of gadgetResults) {\n if (output.type === \"gadget_result\") {\n const gadgetResult = output.result;\n this.conversation.addGadgetCallResult(\n gadgetResult.gadgetName,\n gadgetResult.parameters,\n gadgetResult.error ?? gadgetResult.result ?? \"\",\n gadgetResult.invocationId,\n gadgetResult.media,\n gadgetResult.mediaIds,\n );\n }\n }\n } else {\n // No gadgets executed - wrap text as synthetic TellUser result\n // This keeps conversation history consistent (gadget-oriented) and\n // helps LLMs stay in the \"gadget invocation\" mindset\n if (finalMessage.trim()) {\n // Generate synthetic invocation ID for TellUser wrapper\n const syntheticId = `gc_tell_${++this.syntheticInvocationCounter}`;\n this.conversation.addGadgetCallResult(\n \"TellUser\",\n { message: finalMessage, done: false, type: \"info\" },\n `ℹ️ ${finalMessage}`,\n syntheticId,\n );\n }\n // Empty responses: don't add anything, just check if we should continue\n\n // Handle text-only responses\n const shouldBreak = await this.handleTextOnlyResponse(finalMessage);\n if (shouldBreak) {\n break;\n }\n }\n\n // Check if loop should break\n if (result.shouldBreakLoop) {\n this.logger.info(\"Loop terminated by gadget or processor\");\n break;\n }\n } catch (error) {\n // Handle LLM error\n const errorHandled = await this.handleLLMError(error as Error, currentIteration);\n\n // Observer: LLM error\n await this.safeObserve(async () => {\n if (this.hooks.observers?.onLLMCallError) {\n const context: ObserveLLMErrorContext = {\n iteration: currentIteration,\n options: {\n model: this.model,\n messages: this.conversation.getMessages(),\n temperature: this.temperature,\n maxTokens: this.defaultMaxTokens,\n },\n error: error as Error,\n recovered: errorHandled,\n logger: this.logger,\n };\n await this.hooks.observers.onLLMCallError(context);\n }\n });\n\n if (!errorHandled) {\n throw error;\n }\n }\n\n currentIteration++;\n }\n\n this.logger.info(\"Agent loop completed\", {\n totalIterations: currentIteration,\n reason: currentIteration >= this.maxIterations ? \"max_iterations\" : \"natural_completion\",\n });\n }\n\n /**\n * Handle LLM error through controller.\n */\n private async handleLLMError(error: Error, iteration: number): Promise<boolean> {\n this.logger.error(\"LLM call failed\", { error: error.message });\n\n if (this.hooks.controllers?.afterLLMError) {\n const context: LLMErrorControllerContext = {\n iteration,\n options: {\n model: this.model,\n messages: this.conversation.getMessages(),\n temperature: this.temperature,\n maxTokens: this.defaultMaxTokens,\n },\n error,\n logger: this.logger,\n };\n const action: AfterLLMErrorAction = await this.hooks.controllers.afterLLMError(context);\n\n // Validate the action\n validateAfterLLMErrorAction(action);\n\n if (action.action === \"recover\") {\n this.logger.info(\"Controller recovered from LLM error\");\n this.conversation.addAssistantMessage(action.fallbackResponse);\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Handle text-only response (no gadgets called).\n */\n private async handleTextOnlyResponse(_text: string): Promise<boolean> {\n const handler = this.textOnlyHandler;\n\n if (typeof handler === \"string\") {\n switch (handler) {\n case \"terminate\":\n this.logger.info(\"No gadgets called, ending loop\");\n return true;\n case \"acknowledge\":\n this.logger.info(\"No gadgets called, continuing loop\");\n return false;\n case \"wait_for_input\":\n this.logger.info(\"No gadgets called, waiting for input\");\n return true;\n default:\n this.logger.warn(`Unknown text-only strategy: ${handler}, defaulting to terminate`);\n return true;\n }\n }\n\n // For gadget and custom handlers, they would need to be implemented\n // This is simplified for now\n return true;\n }\n\n /**\n * Safely execute an observer, catching and logging any errors.\n */\n private async safeObserve(fn: () => void | Promise<void>): Promise<void> {\n try {\n await fn();\n } catch (error) {\n this.logger.error(\"Observer threw error (ignoring)\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Resolve max tokens from model catalog.\n */\n private resolveMaxTokensFromCatalog(modelId: string): number | undefined {\n const limits = this.client.modelRegistry.getModelLimits(modelId);\n if (limits?.maxOutputTokens !== undefined) {\n return limits.maxOutputTokens;\n }\n\n const separatorIndex = modelId.indexOf(\":\");\n if (separatorIndex === -1) {\n return undefined;\n }\n\n const unprefixedModelId = modelId.slice(separatorIndex + 1).trim();\n if (!unprefixedModelId) {\n return undefined;\n }\n\n return this.client.modelRegistry.getModelLimits(unprefixedModelId)?.maxOutputTokens;\n }\n\n /**\n * Chain the output limiter interceptor with user-provided hooks.\n * The limiter runs first, then chains to any user interceptor.\n */\n private chainOutputLimiterWithUserHooks(userHooks?: AgentHooks): AgentHooks {\n if (!this.outputLimitEnabled) {\n return userHooks ?? {};\n }\n\n const limiterInterceptor = (result: string, ctx: GadgetResultInterceptorContext): string => {\n // Skip limiting for GadgetOutputViewer itself to avoid recursion\n if (ctx.gadgetName === \"GadgetOutputViewer\") {\n return result;\n }\n\n if (result.length > this.outputLimitCharLimit) {\n const id = this.outputStore.store(ctx.gadgetName, result);\n const lines = result.split(\"\\n\").length;\n const bytes = new TextEncoder().encode(result).length;\n\n this.logger.info(\"Gadget output exceeded limit, stored for browsing\", {\n gadgetName: ctx.gadgetName,\n outputId: id,\n bytes,\n lines,\n charLimit: this.outputLimitCharLimit,\n });\n\n return (\n `[Gadget \"${ctx.gadgetName}\" returned too much data: ` +\n `${bytes.toLocaleString()} bytes, ${lines.toLocaleString()} lines. ` +\n `Use GadgetOutputViewer with id \"${id}\" to read it]`\n );\n }\n\n return result;\n };\n\n // Chain with any user-provided interceptor (limiter runs first)\n const userInterceptor = userHooks?.interceptors?.interceptGadgetResult;\n const chainedInterceptor = userInterceptor\n ? (result: string, ctx: GadgetResultInterceptorContext) =>\n userInterceptor(limiterInterceptor(result, ctx), ctx)\n : limiterInterceptor;\n\n return {\n ...userHooks,\n interceptors: {\n ...userHooks?.interceptors,\n interceptGadgetResult: chainedInterceptor,\n },\n };\n }\n\n /**\n * Run agent with named event handlers (syntactic sugar).\n *\n * Instead of verbose if/else chains, use named handlers for cleaner code.\n *\n * @param handlers - Named event handlers\n *\n * @example\n * ```typescript\n * await agent.runWith({\n * onText: (text) => console.log(\"LLM:\", text),\n * onGadgetResult: (result) => console.log(\"Result:\", result.result),\n * onGadgetCall: (call) => console.log(\"Calling:\", call.gadgetName),\n * });\n * ```\n */\n async runWith(handlers: EventHandlers): Promise<void> {\n return runWithHandlers(this.run(), handlers);\n }\n}\n","/**\n * Fluent builder for creating agents with delightful DX.\n *\n * @example\n * ```typescript\n * const agent = await LLMist.createAgent()\n * .withModel(\"sonnet\")\n * .withSystem(\"You are a helpful assistant\")\n * .withGadgets(Calculator, Weather)\n * .withMaxIterations(10)\n * .ask(\"What's the weather in Paris?\");\n *\n * for await (const event of agent.run()) {\n * // process events\n * }\n * ```\n */\n\nimport type { ILogObj, Logger } from \"tslog\";\nimport type { LLMist } from \"../core/client.js\";\nimport { GADGET_ARG_PREFIX, GADGET_END_PREFIX, GADGET_START_PREFIX } from \"../core/constants.js\";\nimport type { ExecutionTree, NodeId } from \"../core/execution-tree.js\";\nimport type { ContentPart, ImageMimeType } from \"../core/input-content.js\";\nimport { detectImageMimeType, text, toBase64 } from \"../core/input-content.js\";\nimport type { MessageContent } from \"../core/messages.js\";\nimport { resolveModel } from \"../core/model-shortcuts.js\";\nimport type { PromptTemplateConfig } from \"../core/prompt-config.js\";\nimport type { GadgetOrClass } from \"../gadgets/registry.js\";\nimport { GadgetRegistry } from \"../gadgets/registry.js\";\nimport type { ExecutionContext, SubagentConfigMap, SubagentEvent, TextOnlyHandler } from \"../gadgets/types.js\";\nimport { Agent, type AgentOptions } from \"./agent.js\";\nimport { AGENT_INTERNAL_KEY } from \"./agent-internal-key.js\";\nimport type { CompactionConfig } from \"./compaction/config.js\";\nimport { collectText, type EventHandlers } from \"./event-handlers.js\";\nimport type { AgentHooks, BeforeLLMCallAction, LLMCallControllerContext } from \"./hooks.js\";\n\n/**\n * Message for conversation history.\n * User messages can be text (string) or multimodal (ContentPart[]).\n */\nexport type HistoryMessage =\n | { user: string | ContentPart[] }\n | { assistant: string }\n | { system: string };\n\n/**\n * Context available to trailing message functions.\n * Provides iteration information for dynamic message generation.\n */\nexport type TrailingMessageContext = Pick<LLMCallControllerContext, \"iteration\" | \"maxIterations\">;\n\n/**\n * Trailing message can be a static string or a function that generates the message.\n * The function receives context about the current iteration.\n */\nexport type TrailingMessage = string | ((ctx: TrailingMessageContext) => string);\n\n/**\n * Fluent builder for creating agents.\n *\n * Provides a chainable API for configuring and creating agents,\n * making the code more expressive and easier to read.\n */\nexport class AgentBuilder {\n private client?: LLMist;\n private model?: string;\n private systemPrompt?: string;\n private temperature?: number;\n private maxIterations?: number;\n private logger?: Logger<ILogObj>;\n private hooks?: AgentHooks;\n private promptConfig?: PromptTemplateConfig;\n private gadgets: GadgetOrClass[] = [];\n private initialMessages: Array<{\n role: \"system\" | \"user\" | \"assistant\";\n content: MessageContent;\n }> = [];\n private requestHumanInput?: (question: string) => Promise<string>;\n private gadgetStartPrefix?: string;\n private gadgetEndPrefix?: string;\n private gadgetArgPrefix?: string;\n private textOnlyHandler?: TextOnlyHandler;\n private textWithGadgetsHandler?: {\n gadgetName: string;\n parameterMapping: (text: string) => Record<string, unknown>;\n resultMapping?: (text: string) => string;\n };\n private defaultGadgetTimeoutMs?: number;\n private gadgetOutputLimit?: boolean;\n private gadgetOutputLimitPercent?: number;\n private compactionConfig?: CompactionConfig;\n private signal?: AbortSignal;\n private trailingMessage?: TrailingMessage;\n private subagentConfig?: SubagentConfigMap;\n private subagentEventCallback?: (event: SubagentEvent) => void;\n // Tree context for subagent support - enables shared tree model\n // When a gadget calls withParentContext(ctx), it shares the parent's tree\n private parentContext?: {\n depth: number;\n tree?: ExecutionTree;\n nodeId?: NodeId;\n };\n\n constructor(client?: LLMist) {\n this.client = client;\n }\n\n /**\n * Set the model to use.\n * Supports aliases like \"gpt4\", \"sonnet\", \"flash\".\n *\n * @param model - Model name or alias\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withModel(\"sonnet\") // Alias\n * .withModel(\"gpt-5-nano\") // Auto-detects provider\n * .withModel(\"openai:gpt-5\") // Explicit provider\n * ```\n */\n withModel(model: string): this {\n this.model = resolveModel(model);\n return this;\n }\n\n /**\n * Set the system prompt.\n *\n * @param prompt - System prompt\n * @returns This builder for chaining\n */\n withSystem(prompt: string): this {\n this.systemPrompt = prompt;\n return this;\n }\n\n /**\n * Set the temperature (0-1).\n *\n * @param temperature - Temperature value\n * @returns This builder for chaining\n */\n withTemperature(temperature: number): this {\n this.temperature = temperature;\n return this;\n }\n\n /**\n * Set maximum iterations.\n *\n * @param max - Maximum number of iterations\n * @returns This builder for chaining\n */\n withMaxIterations(max: number): this {\n this.maxIterations = max;\n return this;\n }\n\n /**\n * Set logger instance.\n *\n * @param logger - Logger instance\n * @returns This builder for chaining\n */\n withLogger(logger: Logger<ILogObj>): this {\n this.logger = logger;\n return this;\n }\n\n /**\n * Add hooks for agent lifecycle events.\n *\n * @param hooks - Agent hooks configuration\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * import { HookPresets } from 'llmist/hooks';\n *\n * .withHooks(HookPresets.logging())\n * .withHooks(HookPresets.merge(\n * HookPresets.logging(),\n * HookPresets.timing()\n * ))\n * ```\n */\n withHooks(hooks: AgentHooks): this {\n this.hooks = hooks;\n return this;\n }\n\n /**\n * Configure custom prompts for gadget system messages.\n *\n * @param config - Prompt configuration object\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withPromptTemplateConfig({\n * mainInstruction: \"Use the gadget markers below:\",\n * rules: [\"Always use markers\", \"Never use function calling\"]\n * })\n * ```\n */\n withPromptTemplateConfig(config: PromptTemplateConfig): this {\n this.promptConfig = config;\n return this;\n }\n\n /**\n * Add gadgets (classes or instances).\n * Can be called multiple times to add more gadgets.\n *\n * @param gadgets - Gadget classes or instances\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withGadgets(Calculator, Weather, Email)\n * .withGadgets(new Calculator(), new Weather())\n * .withGadgets(createGadget({ ... }))\n * ```\n */\n withGadgets(...gadgets: GadgetOrClass[]): this {\n this.gadgets.push(...gadgets);\n return this;\n }\n\n /**\n * Add conversation history messages.\n * Useful for continuing previous conversations.\n *\n * @param messages - Array of history messages\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withHistory([\n * { user: \"Hello\" },\n * { assistant: \"Hi there!\" },\n * { user: \"How are you?\" },\n * { assistant: \"I'm doing well, thanks!\" }\n * ])\n * ```\n */\n withHistory(messages: HistoryMessage[]): this {\n for (const msg of messages) {\n if (\"user\" in msg) {\n this.initialMessages.push({ role: \"user\", content: msg.user });\n } else if (\"assistant\" in msg) {\n this.initialMessages.push({ role: \"assistant\", content: msg.assistant });\n } else if (\"system\" in msg) {\n this.initialMessages.push({ role: \"system\", content: msg.system });\n }\n }\n return this;\n }\n\n /**\n * Add a single message to the conversation history.\n *\n * @param message - Single history message\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .addMessage({ user: \"Hello\" })\n * .addMessage({ assistant: \"Hi there!\" })\n * ```\n */\n addMessage(message: HistoryMessage): this {\n return this.withHistory([message]);\n }\n\n /**\n * Set the human input handler for interactive conversations.\n *\n * @param handler - Function to handle human input requests\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .onHumanInput(async (question) => {\n * return await promptUser(question);\n * })\n * ```\n */\n onHumanInput(handler: (question: string) => Promise<string>): this {\n this.requestHumanInput = handler;\n return this;\n }\n\n /**\n * Set custom gadget marker prefix.\n *\n * @param prefix - Custom start prefix for gadget markers\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withGadgetStartPrefix(\"<<GADGET_START>>\")\n * ```\n */\n withGadgetStartPrefix(prefix: string): this {\n this.gadgetStartPrefix = prefix;\n return this;\n }\n\n /**\n * Set custom gadget marker suffix.\n *\n * @param suffix - Custom end suffix for gadget markers\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withGadgetEndPrefix(\"<<GADGET_END>>\")\n * ```\n */\n withGadgetEndPrefix(suffix: string): this {\n this.gadgetEndPrefix = suffix;\n return this;\n }\n\n /**\n * Set custom argument prefix for block format parameters.\n *\n * @param prefix - Custom prefix for argument markers (default: \"!!!ARG:\")\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withGadgetArgPrefix(\"<<ARG>>\")\n * ```\n */\n withGadgetArgPrefix(prefix: string): this {\n this.gadgetArgPrefix = prefix;\n return this;\n }\n\n /**\n * Set the text-only handler strategy.\n *\n * Controls what happens when the LLM returns text without calling any gadgets:\n * - \"terminate\": End the agent loop (default)\n * - \"acknowledge\": Continue the loop for another iteration\n * - \"wait_for_input\": Wait for human input\n * - Custom handler: Provide a function for dynamic behavior\n *\n * @param handler - Text-only handler strategy or custom handler\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * // Simple strategy\n * .withTextOnlyHandler(\"acknowledge\")\n *\n * // Custom handler\n * .withTextOnlyHandler({\n * type: \"custom\",\n * handler: async (context) => {\n * if (context.text.includes(\"?\")) {\n * return { action: \"wait_for_input\", question: context.text };\n * }\n * return { action: \"continue\" };\n * }\n * })\n * ```\n */\n withTextOnlyHandler(handler: TextOnlyHandler): this {\n this.textOnlyHandler = handler;\n return this;\n }\n\n /**\n * Set the handler for text content that appears alongside gadget calls.\n *\n * When set, text accompanying gadget responses will be wrapped as a\n * synthetic gadget call before the actual gadget results in the\n * conversation history.\n *\n * @param handler - Configuration for wrapping text\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * // Wrap text as TellUser gadget\n * .withTextWithGadgetsHandler({\n * gadgetName: \"TellUser\",\n * parameterMapping: (text) => ({ message: text, done: false, type: \"info\" }),\n * resultMapping: (text) => `ℹ️ ${text}`,\n * })\n * ```\n */\n withTextWithGadgetsHandler(handler: {\n gadgetName: string;\n parameterMapping: (text: string) => Record<string, unknown>;\n resultMapping?: (text: string) => string;\n }): this {\n this.textWithGadgetsHandler = handler;\n return this;\n }\n\n /**\n * Set default timeout for gadget execution.\n *\n * @param timeoutMs - Timeout in milliseconds (must be non-negative)\n * @returns This builder for chaining\n * @throws {Error} If timeout is negative\n *\n * @example\n * ```typescript\n * .withDefaultGadgetTimeout(5000) // 5 second timeout\n * ```\n */\n withDefaultGadgetTimeout(timeoutMs: number): this {\n if (timeoutMs < 0) {\n throw new Error(\"Timeout must be a non-negative number\");\n }\n this.defaultGadgetTimeoutMs = timeoutMs;\n return this;\n }\n\n /**\n * Enable or disable gadget output limiting.\n *\n * When enabled, gadget outputs exceeding the configured limit are stored\n * and can be browsed using the GadgetOutputViewer gadget.\n *\n * @param enabled - Whether to enable output limiting (default: true)\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withGadgetOutputLimit(false) // Disable output limiting\n * ```\n */\n withGadgetOutputLimit(enabled: boolean): this {\n this.gadgetOutputLimit = enabled;\n return this;\n }\n\n /**\n * Set the maximum gadget output as a percentage of the model's context window.\n *\n * Outputs exceeding this limit are stored for later browsing with GadgetOutputViewer.\n *\n * @param percent - Percentage of context window (1-100, default: 15)\n * @returns This builder for chaining\n * @throws {Error} If percent is not between 1 and 100\n *\n * @example\n * ```typescript\n * .withGadgetOutputLimitPercent(25) // 25% of context window\n * ```\n */\n withGadgetOutputLimitPercent(percent: number): this {\n if (percent < 1 || percent > 100) {\n throw new Error(\"Output limit percent must be between 1 and 100\");\n }\n this.gadgetOutputLimitPercent = percent;\n return this;\n }\n\n /**\n * Configure context compaction.\n *\n * Context compaction automatically manages conversation history to prevent\n * context window overflow in long-running agent conversations.\n *\n * @param config - Compaction configuration options\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * // Custom thresholds\n * .withCompaction({\n * triggerThresholdPercent: 70,\n * targetPercent: 40,\n * preserveRecentTurns: 10,\n * })\n *\n * // Different strategy\n * .withCompaction({\n * strategy: 'sliding-window',\n * })\n *\n * // With callback\n * .withCompaction({\n * onCompaction: (event) => {\n * console.log(`Saved ${event.tokensBefore - event.tokensAfter} tokens`);\n * }\n * })\n * ```\n */\n withCompaction(config: CompactionConfig): this {\n this.compactionConfig = { ...config, enabled: config.enabled ?? true };\n return this;\n }\n\n /**\n * Disable context compaction.\n *\n * By default, compaction is enabled. Use this method to explicitly disable it.\n *\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withoutCompaction() // Disable automatic compaction\n * ```\n */\n withoutCompaction(): this {\n this.compactionConfig = { enabled: false };\n return this;\n }\n\n /**\n * Set an abort signal for cancelling requests mid-flight.\n *\n * When the signal is aborted, the current LLM request will be cancelled\n * and the agent loop will exit gracefully.\n *\n * @param signal - AbortSignal from an AbortController\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * const controller = new AbortController();\n *\n * // Cancel after 30 seconds\n * setTimeout(() => controller.abort(), 30000);\n *\n * const agent = LLMist.createAgent()\n * .withModel(\"sonnet\")\n * .withSignal(controller.signal)\n * .ask(\"Write a long story\");\n *\n * // Or cancel on user action\n * document.getElementById(\"cancel\").onclick = () => controller.abort();\n * ```\n */\n withSignal(signal: AbortSignal): this {\n this.signal = signal;\n return this;\n }\n\n /**\n * Set subagent configuration overrides.\n *\n * Subagent gadgets (like BrowseWeb) can read these settings from ExecutionContext\n * to inherit model and other options from the CLI configuration.\n *\n * @param config - Subagent configuration map keyed by gadget name\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withSubagentConfig({\n * BrowseWeb: { model: \"inherit\", maxIterations: 20, headless: true },\n * CodeAnalyzer: { model: \"sonnet\", maxIterations: 10 }\n * })\n * ```\n */\n withSubagentConfig(config: SubagentConfigMap): this {\n this.subagentConfig = config;\n return this;\n }\n\n /**\n * Set the callback for subagent events.\n *\n * Subagent gadgets (like BrowseWeb) can use ExecutionContext.onSubagentEvent\n * to report their internal LLM calls and gadget executions in real-time.\n * This callback receives those events, enabling hierarchical progress display.\n *\n * @param callback - Function to handle subagent events\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withSubagentEventCallback((event) => {\n * if (event.type === \"llm_call_start\") {\n * console.log(` Subagent LLM #${event.event.iteration} starting...`);\n * } else if (event.type === \"gadget_call\") {\n * console.log(` ⏵ ${event.event.call.gadgetName}...`);\n * }\n * })\n * ```\n */\n withSubagentEventCallback(callback: (event: SubagentEvent) => void): this {\n this.subagentEventCallback = callback;\n return this;\n }\n\n /**\n * Enable automatic subagent event forwarding to parent agent.\n *\n * When building a subagent inside a gadget, call this method to automatically\n * forward all LLM calls and gadget events to the parent agent. This enables\n * hierarchical progress display without any manual event handling.\n *\n * The method extracts `invocationId` and `onSubagentEvent` from the execution\n * context and sets up automatic forwarding via hooks and event wrapping.\n *\n * **NEW: Shared Tree Model** - When the parent provides an ExecutionTree via context,\n * the subagent shares that tree instead of creating its own. This enables:\n * - Unified cost tracking across all nesting levels\n * - Automatic media aggregation via `tree.getSubtreeMedia(nodeId)`\n * - Real-time visibility of nested execution in the parent\n *\n * **Signal Forwarding** - When parent context includes a signal, it's automatically\n * forwarded to the subagent for proper cancellation propagation.\n *\n * @param ctx - ExecutionContext passed to the gadget's execute() method\n * @param depth - Nesting depth (default: 1 for direct child)\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * // In a subagent gadget like BrowseWeb - ONE LINE enables auto-forwarding:\n * execute: async (params, ctx) => {\n * const agent = new AgentBuilder(client)\n * .withModel(model)\n * .withGadgets(Navigate, Click, Screenshot)\n * .withParentContext(ctx) // <-- This is all you need!\n * .ask(params.task);\n *\n * for await (const event of agent.run()) {\n * // Events automatically forwarded - just process normally\n * if (event.type === \"text\") {\n * result = event.content;\n * }\n * }\n *\n * // After subagent completes, costs are automatically aggregated\n * // No manual tracking needed - use tree methods:\n * const totalCost = ctx.tree?.getSubtreeCost(ctx.nodeId!);\n * const allMedia = ctx.tree?.getSubtreeMedia(ctx.nodeId!);\n * }\n * ```\n */\n withParentContext(ctx: ExecutionContext, depth = 1): this {\n // Capture tree context for shared tree model\n // This enables subagent events to flow through the parent's tree,\n // giving the TUI (and any tree subscribers) visibility into nested activity\n if (ctx.tree) {\n this.parentContext = {\n tree: ctx.tree,\n nodeId: ctx.nodeId,\n depth,\n };\n }\n\n // Auto-forward abort signal from parent for proper cancellation propagation\n if (ctx.signal && !this.signal) {\n this.signal = ctx.signal;\n }\n\n return this;\n }\n\n /**\n * Add an ephemeral trailing message that appears at the end of each LLM request.\n *\n * The message is NOT persisted to conversation history - it only appears in the\n * current LLM call. This is useful for injecting context-specific instructions\n * or reminders without polluting the conversation history.\n *\n * @param message - Static string or function that generates the message\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * // Static message\n * .withTrailingMessage(\"Always respond in JSON format.\")\n *\n * // Dynamic message based on iteration\n * .withTrailingMessage((ctx) =>\n * `[Iteration ${ctx.iteration}/${ctx.maxIterations}] Stay focused on the task.`\n * )\n * ```\n */\n withTrailingMessage(message: TrailingMessage): this {\n this.trailingMessage = message;\n return this;\n }\n\n /**\n * Add a synthetic gadget call to the conversation history.\n *\n * This is useful for in-context learning - showing the LLM what \"past self\"\n * did correctly so it mimics the pattern. The call is formatted with proper\n * markers and parameter format, including the invocation ID so the LLM can\n * reference previous calls when building dependencies.\n *\n * @param gadgetName - Name of the gadget\n * @param parameters - Parameters passed to the gadget\n * @param result - Result returned by the gadget\n * @param invocationId - Invocation ID (shown to LLM so it can reference for dependencies)\n * @returns This builder for chaining\n *\n * @example\n * ```typescript\n * .withSyntheticGadgetCall(\n * 'TellUser',\n * {\n * message: '👋 Hello!\\n\\nHere\\'s what I can do:\\n- Analyze code\\n- Run commands',\n * done: false,\n * type: 'info'\n * },\n * 'ℹ️ 👋 Hello!\\n\\nHere\\'s what I can do:\\n- Analyze code\\n- Run commands',\n * 'gc_1'\n * )\n * ```\n */\n withSyntheticGadgetCall(\n gadgetName: string,\n parameters: Record<string, unknown>,\n result: string,\n invocationId: string,\n ): this {\n const startPrefix = this.gadgetStartPrefix ?? GADGET_START_PREFIX;\n const endPrefix = this.gadgetEndPrefix ?? GADGET_END_PREFIX;\n\n const paramStr = this.formatBlockParameters(parameters, \"\");\n\n // Assistant message with gadget call (including invocation ID)\n this.initialMessages.push({\n role: \"assistant\",\n content: `${startPrefix}${gadgetName}:${invocationId}\\n${paramStr}\\n${endPrefix}`,\n });\n\n // User message with result (including invocation ID so LLM can reference it)\n this.initialMessages.push({\n role: \"user\",\n content: `Result (${invocationId}): ${result}`,\n });\n\n return this;\n }\n\n /**\n * Compose the final hooks, including trailing message injection if configured.\n *\n * Note: Subagent event visibility is now handled entirely by the ExecutionTree.\n * When a subagent uses withParentContext(ctx), it shares the parent's tree,\n * and all events are automatically visible to tree subscribers (like the TUI).\n */\n private composeHooks(): AgentHooks | undefined {\n const hooks = this.hooks;\n\n // Handle trailing message injection\n if (!this.trailingMessage) {\n return hooks;\n }\n\n const trailingMsg = this.trailingMessage;\n const existingBeforeLLMCall = hooks?.controllers?.beforeLLMCall;\n\n const trailingMessageController = async (\n ctx: LLMCallControllerContext,\n ): Promise<BeforeLLMCallAction> => {\n // Run existing beforeLLMCall first if present\n const result: BeforeLLMCallAction = existingBeforeLLMCall\n ? await existingBeforeLLMCall(ctx)\n : { action: \"proceed\" };\n\n // If action is \"skip\", don't inject trailing message\n if (result.action === \"skip\") {\n return result;\n }\n\n // Get messages (possibly already modified by existing controller)\n const messages = [...(result.modifiedOptions?.messages || ctx.options.messages)];\n\n // Generate trailing message content\n const content =\n typeof trailingMsg === \"function\"\n ? trailingMsg({ iteration: ctx.iteration, maxIterations: ctx.maxIterations })\n : trailingMsg;\n\n // Append as ephemeral user message\n messages.push({ role: \"user\", content });\n\n return {\n action: \"proceed\",\n modifiedOptions: { ...result.modifiedOptions, messages },\n };\n };\n\n return {\n ...hooks,\n controllers: {\n ...hooks?.controllers,\n beforeLLMCall: trailingMessageController,\n },\n };\n }\n\n /**\n * Format parameters as block format with JSON Pointer paths.\n */\n private formatBlockParameters(params: Record<string, unknown>, prefix: string): string {\n const lines: string[] = [];\n const argPrefix = this.gadgetArgPrefix ?? GADGET_ARG_PREFIX;\n\n for (const [key, value] of Object.entries(params)) {\n const fullPath = prefix ? `${prefix}/${key}` : key;\n\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n const itemPath = `${fullPath}/${index}`;\n if (typeof item === \"object\" && item !== null) {\n lines.push(this.formatBlockParameters(item as Record<string, unknown>, itemPath));\n } else {\n lines.push(`${argPrefix}${itemPath}`);\n lines.push(String(item));\n }\n });\n } else if (typeof value === \"object\" && value !== null) {\n lines.push(this.formatBlockParameters(value as Record<string, unknown>, fullPath));\n } else {\n lines.push(`${argPrefix}${fullPath}`);\n lines.push(String(value));\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n /**\n * Build and create the agent with the given user prompt.\n * Returns the Agent instance ready to run.\n *\n * @param userPrompt - User's question or request\n * @returns Configured Agent instance\n *\n * @example\n * ```typescript\n * const agent = await LLMist.createAgent()\n * .withModel(\"sonnet\")\n * .withGadgets(Calculator)\n * .ask(\"What is 2+2?\");\n *\n * for await (const event of agent.run()) {\n * // handle events\n * }\n * ```\n */\n /**\n * Build AgentOptions with the given user prompt.\n * Centralizes options construction for ask(), askWithImage(), and askWithContent().\n */\n private buildAgentOptions(userPrompt: string | ContentPart[]): AgentOptions {\n // Lazy import to avoid circular dependency\n if (!this.client) {\n const { LLMist: LLMistClass } =\n require(\"../core/client.js\") as typeof import(\"../core/client.js\");\n this.client = new LLMistClass();\n }\n\n const registry = GadgetRegistry.from(this.gadgets);\n\n return {\n client: this.client,\n model: this.model ?? \"openai:gpt-5-nano\",\n systemPrompt: this.systemPrompt,\n userPrompt,\n registry,\n maxIterations: this.maxIterations,\n temperature: this.temperature,\n logger: this.logger,\n hooks: this.composeHooks(),\n promptConfig: this.promptConfig,\n initialMessages: this.initialMessages,\n requestHumanInput: this.requestHumanInput,\n gadgetStartPrefix: this.gadgetStartPrefix,\n gadgetEndPrefix: this.gadgetEndPrefix,\n gadgetArgPrefix: this.gadgetArgPrefix,\n textOnlyHandler: this.textOnlyHandler,\n textWithGadgetsHandler: this.textWithGadgetsHandler,\n defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,\n gadgetOutputLimit: this.gadgetOutputLimit,\n gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,\n compactionConfig: this.compactionConfig,\n signal: this.signal,\n subagentConfig: this.subagentConfig,\n onSubagentEvent: this.subagentEventCallback,\n // Tree context for shared tree model (subagents share parent's tree)\n parentTree: this.parentContext?.tree,\n parentNodeId: this.parentContext?.nodeId,\n baseDepth: this.parentContext ? (this.parentContext.depth ?? 0) + 1 : 0,\n };\n }\n\n ask(userPrompt: string): Agent {\n const options = this.buildAgentOptions(userPrompt);\n return new Agent(AGENT_INTERNAL_KEY, options);\n }\n\n /**\n * Build and create the agent with a multimodal user prompt (text + image).\n * Returns the Agent instance ready to run.\n *\n * @param textPrompt - Text prompt describing what to do with the image\n * @param imageData - Image data (Buffer, Uint8Array, or base64 string)\n * @param mimeType - Optional MIME type (auto-detected if not provided)\n * @returns Configured Agent instance\n *\n * @example\n * ```typescript\n * const agent = LLMist.createAgent()\n * .withModel(\"gpt-4o\")\n * .withSystem(\"You analyze images\")\n * .askWithImage(\n * \"What's in this image?\",\n * await fs.readFile(\"photo.jpg\")\n * );\n *\n * for await (const event of agent.run()) {\n * // handle events\n * }\n * ```\n */\n askWithImage(\n textPrompt: string,\n imageData: Buffer | Uint8Array | string,\n mimeType?: ImageMimeType,\n ): Agent {\n const imageBuffer =\n typeof imageData === \"string\" ? Buffer.from(imageData, \"base64\") : imageData;\n const detectedMime = mimeType ?? detectImageMimeType(imageBuffer);\n\n if (!detectedMime) {\n throw new Error(\n \"Could not detect image MIME type. Please provide the mimeType parameter explicitly.\",\n );\n }\n\n // Build multimodal content\n const userContent: ContentPart[] = [\n text(textPrompt),\n {\n type: \"image\",\n source: {\n type: \"base64\",\n mediaType: detectedMime,\n data: toBase64(imageBuffer),\n },\n },\n ];\n\n const options = this.buildAgentOptions(userContent);\n return new Agent(AGENT_INTERNAL_KEY, options);\n }\n\n /**\n * Build and return an Agent configured with multimodal content.\n * More flexible than askWithImage - accepts any combination of content parts.\n *\n * @param content - Array of content parts (text, images, audio)\n * @returns A configured Agent ready for execution\n *\n * @example\n * ```typescript\n * import { text, imageFromBuffer, audioFromBuffer } from \"llmist\";\n *\n * const agent = LLMist.createAgent()\n * .withModel(\"gemini:gemini-2.5-flash\")\n * .askWithContent([\n * text(\"Describe this image and transcribe the audio:\"),\n * imageFromBuffer(imageData),\n * audioFromBuffer(audioData),\n * ]);\n *\n * for await (const event of agent.run()) {\n * // handle events\n * }\n * ```\n */\n askWithContent(content: ContentPart[]): Agent {\n const options = this.buildAgentOptions(content);\n return new Agent(AGENT_INTERNAL_KEY, options);\n }\n\n /**\n * Build, run, and collect only the text response.\n * Convenient for simple queries where you just want the final answer.\n *\n * @param userPrompt - User's question or request\n * @returns Promise resolving to the complete text response\n *\n * @example\n * ```typescript\n * const answer = await LLMist.createAgent()\n * .withModel(\"gpt4-mini\")\n * .withGadgets(Calculator)\n * .askAndCollect(\"What is 42 * 7?\");\n *\n * console.log(answer); // \"294\"\n * ```\n */\n async askAndCollect(userPrompt: string): Promise<string> {\n const agent = this.ask(userPrompt);\n return collectText(agent.run());\n }\n\n /**\n * Build and run with event handlers.\n * Combines agent creation and event handling in one call.\n *\n * @param userPrompt - User's question or request\n * @param handlers - Event handlers\n *\n * @example\n * ```typescript\n * await LLMist.createAgent()\n * .withModel(\"sonnet\")\n * .withGadgets(Calculator)\n * .askWith(\"What is 2+2?\", {\n * onText: (text) => console.log(\"LLM:\", text),\n * onGadgetResult: (result) => console.log(\"Result:\", result.result),\n * });\n * ```\n */\n async askWith(userPrompt: string, handlers: EventHandlers): Promise<void> {\n const agent = this.ask(userPrompt);\n await agent.runWith(handlers);\n }\n\n /**\n * Build the agent without a user prompt.\n *\n * Returns an Agent instance that can be inspected (e.g., check registered gadgets)\n * but cannot be run without first calling .ask(prompt).\n *\n * This is useful for:\n * - Testing: Inspect the registry, configuration, etc.\n * - Advanced use cases: Build agent configuration separately from execution\n *\n * @returns Configured Agent instance (without user prompt)\n *\n * @example\n * ```typescript\n * // Build agent for inspection\n * const agent = new AgentBuilder()\n * .withModel(\"sonnet\")\n * .withGadgets(Calculator, Weather)\n * .build();\n *\n * // Inspect registered gadgets\n * console.log(agent.getRegistry().getNames()); // ['Calculator', 'Weather']\n *\n * // Note: Calling agent.run() will throw an error\n * // Use .ask(prompt) instead if you want to run the agent\n * ```\n */\n build(): Agent {\n // Lazy import to avoid circular dependency\n if (!this.client) {\n const { LLMist: LLMistClass } =\n require(\"../core/client.js\") as typeof import(\"../core/client.js\");\n this.client = new LLMistClass();\n }\n const registry = GadgetRegistry.from(this.gadgets);\n\n const options: AgentOptions = {\n client: this.client,\n model: this.model ?? \"openai:gpt-5-nano\",\n systemPrompt: this.systemPrompt,\n // No userPrompt - agent.run() will throw if called directly\n registry,\n maxIterations: this.maxIterations,\n temperature: this.temperature,\n logger: this.logger,\n hooks: this.composeHooks(),\n promptConfig: this.promptConfig,\n initialMessages: this.initialMessages,\n requestHumanInput: this.requestHumanInput,\n gadgetStartPrefix: this.gadgetStartPrefix,\n gadgetEndPrefix: this.gadgetEndPrefix,\n gadgetArgPrefix: this.gadgetArgPrefix,\n textOnlyHandler: this.textOnlyHandler,\n textWithGadgetsHandler: this.textWithGadgetsHandler,\n defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,\n gadgetOutputLimit: this.gadgetOutputLimit,\n gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,\n compactionConfig: this.compactionConfig,\n signal: this.signal,\n subagentConfig: this.subagentConfig,\n onSubagentEvent: this.subagentEventCallback,\n // Tree context for shared tree model (subagents share parent's tree)\n parentTree: this.parentContext?.tree,\n parentNodeId: this.parentContext?.nodeId,\n baseDepth: this.parentContext ? (this.parentContext.depth ?? 0) + 1 : 0,\n };\n\n return new Agent(AGENT_INTERNAL_KEY, options);\n }\n}\n","/** CLI program name */\nexport const CLI_NAME = \"llmist\";\n\n/** CLI program description shown in --help */\nexport const CLI_DESCRIPTION = \"Command line utilities for llmist agents and direct LLM access.\";\n\n/** Available CLI commands */\nexport const COMMANDS = {\n complete: \"complete\",\n agent: \"agent\",\n models: \"models\",\n gadget: \"gadget\",\n image: \"image\",\n speech: \"speech\",\n vision: \"vision\",\n init: \"init\",\n} as const;\n\n/** Valid log level names */\nexport const LOG_LEVELS = [\"silly\", \"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\"] as const;\nexport type CLILogLevel = (typeof LOG_LEVELS)[number];\n\n/** Default model used when --model is not specified */\nexport const DEFAULT_MODEL = \"openai:gpt-5-nano\";\n\n/** Command-line option flags */\nexport const OPTION_FLAGS = {\n model: \"-m, --model <identifier>\",\n systemPrompt: \"-s, --system <prompt>\",\n temperature: \"-t, --temperature <value>\",\n maxTokens: \"--max-tokens <count>\",\n maxIterations: \"-i, --max-iterations <count>\",\n gadgetModule: \"-g, --gadget <module>\",\n logLevel: \"--log-level <level>\",\n logFile: \"--log-file <path>\",\n logReset: \"--log-reset\",\n logLlmRequests: \"--log-llm-requests [dir]\",\n noBuiltins: \"--no-builtins\",\n noBuiltinInteraction: \"--no-builtin-interaction\",\n quiet: \"-q, --quiet\",\n docker: \"--docker\",\n dockerRo: \"--docker-ro\",\n noDocker: \"--no-docker\",\n // Multimodal input options\n inputImage: \"--image <path>\",\n inputAudio: \"--audio <path>\",\n // Image generation options\n imageSize: \"--size <size>\",\n imageQuality: \"--quality <quality>\",\n imageCount: \"-n, --count <number>\",\n imageOutput: \"-o, --output <path>\",\n // Speech generation options\n voice: \"--voice <name>\",\n speechFormat: \"--format <format>\",\n speechSpeed: \"--speed <value>\",\n speechOutput: \"-o, --output <path>\",\n} as const;\n\n/** Human-readable descriptions for command-line options */\nexport const OPTION_DESCRIPTIONS = {\n model: \"Model identifier, e.g. openai:gpt-5-nano or anthropic:claude-sonnet-4-5.\",\n systemPrompt: \"Optional system prompt prepended to the conversation.\",\n temperature: \"Sampling temperature between 0 and 2.\",\n maxTokens: \"Maximum number of output tokens requested from the model.\",\n maxIterations: \"Maximum number of agent loop iterations before exiting.\",\n gadgetModule:\n \"Path or module specifier for a gadget export. Repeat to register multiple gadgets.\",\n logLevel: \"Log level: silly, trace, debug, info, warn, error, fatal.\",\n logFile: \"Path to log file. When set, logs are written to file instead of stderr.\",\n logReset: \"Reset (truncate) the log file at session start instead of appending.\",\n logLlmRequests:\n \"Save LLM requests/responses to session directories. Optional dir, defaults to ~/.llmist/logs/requests/\",\n noBuiltins: \"Disable built-in gadgets (AskUser, TellUser).\",\n noBuiltinInteraction: \"Disable interactive gadgets (AskUser) while keeping TellUser.\",\n quiet: \"Suppress all output except content (text and TellUser messages).\",\n // Multimodal input descriptions\n inputImage: \"Image file to include with the prompt (vision models).\",\n inputAudio: \"Audio file to include with the prompt (Gemini only).\",\n docker: \"Run agent in a Docker sandbox container for security isolation.\",\n dockerRo: \"Run in Docker with current directory mounted read-only.\",\n noDocker: \"Disable Docker sandboxing (override config).\",\n // Image generation descriptions\n imageSize: \"Image size/aspect ratio, e.g. '1024x1024', '1:1', '16:9'.\",\n imageQuality: \"Image quality: 'standard', 'hd', 'low', 'medium', 'high'.\",\n imageCount: \"Number of images to generate (model dependent, usually 1-4).\",\n imageOutput: \"Output path for the generated image. Defaults to stdout if not specified.\",\n // Speech generation descriptions\n voice: \"Voice name for speech generation, e.g. 'nova', 'alloy', 'Zephyr'.\",\n speechFormat: \"Audio format: 'mp3', 'opus', 'aac', 'flac', 'wav', 'pcm'.\",\n speechSpeed: \"Speech speed multiplier (0.25 to 4.0, default 1.0).\",\n speechOutput: \"Output path for audio file. Defaults to stdout if not specified.\",\n} as const;\n\n/** Prefix for summary output written to stderr */\nexport const SUMMARY_PREFIX = \"[llmist]\";\n","import { Command, InvalidArgumentError } from \"commander\";\n\nimport packageJson from \"../../package.json\";\n\nimport { registerAgentCommand } from \"./agent-command.js\";\nimport { registerCompleteCommand } from \"./complete-command.js\";\nimport { registerInitCommand } from \"./init-command.js\";\nimport {\n type CLIConfig,\n type CustomCommandConfig,\n getCustomCommandNames,\n loadConfig,\n} from \"./config.js\";\nimport {\n CLI_DESCRIPTION,\n CLI_NAME,\n LOG_LEVELS,\n type CLILogLevel,\n OPTION_DESCRIPTIONS,\n OPTION_FLAGS,\n} from \"./constants.js\";\nimport { registerCustomCommand } from \"./custom-command.js\";\nimport type { CLIEnvironment, CLILoggerConfig } from \"./environment.js\";\nimport { createDefaultEnvironment } from \"./environment.js\";\nimport { registerGadgetCommand } from \"./gadget-command.js\";\nimport { registerImageCommand } from \"./image-command.js\";\nimport { registerModelsCommand } from \"./models-command.js\";\nimport { registerSpeechCommand } from \"./speech-command.js\";\nimport { registerVisionCommand } from \"./vision-command.js\";\n\n/**\n * Parses and validates the log level option value.\n */\nfunction parseLogLevel(value: string): CLILogLevel {\n const normalized = value.toLowerCase() as CLILogLevel;\n if (!LOG_LEVELS.includes(normalized)) {\n throw new InvalidArgumentError(`Log level must be one of: ${LOG_LEVELS.join(\", \")}`);\n }\n return normalized;\n}\n\n/**\n * Global CLI options that apply to all commands.\n */\ninterface GlobalOptions {\n logLevel?: CLILogLevel;\n logFile?: string;\n logReset?: boolean;\n}\n\n/**\n * Creates and configures the CLI program with complete and agent commands.\n *\n * @param env - CLI environment configuration for I/O and dependencies\n * @param config - Optional CLI configuration loaded from config file\n * @returns Configured Commander program ready for parsing\n */\nexport function createProgram(env: CLIEnvironment, config?: CLIConfig): Command {\n const program = new Command();\n\n program\n .name(CLI_NAME)\n .description(CLI_DESCRIPTION)\n .version(packageJson.version)\n .option(OPTION_FLAGS.logLevel, OPTION_DESCRIPTIONS.logLevel, parseLogLevel)\n .option(OPTION_FLAGS.logFile, OPTION_DESCRIPTIONS.logFile)\n .option(OPTION_FLAGS.logReset, OPTION_DESCRIPTIONS.logReset)\n .configureOutput({\n writeOut: (str) => env.stdout.write(str),\n writeErr: (str) => env.stderr.write(str),\n });\n\n // Register built-in commands with config defaults\n registerCompleteCommand(program, env, config?.complete);\n registerAgentCommand(program, env, config?.agent, config?.subagents);\n registerImageCommand(program, env, config?.image);\n registerSpeechCommand(program, env, config?.speech);\n registerVisionCommand(program, env);\n registerModelsCommand(program, env);\n registerGadgetCommand(program, env);\n registerInitCommand(program, env);\n\n // Register custom commands from config\n if (config) {\n const customNames = getCustomCommandNames(config);\n for (const name of customNames) {\n const cmdConfig = config[name] as CustomCommandConfig;\n registerCustomCommand(program, name, cmdConfig, env, config.subagents);\n }\n }\n\n return program;\n}\n\n/**\n * Options for runCLI function.\n */\nexport interface RunCLIOptions {\n /** Environment overrides for testing or customization */\n env?: Partial<CLIEnvironment>;\n /** Config override - if provided, skips loading from file. Use {} to disable config. */\n config?: CLIConfig;\n}\n\n/**\n * Main entry point for running the CLI.\n * Creates environment, parses arguments, and executes the appropriate command.\n *\n * @param overrides - Optional environment overrides or options object\n */\nexport async function runCLI(\n overrides: Partial<CLIEnvironment> | RunCLIOptions = {},\n): Promise<void> {\n // Handle both old signature (Partial<CLIEnvironment>) and new signature (RunCLIOptions)\n const opts: RunCLIOptions =\n \"env\" in overrides || \"config\" in overrides\n ? (overrides as RunCLIOptions)\n : { env: overrides as Partial<CLIEnvironment> };\n\n // Load config early (before program creation) - errors here should fail fast\n // If config is provided in options, use it instead of loading from file\n const config = opts.config !== undefined ? opts.config : loadConfig();\n const envOverrides = opts.env ?? {};\n\n // First pass: parse global options only (skip if help requested)\n const preParser = new Command();\n preParser\n .option(OPTION_FLAGS.logLevel, OPTION_DESCRIPTIONS.logLevel, parseLogLevel)\n .option(OPTION_FLAGS.logFile, OPTION_DESCRIPTIONS.logFile)\n .option(OPTION_FLAGS.logReset, OPTION_DESCRIPTIONS.logReset)\n .allowUnknownOption()\n .allowExcessArguments()\n .helpOption(false); // Don't intercept --help\n\n preParser.parse(process.argv);\n const globalOpts = preParser.opts<GlobalOptions>();\n\n // Create environment with logger config from global options\n // Priority: CLI flags > config file > defaults\n const loggerConfig: CLILoggerConfig = {\n logLevel: globalOpts.logLevel ?? config.global?.[\"log-level\"],\n logFile: globalOpts.logFile ?? config.global?.[\"log-file\"],\n logReset: globalOpts.logReset ?? config.global?.[\"log-reset\"],\n };\n\n const defaultEnv = createDefaultEnvironment(loggerConfig);\n const env: CLIEnvironment = {\n ...defaultEnv,\n ...envOverrides,\n // Pass Docker config from [docker] section\n dockerConfig: config.docker,\n };\n const program = createProgram(env, config);\n await program.parseAsync(env.argv);\n}\n","{\n \"name\": \"llmist\",\n \"version\": \"6.0.0\",\n \"description\": \"TypeScript LLM client with streaming tool execution. Tools fire mid-stream. Built-in function calling works with any model—no structured outputs or native tool support required.\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"module\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n },\n \"require\": {\n \"types\": \"./dist/index.d.cts\",\n \"default\": \"./dist/index.cjs\"\n }\n },\n \"./testing\": {\n \"import\": {\n \"types\": \"./dist/testing/index.d.ts\",\n \"default\": \"./dist/testing/index.js\"\n },\n \"require\": {\n \"types\": \"./dist/testing/index.d.cts\",\n \"default\": \"./dist/testing/index.cjs\"\n }\n }\n },\n \"scripts\": {\n \"cli\": \"bun run scripts/cli-runner.ts\",\n \"build\": \"tsup\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"biome lint .\",\n \"format\": \"biome format --write .\",\n \"check\": \"biome check --write .\",\n \"test\": \"bun test\",\n \"test:unit\": \"bun test src/agent src/core src/gadgets src/providers src/testing\",\n \"test:watch\": \"bun test --watch\",\n \"test:e2e\": \"bun test src/e2e --timeout 60000 --bail 1\",\n \"test:e2e:watch\": \"bun test src/e2e --watch --timeout 60000\",\n \"test:all\": \"bun run test && bun run test:e2e\",\n \"clean\": \"rimraf dist\",\n \"prepare\": \"node scripts/install-hooks.js || true\",\n \"release:dry\": \"bunx semantic-release --dry-run\",\n \"release:publish\": \"test \\\"$(git branch --show-current)\\\" = \\\"main\\\" && git pull origin main && bun run build && npm publish\"\n },\n \"bin\": {\n \"llmist\": \"dist/cli.js\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/zbigniewsobiecki/llmist.git\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"files\": [\n \"dist\"\n ],\n \"keywords\": [\n \"llm\",\n \"ai\",\n \"agent\",\n \"agents\",\n \"openai\",\n \"anthropic\",\n \"claude\",\n \"gemini\",\n \"gpt\",\n \"streaming\",\n \"function-calling\",\n \"tool-calling\",\n \"typescript\",\n \"universal-client\",\n \"multi-provider\",\n \"hooks\",\n \"gadgets\",\n \"chatbot\",\n \"chatgpt\",\n \"agentic\",\n \"language-model\",\n \"generative-ai\",\n \"bun\",\n \"nodejs\"\n ],\n \"author\": \"Zbigniew Sobiecki <zbigniew@sobiecki.name>\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@anthropic-ai/sdk\": \"^0.69.0\",\n \"@google/genai\": \"^1.27.0\",\n \"@unblessed/node\": \"^1.0.0-alpha.23\",\n \"chalk\": \"^5.6.2\",\n \"commander\": \"^12.1.0\",\n \"diff\": \"^8.0.2\",\n \"eta\": \"^4.4.1\",\n \"js-toml\": \"^1.0.2\",\n \"js-yaml\": \"^4.1.0\",\n \"marked\": \"^15.0.12\",\n \"marked-terminal\": \"^7.3.0\",\n \"openai\": \"^6.0.0\",\n \"tiktoken\": \"^1.0.22\",\n \"tslog\": \"^4.10.2\",\n \"zod\": \"^4.1.12\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.3.2\",\n \"@commitlint/cli\": \"^20.1.0\",\n \"@commitlint/config-conventional\": \"^20.0.0\",\n \"@semantic-release/changelog\": \"^6.0.3\",\n \"@semantic-release/git\": \"^10.0.1\",\n \"@types/diff\": \"^8.0.0\",\n \"@types/js-yaml\": \"^4.0.9\",\n \"@types/marked-terminal\": \"^6.1.1\",\n \"@types/node\": \"^20.12.7\",\n \"bun-types\": \"^1.3.2\",\n \"dotenv\": \"^17.2.3\",\n \"rimraf\": \"^5.0.5\",\n \"semantic-release\": \"^25.0.2\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.4.5\"\n }\n}\n","import chalk from \"chalk\";\nimport type { Command } from \"commander\";\nimport { AgentBuilder } from \"../agent/builder.js\";\nimport { isAbortError } from \"../core/errors.js\";\nimport type { ContentPart } from \"../core/input-content.js\";\nimport { text } from \"../core/input-content.js\";\nimport type { LLMMessage } from \"../core/messages.js\";\nimport type { TokenUsage } from \"../core/options.js\";\nimport { GadgetRegistry } from \"../gadgets/registry.js\";\nimport { FALLBACK_CHARS_PER_TOKEN } from \"../providers/constants.js\";\nimport type { ApprovalConfig } from \"./approval/index.js\";\nimport { builtinGadgets } from \"./builtin-gadgets.js\";\nimport type { AgentConfig, GlobalSubagentConfig } from \"./config.js\";\nimport { buildSubagentConfigMap } from \"./subagent-config.js\";\nimport { COMMANDS } from \"./constants.js\";\nimport {\n createDockerContext,\n type DockerOptions,\n DockerSkipError,\n executeInDocker,\n resolveDockerEnabled,\n} from \"./docker/index.js\";\nimport type { CLIEnvironment } from \"./environment.js\";\nimport { readAudioFile, readImageFile } from \"./file-utils.js\";\nimport { loadGadgets } from \"./gadgets.js\";\nimport {\n createSessionDir,\n formatCallNumber,\n formatLlmRequest,\n resolveLogDir,\n writeLogFile,\n} from \"./llm-logging.js\";\nimport { type CLIAgentOptions, addAgentOptions } from \"./option-helpers.js\";\nimport { TUIApp, StatusBar } from \"./tui/index.js\";\nimport { executeAction, isInteractive, resolvePrompt } from \"./utils.js\";\n\n/**\n * Executes the agent command.\n *\n * SHOWCASE: This function demonstrates how to build a production-grade CLI\n * on top of llmist's core capabilities:\n *\n * 1. **Dynamic gadget loading** - GadgetRegistry for plugin-like extensibility\n * 2. **Observer hooks** - Custom progress tracking and real-time UI updates\n * 3. **Event-driven execution** - React to agent events (text, gadget results)\n * 4. **ModelRegistry integration** - Automatic cost estimation and tracking\n * 5. **Streaming support** - Display LLM output as it's generated\n * 6. **Human-in-the-loop** - Interactive prompts during agent execution\n * 7. **Clean separation** - stdout for content, stderr for metrics/progress\n *\n * The implementation showcases llmist's flexibility: from simple scripts to\n * polished CLIs with spinners, cost tracking, and real-time feedback.\n *\n * @param promptArg - User prompt from command line argument (optional if using stdin)\n * @param options - Agent command options (model, gadgets, max iterations, etc.)\n * @param env - CLI environment for I/O operations\n */\nexport async function executeAgent(\n promptArg: string | undefined,\n options: CLIAgentOptions,\n env: CLIEnvironment,\n): Promise<void> {\n // Check if Docker sandboxing is enabled\n const dockerOptions: DockerOptions = {\n docker: options.docker ?? false,\n dockerRo: options.dockerRo ?? false,\n noDocker: options.noDocker ?? false,\n };\n\n const dockerEnabled = resolveDockerEnabled(\n env.dockerConfig,\n dockerOptions,\n options.docker, // Profile-level docker: true/false\n );\n\n if (dockerEnabled) {\n // Execute inside Docker container\n const ctx = createDockerContext(\n env.dockerConfig,\n dockerOptions,\n env.argv.slice(2), // Remove 'node' and script path\n process.cwd(),\n options.dockerCwdPermission, // Profile-level CWD permission override\n );\n\n try {\n await executeInDocker(ctx);\n // executeInDocker calls process.exit(), so we won't reach here\n } catch (error) {\n // DockerSkipError means we're already inside a container, continue normally\n if (error instanceof DockerSkipError) {\n // Continue with normal execution\n } else {\n throw error;\n }\n }\n }\n\n const client = env.createClient();\n\n // Detect TUI mode early: use TUI when both stdin and stdout are TTY\n const stdinIsInteractive = isInteractive(env.stdin);\n const stdoutTTY = (env.stdout as NodeJS.WriteStream).isTTY === true;\n const useTUI = stdinIsInteractive && stdoutTTY && !options.quiet;\n\n // Resolve prompt: required for piped mode, optional for TUI mode (REPL will wait)\n let prompt: string;\n if (useTUI) {\n // TUI mode: prompt is optional (REPL will wait for input if not provided)\n prompt = promptArg ?? \"\";\n } else {\n // Piped mode: prompt is required\n prompt = await resolvePrompt(promptArg, env);\n }\n\n // SHOWCASE: llmist's GadgetRegistry for dynamic tool loading\n const registry = new GadgetRegistry();\n\n // Register built-in gadgets for basic agent interaction\n // AskUser is auto-excluded when stdin is not interactive (piped input)\n if (options.builtins !== false) {\n for (const gadget of builtinGadgets) {\n // Skip AskUser if:\n // 1. --no-builtin-interaction is set, OR\n // 2. stdin is not interactive (piped input) - AskUser can't work anyway\n if (\n gadget.name === \"AskUser\" &&\n (options.builtinInteraction === false || !stdinIsInteractive)\n ) {\n continue;\n }\n registry.registerByClass(gadget);\n }\n }\n\n // Load user-provided gadgets from file paths\n const gadgetSpecifiers = options.gadget ?? [];\n if (gadgetSpecifiers.length > 0) {\n const gadgets = await loadGadgets(gadgetSpecifiers, process.cwd());\n for (const gadget of gadgets) {\n registry.registerByClass(gadget);\n }\n }\n\n // Create TUI app if in TUI mode\n let tui: TUIApp | null = null;\n if (useTUI) {\n tui = await TUIApp.create({\n model: options.model,\n stdin: env.stdin as NodeJS.ReadStream,\n stdout: env.stdout as NodeJS.WriteStream,\n });\n }\n\n // Set up cancellation support\n const abortController = new AbortController();\n let wasCancelled = false;\n\n // Quit handler - cleanup and exit\n const handleQuit = () => {\n if (tui) {\n tui.destroy();\n }\n process.exit(130); // SIGINT convention: 128 + signal number (2)\n };\n\n // Set up TUI event handlers for ESC and Ctrl+C\n if (tui) {\n tui.onQuit(handleQuit);\n tui.onCancel(() => {\n wasCancelled = true;\n abortController.abort();\n });\n }\n\n // In piped mode, set up basic SIGINT handler\n if (!useTUI) {\n process.once(\"SIGINT\", () => process.exit(130));\n }\n\n // Set up gadget approval manager\n // Default: RunCommand, WriteFile, EditFile require approval unless overridden by config\n const DEFAULT_APPROVAL_REQUIRED = [\"RunCommand\", \"WriteFile\", \"EditFile\"];\n const userApprovals = options.gadgetApproval ?? {};\n\n // Apply defaults for dangerous gadgets if not explicitly configured\n const gadgetApprovals: Record<\n string,\n \"allowed\" | \"denied\" | \"approval-required\"\n > = {\n ...userApprovals,\n };\n for (const gadget of DEFAULT_APPROVAL_REQUIRED) {\n const normalizedGadget = gadget.toLowerCase();\n const isConfigured = Object.keys(userApprovals).some(\n (key) => key.toLowerCase() === normalizedGadget,\n );\n if (!isConfigured) {\n gadgetApprovals[gadget] = \"approval-required\";\n }\n }\n\n const approvalConfig: ApprovalConfig = {\n gadgetApprovals,\n defaultMode: \"allowed\",\n };\n // Approval is handled:\n // - TUI mode: TUI's modal dialogs (in beforeGadgetExecution controller)\n // - Piped mode: auto-deny gadgets requiring approval (can't prompt)\n\n let usage: TokenUsage | undefined;\n let iterations = 0;\n\n // Resolve LLM debug log directory (if enabled)\n const llmLogsBaseDir = resolveLogDir(options.logLlmRequests, \"requests\");\n let llmSessionDir: string | undefined;\n let llmCallCounter = 0;\n\n // Count tokens accurately using provider-specific methods\n const countMessagesTokens = async (\n model: string,\n messages: LLMMessage[],\n ): Promise<number> => {\n try {\n return await client.countTokens(model, messages);\n } catch {\n // Fallback to character-based estimation if counting fails\n const totalChars = messages.reduce(\n (sum, m) => sum + (m.content?.length ?? 0),\n 0,\n );\n return Math.round(totalChars / FALLBACK_CHARS_PER_TOKEN);\n }\n };\n\n // Count tokens for gadget output text\n const countGadgetOutputTokens = async (\n output: string | undefined,\n ): Promise<number | undefined> => {\n if (!output) return undefined;\n try {\n // Wrap gadget output as assistant message for accurate token counting\n const messages: LLMMessage[] = [{ role: \"assistant\", content: output }];\n return await client.countTokens(options.model, messages);\n } catch {\n // Fallback: return undefined to trigger byte count fallback in formatter\n return undefined;\n }\n };\n\n // Build the agent with hooks for progress tracking\n // SHOWCASE: This demonstrates llmist's observer pattern for building custom UIs\n //\n // For simpler use cases, use HookPresets.progressTracking() instead:\n // .withHooks(HookPresets.progressTracking({\n // modelRegistry: client.modelRegistry,\n // onProgress: (stats) => { /* update your UI */ }\n // }))\n //\n // The CLI uses custom hooks for fine-grained control over the spinner animation\n // and real-time updates, showcasing llmist's flexibility for building polished UIs.\n // Build resolved subagent config map for subagent gadgets to inherit settings\n const resolvedSubagentConfig = buildSubagentConfigMap(\n options.model,\n options.subagents,\n options.globalSubagents,\n );\n\n const builder = new AgentBuilder(client)\n .withModel(options.model)\n .withSubagentConfig(resolvedSubagentConfig)\n .withLogger(env.createLogger(\"llmist:cli:agent\"))\n .withHooks({\n observers: {\n // onLLMCallStart: Update TUI with LLM call info and estimated input tokens\n onLLMCallStart: async (context) => {\n if (context.subagentContext) return;\n llmCallCounter++;\n\n if (tui) {\n // Estimate input tokens from messages\n const estimatedInput = await countMessagesTokens(\n context.options.model,\n context.options.messages,\n );\n tui.showLLMCallStart(iterations + 1, context.options.model, estimatedInput);\n }\n },\n\n // onLLMCallReady: Log the exact request being sent to the LLM\n onLLMCallReady: async (context) => {\n if (context.subagentContext) return;\n\n // Store raw request in TUI for raw viewer\n if (tui) {\n tui.setLLMCallRequest(context.options.messages);\n }\n\n if (llmLogsBaseDir) {\n if (!llmSessionDir) {\n llmSessionDir = await createSessionDir(llmLogsBaseDir);\n }\n if (llmSessionDir) {\n const filename = `${formatCallNumber(llmCallCounter)}.request`;\n const content = formatLlmRequest(context.options.messages);\n await writeLogFile(llmSessionDir, filename, content);\n }\n }\n },\n\n // onStreamChunk: Update status bar with real-time output token estimate\n onStreamChunk: async (context) => {\n if (context.subagentContext) return;\n if (!tui) return;\n\n // Use accumulated text from context to estimate output tokens\n const estimatedOutputTokens = StatusBar.estimateTokens(context.accumulatedText);\n tui.updateStreamingTokens(estimatedOutputTokens);\n },\n\n // onLLMCallComplete: Update TUI with completion metrics\n onLLMCallComplete: async (context) => {\n if (context.subagentContext) return;\n\n // Capture completion metadata\n usage = context.usage;\n iterations = Math.max(iterations, context.iteration + 1);\n\n // Calculate per-call cost\n let callCost: number | undefined;\n if (context.usage && client.modelRegistry) {\n try {\n const modelName = context.options.model.includes(\":\")\n ? context.options.model.split(\":\")[1]\n : context.options.model;\n const costResult = client.modelRegistry.estimateCost(\n modelName,\n context.usage.inputTokens,\n context.usage.outputTokens,\n context.usage.cachedInputTokens ?? 0,\n context.usage.cacheCreationInputTokens ?? 0,\n );\n if (costResult) callCost = costResult.totalCost;\n } catch {\n // Ignore cost calculation errors\n }\n }\n\n if (tui) {\n tui.showLLMCallComplete({\n iteration: context.iteration + 1,\n model: context.options.model,\n inputTokens: context.usage?.inputTokens,\n outputTokens: context.usage?.outputTokens,\n cachedInputTokens: context.usage?.cachedInputTokens,\n elapsedSeconds: tui.getElapsedSeconds(),\n cost: callCost,\n finishReason: context.finishReason ?? \"stop\",\n rawResponse: context.rawResponse,\n });\n }\n\n // Write LLM response to debug log if enabled\n if (llmSessionDir) {\n const filename = `${formatCallNumber(llmCallCounter)}.response`;\n await writeLogFile(llmSessionDir, filename, context.rawResponse);\n }\n },\n },\n\n // SHOWCASE: Controller-based approval gating for gadgets\n //\n // This demonstrates how to add safety layers WITHOUT modifying gadgets.\n // The ApprovalManager handles approval flows externally via beforeGadgetExecution.\n // Approval modes are configurable via cli.toml:\n // - \"allowed\": auto-proceed\n // - \"denied\": auto-reject, return message to LLM\n // - \"approval-required\": prompt user interactively\n //\n // Default: RunCommand, WriteFile, EditFile require approval unless overridden.\n controllers: {\n beforeGadgetExecution: async (ctx) => {\n // Get approval mode from config\n const normalizedGadgetName = ctx.gadgetName.toLowerCase();\n const configuredMode = Object.entries(gadgetApprovals).find(\n ([key]) => key.toLowerCase() === normalizedGadgetName,\n )?.[1];\n const mode = configuredMode ?? approvalConfig.defaultMode;\n\n // Fast path: allowed gadgets proceed immediately\n if (mode === \"allowed\") {\n return { action: \"proceed\" };\n }\n\n // Check if we can prompt (interactive mode required for approval-required)\n const stdinTTY = isInteractive(env.stdin);\n const stderrTTY = (env.stderr as NodeJS.WriteStream).isTTY === true;\n const canPrompt = stdinTTY && stderrTTY;\n\n // Non-interactive mode handling\n if (!canPrompt) {\n if (mode === \"approval-required\") {\n return {\n action: \"skip\",\n syntheticResult: `status=denied\\n\\n${ctx.gadgetName} requires interactive approval. Run in a terminal to approve.`,\n };\n }\n if (mode === \"denied\") {\n return {\n action: \"skip\",\n syntheticResult: `status=denied\\n\\n${ctx.gadgetName} is denied by configuration.`,\n };\n }\n return { action: \"proceed\" };\n }\n\n // TUI mode: use TUI's modal approval dialog\n if (tui) {\n const response = await tui.showApproval({\n gadgetName: ctx.gadgetName,\n parameters: ctx.parameters,\n });\n\n if (response === \"yes\" || response === \"always\") {\n // TODO: Handle \"always\" by updating gadgetApprovals\n return { action: \"proceed\" };\n }\n return {\n action: \"skip\",\n syntheticResult: `status=denied\\n\\nDenied by user`,\n };\n }\n\n // Piped mode: can't prompt for approval, deny\n return {\n action: \"skip\",\n syntheticResult: `status=denied\\n\\n${ctx.gadgetName} requires interactive approval. Run in a terminal to approve.`,\n };\n },\n },\n });\n\n // Add optional configurations\n if (options.system) {\n builder.withSystem(options.system);\n }\n if (options.maxIterations !== undefined) {\n builder.withMaxIterations(options.maxIterations);\n }\n if (options.temperature !== undefined) {\n builder.withTemperature(options.temperature);\n }\n\n // Set up human input handler (TUI mode only)\n // In piped mode, AskUser gadget is excluded (see gadget registration above)\n if (tui) {\n builder.onHumanInput(async (question: string) => {\n return tui.waitForInput(question, \"AskUser\");\n });\n }\n\n // Pass abort signal for ESC key cancellation\n builder.withSignal(abortController.signal);\n\n // Add gadgets from the registry\n const gadgets = registry.getAll();\n if (gadgets.length > 0) {\n builder.withGadgets(...gadgets);\n }\n\n // Set custom gadget markers if configured, otherwise use library defaults\n if (options.gadgetStartPrefix) {\n builder.withGadgetStartPrefix(options.gadgetStartPrefix);\n }\n if (options.gadgetEndPrefix) {\n builder.withGadgetEndPrefix(options.gadgetEndPrefix);\n }\n if (options.gadgetArgPrefix) {\n builder.withGadgetArgPrefix(options.gadgetArgPrefix);\n }\n\n // Inject synthetic heredoc example for in-context learning\n // This teaches the LLM to use heredoc syntax (<<<EOF...EOF) for multiline strings\n // by showing what \"past self\" did correctly. LLMs mimic patterns in conversation history.\n builder.withSyntheticGadgetCall(\n \"TellUser\",\n {\n message:\n \"👋 Hello! I'm ready to help.\\n\\nWhat would you like me to work on?\",\n done: false,\n type: \"info\",\n },\n \"ℹ️ 👋 Hello! I'm ready to help.\\n\\nWhat would you like me to work on?\",\n \"gc_init_1\",\n );\n\n // Continue looping when LLM responds with just text (no gadget calls)\n // This allows multi-turn conversations where the LLM may explain before acting\n builder.withTextOnlyHandler(\"acknowledge\");\n\n // Wrap text that accompanies gadget calls as TellUser gadget calls\n // This keeps conversation history consistent and gadget-oriented\n builder.withTextWithGadgetsHandler({\n gadgetName: \"TellUser\",\n parameterMapping: (text) => ({ message: text, done: false, type: \"info\" }),\n resultMapping: (text) => `ℹ️ ${text}`,\n });\n\n // Inject ephemeral trailing message to encourage parallel gadget invocations\n // This message is appended to each LLM request but NOT persisted in history\n builder.withTrailingMessage((ctx) =>\n [\n `[Iteration ${ctx.iteration + 1}/${ctx.maxIterations}]`,\n \"Think carefully in two steps: 1. what gadget invocations we should be making next? 2. how do they depend on one another so we can run all of them in the right order? Then respond with all the gadget invocations you are able to do now.\",\n ].join(\" \"),\n );\n\n // Helper to create and run an agent with a given prompt\n const runAgentWithPrompt = async (userPrompt: string) => {\n // Reset abort controller for new iteration (TUI mode)\n if (tui) {\n tui.resetAbort();\n builder.withSignal(tui.getAbortSignal());\n }\n\n // Build the agent\n let agent;\n if (options.image || options.audio) {\n const parts: ContentPart[] = [text(userPrompt)];\n if (options.image) {\n parts.push(await readImageFile(options.image));\n }\n if (options.audio) {\n parts.push(await readAudioFile(options.audio));\n }\n agent = builder.askWithContent(parts);\n } else {\n agent = builder.ask(userPrompt);\n }\n\n // Subscribe TUI to ExecutionTree for automatic block management\n // This handles nested subagent events automatically via tree events\n let unsubscribeTree: (() => void) | undefined;\n if (tui) {\n unsubscribeTree = tui.subscribeToTree(agent.getTree());\n }\n\n // Run the agent and handle events\n for await (const event of agent.run()) {\n if (tui) {\n // TUI mode: pass all events to TUI\n tui.handleEvent(event);\n\n // Track gadget costs in TUI status bar\n if (event.type === \"gadget_result\" && event.result.cost) {\n tui.addGadgetCost(event.result.cost);\n }\n } else {\n // Piped mode: output text events and TellUser messages to stdout\n if (event.type === \"text\") {\n env.stdout.write(event.content);\n } else if (\n event.type === \"gadget_result\" &&\n event.result.gadgetName === \"TellUser\" &&\n event.result.result\n ) {\n // TellUser gadget returns formatted message in result field\n env.stdout.write(`${event.result.result}\\n`);\n }\n }\n }\n\n // Flush any buffered text\n if (tui) {\n tui.flushText();\n }\n\n // Clean up tree subscription\n if (unsubscribeTree) {\n unsubscribeTree();\n }\n };\n\n // TUI mode: REPL loop - wait for input, run agent, repeat\n // Piped mode: Run once and exit\n if (tui) {\n // Get initial prompt (from CLI arg or wait for user input)\n let currentPrompt = prompt;\n if (!currentPrompt) {\n currentPrompt = await tui.waitForPrompt();\n }\n\n // REPL loop\n while (true) {\n try {\n await runAgentWithPrompt(currentPrompt);\n } catch (error) {\n // Handle abort gracefully - continue to next prompt\n if (!isAbortError(error)) {\n throw error;\n }\n }\n\n // Wait for next prompt\n currentPrompt = await tui.waitForPrompt();\n }\n } else {\n // Piped mode: run once and exit\n try {\n await runAgentWithPrompt(prompt);\n } catch (error) {\n if (!isAbortError(error)) {\n throw error;\n }\n }\n }\n}\n\n/**\n * Registers the agent command with the CLI program.\n * Configures options for model, gadgets, max iterations, temperature, and parameter format.\n *\n * @param program - Commander program to register the command with\n * @param env - CLI environment for dependencies and I/O\n * @param config - Optional configuration defaults from config file\n */\nexport function registerAgentCommand(\n program: Command,\n env: CLIEnvironment,\n config?: AgentConfig,\n globalSubagents?: GlobalSubagentConfig,\n): void {\n const cmd = program\n .command(COMMANDS.agent)\n .description(\"Run the llmist agent loop with optional gadgets.\")\n .argument(\n \"[prompt]\",\n \"Prompt for the agent loop. Falls back to stdin when available.\",\n );\n\n addAgentOptions(cmd, config);\n\n cmd.action((prompt, options) =>\n executeAction(() => {\n // Merge config-only options (no CLI flags) into command options\n const mergedOptions: CLIAgentOptions = {\n ...(options as CLIAgentOptions),\n gadgetApproval: config?.[\"gadget-approval\"],\n subagents: config?.subagents,\n globalSubagents,\n };\n return executeAgent(prompt, mergedOptions, env);\n }, env),\n );\n}\n","/**\n * Error utilities for llmist.\n */\n\n/**\n * Detects if an error is an abort/cancellation error from any provider.\n *\n * Different providers throw different error types when a request is aborted:\n * - Standard: `AbortError` (name) - from fetch/AbortController\n * - Anthropic SDK: `APIConnectionAbortedError`\n * - OpenAI SDK: `APIUserAbortError`\n * - Generic: errors with \"abort\", \"cancelled\", or \"canceled\" in the message\n *\n * @param error - The error to check\n * @returns `true` if the error is an abort-related error, `false` otherwise\n *\n * @example\n * ```typescript\n * import { isAbortError } from \"@llmist/core/errors\";\n *\n * const controller = new AbortController();\n *\n * try {\n * for await (const chunk of client.stream({ signal: controller.signal, ... })) {\n * // Process chunks...\n * }\n * } catch (error) {\n * if (isAbortError(error)) {\n * console.log(\"Request was cancelled - this is expected\");\n * return; // Graceful exit\n * }\n * // Re-throw unexpected errors\n * throw error;\n * }\n * ```\n */\nexport function isAbortError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n\n // Standard AbortError (from fetch/AbortController)\n if (error.name === \"AbortError\") return true;\n\n // Anthropic SDK\n if (error.name === \"APIConnectionAbortedError\") return true;\n\n // OpenAI SDK\n if (error.name === \"APIUserAbortError\") return true;\n\n // Message-based detection (fallback for edge cases)\n const message = error.message.toLowerCase();\n if (message.includes(\"abort\")) return true;\n if (message.includes(\"cancelled\")) return true;\n if (message.includes(\"canceled\")) return true;\n\n return false;\n}\n","/**\n * Built-in gadgets for CLI agent command.\n * These gadgets provide basic communication capabilities out-of-the-box.\n */\nimport { z } from \"zod\";\n\nimport { createGadget } from \"../gadgets/create-gadget.js\";\nimport { TaskCompletionSignal, HumanInputRequiredException } from \"../gadgets/exceptions.js\";\n\n/**\n * AskUser gadget - Asks the user a question and waits for their response.\n *\n * Use this when you need more information or clarification from the user.\n */\nexport const askUser = createGadget({\n name: \"AskUser\",\n description:\n \"Ask the user a question when you need more information or clarification. The user's response will be provided back to you.\",\n schema: z.object({\n question: z.string().describe(\"The question to ask the user in plain-text or Markdown\"),\n }),\n examples: [\n {\n comment: \"Ask for clarification about the task\",\n params: { question: \"Which file would you like me to modify?\" },\n },\n {\n comment: \"Ask user to choose between options\",\n params: {\n question:\n \"I found multiple matches. Which one should I use?\\n- src/utils/helper.ts\\n- src/lib/helper.ts\",\n },\n },\n ],\n execute: ({ question }) => {\n throw new HumanInputRequiredException(question);\n },\n});\n\n/**\n * TellUser gadget - Outputs a message to the user.\n *\n * Use this for key results, warnings, or structured output that should stand out\n * from regular streamed text.\n */\nexport const tellUser = createGadget({\n name: \"TellUser\",\n description: \"Tell the user something important.\",\n schema: z.object({\n message: z.string().optional().describe(\"The message to display to the user in Markdown\"),\n type: z\n .enum([\"info\", \"success\", \"warning\", \"error\"])\n .default(\"info\")\n .describe(\"Message type: info, success, warning, or error\"),\n }),\n examples: [\n {\n comment: \"Warn the user about something\",\n params: {\n message: \"Found 3 files with potential issues. Continuing analysis...\",\n type: \"warning\",\n },\n },\n {\n comment: \"Share detailed analysis with bullet points (use heredoc for multiline)\",\n params: {\n message:\n \"Here's what I found in the codebase:\\n\\n1. **Main entry point**: `src/index.ts` exports all public APIs\\n2. **Core logic**: Located in `src/core/` with 5 modules\\n3. **Tests**: Good coverage in `src/__tests__/`\\n\\nI'll continue exploring the core modules.\",\n type: \"info\",\n },\n },\n ],\n execute: ({ message, type }) => {\n // Handle empty or missing message gracefully\n // This happens when LLM sends malformed parameters that fail to parse the message field\n if (!message || message.trim() === \"\") {\n return \"⚠️ TellUser was called without a message. Please provide content in the 'message' field.\";\n }\n\n // Format message for display, but return plain text for LLM context\n // This prevents ANSI color codes from polluting the conversation\n const prefixes = {\n info: \"ℹ️ \",\n success: \"✅ \",\n warning: \"⚠️ \",\n error: \"❌ \",\n };\n return prefixes[type] + message;\n },\n});\n\n/**\n * Finish gadget - Signals that the task is complete.\n *\n * Use this when you have completed all requested work and want to end the conversation.\n */\nexport const finish = createGadget({\n name: \"Finish\",\n description: \"Signal that you have completed your task. Call this when your work is done.\",\n schema: z.object({}),\n examples: [\n {\n comment: \"Signal task completion\",\n params: {},\n },\n ],\n execute: () => {\n throw new TaskCompletionSignal(\"Task completed\");\n },\n});\n\n/**\n * All built-in gadgets as an array for easy registration.\n */\nexport const builtinGadgets = [askUser, tellUser, finish];\n","/**\n * Subagent configuration resolution.\n *\n * Handles merging and resolving subagent configurations from multiple sources:\n * - Global `[subagents]` section\n * - Profile-level `[profile.subagents]` sections\n * - \"inherit\" keyword for model inheritance\n */\n\nimport type { SubagentConfig, SubagentConfigMap } from \"../gadgets/types.js\";\n\n/**\n * Special model value indicating the subagent should inherit from parent agent.\n */\nexport const INHERIT_MODEL = \"inherit\";\n\n/**\n * Global subagent configuration section from cli.toml.\n * Contains default-model and per-subagent configs.\n */\nexport interface GlobalSubagentConfig {\n /** Default model for all subagents (\"inherit\" or specific model) */\n \"default-model\"?: string;\n /** Per-subagent configurations */\n [subagentName: string]: SubagentConfig | string | undefined;\n}\n\n/**\n * Resolves a subagent's configuration by merging global and profile-level configs.\n *\n * Resolution priority (highest to lowest):\n * 1. Profile-level subagent config (`[profile.subagents.Name]`)\n * 2. Global subagent config (`[subagents.Name]`)\n * 3. Global default-model (`[subagents] default-model`)\n * 4. \"inherit\" (use parent model)\n *\n * @param subagentName - Name of the subagent (e.g., \"BrowseWeb\")\n * @param parentModel - Model used by the parent agent\n * @param profileConfig - Profile-level subagent config (from `[profile.subagents]`)\n * @param globalConfig - Global subagent config (from `[subagents]`)\n * @returns Resolved configuration with model resolved to actual value\n *\n * @example\n * ```typescript\n * const config = resolveSubagentConfig(\n * \"BrowseWeb\",\n * \"gemini-2.5-flash\",\n * { BrowseWeb: { maxIterations: 30 } },\n * { BrowseWeb: { model: \"inherit\", headless: true } }\n * );\n * // Result: { model: \"gemini-2.5-flash\", maxIterations: 30, headless: true }\n * ```\n */\nexport function resolveSubagentConfig(\n subagentName: string,\n parentModel: string,\n profileConfig?: SubagentConfigMap,\n globalConfig?: GlobalSubagentConfig,\n): SubagentConfig {\n const resolved: SubagentConfig = {};\n\n // Get global defaults\n const globalDefaultModel = globalConfig?.[\"default-model\"];\n const globalSubagent = extractSubagentConfig(globalConfig, subagentName);\n const profileSubagent = profileConfig?.[subagentName] ?? {};\n\n // Merge configs (profile overrides global)\n const merged = { ...globalSubagent, ...profileSubagent };\n\n // Resolve model with priority: merged > globalDefault > \"inherit\"\n const configModel = merged.model ?? globalDefaultModel ?? INHERIT_MODEL;\n\n // Apply \"inherit\" resolution\n resolved.model = configModel === INHERIT_MODEL ? parentModel : configModel;\n\n // Copy all other options (excluding model which we just resolved)\n for (const [key, value] of Object.entries(merged)) {\n if (key !== \"model\") {\n resolved[key] = value;\n }\n }\n\n return resolved;\n}\n\n/**\n * Builds a complete SubagentConfigMap with all subagents resolved.\n *\n * @param parentModel - Model used by the parent agent\n * @param profileConfig - Profile-level subagent configs\n * @param globalConfig - Global subagent configs\n * @returns Map of all resolved subagent configurations\n */\nexport function buildSubagentConfigMap(\n parentModel: string,\n profileConfig?: SubagentConfigMap,\n globalConfig?: GlobalSubagentConfig,\n): SubagentConfigMap {\n // Collect all subagent names from both sources\n const subagentNames = new Set<string>();\n\n if (globalConfig) {\n for (const key of Object.keys(globalConfig)) {\n if (key !== \"default-model\" && typeof globalConfig[key] === \"object\") {\n subagentNames.add(key);\n }\n }\n }\n\n if (profileConfig) {\n for (const key of Object.keys(profileConfig)) {\n subagentNames.add(key);\n }\n }\n\n // Resolve each subagent\n const result: SubagentConfigMap = {};\n for (const name of subagentNames) {\n result[name] = resolveSubagentConfig(name, parentModel, profileConfig, globalConfig);\n }\n\n return result;\n}\n\n/**\n * Extracts SubagentConfig from GlobalSubagentConfig for a specific subagent.\n * Handles the fact that GlobalSubagentConfig has mixed types (string for default-model).\n */\nfunction extractSubagentConfig(\n globalConfig: GlobalSubagentConfig | undefined,\n subagentName: string,\n): SubagentConfig {\n if (!globalConfig) {\n return {};\n }\n\n const value = globalConfig[subagentName];\n if (typeof value === \"object\" && value !== null) {\n return value as SubagentConfig;\n }\n\n return {};\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { load as parseToml } from \"js-toml\";\nimport { validateDockerConfig } from \"./docker/docker-config.js\";\nimport type { DockerConfig } from \"./docker/types.js\";\nimport type { SubagentConfig, SubagentConfigMap } from \"../gadgets/types.js\";\nimport type { GlobalSubagentConfig } from \"./subagent-config.js\";\n\n// Re-export subagent config types for consumers\nexport type { SubagentConfig, SubagentConfigMap } from \"../gadgets/types.js\";\nexport type { GlobalSubagentConfig } from \"./subagent-config.js\";\nimport {\n createTemplateEngine,\n hasTemplateSyntax,\n type PromptsConfig,\n resolveTemplate,\n TemplateError,\n validateEnvVars,\n validatePrompts,\n} from \"./templates.js\";\n\n// Re-export PromptsConfig for consumers\nexport type { PromptsConfig } from \"./templates.js\";\n\n/**\n * Valid log level names.\n */\nexport type LogLevel = \"silly\" | \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"fatal\";\n\n/**\n * Gadget permission level determines how a gadget execution is handled.\n * - \"allowed\": Auto-proceed without prompting\n * - \"denied\": Auto-reject, return denial message to LLM\n * - \"approval-required\": Prompt user for approval before execution\n */\nexport type GadgetPermissionLevel = \"allowed\" | \"denied\" | \"approval-required\";\n\n/**\n * Valid gadget permission levels.\n */\nconst VALID_PERMISSION_LEVELS: GadgetPermissionLevel[] = [\"allowed\", \"denied\", \"approval-required\"];\n\n/**\n * Configuration for per-gadget permission behavior.\n * Keys are gadget names (case-insensitive), values are permission levels.\n * Special key \"*\" sets the default for unconfigured gadgets.\n */\nexport type GadgetPermissionPolicy = Record<string, GadgetPermissionLevel>;\n\n/**\n * Global CLI options that apply to all commands.\n */\nexport interface GlobalConfig {\n \"log-level\"?: LogLevel;\n \"log-file\"?: string;\n \"log-reset\"?: boolean;\n}\n\n/**\n * Shared options used by both complete and agent command configurations.\n */\nexport interface SharedCommandConfig {\n model?: string;\n system?: string;\n temperature?: number;\n inherits?: string | string[];\n /** Enable Docker sandboxing for this profile/command */\n docker?: boolean;\n /** Override CWD mount permission for this profile (\"ro\" or \"rw\") */\n \"docker-cwd-permission\"?: \"ro\" | \"rw\";\n}\n\n/**\n * Configuration for the complete command.\n */\nexport interface CompleteConfig extends SharedCommandConfig {\n \"max-tokens\"?: number;\n quiet?: boolean;\n \"log-level\"?: LogLevel;\n \"log-file\"?: string;\n \"log-reset\"?: boolean;\n \"log-llm-requests\"?: string | boolean;\n}\n\n/**\n * Configuration for the image command.\n */\nexport interface ImageConfig {\n model?: string;\n size?: string;\n quality?: string;\n count?: number;\n output?: string;\n quiet?: boolean;\n}\n\n/**\n * Configuration for the speech command.\n */\nexport interface SpeechConfig {\n model?: string;\n voice?: string;\n format?: string;\n speed?: number;\n output?: string;\n quiet?: boolean;\n}\n\n/**\n * Configuration for the agent command.\n */\nexport interface AgentConfig extends SharedCommandConfig {\n \"max-iterations\"?: number;\n gadgets?: string[]; // Full replacement (preferred)\n \"gadget-add\"?: string[]; // Add to inherited gadgets\n \"gadget-remove\"?: string[]; // Remove from inherited gadgets\n gadget?: string[]; // DEPRECATED: alias for gadgets\n builtins?: boolean;\n \"builtin-interaction\"?: boolean;\n \"gadget-start-prefix\"?: string;\n \"gadget-end-prefix\"?: string;\n \"gadget-arg-prefix\"?: string;\n \"gadget-approval\"?: GadgetPermissionPolicy;\n /** Per-subagent configuration overrides for this profile/command */\n subagents?: SubagentConfigMap;\n quiet?: boolean;\n \"log-level\"?: LogLevel;\n \"log-file\"?: string;\n \"log-reset\"?: boolean;\n \"log-llm-requests\"?: string | boolean;\n}\n\n/**\n * Command type determines execution behavior.\n */\nexport type CommandType = \"agent\" | \"complete\";\n\n/**\n * Custom command configuration from config file.\n * Extends both agent and complete configs, with type determining behavior.\n */\nexport interface CustomCommandConfig extends AgentConfig, CompleteConfig {\n type?: CommandType;\n description?: string;\n}\n\n/**\n * Root configuration structure matching ~/.llmist/cli.toml.\n */\nexport interface CLIConfig {\n global?: GlobalConfig;\n complete?: CompleteConfig;\n agent?: AgentConfig;\n image?: ImageConfig;\n speech?: SpeechConfig;\n prompts?: PromptsConfig;\n docker?: DockerConfig;\n /** Global subagent configuration defaults */\n subagents?: GlobalSubagentConfig;\n [customCommand: string]:\n | CustomCommandConfig\n | CompleteConfig\n | AgentConfig\n | ImageConfig\n | SpeechConfig\n | GlobalConfig\n | PromptsConfig\n | DockerConfig\n | GlobalSubagentConfig\n | undefined;\n}\n\n// Re-export DockerConfig for consumers\nexport type { DockerConfig } from \"./docker/types.js\";\n\n/** Valid keys for global config */\nconst GLOBAL_CONFIG_KEYS = new Set([\"log-level\", \"log-file\", \"log-reset\"]);\n\n/** Valid log levels */\nconst VALID_LOG_LEVELS: LogLevel[] = [\"silly\", \"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\"];\n\n/** Valid keys for complete command config */\nconst COMPLETE_CONFIG_KEYS = new Set([\n \"model\",\n \"system\",\n \"temperature\",\n \"max-tokens\",\n \"quiet\",\n \"inherits\",\n \"log-level\",\n \"log-file\",\n \"log-reset\",\n \"log-llm-requests\",\n \"type\", // Allowed for inheritance compatibility, ignored for built-in commands\n \"docker\", // Enable Docker sandboxing (only effective for agent type)\n \"docker-cwd-permission\", // Override CWD mount permission for this profile\n]);\n\n/** Valid keys for agent command config */\nconst AGENT_CONFIG_KEYS = new Set([\n \"model\",\n \"system\",\n \"temperature\",\n \"max-iterations\",\n \"gadgets\", // Full replacement (preferred)\n \"gadget-add\", // Add to inherited gadgets\n \"gadget-remove\", // Remove from inherited gadgets\n \"gadget\", // DEPRECATED: alias for gadgets\n \"builtins\",\n \"builtin-interaction\",\n \"gadget-start-prefix\",\n \"gadget-end-prefix\",\n \"gadget-arg-prefix\",\n \"gadget-approval\",\n \"subagents\", // Per-subagent configuration overrides\n \"quiet\",\n \"inherits\",\n \"log-level\",\n \"log-file\",\n \"log-reset\",\n \"log-llm-requests\",\n \"type\", // Allowed for inheritance compatibility, ignored for built-in commands\n \"docker\", // Enable Docker sandboxing for this profile\n \"docker-cwd-permission\", // Override CWD mount permission for this profile\n]);\n\n/** Valid keys for image command config */\nconst IMAGE_CONFIG_KEYS = new Set([\"model\", \"size\", \"quality\", \"count\", \"output\", \"quiet\"]);\n\n/** Valid keys for speech command config */\nconst SPEECH_CONFIG_KEYS = new Set([\"model\", \"voice\", \"format\", \"speed\", \"output\", \"quiet\"]);\n\n/** Valid keys for custom command config (union of complete + agent + type + description) */\nconst CUSTOM_CONFIG_KEYS = new Set([\n ...COMPLETE_CONFIG_KEYS,\n ...AGENT_CONFIG_KEYS,\n \"type\",\n \"description\",\n]);\n\n/**\n * Returns the default config file path: ~/.llmist/cli.toml\n */\nexport function getConfigPath(): string {\n return join(homedir(), \".llmist\", \"cli.toml\");\n}\n\n/**\n * Configuration validation error.\n */\nexport class ConfigError extends Error {\n constructor(\n message: string,\n public readonly path?: string,\n ) {\n super(path ? `${path}: ${message}` : message);\n this.name = \"ConfigError\";\n }\n}\n\n/**\n * Validates that a value is a string.\n */\nfunction validateString(value: unknown, key: string, section: string): string {\n if (typeof value !== \"string\") {\n throw new ConfigError(`[${section}].${key} must be a string`);\n }\n return value;\n}\n\n/**\n * Validates that a value is a number within optional bounds.\n */\nfunction validateNumber(\n value: unknown,\n key: string,\n section: string,\n opts?: { min?: number; max?: number; integer?: boolean },\n): number {\n if (typeof value !== \"number\") {\n throw new ConfigError(`[${section}].${key} must be a number`);\n }\n if (opts?.integer && !Number.isInteger(value)) {\n throw new ConfigError(`[${section}].${key} must be an integer`);\n }\n if (opts?.min !== undefined && value < opts.min) {\n throw new ConfigError(`[${section}].${key} must be >= ${opts.min}`);\n }\n if (opts?.max !== undefined && value > opts.max) {\n throw new ConfigError(`[${section}].${key} must be <= ${opts.max}`);\n }\n return value;\n}\n\n/**\n * Validates that a value is a boolean.\n */\nfunction validateBoolean(value: unknown, key: string, section: string): boolean {\n if (typeof value !== \"boolean\") {\n throw new ConfigError(`[${section}].${key} must be a boolean`);\n }\n return value;\n}\n\n/**\n * Validates that a value is an array of strings.\n */\nfunction validateStringArray(value: unknown, key: string, section: string): string[] {\n if (!Array.isArray(value)) {\n throw new ConfigError(`[${section}].${key} must be an array`);\n }\n for (let i = 0; i < value.length; i++) {\n if (typeof value[i] !== \"string\") {\n throw new ConfigError(`[${section}].${key}[${i}] must be a string`);\n }\n }\n return value as string[];\n}\n\n/**\n * Validates that a value is a string or array of strings (for inherits field).\n */\nfunction validateInherits(value: unknown, section: string): string | string[] {\n if (typeof value === \"string\") {\n return value;\n }\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n if (typeof value[i] !== \"string\") {\n throw new ConfigError(`[${section}].inherits[${i}] must be a string`);\n }\n }\n return value as string[];\n }\n throw new ConfigError(`[${section}].inherits must be a string or array of strings`);\n}\n\n/**\n * Validates a single subagent configuration.\n * Subagent configs are flexible objects with optional model and maxIterations.\n */\nfunction validateSingleSubagentConfig(\n value: unknown,\n subagentName: string,\n section: string,\n): SubagentConfig {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ConfigError(\n `[${section}].${subagentName} must be a table (e.g., { model = \"inherit\", maxIterations = 20 })`,\n );\n }\n\n const result: SubagentConfig = {};\n const rawObj = value as Record<string, unknown>;\n\n for (const [key, val] of Object.entries(rawObj)) {\n if (key === \"model\") {\n if (typeof val !== \"string\") {\n throw new ConfigError(`[${section}].${subagentName}.model must be a string`);\n }\n result.model = val;\n } else if (key === \"maxIterations\") {\n if (typeof val !== \"number\" || !Number.isInteger(val) || val < 1) {\n throw new ConfigError(\n `[${section}].${subagentName}.maxIterations must be a positive integer`,\n );\n }\n result.maxIterations = val;\n } else {\n // Allow arbitrary additional options (headless, etc.)\n result[key] = val;\n }\n }\n\n return result;\n}\n\n/**\n * Validates a subagent configuration map (per-profile subagents).\n */\nfunction validateSubagentConfigMap(value: unknown, section: string): SubagentConfigMap {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ConfigError(\n `[${section}].subagents must be a table (e.g., { BrowseWeb = { model = \"inherit\" } })`,\n );\n }\n\n const result: SubagentConfigMap = {};\n for (const [subagentName, config] of Object.entries(value as Record<string, unknown>)) {\n result[subagentName] = validateSingleSubagentConfig(config, subagentName, `${section}.subagents`);\n }\n return result;\n}\n\n/**\n * Validates the global [subagents] section.\n * Contains default-model and per-subagent configurations.\n */\nfunction validateGlobalSubagentConfig(value: unknown, section: string): GlobalSubagentConfig {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ConfigError(`[${section}] must be a table`);\n }\n\n const result: GlobalSubagentConfig = {};\n const rawObj = value as Record<string, unknown>;\n\n for (const [key, val] of Object.entries(rawObj)) {\n if (key === \"default-model\") {\n if (typeof val !== \"string\") {\n throw new ConfigError(`[${section}].default-model must be a string`);\n }\n result[\"default-model\"] = val;\n } else {\n // Per-subagent config (nested table)\n result[key] = validateSingleSubagentConfig(val, key, section);\n }\n }\n\n return result;\n}\n\n/**\n * Validates that a value is a gadget approval config (object mapping gadget names to modes).\n */\nfunction validateGadgetApproval(value: unknown, section: string): GadgetPermissionPolicy {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ConfigError(\n `[${section}].gadget-approval must be a table (e.g., { WriteFile = \"approval-required\" })`,\n );\n }\n\n const result: GadgetPermissionPolicy = {};\n for (const [gadgetName, mode] of Object.entries(value as Record<string, unknown>)) {\n if (typeof mode !== \"string\") {\n throw new ConfigError(`[${section}].gadget-approval.${gadgetName} must be a string`);\n }\n if (!VALID_PERMISSION_LEVELS.includes(mode as GadgetPermissionLevel)) {\n throw new ConfigError(\n `[${section}].gadget-approval.${gadgetName} must be one of: ${VALID_PERMISSION_LEVELS.join(\", \")}`,\n );\n }\n result[gadgetName] = mode as GadgetPermissionLevel;\n }\n return result;\n}\n\n/**\n * Validates and extracts logging config fields from a raw object.\n */\nfunction validateLoggingConfig(\n raw: Record<string, unknown>,\n section: string,\n): { \"log-level\"?: LogLevel; \"log-file\"?: string; \"log-reset\"?: boolean } {\n const result: { \"log-level\"?: LogLevel; \"log-file\"?: string; \"log-reset\"?: boolean } = {};\n\n if (\"log-level\" in raw) {\n const level = validateString(raw[\"log-level\"], \"log-level\", section);\n if (!VALID_LOG_LEVELS.includes(level as LogLevel)) {\n throw new ConfigError(\n `[${section}].log-level must be one of: ${VALID_LOG_LEVELS.join(\", \")}`,\n );\n }\n result[\"log-level\"] = level as LogLevel;\n }\n if (\"log-file\" in raw) {\n result[\"log-file\"] = validateString(raw[\"log-file\"], \"log-file\", section);\n }\n if (\"log-reset\" in raw) {\n result[\"log-reset\"] = validateBoolean(raw[\"log-reset\"], \"log-reset\", section);\n }\n\n return result;\n}\n\n/**\n * Validates and extracts base command config fields.\n */\nfunction validateBaseConfig(\n raw: Record<string, unknown>,\n section: string,\n): Partial<SharedCommandConfig> {\n const result: Partial<SharedCommandConfig> = {};\n\n if (\"model\" in raw) {\n result.model = validateString(raw.model, \"model\", section);\n }\n if (\"system\" in raw) {\n result.system = validateString(raw.system, \"system\", section);\n }\n if (\"temperature\" in raw) {\n result.temperature = validateNumber(raw.temperature, \"temperature\", section, {\n min: 0,\n max: 2,\n });\n }\n if (\"inherits\" in raw) {\n result.inherits = validateInherits(raw.inherits, section);\n }\n if (\"docker\" in raw) {\n result.docker = validateBoolean(raw.docker, \"docker\", section);\n }\n if (\"docker-cwd-permission\" in raw) {\n const perm = validateString(raw[\"docker-cwd-permission\"], \"docker-cwd-permission\", section);\n if (perm !== \"ro\" && perm !== \"rw\") {\n throw new ConfigError(`[${section}].docker-cwd-permission must be \"ro\" or \"rw\"`);\n }\n result[\"docker-cwd-permission\"] = perm as \"ro\" | \"rw\";\n }\n\n return result;\n}\n\n/**\n * Validates the global config section.\n */\nfunction validateGlobalConfig(raw: unknown, section: string): GlobalConfig {\n if (typeof raw !== \"object\" || raw === null) {\n throw new ConfigError(`[${section}] must be a table`);\n }\n\n const rawObj = raw as Record<string, unknown>;\n\n // Check for unknown keys\n for (const key of Object.keys(rawObj)) {\n if (!GLOBAL_CONFIG_KEYS.has(key)) {\n throw new ConfigError(`[${section}].${key} is not a valid option`);\n }\n }\n\n return validateLoggingConfig(rawObj, section);\n}\n\n/**\n * Validates a complete command config section.\n */\nfunction validateCompleteConfig(raw: unknown, section: string): CompleteConfig {\n if (typeof raw !== \"object\" || raw === null) {\n throw new ConfigError(`[${section}] must be a table`);\n }\n\n const rawObj = raw as Record<string, unknown>;\n\n // Check for unknown keys\n for (const key of Object.keys(rawObj)) {\n if (!COMPLETE_CONFIG_KEYS.has(key)) {\n throw new ConfigError(`[${section}].${key} is not a valid option`);\n }\n }\n\n const result: CompleteConfig = {\n ...validateBaseConfig(rawObj, section),\n ...validateLoggingConfig(rawObj, section),\n };\n\n if (\"max-tokens\" in rawObj) {\n result[\"max-tokens\"] = validateNumber(rawObj[\"max-tokens\"], \"max-tokens\", section, {\n integer: true,\n min: 1,\n });\n }\n if (\"quiet\" in rawObj) {\n result.quiet = validateBoolean(rawObj.quiet, \"quiet\", section);\n }\n if (\"log-llm-requests\" in rawObj) {\n result[\"log-llm-requests\"] = validateStringOrBoolean(\n rawObj[\"log-llm-requests\"],\n \"log-llm-requests\",\n section,\n );\n }\n\n return result;\n}\n\n/**\n * Validates an agent command config section.\n */\nfunction validateAgentConfig(raw: unknown, section: string): AgentConfig {\n if (typeof raw !== \"object\" || raw === null) {\n throw new ConfigError(`[${section}] must be a table`);\n }\n\n const rawObj = raw as Record<string, unknown>;\n\n // Check for unknown keys\n for (const key of Object.keys(rawObj)) {\n if (!AGENT_CONFIG_KEYS.has(key)) {\n throw new ConfigError(`[${section}].${key} is not a valid option`);\n }\n }\n\n const result: AgentConfig = {\n ...validateBaseConfig(rawObj, section),\n ...validateLoggingConfig(rawObj, section),\n };\n\n if (\"max-iterations\" in rawObj) {\n result[\"max-iterations\"] = validateNumber(rawObj[\"max-iterations\"], \"max-iterations\", section, {\n integer: true,\n min: 1,\n });\n }\n // Gadget configuration (new plural form preferred)\n if (\"gadgets\" in rawObj) {\n result.gadgets = validateStringArray(rawObj.gadgets, \"gadgets\", section);\n }\n if (\"gadget-add\" in rawObj) {\n result[\"gadget-add\"] = validateStringArray(rawObj[\"gadget-add\"], \"gadget-add\", section);\n }\n if (\"gadget-remove\" in rawObj) {\n result[\"gadget-remove\"] = validateStringArray(\n rawObj[\"gadget-remove\"],\n \"gadget-remove\",\n section,\n );\n }\n // Legacy singular form (deprecated)\n if (\"gadget\" in rawObj) {\n result.gadget = validateStringArray(rawObj.gadget, \"gadget\", section);\n }\n if (\"builtins\" in rawObj) {\n result.builtins = validateBoolean(rawObj.builtins, \"builtins\", section);\n }\n if (\"builtin-interaction\" in rawObj) {\n result[\"builtin-interaction\"] = validateBoolean(\n rawObj[\"builtin-interaction\"],\n \"builtin-interaction\",\n section,\n );\n }\n if (\"gadget-start-prefix\" in rawObj) {\n result[\"gadget-start-prefix\"] = validateString(\n rawObj[\"gadget-start-prefix\"],\n \"gadget-start-prefix\",\n section,\n );\n }\n if (\"gadget-end-prefix\" in rawObj) {\n result[\"gadget-end-prefix\"] = validateString(\n rawObj[\"gadget-end-prefix\"],\n \"gadget-end-prefix\",\n section,\n );\n }\n if (\"gadget-arg-prefix\" in rawObj) {\n result[\"gadget-arg-prefix\"] = validateString(\n rawObj[\"gadget-arg-prefix\"],\n \"gadget-arg-prefix\",\n section,\n );\n }\n if (\"gadget-approval\" in rawObj) {\n result[\"gadget-approval\"] = validateGadgetApproval(rawObj[\"gadget-approval\"], section);\n }\n if (\"subagents\" in rawObj) {\n result.subagents = validateSubagentConfigMap(rawObj.subagents, section);\n }\n if (\"quiet\" in rawObj) {\n result.quiet = validateBoolean(rawObj.quiet, \"quiet\", section);\n }\n if (\"log-llm-requests\" in rawObj) {\n result[\"log-llm-requests\"] = validateStringOrBoolean(\n rawObj[\"log-llm-requests\"],\n \"log-llm-requests\",\n section,\n );\n }\n\n return result;\n}\n\n/**\n * Validates an image command config section.\n */\nfunction validateImageConfig(raw: unknown, section: string): ImageConfig {\n if (typeof raw !== \"object\" || raw === null) {\n throw new ConfigError(`[${section}] must be a table`);\n }\n\n const rawObj = raw as Record<string, unknown>;\n\n // Check for unknown keys\n for (const key of Object.keys(rawObj)) {\n if (!IMAGE_CONFIG_KEYS.has(key)) {\n throw new ConfigError(`[${section}].${key} is not a valid option`);\n }\n }\n\n const result: ImageConfig = {};\n\n if (\"model\" in rawObj) {\n result.model = validateString(rawObj.model, \"model\", section);\n }\n if (\"size\" in rawObj) {\n result.size = validateString(rawObj.size, \"size\", section);\n }\n if (\"quality\" in rawObj) {\n result.quality = validateString(rawObj.quality, \"quality\", section);\n }\n if (\"count\" in rawObj) {\n result.count = validateNumber(rawObj.count, \"count\", section, {\n integer: true,\n min: 1,\n max: 10,\n });\n }\n if (\"output\" in rawObj) {\n result.output = validateString(rawObj.output, \"output\", section);\n }\n if (\"quiet\" in rawObj) {\n result.quiet = validateBoolean(rawObj.quiet, \"quiet\", section);\n }\n\n return result;\n}\n\n/**\n * Validates a speech command config section.\n */\nfunction validateSpeechConfig(raw: unknown, section: string): SpeechConfig {\n if (typeof raw !== \"object\" || raw === null) {\n throw new ConfigError(`[${section}] must be a table`);\n }\n\n const rawObj = raw as Record<string, unknown>;\n\n // Check for unknown keys\n for (const key of Object.keys(rawObj)) {\n if (!SPEECH_CONFIG_KEYS.has(key)) {\n throw new ConfigError(`[${section}].${key} is not a valid option`);\n }\n }\n\n const result: SpeechConfig = {};\n\n if (\"model\" in rawObj) {\n result.model = validateString(rawObj.model, \"model\", section);\n }\n if (\"voice\" in rawObj) {\n result.voice = validateString(rawObj.voice, \"voice\", section);\n }\n if (\"format\" in rawObj) {\n result.format = validateString(rawObj.format, \"format\", section);\n }\n if (\"speed\" in rawObj) {\n result.speed = validateNumber(rawObj.speed, \"speed\", section, {\n min: 0.25,\n max: 4.0,\n });\n }\n if (\"output\" in rawObj) {\n result.output = validateString(rawObj.output, \"output\", section);\n }\n if (\"quiet\" in rawObj) {\n result.quiet = validateBoolean(rawObj.quiet, \"quiet\", section);\n }\n\n return result;\n}\n\n/**\n * Validates a value is either a string or boolean.\n */\nfunction validateStringOrBoolean(value: unknown, field: string, section: string): string | boolean {\n if (typeof value === \"string\" || typeof value === \"boolean\") {\n return value;\n }\n throw new ConfigError(`[${section}].${field} must be a string or boolean`);\n}\n\n/**\n * Validates a custom command config section.\n */\nfunction validateCustomConfig(raw: unknown, section: string): CustomCommandConfig {\n if (typeof raw !== \"object\" || raw === null) {\n throw new ConfigError(`[${section}] must be a table`);\n }\n\n const rawObj = raw as Record<string, unknown>;\n\n // Check for unknown keys\n for (const key of Object.keys(rawObj)) {\n if (!CUSTOM_CONFIG_KEYS.has(key)) {\n throw new ConfigError(`[${section}].${key} is not a valid option`);\n }\n }\n\n // Get the type first to validate properly\n let type: CommandType = \"agent\"; // Default\n if (\"type\" in rawObj) {\n const typeValue = validateString(rawObj.type, \"type\", section);\n if (typeValue !== \"agent\" && typeValue !== \"complete\") {\n throw new ConfigError(`[${section}].type must be \"agent\" or \"complete\"`);\n }\n type = typeValue;\n }\n\n // Validate base fields + type-specific fields\n const result: CustomCommandConfig = {\n ...validateBaseConfig(rawObj, section),\n type,\n };\n\n if (\"description\" in rawObj) {\n result.description = validateString(rawObj.description, \"description\", section);\n }\n\n // Always allow agent-specific fields (they'll be ignored for complete type)\n if (\"max-iterations\" in rawObj) {\n result[\"max-iterations\"] = validateNumber(rawObj[\"max-iterations\"], \"max-iterations\", section, {\n integer: true,\n min: 1,\n });\n }\n // Gadget configuration (new plural form preferred)\n if (\"gadgets\" in rawObj) {\n result.gadgets = validateStringArray(rawObj.gadgets, \"gadgets\", section);\n }\n if (\"gadget-add\" in rawObj) {\n result[\"gadget-add\"] = validateStringArray(rawObj[\"gadget-add\"], \"gadget-add\", section);\n }\n if (\"gadget-remove\" in rawObj) {\n result[\"gadget-remove\"] = validateStringArray(\n rawObj[\"gadget-remove\"],\n \"gadget-remove\",\n section,\n );\n }\n // Legacy singular form (deprecated)\n if (\"gadget\" in rawObj) {\n result.gadget = validateStringArray(rawObj.gadget, \"gadget\", section);\n }\n if (\"builtins\" in rawObj) {\n result.builtins = validateBoolean(rawObj.builtins, \"builtins\", section);\n }\n if (\"builtin-interaction\" in rawObj) {\n result[\"builtin-interaction\"] = validateBoolean(\n rawObj[\"builtin-interaction\"],\n \"builtin-interaction\",\n section,\n );\n }\n if (\"gadget-start-prefix\" in rawObj) {\n result[\"gadget-start-prefix\"] = validateString(\n rawObj[\"gadget-start-prefix\"],\n \"gadget-start-prefix\",\n section,\n );\n }\n if (\"gadget-end-prefix\" in rawObj) {\n result[\"gadget-end-prefix\"] = validateString(\n rawObj[\"gadget-end-prefix\"],\n \"gadget-end-prefix\",\n section,\n );\n }\n if (\"gadget-arg-prefix\" in rawObj) {\n result[\"gadget-arg-prefix\"] = validateString(\n rawObj[\"gadget-arg-prefix\"],\n \"gadget-arg-prefix\",\n section,\n );\n }\n if (\"gadget-approval\" in rawObj) {\n result[\"gadget-approval\"] = validateGadgetApproval(rawObj[\"gadget-approval\"], section);\n }\n if (\"subagents\" in rawObj) {\n result.subagents = validateSubagentConfigMap(rawObj.subagents, section);\n }\n\n // Complete-specific fields\n if (\"max-tokens\" in rawObj) {\n result[\"max-tokens\"] = validateNumber(rawObj[\"max-tokens\"], \"max-tokens\", section, {\n integer: true,\n min: 1,\n });\n }\n\n // Shared fields\n if (\"quiet\" in rawObj) {\n result.quiet = validateBoolean(rawObj.quiet, \"quiet\", section);\n }\n\n // Logging options\n Object.assign(result, validateLoggingConfig(rawObj, section));\n\n return result;\n}\n\n/**\n * Validates the prompts config section.\n * Each key must be a string (prompt name) and each value must be a string (template).\n */\nfunction validatePromptsConfig(raw: unknown, section: string): PromptsConfig {\n if (typeof raw !== \"object\" || raw === null) {\n throw new ConfigError(`[${section}] must be a table`);\n }\n\n const result: PromptsConfig = {};\n for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof value !== \"string\") {\n throw new ConfigError(`[${section}].${key} must be a string`);\n }\n result[key] = value;\n }\n return result;\n}\n\n/**\n * Validates and normalizes raw TOML object to CLIConfig.\n *\n * @throws ConfigError if validation fails\n */\nexport function validateConfig(raw: unknown, configPath?: string): CLIConfig {\n if (typeof raw !== \"object\" || raw === null) {\n throw new ConfigError(\"Config must be a TOML table\", configPath);\n }\n\n const rawObj = raw as Record<string, unknown>;\n const result: CLIConfig = {};\n\n for (const [key, value] of Object.entries(rawObj)) {\n try {\n if (key === \"global\") {\n result.global = validateGlobalConfig(value, key);\n } else if (key === \"complete\") {\n result.complete = validateCompleteConfig(value, key);\n } else if (key === \"agent\") {\n result.agent = validateAgentConfig(value, key);\n } else if (key === \"image\") {\n result.image = validateImageConfig(value, key);\n } else if (key === \"speech\") {\n result.speech = validateSpeechConfig(value, key);\n } else if (key === \"prompts\") {\n result.prompts = validatePromptsConfig(value, key);\n } else if (key === \"docker\") {\n result.docker = validateDockerConfig(value, key);\n } else if (key === \"subagents\") {\n result.subagents = validateGlobalSubagentConfig(value, key);\n } else {\n // Custom command section\n result[key] = validateCustomConfig(value, key);\n }\n } catch (error) {\n if (error instanceof ConfigError) {\n throw new ConfigError(error.message, configPath);\n }\n throw error;\n }\n }\n\n return result;\n}\n\n/**\n * Loads configuration from the default path (~/.llmist/cli.toml).\n * Returns empty config if file doesn't exist.\n *\n * @throws ConfigError if file exists but has invalid syntax or unknown fields\n */\nexport function loadConfig(): CLIConfig {\n const configPath = getConfigPath();\n\n if (!existsSync(configPath)) {\n return {};\n }\n\n let content: string;\n try {\n content = readFileSync(configPath, \"utf-8\");\n } catch (error) {\n throw new ConfigError(\n `Failed to read config file: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n configPath,\n );\n }\n\n let raw: unknown;\n try {\n raw = parseToml(content);\n } catch (error) {\n throw new ConfigError(\n `Invalid TOML syntax: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n configPath,\n );\n }\n\n const validated = validateConfig(raw, configPath);\n const inherited = resolveInheritance(validated, configPath);\n return resolveTemplatesInConfig(inherited, configPath);\n}\n\n/**\n * Gets list of custom command names from config (excludes built-in sections).\n */\nexport function getCustomCommandNames(config: CLIConfig): string[] {\n const reserved = new Set([\n \"global\",\n \"complete\",\n \"agent\",\n \"image\",\n \"speech\",\n \"prompts\",\n \"docker\",\n \"subagents\",\n ]);\n return Object.keys(config).filter((key) => !reserved.has(key));\n}\n\n/**\n * Resolves Eta templates in system prompts throughout the config.\n * Templates are resolved using the [prompts] section as named partials.\n *\n * @param config - Config with inheritance already resolved\n * @param configPath - Path to config file for error messages\n * @returns Config with all templates resolved in system prompts\n * @throws ConfigError if template resolution fails\n */\nexport function resolveTemplatesInConfig(config: CLIConfig, configPath?: string): CLIConfig {\n const prompts = config.prompts ?? {};\n\n // If no prompts and no templates used, return as-is\n const hasPrompts = Object.keys(prompts).length > 0;\n\n // Check if any section uses template syntax\n let hasTemplates = false;\n for (const [sectionName, section] of Object.entries(config)) {\n if (sectionName === \"global\" || sectionName === \"prompts\") continue;\n if (!section || typeof section !== \"object\") continue;\n\n const sectionObj = section as Record<string, unknown>;\n if (typeof sectionObj.system === \"string\" && hasTemplateSyntax(sectionObj.system)) {\n hasTemplates = true;\n break;\n }\n }\n\n // Also check prompts for template syntax (they may reference each other)\n for (const template of Object.values(prompts)) {\n if (hasTemplateSyntax(template)) {\n hasTemplates = true;\n break;\n }\n }\n\n // Quick return if nothing to do\n if (!hasPrompts && !hasTemplates) {\n return config;\n }\n\n // Validate all prompts compile correctly and env vars exist\n try {\n validatePrompts(prompts, configPath);\n } catch (error) {\n if (error instanceof TemplateError) {\n throw new ConfigError(error.message, configPath);\n }\n throw error;\n }\n\n // Validate environment variables in all prompts\n for (const [name, template] of Object.entries(prompts)) {\n try {\n validateEnvVars(template, name, configPath);\n } catch (error) {\n if (error instanceof TemplateError) {\n throw new ConfigError(error.message, configPath);\n }\n throw error;\n }\n }\n\n // Create template engine with all prompts registered\n const eta = createTemplateEngine(prompts, configPath);\n const result = { ...config };\n\n // Resolve templates in all sections with system fields\n for (const [sectionName, section] of Object.entries(config)) {\n if (sectionName === \"global\" || sectionName === \"prompts\") continue;\n if (!section || typeof section !== \"object\") continue;\n\n const sectionObj = section as Record<string, unknown>;\n if (typeof sectionObj.system === \"string\" && hasTemplateSyntax(sectionObj.system)) {\n // Validate env vars in the system prompt itself\n try {\n validateEnvVars(sectionObj.system, undefined, configPath);\n } catch (error) {\n if (error instanceof TemplateError) {\n throw new ConfigError(`[${sectionName}].system: ${error.message}`, configPath);\n }\n throw error;\n }\n\n // Resolve the template\n try {\n const resolved = resolveTemplate(eta, sectionObj.system, {}, configPath);\n result[sectionName] = {\n ...sectionObj,\n system: resolved,\n };\n } catch (error) {\n if (error instanceof TemplateError) {\n throw new ConfigError(`[${sectionName}].system: ${error.message}`, configPath);\n }\n throw error;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Resolves gadget configuration with inheritance support.\n * Handles gadgets (full replacement), gadget-add (append), and gadget-remove (filter).\n *\n * Resolution order:\n * 1. If `gadgets` is present (or deprecated `gadget`), use it as full replacement\n * 2. Otherwise, start with inherited gadgets and apply add/remove\n *\n * @param section - The section's own values (not yet merged)\n * @param inheritedGadgets - Gadgets from parent sections\n * @param sectionName - Name of section for error messages\n * @param configPath - Path to config file for error messages\n * @returns Resolved gadget array\n * @throws ConfigError if conflicting gadget options\n */\nfunction resolveGadgets(\n section: Record<string, unknown>,\n inheritedGadgets: string[],\n sectionName: string,\n configPath?: string,\n): string[] {\n const hasGadgets = \"gadgets\" in section;\n const hasGadgetLegacy = \"gadget\" in section;\n const hasGadgetAdd = \"gadget-add\" in section;\n const hasGadgetRemove = \"gadget-remove\" in section;\n\n // Warn on deprecated 'gadget' usage\n if (hasGadgetLegacy && !hasGadgets) {\n console.warn(\n `[config] Warning: [${sectionName}].gadget is deprecated, use 'gadgets' (plural) instead`,\n );\n }\n\n // Error if both full replacement AND add/remove\n if ((hasGadgets || hasGadgetLegacy) && (hasGadgetAdd || hasGadgetRemove)) {\n throw new ConfigError(\n `[${sectionName}] Cannot use 'gadgets' with 'gadget-add'/'gadget-remove'. ` +\n `Use either full replacement (gadgets) OR modification (gadget-add/gadget-remove).`,\n configPath,\n );\n }\n\n // Full replacement mode (new `gadgets` takes precedence over deprecated `gadget`)\n if (hasGadgets) {\n return section.gadgets as string[];\n }\n if (hasGadgetLegacy) {\n return section.gadget as string[];\n }\n\n // Modification mode: start with inherited\n let result = [...inheritedGadgets];\n\n // Apply removes first\n if (hasGadgetRemove) {\n const toRemove = new Set(section[\"gadget-remove\"] as string[]);\n result = result.filter((g) => !toRemove.has(g));\n }\n\n // Then apply adds\n if (hasGadgetAdd) {\n const toAdd = section[\"gadget-add\"] as string[];\n result.push(...toAdd);\n }\n\n return result;\n}\n\n/**\n * Resolves inheritance chains for all sections in the config.\n * Each section can specify `inherits` as a string or array of strings.\n * Resolution follows these rules:\n * - For multiple parents, later parents override earlier ones (last wins)\n * - Section's own values always override inherited values\n * - Arrays are replaced, not merged (except gadgets with add/remove support)\n * - Circular inheritance is detected and throws an error\n *\n * @param config - Validated config with possible unresolved inheritance\n * @param configPath - Path to config file for error messages\n * @returns Config with all inheritance resolved\n * @throws ConfigError if circular inheritance or unknown parent section\n */\nexport function resolveInheritance(config: CLIConfig, configPath?: string): CLIConfig {\n const resolved: Record<string, Record<string, unknown>> = {};\n const resolving = new Set<string>(); // For cycle detection\n\n function resolveSection(name: string): Record<string, unknown> {\n // Return cached if already resolved\n if (name in resolved) {\n return resolved[name];\n }\n\n // Cycle detection\n if (resolving.has(name)) {\n throw new ConfigError(`Circular inheritance detected: ${name}`, configPath);\n }\n\n const section = config[name];\n if (section === undefined || typeof section !== \"object\") {\n throw new ConfigError(`Cannot inherit from unknown section: ${name}`, configPath);\n }\n\n resolving.add(name);\n\n // Get inheritance list (normalize to array)\n const sectionObj = section as Record<string, unknown>;\n const inheritsRaw = sectionObj.inherits;\n const inheritsList: string[] = inheritsRaw\n ? Array.isArray(inheritsRaw)\n ? inheritsRaw\n : [inheritsRaw]\n : [];\n\n // Resolve all parents first (recursive), merge in order (last wins)\n let merged: Record<string, unknown> = {};\n for (const parent of inheritsList) {\n const parentResolved = resolveSection(parent);\n merged = { ...merged, ...parentResolved };\n }\n\n // Get inherited gadgets before applying own values\n const inheritedGadgets = (merged.gadgets as string[] | undefined) ?? [];\n\n // Apply own values on top (excluding metadata and gadget-related keys handled specially)\n const {\n inherits: _inherits,\n gadgets: _gadgets,\n gadget: _gadget,\n \"gadget-add\": _gadgetAdd,\n \"gadget-remove\": _gadgetRemove,\n ...ownValues\n } = sectionObj;\n merged = { ...merged, ...ownValues };\n\n // Resolve gadgets with add/remove support\n const resolvedGadgets = resolveGadgets(sectionObj, inheritedGadgets, name, configPath);\n if (resolvedGadgets.length > 0) {\n merged.gadgets = resolvedGadgets;\n }\n\n // Clean up legacy/modification fields from output\n delete merged[\"gadget\"];\n delete merged[\"gadget-add\"];\n delete merged[\"gadget-remove\"];\n\n resolving.delete(name);\n resolved[name] = merged;\n return merged;\n }\n\n // Resolve all sections\n for (const name of Object.keys(config)) {\n resolveSection(name);\n }\n\n return resolved as unknown as CLIConfig;\n}\n","import { Eta } from \"eta\";\n\n/**\n * Configuration for reusable prompt templates.\n * Each key is a prompt name, value is the template string.\n */\nexport interface PromptsConfig {\n [name: string]: string;\n}\n\n/**\n * Error thrown when template processing fails.\n */\nexport class TemplateError extends Error {\n constructor(\n message: string,\n public readonly promptName?: string,\n public readonly configPath?: string,\n ) {\n super(promptName ? `[prompts.${promptName}]: ${message}` : message);\n this.name = \"TemplateError\";\n }\n}\n\n/**\n * Creates an Eta instance configured with prompts as named templates.\n * Templates are registered with an @ prefix (e.g., @base-assistant).\n *\n * @param prompts - Map of prompt names to template strings\n * @param configPath - Path to config file for error messages\n * @returns Configured Eta instance\n * @throws TemplateError if a template has invalid syntax\n */\nexport function createTemplateEngine(prompts: PromptsConfig, configPath?: string): Eta {\n const eta = new Eta({\n views: \"/\", // Required but we use named templates\n autoEscape: false, // Don't escape - these are prompts, not HTML\n autoTrim: false, // Preserve whitespace in prompts\n });\n\n // Register all prompts as named templates with @ prefix\n // loadTemplate parses the template and will throw on syntax errors\n for (const [name, template] of Object.entries(prompts)) {\n try {\n eta.loadTemplate(`@${name}`, template);\n } catch (error) {\n throw new TemplateError(\n error instanceof Error ? error.message : String(error),\n name,\n configPath,\n );\n }\n }\n\n return eta;\n}\n\n/**\n * Resolves a template string using the configured Eta engine.\n * Injects environment variables into the context.\n *\n * @param eta - Configured Eta instance\n * @param template - Template string to resolve\n * @param context - Additional context variables\n * @param configPath - Path to config file for error messages\n * @returns Resolved template string\n */\nexport function resolveTemplate(\n eta: Eta,\n template: string,\n context: Record<string, unknown> = {},\n configPath?: string,\n): string {\n try {\n // Merge env vars and built-in variables into context\n const fullContext = {\n ...context,\n env: process.env,\n date: new Date().toISOString().split(\"T\")[0], // \"2025-12-01\"\n };\n return eta.renderString(template, fullContext);\n } catch (error) {\n throw new TemplateError(\n error instanceof Error ? error.message : String(error),\n undefined,\n configPath,\n );\n }\n}\n\n/**\n * Validates that all prompts can be compiled and references exist.\n * This is called at config load time to fail fast on errors.\n *\n * @param prompts - Map of prompt names to template strings\n * @param configPath - Path to config file for error messages\n * @throws TemplateError if validation fails\n */\nexport function validatePrompts(prompts: PromptsConfig, configPath?: string): void {\n // createTemplateEngine will throw TemplateError on syntax errors during loadTemplate\n const eta = createTemplateEngine(prompts, configPath);\n\n // Also try to render each template to catch missing includes\n for (const [name, template] of Object.entries(prompts)) {\n try {\n // Try to render with empty context to catch missing includes\n // (references to undefined prompts)\n eta.renderString(template, { env: {} });\n } catch (error) {\n throw new TemplateError(\n error instanceof Error ? error.message : String(error),\n name,\n configPath,\n );\n }\n }\n}\n\n/**\n * Validates that all environment variables referenced in a template are defined.\n *\n * @param template - Template string to check\n * @param promptName - Name of the prompt for error messages\n * @param configPath - Path to config file for error messages\n * @throws TemplateError if an undefined env var is referenced\n */\nexport function validateEnvVars(template: string, promptName?: string, configPath?: string): void {\n // Match <%= it.env.VAR_NAME %> patterns\n const envVarPattern = /<%=\\s*it\\.env\\.(\\w+)\\s*%>/g;\n const matches = template.matchAll(envVarPattern);\n\n for (const match of matches) {\n const varName = match[1] as string;\n if (process.env[varName] === undefined) {\n throw new TemplateError(\n `Environment variable '${varName}' is not set`,\n promptName,\n configPath,\n );\n }\n }\n}\n\n/**\n * Checks if a string contains Eta template syntax.\n * Used to determine if a system prompt needs template resolution.\n *\n * @param str - String to check\n * @returns true if the string contains template syntax\n */\nexport function hasTemplateSyntax(str: string): boolean {\n return str.includes(\"<%\");\n}\n","/**\n * Docker sandboxing type definitions.\n *\n * These types define the configuration schema for running llmist agent\n * commands inside Docker containers for security isolation.\n */\n\n/**\n * Mount permission for Docker volume mounts.\n * - \"ro\": Read-only mount (safer, prevents modifications)\n * - \"rw\": Read-write mount (allows modifications)\n */\nexport type MountPermission = \"ro\" | \"rw\";\n\n/**\n * Valid mount permissions for validation.\n */\nexport const VALID_MOUNT_PERMISSIONS: MountPermission[] = [\"ro\", \"rw\"];\n\n/**\n * Configuration for an additional mount point.\n */\nexport interface MountConfig {\n /** Host path to mount (supports ~ for home directory) */\n source: string;\n /** Path inside the container */\n target: string;\n /** Mount permission mode */\n permission: MountPermission;\n}\n\n/**\n * Docker configuration section in cli.toml.\n *\n * @example\n * ```toml\n * [docker]\n * enabled = true\n * cwd-permission = \"rw\"\n * config-permission = \"ro\"\n * image-name = \"llmist-sandbox\"\n *\n * [[docker.mounts]]\n * source = \"~/data\"\n * target = \"/data\"\n * permission = \"ro\"\n * ```\n */\nexport interface DockerConfig {\n /** Enable Docker sandboxing globally (default: false) */\n enabled?: boolean;\n\n /** Custom Dockerfile contents (overrides default template) */\n dockerfile?: string;\n\n /** Permission for current working directory mount (default: \"rw\") */\n \"cwd-permission\"?: MountPermission;\n\n /** Permission for ~/.llmist config directory mount (default: \"ro\") */\n \"config-permission\"?: MountPermission;\n\n /** Additional mount points */\n mounts?: MountConfig[];\n\n /** Extra environment variables to forward to container */\n \"env-vars\"?: string[];\n\n /** Custom Docker image name (default: \"llmist-sandbox\") */\n \"image-name\"?: string;\n\n /** Extra arguments to pass to docker run (e.g., [\"-p\", \"3000:3000\"]) */\n \"docker-args\"?: string[];\n}\n\n/**\n * Valid keys for docker config validation.\n */\nexport const DOCKER_CONFIG_KEYS = new Set([\n \"enabled\",\n \"dockerfile\",\n \"cwd-permission\",\n \"config-permission\",\n \"mounts\",\n \"env-vars\",\n \"image-name\",\n \"docker-args\",\n]);\n\n/**\n * Docker CLI options (resolved from config and CLI flags).\n */\nexport interface DockerOptions {\n /** Docker mode enabled via --docker flag */\n docker: boolean;\n /** Read-only CWD mount via --docker-ro flag */\n dockerRo: boolean;\n /** Explicitly disabled via --no-docker flag */\n noDocker: boolean;\n}\n\n/**\n * Resolved Docker execution context.\n */\nexport interface DockerExecutionContext {\n /** Merged Docker configuration */\n config: DockerConfig;\n /** CLI options */\n options: DockerOptions;\n /** Original CLI arguments to forward (minus docker flags) */\n forwardArgs: string[];\n /** Current working directory on host */\n cwd: string;\n /** Profile-level CWD permission override (takes precedence over config) */\n profileCwdPermission?: MountPermission;\n}\n\n/**\n * Default Docker image name.\n */\nexport const DEFAULT_IMAGE_NAME = \"llmist-sandbox\";\n\n/**\n * Default mount permissions.\n */\nexport const DEFAULT_CWD_PERMISSION: MountPermission = \"rw\";\nexport const DEFAULT_CONFIG_PERMISSION: MountPermission = \"ro\";\n\n/**\n * Named Docker volume for container's gadget-cache.\n *\n * This keeps the container's compiled gadgets separate from the host's,\n * avoiding cross-platform native module issues (e.g., macOS host -> Linux container).\n */\nexport const GADGET_CACHE_VOLUME = \"llmist-gadget-cache\";\n\n/**\n * API keys that are always forwarded to the container.\n */\nexport const FORWARDED_API_KEYS = [\n \"ANTHROPIC_API_KEY\",\n \"OPENAI_API_KEY\",\n \"GEMINI_API_KEY\",\n] as const;\n\n","/**\n * Docker configuration validation.\n *\n * Follows the same validation patterns as the main config.ts module.\n */\n\nimport { ConfigError } from \"../config.js\";\nimport {\n DOCKER_CONFIG_KEYS,\n type DockerConfig,\n type MountConfig,\n type MountPermission,\n VALID_MOUNT_PERMISSIONS,\n} from \"./types.js\";\n\n/**\n * Valid keys for mount config objects.\n */\nconst MOUNT_CONFIG_KEYS = new Set([\"source\", \"target\", \"permission\"]);\n\n/**\n * Validates that a value is a string.\n */\nfunction validateString(value: unknown, key: string, section: string): string {\n if (typeof value !== \"string\") {\n throw new ConfigError(`[${section}].${key} must be a string`);\n }\n return value;\n}\n\n/**\n * Validates that a value is a boolean.\n */\nfunction validateBoolean(value: unknown, key: string, section: string): boolean {\n if (typeof value !== \"boolean\") {\n throw new ConfigError(`[${section}].${key} must be a boolean`);\n }\n return value;\n}\n\n/**\n * Validates that a value is an array of strings.\n */\nfunction validateStringArray(value: unknown, key: string, section: string): string[] {\n if (!Array.isArray(value)) {\n throw new ConfigError(`[${section}].${key} must be an array`);\n }\n for (let i = 0; i < value.length; i++) {\n if (typeof value[i] !== \"string\") {\n throw new ConfigError(`[${section}].${key}[${i}] must be a string`);\n }\n }\n return value as string[];\n}\n\n/**\n * Validates a mount permission value.\n */\nfunction validateMountPermission(value: unknown, key: string, section: string): MountPermission {\n const str = validateString(value, key, section);\n if (!VALID_MOUNT_PERMISSIONS.includes(str as MountPermission)) {\n throw new ConfigError(\n `[${section}].${key} must be one of: ${VALID_MOUNT_PERMISSIONS.join(\", \")}`,\n );\n }\n return str as MountPermission;\n}\n\n/**\n * Validates a single mount configuration object.\n */\nfunction validateMountConfig(value: unknown, index: number, section: string): MountConfig {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ConfigError(`[${section}].mounts[${index}] must be a table`);\n }\n\n const rawObj = value as Record<string, unknown>;\n const mountSection = `${section}.mounts[${index}]`;\n\n // Check for unknown keys\n for (const key of Object.keys(rawObj)) {\n if (!MOUNT_CONFIG_KEYS.has(key)) {\n throw new ConfigError(`[${mountSection}].${key} is not a valid mount option`);\n }\n }\n\n // Required fields\n if (!(\"source\" in rawObj)) {\n throw new ConfigError(`[${mountSection}] missing required field 'source'`);\n }\n if (!(\"target\" in rawObj)) {\n throw new ConfigError(`[${mountSection}] missing required field 'target'`);\n }\n if (!(\"permission\" in rawObj)) {\n throw new ConfigError(`[${mountSection}] missing required field 'permission'`);\n }\n\n return {\n source: validateString(rawObj.source, \"source\", mountSection),\n target: validateString(rawObj.target, \"target\", mountSection),\n permission: validateMountPermission(rawObj.permission, \"permission\", mountSection),\n };\n}\n\n/**\n * Validates an array of mount configurations.\n */\nfunction validateMountsArray(value: unknown, section: string): MountConfig[] {\n if (!Array.isArray(value)) {\n throw new ConfigError(`[${section}].mounts must be an array of tables`);\n }\n\n const result: MountConfig[] = [];\n for (let i = 0; i < value.length; i++) {\n result.push(validateMountConfig(value[i], i, section));\n }\n return result;\n}\n\n/**\n * Validates the docker configuration section.\n *\n * @param raw - Raw config object from TOML parser\n * @param section - Section name for error messages (usually \"docker\")\n * @returns Validated DockerConfig\n * @throws ConfigError if validation fails\n */\nexport function validateDockerConfig(raw: unknown, section: string): DockerConfig {\n if (typeof raw !== \"object\" || raw === null) {\n throw new ConfigError(`[${section}] must be a table`);\n }\n\n const rawObj = raw as Record<string, unknown>;\n\n // Check for unknown keys\n for (const key of Object.keys(rawObj)) {\n if (!DOCKER_CONFIG_KEYS.has(key)) {\n throw new ConfigError(`[${section}].${key} is not a valid option`);\n }\n }\n\n const result: DockerConfig = {};\n\n if (\"enabled\" in rawObj) {\n result.enabled = validateBoolean(rawObj.enabled, \"enabled\", section);\n }\n\n if (\"dockerfile\" in rawObj) {\n result.dockerfile = validateString(rawObj.dockerfile, \"dockerfile\", section);\n }\n\n if (\"cwd-permission\" in rawObj) {\n result[\"cwd-permission\"] = validateMountPermission(\n rawObj[\"cwd-permission\"],\n \"cwd-permission\",\n section,\n );\n }\n\n if (\"config-permission\" in rawObj) {\n result[\"config-permission\"] = validateMountPermission(\n rawObj[\"config-permission\"],\n \"config-permission\",\n section,\n );\n }\n\n if (\"mounts\" in rawObj) {\n result.mounts = validateMountsArray(rawObj.mounts, section);\n }\n\n if (\"env-vars\" in rawObj) {\n result[\"env-vars\"] = validateStringArray(rawObj[\"env-vars\"], \"env-vars\", section);\n }\n\n if (\"image-name\" in rawObj) {\n result[\"image-name\"] = validateString(rawObj[\"image-name\"], \"image-name\", section);\n }\n\n // Note: docker-args is intentionally only configurable in the global ~/.llmist/cli.toml.\n // Since llmist only loads config from the user's home directory (not project-level configs),\n // this is inherently safe from supply-chain attacks where a malicious project could inject\n // dangerous Docker arguments like \"--privileged\" or \"-v /:/host\".\n if (\"docker-args\" in rawObj) {\n result[\"docker-args\"] = validateStringArray(rawObj[\"docker-args\"], \"docker-args\", section);\n }\n\n return result;\n}\n","/**\n * Docker execution wrapper.\n *\n * Handles:\n * - Checking if Docker is available\n * - Building/caching the Docker image\n * - Running llmist inside the container\n * - Forwarding environment variables and mounts\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { resolveDockerfile } from \"./dockerfile.js\";\nimport { DockerBuildError, ensureImage } from \"./image-manager.js\";\nimport {\n DEFAULT_CONFIG_PERMISSION,\n DEFAULT_CWD_PERMISSION,\n DEFAULT_IMAGE_NAME,\n GADGET_CACHE_VOLUME,\n type DockerConfig,\n type DockerExecutionContext,\n type DockerOptions,\n FORWARDED_API_KEYS,\n type MountPermission,\n} from \"./types.js\";\n\n/**\n * Error thrown when Docker is not available.\n */\nexport class DockerUnavailableError extends Error {\n constructor() {\n super(\n \"Docker is required but not available. \" +\n \"Install Docker or disable Docker sandboxing in your configuration.\",\n );\n this.name = \"DockerUnavailableError\";\n }\n}\n\n/**\n * Error thrown when Docker container execution fails.\n */\nexport class DockerRunError extends Error {\n constructor(\n public readonly exitCode: number,\n public readonly stderr: string,\n ) {\n super(`Docker container exited with code ${exitCode}`);\n this.name = \"DockerRunError\";\n }\n}\n\n/**\n * Error thrown when Docker execution should be skipped.\n * This occurs when already running inside a container.\n */\nexport class DockerSkipError extends Error {\n constructor() {\n super(\"Docker execution skipped - already inside container\");\n this.name = \"DockerSkipError\";\n }\n}\n\n/**\n * Checks if Docker is available and running.\n *\n * @returns true if Docker is available\n */\nexport async function checkDockerAvailable(): Promise<boolean> {\n try {\n const proc = Bun.spawn([\"docker\", \"info\"], {\n stdout: \"pipe\",\n stderr: \"pipe\",\n });\n // Consume streams concurrently with awaiting exit to prevent potential deadlock\n await Promise.all([\n proc.exited,\n new Response(proc.stdout).text(),\n new Response(proc.stderr).text(),\n ]);\n return proc.exitCode === 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if we're already running inside a Docker container.\n *\n * Detection methods:\n * 1. /.dockerenv file - Docker creates this in all containers\n * 2. /proc/1/cgroup contains \"docker\" or \"containerd\" - Linux cgroup detection\n *\n * @returns true if running inside a container\n */\nexport function isInsideContainer(): boolean {\n // Method 1: Check for /.dockerenv (most reliable)\n if (existsSync(\"/.dockerenv\")) {\n return true;\n }\n\n // Method 2: Check cgroup for docker/containerd (Linux)\n try {\n const cgroup = readFileSync(\"/proc/1/cgroup\", \"utf-8\");\n if (cgroup.includes(\"docker\") || cgroup.includes(\"containerd\")) {\n return true;\n }\n } catch {\n // Not on Linux or no access to /proc\n }\n\n return false;\n}\n\n/**\n * Expands ~ to home directory in a path.\n */\nfunction expandHome(path: string): string {\n if (path.startsWith(\"~\")) {\n return path.replace(/^~/, homedir());\n }\n return path;\n}\n\n/**\n * Builds the docker run command arguments.\n *\n * @param ctx - Docker execution context\n * @param imageName - Docker image name to run\n * @returns Array of arguments for docker run\n */\nfunction buildDockerRunArgs(ctx: DockerExecutionContext, imageName: string): string[] {\n const args: string[] = [\"run\", \"--rm\"];\n\n // Generate unique container name to avoid collisions\n const timestamp = Date.now();\n const random = Math.random().toString(36).slice(2, 8);\n const containerName = `llmist-${timestamp}-${random}`;\n args.push(\"--name\", containerName);\n\n // TTY handling - only add -it if stdin is a TTY\n if (process.stdin.isTTY) {\n args.push(\"-it\");\n }\n\n // Mount current working directory\n // Priority: --docker-ro flag > profile-level > config-level > default\n const cwdPermission: MountPermission = ctx.options.dockerRo\n ? \"ro\"\n : (ctx.profileCwdPermission ?? ctx.config[\"cwd-permission\"] ?? DEFAULT_CWD_PERMISSION);\n args.push(\"-v\", `${ctx.cwd}:/workspace:${cwdPermission}`);\n args.push(\"-w\", \"/workspace\");\n\n // Mount llmist config selectively (not entire ~/.llmist)\n // This avoids sharing gadget-cache between host and container, preventing\n // cross-platform native module issues (e.g., macOS host -> Linux container)\n const configPermission = ctx.config[\"config-permission\"] ?? DEFAULT_CONFIG_PERMISSION;\n const llmistDir = expandHome(\"~/.llmist\");\n\n // Mount cli.toml config file (if exists)\n const cliTomlPath = `${llmistDir}/cli.toml`;\n if (existsSync(cliTomlPath)) {\n args.push(\"-v\", `${cliTomlPath}:/root/.llmist/cli.toml:${configPermission}`);\n }\n\n // Mount gadgets directory (if exists) - local gadget definitions\n const gadgetsDir = `${llmistDir}/gadgets`;\n if (existsSync(gadgetsDir)) {\n args.push(\"-v\", `${gadgetsDir}:/root/.llmist/gadgets:${configPermission}`);\n }\n\n // Use named volume for gadget-cache - container builds its own cached gadgets\n // This persists across container runs but stays separate from host's cache\n args.push(\"-v\", `${GADGET_CACHE_VOLUME}:/root/.llmist/gadget-cache`);\n\n // Additional mounts from config\n if (ctx.config.mounts) {\n for (const mount of ctx.config.mounts) {\n const source = expandHome(mount.source);\n args.push(\"-v\", `${source}:${mount.target}:${mount.permission}`);\n }\n }\n\n // Forward API keys (if set in environment)\n for (const key of FORWARDED_API_KEYS) {\n if (process.env[key]) {\n args.push(\"-e\", key);\n }\n }\n\n // Forward additional env vars from config\n if (ctx.config[\"env-vars\"]) {\n for (const key of ctx.config[\"env-vars\"]) {\n if (process.env[key]) {\n args.push(\"-e\", key);\n }\n }\n }\n\n // Extra docker run arguments from config (e.g., port mappings, network mode)\n if (ctx.config[\"docker-args\"]) {\n args.push(...ctx.config[\"docker-args\"]);\n }\n\n // Image name\n args.push(imageName);\n\n // Forward the CLI arguments (these go to llmist inside the container)\n args.push(...ctx.forwardArgs);\n\n return args;\n}\n\n/**\n * Filters out Docker-related flags from CLI arguments.\n *\n * These flags are consumed by the wrapper and should not be\n * passed to the llmist instance inside the container.\n *\n * @param argv - Original CLI arguments\n * @returns Filtered arguments without Docker flags\n */\nexport function filterDockerArgs(argv: string[]): string[] {\n const dockerFlags = new Set([\"--docker\", \"--docker-ro\", \"--no-docker\"]);\n return argv.filter((arg) => !dockerFlags.has(arg));\n}\n\n/**\n * Resolves whether Docker mode should be enabled.\n *\n * Priority (highest to lowest):\n * 1. --no-docker flag (disables)\n * 2. --docker or --docker-ro flag (enables)\n * 3. Profile/command docker: true in config\n * 4. Global [docker].enabled in config\n *\n * @param config - Docker configuration\n * @param options - CLI options\n * @param profileDocker - docker: true/false from profile config\n * @returns Whether Docker mode is enabled\n */\nexport function resolveDockerEnabled(\n config: DockerConfig | undefined,\n options: DockerOptions,\n profileDocker?: boolean,\n): boolean {\n // CLI --no-docker overrides everything\n if (options.noDocker) {\n return false;\n }\n\n // CLI --docker or --docker-ro enables\n if (options.docker || options.dockerRo) {\n return true;\n }\n\n // Profile-level docker: true/false\n if (profileDocker !== undefined) {\n return profileDocker;\n }\n\n // Global [docker].enabled\n return config?.enabled ?? false;\n}\n\n/**\n * Executes llmist inside a Docker container.\n *\n * This function:\n * 1. Checks if already inside a container (prevents nesting)\n * 2. Verifies Docker is available\n * 3. Builds/caches the image\n * 4. Runs the container with appropriate mounts and env vars\n * 5. Exits with the container's exit code\n *\n * @param ctx - Docker execution context\n * @throws DockerUnavailableError if Docker is not available\n * @throws DockerBuildError if image building fails\n * @throws DockerRunError if container execution fails\n */\nexport async function executeInDocker(ctx: DockerExecutionContext): Promise<never> {\n // Check if we're already inside a container\n if (isInsideContainer()) {\n // Silently skip re-containerization when already inside a container\n throw new DockerSkipError();\n }\n\n // Check Docker availability\n const available = await checkDockerAvailable();\n if (!available) {\n throw new DockerUnavailableError();\n }\n\n // Resolve Dockerfile and image name\n const dockerfile = resolveDockerfile(ctx.config);\n const imageName = ctx.config[\"image-name\"] ?? DEFAULT_IMAGE_NAME;\n\n try {\n await ensureImage(imageName, dockerfile);\n } catch (error) {\n if (error instanceof DockerBuildError) {\n console.error(\"Docker build failed:\");\n console.error(error.output);\n throw error;\n }\n throw error;\n }\n\n // Build docker run command\n const dockerArgs = buildDockerRunArgs(ctx, imageName);\n\n // Execute container\n const proc = Bun.spawn([\"docker\", ...dockerArgs], {\n stdin: \"inherit\",\n stdout: \"inherit\",\n stderr: \"inherit\",\n });\n\n const exitCode = await proc.exited;\n process.exit(exitCode);\n}\n\n/**\n * Creates a Docker execution context from config and options.\n *\n * @param config - Docker configuration\n * @param options - CLI options\n * @param argv - Original CLI arguments (without 'node' and script name)\n * @param cwd - Current working directory\n * @param profileCwdPermission - Profile-level CWD permission override\n * @returns Docker execution context\n */\nexport function createDockerContext(\n config: DockerConfig | undefined,\n options: DockerOptions,\n argv: string[],\n cwd: string,\n profileCwdPermission?: \"ro\" | \"rw\",\n): DockerExecutionContext {\n return {\n config: config ?? {},\n options,\n forwardArgs: filterDockerArgs(argv),\n cwd,\n profileCwdPermission,\n };\n}\n\n// Re-export errors for consumers\nexport { DockerBuildError } from \"./image-manager.js\";\n","/**\n * Dockerfile templates for llmist sandboxing.\n *\n * Includes:\n * - Bun runtime\n * - ed (line editor for EditFile gadget)\n * - ripgrep (fast search tool)\n * - ast-grep (code search/refactoring)\n * - git (version control)\n *\n * For development setups, use a custom dockerfile in config with docker-args\n * to mount your local source.\n */\n\nimport type { DockerConfig } from \"./types.js\";\n\n/**\n * Default Dockerfile template.\n *\n * Uses oven/bun:1-debian as base for:\n * - Modern Bun runtime\n * - Debian's extensive package ecosystem\n * - Good compatibility with common tools\n */\nexport const DEFAULT_DOCKERFILE = `# llmist sandbox image\n# Auto-generated - customize via [docker].dockerfile in cli.toml\n\nFROM oven/bun:1-debian\n\n# Install essential tools\nRUN apt-get update && apt-get install -y --no-install-recommends \\\\\n # ed for EditFile gadget (line-oriented editor)\n ed \\\\\n # ripgrep for fast file searching\n ripgrep \\\\\n # git for version control operations\n git \\\\\n # curl for downloads and API calls\n curl \\\\\n # ca-certificates for HTTPS\n ca-certificates \\\\\n # python3 for native module compilation (node-gyp)\n python3 \\\\\n # build-essential for compiling native modules\n build-essential \\\\\n && rm -rf /var/lib/apt/lists/*\n\n# Install ast-grep for code search/refactoring\n# Using the official install script\nRUN curl -fsSL https://raw.githubusercontent.com/ast-grep/ast-grep/main/install.sh | bash \\\\\n && mv /root/.local/bin/ast-grep /usr/local/bin/ 2>/dev/null || true \\\\\n && mv /root/.local/bin/sg /usr/local/bin/ 2>/dev/null || true\n\n# Install llmist globally via bun\nRUN bun add -g llmist\n\n# Working directory (host CWD will be mounted here)\nWORKDIR /workspace\n\n# Entry point - llmist with all arguments forwarded\nENTRYPOINT [\"llmist\"]\n`;\n\n/**\n * Resolves the Dockerfile content to use.\n *\n * Returns custom dockerfile from config if provided, otherwise DEFAULT_DOCKERFILE.\n *\n * @param config - Docker configuration\n * @returns Dockerfile content\n */\nexport function resolveDockerfile(config: DockerConfig): string {\n return config.dockerfile ?? DEFAULT_DOCKERFILE;\n}\n\n/**\n * Computes a hash of the Dockerfile content for cache invalidation.\n *\n * Uses Bun's fast native hash function.\n *\n * @param dockerfile - Dockerfile content\n * @returns Hex string hash\n */\nexport function computeDockerfileHash(dockerfile: string): string {\n const encoder = new TextEncoder();\n const data = encoder.encode(dockerfile);\n // Bun.hash returns a 64-bit hash as BigInt, convert to hex string\n return Bun.hash(data).toString(16);\n}\n","/**\n * Docker image building and caching.\n *\n * Handles:\n * - Building Docker images from Dockerfile content\n * - Caching image hashes to avoid unnecessary rebuilds\n * - Checking if an image needs to be rebuilt\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { computeDockerfileHash } from \"./dockerfile.js\";\nimport { DEFAULT_IMAGE_NAME } from \"./types.js\";\n\n/**\n * Cache directory for Docker-related files.\n */\nconst CACHE_DIR = join(homedir(), \".llmist\", \"docker-cache\");\n\n/**\n * File storing the current image hash.\n */\nconst HASH_FILE = \"image-hash.json\";\n\n/**\n * Cache entry structure.\n */\ninterface CacheEntry {\n imageName: string;\n dockerfileHash: string;\n builtAt: string;\n}\n\n/**\n * Ensures the cache directory exists.\n */\nfunction ensureCacheDir(): void {\n if (!existsSync(CACHE_DIR)) {\n mkdirSync(CACHE_DIR, { recursive: true });\n }\n}\n\n/**\n * Gets the cached hash for an image name.\n *\n * @param imageName - Docker image name\n * @returns Cached dockerfile hash, or undefined if not cached\n */\nfunction getCachedHash(imageName: string): string | undefined {\n const hashPath = join(CACHE_DIR, HASH_FILE);\n\n if (!existsSync(hashPath)) {\n return undefined;\n }\n\n try {\n const content = readFileSync(hashPath, \"utf-8\");\n const cache = JSON.parse(content) as Record<string, CacheEntry>;\n return cache[imageName]?.dockerfileHash;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Saves the hash for an image name to cache.\n *\n * @param imageName - Docker image name\n * @param hash - Dockerfile hash\n */\nfunction setCachedHash(imageName: string, hash: string): void {\n ensureCacheDir();\n const hashPath = join(CACHE_DIR, HASH_FILE);\n\n let cache: Record<string, CacheEntry> = {};\n\n if (existsSync(hashPath)) {\n try {\n const content = readFileSync(hashPath, \"utf-8\");\n cache = JSON.parse(content) as Record<string, CacheEntry>;\n } catch {\n // Start fresh on parse error\n cache = {};\n }\n }\n\n cache[imageName] = {\n imageName,\n dockerfileHash: hash,\n builtAt: new Date().toISOString(),\n };\n\n writeFileSync(hashPath, JSON.stringify(cache, null, 2));\n}\n\n/**\n * Error thrown when Docker image building fails.\n */\nexport class DockerBuildError extends Error {\n constructor(\n message: string,\n public readonly output: string,\n ) {\n super(message);\n this.name = \"DockerBuildError\";\n }\n}\n\n/**\n * Builds a Docker image from Dockerfile content.\n *\n * @param imageName - Name/tag for the built image\n * @param dockerfile - Dockerfile content\n * @throws DockerBuildError if build fails\n */\nasync function buildImage(imageName: string, dockerfile: string): Promise<void> {\n // Write Dockerfile to temp location\n ensureCacheDir();\n const dockerfilePath = join(CACHE_DIR, \"Dockerfile\");\n writeFileSync(dockerfilePath, dockerfile);\n\n // Build the image with --no-cache to ensure Dockerfile changes take effect\n // Docker layer caching can cause issues when Dockerfile content changes\n const proc = Bun.spawn(\n [\"docker\", \"build\", \"--no-cache\", \"-t\", imageName, \"-f\", dockerfilePath, CACHE_DIR],\n {\n stdout: \"pipe\",\n stderr: \"pipe\",\n },\n );\n\n // Consume streams concurrently with awaiting exit to prevent deadlock.\n // If we await proc.exited first, large Docker build output can fill pipe buffers,\n // causing Docker to block on write while we block on exit - mutual deadlock.\n const [exitCode, stdout, stderr] = await Promise.all([\n proc.exited,\n new Response(proc.stdout).text(),\n new Response(proc.stderr).text(),\n ]);\n\n if (exitCode !== 0) {\n const output = [stdout, stderr].filter(Boolean).join(\"\\n\");\n throw new DockerBuildError(`Docker build failed with exit code ${exitCode}`, output);\n }\n}\n\n/**\n * Ensures the Docker image is built and up-to-date.\n *\n * Checks if the cached Dockerfile hash matches the current content.\n * If not, rebuilds the image.\n *\n * @param imageName - Docker image name (defaults to DEFAULT_IMAGE_NAME)\n * @param dockerfile - Dockerfile content\n * @returns The image name (for chaining)\n * @throws DockerBuildError if build fails\n */\nexport async function ensureImage(\n imageName: string = DEFAULT_IMAGE_NAME,\n dockerfile: string,\n): Promise<string> {\n const hash = computeDockerfileHash(dockerfile);\n const cachedHash = getCachedHash(imageName);\n\n if (cachedHash === hash) {\n // Image is up-to-date\n return imageName;\n }\n\n // Need to build/rebuild\n console.error(`Building Docker image '${imageName}'...`);\n await buildImage(imageName, dockerfile);\n\n // Update cache\n setCachedHash(imageName, hash);\n\n console.error(`Docker image '${imageName}' built successfully.`);\n return imageName;\n}\n\n/**\n * Checks if an image needs to be rebuilt.\n *\n * @param imageName - Docker image name\n * @param dockerfile - Dockerfile content\n * @returns true if rebuild is needed\n */\nexport function needsRebuild(imageName: string, dockerfile: string): boolean {\n const hash = computeDockerfileHash(dockerfile);\n const cachedHash = getCachedHash(imageName);\n return cachedHash !== hash;\n}\n\n/**\n * Clears the image cache for a specific image or all images.\n *\n * @param imageName - Image name to clear, or undefined to clear all\n */\nexport function clearImageCache(imageName?: string): void {\n const hashPath = join(CACHE_DIR, HASH_FILE);\n\n if (!existsSync(hashPath)) {\n return;\n }\n\n if (imageName) {\n try {\n const content = readFileSync(hashPath, \"utf-8\");\n const cache = JSON.parse(content) as Record<string, CacheEntry>;\n delete cache[imageName];\n writeFileSync(hashPath, JSON.stringify(cache, null, 2));\n } catch {\n // Ignore errors\n }\n } else {\n // Clear all\n writeFileSync(hashPath, \"{}\");\n }\n}\n","/**\n * File utilities for CLI multimodal input support.\n *\n * Provides functions to read and validate image and audio files\n * for use with multimodal LLM requests.\n */\n\nimport { readFile, stat } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\n\nimport {\n type AudioContentPart,\n type AudioMimeType,\n audioFromBuffer,\n detectAudioMimeType,\n detectImageMimeType,\n type ImageContentPart,\n type ImageMimeType,\n imageFromBuffer,\n} from \"../core/input-content.js\";\n\n/**\n * Default maximum file size: 50MB\n * This prevents accidentally loading very large files into memory.\n */\nexport const DEFAULT_MAX_FILE_SIZE = 50 * 1024 * 1024;\n\n/**\n * Options for file reading operations.\n */\nexport interface FileReadOptions {\n /**\n * Maximum allowed file size in bytes.\n * Files larger than this will throw an error.\n * Default: 50MB (DEFAULT_MAX_FILE_SIZE)\n */\n maxFileSize?: number;\n}\n\n/**\n * Format file size as human-readable string.\n */\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} bytes`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;\n}\n\n/**\n * Check file size before reading to prevent memory issues.\n */\nasync function checkFileSize(\n absolutePath: string,\n filePath: string,\n maxSize: number,\n): Promise<void> {\n const stats = await stat(absolutePath);\n if (stats.size > maxSize) {\n throw new Error(\n `File \"${filePath}\" is too large (${formatFileSize(stats.size)}). ` +\n `Maximum allowed size is ${formatFileSize(maxSize)}. ` +\n `Consider compressing the file or using a smaller version.`,\n );\n }\n}\n\n/**\n * Read and validate an image file.\n *\n * @param filePath - Path to image file (absolute or relative to cwd)\n * @param options - Optional configuration for file reading\n * @returns Image content part ready for LLM message\n * @throws Error if file doesn't exist, is too large, or isn't a valid image format\n *\n * @example\n * ```typescript\n * const imagePart = await readImageFile(\"./photo.jpg\");\n * const messages = [{ role: \"user\", content: [text(\"Describe this:\"), imagePart] }];\n * ```\n */\nexport async function readImageFile(\n filePath: string,\n options: FileReadOptions = {},\n): Promise<ImageContentPart> {\n const absolutePath = resolve(filePath);\n const maxFileSize = options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;\n\n let buffer: Buffer;\n try {\n await checkFileSize(absolutePath, filePath, maxFileSize);\n buffer = await readFile(absolutePath);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to read image file \"${filePath}\": ${message}`);\n }\n\n // Validate it's an image\n const mimeType = detectImageMimeType(buffer);\n if (!mimeType) {\n throw new Error(\n `File \"${filePath}\" is not a supported image format. ` +\n `Supported formats: JPEG, PNG, GIF, WebP`,\n );\n }\n\n return imageFromBuffer(buffer, mimeType);\n}\n\n/**\n * Read and validate an audio file.\n *\n * @param filePath - Path to audio file (absolute or relative to cwd)\n * @param options - Optional configuration for file reading\n * @returns Audio content part ready for LLM message\n * @throws Error if file doesn't exist, is too large, or isn't a valid audio format\n *\n * @example\n * ```typescript\n * const audioPart = await readAudioFile(\"./recording.mp3\");\n * const messages = [{ role: \"user\", content: [text(\"Transcribe:\"), audioPart] }];\n * ```\n */\nexport async function readAudioFile(\n filePath: string,\n options: FileReadOptions = {},\n): Promise<AudioContentPart> {\n const absolutePath = resolve(filePath);\n const maxFileSize = options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;\n\n let buffer: Buffer;\n try {\n await checkFileSize(absolutePath, filePath, maxFileSize);\n buffer = await readFile(absolutePath);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to read audio file \"${filePath}\": ${message}`);\n }\n\n // Validate it's audio\n const mimeType = detectAudioMimeType(buffer);\n if (!mimeType) {\n throw new Error(\n `File \"${filePath}\" is not a supported audio format. ` +\n `Supported formats: MP3, WAV, OGG, WebM`,\n );\n }\n\n return audioFromBuffer(buffer, mimeType);\n}\n\n/**\n * Read a file as raw buffer for multimodal input.\n * Use this when you need the raw data without converting to content parts.\n *\n * @param filePath - Path to file (absolute or relative to cwd)\n * @param options - Optional configuration for file reading\n * @returns File contents as Buffer\n * @throws Error if file doesn't exist, is too large, or can't be read\n */\nexport async function readFileBuffer(\n filePath: string,\n options: FileReadOptions = {},\n): Promise<Buffer> {\n const absolutePath = resolve(filePath);\n const maxFileSize = options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;\n\n try {\n await checkFileSize(absolutePath, filePath, maxFileSize);\n return await readFile(absolutePath);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to read file \"${filePath}\": ${message}`);\n }\n}\n\n/**\n * Validate that a file exists and has a supported image format.\n *\n * @param filePath - Path to file to validate\n * @returns Object with validation result and detected MIME type\n */\nexport async function validateImageFile(\n filePath: string,\n): Promise<{ valid: boolean; mimeType?: ImageMimeType; error?: string }> {\n try {\n const absolutePath = resolve(filePath);\n const buffer = await readFile(absolutePath);\n const mimeType = detectImageMimeType(buffer);\n\n if (!mimeType) {\n return {\n valid: false,\n error: \"Not a supported image format (JPEG, PNG, GIF, WebP)\",\n };\n }\n\n return { valid: true, mimeType };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { valid: false, error: message };\n }\n}\n\n/**\n * Validate that a file exists and has a supported audio format.\n *\n * @param filePath - Path to file to validate\n * @returns Object with validation result and detected MIME type\n */\nexport async function validateAudioFile(\n filePath: string,\n): Promise<{ valid: boolean; mimeType?: AudioMimeType; error?: string }> {\n try {\n const absolutePath = resolve(filePath);\n const buffer = await readFile(absolutePath);\n const mimeType = detectAudioMimeType(buffer);\n\n if (!mimeType) {\n return {\n valid: false,\n error: \"Not a supported audio format (MP3, WAV, OGG, WebM)\",\n };\n }\n\n return { valid: true, mimeType };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { valid: false, error: message };\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nimport { AbstractGadget } from \"../gadgets/gadget.js\";\nimport { getBuiltinGadget, isBuiltinGadgetName } from \"./builtins/index.js\";\nimport { isExternalPackageSpecifier, loadExternalGadgets } from \"./external-gadgets.js\";\n\n/**\n * Function type for importing modules dynamically.\n */\nexport type GadgetImportFunction = (specifier: string) => Promise<unknown>;\n\nconst PATH_PREFIXES = [\".\", \"/\", \"~\"];\nconst BUILTIN_PREFIX = \"builtin:\";\n\n/**\n * Duck-type check if a value looks like a Gadget instance.\n * This avoids instanceof issues when gadgets are loaded from external files\n * that import from the 'llmist' npm package (different class instance).\n */\nfunction isGadgetLike(value: unknown): value is AbstractGadget {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.execute === \"function\" &&\n typeof obj.description === \"string\" &&\n (\"parameterSchema\" in obj || \"schema\" in obj)\n );\n}\n\n/**\n * Type guard to check if a value is a Gadget constructor.\n * Checks if the prototype has an execute method (gadget classes created via Gadget()\n * factory put description/schema on instances, not prototype, so we just check for execute).\n *\n * @param value - Value to check\n * @returns True if value is a Gadget constructor\n */\nfunction isGadgetConstructor(value: unknown): value is new () => AbstractGadget {\n if (typeof value !== \"function\") {\n return false;\n }\n\n const prototype = value.prototype as unknown;\n if (!prototype) {\n return false;\n }\n\n // Check for AbstractGadget inheritance (works for same package)\n if (prototype instanceof AbstractGadget) {\n return true;\n }\n\n // Duck typing: check if prototype has execute method\n // Gadget classes from external packages may not pass instanceof but have execute\n const proto = prototype as Record<string, unknown>;\n if (typeof proto.execute === \"function\") {\n return true;\n }\n\n // Also check if prototype looks like a gadget (for edge cases)\n return isGadgetLike(prototype);\n}\n\n/**\n * Expands ~ to the user's home directory.\n *\n * @param input - Path that may start with ~\n * @returns Expanded path with HOME directory\n */\nfunction expandHomePath(input: string): string {\n if (!input.startsWith(\"~\")) {\n return input;\n }\n\n const home = process.env.HOME;\n if (!home) {\n return input;\n }\n\n return path.join(home, input.slice(1));\n}\n\n/**\n * Determines if a specifier is a file path vs npm module name.\n * File paths start with ., /, ~ or contain path separators.\n *\n * @param specifier - Module specifier to check\n * @returns True if specifier represents a file path\n */\nfunction isFileLikeSpecifier(specifier: string): boolean {\n return (\n PATH_PREFIXES.some((prefix) => specifier.startsWith(prefix)) || specifier.includes(path.sep)\n );\n}\n\n/**\n * Attempts to resolve a specifier as a built-in gadget.\n * Handles both explicit \"builtin:\" prefix and bare names that match built-in gadgets.\n *\n * @param specifier - The gadget specifier to check\n * @returns The built-in gadget if found, null otherwise\n * @throws Error if \"builtin:\" prefix is used but gadget doesn't exist\n */\nexport function tryResolveBuiltin(specifier: string): AbstractGadget | null {\n // Handle explicit builtin: prefix\n if (specifier.startsWith(BUILTIN_PREFIX)) {\n const name = specifier.slice(BUILTIN_PREFIX.length);\n const gadget = getBuiltinGadget(name);\n if (!gadget) {\n throw new Error(\n `Unknown builtin gadget: ${name}. Available builtins: ListDirectory, ReadFile, WriteFile, EditFile, RunCommand`,\n );\n }\n return gadget;\n }\n\n // For non-file-path specifiers, check builtins first\n if (!isFileLikeSpecifier(specifier) && isBuiltinGadgetName(specifier)) {\n return getBuiltinGadget(specifier)!;\n }\n\n return null;\n}\n\n/**\n * Resolves a gadget specifier to either a file URL or npm module name.\n * File paths are resolved relative to cwd and converted to file:// URLs.\n *\n * @param specifier - Original gadget specifier (file path or module name)\n * @param cwd - Current working directory for resolving relative paths\n * @returns Resolved specifier (file:// URL for files, module name for packages)\n * @throws Error if file path doesn't exist\n */\nexport function resolveGadgetSpecifier(specifier: string, cwd: string): string {\n if (!isFileLikeSpecifier(specifier)) {\n return specifier;\n }\n\n const expanded = expandHomePath(specifier);\n const resolvedPath = path.resolve(cwd, expanded);\n if (!fs.existsSync(resolvedPath)) {\n throw new Error(`Gadget module not found at ${resolvedPath}`);\n }\n return pathToFileURL(resolvedPath).href;\n}\n\n/**\n * Recursively extracts all Gadget instances and classes from a module's exports.\n * Searches default export, named exports, nested objects, and arrays.\n * Automatically instantiates Gadget classes.\n *\n * @param moduleExports - Module exports object to search\n * @returns Array of Gadget instances found in exports\n */\nexport function extractGadgetsFromModule(moduleExports: unknown): AbstractGadget[] {\n const results: AbstractGadget[] = [];\n const visited = new Set<unknown>();\n\n const visit = (value: unknown) => {\n if (value === undefined || value === null) {\n return;\n }\n\n if (visited.has(value)) {\n return;\n }\n visited.add(value);\n\n // Use duck typing to handle gadgets from external packages\n if (value instanceof AbstractGadget || isGadgetLike(value)) {\n results.push(value as AbstractGadget);\n return;\n }\n\n if (isGadgetConstructor(value)) {\n results.push(new value());\n return;\n }\n\n if (Array.isArray(value)) {\n for (const entry of value) {\n visit(entry);\n }\n return;\n }\n\n if (typeof value === \"object\") {\n for (const entry of Object.values(value as Record<string, unknown>)) {\n visit(entry);\n }\n }\n };\n\n visit(moduleExports);\n return results;\n}\n\n/**\n * Loads gadgets from one or more specifiers.\n * Supports built-in gadgets, file paths, npm module names, and external packages.\n *\n * Resolution order:\n * 1. \"builtin:Name\" - explicit built-in lookup (error if not found)\n * 2. Bare \"Name\" without path chars - check built-in registry first\n * 3. External packages (npm/git) - auto-install and load from cache\n * - \"webasto\" - npm package, all gadgets\n * - \"webasto@2.0.0\" - npm package with version\n * - \"webasto:minimal\" - npm package with preset\n * - \"webasto/Navigate\" - npm package with specific gadget\n * - \"git+https://...\" - git URL\n * 4. File paths (starting with ., /, ~) - resolve and import\n * 5. npm module names - dynamic import from node_modules\n *\n * @param specifiers - Array of gadget specifiers\n * @param cwd - Current working directory for resolving relative paths\n * @param importer - Function to dynamically import modules (default: native import)\n * @returns Array of loaded Gadget instances\n * @throws Error if module fails to load, contains no gadgets, or initialization fails\n */\nexport async function loadGadgets(\n specifiers: string[],\n cwd: string,\n importer: GadgetImportFunction = (specifier) => import(specifier),\n): Promise<AbstractGadget[]> {\n const gadgets: AbstractGadget[] = [];\n // Track if we're using a custom importer (for testing) - skip external package resolution\n const usingDefaultImporter = importer.toString().includes(\"import(specifier)\");\n\n for (const specifier of specifiers) {\n // Try builtin resolution first\n const builtin = tryResolveBuiltin(specifier);\n if (builtin) {\n gadgets.push(builtin);\n continue;\n }\n\n // Try external package resolution (npm/git with presets, versions, etc.)\n // Skip this when using a custom importer (for testing)\n if (usingDefaultImporter && isExternalPackageSpecifier(specifier)) {\n try {\n const externalGadgets = await loadExternalGadgets(specifier);\n gadgets.push(...externalGadgets);\n continue;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to load external package '${specifier}': ${message}`);\n }\n }\n\n // Fall back to file/npm resolution\n const resolved = resolveGadgetSpecifier(specifier, cwd);\n let exports: unknown;\n try {\n exports = await importer(resolved);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to load gadget module '${specifier}': ${message}`);\n }\n\n let extracted: AbstractGadget[];\n try {\n extracted = extractGadgetsFromModule(exports);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to initialize gadgets from module '${specifier}': ${message}`);\n }\n if (extracted.length === 0) {\n throw new Error(`Module '${specifier}' does not export any Gadget instances.`);\n }\n gadgets.push(...extracted);\n }\n\n return gadgets;\n}\n","import { z } from \"zod\";\nimport { createGadget } from \"../../../index.js\";\nimport { validatePathIsWithinCwd } from \"./utils.js\";\n\n/**\n * EditFile gadget - Edit files using ed commands.\n * Shell escape commands (!) are filtered for security.\n */\nfunction filterDangerousCommands(commands: string): string {\n return commands\n .split(\"\\n\")\n .filter((line) => !line.trimStart().startsWith(\"!\"))\n .join(\"\\n\");\n}\n\nexport const editFile = createGadget({\n name: \"EditFile\",\n description:\n \"Edit a file using ed commands. Ed is a line-oriented text editor - pipe commands to it for precise file modifications. Commands are executed in sequence. Remember to end with 'w' (write) and 'q' (quit). Shell escape commands (!) are filtered for security.\",\n schema: z.object({\n filePath: z.string().describe(\"Path to the file to edit (relative or absolute)\"),\n commands: z.string().describe(\"Ed commands to execute, one per line\"),\n }),\n examples: [\n {\n params: {\n filePath: \"config.txt\",\n commands: `1,$p\nq`,\n },\n output: \"path=config.txt\\n\\n32\\nkey=value\\noption=true\",\n comment: \"Print entire file contents (ed shows byte count, then content)\",\n },\n {\n params: {\n filePath: \"data.txt\",\n commands: `1,$s/foo/bar/g\nw\nq`,\n },\n output: \"path=data.txt\\n\\n42\\n42\",\n comment: \"Replace all 'foo' with 'bar' (ed shows bytes read, then bytes written)\",\n },\n {\n params: {\n filePath: \"list.txt\",\n commands: `3d\nw\nq`,\n },\n output: \"path=list.txt\\n\\n45\\n28\",\n comment: \"Delete line 3, save and quit\",\n },\n {\n params: {\n filePath: \"readme.txt\",\n commands: `$a\nNew last line\n.\nw\nq`,\n },\n output: \"path=readme.txt\\n\\n40\\n56\",\n comment: \"Append text after last line ($ = last line, . = end input mode)\",\n },\n ],\n timeoutMs: 30000,\n execute: async ({ filePath, commands }) => {\n const validatedPath = validatePathIsWithinCwd(filePath);\n const safeCommands = filterDangerousCommands(commands);\n\n try {\n const proc = Bun.spawn([\"ed\", validatedPath], {\n stdin: \"pipe\",\n stdout: \"pipe\",\n stderr: \"pipe\",\n });\n\n // Write commands to ed's stdin\n proc.stdin.write(`${safeCommands}\\n`);\n proc.stdin.end();\n\n // Create timeout promise (30 seconds) with cleanup capability\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n proc.kill();\n reject(new Error(\"ed command timed out after 30000ms\"));\n }, 30000);\n });\n\n // Wait for process and consume streams concurrently to prevent deadlock.\n // If we await proc.exited first, large output can fill pipe buffers,\n // causing the process to block on write while we block on exit.\n const [exitCode, stdout, stderr] = await Promise.race([\n Promise.all([\n proc.exited,\n new Response(proc.stdout).text(),\n new Response(proc.stderr).text(),\n ]),\n timeoutPromise,\n ]);\n\n // Clear timeout on normal exit to prevent dangling timer\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n\n const output = [stdout, stderr].filter(Boolean).join(\"\\n\").trim();\n\n if (exitCode !== 0) {\n return `path=${filePath}\\n\\n${output || \"ed exited with non-zero status\"}`;\n }\n\n return `path=${filePath}\\n\\n${output || \"(no output)\"}`;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return `path=${filePath}\\n\\nerror: ${message}`;\n }\n },\n});\n","// Re-export Zod's z for schema definitions\n// Using llmist's z ensures .describe() metadata is preserved in JSON schemas\nexport { z } from \"zod\";\n// Syntactic sugar: Agent builder and event handlers\nexport type { HistoryMessage, TrailingMessage, TrailingMessageContext } from \"./agent/builder.js\";\nexport { AgentBuilder } from \"./agent/builder.js\";\nexport type { EventHandlers } from \"./agent/event-handlers.js\";\nexport { collectEvents, collectText, runWithHandlers } from \"./agent/event-handlers.js\";\n// Syntactic sugar: Hook presets\nexport type { LoggingOptions } from \"./agent/hook-presets.js\";\nexport { HookPresets } from \"./agent/hook-presets.js\";\n// Agent infrastructure\n// New clean hooks system\nexport type {\n AfterGadgetExecutionAction,\n AfterGadgetExecutionControllerContext,\n AfterLLMCallAction,\n AfterLLMCallControllerContext,\n AfterLLMErrorAction,\n AgentHooks,\n AgentOptions,\n BeforeGadgetExecutionAction,\n BeforeLLMCallAction,\n // Interceptor contexts\n ChunkInterceptorContext,\n // Context compaction\n CompactionConfig,\n CompactionContext,\n CompactionEvent,\n CompactionResult,\n CompactionStats,\n CompactionStrategy,\n Controllers,\n GadgetExecutionControllerContext,\n GadgetParameterInterceptorContext,\n GadgetResultInterceptorContext,\n // LLM Assistance Hints\n HintsConfig,\n IConversationManager,\n Interceptors,\n IterationHintOptions,\n // Controller contexts and actions\n LLMCallControllerContext,\n LLMErrorControllerContext,\n MessageInterceptorContext,\n MessageTurn,\n ObserveChunkContext,\n ObserveCompactionContext,\n ObserveGadgetCompleteContext,\n ObserveGadgetStartContext,\n // Observer contexts\n ObserveLLMCallContext,\n ObserveLLMCompleteContext,\n ObserveLLMErrorContext,\n Observers,\n ParallelGadgetHintOptions,\n ResolvedCompactionConfig,\n // Gadget output limiting\n StoredOutput,\n StreamProcessingResult,\n StreamProcessorOptions,\n // Subagent context for hook observers\n SubagentContext,\n} from \"./agent/index.js\";\nexport {\n // Compaction exports\n CompactionManager,\n // Existing exports\n ConversationManager,\n // LLM Assistance Hints\n createHints,\n DEFAULT_COMPACTION_CONFIG,\n DEFAULT_SUMMARIZATION_PROMPT,\n GadgetOutputStore,\n HybridStrategy,\n iterationProgressHint,\n parallelGadgetHint,\n SlidingWindowStrategy,\n StreamProcessor,\n SummarizationStrategy,\n} from \"./agent/index.js\";\nexport type { LLMistOptions } from \"./core/client.js\";\nexport { LLMist } from \"./core/client.js\";\n\n// Execution Tree - first-class model for nested subagent support\nexport type {\n AddGadgetParams,\n AddLLMCallParams,\n CompleteGadgetParams,\n CompleteLLMCallParams,\n ExecutionNode,\n ExecutionNodeType,\n GadgetNode,\n GadgetState,\n LLMCallNode,\n NodeId,\n} from \"./core/execution-tree.js\";\nexport { ExecutionTree } from \"./core/execution-tree.js\";\n\n// Unified execution events with tree context\nexport type {\n BaseExecutionEvent,\n CompactionEvent as TreeCompactionEvent,\n ExecutionEvent,\n ExecutionEventType,\n GadgetCallEvent,\n GadgetCompleteEvent,\n GadgetErrorEvent,\n GadgetEvent,\n GadgetSkippedEvent as TreeGadgetSkippedEvent,\n GadgetStartEvent,\n HumanInputRequiredEvent,\n LLMCallCompleteEvent,\n LLMCallErrorEvent,\n LLMCallStartEvent,\n LLMCallStreamEvent,\n LLMEvent,\n StreamCompleteEvent,\n TextEvent,\n} from \"./core/execution-events.js\";\nexport {\n filterByDepth,\n filterByParent,\n filterRootEvents,\n groupByParent,\n isGadgetEvent,\n isLLMEvent,\n isRootEvent,\n isSubagentEvent,\n} from \"./core/execution-events.js\";\n\n// Input content types for multimodal messages\nexport type {\n AudioContentPart,\n AudioMimeType,\n AudioSource,\n ContentPart,\n ImageBase64Source,\n ImageContentPart,\n ImageMimeType,\n ImageSource,\n ImageUrlSource,\n TextContentPart,\n} from \"./core/input-content.js\";\nexport {\n audioFromBase64,\n audioFromBuffer,\n detectAudioMimeType,\n detectImageMimeType,\n imageFromBase64,\n imageFromBuffer,\n imageFromUrl,\n isAudioPart,\n isDataUrl,\n isImagePart,\n isTextPart,\n parseDataUrl,\n text,\n toBase64,\n} from \"./core/input-content.js\";\n\nexport type { LLMMessage, MessageContent, MessageRole } from \"./core/messages.js\";\nexport { extractMessageText, LLMMessageBuilder, normalizeMessageContent } from \"./core/messages.js\";\n// Model catalog\nexport type {\n CostEstimate,\n ModelFeatures,\n ModelLimits,\n ModelPricing,\n ModelSpec,\n} from \"./core/model-catalog.js\";\nexport { ModelRegistry } from \"./core/model-registry.js\";\n// Syntactic sugar: Model shortcuts and quick methods\nexport {\n getModelId,\n getProvider,\n hasProviderPrefix,\n MODEL_ALIASES,\n resolveModel,\n} from \"./core/model-shortcuts.js\";\n// Vision namespace for one-shot image analysis\nexport type { VisionAnalyzeOptions, VisionAnalyzeResult } from \"./core/namespaces/vision.js\";\nexport type {\n LLMGenerationOptions,\n LLMStream,\n LLMStreamChunk,\n ModelDescriptor,\n ProviderIdentifier,\n TokenUsage,\n} from \"./core/options.js\";\nexport { ModelIdentifierParser } from \"./core/options.js\";\nexport type {\n HintContext,\n HintTemplate,\n PromptContext,\n PromptTemplate,\n PromptTemplateConfig,\n} from \"./core/prompt-config.js\";\nexport {\n DEFAULT_HINTS,\n DEFAULT_PROMPTS,\n resolveHintTemplate,\n resolvePromptTemplate,\n resolveRulesTemplate,\n} from \"./core/prompt-config.js\";\nexport type { TextGenerationOptions } from \"./core/quick-methods.js\";\nexport { complete, stream } from \"./core/quick-methods.js\";\nexport type { CreateGadgetConfig } from \"./gadgets/create-gadget.js\";\nexport { createGadget } from \"./gadgets/create-gadget.js\";\n// Gadget infrastructure\nexport {\n AbortException,\n HumanInputRequiredException,\n TaskCompletionSignal,\n TimeoutException,\n} from \"./gadgets/exceptions.js\";\nexport { GadgetExecutor } from \"./gadgets/executor.js\";\nexport { AbstractGadget } from \"./gadgets/gadget.js\";\n// Gadget output viewer (for custom output store integration)\nexport { createGadgetOutputViewer } from \"./gadgets/output-viewer.js\";\nexport { GadgetCallParser } from \"./gadgets/parser.js\";\nexport type { GadgetClass, GadgetOrClass } from \"./gadgets/registry.js\";\nexport { GadgetRegistry } from \"./gadgets/registry.js\";\n\n// Syntactic sugar: Typed gadgets and helpers\nexport type { GadgetConfig } from \"./gadgets/typed-gadget.js\";\nexport { Gadget } from \"./gadgets/typed-gadget.js\";\nexport type {\n CostReportingLLMist,\n ExecutionContext,\n GadgetExample,\n GadgetExecuteResult,\n GadgetExecuteResultWithMedia,\n GadgetExecuteReturn,\n GadgetExecutionResult,\n GadgetMediaOutput,\n GadgetSkippedEvent,\n // Host exports for external gadgets\n HostExports,\n MediaKind,\n MediaMetadata,\n ParsedGadgetCall,\n StoredMedia,\n StreamEvent,\n // Subagent event types\n SubagentEvent,\n SubagentStreamEvent,\n TextOnlyAction,\n TextOnlyContext,\n TextOnlyCustomHandler,\n TextOnlyGadgetConfig,\n TextOnlyHandler,\n TextOnlyStrategy,\n} from \"./gadgets/types.js\";\n// Media output helpers for gadgets\nexport {\n createMediaOutput,\n resultWithAudio,\n resultWithFile,\n resultWithImage,\n resultWithImages,\n resultWithMedia,\n} from \"./gadgets/helpers.js\";\n\n// Host exports helper for external gadgets\nimport type { ExecutionContext, HostExports } from \"./gadgets/types.js\";\n\n/**\n * Get host llmist exports from execution context.\n *\n * External gadgets MUST use this instead of importing classes directly from 'llmist'\n * to ensure they use the same version as the host CLI, enabling proper tree sharing\n * and avoiding the \"dual-package problem\".\n *\n * @param ctx - The execution context passed to gadget.execute()\n * @returns The host's llmist exports (AgentBuilder, Gadget, etc.)\n * @throws Error if ctx or ctx.hostExports is undefined\n *\n * @example\n * ```typescript\n * import { getHostExports, Gadget, z } from 'llmist';\n * import type { ExecutionContext } from 'llmist';\n *\n * class BrowseWeb extends Gadget({\n * name: 'BrowseWeb',\n * description: 'Browse a website autonomously',\n * schema: z.object({ task: z.string(), url: z.string() }),\n * }) {\n * async execute(params: this['params'], ctx?: ExecutionContext) {\n * // Get host's AgentBuilder to ensure tree sharing works correctly\n * const { AgentBuilder } = getHostExports(ctx!);\n *\n * const agent = new AgentBuilder()\n * .withParentContext(ctx!)\n * .withGadgets(Navigate, Click, Screenshot)\n * .ask(params.task);\n *\n * for await (const event of agent.run()) {\n * // Events flow through host's shared tree\n * }\n * }\n * }\n * ```\n */\nexport function getHostExports(ctx: ExecutionContext): HostExports {\n if (!ctx?.hostExports) {\n throw new Error(\n \"hostExports not available. Gadgets that create subagents must be run \" +\n \"via llmist agent, not standalone. Ensure you are using llmist >= 6.2.0.\",\n );\n }\n return ctx.hostExports;\n}\n// Media storage for gadget outputs\nexport { MediaStore } from \"./gadgets/media-store.js\";\nexport type { ValidationIssue, ValidationResult } from \"./gadgets/validation.js\";\nexport { validateAndApplyDefaults, validateGadgetParams } from \"./gadgets/validation.js\";\nexport type { LoggerOptions } from \"./logging/logger.js\";\nexport { createLogger, defaultLogger } from \"./logging/logger.js\";\n\n// Utility functions for subagent gadgets\nexport type { ResolveValueOptions } from \"./utils/config-resolver.js\";\nexport { resolveConfig, resolveSubagentModel, resolveValue } from \"./utils/config-resolver.js\";\nexport {\n AnthropicMessagesProvider,\n createAnthropicProviderFromEnv,\n} from \"./providers/anthropic.js\";\nexport { discoverProviderAdapters } from \"./providers/discovery.js\";\nexport { createGeminiProviderFromEnv, GeminiGenerativeProvider } from \"./providers/gemini.js\";\nexport { createOpenAIProviderFromEnv, OpenAIChatProvider } from \"./providers/openai.js\";\nexport type { ProviderAdapter } from \"./providers/provider.js\";\n\n// Testing/Mock infrastructure\nexport type {\n MockMatcher,\n MockMatcherContext,\n MockOptions,\n MockRegistration,\n MockResponse,\n MockStats,\n} from \"./testing/index.js\";\nexport {\n createMockAdapter,\n createMockClient,\n createMockStream,\n createTextMockStream,\n getMockManager,\n MockBuilder,\n MockManager,\n MockProviderAdapter,\n mockLLM,\n} from \"./testing/index.js\";\n","/**\n * Context Compaction System\n *\n * Automatically manages conversation context to prevent context window overflow\n * in long-running agent conversations.\n *\n * Features:\n * - Automatic threshold monitoring (default: 80% of context window)\n * - Multiple strategies: sliding-window, summarization, hybrid (default)\n * - Full visibility via StreamEvents and hooks\n * - Enabled by default with sensible defaults\n *\n * @example\n * ```typescript\n * // Auto-enabled with defaults\n * const agent = await LLMist.createAgent()\n * .withModel('sonnet')\n * .ask('Help me...');\n *\n * // Custom configuration\n * const agent = await LLMist.createAgent()\n * .withModel('gpt-4')\n * .withCompaction({\n * triggerThresholdPercent: 70,\n * preserveRecentTurns: 10,\n * })\n * .ask('...');\n *\n * // Disable compaction\n * const agent = await LLMist.createAgent()\n * .withModel('sonnet')\n * .withoutCompaction()\n * .ask('...');\n * ```\n */\n\n// Configuration\nexport {\n type CompactionConfig,\n type CompactionEvent,\n type CompactionStats,\n DEFAULT_COMPACTION_CONFIG,\n DEFAULT_SUMMARIZATION_PROMPT,\n type ResolvedCompactionConfig,\n resolveCompactionConfig,\n} from \"./config.js\";\n// Manager\nexport { CompactionManager } from \"./manager.js\";\n\n// Strategy implementations\nexport {\n HybridStrategy,\n SlidingWindowStrategy,\n SummarizationStrategy,\n} from \"./strategies/index.js\";\n// Strategy interface and utilities\nexport {\n type CompactionContext,\n type CompactionResult,\n type CompactionStrategy,\n flattenTurns,\n groupIntoTurns,\n type MessageTurn,\n} from \"./strategy.js\";\n","/**\n * Agent module - Composable, single-responsibility architecture for LLM agents.\n * This module provides a cleaner alternative to the monolithic AgentLoop.\n */\n\nexport type { AgentOptions } from \"./agent.js\";\n// Context compaction\nexport {\n type CompactionConfig,\n type CompactionContext,\n type CompactionEvent,\n CompactionManager,\n type CompactionResult,\n type CompactionStats,\n type CompactionStrategy,\n DEFAULT_COMPACTION_CONFIG,\n DEFAULT_SUMMARIZATION_PROMPT,\n HybridStrategy,\n type MessageTurn,\n type ResolvedCompactionConfig,\n SlidingWindowStrategy,\n SummarizationStrategy,\n} from \"./compaction/index.js\";\nexport { ConversationManager } from \"./conversation-manager.js\";\n// Gadget output limiting\nexport type { StoredOutput } from \"./gadget-output-store.js\";\nexport { GadgetOutputStore } from \"./gadget-output-store.js\";\n// LLM Assistance Hints\nexport {\n createHints,\n type HintsConfig,\n type IterationHintOptions,\n iterationProgressHint,\n type ParallelGadgetHintOptions,\n parallelGadgetHint,\n} from \"./hints.js\";\n// New clean hooks system\nexport type {\n AfterGadgetExecutionAction,\n AfterGadgetExecutionControllerContext,\n AfterLLMCallAction,\n AfterLLMCallControllerContext,\n AfterLLMErrorAction,\n AgentHooks,\n BeforeGadgetExecutionAction,\n BeforeLLMCallAction,\n // Interceptor contexts\n ChunkInterceptorContext,\n Controllers,\n // Dependency skip controller\n DependencySkipAction,\n DependencySkipControllerContext,\n GadgetExecutionControllerContext,\n GadgetParameterInterceptorContext,\n GadgetResultInterceptorContext,\n Interceptors,\n // Controller contexts and actions\n LLMCallControllerContext,\n LLMErrorControllerContext,\n MessageInterceptorContext,\n ObserveChunkContext,\n ObserveCompactionContext,\n ObserveGadgetCompleteContext,\n // Gadget skip observer\n ObserveGadgetSkippedContext,\n ObserveGadgetStartContext,\n // Observer contexts\n ObserveLLMCallContext,\n ObserveLLMCompleteContext,\n ObserveLLMErrorContext,\n Observers,\n // Subagent context for distinguishing subagent events in hooks\n SubagentContext,\n} from \"./hooks.js\";\nexport type { IConversationManager } from \"./interfaces.js\";\n// StreamProcessor for advanced use cases\nexport {\n type StreamProcessingResult,\n StreamProcessor,\n type StreamProcessorOptions,\n} from \"./stream-processor.js\";\n","/**\n * LLM Assistance Hints System\n *\n * Provides reusable hook factories that inject helpful context and coaching\n * messages to guide LLM behavior during agentic execution.\n *\n * ## Two Types of Hints\n *\n * 1. **Proactive (beforeLLMCall)**: Inject context before LLM generates response\n * - Example: Iteration progress (\"You're on iteration 3/10\")\n *\n * 2. **Reactive (afterLLMCall)**: Coach based on what LLM did\n * - Example: \"Tip: You can call multiple gadgets in parallel\"\n *\n * ## Usage\n *\n * ```typescript\n * import { createHints, iterationProgressHint, parallelGadgetHint } from \"llmist\";\n *\n * // Option 1: Use individual hints\n * const agent = new AgentBuilder()\n * .withHooks(HookPresets.merge(\n * iterationProgressHint({ timing: \"late\" }),\n * parallelGadgetHint(),\n * ))\n * .build();\n *\n * // Option 2: Use convenience factory\n * const agent = new AgentBuilder()\n * .withHooks(createHints({\n * iterationProgress: { timing: \"late\" },\n * parallelGadgets: true,\n * }))\n * .build();\n * ```\n *\n * @module agent/hints\n */\n\nimport {\n DEFAULT_HINTS,\n type HintContext,\n type HintTemplate,\n resolveHintTemplate,\n} from \"../core/prompt-config.js\";\nimport { HookPresets } from \"./hook-presets.js\";\nimport type { AgentHooks } from \"./hooks.js\";\n\n// ============================================================================\n// CONFIGURATION TYPES\n// ============================================================================\n\n/**\n * Options for iteration progress hint.\n */\nexport interface IterationHintOptions {\n /**\n * When to show the hint.\n * - \"always\": Show on every iteration\n * - \"late\": Show only when >= 50% through iterations\n * - \"urgent\": Show only when >= 80% through iterations\n * @default \"always\"\n */\n timing?: \"always\" | \"late\" | \"urgent\";\n\n /**\n * Whether to include urgency indicators for late iterations.\n * Adds extra text when running low on iterations.\n * @default true\n */\n showUrgency?: boolean;\n\n /**\n * Custom template. Supports placeholders: {iteration}, {maxIterations}, {remaining}\n * Or a function receiving HintContext.\n * @default DEFAULT_HINTS.iterationProgressHint\n */\n template?: HintTemplate;\n}\n\n/**\n * Options for parallel gadget usage hint.\n */\nexport interface ParallelGadgetHintOptions {\n /**\n * Minimum number of gadget calls to consider \"efficient\".\n * If response has fewer calls, hint will suggest parallelization.\n * @default 2\n */\n minGadgetsForEfficiency?: number;\n\n /**\n * Custom message when single gadget detected.\n * @default DEFAULT_HINTS.parallelGadgetsHint\n */\n message?: string;\n\n /**\n * Whether to enable this hint.\n * @default true\n */\n enabled?: boolean;\n}\n\n/**\n * Combined hints configuration for createHints().\n */\nexport interface HintsConfig {\n /**\n * Enable iteration progress hints.\n * Pass `true` for defaults, or options object for customization.\n */\n iterationProgress?: boolean | IterationHintOptions;\n\n /**\n * Enable parallel gadget hints.\n * Pass `true` for defaults, or options object for customization.\n */\n parallelGadgets?: boolean | ParallelGadgetHintOptions;\n\n /**\n * Additional custom hooks to merge.\n */\n custom?: AgentHooks[];\n}\n\n// ============================================================================\n// HINT FACTORIES\n// ============================================================================\n\n/**\n * Creates a proactive hint that informs the LLM about iteration progress.\n *\n * This hint is injected before each LLM call (via beforeLLMCall controller),\n * helping the LLM understand how much \"budget\" remains for completing the task.\n *\n * @param options - Configuration options\n * @returns AgentHooks that can be merged with other hooks\n *\n * @example\n * ```typescript\n * // Basic usage - show on every iteration\n * const hooks = iterationProgressHint();\n *\n * // Show only when running low on iterations\n * const hooks = iterationProgressHint({ timing: \"late\" });\n *\n * // Custom template\n * const hooks = iterationProgressHint({\n * template: \"Turn {iteration} of {maxIterations}. {remaining} turns left.\",\n * });\n * ```\n */\nexport function iterationProgressHint(options?: IterationHintOptions): AgentHooks {\n const { timing = \"always\", showUrgency = true, template } = options ?? {};\n\n return {\n controllers: {\n beforeLLMCall: async (ctx) => {\n const iteration = ctx.iteration + 1; // 1-based for user-friendliness\n const maxIterations = ctx.maxIterations;\n const progress = iteration / maxIterations;\n\n // Check timing condition\n if (timing === \"late\" && progress < 0.5) {\n return { action: \"proceed\" };\n }\n if (timing === \"urgent\" && progress < 0.8) {\n return { action: \"proceed\" };\n }\n\n // Build hint context with all fields populated\n const remaining = maxIterations - iteration;\n const hintContext: HintContext = {\n iteration,\n maxIterations,\n remaining,\n };\n\n // Resolve template\n let hint = resolveHintTemplate(template, DEFAULT_HINTS.iterationProgressHint, hintContext);\n\n // Add urgency indicator if late in iterations\n if (showUrgency && progress >= 0.8) {\n hint += \" ⚠️ Running low on iterations - focus on completing the task.\";\n }\n\n // Inject as system-level context in messages\n const messages = [...ctx.options.messages];\n\n // Find last user message index (compatible with older ES targets)\n let lastUserIndex = -1;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === \"user\") {\n lastUserIndex = i;\n break;\n }\n }\n\n if (lastUserIndex >= 0) {\n // Insert hint after the last user message\n messages.splice(lastUserIndex + 1, 0, {\n role: \"user\",\n content: `[System Hint] ${hint}`,\n });\n } else {\n // No user messages found - append hint at the end\n messages.push({\n role: \"user\",\n content: `[System Hint] ${hint}`,\n });\n }\n\n return {\n action: \"proceed\",\n modifiedOptions: { messages },\n };\n },\n },\n };\n}\n\n/**\n * Creates a reactive hint that encourages parallel gadget usage.\n *\n * This hint analyzes the LLM's response and, if only a single gadget was called,\n * appends a reminder that multiple gadgets can be used in parallel for efficiency.\n *\n * @param options - Configuration options\n * @returns AgentHooks that can be merged with other hooks\n *\n * @example\n * ```typescript\n * // Basic usage\n * const hooks = parallelGadgetHint();\n *\n * // Custom threshold and message\n * const hooks = parallelGadgetHint({\n * minGadgetsForEfficiency: 3,\n * message: \"Consider calling multiple gadgets at once!\",\n * });\n * ```\n */\nexport function parallelGadgetHint(options?: ParallelGadgetHintOptions): AgentHooks {\n const {\n minGadgetsForEfficiency = 2,\n message = DEFAULT_HINTS.parallelGadgetsHint,\n enabled = true,\n } = options ?? {};\n\n return {\n controllers: {\n afterLLMCall: async (ctx) => {\n if (!enabled) {\n return { action: \"continue\" };\n }\n\n // Only hint if gadgets were called but below efficiency threshold\n if (ctx.gadgetCallCount > 0 && ctx.gadgetCallCount < minGadgetsForEfficiency) {\n return {\n action: \"append_messages\",\n messages: [\n {\n role: \"user\",\n content: `[System Hint] ${message}`,\n },\n ],\n };\n }\n\n return { action: \"continue\" };\n },\n },\n };\n}\n\n// ============================================================================\n// CONVENIENCE FACTORY\n// ============================================================================\n\n/**\n * Creates combined hints from a configuration object.\n *\n * This is a convenience function that creates and merges multiple hints\n * based on a simple configuration object.\n *\n * @param config - Configuration for which hints to enable\n * @returns Merged AgentHooks\n *\n * @example\n * ```typescript\n * const hooks = createHints({\n * iterationProgress: { timing: \"late\" },\n * parallelGadgets: true,\n * });\n *\n * const agent = new AgentBuilder()\n * .withHooks(HookPresets.merge(existingHooks, hooks))\n * .build();\n * ```\n */\nexport function createHints(config: HintsConfig): AgentHooks {\n const hooksToMerge: AgentHooks[] = [];\n\n // Iteration progress hint\n if (config.iterationProgress) {\n const options = typeof config.iterationProgress === \"boolean\" ? {} : config.iterationProgress;\n hooksToMerge.push(iterationProgressHint(options));\n }\n\n // Parallel gadgets hint\n if (config.parallelGadgets) {\n const options = typeof config.parallelGadgets === \"boolean\" ? {} : config.parallelGadgets;\n hooksToMerge.push(parallelGadgetHint(options));\n }\n\n // Custom hooks\n if (config.custom) {\n hooksToMerge.push(...config.custom);\n }\n\n return HookPresets.merge(...hooksToMerge);\n}\n","/**\n * Helper functions for gadget authors to easily return media outputs.\n *\n * These functions provide type-specific conveniences while using the\n * generic GadgetMediaOutput system underneath.\n *\n * @example\n * ```typescript\n * import { resultWithImage } from \"llmist/gadgets\";\n *\n * const screenshotGadget = createGadget({\n * name: \"Screenshot\",\n * schema: z.object({ url: z.string() }),\n * execute: async ({ url }) => {\n * const screenshot = await takeScreenshot(url);\n * return resultWithImage(\n * `Screenshot of ${url}`,\n * screenshot,\n * { description: \"Webpage screenshot\" }\n * );\n * },\n * });\n * ```\n */\n\nimport { detectAudioMimeType, detectImageMimeType } from \"../core/input-content.js\";\nimport type {\n GadgetExecuteResultWithMedia,\n GadgetMediaOutput,\n MediaKind,\n MediaMetadata,\n} from \"./types.js\";\n\n/**\n * Create a GadgetMediaOutput from raw data.\n *\n * @param kind - Type of media\n * @param data - Raw binary data (Buffer or Uint8Array)\n * @param mimeType - MIME type string\n * @param options - Optional description, metadata, and fileName\n * @returns A GadgetMediaOutput ready to include in results\n */\nexport function createMediaOutput(\n kind: MediaKind,\n data: Buffer | Uint8Array,\n mimeType: string,\n options?: { description?: string; metadata?: MediaMetadata; fileName?: string },\n): GadgetMediaOutput {\n const buffer = data instanceof Buffer ? data : Buffer.from(data);\n return {\n kind,\n data: buffer.toString(\"base64\"),\n mimeType,\n description: options?.description,\n metadata: options?.metadata,\n fileName: options?.fileName,\n };\n}\n\n/**\n * Create a result with multiple media outputs.\n *\n * @param result - Text result string\n * @param media - Array of GadgetMediaOutput items (must not be empty)\n * @param cost - Optional cost in USD\n * @returns A GadgetExecuteResultWithMedia\n * @throws Error if media array is empty\n *\n * @example\n * ```typescript\n * return resultWithMedia(\n * \"Generated 2 charts\",\n * [\n * createMediaOutput(\"image\", barChartPng, \"image/png\", { description: \"Bar chart\" }),\n * createMediaOutput(\"image\", pieChartPng, \"image/png\", { description: \"Pie chart\" }),\n * ],\n * 0.002\n * );\n * ```\n */\nexport function resultWithMedia(\n result: string,\n media: GadgetMediaOutput[],\n cost?: number,\n): GadgetExecuteResultWithMedia {\n if (media.length === 0) {\n throw new Error(\"resultWithMedia: media array cannot be empty\");\n }\n return {\n result,\n media,\n cost,\n };\n}\n\n/**\n * Options for resultWithImage helper.\n */\nexport interface ImageOptions {\n /** MIME type (auto-detected if not provided) */\n mimeType?: string;\n /** Human-readable description */\n description?: string;\n /** Image dimensions and other metadata */\n metadata?: MediaMetadata;\n /** Cost in USD */\n cost?: number;\n /** Filename to use when saving (if not provided, auto-generated) */\n fileName?: string;\n}\n\n/**\n * Create a result with a single image output.\n *\n * @param result - Text result string\n * @param imageData - Raw image data (PNG, JPEG, GIF, WebP)\n * @param options - Optional MIME type, description, metadata, cost\n * @returns A GadgetExecuteResultWithMedia\n *\n * @example\n * ```typescript\n * const screenshot = await page.screenshot({ type: \"png\" });\n * return resultWithImage(\n * \"Screenshot captured\",\n * screenshot,\n * { description: \"Homepage screenshot\", metadata: { width: 1920, height: 1080 } }\n * );\n * ```\n */\nexport function resultWithImage(\n result: string,\n imageData: Buffer | Uint8Array,\n options?: ImageOptions,\n): GadgetExecuteResultWithMedia {\n const buffer = imageData instanceof Buffer ? imageData : Buffer.from(imageData);\n const mimeType = options?.mimeType ?? detectImageMimeType(buffer);\n\n if (!mimeType) {\n throw new Error(\n \"Could not detect image MIME type. Please provide mimeType explicitly in options.\",\n );\n }\n\n return {\n result,\n media: [\n {\n kind: \"image\",\n data: buffer.toString(\"base64\"),\n mimeType,\n description: options?.description,\n metadata: options?.metadata,\n fileName: options?.fileName,\n },\n ],\n cost: options?.cost,\n };\n}\n\n/**\n * Image item for resultWithImages helper.\n */\nexport interface ImageItem {\n /** Raw image data */\n data: Buffer | Uint8Array;\n /** MIME type (auto-detected if not provided) */\n mimeType?: string;\n /** Human-readable description */\n description?: string;\n /** Image dimensions and other metadata */\n metadata?: MediaMetadata;\n /** Filename to use when saving (if not provided, auto-generated) */\n fileName?: string;\n}\n\n/**\n * Create a result with multiple image outputs.\n *\n * @param result - Text result string\n * @param images - Array of image items (must not be empty)\n * @param cost - Optional cost in USD\n * @returns A GadgetExecuteResultWithMedia\n * @throws Error if images array is empty\n *\n * @example\n * ```typescript\n * return resultWithImages(\n * \"Generated comparison images\",\n * [\n * { data: beforeImg, description: \"Before\" },\n * { data: afterImg, description: \"After\" },\n * ],\n * 0.01\n * );\n * ```\n */\nexport function resultWithImages(\n result: string,\n images: ImageItem[],\n cost?: number,\n): GadgetExecuteResultWithMedia {\n if (images.length === 0) {\n throw new Error(\"resultWithImages: images array cannot be empty\");\n }\n\n const media: GadgetMediaOutput[] = images.map((img, index) => {\n const buffer = img.data instanceof Buffer ? img.data : Buffer.from(img.data);\n const mimeType = img.mimeType ?? detectImageMimeType(buffer);\n\n if (!mimeType) {\n throw new Error(\n `Could not detect MIME type for image at index ${index}. Please provide mimeType explicitly.`,\n );\n }\n\n return {\n kind: \"image\" as const,\n data: buffer.toString(\"base64\"),\n mimeType,\n description: img.description,\n metadata: img.metadata,\n fileName: img.fileName,\n };\n });\n\n return { result, media, cost };\n}\n\n/**\n * Options for resultWithAudio helper.\n */\nexport interface AudioOptions {\n /** MIME type (auto-detected if not provided) */\n mimeType?: string;\n /** Human-readable description */\n description?: string;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Cost in USD */\n cost?: number;\n /** Filename to use when saving (if not provided, auto-generated) */\n fileName?: string;\n}\n\n/**\n * Create a result with a single audio output.\n *\n * @param result - Text result string\n * @param audioData - Raw audio data (MP3, WAV, OGG, etc.)\n * @param options - Optional MIME type, description, duration, cost\n * @returns A GadgetExecuteResultWithMedia\n *\n * @example\n * ```typescript\n * const speech = await generateSpeech(text);\n * return resultWithAudio(\n * `Generated speech for: \"${text.slice(0, 50)}...\"`,\n * speech,\n * { mimeType: \"audio/mp3\", durationMs: 5000 }\n * );\n * ```\n */\nexport function resultWithAudio(\n result: string,\n audioData: Buffer | Uint8Array,\n options?: AudioOptions,\n): GadgetExecuteResultWithMedia {\n const buffer = audioData instanceof Buffer ? audioData : Buffer.from(audioData);\n const mimeType = options?.mimeType ?? detectAudioMimeType(buffer);\n\n if (!mimeType) {\n throw new Error(\n \"Could not detect audio MIME type. Please provide mimeType explicitly in options.\",\n );\n }\n\n const metadata: MediaMetadata | undefined = options?.durationMs\n ? { durationMs: options.durationMs }\n : undefined;\n\n return {\n result,\n media: [\n {\n kind: \"audio\",\n data: buffer.toString(\"base64\"),\n mimeType,\n description: options?.description,\n metadata,\n fileName: options?.fileName,\n },\n ],\n cost: options?.cost,\n };\n}\n\n/**\n * Options for resultWithFile helper.\n */\nexport interface FileOptions {\n /** Human-readable description */\n description?: string;\n /** Cost in USD */\n cost?: number;\n /** Filename to use when saving (if not provided, auto-generated) */\n fileName?: string;\n}\n\n/**\n * Create a result with a generic file output.\n *\n * Use this for arbitrary file types that don't fit image/audio categories.\n *\n * @param result - Text result string\n * @param fileData - Raw file data\n * @param mimeType - MIME type (required, not auto-detected)\n * @param options - Optional description and cost\n * @returns A GadgetExecuteResultWithMedia\n *\n * @example\n * ```typescript\n * const pdf = await generatePdf(content);\n * return resultWithFile(\n * \"Generated PDF report\",\n * pdf,\n * \"application/pdf\",\n * { description: \"Monthly report\" }\n * );\n * ```\n */\nexport function resultWithFile(\n result: string,\n fileData: Buffer | Uint8Array,\n mimeType: string,\n options?: FileOptions,\n): GadgetExecuteResultWithMedia {\n const buffer = fileData instanceof Buffer ? fileData : Buffer.from(fileData);\n\n return {\n result,\n media: [\n {\n kind: \"file\",\n data: buffer.toString(\"base64\"),\n mimeType,\n description: options?.description,\n fileName: options?.fileName,\n },\n ],\n cost: options?.cost,\n };\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(responses: string[]): (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","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 {\n type AudioMimeType,\n detectAudioMimeType,\n detectImageMimeType,\n type ImageMimeType,\n isAudioPart,\n isImagePart,\n toBase64,\n} from \"../core/input-content.js\";\nimport type { LLMMessage, MessageContent } from \"../core/messages.js\";\nimport { extractMessageText } 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// Multimodal Content Helpers\n// ============================================================================\n\n/**\n * Check if message content contains at least one image.\n */\nfunction hasImageContent(content: MessageContent): boolean {\n if (typeof content === \"string\") return false;\n return content.some((part) => isImagePart(part));\n}\n\n/**\n * Check if message content contains audio.\n */\nfunction hasAudioContent(content: MessageContent): boolean {\n if (typeof content === \"string\") return false;\n return content.some((part) => isAudioPart(part));\n}\n\n/**\n * Count the number of images in message content.\n */\nfunction countImages(content: MessageContent): number {\n if (typeof content === \"string\") return 0;\n return content.filter((part) => isImagePart(part)).length;\n}\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) =>\n extractMessageText(msg.content).toLowerCase().includes(text.toLowerCase()),\n ),\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 if (!lastMsg) return false;\n return extractMessageText(lastMsg.content).toLowerCase().includes(text.toLowerCase());\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(extractMessageText(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) =>\n msg.role === role && extractMessageText(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 // Multimodal Matchers\n // ==========================================================================\n\n /**\n * Match when any message contains an image.\n *\n * @example\n * mockLLM().whenMessageHasImage().returns(\"I see an image of a sunset.\")\n */\n whenMessageHasImage(): this {\n this.matchers.push((ctx) => ctx.messages.some((msg) => hasImageContent(msg.content)));\n return this;\n }\n\n /**\n * Match when any message contains audio.\n *\n * @example\n * mockLLM().whenMessageHasAudio().returns(\"I hear music playing.\")\n */\n whenMessageHasAudio(): this {\n this.matchers.push((ctx) => ctx.messages.some((msg) => hasAudioContent(msg.content)));\n return this;\n }\n\n /**\n * Match based on the number of images in the last message.\n *\n * @example\n * mockLLM().whenImageCount((n) => n >= 2).returns(\"Comparing multiple images...\")\n */\n whenImageCount(predicate: (count: number) => boolean): this {\n this.matchers.push((ctx) => {\n const lastMsg = ctx.messages[ctx.messages.length - 1];\n if (!lastMsg) return false;\n return predicate(countImages(lastMsg.content));\n });\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 // Multimodal Response Helpers\n // ==========================================================================\n\n /**\n * Return a single image in the response.\n * Useful for mocking image generation endpoints.\n *\n * @param data - Image data (base64 string or Buffer)\n * @param mimeType - MIME type (auto-detected if Buffer provided without type)\n *\n * @example\n * mockLLM()\n * .forModel('dall-e-3')\n * .returnsImage(pngBuffer)\n * .register();\n */\n returnsImage(data: string | Buffer | Uint8Array, mimeType?: ImageMimeType): this {\n if (typeof this.response === \"function\") {\n throw new Error(\"Cannot use returnsImage() after withResponse() with a function\");\n }\n\n let imageData: string;\n let imageMime: ImageMimeType;\n\n if (typeof data === \"string\") {\n imageData = data;\n if (!mimeType) {\n throw new Error(\"MIME type is required when providing base64 string data\");\n }\n imageMime = mimeType;\n } else {\n imageData = toBase64(data);\n const detected = mimeType ?? detectImageMimeType(data);\n if (!detected) {\n throw new Error(\n \"Could not detect image MIME type. Please provide the mimeType parameter explicitly.\",\n );\n }\n imageMime = detected;\n }\n\n if (!this.response.images) {\n this.response.images = [];\n }\n this.response.images.push({ data: imageData, mimeType: imageMime });\n return this;\n }\n\n /**\n * Return multiple images in the response.\n *\n * @example\n * mockLLM()\n * .forModel('dall-e-3')\n * .returnsImages([\n * { data: pngBuffer1 },\n * { data: pngBuffer2 },\n * ])\n * .register();\n */\n returnsImages(\n images: Array<{\n data: string | Buffer | Uint8Array;\n mimeType?: ImageMimeType;\n revisedPrompt?: string;\n }>,\n ): this {\n for (const img of images) {\n this.returnsImage(img.data, img.mimeType);\n // Set revised prompt if provided (on the last added image)\n if (img.revisedPrompt && this.response && typeof this.response !== \"function\") {\n const lastImage = this.response.images?.[this.response.images.length - 1];\n if (lastImage) {\n lastImage.revisedPrompt = img.revisedPrompt;\n }\n }\n }\n return this;\n }\n\n /**\n * Return audio data in the response.\n * Useful for mocking speech synthesis endpoints.\n *\n * @param data - Audio data (base64 string or Buffer)\n * @param mimeType - MIME type (auto-detected if Buffer provided without type)\n *\n * @example\n * mockLLM()\n * .forModel('tts-1')\n * .returnsAudio(mp3Buffer)\n * .register();\n */\n returnsAudio(data: string | Buffer | Uint8Array, mimeType?: AudioMimeType): this {\n if (typeof this.response === \"function\") {\n throw new Error(\"Cannot use returnsAudio() after withResponse() with a function\");\n }\n\n let audioData: string;\n let audioMime: AudioMimeType;\n\n if (typeof data === \"string\") {\n audioData = data;\n if (!mimeType) {\n throw new Error(\"MIME type is required when providing base64 string data\");\n }\n audioMime = mimeType;\n } else {\n audioData = toBase64(data);\n const detected = mimeType ?? detectAudioMimeType(data);\n if (!detected) {\n throw new Error(\n \"Could not detect audio MIME type. Please provide the mimeType parameter explicitly.\",\n );\n }\n audioMime = detected;\n }\n\n this.response.audio = { data: audioData, mimeType: audioMime };\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 { AbstractGadget } 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 AbstractGadget {\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 AbstractGadget 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","import fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Exception thrown when a path validation fails due to sandbox constraints.\n * This ensures all file operations are restricted to the current working directory.\n */\nexport class PathSandboxException extends Error {\n constructor(inputPath: string, reason: string) {\n super(`Path access denied: ${inputPath}. ${reason}`);\n this.name = \"PathSandboxException\";\n }\n}\n\n/**\n * Validates that a given path is within the current working directory.\n * This prevents directory traversal attacks and ensures all file operations\n * are sandboxed to the CWD and its subdirectories.\n *\n * @param inputPath - Path to validate (can be relative or absolute)\n * @returns The validated absolute path\n * @throws PathSandboxException if the path is outside the CWD\n * @throws Error for other file system errors\n */\nexport function validatePathIsWithinCwd(inputPath: string): string {\n const cwd = process.cwd();\n const resolvedPath = path.resolve(cwd, inputPath);\n\n // Try to get the real path to handle symlinks securely\n let finalPath: string;\n try {\n finalPath = fs.realpathSync(resolvedPath);\n } catch (error) {\n // If path doesn't exist, use the resolved path for validation\n const nodeError = error as NodeJS.ErrnoException;\n if (nodeError.code === \"ENOENT\") {\n finalPath = resolvedPath;\n } else {\n // Re-throw other errors (permission denied, etc.)\n throw error;\n }\n }\n\n // Ensure the path is within CWD or is CWD itself\n // Use path.sep to prevent matching partial directory names\n const cwdWithSep = cwd + path.sep;\n if (!finalPath.startsWith(cwdWithSep) && finalPath !== cwd) {\n throw new PathSandboxException(inputPath, \"Path is outside the current working directory\");\n }\n\n return finalPath;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { createGadget } from \"../../../index.js\";\nimport { validatePathIsWithinCwd } from \"./utils.js\";\n\n/**\n * Represents metadata for a file system entry\n */\ninterface FileEntry {\n name: string;\n relativePath: string;\n type: \"file\" | \"directory\" | \"symlink\";\n size: number;\n modified: number; // Unix epoch seconds\n}\n\n/**\n * Lists all files and directories in a given path with optional recursion.\n * Skips entries that cannot be accessed due to permissions.\n *\n * @param dirPath - Absolute path to the directory\n * @param basePath - Base path for calculating relative paths (defaults to dirPath)\n * @param maxDepth - Maximum depth to recurse (1 = immediate children only)\n * @param currentDepth - Current recursion depth (internal use)\n * @returns Array of file entries with metadata\n */\nfunction listFiles(\n dirPath: string,\n basePath: string = dirPath,\n maxDepth: number = 1,\n currentDepth: number = 1,\n): FileEntry[] {\n const entries: FileEntry[] = [];\n\n try {\n const items = fs.readdirSync(dirPath);\n\n for (const item of items) {\n const fullPath = path.join(dirPath, item);\n const relativePath = path.relative(basePath, fullPath);\n\n try {\n const stats = fs.lstatSync(fullPath);\n let type: \"file\" | \"directory\" | \"symlink\";\n let size: number;\n\n if (stats.isSymbolicLink()) {\n type = \"symlink\";\n size = 0;\n } else if (stats.isDirectory()) {\n type = \"directory\";\n size = 0;\n } else {\n type = \"file\";\n size = stats.size;\n }\n\n entries.push({\n name: item,\n relativePath,\n type,\n size,\n modified: Math.floor(stats.mtime.getTime() / 1000),\n });\n\n // Recurse into directories if we haven't reached max depth\n if (type === \"directory\" && currentDepth < maxDepth) {\n // Validate subdirectory is still within CWD (security check)\n try {\n validatePathIsWithinCwd(fullPath);\n const subEntries = listFiles(fullPath, basePath, maxDepth, currentDepth + 1);\n entries.push(...subEntries);\n } catch {\n // Skip directories outside CWD or inaccessible\n }\n }\n } catch {\n // Skip entries that can't be accessed (permission denied, etc.)\n }\n }\n } catch {\n // If we can't read the directory, return empty array\n return [];\n }\n\n return entries;\n}\n\n/**\n * Formats age from Unix epoch timestamp to human-readable string.\n * Uses compact format: 5m, 2h, 3d, 2w, 4mo, 1y\n *\n * @param epochSeconds - Unix timestamp in seconds\n * @returns Compact age string\n */\nfunction formatAge(epochSeconds: number): string {\n const now = Math.floor(Date.now() / 1000);\n const seconds = now - epochSeconds;\n\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h`;\n const days = Math.floor(hours / 24);\n if (days < 7) return `${days}d`;\n const weeks = Math.floor(days / 7);\n if (weeks < 4) return `${weeks}w`;\n const months = Math.floor(days / 30);\n if (months < 12) return `${months}mo`;\n const years = Math.floor(days / 365);\n return `${years}y`;\n}\n\n/**\n * Formats file entries as a compact pipe-separated DSL.\n * Format: #T|N|S|A header (Type, Name, Size, Age)\n * Optimized for LLM token efficiency (~70% savings vs table format).\n *\n * @param entries - Array of file entries to format\n * @returns Compact DSL string\n */\nfunction formatEntriesAsString(entries: FileEntry[]): string {\n if (entries.length === 0) {\n return \"#empty\";\n }\n\n // Sort: directories first, then files, then symlinks, alphabetically within each\n const sortedEntries = [...entries].sort((a, b) => {\n const typeOrder = { directory: 0, file: 1, symlink: 2 };\n const typeCompare = typeOrder[a.type] - typeOrder[b.type];\n if (typeCompare !== 0) return typeCompare;\n return a.relativePath.localeCompare(b.relativePath);\n });\n\n // Type code mapping\n const typeCode: Record<FileEntry[\"type\"], string> = {\n directory: \"D\",\n file: \"F\",\n symlink: \"L\",\n };\n\n // URL-encode special chars that would break parsing\n const encodeName = (name: string) => name.replace(/\\|/g, \"%7C\").replace(/\\n/g, \"%0A\");\n\n // Build compact output\n const header = \"#T|N|S|A\";\n const rows = sortedEntries.map(\n (e) => `${typeCode[e.type]}|${encodeName(e.relativePath)}|${e.size}|${formatAge(e.modified)}`,\n );\n\n return [header, ...rows].join(\"\\n\");\n}\n\n/**\n * ListDirectory gadget - Lists files and directories with full metadata.\n * All directory paths are validated to be within the current working directory.\n */\nexport const listDirectory = createGadget({\n name: \"ListDirectory\",\n description:\n \"List files and directories in a directory with full details (names, types, sizes, modification dates). Use maxDepth to explore subdirectories recursively. The directory path must be within the current working directory or its subdirectories.\",\n schema: z.object({\n directoryPath: z.string().default(\".\").describe(\"Path to the directory to list\"),\n maxDepth: z\n .number()\n .int()\n .min(1)\n .max(10)\n .default(1)\n .describe(\n \"Maximum depth to recurse (1 = immediate children only, 2 = include grandchildren, etc.)\",\n ),\n }),\n examples: [\n {\n params: { directoryPath: \".\", maxDepth: 1 },\n output: \"path=. maxDepth=1\\n\\n#T|N|S|A\\nD|src|0|2h\\nD|tests|0|1d\\nF|package.json|2841|3h\",\n comment: \"List current directory\",\n },\n {\n params: { directoryPath: \"src\", maxDepth: 2 },\n output:\n \"path=src maxDepth=2\\n\\n#T|N|S|A\\nD|components|0|1d\\nD|utils|0|2d\\nF|index.ts|512|1h\\nF|components/Button.tsx|1024|3h\",\n comment: \"List src directory recursively\",\n },\n ],\n execute: ({ directoryPath, maxDepth }) => {\n // Validate path is within CWD\n const validatedPath = validatePathIsWithinCwd(directoryPath);\n\n // Verify it's actually a directory\n const stats = fs.statSync(validatedPath);\n if (!stats.isDirectory()) {\n throw new Error(`Path is not a directory: ${directoryPath}`);\n }\n\n // List files and format output\n const entries = listFiles(validatedPath, validatedPath, maxDepth);\n const formattedList = formatEntriesAsString(entries);\n\n // Show params on first line, listing follows\n return `path=${directoryPath} maxDepth=${maxDepth}\\n\\n${formattedList}`;\n },\n});\n","import fs from \"node:fs\";\nimport { z } from \"zod\";\nimport { createGadget } from \"../../../index.js\";\nimport { validatePathIsWithinCwd } from \"./utils.js\";\n\n/**\n * ReadFile gadget - Reads the entire content of a file and returns it as text.\n * All file paths are validated to be within the current working directory.\n */\nexport const readFile = createGadget({\n name: \"ReadFile\",\n description:\n \"Read the entire content of a file and return it as text. The file path must be within the current working directory or its subdirectories.\",\n schema: z.object({\n filePath: z.string().describe(\"Path to the file to read (relative or absolute)\"),\n }),\n examples: [\n {\n params: { filePath: \"package.json\" },\n output: 'path=package.json\\n\\n{\\n \"name\": \"my-project\",\\n \"version\": \"1.0.0\"\\n ...\\n}',\n comment: \"Read a JSON config file\",\n },\n {\n params: { filePath: \"src/index.ts\" },\n output: \"path=src/index.ts\\n\\nexport function main() { ... }\",\n comment: \"Read a source file\",\n },\n ],\n execute: ({ filePath }) => {\n // Validate path is within CWD\n const validatedPath = validatePathIsWithinCwd(filePath);\n\n // Read and return file content\n const content = fs.readFileSync(validatedPath, \"utf-8\");\n\n // Show params on first line, content follows\n return `path=${filePath}\\n\\n${content}`;\n },\n});\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { createGadget } from \"../../../index.js\";\nimport { validatePathIsWithinCwd } from \"./utils.js\";\n\n/**\n * WriteFile gadget - Writes content to a file.\n * Creates parent directories if needed. Overwrites existing files.\n * All file paths are validated to be within the current working directory.\n */\nexport const writeFile = createGadget({\n name: \"WriteFile\",\n description:\n \"Write content to a file. Creates parent directories if needed. Overwrites existing files. The file path must be within the current working directory or its subdirectories.\",\n schema: z.object({\n filePath: z.string().describe(\"Path to the file to write (relative or absolute)\"),\n content: z.string().describe(\"Content to write to the file\"),\n }),\n examples: [\n {\n params: { filePath: \"output.txt\", content: \"Hello, World!\" },\n output: \"path=output.txt\\n\\nWrote 13 bytes\",\n comment: \"Write a simple text file\",\n },\n {\n params: {\n filePath: \"src/server.ts\",\n content: `import { serve } from \"bun\";\n\nconst port = 3000;\n\nserve({\n port,\n fetch: (req) => new Response(\\`Hello from \\${req.url}\\`),\n});\n\nconsole.log(\\`Server running on http://localhost:\\${port}\\`);`,\n },\n output: \"path=src/server.ts\\n\\nWrote 198 bytes (created directory: src)\",\n comment:\n \"Write code with template literals - NO escaping needed inside heredoc (use <<<EOF...EOF)\",\n },\n ],\n execute: ({ filePath, content }) => {\n // Validate path is within CWD\n const validatedPath = validatePathIsWithinCwd(filePath);\n\n // Ensure parent directory exists (create if needed)\n const parentDir = path.dirname(validatedPath);\n let createdDir = false;\n if (!fs.existsSync(parentDir)) {\n // Validate parent dir is also within CWD before creating\n validatePathIsWithinCwd(parentDir);\n fs.mkdirSync(parentDir, { recursive: true });\n createdDir = true;\n }\n\n // Write the file\n fs.writeFileSync(validatedPath, content, \"utf-8\");\n const bytesWritten = Buffer.byteLength(content, \"utf-8\");\n\n // Format output following the established pattern\n const dirNote = createdDir ? ` (created directory: ${path.dirname(filePath)})` : \"\";\n return `path=${filePath}\\n\\nWrote ${bytesWritten} bytes${dirNote}`;\n },\n});\n","import { z } from \"zod\";\nimport { createGadget } from \"../../index.js\";\n\n/**\n * RunCommand gadget - Executes a command with arguments and returns its output.\n *\n * Uses argv array to bypass shell interpretation entirely - arguments are\n * passed directly to the process without any escaping or shell expansion.\n * This allows special characters (quotes, backticks, newlines) to work correctly.\n *\n * Safety should be added externally via the hook system (see example 10).\n *\n * Output format follows the established pattern: `status=N\\n\\n<output>`\n */\nexport const runCommand = createGadget({\n name: \"RunCommand\",\n description:\n \"Execute a command with arguments and return its output. Uses argv array to bypass shell - arguments are passed directly without interpretation. Returns stdout/stderr combined with exit status.\",\n schema: z.object({\n argv: z\n .array(z.string())\n .describe(\"Command and arguments as array (e.g., ['git', 'commit', '-m', 'message'])\"),\n cwd: z\n .string()\n .optional()\n .describe(\"Working directory for the command (default: current directory)\"),\n timeout: z.number().default(30000).describe(\"Timeout in milliseconds (default: 30000)\"),\n }),\n examples: [\n {\n params: { argv: [\"ls\", \"-la\"], timeout: 30000 },\n output:\n \"status=0\\n\\ntotal 24\\ndrwxr-xr-x 5 user staff 160 Nov 27 10:00 .\\ndrwxr-xr-x 3 user staff 96 Nov 27 09:00 ..\\n-rw-r--r-- 1 user staff 1024 Nov 27 10:00 package.json\",\n comment: \"List directory contents with details\",\n },\n {\n params: { argv: [\"echo\", \"Hello World\"], timeout: 30000 },\n output: \"status=0\\n\\nHello World\",\n comment: \"Echo without shell - argument passed directly\",\n },\n {\n params: { argv: [\"cat\", \"nonexistent.txt\"], timeout: 30000 },\n output: \"status=1\\n\\ncat: nonexistent.txt: No such file or directory\",\n comment: \"Command that fails returns non-zero status\",\n },\n {\n params: { argv: [\"pwd\"], cwd: \"/tmp\", timeout: 30000 },\n output: \"status=0\\n\\n/tmp\",\n comment: \"Execute command in a specific directory\",\n },\n {\n params: {\n argv: [\n \"gh\",\n \"pr\",\n \"review\",\n \"123\",\n \"--comment\",\n \"--body\",\n \"Review with `backticks` and 'quotes'\",\n ],\n timeout: 30000,\n },\n output: \"status=0\\n\\n(no output)\",\n comment: \"Complex arguments with special characters - no escaping needed\",\n },\n {\n params: {\n argv: [\n \"gh\",\n \"pr\",\n \"review\",\n \"123\",\n \"--approve\",\n \"--body\",\n \"## Review Summary\\n\\n**Looks good!**\\n\\n- Clean code\\n- Tests pass\",\n ],\n timeout: 30000,\n },\n output: \"status=0\\n\\nApproving pull request #123\",\n comment: \"Multiline body: --body flag and content must be SEPARATE array elements\",\n },\n ],\n execute: async ({ argv, cwd, timeout }) => {\n const workingDir = cwd ?? process.cwd();\n\n if (argv.length === 0) {\n return \"status=1\\n\\nerror: argv array cannot be empty\";\n }\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n try {\n // Spawn process directly without shell - arguments passed as-is\n const proc = Bun.spawn(argv, {\n cwd: workingDir,\n stdout: \"pipe\",\n stderr: \"pipe\",\n });\n\n // Create a timeout promise with cleanup\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n proc.kill();\n reject(new Error(`Command timed out after ${timeout}ms`));\n }, timeout);\n });\n\n // Wait for process and consume streams concurrently to prevent deadlock.\n // If we await proc.exited first, large output can fill pipe buffers,\n // causing the process to block on write while we block on exit.\n const [exitCode, stdout, stderr] = await Promise.race([\n Promise.all([\n proc.exited,\n new Response(proc.stdout).text(),\n new Response(proc.stderr).text(),\n ]),\n timeoutPromise,\n ]);\n\n // Clear timeout on normal exit to prevent dangling timer\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n\n // Combine output (stdout first, then stderr if any)\n const output = [stdout, stderr].filter(Boolean).join(\"\\n\").trim();\n\n return `status=${exitCode}\\n\\n${output || \"(no output)\"}`;\n } catch (error) {\n // Clear timeout on error path too\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n const message = error instanceof Error ? error.message : String(error);\n return `status=1\\n\\nerror: ${message}`;\n }\n },\n});\n","/**\n * Built-in gadgets registry.\n * These gadgets can be referenced by name (e.g., \"ListDirectory\") or\n * with the explicit \"builtin:\" prefix (e.g., \"builtin:ListDirectory\").\n */\n\nimport type { AbstractGadget } from \"../../gadgets/gadget.js\";\nimport { editFile } from \"./filesystem/edit-file.js\";\nimport { listDirectory } from \"./filesystem/list-directory.js\";\nimport { readFile } from \"./filesystem/read-file.js\";\nimport { writeFile } from \"./filesystem/write-file.js\";\nimport { runCommand } from \"./run-command.js\";\n\n/**\n * Registry mapping gadget names to their instances.\n * Names are case-sensitive and match the gadget's declared name.\n */\nexport const builtinGadgetRegistry: Record<string, AbstractGadget> = {\n ListDirectory: listDirectory,\n ReadFile: readFile,\n WriteFile: writeFile,\n EditFile: editFile,\n RunCommand: runCommand,\n};\n\n/**\n * Gets a built-in gadget by name.\n *\n * @param name - The gadget name (e.g., \"ListDirectory\")\n * @returns The gadget instance, or undefined if not found\n */\nexport function getBuiltinGadget(name: string): AbstractGadget | undefined {\n return builtinGadgetRegistry[name];\n}\n\n/**\n * Checks if a name corresponds to a built-in gadget.\n *\n * @param name - The name to check\n * @returns True if the name is a registered built-in gadget\n */\nexport function isBuiltinGadgetName(name: string): boolean {\n return name in builtinGadgetRegistry;\n}\n\n/**\n * Gets all available built-in gadget names.\n *\n * @returns Array of built-in gadget names\n */\nexport function getBuiltinGadgetNames(): string[] {\n return Object.keys(builtinGadgetRegistry);\n}\n\n// Re-export individual gadgets for direct imports\nexport { listDirectory, readFile, writeFile, editFile, runCommand };\n","/**\n * External gadget loader for llmist CLI.\n *\n * Supports loading gadgets from:\n * - npm packages (with auto-installation)\n * - git URLs\n * - Manifest-based presets and individual gadget selection\n *\n * @module cli/external-gadgets\n */\n\nimport { execSync, spawnSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { pathToFileURL } from \"node:url\";\n\nimport type { AbstractGadget } from \"../gadgets/gadget.js\";\nimport { extractGadgetsFromModule } from \"./gadgets.js\";\n\n/**\n * Cache directory for external gadget packages.\n */\nconst CACHE_DIR = path.join(os.homedir(), \".llmist\", \"gadget-cache\");\n\n/**\n * Parsed gadget specifier.\n */\nexport interface GadgetSpecifier {\n type: \"npm\" | \"git\";\n /** Package name (npm) or URL (git) */\n package: string;\n /** Version or git ref */\n version?: string;\n /** Preset name (e.g., \"minimal\", \"readonly\") */\n preset?: string;\n /** Individual gadget name (e.g., \"Navigate\") */\n gadgetName?: string;\n}\n\n/**\n * Manifest structure from package.json llmist field.\n */\nexport interface LlmistManifest {\n /** Entry point for all gadgets */\n gadgets?: string;\n /** Factory function entry point */\n factory?: string;\n /** Subagent definitions */\n subagents?: Record<\n string,\n {\n entryPoint: string;\n export: string;\n description?: string;\n uses?: string[];\n defaultModel?: string;\n maxIterations?: number;\n }\n >;\n /** Preset definitions */\n presets?: Record<string, string[] | \"*\">;\n /** Session factory info */\n session?: {\n factory: string;\n type: string;\n };\n}\n\n/**\n * Check if a specifier is an external package (npm or git).\n */\nexport function isExternalPackageSpecifier(specifier: string): boolean {\n // npm package patterns\n if (/^@?[a-z0-9][\\w.-]*(?:@[\\w.-]+)?(?::[a-z]+)?(?:\\/\\w+)?$/i.test(specifier)) {\n return true;\n }\n // git URL patterns\n if (specifier.startsWith(\"git+\")) {\n return true;\n }\n return false;\n}\n\n/**\n * Parse a gadget specifier into its components.\n *\n * Supported formats:\n * - `webasto` - npm package, all gadgets\n * - `webasto@2.0.0` - npm package with version\n * - `webasto:minimal` - npm package with preset\n * - `webasto/Navigate` - npm package with specific gadget\n * - `webasto@2.0.0:minimal` - all combined\n * - `git+https://github.com/user/repo` - git URL\n * - `git+https://github.com/user/repo#v1.0.0` - git URL with ref\n */\nexport function parseGadgetSpecifier(specifier: string): GadgetSpecifier | null {\n // Git URL\n if (specifier.startsWith(\"git+\")) {\n const url = specifier.slice(4);\n const [baseUrl, ref] = url.split(\"#\");\n return {\n type: \"git\",\n package: baseUrl,\n version: ref,\n };\n }\n\n // npm package with optional version, preset, and gadget name\n // Format: package[@version][:preset][/gadgetName]\n const npmMatch = specifier.match(\n /^(@?[a-z0-9][\\w.-]*)(?:@([\\w.-]+))?(?::([a-z]+))?(?:\\/(\\w+))?$/i,\n );\n\n if (npmMatch) {\n const [, pkg, version, preset, gadgetName] = npmMatch;\n return {\n type: \"npm\",\n package: pkg,\n version,\n preset,\n gadgetName,\n };\n }\n\n return null;\n}\n\n/**\n * Get the cache directory for a package.\n */\nfunction getCacheDir(spec: GadgetSpecifier): string {\n const versionSuffix = spec.version ? `@${spec.version}` : \"@latest\";\n\n if (spec.type === \"npm\") {\n return path.join(CACHE_DIR, \"npm\", `${spec.package}${versionSuffix}`);\n }\n // git: sanitize URL for filesystem\n const sanitizedUrl = spec.package.replace(/[/:]/g, \"-\").replace(/^-+|-+$/g, \"\");\n return path.join(CACHE_DIR, \"git\", `${sanitizedUrl}${versionSuffix}`);\n}\n\n/**\n * Check if a package is already cached and up to date.\n */\nfunction isCached(cacheDir: string): boolean {\n const packageJsonPath = path.join(cacheDir, \"package.json\");\n return fs.existsSync(packageJsonPath);\n}\n\n/**\n * Install an npm package to the cache directory.\n */\nasync function installNpmPackage(spec: GadgetSpecifier, cacheDir: string): Promise<void> {\n // Create cache directory\n fs.mkdirSync(cacheDir, { recursive: true });\n\n // Create minimal package.json\n const packageJson = {\n name: \"llmist-gadget-cache\",\n private: true,\n type: \"module\",\n };\n fs.writeFileSync(path.join(cacheDir, \"package.json\"), JSON.stringify(packageJson, null, 2));\n\n // Install the package\n const packageSpec = spec.version ? `${spec.package}@${spec.version}` : spec.package;\n\n try {\n // Use bun add for isolated install (works in Docker containers that only have bun)\n execSync(`bun add \"${packageSpec}\"`, {\n stdio: \"pipe\",\n cwd: cacheDir,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to install npm package '${packageSpec}': ${message}`);\n }\n}\n\n/**\n * Clone/fetch a git repository to the cache directory.\n */\nasync function installGitPackage(spec: GadgetSpecifier, cacheDir: string): Promise<void> {\n // Create parent directory\n fs.mkdirSync(path.dirname(cacheDir), { recursive: true });\n\n if (fs.existsSync(cacheDir)) {\n // Update existing repo\n try {\n execSync(\"git fetch\", { cwd: cacheDir, stdio: \"pipe\" });\n if (spec.version) {\n execSync(`git checkout ${spec.version}`, { cwd: cacheDir, stdio: \"pipe\" });\n }\n } catch (error) {\n // If update fails, remove and re-clone\n fs.rmSync(cacheDir, { recursive: true, force: true });\n }\n }\n\n if (!fs.existsSync(cacheDir)) {\n try {\n const cloneCmd = spec.version\n ? `git clone --branch ${spec.version} \"${spec.package}\" \"${cacheDir}\"`\n : `git clone \"${spec.package}\" \"${cacheDir}\"`;\n execSync(cloneCmd, { stdio: \"pipe\" });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to clone git repository '${spec.package}': ${message}`);\n }\n\n // Install dependencies and build\n if (fs.existsSync(path.join(cacheDir, \"package.json\"))) {\n try {\n execSync(\"bun install\", { cwd: cacheDir, stdio: \"inherit\" });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to install dependencies for '${spec.package}': ${message}`);\n }\n\n // Run build if available (git packages need to be built)\n try {\n const packageJson = JSON.parse(fs.readFileSync(path.join(cacheDir, \"package.json\"), \"utf-8\"));\n if (packageJson.scripts?.build) {\n execSync(\"bun run build\", { cwd: cacheDir, stdio: \"inherit\" });\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to build package '${spec.package}': ${message}`);\n }\n }\n }\n}\n\n/**\n * Read the llmist manifest from a package.\n */\nfunction readManifest(packageDir: string): LlmistManifest | null {\n const packageJsonPath = path.join(packageDir, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) {\n return null;\n }\n\n try {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n return packageJson.llmist || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the path to the installed package.\n */\nfunction getPackagePath(cacheDir: string, packageName: string): string {\n // For npm packages, the actual package is in node_modules\n const nodeModulesPath = path.join(cacheDir, \"node_modules\", packageName);\n if (fs.existsSync(nodeModulesPath)) {\n return nodeModulesPath;\n }\n // For git packages, it's the cache dir itself\n return cacheDir;\n}\n\n/**\n * Load gadgets from an external package.\n *\n * @param specifier - External package specifier\n * @param forceInstall - Force reinstall even if cached\n * @returns Array of loaded gadgets\n */\nexport async function loadExternalGadgets(\n specifier: string,\n forceInstall = false,\n): Promise<AbstractGadget[]> {\n const spec = parseGadgetSpecifier(specifier);\n if (!spec) {\n throw new Error(`Invalid external package specifier: ${specifier}`);\n }\n\n const cacheDir = getCacheDir(spec);\n\n // Install if not cached or force install\n if (!isCached(cacheDir) || forceInstall) {\n if (spec.type === \"npm\") {\n await installNpmPackage(spec, cacheDir);\n } else {\n await installGitPackage(spec, cacheDir);\n }\n }\n\n // Get the actual package path\n const packagePath = getPackagePath(cacheDir, spec.package);\n\n // Read manifest\n const manifest = readManifest(packagePath);\n\n // Determine what to load\n let entryPoint: string;\n let gadgetNames: string[] | null = null;\n\n if (spec.gadgetName) {\n // Single gadget requested\n gadgetNames = [spec.gadgetName];\n // Check if it's a subagent\n if (manifest?.subagents?.[spec.gadgetName]) {\n entryPoint = manifest.subagents[spec.gadgetName].entryPoint;\n } else {\n entryPoint = manifest?.gadgets || \"./dist/index.js\";\n }\n } else if (spec.preset) {\n // Preset requested\n if (!manifest?.presets?.[spec.preset]) {\n throw new Error(`Unknown preset '${spec.preset}' in package '${spec.package}'`);\n }\n const preset = manifest.presets[spec.preset];\n if (preset === \"*\") {\n // All gadgets\n gadgetNames = null;\n } else {\n gadgetNames = preset;\n }\n entryPoint = manifest?.gadgets || \"./dist/index.js\";\n } else {\n // All gadgets (default)\n entryPoint = manifest?.gadgets || \"./dist/index.js\";\n }\n\n // Resolve entry point\n const resolvedEntryPoint = path.resolve(packagePath, entryPoint);\n if (!fs.existsSync(resolvedEntryPoint)) {\n throw new Error(\n `Entry point not found: ${resolvedEntryPoint}. ` +\n \"Make sure the package is built (run 'npm run build' in the package directory).\",\n );\n }\n\n // Import the module\n const moduleUrl = pathToFileURL(resolvedEntryPoint).href;\n let exports: unknown;\n try {\n exports = await import(moduleUrl);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to import '${specifier}': ${message}`);\n }\n\n // Extract gadgets\n let gadgets = extractGadgetsFromModule(exports);\n\n // Filter by name if specific gadgets requested\n if (gadgetNames) {\n const gadgetSet = new Set(gadgetNames.map((n) => n.toLowerCase()));\n gadgets = gadgets.filter((g) => {\n const name = g.name?.toLowerCase() || \"\";\n return gadgetSet.has(name);\n });\n\n // Check if all requested gadgets were found\n const foundNames = new Set(gadgets.map((g) => g.name?.toLowerCase() || \"\"));\n for (const requested of gadgetNames) {\n if (!foundNames.has(requested.toLowerCase())) {\n throw new Error(`Gadget '${requested}' not found in package '${spec.package}'`);\n }\n }\n }\n\n if (gadgets.length === 0) {\n throw new Error(`No gadgets found in package '${spec.package}'`);\n }\n\n return gadgets;\n}\n\n/**\n * List available gadgets from an external package.\n *\n * @param specifier - External package specifier\n * @returns Object with gadget info\n */\nexport async function listExternalGadgets(specifier: string): Promise<{\n packageName: string;\n gadgets: Array<{ name: string; description: string }>;\n subagents: Array<{ name: string; description: string }>;\n presets: string[];\n}> {\n const spec = parseGadgetSpecifier(specifier);\n if (!spec) {\n throw new Error(`Invalid external package specifier: ${specifier}`);\n }\n\n const cacheDir = getCacheDir(spec);\n\n // Install if not cached\n if (!isCached(cacheDir)) {\n if (spec.type === \"npm\") {\n await installNpmPackage(spec, cacheDir);\n } else {\n await installGitPackage(spec, cacheDir);\n }\n }\n\n const packagePath = getPackagePath(cacheDir, spec.package);\n const manifest = readManifest(packagePath);\n\n // Load gadgets to get their info\n const entryPoint = manifest?.gadgets || \"./dist/index.js\";\n const resolvedEntryPoint = path.resolve(packagePath, entryPoint);\n\n let gadgetInfo: Array<{ name: string; description: string }> = [];\n\n if (fs.existsSync(resolvedEntryPoint)) {\n try {\n const moduleUrl = pathToFileURL(resolvedEntryPoint).href;\n const exports = await import(moduleUrl);\n const gadgets = extractGadgetsFromModule(exports);\n gadgetInfo = gadgets.map((g) => ({\n name: g.name || \"unnamed\",\n description: g.description || \"\",\n }));\n } catch {\n // Ignore import errors for listing\n }\n }\n\n // Get subagent info from manifest\n const subagentInfo = Object.entries(manifest?.subagents || {}).map(([name, info]) => ({\n name,\n description: info.description || \"\",\n }));\n\n return {\n packageName: spec.package,\n gadgets: gadgetInfo,\n subagents: subagentInfo,\n presets: Object.keys(manifest?.presets || {}),\n };\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { extractMessageText, type LLMMessage } from \"../core/messages.js\";\n\n/**\n * Default directory for LLM debug logs.\n */\nexport const DEFAULT_LLM_LOG_DIR = join(homedir(), \".llmist\", \"logs\");\n\n/**\n * Resolves the log directory from a boolean or string option.\n * - true: use default directory with subdir\n * - string: use the provided path\n * - undefined/false: disabled\n */\nexport function resolveLogDir(\n option: string | boolean | undefined,\n subdir: string,\n): string | undefined {\n if (option === true) {\n return join(DEFAULT_LLM_LOG_DIR, subdir);\n }\n if (typeof option === \"string\") {\n return option;\n }\n return undefined;\n}\n\n/**\n * Formats LLM messages as plain text for debugging.\n */\nexport function formatLlmRequest(messages: LLMMessage[]): string {\n const lines: string[] = [];\n for (const msg of messages) {\n lines.push(`=== ${msg.role.toUpperCase()} ===`);\n // Handle undefined content (for incomplete/malformed messages)\n lines.push(msg.content ? extractMessageText(msg.content) : \"\");\n lines.push(\"\");\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Writes a debug log file, creating the directory if needed.\n */\nexport async function writeLogFile(dir: string, filename: string, content: string): Promise<void> {\n await mkdir(dir, { recursive: true });\n await writeFile(join(dir, filename), content, \"utf-8\");\n}\n\n/**\n * Formats a timestamp for session directory naming.\n * Returns format: \"YYYY-MM-DD_HH-MM-SS\" (e.g., \"2025-12-09_14-30-45\")\n */\nexport function formatSessionTimestamp(date: Date = new Date()): string {\n const pad = (n: number) => n.toString().padStart(2, \"0\");\n const year = date.getFullYear();\n const month = pad(date.getMonth() + 1);\n const day = pad(date.getDate());\n const hours = pad(date.getHours());\n const minutes = pad(date.getMinutes());\n const seconds = pad(date.getSeconds());\n return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;\n}\n\n/**\n * Creates a session directory with a timestamped name.\n * Returns the full path to the created directory, or undefined if creation fails.\n */\nexport async function createSessionDir(baseDir: string): Promise<string | undefined> {\n const timestamp = formatSessionTimestamp();\n const sessionDir = join(baseDir, timestamp);\n try {\n await mkdir(sessionDir, { recursive: true });\n return sessionDir;\n } catch (error) {\n console.warn(`[llmist] Failed to create log session directory: ${sessionDir}`, error);\n return undefined;\n }\n}\n\n/**\n * Formats a call number as a zero-padded 4-digit string.\n * E.g., 1 → \"0001\", 42 → \"0042\"\n */\nexport function formatCallNumber(n: number): string {\n return n.toString().padStart(4, \"0\");\n}\n","import chalk from \"chalk\";\nimport { InvalidArgumentError } from \"commander\";\n\nimport type { ModelRegistry } from \"../core/model-registry.js\";\nimport type { TokenUsage } from \"../core/options.js\";\nimport { FALLBACK_CHARS_PER_TOKEN } from \"../providers/constants.js\";\nimport type { CLIEnvironment, TTYAwareStream } from \"./environment.js\";\n\n/**\n * Options for creating a numeric value parser.\n */\nexport interface NumericParserOptions {\n label: string;\n integer?: boolean;\n min?: number;\n max?: number;\n}\n\n/**\n * Creates a parser function for numeric command-line options with validation.\n * Validates that values are numbers, optionally integers, and within min/max bounds.\n *\n * @param options - Parser configuration (label, integer, min, max)\n * @returns Parser function that validates and returns the numeric value\n * @throws InvalidArgumentError if validation fails\n */\nexport function createNumericParser({\n label,\n integer = false,\n min,\n max,\n}: NumericParserOptions): (value: string) => number {\n return (value: string) => {\n const parsed = Number(value);\n if (Number.isNaN(parsed)) {\n throw new InvalidArgumentError(`${label} must be a number.`);\n }\n\n if (integer && !Number.isInteger(parsed)) {\n throw new InvalidArgumentError(`${label} must be an integer.`);\n }\n\n if (min !== undefined && parsed < min) {\n throw new InvalidArgumentError(`${label} must be greater than or equal to ${min}.`);\n }\n\n if (max !== undefined && parsed > max) {\n throw new InvalidArgumentError(`${label} must be less than or equal to ${max}.`);\n }\n\n return parsed;\n };\n}\n\n/**\n * Helper class for writing text to a stream while tracking newline state.\n * Ensures output ends with a newline for proper terminal formatting.\n */\nexport class StreamPrinter {\n private endedWithNewline = true;\n\n constructor(private readonly target: NodeJS.WritableStream) {}\n\n /**\n * Writes text to the target stream and tracks newline state.\n *\n * @param text - Text to write\n */\n write(text: string): void {\n if (!text) {\n return;\n }\n this.target.write(text);\n this.endedWithNewline = text.endsWith(\"\\n\");\n }\n\n /**\n * Ensures output ends with a newline by writing one if needed.\n */\n ensureNewline(): void {\n if (!this.endedWithNewline) {\n this.target.write(\"\\n\");\n this.endedWithNewline = true;\n }\n }\n}\n\n/**\n * Checks if a stream is a TTY (terminal) for interactive input.\n *\n * @param stream - Stream to check\n * @returns True if stream is a TTY\n */\nexport function isInteractive(stream: TTYAwareStream): boolean {\n return Boolean(stream.isTTY);\n}\n\n/** ESC key byte code */\nconst ESC_KEY = 0x1b;\n\n/**\n * Timeout in milliseconds to distinguish standalone ESC key from escape sequences.\n *\n * When a user presses the ESC key alone, only byte 0x1B is sent. However, arrow keys\n * and other special keys send escape sequences that START with 0x1B followed by\n * additional bytes (e.g., `ESC[A` for up arrow, `ESC[B` for down arrow).\n *\n * These additional bytes typically arrive within 10-20ms on most terminals and SSH\n * connections. The 50ms timeout provides a safe buffer to detect escape sequences\n * while keeping the standalone ESC key responsive to user input.\n *\n * If no additional bytes arrive within this window after an initial ESC byte,\n * we treat it as a standalone ESC key press.\n */\nconst ESC_TIMEOUT_MS = 50;\nconst CTRL_C = 0x03; // ETX - End of Text (Ctrl+C in raw mode)\n\n/**\n * Creates a keyboard listener for ESC key and Ctrl+C detection in TTY mode.\n *\n * Uses a timeout to distinguish standalone ESC from escape sequences (like arrow keys).\n * Arrow keys start with ESC byte (0x1B) followed by additional bytes, so we wait briefly\n * to see if more bytes arrive before triggering the callback.\n *\n * When stdin is in raw mode, Ctrl+C is received as byte 0x03 instead of generating\n * a SIGINT signal. This function handles Ctrl+C explicitly via the onCtrlC callback.\n *\n * @param stdin - The stdin stream (must be TTY with setRawMode support)\n * @param onEsc - Callback when ESC is pressed\n * @param onCtrlC - Optional callback when Ctrl+C is pressed in raw mode\n * @returns Cleanup function to restore normal mode, or null if not supported\n */\nexport function createEscKeyListener(\n stdin: NodeJS.ReadStream,\n onEsc: () => void,\n onCtrlC?: () => void,\n): (() => void) | null {\n // Check both isTTY and setRawMode availability (mock streams may have isTTY but no setRawMode)\n if (!stdin.isTTY || typeof stdin.setRawMode !== \"function\") {\n return null;\n }\n\n let escTimeout: NodeJS.Timeout | null = null;\n\n const handleData = (data: Buffer) => {\n // Handle Ctrl+C in raw mode (since SIGINT won't be generated)\n if (data[0] === CTRL_C && onCtrlC) {\n // Clear any pending ESC timeout before handling Ctrl+C\n if (escTimeout) {\n clearTimeout(escTimeout);\n escTimeout = null;\n }\n onCtrlC();\n return;\n }\n\n if (data[0] === ESC_KEY) {\n if (data.length === 1) {\n // Could be standalone ESC or start of sequence - use timeout\n escTimeout = setTimeout(() => {\n onEsc();\n }, ESC_TIMEOUT_MS);\n } else {\n // Part of escape sequence (arrow key, etc.) - clear any pending timeout\n if (escTimeout) {\n clearTimeout(escTimeout);\n escTimeout = null;\n }\n }\n } else {\n // Other key - clear any pending ESC timeout\n if (escTimeout) {\n clearTimeout(escTimeout);\n escTimeout = null;\n }\n }\n };\n\n // Enable raw mode to get individual keystrokes\n stdin.setRawMode(true);\n stdin.resume();\n stdin.on(\"data\", handleData);\n\n // Return cleanup function\n return () => {\n if (escTimeout) {\n clearTimeout(escTimeout);\n }\n stdin.removeListener(\"data\", handleData);\n stdin.setRawMode(false);\n stdin.pause();\n };\n}\n\n/**\n * Timeout window for detecting double Ctrl+C press (in milliseconds).\n *\n * When no operation is active, pressing Ctrl+C once shows a hint message.\n * If a second Ctrl+C is pressed within this window, the CLI exits gracefully.\n * This pattern is familiar from many CLI tools (npm, vim, etc.).\n */\nconst SIGINT_DOUBLE_PRESS_MS = 1000;\n\n/**\n * Creates a SIGINT (Ctrl+C) listener with double-press detection.\n *\n * Behavior:\n * - If an operation is active: cancels the operation via `onCancel`\n * - If no operation active and first press: shows hint message\n * - If no operation active and second press within 1 second: calls `onQuit`\n *\n * @param onCancel - Callback when Ctrl+C pressed during an active operation\n * @param onQuit - Callback when double Ctrl+C pressed (quit CLI)\n * @param isOperationActive - Function that returns true if an operation is in progress\n * @param stderr - Stream to write hint messages to (defaults to process.stderr)\n * @returns Cleanup function to remove the listener\n *\n * @example\n * ```typescript\n * const cleanup = createSigintListener(\n * () => abortController.abort(),\n * () => process.exit(0),\n * () => isStreaming,\n * );\n *\n * // When done:\n * cleanup();\n * ```\n */\nexport function createSigintListener(\n onCancel: () => void,\n onQuit: () => void,\n isOperationActive: () => boolean,\n stderr: NodeJS.WritableStream = process.stderr,\n): () => void {\n let lastSigintTime = 0;\n\n const handler = () => {\n const now = Date.now();\n\n if (isOperationActive()) {\n // Cancel the current operation\n onCancel();\n // Set timer to now so that a second Ctrl+C within 1 second will trigger quit\n lastSigintTime = now;\n return;\n }\n\n // Check for double-press\n if (now - lastSigintTime < SIGINT_DOUBLE_PRESS_MS) {\n onQuit();\n return;\n }\n\n // First press when no operation is active\n lastSigintTime = now;\n stderr.write(chalk.dim(\"\\n[Press Ctrl+C again to quit]\\n\"));\n };\n\n process.on(\"SIGINT\", handler);\n\n return () => {\n process.removeListener(\"SIGINT\", handler);\n };\n}\n\nconst SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\nconst SPINNER_DELAY_MS = 500; // Don't show spinner for fast responses\n\ntype ProgressMode = \"streaming\" | \"cumulative\";\n\n// Import formatters from centralized formatting module\n// This showcases llmist's clean code organization\nimport { formatCost, formatGadgetLine, formatLLMCallLine, formatTokens } from \"./ui/formatters.js\";\n\n/**\n * Progress indicator shown while waiting for LLM response.\n * Two modes:\n * - streaming: Shows current LLM call stats (out/in tokens, call time)\n * - cumulative: Shows total stats across all calls (total tokens, iterations, total time)\n * Only displays on TTY (interactive terminal), silent when piped.\n */\nexport class StreamProgress {\n // Animation state\n private frameIndex = 0;\n private interval: ReturnType<typeof setInterval> | null = null;\n private delayTimeout: ReturnType<typeof setTimeout> | null = null;\n private isRunning = false;\n private hasRendered = false;\n private lastRenderLineCount = 0; // Track lines rendered for multi-line clearing\n\n // Current call stats (streaming mode)\n private mode: ProgressMode = \"cumulative\";\n private model = \"\";\n private callStartTime = Date.now();\n private callInputTokens = 0;\n private callInputTokensEstimated = true;\n private callOutputTokens = 0;\n private callOutputTokensEstimated = true;\n private callOutputChars = 0;\n private isStreaming = false;\n // Cache token tracking for live cost estimation during streaming\n private callCachedInputTokens = 0;\n private callCacheCreationInputTokens = 0;\n\n // Cumulative stats (cumulative mode)\n private totalStartTime = Date.now();\n private totalTokens = 0;\n private totalCost = 0;\n private iterations = 0;\n private currentIteration = 0;\n\n // In-flight gadget tracking for concurrent status display\n private inFlightGadgets: Map<\n string,\n {\n name: string;\n params?: Record<string, unknown>;\n startTime: number;\n completed?: boolean;\n completedTime?: number;\n }\n > = new Map();\n\n // Nested agent tracking for hierarchical subagent display\n private nestedAgents: Map<\n string,\n {\n parentInvocationId: string;\n depth: number;\n model: string;\n iteration: number;\n /** Parent call number for hierarchical display (e.g., #1.2) */\n parentCallNumber?: number;\n /** Gadget invocation ID for unique subagent identification (e.g., #6.browse_web_1.2) */\n gadgetInvocationId?: string;\n startTime: number;\n inputTokens?: number;\n outputTokens?: number;\n // First-class subagent metrics (cached tokens, cost, finish reason)\n cachedInputTokens?: number;\n cacheCreationInputTokens?: number;\n finishReason?: string;\n cost?: number;\n completed?: boolean;\n completedTime?: number;\n }\n > = new Map();\n\n // Nested gadget tracking for hierarchical subagent display\n private nestedGadgets: Map<\n string,\n {\n depth: number;\n parentInvocationId: string;\n name: string;\n parameters?: Record<string, unknown>;\n startTime: number;\n completed?: boolean;\n completedTime?: number;\n }\n > = new Map();\n\n constructor(\n private readonly target: NodeJS.WritableStream,\n private readonly isTTY: boolean,\n private readonly modelRegistry?: ModelRegistry,\n ) {}\n\n /**\n * Add a gadget to the in-flight tracking (called when gadget_call event received).\n * Triggers re-render to show the gadget in the status display.\n */\n addGadget(invocationId: string, name: string, params?: Record<string, unknown>): void {\n this.inFlightGadgets.set(invocationId, { name, params, startTime: Date.now() });\n // Re-render immediately to show the new gadget\n if (this.isRunning && this.isTTY) {\n this.render();\n }\n }\n\n /**\n * Remove a gadget from in-flight tracking (called when gadget_result event received).\n * Triggers re-render to update the status display.\n */\n removeGadget(invocationId: string): void {\n this.inFlightGadgets.delete(invocationId);\n // Re-render immediately to remove the gadget from display\n if (this.isRunning && this.isTTY) {\n this.render();\n }\n }\n\n /**\n * Check if there are any gadgets currently in flight.\n */\n hasInFlightGadgets(): boolean {\n return this.inFlightGadgets.size > 0;\n }\n\n /**\n * Get a gadget by ID (for accessing name, params, etc.).\n */\n getGadget(invocationId: string) {\n return this.inFlightGadgets.get(invocationId);\n }\n\n /**\n * Mark a gadget as completed (keeps it visible with ✓ indicator).\n * Records completion time to freeze the elapsed timer.\n * The gadget and its nested operations remain visible until clearCompletedGadgets() is called.\n */\n completeGadget(invocationId: string): void {\n const gadget = this.inFlightGadgets.get(invocationId);\n if (gadget) {\n gadget.completed = true;\n gadget.completedTime = Date.now();\n if (this.isRunning && this.isTTY) {\n this.render();\n }\n }\n }\n\n /**\n * Clear all completed gadgets from the display.\n * Called when new text output arrives to clean up the finished gadget section.\n */\n clearCompletedGadgets(): void {\n for (const [id, gadget] of this.inFlightGadgets) {\n if (gadget.completed) {\n this.inFlightGadgets.delete(id);\n // Also clean up nested operations for this gadget\n for (const [nestedId, nested] of this.nestedAgents) {\n if (nested.parentInvocationId === id) {\n this.nestedAgents.delete(nestedId);\n }\n }\n for (const [nestedId, nested] of this.nestedGadgets) {\n if (nested.parentInvocationId === id) {\n this.nestedGadgets.delete(nestedId);\n }\n }\n }\n }\n if (this.isRunning && this.isTTY) {\n this.render();\n }\n }\n\n /**\n * Add a nested agent LLM call (called when nested llm_call_start event received).\n * Used to display hierarchical progress for subagent gadgets.\n * @param parentCallNumber - Top-level call number for hierarchical display (e.g., #1.2)\n * @param gadgetInvocationId - Gadget invocation ID for unique subagent identification\n */\n addNestedAgent(\n id: string,\n parentInvocationId: string,\n depth: number,\n model: string,\n iteration: number,\n info?: {\n inputTokens?: number;\n cachedInputTokens?: number;\n },\n parentCallNumber?: number,\n gadgetInvocationId?: string,\n ): void {\n this.nestedAgents.set(id, {\n parentInvocationId,\n depth,\n model,\n iteration,\n parentCallNumber,\n gadgetInvocationId,\n startTime: Date.now(),\n inputTokens: info?.inputTokens,\n cachedInputTokens: info?.cachedInputTokens,\n });\n if (this.isRunning && this.isTTY) {\n this.render();\n }\n }\n\n /**\n * Update a nested agent with completion info (called when nested llm_call_end event received).\n * Records completion time to freeze the elapsed timer.\n * @param info - Full LLM call info including tokens, cache details, and cost\n */\n updateNestedAgent(\n id: string,\n info: {\n inputTokens?: number;\n outputTokens?: number;\n cachedInputTokens?: number;\n cacheCreationInputTokens?: number;\n finishReason?: string;\n cost?: number;\n },\n ): void {\n const agent = this.nestedAgents.get(id);\n if (agent) {\n // Only update if new value is defined - preserve initial values from addNestedAgent()\n if (info.inputTokens !== undefined) agent.inputTokens = info.inputTokens;\n if (info.outputTokens !== undefined) agent.outputTokens = info.outputTokens;\n if (info.cachedInputTokens !== undefined) agent.cachedInputTokens = info.cachedInputTokens;\n if (info.cacheCreationInputTokens !== undefined)\n agent.cacheCreationInputTokens = info.cacheCreationInputTokens;\n if (info.finishReason !== undefined) agent.finishReason = info.finishReason;\n\n // Calculate cost if not provided and we have model registry\n if (info.cost !== undefined) {\n agent.cost = info.cost;\n } else if (this.modelRegistry && agent.model && agent.outputTokens) {\n // Calculate cost using model registry (first-class subagent metric)\n // Use agent.* values which include preserved initial values from addNestedAgent()\n try {\n const modelName = agent.model.includes(\":\") ? agent.model.split(\":\")[1] : agent.model;\n const costResult = this.modelRegistry.estimateCost(\n modelName,\n agent.inputTokens ?? 0,\n agent.outputTokens,\n agent.cachedInputTokens,\n agent.cacheCreationInputTokens,\n );\n agent.cost = costResult?.totalCost;\n } catch {\n // Ignore cost calculation errors\n }\n }\n\n agent.completed = true;\n agent.completedTime = Date.now();\n if (this.isRunning && this.isTTY) {\n this.render();\n }\n }\n }\n\n /**\n * Remove a nested agent (called when the nested LLM call completes).\n */\n removeNestedAgent(id: string): void {\n this.nestedAgents.delete(id);\n if (this.isRunning && this.isTTY) {\n this.render();\n }\n }\n\n /**\n * Get a nested agent by ID (for accessing startTime, etc.).\n */\n getNestedAgent(id: string) {\n return this.nestedAgents.get(id);\n }\n\n /**\n * Get aggregated metrics from all nested agents for a parent gadget.\n * Used to show total token counts and cost for subagent gadgets like BrowseWeb.\n */\n getAggregatedSubagentMetrics(parentInvocationId: string): {\n inputTokens: number;\n outputTokens: number;\n cachedInputTokens: number;\n cost: number;\n callCount: number;\n } {\n let inputTokens = 0;\n let outputTokens = 0;\n let cachedInputTokens = 0;\n let cost = 0;\n let callCount = 0;\n\n for (const [, nested] of this.nestedAgents) {\n if (nested.parentInvocationId === parentInvocationId) {\n inputTokens += nested.inputTokens ?? 0;\n outputTokens += nested.outputTokens ?? 0;\n cachedInputTokens += nested.cachedInputTokens ?? 0;\n cost += nested.cost ?? 0;\n callCount++;\n }\n }\n\n return { inputTokens, outputTokens, cachedInputTokens, cost, callCount };\n }\n\n /**\n * Add a nested gadget call (called when nested gadget_call event received).\n */\n addNestedGadget(\n id: string,\n depth: number,\n parentInvocationId: string,\n name: string,\n parameters?: Record<string, unknown>,\n ): void {\n this.nestedGadgets.set(id, {\n depth,\n parentInvocationId,\n name,\n parameters,\n startTime: Date.now(),\n });\n if (this.isRunning && this.isTTY) {\n this.render();\n }\n }\n\n /**\n * Remove a nested gadget (called when nested gadget_result event received).\n */\n removeNestedGadget(id: string): void {\n this.nestedGadgets.delete(id);\n if (this.isRunning && this.isTTY) {\n this.render();\n }\n }\n\n /**\n * Get a nested gadget by ID (for accessing startTime, name, etc.).\n */\n getNestedGadget(id: string) {\n return this.nestedGadgets.get(id);\n }\n\n /**\n * Mark a nested gadget as completed (keeps it visible with ✓ indicator).\n * Records completion time to freeze the elapsed timer.\n */\n completeNestedGadget(id: string): void {\n const gadget = this.nestedGadgets.get(id);\n if (gadget) {\n gadget.completed = true;\n gadget.completedTime = Date.now();\n if (this.isRunning && this.isTTY) {\n this.render();\n }\n }\n }\n\n /**\n * Starts a new LLM call. Switches to streaming mode.\n * @param model - Model name being used\n * @param estimatedInputTokens - Initial input token count. Should come from\n * client.countTokens() for accuracy (provider-specific counting), not\n * character-based estimation. Will be updated with provider-returned counts\n * via setInputTokens() during streaming if available.\n */\n startCall(model: string, estimatedInputTokens?: number): void {\n this.mode = \"streaming\";\n this.model = model;\n this.callStartTime = Date.now();\n this.currentIteration++;\n this.callInputTokens = estimatedInputTokens ?? 0;\n this.callInputTokensEstimated = true;\n this.callOutputTokens = 0;\n this.callOutputTokensEstimated = true;\n this.callOutputChars = 0;\n this.isStreaming = false;\n // Reset cache tracking for new call\n this.callCachedInputTokens = 0;\n this.callCacheCreationInputTokens = 0;\n this.start();\n }\n\n /**\n * Ends the current LLM call. Updates cumulative stats and switches to cumulative mode.\n * @param usage - Final token usage from the call (including cached tokens if available)\n */\n endCall(usage?: TokenUsage): void {\n this.iterations++;\n if (usage) {\n this.totalTokens += usage.totalTokens;\n\n // Calculate and accumulate cost if model registry is available\n if (this.modelRegistry && this.model) {\n try {\n // Strip provider prefix if present (e.g., \"openai:gpt-5-nano\" -> \"gpt-5-nano\")\n const modelName = this.model.includes(\":\") ? this.model.split(\":\")[1] : this.model;\n\n const cost = this.modelRegistry.estimateCost(\n modelName,\n usage.inputTokens,\n usage.outputTokens,\n usage.cachedInputTokens ?? 0,\n usage.cacheCreationInputTokens ?? 0,\n );\n if (cost) {\n this.totalCost += cost.totalCost;\n }\n } catch {\n // Ignore errors (e.g., unknown model) - just don't add to cost\n }\n }\n }\n this.pause();\n this.mode = \"cumulative\";\n }\n\n /**\n * Adds gadget execution cost to the total.\n * Called when gadgets complete to include their costs (direct + subagent) in the total.\n */\n addGadgetCost(cost: number): void {\n if (cost > 0) {\n this.totalCost += cost;\n }\n }\n\n /**\n * Sets the input token count for current call (from stream metadata).\n * @param tokens - Token count from provider or client.countTokens()\n * @param estimated - If true, this is a fallback estimate (character-based).\n * If false, this is an accurate count from the provider API or client.countTokens().\n * Display shows ~ prefix only when estimated=true.\n */\n setInputTokens(tokens: number, estimated = false): void {\n // Don't overwrite actual count with a new estimate\n if (estimated && !this.callInputTokensEstimated) {\n return;\n }\n this.callInputTokens = tokens;\n this.callInputTokensEstimated = estimated;\n }\n\n /**\n * Sets the output token count for current call (from stream metadata).\n * @param tokens - Token count from provider streaming response\n * @param estimated - If true, this is a fallback estimate (character-based).\n * If false, this is an accurate count from the provider's streaming metadata.\n * Display shows ~ prefix only when estimated=true.\n */\n setOutputTokens(tokens: number, estimated = false): void {\n // Don't overwrite actual count with a new estimate\n if (estimated && !this.callOutputTokensEstimated) {\n return;\n }\n this.callOutputTokens = tokens;\n this.callOutputTokensEstimated = estimated;\n }\n\n /**\n * Sets cached token counts for the current call (from stream metadata).\n * Used for live cost estimation during streaming.\n * @param cachedInputTokens - Number of tokens read from cache (cheaper)\n * @param cacheCreationInputTokens - Number of tokens written to cache (more expensive)\n */\n setCachedTokens(cachedInputTokens: number, cacheCreationInputTokens: number): void {\n this.callCachedInputTokens = cachedInputTokens;\n this.callCacheCreationInputTokens = cacheCreationInputTokens;\n }\n\n /**\n * Get total elapsed time in seconds since the first call started.\n * @returns Elapsed time in seconds with 1 decimal place\n */\n getTotalElapsedSeconds(): number {\n if (this.totalStartTime === 0) return 0;\n return Number(((Date.now() - this.totalStartTime) / 1000).toFixed(1));\n }\n\n /**\n * Get elapsed time in seconds for the current call.\n * @returns Elapsed time in seconds with 1 decimal place\n */\n getCallElapsedSeconds(): number {\n return Number(((Date.now() - this.callStartTime) / 1000).toFixed(1));\n }\n\n /**\n * Starts the progress indicator animation after a brief delay.\n */\n start(): void {\n if (!this.isTTY || this.isRunning) return;\n this.isRunning = true;\n\n // Delay showing spinner to avoid flicker for fast responses\n this.delayTimeout = setTimeout(() => {\n if (this.isRunning) {\n this.interval = setInterval(() => this.render(), 80);\n this.render();\n }\n }, SPINNER_DELAY_MS);\n }\n\n /**\n * Updates output character count for current call and marks streaming as active.\n * @param totalChars - Total accumulated character count\n */\n update(totalChars: number): void {\n this.callOutputChars = totalChars;\n this.isStreaming = true;\n }\n\n private render(): void {\n // Clear previous multi-line render before drawing new content\n this.clearRenderedLines();\n\n const spinner = SPINNER_FRAMES[this.frameIndex++ % SPINNER_FRAMES.length];\n const lines: string[] = [];\n\n // Collect actively streaming nested agents (to show at bottom, not in hierarchy)\n const activeNestedStreams: Array<{\n depth: number;\n iteration: number;\n parentCallNumber?: number;\n gadgetInvocationId?: string;\n model: string;\n inputTokens?: number;\n cachedInputTokens?: number;\n outputTokens?: number;\n cost?: number;\n startTime: number;\n parentGadgetName: string; // For prefixing nested operation lines\n }> = [];\n\n // In-flight gadgets - ONLY show gadgets that are still running\n // Completed gadgets are printed inline when they finish (via completeGadget)\n if (this.isTTY) {\n for (const [gadgetId, gadget] of this.inFlightGadgets) {\n // Skip completed gadgets - they were already printed inline\n if (gadget.completed) {\n continue;\n }\n const elapsedSeconds = (Date.now() - gadget.startTime) / 1000;\n\n // Get aggregated subagent metrics for realtime display\n const subagentMetrics = this.getAggregatedSubagentMetrics(gadgetId);\n\n // Use shared formatGadgetLine for consistent formatting with parameters\n // Pass maxWidth adjusted for 2-space indent\n const termWidth = process.stdout.columns ?? 80;\n const gadgetIndent = \" \";\n const line = formatGadgetLine(\n {\n name: gadget.name,\n parameters: gadget.params,\n elapsedSeconds,\n isComplete: false, // We only show running gadgets here\n // Pass realtime subagent metrics\n subagentInputTokens: subagentMetrics.inputTokens,\n subagentOutputTokens: subagentMetrics.outputTokens,\n subagentCachedTokens: subagentMetrics.cachedInputTokens,\n subagentCost: subagentMetrics.cost,\n },\n termWidth - gadgetIndent.length,\n );\n // Add indent to EACH line of multi-line output\n const gadgetLine = line\n .split(\"\\n\")\n .map((l) => gadgetIndent + l)\n .join(\"\\n\");\n lines.push(gadgetLine);\n\n // Build unified timeline of nested operations sorted by startTime\n // This fixes the display ordering bug where agents were grouped above gadgets\n const nestedOps: Array<{\n type: \"agent\" | \"gadget\";\n startTime: number;\n depth: number;\n // Agent-specific fields\n iteration?: number;\n parentCallNumber?: number;\n gadgetInvocationId?: string;\n model?: string;\n inputTokens?: number;\n cachedInputTokens?: number;\n outputTokens?: number;\n cost?: number;\n finishReason?: string;\n completed?: boolean;\n completedTime?: number;\n // Gadget-specific fields\n id?: string; // For metrics aggregation\n name?: string;\n parameters?: Record<string, unknown>;\n }> = [];\n\n // Collect nested agents for this parent\n for (const [_agentId, nested] of this.nestedAgents) {\n if (nested.parentInvocationId === gadgetId) {\n nestedOps.push({\n type: \"agent\",\n startTime: nested.startTime,\n depth: nested.depth,\n iteration: nested.iteration,\n parentCallNumber: nested.parentCallNumber,\n gadgetInvocationId: nested.gadgetInvocationId,\n model: nested.model,\n inputTokens: nested.inputTokens,\n cachedInputTokens: nested.cachedInputTokens,\n outputTokens: nested.outputTokens,\n cost: nested.cost,\n finishReason: nested.finishReason,\n completed: nested.completed,\n completedTime: nested.completedTime,\n });\n\n // Collect actively streaming agents for bottom section\n if (!nested.completed) {\n activeNestedStreams.push({\n depth: nested.depth,\n iteration: nested.iteration,\n parentCallNumber: nested.parentCallNumber,\n gadgetInvocationId: nested.gadgetInvocationId,\n model: nested.model,\n inputTokens: nested.inputTokens,\n cachedInputTokens: nested.cachedInputTokens,\n outputTokens: nested.outputTokens,\n cost: nested.cost,\n startTime: nested.startTime,\n parentGadgetName: gadget.name, // Track parent for prefixing\n });\n }\n }\n }\n\n // Collect nested gadgets for this parent\n for (const [nestedId, nestedGadget] of this.nestedGadgets) {\n if (nestedGadget.parentInvocationId === gadgetId) {\n nestedOps.push({\n type: \"gadget\",\n id: nestedId, // Preserve ID for metrics aggregation\n startTime: nestedGadget.startTime,\n depth: nestedGadget.depth,\n name: nestedGadget.name,\n parameters: nestedGadget.parameters,\n completed: nestedGadget.completed,\n completedTime: nestedGadget.completedTime,\n });\n }\n }\n\n // Sort by startTime for chronological display\n nestedOps.sort((a, b) => a.startTime - b.startTime);\n\n // Render in chronological order using shared formatting functions\n // Nested operations are indented under parent gadget (which has 2-space indent)\n // So base indent is 4 spaces, plus 2 more for each depth level\n // SKIP completed ops (printed inline) and streaming agents (shown at bottom)\n for (const op of nestedOps) {\n // Skip ALL completed operations - they were printed inline when they finished\n if (op.completed) {\n continue;\n }\n\n // Skip in-progress agents - they're shown in active streams section at bottom\n if (op.type === \"agent\") {\n continue;\n }\n\n // Only in-progress GADGETS reach here - render them\n const indent = \" \".repeat(op.depth + 2);\n const elapsedSeconds = (Date.now() - op.startTime) / 1000;\n\n // Get aggregated subagent metrics (for nested gadgets that run LLM calls)\n const nestedMetrics = op.id ? this.getAggregatedSubagentMetrics(op.id) : { inputTokens: 0, outputTokens: 0, cachedInputTokens: 0, cost: 0, callCount: 0 };\n\n // Use shared formatGadgetLine for consistent formatting\n // Pass maxWidth adjusted for indent to prevent line overflow\n const termWidth = process.stdout.columns ?? 80;\n // Parent gadget prefix for nested operations\n const parentPrefix = `${chalk.dim(`${gadget.name}:`)} `;\n const line = formatGadgetLine(\n {\n name: op.name ?? \"\",\n parameters: op.parameters,\n elapsedSeconds,\n isComplete: false, // Only in-progress gadgets reach here\n // Pass realtime subagent metrics\n subagentInputTokens: nestedMetrics.inputTokens,\n subagentOutputTokens: nestedMetrics.outputTokens,\n subagentCachedTokens: nestedMetrics.cachedInputTokens,\n subagentCost: nestedMetrics.cost,\n },\n termWidth - indent.length - parentPrefix.length,\n );\n // Add indent and parent prefix to EACH line of multi-line output\n const indentedLine = line\n .split(\"\\n\")\n .map((l) => indent + parentPrefix + l)\n .join(\"\\n\");\n lines.push(indentedLine);\n }\n }\n }\n\n // ACTIVE STREAMS SECTION: Show all actively streaming LLM calls at bottom\n // Ordered from innermost (top) to outermost (bottom) - like a call stack\n // This shows nested streams first, then the main agent line below them\n\n // Nested active streams FIRST (they are \"inside\" the main agent context)\n for (const stream of activeNestedStreams) {\n // Use depth-based indent to align with completed nested agents in hierarchy\n const indent = \" \".repeat(stream.depth + 2);\n // Parent gadget prefix for nested operations\n const parentPrefix = `${chalk.dim(`${stream.parentGadgetName}:`)} `;\n const elapsedSeconds = (Date.now() - stream.startTime) / 1000;\n const line = formatLLMCallLine({\n iteration: stream.iteration,\n parentCallNumber: stream.parentCallNumber,\n gadgetInvocationId: stream.gadgetInvocationId,\n model: stream.model,\n inputTokens: stream.inputTokens,\n cachedInputTokens: stream.cachedInputTokens,\n outputTokens: stream.outputTokens,\n elapsedSeconds,\n cost: stream.cost,\n isStreaming: true,\n spinner,\n });\n lines.push(`${indent}${parentPrefix}${line}`);\n }\n\n // Main progress line LAST (it's the outer/root context)\n if (this.mode === \"streaming\") {\n lines.push(this.formatStreamingLine(spinner));\n } else {\n lines.push(this.formatCumulativeLine(spinner));\n }\n\n // Write all lines and track count for clearing\n const output = lines.join(\"\\n\");\n // Count actual terminal lines (some elements may contain \\n for multi-line gadgets)\n this.lastRenderLineCount = (output.match(/\\n/g) || []).length + 1;\n // Use \\r to return to start of first line, then join with newlines\n // Each line ends implicitly, cursor stays at end of last line\n this.target.write(\"\\r\" + output);\n this.hasRendered = true;\n }\n\n /**\n * Clears the previously rendered lines (for multi-line status display).\n */\n private clearRenderedLines(): void {\n if (!this.hasRendered || this.lastRenderLineCount === 0) return;\n\n // First, clear the current line\n this.target.write(\"\\r\\x1b[K\");\n\n // Then move up and clear each additional line\n for (let i = 1; i < this.lastRenderLineCount; i++) {\n // Move up one line and clear it\n this.target.write(\"\\x1b[1A\\x1b[K\");\n }\n\n // Return cursor to start\n this.target.write(\"\\r\");\n }\n\n /**\n * Clear rendered lines and reset counter.\n * Call this before printing static output that should remain visible\n * above the render zone (e.g., opening/closing lines for nested operations).\n */\n clearAndReset(): void {\n if (this.isTTY) {\n this.clearRenderedLines();\n }\n this.lastRenderLineCount = 0;\n this.hasRendered = false;\n }\n\n /**\n * Format the streaming mode progress line (returns string, doesn't write).\n * Uses the shared formatLLMCallLine() function for consistent formatting\n * between main agent and nested subagent displays.\n */\n private formatStreamingLine(spinner: string): string {\n // Output tokens: use actual if available, otherwise estimate from chars\n const outTokens = this.callOutputTokensEstimated\n ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN)\n : this.callOutputTokens;\n\n // Use shared formatting function for consistent display\n return formatLLMCallLine({\n iteration: this.currentIteration,\n model: this.model ?? \"\",\n inputTokens: this.callInputTokens,\n cachedInputTokens: this.callCachedInputTokens,\n outputTokens: outTokens,\n elapsedSeconds: (Date.now() - this.callStartTime) / 1000,\n cost: this.calculateCurrentCallCost(outTokens),\n isStreaming: true,\n spinner,\n contextPercent: this.getContextUsagePercent(),\n estimated: {\n input: this.callInputTokensEstimated,\n output: this.callOutputTokensEstimated,\n },\n });\n }\n\n /**\n * Calculates live cost estimate for the current streaming call.\n * Uses current input/output tokens and cached token counts.\n */\n private calculateCurrentCallCost(outputTokens: number): number {\n if (!this.modelRegistry || !this.model) return 0;\n\n try {\n // Strip provider prefix if present (e.g., \"anthropic:claude-sonnet-4-5\" -> \"claude-sonnet-4-5\")\n const modelName = this.model.includes(\":\") ? this.model.split(\":\")[1] : this.model;\n\n const cost = this.modelRegistry.estimateCost(\n modelName,\n this.callInputTokens,\n outputTokens,\n this.callCachedInputTokens,\n this.callCacheCreationInputTokens,\n );\n\n return cost?.totalCost ?? 0;\n } catch {\n return 0;\n }\n }\n\n /**\n * Calculates context window usage percentage.\n * Returns null if model is unknown or context window unavailable.\n */\n private getContextUsagePercent(): number | null {\n if (!this.modelRegistry || !this.model || this.callInputTokens === 0) {\n return null;\n }\n\n // Strip provider prefix if present (e.g., \"anthropic:claude-sonnet-4-5\" -> \"claude-sonnet-4-5\")\n const modelName = this.model.includes(\":\") ? this.model.split(\":\")[1] : this.model;\n\n const limits = this.modelRegistry.getModelLimits(modelName);\n if (!limits?.contextWindow) {\n return null;\n }\n\n return (this.callInputTokens / limits.contextWindow) * 100;\n }\n\n /**\n * Format the cumulative mode progress line (returns string, doesn't write).\n */\n private formatCumulativeLine(spinner: string): string {\n const elapsed = ((Date.now() - this.totalStartTime) / 1000).toFixed(1);\n\n // Build status parts: model, total tokens, iterations, cost, total time\n const parts: string[] = [];\n if (this.model) {\n parts.push(chalk.cyan(this.model));\n }\n if (this.totalTokens > 0) {\n parts.push(chalk.dim(\"total:\") + chalk.magenta(` ${this.totalTokens}`));\n }\n if (this.iterations > 0) {\n parts.push(chalk.dim(\"iter:\") + chalk.blue(` ${this.iterations}`));\n }\n if (this.totalCost > 0) {\n parts.push(chalk.dim(\"cost:\") + chalk.cyan(` $${formatCost(this.totalCost)}`));\n }\n parts.push(chalk.dim(`${elapsed}s`));\n\n return `${parts.join(chalk.dim(\" | \"))} ${chalk.cyan(spinner)}`;\n }\n\n /**\n * Pauses the progress indicator and clears all rendered lines.\n * Can be resumed with start().\n */\n pause(): void {\n if (!this.isTTY || !this.isRunning) return;\n\n if (this.delayTimeout) {\n clearTimeout(this.delayTimeout);\n this.delayTimeout = null;\n }\n if (this.interval) {\n clearInterval(this.interval);\n this.interval = null;\n }\n this.isRunning = false;\n\n // Clear all rendered lines (multi-line status display)\n this.clearRenderedLines();\n this.hasRendered = false;\n this.lastRenderLineCount = 0;\n }\n\n /**\n * Completes the progress indicator and clears the line.\n */\n complete(): void {\n this.pause();\n }\n\n /**\n * Returns the total accumulated cost across all calls.\n */\n getTotalCost(): number {\n return this.totalCost;\n }\n\n /**\n * Returns a formatted stats string for cancellation messages.\n * Format: \"↑ 1.2k | ↓ 300 | 5.0s\"\n */\n formatStats(): string {\n const parts: string[] = [];\n const elapsed = ((Date.now() - this.callStartTime) / 1000).toFixed(1);\n\n // Output tokens: use actual if available, otherwise estimate from chars\n const outTokens = this.callOutputTokensEstimated\n ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN)\n : this.callOutputTokens;\n\n if (this.callInputTokens > 0) {\n const prefix = this.callInputTokensEstimated ? \"~\" : \"\";\n parts.push(`↑ ${prefix}${formatTokens(this.callInputTokens)}`);\n }\n\n if (outTokens > 0) {\n const prefix = this.callOutputTokensEstimated ? \"~\" : \"\";\n parts.push(`↓ ${prefix}${formatTokens(outTokens)}`);\n }\n\n parts.push(`${elapsed}s`);\n\n return parts.join(\" | \");\n }\n\n /**\n * Returns a formatted prompt string with stats (like bash PS1).\n * Shows current call stats during streaming, cumulative stats otherwise.\n * Format: \"out: 1.2k │ in: ~300 │ 5s > \" or \"3.6k │ i2 │ 34s > \"\n */\n formatPrompt(): string {\n const parts: string[] = [];\n\n if (this.mode === \"streaming\") {\n // During a call: show current call stats\n const elapsed = Math.round((Date.now() - this.callStartTime) / 1000);\n\n // Output tokens: use actual if available, otherwise estimate from chars\n const outTokens = this.callOutputTokensEstimated\n ? Math.round(this.callOutputChars / FALLBACK_CHARS_PER_TOKEN)\n : this.callOutputTokens;\n const outEstimated = this.callOutputTokensEstimated;\n\n if (this.callInputTokens > 0) {\n const prefix = this.callInputTokensEstimated ? \"~\" : \"\";\n parts.push(\n chalk.dim(\"↑\") + chalk.yellow(` ${prefix}${formatTokens(this.callInputTokens)}`),\n );\n }\n if (outTokens > 0) {\n const prefix = outEstimated ? \"~\" : \"\";\n parts.push(chalk.dim(\"↓\") + chalk.green(` ${prefix}${formatTokens(outTokens)}`));\n }\n parts.push(chalk.dim(`${elapsed}s`));\n } else {\n // Between calls: show cumulative stats\n const elapsed = Math.round((Date.now() - this.totalStartTime) / 1000);\n\n if (this.totalTokens > 0) {\n parts.push(chalk.magenta(formatTokens(this.totalTokens)));\n }\n if (this.iterations > 0) {\n parts.push(chalk.blue(`i${this.iterations}`));\n }\n if (this.totalCost > 0) {\n parts.push(chalk.cyan(`$${formatCost(this.totalCost)}`));\n }\n parts.push(chalk.dim(`${elapsed}s`));\n }\n\n return `${parts.join(chalk.dim(\" | \"))} ${chalk.green(\">\")} `;\n }\n}\n\n/**\n * Reads all data from a readable stream into a string.\n *\n * @param stream - Stream to read from\n * @returns Complete stream contents as string\n */\nasync function readStream(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: string[] = [];\n for await (const chunk of stream) {\n if (typeof chunk === \"string\") {\n chunks.push(chunk);\n } else {\n chunks.push(chunk.toString(\"utf8\"));\n }\n }\n return chunks.join(\"\");\n}\n\n/**\n * Normalizes a prompt by trimming whitespace.\n *\n * @param value - Prompt to normalize\n * @returns Trimmed prompt\n */\nfunction normalizePrompt(value: string): string {\n return value.trim();\n}\n\n/**\n * Resolves the user prompt from either command-line argument or stdin.\n * Priority: 1) promptArg if provided, 2) stdin if piped, 3) error if neither.\n *\n * @param promptArg - Optional prompt from command-line argument\n * @param env - CLI environment for accessing stdin\n * @returns Resolved and normalized prompt\n * @throws Error if no prompt available or stdin is empty\n */\nexport async function resolvePrompt(\n promptArg: string | undefined,\n env: CLIEnvironment,\n): Promise<string> {\n if (promptArg?.trim()) {\n return normalizePrompt(promptArg);\n }\n\n if (isInteractive(env.stdin)) {\n throw new Error(\"Prompt is required. Provide an argument or pipe content via stdin.\");\n }\n\n const pipedInput = normalizePrompt(await readStream(env.stdin));\n if (!pipedInput) {\n throw new Error(\"Received empty stdin payload. Provide a prompt to continue.\");\n }\n\n return pipedInput;\n}\n\n// Re-export summary rendering from formatters module\n// This maintains backward compatibility while organizing code better\nexport { renderSummary, type SummaryMetadata } from \"./ui/formatters.js\";\n\n/**\n * Executes a CLI action with error handling.\n * Catches errors, writes to stderr, and sets exit code 1 on failure.\n *\n * @param action - Async action to execute\n * @param env - CLI environment for error output and exit code\n */\nexport async function executeAction(\n action: () => Promise<void>,\n env: CLIEnvironment,\n): Promise<void> {\n try {\n await action();\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n env.stderr.write(`${chalk.red.bold(\"Error:\")} ${message}\\n`);\n env.setExitCode(1);\n }\n}\n","/**\n * CLI output formatting utilities.\n *\n * This module provides formatting functions for displaying metrics, summaries,\n * and gadget results in a clean, consistent format across the llmist CLI.\n *\n * **Design principles:**\n * - Consistent formatting across all commands (agent, complete, models)\n * - Human-readable output with appropriate precision\n * - Color-coded for visual clarity (using chalk)\n * - Compact format optimized for terminal display\n *\n * **SHOWCASE:** Demonstrates how to build a polished CLI on top of llmist's core.\n */\n\nimport chalk from \"chalk\";\nimport { type MarkedExtension, marked } from \"marked\";\nimport { markedTerminal } from \"marked-terminal\";\nimport type { TokenUsage } from \"../../core/options.js\";\nimport type { StoredMedia } from \"../../gadgets/types.js\";\n\n/**\n * Lazy-initialized flag for marked-terminal configuration.\n *\n * We defer `marked.use(markedTerminal())` until first render because:\n * - markedTerminal() captures chalk's color level at call time\n * - At module import time, TTY detection may not be complete\n * - Lazy init ensures colors work in interactive terminals\n */\nlet markedConfigured = false;\n\n/**\n * Configure marked for terminal output (lazy initialization).\n *\n * Uses marked-terminal to convert markdown to ANSI-styled terminal output.\n * This enables rich formatting in TellUser messages and AskUser questions.\n *\n * We override marked-terminal's style functions with our own chalk instance\n * because marked-terminal bundles its own chalk that detects colors at module\n * load time. Bun's broken TTY detection causes that bundled chalk to detect\n * level 0 (no colors). See: https://github.com/oven-sh/bun/issues/1322\n *\n * By forcing `chalk.level = 3` on our imported chalk and passing custom style\n * functions, we ensure colors work regardless of TTY detection.\n *\n * Respects the NO_COLOR environment variable for accessibility.\n *\n * Note: Type assertion needed due to @types/marked-terminal lag behind the runtime API.\n */\nfunction ensureMarkedConfigured(): void {\n if (!markedConfigured) {\n // Respect NO_COLOR env var, otherwise force truecolor (level 3)\n chalk.level = process.env.NO_COLOR ? 0 : 3;\n\n // Override marked-terminal's style functions with our chalk instance\n // to work around Bun's broken TTY detection\n marked.use(\n markedTerminal({\n // Text styling\n strong: chalk.bold,\n em: chalk.italic,\n del: chalk.dim.gray.strikethrough,\n\n // Code styling\n code: chalk.yellow,\n codespan: chalk.yellow,\n\n // Headings\n heading: chalk.green.bold,\n firstHeading: chalk.magenta.underline.bold,\n\n // Links\n link: chalk.blue,\n href: chalk.blue.underline,\n\n // Block elements\n blockquote: chalk.gray.italic,\n\n // List formatting - reduce indentation and add bullet styling\n tab: 2, // Reduce from default 4 to 2 spaces\n listitem: chalk.reset, // Keep items readable (no dim)\n }) as unknown as MarkedExtension,\n );\n markedConfigured = true;\n }\n}\n\n/**\n * Renders markdown text as styled terminal output.\n *\n * Converts markdown syntax to ANSI escape codes for terminal display:\n * - **bold** and *italic* text\n * - `inline code` and code blocks\n * - Lists (bulleted and numbered)\n * - Headers\n * - Links (clickable in supported terminals)\n *\n * @param text - Markdown text to render\n * @returns ANSI-styled string for terminal output\n *\n * @example\n * ```typescript\n * renderMarkdown(\"**Important:** Check the `config.json` file\");\n * // Returns styled text with bold \"Important:\" and code-styled \"config.json\"\n * ```\n */\nexport function renderMarkdown(text: string): string {\n ensureMarkedConfigured();\n let rendered = marked.parse(text) as string;\n\n // Workaround for marked-terminal bug: inline markdown in list items\n // is not processed. Post-process to handle **bold** and *italic*.\n // See: https://github.com/mikaelbr/marked-terminal/issues\n rendered = rendered\n .replace(/\\*\\*(.+?)\\*\\*/g, (_, content) => chalk.bold(content))\n // Italic: require non-space after * to avoid matching bullet points ( * )\n .replace(/(?<!\\*)\\*(\\S[^*]*)\\*(?!\\*)/g, (_, content) => chalk.italic(content));\n\n // Remove trailing newlines that marked adds\n return rendered.trimEnd();\n}\n\n/**\n * Creates a rainbow-colored horizontal line for visual emphasis.\n * Cycles through colors for each character segment.\n * Uses the full terminal width for a complete visual separator.\n *\n * @returns Rainbow-colored separator string spanning the terminal width\n */\nfunction createRainbowSeparator(): string {\n const colors = [chalk.red, chalk.yellow, chalk.green, chalk.cyan, chalk.blue, chalk.magenta];\n const char = \"─\";\n // Use terminal width, fallback to 80 if not available (e.g., piped output)\n const width = process.stdout.columns || 80;\n let result = \"\";\n for (let i = 0; i < width; i++) {\n result += colors[i % colors.length](char);\n }\n return result;\n}\n\n/**\n * Renders markdown with colorful rainbow horizontal line separators above and below.\n * Use this for prominent markdown content that should stand out visually.\n *\n * @param text - Markdown text to render\n * @returns Rendered markdown with rainbow separators\n *\n * @example\n * ```typescript\n * renderMarkdownWithSeparators(\"**Hello** world!\");\n * // Returns rainbow line + styled markdown + rainbow line\n * ```\n */\nexport function renderMarkdownWithSeparators(text: string): string {\n const rendered = renderMarkdown(text);\n const separator = createRainbowSeparator();\n return `\\n${separator}\\n${rendered}\\n${separator}\\n`;\n}\n\n/**\n * Formats token count with 'k' suffix for thousands.\n *\n * Uses compact notation to save terminal space while maintaining readability.\n * Numbers below 1000 are shown as-is, larger numbers use 'k' suffix with one decimal.\n *\n * @param tokens - Number of tokens\n * @returns Formatted string (e.g., \"896\" or \"11.5k\")\n *\n * @example\n * ```typescript\n * formatTokens(896) // \"896\"\n * formatTokens(11500) // \"11.5k\"\n * formatTokens(1234) // \"1.2k\"\n * ```\n */\nexport function formatTokens(tokens: number): string {\n return tokens >= 1000 ? `${(tokens / 1000).toFixed(1)}k` : `${tokens}`;\n}\n\n/**\n * Formats cost with appropriate precision based on magnitude.\n *\n * Uses variable precision to balance readability and accuracy:\n * - Very small costs (<$0.001): 5 decimal places to show meaningful value\n * - Small costs (<$0.01): 4 decimal places for precision\n * - Medium costs (<$1): 3 decimal places for clarity\n * - Larger costs (≥$1): 2 decimal places (standard currency format)\n *\n * @param cost - Cost in USD\n * @returns Formatted cost string without currency symbol (e.g., \"0.0123\")\n *\n * @example\n * ```typescript\n * formatCost(0.00012) // \"0.00012\"\n * formatCost(0.0056) // \"0.0056\"\n * formatCost(0.123) // \"0.123\"\n * formatCost(1.5) // \"1.50\"\n * ```\n */\nexport function formatCost(cost: number): string {\n if (cost < 0.001) {\n return cost.toFixed(5);\n }\n if (cost < 0.01) {\n return cost.toFixed(4);\n }\n if (cost < 1) {\n return cost.toFixed(3);\n }\n return cost.toFixed(2);\n}\n\n/**\n * Display information for formatting an LLM call progress line.\n *\n * Used by both main agent display and nested subagent display.\n * This enables consistent formatting across all LLM call displays.\n */\nexport interface LLMCallDisplayInfo {\n /** Iteration number (0-indexed for subagents, 1-indexed for main) */\n iteration: number;\n /** Parent call number for hierarchical display (e.g., parent=1, iteration=2 → #1.2) */\n parentCallNumber?: number;\n /** Gadget invocation ID for unique subagent identification (e.g., #6.browse_web_1.2) */\n gadgetInvocationId?: string;\n /** Model name/ID */\n model: string;\n /** Input tokens sent to LLM */\n inputTokens?: number;\n /** Cached input tokens (prompt cache hit) */\n cachedInputTokens?: number;\n /** Output tokens received from LLM */\n outputTokens?: number;\n /** Elapsed time in seconds */\n elapsedSeconds: number;\n /** Cost in USD */\n cost?: number;\n /** Finish reason (null/undefined while streaming, string when done) */\n finishReason?: string | null;\n /** Whether the call is still streaming */\n isStreaming?: boolean;\n /** Spinner character for streaming display */\n spinner?: string;\n /** Context window usage percentage (optional, main agent only) */\n contextPercent?: number | null;\n /** Token estimation flags (when counts are estimated, not exact) */\n estimated?: { input?: boolean; output?: boolean };\n}\n\n/**\n * Formats an LLM call opening line for display.\n *\n * This is printed once when an LLM call starts, before streaming begins.\n * The opening line is static and never refreshed.\n *\n * **Format:** `→ #N model` (main agent) or `→ #N.gadgetId.M model` (subagent)\n *\n * @param iteration - Iteration/call number\n * @param model - Model name/ID\n * @param parentCallNumber - Parent call number for nested calls\n * @param gadgetInvocationId - Gadget invocation ID for unique subagent identification\n * @returns Formatted opening line string with ANSI colors\n *\n * @example\n * ```typescript\n * formatLLMCallOpening(1, \"gemini:gemini-2.5-flash\");\n * // Output: \"→ #1 gemini:gemini-2.5-flash\"\n *\n * formatLLMCallOpening(2, \"gemini:gemini-2.5-flash\", 1, \"browse_web_1\");\n * // Output: \"→ #1.browse_web_1.2 gemini:gemini-2.5-flash\"\n * ```\n */\nexport function formatLLMCallOpening(\n iteration: number,\n model: string,\n parentCallNumber?: number,\n gadgetInvocationId?: string,\n): string {\n let callNumber: string;\n if (parentCallNumber !== undefined && gadgetInvocationId) {\n // Subagent with full context: #parent.gadgetId.iteration\n callNumber = `#${parentCallNumber}.${gadgetInvocationId}.${iteration}`;\n } else if (parentCallNumber !== undefined) {\n // Subagent without gadget ID (legacy): #parent.iteration\n callNumber = `#${parentCallNumber}.${iteration}`;\n } else {\n // Main agent: #iteration\n callNumber = `#${iteration}`;\n }\n return `${chalk.dim(\"→\")} ${chalk.cyan(callNumber)} ${chalk.magenta(model)}`;\n}\n\n/**\n * Formats an LLM call progress line for display.\n *\n * This is the **shared formatting function** used by both main agent and\n * nested subagent displays. Using a single function eliminates code\n * duplication and ensures consistent formatting.\n *\n * **Format:** `#N model | %ctx | ↑ input | ⟳ cached | ↓ output | time | $cost | status`\n *\n * **Color scheme:**\n * - Cyan: Iteration number, cost, spinner\n * - Magenta: Model name\n * - Yellow: Input tokens\n * - Blue: Cached tokens\n * - Green: Output tokens, success checkmark\n *\n * @param info - Display information for the LLM call\n * @returns Formatted progress line string\n *\n * @example\n * ```typescript\n * // Streaming call\n * formatLLMCallLine({\n * iteration: 1,\n * model: \"claude-sonnet-4-20250514\",\n * inputTokens: 10400,\n * outputTokens: 49,\n * elapsedSeconds: 24.8,\n * cost: 0.0032,\n * isStreaming: true,\n * spinner: \"⠧\",\n * contextPercent: 1,\n * });\n * // Output: \"#1 claude-sonnet-4-20250514 | 1% | ↑ 10.4k | ↓ 49 | 24.8s | $0.0032 | ⠧\"\n *\n * // Completed call\n * formatLLMCallLine({\n * iteration: 0,\n * model: \"gemini-2.5-flash\",\n * inputTokens: 5200,\n * cachedInputTokens: 3000,\n * outputTokens: 36,\n * elapsedSeconds: 3.7,\n * cost: 0.00009,\n * finishReason: \"stop\",\n * });\n * // Output: \"#0 gemini-2.5-flash | ↑ 5.2k | ⟳ 3.0k | ↓ 36 | 3.7s | $0.00009 | ✓\"\n * ```\n */\nexport function formatLLMCallLine(info: LLMCallDisplayInfo): string {\n const parts: string[] = [];\n\n // #N or #N.gadgetId.M model (iteration number + model name) - combined as one unit\n // Hierarchical format: parent.gadgetId.child (e.g., #1.browse_web_1.2 for 2nd call of gadget browse_web_1 in parent #1)\n let callNumber: string;\n if (info.parentCallNumber !== undefined && info.gadgetInvocationId) {\n // Subagent with full context: #parent.gadgetId.iteration\n callNumber = `#${info.parentCallNumber}.${info.gadgetInvocationId}.${info.iteration}`;\n } else if (info.parentCallNumber !== undefined) {\n // Subagent without gadget ID (legacy): #parent.iteration\n callNumber = `#${info.parentCallNumber}.${info.iteration}`;\n } else {\n // Main agent: #iteration\n callNumber = `#${info.iteration}`;\n }\n parts.push(`${chalk.cyan(callNumber)} ${chalk.magenta(info.model)}`);\n\n // Context usage percentage (color-coded by usage level, main agent only)\n if (info.contextPercent !== undefined && info.contextPercent !== null) {\n const formatted = `${Math.round(info.contextPercent)}%`;\n if (info.contextPercent >= 80) {\n parts.push(chalk.red(formatted)); // Danger zone\n } else if (info.contextPercent >= 50) {\n parts.push(chalk.yellow(formatted)); // Warning zone\n } else {\n parts.push(chalk.green(formatted)); // Safe zone\n }\n }\n\n // ↑ input tokens\n if (info.inputTokens && info.inputTokens > 0) {\n const prefix = info.estimated?.input ? \"~\" : \"\";\n parts.push(chalk.dim(\"↑\") + chalk.yellow(` ${prefix}${formatTokens(info.inputTokens)}`));\n }\n\n // ⟳ cached tokens\n if (info.cachedInputTokens && info.cachedInputTokens > 0) {\n parts.push(chalk.dim(\"⟳\") + chalk.blue(` ${formatTokens(info.cachedInputTokens)}`));\n }\n\n // ↓ output tokens\n if (info.outputTokens !== undefined && info.outputTokens > 0 || info.isStreaming) {\n const prefix = info.estimated?.output ? \"~\" : \"\";\n parts.push(chalk.dim(\"↓\") + chalk.green(` ${prefix}${formatTokens(info.outputTokens ?? 0)}`));\n }\n\n // Time\n parts.push(chalk.dim(`${info.elapsedSeconds.toFixed(1)}s`));\n\n // Cost\n if (info.cost !== undefined && info.cost > 0) {\n parts.push(chalk.cyan(`$${formatCost(info.cost)}`));\n }\n\n // Finish reason at the END when completed (not streaming)\n // Always show the actual finish reason (STOP, end_turn, etc.)\n if (!info.isStreaming && info.finishReason !== undefined) {\n const reason = info.finishReason || \"stop\";\n // Uppercase for visibility, green for normal completion, yellow for others\n if (reason === \"stop\" || reason === \"end_turn\") {\n parts.push(chalk.green(reason.toUpperCase()));\n } else {\n parts.push(chalk.yellow(reason.toUpperCase()));\n }\n }\n\n const line = parts.join(chalk.dim(\" | \"));\n\n // Prepend spinner when streaming, ✓ when completed\n if (info.isStreaming && info.spinner) {\n return `${chalk.cyan(info.spinner)} ${line}`;\n }\n\n // Completed calls get ✓ prefix like gadgets\n if (!info.isStreaming) {\n return `${chalk.green(\"✓\")} ${line}`;\n }\n\n return line;\n}\n\n/**\n * Metadata for generating execution summaries.\n *\n * Contains optional metrics collected during agent/LLM execution.\n * All fields are optional to allow partial summaries when data isn't available.\n */\nexport interface SummaryMetadata {\n /** LLM finish reason (e.g., \"stop\", \"length\", \"tool_calls\") */\n finishReason?: string | null;\n\n /** Token usage statistics from LLM provider */\n usage?: TokenUsage;\n\n /** Number of agent iterations (LLM calls) */\n iterations?: number;\n\n /** Model name/ID being used */\n model?: string;\n\n /** Total cost in USD (calculated via ModelRegistry) */\n cost?: number;\n\n /** Elapsed time in seconds */\n elapsedSeconds?: number;\n}\n\n/**\n * Renders execution metadata as a compact, color-coded summary line.\n *\n * Formats agent/LLM execution metrics in a consistent format used across CLI commands.\n * Only includes fields that have values, making the output clean and concise.\n *\n * **Format:** `#N | ↑ input │ ↓ output │ time | cost | finish`\n *\n * **Color scheme:**\n * - Cyan: Iteration number and cost (highlights key metrics)\n * - Yellow: Input tokens (shows what you sent)\n * - Green: Output tokens (shows what you received)\n * - Dim: Separators and finish reason (de-emphasize metadata)\n *\n * @param metadata - Summary metadata to format\n * @returns Formatted summary string, or null if no fields are populated\n *\n * @example\n * ```typescript\n * // Full summary with all fields (including cached tokens)\n * renderSummary({\n * iterations: 3,\n * usage: { inputTokens: 896, outputTokens: 11500, totalTokens: 12396, cachedInputTokens: 500 },\n * elapsedSeconds: 9,\n * cost: 0.0123,\n * finishReason: \"stop\"\n * });\n * // Output: \"#3 | ↑ 896 | ⟳ 500 | ↓ 11.5k | 9s | $0.0123 | stop\"\n *\n * // Partial summary (only tokens, no cache hit)\n * renderSummary({\n * usage: { inputTokens: 500, outputTokens: 200, totalTokens: 700 }\n * });\n * // Output: \"↑ 500 | ↓ 200\"\n * ```\n */\nexport function renderSummary(metadata: SummaryMetadata): string | null {\n const parts: string[] = [];\n\n // Iteration number and model (#N modelname) - shown first for context\n if (metadata.iterations !== undefined) {\n const iterPart = chalk.cyan(`#${metadata.iterations}`);\n if (metadata.model) {\n parts.push(`${iterPart} ${chalk.magenta(metadata.model)}`);\n } else {\n parts.push(iterPart);\n }\n } else if (metadata.model) {\n // Model without iteration number\n parts.push(chalk.magenta(metadata.model));\n }\n\n // Token usage (↑ input │ ⟳ cached │ ✎ cache-write │ ↓ output) - core metrics\n if (metadata.usage) {\n const { inputTokens, outputTokens, cachedInputTokens, cacheCreationInputTokens } =\n metadata.usage;\n parts.push(chalk.dim(\"↑\") + chalk.yellow(` ${formatTokens(inputTokens)}`));\n // Show cached tokens if present (indicates prompt caching hit - 0.1x cost)\n if (cachedInputTokens && cachedInputTokens > 0) {\n parts.push(chalk.dim(\"⟳\") + chalk.blue(` ${formatTokens(cachedInputTokens)}`));\n }\n // Show cache creation tokens if present (Anthropic cache writes - 1.25x cost)\n if (cacheCreationInputTokens && cacheCreationInputTokens > 0) {\n parts.push(chalk.dim(\"✎\") + chalk.magenta(` ${formatTokens(cacheCreationInputTokens)}`));\n }\n parts.push(chalk.dim(\"↓\") + chalk.green(` ${formatTokens(outputTokens)}`));\n }\n\n // Elapsed time - performance metric\n if (metadata.elapsedSeconds !== undefined && metadata.elapsedSeconds > 0) {\n parts.push(chalk.dim(`${metadata.elapsedSeconds}s`));\n }\n\n // Cost - financial tracking (showcases ModelRegistry integration)\n if (metadata.cost !== undefined && metadata.cost > 0) {\n parts.push(chalk.cyan(`$${formatCost(metadata.cost)}`));\n }\n\n // Finish reason - completion status (shown last for context)\n if (metadata.finishReason) {\n parts.push(chalk.dim(metadata.finishReason));\n }\n\n // Return null if no fields populated (cleaner than empty string)\n if (parts.length === 0) {\n return null;\n }\n\n // Join with \" | \" separator for visual clarity\n return parts.join(chalk.dim(\" | \"));\n}\n\n/**\n * Metadata for generating overall execution summaries.\n *\n * Used for the final accumulated summary at the end of agent execution.\n */\nexport interface OverallSummaryMetadata {\n /** Total tokens across all calls */\n totalTokens?: number;\n\n /** Number of agent iterations (LLM calls) */\n iterations?: number;\n\n /** Total elapsed time in seconds */\n elapsedSeconds?: number;\n\n /** Total cost in USD */\n cost?: number;\n}\n\n/**\n * Renders overall accumulated execution summary as a distinct styled line.\n *\n * This is displayed at the end of agent execution to show total metrics.\n * Uses a \"total:\" prefix to distinguish from per-call summaries.\n *\n * **Format:** `total: 3.5k | #2 | 19s | $0.0021`\n *\n * @param metadata - Overall summary metadata\n * @returns Formatted summary string, or null if no fields are populated\n *\n * @example\n * ```typescript\n * renderOverallSummary({\n * totalTokens: 3500,\n * iterations: 2,\n * elapsedSeconds: 19,\n * cost: 0.0021\n * });\n * // Output: \"total: 3.5k | #2 | 19s | $0.0021\"\n * ```\n */\nexport function renderOverallSummary(metadata: OverallSummaryMetadata): string | null {\n const parts: string[] = [];\n\n // Total tokens - primary metric for overall summary\n if (metadata.totalTokens !== undefined && metadata.totalTokens > 0) {\n parts.push(chalk.dim(\"total:\") + chalk.magenta(` ${formatTokens(metadata.totalTokens)}`));\n }\n\n // Iteration count (#N)\n if (metadata.iterations !== undefined && metadata.iterations > 0) {\n parts.push(chalk.cyan(`#${metadata.iterations}`));\n }\n\n // Total elapsed time\n if (metadata.elapsedSeconds !== undefined && metadata.elapsedSeconds > 0) {\n parts.push(chalk.dim(`${metadata.elapsedSeconds}s`));\n }\n\n // Total cost\n if (metadata.cost !== undefined && metadata.cost > 0) {\n parts.push(chalk.cyan(`$${formatCost(metadata.cost)}`));\n }\n\n if (parts.length === 0) {\n return null;\n }\n\n return parts.join(chalk.dim(\" | \"));\n}\n\n/**\n * Aggregated metrics from subagent LLM calls.\n *\n * These metrics are collected from all nested LLM calls that occur during\n * gadget execution (e.g., BrowseWeb spawns multiple LLM calls internally).\n */\nexport interface SubagentMetrics {\n /** Total input tokens across all subagent calls */\n inputTokens: number;\n /** Total output tokens across all subagent calls */\n outputTokens: number;\n /** Total cached input tokens across all subagent calls */\n cachedInputTokens: number;\n /** Total cost in USD across all subagent calls */\n cost: number;\n /** Number of LLM calls made by the subagent */\n callCount: number;\n}\n\n/**\n * Gadget execution result for formatting.\n *\n * Contains metadata about a single gadget invocation during agent execution.\n */\nexport interface GadgetResult {\n /** Name of the gadget that was executed */\n gadgetName: string;\n\n /** Execution time in milliseconds */\n executionTimeMs: number;\n\n /** Error message if gadget failed */\n error?: string;\n\n /** Result value from successful gadget execution */\n result?: string;\n\n /** Whether this gadget execution ended the agent loop */\n breaksLoop?: boolean;\n\n /** Parameters passed to the gadget */\n parameters?: Record<string, unknown>;\n\n /** Token count for output (calculated via provider API) */\n tokenCount?: number;\n\n /** Media outputs (images, audio, etc.) produced by the gadget */\n media?: StoredMedia[];\n\n /** Aggregated metrics from subagent LLM calls (if gadget spawned a subagent) */\n subagentMetrics?: SubagentMetrics;\n}\n\n/**\n * Formats a gadget execution result as a 2-line output for stderr.\n *\n * Provides visual feedback for gadget execution during agent runs.\n *\n * **Format (2 lines):**\n * - Line 1 (call): `→ GadgetName(param=value, ...)` - shows \"was called\"\n * - Line 2 (result): ` ✓ GadgetName ↓ 248 4ms: preview` - shows execution result\n * - Error: Line 2 becomes ` ✗ GadgetName error: message 2ms`\n *\n * **Design:**\n * - All parameters shown inline (truncated if too long)\n * - Output shown as token count (via provider API) or bytes as fallback\n * - Execution time always shown at the end\n *\n * @param result - Gadget execution result with timing and output info\n * @returns Formatted 2-line string with ANSI colors\n *\n * @example\n * ```typescript\n * // Successful gadget execution with token count\n * formatGadgetSummary({\n * gadgetName: \"ListDirectory\",\n * executionTimeMs: 4,\n * parameters: { path: \".\", recursive: true },\n * result: \"Type | Name | Size...\",\n * tokenCount: 248\n * });\n * // Output: \"→ ListDirectory(path=., recursive=true)\\n ✓ ListDirectory ↓ 248 4ms: ...\"\n *\n * // Error case\n * formatGadgetSummary({\n * gadgetName: \"ReadFile\",\n * executionTimeMs: 2,\n * parameters: { path: \"/missing.txt\" },\n * error: \"File not found\"\n * });\n * // Output: \"→ ReadFile(path=/missing.txt)\\n ✗ ReadFile error: File not found 2ms\"\n * ```\n */\n/**\n * Gets the raw string value for a parameter (without truncation or colors).\n */\nfunction getRawValue(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (typeof value === \"boolean\" || typeof value === \"number\") {\n return String(value);\n }\n return JSON.stringify(value);\n}\n\n/**\n * Truncates a string to maxLen characters with ellipsis if needed.\n * The ellipsis is included in the maxLen budget (result is always <= maxLen chars).\n * @internal Exported for testing\n */\nexport function truncateValue(str: string, maxLen: number): string {\n if (maxLen <= 0) return \"\";\n if (str.length <= maxLen) return str;\n // Account for ellipsis taking 1 char of the budget\n return `${str.slice(0, maxLen - 1)}…`;\n}\n\n/**\n * Formats parameters as a compact inline string with color-coded keys and values.\n * Expands to fit available terminal width when maxWidth is provided.\n *\n * @param params - Parameter key-value pairs\n * @param maxWidth - Optional maximum width for the entire parameters string (excluding parentheses)\n * @returns Formatted string with dim keys and cyan values, e.g., \"path=., recursive=true\"\n */\nexport function formatParametersInline(\n params: Record<string, unknown> | undefined,\n maxWidth?: number,\n): string {\n if (!params || Object.keys(params).length === 0) {\n return \"\";\n }\n\n const entries = Object.entries(params);\n const defaultLimit = 30;\n\n // Get raw values for each entry\n const rawValues = entries.map(([, value]) => getRawValue(value));\n\n // Calculate overhead: \"key=\" for each entry, \", \" between entries\n const overhead = entries.reduce((sum, [key], i) => {\n return sum + key.length + 1 + (i > 0 ? 2 : 0); // \"key=\" + \", \" separator\n }, 0);\n\n // Determine limits for each value\n let limits: number[];\n\n if (maxWidth && maxWidth > overhead) {\n const availableForValues = maxWidth - overhead;\n const totalRawLength = rawValues.reduce((sum, v) => sum + v.length, 0);\n\n if (totalRawLength <= availableForValues) {\n // Everything fits - no truncation needed\n limits = rawValues.map(() => Infinity);\n } else {\n // Distribute space proportionally, with minimum of 10 chars per value\n const minPerValue = 10;\n const minTotal = entries.length * minPerValue;\n\n if (availableForValues <= minTotal) {\n // Very tight - give each value equal minimum space\n limits = rawValues.map(() => Math.max(1, Math.floor(availableForValues / entries.length)));\n } else {\n // Proportional distribution\n limits = rawValues.map((v) => {\n const proportion = v.length / totalRawLength;\n return Math.max(minPerValue, Math.floor(proportion * availableForValues));\n });\n\n // CRITICAL: Ensure total limits don't exceed budget\n // The minPerValue floor can cause sum of limits to exceed availableForValues\n const totalLimits = limits.reduce((sum, l) => sum + l, 0);\n if (totalLimits > availableForValues) {\n // Scale down proportionally to fit within budget\n const scale = availableForValues / totalLimits;\n limits = limits.map((l) => Math.max(1, Math.floor(l * scale)));\n }\n }\n }\n } else {\n // No maxWidth or too small - use default limit\n limits = rawValues.map(() => defaultLimit);\n }\n\n // Format each entry with its limit\n return entries\n .map(([key, _], i) => {\n const formatted = truncateValue(rawValues[i], limits[i]);\n return `${chalk.dim(key)}${chalk.dim(\"=\")}${chalk.cyan(formatted)}`;\n })\n .join(chalk.dim(\", \"));\n}\n\n/**\n * Formats a gadget opening line (printed once when gadget is called).\n *\n * Shows the call indicator (`→`) for static opening lines.\n *\n * Format: `→ GadgetName(param=value, ...)`\n *\n * @param gadgetName - Name of the gadget being executed\n * @param parameters - Parameters passed to the gadget\n * @returns Formatted one-liner string with ANSI colors\n */\nexport function formatGadgetOpening(\n gadgetName: string,\n parameters?: Record<string, unknown>,\n): string {\n // Get terminal width (default to 80 if not available)\n const terminalWidth = process.stdout.columns || 80;\n\n const gadgetLabel = chalk.magenta.bold(gadgetName);\n\n // Calculate fixed parts length: \"→ \" + gadgetName + \"()\"\n // Arrow=2, parens=2\n const fixedLength = 2 + gadgetName.length + 2;\n\n // Available width for parameters\n const availableForParams = Math.max(40, terminalWidth - fixedLength - 3); // -3 safety margin\n\n const paramsStr = formatParametersInline(parameters, availableForParams);\n const paramsLabel = paramsStr ? `${chalk.dim(\"(\")}${paramsStr}${chalk.dim(\")\")}` : \"\";\n\n return `${chalk.dim(\"→\")} ${gadgetLabel}${paramsLabel}`;\n}\n\n/**\n * Formats a single-line gadget result (for nested gadgets).\n *\n * Unlike `formatGadgetLine()` which returns 2 lines for completed gadgets,\n * this returns a single result line. Used for nested gadgets where the\n * opening line was already printed separately.\n *\n * Format: `✓ GadgetName [↑ in | ↓ out | $cost |] time`\n *\n * @param info - Result information\n * @returns Formatted single-line result string with ANSI colors\n */\nexport function formatNestedGadgetResult(info: {\n name: string;\n elapsedSeconds: number;\n inputTokens?: number;\n outputTokens?: number;\n cost?: number;\n error?: string;\n}): string {\n const parts: string[] = [];\n\n // Add token metrics if present\n if (info.inputTokens && info.inputTokens > 0) {\n parts.push(chalk.dim(\"↑\") + chalk.yellow(` ${formatTokens(info.inputTokens)}`));\n }\n if (info.outputTokens && info.outputTokens > 0) {\n parts.push(chalk.dim(\"↓\") + chalk.green(` ${formatTokens(info.outputTokens)}`));\n }\n if (info.cost && info.cost > 0) {\n parts.push(chalk.cyan(`$${formatCost(info.cost)}`));\n }\n\n const metricsStr = parts.length > 0 ? ` ${parts.join(chalk.dim(\" | \"))} ${chalk.dim(\"|\")}` : \"\";\n const timeStr = chalk.dim(`${info.elapsedSeconds.toFixed(1)}s`);\n const gadgetLabel = chalk.magenta.bold(info.name);\n\n // Use error indicator if failed\n const icon = info.error ? chalk.red(\"✗\") : chalk.green(\"✓\");\n\n return `${icon} ${gadgetLabel}${metricsStr} ${timeStr}`;\n}\n\n/**\n * Display information for formatting a gadget call progress line.\n *\n * Used by both main gadget display and nested subagent gadget display.\n * This enables consistent formatting across all gadget displays.\n */\nexport interface GadgetDisplayInfo {\n /** Gadget name */\n name: string;\n /** Parameters passed to the gadget */\n parameters?: Record<string, unknown>;\n /** Elapsed time in seconds */\n elapsedSeconds: number;\n /** Whether the gadget has completed */\n isComplete: boolean;\n /** Token count from output (if available) */\n tokenCount?: number;\n /** Output size in bytes (fallback if tokenCount unavailable) */\n outputBytes?: number;\n /** Error message if gadget failed */\n error?: string;\n /** Whether the gadget breaks the loop (uses ⏹ icon) */\n breaksLoop?: boolean;\n\n // Realtime subagent metrics (for gadgets that run LLM calls internally)\n /** Aggregated input tokens from nested LLM calls */\n subagentInputTokens?: number;\n /** Aggregated output tokens from nested LLM calls */\n subagentOutputTokens?: number;\n /** Aggregated cached tokens from nested LLM calls */\n subagentCachedTokens?: number;\n /** Aggregated cost from nested LLM calls */\n subagentCost?: number;\n}\n\n/**\n * Formats a gadget call progress line for display.\n *\n * This is the **shared formatting function** used by both main gadget display\n * and nested subagent gadget display. Using a single function eliminates code\n * duplication and ensures consistent formatting.\n *\n * **Format (in-progress):** `⏵ GadgetName(params)` (no time - time shown on result)\n * **Format (completed - 2 lines):**\n * Line 1: `→ GadgetName(params)` (call indicator)\n * Line 2: ` ✓ GadgetName output time` (result indicator)\n * **Format (error):** `✗ GadgetName(params) error: msg time`\n *\n * @param info - Display information for the gadget call\n * @param maxWidth - Maximum width for parameter truncation (optional)\n * @returns Formatted progress line string\n *\n * @example\n * ```typescript\n * // In-progress call (no time shown)\n * formatGadgetLine({\n * name: \"Navigate\",\n * parameters: { url: \"https://example.com\" },\n * elapsedSeconds: 2.5,\n * isComplete: false,\n * });\n * // Output: \"⏵ Navigate(url=https://example.com)\"\n *\n * // Completed call (time on result line)\n * formatGadgetLine({\n * name: \"GetPageContent\",\n * parameters: { selector: \"article\" },\n * elapsedSeconds: 1.2,\n * isComplete: true,\n * tokenCount: 248,\n * });\n * // Output: \"→ GetPageContent(selector=article)\\n ✓ GetPageContent ↓ 248 1.2s\"\n * ```\n */\nexport function formatGadgetLine(info: GadgetDisplayInfo, maxWidth?: number): string {\n // Get terminal width if not specified\n const terminalWidth = maxWidth ?? process.stdout.columns ?? 80;\n\n const gadgetLabel = chalk.magenta.bold(info.name);\n const timeStr = `${info.elapsedSeconds.toFixed(1)}s`;\n const timeLabel = chalk.dim(timeStr);\n\n // Calculate fixed parts length for parameter truncation\n // Icon may be 2 columns wide in some terminals (Unicode width varies)\n const fixedLength = 3 + info.name.length + 2 + 1 + timeStr.length;\n const availableForParams = Math.max(40, terminalWidth - fixedLength - 3); // -3 safety margin\n\n // Format parameters inline with truncation\n const paramsStr = formatParametersInline(info.parameters, availableForParams);\n const paramsLabel = paramsStr ? `${chalk.dim(\"(\")}${paramsStr}${chalk.dim(\")\")}` : \"\";\n\n // Error case\n if (info.error) {\n const errorMsg = info.error.length > 50 ? `${info.error.slice(0, 50)}…` : info.error;\n return `${chalk.red(\"✗\")} ${gadgetLabel}${paramsLabel} ${chalk.red(\"error:\")} ${errorMsg} ${timeLabel}`;\n }\n\n // In-progress case - show elapsed time and any accumulated subagent metrics\n // NO parameters here - they were already shown on the opening line (→ GadgetName(params))\n // This keeps the refreshing line compact and focused on changing metrics\n if (!info.isComplete) {\n const parts: string[] = [];\n\n // Add subagent metrics if present (for gadgets that run LLM calls internally)\n if (info.subagentInputTokens && info.subagentInputTokens > 0) {\n parts.push(chalk.dim(\"↑\") + chalk.yellow(` ${formatTokens(info.subagentInputTokens)}`));\n }\n if (info.subagentOutputTokens && info.subagentOutputTokens > 0) {\n parts.push(chalk.dim(\"↓\") + chalk.green(` ${formatTokens(info.subagentOutputTokens)}`));\n }\n if (info.subagentCost && info.subagentCost > 0) {\n parts.push(chalk.cyan(`$${formatCost(info.subagentCost)}`));\n }\n\n // Always show elapsed time\n parts.push(chalk.dim(`${info.elapsedSeconds.toFixed(1)}s`));\n\n const metricsStr = parts.length > 0 ? ` ${parts.join(chalk.dim(\" | \"))}` : \"\";\n return `${chalk.blue(\"⏵\")} ${gadgetLabel}${metricsStr}`;\n }\n\n // Completed case - 2-line format for consistency with formatGadgetSummary\n // Line 1: icon + name + params (START info)\n // Line 2: name reference + output + time (END info)\n let outputLabel: string;\n if (info.tokenCount !== undefined && info.tokenCount > 0) {\n // Use same format as LLM calls: \"↓ 1.2k\" with dim arrow and green number\n outputLabel = chalk.dim(\"↓\") + chalk.green(` ${formatTokens(info.tokenCount)} `);\n } else if (info.outputBytes !== undefined && info.outputBytes > 0) {\n outputLabel = chalk.green(formatBytes(info.outputBytes)) + \" \";\n } else {\n outputLabel = \"\"; // No output to show\n }\n\n // Line 1: → (call indicator), Line 2: ✓/⏹ (result indicator)\n const resultIcon = info.breaksLoop ? chalk.yellow(\"⏹\") : chalk.green(\"✓\");\n const nameRef = chalk.magenta(info.name); // Not bold - line 2 is for reference, not emphasis\n\n const line1 = `${chalk.dim(\"→\")} ${gadgetLabel}${paramsLabel}`;\n\n // Line 2: ensure it fits within terminal width\n // Fixed parts: \" ✓ \" + name + \" \" + output + \" \" + time\n const line2Prefix = ` ${resultIcon} ${nameRef} ${outputLabel}`;\n const line2 = `${line2Prefix}${timeLabel}`;\n\n return `${line1}\\n${line2}`;\n}\n\n/**\n * Formats byte count in human-readable form.\n *\n * @param bytes - Number of bytes\n * @returns Formatted string like \"245 bytes\" or \"1.2 KB\"\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} bytes`;\n }\n if (bytes < 1024 * 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`;\n }\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Truncates output text for preview display.\n * Normalizes whitespace (collapses newlines/tabs to single spaces) and truncates with ellipsis.\n *\n * @param output - The output text to truncate\n * @param maxWidth - Maximum character width for the preview\n * @returns Truncated string with ellipsis if needed\n */\nfunction truncateOutputPreview(output: string, maxWidth: number): string {\n // Normalize whitespace (collapse newlines/tabs to single spaces)\n const normalized = output.replace(/\\s+/g, \" \").trim();\n if (normalized.length <= maxWidth) return normalized;\n return normalized.slice(0, maxWidth - 1) + \"…\";\n}\n\n/**\n * Get icon for media kind.\n *\n * @param kind - Media kind (image, audio, video, file)\n * @returns Emoji icon for the media kind\n */\nfunction getMediaIcon(kind: string): string {\n switch (kind) {\n case \"image\":\n return \"📷\";\n case \"audio\":\n return \"🔊\";\n case \"video\":\n return \"🎬\";\n case \"file\":\n return \"📄\";\n default:\n return \"📎\";\n }\n}\n\n/**\n * Formats a single media output for CLI display.\n *\n * Format: `[📷 media_a1b2c3 image/png 256KB] → /path/to/file.png`\n *\n * @param media - Stored media information\n * @returns Formatted media line with icon, ID, MIME type, size, and path\n */\nfunction formatMediaLine(media: StoredMedia): string {\n const icon = getMediaIcon(media.kind);\n const id = chalk.cyan(media.id);\n const mimeType = chalk.dim(media.mimeType);\n const size = chalk.yellow(formatBytes(media.sizeBytes));\n const path = chalk.dim(media.path);\n\n return `${chalk.dim(\"[\")}${icon} ${id} ${mimeType} ${size}${chalk.dim(\"]\")} ${chalk.dim(\"→\")} ${path}`;\n}\n\nexport function formatGadgetSummary(result: GadgetResult): string {\n // Get terminal width (default to 80 if not available)\n const terminalWidth = process.stdout.columns || 80;\n\n // Format gadget name\n const gadgetLabel = chalk.magenta.bold(result.gadgetName);\n\n // Show seconds for values >= 1000ms, otherwise milliseconds\n const timeStr =\n result.executionTimeMs >= 1000\n ? `${(result.executionTimeMs / 1000).toFixed(1)}s`\n : `${Math.round(result.executionTimeMs)}ms`;\n const timeLabel = chalk.dim(timeStr);\n\n // Note: Opening line (→ GadgetName(params)) is now printed separately on gadget_call\n // This function only returns the RESULT line\n\n // Result line: name reference + output metrics + time + preview\n const nameRef = chalk.magenta(result.gadgetName); // Not bold - result line is for reference, not emphasis\n\n // Calculate output metrics (tokens or bytes)\n // Use same format as LLM calls: \"↓ 1.2k\" with dim arrow and green number\n // Skip if we have subagent metrics - those provide comprehensive token info\n const hasSubagentMetrics = result.subagentMetrics && result.subagentMetrics.callCount > 0;\n let outputLabel: string;\n let outputStrRaw: string; // For preview width calculation (without ANSI codes)\n if (!hasSubagentMetrics && result.tokenCount !== undefined && result.tokenCount > 0) {\n const tokenStr = formatTokens(result.tokenCount);\n outputLabel = chalk.dim(\"↓\") + chalk.green(` ${tokenStr} `);\n outputStrRaw = `↓ ${tokenStr} `;\n } else if (!hasSubagentMetrics && result.result) {\n const outputBytes = Buffer.byteLength(result.result, \"utf-8\");\n if (outputBytes > 0) {\n const bytesStr = formatBytes(outputBytes);\n outputLabel = chalk.green(bytesStr) + \" \";\n outputStrRaw = bytesStr + \" \";\n } else {\n outputLabel = \"\";\n outputStrRaw = \"\";\n }\n } else {\n outputLabel = \"\";\n outputStrRaw = \"\";\n }\n\n // Error case: show error message with ✗ (opening line was already printed on gadget_call)\n if (result.error) {\n const errorMsg = result.error.length > 50 ? `${result.error.slice(0, 50)}…` : result.error;\n return `${chalk.red(\"✗\")} ${nameRef} ${chalk.red(\"error:\")} ${errorMsg} ${timeLabel}`;\n }\n\n // Result icon: ✓ for success, ⏹ for loop-breaking\n const resultIcon = result.breaksLoop ? chalk.yellow(\"⏹\") : chalk.green(\"✓\");\n\n // Build result line with output preview\n // Calculate available width for preview (~60% of terminal)\n const previewWidth = Math.floor(terminalWidth * 0.6);\n // Account for prefix: \"✓ \" + name + \" \" + output + time + \": \"\n const prefixLength = 2 + result.gadgetName.length + 1 + outputStrRaw.length + timeStr.length + 2;\n const availablePreview = Math.max(20, previewWidth - prefixLength);\n\n // Custom previews for specific gadgets\n let customPreview: string | undefined;\n\n // TodoUpsert: show status emoji + content instead of generic output\n if (result.gadgetName === \"TodoUpsert\" && result.parameters?.content) {\n const statusEmoji =\n result.parameters.status === \"done\"\n ? \"✅\"\n : result.parameters.status === \"in_progress\"\n ? \"🔄\"\n : \"⬜\";\n const content = String(result.parameters.content);\n customPreview = `${statusEmoji} ${truncateOutputPreview(content, availablePreview - 3)}`; // -3 for emoji+space\n }\n\n // GoogleSearch: show query and result count\n if (result.gadgetName === \"GoogleSearch\" && result.parameters?.query) {\n const query = String(result.parameters.query);\n // Parse result count from output - try multiple patterns\n const countMatch =\n result.result?.match(/\\((\\d+)\\s+of\\s+[\\d,]+\\s+results?\\)/i) || // \"(10 of 36400000 results)\"\n result.result?.match(/(\\d+)\\s+results?\\s+found/i) || // \"10 results found\"\n result.result?.match(/found\\s+(\\d+)\\s+results?/i); // \"found 10 results\"\n // Fall back to maxResults parameter if no count found in output\n const count = countMatch?.[1] ?? (result.parameters.maxResults ? String(result.parameters.maxResults) : null);\n const countStr = count ? ` → ${count} results` : \"\";\n const queryPreview = truncateOutputPreview(query, availablePreview - 5 - countStr.length); // 🔍 + space + quotes\n customPreview = `🔍 \"${queryPreview}\"${countStr}`;\n }\n\n // Build subagent metrics string if this gadget spawned a subagent\n // Format: \"↑ input | ⟳ cached | ↓ output | $cost\"\n let subagentMetricsStr = \"\";\n if (result.subagentMetrics && result.subagentMetrics.callCount > 0) {\n const parts: string[] = [];\n const m = result.subagentMetrics;\n\n // ↑ input tokens\n if (m.inputTokens > 0) {\n parts.push(chalk.dim(\"↑\") + chalk.yellow(` ${formatTokens(m.inputTokens)}`));\n }\n\n // ⟳ cached tokens\n if (m.cachedInputTokens > 0) {\n parts.push(chalk.dim(\"⟳\") + chalk.blue(` ${formatTokens(m.cachedInputTokens)}`));\n }\n\n // ↓ output tokens\n if (m.outputTokens > 0) {\n parts.push(chalk.dim(\"↓\") + chalk.green(` ${formatTokens(m.outputTokens)}`));\n }\n\n // $cost\n if (m.cost > 0) {\n parts.push(chalk.cyan(`$${formatCost(m.cost)}`));\n }\n\n if (parts.length > 0) {\n subagentMetricsStr = parts.join(chalk.dim(\" | \")) + chalk.dim(\" | \");\n }\n }\n\n // Build result line (opening line is now printed separately on gadget_call)\n let resultLine: string;\n const previewContent = customPreview ?? (result.result?.trim() ? truncateOutputPreview(result.result, availablePreview) : null);\n if (previewContent) {\n resultLine = `${resultIcon} ${nameRef} ${outputLabel}${subagentMetricsStr}${timeLabel}${chalk.dim(\":\")} ${chalk.dim(previewContent)}`;\n } else {\n // No output content\n resultLine = `${resultIcon} ${nameRef} ${outputLabel}${subagentMetricsStr}${timeLabel}`;\n }\n\n let output = resultLine;\n\n // Add media lines if present (images, audio, etc.)\n if (result.media && result.media.length > 0) {\n const mediaLines = result.media.map(formatMediaLine);\n output += \"\\n\" + mediaLines.join(\"\\n\");\n }\n\n // TellUser gadget: display full message content below (with markdown and separators)\n if (result.gadgetName === \"TellUser\" && result.parameters?.message) {\n const message = String(result.parameters.message);\n const rendered = renderMarkdownWithSeparators(message);\n return `${output}\\n${rendered}`;\n }\n\n return output;\n}\n","import type { Command } from \"commander\";\nimport type {\n AgentConfig,\n CompleteConfig,\n CustomCommandConfig,\n GadgetPermissionPolicy,\n GlobalSubagentConfig,\n SubagentConfigMap,\n} from \"./config.js\";\nimport { DEFAULT_MODEL, OPTION_DESCRIPTIONS, OPTION_FLAGS } from \"./constants.js\";\nimport { createNumericParser } from \"./utils.js\";\n\n/**\n * CLI options for the complete command (camelCase, matching Commander output).\n */\nexport interface CLICompleteOptions {\n model: string;\n system?: string;\n temperature?: number;\n maxTokens?: number;\n quiet?: boolean;\n logLlmRequests?: string | boolean;\n /** Path to image file to include with the prompt */\n image?: string;\n /** Path to audio file to include with the prompt */\n audio?: string;\n}\n\n/**\n * CLI options for the agent command (camelCase, matching Commander output).\n */\nexport interface CLIAgentOptions {\n model: string;\n system?: string;\n temperature?: number;\n maxIterations?: number;\n gadget?: string[];\n builtins: boolean;\n builtinInteraction: boolean;\n gadgetStartPrefix?: string;\n gadgetEndPrefix?: string;\n gadgetArgPrefix?: string;\n gadgetApproval?: GadgetPermissionPolicy;\n quiet?: boolean;\n logLlmRequests?: string | boolean;\n /** Path to image file to include with the initial prompt */\n image?: string;\n /** Path to audio file to include with the initial prompt */\n audio?: string;\n /** Enable Docker sandboxing */\n docker?: boolean;\n /** Enable Docker with read-only CWD mount */\n dockerRo?: boolean;\n /** Disable Docker (override config) */\n noDocker?: boolean;\n /** Per-profile CWD mount permission override */\n dockerCwdPermission?: \"ro\" | \"rw\";\n /** Profile-level subagent configuration overrides */\n subagents?: SubagentConfigMap;\n /** Global subagent configuration (from [subagents] section) */\n globalSubagents?: GlobalSubagentConfig;\n}\n\n/**\n * Adds complete command options to a Commander command.\n *\n * @param cmd - Command to add options to\n * @param defaults - Optional defaults from config file\n * @returns The command with options added\n */\nexport function addCompleteOptions(cmd: Command, defaults?: CompleteConfig): Command {\n return cmd\n .option(OPTION_FLAGS.model, OPTION_DESCRIPTIONS.model, defaults?.model ?? DEFAULT_MODEL)\n .option(OPTION_FLAGS.systemPrompt, OPTION_DESCRIPTIONS.systemPrompt, defaults?.system)\n .option(\n OPTION_FLAGS.temperature,\n OPTION_DESCRIPTIONS.temperature,\n createNumericParser({ label: \"Temperature\", min: 0, max: 2 }),\n defaults?.temperature,\n )\n .option(\n OPTION_FLAGS.maxTokens,\n OPTION_DESCRIPTIONS.maxTokens,\n createNumericParser({ label: \"Max tokens\", integer: true, min: 1 }),\n defaults?.[\"max-tokens\"],\n )\n .option(OPTION_FLAGS.quiet, OPTION_DESCRIPTIONS.quiet, defaults?.quiet)\n .option(\n OPTION_FLAGS.logLlmRequests,\n OPTION_DESCRIPTIONS.logLlmRequests,\n defaults?.[\"log-llm-requests\"],\n )\n .option(OPTION_FLAGS.inputImage, OPTION_DESCRIPTIONS.inputImage)\n .option(OPTION_FLAGS.inputAudio, OPTION_DESCRIPTIONS.inputAudio);\n}\n\n/**\n * Adds agent command options to a Commander command.\n *\n * @param cmd - Command to add options to\n * @param defaults - Optional defaults from config file\n * @returns The command with options added\n */\nexport function addAgentOptions(cmd: Command, defaults?: AgentConfig): Command {\n // Gadget accumulator needs special handling for defaults\n const gadgetAccumulator = (value: string, previous: string[] = []): string[] => [\n ...previous,\n value,\n ];\n const defaultGadgets = defaults?.gadgets ?? defaults?.gadget ?? [];\n\n return cmd\n .option(OPTION_FLAGS.model, OPTION_DESCRIPTIONS.model, defaults?.model ?? DEFAULT_MODEL)\n .option(OPTION_FLAGS.systemPrompt, OPTION_DESCRIPTIONS.systemPrompt, defaults?.system)\n .option(\n OPTION_FLAGS.temperature,\n OPTION_DESCRIPTIONS.temperature,\n createNumericParser({ label: \"Temperature\", min: 0, max: 2 }),\n defaults?.temperature,\n )\n .option(\n OPTION_FLAGS.maxIterations,\n OPTION_DESCRIPTIONS.maxIterations,\n createNumericParser({ label: \"Max iterations\", integer: true, min: 1 }),\n defaults?.[\"max-iterations\"],\n )\n .option(OPTION_FLAGS.gadgetModule, OPTION_DESCRIPTIONS.gadgetModule, gadgetAccumulator, [\n ...defaultGadgets,\n ])\n .option(OPTION_FLAGS.noBuiltins, OPTION_DESCRIPTIONS.noBuiltins, defaults?.builtins !== false)\n .option(\n OPTION_FLAGS.noBuiltinInteraction,\n OPTION_DESCRIPTIONS.noBuiltinInteraction,\n defaults?.[\"builtin-interaction\"] !== false,\n )\n .option(OPTION_FLAGS.quiet, OPTION_DESCRIPTIONS.quiet, defaults?.quiet)\n .option(\n OPTION_FLAGS.logLlmRequests,\n OPTION_DESCRIPTIONS.logLlmRequests,\n defaults?.[\"log-llm-requests\"],\n )\n .option(OPTION_FLAGS.inputImage, OPTION_DESCRIPTIONS.inputImage)\n .option(OPTION_FLAGS.inputAudio, OPTION_DESCRIPTIONS.inputAudio)\n .option(OPTION_FLAGS.docker, OPTION_DESCRIPTIONS.docker)\n .option(OPTION_FLAGS.dockerRo, OPTION_DESCRIPTIONS.dockerRo)\n .option(OPTION_FLAGS.noDocker, OPTION_DESCRIPTIONS.noDocker);\n}\n\n/**\n * Converts kebab-case config to camelCase command options for complete command.\n */\nexport function configToCompleteOptions(\n config: CustomCommandConfig,\n): Partial<CLICompleteOptions> {\n const result: Partial<CLICompleteOptions> = {};\n if (config.model !== undefined) result.model = config.model;\n if (config.system !== undefined) result.system = config.system;\n if (config.temperature !== undefined) result.temperature = config.temperature;\n if (config[\"max-tokens\"] !== undefined) result.maxTokens = config[\"max-tokens\"];\n if (config.quiet !== undefined) result.quiet = config.quiet;\n if (config[\"log-llm-requests\"] !== undefined) result.logLlmRequests = config[\"log-llm-requests\"];\n return result;\n}\n\n/**\n * Converts kebab-case config to camelCase command options for agent command.\n */\nexport function configToAgentOptions(config: CustomCommandConfig): Partial<CLIAgentOptions> {\n const result: Partial<CLIAgentOptions> = {};\n if (config.model !== undefined) result.model = config.model;\n if (config.system !== undefined) result.system = config.system;\n if (config.temperature !== undefined) result.temperature = config.temperature;\n if (config[\"max-iterations\"] !== undefined) result.maxIterations = config[\"max-iterations\"];\n // Prefer gadgets (plural) from resolved config, fall back to legacy gadget (singular)\n const gadgets = config.gadgets ?? config.gadget;\n if (gadgets !== undefined) result.gadget = gadgets;\n if (config.builtins !== undefined) result.builtins = config.builtins;\n if (config[\"builtin-interaction\"] !== undefined)\n result.builtinInteraction = config[\"builtin-interaction\"];\n if (config[\"gadget-start-prefix\"] !== undefined)\n result.gadgetStartPrefix = config[\"gadget-start-prefix\"];\n if (config[\"gadget-end-prefix\"] !== undefined)\n result.gadgetEndPrefix = config[\"gadget-end-prefix\"];\n if (config[\"gadget-arg-prefix\"] !== undefined)\n result.gadgetArgPrefix = config[\"gadget-arg-prefix\"];\n if (config[\"gadget-approval\"] !== undefined) result.gadgetApproval = config[\"gadget-approval\"];\n if (config.quiet !== undefined) result.quiet = config.quiet;\n if (config[\"log-llm-requests\"] !== undefined) result.logLlmRequests = config[\"log-llm-requests\"];\n if (config.docker !== undefined) result.docker = config.docker;\n if (config[\"docker-cwd-permission\"] !== undefined)\n result.dockerCwdPermission = config[\"docker-cwd-permission\"];\n if (config.subagents !== undefined) result.subagents = config.subagents;\n return result;\n}\n","/**\n * TUI screen lifecycle management.\n *\n * Handles creation, rendering, and cleanup of the blessed Screen instance.\n * Ensures proper terminal restoration on exit.\n */\n\nimport { Screen, setRuntime, NodeRuntime } from \"@unblessed/node\";\nimport type { TUIScreenContext } from \"./types.js\";\n\n// Initialize the Node.js runtime (required before any blessed widgets can be created)\nlet runtimeInitialized = false;\n\nfunction ensureRuntimeInitialized(): void {\n if (!runtimeInitialized) {\n setRuntime(new NodeRuntime());\n runtimeInitialized = true;\n }\n}\n\n/** Default render debounce interval in milliseconds */\nconst RENDER_DEBOUNCE_MS = 16; // ~60fps\n\n/**\n * Creates and configures a blessed Screen with proper lifecycle management.\n *\n * @param options - Screen configuration options\n * @returns Screen context with lifecycle methods\n */\nexport function createScreen(options?: {\n stdin?: NodeJS.ReadStream;\n stdout?: NodeJS.WriteStream;\n title?: string;\n}): TUIScreenContext {\n // Ensure runtime is initialized before creating any blessed widgets\n ensureRuntimeInitialized();\n\n const screen = new Screen({\n smartCSR: true, // Smart cursor rendering for better performance\n fullUnicode: true, // Support emoji and extended characters\n title: options?.title ?? \"llmist\",\n input: options?.stdin,\n output: options?.stdout,\n // Capture all keyboard input\n grabKeys: true,\n // Use alternate screen buffer (restores on exit)\n useBCE: true,\n });\n\n let isDestroyed = false;\n let renderPending = false;\n let renderTimeout: ReturnType<typeof setTimeout> | null = null;\n\n // Debounced render function to avoid excessive redraws\n // Uses trailing-edge debounce: captures latest state before rendering\n const requestRender = () => {\n if (isDestroyed) return;\n\n // If a render is already pending, it will pick up the latest state\n // when it fires, so we don't need to schedule another one\n if (renderPending) return;\n\n renderPending = true;\n renderTimeout = setTimeout(() => {\n renderPending = false;\n if (!isDestroyed) {\n screen.render();\n }\n }, RENDER_DEBOUNCE_MS);\n };\n\n // Immediate render for time-sensitive updates (like streaming tokens)\n const renderNow = () => {\n if (isDestroyed) return;\n\n // Cancel any pending debounced render\n if (renderTimeout) {\n clearTimeout(renderTimeout);\n renderTimeout = null;\n renderPending = false;\n }\n\n screen.render();\n };\n\n // Cleanup function\n const destroy = () => {\n if (isDestroyed) return;\n isDestroyed = true;\n\n // Clear any pending render\n if (renderTimeout) {\n clearTimeout(renderTimeout);\n renderTimeout = null;\n }\n\n // Destroy screen (restores terminal)\n screen.destroy();\n\n // Ensure cursor is visible\n process.stdout.write(\"\\x1b[?25h\");\n };\n\n // Handle process signals for graceful cleanup\n const sigintHandler = () => {\n destroy();\n process.exit(130); // SIGINT convention\n };\n\n const sigtermHandler = () => {\n destroy();\n process.exit(143); // SIGTERM convention\n };\n\n process.once(\"SIGINT\", sigintHandler);\n process.once(\"SIGTERM\", sigtermHandler);\n\n // Also handle uncaught exceptions to restore terminal\n process.once(\"uncaughtException\", (err) => {\n destroy();\n console.error(\"Uncaught exception:\", err);\n process.exit(1);\n });\n\n return {\n screen,\n requestRender,\n renderNow,\n destroy,\n };\n}\n","/**\n * TUI layout widget creation.\n *\n * Creates and configures the three main TUI widgets:\n * - Body: ScrollableBox for interactive block widgets\n * - InputBar: Always-visible input field at the bottom\n * - StatusBar: Metrics display (tokens, time, cost)\n */\n\nimport { Box, ScrollableBox, Textbox, type Screen } from \"@unblessed/node\";\nimport type { TUIBlockLayout, FocusMode } from \"./types.js\";\n\n/**\n * Creates the TUI layout with ScrollableBox for interactive blocks.\n *\n * Layout structure (from bottom):\n * - Status bar: 1 line at very bottom\n * - Input bar: 1 line above status\n * - Body: Remaining space (ScrollableBox with Box children)\n *\n * @param screen - The blessed Screen instance\n * @returns Layout object containing all widgets\n */\nexport function createBlockLayout(screen: Screen): TUIBlockLayout {\n // Main scrollable container for block widgets\n // Uses ScrollableBox to support Box children (not just text)\n const body = new ScrollableBox({\n parent: screen,\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%-2\",\n // Scrolling configuration\n scrollable: true,\n alwaysScroll: true,\n mouse: true,\n keys: false, // We handle keys ourselves for block selection\n scrollbar: {\n ch: \" \",\n style: {\n bg: \"blue\",\n },\n },\n // Don't use blessed tags - we pass ANSI directly from chalk\n tags: false,\n // Style\n style: {\n fg: \"white\",\n bg: \"black\",\n },\n });\n\n // Input bar - always visible at bottom - 1\n // Shows \"> \" prompt indicator even when idle\n const inputBar = new Textbox({\n parent: screen,\n bottom: 1,\n left: 0,\n width: \"100%\",\n height: 1,\n inputOnFocus: true,\n keys: true,\n mouse: true,\n style: {\n fg: \"white\",\n bg: \"black\",\n },\n });\n\n // Pre-fill with prompt indicator\n inputBar.setValue(\"> \");\n\n // Status bar at very bottom\n // Uses ANSI codes for color formatting (tags: false)\n const statusBar = new Box({\n parent: screen,\n bottom: 0,\n left: 0,\n width: \"100%\",\n height: 1,\n tags: false,\n style: {\n fg: \"white\",\n bg: \"black\",\n },\n });\n\n return { body, inputBar, statusBar };\n}\n\n/**\n * Sets up keyboard navigation for block selection in the TUI.\n *\n * Provides navigation between selectable blocks (LLM calls, gadgets)\n * and expand/collapse functionality for viewing details.\n *\n * Navigation only works in \"browse\" focus mode. In \"input\" mode,\n * keys are captured by the input field.\n *\n * @param screen - The blessed Screen instance\n * @param callbacks - Object with navigation callback functions\n * @param getFocusMode - Function to get current focus mode\n */\nexport function setupBlockNavigationKeys(\n screen: Screen,\n callbacks: {\n onSelectNext: () => void;\n onSelectPrevious: () => void;\n onToggleExpand: () => void;\n onCollapse: () => void;\n onSelectFirst: () => void;\n onSelectLast: () => void;\n onShowRawRequest?: () => void;\n onShowRawResponse?: () => void;\n },\n getFocusMode: () => FocusMode,\n): void {\n // Navigation: up/down or vim keys (browse mode only)\n screen.key([\"up\", \"k\"], () => {\n if (getFocusMode() !== \"browse\") return;\n callbacks.onSelectPrevious();\n screen.render();\n });\n\n screen.key([\"down\", \"j\"], () => {\n if (getFocusMode() !== \"browse\") return;\n callbacks.onSelectNext();\n screen.render();\n });\n\n // Expand/collapse with Enter or Space (browse mode only)\n screen.key([\"enter\", \"space\"], () => {\n if (getFocusMode() !== \"browse\") return;\n callbacks.onToggleExpand();\n screen.render();\n });\n\n // Collapse with Escape or h (vim-style left) (browse mode only)\n screen.key([\"escape\", \"h\"], () => {\n if (getFocusMode() !== \"browse\") return;\n callbacks.onCollapse();\n screen.render();\n });\n\n // Jump to first/last (browse mode only)\n screen.key([\"home\", \"g\"], () => {\n if (getFocusMode() !== \"browse\") return;\n callbacks.onSelectFirst();\n screen.render();\n });\n\n screen.key([\"end\", \"G\"], () => {\n if (getFocusMode() !== \"browse\") return;\n callbacks.onSelectLast();\n screen.render();\n });\n\n // Raw viewer: r = request, R = response (browse mode only)\n screen.key([\"r\"], () => {\n if (getFocusMode() !== \"browse\") return;\n callbacks.onShowRawRequest?.();\n });\n\n screen.key([\"S-r\"], () => {\n if (getFocusMode() !== \"browse\") return;\n callbacks.onShowRawResponse?.();\n });\n}\n","/**\n * TUI status bar for displaying real-time metrics.\n *\n * Shows accumulated token counts, elapsed time, and cost.\n * Also displays currently active LLM calls and gadgets with a spinner.\n * Updates on LLM call lifecycle events.\n */\n\nimport type { Box } from \"@unblessed/node\";\nimport type { TUIMetrics, FocusMode } from \"./types.js\";\nimport { formatTokens, formatCost } from \"../ui/formatters.js\";\nimport type { ExecutionTree, ExecutionEvent, NodeId } from \"../../core/execution-tree.js\";\n\n/** Rough estimate: ~4 characters per token for English text */\nconst CHARS_PER_TOKEN = 4;\n\n/** Braille spinner frames for smooth animation */\nconst SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n\n/** Spinner animation interval in ms (~12fps) */\nconst SPINNER_INTERVAL_MS = 80;\n\n/**\n * Manages the status bar display and metrics tracking.\n */\nexport class StatusBar {\n private metrics: TUIMetrics;\n private statusBox: Box;\n private renderCallback: () => void;\n private renderNowCallback: () => void;\n\n /** Current call's streaming input tokens (estimate) */\n private streamingInputTokens = 0;\n /** Current call's streaming output tokens (estimate) */\n private streamingOutputTokens = 0;\n /** Whether we're currently streaming */\n private isStreaming = false;\n\n /** Active LLM calls: Map from label (\"#1\") to model name */\n private activeLLMCalls = new Map<string, string>();\n\n /** Active gadgets (by name) */\n private activeGadgets = new Set<string>();\n\n /** Spinner frame index */\n private spinnerFrame = 0;\n\n /** Spinner animation interval */\n private spinnerInterval: ReturnType<typeof setInterval> | null = null;\n\n /** Current focus mode */\n private focusMode: FocusMode = \"browse\";\n\n /** Track tree node IDs to display labels for LLM calls */\n private nodeIdToLabel = new Map<NodeId, string>();\n\n /** Track tree node IDs for gadgets */\n private nodeIdToGadgetName = new Map<NodeId, string>();\n\n /** Tree subscription unsubscribe function */\n private treeUnsubscribe: (() => void) | null = null;\n\n constructor(\n statusBox: Box,\n model: string,\n renderCallback: () => void,\n renderNowCallback?: () => void,\n ) {\n this.statusBox = statusBox;\n this.renderCallback = renderCallback;\n this.renderNowCallback = renderNowCallback ?? renderCallback;\n this.metrics = {\n inputTokens: 0,\n outputTokens: 0,\n cachedTokens: 0,\n cost: 0,\n startTime: Date.now(),\n iteration: 0,\n model,\n };\n\n // Initial render\n this.render();\n }\n\n /**\n * Called when a new LLM call starts.\n * @param model - Model name\n * @param estimatedInputTokens - Estimated input tokens for this call\n */\n startCall(model: string, estimatedInputTokens: number): void {\n this.metrics.model = model;\n this.metrics.iteration++;\n // Track streaming estimates separately\n this.streamingInputTokens = estimatedInputTokens;\n this.streamingOutputTokens = 0;\n this.isStreaming = true;\n this.render();\n }\n\n /**\n * Called during streaming to update output token estimate.\n * Uses immediate rendering for real-time feedback.\n * @param estimatedOutputTokens - Estimated output tokens so far\n */\n updateStreaming(estimatedOutputTokens: number): void {\n this.streamingOutputTokens = estimatedOutputTokens;\n this.render(true); // immediate render for streaming updates\n }\n\n /**\n * Called when an LLM call completes.\n * Replaces streaming estimates with actual values.\n */\n endCall(\n inputTokens: number,\n outputTokens: number,\n cachedTokens: number,\n cost: number,\n ): void {\n // Add actual values to accumulated totals\n this.metrics.inputTokens += inputTokens;\n this.metrics.outputTokens += outputTokens;\n this.metrics.cachedTokens += cachedTokens;\n this.metrics.cost += cost;\n // Clear streaming state\n this.streamingInputTokens = 0;\n this.streamingOutputTokens = 0;\n this.isStreaming = false;\n this.render();\n }\n\n /**\n * Add cost from gadget execution (e.g., subagent costs).\n */\n addGadgetCost(cost: number): void {\n if (cost > 0) {\n this.metrics.cost += cost;\n this.render();\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Activity Tracking (for real-time display of what's running)\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Track an LLM call as active.\n * @param label - Display label like \"#1\" or \"#1.1\"\n * @param model - Full model name like \"gemini:gemini-2.5-flash\"\n */\n startLLMCall(label: string, model: string): void {\n this.activeLLMCalls.set(label, model);\n this.startSpinner();\n this.render();\n }\n\n /**\n * Mark an LLM call as complete.\n * @param label - Display label like \"#1\" or \"#1.1\"\n */\n endLLMCall(label: string): void {\n this.activeLLMCalls.delete(label);\n this.maybeStopSpinner();\n this.render();\n }\n\n /**\n * Track a gadget as active.\n * @param name - Gadget name like \"ReadFile\" or \"BrowseWeb\"\n */\n startGadget(name: string): void {\n this.activeGadgets.add(name);\n this.startSpinner();\n this.render();\n }\n\n /**\n * Mark a gadget as complete.\n * @param name - Gadget name\n */\n endGadget(name: string): void {\n this.activeGadgets.delete(name);\n this.maybeStopSpinner();\n this.render();\n }\n\n /**\n * Start the spinner animation if not already running.\n */\n private startSpinner(): void {\n if (this.spinnerInterval) return;\n this.spinnerInterval = setInterval(() => {\n this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;\n this.render(true); // immediate render for smooth animation\n }, SPINNER_INTERVAL_MS);\n }\n\n /**\n * Stop the spinner if no activity is in progress.\n */\n private maybeStopSpinner(): void {\n if (this.activeLLMCalls.size === 0 && this.activeGadgets.size === 0) {\n this.stopSpinner();\n }\n }\n\n /**\n * Force stop the spinner animation.\n */\n private stopSpinner(): void {\n if (this.spinnerInterval) {\n clearInterval(this.spinnerInterval);\n this.spinnerInterval = null;\n }\n }\n\n /**\n * Clear all activity tracking and stop spinner.\n * Call this when the agent loop completes or between REPL iterations.\n */\n clearActivity(): void {\n this.activeLLMCalls.clear();\n this.activeGadgets.clear();\n this.nodeIdToLabel.clear();\n this.nodeIdToGadgetName.clear();\n this.stopSpinner();\n this.render();\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Tree Subscription (for tree-only block creation)\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Subscribe to ExecutionTree events for automatic activity tracking.\n * This enables tree-only block creation where the tree is the single\n * source of truth for LLM calls and gadgets.\n *\n * @param tree - The ExecutionTree to subscribe to\n * @returns Unsubscribe function\n */\n subscribeToTree(tree: ExecutionTree): () => void {\n // Unsubscribe from any previous tree\n if (this.treeUnsubscribe) {\n this.treeUnsubscribe();\n }\n\n // Clear previous mappings\n this.nodeIdToLabel.clear();\n this.nodeIdToGadgetName.clear();\n\n this.treeUnsubscribe = tree.onAll((event: ExecutionEvent) => {\n this.handleTreeEvent(event);\n });\n\n return () => {\n if (this.treeUnsubscribe) {\n this.treeUnsubscribe();\n this.treeUnsubscribe = null;\n }\n };\n }\n\n /**\n * Handle an ExecutionTree event for activity tracking.\n */\n private handleTreeEvent(event: ExecutionEvent): void {\n switch (event.type) {\n case \"llm_call_start\": {\n // Create label like \"#1\" for root calls, \"#1.1\" for nested\n const label = event.depth === 0\n ? `#${event.iteration + 1}`\n : `#${event.iteration + 1}.${event.depth}`;\n this.nodeIdToLabel.set(event.nodeId, label);\n this.startLLMCall(label, event.model);\n break;\n }\n\n case \"llm_call_complete\":\n case \"llm_call_error\": {\n const label = this.nodeIdToLabel.get(event.nodeId);\n if (label) {\n this.endLLMCall(label);\n this.nodeIdToLabel.delete(event.nodeId);\n }\n break;\n }\n\n case \"gadget_call\": {\n this.nodeIdToGadgetName.set(event.nodeId, event.name);\n this.startGadget(event.name);\n break;\n }\n\n case \"gadget_complete\": {\n const name = this.nodeIdToGadgetName.get(event.nodeId);\n if (name) {\n this.endGadget(name);\n if (event.cost) {\n this.addGadgetCost(event.cost);\n }\n this.nodeIdToGadgetName.delete(event.nodeId);\n }\n break;\n }\n\n case \"gadget_error\":\n case \"gadget_skipped\": {\n const name = this.nodeIdToGadgetName.get(event.nodeId);\n if (name) {\n this.endGadget(name);\n this.nodeIdToGadgetName.delete(event.nodeId);\n }\n break;\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Focus Mode\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Set the current focus mode (called by TUIApp).\n * Updates the status bar to show the mode indicator.\n * Uses immediate render to ensure the mode is visible before input focus changes.\n */\n setFocusMode(mode: FocusMode): void {\n this.focusMode = mode;\n this.render(true); // immediate render for mode changes\n }\n\n /**\n * Get the current focus mode.\n */\n getFocusMode(): FocusMode {\n return this.focusMode;\n }\n\n /**\n * Shorten model name for display.\n * \"gemini:gemini-2.5-flash\" → \"2.5-flash\"\n */\n private shortenModelName(model: string): string {\n // Remove provider prefix\n const withoutProvider = model.includes(\":\") ? model.split(\":\")[1] : model;\n // Shorten common patterns\n return withoutProvider\n .replace(\"claude-\", \"\")\n .replace(\"gemini-\", \"\")\n .replace(\"gpt-\", \"\")\n .replace(\"-latest\", \"\");\n }\n\n /**\n * Get current metrics for external use.\n */\n getMetrics(): Readonly<TUIMetrics> {\n return { ...this.metrics };\n }\n\n /**\n * Get elapsed time in seconds.\n */\n getElapsedSeconds(): number {\n return (Date.now() - this.metrics.startTime) / 1000;\n }\n\n /**\n * Render the status bar content.\n * @param immediate - If true, render immediately without debouncing\n */\n private render(immediate = false): void {\n const elapsed = this.getElapsedSeconds().toFixed(1);\n\n // ANSI color codes\n const YELLOW = \"\\x1b[33m\";\n const GREEN = \"\\x1b[32m\";\n const BLUE = \"\\x1b[34m\";\n const CYAN = \"\\x1b[36m\";\n const MAGENTA = \"\\x1b[35m\";\n const GRAY = \"\\x1b[90m\";\n const RESET = \"\\x1b[0m\";\n const BG_BLUE = \"\\x1b[44m\";\n const BG_GREEN = \"\\x1b[42m\";\n const WHITE = \"\\x1b[37m\";\n const BLACK = \"\\x1b[30m\";\n\n // Calculate display values: accumulated + current streaming\n const displayInputTokens = this.metrics.inputTokens + this.streamingInputTokens;\n const displayOutputTokens = this.metrics.outputTokens + this.streamingOutputTokens;\n\n // Build status line using ANSI codes\n // Order: mode indicator, stable metrics (tokens, time, cost), then dynamic activity (LLM calls, gadgets)\n const parts: string[] = [];\n\n // Focus mode indicator at the start\n if (this.focusMode === \"browse\") {\n parts.push(`${BG_BLUE}${WHITE} BROWSE ${RESET}`);\n } else {\n parts.push(`${BG_GREEN}${BLACK} INPUT ${RESET}`);\n }\n\n // Input tokens (yellow) - show ~ prefix during streaming to indicate estimate\n const inputPrefix = this.isStreaming && this.streamingInputTokens > 0 ? \"~\" : \"\";\n parts.push(`${YELLOW}↑ ${inputPrefix}${formatTokens(displayInputTokens)}${RESET}`);\n\n // Cached tokens (blue) - only show if present\n if (this.metrics.cachedTokens > 0) {\n parts.push(`${BLUE}⤿ ${formatTokens(this.metrics.cachedTokens)}${RESET}`);\n }\n\n // Output tokens (green) - show ~ prefix during streaming to indicate estimate\n const outputPrefix = this.isStreaming ? \"~\" : \"\";\n parts.push(`${GREEN}↓ ${outputPrefix}${formatTokens(displayOutputTokens)}${RESET}`);\n\n // Elapsed time (gray)\n parts.push(`${GRAY}${elapsed}s${RESET}`);\n\n // Cost (cyan)\n parts.push(`${CYAN}$${formatCost(this.metrics.cost)}${RESET}`);\n\n // Activity section at the end (if anything is running)\n if (this.activeLLMCalls.size > 0 || this.activeGadgets.size > 0) {\n const spinner = SPINNER_FRAMES[this.spinnerFrame];\n\n // Show active LLM calls with model names, grouped by model\n if (this.activeLLMCalls.size > 0) {\n const byModel = new Map<string, string[]>();\n for (const [label, model] of this.activeLLMCalls) {\n const shortModel = this.shortenModelName(model);\n if (!byModel.has(shortModel)) byModel.set(shortModel, []);\n byModel.get(shortModel)?.push(label);\n }\n\n const llmParts: string[] = [];\n for (const [model, labels] of byModel) {\n llmParts.push(`${model} ${labels.join(\", \")}`);\n }\n parts.push(`${spinner} ${MAGENTA}${llmParts.join(\" | \")}${RESET}`);\n }\n\n // Show active gadgets (limit to 3, show +N for more)\n if (this.activeGadgets.size > 0) {\n const gadgetList = [...this.activeGadgets].slice(0, 3).join(\", \");\n const more = this.activeGadgets.size > 3 ? ` +${this.activeGadgets.size - 3}` : \"\";\n parts.push(`${CYAN}⏵ ${gadgetList}${more}${RESET}`);\n }\n }\n\n this.statusBox.setContent(parts.join(` ${GRAY}|${RESET} `));\n\n // Use immediate render for streaming updates, debounced for others\n if (immediate) {\n this.renderNowCallback();\n } else {\n this.renderCallback();\n }\n }\n\n /**\n * Estimate tokens from text length.\n * @param text - Text to estimate tokens for\n * @returns Estimated token count\n */\n static estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n }\n}\n","/**\n * TUI input handler for AskUser prompts.\n *\n * Manages the input field lifecycle for user responses.\n * The input field is always visible but only active during prompts.\n */\n\nimport type { Screen, Textbox, Box } from \"@unblessed/node\";\nimport type { PendingInput, CtrlCCallback } from \"./types.js\";\n\n/** Prompt indicator shown when input is idle */\nconst IDLE_PROMPT = \"> \";\n\n/** Prompt indicator shown when waiting for input */\nconst ACTIVE_PROMPT = \">>> \";\n\n/** Prompt indicator for pending REPL input (not capturing keys yet) */\nconst PENDING_PROMPT = \"> \";\n\n/**\n * Manages input field for AskUser responses.\n */\nexport class InputHandler {\n private inputBar: Textbox;\n private body: Box;\n private screen: Screen;\n private renderCallback: () => void;\n private renderNowCallback: () => void;\n\n /** Currently pending input request */\n private pendingInput: PendingInput | null = null;\n\n /** Whether we're waiting for REPL prompt (vs AskUser which should auto-focus) */\n private isPendingREPLPrompt = false;\n\n /** Callback when Ctrl+C is pressed */\n private ctrlCCallback: CtrlCCallback | null = null;\n\n /** Callback when Ctrl+B is pressed (toggle focus mode) */\n private ctrlBCallback: (() => void) | null = null;\n\n constructor(\n inputBar: Textbox,\n body: Box,\n screen: Screen,\n renderCallback: () => void,\n renderNowCallback?: () => void,\n ) {\n this.inputBar = inputBar;\n this.body = body;\n this.screen = screen;\n this.renderCallback = renderCallback;\n this.renderNowCallback = renderNowCallback ?? renderCallback;\n\n // Set up input submission handler\n this.inputBar.on(\"submit\", (value: string) => {\n this.handleSubmit(value);\n });\n\n // Handle cancel (ESC while focused)\n this.inputBar.on(\"cancel\", () => {\n this.handleCancel();\n });\n\n // Handle Ctrl+C on the input bar - propagate to callback\n // This ensures Ctrl+C works even when textbox has focus\n this.inputBar.key([\"C-c\"], () => {\n if (this.ctrlCCallback) {\n this.ctrlCCallback();\n }\n });\n\n // Handle Ctrl+B on the input bar - toggle focus mode\n // This ensures Ctrl+B works to exit input mode back to browse mode\n this.inputBar.key([\"C-b\"], () => {\n if (this.ctrlBCallback) {\n this.ctrlBCallback();\n }\n });\n\n // Screen-level Enter key to activate pending REPL prompt\n // This allows navigation to work when not actively typing\n this.screen.key([\"enter\"], () => {\n if (this.isPendingREPLPrompt) {\n this.activatePendingPrompt();\n }\n });\n\n // Show idle prompt\n this.setIdle();\n }\n\n /**\n * Set callback for Ctrl+C events.\n */\n onCtrlC(callback: CtrlCCallback): void {\n this.ctrlCCallback = callback;\n }\n\n /**\n * Set callback for Ctrl+B events (toggle focus mode).\n */\n onCtrlB(callback: () => void): void {\n this.ctrlBCallback = callback;\n }\n\n /**\n * Request user input with a question.\n *\n * @param question - The question to display\n * @param gadgetName - Name of the gadget requesting input\n * @returns Promise that resolves with user's response\n */\n async waitForInput(question: string, gadgetName: string): Promise<string> {\n return new Promise((resolve, reject) => {\n this.pendingInput = {\n question,\n gadgetName,\n resolve,\n reject,\n };\n\n // Show the question in the body area\n this.appendQuestionToBody(question);\n\n // Activate input mode\n this.setActive();\n });\n }\n\n /**\n * Wait for user to enter a new prompt (REPL mode).\n *\n * Unlike waitForInput, this doesn't auto-focus so navigation keys still work.\n * Press Enter to start typing a new prompt.\n *\n * @returns Promise that resolves with user's prompt\n */\n async waitForPrompt(): Promise<string> {\n return new Promise((resolve, reject) => {\n this.pendingInput = {\n question: \"\",\n gadgetName: \"prompt\",\n resolve,\n reject,\n };\n\n // Set to pending state - show prompt but don't capture all keys\n // This allows block navigation to work while waiting for user to start typing\n this.setPendingPrompt();\n });\n }\n\n /**\n * Activate a pending REPL prompt (called when user presses Enter).\n */\n activatePendingPrompt(): void {\n if (this.isPendingREPLPrompt && this.pendingInput) {\n this.isPendingREPLPrompt = false;\n this.setActive();\n }\n }\n\n /**\n * Check if there's a pending input request.\n */\n hasPendingInput(): boolean {\n return this.pendingInput !== null;\n }\n\n /**\n * Cancel any pending input request.\n */\n cancelPending(): void {\n if (this.pendingInput) {\n this.pendingInput.reject(new Error(\"Input cancelled\"));\n this.pendingInput = null;\n this.setIdle();\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Focus Mode API (controlled by TUIApp)\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Activate input mode - show input bar and capture keyboard.\n * Called by TUIApp when switching to input mode.\n */\n activate(): void {\n this.isPendingREPLPrompt = false;\n this.inputBar.show();\n this.inputBar.setValue(ACTIVE_PROMPT);\n // Render immediately to ensure input bar is visible before focus\n this.renderNowCallback();\n // Then focus and start reading input\n this.inputBar.focus();\n this.inputBar.readInput();\n }\n\n /**\n * Deactivate input mode - hide input bar completely.\n * Called by TUIApp when switching to browse mode.\n */\n deactivate(): void {\n this.inputBar.hide();\n this.isPendingREPLPrompt = false;\n this.renderNowCallback();\n }\n\n /**\n * Check if input mode is active (input bar visible and focused).\n */\n isInputActive(): boolean {\n return this.inputBar.visible !== false;\n }\n\n /**\n * Handle input submission.\n */\n private handleSubmit(rawValue: string): void {\n // Extract actual input (remove prompt prefix)\n const value = rawValue.startsWith(ACTIVE_PROMPT)\n ? rawValue.slice(ACTIVE_PROMPT.length).trim()\n : rawValue.startsWith(IDLE_PROMPT)\n ? rawValue.slice(IDLE_PROMPT.length).trim()\n : rawValue.trim();\n\n if (!value) {\n // Empty input - refocus for retry\n this.inputBar.focus();\n this.inputBar.readInput();\n return;\n }\n\n if (this.pendingInput) {\n // Resolve the pending promise\n const { resolve } = this.pendingInput;\n this.pendingInput = null;\n\n // Reset to idle state\n this.setIdle();\n\n // Resolve with the user's input\n resolve(value);\n } else {\n // No pending input - just reset\n this.setIdle();\n }\n }\n\n /**\n * Handle input cancellation (ESC key).\n */\n private handleCancel(): void {\n if (this.pendingInput) {\n // Don't actually cancel - just reset focus\n // The pending input will continue to wait\n this.inputBar.focus();\n this.inputBar.readInput();\n } else {\n this.setIdle();\n }\n }\n\n /**\n * Set input to idle state.\n */\n private setIdle(): void {\n this.isPendingREPLPrompt = false;\n this.inputBar.setValue(IDLE_PROMPT);\n // Don't focus - let body handle scroll keys\n this.renderCallback();\n }\n\n /**\n * Set input to pending REPL prompt state.\n * Shows the prompt indicator but doesn't capture all keys.\n */\n private setPendingPrompt(): void {\n this.isPendingREPLPrompt = true;\n this.inputBar.setValue(PENDING_PROMPT);\n // Don't focus - let navigation keys work\n // User presses Enter to activate and start typing\n this.renderCallback();\n }\n\n /**\n * Set input to active state for user input.\n */\n private setActive(): void {\n this.isPendingREPLPrompt = false;\n this.inputBar.setValue(ACTIVE_PROMPT);\n this.inputBar.focus();\n this.inputBar.readInput();\n this.renderCallback();\n }\n\n /**\n * Append the question to the body content.\n */\n private appendQuestionToBody(question: string): void {\n const currentContent = this.body.getContent();\n const separator = \"\\n\" + \"─\".repeat(40) + \"\\n\";\n const formatted = `${separator}? ${question}${separator}`;\n\n this.body.setContent(currentContent + formatted);\n this.body.setScrollPerc?.(100);\n this.renderCallback();\n }\n}\n","/**\n * BlockRenderer - Interactive block-based TUI renderer.\n *\n * Manages a tree of selectable/expandable blocks for LLM calls and gadgets.\n * Handles navigation, selection, and expand/collapse interactions.\n *\n * Can optionally subscribe to an ExecutionTree for automatic updates,\n * eliminating the need for manual event handling.\n *\n * @module\n */\n\nimport { Box, type ScrollableBox } from \"@unblessed/node\";\nimport type {\n ExecutionTree,\n ExecutionEvent,\n} from \"../../core/execution-tree.js\";\nimport type {\n BlockNode,\n LLMCallNode,\n GadgetNode,\n TextNode,\n SelectableBlock,\n} from \"./types.js\";\nimport {\n formatLLMCallCollapsed,\n formatLLMCallExpanded,\n formatGadgetCollapsed,\n formatGadgetExpanded,\n getIndent,\n getContinuationIndent,\n} from \"../ui/block-formatters.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// BlockRenderer Class\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Manages interactive blocks in the TUI.\n *\n * Features:\n * - Tree structure of LLM calls and gadgets\n * - Keyboard navigation (up/down)\n * - Expand/collapse for details\n * - Dynamic updates (gadget results, subagent events)\n */\nexport class BlockRenderer {\n private container: ScrollableBox;\n private renderCallback: () => void;\n\n /** All nodes in the tree (flat for easy lookup) */\n private nodes = new Map<string, BlockNode>();\n\n /** Root node IDs (top-level LLM calls and text) */\n private rootIds: string[] = [];\n\n /** Rendered blocks with UI state */\n private blocks = new Map<string, SelectableBlock>();\n\n /** IDs of selectable blocks in display order */\n private selectableIds: string[] = [];\n\n /** Currently selected block index (-1 = none) */\n private selectedIndex = -1;\n\n /** Counter for generating unique node IDs */\n private nodeIdCounter = 0;\n\n /** Current LLM call node (for adding gadget children) */\n private currentLLMCallId: string | null = null;\n\n /** Persisted expanded states (survives rebuildBlocks) */\n private expandedStates = new Map<string, boolean>();\n\n /** Track main agent LLM calls by iteration to prevent duplicates */\n private llmCallByIteration = new Map<number, string>();\n\n /** Track gadgets by invocationId to prevent duplicates */\n private gadgetByInvocationId = new Map<string, string>();\n\n /** Track nested LLM calls by parentId_iteration to prevent duplicates */\n private nestedLLMCallByKey = new Map<string, string>();\n\n constructor(container: ScrollableBox, renderCallback: () => void) {\n this.container = container;\n this.renderCallback = renderCallback;\n }\n\n // ───────────────────────────────────────────────────────────────────────────\n // Public API - Node Management\n // ───────────────────────────────────────────────────────────────────────────\n\n /**\n * Add an LLM call node (top-level or nested in gadget).\n * For main agent calls (no parent), deduplicates by iteration number.\n */\n addLLMCall(\n iteration: number,\n model: string,\n parentGadgetId?: string,\n ): string {\n // Deduplicate main agent LLM calls by iteration\n if (!parentGadgetId) {\n const existingId = this.llmCallByIteration.get(iteration);\n if (existingId) {\n // Return existing block instead of creating duplicate\n this.currentLLMCallId = existingId;\n return existingId;\n }\n } else {\n // Deduplicate nested subagent LLM calls by parent + iteration\n const nestedKey = `${parentGadgetId}_${iteration}`;\n const existingId = this.nestedLLMCallByKey.get(nestedKey);\n if (existingId) {\n // Return existing block instead of creating duplicate\n this.currentLLMCallId = existingId;\n return existingId;\n }\n }\n\n const id = this.generateId(\"llm\");\n const parentNode = parentGadgetId ? this.getNode(parentGadgetId) : undefined;\n const depth = parentNode ? parentNode.depth + 1 : 0;\n\n const node: LLMCallNode = {\n id,\n type: \"llm_call\",\n depth,\n parentId: parentGadgetId ?? null,\n iteration,\n model,\n isComplete: false,\n children: [],\n };\n\n this.nodes.set(id, node);\n\n if (parentGadgetId) {\n // Nested LLM call - add to parent gadget's children\n const parent = this.getNode(parentGadgetId) as GadgetNode;\n parent.children.push(id);\n // Track for deduplication\n const nestedKey = `${parentGadgetId}_${iteration}`;\n this.nestedLLMCallByKey.set(nestedKey, id);\n } else {\n // Top-level LLM call - track by iteration for deduplication\n this.rootIds.push(id);\n this.llmCallByIteration.set(iteration, id);\n }\n\n this.currentLLMCallId = id;\n this.rebuildBlocks();\n return id;\n }\n\n /**\n * Complete an LLM call with details and optional raw response.\n */\n completeLLMCall(\n id: string,\n details: LLMCallNode[\"details\"],\n rawResponse?: string,\n ): void {\n const node = this.getNode(id) as LLMCallNode | undefined;\n if (!node || node.type !== \"llm_call\") return;\n\n node.isComplete = true;\n node.details = details;\n if (rawResponse !== undefined) {\n node.rawResponse = rawResponse;\n }\n this.updateBlock(id);\n }\n\n /**\n * Store raw request messages for an LLM call.\n * Called when the LLM call is ready (after controller modifications).\n */\n setLLMCallRequest(\n id: string,\n messages: import(\"../../core/messages.js\").LLMMessage[],\n ): void {\n const node = this.getNode(id) as LLMCallNode | undefined;\n if (!node || node.type !== \"llm_call\") return;\n node.rawRequest = messages;\n }\n\n /**\n * Add a gadget node as a child of the current LLM call.\n *\n * Gadgets are nested under the LLM call that spawned them.\n * They appear indented and are visible when the parent is rendered.\n */\n addGadget(\n invocationId: string,\n name: string,\n parameters?: Record<string, unknown>,\n ): string {\n // Deduplicate gadgets by invocationId\n const existingId = this.gadgetByInvocationId.get(invocationId);\n if (existingId) {\n // Return existing block instead of creating duplicate\n return existingId;\n }\n\n const id = this.generateId(\"gadget\");\n const parentLLMCallId = this.currentLLMCallId;\n\n // Calculate depth based on parent\n let depth = 0;\n if (parentLLMCallId) {\n const parent = this.getNode(parentLLMCallId);\n if (parent) {\n depth = parent.depth + 1;\n }\n }\n\n const node: GadgetNode = {\n id,\n type: \"gadget\",\n depth,\n parentId: parentLLMCallId,\n invocationId,\n name,\n isComplete: false,\n parameters,\n children: [], // Used for subagent nested LLM calls\n };\n\n this.nodes.set(id, node);\n\n if (parentLLMCallId) {\n // Nest under parent LLM call\n const parent = this.getNode(parentLLMCallId) as LLMCallNode;\n parent.children.push(id);\n } else {\n // No parent LLM call - add to root\n this.rootIds.push(id);\n }\n\n // Track for deduplication\n this.gadgetByInvocationId.set(invocationId, id);\n\n this.rebuildBlocks();\n return id;\n }\n\n /**\n * Complete a gadget with result.\n */\n completeGadget(\n invocationId: string,\n result?: string,\n error?: string,\n executionTimeMs?: number,\n cost?: number,\n ): void {\n // Find gadget by invocationId\n const node = this.findGadgetByInvocationId(invocationId);\n if (!node) return;\n\n node.isComplete = true;\n node.result = result;\n node.error = error;\n node.executionTimeMs = executionTimeMs;\n node.cost = cost;\n\n // Estimate result tokens (rough: ~4 chars per token)\n if (result) {\n node.resultTokens = Math.ceil(result.length / 4);\n }\n\n // Aggregate subagent stats from child LLM call nodes\n if (node.children.length > 0) {\n node.subagentStats = this.aggregateSubagentStats(node.children);\n }\n\n this.updateBlock(node.id);\n }\n\n /**\n * Aggregate token/cost stats from child LLM call nodes.\n */\n private aggregateSubagentStats(\n childIds: string[],\n ): GadgetNode[\"subagentStats\"] {\n let inputTokens = 0;\n let outputTokens = 0;\n let cachedTokens = 0;\n let cost = 0;\n let llmCallCount = 0;\n\n for (const childId of childIds) {\n const child = this.nodes.get(childId);\n if (child?.type === \"llm_call\" && child.details) {\n inputTokens += child.details.inputTokens ?? 0;\n outputTokens += child.details.outputTokens ?? 0;\n cachedTokens += child.details.cachedInputTokens ?? 0;\n cost += child.details.cost ?? 0;\n llmCallCount++;\n }\n }\n\n return { inputTokens, outputTokens, cachedTokens, cost, llmCallCount };\n }\n\n /**\n * Add a text node (flows between LLM calls).\n */\n addText(content: string): string {\n const id = this.generateId(\"text\");\n\n const node: TextNode = {\n id,\n type: \"text\",\n depth: 0,\n parentId: null,\n content,\n children: [] as never[],\n };\n\n this.nodes.set(id, node);\n this.rootIds.push(id);\n this.rebuildBlocks();\n return id;\n }\n\n /**\n * Find a gadget node by its invocation ID.\n */\n findGadgetByInvocationId(invocationId: string): GadgetNode | undefined {\n for (const node of this.nodes.values()) {\n if (node.type === \"gadget\" && node.invocationId === invocationId) {\n return node;\n }\n }\n return undefined;\n }\n\n /**\n * Set the current LLM call context for gadget parenting.\n * Used when processing subagent events to ensure gadgets are nested\n * under the correct subagent LLM call.\n */\n setCurrentLLMCall(llmCallId: string | null): void {\n this.currentLLMCallId = llmCallId;\n }\n\n /**\n * Get the current LLM call ID.\n *\n * In tree mode, this is only used for attaching raw request/response data\n * to the block for the raw viewer feature. Parent-child relationships are\n * determined by event.parentId in handleTreeEvent(), not by this method.\n */\n getCurrentLLMCallId(): string | null {\n return this.currentLLMCallId;\n }\n\n /**\n * Check if tree subscription is active.\n * When active, external code should skip block creation (tree handles it).\n */\n isTreeSubscribed(): boolean {\n return this.treeUnsubscribe !== null;\n }\n\n /**\n * Store raw response for an LLM call (enrichment only).\n * Use this when tree handles completion but hooks have raw data.\n */\n setLLMCallResponse(id: string, rawResponse: string): void {\n const node = this.getNode(id) as LLMCallNode | undefined;\n if (!node || node.type !== \"llm_call\") return;\n node.rawResponse = rawResponse;\n }\n\n /**\n * Clear all blocks.\n */\n clear(): void {\n this.nodes.clear();\n this.blocks.clear();\n this.expandedStates.clear();\n this.llmCallByIteration.clear();\n this.gadgetByInvocationId.clear();\n this.nestedLLMCallByKey.clear();\n this.rootIds = [];\n this.selectableIds = [];\n this.selectedIndex = -1;\n this.currentLLMCallId = null;\n\n // Clear container children\n for (const child of [...this.container.children]) {\n child.detach();\n }\n this.renderCallback();\n }\n\n // ───────────────────────────────────────────────────────────────────────────\n // Public API - Selection & Navigation\n // ───────────────────────────────────────────────────────────────────────────\n\n /**\n * Move selection to the next selectable block.\n */\n selectNext(): void {\n if (this.selectableIds.length === 0) return;\n\n if (this.selectedIndex < this.selectableIds.length - 1) {\n this.selectedIndex++;\n this.updateSelection();\n }\n }\n\n /**\n * Move selection to the previous selectable block.\n */\n selectPrevious(): void {\n if (this.selectableIds.length === 0) return;\n\n if (this.selectedIndex > 0) {\n this.selectedIndex--;\n this.updateSelection();\n } else if (this.selectedIndex === -1 && this.selectableIds.length > 0) {\n // Select last if nothing selected\n this.selectedIndex = this.selectableIds.length - 1;\n this.updateSelection();\n }\n }\n\n /**\n * Select first selectable block.\n */\n selectFirst(): void {\n if (this.selectableIds.length > 0) {\n this.selectedIndex = 0;\n this.updateSelection();\n }\n }\n\n /**\n * Select last selectable block.\n */\n selectLast(): void {\n if (this.selectableIds.length > 0) {\n this.selectedIndex = this.selectableIds.length - 1;\n this.updateSelection();\n }\n }\n\n /**\n * Get currently selected block.\n */\n getSelectedBlock(): SelectableBlock | undefined {\n if (this.selectedIndex < 0 || this.selectedIndex >= this.selectableIds.length) {\n return undefined;\n }\n return this.blocks.get(this.selectableIds[this.selectedIndex]);\n }\n\n /**\n * Toggle expand/collapse of selected block.\n */\n toggleExpand(): void {\n const block = this.getSelectedBlock();\n if (!block) return;\n\n block.expanded = !block.expanded;\n // Persist expanded state across rebuilds\n this.expandedStates.set(block.node.id, block.expanded);\n this.updateBlock(block.node.id);\n }\n\n /**\n * Collapse selected block (or deselect if already collapsed).\n */\n collapseOrDeselect(): void {\n const block = this.getSelectedBlock();\n if (!block) return;\n\n if (block.expanded) {\n block.expanded = false;\n // Persist collapsed state across rebuilds\n this.expandedStates.set(block.node.id, false);\n this.updateBlock(block.node.id);\n } else {\n this.selectedIndex = -1;\n this.updateSelection();\n }\n }\n\n // ───────────────────────────────────────────────────────────────────────────\n // Private - Node & Block Management\n // ───────────────────────────────────────────────────────────────────────────\n\n private generateId(prefix: string): string {\n return `${prefix}_${++this.nodeIdCounter}`;\n }\n\n private getNode(id: string): BlockNode | undefined {\n return this.nodes.get(id);\n }\n\n /**\n * Rebuild all blocks from the node tree.\n * Called when nodes are added/removed.\n */\n private rebuildBlocks(): void {\n // Clear existing blocks\n for (const child of [...this.container.children]) {\n child.detach();\n }\n this.blocks.clear();\n this.selectableIds = [];\n\n // Track vertical position\n let top = 0;\n\n // Traverse tree in order\n for (const rootId of this.rootIds) {\n top = this.renderNodeTree(rootId, top);\n }\n\n // Restore selection if possible\n if (this.selectedIndex >= this.selectableIds.length) {\n this.selectedIndex = this.selectableIds.length - 1;\n }\n\n this.renderCallback();\n }\n\n /**\n * Render a node and its children recursively.\n * Returns the next available top position.\n */\n private renderNodeTree(nodeId: string, top: number): number {\n const node = this.getNode(nodeId);\n if (!node) return top;\n\n // Create block for this node\n const block = this.createBlock(node, top);\n this.blocks.set(nodeId, block);\n\n // Track selectable blocks\n if (block.selectable) {\n this.selectableIds.push(nodeId);\n }\n\n // Calculate height of this block\n const height = this.getBlockHeight(block);\n top += height;\n\n // Always render children (gadgets are always visible under their LLM call)\n // The expanded state controls inline details, not child visibility\n if (\"children\" in node && node.children.length > 0) {\n for (const childId of node.children) {\n top = this.renderNodeTree(childId, top);\n }\n }\n\n return top;\n }\n\n /**\n * Create a block for a node.\n */\n private createBlock(node: BlockNode, top: number): SelectableBlock {\n const isSelected = this.selectableIds.length === this.selectedIndex;\n const selectable = node.type !== \"text\";\n\n // Get persisted expanded state (survives rebuildBlocks), default to collapsed\n const expanded = this.expandedStates.get(node.id) ?? false;\n\n // Format content\n const content = this.formatBlockContent(node, isSelected, expanded);\n\n // Create Box widget\n const box = new Box({\n parent: this.container,\n top,\n left: 0,\n width: \"100%\",\n height: content.split(\"\\n\").length,\n content,\n tags: false, // We use ANSI codes directly\n });\n\n return {\n node,\n box,\n expanded,\n selectable,\n };\n }\n\n /**\n * Format block content based on type and state.\n */\n private formatBlockContent(\n node: BlockNode,\n selected: boolean,\n expanded: boolean,\n ): string {\n const indent = getIndent(node.depth);\n\n switch (node.type) {\n case \"llm_call\": {\n const collapsed = formatLLMCallCollapsed(node, selected);\n if (!expanded) {\n return indent + collapsed;\n }\n const expandedLines = formatLLMCallExpanded(node);\n const contIndent = getContinuationIndent(node.depth);\n return [\n indent + collapsed,\n ...expandedLines.map((line) => contIndent + line),\n ].join(\"\\n\");\n }\n\n case \"gadget\": {\n const collapsed = formatGadgetCollapsed(node, selected);\n if (!expanded) {\n return indent + collapsed;\n }\n const expandedLines = formatGadgetExpanded(node);\n const contIndent = getContinuationIndent(node.depth);\n return [\n indent + collapsed,\n ...expandedLines.map((line) => contIndent + line),\n ].join(\"\\n\");\n }\n\n case \"text\":\n return node.content;\n }\n }\n\n /**\n * Get the height (in lines) of a block.\n */\n private getBlockHeight(block: SelectableBlock): number {\n const content = block.box.getContent();\n return content.split(\"\\n\").length;\n }\n\n /**\n * Update a single block (after state change).\n */\n private updateBlock(nodeId: string): void {\n const block = this.blocks.get(nodeId);\n const node = this.getNode(nodeId);\n if (!block || !node) return;\n\n const isSelected = this.selectableIds[this.selectedIndex] === nodeId;\n const content = this.formatBlockContent(node, isSelected, block.expanded);\n\n const oldHeight = this.getBlockHeight(block);\n block.box.setContent(content);\n const newHeight = content.split(\"\\n\").length;\n block.box.height = newHeight;\n\n // If height changed, need to reposition subsequent blocks\n if (oldHeight !== newHeight) {\n this.repositionBlocks();\n }\n\n this.renderCallback();\n }\n\n /**\n * Update selection highlighting.\n */\n private updateSelection(): void {\n // Update all selectable blocks\n for (const id of this.selectableIds) {\n const block = this.blocks.get(id);\n if (block) {\n const isSelected = this.selectableIds[this.selectedIndex] === id;\n const content = this.formatBlockContent(block.node, isSelected, block.expanded);\n block.box.setContent(content);\n }\n }\n\n // Scroll to keep selection visible\n this.scrollToSelection();\n this.renderCallback();\n }\n\n /**\n * Reposition all blocks after height change.\n */\n private repositionBlocks(): void {\n let top = 0;\n for (const rootId of this.rootIds) {\n top = this.repositionNodeTree(rootId, top);\n }\n }\n\n private repositionNodeTree(nodeId: string, top: number): number {\n const block = this.blocks.get(nodeId);\n const node = this.getNode(nodeId);\n if (!block || !node) return top;\n\n block.box.top = top;\n const height = this.getBlockHeight(block);\n top += height;\n\n // Always traverse children (they're always visible)\n if (\"children\" in node) {\n for (const childId of node.children) {\n top = this.repositionNodeTree(childId, top);\n }\n }\n\n return top;\n }\n\n /**\n * Scroll container to keep selected block visible.\n */\n private scrollToSelection(): void {\n const block = this.getSelectedBlock();\n if (!block) return;\n\n // Skip if scroll methods not available\n if (!this.container.getScroll || !this.container.scrollTo) return;\n\n const blockTop = block.box.top as number;\n const blockHeight = this.getBlockHeight(block);\n const containerHeight = this.container.height as number;\n const scrollPos = this.container.getScroll();\n\n // If block is above visible area, scroll up\n if (blockTop < scrollPos) {\n this.container.scrollTo(blockTop);\n }\n // If block is below visible area, scroll down\n else if (blockTop + blockHeight > scrollPos + containerHeight) {\n this.container.scrollTo(blockTop + blockHeight - containerHeight);\n }\n }\n\n // ───────────────────────────────────────────────────────────────────────────\n // ExecutionTree Integration\n // ───────────────────────────────────────────────────────────────────────────\n\n /** Unsubscribe function for tree events */\n private treeUnsubscribe: (() => void) | null = null;\n\n /** Map tree node IDs to block node IDs */\n private treeNodeToBlockId = new Map<string, string>();\n\n /**\n * Subscribe to an ExecutionTree for automatic block updates.\n *\n * When subscribed, the BlockRenderer will automatically create and update\n * blocks based on tree events. This eliminates the need to manually call\n * addLLMCall(), addGadget(), etc.\n *\n * @param tree - The ExecutionTree to subscribe to\n * @returns Unsubscribe function to stop listening\n *\n * @example\n * ```typescript\n * const agent = builder.ask(\"Hello\");\n * const unsubscribe = blockRenderer.subscribeToTree(agent.getTree());\n *\n * for await (const event of agent.run()) {\n * // Blocks are automatically updated via tree subscription\n * }\n *\n * unsubscribe();\n * ```\n */\n subscribeToTree(tree: ExecutionTree): () => void {\n // Unsubscribe from previous tree if any\n if (this.treeUnsubscribe) {\n this.treeUnsubscribe();\n }\n\n this.treeNodeToBlockId.clear();\n\n // Subscribe to all events\n this.treeUnsubscribe = tree.onAll((event: ExecutionEvent) => {\n this.handleTreeEvent(event, tree);\n });\n\n return () => {\n if (this.treeUnsubscribe) {\n this.treeUnsubscribe();\n this.treeUnsubscribe = null;\n }\n };\n }\n\n /**\n * Handle an ExecutionTree event.\n */\n private handleTreeEvent(event: ExecutionEvent, _tree: ExecutionTree): void {\n switch (event.type) {\n case \"llm_call_start\": {\n // Find parent block ID if this is a nested LLM call\n let parentBlockId: string | undefined;\n if (event.parentId) {\n parentBlockId = this.treeNodeToBlockId.get(event.parentId);\n }\n\n // Create the LLM call block\n // Note: event.iteration is 0-indexed, but display uses 1-indexed\n // The hook path already adds +1, so we do the same here for deduplication\n const blockId = this.addLLMCall(\n event.iteration + 1,\n event.model,\n parentBlockId,\n );\n this.treeNodeToBlockId.set(event.nodeId, blockId);\n break;\n }\n\n case \"llm_call_complete\": {\n const blockId = this.treeNodeToBlockId.get(event.nodeId);\n if (blockId) {\n this.completeLLMCall(blockId, {\n inputTokens: event.usage?.inputTokens,\n cachedInputTokens: event.usage?.cachedInputTokens,\n outputTokens: event.usage?.outputTokens,\n cost: event.cost,\n finishReason: event.finishReason ?? undefined,\n });\n }\n break;\n }\n\n case \"gadget_call\": {\n // Find parent LLM call block\n let parentBlockId: string | undefined;\n if (event.parentId) {\n parentBlockId = this.treeNodeToBlockId.get(event.parentId);\n }\n\n // Temporarily set current LLM call for proper parenting\n const previousLLMCallId = this.currentLLMCallId;\n if (parentBlockId) {\n this.setCurrentLLMCall(parentBlockId);\n }\n\n const blockId = this.addGadget(\n event.invocationId,\n event.name,\n event.parameters,\n );\n this.treeNodeToBlockId.set(event.nodeId, blockId);\n\n // Restore previous context\n this.currentLLMCallId = previousLLMCallId;\n break;\n }\n\n case \"gadget_complete\": {\n this.completeGadget(\n event.invocationId,\n event.result,\n undefined,\n event.executionTimeMs,\n event.cost,\n );\n break;\n }\n\n case \"gadget_error\": {\n this.completeGadget(\n event.invocationId,\n undefined,\n event.error,\n event.executionTimeMs,\n );\n break;\n }\n\n case \"gadget_skipped\": {\n // Find the gadget and mark it as skipped\n const node = this.findGadgetByInvocationId(event.invocationId);\n if (node) {\n node.isComplete = true;\n node.error = `Skipped: ${event.failedDependencyError}`;\n this.updateBlock(node.id);\n }\n break;\n }\n\n // text events are handled separately (not part of tree structure)\n // llm_call_stream and llm_call_error are informational\n }\n }\n\n /**\n * Get block ID for a tree node ID.\n * Useful for external code that needs to correlate tree nodes with blocks.\n */\n getBlockIdForTreeNode(treeNodeId: string): string | undefined {\n return this.treeNodeToBlockId.get(treeNodeId);\n }\n}\n","/**\n * Block content formatters for interactive TUI blocks.\n *\n * Provides formatting for both collapsed (one-line) and expanded (multi-line)\n * views of LLM calls and gadget executions.\n *\n * @module\n */\n\nimport chalk from \"chalk\";\nimport type { LLMCallNode, GadgetNode } from \"../tui/types.js\";\nimport { formatTokens, formatCost } from \"./formatters.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Box Drawing Characters\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst BOX = {\n topLeft: \"┌\",\n topRight: \"┐\",\n bottomLeft: \"└\",\n bottomRight: \"┘\",\n horizontal: \"─\",\n vertical: \"│\",\n verticalRight: \"├\",\n verticalLeft: \"┤\",\n} as const;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Collapse/Expand Indicators\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Indicator for a collapsed block that can be expanded */\nexport const COLLAPSED_INDICATOR = \"▶\";\n/** Indicator for an expanded block */\nexport const EXPANDED_INDICATOR = \"▼\";\n/** Indicator for an in-progress item */\nexport const PROGRESS_INDICATOR = \"⏵\";\n/** Indicator for a completed item */\nexport const COMPLETE_INDICATOR = \"✓\";\n/** Indicator for an error */\nexport const ERROR_INDICATOR = \"✗\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// LLM Call Formatting\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Formats a collapsed LLM call line.\n *\n * Format: `▶ #1 claude-sonnet-4 | ↑ 10.4k | ⟳ 3.0k | ↓ 49 | 24.8s | $0.0032 | STOP`\n */\nexport function formatLLMCallCollapsed(node: LLMCallNode, selected: boolean): string {\n const indicator = node.isComplete ? COMPLETE_INDICATOR : PROGRESS_INDICATOR;\n const indicatorColor = node.isComplete ? chalk.green : chalk.blue;\n\n const parts: string[] = [];\n\n // #N model\n const callNumber = chalk.cyan(`#${node.iteration}`);\n const model = chalk.magenta(node.model);\n parts.push(`${callNumber} ${model}`);\n\n if (node.details) {\n const d = node.details;\n\n // ↑ input tokens\n if (d.inputTokens && d.inputTokens > 0) {\n parts.push(chalk.dim(\"↑\") + chalk.yellow(` ${formatTokens(d.inputTokens)}`));\n }\n\n // ⟳ cached tokens\n if (d.cachedInputTokens && d.cachedInputTokens > 0) {\n parts.push(chalk.dim(\"⟳\") + chalk.blue(` ${formatTokens(d.cachedInputTokens)}`));\n }\n\n // ↓ output tokens\n if (d.outputTokens && d.outputTokens > 0) {\n parts.push(chalk.dim(\"↓\") + chalk.green(` ${formatTokens(d.outputTokens)}`));\n }\n\n // Time\n if (d.elapsedSeconds !== undefined) {\n parts.push(chalk.dim(`${d.elapsedSeconds.toFixed(1)}s`));\n }\n\n // Cost\n if (d.cost !== undefined && d.cost > 0) {\n parts.push(chalk.cyan(`$${formatCost(d.cost)}`));\n }\n\n // Finish reason\n if (node.isComplete && d.finishReason) {\n const reason = d.finishReason.toUpperCase();\n if (reason === \"STOP\" || reason === \"END_TURN\") {\n parts.push(chalk.green(reason));\n } else {\n parts.push(chalk.yellow(reason));\n }\n }\n }\n\n const line = parts.join(chalk.dim(\" | \"));\n const prefix = indicatorColor(indicator);\n\n // Highlight selected line\n if (selected) {\n return chalk.bgBlue.white(`${prefix} ${line}`);\n }\n\n return `${prefix} ${line}`;\n}\n\n/**\n * Formats expanded LLM call details as multiple lines.\n *\n * Returns an array of lines to display below the collapsed header.\n */\nexport function formatLLMCallExpanded(node: LLMCallNode): string[] {\n const lines: string[] = [];\n const indent = \" \";\n const d = node.details;\n\n if (!d) {\n lines.push(`${indent}${chalk.dim(\"No details available\")}`);\n return lines;\n }\n\n // Calculate box width\n const width = Math.min(60, (process.stdout.columns || 80) - 4);\n const headerLine = `${BOX.topLeft}${BOX.horizontal} Details ${BOX.horizontal.repeat(width - 11)}`;\n\n lines.push(`${indent}${chalk.dim(headerLine)}`);\n\n // Model\n lines.push(`${indent}${chalk.dim(BOX.vertical)} Model: ${chalk.magenta(node.model)}`);\n\n // Input tokens with cache breakdown\n if (d.inputTokens !== undefined) {\n let inputLine = `${indent}${chalk.dim(BOX.vertical)} Input: ${chalk.yellow(formatTokens(d.inputTokens))} tokens`;\n if (d.cachedInputTokens && d.cachedInputTokens > 0) {\n const cachePercent = ((d.cachedInputTokens / d.inputTokens) * 100).toFixed(1);\n inputLine += chalk.blue(` (${formatTokens(d.cachedInputTokens)} cached, ${cachePercent}%)`);\n }\n lines.push(inputLine);\n }\n\n // Output tokens\n if (d.outputTokens !== undefined) {\n lines.push(`${indent}${chalk.dim(BOX.vertical)} Output: ${chalk.green(formatTokens(d.outputTokens))} tokens`);\n }\n\n // Context usage\n if (d.contextPercent !== undefined) {\n let contextColor = chalk.green;\n if (d.contextPercent >= 80) contextColor = chalk.red;\n else if (d.contextPercent >= 50) contextColor = chalk.yellow;\n lines.push(`${indent}${chalk.dim(BOX.vertical)} Context: ${contextColor(`${Math.round(d.contextPercent)}%`)}`);\n }\n\n // Time with tokens/second calculation\n if (d.elapsedSeconds !== undefined) {\n let timeLine = `${indent}${chalk.dim(BOX.vertical)} Time: ${chalk.dim(`${d.elapsedSeconds.toFixed(1)}s`)}`;\n if (d.outputTokens && d.elapsedSeconds > 0) {\n const tokensPerSec = Math.round(d.outputTokens / d.elapsedSeconds);\n timeLine += chalk.dim(` (${tokensPerSec} tok/s)`);\n }\n lines.push(timeLine);\n }\n\n // Cost with breakdown\n if (d.cost !== undefined && d.cost > 0) {\n lines.push(`${indent}${chalk.dim(BOX.vertical)} Cost: ${chalk.cyan(`$${formatCost(d.cost)}`)}`);\n }\n\n // Finish reason\n if (d.finishReason) {\n const reason = d.finishReason.toUpperCase();\n const reasonColor = reason === \"STOP\" || reason === \"END_TURN\" ? chalk.green : chalk.yellow;\n lines.push(`${indent}${chalk.dim(BOX.vertical)} Finish: ${reasonColor(reason)}`);\n }\n\n // Close box\n lines.push(`${indent}${chalk.dim(BOX.bottomLeft + BOX.horizontal.repeat(width - 1))}`);\n\n return lines;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Gadget Formatting\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Formats a collapsed gadget line.\n *\n * Format: `✓ Navigate(url=https://...) 1.2s | ↑ 5k ⤿ 2k ↓ 1k | $0.01`\n */\nexport function formatGadgetCollapsed(node: GadgetNode, selected: boolean): string {\n let indicator: string;\n let indicatorColor: typeof chalk;\n\n if (node.error) {\n indicator = ERROR_INDICATOR;\n indicatorColor = chalk.red;\n } else if (node.isComplete) {\n indicator = COMPLETE_INDICATOR;\n indicatorColor = chalk.green;\n } else {\n indicator = PROGRESS_INDICATOR;\n indicatorColor = chalk.blue;\n }\n\n const gadgetLabel = chalk.magenta.bold(node.name);\n\n // Format parameters inline (use available terminal width)\n let paramsStr = \"\";\n if (node.parameters && Object.keys(node.parameters).length > 0) {\n const termWidth = process.stdout.columns || 120;\n const maxParamLen = Math.max(60, termWidth - 40); // Leave room for indicator, name, time\n const entries = Object.entries(node.parameters).slice(0, 4);\n const formatted = entries.map(([key, value]) => {\n const strValue = typeof value === \"string\" ? value : JSON.stringify(value);\n const truncated = strValue.length > maxParamLen ? strValue.slice(0, maxParamLen - 3) + \"...\" : strValue;\n return `${chalk.dim(key)}=${chalk.cyan(truncated)}`;\n });\n paramsStr = `${chalk.dim(\"(\")}${formatted.join(chalk.dim(\", \"))}${chalk.dim(\")\")}`;\n }\n\n // Error preview\n let errorStr = \"\";\n if (node.error) {\n const truncated = node.error.length > 40 ? node.error.slice(0, 37) + \"...\" : node.error;\n errorStr = ` ${chalk.red(\"error:\")} ${truncated}`;\n }\n\n // Build metrics array\n const metrics: string[] = [];\n\n // Duration\n if (node.executionTimeMs !== undefined) {\n const time = node.executionTimeMs >= 1000\n ? `${(node.executionTimeMs / 1000).toFixed(1)}s`\n : `${Math.round(node.executionTimeMs)}ms`;\n metrics.push(time);\n }\n\n // Subagent token stats (if any LLM calls were made)\n if (node.subagentStats && node.subagentStats.llmCallCount > 0) {\n const { inputTokens, cachedTokens, outputTokens } = node.subagentStats;\n const tokenParts: string[] = [];\n tokenParts.push(chalk.dim(\"↑\") + chalk.yellow(` ${formatTokens(inputTokens)}`));\n if (cachedTokens > 0) {\n tokenParts.push(chalk.dim(\"⤿\") + chalk.blue(` ${formatTokens(cachedTokens)}`));\n }\n tokenParts.push(chalk.dim(\"↓\") + chalk.green(` ${formatTokens(outputTokens)}`));\n metrics.push(tokenParts.join(\" \"));\n } else if (node.resultTokens && node.resultTokens > 0) {\n // Simple gadget - just show output tokens\n metrics.push(chalk.dim(\"↓\") + chalk.green(` ${formatTokens(node.resultTokens)}`));\n }\n\n // Cost\n if (node.cost && node.cost > 0) {\n metrics.push(chalk.cyan(`$${formatCost(node.cost)}`));\n }\n\n // Join metrics with separator\n const metricsStr = metrics.length > 0 ? ` ${chalk.dim(metrics.join(\" | \"))}` : \"\";\n\n const line = `${indicatorColor(indicator)} ${gadgetLabel}${paramsStr}${errorStr}${metricsStr}`;\n\n // Highlight selected line\n if (selected) {\n return chalk.bgBlue.white(line);\n }\n\n return line;\n}\n\n/**\n * Formats expanded gadget details as multiple lines.\n *\n * Returns an array of lines to display below the collapsed header.\n */\nexport function formatGadgetExpanded(node: GadgetNode): string[] {\n const lines: string[] = [];\n const indent = \" \";\n const termWidth = process.stdout.columns || 120;\n const width = Math.max(60, termWidth - 8); // Use most of terminal width\n\n // Parameters section\n if (node.parameters && Object.keys(node.parameters).length > 0) {\n const headerLine = `${BOX.topLeft}${BOX.horizontal} Parameters ${BOX.horizontal.repeat(width - 14)}`;\n lines.push(`${indent}${chalk.dim(headerLine)}`);\n\n for (const [key, value] of Object.entries(node.parameters)) {\n const strValue = typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n // Handle multi-line values\n const valueLines = strValue.split(\"\\n\");\n const maxValueLen = width - 10; // Leave room for indent and key\n if (valueLines.length === 1) {\n const truncated = strValue.length > maxValueLen ? strValue.slice(0, maxValueLen - 3) + \"...\" : strValue;\n lines.push(`${indent}${chalk.dim(BOX.vertical)} ${chalk.dim(key)}: ${chalk.cyan(truncated)}`);\n } else {\n lines.push(`${indent}${chalk.dim(BOX.vertical)} ${chalk.dim(key)}:`);\n for (const line of valueLines.slice(0, 5)) {\n lines.push(`${indent}${chalk.dim(BOX.vertical)} ${chalk.cyan(line)}`);\n }\n if (valueLines.length > 5) {\n lines.push(`${indent}${chalk.dim(BOX.vertical)} ${chalk.dim(`... (${valueLines.length - 5} more lines)`)}`);\n }\n }\n }\n lines.push(`${indent}${chalk.dim(BOX.bottomLeft + BOX.horizontal.repeat(width - 1))}`);\n }\n\n // Result section\n if (node.result || node.error) {\n const headerText = node.error ? \" Error \" : \" Result \";\n const headerLine = `${BOX.topLeft}${BOX.horizontal}${headerText}${BOX.horizontal.repeat(width - headerText.length - 2)}`;\n lines.push(`${indent}${chalk.dim(headerLine)}`);\n\n const content = node.error || node.result || \"\";\n const contentLines = content.split(\"\\n\");\n const maxLines = 10;\n const displayLines = contentLines.slice(0, maxLines);\n\n for (const line of displayLines) {\n const truncated = line.length > width - 4 ? line.slice(0, width - 7) + \"...\" : line;\n const color = node.error ? chalk.red : chalk.white;\n lines.push(`${indent}${chalk.dim(BOX.vertical)} ${color(truncated)}`);\n }\n\n if (contentLines.length > maxLines) {\n lines.push(`${indent}${chalk.dim(BOX.vertical)} ${chalk.dim(`... (${contentLines.length - maxLines} more lines)`)}`);\n }\n\n // Execution time\n if (node.executionTimeMs !== undefined) {\n const time = node.executionTimeMs >= 1000\n ? `${(node.executionTimeMs / 1000).toFixed(1)}s`\n : `${Math.round(node.executionTimeMs)}ms`;\n lines.push(`${indent}${chalk.dim(BOX.vertical)} Time: ${chalk.dim(time)}`);\n }\n\n lines.push(`${indent}${chalk.dim(BOX.bottomLeft + BOX.horizontal.repeat(width - 1))}`);\n }\n\n // Subagent activity section\n if (node.children.length > 0) {\n const headerLine = `${BOX.topLeft}${BOX.horizontal} Subagent Activity ${BOX.horizontal.repeat(width - 21)}`;\n lines.push(`${indent}${chalk.dim(headerLine)}`);\n lines.push(`${indent}${chalk.dim(BOX.vertical)} ${chalk.dim(`${node.children.length} nested calls (expand children to see details)`)}`);\n lines.push(`${indent}${chalk.dim(BOX.bottomLeft + BOX.horizontal.repeat(width - 1))}`);\n }\n\n // Metrics section - show if any metrics are available\n if (node.executionTimeMs !== undefined || node.cost || node.resultTokens || node.subagentStats) {\n const metricsHeaderLine = `${BOX.topLeft}${BOX.horizontal} Metrics ${BOX.horizontal.repeat(width - 11)}`;\n lines.push(`${indent}${chalk.dim(metricsHeaderLine)}`);\n\n // Duration\n if (node.executionTimeMs !== undefined) {\n const time = node.executionTimeMs >= 1000\n ? `${(node.executionTimeMs / 1000).toFixed(1)}s`\n : `${Math.round(node.executionTimeMs)}ms`;\n lines.push(`${indent}${chalk.dim(BOX.vertical)} Duration: ${chalk.dim(time)}`);\n }\n\n // Output tokens (estimated from result)\n if (node.resultTokens && node.resultTokens > 0) {\n lines.push(`${indent}${chalk.dim(BOX.vertical)} Output: ${chalk.green(`~${formatTokens(node.resultTokens)}`)} tokens`);\n }\n\n // Cost\n if (node.cost && node.cost > 0) {\n lines.push(`${indent}${chalk.dim(BOX.vertical)} Cost: ${chalk.cyan(`$${formatCost(node.cost)}`)}`);\n }\n\n // Subagent stats (aggregated from child LLM calls)\n if (node.subagentStats && node.subagentStats.llmCallCount > 0) {\n const s = node.subagentStats;\n const tokenParts: string[] = [];\n tokenParts.push(chalk.dim(\"↑\") + chalk.yellow(` ${formatTokens(s.inputTokens)}`));\n if (s.cachedTokens > 0) {\n tokenParts.push(chalk.dim(\"⤿\") + chalk.blue(` ${formatTokens(s.cachedTokens)}`));\n }\n tokenParts.push(chalk.dim(\"↓\") + chalk.green(` ${formatTokens(s.outputTokens)}`));\n const tokenStr = tokenParts.join(\" \");\n lines.push(`${indent}${chalk.dim(BOX.vertical)} LLM calls: ${s.llmCallCount} (${tokenStr})`);\n }\n\n lines.push(`${indent}${chalk.dim(BOX.bottomLeft + BOX.horizontal.repeat(width - 1))}`);\n }\n\n if (lines.length === 0) {\n lines.push(`${indent}${chalk.dim(\"No details available\")}`);\n }\n\n return lines;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Indentation Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Creates indentation string based on tree depth.\n * Uses tree-style prefixes for visual hierarchy.\n */\nexport function getIndent(depth: number, isLast = false): string {\n if (depth === 0) return \"\";\n\n const baseIndent = \" \".repeat(depth - 1);\n const connector = isLast ? \"└─ \" : \"├─ \";\n return baseIndent + connector;\n}\n\n/**\n * Creates continuation indent for expanded content.\n */\nexport function getContinuationIndent(depth: number): string {\n if (depth === 0) return \"\";\n return \" \".repeat(depth) + \" \";\n}\n","/**\n * TUI approval dialog for gadget execution approvals.\n *\n * Shows a modal popup for dangerous gadgets (WriteFile, RunCommand, etc.)\n * that require user confirmation before execution.\n */\n\nimport { Box, type Screen } from \"@unblessed/node\";\nimport type { ApprovalResponse, ApprovalContext } from \"./types.js\";\n\n/** Maximum lines to show in preview */\nconst MAX_PREVIEW_LINES = 10;\n\n/** Maximum width for parameter values */\nconst MAX_PARAM_VALUE_LENGTH = 60;\n\n/**\n * Shows an approval dialog and waits for user response.\n *\n * @param screen - The blessed Screen instance\n * @param context - Approval context (gadget name, parameters, preview)\n * @returns Promise resolving to user's response\n */\nexport function showApprovalDialog(\n screen: Screen,\n context: ApprovalContext,\n): Promise<ApprovalResponse> {\n return new Promise((resolve) => {\n // Build dialog content\n const content = buildDialogContent(context);\n\n // Create modal dialog box\n const dialog = new Box({\n parent: screen,\n top: \"center\",\n left: \"center\",\n width: \"70%\",\n height: \"shrink\",\n // Content\n content,\n tags: true,\n // Visual style\n border: {\n type: \"line\",\n },\n style: {\n fg: \"white\",\n bg: \"black\",\n border: {\n fg: \"yellow\",\n },\n },\n // Padding inside border\n padding: {\n left: 1,\n right: 1,\n top: 0,\n bottom: 0,\n },\n // Ensure it's on top\n // Note: blessed doesn't have zIndex, but later-added elements render on top\n });\n\n // Focus the dialog to capture key events\n dialog.focus();\n\n // Handle key presses\n const handleKey = (ch: string, key: { name: string }) => {\n let response: ApprovalResponse | null = null;\n\n switch (key.name) {\n case \"y\":\n response = \"yes\";\n break;\n case \"n\":\n response = \"no\";\n break;\n case \"a\":\n response = \"always\";\n break;\n case \"d\":\n response = \"deny\";\n break;\n case \"escape\":\n response = \"cancel\";\n break;\n }\n\n if (response) {\n // Clean up\n dialog.destroy();\n screen.render();\n\n // Resolve with response\n resolve(response);\n }\n };\n\n dialog.on(\"keypress\", handleKey);\n screen.render();\n });\n}\n\n/**\n * Build the dialog content string.\n */\nfunction buildDialogContent(context: ApprovalContext): string {\n const lines: string[] = [];\n\n // Title\n lines.push(`{bold}{yellow-fg}Approve ${context.gadgetName}?{/}`);\n lines.push(\"\");\n\n // Parameters\n if (Object.keys(context.parameters).length > 0) {\n lines.push(\"{bold}Parameters:{/}\");\n for (const [key, value] of Object.entries(context.parameters)) {\n const valueStr = formatParamValue(value);\n lines.push(` {cyan-fg}${key}{/}: ${valueStr}`);\n }\n lines.push(\"\");\n }\n\n // Preview (if available)\n if (context.preview) {\n lines.push(\"{bold}Preview:{/}\");\n const previewLines = context.preview.split(\"\\n\").slice(0, MAX_PREVIEW_LINES);\n for (const line of previewLines) {\n lines.push(` {gray-fg}${escapeContent(line)}{/}`);\n }\n if (context.preview.split(\"\\n\").length > MAX_PREVIEW_LINES) {\n lines.push(\" {gray-fg}...{/}\");\n }\n lines.push(\"\");\n }\n\n // Options\n lines.push(\"{bold}Options:{/}\");\n lines.push(\" {green-fg}[y]{/}es - Execute this time\");\n lines.push(\" {red-fg}[n]{/}o - Skip this time\");\n lines.push(\" {blue-fg}[a]{/}lways - Always allow this gadget\");\n lines.push(\" {magenta-fg}[d]{/}eny - Always deny this gadget\");\n lines.push(\" {gray-fg}[ESC]{/} - Cancel\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format a parameter value for display.\n */\nfunction formatParamValue(value: unknown): string {\n let str: string;\n\n if (typeof value === \"string\") {\n str = value;\n } else if (value === null || value === undefined) {\n str = String(value);\n } else {\n str = JSON.stringify(value);\n }\n\n // Truncate if too long\n if (str.length > MAX_PARAM_VALUE_LENGTH) {\n str = str.slice(0, MAX_PARAM_VALUE_LENGTH - 1) + \"…\";\n }\n\n // Escape blessed tags\n return escapeContent(str);\n}\n\n/**\n * Escape content for blessed tags.\n */\nfunction escapeContent(str: string): string {\n // Escape curly braces that could be interpreted as blessed tags\n return str.replace(/\\{/g, \"{{\").replace(/\\}/g, \"}}\");\n}\n","/**\n * Full-screen raw request/response viewer for LLM calls.\n *\n * Features:\n * - Scrollable content with arrow keys, PgUp/PgDn, Home/End\n * - Message formatting with role headers\n * - Escape or \"q\" to close\n */\n\nimport { Box, type Screen } from \"@unblessed/node\";\nimport type { LLMMessage } from \"../../core/messages.js\";\n\nexport type RawViewerMode = \"request\" | \"response\";\n\ninterface RawViewerOptions {\n screen: Screen;\n mode: RawViewerMode;\n request?: LLMMessage[];\n response?: string;\n iteration: number;\n model: string;\n}\n\n// ANSI color codes\nconst RESET = \"\\x1b[0m\";\nconst BOLD = \"\\x1b[1m\";\nconst DIM = \"\\x1b[2m\";\nconst MAGENTA = \"\\x1b[35m\";\nconst GREEN = \"\\x1b[32m\";\nconst CYAN = \"\\x1b[36m\";\nconst YELLOW = \"\\x1b[33m\";\nconst WHITE = \"\\x1b[37m\";\nconst BG_BLUE = \"\\x1b[44m\";\n\n/** Return type for showRawViewer */\nexport interface RawViewerHandle {\n /** Promise that resolves when the viewer is closed */\n closed: Promise<void>;\n /** Function to programmatically close the viewer */\n close: () => void;\n}\n\n/**\n * Shows a full-screen viewer for raw LLM request or response.\n * Returns a handle with a promise and a close function.\n */\nexport function showRawViewer(options: RawViewerOptions): RawViewerHandle {\n let closeCallback: () => void = () => {};\n\n const closed = new Promise<void>((resolve) => {\n const { screen, mode, request, response, iteration, model } = options;\n\n // Format content based on mode\n let content: string;\n let title: string;\n\n if (mode === \"request\") {\n title = ` Raw Request - #${iteration} ${model} `;\n if (!request || request.length === 0) {\n content = `${DIM}No request data available${RESET}`;\n } else {\n content = formatMessages(request);\n }\n } else {\n title = ` Raw Response - #${iteration} ${model} `;\n if (!response) {\n content = `${DIM}No response data available${RESET}`;\n } else {\n content = response;\n }\n }\n\n // Create full-screen modal\n const viewer = new Box({\n parent: screen,\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%-1\", // Leave room for help bar\n scrollable: true,\n alwaysScroll: true,\n keys: true,\n vi: true,\n mouse: true,\n scrollbar: {\n ch: \" \",\n style: { bg: \"blue\" },\n },\n border: { type: \"line\" },\n label: title,\n style: {\n fg: \"white\",\n bg: \"black\",\n border: { fg: \"cyan\" },\n label: { fg: \"cyan\", bold: true },\n },\n padding: { left: 1, right: 1 },\n content,\n tags: false, // We use ANSI codes directly\n });\n\n // Add help bar at the bottom\n const helpBar = new Box({\n parent: screen,\n bottom: 0,\n left: 0,\n width: \"100%\",\n height: 1,\n content: `${DIM} [${WHITE}↑/↓/PgUp/PgDn${DIM}] Scroll [${WHITE}Home/End${DIM}] Jump [${WHITE}Escape/q${DIM}] Close${RESET}`,\n tags: false,\n style: { fg: \"white\", bg: \"black\" },\n });\n\n viewer.focus();\n\n // Handle close\n const close = () => {\n helpBar.destroy();\n viewer.destroy();\n screen.render();\n resolve();\n };\n\n // Expose close function for external use\n closeCallback = close;\n\n viewer.key([\"escape\", \"q\"], close);\n\n // Additional scroll shortcuts\n viewer.key([\"home\", \"g\"], () => {\n viewer.setScrollPerc?.(0);\n screen.render();\n });\n\n viewer.key([\"end\", \"S-g\"], () => {\n viewer.setScrollPerc?.(100);\n screen.render();\n });\n\n screen.render();\n });\n\n return { closed, close: closeCallback };\n}\n\n/**\n * Format LLM messages array for display.\n * Shows role headers and content with color coding.\n */\nfunction formatMessages(messages: LLMMessage[]): string {\n const lines: string[] = [];\n const separator = \"─\".repeat(78);\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i];\n const roleColor = getRoleColor(msg.role);\n const roleName = msg.role.toUpperCase();\n\n // Message header\n lines.push(`${DIM}${separator}${RESET}`);\n lines.push(\n `${roleColor}${BOLD}[${roleName}]${RESET} ${DIM}Message ${i + 1} of ${messages.length}${RESET}`,\n );\n lines.push(`${DIM}${separator}${RESET}`);\n lines.push(\"\");\n\n // Message content\n const contentLines = formatMessageContent(msg.content);\n lines.push(...contentLines);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format message content (handles string and multimodal content).\n */\nfunction formatMessageContent(content: string | unknown[]): string[] {\n if (typeof content === \"string\") {\n return content.split(\"\\n\");\n }\n\n if (!Array.isArray(content)) {\n return [JSON.stringify(content, null, 2)];\n }\n\n const lines: string[] = [];\n\n for (const part of content) {\n if (typeof part === \"string\") {\n lines.push(...part.split(\"\\n\"));\n } else if (isTextPart(part)) {\n lines.push(...part.text.split(\"\\n\"));\n } else if (isImagePart(part)) {\n const mediaType = part.source?.media_type || \"unknown\";\n lines.push(`${DIM}[Image: ${mediaType}]${RESET}`);\n } else if (isAudioPart(part)) {\n const mediaType = part.source?.media_type || \"unknown\";\n lines.push(`${DIM}[Audio: ${mediaType}]${RESET}`);\n } else if (isToolUsePart(part)) {\n lines.push(`${YELLOW}${BOLD}[Tool Use: ${part.name}]${RESET}`);\n lines.push(`${DIM}ID: ${part.id}${RESET}`);\n lines.push(`${DIM}Input:${RESET}`);\n const inputStr = JSON.stringify(part.input, null, 2);\n lines.push(...inputStr.split(\"\\n\").map((l) => ` ${l}`));\n } else if (isToolResultPart(part)) {\n lines.push(`${CYAN}${BOLD}[Tool Result]${RESET}`);\n lines.push(`${DIM}Tool Use ID: ${part.tool_use_id}${RESET}`);\n if (typeof part.content === \"string\") {\n lines.push(...part.content.split(\"\\n\"));\n } else {\n lines.push(JSON.stringify(part.content, null, 2));\n }\n } else {\n // Unknown part type - show as JSON\n const partType = (part as { type?: string }).type || \"unknown\";\n lines.push(`${DIM}[${partType}]${RESET}`);\n lines.push(JSON.stringify(part, null, 2));\n }\n }\n\n return lines;\n}\n\n/**\n * Get ANSI color code for a message role.\n */\nfunction getRoleColor(role: string): string {\n switch (role) {\n case \"system\":\n return MAGENTA;\n case \"user\":\n return GREEN;\n case \"assistant\":\n return CYAN;\n default:\n return WHITE;\n }\n}\n\n// Type guards for content parts\nfunction isTextPart(part: unknown): part is { type: \"text\"; text: string } {\n return (\n typeof part === \"object\" &&\n part !== null &&\n (part as { type?: string }).type === \"text\" &&\n typeof (part as { text?: unknown }).text === \"string\"\n );\n}\n\nfunction isImagePart(\n part: unknown,\n): part is { type: \"image\"; source?: { media_type?: string } } {\n return (\n typeof part === \"object\" &&\n part !== null &&\n (part as { type?: string }).type === \"image\"\n );\n}\n\nfunction isAudioPart(\n part: unknown,\n): part is { type: \"audio\"; source?: { media_type?: string } } {\n return (\n typeof part === \"object\" &&\n part !== null &&\n (part as { type?: string }).type === \"audio\"\n );\n}\n\nfunction isToolUsePart(\n part: unknown,\n): part is { type: \"tool_use\"; id: string; name: string; input: unknown } {\n return (\n typeof part === \"object\" &&\n part !== null &&\n (part as { type?: string }).type === \"tool_use\"\n );\n}\n\nfunction isToolResultPart(\n part: unknown,\n): part is { type: \"tool_result\"; tool_use_id: string; content: unknown } {\n return (\n typeof part === \"object\" &&\n part !== null &&\n (part as { type?: string }).type === \"tool_result\"\n );\n}\n","/**\n * TUI Application - Main entry point for the blessed-based terminal interface.\n *\n * Provides a complete TUI experience with:\n * - Interactive selectable/expandable blocks for LLM calls and gadgets\n * - Always-visible input field for AskUser responses\n * - Status bar showing token counts, elapsed time, and cost\n * - Modal dialogs for gadget approval\n *\n * @example\n * ```typescript\n * import { TUIApp } from './tui/index.js';\n *\n * const tui = await TUIApp.create({ model: 'claude-sonnet-4' });\n *\n * // Handle events from agent\n * for await (const event of agent.run()) {\n * tui.handleEvent(event);\n * }\n *\n * tui.destroy();\n * ```\n */\n\nimport type { Screen } from \"@unblessed/node\";\nimport type { ExecutionTree } from \"../../core/execution-tree.js\";\nimport type { StreamEvent, SubagentEvent } from \"../../gadgets/types.js\";\nimport type {\n TUIOptions,\n TUIScreenContext,\n TUIBlockLayout,\n ApprovalContext,\n ApprovalResponse,\n FocusMode,\n} from \"./types.js\";\nimport { createScreen } from \"./screen.js\";\nimport { createBlockLayout, setupBlockNavigationKeys } from \"./layout.js\";\nimport { StatusBar } from \"./status-bar.js\";\nimport { InputHandler } from \"./input-handler.js\";\nimport { BlockRenderer } from \"./block-renderer.js\";\nimport { showApprovalDialog } from \"./approval-dialog.js\";\nimport { showRawViewer, type RawViewerMode } from \"./raw-viewer.js\";\nimport type { LLMCallDisplayInfo } from \"../ui/formatters.js\";\nimport type { LLMMessage } from \"../../core/messages.js\";\n\n/** Window for double Ctrl+C detection (ms) */\nconst CTRL_C_WINDOW_MS = 1000;\n\n/**\n * Main TUI application class with interactive selectable/expandable blocks.\n *\n * Renders LLM calls and gadgets as selectable Box widgets that users\n * can navigate with up/down arrows and expand to see details.\n */\nexport class TUIApp {\n private screenCtx: TUIScreenContext;\n private layout: TUIBlockLayout;\n private statusBar: StatusBar;\n private inputHandler: InputHandler;\n private blockRenderer: BlockRenderer;\n\n /** Abort controller for cancellation */\n private abortController: AbortController | null = null;\n\n /** Last Ctrl+C timestamp for double-press detection */\n private lastCtrlC = 0;\n\n /** Callback for quit events */\n private onQuitCallback: (() => void) | null = null;\n\n /** Callback for cancel events */\n private onCancelCallback: (() => void) | null = null;\n\n /** Track current LLM call ID for gadget parenting */\n private currentLLMCallId: string | null = null;\n\n /** Track current iteration number for status bar */\n private currentIteration = 0;\n\n /** Map gadget invocationId to block renderer's internal ID */\n private gadgetIdMap = new Map<string, string>();\n\n /** Map subagent LLM call key to block renderer's internal ID */\n private subagentLLMCallMap = new Map<string, string>();\n\n /** Current focus mode (browse = navigate blocks, input = type in input field) */\n private focusMode: FocusMode = \"browse\";\n\n /** Close function for currently open raw viewer (if any) */\n private closeRawViewer: (() => void) | null = null;\n\n private constructor(\n screenCtx: TUIScreenContext,\n layout: TUIBlockLayout,\n statusBar: StatusBar,\n inputHandler: InputHandler,\n blockRenderer: BlockRenderer,\n ) {\n this.screenCtx = screenCtx;\n this.layout = layout;\n this.statusBar = statusBar;\n this.inputHandler = inputHandler;\n this.blockRenderer = blockRenderer;\n }\n\n /**\n * Create a new TUI application instance.\n */\n static async create(options: TUIOptions): Promise<TUIApp> {\n const screenCtx = createScreen({\n stdin: options.stdin,\n stdout: options.stdout,\n title: \"llmist\",\n });\n\n const { screen } = screenCtx;\n\n // Create block-based layout with ScrollableBox\n const layout = createBlockLayout(screen);\n\n // Create status bar with both debounced and immediate render callbacks\n const statusBar = new StatusBar(\n layout.statusBar,\n options.model,\n () => screenCtx.requestRender(),\n () => screenCtx.renderNow(),\n );\n\n // Create input handler with both debounced and immediate render callbacks\n // Cast ScrollableBox to Box for InputHandler compatibility\n const inputHandler = new InputHandler(\n layout.inputBar,\n layout.body as unknown as import(\"@unblessed/node\").Box,\n screen,\n () => screenCtx.requestRender(),\n () => screenCtx.renderNow(),\n );\n\n // Create block renderer\n const blockRenderer = new BlockRenderer(\n layout.body,\n () => screenCtx.requestRender(),\n );\n\n const app = new TUIApp(screenCtx, layout, statusBar, inputHandler, blockRenderer);\n\n // Set up keyboard handlers\n app.setupKeyHandlers(screen);\n\n // Wire up Ctrl+C from input handler to same quit logic\n inputHandler.onCtrlC(() => app.handleCtrlC());\n\n // Wire up Ctrl+B from input handler to toggle focus mode\n inputHandler.onCtrlB(() => app.toggleFocusMode());\n\n // Set up block navigation keys (pass focus mode getter)\n setupBlockNavigationKeys(\n screen,\n {\n onSelectNext: () => blockRenderer.selectNext(),\n onSelectPrevious: () => blockRenderer.selectPrevious(),\n onToggleExpand: () => blockRenderer.toggleExpand(),\n onCollapse: () => blockRenderer.collapseOrDeselect(),\n onSelectFirst: () => blockRenderer.selectFirst(),\n onSelectLast: () => blockRenderer.selectLast(),\n onShowRawRequest: () => app.showRawViewer(\"request\"),\n onShowRawResponse: () => app.showRawViewer(\"response\"),\n },\n () => app.focusMode,\n );\n\n // Initialize in browse mode (input bar hidden)\n app.applyFocusMode();\n\n // Initial render\n screenCtx.requestRender();\n\n return app;\n }\n\n /**\n * Set up keyboard event handlers.\n */\n private setupKeyHandlers(screen: Screen): void {\n // ESC to cancel current operation\n screen.key([\"escape\"], () => {\n if (this.inputHandler.hasPendingInput()) {\n // Don't cancel input - let user continue typing\n return;\n }\n\n // Check if a block is selected and expanded\n const selected = this.blockRenderer.getSelectedBlock();\n if (selected?.expanded) {\n // Let the block navigation handler deal with collapse\n return;\n }\n\n // Cancel current operation (streaming, etc.)\n if (this.onCancelCallback) {\n this.onCancelCallback();\n }\n\n // Abort if controller exists\n if (this.abortController && !this.abortController.signal.aborted) {\n this.abortController.abort();\n }\n });\n\n // Ctrl+C for quit (double-press)\n screen.key([\"C-c\"], () => {\n this.handleCtrlC();\n });\n\n // Ctrl+B to toggle focus mode (browse <-> input)\n screen.key([\"C-b\"], () => {\n this.toggleFocusMode();\n });\n }\n\n /**\n * Handle Ctrl+C keypress (double-press to quit).\n * This is public so it can be called from InputHandler.\n */\n handleCtrlC(): void {\n const now = Date.now();\n\n if (now - this.lastCtrlC < CTRL_C_WINDOW_MS) {\n // Second press within window - quit\n if (this.onQuitCallback) {\n this.onQuitCallback();\n }\n this.destroy();\n process.exit(130);\n } else {\n // First press - show hint and record time\n this.lastCtrlC = now;\n this.showHint(\"Press Ctrl+C again to quit\");\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Focus Mode Management\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Toggle between browse and input modes.\n * Called by Tab key handler.\n */\n toggleFocusMode(): void {\n this.focusMode = this.focusMode === \"browse\" ? \"input\" : \"browse\";\n this.applyFocusMode();\n }\n\n /**\n * Set focus mode programmatically.\n * Used by AskUser to force input mode.\n */\n setFocusMode(mode: FocusMode): void {\n if (this.focusMode !== mode) {\n this.focusMode = mode;\n this.applyFocusMode();\n }\n }\n\n /**\n * Apply current focus mode to UI components.\n * - Browse mode: Hide input bar, body takes full space minus status bar\n * - Input mode: Show input bar, body shrinks to make room\n */\n private applyFocusMode(): void {\n // Update status bar FIRST (before input gets focus, which may affect event processing)\n this.statusBar.setFocusMode(this.focusMode);\n\n // Update layout\n if (this.focusMode === \"input\") {\n // Input mode: show input bar, body height = 100%-2\n this.layout.body.height = \"100%-2\";\n } else {\n // Browse mode: hide input bar, body height = 100%-1\n this.layout.body.height = \"100%-1\";\n }\n\n // Render the layout changes\n this.screenCtx.renderNow();\n\n // Now activate/deactivate input handler (this changes focus)\n if (this.focusMode === \"input\") {\n this.inputHandler.activate();\n } else {\n this.inputHandler.deactivate();\n }\n }\n\n /**\n * Handle an agent stream event.\n * Converts events to interactive block operations.\n *\n * When tree subscription is active, only handles text events.\n * Gadgets and subagent events are handled automatically by tree.\n */\n handleEvent(event: StreamEvent): void {\n switch (event.type) {\n case \"text\":\n // Text flows as non-selectable content (tree doesn't track text)\n this.blockRenderer.addText(event.content);\n break;\n\n case \"gadget_call\": {\n // Tree handles gadget creation when subscribed\n if (this.blockRenderer.isTreeSubscribed()) break;\n\n // Legacy path: create gadget block as child of current LLM call\n const gadgetId = this.blockRenderer.addGadget(\n event.call.invocationId,\n event.call.gadgetName,\n event.call.parameters,\n );\n this.gadgetIdMap.set(event.call.invocationId, gadgetId);\n // Track in status bar\n this.statusBar.startGadget(event.call.gadgetName);\n break;\n }\n\n case \"gadget_result\":\n // Tree handles gadget completion when subscribed\n if (this.blockRenderer.isTreeSubscribed()) break;\n\n // Legacy path: complete the gadget block\n this.blockRenderer.completeGadget(\n event.result.invocationId,\n event.result.result,\n event.result.error,\n event.result.executionTimeMs,\n event.result.cost,\n );\n // Remove from status bar\n this.statusBar.endGadget(event.result.gadgetName);\n break;\n\n case \"subagent_event\":\n // Tree handles nested events automatically via parent-child relationships\n if (this.blockRenderer.isTreeSubscribed()) break;\n\n // Legacy path: handle nested events within gadgets\n this.handleSubagentEvent(event.subagentEvent);\n break;\n\n case \"stream_complete\":\n // Nothing special needed for blocks\n break;\n\n case \"human_input_required\":\n // Handled by InputHandler, not here\n break;\n\n default:\n // Other events (gadget_skipped, compaction, etc.)\n break;\n }\n }\n\n /**\n * Handle subagent events (nested LLM calls and gadgets within gadgets).\n */\n private handleSubagentEvent(subEvent: SubagentEvent): void {\n // Find the parent gadget block\n const parentGadgetId = this.gadgetIdMap.get(subEvent.gadgetInvocationId);\n if (!parentGadgetId) return;\n\n switch (subEvent.type) {\n case \"llm_call_start\": {\n // Create nested LLM call as child of the gadget\n const info = subEvent.event as import(\"../../gadgets/types.js\").LLMCallInfo;\n // Unique key: gadgetInvocationId + iteration (uses raw iteration for tracking)\n const key = `${subEvent.gadgetInvocationId}_${info.iteration}`;\n\n // Deduplicate: skip if we already have this subagent LLM call\n if (this.subagentLLMCallMap.has(key)) {\n break;\n }\n\n const llmCallId = this.blockRenderer.addLLMCall(\n info.iteration + 1, // Display as 1-indexed (consistent with main agent)\n info.model,\n parentGadgetId, // Parent is the gadget\n );\n this.subagentLLMCallMap.set(key, llmCallId);\n // Track in status bar with subagent label\n const subLabel = `#${this.currentIteration}.${info.iteration + 1}`;\n this.statusBar.startLLMCall(subLabel, info.model);\n break;\n }\n\n case \"llm_call_end\": {\n const info = subEvent.event as import(\"../../gadgets/types.js\").LLMCallInfo;\n const key = `${subEvent.gadgetInvocationId}_${info.iteration}`;\n const llmCallId = this.subagentLLMCallMap.get(key);\n if (llmCallId) {\n this.blockRenderer.completeLLMCall(llmCallId, {\n inputTokens: info.usage?.inputTokens ?? info.inputTokens,\n cachedInputTokens: info.usage?.cachedInputTokens,\n outputTokens: info.usage?.outputTokens ?? info.outputTokens,\n elapsedSeconds: info.elapsedMs ? info.elapsedMs / 1000 : undefined,\n cost: info.cost,\n finishReason: info.finishReason ?? undefined,\n });\n // Remove from status bar\n const subLabel = `#${this.currentIteration}.${info.iteration + 1}`;\n this.statusBar.endLLMCall(subLabel);\n // Accumulate subagent LLM call cost in status bar\n if (info.cost && info.cost > 0) {\n this.statusBar.addGadgetCost(info.cost);\n }\n }\n break;\n }\n\n case \"gadget_call\": {\n // Subagent gadget call - create as child of the subagent's LLM call\n const gadgetEvent = subEvent.event as { call?: { gadgetName: string; parameters: Record<string, unknown>; invocationId: string } };\n if (gadgetEvent.call) {\n // Deduplicate: skip if we already have this gadget\n if (this.gadgetIdMap.has(gadgetEvent.call.invocationId)) {\n break;\n }\n\n // Set correct LLM call context for parenting\n // Use the iteration from subagent event to find the correct subagent LLM call\n if (subEvent.iteration !== undefined) {\n const key = `${subEvent.gadgetInvocationId}_${subEvent.iteration}`;\n const subagentLLMCallId = this.subagentLLMCallMap.get(key);\n if (subagentLLMCallId) {\n this.blockRenderer.setCurrentLLMCall(subagentLLMCallId);\n }\n }\n\n const gadgetId = this.blockRenderer.addGadget(\n gadgetEvent.call.invocationId,\n gadgetEvent.call.gadgetName,\n gadgetEvent.call.parameters,\n );\n this.gadgetIdMap.set(gadgetEvent.call.invocationId, gadgetId);\n // Track in status bar\n this.statusBar.startGadget(gadgetEvent.call.gadgetName);\n }\n break;\n }\n\n case \"gadget_result\": {\n const gadgetEvent = subEvent.event as { result?: { invocationId: string; gadgetName?: string; executionTimeMs?: number; error?: string; result?: string; cost?: number } };\n if (gadgetEvent.result) {\n this.blockRenderer.completeGadget(\n gadgetEvent.result.invocationId,\n gadgetEvent.result.result,\n gadgetEvent.result.error,\n gadgetEvent.result.executionTimeMs,\n gadgetEvent.result.cost,\n );\n // Remove from status bar\n if (gadgetEvent.result.gadgetName) {\n this.statusBar.endGadget(gadgetEvent.result.gadgetName);\n }\n // Track subagent gadget cost\n if (gadgetEvent.result.cost && gadgetEvent.result.cost > 0) {\n this.statusBar.addGadgetCost(gadgetEvent.result.cost);\n }\n }\n break;\n }\n }\n }\n\n /**\n * Show an LLM call starting.\n * @param iteration - Current iteration number\n * @param model - Model name\n * @param estimatedInputTokens - Estimated input tokens for real-time display\n */\n showLLMCallStart(iteration: number, model: string, _estimatedInputTokens = 0): void {\n // Tree subscription handles block creation and activity tracking via handleTreeEvent\n // We only track IDs for raw response attachment in raw viewer\n this.currentIteration = iteration;\n this.currentLLMCallId = this.blockRenderer.getCurrentLLMCallId();\n }\n\n /**\n * Update streaming token estimates (call during streaming).\n * @param estimatedOutputTokens - Estimated output tokens so far\n */\n updateStreamingTokens(estimatedOutputTokens: number): void {\n this.statusBar.updateStreaming(estimatedOutputTokens);\n }\n\n /**\n * Show an LLM call completion.\n */\n showLLMCallComplete(info: LLMCallDisplayInfo & { rawResponse?: string }): void {\n // Tree subscription handles completion via handleTreeEvent\n // We only enrich with raw response for the raw viewer feature\n if (this.currentLLMCallId && info.rawResponse) {\n this.blockRenderer.setLLMCallResponse(this.currentLLMCallId, info.rawResponse);\n }\n }\n\n /**\n * Store raw request messages for the current LLM call.\n * Called from onLLMCallReady hook after controller modifications.\n */\n setLLMCallRequest(messages: LLMMessage[]): void {\n if (this.currentLLMCallId) {\n this.blockRenderer.setLLMCallRequest(this.currentLLMCallId, messages);\n }\n }\n\n /**\n * Show raw request or response viewer for selected LLM call.\n * Only works in browse mode when an LLM call is selected.\n * If a viewer is already open, closes it first (single-instance modal).\n */\n async showRawViewer(mode: RawViewerMode): Promise<void> {\n if (this.focusMode !== \"browse\") return;\n\n const selected = this.blockRenderer.getSelectedBlock();\n if (!selected || selected.node.type !== \"llm_call\") return;\n\n const node = selected.node as import(\"./types.js\").LLMCallNode;\n\n // Close any existing viewer first (single-instance modal pattern)\n if (this.closeRawViewer) {\n this.closeRawViewer();\n this.closeRawViewer = null;\n }\n\n const handle = showRawViewer({\n screen: this.screenCtx.screen,\n mode,\n request: node.rawRequest,\n response: node.rawResponse,\n iteration: node.iteration,\n model: node.model,\n });\n\n // Store close function for potential replacement\n this.closeRawViewer = handle.close;\n\n // Wait for viewer to close and clear the reference\n await handle.closed;\n this.closeRawViewer = null;\n }\n\n /**\n * Request user input for AskUser gadget.\n * Auto-activates input mode and restores browse mode after.\n */\n async waitForInput(question: string, gadgetName: string): Promise<string> {\n // Force input mode for AskUser\n const previousMode = this.focusMode;\n this.setFocusMode(\"input\");\n\n try {\n const result = await this.inputHandler.waitForInput(question, gadgetName);\n return result;\n } finally {\n // Restore previous mode after input\n this.setFocusMode(previousMode);\n }\n }\n\n /**\n * Wait for user to enter a new prompt (REPL mode).\n * Used between agent runs to get the next user prompt.\n * Auto-activates input mode for typing.\n */\n async waitForPrompt(): Promise<string> {\n // Force input mode for REPL prompt\n this.setFocusMode(\"input\");\n\n try {\n const result = await this.inputHandler.waitForPrompt();\n return result;\n } finally {\n // Return to browse mode after prompt is entered\n this.setFocusMode(\"browse\");\n }\n }\n\n /**\n * Show approval dialog for gadget execution.\n */\n async showApproval(context: ApprovalContext): Promise<ApprovalResponse> {\n return showApprovalDialog(this.screenCtx.screen, context);\n }\n\n /**\n * Add cost from gadget execution.\n */\n addGadgetCost(cost: number): void {\n this.statusBar.addGadgetCost(cost);\n }\n\n /** Unsubscribe function for tree subscription */\n private treeUnsubscribe: (() => void) | null = null;\n\n /**\n * Subscribe to an ExecutionTree for automatic block updates.\n *\n * When subscribed, blocks for LLM calls and gadgets are automatically\n * created and updated based on tree events. This eliminates the need\n * to manually handle subagent events via handleEvent().\n *\n * The subscription is automatically cleaned up when destroy() is called.\n *\n * @param tree - The ExecutionTree from agent.getTree()\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const agent = builder.ask(\"Hello\");\n * tui.subscribeToTree(agent.getTree());\n *\n * for await (const event of agent.run()) {\n * // LLM/gadget blocks are auto-managed via tree subscription\n * // Only handle text events manually\n * if (event.type === \"text\") {\n * tui.handleEvent(event);\n * }\n * }\n * ```\n */\n subscribeToTree(tree: ExecutionTree): () => void {\n // Unsubscribe from previous tree\n if (this.treeUnsubscribe) {\n this.treeUnsubscribe();\n }\n\n // Subscribe block renderer to tree (for block creation)\n const unsubBlock = this.blockRenderer.subscribeToTree(tree);\n\n // Subscribe status bar to tree (for activity tracking)\n const unsubStatus = this.statusBar.subscribeToTree(tree);\n\n // Combined unsubscribe\n this.treeUnsubscribe = () => {\n unsubBlock();\n unsubStatus();\n };\n\n return () => {\n if (this.treeUnsubscribe) {\n this.treeUnsubscribe();\n this.treeUnsubscribe = null;\n }\n };\n }\n\n /**\n * Get the abort signal for cancellation support.\n */\n getAbortSignal(): AbortSignal {\n if (!this.abortController) {\n this.abortController = new AbortController();\n }\n return this.abortController.signal;\n }\n\n /**\n * Reset the abort controller for a new agent run.\n * Called at the start of each REPL iteration.\n */\n resetAbort(): void {\n this.abortController = new AbortController();\n }\n\n /**\n * Check if aborted.\n */\n isAborted(): boolean {\n return this.abortController?.signal.aborted ?? false;\n }\n\n /**\n * Set callback for quit events.\n */\n onQuit(callback: () => void): void {\n this.onQuitCallback = callback;\n }\n\n /**\n * Set callback for cancel events (ESC).\n */\n onCancel(callback: () => void): void {\n this.onCancelCallback = callback;\n }\n\n /**\n * Show a temporary hint in the body.\n */\n private showHint(message: string): void {\n this.blockRenderer.addText(`\\n[${message}]\\n`);\n }\n\n /**\n * Get current metrics from status bar.\n */\n getMetrics() {\n return this.statusBar.getMetrics();\n }\n\n /**\n * Get elapsed session time in seconds.\n */\n getElapsedSeconds(): number {\n return this.statusBar.getElapsedSeconds();\n }\n\n /**\n * Flush any buffered text (no-op for block-based rendering).\n */\n flushText(): void {\n // Block-based rendering doesn't buffer text\n // Also clear activity tracking when agent run completes\n this.statusBar.clearActivity();\n }\n\n /**\n * Clean up and restore terminal.\n */\n destroy(): void {\n // Unsubscribe from tree events\n if (this.treeUnsubscribe) {\n this.treeUnsubscribe();\n this.treeUnsubscribe = null;\n }\n\n // Cancel any pending input\n this.inputHandler.cancelPending();\n\n // Destroy screen (restores terminal)\n this.screenCtx.destroy();\n }\n}\n\n// Re-export types for convenience\nexport type { TUIOptions, ApprovalContext, ApprovalResponse } from \"./types.js\";\n\n// Re-export utilities\nexport { StatusBar } from \"./status-bar.js\";\n","import type { Command } from \"commander\";\n\nimport type { ContentPart } from \"../core/input-content.js\";\nimport { text } from \"../core/input-content.js\";\nimport { LLMMessageBuilder } from \"../core/messages.js\";\nimport { resolveModel } from \"../core/model-shortcuts.js\";\nimport type { TokenUsage } from \"../core/options.js\";\nimport { FALLBACK_CHARS_PER_TOKEN } from \"../providers/constants.js\";\nimport type { CompleteConfig } from \"./config.js\";\nimport { COMMANDS } from \"./constants.js\";\nimport type { CLIEnvironment } from \"./environment.js\";\nimport { readAudioFile, readImageFile } from \"./file-utils.js\";\nimport { createSessionDir, formatLlmRequest, resolveLogDir, writeLogFile } from \"./llm-logging.js\";\nimport { addCompleteOptions, type CLICompleteOptions } from \"./option-helpers.js\";\nimport {\n executeAction,\n renderSummary,\n resolvePrompt,\n StreamPrinter,\n StreamProgress,\n} from \"./utils.js\";\n\n/**\n * Executes the complete command.\n * Streams a single LLM response without agent loop or gadgets.\n *\n * @param promptArg - User prompt from command line argument (optional if using stdin)\n * @param options - Complete command options (model, system prompt, temperature, etc.)\n * @param env - CLI environment for I/O operations\n */\nexport async function executeComplete(\n promptArg: string | undefined,\n options: CLICompleteOptions,\n env: CLIEnvironment,\n): Promise<void> {\n const prompt = await resolvePrompt(promptArg, env);\n const client = env.createClient();\n const model = resolveModel(options.model);\n\n const builder = new LLMMessageBuilder();\n if (options.system) {\n builder.addSystem(options.system);\n }\n\n // Build multimodal message if --image or --audio flags are present\n if (options.image || options.audio) {\n const parts: ContentPart[] = [text(prompt)];\n\n if (options.image) {\n parts.push(await readImageFile(options.image));\n }\n if (options.audio) {\n parts.push(await readAudioFile(options.audio));\n }\n\n builder.addUserMultimodal(parts);\n } else {\n builder.addUser(prompt);\n }\n\n const messages = builder.build();\n\n // Resolve LLM debug log directory (if enabled)\n const llmLogsBaseDir = resolveLogDir(options.logLlmRequests, \"requests\");\n let llmSessionDir: string | undefined;\n\n // Log request before streaming\n if (llmLogsBaseDir) {\n llmSessionDir = await createSessionDir(llmLogsBaseDir);\n if (llmSessionDir) {\n const filename = \"0001.request\";\n const content = formatLlmRequest(messages);\n await writeLogFile(llmSessionDir, filename, content);\n }\n }\n\n const stream = client.stream({\n model,\n messages,\n temperature: options.temperature,\n maxTokens: options.maxTokens,\n });\n\n const printer = new StreamPrinter(env.stdout);\n const stderrTTY = (env.stderr as NodeJS.WriteStream).isTTY === true;\n const progress = new StreamProgress(env.stderr, stderrTTY, client.modelRegistry);\n\n // Start call with model and estimate based on prompt length\n const estimatedInputTokens = Math.round(prompt.length / FALLBACK_CHARS_PER_TOKEN);\n progress.startCall(model, estimatedInputTokens);\n\n let finishReason: string | null | undefined;\n let usage: TokenUsage | undefined;\n let accumulatedResponse = \"\";\n\n for await (const chunk of stream) {\n // Capture actual usage from stream\n if (chunk.usage) {\n usage = chunk.usage;\n if (chunk.usage.inputTokens) {\n progress.setInputTokens(chunk.usage.inputTokens, false);\n }\n if (chunk.usage.outputTokens) {\n progress.setOutputTokens(chunk.usage.outputTokens, false);\n }\n }\n if (chunk.text) {\n progress.pause(); // Must pause to avoid stderr/stdout interleaving\n accumulatedResponse += chunk.text;\n progress.update(accumulatedResponse.length); // Update token estimate from chars\n printer.write(chunk.text);\n }\n if (chunk.finishReason !== undefined) {\n finishReason = chunk.finishReason;\n }\n }\n\n progress.endCall(usage); // Calculate cost before completing\n progress.complete();\n printer.ensureNewline();\n\n // Log response after streaming\n if (llmSessionDir) {\n const filename = \"0001.response\";\n await writeLogFile(llmSessionDir, filename, accumulatedResponse);\n }\n\n // Only show summary if stderr is a TTY (not redirected) and not in quiet mode\n if (stderrTTY && !options.quiet) {\n const summary = renderSummary({ finishReason, usage, cost: progress.getTotalCost() });\n if (summary) {\n env.stderr.write(`${summary}\\n`);\n }\n }\n}\n\n/**\n * Registers the complete command with the CLI program.\n * Configures options for model, system prompt, temperature, and max tokens.\n *\n * @param program - Commander program to register the command with\n * @param env - CLI environment for dependencies and I/O\n * @param config - Optional configuration defaults from config file\n */\nexport function registerCompleteCommand(\n program: Command,\n env: CLIEnvironment,\n config?: CompleteConfig,\n): void {\n const cmd = program\n .command(COMMANDS.complete)\n .description(\"Stream a single completion from a specified model.\")\n .argument(\"[prompt]\", \"Prompt to send to the LLM. If omitted, stdin is used when available.\");\n\n addCompleteOptions(cmd, config);\n\n cmd.action((prompt, options) =>\n executeAction(() => executeComplete(prompt, options as CLICompleteOptions, env), env),\n );\n}\n","import type { Command } from \"commander\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nimport { getConfigPath } from \"./config.js\";\nimport { COMMANDS } from \"./constants.js\";\nimport type { CLIEnvironment } from \"./environment.js\";\nimport { executeAction } from \"./utils.js\";\n\n/**\n * Options for the init command.\n * Empty for now, but structured for future extensibility (e.g., --force flag).\n */\nexport type InitCommandOptions = Record<string, never>;\n\n/**\n * Starter configuration template with helpful comments.\n * Points users to the comprehensive example for more options.\n */\nconst STARTER_CONFIG = `# ~/.llmist/cli.toml\n# llmist CLI configuration file\n#\n# This is a minimal starter config. For a comprehensive example with all options:\n# https://github.com/zbigniewsobiecki/llmist/blob/main/examples/cli.example.toml\n#\n# Key concepts:\n# - Any section can inherit from others using: inherits = \"section-name\"\n# - Prompts can use templates with Eta syntax: <%~ include(\"@prompt-name\") %>\n# - Custom sections become CLI commands: [my-command] -> llmist my-command\n\n#──────────────────────────────────────────────────────────────────────────────\n# GLOBAL OPTIONS\n# These apply to all commands. CLI flags override these settings.\n#──────────────────────────────────────────────────────────────────────────────\n[global]\n# log-level = \"info\" # silly, trace, debug, info, warn, error, fatal\n# log-file = \"/tmp/llmist.log\" # Enable file logging (JSON format)\n\n#──────────────────────────────────────────────────────────────────────────────\n# COMPLETE COMMAND DEFAULTS\n# For single LLM responses: llmist complete \"prompt\"\n# Model format: provider:model (e.g., openai:gpt-4o, anthropic:claude-sonnet-4-5)\n#──────────────────────────────────────────────────────────────────────────────\n[complete]\n# model = \"openai:gpt-4o\"\n# temperature = 0.7 # 0-2, higher = more creative\n# max-tokens = 4096 # Maximum response length\n\n#──────────────────────────────────────────────────────────────────────────────\n# AGENT COMMAND DEFAULTS\n# For tool-using agents: llmist agent \"prompt\"\n#──────────────────────────────────────────────────────────────────────────────\n[agent]\n# model = \"anthropic:claude-sonnet-4-5\"\n# max-iterations = 15 # Max tool-use loops before stopping\n# gadgets = [ # Tools the agent can use\n# \"ListDirectory\",\n# \"ReadFile\",\n# \"WriteFile\",\n# ]\n\n#──────────────────────────────────────────────────────────────────────────────\n# CUSTOM COMMANDS\n# Any other section becomes a new CLI command!\n# Uncomment below to create: llmist summarize \"your text\"\n#──────────────────────────────────────────────────────────────────────────────\n# [summarize]\n# type = \"complete\" # \"complete\" or \"agent\"\n# description = \"Summarize text concisely.\"\n# system = \"Summarize the following text in 2-3 bullet points.\"\n# temperature = 0.3\n`;\n\n/**\n * Executes the init command - creates ~/.llmist/cli.toml with a starter config.\n */\nexport async function executeInit(\n _options: InitCommandOptions,\n env: CLIEnvironment,\n): Promise<void> {\n const configPath = getConfigPath();\n const configDir = dirname(configPath);\n\n // Check if config already exists\n if (existsSync(configPath)) {\n env.stderr.write(`Configuration already exists at ${configPath}\\n`);\n env.stderr.write(\"\\n\");\n env.stderr.write(`To view it: cat ${configPath}\\n`);\n env.stderr.write(`To reset: rm ${configPath} && llmist init\\n`);\n return;\n }\n\n // Create directory if needed\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true });\n }\n\n // Write starter config\n writeFileSync(configPath, STARTER_CONFIG, \"utf-8\");\n\n // Success message with next steps\n env.stderr.write(`Created ${configPath}\\n`);\n env.stderr.write(\"\\n\");\n env.stderr.write(\"Next steps:\\n\");\n env.stderr.write(\" 1. Set your API key:\\n\");\n env.stderr.write(\" export OPENAI_API_KEY=sk-...\\n\");\n env.stderr.write(\" export ANTHROPIC_API_KEY=sk-...\\n\");\n env.stderr.write(\" export GEMINI_API_KEY=...\\n\");\n env.stderr.write(\"\\n\");\n env.stderr.write(` 2. Customize your config:\\n`);\n env.stderr.write(` $EDITOR ${configPath}\\n`);\n env.stderr.write(\"\\n\");\n env.stderr.write(\" 3. See all options:\\n\");\n env.stderr.write(\n \" https://github.com/zbigniewsobiecki/llmist/blob/main/examples/cli.example.toml\\n\",\n );\n env.stderr.write(\"\\n\");\n env.stderr.write('Try it: llmist complete \"Hello, world!\"\\n');\n}\n\n/**\n * Registers the init command with the program.\n */\nexport function registerInitCommand(program: Command, env: CLIEnvironment): void {\n program\n .command(COMMANDS.init)\n .description(\"Initialize llmist configuration at ~/.llmist/cli.toml\")\n .action((options: InitCommandOptions) => executeAction(() => executeInit(options, env), env));\n}\n","import readline from \"node:readline\";\nimport chalk from \"chalk\";\nimport type { ILogObj, Logger } from \"tslog\";\nimport { LLMist } from \"../core/client.js\";\nimport type { LoggerOptions } from \"../logging/logger.js\";\nimport { createLogger } from \"../logging/logger.js\";\nimport type { DockerConfig } from \"./docker/types.js\";\n\n/**\n * Stream type that may have TTY detection capability.\n */\nexport type TTYAwareStream = NodeJS.ReadableStream & { isTTY?: boolean };\n\n/**\n * Logger configuration for CLI commands.\n */\nexport interface CLILoggerConfig {\n logLevel?: string;\n logFile?: string;\n logReset?: boolean;\n}\n\n/**\n * Environment abstraction for CLI dependencies and I/O.\n * Allows dependency injection for testing.\n */\nexport interface CLIEnvironment {\n argv: string[];\n stdin: TTYAwareStream;\n stdout: NodeJS.WritableStream;\n stderr: NodeJS.WritableStream;\n createClient: () => LLMist;\n setExitCode: (code: number) => void;\n loggerConfig?: CLILoggerConfig;\n createLogger: (name: string) => Logger<ILogObj>;\n /** Whether stdin is a TTY (interactive terminal) */\n isTTY: boolean;\n /** Prompt the user for input (only works when isTTY is true) */\n prompt: (question: string) => Promise<string>;\n /** Docker sandboxing configuration from [docker] section */\n dockerConfig?: DockerConfig;\n}\n\nconst LOG_LEVEL_MAP: Record<string, number> = {\n silly: 0,\n trace: 1,\n debug: 2,\n info: 3,\n warn: 4,\n error: 5,\n fatal: 6,\n};\n\n/**\n * Creates a logger factory based on CLI configuration.\n * Priority: CLI options > environment variables > defaults\n */\nexport function createLoggerFactory(config?: CLILoggerConfig): (name: string) => Logger<ILogObj> {\n return (name: string) => {\n const options: LoggerOptions = { name };\n\n // CLI --log-level takes priority over LLMIST_LOG_LEVEL env var\n if (config?.logLevel) {\n const level = config.logLevel.toLowerCase();\n if (level in LOG_LEVEL_MAP) {\n options.minLevel = LOG_LEVEL_MAP[level];\n }\n }\n\n // CLI --log-reset takes priority over LLMIST_LOG_RESET env var\n if (config?.logReset !== undefined) {\n options.logReset = config.logReset;\n }\n\n // CLI --log-file takes priority over LLMIST_LOG_FILE env var\n // When log file is set via CLI, we temporarily set the env var\n // so createLogger picks it up\n if (config?.logFile) {\n const originalLogFile = process.env.LLMIST_LOG_FILE;\n process.env.LLMIST_LOG_FILE = config.logFile;\n const logger = createLogger(options);\n // Restore original (or delete if it wasn't set)\n if (originalLogFile === undefined) {\n delete process.env.LLMIST_LOG_FILE;\n } else {\n process.env.LLMIST_LOG_FILE = originalLogFile;\n }\n return logger;\n }\n\n // If no log file, default to pretty output (not hidden)\n if (!process.env.LLMIST_LOG_FILE) {\n options.type = \"pretty\";\n }\n\n return createLogger(options);\n };\n}\n\n/**\n * Creates a readline-based prompt function for user input.\n */\nfunction createPromptFunction(\n stdin: NodeJS.ReadableStream,\n stdout: NodeJS.WritableStream,\n): (question: string) => Promise<string> {\n return (question: string) => {\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: stdin,\n output: stdout,\n });\n // Display question with visual styling\n stdout.write(\"\\n\");\n stdout.write(`${chalk.cyan(\"─\".repeat(60))}\\n`);\n stdout.write(chalk.cyan.bold(\"🤖 Agent asks:\\n\"));\n stdout.write(`${question}\\n`);\n stdout.write(`${chalk.cyan(\"─\".repeat(60))}\\n`);\n rl.question(chalk.green.bold(\"You: \"), (answer) => {\n rl.close();\n resolve(answer);\n });\n });\n };\n}\n\n/**\n * Creates the default CLI environment using Node.js process globals.\n * Uses process.argv, process.stdin/stdout/stderr, and creates a new LLMist client.\n *\n * @param loggerConfig - Optional logger configuration from CLI options\n * @returns Default CLI environment\n */\nexport function createDefaultEnvironment(loggerConfig?: CLILoggerConfig): CLIEnvironment {\n const isTTY = Boolean(process.stdin.isTTY);\n\n return {\n argv: process.argv,\n stdin: process.stdin,\n stdout: process.stdout,\n stderr: process.stderr,\n createClient: () => new LLMist(),\n setExitCode: (code: number) => {\n process.exitCode = code;\n },\n loggerConfig,\n createLogger: createLoggerFactory(loggerConfig),\n isTTY,\n prompt: isTTY\n ? createPromptFunction(process.stdin, process.stdout)\n : async () => {\n throw new Error(\"Cannot prompt for input: stdin is not a TTY\");\n },\n };\n}\n","import type { Command } from \"commander\";\nimport { executeAgent } from \"./agent-command.js\";\nimport { executeComplete } from \"./complete-command.js\";\nimport type { CustomCommandConfig, GlobalSubagentConfig } from \"./config.js\";\nimport { type CLIEnvironment, type CLILoggerConfig, createLoggerFactory } from \"./environment.js\";\nimport {\n type CLIAgentOptions,\n addAgentOptions,\n addCompleteOptions,\n type CLICompleteOptions,\n configToAgentOptions,\n configToCompleteOptions,\n} from \"./option-helpers.js\";\nimport { executeAction } from \"./utils.js\";\n\n/**\n * Creates an environment with per-command logging config merged in.\n * If the command has logging options, creates a new environment; otherwise returns the original.\n */\nfunction createCommandEnvironment(\n baseEnv: CLIEnvironment,\n config: CustomCommandConfig,\n): CLIEnvironment {\n // Check if command has any logging overrides\n const hasLoggingConfig =\n config[\"log-level\"] !== undefined ||\n config[\"log-file\"] !== undefined ||\n config[\"log-reset\"] !== undefined;\n\n if (!hasLoggingConfig) {\n return baseEnv;\n }\n\n // Merge per-command logging config with base environment's config\n const loggerConfig: CLILoggerConfig = {\n logLevel: config[\"log-level\"] ?? baseEnv.loggerConfig?.logLevel,\n logFile: config[\"log-file\"] ?? baseEnv.loggerConfig?.logFile,\n logReset: config[\"log-reset\"] ?? baseEnv.loggerConfig?.logReset,\n };\n\n // Preserve all baseEnv properties, only override logging config\n return {\n ...baseEnv,\n loggerConfig,\n createLogger: createLoggerFactory(loggerConfig),\n };\n}\n\n/**\n * Registers a custom command from config file.\n *\n * Custom commands are defined in ~/.llmist/cli.toml as sections like [code-review].\n * Each section can specify `type = \"agent\"` (default) or `type = \"complete\"` to\n * determine the execution behavior.\n *\n * @param program - Commander program to register the command with\n * @param name - Command name (e.g., \"code-review\")\n * @param config - Command configuration from TOML file\n * @param env - CLI environment for I/O operations\n */\nexport function registerCustomCommand(\n program: Command,\n name: string,\n config: CustomCommandConfig,\n env: CLIEnvironment,\n globalSubagents?: GlobalSubagentConfig,\n): void {\n const type = config.type ?? \"agent\";\n const description = config.description ?? `Custom ${type} command`;\n\n const cmd = program\n .command(name)\n .description(description)\n .argument(\"[prompt]\", \"Prompt for the command. Falls back to stdin when available.\");\n\n if (type === \"complete\") {\n // Complete type command\n addCompleteOptions(cmd, config);\n\n cmd.action((prompt, cliOptions) => {\n // Create environment with per-command logging config\n const cmdEnv = createCommandEnvironment(env, config);\n return executeAction(async () => {\n // Config values are base, CLI options override\n const configDefaults = configToCompleteOptions(config);\n const options: CLICompleteOptions = {\n ...configDefaults,\n ...(cliOptions as Partial<CLICompleteOptions>),\n } as CLICompleteOptions;\n await executeComplete(prompt, options, cmdEnv);\n }, cmdEnv);\n });\n } else {\n // Agent type command (default)\n addAgentOptions(cmd, config);\n\n cmd.action((prompt, cliOptions) => {\n // Create environment with per-command logging config\n const cmdEnv = createCommandEnvironment(env, config);\n return executeAction(async () => {\n // Config values are base, CLI options override\n const configDefaults = configToAgentOptions(config);\n const options: CLIAgentOptions = {\n ...configDefaults,\n ...(cliOptions as Partial<CLIAgentOptions>),\n globalSubagents,\n } as CLIAgentOptions;\n await executeAgent(prompt, options, cmdEnv);\n }, cmdEnv);\n });\n }\n}\n","/**\n * CLI command for testing and inspecting gadgets outside the agent loop.\n * Provides `gadget run`, `gadget info`, and `gadget validate` subcommands.\n *\n * @module cli/gadget-command\n */\n\nimport chalk from \"chalk\";\nimport type { Command } from \"commander\";\n\nimport type { AbstractGadget } from \"../gadgets/gadget.js\";\nimport { schemaToJSONSchema } from \"../gadgets/schema-to-json.js\";\nimport { validateGadgetSchema } from \"../gadgets/schema-validator.js\";\n\nimport type { CLIEnvironment } from \"./environment.js\";\nimport { promptForParameters, readStdinJson } from \"./gadget-prompts.js\";\nimport { loadGadgets } from \"./gadgets.js\";\nimport { executeAction } from \"./utils.js\";\n\n/**\n * Result of selecting a gadget from a file.\n */\ninterface GadgetSelection {\n gadget: AbstractGadget;\n name: string;\n}\n\n/**\n * Options for the `gadget run` subcommand.\n */\ninterface GadgetRunOptions {\n name?: string;\n json?: boolean;\n raw?: boolean;\n}\n\n/**\n * Options for the `gadget info` subcommand.\n */\ninterface GadgetInfoOptions {\n name?: string;\n json?: boolean;\n}\n\n/**\n * Loads and selects a gadget from a file.\n * - Single gadget: returns it directly\n * - Multiple gadgets without --name: throws error listing available names\n * - Multiple gadgets with --name: finds matching gadget\n *\n * @param file - Path to gadget file\n * @param nameOption - Optional gadget name for selection\n * @param cwd - Current working directory\n * @returns Selected gadget with its name\n */\nasync function selectGadget(\n file: string,\n nameOption: string | undefined,\n cwd: string,\n): Promise<GadgetSelection> {\n const gadgets = await loadGadgets([file], cwd);\n\n if (gadgets.length === 0) {\n throw new Error(\n `No gadgets found in '${file}'.\\n` + \"Ensure the file exports a Gadget class or instance.\",\n );\n }\n\n // Single gadget - return it\n if (gadgets.length === 1) {\n const gadget = gadgets[0];\n const name = gadget.name ?? gadget.constructor.name;\n return { gadget, name };\n }\n\n // Multiple gadgets - need --name selection\n const names = gadgets.map((g) => g.name ?? g.constructor.name);\n\n if (!nameOption) {\n throw new Error(\n `File '${file}' exports ${gadgets.length} gadgets.\\n` +\n `Use --name to select one:\\n` +\n names.map((n) => ` - ${n}`).join(\"\\n\"),\n );\n }\n\n // Find by name (case-sensitive)\n const found = gadgets.find((g) => (g.name ?? g.constructor.name) === nameOption);\n\n if (!found) {\n throw new Error(\n `Gadget '${nameOption}' not found in '${file}'.\\n` +\n `Available gadgets:\\n` +\n names.map((n) => ` - ${n}`).join(\"\\n\"),\n );\n }\n\n return { gadget: found, name: nameOption };\n}\n\n/**\n * Executes the `gadget run` subcommand.\n * Loads a gadget, prompts for parameters (or reads from stdin), and executes it.\n */\nasync function executeGadgetRun(\n file: string,\n options: GadgetRunOptions,\n env: CLIEnvironment,\n): Promise<void> {\n const cwd = process.cwd();\n const { gadget, name } = await selectGadget(file, options.name, cwd);\n\n env.stderr.write(chalk.cyan.bold(`\\n🔧 Running gadget: ${name}\\n`));\n\n // Get parameters - either interactive or from stdin\n let params: Record<string, unknown>;\n\n if (env.isTTY) {\n // Interactive mode: prompt for each parameter\n params = await promptForParameters(gadget.parameterSchema, {\n stdin: env.stdin,\n stdout: env.stderr, // Prompts go to stderr to keep stdout clean\n });\n } else {\n // Non-TTY mode: read JSON from stdin\n env.stderr.write(chalk.dim(\"Reading parameters from stdin...\\n\"));\n const stdinParams = await readStdinJson(env.stdin);\n\n // Validate through Zod if schema exists\n if (gadget.parameterSchema) {\n const result = gadget.parameterSchema.safeParse(stdinParams);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid parameters:\\n${issues}`);\n }\n params = result.data as Record<string, unknown>;\n } else {\n params = stdinParams;\n }\n }\n\n env.stderr.write(chalk.dim(\"\\nExecuting...\\n\"));\n\n // Execute with timeout if configured\n const startTime = Date.now();\n let result: string;\n let cost: number | undefined;\n\n try {\n let rawResult: string | { result: string; cost?: number };\n if (gadget.timeoutMs && gadget.timeoutMs > 0) {\n rawResult = await Promise.race([\n Promise.resolve(gadget.execute(params)),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(`Gadget timed out after ${gadget.timeoutMs}ms`)),\n gadget.timeoutMs,\n ),\n ),\n ]);\n } else {\n rawResult = await Promise.resolve(gadget.execute(params));\n }\n // Normalize result: handle both string and { result, cost } return types\n result = typeof rawResult === \"string\" ? rawResult : rawResult.result;\n cost = typeof rawResult === \"object\" ? rawResult.cost : undefined;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Execution failed: ${message}`);\n }\n\n const elapsed = Date.now() - startTime;\n const costInfo = cost !== undefined && cost > 0 ? ` (Cost: $${cost.toFixed(6)})` : \"\";\n env.stderr.write(chalk.green(`\\n✓ Completed in ${elapsed}ms${costInfo}\\n\\n`));\n\n // Output result\n formatOutput(result, options, env.stdout);\n}\n\n/**\n * Formats and writes the gadget execution result to stdout.\n */\nfunction formatOutput(\n result: string,\n options: GadgetRunOptions,\n stdout: NodeJS.WritableStream,\n): void {\n // Raw mode: output as-is\n if (options.raw) {\n stdout.write(result);\n if (!result.endsWith(\"\\n\")) stdout.write(\"\\n\");\n return;\n }\n\n // JSON mode or auto-detect JSON\n if (options.json || looksLikeJson(result)) {\n try {\n const parsed = JSON.parse(result);\n stdout.write(JSON.stringify(parsed, null, 2) + \"\\n\");\n return;\n } catch {\n // Not valid JSON, output as-is\n }\n }\n\n // Default: output as-is with trailing newline\n stdout.write(result);\n if (!result.endsWith(\"\\n\")) stdout.write(\"\\n\");\n}\n\n/**\n * Checks if a string looks like JSON (starts with { or [).\n */\nfunction looksLikeJson(str: string): boolean {\n const trimmed = str.trim();\n return (\n (trimmed.startsWith(\"{\") && trimmed.endsWith(\"}\")) ||\n (trimmed.startsWith(\"[\") && trimmed.endsWith(\"]\"))\n );\n}\n\n/**\n * Executes the `gadget info` subcommand.\n * Displays gadget description, schema, and examples.\n */\nasync function executeGadgetInfo(\n file: string,\n options: GadgetInfoOptions,\n env: CLIEnvironment,\n): Promise<void> {\n const cwd = process.cwd();\n const { gadget, name } = await selectGadget(file, options.name, cwd);\n\n if (options.json) {\n // JSON output for programmatic use\n const info = buildGadgetInfo(gadget, name);\n env.stdout.write(JSON.stringify(info, null, 2) + \"\\n\");\n return;\n }\n\n // Pretty-printed output\n env.stdout.write(\"\\n\");\n env.stdout.write(chalk.cyan.bold(`${name}\\n`));\n env.stdout.write(chalk.cyan(\"═\".repeat(name.length)) + \"\\n\\n\");\n\n // Description\n env.stdout.write(chalk.bold(\"Description:\\n\"));\n env.stdout.write(` ${gadget.description}\\n\\n`);\n\n // Parameters\n if (gadget.parameterSchema) {\n env.stdout.write(chalk.bold(\"Parameters:\\n\"));\n const jsonSchema = schemaToJSONSchema(gadget.parameterSchema, { target: \"draft-7\" });\n env.stdout.write(formatSchemaAsText(jsonSchema, \" \") + \"\\n\\n\");\n } else {\n env.stdout.write(chalk.dim(\"No parameters required.\\n\\n\"));\n }\n\n // Timeout\n if (gadget.timeoutMs) {\n env.stdout.write(chalk.bold(\"Timeout:\\n\"));\n env.stdout.write(` ${gadget.timeoutMs}ms\\n\\n`);\n }\n\n // Examples\n if (gadget.examples && gadget.examples.length > 0) {\n env.stdout.write(chalk.bold(\"Examples:\\n\"));\n for (const example of gadget.examples) {\n if (example.comment) {\n env.stdout.write(chalk.dim(` # ${example.comment}\\n`));\n }\n env.stdout.write(` Input: ${chalk.cyan(JSON.stringify(example.params))}\\n`);\n if (example.output !== undefined) {\n env.stdout.write(` Output: ${chalk.green(example.output)}\\n`);\n }\n env.stdout.write(\"\\n\");\n }\n }\n}\n\n/**\n * Builds a JSON-serializable info object for a gadget.\n */\nfunction buildGadgetInfo(gadget: AbstractGadget, name: string): Record<string, unknown> {\n const info: Record<string, unknown> = {\n name,\n description: gadget.description,\n };\n\n if (gadget.parameterSchema) {\n info.schema = schemaToJSONSchema(gadget.parameterSchema, { target: \"draft-7\" });\n }\n\n if (gadget.timeoutMs) {\n info.timeoutMs = gadget.timeoutMs;\n }\n\n if (gadget.examples && gadget.examples.length > 0) {\n info.examples = gadget.examples;\n }\n\n return info;\n}\n\n/**\n * Formats a JSON Schema as readable text with indentation.\n */\nfunction formatSchemaAsText(schema: Record<string, unknown>, indent = \"\"): string {\n const lines: string[] = [];\n const properties = (schema.properties || {}) as Record<string, Record<string, unknown>>;\n const required = (schema.required || []) as string[];\n\n for (const [key, prop] of Object.entries(properties)) {\n const type = prop.type as string;\n const description = prop.description as string | undefined;\n const isRequired = required.includes(key);\n const enumValues = prop.enum as string[] | undefined;\n const defaultValue = prop.default;\n\n // Build the line\n let line = `${indent}${chalk.cyan(key)}`;\n\n // Required marker\n if (isRequired) {\n line += chalk.red(\"*\");\n }\n\n // Type info\n if (type === \"array\") {\n const items = prop.items as Record<string, unknown> | undefined;\n const itemType = items?.type || \"any\";\n line += chalk.dim(` (${itemType}[])`);\n } else if (type === \"object\" && prop.properties) {\n line += chalk.dim(\" (object)\");\n } else {\n line += chalk.dim(` (${type})`);\n }\n\n // Default value\n if (defaultValue !== undefined) {\n line += chalk.dim(` [default: ${JSON.stringify(defaultValue)}]`);\n }\n\n // Description\n if (description) {\n line += `: ${description}`;\n }\n\n // Enum values\n if (enumValues) {\n line += chalk.yellow(` - one of: ${enumValues.join(\", \")}`);\n }\n\n lines.push(line);\n\n // Recurse for nested objects\n if (type === \"object\" && prop.properties) {\n lines.push(formatSchemaAsText(prop, indent + \" \"));\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Executes the `gadget validate` subcommand.\n * Checks if a file exports valid gadget(s).\n */\nasync function executeGadgetValidate(file: string, env: CLIEnvironment): Promise<void> {\n const cwd = process.cwd();\n\n try {\n const gadgets = await loadGadgets([file], cwd);\n\n if (gadgets.length === 0) {\n throw new Error(\n \"No gadgets exported from file.\\n\" +\n \"A valid gadget must have:\\n\" +\n \" - execute() method\\n\" +\n \" - description property\\n\" +\n \" - parameterSchema (optional)\",\n );\n }\n\n // Validate each gadget's structure and schema\n const issues: string[] = [];\n\n for (const gadget of gadgets) {\n const name = gadget.name ?? gadget.constructor.name;\n\n // Check required fields\n if (!gadget.description) {\n issues.push(`${name}: Missing 'description' property.`);\n }\n\n // Validate schema if present\n if (gadget.parameterSchema) {\n try {\n validateGadgetSchema(gadget.parameterSchema, name);\n } catch (schemaError) {\n const message = schemaError instanceof Error ? schemaError.message : String(schemaError);\n issues.push(`${name}: ${message}`);\n }\n }\n\n // Check execute method\n if (typeof gadget.execute !== \"function\") {\n issues.push(`${name}: Missing 'execute()' method.`);\n }\n }\n\n if (issues.length > 0) {\n throw new Error(`Validation issues:\\n${issues.map((i) => ` - ${i}`).join(\"\\n\")}`);\n }\n\n // Success output\n env.stdout.write(chalk.green.bold(\"\\n✓ Valid\\n\\n\"));\n env.stdout.write(chalk.bold(\"Gadgets found:\\n\"));\n\n for (const gadget of gadgets) {\n const name = gadget.name ?? gadget.constructor.name;\n const schemaInfo = gadget.parameterSchema\n ? chalk.cyan(\"(with schema)\")\n : chalk.dim(\"(no schema)\");\n env.stdout.write(` ${chalk.bold(name)} ${schemaInfo}\\n`);\n env.stdout.write(chalk.dim(` ${gadget.description}\\n`));\n }\n\n env.stdout.write(\"\\n\");\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n env.stdout.write(chalk.red.bold(`\\n✗ Invalid\\n\\n`));\n env.stdout.write(`${message}\\n\\n`);\n env.setExitCode(1);\n }\n}\n\n/**\n * Registers the `gadget` command group with run/info/validate subcommands.\n *\n * @param program - Commander program to register on\n * @param env - CLI environment for I/O\n */\nexport function registerGadgetCommand(program: Command, env: CLIEnvironment): void {\n const gadgetCmd = program\n .command(\"gadget\")\n .description(\"Test and inspect gadgets outside the agent loop.\");\n\n // Subcommand: run\n gadgetCmd\n .command(\"run <file>\")\n .description(\"Execute a gadget with interactive prompts or stdin JSON.\")\n .option(\"--name <gadget>\", \"Select gadget by name (required if file exports multiple)\")\n .option(\"--json\", \"Format output as pretty-printed JSON\")\n .option(\"--raw\", \"Output result as raw string without formatting\")\n .action((file: string, options: GadgetRunOptions) =>\n executeAction(() => executeGadgetRun(file, options, env), env),\n );\n\n // Subcommand: info\n gadgetCmd\n .command(\"info <file>\")\n .description(\"Display gadget description, schema, and examples.\")\n .option(\"--name <gadget>\", \"Select gadget by name (required if file exports multiple)\")\n .option(\"--json\", \"Output as JSON instead of formatted text\")\n .action((file: string, options: GadgetInfoOptions) =>\n executeAction(() => executeGadgetInfo(file, options, env), env),\n );\n\n // Subcommand: validate\n gadgetCmd\n .command(\"validate <file>\")\n .description(\"Check if file exports valid gadget(s).\")\n .action((file: string) => executeAction(() => executeGadgetValidate(file, env), env));\n}\n","/**\n * Interactive prompts for schema-driven gadget parameter input.\n * Converts Zod schemas to JSON Schema for introspection and prompts\n * users for each parameter with type hints, descriptions, and defaults.\n *\n * @module cli/gadget-prompts\n */\n\nimport { createInterface } from \"node:readline/promises\";\nimport chalk from \"chalk\";\nimport type { ZodTypeAny } from \"zod\";\n\nimport { schemaToJSONSchema } from \"../gadgets/schema-to-json.js\";\n\n/**\n * Context for interactive prompting.\n */\nexport interface PromptContext {\n stdin: NodeJS.ReadableStream;\n stdout: NodeJS.WritableStream;\n}\n\n/**\n * JSON Schema property representation for a single field.\n */\ninterface JsonSchemaProperty {\n type?: string;\n description?: string;\n enum?: string[];\n default?: unknown;\n items?: { type?: string; enum?: string[] };\n properties?: Record<string, JsonSchemaProperty>;\n required?: string[];\n}\n\n/**\n * Prompts user for parameter values based on Zod schema.\n * Displays type hints, descriptions, and defaults for each field.\n * Returns validated and transformed parameters.\n *\n * @param schema - Zod schema describing expected parameters\n * @param ctx - I/O context for prompts\n * @returns Object containing user-provided parameter values\n */\nexport async function promptForParameters(\n schema: ZodTypeAny | undefined,\n ctx: PromptContext,\n): Promise<Record<string, unknown>> {\n if (!schema) {\n return {}; // No parameters required\n }\n\n const jsonSchema = schemaToJSONSchema(schema, { target: \"draft-7\" }) as {\n properties?: Record<string, JsonSchemaProperty>;\n required?: string[];\n };\n\n if (!jsonSchema.properties || Object.keys(jsonSchema.properties).length === 0) {\n return {};\n }\n\n const rl = createInterface({ input: ctx.stdin, output: ctx.stdout });\n const params: Record<string, unknown> = {};\n\n try {\n for (const [key, prop] of Object.entries(jsonSchema.properties)) {\n const value = await promptForField(rl, key, prop, jsonSchema.required ?? []);\n if (value !== undefined) {\n params[key] = value;\n }\n }\n } finally {\n rl.close();\n }\n\n // Validate and apply defaults/transforms through Zod\n const result = schema.safeParse(params);\n if (!result.success) {\n const issues = result.error.issues.map((i) => ` ${i.path.join(\".\")}: ${i.message}`).join(\"\\n\");\n throw new Error(`Invalid parameters:\\n${issues}`);\n }\n\n return result.data as Record<string, unknown>;\n}\n\n/**\n * Prompts for a single field value with type-aware formatting.\n */\nasync function promptForField(\n rl: ReturnType<typeof createInterface>,\n key: string,\n prop: JsonSchemaProperty,\n required: string[],\n): Promise<unknown> {\n const isRequired = required.includes(key);\n const typeHint = formatTypeHint(prop);\n const defaultHint =\n prop.default !== undefined ? chalk.dim(` [default: ${JSON.stringify(prop.default)}]`) : \"\";\n const requiredMarker = isRequired ? chalk.red(\"*\") : \"\";\n\n // Build prompt with description\n let prompt = `\\n${chalk.cyan.bold(key)}${requiredMarker}`;\n if (prop.description) {\n prompt += chalk.dim(` - ${prop.description}`);\n }\n prompt += `\\n ${typeHint}${defaultHint}\\n ${chalk.green(\">\")} `;\n\n const answer = await rl.question(prompt);\n const trimmed = answer.trim();\n\n // Handle empty input\n if (!trimmed) {\n if (prop.default !== undefined) {\n return undefined; // Let Zod apply default\n }\n if (!isRequired) {\n return undefined; // Optional field, skip\n }\n throw new Error(`Parameter '${key}' is required.`);\n }\n\n // Parse based on type\n return parseValue(trimmed, prop, key);\n}\n\n/**\n * Formats the type hint for display (e.g., \"(number)\", \"(add | subtract)\").\n */\nfunction formatTypeHint(prop: JsonSchemaProperty): string {\n // Enum types: show allowed values\n if (prop.enum) {\n return chalk.yellow(`(${prop.enum.join(\" | \")})`);\n }\n\n // Array types: show item type\n if (prop.type === \"array\") {\n const items = prop.items;\n if (items?.enum) {\n return chalk.yellow(`(${items.enum.join(\" | \")})[] comma-separated`);\n }\n const itemType = items?.type ?? \"any\";\n return chalk.yellow(`(${itemType}[]) comma-separated`);\n }\n\n // Object types: indicate nested structure\n if (prop.type === \"object\" && prop.properties) {\n return chalk.yellow(\"(object) enter as JSON\");\n }\n\n // Simple types\n return chalk.yellow(`(${prop.type ?? \"any\"})`);\n}\n\n/**\n * Parses a string value into the appropriate type based on schema.\n */\nfunction parseValue(input: string, prop: JsonSchemaProperty, key: string): unknown {\n const type = prop.type;\n\n // Numbers\n if (type === \"number\" || type === \"integer\") {\n const num = Number(input);\n if (Number.isNaN(num)) {\n throw new Error(`Invalid number for '${key}': ${input}`);\n }\n if (type === \"integer\" && !Number.isInteger(num)) {\n throw new Error(`Expected integer for '${key}', got: ${input}`);\n }\n return num;\n }\n\n // Booleans\n if (type === \"boolean\") {\n const lower = input.toLowerCase();\n if ([\"true\", \"yes\", \"1\", \"y\"].includes(lower)) return true;\n if ([\"false\", \"no\", \"0\", \"n\"].includes(lower)) return false;\n throw new Error(`Invalid boolean for '${key}': ${input} (use true/false, yes/no, 1/0)`);\n }\n\n // Arrays (comma-separated)\n if (type === \"array\") {\n const items = input\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n const itemType = prop.items?.type;\n\n // Convert array items to appropriate type\n if (itemType === \"number\" || itemType === \"integer\") {\n return items.map((item) => {\n const num = Number(item);\n if (Number.isNaN(num)) throw new Error(`Invalid number in '${key}' array: ${item}`);\n return num;\n });\n }\n if (itemType === \"boolean\") {\n return items.map((item) => {\n const lower = item.toLowerCase();\n if ([\"true\", \"yes\", \"1\", \"y\"].includes(lower)) return true;\n if ([\"false\", \"no\", \"0\", \"n\"].includes(lower)) return false;\n throw new Error(`Invalid boolean in '${key}' array: ${item}`);\n });\n }\n return items; // String array\n }\n\n // Objects (parse as JSON)\n if (type === \"object\") {\n try {\n return JSON.parse(input);\n } catch {\n throw new Error(`Invalid JSON for '${key}': ${input}`);\n }\n }\n\n // String (default) - also handles enums which are validated by Zod\n return input;\n}\n\n/**\n * Reads JSON parameters from stdin (for non-TTY piped input).\n *\n * @param stdin - Readable stream to read from\n * @returns Parsed JSON object\n */\nexport async function readStdinJson(\n stdin: NodeJS.ReadableStream,\n): Promise<Record<string, unknown>> {\n const chunks: string[] = [];\n\n for await (const chunk of stdin) {\n if (typeof chunk === \"string\") {\n chunks.push(chunk);\n } else {\n chunks.push(chunk.toString(\"utf8\"));\n }\n }\n\n const content = chunks.join(\"\").trim();\n\n if (!content) {\n return {}; // Empty stdin, use defaults\n }\n\n try {\n const parsed = JSON.parse(content);\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw new Error(\"Stdin must contain a JSON object, not an array or primitive.\");\n }\n return parsed as Record<string, unknown>;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(`Invalid JSON from stdin: ${error.message}`);\n }\n throw error;\n }\n}\n","import { writeFileSync } from \"node:fs\";\nimport type { Command } from \"commander\";\n\nimport type { ImageConfig } from \"./config.js\";\nimport { COMMANDS, OPTION_DESCRIPTIONS, OPTION_FLAGS, SUMMARY_PREFIX } from \"./constants.js\";\nimport type { CLIEnvironment } from \"./environment.js\";\nimport { formatCost } from \"./ui/formatters.js\";\nimport { executeAction, resolvePrompt } from \"./utils.js\";\n\n/**\n * Default image generation model.\n */\nconst DEFAULT_IMAGE_MODEL = \"dall-e-3\";\n\n/**\n * Options for the image command.\n */\nexport interface ImageCommandOptions {\n model: string;\n size?: string;\n quality?: string;\n count?: string;\n output?: string;\n quiet?: boolean;\n}\n\n/**\n * Executes the image command.\n * Generates images from a text prompt using the specified model.\n *\n * @param promptArg - Prompt from command line argument (optional if using stdin)\n * @param options - Image command options\n * @param env - CLI environment for I/O operations\n */\nexport async function executeImage(\n promptArg: string | undefined,\n options: ImageCommandOptions,\n env: CLIEnvironment,\n): Promise<void> {\n const prompt = await resolvePrompt(promptArg, env);\n const client = env.createClient();\n\n const model = options.model;\n const n = options.count ? Number.parseInt(options.count, 10) : 1;\n\n const stderrTTY = (env.stderr as NodeJS.WriteStream).isTTY === true;\n\n if (!options.quiet && stderrTTY) {\n env.stderr.write(`${SUMMARY_PREFIX} Generating image with ${model}...\\n`);\n }\n\n const result = await client.image.generate({\n model,\n prompt,\n size: options.size,\n quality: options.quality,\n n,\n responseFormat: options.output ? \"b64_json\" : \"url\",\n });\n\n // Handle output\n if (options.output) {\n // Save to file\n const imageData = result.images[0];\n if (imageData.b64Json) {\n const buffer = Buffer.from(imageData.b64Json, \"base64\");\n writeFileSync(options.output, buffer);\n if (!options.quiet) {\n env.stderr.write(`${SUMMARY_PREFIX} Image saved to ${options.output}\\n`);\n }\n } else if (imageData.url) {\n // If we got URL but requested file, write the URL\n env.stdout.write(`${imageData.url}\\n`);\n }\n } else {\n // Output URLs to stdout\n for (const image of result.images) {\n if (image.url) {\n env.stdout.write(`${image.url}\\n`);\n } else if (image.b64Json) {\n // For base64, output the raw data (can be piped to file)\n env.stdout.write(image.b64Json);\n }\n }\n }\n\n // Show summary\n if (!options.quiet && stderrTTY) {\n const parts = [\n `${result.images.length} image(s)`,\n `size: ${result.usage.size}`,\n `quality: ${result.usage.quality}`,\n ];\n if (result.cost !== undefined) {\n parts.push(`cost: ${formatCost(result.cost)}`);\n }\n env.stderr.write(`${SUMMARY_PREFIX} ${parts.join(\" | \")}\\n`);\n }\n}\n\n/**\n * Registers the image command with the CLI program.\n *\n * @param program - Commander program to register the command with\n * @param env - CLI environment for dependencies and I/O\n * @param config - Optional configuration defaults from config file\n */\nexport function registerImageCommand(\n program: Command,\n env: CLIEnvironment,\n config?: ImageConfig,\n): void {\n program\n .command(COMMANDS.image)\n .description(\"Generate images from a text prompt.\")\n .argument(\"[prompt]\", \"Image generation prompt. If omitted, stdin is used when available.\")\n .option(OPTION_FLAGS.model, OPTION_DESCRIPTIONS.model, config?.model ?? DEFAULT_IMAGE_MODEL)\n .option(OPTION_FLAGS.imageSize, OPTION_DESCRIPTIONS.imageSize, config?.size)\n .option(OPTION_FLAGS.imageQuality, OPTION_DESCRIPTIONS.imageQuality, config?.quality)\n .option(OPTION_FLAGS.imageCount, OPTION_DESCRIPTIONS.imageCount, config?.count?.toString())\n .option(OPTION_FLAGS.imageOutput, OPTION_DESCRIPTIONS.imageOutput, config?.output)\n .option(OPTION_FLAGS.quiet, OPTION_DESCRIPTIONS.quiet, config?.quiet ?? false)\n .action((prompt, options) =>\n executeAction(() => executeImage(prompt, options as ImageCommandOptions, env), env),\n );\n}\n","import chalk from \"chalk\";\nimport type { Command } from \"commander\";\nimport type { ImageModelSpec, SpeechModelSpec } from \"../core/media-types.js\";\nimport type { ModelSpec } from \"../core/model-catalog.js\";\nimport { MODEL_ALIASES } from \"../core/model-shortcuts.js\";\nimport { COMMANDS } from \"./constants.js\";\nimport type { CLIEnvironment } from \"./environment.js\";\nimport { executeAction } from \"./utils.js\";\n\ninterface ModelsCommandOptions {\n provider?: string;\n format?: \"table\" | \"json\";\n verbose?: boolean;\n text?: boolean;\n image?: boolean;\n speech?: boolean;\n all?: boolean;\n}\n\nasync function handleModelsCommand(\n options: ModelsCommandOptions,\n env: CLIEnvironment,\n): Promise<void> {\n const client = env.createClient();\n\n // Determine which model types to show\n // Default: text models if no specific flag is set\n const showText = options.all || options.text || (!options.image && !options.speech);\n const showImage = options.all || options.image;\n const showSpeech = options.all || options.speech;\n\n // Collect models\n const textModels = showText ? client.modelRegistry.listModels(options.provider) : [];\n const imageModels = showImage\n ? client.image.listModels().filter((m) => !options.provider || m.provider === options.provider)\n : [];\n const speechModels = showSpeech\n ? client.speech.listModels().filter((m) => !options.provider || m.provider === options.provider)\n : [];\n\n if (options.format === \"json\") {\n renderJSON(textModels, imageModels, speechModels, env.stdout);\n } else {\n renderAllTables(textModels, imageModels, speechModels, options.verbose || false, env.stdout);\n }\n}\n\n/**\n * Main rendering orchestrator for all model types.\n */\nfunction renderAllTables(\n textModels: ModelSpec[],\n imageModels: ImageModelSpec[],\n speechModels: SpeechModelSpec[],\n verbose: boolean,\n stream: NodeJS.WritableStream,\n): void {\n const hasAnyModels = textModels.length > 0 || imageModels.length > 0 || speechModels.length > 0;\n\n if (!hasAnyModels) {\n stream.write(chalk.yellow(\"\\nNo models found matching the specified criteria.\\n\\n\"));\n return;\n }\n\n stream.write(chalk.bold.cyan(\"\\nAvailable Models\\n\"));\n stream.write(chalk.cyan(\"=\".repeat(80)) + \"\\n\\n\");\n\n // Text models\n if (textModels.length > 0) {\n renderTextTable(textModels, verbose, stream);\n }\n\n // Image models\n if (imageModels.length > 0) {\n renderImageTable(imageModels, verbose, stream);\n }\n\n // Speech models\n if (speechModels.length > 0) {\n renderSpeechTable(speechModels, verbose, stream);\n }\n\n // Display shortcuts (only if showing text models)\n if (textModels.length > 0) {\n stream.write(chalk.bold.magenta(\"Model Shortcuts\\n\"));\n stream.write(chalk.dim(\"─\".repeat(80)) + \"\\n\");\n\n const shortcuts = Object.entries(MODEL_ALIASES).sort((a, b) => a[0].localeCompare(b[0]));\n for (const [shortcut, fullName] of shortcuts) {\n stream.write(\n chalk.cyan(` ${shortcut.padEnd(15)}`) + chalk.dim(\" → \") + chalk.white(fullName) + \"\\n\",\n );\n }\n stream.write(\"\\n\");\n }\n}\n\n/**\n * Render text/LLM models grouped by provider.\n */\nfunction renderTextTable(\n models: ModelSpec[],\n verbose: boolean,\n stream: NodeJS.WritableStream,\n): void {\n // Group models by provider\n const grouped = new Map<string, ModelSpec[]>();\n for (const model of models) {\n const provider = model.provider;\n if (!grouped.has(provider)) {\n grouped.set(provider, []);\n }\n grouped.get(provider)!.push(model);\n }\n\n stream.write(chalk.bold.blue(\"📝 Text/LLM Models\\n\"));\n stream.write(chalk.dim(\"─\".repeat(80)) + \"\\n\\n\");\n\n // Display each provider's models\n const providers = Array.from(grouped.keys()).sort();\n for (const provider of providers) {\n const providerModels = grouped.get(provider)!;\n const providerName = provider.charAt(0).toUpperCase() + provider.slice(1);\n\n stream.write(chalk.bold.yellow(`${providerName}\\n`));\n\n if (verbose) {\n renderVerboseTable(providerModels, stream);\n } else {\n renderCompactTable(providerModels, stream);\n }\n\n stream.write(\"\\n\");\n }\n}\n\nfunction renderCompactTable(models: ModelSpec[], stream: NodeJS.WritableStream): void {\n // Column widths\n const idWidth = 25;\n const nameWidth = 22;\n const contextWidth = 13;\n const inputWidth = 10;\n const outputWidth = 10;\n\n // Header\n stream.write(\n chalk.dim(\"─\".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + \"\\n\",\n );\n stream.write(\n chalk.bold(\n \"Model ID\".padEnd(idWidth) +\n \" \" +\n \"Display Name\".padEnd(nameWidth) +\n \" \" +\n \"Context\".padEnd(contextWidth) +\n \" \" +\n \"Input\".padEnd(inputWidth) +\n \" \" +\n \"Output\".padEnd(outputWidth),\n ) + \"\\n\",\n );\n stream.write(\n chalk.dim(\"─\".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + \"\\n\",\n );\n\n // Rows\n for (const model of models) {\n const contextFormatted = formatTokens(model.contextWindow);\n const inputPrice = `$${model.pricing.input.toFixed(2)}`;\n const outputPrice = `$${model.pricing.output.toFixed(2)}`;\n\n stream.write(\n chalk.green(model.modelId.padEnd(idWidth)) +\n \" \" +\n chalk.white(model.displayName.padEnd(nameWidth)) +\n \" \" +\n chalk.yellow(contextFormatted.padEnd(contextWidth)) +\n \" \" +\n chalk.cyan(inputPrice.padEnd(inputWidth)) +\n \" \" +\n chalk.cyan(outputPrice.padEnd(outputWidth)) +\n \"\\n\",\n );\n }\n\n stream.write(\n chalk.dim(\"─\".repeat(idWidth + nameWidth + contextWidth + inputWidth + outputWidth + 8)) + \"\\n\",\n );\n stream.write(chalk.dim(` * Prices are per 1M tokens\\n`));\n}\n\nfunction renderVerboseTable(models: ModelSpec[], stream: NodeJS.WritableStream): void {\n for (const model of models) {\n stream.write(chalk.bold.green(`\\n ${model.modelId}\\n`));\n stream.write(chalk.dim(\" \" + \"─\".repeat(60)) + \"\\n\");\n stream.write(` ${chalk.dim(\"Name:\")} ${chalk.white(model.displayName)}\\n`);\n stream.write(\n ` ${chalk.dim(\"Context:\")} ${chalk.yellow(formatTokens(model.contextWindow))}\\n`,\n );\n stream.write(\n ` ${chalk.dim(\"Max Output:\")} ${chalk.yellow(formatTokens(model.maxOutputTokens))}\\n`,\n );\n stream.write(\n ` ${chalk.dim(\"Pricing:\")} ${chalk.cyan(`$${model.pricing.input.toFixed(2)} input`)} ${chalk.dim(\"/\")} ${chalk.cyan(`$${model.pricing.output.toFixed(2)} output`)} ${chalk.dim(\"(per 1M tokens)\")}\\n`,\n );\n\n if (model.pricing.cachedInput !== undefined) {\n stream.write(\n ` ${chalk.dim(\"Cached Input:\")} ${chalk.cyan(`$${model.pricing.cachedInput.toFixed(2)} per 1M tokens`)}\\n`,\n );\n }\n\n if (model.knowledgeCutoff) {\n stream.write(` ${chalk.dim(\"Knowledge:\")} ${model.knowledgeCutoff}\\n`);\n }\n\n // Features\n const features: string[] = [];\n if (model.features.streaming) features.push(\"streaming\");\n if (model.features.functionCalling) features.push(\"function-calling\");\n if (model.features.vision) features.push(\"vision\");\n if (model.features.reasoning) features.push(\"reasoning\");\n if (model.features.structuredOutputs) features.push(\"structured-outputs\");\n if (model.features.fineTuning) features.push(\"fine-tuning\");\n\n if (features.length > 0) {\n stream.write(` ${chalk.dim(\"Features:\")} ${chalk.blue(features.join(\", \"))}\\n`);\n }\n\n // Metadata\n if (model.metadata) {\n if (model.metadata.family) {\n stream.write(` ${chalk.dim(\"Family:\")} ${model.metadata.family}\\n`);\n }\n if (model.metadata.releaseDate) {\n stream.write(` ${chalk.dim(\"Released:\")} ${model.metadata.releaseDate}\\n`);\n }\n if (model.metadata.notes) {\n stream.write(` ${chalk.dim(\"Notes:\")} ${chalk.italic(model.metadata.notes)}\\n`);\n }\n }\n }\n stream.write(\"\\n\");\n}\n\n/**\n * Render image generation models table.\n */\nfunction renderImageTable(\n models: ImageModelSpec[],\n verbose: boolean,\n stream: NodeJS.WritableStream,\n): void {\n stream.write(chalk.bold.green(\"🎨 Image Generation Models\\n\"));\n stream.write(chalk.dim(\"─\".repeat(80)) + \"\\n\\n\");\n\n // Group by provider\n const grouped = new Map<string, ImageModelSpec[]>();\n for (const model of models) {\n if (!grouped.has(model.provider)) {\n grouped.set(model.provider, []);\n }\n grouped.get(model.provider)!.push(model);\n }\n\n for (const [provider, providerModels] of Array.from(grouped.entries()).sort()) {\n const providerName = provider.charAt(0).toUpperCase() + provider.slice(1);\n stream.write(chalk.bold.yellow(`${providerName}\\n`));\n\n if (verbose) {\n for (const model of providerModels) {\n stream.write(chalk.bold.green(`\\n ${model.modelId}\\n`));\n stream.write(chalk.dim(\" \" + \"─\".repeat(60)) + \"\\n\");\n stream.write(` ${chalk.dim(\"Name:\")} ${chalk.white(model.displayName)}\\n`);\n stream.write(\n ` ${chalk.dim(\"Sizes:\")} ${chalk.yellow(model.supportedSizes.join(\", \"))}\\n`,\n );\n if (model.supportedQualities) {\n stream.write(\n ` ${chalk.dim(\"Qualities:\")} ${chalk.yellow(model.supportedQualities.join(\", \"))}\\n`,\n );\n }\n stream.write(` ${chalk.dim(\"Max Images:\")} ${chalk.yellow(model.maxImages.toString())}\\n`);\n stream.write(` ${chalk.dim(\"Pricing:\")} ${chalk.cyan(formatImagePrice(model))}\\n`);\n if (model.features) {\n const features: string[] = [];\n if (model.features.textRendering) features.push(\"text-rendering\");\n if (model.features.transparency) features.push(\"transparency\");\n if (model.features.conversational) features.push(\"conversational\");\n if (features.length > 0) {\n stream.write(` ${chalk.dim(\"Features:\")} ${chalk.blue(features.join(\", \"))}\\n`);\n }\n }\n }\n } else {\n const idWidth = 32;\n const nameWidth = 25;\n const sizesWidth = 20;\n const priceWidth = 15;\n\n stream.write(chalk.dim(\"─\".repeat(idWidth + nameWidth + sizesWidth + priceWidth + 6)) + \"\\n\");\n stream.write(\n chalk.bold(\n \"Model ID\".padEnd(idWidth) +\n \" \" +\n \"Display Name\".padEnd(nameWidth) +\n \" \" +\n \"Sizes\".padEnd(sizesWidth) +\n \" \" +\n \"Price\".padEnd(priceWidth),\n ) + \"\\n\",\n );\n stream.write(chalk.dim(\"─\".repeat(idWidth + nameWidth + sizesWidth + priceWidth + 6)) + \"\\n\");\n\n for (const model of providerModels) {\n const sizes =\n model.supportedSizes.length > 2\n ? model.supportedSizes.slice(0, 2).join(\", \") + \"...\"\n : model.supportedSizes.join(\", \");\n\n stream.write(\n chalk.green(model.modelId.padEnd(idWidth)) +\n \" \" +\n chalk.white(model.displayName.substring(0, nameWidth - 1).padEnd(nameWidth)) +\n \" \" +\n chalk.yellow(sizes.padEnd(sizesWidth)) +\n \" \" +\n chalk.cyan(formatImagePrice(model).padEnd(priceWidth)) +\n \"\\n\",\n );\n }\n stream.write(chalk.dim(\"─\".repeat(idWidth + nameWidth + sizesWidth + priceWidth + 6)) + \"\\n\");\n }\n\n stream.write(\"\\n\");\n }\n}\n\n/**\n * Render speech/TTS models table.\n */\nfunction renderSpeechTable(\n models: SpeechModelSpec[],\n verbose: boolean,\n stream: NodeJS.WritableStream,\n): void {\n stream.write(chalk.bold.magenta(\"🎤 Speech (TTS) Models\\n\"));\n stream.write(chalk.dim(\"─\".repeat(80)) + \"\\n\\n\");\n\n // Group by provider\n const grouped = new Map<string, SpeechModelSpec[]>();\n for (const model of models) {\n if (!grouped.has(model.provider)) {\n grouped.set(model.provider, []);\n }\n grouped.get(model.provider)!.push(model);\n }\n\n for (const [provider, providerModels] of Array.from(grouped.entries()).sort()) {\n const providerName = provider.charAt(0).toUpperCase() + provider.slice(1);\n stream.write(chalk.bold.yellow(`${providerName}\\n`));\n\n if (verbose) {\n for (const model of providerModels) {\n stream.write(chalk.bold.green(`\\n ${model.modelId}\\n`));\n stream.write(chalk.dim(\" \" + \"─\".repeat(60)) + \"\\n\");\n stream.write(` ${chalk.dim(\"Name:\")} ${chalk.white(model.displayName)}\\n`);\n stream.write(\n ` ${chalk.dim(\"Voices:\")} ${chalk.yellow(model.voices.length.toString())} voices\\n`,\n );\n if (model.voices.length <= 6) {\n stream.write(` ${chalk.dim(model.voices.join(\", \"))}\\n`);\n } else {\n stream.write(` ${chalk.dim(model.voices.slice(0, 6).join(\", \") + \"...\")}\\n`);\n }\n stream.write(` ${chalk.dim(\"Formats:\")} ${chalk.yellow(model.formats.join(\", \"))}\\n`);\n stream.write(\n ` ${chalk.dim(\"Max Input:\")} ${chalk.yellow(model.maxInputLength.toString())} chars\\n`,\n );\n stream.write(` ${chalk.dim(\"Pricing:\")} ${chalk.cyan(formatSpeechPrice(model))}\\n`);\n if (model.features) {\n const features: string[] = [];\n if (model.features.multiSpeaker) features.push(\"multi-speaker\");\n if (model.features.voiceInstructions) features.push(\"voice-instructions\");\n if (model.features.languages) features.push(`${model.features.languages} languages`);\n if (features.length > 0) {\n stream.write(` ${chalk.dim(\"Features:\")} ${chalk.blue(features.join(\", \"))}\\n`);\n }\n }\n }\n } else {\n const idWidth = 30;\n const nameWidth = 28;\n const voicesWidth = 12;\n const priceWidth = 18;\n\n stream.write(\n chalk.dim(\"─\".repeat(idWidth + nameWidth + voicesWidth + priceWidth + 6)) + \"\\n\",\n );\n stream.write(\n chalk.bold(\n \"Model ID\".padEnd(idWidth) +\n \" \" +\n \"Display Name\".padEnd(nameWidth) +\n \" \" +\n \"Voices\".padEnd(voicesWidth) +\n \" \" +\n \"Price\".padEnd(priceWidth),\n ) + \"\\n\",\n );\n stream.write(\n chalk.dim(\"─\".repeat(idWidth + nameWidth + voicesWidth + priceWidth + 6)) + \"\\n\",\n );\n\n for (const model of providerModels) {\n stream.write(\n chalk.green(model.modelId.padEnd(idWidth)) +\n \" \" +\n chalk.white(model.displayName.substring(0, nameWidth - 1).padEnd(nameWidth)) +\n \" \" +\n chalk.yellow(`${model.voices.length} voices`.padEnd(voicesWidth)) +\n \" \" +\n chalk.cyan(formatSpeechPrice(model).padEnd(priceWidth)) +\n \"\\n\",\n );\n }\n stream.write(\n chalk.dim(\"─\".repeat(idWidth + nameWidth + voicesWidth + priceWidth + 6)) + \"\\n\",\n );\n }\n\n stream.write(\"\\n\");\n }\n}\n\n/**\n * Format image model pricing for display.\n */\nfunction formatImagePrice(model: ImageModelSpec): string {\n if (model.pricing.perImage !== undefined) {\n return `$${model.pricing.perImage.toFixed(2)}/img`;\n }\n if (model.pricing.bySize) {\n const prices = Object.values(model.pricing.bySize);\n const minPrice = Math.min(\n ...prices.flatMap((p) => (typeof p === \"number\" ? [p] : Object.values(p))),\n );\n const maxPrice = Math.max(\n ...prices.flatMap((p) => (typeof p === \"number\" ? [p] : Object.values(p))),\n );\n if (minPrice === maxPrice) {\n return `$${minPrice.toFixed(2)}/img`;\n }\n return `$${minPrice.toFixed(2)}-${maxPrice.toFixed(2)}`;\n }\n return \"varies\";\n}\n\n/**\n * Format speech model pricing for display.\n */\nfunction formatSpeechPrice(model: SpeechModelSpec): string {\n if (model.pricing.perCharacter !== undefined) {\n const perMillion = model.pricing.perCharacter * 1_000_000;\n return `$${perMillion.toFixed(0)}/1M chars`;\n }\n if (model.pricing.perMinute !== undefined) {\n return `~$${model.pricing.perMinute.toFixed(2)}/min`;\n }\n return \"varies\";\n}\n\nfunction renderJSON(\n textModels: ModelSpec[],\n imageModels: ImageModelSpec[],\n speechModels: SpeechModelSpec[],\n stream: NodeJS.WritableStream,\n): void {\n const output: Record<string, unknown> = {};\n\n if (textModels.length > 0) {\n output.textModels = textModels.map((model) => ({\n provider: model.provider,\n modelId: model.modelId,\n displayName: model.displayName,\n contextWindow: model.contextWindow,\n maxOutputTokens: model.maxOutputTokens,\n pricing: {\n input: model.pricing.input,\n output: model.pricing.output,\n cachedInput: model.pricing.cachedInput,\n currency: \"USD\",\n per: \"1M tokens\",\n },\n knowledgeCutoff: model.knowledgeCutoff,\n features: model.features,\n metadata: model.metadata,\n }));\n output.shortcuts = MODEL_ALIASES;\n }\n\n if (imageModels.length > 0) {\n output.imageModels = imageModels.map((model) => ({\n provider: model.provider,\n modelId: model.modelId,\n displayName: model.displayName,\n supportedSizes: model.supportedSizes,\n supportedQualities: model.supportedQualities,\n maxImages: model.maxImages,\n pricing: model.pricing,\n features: model.features,\n }));\n }\n\n if (speechModels.length > 0) {\n output.speechModels = speechModels.map((model) => ({\n provider: model.provider,\n modelId: model.modelId,\n displayName: model.displayName,\n voices: model.voices,\n formats: model.formats,\n maxInputLength: model.maxInputLength,\n pricing: model.pricing,\n features: model.features,\n }));\n }\n\n stream.write(JSON.stringify(output, null, 2) + \"\\n\");\n}\n\nfunction formatTokens(count: number): string {\n if (count >= 1_000_000) {\n return `${(count / 1_000_000).toFixed(1)}M tokens`;\n } else if (count >= 1_000) {\n return `${(count / 1_000).toFixed(0)}K tokens`;\n } else {\n return `${count} tokens`;\n }\n}\n\nexport function registerModelsCommand(program: Command, env: CLIEnvironment): void {\n program\n .command(COMMANDS.models)\n .description(\"List available models with pricing and capabilities.\")\n .option(\"--provider <name>\", \"Filter by provider (openai, anthropic, gemini)\")\n .option(\"--format <format>\", \"Output format: table or json\", \"table\")\n .option(\"--verbose\", \"Show detailed model information\", false)\n .option(\"--text\", \"Show text/LLM models (default if no type specified)\")\n .option(\"--image\", \"Show image generation models\")\n .option(\"--speech\", \"Show speech/TTS models\")\n .option(\"--all\", \"Show all model types (text, image, speech)\")\n .action((options) =>\n executeAction(() => handleModelsCommand(options as ModelsCommandOptions, env), env),\n );\n}\n","import { writeFileSync } from \"node:fs\";\nimport type { Command } from \"commander\";\n\nimport type { SpeechConfig } from \"./config.js\";\nimport { COMMANDS, OPTION_DESCRIPTIONS, OPTION_FLAGS, SUMMARY_PREFIX } from \"./constants.js\";\nimport type { CLIEnvironment } from \"./environment.js\";\nimport { formatCost } from \"./ui/formatters.js\";\nimport { executeAction, resolvePrompt } from \"./utils.js\";\n\n/**\n * Default speech generation model.\n */\nconst DEFAULT_SPEECH_MODEL = \"tts-1\";\n\n/**\n * Default voice for speech generation.\n */\nconst DEFAULT_VOICE = \"nova\";\n\n/**\n * Options for the speech command.\n */\nexport interface SpeechCommandOptions {\n model: string;\n voice?: string;\n format?: string;\n speed?: string;\n output?: string;\n quiet?: boolean;\n}\n\n/**\n * Executes the speech command.\n * Generates speech audio from text using the specified model and voice.\n *\n * @param textArg - Text from command line argument (optional if using stdin)\n * @param options - Speech command options\n * @param env - CLI environment for I/O operations\n */\nexport async function executeSpeech(\n textArg: string | undefined,\n options: SpeechCommandOptions,\n env: CLIEnvironment,\n): Promise<void> {\n const text = await resolvePrompt(textArg, env);\n const client = env.createClient();\n\n const model = options.model;\n const voice = options.voice ?? DEFAULT_VOICE;\n const speed = options.speed ? Number.parseFloat(options.speed) : undefined;\n\n const stderrTTY = (env.stderr as NodeJS.WriteStream).isTTY === true;\n\n if (!options.quiet && stderrTTY) {\n env.stderr.write(`${SUMMARY_PREFIX} Generating speech with ${model} (voice: ${voice})...\\n`);\n }\n\n const result = await client.speech.generate({\n model,\n input: text,\n voice,\n responseFormat: options.format as \"mp3\" | \"opus\" | \"aac\" | \"flac\" | \"wav\" | \"pcm\" | undefined,\n speed,\n });\n\n // Get the audio data as a Buffer\n const audioBuffer = Buffer.from(result.audio);\n\n // Handle output\n if (options.output) {\n // Save to file\n writeFileSync(options.output, audioBuffer);\n if (!options.quiet) {\n env.stderr.write(`${SUMMARY_PREFIX} Audio saved to ${options.output}\\n`);\n }\n } else {\n // Output raw audio to stdout (for piping)\n env.stdout.write(audioBuffer);\n }\n\n // Show summary\n if (!options.quiet && stderrTTY) {\n const parts = [`${result.usage.characterCount} characters`, `format: ${result.format}`];\n if (result.cost !== undefined) {\n parts.push(`cost: ${formatCost(result.cost)}`);\n }\n env.stderr.write(`${SUMMARY_PREFIX} ${parts.join(\" | \")}\\n`);\n }\n}\n\n/**\n * Registers the speech command with the CLI program.\n *\n * @param program - Commander program to register the command with\n * @param env - CLI environment for dependencies and I/O\n * @param config - Optional configuration defaults from config file\n */\nexport function registerSpeechCommand(\n program: Command,\n env: CLIEnvironment,\n config?: SpeechConfig,\n): void {\n program\n .command(COMMANDS.speech)\n .description(\"Generate speech audio from text.\")\n .argument(\"[text]\", \"Text to convert to speech. If omitted, stdin is used when available.\")\n .option(OPTION_FLAGS.model, OPTION_DESCRIPTIONS.model, config?.model ?? DEFAULT_SPEECH_MODEL)\n .option(OPTION_FLAGS.voice, OPTION_DESCRIPTIONS.voice, config?.voice ?? DEFAULT_VOICE)\n .option(OPTION_FLAGS.speechFormat, OPTION_DESCRIPTIONS.speechFormat, config?.format)\n .option(OPTION_FLAGS.speechSpeed, OPTION_DESCRIPTIONS.speechSpeed, config?.speed?.toString())\n .option(OPTION_FLAGS.speechOutput, OPTION_DESCRIPTIONS.speechOutput, config?.output)\n .option(OPTION_FLAGS.quiet, OPTION_DESCRIPTIONS.quiet, config?.quiet ?? false)\n .action((text, options) =>\n executeAction(() => executeSpeech(text, options as SpeechCommandOptions, env), env),\n );\n}\n","/**\n * Vision command for image analysis.\n *\n * Provides a dedicated CLI for one-shot image analysis using vision-capable models.\n *\n * @example\n * ```bash\n * llmist vision photo.jpg -p \"Describe this image\"\n * llmist vision screenshot.png --model gpt-4o -p \"Extract all text from this image\"\n * ```\n */\n\nimport type { Command } from \"commander\";\nimport { resolveModel } from \"../core/model-shortcuts.js\";\nimport { COMMANDS, OPTION_DESCRIPTIONS, OPTION_FLAGS, SUMMARY_PREFIX } from \"./constants.js\";\nimport type { CLIEnvironment } from \"./environment.js\";\nimport { readFileBuffer } from \"./file-utils.js\";\nimport { createNumericParser, executeAction } from \"./utils.js\";\n\n/**\n * Options for the vision command.\n */\nexport interface VisionCommandOptions {\n /** Model to use for vision analysis */\n model: string;\n /** Analysis prompt */\n prompt?: string;\n /** Maximum tokens in response */\n maxTokens?: number;\n /** Suppress progress output */\n quiet?: boolean;\n}\n\n/**\n * Execute vision analysis on an image.\n *\n * @param imagePath - Path to the image file\n * @param options - Vision command options\n * @param env - CLI environment\n */\nexport async function executeVision(\n imagePath: string,\n options: VisionCommandOptions,\n env: CLIEnvironment,\n): Promise<void> {\n const client = env.createClient();\n const model = resolveModel(options.model);\n\n // Read image file\n const imageBuffer = await readFileBuffer(imagePath);\n\n // Default prompt for vision analysis\n const prompt = options.prompt ?? \"Describe this image in detail.\";\n\n const stderrTTY = (env.stderr as NodeJS.WriteStream).isTTY === true;\n\n if (!options.quiet && stderrTTY) {\n env.stderr.write(`${SUMMARY_PREFIX} Analyzing image with ${model}...\\n`);\n }\n\n // Use vision namespace for one-shot analysis\n const result = await client.vision.analyze({\n model,\n image: imageBuffer,\n prompt,\n maxTokens: options.maxTokens,\n });\n\n // Output result\n env.stdout.write(result);\n env.stdout.write(\"\\n\");\n}\n\n/**\n * Register the vision command with the CLI program.\n *\n * @param program - Commander program instance\n * @param env - CLI environment\n */\nexport function registerVisionCommand(program: Command, env: CLIEnvironment): void {\n program\n .command(COMMANDS.vision ?? \"vision\")\n .description(\"Analyze an image using vision-capable models\")\n .argument(\"<image>\", \"Path to image file to analyze\")\n .option(\n OPTION_FLAGS.model,\n OPTION_DESCRIPTIONS.model,\n \"gpt-4o\", // Default to a vision-capable model\n )\n .option(\"-p, --prompt <prompt>\", \"Analysis prompt describing what to extract or describe\")\n .option(\n OPTION_FLAGS.maxTokens,\n OPTION_DESCRIPTIONS.maxTokens,\n createNumericParser({ label: \"Max tokens\", integer: true, min: 1 }),\n )\n .option(OPTION_FLAGS.quiet, OPTION_DESCRIPTIONS.quiet)\n .action((imagePath: string, options: VisionCommandOptions) =>\n executeAction(() => executeVision(imagePath, options, env), env),\n );\n}\n","#!/usr/bin/env node\nimport { SUMMARY_PREFIX } from \"./cli/constants.js\";\nimport { runCLI } from \"./cli/program.js\";\n\nrunCLI().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`${SUMMARY_PREFIX} Error: ${message}\\n`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":["path","path","resolve","import_node_path","path","z","import_node_crypto","init_constants","Anthropic","init_constants","stream","init_constants","response","images","cost","stream","text","OpenAI","init_constants","stream","text","providerSpecs","text","pointer","path","import_zod","stream","resolve","stream","import_commander","init_constants","import_zod","import_node_fs","import_node_os","import_node_path","path","parseToml","validateString","validateBoolean","validateStringArray","import_node_fs","import_node_os","import_node_fs","import_node_os","import_node_path","path","import_promises","import_node_path","import_node_fs","import_node_path","import_node_url","import_zod","import_zod","import_node_fs","import_node_path","path","fs","import_node_fs","import_node_path","import_zod","fs","path","import_node_fs","import_zod","readFile","fs","import_node_fs","import_node_path","import_zod","writeFile","path","fs","import_zod","readFile","writeFile","import_node_fs","import_node_path","import_node_os","CACHE_DIR","path","os","fs","exports","path","fs","exports","import_promises","import_node_os","import_node_path","import_chalk","init_constants","chalk","chalk","chalk","text","stream","elapsedSeconds","termWidth","chalk","line","stream","import_node","CHARS_PER_TOKEN","SPINNER_FRAMES","YELLOW","GREEN","CYAN","MAGENTA","RESET","WHITE","text","resolve","import_node","import_chalk","chalk","import_node","resolve","import_node","resolve","isTextPart","isImagePart","isAudioPart","gadgets","text","init_constants","stream","import_node_fs","import_node_path","import_chalk","resolve","readline","chalk","import_chalk","import_promises","import_chalk","chalk","chalk","result","import_node_fs","import_chalk","stream","chalk","formatTokens","import_node_fs","text","parseLogLevel"]}