openfox 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/agent-defaults/builder.agent.md +38 -0
  2. package/dist/agent-defaults/code-reviewer.agent.md +21 -0
  3. package/dist/agent-defaults/debugger.agent.md +21 -0
  4. package/dist/agent-defaults/planner.agent.md +35 -0
  5. package/dist/agent-defaults/test-generator.agent.md +22 -0
  6. package/dist/agent-defaults/verifier.agent.md +41 -0
  7. package/dist/{chunk-FF6Z2MC3.js → chunk-5ZUU23XF.js} +18 -1
  8. package/dist/{chunk-IVHCPQO2.js → chunk-ARFK3RZW.js} +1 -1
  9. package/dist/{chunk-IKAWIOXM.js → chunk-FUUYYDVG.js} +387 -73
  10. package/dist/{chunk-YQ36AK5A.js → chunk-JFQEATRC.js} +623 -327
  11. package/dist/{chunk-43SWNGYW.js → chunk-L475ND2Z.js} +9 -9
  12. package/dist/{chunk-6MOGZMGX.js → chunk-L4XDA3V7.js} +2 -2
  13. package/dist/{chunk-EI46G5WO.js → chunk-MKAHOQBI.js} +10 -10
  14. package/dist/cli/dev.js +1 -1
  15. package/dist/cli/index.js +1 -1
  16. package/dist/{config-6GJ4SVFH.js → config-BMXSDOZB.js} +3 -3
  17. package/dist/{init-UVZDOHMX.js → init-PLRTRSDC.js} +6 -6
  18. package/dist/{protocol-BJsm88OW.d.ts → protocol-BFFz3WM0.d.ts} +14 -3
  19. package/dist/{provider-LCE6WZA6.js → provider-ETVY64A2.js} +5 -5
  20. package/dist/{serve-27DZK34K.js → serve-EOKIXTWM.js} +8 -8
  21. package/dist/server/index.d.ts +1 -1
  22. package/dist/server/index.js +5 -5
  23. package/dist/shared/index.d.ts +2 -2
  24. package/dist/shared/index.js +1 -1
  25. package/dist/{tools-R4YQAYUF.js → tools-QMIIDJTV.js} +7 -5
  26. package/dist/web/assets/index-CAD7Iv_d.js +122 -0
  27. package/dist/web/assets/{index-BSlSWZrM.css → index-DHmZmhnR.css} +1 -1
  28. package/dist/web/index.html +2 -2
  29. package/dist/workflow-defaults/default.workflow.json +45 -0
  30. package/package.json +34 -16
  31. package/dist/branch.api-WDHKZJS6.js.map +0 -1
  32. package/dist/chunk-26NRL3HX.js.map +0 -1
  33. package/dist/chunk-43SWNGYW.js.map +0 -1
  34. package/dist/chunk-4Z2OZ6NX.js.map +0 -1
  35. package/dist/chunk-6MOGZMGX.js.map +0 -1
  36. package/dist/chunk-AF7XS4OI.js.map +0 -1
  37. package/dist/chunk-EI46G5WO.js.map +0 -1
  38. package/dist/chunk-FF6Z2MC3.js.map +0 -1
  39. package/dist/chunk-IKAWIOXM.js.map +0 -1
  40. package/dist/chunk-IVHCPQO2.js.map +0 -1
  41. package/dist/chunk-MTX5Y3V3.js.map +0 -1
  42. package/dist/chunk-N2XYX4ZA.js.map +0 -1
  43. package/dist/chunk-QY7BMXWT.js.map +0 -1
  44. package/dist/chunk-U62ZECSQ.js.map +0 -1
  45. package/dist/chunk-YQ36AK5A.js.map +0 -1
  46. package/dist/cli/dev.js.map +0 -1
  47. package/dist/cli/index.js.map +0 -1
  48. package/dist/config-6GJ4SVFH.js.map +0 -1
  49. package/dist/init-UVZDOHMX.js.map +0 -1
  50. package/dist/paths-4BPXWB2W.js.map +0 -1
  51. package/dist/project-creator-CWPKRIKI.js.map +0 -1
  52. package/dist/provider-LCE6WZA6.js.map +0 -1
  53. package/dist/serve-27DZK34K.js.map +0 -1
  54. package/dist/server/index.js.map +0 -1
  55. package/dist/settings-D5O3TMLD.js.map +0 -1
  56. package/dist/shared/index.js.map +0 -1
  57. package/dist/tools-R4YQAYUF.js.map +0 -1
  58. package/dist/web/assets/index-BMNDCsbJ.js +0 -120
  59. /package/dist/command-defaults/{defaults/commit-push.command.md → commit-push.command.md} +0 -0
  60. /package/dist/command-defaults/{defaults/init.command.md → init.command.md} +0 -0
  61. /package/dist/command-defaults/{defaults/test-ui.command.md → test-ui.command.md} +0 -0
  62. /package/dist/skill-defaults/{defaults/playwright-cli.skill.md → playwright-cli.skill.md} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/db/index.ts"],"sourcesContent":["import Database from 'better-sqlite3'\nimport type { Config } from '../config.js'\nimport { logger } from '../utils/logger.js'\n\nlet db: Database.Database | null = null\n\nexport function initDatabase(config: Config): Database.Database {\n if (db) {\n return db\n }\n \n logger.info('Initializing database', { path: config.database.path })\n \n db = new Database(config.database.path)\n db.pragma('journal_mode = WAL')\n db.pragma('foreign_keys = ON')\n \n runMigrations(db)\n \n // Reset any stale running states from previous server runs\n // Sessions cannot actually be running when server starts\n const result = db.prepare(`UPDATE sessions SET is_running = 0 WHERE is_running = 1`).run()\n if (result.changes > 0) {\n logger.info('Reset stale running states', { count: result.changes })\n }\n \n return db\n}\n\nexport function getDatabase(): Database.Database {\n if (!db) {\n throw new Error('Database not initialized. Call initDatabase first.')\n }\n return db\n}\n\nexport function closeDatabase(): void {\n if (db) {\n db.close()\n db = null\n }\n}\n\nfunction runMigrations(db: Database.Database): void {\n logger.info('Running database migrations')\n \n // Create projects table\n db.exec(`\n CREATE TABLE IF NOT EXISTS projects (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n workdir TEXT NOT NULL UNIQUE,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )\n `)\n \n // Create sessions table with project_id\n // Note: mode, phase, isRunning, summary are persisted here for quick access\n // Full session state (messages, criteria, todos) is derived from events table\n db.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n workdir TEXT NOT NULL,\n phase TEXT NOT NULL DEFAULT 'idle',\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n title TEXT,\n total_tokens_used INTEGER DEFAULT 0,\n total_tool_calls INTEGER DEFAULT 0,\n iteration_count INTEGER DEFAULT 0,\n FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE\n )\n `)\n \n // Create indexes\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id)\n `)\n \n // Migration: Add mode, is_running, summary columns if they don't exist\n const columns = db.prepare(`PRAGMA table_info(sessions)`).all() as { name: string }[]\n const columnNames = columns.map(c => c.name)\n \n if (!columnNames.includes('mode')) {\n logger.info('Migrating sessions table: adding mode column')\n db.exec(`ALTER TABLE sessions ADD COLUMN mode TEXT NOT NULL DEFAULT 'planner'`)\n // Migrate existing phase values to mode\n db.exec(`\n UPDATE sessions SET mode = CASE\n WHEN phase = 'idle' THEN 'planner'\n WHEN phase = 'planning' THEN 'planner'\n WHEN phase = 'executing' THEN 'builder'\n WHEN phase = 'validating' THEN 'verifier'\n WHEN phase = 'completed' THEN 'planner'\n ELSE 'planner'\n END\n `)\n }\n \n if (!columnNames.includes('is_running')) {\n logger.info('Migrating sessions table: adding is_running column')\n db.exec(`ALTER TABLE sessions ADD COLUMN is_running INTEGER NOT NULL DEFAULT 0`)\n }\n \n if (!columnNames.includes('summary')) {\n logger.info('Migrating sessions table: adding summary column')\n db.exec(`ALTER TABLE sessions ADD COLUMN summary TEXT`)\n }\n \n // Note: The old 'phase' column was for the state machine (idle/planning/executing/etc.)\n // This new 'workflow_phase' column is for UI display (plan/build/verification/done)\n if (!columnNames.includes('workflow_phase')) {\n logger.info('Migrating sessions table: adding workflow_phase column')\n db.exec(`ALTER TABLE sessions ADD COLUMN workflow_phase TEXT NOT NULL DEFAULT 'plan'`)\n }\n \n // Create settings table for global configuration (e.g., global instructions)\n db.exec(`\n CREATE TABLE IF NOT EXISTS settings (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )\n `)\n \n // Migration: Add custom_instructions column to projects table\n const projectColumns = db.prepare(`PRAGMA table_info(projects)`).all() as { name: string }[]\n const projectColumnNames = projectColumns.map(c => c.name)\n \n if (!projectColumnNames.includes('custom_instructions')) {\n logger.info('Migrating projects table: adding custom_instructions column')\n db.exec(`ALTER TABLE projects ADD COLUMN custom_instructions TEXT`)\n }\n \n // Create events table for EventStore (single source of truth)\n // Note: EventStore creates this table with its own schema in initSchema()\n // We just ensure the index exists for the event_type column\n db.exec(`\n CREATE TABLE IF NOT EXISTS events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL,\n seq INTEGER NOT NULL,\n timestamp INTEGER NOT NULL,\n event_type TEXT NOT NULL,\n payload TEXT NOT NULL,\n UNIQUE(session_id, seq),\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE\n )\n `)\n \n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_events_session_seq ON events(session_id, seq)\n `)\n \n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_events_session_type ON events(session_id, event_type)\n `)\n \n // Migration: Add per-session provider/model columns\n if (!columnNames.includes('provider_id')) {\n logger.info('Migrating sessions table: adding provider_id column')\n db.exec(`ALTER TABLE sessions ADD COLUMN provider_id TEXT`)\n }\n\n if (!columnNames.includes('provider_model')) {\n logger.info('Migrating sessions table: adding provider_model column')\n db.exec(`ALTER TABLE sessions ADD COLUMN provider_model TEXT`)\n }\n\n logger.info('Database migrations completed')\n}\n"],"mappings":";;;;;AAAA,OAAO,cAAc;AAIrB,IAAI,KAA+B;AAE5B,SAAS,aAAa,QAAmC;AAC9D,MAAI,IAAI;AACN,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,yBAAyB,EAAE,MAAM,OAAO,SAAS,KAAK,CAAC;AAEnE,OAAK,IAAI,SAAS,OAAO,SAAS,IAAI;AACtC,KAAG,OAAO,oBAAoB;AAC9B,KAAG,OAAO,mBAAmB;AAE7B,gBAAc,EAAE;AAIhB,QAAM,SAAS,GAAG,QAAQ,yDAAyD,EAAE,IAAI;AACzF,MAAI,OAAO,UAAU,GAAG;AACtB,WAAO,KAAK,8BAA8B,EAAE,OAAO,OAAO,QAAQ,CAAC;AAAA,EACrE;AAEA,SAAO;AACT;AAEO,SAAS,cAAiC;AAC/C,MAAI,CAAC,IAAI;AACP,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,SAAO;AACT;AASA,SAAS,cAAcA,KAA6B;AAClD,SAAO,KAAK,6BAA6B;AAGzC,EAAAA,IAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAQP;AAKD,EAAAA,IAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAcP;AAGD,EAAAA,IAAG,KAAK;AAAA;AAAA,GAEP;AAGD,QAAM,UAAUA,IAAG,QAAQ,6BAA6B,EAAE,IAAI;AAC9D,QAAM,cAAc,QAAQ,IAAI,OAAK,EAAE,IAAI;AAE3C,MAAI,CAAC,YAAY,SAAS,MAAM,GAAG;AACjC,WAAO,KAAK,8CAA8C;AAC1D,IAAAA,IAAG,KAAK,sEAAsE;AAE9E,IAAAA,IAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KASP;AAAA,EACH;AAEA,MAAI,CAAC,YAAY,SAAS,YAAY,GAAG;AACvC,WAAO,KAAK,oDAAoD;AAChE,IAAAA,IAAG,KAAK,uEAAuE;AAAA,EACjF;AAEA,MAAI,CAAC,YAAY,SAAS,SAAS,GAAG;AACpC,WAAO,KAAK,iDAAiD;AAC7D,IAAAA,IAAG,KAAK,8CAA8C;AAAA,EACxD;AAIA,MAAI,CAAC,YAAY,SAAS,gBAAgB,GAAG;AAC3C,WAAO,KAAK,wDAAwD;AACpE,IAAAA,IAAG,KAAK,6EAA6E;AAAA,EACvF;AAGA,EAAAA,IAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAMP;AAGD,QAAM,iBAAiBA,IAAG,QAAQ,6BAA6B,EAAE,IAAI;AACrE,QAAM,qBAAqB,eAAe,IAAI,OAAK,EAAE,IAAI;AAEzD,MAAI,CAAC,mBAAmB,SAAS,qBAAqB,GAAG;AACvD,WAAO,KAAK,6DAA6D;AACzE,IAAAA,IAAG,KAAK,0DAA0D;AAAA,EACpE;AAKA,EAAAA,IAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAWP;AAED,EAAAA,IAAG,KAAK;AAAA;AAAA,GAEP;AAED,EAAAA,IAAG,KAAK;AAAA;AAAA,GAEP;AAGD,MAAI,CAAC,YAAY,SAAS,aAAa,GAAG;AACxC,WAAO,KAAK,qDAAqD;AACjE,IAAAA,IAAG,KAAK,kDAAkD;AAAA,EAC5D;AAEA,MAAI,CAAC,YAAY,SAAS,gBAAgB,GAAG;AAC3C,WAAO,KAAK,wDAAwD;AACpE,IAAAA,IAAG,KAAK,qDAAqD;AAAA,EAC/D;AAEA,SAAO,KAAK,+BAA+B;AAC7C;","names":["db"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/provider-manager.ts"],"sourcesContent":["import type { Provider, Config, LlmBackend } from '../shared/types.js'\nimport { createLLMClient, detectBackend, detectModel, clearModelCache, type LLMClientWithModel } from './llm/index.js'\nimport { logger } from './utils/logger.js'\n\n/** Fetch available models from a provider's backend */\nexport async function fetchAvailableModelsFromBackend(baseUrl: string, apiKey?: string): Promise<string[]> {\n const url = baseUrl.includes('/v1') ? `${baseUrl}/models` : `${baseUrl}/v1/models`\n\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n }\n if (apiKey) {\n headers['Authorization'] = `Bearer ${apiKey}`\n }\n\n const response = await fetch(url, {\n method: 'GET',\n headers,\n signal: AbortSignal.timeout(10000),\n })\n\n if (!response.ok) {\n logger.debug('Failed to fetch models', { url, status: response.status })\n return []\n }\n\n const data = await response.json() as { data?: Array<{ id: string }> }\n if (data.data && Array.isArray(data.data)) {\n return data.data.map(m => m.id).filter(Boolean)\n }\n\n return []\n } catch (error) {\n logger.debug('Error fetching models from backend', { url, error: error instanceof Error ? error.message : String(error) })\n return []\n }\n}\n\nexport interface ProviderManager {\n getProviders(): Provider[]\n getActiveProvider(): Provider | undefined\n getActiveProviderId(): string | undefined\n getCurrentModel(): string | undefined\n getLLMClient(): LLMClientWithModel\n activateProvider(providerId: string, options?: { model?: string }): Promise<{ success: boolean; error?: string }>\n addProvider(provider: Omit<Provider, 'id' | 'createdAt'>): Provider\n removeProvider(providerId: string): boolean\n setProviders(providers: Provider[], defaultModelSelection?: string): void\n getProviderStatus(providerId: string): 'connected' | 'disconnected' | 'unknown'\n getProviderModels(providerId: string): Promise<string[]>\n setDefaultModelSelection(providerId: string, model: string): Promise<{ success: boolean; error?: string }>\n}\n\nfunction parseDefaultModelSelection(selection?: string): { providerId: string | undefined; model: string | undefined } {\n if (!selection) return { providerId: undefined, model: undefined }\n const parts = selection.split('/')\n return {\n providerId: parts[0],\n model: parts[1] ?? 'auto',\n }\n}\n\nexport function createProviderManager(config: Config): ProviderManager {\n let providers: Provider[] = [...(config.providers ?? [])]\n const { providerId: initialProviderId, model: initialModel } = parseDefaultModelSelection(config.defaultModelSelection)\n let defaultModelSelection: string | undefined = config.defaultModelSelection\n let llmClient = createLLMClient(config)\n const providerStatus = new Map<string, 'connected' | 'disconnected' | 'unknown'>()\n \n for (const p of providers) {\n providerStatus.set(p.id, 'unknown')\n }\n \n function createConfigForProvider(provider: Provider, model: string): Config {\n return {\n ...config,\n llm: {\n ...config.llm,\n baseUrl: provider.url.includes('/v1') ? provider.url : `${provider.url}/v1`,\n model,\n backend: provider.backend as LlmBackend | 'auto',\n },\n }\n }\n \n return {\n getProviders() {\n return [...providers]\n },\n \n getActiveProvider() {\n const { providerId } = parseDefaultModelSelection(defaultModelSelection)\n if (!providerId) return undefined\n return providers.find(p => p.id === providerId)\n },\n \n getActiveProviderId() {\n const { providerId } = parseDefaultModelSelection(defaultModelSelection)\n return providerId\n },\n \n getCurrentModel() {\n const { model } = parseDefaultModelSelection(defaultModelSelection)\n return model\n },\n \n getLLMClient() {\n return llmClient\n },\n \n async activateProvider(providerId: string, options?: { model?: string }) {\n const provider = providers.find(p => p.id === providerId)\n if (!provider) {\n return { success: false, error: 'Provider not found' }\n }\n\n const currentModel = parseDefaultModelSelection(defaultModelSelection).model ?? 'auto'\n const targetModel = options?.model ?? currentModel\n const isModelSwitch = providerId === parseDefaultModelSelection(defaultModelSelection).providerId && options?.model && options.model !== currentModel\n \n if (providerId === parseDefaultModelSelection(defaultModelSelection).providerId && !isModelSwitch) {\n return { success: true }\n }\n\n logger.info('Switching provider', {\n from: parseDefaultModelSelection(defaultModelSelection).providerId,\n to: providerId,\n providerName: provider.name,\n url: provider.url,\n model: targetModel,\n })\n\n const providerConfig = createConfigForProvider(provider, targetModel)\n const newClient = createLLMClient(providerConfig)\n\n try {\n const url = provider.url.includes('/v1') ? provider.url.replace('/v1', '') : provider.url\n clearModelCache(url)\n\n if (provider.backend === 'auto') {\n const detected = await detectBackend(url)\n newClient.setBackend(detected)\n } else {\n newClient.setBackend(provider.backend as LlmBackend)\n }\n\n if (targetModel === 'auto') {\n const detected = await detectModel(url)\n if (detected) {\n newClient.setModel(detected)\n }\n } else {\n newClient.setModel(targetModel)\n }\n\n providerStatus.set(providerId, 'connected')\n } catch (err) {\n logger.warn('Could not connect to provider', {\n providerId,\n error: err instanceof Error ? err.message : String(err),\n })\n providerStatus.set(providerId, 'disconnected')\n }\n\n providers = providers.map(p => ({\n ...p,\n isActive: p.id === providerId,\n }))\n defaultModelSelection = `${providerId}/${targetModel}`\n llmClient = newClient\n\n logger.info('Provider activated', {\n providerId,\n providerName: provider.name,\n model: llmClient.getModel(),\n backend: llmClient.getBackend(),\n })\n\n return { success: true }\n },\n \n addProvider(providerData) {\n const id = crypto.randomUUID()\n const provider: Provider = {\n ...providerData,\n id,\n createdAt: new Date().toISOString(),\n }\n \n if (providerData.isActive || providers.length === 0) {\n providers = providers.map(p => ({ ...p, isActive: false }))\n provider.isActive = true\n defaultModelSelection = `${id}/auto`\n }\n \n providers.push(provider)\n providerStatus.set(id, 'unknown')\n \n return provider\n },\n \n removeProvider(providerId) {\n const index = providers.findIndex(p => p.id === providerId)\n if (index === -1) return false\n \n const wasActive = providers[index]?.isActive\n providers.splice(index, 1)\n providerStatus.delete(providerId)\n \n if (wasActive && providers.length > 0) {\n providers[0]!.isActive = true\n defaultModelSelection = `${providers[0]!.id}/auto`\n } else if (providers.length === 0) {\n defaultModelSelection = undefined\n }\n \n return true\n },\n \n setProviders(newProviders, newDefaultModelSelection) {\n providers = [...newProviders]\n defaultModelSelection = newDefaultModelSelection\n \n providerStatus.clear()\n for (const p of providers) {\n providerStatus.set(p.id, 'unknown')\n }\n },\n \n getProviderStatus(providerId) {\n return providerStatus.get(providerId) ?? 'unknown'\n },\n\n async getProviderModels(providerId: string): Promise<string[]> {\n const provider = providers.find(p => p.id === providerId)\n if (!provider) {\n return []\n }\n\n const url = provider.url.includes('/v1') ? provider.url.replace('/v1', '') : provider.url\n return fetchAvailableModelsFromBackend(url, provider.apiKey)\n },\n\n async setDefaultModelSelection(providerId: string, model: string) {\n const provider = providers.find(p => p.id === providerId)\n if (!provider) {\n return { success: false, error: 'Provider not found' }\n }\n\n logger.info('Setting default model selection', { providerId, model, providerName: provider.name })\n\n defaultModelSelection = `${providerId}/${model}`\n providers = providers.map(p => ({ ...p, isActive: p.id === providerId }))\n\n const currentProviderId = parseDefaultModelSelection(defaultModelSelection).providerId\n if (currentProviderId === providerId) {\n llmClient.setModel(model)\n logger.info('Model updated', { providerId, model })\n }\n\n return { success: true }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;AAKA,eAAsB,gCAAgC,SAAiB,QAAoC;AACzG,QAAM,MAAM,QAAQ,SAAS,KAAK,IAAI,GAAG,OAAO,YAAY,GAAG,OAAO;AAEtE,MAAI;AACF,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,IAClB;AACA,QAAI,QAAQ;AACV,cAAQ,eAAe,IAAI,UAAU,MAAM;AAAA,IAC7C;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,YAAY,QAAQ,GAAK;AAAA,IACnC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,aAAO,MAAM,0BAA0B,EAAE,KAAK,QAAQ,SAAS,OAAO,CAAC;AACvE,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,KAAK,QAAQ,MAAM,QAAQ,KAAK,IAAI,GAAG;AACzC,aAAO,KAAK,KAAK,IAAI,OAAK,EAAE,EAAE,EAAE,OAAO,OAAO;AAAA,IAChD;AAEA,WAAO,CAAC;AAAA,EACV,SAAS,OAAO;AACd,WAAO,MAAM,sCAAsC,EAAE,KAAK,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC;AACzH,WAAO,CAAC;AAAA,EACV;AACF;AAiBA,SAAS,2BAA2B,WAAmF;AACrH,MAAI,CAAC,UAAW,QAAO,EAAE,YAAY,QAAW,OAAO,OAAU;AACjE,QAAM,QAAQ,UAAU,MAAM,GAAG;AACjC,SAAO;AAAA,IACL,YAAY,MAAM,CAAC;AAAA,IACnB,OAAO,MAAM,CAAC,KAAK;AAAA,EACrB;AACF;AAEO,SAAS,sBAAsB,QAAiC;AACrE,MAAI,YAAwB,CAAC,GAAI,OAAO,aAAa,CAAC,CAAE;AACxD,QAAM,EAAE,YAAY,mBAAmB,OAAO,aAAa,IAAI,2BAA2B,OAAO,qBAAqB;AACtH,MAAI,wBAA4C,OAAO;AACvD,MAAI,YAAY,gBAAgB,MAAM;AACtC,QAAM,iBAAiB,oBAAI,IAAsD;AAEjF,aAAW,KAAK,WAAW;AACzB,mBAAe,IAAI,EAAE,IAAI,SAAS;AAAA,EACpC;AAEA,WAAS,wBAAwB,UAAoB,OAAuB;AAC1E,WAAO;AAAA,MACL,GAAG;AAAA,MACH,KAAK;AAAA,QACH,GAAG,OAAO;AAAA,QACV,SAAS,SAAS,IAAI,SAAS,KAAK,IAAI,SAAS,MAAM,GAAG,SAAS,GAAG;AAAA,QACtE;AAAA,QACA,SAAS,SAAS;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,eAAe;AACb,aAAO,CAAC,GAAG,SAAS;AAAA,IACtB;AAAA,IAEA,oBAAoB;AAClB,YAAM,EAAE,WAAW,IAAI,2BAA2B,qBAAqB;AACvE,UAAI,CAAC,WAAY,QAAO;AACxB,aAAO,UAAU,KAAK,OAAK,EAAE,OAAO,UAAU;AAAA,IAChD;AAAA,IAEA,sBAAsB;AACpB,YAAM,EAAE,WAAW,IAAI,2BAA2B,qBAAqB;AACvE,aAAO;AAAA,IACT;AAAA,IAEA,kBAAkB;AAChB,YAAM,EAAE,MAAM,IAAI,2BAA2B,qBAAqB;AAClE,aAAO;AAAA,IACT;AAAA,IAEA,eAAe;AACb,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,iBAAiB,YAAoB,SAA8B;AACvE,YAAM,WAAW,UAAU,KAAK,OAAK,EAAE,OAAO,UAAU;AACxD,UAAI,CAAC,UAAU;AACb,eAAO,EAAE,SAAS,OAAO,OAAO,qBAAqB;AAAA,MACvD;AAEA,YAAM,eAAe,2BAA2B,qBAAqB,EAAE,SAAS;AAChF,YAAM,cAAc,SAAS,SAAS;AACtC,YAAM,gBAAgB,eAAe,2BAA2B,qBAAqB,EAAE,cAAc,SAAS,SAAS,QAAQ,UAAU;AAEzI,UAAI,eAAe,2BAA2B,qBAAqB,EAAE,cAAc,CAAC,eAAe;AACjG,eAAO,EAAE,SAAS,KAAK;AAAA,MACzB;AAEA,aAAO,KAAK,sBAAsB;AAAA,QAChC,MAAM,2BAA2B,qBAAqB,EAAE;AAAA,QACxD,IAAI;AAAA,QACJ,cAAc,SAAS;AAAA,QACvB,KAAK,SAAS;AAAA,QACd,OAAO;AAAA,MACT,CAAC;AAED,YAAM,iBAAiB,wBAAwB,UAAU,WAAW;AACpE,YAAM,YAAY,gBAAgB,cAAc;AAEhD,UAAI;AACF,cAAM,MAAM,SAAS,IAAI,SAAS,KAAK,IAAI,SAAS,IAAI,QAAQ,OAAO,EAAE,IAAI,SAAS;AACtF,wBAAgB,GAAG;AAEnB,YAAI,SAAS,YAAY,QAAQ;AAC/B,gBAAM,WAAW,MAAM,cAAc,GAAG;AACxC,oBAAU,WAAW,QAAQ;AAAA,QAC/B,OAAO;AACL,oBAAU,WAAW,SAAS,OAAqB;AAAA,QACrD;AAEA,YAAI,gBAAgB,QAAQ;AAC1B,gBAAM,WAAW,MAAM,YAAY,GAAG;AACtC,cAAI,UAAU;AACZ,sBAAU,SAAS,QAAQ;AAAA,UAC7B;AAAA,QACF,OAAO;AACL,oBAAU,SAAS,WAAW;AAAA,QAChC;AAEA,uBAAe,IAAI,YAAY,WAAW;AAAA,MAC5C,SAAS,KAAK;AACZ,eAAO,KAAK,iCAAiC;AAAA,UAC3C;AAAA,UACA,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACxD,CAAC;AACD,uBAAe,IAAI,YAAY,cAAc;AAAA,MAC/C;AAEA,kBAAY,UAAU,IAAI,QAAM;AAAA,QAC9B,GAAG;AAAA,QACH,UAAU,EAAE,OAAO;AAAA,MACrB,EAAE;AACF,8BAAwB,GAAG,UAAU,IAAI,WAAW;AACpD,kBAAY;AAEZ,aAAO,KAAK,sBAAsB;AAAA,QAChC;AAAA,QACA,cAAc,SAAS;AAAA,QACvB,OAAO,UAAU,SAAS;AAAA,QAC1B,SAAS,UAAU,WAAW;AAAA,MAChC,CAAC;AAED,aAAO,EAAE,SAAS,KAAK;AAAA,IACzB;AAAA,IAEA,YAAY,cAAc;AACxB,YAAM,KAAK,OAAO,WAAW;AAC7B,YAAM,WAAqB;AAAA,QACzB,GAAG;AAAA,QACH;AAAA,QACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAEA,UAAI,aAAa,YAAY,UAAU,WAAW,GAAG;AACnD,oBAAY,UAAU,IAAI,QAAM,EAAE,GAAG,GAAG,UAAU,MAAM,EAAE;AAC1D,iBAAS,WAAW;AACpB,gCAAwB,GAAG,EAAE;AAAA,MAC/B;AAEA,gBAAU,KAAK,QAAQ;AACvB,qBAAe,IAAI,IAAI,SAAS;AAEhC,aAAO;AAAA,IACT;AAAA,IAEA,eAAe,YAAY;AACzB,YAAM,QAAQ,UAAU,UAAU,OAAK,EAAE,OAAO,UAAU;AAC1D,UAAI,UAAU,GAAI,QAAO;AAEzB,YAAM,YAAY,UAAU,KAAK,GAAG;AACpC,gBAAU,OAAO,OAAO,CAAC;AACzB,qBAAe,OAAO,UAAU;AAEhC,UAAI,aAAa,UAAU,SAAS,GAAG;AACrC,kBAAU,CAAC,EAAG,WAAW;AACzB,gCAAwB,GAAG,UAAU,CAAC,EAAG,EAAE;AAAA,MAC7C,WAAW,UAAU,WAAW,GAAG;AACjC,gCAAwB;AAAA,MAC1B;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,aAAa,cAAc,0BAA0B;AACnD,kBAAY,CAAC,GAAG,YAAY;AAC5B,8BAAwB;AAExB,qBAAe,MAAM;AACrB,iBAAW,KAAK,WAAW;AACzB,uBAAe,IAAI,EAAE,IAAI,SAAS;AAAA,MACpC;AAAA,IACF;AAAA,IAEA,kBAAkB,YAAY;AAC5B,aAAO,eAAe,IAAI,UAAU,KAAK;AAAA,IAC3C;AAAA,IAEA,MAAM,kBAAkB,YAAuC;AAC7D,YAAM,WAAW,UAAU,KAAK,OAAK,EAAE,OAAO,UAAU;AACxD,UAAI,CAAC,UAAU;AACb,eAAO,CAAC;AAAA,MACV;AAEA,YAAM,MAAM,SAAS,IAAI,SAAS,KAAK,IAAI,SAAS,IAAI,QAAQ,OAAO,EAAE,IAAI,SAAS;AACtF,aAAO,gCAAgC,KAAK,SAAS,MAAM;AAAA,IAC7D;AAAA,IAEA,MAAM,yBAAyB,YAAoB,OAAe;AAChE,YAAM,WAAW,UAAU,KAAK,OAAK,EAAE,OAAO,UAAU;AACxD,UAAI,CAAC,UAAU;AACb,eAAO,EAAE,SAAS,OAAO,OAAO,qBAAqB;AAAA,MACvD;AAEA,aAAO,KAAK,mCAAmC,EAAE,YAAY,OAAO,cAAc,SAAS,KAAK,CAAC;AAEjG,8BAAwB,GAAG,UAAU,IAAI,KAAK;AAC9C,kBAAY,UAAU,IAAI,QAAM,EAAE,GAAG,GAAG,UAAU,EAAE,OAAO,WAAW,EAAE;AAExE,YAAM,oBAAoB,2BAA2B,qBAAqB,EAAE;AAC5E,UAAI,sBAAsB,YAAY;AACpC,kBAAU,SAAS,KAAK;AACxB,eAAO,KAAK,iBAAiB,EAAE,YAAY,MAAM,CAAC;AAAA,MACpD;AAEA,aAAO,EAAE,SAAS,KAAK;AAAA,IACzB;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/paths.ts"],"sourcesContent":["import { homedir, platform } from 'node:os'\nimport { join } from 'node:path'\nimport { mkdir, access } from 'node:fs/promises'\nimport type { Mode } from './main.js'\n\nexport function getGlobalConfigDir(mode: Mode): string {\n const suffix = mode === 'development' ? '-dev' : ''\n const home = homedir()\n \n switch (platform()) {\n case 'darwin':\n return join(home, 'Library', 'Application Support', `openfox${suffix}`)\n case 'win32':\n return join(process.env['APPDATA'] ?? join(home, 'AppData', 'Roaming'), `openfox${suffix}`)\n default:\n return join(process.env['XDG_CONFIG_HOME'] ?? join(home, '.config'), `openfox${suffix}`)\n }\n}\n\nexport function getGlobalConfigPath(mode: Mode): string {\n return join(getGlobalConfigDir(mode), 'config.json')\n}\n\nexport function getGlobalDataDir(mode: Mode): string {\n const suffix = mode === 'development' ? '-dev' : ''\n const home = homedir()\n \n switch (platform()) {\n case 'darwin':\n return join(home, 'Library', 'Application Support', `openfox${suffix}`)\n case 'win32':\n return join(process.env['LOCALAPPDATA'] ?? join(home, 'AppData', 'Local'), `openfox${suffix}`)\n default:\n return join(process.env['XDG_DATA_HOME'] ?? join(home, '.local', 'share'), `openfox${suffix}`)\n }\n}\n\nexport function getDatabasePath(mode: Mode): string {\n return join(getGlobalDataDir(mode), 'sessions.db')\n}\n\nexport function getSkillsDir(mode: Mode): string {\n return join(getGlobalConfigDir(mode), 'skills')\n}\n\nexport async function ensureDataDirExists(mode: Mode): Promise<void> {\n const dataDir = getGlobalDataDir(mode)\n try {\n await access(dataDir)\n } catch {\n await mkdir(dataDir, { recursive: true })\n }\n}\n"],"mappings":";AAAA,SAAS,SAAS,gBAAgB;AAClC,SAAS,YAAY;AACrB,SAAS,OAAO,cAAc;AAGvB,SAAS,mBAAmB,MAAoB;AACrD,QAAM,SAAS,SAAS,gBAAgB,SAAS;AACjD,QAAM,OAAO,QAAQ;AAErB,UAAQ,SAAS,GAAG;AAAA,IAClB,KAAK;AACH,aAAO,KAAK,MAAM,WAAW,uBAAuB,UAAU,MAAM,EAAE;AAAA,IACxE,KAAK;AACH,aAAO,KAAK,QAAQ,IAAI,SAAS,KAAK,KAAK,MAAM,WAAW,SAAS,GAAG,UAAU,MAAM,EAAE;AAAA,IAC5F;AACE,aAAO,KAAK,QAAQ,IAAI,iBAAiB,KAAK,KAAK,MAAM,SAAS,GAAG,UAAU,MAAM,EAAE;AAAA,EAC3F;AACF;AAEO,SAAS,oBAAoB,MAAoB;AACtD,SAAO,KAAK,mBAAmB,IAAI,GAAG,aAAa;AACrD;AAEO,SAAS,iBAAiB,MAAoB;AACnD,QAAM,SAAS,SAAS,gBAAgB,SAAS;AACjD,QAAM,OAAO,QAAQ;AAErB,UAAQ,SAAS,GAAG;AAAA,IAClB,KAAK;AACH,aAAO,KAAK,MAAM,WAAW,uBAAuB,UAAU,MAAM,EAAE;AAAA,IACxE,KAAK;AACH,aAAO,KAAK,QAAQ,IAAI,cAAc,KAAK,KAAK,MAAM,WAAW,OAAO,GAAG,UAAU,MAAM,EAAE;AAAA,IAC/F;AACE,aAAO,KAAK,QAAQ,IAAI,eAAe,KAAK,KAAK,MAAM,UAAU,OAAO,GAAG,UAAU,MAAM,EAAE;AAAA,EACjG;AACF;AAEO,SAAS,gBAAgB,MAAoB;AAClD,SAAO,KAAK,iBAAiB,IAAI,GAAG,aAAa;AACnD;AAEO,SAAS,aAAa,MAAoB;AAC/C,SAAO,KAAK,mBAAmB,IAAI,GAAG,QAAQ;AAChD;AAEA,eAAsB,oBAAoB,MAA2B;AACnE,QAAM,UAAU,iBAAiB,IAAI;AACrC,MAAI;AACF,UAAM,OAAO,OAAO;AAAA,EACtB,QAAQ;AACN,UAAM,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,EAC1C;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/main.ts"],"sourcesContent":["import { parseArgs } from 'node:util'\n\nexport type Mode = 'production' | 'development'\n\nexport function printHelp(): void {\n console.log(`\nOpenFox - Local LLM coding assistant\n\nUsage:\n openfox [command] [options]\n\nCommands:\n (none) Start server for current project\n init Interactive configuration setup\n config Show current configuration\n provider add Add a new LLM provider\n provider list List configured providers\n provider use Switch active provider\n provider remove Remove a provider\n\nOptions:\n -p, --port <number> Specify port (default: 10369 for prod, 10469 for dev)\n --no-browser Don't open browser on start\n -h, --help Show this help message\n -v, --version Show version number\n`)\n}\n\nexport async function runConfig(mode: Mode): Promise<void> {\n const { loadGlobalConfig, getActiveProvider, getDefaultModel } = await import('./config.js')\n const { getGlobalConfigPath } = await import('./paths.js')\n \n const config = await loadGlobalConfig(mode)\n const configPath = getGlobalConfigPath(mode)\n const activeProvider = getActiveProvider(config)\n const defaultModel = getDefaultModel(config)\n \n console.log(`Configuration (${mode}):`)\n console.log(` Location: ${configPath}`)\n console.log(` Providers: ${config.providers.length}`)\n if (activeProvider) {\n console.log(` Active: ${activeProvider.name}`)\n console.log(` URL: ${activeProvider.url}`)\n console.log(` Model: ${defaultModel ?? 'auto'}`)\n console.log(` Backend: ${activeProvider.backend}`)\n } else {\n console.log(` Active: (none configured)`)\n }\n \n // Display server host with human-readable description\n const hostDisplay = config.server.host === '0.0.0.0' \n ? `${config.server.host} (accessible from local network)`\n : `${config.server.host} (localhost only)`\n console.log(` Server: ${hostDisplay}`)\n console.log(` Port: ${config.server.port}`)\n}\n\nexport async function runCli(options: { mode: Mode }): Promise<void> {\n const { mode } = options\n \n const { values, positionals } = parseArgs({\n options: {\n port: { type: 'string', short: 'p' },\n 'no-browser': { type: 'boolean' },\n help: { type: 'boolean', short: 'h' },\n version: { type: 'boolean', short: 'v' },\n },\n allowPositionals: true,\n strict: true,\n })\n\n if (values.help) {\n printHelp()\n process.exit(0)\n }\n\n if (values.version) {\n console.log('0.1.0')\n process.exit(0)\n }\n\n const [command] = positionals\n\n switch (command) {\n case 'init': {\n const { runInitWithSelect } = await import('./init.js')\n const { loadGlobalConfig, getActiveProvider } = await import('./config.js')\n const config = await loadGlobalConfig(mode)\n const activeProvider = getActiveProvider(config)\n if (activeProvider) {\n console.log(`Current provider: ${activeProvider.name} (${activeProvider.url})\\n`)\n }\n // Pass existing config to init for potential preservation\n await runInitWithSelect(mode, config)\n break\n }\n case 'config': {\n await runConfig(mode)\n break\n }\n case 'provider': {\n const { runProviderCommand } = await import('./provider.js')\n const [, subcommand] = positionals\n await runProviderCommand(mode, subcommand)\n break\n }\n default: {\n // Check if config exists - only run wizard on first install\n const { configFileExists } = await import('./config.js')\n const configExists = await configFileExists(mode)\n \n if (!configExists) {\n // First run - show welcome message\n console.log('Welcome to OpenFox!\\n')\n \n // Try smart defaults in parallel (silent - no logs)\n const { trySmartDefaults, saveGlobalConfig, addProvider } = await import('./config.js')\n const detected = await trySmartDefaults(mode)\n \n if (detected) {\n console.log(`✓ Found ${detected.backend} (${detected.model}) at ${detected.url}`)\n const baseConfig = {\n providers: [],\n server: { port: 10369, host: '127.0.0.1', openBrowser: true },\n logging: { level: 'info' as const },\n database: { path: '' },\n workspace: { workdir: process.cwd() },\n }\n const configWithProvider = addProvider(baseConfig, {\n name: 'Default',\n url: detected.url,\n backend: detected.backend as 'auto' | 'vllm' | 'sglang' | 'ollama' | 'llamacpp',\n maxContext: 200000,\n isActive: true,\n })\n // Set the default model selection after adding provider\n const { setDefaultModelSelection } = await import('./config.js')\n const finalConfig = setDefaultModelSelection(configWithProvider, configWithProvider.providers[0]!.id, detected.model)\n await saveGlobalConfig(mode, finalConfig)\n console.log('Configuration saved!\\n')\n } else {\n console.log('✗ No LLM server detected\\n')\n const { runInitWithSelect } = await import('./init.js')\n await runInitWithSelect(mode)\n }\n }\n \n const { runServe } = await import('./serve.js')\n await runServe({\n mode,\n port: values.port ? parseInt(values.port) : undefined,\n openBrowser: !values['no-browser'],\n } as any)\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/llm/backend.ts","../src/server/llm/models.ts","../src/server/llm/client.ts","../src/server/utils/errors.ts","../src/server/llm/profiles.ts","../src/server/llm/client-pure.ts"],"sourcesContent":["/**\n * LLM Backend detection and capabilities.\n * Supports vLLM, SGLang, Ollama, and llama.cpp inference engines.\n */\n\nimport { logger } from '../utils/logger.js'\n\nexport type Backend = 'vllm' | 'sglang' | 'ollama' | 'llamacpp' | 'unknown'\n\nexport interface BackendCapabilities {\n /** Whether the backend returns reasoning_content as a separate field (vLLM/SGLang) */\n supportsReasoningField: boolean\n /** Whether chat_template_kwargs with enable_thinking works (vLLM/SGLang) */\n supportsChatTemplateKwargs: boolean\n /** Whether top_k parameter is supported in OpenAI-compatible mode */\n supportsTopK: boolean\n}\n\nconst BACKEND_CAPABILITIES: Record<Backend, BackendCapabilities> = {\n vllm: {\n supportsReasoningField: true,\n supportsChatTemplateKwargs: true,\n supportsTopK: true,\n },\n sglang: {\n supportsReasoningField: true,\n supportsChatTemplateKwargs: true,\n supportsTopK: true,\n },\n ollama: {\n supportsReasoningField: false,\n supportsChatTemplateKwargs: false,\n supportsTopK: false,\n },\n llamacpp: {\n supportsReasoningField: false,\n supportsChatTemplateKwargs: false,\n supportsTopK: true,\n },\n unknown: {\n // Assume vLLM-like for unknown backends\n supportsReasoningField: true,\n supportsChatTemplateKwargs: true,\n supportsTopK: true,\n },\n}\n\nexport function getBackendCapabilities(backend: Backend): BackendCapabilities {\n return BACKEND_CAPABILITIES[backend]\n}\n\n/**\n * Detect which LLM backend is running at the given URL.\n * \n * Detection order:\n * 1. Ollama: /api/tags endpoint exists\n * 2. llama.cpp: /health returns slots_idle/slots_processing\n * 3. SGLang: /get_model_info endpoint exists\n * 4. vLLM: /v1/models works (default for OpenAI-compatible)\n * 5. unknown: nothing responds\n * \n * @param silent - If true, use debug logging instead of info/warn (for auto-detection)\n */\nexport async function detectBackend(\n baseUrl: string,\n explicitBackend?: Backend,\n silent = false\n): Promise<Backend> {\n // Allow explicit override\n if (explicitBackend && explicitBackend !== 'unknown') {\n if (silent) {\n logger.debug('Using explicit backend', { backend: explicitBackend })\n } else {\n logger.info('Using explicit backend', { backend: explicitBackend })\n }\n return explicitBackend\n }\n\n // Normalize URL - remove /v1 suffix if present for probing\n const probeUrl = baseUrl.replace(/\\/v1\\/?$/, '')\n\n try {\n // 1. Check for Ollama\n if (await probeOllama(probeUrl)) {\n if (silent) {\n logger.debug('Detected Ollama backend', { url: probeUrl })\n } else {\n logger.info('Detected Ollama backend', { url: probeUrl })\n }\n return 'ollama'\n }\n\n // 2. Check for llama.cpp\n if (await probeLlamaCpp(probeUrl)) {\n if (silent) {\n logger.debug('Detected llama.cpp backend', { url: probeUrl })\n } else {\n logger.info('Detected llama.cpp backend', { url: probeUrl })\n }\n return 'llamacpp'\n }\n\n // 3. Check for SGLang\n if (await probeSGLang(probeUrl)) {\n if (silent) {\n logger.debug('Detected SGLang backend', { url: probeUrl })\n } else {\n logger.info('Detected SGLang backend', { url: probeUrl })\n }\n return 'sglang'\n }\n\n // 4. Check for vLLM (or any OpenAI-compatible)\n if (await probeOpenAI(baseUrl)) {\n if (silent) {\n logger.debug('Detected vLLM backend (OpenAI-compatible)', { url: baseUrl })\n } else {\n logger.info('Detected vLLM backend (OpenAI-compatible)', { url: baseUrl })\n }\n return 'vllm'\n }\n\n if (silent) {\n logger.debug('Could not detect backend, using unknown', { url: baseUrl })\n } else {\n logger.warn('Could not detect backend, using unknown', { url: baseUrl })\n }\n return 'unknown'\n } catch (error) {\n if (silent) {\n logger.debug('Backend detection failed', { \n url: baseUrl, \n error: error instanceof Error ? error.message : String(error) \n })\n } else {\n logger.warn('Backend detection failed', { \n url: baseUrl, \n error: error instanceof Error ? error.message : String(error) \n })\n }\n return 'unknown'\n }\n}\n\nasync function probeOllama(baseUrl: string): Promise<boolean> {\n try {\n const response = await fetch(`${baseUrl}/api/tags`, {\n signal: AbortSignal.timeout(5000),\n })\n return response.ok\n } catch {\n return false\n }\n}\n\nasync function probeLlamaCpp(baseUrl: string): Promise<boolean> {\n try {\n const response = await fetch(`${baseUrl}/health`, {\n signal: AbortSignal.timeout(5000),\n })\n if (!response.ok) return false\n \n const data = await response.json() as Record<string, unknown>\n // llama.cpp health returns slots_idle and slots_processing\n return 'slots_idle' in data || 'slots_processing' in data\n } catch {\n return false\n }\n}\n\nasync function probeSGLang(baseUrl: string): Promise<boolean> {\n try {\n const response = await fetch(`${baseUrl}/get_model_info`, {\n signal: AbortSignal.timeout(5000),\n })\n return response.ok\n } catch {\n return false\n }\n}\n\nasync function probeOpenAI(baseUrl: string): Promise<boolean> {\n try {\n // Ensure URL has /v1 for OpenAI-compatible endpoint\n const url = baseUrl.includes('/v1') ? baseUrl : `${baseUrl}/v1`\n const response = await fetch(`${url}/models`, {\n signal: AbortSignal.timeout(5000),\n })\n return response.ok\n } catch {\n return false\n }\n}\n\n/** Display name for each backend */\nexport function getBackendDisplayName(backend: Backend): string {\n switch (backend) {\n case 'vllm': return 'vLLM'\n case 'sglang': return 'SGLang'\n case 'ollama': return 'Ollama'\n case 'llamacpp': return 'llama.cpp'\n case 'unknown': return 'Unknown'\n }\n}\n","import { logger } from '../utils/logger.js'\n\nexport interface LlmModel {\n id: string\n object: string\n created: number\n owned_by: string\n root?: string\n max_model_len?: number\n}\n\nexport interface ModelsResponse {\n object: string\n data: LlmModel[]\n}\n\nexport type LlmStatus = 'connected' | 'disconnected' | 'unknown'\n\n// URL-keyed cache to support multiple providers\ninterface ModelCacheEntry {\n model: string\n modelInfo: LlmModel\n timestamp: number\n}\nconst modelCache = new Map<string, ModelCacheEntry>()\nlet llmStatus: LlmStatus = 'unknown'\nlet lastActiveUrl: string | null = null\nconst CACHE_TTL_MS = 30_000 // 30 seconds\n\n/** Normalize URL for cache key (strip /v1 suffix) */\nfunction getCacheKey(url: string): string {\n return url.replace(/\\/v1\\/?$/, '')\n}\n\n/**\n * Detect model from LLM server.\n * \n * @param silent - If true, use debug logging instead of info/warn (for auto-detection)\n */\nexport async function detectModel(llmBaseUrl: string, retries = 3, silent = false): Promise<string | null> {\n const cacheKey = getCacheKey(llmBaseUrl)\n \n // Return cached model if still fresh for this URL\n const now = Date.now()\n const cached = modelCache.get(cacheKey)\n if (cached && now - cached.timestamp < CACHE_TTL_MS) {\n lastActiveUrl = cacheKey\n llmStatus = 'connected'\n return cached.model\n }\n \n // Ensure URL has /v1 for OpenAI-compatible endpoint\n const url = llmBaseUrl.includes('/v1') ? `${llmBaseUrl}/models` : `${llmBaseUrl}/v1/models`\n \n for (let attempt = 1; attempt <= retries; attempt++) {\n try {\n if (silent) {\n logger.debug('Fetching models from LLM server', { url, attempt })\n }\n \n const response = await fetch(url, {\n signal: AbortSignal.timeout(10000),\n })\n \n if (!response.ok) {\n if (silent) {\n logger.debug('Failed to fetch models from LLM server', { status: response.status, attempt })\n } else {\n logger.warn('Failed to fetch models from LLM server', { status: response.status, attempt })\n }\n if (attempt < retries) {\n await new Promise(r => setTimeout(r, 1000 * attempt))\n continue\n }\n llmStatus = 'disconnected'\n return cached?.model ?? null\n }\n \n const data = await response.json() as ModelsResponse\n \n if (data.data && data.data.length > 0) {\n // Get the first (usually only) model\n const modelData = data.data[0]!\n const modelId = modelData.id\n \n // Cache with URL as key\n modelCache.set(cacheKey, {\n model: modelId,\n modelInfo: modelData,\n timestamp: now,\n })\n lastActiveUrl = cacheKey\n llmStatus = 'connected'\n \n if (silent) {\n logger.debug('Detected LLM model', { \n model: modelId,\n maxLen: modelData.max_model_len,\n root: modelData.root\n })\n } else {\n logger.info('Detected LLM model', { \n model: modelId,\n maxLen: modelData.max_model_len,\n root: modelData.root\n })\n }\n return modelId\n }\n \n if (silent) {\n logger.debug('LLM server returned empty models list')\n } else {\n logger.warn('LLM server returned empty models list')\n }\n llmStatus = 'disconnected'\n return null\n } catch (error) {\n const errMsg = error instanceof Error ? error.message : String(error)\n if (silent) {\n logger.debug('Could not detect model from LLM server', { error: errMsg, attempt })\n } else {\n logger.warn('Could not detect model from LLM server', { error: errMsg, attempt })\n }\n \n if (attempt < retries) {\n await new Promise(r => setTimeout(r, 1000 * attempt))\n continue\n }\n }\n }\n \n llmStatus = 'disconnected'\n return cached?.model ?? null\n}\n\nexport function getModelInfo(): LlmModel | null {\n if (!lastActiveUrl) return null\n return modelCache.get(lastActiveUrl)?.modelInfo ?? null\n}\n\nexport function getCachedModel(): string | null {\n if (!lastActiveUrl) return null\n return modelCache.get(lastActiveUrl)?.model ?? null\n}\n\nexport function getLlmStatus(): LlmStatus {\n return llmStatus\n}\n\n/**\n * Clear model cache for a specific URL, or all if no URL provided.\n */\nexport function clearModelCache(url?: string): void {\n if (url) {\n modelCache.delete(getCacheKey(url))\n } else {\n modelCache.clear()\n }\n llmStatus = 'unknown'\n}\n","import OpenAI from 'openai'\nimport type { ChatCompletionMessageParam, ChatCompletionTool, ChatCompletionToolChoiceOption } from 'openai/resources/chat/completions'\nimport type { Config } from '../config.js'\nimport type {\n LLMClient,\n LLMMessage,\n LLMToolDefinition,\n LLMCompletionRequest,\n LLMCompletionResponse,\n LLMStreamEvent,\n} from './types.js'\nimport type { ToolCall } from '../../shared/types.js'\nimport { logger } from '../utils/logger.js'\nimport { LLMError } from '../utils/errors.js'\nimport { getModelProfile, type ModelProfile } from './profiles.js'\nimport { type Backend, type BackendCapabilities, getBackendCapabilities } from './backend.js'\nimport {\n buildNonStreamingCreateParams,\n buildStreamingCreateParams,\n extractThinking,\n mapFinishReason,\n} from './client-pure.js'\n\nexport interface LLMClientWithModel extends LLMClient {\n getModel(): string\n setModel(model: string): void\n getProfile(): ModelProfile\n getBackend(): Backend\n setBackend(backend: Backend): void\n}\n\nexport function createLLMClient(config: Config, initialBackend: Backend = 'unknown'): LLMClientWithModel {\n // Ensure baseURL includes /v1 for OpenAI-compatible endpoint\n const baseURL = config.llm.baseUrl.includes('/v1') \n ? config.llm.baseUrl \n : `${config.llm.baseUrl}/v1`\n \n const openai = new OpenAI({\n baseURL,\n apiKey: 'not-needed', // Most local backends don't require API key\n })\n \n let model = config.llm.model\n let profile = getModelProfile(model)\n let backend = initialBackend\n let capabilities = getBackendCapabilities(backend)\n const disableThinking = config.llm.disableThinking ?? false\n const idleTimeout = config.llm.idleTimeout ?? 30_000\n \n return {\n getModel() {\n return model\n },\n \n getProfile() {\n return profile\n },\n \n getBackend() {\n return backend\n },\n \n setBackend(newBackend: Backend) {\n logger.debug('Setting LLM backend', { from: backend, to: newBackend })\n backend = newBackend\n capabilities = getBackendCapabilities(newBackend)\n },\n \n setModel(newModel: string) {\n const newProfile = getModelProfile(newModel)\n logger.debug('Switching model', { \n from: model, \n to: newModel,\n profile: newProfile.name,\n temperature: newProfile.temperature,\n supportsReasoning: newProfile.supportsReasoning,\n })\n model = newModel\n profile = newProfile\n },\n\n async complete(request: LLMCompletionRequest): Promise<LLMCompletionResponse> {\n logger.debug('LLM complete request', { \n messageCount: request.messages.length,\n hasTools: !!request.tools?.length,\n profile: profile.name,\n disableThinking,\n })\n \n try {\n const shouldDisableThinking = disableThinking || request.disableThinking === true\n const createParams = buildNonStreamingCreateParams({\n model, \n request, \n profile, \n capabilities, \n disableThinking: shouldDisableThinking,\n })\n const response = await openai.chat.completions.create(createParams, {\n signal: request.signal,\n })\n \n const choice = response.choices[0]\n if (!choice) {\n throw new LLMError('No completion choice returned')\n }\n \n // Handle reasoning output - different backends return it differently\n const message = choice.message as {\n content?: string | null\n reasoning_content?: string | null\n reasoning?: string | null\n tool_calls?: Array<{ id: string; function: { name: string; arguments: string } }>\n }\n \n let content = message.content ?? ''\n let thinkingContent = ''\n \n // Only process reasoning if model supports it\n if (profile.supportsReasoning) {\n if (capabilities.supportsReasoningField) {\n // vLLM/SGLang: use reasoning_content field\n thinkingContent = message.reasoning_content ?? message.reasoning ?? ''\n } else {\n // Ollama/llama.cpp: extract <think> tags from content\n const extracted = extractThinking(content)\n content = extracted.content\n thinkingContent = extracted.thinkingContent ?? ''\n }\n \n // If model outputs reasoning as content (broken config), handle it\n if (profile.reasoningAsContent && thinkingContent.trim()) {\n content = thinkingContent\n thinkingContent = ''\n }\n }\n \n // Fallback: if content is empty but reasoning has content, use reasoning as content\n if (!content.trim() && thinkingContent.trim()) {\n content = thinkingContent\n thinkingContent = ''\n }\n \n const toolCalls = message.tool_calls?.map(tc => ({\n id: tc.id,\n name: tc.function.name,\n arguments: JSON.parse(tc.function.arguments) as Record<string, unknown>,\n }))\n \n return {\n id: response.id,\n content,\n ...(thinkingContent ? { thinkingContent } : {}),\n ...(toolCalls && toolCalls.length > 0 ? { toolCalls } : {}),\n finishReason: mapFinishReason(choice.finish_reason),\n usage: {\n promptTokens: response.usage?.prompt_tokens ?? 0,\n completionTokens: response.usage?.completion_tokens ?? 0,\n totalTokens: response.usage?.total_tokens ?? 0,\n },\n }\n } catch (error: any) {\n logger.error('LLM complete error', { error: error.toString() })\n throw new LLMError(\n error instanceof Error ? error.message : 'Unknown LLM error',\n { originalError: error }\n )\n }\n },\n \n async *stream(request: LLMCompletionRequest): AsyncIterable<LLMStreamEvent> {\n logger.debug('LLM stream request', {\n messageCount: request.messages.length,\n hasTools: !!request.tools?.length,\n profile: profile.name,\n disableThinking,\n idleTimeout,\n })\n \n try {\n // Disable thinking if configured globally or requested per-call\n const shouldDisableThinking = disableThinking || request.disableThinking === true\n \n const createParams = buildStreamingCreateParams({ model, request, profile, capabilities, disableThinking: shouldDisableThinking })\n \n const stream = await openai.chat.completions.create(createParams, {\n signal: request.signal,\n })\n \n let fullContent = ''\n let fullThinking = ''\n let inThinking = false\n let tagBuffer = '' // Buffer for parsing <think> tags across chunk boundaries\n const toolCalls: Map<number, { id: string; name: string; arguments: string }> = new Map()\n let finishReason: LLMCompletionResponse['finishReason'] = 'stop'\n let usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 }\n let responseId = ''\n \n // Idle timeout tracking\n let lastChunkTime = Date.now()\n const idleTimeoutController = new AbortController()\n \n // Start idle timeout timer\n const idleTimer = setInterval(() => {\n const idleDuration = Date.now() - lastChunkTime\n if (idleDuration > idleTimeout) {\n logger.warn('LLM stream idle timeout triggered', { idleDuration, idleTimeout })\n idleTimeoutController.abort()\n }\n }, 100) // Check every 100ms\n \n try {\n for await (const chunk of stream) {\n // Check if idle timeout was triggered\n if (idleTimeoutController.signal.aborted) {\n throw new Error(`LLM stream idle timeout: no chunks received for ${idleTimeout}ms`)\n }\n \n // Reset idle timer on each chunk\n lastChunkTime = Date.now()\n \n responseId = chunk.id\n \n if (chunk.usage) {\n usage = {\n promptTokens: chunk.usage.prompt_tokens,\n completionTokens: chunk.usage.completion_tokens,\n totalTokens: chunk.usage.total_tokens,\n }\n }\n \n const choice = chunk.choices[0]\n if (!choice) continue\n \n if (choice.finish_reason) {\n finishReason = mapFinishReason(choice.finish_reason)\n }\n \n const delta = choice.delta as {\n content?: string | null\n reasoning_content?: string | null\n reasoning?: string | null\n tool_calls?: Array<{\n index: number\n id?: string\n function?: { name?: string; arguments?: string }\n }>\n }\n \n // Handle reasoning/thinking delta\n // vLLM/SGLang: reasoning comes as separate field\n // Ollama/llama.cpp: reasoning is embedded as <think> tags in content\n if (capabilities.supportsReasoningField) {\n const reasoning = delta.reasoning_content ?? delta.reasoning\n if (reasoning) {\n // Only emit thinking if model supports reasoning\n if (profile.supportsReasoning && !profile.reasoningAsContent) {\n fullThinking += reasoning\n yield { type: 'thinking_delta', content: reasoning }\n } else {\n // Model doesn't support reasoning or outputs it as content\n fullContent += reasoning\n yield { type: 'text_delta', content: reasoning }\n }\n }\n }\n \n // Handle content delta\n if (delta.content) {\n fullContent += delta.content\n\n // For backends without reasoning field (ollama/llama.cpp), parse <think> tags in real-time\n if (!capabilities.supportsReasoningField && profile.supportsReasoning && !profile.reasoningAsContent) {\n // Feed content through the think tag parser\n tagBuffer += delta.content\n\n while (tagBuffer.length > 0) {\n if (inThinking) {\n // Look for </think>\n const closeIdx = tagBuffer.indexOf('</think>')\n if (closeIdx !== -1) {\n // Emit thinking content before the close tag\n const thinkText = tagBuffer.slice(0, closeIdx)\n if (thinkText) {\n fullThinking += thinkText\n yield { type: 'thinking_delta', content: thinkText }\n }\n tagBuffer = tagBuffer.slice(closeIdx + '</think>'.length)\n inThinking = false\n } else if (tagBuffer.includes('</')) {\n // Might be a partial </think> tag - emit everything before it\n const partialIdx = tagBuffer.lastIndexOf('</')\n const before = tagBuffer.slice(0, partialIdx)\n if (before) {\n fullThinking += before\n yield { type: 'thinking_delta', content: before }\n }\n tagBuffer = tagBuffer.slice(partialIdx)\n break // wait for more data\n } else {\n // No close tag at all, emit all as thinking\n fullThinking += tagBuffer\n yield { type: 'thinking_delta', content: tagBuffer }\n tagBuffer = ''\n }\n } else {\n // Look for <think>\n const openIdx = tagBuffer.indexOf('<think>')\n if (openIdx !== -1) {\n // Emit text content before the open tag\n const textBefore = tagBuffer.slice(0, openIdx)\n if (textBefore) {\n yield { type: 'text_delta', content: textBefore }\n }\n tagBuffer = tagBuffer.slice(openIdx + '<think>'.length)\n inThinking = true\n } else if (tagBuffer.includes('<')) {\n // Might be a partial <think> tag - emit everything before it\n const partialIdx = tagBuffer.lastIndexOf('<')\n const before = tagBuffer.slice(0, partialIdx)\n if (before) {\n yield { type: 'text_delta', content: before }\n }\n tagBuffer = tagBuffer.slice(partialIdx)\n break // wait for more data\n } else {\n // No open tag at all, emit all as text\n yield { type: 'text_delta', content: tagBuffer }\n tagBuffer = ''\n }\n }\n }\n } else {\n yield { type: 'text_delta', content: delta.content }\n }\n }\n \n // Handle tool call deltas\n if (delta.tool_calls) {\n for (const tc of delta.tool_calls) {\n const existing = toolCalls.get(tc.index)\n \n if (!existing) {\n toolCalls.set(tc.index, {\n id: tc.id ?? '',\n name: tc.function?.name ?? '',\n arguments: tc.function?.arguments ?? '',\n })\n } else {\n if (tc.id) existing.id = tc.id\n if (tc.function?.name) existing.name += tc.function.name\n if (tc.function?.arguments) existing.arguments += tc.function.arguments\n }\n \n yield {\n type: 'tool_call_delta' as const,\n index: tc.index,\n ...(tc.id ? { id: tc.id } : {}),\n ...(tc.function?.name ? { name: tc.function.name } : {}),\n ...(tc.function?.arguments ? { arguments: tc.function.arguments } : {}),\n }\n }\n }\n }\n } finally {\n clearInterval(idleTimer)\n }\n \n // Flush any remaining tag buffer content\n if (tagBuffer) {\n if (inThinking) {\n fullThinking += tagBuffer\n }\n tagBuffer = ''\n }\n\n // For backends without reasoning field, extract <think> tags from accumulated content\n let finalContent = fullContent.trim()\n let finalThinking = fullThinking.trim()\n \n if (!capabilities.supportsReasoningField && profile.supportsReasoning) {\n const extracted = extractThinking(finalContent)\n finalContent = extracted.content\n finalThinking = extracted.thinkingContent ?? ''\n }\n \n // If content is empty but we have thinking, use thinking as content\n // (some models output everything as reasoning)\n if (!finalContent && finalThinking) {\n finalContent = finalThinking\n finalThinking = ''\n }\n \n // Parse tool calls\n const parsedToolCalls: ToolCall[] = []\n for (const [, tc] of toolCalls) {\n try {\n parsedToolCalls.push({\n id: tc.id,\n name: tc.name,\n arguments: JSON.parse(tc.arguments) as Record<string, unknown>,\n })\n } catch (error) {\n logger.warn('Failed to parse tool call arguments', { name: tc.name, arguments: tc.arguments })\n // Include the failed tool call with error metadata so the LLM can retry\n parsedToolCalls.push({\n id: tc.id,\n name: tc.name,\n arguments: {},\n parseError: error instanceof Error ? error.message : 'Unknown JSON parse error',\n rawArguments: tc.arguments,\n })\n }\n }\n \n yield {\n type: 'done',\n response: {\n id: responseId,\n content: finalContent,\n ...(finalThinking ? { thinkingContent: finalThinking } : {}),\n ...(parsedToolCalls.length > 0 ? { toolCalls: parsedToolCalls } : {}),\n finishReason,\n usage,\n },\n }\n } catch (error) {\n logger.error('LLM stream error', { error })\n yield {\n type: 'error',\n error: error instanceof Error ? error.message : 'Unknown LLM error',\n }\n }\n },\n }\n}\n","export class OpenFoxError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly details?: unknown\n ) {\n super(message)\n this.name = 'OpenFoxError'\n }\n}\n\nexport class SessionNotFoundError extends OpenFoxError {\n constructor(sessionId: string) {\n super(`Session not found: ${sessionId}`, 'SESSION_NOT_FOUND', { sessionId })\n this.name = 'SessionNotFoundError'\n }\n}\n\nexport class InvalidPhaseTransitionError extends OpenFoxError {\n constructor(from: string, to: string) {\n super(`Invalid phase transition: ${from} -> ${to}`, 'INVALID_PHASE_TRANSITION', { from, to })\n this.name = 'InvalidPhaseTransitionError'\n }\n}\n\nexport class ToolExecutionError extends OpenFoxError {\n constructor(tool: string, message: string, details?: unknown) {\n super(`Tool '${tool}' failed: ${message}`, 'TOOL_EXECUTION_ERROR', { tool, ...details as object })\n this.name = 'ToolExecutionError'\n }\n}\n\nexport class LLMError extends OpenFoxError {\n constructor(message: string, details?: unknown) {\n super(message, 'LLM_ERROR', details)\n this.name = 'LLMError'\n }\n}\n\nexport class ValidationError extends OpenFoxError {\n constructor(message: string, details?: unknown) {\n super(message, 'VALIDATION_ERROR', details)\n this.name = 'ValidationError'\n }\n}\n\nexport function isRetryableError(error: unknown): boolean {\n if (error instanceof OpenFoxError) {\n return ['LLM_ERROR', 'TOOL_EXECUTION_ERROR'].includes(error.code)\n }\n return false\n}\n","/**\n * Model-specific configuration profiles.\n * Different models have different optimal settings and capabilities.\n */\n\nexport interface ModelProfile {\n /** Display name for the model */\n name: string\n \n /** Sampling parameters */\n temperature: number\n topP: number\n topK?: number\n \n /** Whether the model outputs reasoning/thinking content */\n supportsReasoning: boolean\n \n /** Whether reasoning should be treated as regular content (for broken configs) */\n reasoningAsContent: boolean\n \n /** Max tokens to generate if not specified */\n defaultMaxTokens: number\n}\n\n/** Default profile for unknown models */\nconst DEFAULT_PROFILE: ModelProfile = {\n name: 'default',\n temperature: 0.7,\n topP: 0.9,\n supportsReasoning: false,\n reasoningAsContent: false,\n defaultMaxTokens: 4096,\n}\n\n/** Profile for mock LLM testing */\nconst MOCK_PROFILE: ModelProfile = {\n name: 'mock',\n temperature: 0.7,\n topP: 0.9,\n supportsReasoning: false,\n reasoningAsContent: false,\n defaultMaxTokens: 1024,\n}\n\n/** \n * Model profiles indexed by model name patterns.\n * Patterns are matched against the model name (case-insensitive, partial match).\n */\nconst MODEL_PROFILES: Array<{ pattern: string; profile: ModelProfile }> = [\n {\n pattern: 'mistral',\n profile: {\n name: 'Mistral',\n temperature: 0.7,\n topP: 0.9,\n supportsReasoning: false,\n reasoningAsContent: false,\n defaultMaxTokens: 4096,\n },\n },\n {\n pattern: 'qwen3-coder-next',\n profile: {\n name: 'Qwen3-Coder-Next',\n // Per Qwen docs: \"temperature=1.0, top_p=0.95, top_k=40\"\n temperature: 1.0,\n topP: 0.95,\n topK: 40,\n // \"This model supports only non-thinking mode and does not generate <think></think> blocks\"\n supportsReasoning: false,\n reasoningAsContent: false,\n defaultMaxTokens: 8192,\n },\n },\n {\n pattern: 'qwen3',\n profile: {\n name: 'Qwen3',\n temperature: 0.7,\n topP: 0.9,\n supportsReasoning: true,\n reasoningAsContent: false,\n defaultMaxTokens: 4096,\n },\n },\n {\n pattern: 'deepseek',\n profile: {\n name: 'DeepSeek',\n temperature: 0.6,\n topP: 0.95,\n supportsReasoning: true,\n reasoningAsContent: false,\n defaultMaxTokens: 4096,\n },\n },\n {\n pattern: 'llama',\n profile: {\n name: 'Llama',\n temperature: 0.7,\n topP: 0.9,\n supportsReasoning: false,\n reasoningAsContent: false,\n defaultMaxTokens: 4096,\n },\n },\n {\n pattern: 'claude',\n profile: {\n name: 'Claude',\n temperature: 0.7,\n topP: 0.9,\n supportsReasoning: true,\n reasoningAsContent: false,\n defaultMaxTokens: 4096,\n },\n },\n]\n\n/**\n * Get the profile for a model by name.\n * Matches patterns in order, returns first match or default.\n */\nexport function getModelProfile(modelName: string): ModelProfile {\n const lowerName = modelName.toLowerCase()\n \n // Mock model\n if (lowerName.includes('mock')) {\n return MOCK_PROFILE\n }\n \n for (const { pattern, profile } of MODEL_PROFILES) {\n if (lowerName.includes(pattern.toLowerCase())) {\n return profile\n }\n }\n \n return DEFAULT_PROFILE\n}\n\n/**\n * Check if a model supports reasoning/thinking output.\n */\nexport function modelSupportsReasoning(modelName: string): boolean {\n return getModelProfile(modelName).supportsReasoning\n}\n","import type OpenAI from 'openai'\nimport type {\n ChatCompletionMessageParam,\n ChatCompletionTool,\n ChatCompletionToolChoiceOption,\n} from 'openai/resources/chat/completions'\nimport type { LLMCompletionRequest, LLMCompletionResponse, LLMMessage, LLMToolDefinition } from './types.js'\nimport type { ModelProfile } from './profiles.js'\nimport type { BackendCapabilities } from './backend.js'\nimport { logger } from '../utils/logger.js'\n\ntype MinimalCapabilities = Pick<BackendCapabilities, 'supportsTopK' | 'supportsChatTemplateKwargs'>\ntype MinimalProfile = Pick<ModelProfile, 'temperature' | 'defaultMaxTokens' | 'topP' | 'topK' | 'supportsReasoning'>\n\nexport function convertMessages(messages: LLMMessage[]): ChatCompletionMessageParam[] {\n const filtered = messages.filter((msg) => {\n return !(msg.role === 'assistant' && !msg.content?.trim() && !msg.toolCalls?.length)\n })\n\n return filtered.map((msg): ChatCompletionMessageParam => {\n if (msg.role === 'tool') {\n return {\n role: 'tool',\n content: msg.content,\n tool_call_id: msg.toolCallId!,\n }\n }\n\n if (msg.role === 'assistant' && msg.toolCalls?.length) {\n return {\n role: 'assistant',\n content: msg.content || null,\n tool_calls: msg.toolCalls.map((toolCall) => ({\n id: toolCall.id,\n type: 'function',\n function: {\n name: toolCall.name,\n arguments: JSON.stringify(toolCall.arguments),\n },\n })),\n }\n }\n\n // Handle user messages with attachments\n if (msg.role === 'user' && msg.attachments && msg.attachments.length > 0) {\n const content: Array<{ type: 'text'; text: string } | { type: 'image_url'; image_url: { url: string } }> = []\n\n // Add text content if present\n if (msg.content?.trim()) {\n content.push({ type: 'text', text: msg.content })\n }\n\n // Add attachments as image URLs\n for (const attachment of msg.attachments) {\n content.push({\n type: 'image_url',\n image_url: {\n url: attachment.data, // base64 data URL\n },\n })\n }\n\n return {\n role: 'user',\n content,\n }\n }\n\n return {\n role: msg.role as 'system' | 'user' | 'assistant',\n content: msg.content,\n }\n })\n}\n\nexport function convertTools(tools: LLMToolDefinition[]): ChatCompletionTool[] {\n return tools.map((tool) => ({\n type: 'function',\n function: {\n name: tool.function.name,\n description: tool.function.description,\n parameters: tool.function.parameters,\n },\n }))\n}\n\nexport function buildNonStreamingCreateParams(input: {\n model: string\n request: LLMCompletionRequest\n profile: MinimalProfile\n capabilities: MinimalCapabilities\n disableThinking?: boolean\n}): OpenAI.ChatCompletionCreateParamsNonStreaming {\n const { model, request, profile, capabilities, disableThinking } = input\n const params: OpenAI.ChatCompletionCreateParamsNonStreaming = {\n model,\n messages: convertMessages(request.messages),\n ...(request.tools ? { tools: convertTools(request.tools) } : {}),\n ...(request.toolChoice ? { tool_choice: request.toolChoice as ChatCompletionToolChoiceOption } : {}),\n temperature: request.temperature ?? profile.temperature,\n max_tokens: request.maxTokens ?? profile.defaultMaxTokens,\n top_p: profile.topP,\n stream: false,\n }\n\n if (capabilities.supportsTopK && profile.topK !== undefined) {\n ;(params as unknown as Record<string, unknown>)['top_k'] = profile.topK\n }\n\n if (capabilities.supportsChatTemplateKwargs && profile.supportsReasoning && disableThinking) {\n ;(params as unknown as Record<string, unknown>)['chat_template_kwargs'] = { enable_thinking: false }\n }\n\n return params\n}\n\nexport function buildStreamingCreateParams(input: {\n model: string\n request: LLMCompletionRequest\n profile: MinimalProfile\n capabilities: MinimalCapabilities\n disableThinking: boolean\n}): OpenAI.ChatCompletionCreateParamsStreaming {\n const { model, request, profile, capabilities, disableThinking } = input\n const params: OpenAI.ChatCompletionCreateParamsStreaming = {\n model,\n messages: convertMessages(request.messages),\n ...(request.tools ? { tools: convertTools(request.tools) } : {}),\n ...(request.toolChoice ? { tool_choice: request.toolChoice as ChatCompletionToolChoiceOption } : {}),\n temperature: request.temperature ?? profile.temperature,\n max_tokens: request.maxTokens ?? profile.defaultMaxTokens,\n top_p: profile.topP,\n stream: true,\n stream_options: { include_usage: true },\n }\n\n if (capabilities.supportsTopK && profile.topK !== undefined) {\n ;(params as unknown as Record<string, unknown>)['top_k'] = profile.topK\n }\n\n if (capabilities.supportsChatTemplateKwargs && profile.supportsReasoning && (disableThinking || request.disableThinking)) {\n ;(params as unknown as Record<string, unknown>)['chat_template_kwargs'] = { enable_thinking: false }\n }\n\n return params\n}\n\nexport function mapFinishReason(reason: string | null): LLMCompletionResponse['finishReason'] {\n switch (reason) {\n case 'stop':\n return 'stop'\n case 'tool_calls':\n return 'tool_calls'\n case 'length':\n return 'length'\n case 'content_filter':\n return 'content_filter'\n default:\n return 'stop'\n }\n}\n\nexport function extractThinking(content: string): { content: string; thinkingContent: string | null } {\n const thinkRegex = /<think>([\\s\\S]*?)<\\/think>/g\n let thinkingContent = ''\n let cleanContent = content\n\n let match: RegExpExecArray | null\n while ((match = thinkRegex.exec(content)) !== null) {\n thinkingContent += match[1]\n cleanContent = cleanContent.replace(match[0], '')\n }\n\n return {\n content: cleanContent.trim(),\n thinkingContent: thinkingContent.trim() || null,\n }\n}\n"],"mappings":";;;;;AAkBA,IAAM,uBAA6D;AAAA,EACjE,MAAM;AAAA,IACJ,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,cAAc;AAAA,EAChB;AAAA,EACA,QAAQ;AAAA,IACN,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,cAAc;AAAA,EAChB;AAAA,EACA,QAAQ;AAAA,IACN,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,cAAc;AAAA,EAChB;AAAA,EACA,SAAS;AAAA;AAAA,IAEP,wBAAwB;AAAA,IACxB,4BAA4B;AAAA,IAC5B,cAAc;AAAA,EAChB;AACF;AAEO,SAAS,uBAAuB,SAAuC;AAC5E,SAAO,qBAAqB,OAAO;AACrC;AAcA,eAAsB,cACpB,SACA,iBACA,SAAS,OACS;AAElB,MAAI,mBAAmB,oBAAoB,WAAW;AACpD,QAAI,QAAQ;AACV,aAAO,MAAM,0BAA0B,EAAE,SAAS,gBAAgB,CAAC;AAAA,IACrE,OAAO;AACL,aAAO,KAAK,0BAA0B,EAAE,SAAS,gBAAgB,CAAC;AAAA,IACpE;AACA,WAAO;AAAA,EACT;AAGA,QAAM,WAAW,QAAQ,QAAQ,YAAY,EAAE;AAE/C,MAAI;AAEF,QAAI,MAAM,YAAY,QAAQ,GAAG;AAC/B,UAAI,QAAQ;AACV,eAAO,MAAM,2BAA2B,EAAE,KAAK,SAAS,CAAC;AAAA,MAC3D,OAAO;AACL,eAAO,KAAK,2BAA2B,EAAE,KAAK,SAAS,CAAC;AAAA,MAC1D;AACA,aAAO;AAAA,IACT;AAGA,QAAI,MAAM,cAAc,QAAQ,GAAG;AACjC,UAAI,QAAQ;AACV,eAAO,MAAM,8BAA8B,EAAE,KAAK,SAAS,CAAC;AAAA,MAC9D,OAAO;AACL,eAAO,KAAK,8BAA8B,EAAE,KAAK,SAAS,CAAC;AAAA,MAC7D;AACA,aAAO;AAAA,IACT;AAGA,QAAI,MAAM,YAAY,QAAQ,GAAG;AAC/B,UAAI,QAAQ;AACV,eAAO,MAAM,2BAA2B,EAAE,KAAK,SAAS,CAAC;AAAA,MAC3D,OAAO;AACL,eAAO,KAAK,2BAA2B,EAAE,KAAK,SAAS,CAAC;AAAA,MAC1D;AACA,aAAO;AAAA,IACT;AAGA,QAAI,MAAM,YAAY,OAAO,GAAG;AAC9B,UAAI,QAAQ;AACV,eAAO,MAAM,6CAA6C,EAAE,KAAK,QAAQ,CAAC;AAAA,MAC5E,OAAO;AACL,eAAO,KAAK,6CAA6C,EAAE,KAAK,QAAQ,CAAC;AAAA,MAC3E;AACA,aAAO;AAAA,IACT;AAEA,QAAI,QAAQ;AACV,aAAO,MAAM,2CAA2C,EAAE,KAAK,QAAQ,CAAC;AAAA,IAC1E,OAAO;AACL,aAAO,KAAK,2CAA2C,EAAE,KAAK,QAAQ,CAAC;AAAA,IACzE;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,QAAI,QAAQ;AACV,aAAO,MAAM,4BAA4B;AAAA,QACvC,KAAK;AAAA,QACL,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AAAA,IACH,OAAO;AACL,aAAO,KAAK,4BAA4B;AAAA,QACtC,KAAK;AAAA,QACL,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAEA,eAAe,YAAY,SAAmC;AAC5D,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAG,OAAO,aAAa;AAAA,MAClD,QAAQ,YAAY,QAAQ,GAAI;AAAA,IAClC,CAAC;AACD,WAAO,SAAS;AAAA,EAClB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,cAAc,SAAmC;AAC9D,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAG,OAAO,WAAW;AAAA,MAChD,QAAQ,YAAY,QAAQ,GAAI;AAAA,IAClC,CAAC;AACD,QAAI,CAAC,SAAS,GAAI,QAAO;AAEzB,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,WAAO,gBAAgB,QAAQ,sBAAsB;AAAA,EACvD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,YAAY,SAAmC;AAC5D,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAG,OAAO,mBAAmB;AAAA,MACxD,QAAQ,YAAY,QAAQ,GAAI;AAAA,IAClC,CAAC;AACD,WAAO,SAAS;AAAA,EAClB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,YAAY,SAAmC;AAC5D,MAAI;AAEF,UAAM,MAAM,QAAQ,SAAS,KAAK,IAAI,UAAU,GAAG,OAAO;AAC1D,UAAM,WAAW,MAAM,MAAM,GAAG,GAAG,WAAW;AAAA,MAC5C,QAAQ,YAAY,QAAQ,GAAI;AAAA,IAClC,CAAC;AACD,WAAO,SAAS;AAAA,EAClB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,sBAAsB,SAA0B;AAC9D,UAAQ,SAAS;AAAA,IACf,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAW,aAAO;AAAA,EACzB;AACF;;;ACnLA,IAAM,aAAa,oBAAI,IAA6B;AACpD,IAAI,YAAuB;AAC3B,IAAI,gBAA+B;AACnC,IAAM,eAAe;AAGrB,SAAS,YAAY,KAAqB;AACxC,SAAO,IAAI,QAAQ,YAAY,EAAE;AACnC;AAOA,eAAsB,YAAY,YAAoB,UAAU,GAAG,SAAS,OAA+B;AACzG,QAAM,WAAW,YAAY,UAAU;AAGvC,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,SAAS,WAAW,IAAI,QAAQ;AACtC,MAAI,UAAU,MAAM,OAAO,YAAY,cAAc;AACnD,oBAAgB;AAChB,gBAAY;AACZ,WAAO,OAAO;AAAA,EAChB;AAGA,QAAM,MAAM,WAAW,SAAS,KAAK,IAAI,GAAG,UAAU,YAAY,GAAG,UAAU;AAE/E,WAAS,UAAU,GAAG,WAAW,SAAS,WAAW;AACnD,QAAI;AACF,UAAI,QAAQ;AACV,eAAO,MAAM,mCAAmC,EAAE,KAAK,QAAQ,CAAC;AAAA,MAClE;AAEA,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ,YAAY,QAAQ,GAAK;AAAA,MACnC,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,YAAI,QAAQ;AACV,iBAAO,MAAM,0CAA0C,EAAE,QAAQ,SAAS,QAAQ,QAAQ,CAAC;AAAA,QAC7F,OAAO;AACL,iBAAO,KAAK,0CAA0C,EAAE,QAAQ,SAAS,QAAQ,QAAQ,CAAC;AAAA,QAC5F;AACA,YAAI,UAAU,SAAS;AACrB,gBAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,MAAO,OAAO,CAAC;AACpD;AAAA,QACF;AACA,oBAAY;AACZ,eAAO,QAAQ,SAAS;AAAA,MAC1B;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,UAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;AAErC,cAAM,YAAY,KAAK,KAAK,CAAC;AAC7B,cAAM,UAAU,UAAU;AAG1B,mBAAW,IAAI,UAAU;AAAA,UACvB,OAAO;AAAA,UACP,WAAW;AAAA,UACX,WAAW;AAAA,QACb,CAAC;AACD,wBAAgB;AAChB,oBAAY;AAEZ,YAAI,QAAQ;AACV,iBAAO,MAAM,sBAAsB;AAAA,YACjC,OAAO;AAAA,YACP,QAAQ,UAAU;AAAA,YAClB,MAAM,UAAU;AAAA,UAClB,CAAC;AAAA,QACH,OAAO;AACL,iBAAO,KAAK,sBAAsB;AAAA,YAChC,OAAO;AAAA,YACP,QAAQ,UAAU;AAAA,YAClB,MAAM,UAAU;AAAA,UAClB,CAAC;AAAA,QACH;AACA,eAAO;AAAA,MACT;AAEA,UAAI,QAAQ;AACV,eAAO,MAAM,uCAAuC;AAAA,MACtD,OAAO;AACL,eAAO,KAAK,uCAAuC;AAAA,MACrD;AACA,kBAAY;AACZ,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,UAAI,QAAQ;AACV,eAAO,MAAM,0CAA0C,EAAE,OAAO,QAAQ,QAAQ,CAAC;AAAA,MACnF,OAAO;AACL,eAAO,KAAK,0CAA0C,EAAE,OAAO,QAAQ,QAAQ,CAAC;AAAA,MAClF;AAEA,UAAI,UAAU,SAAS;AACrB,cAAM,IAAI,QAAQ,OAAK,WAAW,GAAG,MAAO,OAAO,CAAC;AACpD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,cAAY;AACZ,SAAO,QAAQ,SAAS;AAC1B;AAYO,SAAS,eAA0B;AACxC,SAAO;AACT;AAKO,SAAS,gBAAgB,KAAoB;AAClD,MAAI,KAAK;AACP,eAAW,OAAO,YAAY,GAAG,CAAC;AAAA,EACpC,OAAO;AACL,eAAW,MAAM;AAAA,EACnB;AACA,cAAY;AACd;;;AChKA,OAAO,YAAY;;;ACAZ,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YACE,SACgB,MACA,SAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,uBAAN,cAAmC,aAAa;AAAA,EACrD,YAAY,WAAmB;AAC7B,UAAM,sBAAsB,SAAS,IAAI,qBAAqB,EAAE,UAAU,CAAC;AAC3E,SAAK,OAAO;AAAA,EACd;AACF;AAgBO,IAAM,WAAN,cAAuB,aAAa;AAAA,EACzC,YAAY,SAAiB,SAAmB;AAC9C,UAAM,SAAS,aAAa,OAAO;AACnC,SAAK,OAAO;AAAA,EACd;AACF;;;ACZA,IAAM,kBAAgC;AAAA,EACpC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM;AAAA,EACN,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,kBAAkB;AACpB;AAGA,IAAM,eAA6B;AAAA,EACjC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,MAAM;AAAA,EACN,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,kBAAkB;AACpB;AAMA,IAAM,iBAAoE;AAAA,EACxE;AAAA,IACE,SAAS;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB,kBAAkB;AAAA,IACpB;AAAA,EACF;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA;AAAA,MAEN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,MAAM;AAAA;AAAA,MAEN,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB,kBAAkB;AAAA,IACpB;AAAA,EACF;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB,kBAAkB;AAAA,IACpB;AAAA,EACF;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB,kBAAkB;AAAA,IACpB;AAAA,EACF;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB,kBAAkB;AAAA,IACpB;AAAA,EACF;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB,kBAAkB;AAAA,IACpB;AAAA,EACF;AACF;AAMO,SAAS,gBAAgB,WAAiC;AAC/D,QAAM,YAAY,UAAU,YAAY;AAGxC,MAAI,UAAU,SAAS,MAAM,GAAG;AAC9B,WAAO;AAAA,EACT;AAEA,aAAW,EAAE,SAAS,QAAQ,KAAK,gBAAgB;AACjD,QAAI,UAAU,SAAS,QAAQ,YAAY,CAAC,GAAG;AAC7C,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;;;AC7HO,SAAS,gBAAgB,UAAsD;AACpF,QAAM,WAAW,SAAS,OAAO,CAAC,QAAQ;AACxC,WAAO,EAAE,IAAI,SAAS,eAAe,CAAC,IAAI,SAAS,KAAK,KAAK,CAAC,IAAI,WAAW;AAAA,EAC/E,CAAC;AAED,SAAO,SAAS,IAAI,CAAC,QAAoC;AACvD,QAAI,IAAI,SAAS,QAAQ;AACvB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS,IAAI;AAAA,QACb,cAAc,IAAI;AAAA,MACpB;AAAA,IACF;AAEA,QAAI,IAAI,SAAS,eAAe,IAAI,WAAW,QAAQ;AACrD,aAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS,IAAI,WAAW;AAAA,QACxB,YAAY,IAAI,UAAU,IAAI,CAAC,cAAc;AAAA,UAC3C,IAAI,SAAS;AAAA,UACb,MAAM;AAAA,UACN,UAAU;AAAA,YACR,MAAM,SAAS;AAAA,YACf,WAAW,KAAK,UAAU,SAAS,SAAS;AAAA,UAC9C;AAAA,QACF,EAAE;AAAA,MACJ;AAAA,IACF;AAGA,QAAI,IAAI,SAAS,UAAU,IAAI,eAAe,IAAI,YAAY,SAAS,GAAG;AACxE,YAAM,UAAqG,CAAC;AAG5G,UAAI,IAAI,SAAS,KAAK,GAAG;AACvB,gBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,IAAI,QAAQ,CAAC;AAAA,MAClD;AAGA,iBAAW,cAAc,IAAI,aAAa;AACxC,gBAAQ,KAAK;AAAA,UACX,MAAM;AAAA,UACN,WAAW;AAAA,YACT,KAAK,WAAW;AAAA;AAAA,UAClB;AAAA,QACF,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,MAAM,IAAI;AAAA,MACV,SAAS,IAAI;AAAA,IACf;AAAA,EACF,CAAC;AACH;AAEO,SAAS,aAAa,OAAkD;AAC7E,SAAO,MAAM,IAAI,CAAC,UAAU;AAAA,IAC1B,MAAM;AAAA,IACN,UAAU;AAAA,MACR,MAAM,KAAK,SAAS;AAAA,MACpB,aAAa,KAAK,SAAS;AAAA,MAC3B,YAAY,KAAK,SAAS;AAAA,IAC5B;AAAA,EACF,EAAE;AACJ;AAEO,SAAS,8BAA8B,OAMI;AAChD,QAAM,EAAE,OAAO,SAAS,SAAS,cAAc,gBAAgB,IAAI;AACnE,QAAM,SAAwD;AAAA,IAC5D;AAAA,IACA,UAAU,gBAAgB,QAAQ,QAAQ;AAAA,IAC1C,GAAI,QAAQ,QAAQ,EAAE,OAAO,aAAa,QAAQ,KAAK,EAAE,IAAI,CAAC;AAAA,IAC9D,GAAI,QAAQ,aAAa,EAAE,aAAa,QAAQ,WAA6C,IAAI,CAAC;AAAA,IAClG,aAAa,QAAQ,eAAe,QAAQ;AAAA,IAC5C,YAAY,QAAQ,aAAa,QAAQ;AAAA,IACzC,OAAO,QAAQ;AAAA,IACf,QAAQ;AAAA,EACV;AAEA,MAAI,aAAa,gBAAgB,QAAQ,SAAS,QAAW;AAC3D;AAAC,IAAC,OAA8C,OAAO,IAAI,QAAQ;AAAA,EACrE;AAEA,MAAI,aAAa,8BAA8B,QAAQ,qBAAqB,iBAAiB;AAC3F;AAAC,IAAC,OAA8C,sBAAsB,IAAI,EAAE,iBAAiB,MAAM;AAAA,EACrG;AAEA,SAAO;AACT;AAEO,SAAS,2BAA2B,OAMI;AAC7C,QAAM,EAAE,OAAO,SAAS,SAAS,cAAc,gBAAgB,IAAI;AACnE,QAAM,SAAqD;AAAA,IACzD;AAAA,IACA,UAAU,gBAAgB,QAAQ,QAAQ;AAAA,IAC1C,GAAI,QAAQ,QAAQ,EAAE,OAAO,aAAa,QAAQ,KAAK,EAAE,IAAI,CAAC;AAAA,IAC9D,GAAI,QAAQ,aAAa,EAAE,aAAa,QAAQ,WAA6C,IAAI,CAAC;AAAA,IAClG,aAAa,QAAQ,eAAe,QAAQ;AAAA,IAC5C,YAAY,QAAQ,aAAa,QAAQ;AAAA,IACzC,OAAO,QAAQ;AAAA,IACf,QAAQ;AAAA,IACR,gBAAgB,EAAE,eAAe,KAAK;AAAA,EACxC;AAEA,MAAI,aAAa,gBAAgB,QAAQ,SAAS,QAAW;AAC3D;AAAC,IAAC,OAA8C,OAAO,IAAI,QAAQ;AAAA,EACrE;AAEA,MAAI,aAAa,8BAA8B,QAAQ,sBAAsB,mBAAmB,QAAQ,kBAAkB;AACxH;AAAC,IAAC,OAA8C,sBAAsB,IAAI,EAAE,iBAAiB,MAAM;AAAA,EACrG;AAEA,SAAO;AACT;AAEO,SAAS,gBAAgB,QAA8D;AAC5F,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEO,SAAS,gBAAgB,SAAsE;AACpG,QAAM,aAAa;AACnB,MAAI,kBAAkB;AACtB,MAAI,eAAe;AAEnB,MAAI;AACJ,UAAQ,QAAQ,WAAW,KAAK,OAAO,OAAO,MAAM;AAClD,uBAAmB,MAAM,CAAC;AAC1B,mBAAe,aAAa,QAAQ,MAAM,CAAC,GAAG,EAAE;AAAA,EAClD;AAEA,SAAO;AAAA,IACL,SAAS,aAAa,KAAK;AAAA,IAC3B,iBAAiB,gBAAgB,KAAK,KAAK;AAAA,EAC7C;AACF;;;AHlJO,SAAS,gBAAgB,QAAgB,iBAA0B,WAA+B;AAEvG,QAAM,UAAU,OAAO,IAAI,QAAQ,SAAS,KAAK,IAC7C,OAAO,IAAI,UACX,GAAG,OAAO,IAAI,OAAO;AAEzB,QAAM,SAAS,IAAI,OAAO;AAAA,IACxB;AAAA,IACA,QAAQ;AAAA;AAAA,EACV,CAAC;AAED,MAAI,QAAQ,OAAO,IAAI;AACvB,MAAI,UAAU,gBAAgB,KAAK;AACnC,MAAI,UAAU;AACd,MAAI,eAAe,uBAAuB,OAAO;AACjD,QAAM,kBAAkB,OAAO,IAAI,mBAAmB;AACtD,QAAM,cAAc,OAAO,IAAI,eAAe;AAE9C,SAAO;AAAA,IACL,WAAW;AACT,aAAO;AAAA,IACT;AAAA,IAEA,aAAa;AACX,aAAO;AAAA,IACT;AAAA,IAEA,aAAa;AACX,aAAO;AAAA,IACT;AAAA,IAEA,WAAW,YAAqB;AAC9B,aAAO,MAAM,uBAAuB,EAAE,MAAM,SAAS,IAAI,WAAW,CAAC;AACrE,gBAAU;AACV,qBAAe,uBAAuB,UAAU;AAAA,IAClD;AAAA,IAEA,SAAS,UAAkB;AACzB,YAAM,aAAa,gBAAgB,QAAQ;AAC3C,aAAO,MAAM,mBAAmB;AAAA,QAC9B,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,SAAS,WAAW;AAAA,QACpB,aAAa,WAAW;AAAA,QACxB,mBAAmB,WAAW;AAAA,MAChC,CAAC;AACD,cAAQ;AACR,gBAAU;AAAA,IACZ;AAAA,IAEA,MAAM,SAAS,SAA+D;AAC5E,aAAO,MAAM,wBAAwB;AAAA,QACnC,cAAc,QAAQ,SAAS;AAAA,QAC/B,UAAU,CAAC,CAAC,QAAQ,OAAO;AAAA,QAC3B,SAAS,QAAQ;AAAA,QACjB;AAAA,MACF,CAAC;AAED,UAAI;AACF,cAAM,wBAAwB,mBAAmB,QAAQ,oBAAoB;AAC7E,cAAM,eAAe,8BAA8B;AAAA,UACjD;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,iBAAiB;AAAA,QACnB,CAAC;AACD,cAAM,WAAW,MAAM,OAAO,KAAK,YAAY,OAAO,cAAc;AAAA,UAClE,QAAQ,QAAQ;AAAA,QAClB,CAAC;AAED,cAAM,SAAS,SAAS,QAAQ,CAAC;AACjC,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI,SAAS,+BAA+B;AAAA,QACpD;AAGA,cAAM,UAAU,OAAO;AAOvB,YAAI,UAAU,QAAQ,WAAW;AACjC,YAAI,kBAAkB;AAGtB,YAAI,QAAQ,mBAAmB;AAC7B,cAAI,aAAa,wBAAwB;AAEvC,8BAAkB,QAAQ,qBAAqB,QAAQ,aAAa;AAAA,UACtE,OAAO;AAEL,kBAAM,YAAY,gBAAgB,OAAO;AACzC,sBAAU,UAAU;AACpB,8BAAkB,UAAU,mBAAmB;AAAA,UACjD;AAGA,cAAI,QAAQ,sBAAsB,gBAAgB,KAAK,GAAG;AACxD,sBAAU;AACV,8BAAkB;AAAA,UACpB;AAAA,QACF;AAGA,YAAI,CAAC,QAAQ,KAAK,KAAK,gBAAgB,KAAK,GAAG;AAC7C,oBAAU;AACV,4BAAkB;AAAA,QACpB;AAEA,cAAM,YAAY,QAAQ,YAAY,IAAI,SAAO;AAAA,UAC/C,IAAI,GAAG;AAAA,UACP,MAAM,GAAG,SAAS;AAAA,UAClB,WAAW,KAAK,MAAM,GAAG,SAAS,SAAS;AAAA,QAC7C,EAAE;AAEF,eAAO;AAAA,UACL,IAAI,SAAS;AAAA,UACb;AAAA,UACA,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,UAC7C,GAAI,aAAa,UAAU,SAAS,IAAI,EAAE,UAAU,IAAI,CAAC;AAAA,UACzD,cAAc,gBAAgB,OAAO,aAAa;AAAA,UAClD,OAAO;AAAA,YACL,cAAc,SAAS,OAAO,iBAAiB;AAAA,YAC/C,kBAAkB,SAAS,OAAO,qBAAqB;AAAA,YACvD,aAAa,SAAS,OAAO,gBAAgB;AAAA,UAC/C;AAAA,QACF;AAAA,MACF,SAAS,OAAY;AACnB,eAAO,MAAM,sBAAsB,EAAE,OAAO,MAAM,SAAS,EAAE,CAAC;AAC9D,cAAM,IAAI;AAAA,UACR,iBAAiB,QAAQ,MAAM,UAAU;AAAA,UACzC,EAAE,eAAe,MAAM;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,OAAO,OAAO,SAA8D;AAC1E,aAAO,MAAM,sBAAsB;AAAA,QACjC,cAAc,QAAQ,SAAS;AAAA,QAC/B,UAAU,CAAC,CAAC,QAAQ,OAAO;AAAA,QAC3B,SAAS,QAAQ;AAAA,QACjB;AAAA,QACA;AAAA,MACF,CAAC;AAED,UAAI;AAEF,cAAM,wBAAwB,mBAAmB,QAAQ,oBAAoB;AAE7E,cAAM,eAAe,2BAA2B,EAAE,OAAO,SAAS,SAAS,cAAc,iBAAiB,sBAAsB,CAAC;AAEjI,cAAM,SAAS,MAAM,OAAO,KAAK,YAAY,OAAO,cAAc;AAAA,UAChE,QAAQ,QAAQ;AAAA,QAClB,CAAC;AAED,YAAI,cAAc;AAClB,YAAI,eAAe;AACnB,YAAI,aAAa;AACjB,YAAI,YAAY;AAChB,cAAM,YAA0E,oBAAI,IAAI;AACxF,YAAI,eAAsD;AAC1D,YAAI,QAAQ,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AACnE,YAAI,aAAa;AAGjB,YAAI,gBAAgB,KAAK,IAAI;AAC7B,cAAM,wBAAwB,IAAI,gBAAgB;AAGlD,cAAM,YAAY,YAAY,MAAM;AAClC,gBAAM,eAAe,KAAK,IAAI,IAAI;AAClC,cAAI,eAAe,aAAa;AAC9B,mBAAO,KAAK,qCAAqC,EAAE,cAAc,YAAY,CAAC;AAC9E,kCAAsB,MAAM;AAAA,UAC9B;AAAA,QACF,GAAG,GAAG;AAEN,YAAI;AACF,2BAAiB,SAAS,QAAQ;AAEhC,gBAAI,sBAAsB,OAAO,SAAS;AACxC,oBAAM,IAAI,MAAM,mDAAmD,WAAW,IAAI;AAAA,YACpF;AAGA,4BAAgB,KAAK,IAAI;AAEzB,yBAAa,MAAM;AAEnB,gBAAI,MAAM,OAAO;AACf,sBAAQ;AAAA,gBACN,cAAc,MAAM,MAAM;AAAA,gBAC1B,kBAAkB,MAAM,MAAM;AAAA,gBAC9B,aAAa,MAAM,MAAM;AAAA,cAC3B;AAAA,YACF;AAEA,kBAAM,SAAS,MAAM,QAAQ,CAAC;AAC9B,gBAAI,CAAC,OAAQ;AAEb,gBAAI,OAAO,eAAe;AACxB,6BAAe,gBAAgB,OAAO,aAAa;AAAA,YACrD;AAEA,kBAAM,QAAQ,OAAO;AAcrB,gBAAI,aAAa,wBAAwB;AACvC,oBAAM,YAAY,MAAM,qBAAqB,MAAM;AACnD,kBAAI,WAAW;AAEb,oBAAI,QAAQ,qBAAqB,CAAC,QAAQ,oBAAoB;AAC5D,kCAAgB;AAChB,wBAAM,EAAE,MAAM,kBAAkB,SAAS,UAAU;AAAA,gBACrD,OAAO;AAEL,iCAAe;AACf,wBAAM,EAAE,MAAM,cAAc,SAAS,UAAU;AAAA,gBACjD;AAAA,cACF;AAAA,YACF;AAGA,gBAAI,MAAM,SAAS;AACjB,6BAAe,MAAM;AAGrB,kBAAI,CAAC,aAAa,0BAA0B,QAAQ,qBAAqB,CAAC,QAAQ,oBAAoB;AAEpG,6BAAa,MAAM;AAEnB,uBAAO,UAAU,SAAS,GAAG;AAC3B,sBAAI,YAAY;AAEd,0BAAM,WAAW,UAAU,QAAQ,UAAU;AAC7C,wBAAI,aAAa,IAAI;AAEnB,4BAAM,YAAY,UAAU,MAAM,GAAG,QAAQ;AAC7C,0BAAI,WAAW;AACb,wCAAgB;AAChB,8BAAM,EAAE,MAAM,kBAAkB,SAAS,UAAU;AAAA,sBACrD;AACA,kCAAY,UAAU,MAAM,WAAW,WAAW,MAAM;AACxD,mCAAa;AAAA,oBACf,WAAW,UAAU,SAAS,IAAI,GAAG;AAEnC,4BAAM,aAAa,UAAU,YAAY,IAAI;AAC7C,4BAAM,SAAS,UAAU,MAAM,GAAG,UAAU;AAC5C,0BAAI,QAAQ;AACV,wCAAgB;AAChB,8BAAM,EAAE,MAAM,kBAAkB,SAAS,OAAO;AAAA,sBAClD;AACA,kCAAY,UAAU,MAAM,UAAU;AACtC;AAAA,oBACF,OAAO;AAEL,sCAAgB;AAChB,4BAAM,EAAE,MAAM,kBAAkB,SAAS,UAAU;AACnD,kCAAY;AAAA,oBACd;AAAA,kBACF,OAAO;AAEL,0BAAM,UAAU,UAAU,QAAQ,SAAS;AAC3C,wBAAI,YAAY,IAAI;AAElB,4BAAM,aAAa,UAAU,MAAM,GAAG,OAAO;AAC7C,0BAAI,YAAY;AACd,8BAAM,EAAE,MAAM,cAAc,SAAS,WAAW;AAAA,sBAClD;AACA,kCAAY,UAAU,MAAM,UAAU,UAAU,MAAM;AACtD,mCAAa;AAAA,oBACf,WAAW,UAAU,SAAS,GAAG,GAAG;AAElC,4BAAM,aAAa,UAAU,YAAY,GAAG;AAC5C,4BAAM,SAAS,UAAU,MAAM,GAAG,UAAU;AAC5C,0BAAI,QAAQ;AACV,8BAAM,EAAE,MAAM,cAAc,SAAS,OAAO;AAAA,sBAC9C;AACA,kCAAY,UAAU,MAAM,UAAU;AACtC;AAAA,oBACF,OAAO;AAEL,4BAAM,EAAE,MAAM,cAAc,SAAS,UAAU;AAC/C,kCAAY;AAAA,oBACd;AAAA,kBACF;AAAA,gBACF;AAAA,cACF,OAAO;AACL,sBAAM,EAAE,MAAM,cAAc,SAAS,MAAM,QAAQ;AAAA,cACrD;AAAA,YACF;AAGA,gBAAI,MAAM,YAAY;AACpB,yBAAW,MAAM,MAAM,YAAY;AACjC,sBAAM,WAAW,UAAU,IAAI,GAAG,KAAK;AAEvC,oBAAI,CAAC,UAAU;AACb,4BAAU,IAAI,GAAG,OAAO;AAAA,oBACtB,IAAI,GAAG,MAAM;AAAA,oBACb,MAAM,GAAG,UAAU,QAAQ;AAAA,oBAC3B,WAAW,GAAG,UAAU,aAAa;AAAA,kBACvC,CAAC;AAAA,gBACH,OAAO;AACL,sBAAI,GAAG,GAAI,UAAS,KAAK,GAAG;AAC5B,sBAAI,GAAG,UAAU,KAAM,UAAS,QAAQ,GAAG,SAAS;AACpD,sBAAI,GAAG,UAAU,UAAW,UAAS,aAAa,GAAG,SAAS;AAAA,gBAChE;AAEA,sBAAM;AAAA,kBACJ,MAAM;AAAA,kBACN,OAAO,GAAG;AAAA,kBACV,GAAI,GAAG,KAAK,EAAE,IAAI,GAAG,GAAG,IAAI,CAAC;AAAA,kBAC7B,GAAI,GAAG,UAAU,OAAO,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;AAAA,kBACtD,GAAI,GAAG,UAAU,YAAY,EAAE,WAAW,GAAG,SAAS,UAAU,IAAI,CAAC;AAAA,gBACvE;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF,UAAE;AACA,wBAAc,SAAS;AAAA,QACzB;AAGA,YAAI,WAAW;AACb,cAAI,YAAY;AACd,4BAAgB;AAAA,UAClB;AACA,sBAAY;AAAA,QACd;AAGA,YAAI,eAAe,YAAY,KAAK;AACpC,YAAI,gBAAgB,aAAa,KAAK;AAEtC,YAAI,CAAC,aAAa,0BAA0B,QAAQ,mBAAmB;AACrE,gBAAM,YAAY,gBAAgB,YAAY;AAC9C,yBAAe,UAAU;AACzB,0BAAgB,UAAU,mBAAmB;AAAA,QAC/C;AAIA,YAAI,CAAC,gBAAgB,eAAe;AAClC,yBAAe;AACf,0BAAgB;AAAA,QAClB;AAGA,cAAM,kBAA8B,CAAC;AACrC,mBAAW,CAAC,EAAE,EAAE,KAAK,WAAW;AAC9B,cAAI;AACF,4BAAgB,KAAK;AAAA,cACnB,IAAI,GAAG;AAAA,cACP,MAAM,GAAG;AAAA,cACT,WAAW,KAAK,MAAM,GAAG,SAAS;AAAA,YACpC,CAAC;AAAA,UACH,SAAS,OAAO;AACd,mBAAO,KAAK,uCAAuC,EAAE,MAAM,GAAG,MAAM,WAAW,GAAG,UAAU,CAAC;AAE7F,4BAAgB,KAAK;AAAA,cACnB,IAAI,GAAG;AAAA,cACP,MAAM,GAAG;AAAA,cACT,WAAW,CAAC;AAAA,cACZ,YAAY,iBAAiB,QAAQ,MAAM,UAAU;AAAA,cACrD,cAAc,GAAG;AAAA,YACnB,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,UAAU;AAAA,YACR,IAAI;AAAA,YACJ,SAAS;AAAA,YACT,GAAI,gBAAgB,EAAE,iBAAiB,cAAc,IAAI,CAAC;AAAA,YAC1D,GAAI,gBAAgB,SAAS,IAAI,EAAE,WAAW,gBAAgB,IAAI,CAAC;AAAA,YACnE;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC;AAC1C,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}