@deepagents/text2sql 0.10.2 → 0.11.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.
Files changed (98) hide show
  1. package/README.md +32 -41
  2. package/dist/index.d.ts +1 -6
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2338 -2398
  5. package/dist/index.js.map +4 -4
  6. package/dist/lib/adapters/adapter.d.ts +13 -1
  7. package/dist/lib/adapters/adapter.d.ts.map +1 -1
  8. package/dist/lib/adapters/groundings/abstract.grounding.d.ts +19 -3
  9. package/dist/lib/adapters/groundings/abstract.grounding.d.ts.map +1 -1
  10. package/dist/lib/adapters/groundings/column-stats.grounding.d.ts +1 -2
  11. package/dist/lib/adapters/groundings/column-stats.grounding.d.ts.map +1 -1
  12. package/dist/lib/adapters/groundings/column-values.grounding.d.ts +1 -2
  13. package/dist/lib/adapters/groundings/column-values.grounding.d.ts.map +1 -1
  14. package/dist/lib/adapters/groundings/constraint.grounding.d.ts +1 -1
  15. package/dist/lib/adapters/groundings/constraint.grounding.d.ts.map +1 -1
  16. package/dist/lib/adapters/groundings/index.js +15 -222
  17. package/dist/lib/adapters/groundings/index.js.map +3 -3
  18. package/dist/lib/adapters/groundings/indexes.grounding.d.ts +1 -1
  19. package/dist/lib/adapters/groundings/indexes.grounding.d.ts.map +1 -1
  20. package/dist/lib/adapters/groundings/info.grounding.d.ts +1 -1
  21. package/dist/lib/adapters/groundings/info.grounding.d.ts.map +1 -1
  22. package/dist/lib/adapters/groundings/report.grounding.d.ts +1 -1
  23. package/dist/lib/adapters/groundings/report.grounding.d.ts.map +1 -1
  24. package/dist/lib/adapters/groundings/row-count.grounding.d.ts +1 -1
  25. package/dist/lib/adapters/groundings/row-count.grounding.d.ts.map +1 -1
  26. package/dist/lib/adapters/groundings/table.grounding.d.ts +3 -3
  27. package/dist/lib/adapters/groundings/table.grounding.d.ts.map +1 -1
  28. package/dist/lib/adapters/groundings/view.grounding.d.ts +1 -1
  29. package/dist/lib/adapters/groundings/view.grounding.d.ts.map +1 -1
  30. package/dist/lib/adapters/mysql/index.js +343 -315
  31. package/dist/lib/adapters/mysql/index.js.map +4 -4
  32. package/dist/lib/adapters/postgres/index.js +385 -357
  33. package/dist/lib/adapters/postgres/index.js.map +4 -4
  34. package/dist/lib/adapters/spreadsheet/index.js +290 -223
  35. package/dist/lib/adapters/spreadsheet/index.js.map +4 -4
  36. package/dist/lib/adapters/sqlite/index.js +307 -279
  37. package/dist/lib/adapters/sqlite/index.js.map +4 -4
  38. package/dist/lib/adapters/sqlserver/index.js +383 -355
  39. package/dist/lib/adapters/sqlserver/index.js.map +4 -4
  40. package/dist/lib/agents/developer.agent.d.ts +33 -23
  41. package/dist/lib/agents/developer.agent.d.ts.map +1 -1
  42. package/dist/lib/agents/sql.agent.d.ts +4 -4
  43. package/dist/lib/agents/sql.agent.d.ts.map +1 -1
  44. package/dist/lib/agents/teachables.agent.d.ts +2 -2
  45. package/dist/lib/agents/teachables.agent.d.ts.map +1 -1
  46. package/dist/lib/agents/text2sql.agent.d.ts +18 -71
  47. package/dist/lib/agents/text2sql.agent.d.ts.map +1 -1
  48. package/dist/lib/fragments/schema.d.ts +214 -0
  49. package/dist/lib/fragments/schema.d.ts.map +1 -0
  50. package/dist/lib/instructions.d.ts +29 -2
  51. package/dist/lib/instructions.d.ts.map +1 -1
  52. package/dist/lib/instructions.js +336 -319
  53. package/dist/lib/instructions.js.map +4 -4
  54. package/dist/lib/sql.d.ts +13 -103
  55. package/dist/lib/sql.d.ts.map +1 -1
  56. package/dist/lib/synthesis/extractors/base-contextual-extractor.d.ts +2 -2
  57. package/dist/lib/synthesis/extractors/base-contextual-extractor.d.ts.map +1 -1
  58. package/dist/lib/synthesis/extractors/message-extractor.d.ts +1 -2
  59. package/dist/lib/synthesis/extractors/message-extractor.d.ts.map +1 -1
  60. package/dist/lib/synthesis/extractors/sql-extractor.d.ts.map +1 -1
  61. package/dist/lib/synthesis/index.js +1794 -572
  62. package/dist/lib/synthesis/index.js.map +4 -4
  63. package/dist/lib/synthesis/synthesizers/depth-evolver.d.ts.map +1 -1
  64. package/dist/lib/synthesis/synthesizers/persona-generator.d.ts +7 -17
  65. package/dist/lib/synthesis/synthesizers/persona-generator.d.ts.map +1 -1
  66. package/dist/lib/synthesis/synthesizers/schema-synthesizer.d.ts +2 -2
  67. package/dist/lib/synthesis/synthesizers/schema-synthesizer.d.ts.map +1 -1
  68. package/dist/lib/synthesis/synthesizers/teachings-generator.d.ts +8 -20
  69. package/dist/lib/synthesis/synthesizers/teachings-generator.d.ts.map +1 -1
  70. package/dist/lib/teach/teachings.d.ts +2 -2
  71. package/dist/lib/teach/teachings.d.ts.map +1 -1
  72. package/package.json +4 -3
  73. package/dist/lib/agents/chat1.agent.d.ts +0 -50
  74. package/dist/lib/agents/chat1.agent.d.ts.map +0 -1
  75. package/dist/lib/agents/chat2.agent.d.ts +0 -68
  76. package/dist/lib/agents/chat2.agent.d.ts.map +0 -1
  77. package/dist/lib/agents/chat3.agent.d.ts +0 -80
  78. package/dist/lib/agents/chat3.agent.d.ts.map +0 -1
  79. package/dist/lib/agents/chat4.agent.d.ts +0 -88
  80. package/dist/lib/agents/chat4.agent.d.ts.map +0 -1
  81. package/dist/lib/history/history.d.ts +0 -41
  82. package/dist/lib/history/history.d.ts.map +0 -1
  83. package/dist/lib/history/memory.history.d.ts +0 -5
  84. package/dist/lib/history/memory.history.d.ts.map +0 -1
  85. package/dist/lib/history/sqlite.history.d.ts +0 -15
  86. package/dist/lib/history/sqlite.history.d.ts.map +0 -1
  87. package/dist/lib/memory/memory.prompt.d.ts +0 -3
  88. package/dist/lib/memory/memory.prompt.d.ts.map +0 -1
  89. package/dist/lib/memory/memory.store.d.ts +0 -5
  90. package/dist/lib/memory/memory.store.d.ts.map +0 -1
  91. package/dist/lib/memory/sqlite.store.d.ts +0 -14
  92. package/dist/lib/memory/sqlite.store.d.ts.map +0 -1
  93. package/dist/lib/memory/store.d.ts +0 -40
  94. package/dist/lib/memory/store.d.ts.map +0 -1
  95. package/dist/lib/teach/teachables.d.ts +0 -648
  96. package/dist/lib/teach/teachables.d.ts.map +0 -1
  97. package/dist/lib/teach/xml.d.ts +0 -6
  98. package/dist/lib/teach/xml.d.ts.map +0 -1
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/lib/adapters/groundings/context.ts", "../src/lib/adapters/adapter.ts", "../src/lib/agents/developer.agent.ts", "../src/lib/agents/explainer.agent.ts", "../src/lib/agents/sql.agent.ts", "../src/lib/teach/xml.ts", "../src/lib/teach/teachables.ts", "../src/lib/agents/suggestions.agents.ts", "../src/lib/agents/text2sql.agent.ts", "../src/lib/memory/memory.prompt.ts", "../src/lib/checkpoint.ts", "../src/lib/file-cache.ts", "../src/lib/history/history.ts", "../src/lib/history/sqlite.history.ts", "../src/lib/history/history.sqlite.sql", "../src/lib/history/memory.history.ts", "../src/lib/memory/sqlite.store.ts", "../src/lib/memory/store.sqlite.sql", "../src/lib/memory/store.ts", "../src/lib/memory/memory.store.ts", "../src/lib/sql.ts", "../src/lib/agents/chat1.agent.ts", "../src/lib/agents/chat2.agent.ts", "../src/lib/agents/chat3.agent.ts", "../src/lib/agents/chat4.agent.ts", "../src/lib/teach/teachings.ts"],
4
- "sourcesContent": ["import type { AdapterInfo, ColumnStats, Relationship, Table } from '../adapter.ts';\nimport type { View } from './view.grounding.ts';\n\n/**\n * Column type for grounding operations.\n * Common interface between Table.columns and View.columns.\n */\nexport interface Column {\n name: string;\n type: string;\n kind?: 'LowCardinality' | 'Enum';\n values?: string[];\n stats?: ColumnStats;\n}\n\n/**\n * Entity with columns (Table or View).\n */\nexport interface ColumnContainer {\n name: string;\n columns: Column[];\n}\n\n/**\n * Shared context object passed to all groundings.\n * Groundings read from and write to this context.\n */\nexport interface GroundingContext {\n /** Tables discovered by TableGrounding */\n tables: Table[];\n\n /** Views discovered by ViewGrounding */\n views: View[];\n\n /** Relationships discovered by TableGrounding */\n relationships: Relationship[];\n\n /** Database info collected by InfoGrounding */\n info?: AdapterInfo;\n\n /** Business context report generated by ReportGrounding */\n report?: string;\n}\n\n/**\n * Create a new empty grounding context.\n */\nexport function createGroundingContext(): GroundingContext {\n return {\n tables: [],\n views: [],\n relationships: [],\n info: undefined,\n };\n}\n", "import type { AbstractGrounding } from './groundings/abstract.grounding.ts';\nimport { createGroundingContext } from './groundings/context.ts';\n\n/**\n * Filter type for view/table names.\n * - string[]: explicit list of view names\n * - RegExp: pattern to match view names\n * - function: predicate to filter view names\n */\nexport type Filter = string[] | RegExp | ((viewName: string) => boolean);\n\nexport interface Table {\n name: string;\n schema?: string;\n rawName?: string;\n columns: {\n name: string;\n type: string;\n kind?: 'LowCardinality' | 'Enum';\n values?: string[];\n isIndexed?: boolean;\n stats?: ColumnStats;\n }[];\n rowCount?: number;\n sizeHint?: 'tiny' | 'small' | 'medium' | 'large' | 'huge';\n indexes?: TableIndex[];\n constraints?: TableConstraint[];\n}\n\nexport interface TableIndex {\n name: string;\n columns: string[];\n unique?: boolean;\n type?: string;\n}\n\nexport interface TableConstraint {\n name: string;\n type:\n | 'CHECK'\n | 'UNIQUE'\n | 'NOT_NULL'\n | 'DEFAULT'\n | 'PRIMARY_KEY'\n | 'FOREIGN_KEY';\n columns?: string[];\n definition?: string;\n defaultValue?: string;\n referencedTable?: string;\n referencedColumns?: string[];\n}\n\nexport interface ColumnStats {\n min?: string;\n max?: string;\n nullFraction?: number;\n}\n\nexport type Relationship = {\n table: string;\n from: string[];\n referenced_table: string;\n to: string[];\n};\n\nexport type TablesFilter = string[] | RegExp;\n\nexport interface Introspection {\n tables: Table[];\n relationships: Relationship[];\n}\n\nexport interface AdapterInfo {\n dialect: string;\n version?: string;\n database?: string;\n details?: Record<string, unknown>;\n}\n\nexport type AdapterInfoProvider =\n | AdapterInfo\n | (() => Promise<AdapterInfo> | AdapterInfo);\n\nexport type IntrospectionPhase =\n | 'tables'\n | 'row_counts'\n | 'primary_keys'\n | 'indexes'\n | 'column_stats'\n | 'low_cardinality'\n | 'relationships';\n\nexport interface IntrospectionProgress {\n phase: IntrospectionPhase;\n message: string;\n current?: number;\n total?: number;\n}\n\nexport type OnProgress = (progress: IntrospectionProgress) => void;\n\nexport interface IntrospectOptions {\n onProgress?: OnProgress;\n}\n\nexport type GroundingFn = (adapter: Adapter) => AbstractGrounding;\n\nexport type ExecuteFunction = (sql: string) => Promise<any> | any;\nexport type ValidateFunction = (\n sql: string,\n) => Promise<string | void> | string | void;\n\nexport abstract class Adapter {\n abstract grounding: GroundingFn[];\n\n /**\n * Default schema name for this database.\n * PostgreSQL: 'public', SQL Server: 'dbo', SQLite: undefined\n */\n abstract readonly defaultSchema: string | undefined;\n\n /**\n * System schemas to exclude from introspection by default.\n */\n abstract readonly systemSchemas: string[];\n\n async introspect(ctx = createGroundingContext()) {\n const lines: { tag: string; fn: () => string | null }[] = [];\n for (const fn of this.grounding) {\n const grounding = fn(this);\n lines.push({\n tag: grounding.tag,\n fn: await grounding.execute(ctx),\n });\n }\n return lines\n .map(({ fn, tag }) => {\n const description = fn();\n if (description === null) {\n return '';\n }\n return `<${tag}>\\n${description}\\n</${tag}>`;\n })\n .join('\\n');\n }\n abstract execute(sql: string): Promise<any[]> | any[];\n abstract validate(sql: string): Promise<string | void> | string | void;\n abstract runQuery<Row>(sql: string): Promise<Row[]> | Row[];\n\n /**\n * Quote an identifier (table/column name) for safe use in SQL.\n * Each database uses different quoting styles.\n */\n abstract quoteIdentifier(name: string): string;\n\n /**\n * Escape a string value for safe use in SQL.\n * Each database escapes different characters.\n */\n abstract escape(value: string): string;\n\n /**\n * Build a SELECT query to sample rows from a table.\n * Each database uses different syntax for limiting rows (LIMIT vs TOP).\n */\n abstract buildSampleRowsQuery(\n tableName: string,\n columns: string[] | undefined,\n limit: number,\n ): string;\n\n /**\n * Convert unknown database value to number.\n * Handles number, bigint, and string types.\n */\n toNumber(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n if (typeof value === 'bigint') {\n return Number(value);\n }\n if (typeof value === 'string' && value.trim() !== '') {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n }\n\n /**\n * Parse a potentially qualified table name into schema and table parts.\n */\n parseTableName(name: string): { schema: string; table: string } {\n if (name.includes('.')) {\n const [schema, ...rest] = name.split('.');\n return { schema, table: rest.join('.') };\n }\n return { schema: this.defaultSchema ?? '', table: name };\n }\n\n /**\n * Escape a string value for use in SQL string literals (single quotes).\n * Used in WHERE clauses like: WHERE name = '${escapeString(value)}'\n */\n escapeString(value: string): string {\n return value.replace(/'/g, \"''\");\n }\n\n /**\n * Build a SQL filter clause to include/exclude schemas.\n * @param columnName - The schema column name (e.g., 'TABLE_SCHEMA')\n * @param allowedSchemas - If provided, filter to these schemas only\n */\n buildSchemaFilter(columnName: string, allowedSchemas?: string[]): string {\n if (allowedSchemas && allowedSchemas.length > 0) {\n const values = allowedSchemas\n .map((s) => `'${this.escapeString(s)}'`)\n .join(', ');\n return `AND ${columnName} IN (${values})`;\n }\n if (this.systemSchemas.length > 0) {\n const values = this.systemSchemas\n .map((s) => `'${this.escapeString(s)}'`)\n .join(', ');\n return `AND ${columnName} NOT IN (${values})`;\n }\n return '';\n }\n}\n\nexport function filterTablesByName<T extends { name: string }>(\n tables: T[],\n filter: TablesFilter | undefined,\n): T[] {\n if (!filter) return tables;\n return tables.filter((table) => matchesFilter(table.name, filter));\n}\n\nexport function filterRelationshipsByTables(\n relationships: Relationship[],\n tableNames: Set<string> | undefined,\n): Relationship[] {\n if (tableNames === undefined) {\n return relationships;\n }\n if (tableNames.size === 0) {\n return [];\n }\n return relationships.filter(\n (it) => tableNames.has(it.table) || tableNames.has(it.referenced_table),\n );\n}\n\nexport function applyTablesFilter(\n tables: Table[],\n relationships: Relationship[],\n filter: TablesFilter | undefined,\n): { tables: Table[]; relationships: Relationship[] } {\n if (!filter) {\n return { tables, relationships };\n }\n\n const allowedNames = new Set(\n getTablesWithRelated(tables, relationships, filter),\n );\n\n return {\n tables: tables.filter((table) => allowedNames.has(table.name)),\n relationships: filterRelationshipsByTables(relationships, allowedNames),\n };\n}\n\nexport function matchesFilter(\n tableName: string,\n filter: TablesFilter,\n): boolean {\n if (Array.isArray(filter)) {\n return filter.includes(tableName);\n }\n return filter.test(tableName);\n}\n\nexport function getTablesWithRelated(\n allTables: Table[],\n relationships: Relationship[],\n filter: TablesFilter,\n): string[] {\n const matchedTables = filterTablesByName(allTables, filter).map(\n (it) => it.name,\n );\n\n if (matchedTables.length === 0) {\n return [];\n }\n\n const adjacency = new Map<string, Set<string>>();\n\n for (const rel of relationships) {\n if (!adjacency.has(rel.table)) {\n adjacency.set(rel.table, new Set());\n }\n if (!adjacency.has(rel.referenced_table)) {\n adjacency.set(rel.referenced_table, new Set());\n }\n adjacency.get(rel.table)!.add(rel.referenced_table);\n adjacency.get(rel.referenced_table)!.add(rel.table);\n }\n\n const result = new Set<string>(matchedTables);\n const queue = [...matchedTables];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n const neighbors = adjacency.get(current);\n\n if (!neighbors) {\n continue;\n }\n\n for (const neighbor of neighbors) {\n if (!result.has(neighbor)) {\n result.add(neighbor);\n queue.push(neighbor);\n }\n }\n }\n\n return Array.from(result);\n}\n", "import { groq } from '@ai-sdk/groq';\nimport { tool } from 'ai';\nimport dedent from 'dedent';\nimport z from 'zod';\n\nimport { agent, generate, toState } from '@deepagents/agent';\nimport { scratchpad_tool } from '@deepagents/toolbox';\n\nimport type { Adapter } from '../adapters/adapter.ts';\nimport type { Teachables } from '../teach/teachables.ts';\nimport { explainerAgent } from './explainer.agent.ts';\nimport { toSql } from './sql.agent.ts';\n\n/**\n * State passed to the developer agent\n */\nexport type DeveloperAgentState = {\n /** Database adapter for validation */\n adapter: Adapter;\n /** Schema introspection XML */\n introspection: string;\n /** Combined teachings/instructions */\n teachings: string;\n /** Instructions for SQL generation */\n instructions: Teachables[];\n};\n\nconst tools = {\n /**\n * Generate SQL from natural language question.\n * Uses the toSql function with retry logic and validation.\n */\n generate_sql: tool({\n description: dedent`\n Generate a validated SQL query from a natural language question.\n The query is automatically validated against the database schema.\n Use this when the user asks a question that requires data retrieval.\n\n Returns the SQL query along with generation metadata (attempts, any errors encountered).\n `,\n inputSchema: z.object({\n question: z\n .string()\n .min(1)\n .describe('The natural language question to convert to SQL'),\n }),\n execute: async ({ question }, options) => {\n const state = toState<DeveloperAgentState>(options);\n try {\n const result = await toSql({\n input: question,\n adapter: state.adapter,\n introspection: state.introspection,\n instructions: state.instructions,\n });\n return {\n success: true,\n sql: result.sql,\n attempts: result.attempts,\n errors: result.errors,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n },\n }),\n\n /**\n * Get plain-English explanation of a SQL query.\n */\n explain_sql: tool({\n description: dedent`\n Get a plain-English explanation of a SQL query.\n Use this to help the user understand what a query does.\n\n The explanation focuses on intent and logic, not syntax.\n `,\n inputSchema: z.object({\n sql: z.string().min(1).describe('The SQL query to explain'),\n }),\n execute: async ({ sql }) => {\n const { experimental_output } = await generate(explainerAgent, [], {\n sql,\n });\n return { explanation: experimental_output.explanation };\n },\n }),\n\n /**\n * Show database schema introspection.\n */\n show_schema: tool({\n description: dedent`\n Display the database schema introspection.\n Use this when the user wants to see available tables, columns, or relationships.\n\n Optionally filter by table name to reduce output.\n `,\n inputSchema: z.object({\n table: z\n .string()\n .optional()\n .describe(\n 'Optional: filter to show only a specific table. If omitted, shows full schema.',\n ),\n }),\n execute: async ({ table }, options) => {\n const state = toState<DeveloperAgentState>(options);\n\n if (!table) {\n return { schema: state.introspection };\n }\n\n // Filter introspection to show only the requested table\n // The introspection is XML, so we do a simple string search\n const lines = state.introspection.split('\\n');\n const tableLines: string[] = [];\n let inTable = false;\n let depth = 0;\n\n for (const line of lines) {\n const lowerLine = line.toLowerCase();\n\n // Check if this line starts the target table\n if (\n lowerLine.includes(`name=\"${table.toLowerCase()}\"`) ||\n lowerLine.includes(`table=\"${table.toLowerCase()}\"`)\n ) {\n inTable = true;\n depth = 1;\n tableLines.push(line);\n continue;\n }\n\n if (inTable) {\n tableLines.push(line);\n\n // Track depth for nested tags\n if (line.includes('</')) {\n depth--;\n }\n if (\n line.includes('<') &&\n !line.includes('</') &&\n !line.includes('/>')\n ) {\n depth++;\n }\n\n // End when we close the table tag\n if (depth <= 0) {\n break;\n }\n }\n }\n\n if (tableLines.length === 0) {\n return {\n schema: `Table \"${table}\" not found in schema. Use show_schema without a table filter to see all available tables.`,\n };\n }\n\n return { schema: tableLines.join('\\n') };\n },\n }),\n\n /**\n * Developer scratchpad for notes and reasoning.\n */\n scratchpad: scratchpad_tool,\n};\n\n/**\n * Developer Agent - Power-user conversational interface for SQL generation\n *\n * This agent provides tools for SQL generation, validation, and explanation\n * without execution. Designed for developers/DBAs who want full control\n * over query building and refinement.\n *\n * Tools:\n * - generate_sql: Convert natural language to validated SQL\n * - validate_sql: Check SQL syntax without execution\n * - explain_sql: Get plain-English explanation of SQL\n * - show_schema: Display schema introspection on demand\n * - scratchpad: Developer notes/reasoning\n */\nexport const developerAgent = agent<never, DeveloperAgentState>({\n model: groq('gpt-oss-20b'),\n tools,\n name: 'developer_agent',\n prompt: (state) => {\n return dedent`\n You are an expert SQL developer assistant helping power users build and refine queries.\n\n ## Your Capabilities\n\n You have access to the following tools:\n\n 1. **generate_sql**: Convert natural language questions to validated SQL queries\n - Automatically validates against the database schema\n - Returns generation metadata (attempts, errors if any)\n\n 2. **explain_sql**: Get a plain-English explanation of any SQL query\n - Helps users understand complex queries\n - Focuses on intent and logic, not syntax\n\n 3. **show_schema**: Display database schema information\n - Can show full schema or filter by table name\n - Use to explore available tables and columns\n\n 4. **scratchpad**: Record your reasoning and notes\n\n ## Guidelines\n\n - Be transparent: show the SQL you generate before explaining it\n - Be precise: provide exact column names and table references\n - Be helpful: suggest refinements and alternatives when appropriate\n - Support both natural language questions AND raw SQL input\n - When validating user SQL, explain any errors clearly\n - Use show_schema proactively when you need to verify table/column names\n\n ${state?.teachings || ''}\n ${state?.introspection || ''}\n `;\n },\n});\n", "import { groq } from '@ai-sdk/groq';\nimport dedent from 'dedent';\nimport z from 'zod';\n\nimport { agent } from '@deepagents/agent';\n\nexport const explainerAgent = agent<{ explanation: string }, { sql: string }>({\n name: 'explainer',\n model: groq('openai/gpt-oss-20b'),\n prompt: (state) => dedent`\n You are an expert SQL tutor.\n Explain the following SQL query in plain English to a non-technical user.\n Focus on the intent and logic, not the syntax.\n\n <sql>\n ${state?.sql}\n </sql>\n `,\n output: z.object({\n explanation: z.string().describe('The explanation of the SQL query.'),\n }),\n});\n", "import { groq } from '@ai-sdk/groq';\nimport {\n APICallError,\n JSONParseError,\n NoContentGeneratedError,\n NoObjectGeneratedError,\n NoOutputGeneratedError,\n TypeValidationError,\n defaultSettingsMiddleware,\n wrapLanguageModel,\n} from 'ai';\nimport { Console } from 'node:console';\nimport { createWriteStream } from 'node:fs';\nimport pRetry from 'p-retry';\nimport z from 'zod';\n\nimport {\n type AgentModel,\n agent,\n generate,\n toOutput,\n user,\n} from '@deepagents/agent';\n\nimport type { Adapter } from '../adapters/adapter.ts';\nimport {\n type Teachables,\n persona,\n toInstructions,\n} from '../teach/teachables.ts';\n\nexport interface ToSqlOptions {\n /** The natural language input to convert to SQL */\n input: string;\n /** Database adapter for validation */\n adapter: Adapter;\n /** Introspection/schema context */\n introspection: string;\n /** Instructions/teachings to include */\n instructions: Teachables[];\n /** Optional model override */\n model?: AgentModel;\n /** Maximum retry attempts on validation failure (default: 3) */\n maxRetries?: number;\n}\n\nexport interface ToSqlResult {\n /** The generated SQL query */\n sql: string;\n /** Number of attempts made */\n attempts: number;\n /** Validation errors encountered (if any retries occurred) */\n errors?: string[];\n}\n\nconst logger = new Console({\n stdout: createWriteStream('./sql-agent.log', { flags: 'a' }),\n stderr: createWriteStream('./sql-agent-error.log', { flags: 'a' }),\n inspectOptions: { depth: null },\n});\n\ntype SqlGeneratorState = {\n // FIXME: this should not be here after creating the context package\n introspection: string;\n teachings: string;\n};\n\ntype SqlGeneratorOutput =\n | { sql: string; reasoning?: string }\n | { error: string };\n\n/**\n * Agent that generates SQL queries from introspection and natural language questions.\n * Used for creating synthetic training data for text-to-SQL models.\n */\n/** Temperature progression for retries: deterministic first, then increasingly exploratory */\nconst RETRY_TEMPERATURES = [0, 0.2, 0.3];\n\nconst sqlQueryAgent = agent<SqlGeneratorOutput, SqlGeneratorState>({\n name: 'text2sql',\n model: groq('openai/gpt-oss-20b'),\n logging: process.env.AGENT_LOGGING === 'true',\n output: z.union([\n z.object({\n sql: z.string().describe('The SQL query that answers the question'),\n reasoning: z\n .string()\n .optional()\n .describe('The reasoning steps taken to generate the SQL'),\n }),\n z.object({\n error: z\n .string()\n .describe(\n 'Error message explaining why the question cannot be answered with the given schema',\n ),\n }),\n ]),\n prompt: (state) => {\n return `\n ${state?.teachings || ''}\n ${state?.introspection || ''}\n `;\n },\n});\n\n/** Extract SQL from markdown fenced code block if present */\nfunction extractSql(output: string): string {\n const match = output.match(/```sql\\n?([\\s\\S]*?)```/);\n return match ? match[1].trim() : output.trim();\n}\n\nconst marker = Symbol('SQLValidationError');\n/**\n * Error thrown when SQL validation fails.\n */\nexport class SQLValidationError extends Error {\n [marker]: true;\n constructor(message: string) {\n super(message);\n this.name = 'SQLValidationError';\n this[marker] = true;\n }\n static isInstance(error: unknown): error is SQLValidationError {\n return error instanceof SQLValidationError && error[marker] === true;\n }\n}\n\n/**\n * Error thrown when the question cannot be answered with the given schema.\n */\nexport class UnanswerableSQLError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'UnanswerableSQLError';\n }\n static isInstance(error: unknown): error is UnanswerableSQLError {\n return error instanceof UnanswerableSQLError;\n }\n}\n\nexport async function toSql(options: ToSqlOptions): Promise<ToSqlResult> {\n const { maxRetries = 3 } = options;\n\n return withRetry(\n async (attemptNumber, errors, attempts) => {\n const agentInstance = sqlQueryAgent.clone({\n model: wrapLanguageModel({\n model: options.model ?? sqlQueryAgent.model,\n middleware: defaultSettingsMiddleware({\n settings: {\n temperature: RETRY_TEMPERATURES[attemptNumber - 1] ?? 0.3,\n topP: 1,\n },\n }),\n }),\n });\n\n const messages = errors.length\n ? [\n user(options.input),\n user(\n `<validation_error>Your previous SQL query had the following error: ${errors.at(-1)?.message}. Please fix the query.</validation_error>`,\n ),\n ]\n : [user(options.input)];\n\n const output = await toOutput(\n generate(agentInstance, messages, {\n introspection: options.introspection,\n teachings: toInstructions(\n 'instructions',\n persona({\n name: 'Freya',\n role: 'You are an expert SQL query generator. You translate natural language questions into precise, efficient SQL queries based on the provided database schema.',\n }),\n ...options.instructions,\n ),\n }),\n );\n\n // Handle error responses (question is unanswerable with given schema)\n if ('error' in output) {\n throw new UnanswerableSQLError(output.error);\n }\n\n const sql = extractSql(output.sql);\n\n // Validate the generated SQL\n const validationError = await options.adapter.validate(sql);\n if (validationError) {\n throw new SQLValidationError(validationError);\n }\n\n return {\n attempts,\n sql,\n errors: errors.length ? errors.map(formatErrorMessage) : undefined,\n };\n },\n { retries: maxRetries - 1 },\n );\n}\n\nfunction formatErrorMessage(error: Error) {\n if (APICallError.isInstance(error)) {\n if (error.message.startsWith('Failed to validate JSON')) {\n return `Schema validation failed: ${error.message}`;\n }\n return error.message;\n }\n if (SQLValidationError.isInstance(error)) {\n return `SQL Validation Error: ${error.message}`;\n }\n return error.message;\n}\n\nasync function withRetry<T>(\n computation: (\n attemptNumber: number,\n errors: Error[],\n attempts: number,\n ) => Promise<T>,\n options: { retries: number } = { retries: 3 },\n) {\n const errors: Error[] = [];\n let attempts = 0;\n return pRetry(\n (attemptNumber) => {\n return computation(attemptNumber, errors, ++attempts);\n },\n {\n retries: options.retries,\n shouldRetry: (context) => {\n // Don't retry if unanswerable - it's intentional\n if (UnanswerableSQLError.isInstance(context.error)) {\n return false;\n }\n // Retry on validation errors\n if (SQLValidationError.isInstance(context.error)) {\n return true;\n }\n console.log({\n NoObjectGeneratedError: NoObjectGeneratedError.isInstance(\n context.error,\n ),\n NoOutputGeneratedError: NoOutputGeneratedError.isInstance(\n context.error,\n ),\n APICallError: APICallError.isInstance(context.error),\n JSONParseError: JSONParseError.isInstance(context.error),\n TypeValidationError: TypeValidationError.isInstance(context.error),\n NoContentGeneratedError: NoContentGeneratedError.isInstance(\n context.error,\n ),\n });\n // Retry on AI SDK errors\n return (\n APICallError.isInstance(context.error) ||\n JSONParseError.isInstance(context.error) ||\n TypeValidationError.isInstance(context.error) ||\n NoObjectGeneratedError.isInstance(context.error) ||\n NoOutputGeneratedError.isInstance(context.error) ||\n NoContentGeneratedError.isInstance(context.error)\n );\n },\n onFailedAttempt(context) {\n logger.error(`toSQL`, context.error);\n console.log(\n `Attempt ${context.attemptNumber} failed. There are ${context.retriesLeft} retries left.`,\n );\n // console.dir(context.error, { depth: null });\n errors.push(context.error);\n },\n },\n );\n}\n", "export function wrapBlock(tag: string, children: string[]): string {\n const content = children\n .filter((child): child is string => Boolean(child))\n .join('\\n');\n if (!content) {\n return '';\n }\n return `<${tag}>\\n${indentBlock(content, 2)}\\n</${tag}>`;\n}\n\nexport function list(tag: string, values: string[], childTag: string): string {\n if (!values.length) {\n return '';\n }\n const children = values.map((value) => leaf(childTag, value)).join('\\n');\n return `<${tag}>\\n${indentBlock(children, 2)}\\n</${tag}>`;\n}\n\nexport function leaf(tag: string, value: string): string {\n const safe = escapeXml(value);\n if (safe.includes('\\n')) {\n return `<${tag}>\\n${indentBlock(safe, 2)}\\n</${tag}>`;\n }\n return `<${tag}>${safe}</${tag}>`;\n}\n\nexport function indentBlock(text: string, spaces: number): string {\n if (!text.trim()) {\n return '';\n }\n const padding = ' '.repeat(spaces);\n return text\n .split('\\n')\n .map((line) => (line.length ? padding + line : padding))\n .join('\\n');\n}\n\nexport function escapeXml(value: string): string {\n if (value == null) {\n return '';\n }\n return value\n .replaceAll(/&/g, '&amp;')\n .replaceAll(/</g, '&lt;')\n .replaceAll(/>/g, '&gt;')\n .replaceAll(/\"/g, '&quot;')\n .replaceAll(/'/g, '&apos;');\n}\n", "import { indentBlock, leaf, list, wrapBlock } from './xml.ts';\n\nexport interface Teachables {\n type: GeneratedTeachable['type'] | 'user_profile';\n /** Serialize to GeneratedTeachable for storage */\n encode: () => GeneratedTeachable;\n /** Render to XML string for prompts */\n decode: () => string;\n}\nexport type GeneratedTeachable =\n | { type: 'term'; name: string; definition: string }\n | { type: 'hint'; text: string }\n | { type: 'guardrail'; rule: string; reason?: string; action?: string }\n | {\n type: 'explain';\n concept: string;\n explanation: string;\n therefore?: string;\n }\n | { type: 'example'; question: string; answer: string; note?: string }\n | { type: 'clarification'; when: string; ask: string; reason: string }\n | {\n type: 'workflow';\n task: string;\n steps: string[];\n triggers?: string[];\n notes?: string;\n }\n | { type: 'quirk'; issue: string; workaround: string }\n | { type: 'styleGuide'; prefer: string; never?: string; always?: string }\n | {\n type: 'analogy';\n concept: string[];\n relationship: string;\n insight?: string;\n therefore?: string;\n pitfall?: string;\n }\n | { type: 'glossary'; entries: Record<string, string> }\n // User-specific teachable types\n | { type: 'identity'; name?: string; role?: string }\n | { type: 'persona'; name: string; role: string; tone: string }\n | { type: 'alias'; term: string; meaning: string }\n | { type: 'preference'; aspect: string; value: string }\n | { type: 'context'; description: string }\n | { type: 'correction'; subject: string; clarification: string };\n\n/**\n * Teach the system domain-specific vocabulary and business terminology.\n *\n * Use this to define simple, direct mappings between business terms and their meanings.\n * The system will understand these terms when users mention them in queries.\n *\n * @param name - The business term or acronym to define\n * @param definition - What the term means in your domain\n *\n * @example\n * // Logistics/Transportation dataset\n * term(\"deadhead miles\", \"distance driven with empty truck between deliveries\")\n * term(\"dwell time\", \"total time a truck spends at a loading dock or warehouse\")\n * term(\"LTL\", \"less than truckload - shipment that doesn't fill entire truck\")\n *\n * @example\n * // Education/University dataset\n * term(\"matriculation\", \"students who completed enrollment and started classes\")\n * term(\"DFW rate\", \"percentage of students receiving D, F, or Withdrawal in a course\")\n * term(\"cohort\", \"group of students who entered the same semester or academic year\")\n *\n * @example\n * // Finance/Banking dataset\n * term(\"NPL\", \"non-performing loan - loan past due 90+ days\")\n * term(\"basis points\", \"one hundredth of a percentage point (1% = 100 bps)\")\n * term(\"AUM\", \"assets under management - total market value of client investments\")\n */\nexport function term(name: string, definition: string): Teachables {\n return {\n type: 'term',\n encode: () => ({ type: 'term', name, definition }),\n decode: () =>\n wrapBlock('term', [leaf('name', name), leaf('definition', definition)]),\n };\n}\n\n/**\n * Teach the system behavioral rules and constraints that should always apply.\n *\n * Use this for business logic, data quality rules, or query preferences that should\n * be automatically applied to all relevant queries. Hints are injected as constraints\n * in the system prompt.\n *\n * @param text - The rule or constraint to follow (use imperative language)\n *\n * @example\n * // Manufacturing/Supply Chain dataset\n * hint(\"Always exclude work orders with status = 'simulation' from production metrics\")\n * hint(\"When calculating OEE (overall equipment effectiveness), only count scheduled production time\")\n * hint(\"Defect rates should be calculated per batch, not per individual unit, for consistency\")\n *\n * @example\n * // Real Estate/Property dataset\n * hint(\"Never include properties with listing_status = 'draft' in market analysis\")\n * hint(\"Always filter out duplicate MLS listings - use the earliest listing_date for each property_id\")\n * hint(\"Square footage comparisons must specify if including or excluding basement/garage\")\n *\n * @example\n * // Social Media/Content Platform dataset\n * hint(\"Engagement metrics should exclude bot accounts identified by is_verified_human = false\")\n * hint(\"View counts reset daily - always use cumulative_views for historical analysis\")\n * hint(\"Default content filters to published_status = 'public' unless analyzing drafts\")\n */\nexport function hint(text: string): Teachables {\n return {\n type: 'hint',\n encode: () => ({ type: 'hint', text }),\n decode: () => leaf('hint', text),\n };\n}\n\n/**\n * Define hard guardrails, safety rules, and compliance boundaries the system must enforce.\n *\n * Use this for \"never do\" rules, sensitive data handling, and required behaviors when\n * certain conditions occur. Guardrails should be explicit and action oriented.\n *\n * @param input.rule - The guardrail or restriction to enforce\n * @param input.reason - Why this guardrail exists (compliance, security, performance)\n * @param input.action - What to do when this guardrail is triggered (block, ask, sanitize)\n *\n * @example\n * // Healthcare dataset\n * guardrail({\n * rule: \"Never return PHI like SSN, MRN, or full address in query results\",\n * reason: \"HIPAA compliance\",\n * action: \"If asked, state that identifiable patient data cannot be shared; offer de-identified aggregates instead\"\n * })\n *\n * @example\n * // Finance dataset\n * guardrail({\n * rule: \"Block any query exposing employee-level compensation by name\",\n * reason: \"Confidential payroll data\",\n * action: \"Provide ranges grouped by department or level instead of individual salaries\"\n * })\n *\n * @example\n * // E-commerce dataset\n * guardrail({\n * rule: \"Warn when a query would scan more than 10 million rows; require a narrower date range\",\n * reason: \"Performance and cost control\",\n * action: \"Ask the user to add filters (recent timeframe, specific categories) before proceeding\"\n * })\n */\nexport function guardrail(input: {\n rule: string;\n reason?: string;\n action?: string;\n}): Teachables {\n const { rule, reason, action } = input;\n return {\n type: 'guardrail',\n encode: () => ({ type: 'guardrail', rule, reason, action }),\n decode: () =>\n wrapBlock('guardrail', [\n leaf('rule', rule),\n reason ? leaf('reason', reason) : '',\n action ? leaf('action', action) : '',\n ]),\n };\n}\n\n/**\n * Teach the system a rich understanding of a single concept using metaphors and explanations.\n *\n * Use this when a simple term definition isn't enough - when you need to convey deeper\n * understanding about how to think about and calculate a metric or concept.\n *\n * @param input.concept - The concept being explained\n * @param input.explanation - A metaphor or detailed explanation (often using real-world comparisons)\n * @param input.therefore - Optional actionable instruction based on this understanding\n *\n * @example\n * // Gaming/Entertainment dataset\n * explain({\n * concept: \"daily active users to monthly active users ratio\",\n * explanation: \"like measuring how many club members visit daily vs just once a month - shows stickiness\",\n * therefore: \"Calculate as DAU / MAU, where higher ratio (closer to 1) means more engaged user base\"\n * })\n *\n * @example\n * // HR/Employee Management dataset\n * explain({\n * concept: \"time to fill\",\n * explanation: \"like measuring how long a house sits on the market - from posting job to accepting offer\",\n * therefore: \"Calculate as days between job_posted_date and offer_accepted_date, exclude cancelled requisitions\"\n * })\n *\n * @example\n * // Telecommunications dataset\n * explain({\n * concept: \"network congestion ratio\",\n * explanation: \"like rush hour traffic density - measures actual usage vs total capacity at peak times\",\n * therefore: \"Calculate as (peak_hour_bandwidth_used / total_bandwidth_capacity) during busiest hour of day\"\n * })\n */\nexport function explain(input: {\n concept: string;\n explanation: string;\n therefore?: string;\n}): Teachables {\n const { concept, explanation, therefore } = input;\n return {\n type: 'explain',\n encode: () => ({ type: 'explain', concept, explanation, therefore }),\n decode: () =>\n wrapBlock('explanation', [\n leaf('concept', concept),\n leaf('details', explanation),\n therefore ? leaf('therefore', therefore) : '',\n ]),\n };\n}\n\n/**\n * Teach the system through concrete examples of question \u2192 SQL pairs.\n *\n * Use this for few-shot learning - show the system exactly how to translate\n * specific types of questions into SQL queries. Great for establishing patterns\n * and handling domain-specific query structures.\n *\n * @param input.question - The natural language question or request\n * @param input.answer - The correct answer that responds to the question\n * @param input.note - Optional note or explanation about the example\n *\n * @example\n * // Energy/Utilities dataset\n * example({\n * question: \"show me peak demand hours for the last week\",\n * answer: \"SELECT DATE_TRUNC('hour', reading_timestamp) as hour, MAX(consumption_kwh) as peak_demand FROM meter_readings WHERE reading_timestamp >= CURRENT_DATE - INTERVAL '7 days' GROUP BY hour ORDER BY peak_demand DESC LIMIT 10\"\n * })\n *\n * @example\n * // Agriculture/Farm Management dataset\n * example({\n * question: \"what is the average yield per acre by crop type this season\",\n * answer: \"SELECT crop_type, AVG(harvest_quantity / field_acres) as yield_per_acre FROM harvests WHERE harvest_date >= '2024-01-01' GROUP BY crop_type ORDER BY yield_per_acre DESC\"\n * })\n *\n * @example\n * // Travel/Hospitality dataset\n * example({\n * question: \"show me hotel occupancy rate for this month\",\n * answer: \"SELECT hotel_name, (SUM(occupied_rooms) / SUM(total_rooms)) * 100 as occupancy_rate FROM daily_occupancy WHERE date >= DATE_TRUNC('month', CURRENT_DATE) GROUP BY hotel_id, hotel_name ORDER BY occupancy_rate DESC\",\n * note: \"Occupancy rate is a percentage - multiply by 100 for readable output\"\n * })\n */\nexport function example(input: {\n question: string;\n answer: string;\n note?: string;\n}): Teachables {\n const { question, answer, note } = input;\n return {\n type: 'example',\n encode: () => ({ type: 'example', question, answer, note }),\n decode: () =>\n wrapBlock('example', [\n leaf('question', question),\n leaf('answer', answer),\n note ? leaf('note', note) : '',\n ]),\n };\n}\n\n/**\n * Teach the system when and what to ask for clarification.\n *\n * Use this to handle ambiguous terms or situations where the system should\n * proactively ask the user for more information before generating a query.\n * Makes the system more conversational and precise.\n *\n * @param input.when - The condition or trigger that should prompt clarification\n * @param input.ask - The question to ask the user\n * @param input.reason - Why this clarification is necessary (helps system understand importance)\n *\n * @example\n * // Marketing/Advertising dataset\n * clarification({\n * when: \"user asks for 'conversion rate'\",\n * ask: \"Which conversion: click-to-lead, lead-to-opportunity, or opportunity-to-customer?\",\n * reason: \"Conversion rate means different things at each funnel stage - need to specify which metric\"\n * })\n *\n * @example\n * // Food Delivery dataset\n * clarification({\n * when: \"user asks about 'delivery time'\",\n * ask: \"Do you mean estimated time at order, actual delivery time, or time from kitchen to door?\",\n * reason: \"Multiple time metrics exist - estimated vs actual impacts customer satisfaction differently\"\n * })\n *\n * @example\n * // Fitness/Gym Management dataset\n * clarification({\n * when: \"user mentions 'active members'\",\n * ask: \"Do you mean paid memberships or members who actually visited in last 30 days?\",\n * reason: \"Many paid members don't use facilities - different metrics for revenue vs utilization\"\n * })\n */\nexport function clarification(input: {\n when: string;\n ask: string;\n reason: string;\n}): Teachables {\n const { when, ask, reason } = input;\n return {\n type: 'clarification',\n encode: () => ({ type: 'clarification', when, ask, reason }),\n decode: () =>\n wrapBlock('clarification', [\n leaf('when', when),\n leaf('ask', ask),\n leaf('reason', reason),\n ]),\n };\n}\n\n/**\n * Teach the system multi-step analytical processes that can't be solved with a single query.\n *\n * Use this for complex analytical tasks that require multiple CTEs, sequential logic,\n * or specific methodologies. Workflows teach the system HOW to approach a type of analysis.\n *\n * @param input.task - Name of the analytical task\n * @param input.steps - Sequential steps to execute (can include SQL snippets or descriptions)\n * @param input.triggers - Optional phrases that should activate this workflow\n * @param input.notes - Optional additional context, warnings, or guidance\n *\n * @example\n * // Insurance dataset\n * workflow({\n * task: \"Claims Loss Ratio Analysis\",\n * triggers: [\"loss ratio\", \"claims ratio\", \"underwriting performance\"],\n * steps: [\n * \"Calculate total claims paid for each policy period\",\n * \"Calculate total premiums earned for same period\",\n * \"Compute loss ratio as (claims_paid / premiums_earned) * 100\",\n * \"Segment by policy type, geography, and underwriter\",\n * \"Identify policies with loss ratio > 100% (losing money)\",\n * \"Calculate trend over time using rolling 12-month windows\"\n * ],\n * notes: \"Use incurred date for claims, not paid date. Exclude reinsurance recoveries from claims total.\"\n * })\n *\n * @example\n * // Media/Publishing dataset\n * workflow({\n * task: \"Content Performance Funnel\",\n * triggers: [\"content funnel\", \"engagement funnel\", \"content performance\"],\n * steps: [\n * \"Count total impressions (articles shown) per content piece\",\n * \"Count click-throughs (articles opened)\",\n * \"Count scroll depth > 50% (meaningful engagement)\",\n * \"Count shares, comments, or saves (viral actions)\",\n * \"Calculate conversion rate at each funnel stage\",\n * \"Identify top-performing content by final conversion rate\"\n * ],\n * notes: \"Requires multiple event types. Join events table multiple times or use conditional aggregation.\"\n * })\n *\n * @example\n * // Sports Analytics dataset\n * workflow({\n * task: \"Player Performance Rating Calculation\",\n * triggers: [\"player rating\", \"performance score\", \"player analytics\"],\n * steps: [\n * \"Aggregate per-game stats: points, assists, rebounds, turnovers\",\n * \"Calculate efficiency metrics: shooting percentage, plus/minus\",\n * \"Normalize each metric using z-scores vs league average\",\n * \"Apply position-specific weights to each metric\",\n * \"Combine weighted scores into overall performance rating (0-100)\",\n * \"Rank players within position group and overall\"\n * ],\n * notes: \"Requires league-wide statistics for normalization. Update weights each season based on game trends.\"\n * })\n */\nexport function workflow(input: {\n task: string;\n steps: string[];\n triggers?: string[];\n notes?: string;\n}): Teachables {\n const { task, steps, triggers, notes } = input;\n return {\n type: 'workflow',\n encode: () => ({ type: 'workflow', task, steps, triggers, notes }),\n decode: () =>\n wrapBlock('workflow', [\n leaf('task', task),\n triggers?.length ? list('triggers', triggers, 'trigger') : '',\n list('steps', steps, 'step'),\n notes ? leaf('notes', notes) : '',\n ]),\n };\n}\n\n/**\n * Teach the system about data quirks, edge cases, or database-specific issues and their workarounds.\n *\n * Use this to document weird data patterns, database limitations, or special handling\n * required for specific scenarios. Helps the system navigate real-world messiness.\n *\n * @param input.issue - Description of the quirk, edge case, or problem\n * @param input.workaround - How to handle or work around this issue\n *\n * @example\n * // Government/Public Services dataset\n * quirk({\n * issue: \"Citizen IDs contain leading zeros but are stored as integers, losing the zeros\",\n * workaround: \"Always cast to VARCHAR and use LPAD(citizen_id::VARCHAR, 10, '0') to restore leading zeros\"\n * })\n *\n * @example\n * // Aviation dataset\n * quirk({\n * issue: \"Flight times crossing midnight show as negative duration (landing before takeoff)\",\n * workaround: \"Add 24 hours when calculated duration < 0: CASE WHEN duration < 0 THEN duration + INTERVAL '24 hours' ELSE duration END\"\n * })\n *\n * @example\n * // Automotive/Dealership dataset\n * quirk({\n * issue: \"VIN numbers with letter 'O' were incorrectly entered as zero '0' in legacy data\",\n * workaround: \"When searching by VIN, use REPLACE(vin, '0', 'O') or fuzzy matching to handle both cases\"\n * })\n */\nexport function quirk(input: {\n issue: string;\n workaround: string;\n}): Teachables {\n const { issue, workaround } = input;\n return {\n type: 'quirk',\n encode: () => ({ type: 'quirk', issue, workaround }),\n decode: () =>\n wrapBlock('quirk', [\n leaf('issue', issue),\n leaf('workaround', workaround),\n ]),\n };\n}\n\n/**\n * Teach the system SQL style preferences and coding standards for generated queries.\n *\n * Use this to enforce consistent SQL formatting, naming conventions, and best practices\n * specific to your team or organization. Improves readability and maintainability.\n *\n * @param input.prefer - Preferred SQL style or pattern\n * @param input.never - Optional anti-pattern to avoid\n * @param input.always - Optional rule that must always be followed\n *\n * @example\n * // Non-profit/Charity dataset\n * styleGuide({\n * prefer: \"Use donor-centric language in column aliases: 'donor_name' not 'customer_name'\",\n * never: \"Never expose internal donor IDs in external reports - use public gift IDs\",\n * always: \"Always include fiscal year in date-based aggregations (FY starts July 1)\"\n * })\n *\n * @example\n * // Legal/Law Firm dataset\n * styleGuide({\n * prefer: \"Use billable_hours with 2 decimal precision for accurate client billing\",\n * never: \"Never include attorney_rate in queries visible to paralegals - confidential data\",\n * always: \"Always filter by matter_status = 'open' unless specifically analyzing closed cases\"\n * })\n *\n * @example\n * // Inventory/Warehouse dataset\n * styleGuide({\n * prefer: \"Use location_id in joins rather than location_name (duplicates exist across warehouses)\",\n * never: \"Never aggregate inventory without grouping by warehouse_id first\",\n * always: \"Always use inventory_on_hand - inventory_reserved for available stock calculations\"\n * })\n */\nexport function styleGuide(input: {\n prefer: string;\n never?: string;\n always?: string;\n}): Teachables {\n const { prefer, never, always } = input;\n return {\n type: 'styleGuide',\n encode: () => ({ type: 'styleGuide', prefer, never, always }),\n decode: () =>\n wrapBlock('style_guide', [\n leaf('prefer', prefer),\n always ? leaf('always', always) : '',\n never ? leaf('never', never) : '',\n ]),\n };\n}\n\n/**\n * Teach the system by comparing related concepts through real-world analogies.\n *\n * Use this to teach relational understanding between two concepts by drawing comparisons\n * to familiar real-world scenarios. Helps the system understand WHY concepts differ and\n * when to use each one appropriately.\n *\n * @param input.concept - Array of two related concepts to compare\n * @param input.relationship - The comparison/analogy using real-world examples\n * @param input.insight - Optional key insight the analogy reveals\n * @param input.therefore - Optional actionable instruction based on this understanding\n * @param input.pitfall - Optional common mistake to avoid\n *\n * @example\n * // E-commerce dataset\n * analogy({\n * concept: [\"cart abandonment\", \"browse abandonment\"],\n * relationship: \"Cart abandonment is like leaving items at a checkout counter, browse abandonment is like window shopping without picking anything up\",\n * insight: \"Cart abandonment shows purchase intent (added to cart), browse abandonment shows only interest\",\n * therefore: \"Prioritize cart abandonment recovery campaigns - higher conversion potential than browse\",\n * pitfall: \"Don't combine both into generic 'abandonment rate' - they need different marketing strategies\"\n * })\n *\n * @example\n * // SaaS dataset\n * analogy({\n * concept: [\"logo churn\", \"revenue churn\"],\n * relationship: \"Logo churn is like counting how many customers left the store, revenue churn is how much money walked out\",\n * insight: \"Losing 10 small customers (high logo churn) might hurt less than losing 1 enterprise customer (high revenue churn)\",\n * therefore: \"Always report both metrics - logo churn for customer satisfaction, revenue churn for financial health\",\n * pitfall: \"Don't use logo churn to predict revenue impact - customer size distribution matters\"\n * })\n *\n * @example\n * // Healthcare dataset\n * analogy({\n * concept: [\"incident\", \"prevalence\"],\n * relationship: \"Incidence is like new house sales this month, prevalence is total houses currently occupied\",\n * insight: \"Incidence measures new cases over time, prevalence measures all existing cases at a point in time\",\n * therefore: \"For tracking disease outbreaks use incidence rate, for resource planning use prevalence\",\n * pitfall: \"Don't sum incidence rates across time periods - it's a rate not a count\"\n * })\n */\nexport function analogy(input: {\n concept: string[];\n relationship: string;\n insight?: string;\n therefore?: string;\n pitfall?: string;\n}): Teachables {\n const { concept, relationship, insight, therefore, pitfall } = input;\n return {\n type: 'analogy',\n encode: () => ({\n type: 'analogy',\n concept,\n relationship,\n insight,\n therefore,\n pitfall,\n }),\n decode: () =>\n wrapBlock('analogy', [\n list('concepts', concept, 'concept'),\n leaf('relationship', relationship),\n insight ? leaf('insight', insight) : '',\n therefore ? leaf('therefore', therefore) : '',\n pitfall ? leaf('pitfall', pitfall) : '',\n ]),\n };\n}\n\n/**\n * Map business terms directly to SQL expressions or fragments.\n *\n * Use this to teach the system how to CALCULATE or QUERY specific business concepts.\n * The system will substitute these SQL patterns when users mention the term.\n *\n * **Glossary vs Alias:**\n * - `alias` = user vocabulary \u2192 table/column name (\"the big table\" \u2192 \"orders table\")\n * - `glossary` = business term \u2192 SQL expression (\"revenue\" \u2192 \"SUM(orders.total_amount)\")\n *\n * In short: alias renames, glossary computes.\n *\n * @param entries - Record mapping business terms to their SQL expressions\n *\n * @example\n * glossary({\n * \"revenue\": \"SUM(orders.total_amount)\",\n * \"average order value\": \"AVG(orders.total_amount)\",\n * \"active user\": \"last_login > NOW() - INTERVAL '30 days'\",\n * \"churned\": \"status = 'churned'\",\n * \"power user\": \"order_count > 10\",\n * \"net revenue\": \"SUM(orders.total_amount) - SUM(refunds.amount)\",\n * })\n */\nexport function glossary(entries: Record<string, string>): Teachables {\n return {\n type: 'glossary',\n encode: () => ({ type: 'glossary', entries }),\n decode: () =>\n wrapBlock(\n 'glossary',\n Object.entries(entries).map(([term, sql]) =>\n wrapBlock('entry', [leaf('term', term), leaf('sql', sql)]),\n ),\n ),\n };\n}\n\n// =============================================================================\n// User-Specific Teachable Types\n// =============================================================================\n\n/**\n * Define the user's identity including name and/or role.\n *\n * Use this to capture who the user is and what lens they view data through.\n * Helps tailor explanations, terminology, and focus areas.\n *\n * @param input.name - The user's name (optional)\n * @param input.role - The user's role or position (optional)\n *\n * @example\n * identity({ name: \"John\", role: \"VP of Sales\" })\n * identity({ role: \"Data analyst in the marketing team\" })\n * identity({ name: \"Sarah\" })\n * identity({ role: \"Finance manager focused on cost optimization\" })\n */\nexport function identity(input: { name?: string; role?: string }): Teachables {\n const { name, role } = input;\n return {\n type: 'identity',\n encode: () => ({ type: 'identity', name, role }),\n decode: () =>\n wrapBlock('identity', [\n name ? leaf('name', name) : '',\n role ? leaf('role', role) : '',\n ]),\n };\n}\n\n/**\n * Define an AI persona with a name, role, and communication tone.\n *\n * Use this to customize the assistant's personality and how it communicates.\n * The persona influences the style and approach of responses.\n *\n * @param input.name - The persona's name\n * @param input.role - The persona's role or expertise\n * @param input.tone - The communication style (e.g., friendly, professional, concise)\n *\n * @example\n * persona({ name: \"DataBot\", role: \"SQL Expert\", tone: \"friendly and encouraging\" })\n * persona({ name: \"QueryMaster\", role: \"Database Analyst\", tone: \"professional and concise\" })\n * persona({ name: \"SQLHelper\", role: \"Data Assistant\", tone: \"casual and approachable\" })\n */\nexport function persona(input: {\n name: string;\n role: string;\n tone?: string;\n}): Teachables {\n const { name, role, tone } = input;\n return {\n type: 'persona',\n encode: () => ({ type: 'persona', name, role, tone: tone ?? '' }),\n decode: () =>\n wrapBlock('persona', [\n leaf('name', name),\n leaf('role', role),\n tone ? leaf('tone', tone) : '',\n ]),\n };\n}\n\n/**\n * Define user-specific term meanings and vocabulary.\n *\n * Use this when the user has their own definitions for terms that might\n * differ from standard or domain definitions. Like `term()` but personal.\n *\n * @param termName - The term the user uses\n * @param meaning - What the user means by this term\n *\n * @example\n * alias(\"revenue\", \"gross revenue before deductions, not net\")\n * alias(\"active users\", \"users who logged in within the last 30 days\")\n * alias(\"the big table\", \"the orders table\")\n * alias(\"Q4\", \"October through December, not fiscal Q4\")\n */\nexport function alias(termName: string, meaning: string): Teachables {\n return {\n type: 'alias',\n encode: () => ({ type: 'alias', term: termName, meaning }),\n decode: () =>\n wrapBlock('alias', [leaf('term', termName), leaf('meaning', meaning)]),\n };\n}\n\n/**\n * Define how the user prefers results presented.\n *\n * Use this to capture output formatting, style, and behavioral preferences\n * that should apply to all interactions with this user.\n *\n * @param aspect - What aspect of output this preference applies to\n * @param value - The user's preference\n *\n * @example\n * preference(\"date format\", \"YYYY-MM-DD\")\n * preference(\"output style\", \"tables over charts unless trend data\")\n * preference(\"detail level\", \"always show the SQL query in responses\")\n * preference(\"row limit\", \"default to 50 rows unless I ask for more\")\n * preference(\"explanation style\", \"brief and to the point\")\n */\nexport function preference(aspect: string, value: string): Teachables {\n return {\n type: 'preference',\n encode: () => ({ type: 'preference', aspect, value }),\n decode: () =>\n wrapBlock('preference', [leaf('aspect', aspect), leaf('value', value)]),\n };\n}\n\n/**\n * Define the user's current working focus or project.\n *\n * Use this to capture temporary context that helps inform defaults,\n * assumptions, and suggestions. Should be updated as focus changes.\n *\n * @param description - What the user is currently working on\n *\n * @example\n * context(\"Preparing Q4 board presentation\")\n * context(\"Investigating drop in signups last week\")\n * context(\"Working on EMEA regional analysis for strategy meeting\")\n * context(\"Debugging discrepancy in revenue numbers\")\n */\nexport function context(description: string): Teachables {\n return {\n type: 'context',\n encode: () => ({ type: 'context', description }),\n decode: () => leaf('context', description),\n };\n}\n\n/**\n * Record a correction the user made to previous understanding.\n *\n * Use this when the user corrects a misunderstanding about data, columns,\n * or business logic. Prevents repeating the same mistake.\n *\n * @param subject - What was misunderstood\n * @param clarification - The correct understanding\n *\n * @example\n * correction(\"status column\", \"1 = active, 0 = inactive, not boolean true/false\")\n * correction(\"orders table\", \"Use orders_v2, not the deprecated legacy_orders table\")\n * correction(\"date field\", \"order_date is when order was placed, ship_date is when shipped\")\n * correction(\"revenue calculation\", \"Must exclude refunds and chargebacks\")\n */\nexport function correction(subject: string, clarification: string): Teachables {\n return {\n type: 'correction',\n encode: () => ({ type: 'correction', subject, clarification }),\n decode: () =>\n wrapBlock('correction', [\n leaf('subject', subject),\n leaf('clarification', clarification),\n ]),\n };\n}\n\nexport function teachable(\n tag: string,\n ...teachables: Teachables[]\n): Teachables {\n return {\n type: 'user_profile',\n encode: () => teachables[0]?.encode() ?? ({ type: 'context', description: '' }),\n decode: () => toInstructions(tag, ...teachables),\n };\n}\n\nexport function toInstructions(\n tag: string,\n ...teachables: Teachables[]\n): string {\n if (!teachables.length) {\n return '';\n }\n\n const grouped = new Map<Teachables['type'], Teachables[]>();\n for (const teachable of teachables) {\n const existing = grouped.get(teachable.type) ?? [];\n existing.push(teachable);\n grouped.set(teachable.type, existing);\n }\n\n const definedTypes = new Set(SECTION_ORDER.map((s) => s.type));\n\n const sections = SECTION_ORDER.map(({ type, tag }) => {\n const items = grouped.get(type);\n if (!items?.length) {\n return '';\n }\n const renderedItems = items\n .map((item) => item.decode().trim())\n .filter(Boolean)\n .map((item) => indentBlock(item, 2))\n .join('\\n');\n if (!renderedItems.length) {\n return '';\n }\n return `<${tag}>\\n${renderedItems}\\n</${tag}>`;\n }).filter((section): section is string => Boolean(section));\n\n // Render types not defined in SECTION_ORDER at the end\n for (const [type, items] of grouped) {\n if (definedTypes.has(type)) {\n continue;\n }\n const renderedItems = items\n .map((item) => item.decode().trim())\n .filter(Boolean)\n .map((item) => indentBlock(item, 2))\n .join('\\n');\n if (renderedItems.length) {\n sections.push(renderedItems);\n }\n }\n\n if (!sections.length) {\n return '';\n }\n\n const content = indentBlock(sections.join('\\n'), 2);\n return `<${tag}>\\n${content}\\n</${tag}>`;\n}\n\nconst SECTION_ORDER: Array<{ type: Teachables['type']; tag: string }> = [\n // User context (render first - most important for personalization)\n { type: 'identity', tag: 'identity' },\n { type: 'persona', tag: 'persona' },\n { type: 'context', tag: 'user_context' },\n { type: 'preference', tag: 'user_preferences' },\n { type: 'alias', tag: 'user_vocabulary' },\n { type: 'correction', tag: 'user_corrections' },\n // Domain knowledge\n { type: 'guardrail', tag: 'guardrails' },\n { type: 'styleGuide', tag: 'style_guides' },\n { type: 'hint', tag: 'hints' },\n { type: 'clarification', tag: 'clarifications' },\n { type: 'workflow', tag: 'workflows' },\n { type: 'quirk', tag: 'quirks' },\n { type: 'term', tag: 'terminology' },\n { type: 'explain', tag: 'explanations' },\n { type: 'analogy', tag: 'analogies' },\n { type: 'glossary', tag: 'glossary' },\n { type: 'example', tag: 'examples' },\n];\n\nexport function toTeachables(generated: GeneratedTeachable[]): Teachables[] {\n return generated.map((item) => {\n switch (item.type) {\n case 'persona':\n return persona({ name: item.name, role: item.role, tone: item.tone });\n case 'term':\n return term(item.name, item.definition);\n case 'hint':\n return hint(item.text);\n case 'guardrail':\n return guardrail({\n rule: item.rule,\n reason: item.reason,\n action: item.action,\n });\n case 'explain':\n return explain({\n concept: item.concept,\n explanation: item.explanation,\n therefore: item.therefore,\n });\n case 'example':\n return example({\n question: item.question,\n answer: item.answer,\n note: item.note,\n });\n case 'clarification':\n return clarification({\n when: item.when,\n ask: item.ask,\n reason: item.reason,\n });\n case 'workflow':\n return workflow({\n task: item.task,\n steps: item.steps,\n triggers: item.triggers,\n notes: item.notes,\n });\n case 'quirk':\n return quirk({\n issue: item.issue,\n workaround: item.workaround,\n });\n case 'styleGuide':\n return styleGuide({\n prefer: item.prefer,\n never: item.never,\n always: item.always,\n });\n case 'analogy':\n return analogy({\n concept: item.concept,\n relationship: item.relationship,\n insight: item.insight,\n therefore: item.therefore,\n pitfall: item.pitfall,\n });\n case 'glossary':\n return glossary(item.entries);\n // User-specific teachable types\n case 'identity':\n return identity({ name: item.name, role: item.role });\n case 'alias':\n return alias(item.term, item.meaning);\n case 'preference':\n return preference(item.aspect, item.value);\n case 'context':\n return context(item.description);\n case 'correction':\n return correction(item.subject, item.clarification);\n }\n });\n}\n\n/**\n * Convert Teachables back to GeneratedTeachable format for storage.\n *\n * @param teachables - Array of Teachables to convert\n * @returns Array of GeneratedTeachable objects suitable for storage\n *\n * @example\n * const teachings = [term('NPL', 'non-performing loan'), hint('Always filter by status')];\n * const forStorage = fromTeachables(teachings);\n * // [{ type: 'term', name: 'NPL', definition: 'non-performing loan' }, { type: 'hint', text: 'Always filter by status' }]\n */\nexport function fromTeachables(teachables: Teachables[]): GeneratedTeachable[] {\n return teachables.map((t) => t.encode());\n}\n\n/**\n * Default export containing all system teachable factory functions.\n * Excludes user-specific teachables (identity, alias, preference, context, correction).\n */\nexport default {\n persona,\n term,\n hint,\n guardrail,\n explain,\n example,\n clarification,\n workflow,\n quirk,\n styleGuide,\n analogy,\n glossary,\n teachable,\n};\n", "import { groq } from '@ai-sdk/groq';\nimport dedent from 'dedent';\nimport z from 'zod';\n\nimport { agent, thirdPersonPrompt } from '@deepagents/agent';\n\nimport type { Introspection } from '../adapters/adapter.ts';\nimport { databaseSchemaPrompt } from '../prompt.ts';\n\ntype SuggestionsAgentContext = {\n context?: string;\n adapterInfo?: string;\n};\ntype SuggestionsAgentOutput = {\n suggestions: {\n question: string;\n sql: string;\n businessValue: string;\n }[];\n};\n\nexport const suggestionsAgent = agent<\n SuggestionsAgentOutput,\n SuggestionsAgentContext\n>({\n name: 'text2sql-suggestions',\n model: groq('openai/gpt-oss-20b'),\n output: z.object({\n suggestions: z\n .array(\n z.object({\n question: z\n .string()\n .describe('A complex, high-impact business question.'),\n sql: z\n .string()\n .describe('The SQL statement needed to answer the question.'),\n businessValue: z\n .string()\n .describe('Why the question matters to stakeholders.'),\n }),\n )\n .min(1)\n .max(5)\n .describe('A set of up to two advanced question + SQL pairs.'),\n }),\n prompt: (state) => {\n return dedent`\n ${thirdPersonPrompt()}\n\n <identity>\n You are a senior analytics strategist who proposes ambitious business questions\n and drafts the SQL needed to answer them. You specialize in identifying ideas\n that combine multiple tables, apply segmentation or time analysis, and surface\n metrics that drive executive decisions.\n </identity>\n\n\n <instructions>\n - Recommend one or two UNIQUE questions that go beyond simple counts or listings.\n - Favor questions that require joins, aggregates, time comparisons, cohort analysis,\n or window functions.\n - For each question, explain the business reason stakeholders care about it.\n - Provide the complete SQL query that could answer the question in the given schema.\n - Keep result sets scoped with LIMIT clauses (max 50 rows) when returning raw rows.\n - Ensure table/column names match the provided schema exactly.\n - Use columns marked [LowCardinality: ...] to identify meaningful categorical filters or segmentations.\n - Leverage table [rows / size] hints to determine whether to aggregate (large tables) or inspect detailed data (tiny tables).\n - Reference PK/Indexed annotations and the Indexes list to recommend queries that use efficient join/filter paths.\n - Column annotations may expose ranges/null percentages\u2014use them to suggest realistic thresholds or quality checks.\n - Consult <relationship_examples> to anchor your recommendations in the actual join paths between tables.\n - Output only information grounded in the schema/context provided.\n </instructions>\n\n <response-format>\n Return valid JSON that satisfies the defined output schema.\n </response-format>\n `;\n },\n});\n", "import { groq } from '@ai-sdk/groq';\nimport { type Tool, tool } from 'ai';\nimport z from 'zod';\n\nimport { agent, toState } from '@deepagents/agent';\nimport { scratchpad_tool } from '@deepagents/toolbox';\n\nimport type { Adapter } from '../adapters/adapter.ts';\nimport memoryPrompt from '../memory/memory.prompt.ts';\nimport type { TeachablesStore } from '../memory/store.ts';\nimport type { GeneratedTeachable } from '../teach/teachables.ts';\n\nexport type RenderingTools = Record<string, Tool<unknown, never>>;\n\nconst tools = {\n validate_query: tool({\n description: `Validate SQL query syntax before execution. Use this to check if your SQL is valid before running db_query. This helps catch errors early and allows you to correct the query if needed.`,\n inputSchema: z.object({\n sql: z.string().describe('The SQL query to validate.'),\n }),\n execute: async ({ sql }, options) => {\n const state = toState<{ adapter: Adapter }>(options);\n const result = await state.adapter.validate(sql);\n if (typeof result === 'string') {\n return `Validation Error: ${result}`;\n }\n return 'Query is valid.';\n },\n }),\n get_sample_rows: tool({\n description: `Sample rows from a table to understand data formatting, codes, and value patterns. Use BEFORE writing queries when:\n- Column types in schema don't reveal format (e.g., \"status\" could be 'active'/'inactive' or 1/0)\n- Date/time formats are unclear (ISO, Unix timestamp, locale-specific)\n- You need to understand lookup table codes or enum values\n- Column names are ambiguous (e.g., \"type\", \"category\", \"code\")`,\n inputSchema: z.object({\n tableName: z.string().describe('The name of the table to sample.'),\n columns: z\n .array(z.string())\n .optional()\n .describe(\n 'Specific columns to sample. If omitted, samples all columns.',\n ),\n limit: z\n .number()\n .min(1)\n .max(10)\n .default(3)\n .optional()\n .describe('Number of rows to sample (1-10, default 3).'),\n }),\n execute: ({ tableName, columns, limit = 3 }, options) => {\n const safeLimit = Math.min(Math.max(1, limit), 10);\n const state = toState<{ adapter: Adapter }>(options);\n const sql = state.adapter.buildSampleRowsQuery(\n tableName,\n columns,\n safeLimit,\n );\n return state.adapter.execute(sql);\n },\n }),\n db_query: tool({\n description: `Internal tool to fetch data from the store's database. Write a SQL query to retrieve the information needed to answer the user's question. The results will be returned as data that you can then present to the user in natural language.`,\n inputSchema: z.object({\n reasoning: z\n .string()\n .describe(\n 'Your reasoning for why this SQL query is relevant to the user request.',\n ),\n sql: z\n .string()\n .min(1, { message: 'SQL query cannot be empty.' })\n .refine(\n (sql) =>\n sql.trim().toUpperCase().startsWith('SELECT') ||\n sql.trim().toUpperCase().startsWith('WITH'),\n {\n message: 'Only read-only SELECT or WITH queries are allowed.',\n },\n )\n .describe('The SQL query to execute against the database.'),\n }),\n execute: ({ sql }, options) => {\n const state = toState<{ adapter: Adapter }>(options);\n return state.adapter.execute(sql);\n },\n }),\n scratchpad: scratchpad_tool,\n};\n\nconst userMemoryTypes = [\n 'identity',\n 'alias',\n 'preference',\n 'context',\n 'correction',\n] as const;\n\nconst userMemorySchema = z.discriminatedUnion('type', [\n z.object({\n type: z.literal('identity'),\n description: z.string().describe(\"The user's identity: role or/and name\"),\n }),\n z.object({\n type: z.literal('alias'),\n term: z.string().describe('The term the user uses'),\n meaning: z.string().describe('What the user means by this term'),\n }),\n z.object({\n type: z.literal('preference'),\n aspect: z\n .string()\n .describe('What aspect of output this preference applies to'),\n value: z.string().describe(\"The user's preference\"),\n }),\n z.object({\n type: z.literal('context'),\n description: z.string().describe('What the user is currently working on'),\n }),\n z.object({\n type: z.literal('correction'),\n subject: z.string().describe('What was misunderstood'),\n clarification: z.string().describe('The correct understanding'),\n }),\n]);\n\nexport const memoryTools = {\n remember_memory: tool({\n description:\n 'Store something about the user for future conversations. Use silently when user shares facts, preferences, vocabulary, corrections, or context.',\n inputSchema: z.object({ memory: userMemorySchema }),\n execute: async ({ memory }, options) => {\n const state = toState<{ memory: TeachablesStore; userId: string }>(\n options,\n );\n await state.memory.remember(state.userId, memory as GeneratedTeachable);\n return 'Remembered.';\n },\n }),\n forget_memory: tool({\n description:\n 'Forget a specific memory. Use when user asks to remove something.',\n inputSchema: z.object({\n id: z.string().describe('The ID of the teachable to forget'),\n }),\n execute: async ({ id }, options) => {\n const state = toState<{ memory: TeachablesStore }>(options);\n await state.memory.forget(id);\n return 'Forgotten.';\n },\n }),\n recall_memory: tool({\n description:\n 'List stored memories for the current user. Use when user asks what you remember about them or wants to see their stored preferences.',\n inputSchema: z.object({\n type: z\n .enum(userMemoryTypes)\n .optional()\n .catch(undefined)\n .describe('Optional: filter by memory type'),\n }),\n execute: async ({ type }, options) => {\n const state = toState<{ memory: TeachablesStore; userId: string }>(\n options,\n );\n const memories = await state.memory.recall(state.userId, type);\n if (memories.length === 0) {\n return type ? `No ${type} memories stored.` : 'No memories stored.';\n }\n return memories.map((m) => ({\n id: m.id,\n type: m.type,\n data: m.data,\n createdAt: m.createdAt,\n }));\n },\n }),\n update_memory: tool({\n description:\n 'Update an existing memory. Use when user wants to modify something you previously stored.',\n inputSchema: z.object({\n memory: userMemorySchema,\n id: z.string().describe('The ID of the memory to update'),\n }),\n execute: async ({ id, memory }, options) => {\n const state = toState<{ memory: TeachablesStore }>(options);\n await state.memory.update(id, memory as GeneratedTeachable);\n return 'Updated.';\n },\n }),\n};\n\n/**\n * Chain of Thought prompt for text-to-SQL.\n *\n * Research-backed approach:\n * - Keep reasoning concise to avoid error propagation (EMNLP 2023)\n * - Focus on schema linking and database operations (Struct-SQL 2025)\n * - Use intermediate representations for complex queries\n *\n * @see https://arxiv.org/abs/2305.14215\n * @see https://arxiv.org/html/2512.17053\n */\nconst chainOfThoughtPrompt = `\n## Query Reasoning Process\n\nLet's think step by step before writing SQL:\n\n1. **Schema Link**: Which tables and columns are relevant? Verify they exist in the schema.\n2. **Join Path**: If multiple tables, what relationships connect them?\n3. **Filters**: What WHERE conditions are needed?\n4. **Aggregation**: Is COUNT, SUM, AVG, GROUP BY, or HAVING required?\n5. **Output**: What columns to SELECT and any ORDER BY or LIMIT?\n6. **Verify**: Do all referenced tables and columns exist in the schema above?\n\nFor simple queries, steps 2-4 may not apply\u2014skip them.\n\nFor complex queries requiring multiple data points, decompose into sub-questions:\n- Break the question into simpler parts (Q1, Q2, ...)\n- Determine if each part needs a subquery or CTE\n- Combine the parts into the final query\n\nKeep reasoning brief. Verbose explanations cause errors.\n`;\n\n/**\n * Few-shot examples demonstrating the CoT reasoning process.\n * Uses abstract placeholders (table_a, column_x) for maximum generalization.\n */\nconst fewShotExamples = `\n## Examples\n\n### Example 1: Simple Filter\nQuestion: \"How many records in table_a have column_x equal to 'value'?\"\nReasoning:\n- Schema Link: table_a, column_x\n- Filters: column_x = 'value'\n- Aggregation: COUNT(*)\nSQL: SELECT COUNT(*) FROM table_a WHERE column_x = 'value'\n\n### Example 2: JOIN Query\nQuestion: \"Show column_y from table_b for each record in table_a where column_x is 'value'\"\nReasoning:\n- Schema Link: table_a (column_x, id), table_b (column_y, fk_a)\n- Join Path: table_a.id \u2192 table_b.fk_a\n- Filters: column_x = 'value'\n- Output: column_y from table_b\nSQL: SELECT b.column_y FROM table_a a JOIN table_b b ON b.fk_a = a.id WHERE a.column_x = 'value'\n\n### Example 3: Aggregation with GROUP BY\nQuestion: \"What is the total of column_y grouped by column_x?\"\nReasoning:\n- Schema Link: table_a (column_x, column_y)\n- Aggregation: SUM(column_y), GROUP BY column_x\n- Output: column_x, sum\nSQL: SELECT column_x, SUM(column_y) as total FROM table_a GROUP BY column_x\n\n### Example 4: Complex Aggregation\nQuestion: \"Which values of column_x have more than 10 records, sorted by count descending?\"\nReasoning:\n- Schema Link: table_a (column_x)\n- Aggregation: COUNT(*), GROUP BY column_x, HAVING > 10\n- Output: column_x, count, ORDER BY count DESC\nSQL: SELECT column_x, COUNT(*) as cnt FROM table_a GROUP BY column_x HAVING COUNT(*) > 10 ORDER BY cnt DESC\n\n### Example 5: Subquery (Decomposition)\nQuestion: \"Show records from table_a where column_y is above average\"\nReasoning:\n- Decompose:\n - Q1: What is the average of column_y?\n - Q2: Which records have column_y above that value?\n- Schema Link: table_a (column_y)\n- Filters: column_y > (result of Q1)\n- Output: all columns from matching records\n- Verify: table_a and column_y exist \u2713\nSQL: SELECT * FROM table_a WHERE column_y > (SELECT AVG(column_y) FROM table_a)\n\n### Example 6: Complex Multi-Join (Decomposition)\nQuestion: \"Find the top 3 categories by total sales amount for orders placed last month\"\nReasoning:\n- Decompose:\n - Q1: Which orders were placed last month?\n - Q2: What is the total sales per category for those orders?\n - Q3: Which 3 categories have the highest totals?\n- Schema Link: orders (order_date, id), order_items (order_id, amount, product_id), products (id, category_id), categories (id, name)\n- Join Path: orders \u2192 order_items \u2192 products \u2192 categories\n- Filters: order_date within last month\n- Aggregation: SUM(amount), GROUP BY category\n- Output: category name, total, ORDER BY total DESC, LIMIT 3\n- Verify: all tables and columns exist \u2713\nSQL: SELECT c.name, SUM(oi.amount) as total FROM orders o JOIN order_items oi ON oi.order_id = o.id JOIN products p ON p.id = oi.product_id JOIN categories c ON c.id = p.category_id WHERE o.order_date >= DATE('now', '-1 month') GROUP BY c.id, c.name ORDER BY total DESC LIMIT 3\n`;\n\n/**\n * An agent that does Table Augmented Generation for Text-to-SQL tasks.\n */\nexport const t_a_g = agent<\n { sql: string },\n {\n // FIXME: this should not be here after creating the context package\n introspection: string;\n teachings: string;\n memory?: TeachablesStore;\n userId?: string;\n }\n>({\n model: groq('openai/gpt-oss-20b'),\n tools,\n name: 'text2sql',\n prompt: (state) => {\n const hasMemory = !!state?.memory;\n\n return `\n ${state?.teachings || ''}\n ${state?.introspection || ''}\n\n ${chainOfThoughtPrompt}\n\n ${fewShotExamples}\n\n ${hasMemory ? memoryPrompt : ''}\n `;\n },\n});\n", "import {\n clarification,\n example,\n explain,\n guardrail,\n hint,\n toInstructions,\n workflow,\n} from '../teach/teachables.ts';\n\nexport default toInstructions(\n 'memory_guidelines',\n\n // Section 1: Core behavior\n guardrail({\n rule: 'Silently store user information when revealed. Respond to memory-related requests.',\n reason: 'Memory enables personalized responses across conversations',\n action:\n 'Store silently on reveal. Respond explicitly when asked about memories.',\n }),\n\n // Section 2: Workflows for memory operations\n\n workflow({\n task: 'Store user identity silently',\n triggers: [\"I'm a\", 'I work as', 'my name is', 'my role is'],\n steps: [\n 'Extract name and/or role from the statement',\n 'Call remember_memory() with type: \"identity\" and name/role fields',\n 'Do NOT announce or confirm - continue conversation naturally',\n ],\n notes:\n 'This should happen silently without disrupting the conversation flow.',\n }),\n\n workflow({\n task: 'Store user preferences and context silently',\n triggers: ['When I say', 'I prefer', \"I'm working on\"],\n steps: [\n 'Identify the memory type (alias/preference/context/correction)',\n 'Extract the relevant information',\n 'Call remember_memory() with appropriate type and fields',\n 'Do NOT announce or confirm - continue conversation naturally',\n ],\n notes:\n 'This should happen silently without disrupting the conversation flow.',\n }),\n\n workflow({\n task: 'Forget a memory',\n triggers: ['forget that', 'remove my', 'delete the', \"don't remember that\"],\n steps: [\n 'Call recall_memory() to list relevant memories',\n 'Find the memory ID that matches user request',\n 'Call forget_memory({ id }) with the found ID',\n 'Confirm to user what was forgotten',\n ],\n }),\n\n workflow({\n task: 'Update a memory',\n triggers: ['actually now I', 'I changed', 'update my', 'no longer'],\n steps: [\n 'Call recall_memory() to find the existing memory',\n 'Get the memory ID from results',\n 'Call update_memory({ id, memory }) with new data',\n 'Confirm the update to user',\n ],\n }),\n\n // Section 3: Type disambiguation\n\n explain({\n concept: 'identity vs context',\n explanation:\n 'Identity = WHO the user is (name and/or role, permanent). Context = WHAT they are working on (temporary focus).',\n therefore: 'Identity rarely changes. Context changes per project/task.',\n }),\n\n explain({\n concept: 'alias vs correction',\n explanation:\n 'Alias = user defines their own term/shorthand. Correction = user fixes a misunderstanding about existing data/schema.',\n therefore: 'Alias is vocabulary. Correction is data clarification.',\n }),\n\n explain({\n concept: 'preference memory type',\n explanation:\n 'Stores output/style/format preferences. Fields: { aspect: string, value: string }',\n therefore: 'Use for formatting, limits, display style, data scope filters',\n }),\n\n // Section 4: Clarifications for ambiguous situations\n\n clarification({\n when: 'user says something like \"X actually means Y\" but unclear if defining their term or correcting data',\n ask: 'Are you defining your own shorthand for this term, or correcting how the data/schema actually works?',\n reason:\n 'Alias is personal vocabulary. Correction is a data/schema clarification that applies universally.',\n }),\n\n clarification({\n when: 'user mentions a project or task that could be their identity or current focus',\n ask: 'Is this your ongoing identity (name/role), or a specific project you are currently working on?',\n reason:\n 'Identity is permanent. Context is temporary focus that may change.',\n }),\n\n // Section 5: Examples\n\n // Identity - role\n example({\n question: \"I'm the VP of Sales\",\n answer: 'remember_memory({ memory: { type: \"identity\", role: \"VP of Sales\" }})',\n note: 'Identity stores role',\n }),\n\n // Identity - name\n example({\n question: 'My name is Sarah',\n answer: 'remember_memory({ memory: { type: \"identity\", name: \"Sarah\" }})',\n note: 'Identity stores name',\n }),\n\n // Context\n example({\n question: \"I'm analyzing Q4 performance\",\n answer: 'remember_memory({ memory: { type: \"context\", description: \"Analyzing Q4 performance\" }})',\n note: 'Current task = context',\n }),\n\n // Alias\n example({\n question: 'When I say \"big customers\", I mean revenue > $1M',\n answer: 'remember_memory({ memory: { type: \"alias\", term: \"big customers\", meaning: \"revenue > $1M\" }})',\n note: 'User defining their vocabulary = alias',\n }),\n\n // Correction\n example({\n question:\n 'No, the status column uses 1 for active, not the string \"active\"',\n answer: 'remember_memory({ memory: { type: \"correction\", subject: \"status column values\", clarification: \"Uses 1 for active, not string\" }})',\n note: 'Correcting schema/data assumption = correction',\n }),\n\n // Preference\n example({\n question: 'Always show dates as YYYY-MM-DD',\n answer: 'remember_memory({ memory: { type: \"preference\", aspect: \"date format\", value: \"YYYY-MM-DD\" }})',\n }),\n\n // Recall\n example({\n question: 'What do you remember about me?',\n answer: 'recall_memory({})',\n note: 'List all stored memories',\n }),\n\n // Section 6: What NOT to remember\n hint('Do NOT remember one-time query details like \"show last 10 orders\"'),\n hint(\n 'Do NOT remember information already stored - use recall_memory to check first',\n ),\n hint('Do NOT remember obvious or universal facts'),\n);\n", "import { createHash } from 'node:crypto';\nimport { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport pLimit from 'p-limit';\n\nexport interface CheckpointOptions {\n /** Path to the checkpoint file */\n path: string;\n /** Hash to detect config changes - if changed, checkpoint is invalidated */\n configHash?: string;\n}\n\n/**\n * Codec for encoding/decoding values during checkpoint operations.\n * Use this when storing objects with methods (like Teachables) that need\n * to be serialized to plain JSON and restored with their methods.\n */\nexport interface Codec<T, TSerialized = unknown> {\n /** Convert runtime value to JSON-serializable format */\n encode: (value: T) => TSerialized;\n /** Convert stored JSON back to runtime value */\n decode: (serialized: TSerialized) => T;\n}\n\ninterface PointEntry {\n inputHash: string;\n output: unknown;\n}\n\ninterface PointData {\n committed: boolean;\n entries: PointEntry[];\n}\n\ninterface CheckpointFile {\n configHash?: string;\n points: Record<string, PointData>;\n}\n\nexport class Checkpoint {\n private points: Record<string, PointData>;\n\n private constructor(\n private path: string,\n private configHash: string | undefined,\n points: Record<string, PointData>,\n ) {\n this.points = points;\n }\n\n /**\n * Load checkpoint from file, or return empty checkpoint if none exists.\n * Handles corrupted files and config changes gracefully.\n */\n static async load(options: CheckpointOptions): Promise<Checkpoint> {\n const { path, configHash } = options;\n\n if (existsSync(path)) {\n try {\n const content = readFileSync(path, 'utf-8');\n const file: CheckpointFile = JSON.parse(content);\n\n // Check if config changed\n if (configHash && file.configHash && file.configHash !== configHash) {\n console.log('\u26A0 Config changed, starting fresh');\n return new Checkpoint(path, configHash, {});\n }\n\n const points = file.points ?? {};\n const totalEntries = Object.values(points).reduce(\n (sum, p) => sum + p.entries.length,\n 0,\n );\n console.log(`\u2713 Resuming from checkpoint (${totalEntries} entries)`);\n return new Checkpoint(path, configHash, points);\n } catch {\n console.log('\u26A0 Checkpoint corrupted, starting fresh');\n return new Checkpoint(path, configHash, {});\n }\n }\n\n console.log('Starting new checkpoint');\n return new Checkpoint(path, configHash, {});\n }\n\n /**\n * Run a single computation with checkpointing.\n * If already completed, returns cached value.\n *\n * @param key - Unique identifier for this computation\n * @param computation - Async function that produces the value\n * @param codec - Optional codec for encoding/decoding non-primitive values\n */\n async run<T>(\n key: string,\n computation: () => Promise<T>,\n codec?: Codec<T>,\n ): Promise<T> {\n const point = this.point<T>(key);\n\n // Use fixed input hash for single-value runs\n return point.through(\n 'single',\n async () => {\n const result = await computation();\n return codec ? (codec.encode(result) as T) : result;\n },\n codec,\n );\n }\n\n /**\n * Create a resumable checkpoint point for iterative operations.\n *\n * @param step - Unique identifier for this checkpoint point\n */\n point<T>(step: string): Point<T> {\n this.points[step] ??= { committed: false, entries: [] };\n return new Point<T>(this.points[step], () => this.save());\n }\n\n /**\n * Process each input with automatic checkpointing and concurrency.\n *\n * @param step - Unique identifier for this checkpoint\n * @param inputs - Items to process\n * @param process - Function to process each input\n * @param options - Optional settings like concurrency\n * @returns All outputs (use `.flat()` if outputs are arrays)\n */\n async each<I, O>(\n step: string,\n inputs: Iterable<I>,\n process: (input: I) => Promise<O>,\n options?: { concurrency?: number },\n ): Promise<O[]> {\n const point = this.point<O>(step);\n const limit = pLimit(options?.concurrency ?? 1);\n\n const inputArray = Array.from(inputs);\n await Promise.all(\n inputArray.map((input) =>\n limit(() => point.through(input, () => process(input))),\n ),\n );\n\n await point.commit();\n return point.values();\n }\n\n /**\n * Get clean output from all completed points.\n * Single-entry points return the value directly, multi-entry return arrays.\n */\n getOutput(): Record<string, unknown> {\n const output: Record<string, unknown> = {};\n for (const [key, pointData] of Object.entries(this.points)) {\n if (pointData.entries.length === 1) {\n output[key] = pointData.entries[0].output;\n } else {\n output[key] = pointData.entries.map((e) => e.output);\n }\n }\n return output;\n }\n\n /** Get the file path where checkpoint is stored */\n getPath(): string {\n return this.path;\n }\n\n private async save(): Promise<void> {\n const file: CheckpointFile = {\n configHash: this.configHash,\n points: this.points,\n };\n const content = JSON.stringify(file, null, 2);\n\n // Atomic write: write to temp file, then rename\n const tempPath = `${this.path}.tmp`;\n writeFileSync(tempPath, content);\n renameSync(tempPath, this.path);\n }\n}\n\nfunction hash(value: unknown): string {\n return createHash('md5').update(JSON.stringify(value)).digest('hex');\n}\n\n/**\n * A checkpoint point for tracking iterative operations.\n * Uses input hashing to determine if an operation was already processed.\n */\nexport class Point<T> {\n #cache: Map<string, T>;\n\n constructor(\n private data: PointData,\n private persist: () => Promise<void>,\n ) {\n this.#cache = new Map(\n data.entries.map((e) => [e.inputHash, e.output as T]),\n );\n }\n\n /**\n * Execute computation if input wasn't processed before.\n * Returns cached output if input hash exists, otherwise executes, saves, and returns.\n */\n async through<I, O>(\n input: I,\n compute: () => Promise<O>,\n codec?: Codec<O>,\n ): Promise<O> {\n const inputHash = hash(input);\n\n if (this.#cache.has(inputHash)) {\n const cached = this.#cache.get(inputHash) as O;\n return codec ? codec.decode(cached) : cached;\n }\n\n const output = await compute();\n this.data.entries.push({ inputHash, output });\n this.#cache.set(inputHash, output as T);\n await this.persist();\n return codec ? codec.decode(output) : output;\n }\n\n /** Mark this point as complete. */\n async commit(): Promise<void> {\n this.data.committed = true;\n await this.persist();\n }\n\n /** Check if this point has been committed. */\n isCommitted(): boolean {\n return this.data.committed;\n }\n\n /** Get all outputs from this point. */\n values(): T[] {\n return this.data.entries.map((e) => e.output as T);\n }\n}\n\n/**\n * Generate a hash from a config object for checkpoint invalidation.\n * If config changes, the checkpoint will be invalidated and pipeline restarts.\n */\nexport function hashConfig(config: Record<string, unknown>): string {\n return createHash('md5').update(JSON.stringify(config)).digest('hex');\n}\n", "import { createHash } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport path from 'node:path';\n\nexport class FileCache {\n public path: string;\n constructor(watermark: string, extension = '.txt') {\n const hash = createHash('md5').update(watermark).digest('hex');\n this.path = path.join(tmpdir(), `text2sql-${hash}${extension}`);\n }\n\n async get() {\n if (existsSync(this.path)) {\n return readFile(this.path, 'utf-8');\n }\n return null;\n }\n\n set(content: string) {\n return writeFile(this.path, content, 'utf-8');\n }\n}\n\nexport class JsonCache<T> extends FileCache {\n constructor(watermark: string) {\n super(watermark, '.json');\n }\n\n async read(): Promise<T | null> {\n const content = await this.get();\n if (content) {\n return JSON.parse(content) as T;\n }\n return null;\n }\n\n write(data: T) {\n return this.set(JSON.stringify(data));\n }\n}\n", "import type { UIMessage } from 'ai';\n\nexport interface Message {\n id: string;\n chatId: string;\n role: string;\n createdAt: string | Date;\n content: UIMessage;\n}\n\nexport interface Chat {\n id: string;\n userId: string;\n title?: string | null;\n messages: Message[];\n}\n\nexport interface CreateChatParams {\n id: string;\n userId: string;\n title?: string;\n}\n\nexport interface UpdateChatParams {\n title?: string;\n}\n\nexport interface CreateMessageParams {\n id: string;\n chatId: string;\n role: string;\n content: UIMessage;\n createdAt?: Date;\n}\n\nexport abstract class History {\n abstract listChats(userId: string): Promise<Chat[]>;\n abstract getChat(chatId: string): Promise<Chat | null>;\n abstract createChat(chat: CreateChatParams): Promise<Chat>;\n abstract upsertChat(chat: CreateChatParams): Promise<Chat>;\n abstract deleteChat(chatId: string): Promise<void>;\n abstract updateChat(chatId: string, updates: UpdateChatParams): Promise<void>;\n abstract addMessage(message: CreateMessageParams): Promise<void>;\n abstract upsertMessage(message: CreateMessageParams): Promise<Message>;\n abstract deleteMessage(messageId: string): Promise<void>;\n}\n", "import { DatabaseSync } from 'node:sqlite';\n\nimport historyDDL from './history.sqlite.sql';\nimport {\n type Chat,\n type CreateChatParams,\n type CreateMessageParams,\n History,\n type Message,\n type UpdateChatParams,\n} from './history.ts';\n\nexport class SqliteHistory extends History {\n #db: DatabaseSync;\n\n constructor(path: string) {\n super();\n this.#db = new DatabaseSync(path);\n this.#db.exec(historyDDL);\n }\n\n async listChats(userId: string): Promise<Chat[]> {\n return this.#db\n .prepare(`SELECT * FROM chats WHERE \"userId\" = ?`)\n .all(userId) as unknown as Chat[];\n }\n\n async getChat(chatId: string): Promise<Chat | null> {\n const rows = this.#db\n .prepare(\n `SELECT\n c.id as chatId, c.\"userId\", c.title,\n m.id as messageId, m.role, m.\"createdAt\", m.content\n FROM chats c\n LEFT JOIN messages m ON m.\"chatId\" = c.id\n WHERE c.id = ?\n ORDER BY m.\"createdAt\" ASC`,\n )\n .all(chatId) as unknown as Array<{\n chatId: string;\n userId: string;\n title: string | null;\n messageId: string | null;\n role: string;\n createdAt: string;\n content: string;\n }>;\n\n if (!rows.length) return null;\n\n const firstRow = rows[0];\n const chat: Chat = {\n id: firstRow.chatId,\n userId: firstRow.userId,\n title: firstRow.title,\n messages: [],\n };\n\n for (const row of rows) {\n if (row.messageId) {\n chat.messages.push({\n id: row.messageId,\n chatId: firstRow.chatId,\n role: row.role as string,\n createdAt: row.createdAt as string,\n content: JSON.parse(row.content),\n });\n }\n }\n\n return chat;\n }\n\n async createChat(chat: CreateChatParams): Promise<Chat> {\n this.#db\n .prepare(`INSERT INTO chats (id, \"userId\", title) VALUES (?, ?, ?)`)\n .run(chat.id, chat.userId, chat.title || null);\n return chat as Chat;\n }\n\n async upsertChat(chat: CreateChatParams) {\n this.#db\n .prepare(\n `INSERT INTO chats (id, \"userId\", title) VALUES (?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET title = excluded.title, \"userId\" = excluded.\"userId\"`,\n )\n .run(chat.id, chat.userId, chat.title || null);\n return this.getChat(chat.id) as Promise<Chat>;\n }\n\n async deleteChat(chatId: string): Promise<void> {\n this.#db.prepare(`DELETE FROM chats WHERE id = ?`).run(chatId);\n }\n\n async updateChat(chatId: string, updates: UpdateChatParams): Promise<void> {\n if (updates.title !== undefined) {\n this.#db\n .prepare(`UPDATE chats SET title = ? WHERE id = ?`)\n .run(updates.title, chatId);\n }\n }\n\n async addMessage(message: CreateMessageParams): Promise<void> {\n const createdAt = message.createdAt\n ? message.createdAt.toISOString()\n : new Date().toISOString();\n this.#db\n .prepare(\n `INSERT INTO messages (id, \"chatId\", role, \"createdAt\", content) VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET\n \"chatId\" = excluded.\"chatId\",\n role = excluded.role,\n content = excluded.content`,\n )\n .run(\n message.id,\n message.chatId,\n message.role,\n createdAt,\n JSON.stringify(message.content),\n );\n }\n\n async upsertMessage(message: CreateMessageParams): Promise<Message> {\n const createdAt = message.createdAt\n ? message.createdAt.toISOString()\n : new Date().toISOString();\n this.#db\n .prepare(\n `INSERT INTO messages (id, \"chatId\", role, \"createdAt\", content) VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET \"chatId\" = excluded.\"chatId\", role = excluded.role, \"createdAt\" = excluded.\"createdAt\", content = excluded.content`,\n )\n .run(\n message.id,\n message.chatId,\n message.role,\n createdAt,\n JSON.stringify(message.content),\n );\n return {\n ...message,\n createdAt,\n };\n }\n\n async deleteMessage(messageId: string): Promise<void> {\n this.#db.prepare(`DELETE FROM messages WHERE id = ?`).run(messageId);\n }\n}\n", "CREATE TABLE IF NOT EXISTS \"chats\" (\n\t\"id\" VARCHAR PRIMARY KEY,\n\t\"title\" VARCHAR,\n\t\"userId\" VARCHAR\n);\n\nCREATE TABLE IF NOT EXISTS \"messages\" (\n\t\"id\" VARCHAR PRIMARY KEY,\n\t\"chatId\" VARCHAR NOT NULL REFERENCES \"chats\" (\"id\") ON DELETE CASCADE,\n\t\"createdAt\" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n\t\"role\" VARCHAR NOT NULL,\n\t\"content\" TEXT NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS \"messages_chat_id_idx\" ON \"messages\" (\"chatId\");\n\nCREATE INDEX IF NOT EXISTS \"messages_chat_id_created_at_idx\" ON \"messages\" (\"chatId\", \"createdAt\");\n", "import { SqliteHistory } from './sqlite.history.ts';\n\nexport class InMemoryHistory extends SqliteHistory {\n constructor() {\n super(':memory:');\n }\n}\n", "import { DatabaseSync } from 'node:sqlite';\nimport { v7 } from 'uuid';\n\nimport {\n type GeneratedTeachable,\n type Teachables,\n toTeachables,\n} from '../teach/teachables.ts';\nimport storeDDL from './store.sqlite.sql';\nimport { type StoredTeachable, TeachablesStore } from './store.ts';\n\ninterface TeachableRow {\n id: string;\n userId: string;\n type: string;\n data: string;\n createdAt: string;\n updatedAt: string;\n}\n\nfunction rowToStoredTeachable(row: TeachableRow): StoredTeachable {\n return {\n id: row.id,\n userId: row.userId,\n type: row.type as GeneratedTeachable['type'],\n data: JSON.parse(row.data),\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nexport class SqliteTeachablesStore extends TeachablesStore {\n #db: DatabaseSync;\n\n constructor(path: string) {\n super();\n this.#db = new DatabaseSync(path);\n this.#db.exec(storeDDL);\n }\n\n async remember(\n userId: string,\n data: GeneratedTeachable,\n ): Promise<StoredTeachable> {\n const id = v7();\n const now = new Date().toISOString();\n\n this.#db\n .prepare(\n 'INSERT INTO teachables (id, userId, type, data, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?, ?)',\n )\n .run(id, userId, data.type, JSON.stringify(data), now, now);\n\n return (await this.get(id))!;\n }\n\n async recall(\n userId: string,\n type?: GeneratedTeachable['type'],\n ): Promise<StoredTeachable[]> {\n let rows: TeachableRow[];\n\n if (type === undefined) {\n rows = this.#db\n .prepare('SELECT * FROM teachables WHERE userId = ? ORDER BY createdAt')\n .all(userId) as unknown as TeachableRow[];\n } else {\n rows = this.#db\n .prepare(\n 'SELECT * FROM teachables WHERE userId = ? AND type = ? ORDER BY createdAt',\n )\n .all(userId, type) as unknown as TeachableRow[];\n }\n\n return rows.map(rowToStoredTeachable);\n }\n\n async get(id: string): Promise<StoredTeachable | null> {\n const row = this.#db\n .prepare('SELECT * FROM teachables WHERE id = ?')\n .get(id) as TeachableRow | undefined;\n\n if (!row) return null;\n return rowToStoredTeachable(row);\n }\n\n async update(id: string, data: GeneratedTeachable): Promise<StoredTeachable> {\n const now = new Date().toISOString();\n\n this.#db\n .prepare(\n 'UPDATE teachables SET data = ?, type = ?, updatedAt = ? WHERE id = ?',\n )\n .run(JSON.stringify(data), data.type, now, id);\n\n return (await this.get(id))!;\n }\n\n async forget(id: string): Promise<void> {\n this.#db.prepare('DELETE FROM teachables WHERE id = ?').run(id);\n }\n\n async forgetAll(userId: string): Promise<void> {\n this.#db.prepare('DELETE FROM teachables WHERE userId = ?').run(userId);\n }\n\n async toTeachables(userId: string): Promise<Teachables[]> {\n const stored = await this.recall(userId);\n return toTeachables(stored.map((s) => s.data));\n }\n}\n", "CREATE TABLE IF NOT EXISTS \"teachables\" (\n\t\"id\" VARCHAR PRIMARY KEY,\n\t\"userId\" VARCHAR,\n\t\"type\" VARCHAR NOT NULL,\n\t\"data\" TEXT NOT NULL,\n\t\"createdAt\" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n\t\"updatedAt\" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE INDEX IF NOT EXISTS \"teachables_user_id_idx\" ON \"teachables\" (\"userId\");\n\nCREATE INDEX IF NOT EXISTS \"teachables_type_idx\" ON \"teachables\" (\"type\");\n\nCREATE INDEX IF NOT EXISTS \"teachables_user_type_idx\" ON \"teachables\" (\"userId\", \"type\");\n", "import type { GeneratedTeachable, Teachables } from '../teach/teachables.ts';\n\nexport interface StoredTeachable {\n id: string;\n userId: string;\n type: GeneratedTeachable['type'];\n data: GeneratedTeachable;\n createdAt: string;\n updatedAt: string;\n}\n\nexport abstract class TeachablesStore {\n /**\n * Remember a teachable for a user.\n */\n abstract remember(\n userId: string,\n data: GeneratedTeachable,\n ): Promise<StoredTeachable>;\n\n /**\n * Recall teachables for a user, optionally filtered by type.\n */\n abstract recall(\n userId: string,\n type?: GeneratedTeachable['type'],\n ): Promise<StoredTeachable[]>;\n\n /**\n * Get a specific teachable by ID.\n */\n abstract get(id: string): Promise<StoredTeachable | null>;\n\n /**\n * Update an existing teachable.\n */\n abstract update(\n id: string,\n data: GeneratedTeachable,\n ): Promise<StoredTeachable>;\n\n /**\n * Forget (remove) a specific teachable by ID.\n */\n abstract forget(id: string): Promise<void>;\n\n /**\n * Forget all teachables for a user.\n */\n abstract forgetAll(userId: string): Promise<void>;\n\n /**\n * Convert stored teachables to Teachables array for use with toInstructions().\n */\n abstract toTeachables(userId: string): Promise<Teachables[]>;\n}\n", "import { SqliteTeachablesStore } from './sqlite.store.ts';\n\nexport class InMemoryTeachablesStore extends SqliteTeachablesStore {\n constructor() {\n super(':memory:');\n }\n}\n", "import {\n APICallError,\n InvalidToolInputError,\n NoSuchToolError,\n ToolCallRepairError,\n type UIMessage,\n generateId,\n} from 'ai';\n\nimport {\n type Agent,\n type AgentModel,\n generate,\n stream,\n user,\n} from '@deepagents/agent';\n\nimport type { Adapter, IntrospectOptions } from './adapters/adapter.ts';\nimport { chat1Agent, chat1Tools } from './agents/chat1.agent.ts';\nimport { chat2Agent, chat2Tools } from './agents/chat2.agent.ts';\nimport { chat3Agent, chat3Tools } from './agents/chat3.agent.ts';\nimport { chat4Agent, chat4Tools } from './agents/chat4.agent.ts';\nimport { developerAgent } from './agents/developer.agent.ts';\nimport { explainerAgent } from './agents/explainer.agent.ts';\nimport { toSql as agentToSql } from './agents/sql.agent.ts';\nimport {\n type RenderingTools,\n memoryTools,\n t_a_g,\n} from './agents/text2sql.agent.ts';\nimport { FileCache } from './file-cache.ts';\nimport { History } from './history/history.ts';\nimport type { TeachablesStore } from './memory/store.ts';\nimport { type ExtractedPair, type PairProducer } from './synthesis/types.ts';\nimport {\n type Teachables,\n guardrail,\n hint,\n persona,\n styleGuide,\n teachable,\n toInstructions,\n} from './teach/teachables.ts';\nimport { type TeachingsOptions, guidelines } from './teach/teachings.ts';\n\nexport interface InspectionResult {\n /** The grounding/introspection data (database schema context as XML) */\n grounding: string;\n\n /** The full instructions XML that would be sent to the agent */\n instructions: string;\n\n /** User-specific teachables that were loaded */\n userTeachables: Teachables[];\n\n /** System teachings configured */\n systemTeachings: Teachables[];\n\n /** Tool names available to the agent */\n tools: string[];\n}\n\nexport class Text2Sql {\n #config: {\n model?: AgentModel;\n adapter: Adapter;\n history: History;\n tools?: RenderingTools;\n instructions: Teachables[];\n memory?: TeachablesStore;\n introspection: FileCache;\n };\n\n constructor(config: {\n adapter: Adapter;\n history: History;\n version: string;\n tools?: RenderingTools;\n instructions?: Teachables[];\n model?: AgentModel;\n memory?: TeachablesStore;\n /**\n * Configure teachings behavior\n * @see TeachingsOptions\n */\n teachingsOptions?: TeachingsOptions;\n }) {\n this.#config = {\n adapter: config.adapter,\n history: config.history,\n instructions: [\n ...guidelines(config.teachingsOptions),\n ...(config.instructions ?? []),\n ],\n tools: config.tools ?? {},\n model: config.model,\n memory: config.memory,\n introspection: new FileCache('introspection-' + config.version),\n };\n }\n\n public async explain(sql: string) {\n const { experimental_output } = await generate(\n explainerAgent,\n [user('Explain this SQL.')],\n { sql },\n );\n return experimental_output.explanation;\n }\n\n public async toSql(input: string): Promise<string> {\n const introspection = await this.index();\n\n const result = await agentToSql({\n input,\n adapter: this.#config.adapter,\n introspection,\n instructions: this.#config.instructions,\n model: this.#config.model,\n });\n\n return result.sql;\n }\n\n public instruct(...dataset: Teachables[]) {\n this.#config.instructions.push(...dataset);\n }\n\n public async inspect(agent: Agent) {\n const [grounding] = await Promise.all([this.index() as Promise<string>]);\n\n const renderToolNames = Object.keys(this.#config.tools ?? {}).filter(\n (name) => name.startsWith('render_'),\n );\n const allInstructions = [\n ...this.#config.instructions,\n guardrail({\n rule: 'ALWAYS use `get_sample_rows` before writing queries that filter or compare against string columns.',\n reason: 'Prevents SQL errors from wrong value formats.',\n action:\n \"Target specific columns (e.g., get_sample_rows('table', ['status', 'type'])).\",\n }),\n ...(renderToolNames.length\n ? [\n hint(`Rendering tools available: ${renderToolNames.join(', ')}.`),\n styleGuide({\n prefer:\n 'Use render_* tools for trend/over time/monthly requests or chart asks',\n always:\n 'Include text insight alongside visualizations. Prefer line charts for time-based data.',\n }),\n ]\n : []),\n ];\n\n const tools = Object.keys({\n ...agent.handoff.tools,\n ...(this.#config.memory ? memoryTools : {}),\n ...this.#config.tools,\n });\n\n return {\n tools,\n prompt: agent.instructions({\n introspection: grounding,\n teachings: toInstructions('instructions', ...allInstructions),\n }),\n };\n }\n\n public async index(options?: IntrospectOptions) {\n const cached = await this.#config.introspection.get();\n if (cached) {\n return cached;\n }\n const introspection = await this.#config.adapter.introspect();\n await this.#config.introspection.set(introspection);\n return introspection;\n }\n\n /**\n * Generate training data pairs using a producer factory.\n * The factory receives the configured adapter, so users don't need to pass it manually.\n *\n * @example\n * // Generate questions for existing SQL\n * const pairs = await text2sql.toPairs(\n * (adapter) => new SqlExtractor(sqls, adapter, { validateSql: true })\n * );\n *\n * @example\n * // Extract from chat history with validation\n * const pairs = await text2sql.toPairs(\n * (adapter) => new ValidatedProducer(\n * new MessageExtractor(messages),\n * adapter\n * )\n * );\n */\n public async toPairs<T extends PairProducer>(\n factory: (adapter: Adapter) => T,\n ): Promise<ExtractedPair[]> {\n const producer = factory(this.#config.adapter);\n return producer.toPairs();\n }\n\n // public async suggest() {\n // const [introspection, adapterInfo] = await Promise.all([\n // this.index(),\n // this.#config.adapter.introspect(),\n // ]);\n // const { experimental_output: output } = await generate(\n // suggestionsAgent,\n // [\n // user(\n // 'Suggest high-impact business questions and matching SQL queries for this database.',\n // ),\n // ],\n // {\n // },\n // );\n // return output.suggestions;\n // }\n\n public async chat(\n messages: UIMessage[],\n params: {\n chatId: string;\n userId: string;\n },\n ) {\n const [introspection, userTeachables] = await Promise.all([\n this.index({ onProgress: console.log }),\n this.#config.memory\n ? this.#config.memory.toTeachables(params.userId)\n : [],\n ]);\n const chat = await this.#config.history.upsertChat({\n id: params.chatId,\n userId: params.userId,\n title: 'Chat ' + params.chatId,\n });\n\n // Build instructions with conditional rendering hint\n const renderToolNames = Object.keys(this.#config.tools ?? {}).filter(\n (name) => name.startsWith('render_'),\n );\n const instructions = [\n ...this.#config.instructions,\n guardrail({\n rule: 'ALWAYS use `get_sample_rows` before writing queries that filter or compare against string columns.',\n reason: 'Prevents SQL errors from wrong value formats.',\n action:\n \"Target specific columns (e.g., get_sample_rows('table', ['status', 'type'])).\",\n }),\n ...(renderToolNames.length\n ? [\n hint(`Rendering tools available: ${renderToolNames.join(', ')}.`),\n styleGuide({\n prefer:\n 'Use render_* tools for trend/over time/monthly requests or chart asks',\n always:\n 'Include text insight alongside visualizations. Prefer line charts for time-based data.',\n }),\n ]\n : []),\n ];\n const originalMessage = [\n ...chat.messages.map((it) => it.content),\n ...messages,\n ];\n const result = stream(\n t_a_g.clone({\n model: this.#config.model,\n tools: {\n ...t_a_g.handoff.tools,\n ...(this.#config.memory ? memoryTools : {}),\n ...this.#config.tools,\n },\n }),\n originalMessage,\n {\n teachings: toInstructions(\n 'instructions',\n persona({\n name: 'Freya',\n role: 'You are an expert SQL query generator, answering business questions with accurate queries.',\n tone: 'Your tone should be concise and business-friendly.',\n }),\n ...instructions,\n teachable('user_profile', ...userTeachables),\n ),\n adapter: this.#config.adapter,\n introspection,\n memory: this.#config.memory,\n userId: params.userId,\n },\n );\n\n return this.#createUIMessageStream(\n result,\n messages,\n params,\n originalMessage,\n );\n }\n\n /**\n * Chat1 - Combined tool, no peek.\n *\n * Uses a single `query_database` tool that:\n * 1. Takes a natural language question\n * 2. Internally calls toSql() to generate validated SQL\n * 3. Executes the SQL\n * 4. Returns both SQL and results\n *\n * The agent does NOT see the SQL before execution.\n */\n public async chat1(\n messages: UIMessage[],\n params: {\n chatId: string;\n userId: string;\n },\n ) {\n const [introspection, userTeachables] = await Promise.all([\n this.index({ onProgress: console.log }),\n this.#config.memory\n ? this.#config.memory.toTeachables(params.userId)\n : [],\n ]);\n const chat = await this.#config.history.upsertChat({\n id: params.chatId,\n userId: params.userId,\n title: 'Chat ' + params.chatId,\n });\n\n const renderToolNames = Object.keys(this.#config.tools ?? {}).filter(\n (name) => name.startsWith('render_'),\n );\n const instructions = [\n ...this.#config.instructions,\n ...(renderToolNames.length\n ? [\n hint(`Rendering tools available: ${renderToolNames.join(', ')}.`),\n styleGuide({\n prefer:\n 'Use render_* tools for trend/over time/monthly requests or chart asks',\n always:\n 'Include text insight alongside visualizations. Prefer line charts for time-based data.',\n }),\n ]\n : []),\n ];\n\n const originalMessage = [\n ...chat.messages.map((it) => it.content),\n ...messages,\n ];\n\n const result = stream(\n chat1Agent.clone({\n model: this.#config.model,\n tools: {\n ...chat1Tools,\n ...(this.#config.memory ? memoryTools : {}),\n ...this.#config.tools,\n },\n }),\n originalMessage,\n {\n teachings: toInstructions(\n 'instructions',\n ...instructions,\n teachable('user_profile', ...userTeachables),\n ),\n adapter: this.#config.adapter,\n introspection,\n instructions: this.#config.instructions,\n memory: this.#config.memory,\n userId: params.userId,\n },\n );\n\n return this.#createUIMessageStream(\n result,\n messages,\n params,\n originalMessage,\n );\n }\n\n /**\n * Chat2 - Separate generate + execute tools (with peek).\n *\n * Uses two separate tools:\n * 1. `generate_sql` - Takes a question, returns validated SQL\n * 2. `execute_sql` - Takes SQL, executes it\n *\n * The agent sees the SQL before execution and can review/refine.\n */\n public async chat2(\n messages: UIMessage[],\n params: {\n chatId: string;\n userId: string;\n },\n ) {\n const [introspection, userTeachables] = await Promise.all([\n this.index({ onProgress: console.log }),\n this.#config.memory\n ? this.#config.memory.toTeachables(params.userId)\n : [],\n ]);\n const chat = await this.#config.history.upsertChat({\n id: params.chatId,\n userId: params.userId,\n title: 'Chat ' + params.chatId,\n });\n\n const renderToolNames = Object.keys(this.#config.tools ?? {}).filter(\n (name) => name.startsWith('render_'),\n );\n const instructions = [\n ...this.#config.instructions,\n ...(renderToolNames.length\n ? [\n hint(`Rendering tools available: ${renderToolNames.join(', ')}.`),\n styleGuide({\n prefer:\n 'Use render_* tools for trend/over time/monthly requests or chart asks',\n always:\n 'Include text insight alongside visualizations. Prefer line charts for time-based data.',\n }),\n ]\n : []),\n ];\n\n const originalMessage = [\n ...chat.messages.map((it) => it.content),\n ...messages,\n ];\n\n const result = stream(\n chat2Agent.clone({\n model: this.#config.model,\n tools: {\n ...chat2Tools,\n ...(this.#config.memory ? memoryTools : {}),\n ...this.#config.tools,\n },\n }),\n originalMessage,\n {\n teachings: toInstructions(\n 'instructions',\n ...instructions,\n teachable('user_profile', ...userTeachables),\n ),\n adapter: this.#config.adapter,\n introspection,\n instructions: this.#config.instructions,\n memory: this.#config.memory,\n userId: params.userId,\n },\n );\n\n return this.#createUIMessageStream(\n result,\n messages,\n params,\n originalMessage,\n );\n }\n\n /**\n * Chat3 - Agent conversation/collaboration.\n *\n * Enables richer interaction where the SQL agent can:\n * - Surface confidence levels\n * - State assumptions\n * - Request clarification when uncertain\n */\n public async chat3(\n messages: UIMessage[],\n params: {\n chatId: string;\n userId: string;\n },\n ) {\n const [introspection, userTeachables] = await Promise.all([\n this.index({ onProgress: console.log }),\n this.#config.memory\n ? this.#config.memory.toTeachables(params.userId)\n : [],\n ]);\n const chat = await this.#config.history.upsertChat({\n id: params.chatId,\n userId: params.userId,\n title: 'Chat ' + params.chatId,\n });\n\n const renderToolNames = Object.keys(this.#config.tools ?? {}).filter(\n (name) => name.startsWith('render_'),\n );\n const instructions = [\n ...this.#config.instructions,\n ...(renderToolNames.length\n ? [\n hint(`Rendering tools available: ${renderToolNames.join(', ')}.`),\n styleGuide({\n prefer:\n 'Use render_* tools for trend/over time/monthly requests or chart asks',\n always:\n 'Include text insight alongside visualizations. Prefer line charts for time-based data.',\n }),\n ]\n : []),\n ];\n\n const originalMessage = [\n ...chat.messages.map((it) => it.content),\n ...messages,\n ];\n\n const result = stream(\n chat3Agent.clone({\n model: this.#config.model,\n tools: {\n ...chat3Tools,\n ...(this.#config.memory ? memoryTools : {}),\n ...this.#config.tools,\n },\n }),\n originalMessage,\n {\n teachings: toInstructions(\n 'instructions',\n\n ...instructions,\n teachable('user_profile', ...userTeachables),\n ),\n adapter: this.#config.adapter,\n introspection,\n instructions: this.#config.instructions,\n memory: this.#config.memory,\n userId: params.userId,\n },\n );\n\n return this.#createUIMessageStream(\n result,\n messages,\n params,\n originalMessage,\n );\n }\n\n /**\n * Chat4 - Question decomposition approach.\n *\n * Breaks down questions into semantic components before SQL generation:\n * - entities: Key concepts mentioned\n * - filters: Filtering criteria\n * - aggregation: Type of aggregation\n * - breakdown: Semantic parts of the question\n *\n * This helps ensure all aspects of the question are addressed.\n */\n public async chat4(\n messages: UIMessage[],\n params: {\n chatId: string;\n userId: string;\n },\n ) {\n const [introspection, userTeachables] = await Promise.all([\n this.index({ onProgress: console.log }),\n this.#config.memory\n ? this.#config.memory.toTeachables(params.userId)\n : [],\n ]);\n const chat = await this.#config.history.upsertChat({\n id: params.chatId,\n userId: params.userId,\n title: 'Chat ' + params.chatId,\n });\n\n const renderToolNames = Object.keys(this.#config.tools ?? {}).filter(\n (name) => name.startsWith('render_'),\n );\n const instructions = [\n ...this.#config.instructions,\n ...(renderToolNames.length\n ? [\n hint(`Rendering tools available: ${renderToolNames.join(', ')}.`),\n styleGuide({\n prefer:\n 'Use render_* tools for trend/over time/monthly requests or chart asks',\n always:\n 'Include text insight alongside visualizations. Prefer line charts for time-based data.',\n }),\n ]\n : []),\n ];\n\n const originalMessage = [\n ...chat.messages.map((it) => it.content),\n ...messages,\n ];\n\n const result = stream(\n chat4Agent.clone({\n model: this.#config.model,\n tools: {\n ...chat4Tools,\n ...(this.#config.memory ? memoryTools : {}),\n ...this.#config.tools,\n },\n }),\n originalMessage,\n {\n teachings: toInstructions(\n 'instructions',\n ...instructions,\n teachable('user_profile', ...userTeachables),\n ),\n adapter: this.#config.adapter,\n introspection,\n instructions: this.#config.instructions,\n memory: this.#config.memory,\n userId: params.userId,\n },\n );\n\n return this.#createUIMessageStream(\n result,\n messages,\n params,\n originalMessage,\n );\n }\n\n /**\n * Developer-focused conversational interface for SQL generation.\n *\n * Provides power-user tools for query building without execution:\n * - generate_sql: Convert natural language to validated SQL\n * - validate_sql: Check SQL syntax\n * - explain_sql: Get plain-English explanations\n * - show_schema: Explore database schema on demand\n *\n * @example\n * ```typescript\n * const result = await text2sql.developer(\n * [user(\"Generate a query to find top customers by revenue\")],\n * { chatId: 'dev-session-1', userId: 'dev-1' }\n * );\n * // Agent responds with SQL, can validate, explain, or refine iteratively\n * ```\n */\n public async developer(\n messages: UIMessage[],\n params: {\n chatId: string;\n userId: string;\n },\n ) {\n const [introspection, userTeachables] = await Promise.all([\n this.index({ onProgress: console.log }),\n this.#config.memory\n ? this.#config.memory.toTeachables(params.userId)\n : [],\n ]);\n\n return withChat(\n this.#config.history,\n params,\n messages,\n (originalMessages) =>\n stream(\n developerAgent.clone({\n model: this.#config.model,\n }),\n originalMessages,\n {\n teachings: toInstructions(\n 'instructions',\n ...this.#config.instructions,\n teachable('user_profile', ...userTeachables),\n ),\n adapter: this.#config.adapter,\n introspection,\n instructions: this.#config.instructions,\n },\n ),\n );\n }\n\n /**\n * Helper to create UI message stream with common error handling and persistence.\n */\n #createUIMessageStream(\n result: ReturnType<typeof stream>,\n messages: UIMessage[],\n params: { chatId: string; userId: string },\n originalMessages: UIMessage[],\n ) {\n return result.toUIMessageStream({\n onError: (error) => {\n if (NoSuchToolError.isInstance(error)) {\n return 'The model tried to call an unknown tool.';\n } else if (InvalidToolInputError.isInstance(error)) {\n return 'The model called a tool with invalid arguments.';\n } else if (ToolCallRepairError.isInstance(error)) {\n return 'The model tried to call a tool with invalid arguments, but it was repaired.';\n } else if (APICallError.isInstance(error)) {\n console.error('Upstream API call failed:', error);\n return `Upstream API call failed with status ${error.statusCode}: ${error.message}`;\n } else {\n return JSON.stringify(error);\n }\n },\n sendStart: true,\n sendFinish: true,\n sendReasoning: true,\n sendSources: true,\n originalMessages: originalMessages,\n generateMessageId: generateId,\n onFinish: async ({ responseMessage, isContinuation }) => {\n const userMessage = messages.at(-1);\n if (!isContinuation && userMessage) {\n console.log(\n 'Saving user message to history:',\n JSON.stringify(userMessage),\n );\n await this.#config.history.upsertMessage({\n id: userMessage.id,\n chatId: params.chatId,\n role: userMessage.role,\n content: userMessage,\n });\n }\n\n await this.#config.history.upsertMessage({\n id: responseMessage.id,\n chatId: params.chatId,\n role: responseMessage.role,\n content: responseMessage,\n });\n },\n });\n }\n}\n\nexport async function withChat(\n history: History,\n params: { chatId: string; userId: string },\n messages: UIMessage[],\n streamFn: (originalMessages: UIMessage[]) => ReturnType<typeof stream>,\n) {\n const chat = await history.upsertChat({\n id: params.chatId,\n userId: params.userId,\n title: 'Chat ' + params.chatId,\n });\n const originalMessages = [\n ...chat.messages.map((it) => it.content),\n ...messages,\n ];\n const result = streamFn(originalMessages);\n return result.toUIMessageStream({\n onError: (error) => {\n if (NoSuchToolError.isInstance(error)) {\n return 'The model tried to call an unknown tool.';\n } else if (InvalidToolInputError.isInstance(error)) {\n return 'The model called a tool with invalid arguments.';\n } else if (ToolCallRepairError.isInstance(error)) {\n return 'The model tried to call a tool with invalid arguments, but it was repaired.';\n } else if (APICallError.isInstance(error)) {\n console.error('Upstream API call failed:', error);\n return `Upstream API call failed with status ${error.statusCode}: ${error.message}`;\n } else {\n return JSON.stringify(error);\n }\n },\n sendStart: true,\n sendFinish: true,\n sendReasoning: true,\n sendSources: true,\n originalMessages: originalMessages,\n generateMessageId: generateId,\n onFinish: async ({ responseMessage, isContinuation }) => {\n const userMessage = messages.at(-1);\n if (!isContinuation && userMessage) {\n console.log(\n 'Saving user message to history:',\n JSON.stringify(userMessage),\n );\n\n await history.upsertMessage({\n id: userMessage.id,\n chatId: params.chatId,\n role: userMessage.role,\n content: userMessage,\n });\n }\n\n await history.upsertMessage({\n id: responseMessage.id,\n chatId: params.chatId,\n role: responseMessage.role,\n content: responseMessage,\n });\n },\n });\n}\n", "/**\n * Chat1 Agent - Combined Tool, No Peek\n *\n * This variant uses a single `query_database` tool that:\n * 1. Takes a natural language question\n * 2. Internally calls toSql() to generate validated SQL\n * 3. Executes the SQL\n * 4. Returns both the SQL and results\n *\n * The agent does NOT see the SQL before execution - it's generated and executed in one step.\n */\nimport { groq } from '@ai-sdk/groq';\nimport { tool } from 'ai';\nimport z from 'zod';\n\nimport { agent, toState } from '@deepagents/agent';\nimport { scratchpad_tool } from '@deepagents/toolbox';\n\nimport type { Adapter } from '../adapters/adapter.ts';\nimport type { TeachablesStore } from '../memory/store.ts';\nimport type { Teachables } from '../teach/teachables.ts';\nimport { type ToSqlOptions, toSql } from './sql.agent.ts';\n\nexport type Chat1State = {\n /** Database adapter for query execution */\n adapter: Adapter;\n /** Schema introspection XML */\n introspection: string;\n /** Teachings/instructions for SQL generation */\n instructions: Teachables[];\n /** Combined teachings string for the agent prompt */\n teachings: string;\n /** Optional memory store for user teachables */\n memory?: TeachablesStore;\n /** User ID for memory operations */\n userId?: string;\n};\n\n/**\n * Result returned by the query_database tool\n */\nexport interface QueryDatabaseResult {\n success: boolean;\n /** The generated SQL query */\n sql?: string;\n /** Query results as array of rows */\n data?: unknown[];\n /** Error message if generation or execution failed */\n error?: string;\n /** Number of attempts made during SQL generation */\n attempts?: number;\n}\n\nconst tools = {\n query_database: tool({\n description: `Query the database to answer a question. Provide your question in natural language and this tool will:\n1. Generate the appropriate SQL query\n2. Validate the SQL syntax\n3. Execute the query\n4. Return the results\n\nUse this tool when you need to retrieve data to answer the user's question.`,\n inputSchema: z.object({\n question: z\n .string()\n .min(1)\n .describe(\n 'The question to answer, expressed in natural language. Be specific about what data you need.',\n ),\n reasoning: z\n .string()\n .optional()\n .describe(\n 'Your reasoning for why this query is needed to answer the user.',\n ),\n }),\n execute: async ({ question }, options): Promise<QueryDatabaseResult> => {\n const state = toState<Chat1State>(options);\n\n try {\n // Generate SQL using the dedicated toSql function with validation and retry\n const sqlResult = await toSql({\n input: question,\n adapter: state.adapter,\n introspection: state.introspection,\n instructions: state.instructions,\n });\n\n // If SQL generation failed after all retries\n if (!sqlResult.sql) {\n return {\n success: false,\n error: sqlResult.errors?.join('; ') || 'Failed to generate SQL',\n };\n }\n\n // Execute the validated SQL\n const data = await state.adapter.execute(sqlResult.sql);\n\n return {\n success: true,\n sql: sqlResult.sql,\n data,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error ? error.message : 'Unknown error occurred',\n };\n }\n },\n }),\n\n scratchpad: scratchpad_tool,\n};\n\n/**\n * Chat1 Agent - Table Augmented Generation with combined query tool.\n *\n * This agent receives user questions and uses the query_database tool\n * to fetch data. The SQL generation is delegated to the specialized\n * sqlQueryAgent via the toSql() function.\n */\nexport const chat1Agent = agent<never, Chat1State>({\n name: 'chat1-combined',\n model: groq('openai/gpt-oss-20b'),\n tools,\n prompt: (state) => {\n return `\n${state?.teachings || ''}\n${state?.introspection || ''}\n`;\n },\n});\n\nexport { tools as chat1Tools };\n", "/**\n * Chat2 Agent - Separate Generate + Execute Tools (With Peek)\n *\n * This variant uses two separate tools:\n * 1. `generate_sql` - Takes a question, returns validated SQL (agent can inspect it)\n * 2. `execute_sql` - Takes SQL, executes it, returns results\n *\n * The agent sees the SQL before execution and can:\n * - Review the generated SQL\n * - Explain the approach to the user\n * - Decide to refine the question and regenerate\n * - Choose not to execute if something looks wrong\n */\nimport { groq } from '@ai-sdk/groq';\nimport { tool } from 'ai';\nimport z from 'zod';\n\nimport { agent, toState } from '@deepagents/agent';\nimport { scratchpad_tool } from '@deepagents/toolbox';\n\nimport type { Adapter } from '../adapters/adapter.ts';\nimport type { TeachablesStore } from '../memory/store.ts';\nimport type { Teachables } from '../teach/teachables.ts';\nimport { toSql } from './sql.agent.ts';\n\nexport type Chat2State = {\n /** Database adapter for query execution */\n adapter: Adapter;\n /** Schema introspection XML */\n introspection: string;\n /** Teachings/instructions for SQL generation */\n instructions: Teachables[];\n /** Combined teachings string for the agent prompt */\n teachings: string;\n /** Optional memory store for user teachables */\n memory?: TeachablesStore;\n /** User ID for memory operations */\n userId?: string;\n};\n\n/**\n * Result returned by the generate_sql tool\n */\nexport interface GenerateSqlToolResult {\n success: boolean;\n /** The generated and validated SQL query */\n sql?: string;\n /** Error message if generation failed */\n error?: string;\n /** Number of attempts made during SQL generation */\n attempts?: number;\n /** Validation errors encountered during generation */\n validationErrors?: string[];\n}\n\n/**\n * Result returned by the execute_sql tool\n */\nexport interface ExecuteSqlToolResult {\n success: boolean;\n /** Query results as array of rows */\n data?: unknown[];\n /** Error message if execution failed */\n error?: string;\n /** Row count of results */\n rowCount?: number;\n}\n\nconst tools = {\n generate_sql: tool({\n description: `Generate a SQL query from a natural language question. This tool will:\n1. Translate your question into SQL\n2. Validate the SQL syntax\n3. Retry with corrections if validation fails\n4. Return the validated SQL for your review\n\nUse this BEFORE execute_sql to see what query will be run. You can then:\n- Explain the approach to the user\n- Decide if the SQL looks correct\n- Refine your question and regenerate if needed`,\n inputSchema: z.object({\n question: z\n .string()\n .min(1)\n .describe(\n 'The question to translate into SQL. Be specific about what data you need.',\n ),\n reasoning: z\n .string()\n .optional()\n .describe('Your reasoning for why this data is needed.'),\n }),\n execute: async ({ question }, options): Promise<GenerateSqlToolResult> => {\n const state = toState<Chat2State>(options);\n\n try {\n const sqlResult = await toSql({\n input: question,\n adapter: state.adapter,\n introspection: state.introspection,\n instructions: state.instructions,\n });\n\n if (!sqlResult.sql) {\n return {\n success: false,\n error: sqlResult.errors?.join('; ') || 'Failed to generate SQL',\n validationErrors: sqlResult.errors,\n };\n }\n\n return {\n success: true,\n sql: sqlResult.sql,\n validationErrors: sqlResult.errors,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error ? error.message : 'Unknown error occurred',\n };\n }\n },\n }),\n\n execute_sql: tool({\n description: `Execute a SQL query and return the results. Use this AFTER generate_sql to run the query.\n\nOnly SELECT and WITH (CTE) queries are allowed - no data modification.`,\n inputSchema: z.object({\n sql: z\n .string()\n .min(1)\n .refine(\n (sql) =>\n sql.trim().toUpperCase().startsWith('SELECT') ||\n sql.trim().toUpperCase().startsWith('WITH'),\n {\n message: 'Only read-only SELECT or WITH queries are allowed.',\n },\n )\n .describe('The SQL query to execute (must be SELECT or WITH).'),\n reasoning: z\n .string()\n .optional()\n .describe('Brief explanation of what this query retrieves.'),\n }),\n execute: async ({ sql }, options): Promise<ExecuteSqlToolResult> => {\n const state = toState<Chat2State>(options);\n\n try {\n const data = await state.adapter.execute(sql);\n\n return {\n success: true,\n data,\n rowCount: Array.isArray(data) ? data.length : undefined,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error ? error.message : 'Query execution failed',\n };\n }\n },\n }),\n\n scratchpad: scratchpad_tool,\n};\n\n/**\n * Chat2 Agent - Table Augmented Generation with peek support.\n *\n * This agent uses separate generate_sql and execute_sql tools,\n * allowing it to review the SQL before execution. This enables:\n * - Transparency: Agent knows what SQL will be run\n * - Control: Agent can refine before executing\n * - Explanation: Agent can describe its approach to the user\n */\nexport const chat2Agent = agent<never, Chat2State>({\n name: 'chat2-with-peek',\n model: groq('openai/gpt-oss-20b'),\n tools,\n prompt: (state) => {\n return `\n${state?.teachings || ''}\n${state?.introspection || ''}\n\nWhen answering questions that require database queries:\n1. First use generate_sql to create the SQL query\n2. Review the generated SQL to ensure it matches the user's intent\n3. Use execute_sql to run the query\n4. Present the results to the user\n\nIf the generated SQL doesn't look right, you can refine your question and regenerate.\n`;\n },\n});\n\nexport { tools as chat2Tools };\n", "/**\n * Chat3 Agent - Agent Conversation/Collaboration\n *\n * This variant enables richer interaction between the conversation agent\n * and the SQL generation agent. The SQL agent can:\n * 1. Surface its confidence level\n * 2. State assumptions it's making\n * 3. Request clarification when uncertain\n *\n * The conversation agent can then:\n * - Answer clarifications from its context\n * - Ask the user for clarification\n * - Accept or refine the SQL agent's approach\n */\nimport { groq } from '@ai-sdk/groq';\nimport { defaultSettingsMiddleware, tool, wrapLanguageModel } from 'ai';\nimport z from 'zod';\n\nimport { agent, generate, toState, user } from '@deepagents/agent';\nimport { scratchpad_tool } from '@deepagents/toolbox';\n\nimport type { Adapter } from '../adapters/adapter.ts';\nimport type { TeachablesStore } from '../memory/store.ts';\nimport {\n type Teachables,\n persona,\n toInstructions,\n} from '../teach/teachables.ts';\n\nexport type Chat3State = {\n /** Database adapter for query execution */\n adapter: Adapter;\n /** Schema introspection XML */\n introspection: string;\n /** Teachings/instructions for SQL generation */\n instructions: Teachables[];\n /** Combined teachings string for the agent prompt */\n teachings: string;\n /** Optional memory store for user teachables */\n memory?: TeachablesStore;\n /** User ID for memory operations */\n userId?: string;\n};\n\n/**\n * Output schema for the collaborative SQL agent\n */\nconst collaborativeSqlOutputSchema = z.discriminatedUnion('status', [\n z.object({\n status: z.literal('success'),\n sql: z.string().describe('The generated SQL query'),\n confidence: z\n .enum(['high', 'medium', 'low'])\n .describe('Confidence level in this SQL being correct'),\n assumptions: z\n .array(z.string())\n .optional()\n .describe('Assumptions made during SQL generation'),\n reasoning: z\n .string()\n .optional()\n .describe('Brief explanation of the query approach'),\n }),\n z.object({\n status: z.literal('clarification_needed'),\n question: z.string().describe('Question to clarify the request'),\n context: z.string().optional().describe('Why this clarification is needed'),\n options: z\n .array(z.string())\n .optional()\n .describe('Possible options if applicable'),\n }),\n z.object({\n status: z.literal('unanswerable'),\n reason: z.string().describe('Why this question cannot be answered'),\n suggestions: z\n .array(z.string())\n .optional()\n .describe('Alternative questions that could be answered'),\n }),\n]);\n\ntype CollaborativeSqlOutput = z.infer<typeof collaborativeSqlOutputSchema>;\n\n/**\n * Internal agent for collaborative SQL generation.\n * This agent can ask for clarification instead of guessing.\n */\nconst collaborativeSqlAgent = agent<CollaborativeSqlOutput, Chat3State>({\n name: 'collaborative-sql',\n model: groq('openai/gpt-oss-20b'),\n output: collaborativeSqlOutputSchema,\n prompt: (state) => {\n return `\n${toInstructions(\n 'instructions',\n persona({\n name: 'SQLCollab',\n role: 'You are an expert SQL query generator that collaborates with the user to ensure accuracy.',\n }),\n ...(state?.instructions || []),\n)}\n${state?.introspection || ''}\n\nIMPORTANT: You have three response options:\n\n1. SUCCESS - When you can confidently generate SQL:\n - Provide the SQL query\n - Rate your confidence (high/medium/low)\n - List any assumptions you made\n\n2. CLARIFICATION_NEEDED - When the question is ambiguous:\n - Ask a specific clarifying question\n - Explain why clarification is needed\n - Provide options if applicable\n\n3. UNANSWERABLE - When the question cannot be answered with available data:\n - Explain why\n - Suggest alternative questions that could be answered\n\nPrefer asking for clarification over making low-confidence guesses.\n`;\n },\n});\n\n/**\n * Result from the collaborative query tool\n */\nexport interface CollaborativeQueryResult {\n /** Whether a final SQL was produced */\n success: boolean;\n /** The generated SQL (if success) */\n sql?: string;\n /** Query results (if executed) */\n data?: unknown[];\n /** Confidence level of the SQL */\n confidence?: 'high' | 'medium' | 'low';\n /** Assumptions made during generation */\n assumptions?: string[];\n /** Clarification question (if needed) */\n clarificationNeeded?: string;\n /** Context for clarification */\n clarificationContext?: string;\n /** Options for clarification */\n clarificationOptions?: string[];\n /** Reason if unanswerable */\n unanswerableReason?: string;\n /** Suggested alternatives if unanswerable */\n suggestions?: string[];\n /** Error message if something failed */\n error?: string;\n}\n\nconst tools = {\n consult_sql_agent: tool({\n description: `Consult the SQL specialist agent to generate a query. The SQL agent may:\n- Return a SQL query with confidence level and assumptions\n- Ask for clarification if the question is ambiguous\n- Indicate if the question cannot be answered with available data\n\nBased on the response:\n- If clarification is needed, you can provide context or ask the user\n- If assumptions were made, verify them with the user for important queries\n- If unanswerable, relay the suggestions to the user`,\n inputSchema: z.object({\n question: z\n .string()\n .min(1)\n .describe('The question to translate into SQL.'),\n context: z\n .string()\n .optional()\n .describe('Additional context from the conversation that might help.'),\n previousClarification: z\n .string()\n .optional()\n .describe(\n 'Answer to a previous clarification question from the SQL agent.',\n ),\n }),\n execute: async (\n { question, context, previousClarification },\n options,\n ): Promise<CollaborativeQueryResult> => {\n const state = toState<Chat3State>(options);\n\n try {\n // Build the message for the SQL agent\n let fullQuestion = question;\n if (context) {\n fullQuestion = `${question}\\n\\nAdditional context: ${context}`;\n }\n if (previousClarification) {\n fullQuestion = `${fullQuestion}\\n\\nClarification provided: ${previousClarification}`;\n }\n\n const agentInstance = collaborativeSqlAgent.clone({\n model: wrapLanguageModel({\n model: collaborativeSqlAgent.model,\n middleware: defaultSettingsMiddleware({\n settings: { temperature: 0.1 },\n }),\n }),\n });\n\n const { experimental_output: output } = await generate(\n agentInstance,\n [user(fullQuestion)],\n state,\n );\n\n // Handle the three response types\n if (output.status === 'success') {\n // Validate the SQL\n const validationError = await state.adapter.validate(output.sql);\n if (validationError) {\n return {\n success: false,\n error: `SQL validation failed: ${validationError}`,\n };\n }\n\n // Execute the SQL\n const data = await state.adapter.execute(output.sql);\n\n return {\n success: true,\n sql: output.sql,\n data,\n confidence: output.confidence,\n assumptions: output.assumptions,\n };\n }\n\n if (output.status === 'clarification_needed') {\n return {\n success: false,\n clarificationNeeded: output.question,\n clarificationContext: output.context,\n clarificationOptions: output.options,\n };\n }\n\n if (output.status === 'unanswerable') {\n return {\n success: false,\n unanswerableReason: output.reason,\n suggestions: output.suggestions,\n };\n }\n\n return {\n success: false,\n error: 'Unexpected response from SQL agent',\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error ? error.message : 'Unknown error occurred',\n };\n }\n },\n }),\n\n execute_sql: tool({\n description: `Execute a SQL query directly. Use this when you have SQL that you want to run\n(e.g., after receiving SQL from consult_sql_agent or for follow-up queries).`,\n inputSchema: z.object({\n sql: z\n .string()\n .min(1)\n .refine(\n (sql) =>\n sql.trim().toUpperCase().startsWith('SELECT') ||\n sql.trim().toUpperCase().startsWith('WITH'),\n {\n message: 'Only read-only SELECT or WITH queries are allowed.',\n },\n )\n .describe('The SQL query to execute.'),\n }),\n execute: async ({ sql }, options) => {\n const state = toState<Chat3State>(options);\n\n try {\n // Validate first\n const validationError = await state.adapter.validate(sql);\n if (validationError) {\n return {\n success: false,\n error: `Validation failed: ${validationError}`,\n };\n }\n\n const data = await state.adapter.execute(sql);\n return {\n success: true,\n data,\n rowCount: Array.isArray(data) ? data.length : undefined,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Execution failed',\n };\n }\n },\n }),\n\n scratchpad: scratchpad_tool,\n};\n\n/**\n * Chat3 Agent - Table Augmented Generation with agent collaboration.\n *\n * This agent collaborates with a specialized SQL agent that can:\n * - Express confidence levels\n * - Surface assumptions\n * - Request clarification\n *\n * This enables higher quality SQL generation through dialogue.\n */\nexport const chat3Agent = agent<never, Chat3State>({\n name: 'chat3-collaborative',\n model: groq('openai/gpt-oss-20b'),\n tools,\n prompt: (state) => {\n return `\n${state?.teachings || ''}\n${state?.introspection || ''}\n\nWhen answering questions that require database queries, use the consult_sql_agent tool.\n\nThe SQL agent may respond in three ways:\n1. SUCCESS with SQL, confidence, and assumptions - review the confidence and assumptions\n2. CLARIFICATION_NEEDED with a question - either answer from context or ask the user\n3. UNANSWERABLE with reason and suggestions - relay this to the user helpfully\n\nFor medium/low confidence results, consider mentioning the assumptions to the user.\nFor clarification requests, try to answer from conversation context first before asking the user.\n`;\n },\n});\n\nexport { tools as chat3Tools };\n", "/**\n * Chat4 Agent - Question Decomposition Approach\n *\n * This variant breaks down the user's question into semantic components\n * before passing it to the SQL agent. Instead of:\n * \"Which customers bought the most expensive products last quarter?\"\n *\n * It passes a decomposition:\n * - entities: customers, products, purchases\n * - filters: expensive products, last quarter\n * - aggregation: most (count? value?)\n * - output: list of customers\n *\n * This helps the SQL agent understand the different aspects of the question\n * without being told HOW to implement it.\n */\nimport { groq } from '@ai-sdk/groq';\nimport { defaultSettingsMiddleware, tool, wrapLanguageModel } from 'ai';\nimport z from 'zod';\n\nimport { agent, generate, toState, user } from '@deepagents/agent';\nimport { scratchpad_tool } from '@deepagents/toolbox';\n\nimport type { Adapter } from '../adapters/adapter.ts';\nimport type { TeachablesStore } from '../memory/store.ts';\nimport {\n type Teachables,\n persona,\n toInstructions,\n} from '../teach/teachables.ts';\n\nexport type Chat4State = {\n /** Database adapter for query execution */\n adapter: Adapter;\n /** Schema introspection XML */\n introspection: string;\n /** Teachings/instructions for SQL generation */\n instructions: Teachables[];\n /** Combined teachings string for the agent prompt */\n teachings: string;\n /** Optional memory store for user teachables */\n memory?: TeachablesStore;\n /** User ID for memory operations */\n userId?: string;\n};\n\n/**\n * Schema for question decomposition\n */\nconst questionDecompositionSchema = z.object({\n originalQuestion: z\n .string()\n .describe('The original question being decomposed'),\n breakdown: z\n .array(z.string())\n .min(1)\n .describe(\n 'Semantic breakdown of the question into its component parts. Each part describes an aspect of what is being asked, NOT how to implement it.',\n ),\n entities: z\n .array(z.string())\n .optional()\n .describe(\n 'Key entities/concepts mentioned (e.g., customers, orders, products)',\n ),\n filters: z\n .array(z.string())\n .optional()\n .describe(\n 'Filtering criteria mentioned (e.g., \"last quarter\", \"above $100\")',\n ),\n aggregation: z\n .string()\n .optional()\n .describe(\n 'Type of aggregation if any (e.g., \"count\", \"sum\", \"average\", \"top N\")',\n ),\n ambiguities: z\n .array(z.string())\n .optional()\n .describe('Any ambiguous parts that might need clarification'),\n});\n\ntype QuestionDecomposition = z.infer<typeof questionDecompositionSchema>;\n\n/**\n * Output schema for the decomposition-aware SQL agent\n */\nconst decompositionSqlOutputSchema = z.union([\n z.object({\n sql: z\n .string()\n .describe('The SQL query that answers the decomposed question'),\n reasoning: z\n .string()\n .optional()\n .describe('How each breakdown component was addressed'),\n }),\n z.object({\n error: z\n .string()\n .describe('Error message if the question cannot be answered'),\n }),\n]);\n\ntype DecompositionSqlOutput = z.infer<typeof decompositionSqlOutputSchema>;\n\n/**\n * Internal agent for SQL generation from decomposed questions\n */\nconst decompositionSqlAgent = agent<DecompositionSqlOutput, Chat4State>({\n name: 'decomposition-sql',\n model: groq('openai/gpt-oss-20b'),\n output: decompositionSqlOutputSchema,\n prompt: (state) => {\n return `\n${toInstructions(\n 'instructions',\n persona({\n name: 'SQLDecomp',\n role: 'You are an expert SQL query generator. You receive questions broken down into semantic components and generate precise SQL.',\n }),\n ...(state?.instructions || []),\n)}\n${state?.introspection || ''}\n\nYou will receive questions in a decomposed format with:\n- breakdown: Semantic parts of the question\n- entities: Key concepts mentioned\n- filters: Filtering criteria\n- aggregation: Type of aggregation needed\n- ambiguities: Potentially unclear parts\n\nAddress each component of the breakdown in your SQL.\nIf there are ambiguities, make reasonable assumptions and note them in your reasoning.\n`;\n },\n});\n\n/**\n * Result from the decomposed query tool\n */\nexport interface DecomposedQueryResult {\n success: boolean;\n /** The original question */\n question?: string;\n /** How the question was decomposed */\n decomposition?: QuestionDecomposition;\n /** The generated SQL */\n sql?: string;\n /** Query results */\n data?: unknown[];\n /** How breakdown components were addressed */\n reasoning?: string;\n /** Error message if failed */\n error?: string;\n /** Number of generation attempts */\n attempts?: number;\n}\n\n/** Temperature progression for retries */\nconst RETRY_TEMPERATURES = [0, 0.2, 0.3];\n\nconst tools = {\n query_with_decomposition: tool({\n description: `Query the database using question decomposition. This tool:\n1. Breaks down your question into semantic components (entities, filters, aggregations)\n2. Passes the decomposition to the SQL specialist\n3. Generates and validates SQL\n4. Executes and returns results\n\nThis approach helps ensure all aspects of the question are addressed in the query.`,\n inputSchema: z.object({\n question: z.string().min(1).describe('The question to answer.'),\n breakdown: z\n .array(z.string())\n .min(1)\n .describe(\n 'Break down the question into its semantic parts. Each part should describe an ASPECT of what is being asked, not instructions. Example for \"top customers by revenue last month\": [\"customers who made purchases\", \"revenue from those purchases\", \"time period: last month\", \"ranking: top by total revenue\"]',\n ),\n entities: z\n .array(z.string())\n .optional()\n .describe(\n 'Key entities mentioned (e.g., [\"customers\", \"orders\", \"products\"])',\n ),\n filters: z\n .array(z.string())\n .optional()\n .describe('Filter criteria (e.g., [\"last month\", \"status = active\"])'),\n aggregation: z\n .string()\n .optional()\n .describe(\n 'Aggregation type if any (e.g., \"sum revenue\", \"count orders\", \"top 10\")',\n ),\n ambiguities: z\n .array(z.string())\n .optional()\n .describe('Note any ambiguous parts you identified'),\n }),\n execute: async (\n { question, breakdown, entities, filters, aggregation, ambiguities },\n options,\n ): Promise<DecomposedQueryResult> => {\n const state = toState<Chat4State>(options);\n\n const decomposition: QuestionDecomposition = {\n originalQuestion: question,\n breakdown,\n entities,\n filters,\n aggregation,\n ambiguities,\n };\n\n // Format the decomposition for the SQL agent\n const decomposedPrompt = formatDecomposition(decomposition);\n\n try {\n // Try SQL generation with retry logic\n let lastError: string | undefined;\n\n for (let attempt = 0; attempt < RETRY_TEMPERATURES.length; attempt++) {\n const temperature = RETRY_TEMPERATURES[attempt];\n\n const agentInstance = decompositionSqlAgent.clone({\n model: wrapLanguageModel({\n model: decompositionSqlAgent.model,\n middleware: defaultSettingsMiddleware({\n settings: { temperature },\n }),\n }),\n });\n\n const prompt = lastError\n ? `${decomposedPrompt}\\n\\nPrevious attempt failed with: ${lastError}. Please fix the query.`\n : decomposedPrompt;\n\n const { experimental_output: output } = await generate(\n agentInstance,\n [user(prompt)],\n state,\n );\n\n if ('error' in output) {\n return {\n success: false,\n question,\n decomposition,\n error: output.error,\n attempts: attempt + 1,\n };\n }\n\n // Validate the SQL\n const validationError = await state.adapter.validate(output.sql);\n if (validationError) {\n lastError = validationError;\n continue;\n }\n\n // Execute the SQL\n const data = await state.adapter.execute(output.sql);\n\n return {\n success: true,\n question,\n decomposition,\n sql: output.sql,\n data,\n reasoning: output.reasoning,\n attempts: attempt + 1,\n };\n }\n\n // All retries exhausted\n return {\n success: false,\n question,\n decomposition,\n error: `Failed after ${RETRY_TEMPERATURES.length} attempts. Last error: ${lastError}`,\n attempts: RETRY_TEMPERATURES.length,\n };\n } catch (error) {\n return {\n success: false,\n question,\n decomposition,\n error:\n error instanceof Error ? error.message : 'Unknown error occurred',\n };\n }\n },\n }),\n\n execute_sql: tool({\n description: `Execute a SQL query directly. Use for follow-up queries or when you already have SQL.`,\n inputSchema: z.object({\n sql: z\n .string()\n .min(1)\n .refine(\n (sql) =>\n sql.trim().toUpperCase().startsWith('SELECT') ||\n sql.trim().toUpperCase().startsWith('WITH'),\n {\n message: 'Only read-only SELECT or WITH queries are allowed.',\n },\n )\n .describe('The SQL query to execute.'),\n }),\n execute: async ({ sql }, options) => {\n const state = toState<Chat4State>(options);\n\n try {\n const validationError = await state.adapter.validate(sql);\n if (validationError) {\n return {\n success: false,\n error: `Validation failed: ${validationError}`,\n };\n }\n\n const data = await state.adapter.execute(sql);\n return {\n success: true,\n data,\n rowCount: Array.isArray(data) ? data.length : undefined,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Execution failed',\n };\n }\n },\n }),\n\n scratchpad: scratchpad_tool,\n};\n\n/**\n * Format a question decomposition into a prompt for the SQL agent\n */\nfunction formatDecomposition(decomposition: QuestionDecomposition): string {\n const parts: string[] = [\n `Original Question: ${decomposition.originalQuestion}`,\n '',\n 'Question Breakdown:',\n ...decomposition.breakdown.map((part, i) => ` ${i + 1}. ${part}`),\n ];\n\n if (decomposition.entities?.length) {\n parts.push('', `Entities: ${decomposition.entities.join(', ')}`);\n }\n\n if (decomposition.filters?.length) {\n parts.push('', `Filters: ${decomposition.filters.join(', ')}`);\n }\n\n if (decomposition.aggregation) {\n parts.push('', `Aggregation: ${decomposition.aggregation}`);\n }\n\n if (decomposition.ambiguities?.length) {\n parts.push(\n '',\n 'Potential Ambiguities:',\n ...decomposition.ambiguities.map((a) => ` - ${a}`),\n );\n }\n\n parts.push(\n '',\n 'Generate SQL that addresses each component of the breakdown.',\n );\n\n return parts.join('\\n');\n}\n\n/**\n * Chat4 Agent - Table Augmented Generation with question decomposition.\n *\n * This agent breaks down questions into semantic components before\n * generating SQL. This approach:\n * - Ensures all aspects of the question are addressed\n * - Makes the reasoning explicit\n * - Helps with complex multi-part questions\n */\nexport const chat4Agent = agent<never, Chat4State>({\n name: 'chat4-decomposition',\n model: groq('openai/gpt-oss-20b'),\n tools,\n prompt: (state) => {\n return `\n${state?.teachings || ''}\n${state?.introspection || ''}\n\nWhen answering questions that require database queries, use the query_with_decomposition tool.\n\nIMPORTANT: You must break down the question into semantic parts - describe WHAT is being asked, not HOW to implement it.\n\nGood breakdown example for \"Which customers bought the most expensive products last quarter?\":\n- \"customers who made purchases\" (entity relationship)\n- \"products they purchased\" (what products)\n- \"expensive products - need definition\" (filter criteria - note ambiguity)\n- \"last quarter\" (time filter)\n- \"most - ranking by count or value?\" (aggregation - note ambiguity)\n\nBad breakdown (too instructional):\n- \"JOIN customers with orders\" (this is HOW, not WHAT)\n- \"Use ORDER BY and LIMIT\" (this is implementation)\n\nBreak the question into its semantic aspects, and let the SQL specialist figure out the implementation.\n`;\n },\n});\n\nexport { tools as chat4Tools };\n", "import {\n type Teachables,\n clarification,\n guardrail,\n hint,\n styleGuide,\n workflow,\n} from './teachables.ts';\n\nexport interface TeachingsOptions {\n /**\n * Controls date/time clarification behavior:\n * - 'strict': Ask for clarification when date range is missing (production default)\n * - false: Skip date clarifications, assume all matching data (useful for evals/benchmarks)\n */\n date?: 'strict' | false;\n}\n\nexport function guidelines(options: TeachingsOptions = {}): Teachables[] {\n const { date = 'strict' } = options;\n\n const baseTeachings: Teachables[] = [\n // Schema adherence\n hint(\n 'Use only tables and columns that exist in the schema. Never reference non-existent entities.',\n ),\n hint(\n 'If the user asks to show a table or entity without specifying columns, use SELECT *.',\n ),\n hint(\n 'When showing items associated with another entity, include the item ID and the related details requested.',\n ),\n hint(\n 'When asked to \"show\" items, list them unless the user explicitly asks to count or total.',\n ),\n hint(\n 'Use canonical/LowCardinality values verbatim for filtering; [rows/size] hints suggest when to aggregate instead of listing.',\n ),\n\n // Joins and relationships\n hint(\n 'Use appropriate JOINs based on the relationships defined in the schema.',\n ),\n hint(\n 'Favor PK/indexed columns for joins and filters; follow relationship metadata for join direction and cardinality.',\n ),\n\n // Aggregations and calculations\n hint(\n 'Apply proper aggregations (COUNT, SUM, AVG, etc.) when the question implies summarization.',\n ),\n hint(\n 'When asked \"how many X are there\" about types/categories/statuses (e.g., \"how many statuses are there?\"), use COUNT(DISTINCT column). This asks about variety, not row count.',\n ),\n hint(\n 'Use window functions when the question requires ranking, running totals, or comparisons across rows.',\n ),\n\n // Query semantics\n hint(\n 'Words like \"reach\", \"reached\", \"hit\" with a value (e.g., \"temperature reach 80\") mean >= (greater than or equal), not = (exact match).',\n ),\n hint(\n 'For \"shared by\" two groups or mutually exclusive conditions (e.g., population > 1500 AND < 500), use INTERSECT between separate queries. A single WHERE with contradictory AND returns nothing.',\n ),\n hint(\n 'When filtering by a specific value from a joined table (e.g., \"students who registered course statistics\"), always include that WHERE condition. Do not omit mentioned filters.',\n ),\n hint(\n 'Handle NULL values appropriately using IS NULL, IS NOT NULL, or COALESCE.',\n ),\n\n // Style and readability\n styleGuide({\n prefer:\n 'For table aliases, use the full table name (e.g., \"FROM users AS users\", \"JOIN order_items AS order_items\"). For column aliases, use descriptive names that reflect the data (e.g., \"COUNT(*) AS total_orders\").',\n never:\n 'Use abbreviated table aliases (u, oi, ca) or generic positional aliases (t1, t2, a, b).',\n }),\n styleGuide({\n prefer:\n 'Summaries should be concise, business-friendly, highlight key comparisons, and add a short helpful follow-up when useful.',\n }),\n\n // Guardrails - Query safety\n guardrail({\n rule: 'Generate ONLY valid, executable SQL.',\n reason: 'Invalid SQL wastes resources and confuses users.',\n action: 'Validate syntax and schema references before returning.',\n }),\n guardrail({\n rule: 'Only generate SELECT/WITH statements (read-only queries).',\n reason: 'Prevents accidental data modification.',\n action:\n 'Never generate INSERT, UPDATE, DELETE, DROP, or other DDL/DML statements.',\n }),\n guardrail({\n rule: 'Avoid unbounded scans on large tables.',\n reason: 'Protects performance and prevents runaway queries.',\n action:\n 'Ensure filters are applied on indexed columns before querying broad fact tables.',\n }),\n guardrail({\n rule: 'Do not add LIMIT unless explicitly requested.',\n action:\n 'Only add LIMIT when user explicitly asks for \"top N\", \"first N\", or similar. Do NOT add LIMIT for \"list all\", \"show all\", or simple \"list\" queries.',\n reason: 'Adding arbitrary limits changes query semantics.',\n }),\n guardrail({\n rule: 'Add ORDER BY where appropriate for deterministic results.',\n reason: 'Ensures consistent query output.',\n action:\n 'Include ORDER BY when results have a natural ordering or when combined with LIMIT.',\n }),\n guardrail({\n rule: 'Prevent cartesian or guesswork joins.',\n reason: 'Protect correctness and performance.',\n action:\n 'If join keys are missing or unclear, inspect relationships and ask for the intended join path before executing.',\n }),\n guardrail({\n rule: 'Ensure the query is optimized for the schema.',\n reason: 'Better performance and resource usage.',\n action:\n 'Use indexed columns for filtering, avoid SELECT * on large joins, prefer specific column selection when appropriate.',\n }),\n guardrail({\n rule: 'When facing genuine ambiguity with multiple valid interpretations, seek clarification.',\n reason: 'Prevents incorrect assumptions in edge cases.',\n action:\n 'Ask a focused clarifying question before proceeding with a guess.',\n }),\n\n // Clarifications\n clarification({\n when: 'The request uses ambiguous scoring or ranking language (e.g., \"top\", \"best\", \"active\") without a metric.',\n ask: 'Clarify the ranking metric or definition before writing the query.',\n reason: 'Ensures the correct aggregation/ordering is used.',\n }),\n\n // Workflow\n workflow({\n task: 'SQL generation plan',\n steps: [\n 'Scan column names for terms matching the question. If a phrase like \"total X\" or \"number of Y\" matches a column name (e.g., Total_X, Num_Y), select that column directly instead of aggregating.',\n 'Translate the question into SQL patterns (aggregation, segmentation, time range, ranking) only if no column name match.',\n 'Choose tables/relations that satisfy those patterns; note lookup tables and filter values implied by schema hints.',\n 'Sketch join/filter/aggregation order considering table sizes, indexes, and stats.',\n 'Generate precise, validated SQL that answers the question.',\n ],\n }),\n ];\n\n // Date-specific clarifications (only when strict)\n if (date === 'strict') {\n baseTeachings.push(\n clarification({\n when: 'The request targets time-based data without a date range.',\n ask: 'Confirm the intended timeframe (e.g., last 30/90 days, YTD, specific year).',\n reason: 'Prevents large scans and irrelevant results.',\n }),\n );\n } else {\n // When date is false, assume all matching data without asking\n baseTeachings.push(\n hint(\n 'When a month, day, or time period is mentioned without a year (e.g., \"in August\", \"on Monday\"), assume ALL occurrences of that period in the data. Do not ask for year clarification.',\n ),\n );\n }\n\n return baseTeachings;\n}\n"],
5
- "mappings": "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",
6
- "names": ["groq", "dedent", "z", "agent", "generate", "groq", "z", "agent", "term", "clarification", "teachable", "tag", "agent", "groq", "z", "context", "dedent", "z", "generate", "agent", "groq", "groq", "dedent", "z", "agent", "agent", "groq", "z", "dedent", "groq", "tool", "z", "agent", "toState", "scratchpad_tool", "tools", "tool", "z", "toState", "scratchpad_tool", "agent", "groq", "path", "process", "createHash", "existsSync", "hash", "path", "DatabaseSync", "path", "DatabaseSync", "APICallError", "generate", "user", "groq", "tool", "z", "agent", "toState", "scratchpad_tool", "tools", "tool", "z", "toState", "scratchpad_tool", "agent", "groq", "groq", "tool", "z", "agent", "toState", "scratchpad_tool", "tools", "tool", "z", "toState", "scratchpad_tool", "agent", "groq", "groq", "defaultSettingsMiddleware", "tool", "wrapLanguageModel", "z", "agent", "generate", "toState", "user", "scratchpad_tool", "z", "agent", "groq", "tools", "tool", "context", "toState", "wrapLanguageModel", "defaultSettingsMiddleware", "generate", "user", "scratchpad_tool", "groq", "defaultSettingsMiddleware", "tool", "wrapLanguageModel", "z", "agent", "generate", "toState", "user", "scratchpad_tool", "z", "agent", "groq", "RETRY_TEMPERATURES", "tools", "tool", "toState", "wrapLanguageModel", "defaultSettingsMiddleware", "generate", "user", "scratchpad_tool", "generate", "user", "agent", "tools", "APICallError"]
3
+ "sources": ["../src/lib/fragments/schema.ts", "../src/lib/adapters/groundings/context.ts", "../src/lib/adapters/adapter.ts", "../src/lib/agents/developer.agent.ts", "../../context/src/lib/estimate.ts", "../../context/src/lib/fragments.ts", "../../context/src/lib/renderers/abstract.renderer.ts", "../../context/src/lib/store/store.ts", "../../context/src/lib/engine.ts", "../../context/src/lib/fragments/domain.ts", "../../context/src/lib/fragments/user.ts", "../../context/src/lib/guardrail.ts", "../../context/src/lib/sandbox/binary-bridges.ts", "../../context/src/lib/sandbox/docker-sandbox.ts", "../../context/src/lib/sandbox/container-tool.ts", "../../context/src/lib/skills/loader.ts", "../../context/src/lib/skills/fragments.ts", "../../context/src/lib/store/sqlite.store.ts", "../../context/src/lib/store/memory.store.ts", "../../context/src/lib/visualize.ts", "../../context/src/lib/agent.ts", "../src/lib/agents/explainer.agent.ts", "../src/lib/agents/suggestions.agents.ts", "../src/lib/agents/text2sql.agent.ts", "../src/lib/checkpoint.ts", "../src/lib/file-cache.ts", "../src/lib/sql.ts", "../src/lib/agents/sql.agent.ts", "../src/lib/teach/teachings.ts"],
4
+ "sourcesContent": ["import type { ContextFragment } from '@deepagents/context';\n\n/**\n * Schema fragment builders.\n *\n * These fragments represent database schema metadata that can be injected\n * into AI prompts. Use with renderers (XML, Markdown, TOML, TOON) to format.\n *\n * @example\n * ```ts\n * import { dialectInfo, table, column, relationship } from '@deepagents/text2sql';\n *\n * const schemaFragments = [\n * dialectInfo({ dialect: 'PostgreSQL', version: '14.5' }),\n * table({\n * name: 'users',\n * columns: [\n * column({ name: 'id', type: 'integer', pk: true }),\n * column({ name: 'email', type: 'varchar', unique: true }),\n * ],\n * }),\n * ];\n * ```\n */\n\n/**\n * Database dialect and version information.\n *\n * @param input.dialect - Database type (PostgreSQL, SQLite, SQL Server, etc.)\n * @param input.version - Database version string\n * @param input.database - Database name\n *\n * @example\n * dialectInfo({ dialect: 'PostgreSQL', version: '14.5', database: 'myapp' })\n */\nexport function dialectInfo(input: {\n dialect: string;\n version?: string;\n database?: string;\n}): ContextFragment {\n return {\n name: 'dialectInfo',\n data: {\n dialect: input.dialect,\n ...(input.version && { version: input.version }),\n ...(input.database && { database: input.database }),\n },\n };\n}\n\n/**\n * Database table with columns and optional metadata.\n *\n * @param input.name - Table name\n * @param input.schema - Schema name (e.g., 'public' for PostgreSQL)\n * @param input.rowCount - Approximate row count\n * @param input.sizeHint - Size category for query optimization hints\n * @param input.columns - Array of column() fragments\n * @param input.indexes - Array of index() fragments\n * @param input.constraints - Array of constraint() fragments\n *\n * @example\n * table({\n * name: 'users',\n * rowCount: 1500,\n * sizeHint: 'medium',\n * columns: [\n * column({ name: 'id', type: 'integer', pk: true }),\n * column({ name: 'email', type: 'varchar', unique: true, indexed: true }),\n * ],\n * indexes: [\n * index({ name: 'idx_email', columns: ['email'], unique: true }),\n * ],\n * })\n */\nexport function table(input: {\n name: string;\n schema?: string;\n rowCount?: number;\n sizeHint?: 'tiny' | 'small' | 'medium' | 'large' | 'huge';\n columns: ContextFragment[];\n indexes?: ContextFragment[];\n constraints?: ContextFragment[];\n}): ContextFragment {\n return {\n name: 'table',\n data: {\n name: input.name,\n ...(input.schema && { schema: input.schema }),\n ...(input.rowCount != null && { rowCount: input.rowCount }),\n ...(input.sizeHint && { sizeHint: input.sizeHint }),\n columns: input.columns,\n ...(input.indexes?.length && { indexes: input.indexes }),\n ...(input.constraints?.length && { constraints: input.constraints }),\n },\n };\n}\n\n/**\n * Table column with type and annotations.\n *\n * @param input.name - Column name\n * @param input.type - Column data type (e.g., 'integer', 'varchar(255)')\n * @param input.pk - Is primary key\n * @param input.fk - Foreign key reference in \"table.column\" format\n * @param input.unique - Has unique constraint\n * @param input.notNull - Has NOT NULL constraint\n * @param input.default - Default value expression\n * @param input.indexed - Has index on this column\n * @param input.values - Enum or low cardinality values\n * @param input.stats - Column statistics (min, max, null fraction)\n *\n * @example\n * column({\n * name: 'status',\n * type: 'varchar',\n * notNull: true,\n * indexed: true,\n * values: ['active', 'inactive', 'suspended'],\n * })\n */\nexport function column(input: {\n name: string;\n type: string;\n pk?: boolean;\n fk?: string;\n unique?: boolean;\n notNull?: boolean;\n default?: string;\n indexed?: boolean;\n values?: string[];\n stats?: {\n min?: string;\n max?: string;\n nullFraction?: number;\n };\n}): ContextFragment {\n return {\n name: 'column',\n data: {\n name: input.name,\n type: input.type,\n ...(input.pk && { pk: true }),\n ...(input.fk && { fk: input.fk }),\n ...(input.unique && { unique: true }),\n ...(input.notNull && { notNull: true }),\n ...(input.default && { default: input.default }),\n ...(input.indexed && { indexed: true }),\n ...(input.values?.length && { values: input.values }),\n ...(input.stats && { stats: input.stats }),\n },\n };\n}\n\n/**\n * Table index.\n *\n * @param input.name - Index name\n * @param input.columns - Columns included in the index\n * @param input.unique - Is unique index\n * @param input.type - Index type (BTREE, HASH, GIN, etc.)\n *\n * @example\n * index({ name: 'idx_user_email', columns: ['email'], unique: true, type: 'BTREE' })\n */\nexport function index(input: {\n name: string;\n columns: string[];\n unique?: boolean;\n type?: string;\n}): ContextFragment {\n return {\n name: 'index',\n data: {\n name: input.name,\n columns: input.columns,\n ...(input.unique && { unique: true }),\n ...(input.type && { type: input.type }),\n },\n };\n}\n\n/**\n * Table constraint (CHECK, UNIQUE, PRIMARY_KEY, FOREIGN_KEY, etc).\n *\n * @param input.name - Constraint name\n * @param input.type - Constraint type\n * @param input.columns - Columns involved in the constraint\n * @param input.definition - CHECK constraint SQL definition\n * @param input.defaultValue - DEFAULT constraint value\n * @param input.referencedTable - For FK: referenced table name\n * @param input.referencedColumns - For FK: referenced column names\n *\n * @example\n * constraint({\n * name: 'chk_amount_positive',\n * type: 'CHECK',\n * definition: 'amount > 0',\n * })\n *\n * @example\n * constraint({\n * name: 'fk_order_user',\n * type: 'FOREIGN_KEY',\n * columns: ['user_id'],\n * referencedTable: 'users',\n * referencedColumns: ['id'],\n * })\n */\nexport function constraint(input: {\n name: string;\n type:\n | 'CHECK'\n | 'UNIQUE'\n | 'NOT_NULL'\n | 'DEFAULT'\n | 'PRIMARY_KEY'\n | 'FOREIGN_KEY';\n columns?: string[];\n definition?: string;\n defaultValue?: string;\n referencedTable?: string;\n referencedColumns?: string[];\n}): ContextFragment {\n return {\n name: 'constraint',\n data: {\n name: input.name,\n type: input.type,\n ...(input.columns?.length && { columns: input.columns }),\n ...(input.definition && { definition: input.definition }),\n ...(input.defaultValue && { defaultValue: input.defaultValue }),\n ...(input.referencedTable && { referencedTable: input.referencedTable }),\n ...(input.referencedColumns?.length && {\n referencedColumns: input.referencedColumns,\n }),\n },\n };\n}\n\n/**\n * Database view.\n *\n * @param input.name - View name\n * @param input.schema - Schema name\n * @param input.columns - Array of column() fragments\n * @param input.definition - View SQL definition\n *\n * @example\n * view({\n * name: 'active_users',\n * columns: [\n * column({ name: 'id', type: 'integer' }),\n * column({ name: 'email', type: 'varchar' }),\n * ],\n * definition: \"SELECT id, email FROM users WHERE status = 'active'\",\n * })\n */\nexport function view(input: {\n name: string;\n schema?: string;\n columns: ContextFragment[];\n definition?: string;\n}): ContextFragment {\n return {\n name: 'view',\n data: {\n name: input.name,\n ...(input.schema && { schema: input.schema }),\n columns: input.columns,\n ...(input.definition && { definition: input.definition }),\n },\n };\n}\n\n/**\n * Relationship between tables (foreign key connection).\n *\n * @param input.from - Source table and columns\n * @param input.to - Referenced table and columns\n * @param input.cardinality - Relationship cardinality\n *\n * @example\n * relationship({\n * from: { table: 'orders', columns: ['user_id'] },\n * to: { table: 'users', columns: ['id'] },\n * cardinality: 'many-to-one',\n * })\n */\nexport function relationship(input: {\n from: { table: string; columns: string[] };\n to: { table: string; columns: string[] };\n cardinality?: 'one-to-one' | 'one-to-many' | 'many-to-one' | 'many-to-many';\n}): ContextFragment {\n return {\n name: 'relationship',\n data: {\n from: input.from,\n to: input.to,\n ...(input.cardinality && { cardinality: input.cardinality }),\n },\n };\n}\n", "import type { AdapterInfo, ColumnStats, Relationship, Table } from '../adapter.ts';\nimport type { View } from './view.grounding.ts';\n\n/**\n * Column type for grounding operations.\n * Common interface between Table.columns and View.columns.\n */\nexport interface Column {\n name: string;\n type: string;\n kind?: 'LowCardinality' | 'Enum';\n values?: string[];\n stats?: ColumnStats;\n}\n\n/**\n * Entity with columns (Table or View).\n */\nexport interface ColumnContainer {\n name: string;\n columns: Column[];\n}\n\n/**\n * Shared context object passed to all groundings.\n * Groundings read from and write to this context.\n */\nexport interface GroundingContext {\n /** Tables discovered by TableGrounding */\n tables: Table[];\n\n /** Views discovered by ViewGrounding */\n views: View[];\n\n /** Relationships discovered by TableGrounding */\n relationships: Relationship[];\n\n /** Database info collected by InfoGrounding */\n info?: AdapterInfo;\n\n /** Business context report generated by ReportGrounding */\n report?: string;\n}\n\n/**\n * Create a new empty grounding context.\n */\nexport function createGroundingContext(): GroundingContext {\n return {\n tables: [],\n views: [],\n relationships: [],\n info: undefined,\n };\n}\n", "import type { ContextFragment } from '@deepagents/context';\n\nimport {\n column,\n constraint,\n dialectInfo,\n index,\n relationship,\n table,\n view,\n} from '../fragments/schema.ts';\nimport type { AbstractGrounding } from './groundings/abstract.grounding.ts';\nimport {\n type GroundingContext,\n createGroundingContext,\n} from './groundings/context.ts';\nimport type { View } from './groundings/view.grounding.ts';\n\n/**\n * Filter type for view/table names.\n * - string[]: explicit list of view names\n * - RegExp: pattern to match view names\n * - function: predicate to filter view names\n */\nexport type Filter = string[] | RegExp | ((viewName: string) => boolean);\n\nexport interface Table {\n name: string;\n schema?: string;\n rawName?: string;\n columns: {\n name: string;\n type: string;\n kind?: 'LowCardinality' | 'Enum';\n values?: string[];\n isIndexed?: boolean;\n stats?: ColumnStats;\n }[];\n rowCount?: number;\n sizeHint?: 'tiny' | 'small' | 'medium' | 'large' | 'huge';\n indexes?: TableIndex[];\n constraints?: TableConstraint[];\n}\n\nexport interface TableIndex {\n name: string;\n columns: string[];\n unique?: boolean;\n type?: string;\n}\n\nexport interface TableConstraint {\n name: string;\n type:\n | 'CHECK'\n | 'UNIQUE'\n | 'NOT_NULL'\n | 'DEFAULT'\n | 'PRIMARY_KEY'\n | 'FOREIGN_KEY';\n columns?: string[];\n definition?: string;\n defaultValue?: string;\n referencedTable?: string;\n referencedColumns?: string[];\n}\n\nexport interface ColumnStats {\n min?: string;\n max?: string;\n nullFraction?: number;\n}\n\nexport type Relationship = {\n table: string;\n from: string[];\n referenced_table: string;\n to: string[];\n};\n\nexport type TablesFilter = string[] | RegExp;\n\nexport interface Introspection {\n tables: Table[];\n relationships: Relationship[];\n}\n\nexport interface AdapterInfo {\n dialect: string;\n version?: string;\n database?: string;\n details?: Record<string, unknown>;\n}\n\nexport type AdapterInfoProvider =\n | AdapterInfo\n | (() => Promise<AdapterInfo> | AdapterInfo);\n\nexport type IntrospectionPhase =\n | 'tables'\n | 'row_counts'\n | 'primary_keys'\n | 'indexes'\n | 'column_stats'\n | 'low_cardinality'\n | 'relationships';\n\nexport interface IntrospectionProgress {\n phase: IntrospectionPhase;\n message: string;\n current?: number;\n total?: number;\n}\n\nexport type OnProgress = (progress: IntrospectionProgress) => void;\n\nexport interface IntrospectOptions {\n onProgress?: OnProgress;\n}\n\nexport type GroundingFn = (adapter: Adapter) => AbstractGrounding;\n\nexport type ExecuteFunction = (sql: string) => Promise<any> | any;\nexport type ValidateFunction = (\n sql: string,\n) => Promise<string | void> | string | void;\n\nexport abstract class Adapter {\n abstract grounding: GroundingFn[];\n\n /**\n * Default schema name for this database.\n * PostgreSQL: 'public', SQL Server: 'dbo', SQLite: undefined\n */\n abstract readonly defaultSchema: string | undefined;\n\n /**\n * System schemas to exclude from introspection by default.\n */\n abstract readonly systemSchemas: string[];\n\n /**\n * Introspect the database schema and return context fragments.\n *\n * Executes all configured groundings to populate the context, then\n * generates fragments from the complete context data.\n *\n * @param ctx - Optional grounding context for sharing state between groundings\n * @returns Array of context fragments representing the database schema\n */\n async introspect(ctx = createGroundingContext()): Promise<ContextFragment[]> {\n // Phase 1: All groundings populate ctx\n for (const fn of this.grounding) {\n const grounding = fn(this);\n await grounding.execute(ctx);\n }\n\n // Phase 2: Generate fragments from complete ctx\n return this.#toSchemaFragments(ctx);\n }\n\n /**\n * Convert complete grounding context to schema fragments.\n * Called after all groundings have populated ctx with data.\n */\n #toSchemaFragments(ctx: GroundingContext): ContextFragment[] {\n const fragments: ContextFragment[] = [];\n\n // Dialect info\n if (ctx.info) {\n fragments.push(\n dialectInfo({\n dialect: ctx.info.dialect,\n version: ctx.info.version,\n database: ctx.info.database,\n }),\n );\n }\n\n // Tables (with all annotations now included)\n for (const t of ctx.tables) {\n fragments.push(this.#tableToFragment(t));\n }\n\n // Views\n for (const v of ctx.views) {\n fragments.push(this.#viewToFragment(v));\n }\n\n // Relationships\n const tableMap = new Map(ctx.tables.map((t) => [t.name, t]));\n for (const rel of ctx.relationships) {\n const sourceTable = tableMap.get(rel.table);\n const targetTable = tableMap.get(rel.referenced_table);\n fragments.push(\n this.#relationshipToFragment(rel, sourceTable, targetTable),\n );\n }\n\n // Business context\n if (ctx.report) {\n fragments.push({ name: 'businessContext', data: ctx.report });\n }\n\n return fragments;\n }\n\n /**\n * Convert a Table to a table fragment with nested column, index, and constraint fragments.\n */\n #tableToFragment(t: Table): ContextFragment {\n // Build constraint lookup maps for column-level annotations\n const pkConstraint = t.constraints?.find((c) => c.type === 'PRIMARY_KEY');\n const pkColumns = new Set(pkConstraint?.columns ?? []);\n\n const notNullColumns = new Set(\n t.constraints\n ?.filter((c) => c.type === 'NOT_NULL')\n .flatMap((c) => c.columns ?? []) ?? [],\n );\n\n const defaultByColumn = new Map<string, string>();\n for (const c of t.constraints?.filter((c) => c.type === 'DEFAULT') ?? []) {\n for (const col of c.columns ?? []) {\n if (c.defaultValue != null) {\n defaultByColumn.set(col, c.defaultValue);\n }\n }\n }\n\n // Single-column UNIQUE constraints\n const uniqueColumns = new Set(\n t.constraints\n ?.filter((c) => c.type === 'UNIQUE' && c.columns?.length === 1)\n .flatMap((c) => c.columns ?? []) ?? [],\n );\n\n // Foreign key lookup: column -> referenced table.column\n const fkByColumn = new Map<string, string>();\n for (const c of t.constraints?.filter((c) => c.type === 'FOREIGN_KEY') ??\n []) {\n const cols = c.columns ?? [];\n const refCols = c.referencedColumns ?? [];\n for (let i = 0; i < cols.length; i++) {\n const refCol = refCols[i] ?? refCols[0] ?? cols[i];\n fkByColumn.set(cols[i], `${c.referencedTable}.${refCol}`);\n }\n }\n\n // Build column fragments\n const columnFragments = t.columns.map((col) =>\n column({\n name: col.name,\n type: col.type,\n pk: pkColumns.has(col.name) || undefined,\n fk: fkByColumn.get(col.name),\n unique: uniqueColumns.has(col.name) || undefined,\n notNull: notNullColumns.has(col.name) || undefined,\n default: defaultByColumn.get(col.name),\n indexed: col.isIndexed || undefined,\n values: col.values,\n stats: col.stats,\n }),\n );\n\n // Build index fragments\n const indexFragments = (t.indexes ?? []).map((idx) =>\n index({\n name: idx.name,\n columns: idx.columns,\n unique: idx.unique,\n type: idx.type,\n }),\n );\n\n // Build constraint fragments for multi-column UNIQUE and CHECK constraints\n const constraintFragments = (t.constraints ?? [])\n .filter(\n (c) =>\n c.type === 'CHECK' ||\n (c.type === 'UNIQUE' && (c.columns?.length ?? 0) > 1),\n )\n .map((c) =>\n constraint({\n name: c.name,\n type: c.type,\n columns: c.columns,\n definition: c.definition,\n }),\n );\n\n return table({\n name: t.name,\n schema: t.schema,\n rowCount: t.rowCount,\n sizeHint: t.sizeHint,\n columns: columnFragments,\n indexes: indexFragments.length > 0 ? indexFragments : undefined,\n constraints:\n constraintFragments.length > 0 ? constraintFragments : undefined,\n });\n }\n\n /**\n * Convert a View to a view fragment with nested column fragments.\n */\n #viewToFragment(v: View): ContextFragment {\n const columnFragments = v.columns.map((col) =>\n column({\n name: col.name,\n type: col.type,\n values: col.values,\n stats: col.stats,\n }),\n );\n\n return view({\n name: v.name,\n schema: v.schema,\n columns: columnFragments,\n definition: v.definition,\n });\n }\n\n /**\n * Convert a Relationship to a relationship fragment.\n * Infers cardinality from row counts if available.\n */\n #relationshipToFragment(\n rel: Relationship,\n sourceTable?: Table,\n targetTable?: Table,\n ): ContextFragment {\n const sourceCount = sourceTable?.rowCount;\n const targetCount = targetTable?.rowCount;\n\n let cardinality:\n | 'one-to-one'\n | 'one-to-many'\n | 'many-to-one'\n | 'many-to-many'\n | undefined;\n\n if (sourceCount != null && targetCount != null && targetCount > 0) {\n const ratio = sourceCount / targetCount;\n if (ratio > 5) {\n cardinality = 'many-to-one';\n } else if (ratio < 1.2 && ratio > 0.8) {\n cardinality = 'one-to-one';\n } else if (ratio < 0.2) {\n cardinality = 'one-to-many';\n }\n }\n\n return relationship({\n from: { table: rel.table, columns: rel.from },\n to: { table: rel.referenced_table, columns: rel.to },\n cardinality,\n });\n }\n abstract execute(sql: string): Promise<any[]> | any[];\n abstract validate(sql: string): Promise<string | void> | string | void;\n abstract runQuery<Row>(sql: string): Promise<Row[]> | Row[];\n\n /**\n * Quote an identifier (table/column name) for safe use in SQL.\n * Each database uses different quoting styles.\n */\n abstract quoteIdentifier(name: string): string;\n\n /**\n * Escape a string value for safe use in SQL.\n * Each database escapes different characters.\n */\n abstract escape(value: string): string;\n\n /**\n * Build a SELECT query to sample rows from a table.\n * Each database uses different syntax for limiting rows (LIMIT vs TOP).\n */\n abstract buildSampleRowsQuery(\n tableName: string,\n columns: string[] | undefined,\n limit: number,\n ): string;\n\n /**\n * Convert unknown database value to number.\n * Handles number, bigint, and string types.\n */\n toNumber(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n if (typeof value === 'bigint') {\n return Number(value);\n }\n if (typeof value === 'string' && value.trim() !== '') {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n }\n\n /**\n * Parse a potentially qualified table name into schema and table parts.\n */\n parseTableName(name: string): { schema: string; table: string } {\n if (name.includes('.')) {\n const [schema, ...rest] = name.split('.');\n return { schema, table: rest.join('.') };\n }\n return { schema: this.defaultSchema ?? '', table: name };\n }\n\n /**\n * Escape a string value for use in SQL string literals (single quotes).\n * Used in WHERE clauses like: WHERE name = '${escapeString(value)}'\n */\n escapeString(value: string): string {\n return value.replace(/'/g, \"''\");\n }\n\n /**\n * Build a SQL filter clause to include/exclude schemas.\n * @param columnName - The schema column name (e.g., 'TABLE_SCHEMA')\n * @param allowedSchemas - If provided, filter to these schemas only\n */\n buildSchemaFilter(columnName: string, allowedSchemas?: string[]): string {\n if (allowedSchemas && allowedSchemas.length > 0) {\n const values = allowedSchemas\n .map((s) => `'${this.escapeString(s)}'`)\n .join(', ');\n return `AND ${columnName} IN (${values})`;\n }\n if (this.systemSchemas.length > 0) {\n const values = this.systemSchemas\n .map((s) => `'${this.escapeString(s)}'`)\n .join(', ');\n return `AND ${columnName} NOT IN (${values})`;\n }\n return '';\n }\n}\n\nexport function filterTablesByName<T extends { name: string }>(\n tables: T[],\n filter: TablesFilter | undefined,\n): T[] {\n if (!filter) return tables;\n return tables.filter((table) => matchesFilter(table.name, filter));\n}\n\nexport function filterRelationshipsByTables(\n relationships: Relationship[],\n tableNames: Set<string> | undefined,\n): Relationship[] {\n if (tableNames === undefined) {\n return relationships;\n }\n if (tableNames.size === 0) {\n return [];\n }\n return relationships.filter(\n (it) => tableNames.has(it.table) || tableNames.has(it.referenced_table),\n );\n}\n\nexport function applyTablesFilter(\n tables: Table[],\n relationships: Relationship[],\n filter: TablesFilter | undefined,\n): { tables: Table[]; relationships: Relationship[] } {\n if (!filter) {\n return { tables, relationships };\n }\n\n const allowedNames = new Set(\n getTablesWithRelated(tables, relationships, filter),\n );\n\n return {\n tables: tables.filter((table) => allowedNames.has(table.name)),\n relationships: filterRelationshipsByTables(relationships, allowedNames),\n };\n}\n\nexport function matchesFilter(\n tableName: string,\n filter: TablesFilter,\n): boolean {\n if (Array.isArray(filter)) {\n return filter.includes(tableName);\n }\n return filter.test(tableName);\n}\n\nexport function getTablesWithRelated(\n allTables: Table[],\n relationships: Relationship[],\n filter: TablesFilter,\n): string[] {\n const matchedTables = filterTablesByName(allTables, filter).map(\n (it) => it.name,\n );\n\n if (matchedTables.length === 0) {\n return [];\n }\n\n const adjacency = new Map<string, Set<string>>();\n\n for (const rel of relationships) {\n if (!adjacency.has(rel.table)) {\n adjacency.set(rel.table, new Set());\n }\n if (!adjacency.has(rel.referenced_table)) {\n adjacency.set(rel.referenced_table, new Set());\n }\n adjacency.get(rel.table)!.add(rel.referenced_table);\n adjacency.get(rel.referenced_table)!.add(rel.table);\n }\n\n const result = new Set<string>(matchedTables);\n const queue = [...matchedTables];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n const neighbors = adjacency.get(current);\n\n if (!neighbors) {\n continue;\n }\n\n for (const neighbor of neighbors) {\n if (!result.has(neighbor)) {\n result.add(neighbor);\n queue.push(neighbor);\n }\n }\n }\n\n return Array.from(result);\n}\n", "import { tool } from 'ai';\nimport dedent from 'dedent';\nimport z from 'zod';\n\nimport { generate, toState } from '@deepagents/agent';\nimport { type ContextFragment, hint, persona } from '@deepagents/context';\n\nimport type { Adapter } from '../adapters/adapter.ts';\nimport { explainerAgent } from './explainer.agent.ts';\n\n/**\n * Context variables passed to the developer agent tools via stream().\n */\nexport type DeveloperContextVariables = {\n /** Database adapter for validation and execution */\n adapter: Adapter;\n};\n\n/**\n * Tools for the developer agent.\n * Following the text2sql.agent.ts pattern - LLM writes SQL directly.\n */\nconst tools = {\n /**\n * Validate SQL query syntax before execution.\n */\n validate_query: tool({\n description: `Validate SQL query syntax before execution. Use this to check if your SQL is valid before running db_query. This helps catch errors early and allows you to correct the query if needed.`,\n inputSchema: z.object({\n sql: z.string().describe('The SQL query to validate.'),\n }),\n execute: async ({ sql }, options) => {\n const state = toState<DeveloperContextVariables>(options);\n const result = await state.adapter.validate(sql);\n if (typeof result === 'string') {\n return `Validation Error: ${result}`;\n }\n return 'Query is valid.';\n },\n }),\n\n /**\n * Execute SQL query against the database.\n */\n db_query: tool({\n description: `Internal tool to fetch data from the store's database. Write a SQL query to retrieve the information needed to answer the user's question. The results will be returned as data that you can then present to the user in natural language.`,\n inputSchema: z.object({\n reasoning: z\n .string()\n .describe(\n 'Your reasoning for why this SQL query is relevant to the user request.',\n ),\n sql: z\n .string()\n .min(1, { message: 'SQL query cannot be empty.' })\n .refine(\n (sql) =>\n sql.trim().toUpperCase().startsWith('SELECT') ||\n sql.trim().toUpperCase().startsWith('WITH'),\n {\n message: 'Only read-only SELECT or WITH queries are allowed.',\n },\n )\n .describe('The SQL query to execute against the database.'),\n }),\n execute: ({ sql }, options) => {\n const state = toState<DeveloperContextVariables>(options);\n return state.adapter.execute(sql);\n },\n }),\n\n /**\n * Get plain-English explanation of a SQL query.\n */\n explain_sql: tool({\n description: dedent`\n Get a plain-English explanation of a SQL query.\n Use this to help the user understand what a query does.\n\n The explanation focuses on intent and logic, not syntax.\n `,\n inputSchema: z.object({\n sql: z.string().min(1).describe('The SQL query to explain'),\n }),\n execute: async ({ sql }) => {\n const { experimental_output } = await generate(explainerAgent, [], {\n sql,\n });\n return { explanation: experimental_output.explanation };\n },\n }),\n};\n\n/**\n * Context fragments defining the developer agent's persona and behavior.\n */\nconst fragments: ContextFragment[] = [\n persona({\n name: 'developer_assistant',\n role: 'You are an expert SQL developer assistant helping power users build and refine queries.',\n }),\n hint('Be transparent: show the SQL you generate before explaining it'),\n hint('Be precise: provide exact column names and table references'),\n hint('Suggest refinements and alternatives when appropriate'),\n hint('Support both natural language questions AND raw SQL input'),\n hint('When validating user SQL, explain any errors clearly'),\n];\n\n/**\n * Developer agent exports - tools and context fragments.\n * The agent is constructed dynamically in sql.ts developer() method.\n */\nexport default { tools, fragments };\n", "import { encode } from 'gpt-tokenizer';\n\nimport type { ContextFragment } from './fragments.ts';\nimport type { Models } from './models.generated.ts';\nimport type { ContextRenderer } from './renderers/abstract.renderer.ts';\n\n/**\n * Cost information for a model (prices per 1M tokens)\n */\nexport interface ModelCost {\n input: number;\n output: number;\n cache_read?: number;\n cache_write?: number;\n reasoning?: number;\n}\n\n/**\n * Model information from models.dev\n */\nexport interface ModelInfo {\n id: string;\n name: string;\n family: string;\n cost: ModelCost;\n limit: {\n context: number;\n output: number;\n };\n provider: string;\n}\n\n/**\n * Estimate for a single fragment\n */\nexport interface FragmentEstimate {\n name: string;\n id?: string;\n tokens: number;\n cost: number;\n}\n\n/**\n * Estimate result returned by the estimate function\n */\nexport interface EstimateResult {\n model: string;\n provider: string;\n tokens: number;\n cost: number;\n limits: {\n context: number;\n output: number;\n exceedsContext: boolean;\n };\n fragments: FragmentEstimate[];\n}\n\n/**\n * Tokenizer interface for counting tokens\n */\nexport interface Tokenizer {\n encode(text: string): number[];\n count(text: string): number;\n}\n\n/**\n * Default tokenizer using gpt-tokenizer\n * Works reasonably well for most models (~5-10% variance)\n */\nexport const defaultTokenizer: Tokenizer = {\n encode(text: string): number[] {\n return encode(text);\n },\n count(text: string): number {\n return encode(text).length;\n },\n};\n\ntype ModelsDevResponse = Record<\n string,\n {\n id: string;\n name: string;\n models: Record<\n string,\n {\n id: string;\n name: string;\n family: string;\n cost: ModelCost;\n limit: { context: number; output: number };\n }\n >;\n }\n>;\n\n/**\n * Registry for AI model information from models.dev\n * Caches data and provides lookup by model ID\n */\nexport class ModelsRegistry {\n #cache: Map<string, ModelInfo> = new Map();\n #loaded = false;\n #tokenizers: Map<string, Tokenizer> = new Map();\n #defaultTokenizer: Tokenizer = defaultTokenizer;\n\n /**\n * Load models data from models.dev API\n */\n async load(): Promise<void> {\n if (this.#loaded) return;\n\n const response = await fetch('https://models.dev/api.json');\n if (!response.ok) {\n throw new Error(`Failed to fetch models: ${response.statusText}`);\n }\n\n const data = (await response.json()) as ModelsDevResponse;\n\n for (const [providerId, provider] of Object.entries(data)) {\n for (const [modelId, model] of Object.entries(provider.models)) {\n const info: ModelInfo = {\n id: model.id,\n name: model.name,\n family: model.family,\n cost: model.cost,\n limit: model.limit,\n provider: providerId,\n };\n\n // Store by full ID (provider:model)\n this.#cache.set(`${providerId}:${modelId}`, info);\n }\n }\n\n this.#loaded = true;\n }\n\n /**\n * Get model info by ID\n * @param modelId - Model ID (e.g., \"openai:gpt-4o\")\n */\n get(modelId: string): ModelInfo | undefined {\n return this.#cache.get(modelId);\n }\n\n /**\n * Check if a model exists in the registry\n */\n has(modelId: string): boolean {\n return this.#cache.has(modelId);\n }\n\n /**\n * List all available model IDs\n */\n list(): string[] {\n return [...this.#cache.keys()];\n }\n\n /**\n * Register a custom tokenizer for specific model families\n * @param family - Model family name (e.g., \"llama\", \"claude\")\n * @param tokenizer - Tokenizer implementation\n */\n registerTokenizer(family: string, tokenizer: Tokenizer): void {\n this.#tokenizers.set(family, tokenizer);\n }\n\n /**\n * Set the default tokenizer used when no family-specific tokenizer is registered\n */\n setDefaultTokenizer(tokenizer: Tokenizer): void {\n this.#defaultTokenizer = tokenizer;\n }\n\n /**\n * Get the appropriate tokenizer for a model\n */\n getTokenizer(modelId: string): Tokenizer {\n const model = this.get(modelId);\n if (model) {\n const familyTokenizer = this.#tokenizers.get(model.family);\n if (familyTokenizer) {\n return familyTokenizer;\n }\n }\n return this.#defaultTokenizer;\n }\n\n /**\n * Estimate token count and cost for given text and model\n * @param modelId - Model ID to use for pricing (e.g., \"openai:gpt-4o\")\n * @param input - Input text (prompt)\n */\n estimate(modelId: Models, input: string): EstimateResult {\n const model = this.get(modelId);\n if (!model) {\n throw new Error(\n `Model \"${modelId}\" not found. Call load() first or check model ID.`,\n );\n }\n\n const tokenizer = this.getTokenizer(modelId);\n const tokens = tokenizer.count(input);\n const cost = (tokens / 1_000_000) * model.cost.input;\n\n return {\n model: model.id,\n provider: model.provider,\n tokens,\n cost,\n limits: {\n context: model.limit.context,\n output: model.limit.output,\n exceedsContext: tokens > model.limit.context,\n },\n fragments: [],\n };\n }\n}\n\n// Singleton instance for convenience\nlet _registry: ModelsRegistry | null = null;\n\n/**\n * Get the shared ModelsRegistry instance\n */\nexport function getModelsRegistry(): ModelsRegistry {\n if (!_registry) {\n _registry = new ModelsRegistry();\n }\n return _registry;\n}\n\n/**\n * Convenience function to estimate cost for a model\n * Automatically loads the registry if not already loaded\n *\n * @param modelId - Model ID (e.g., \"openai:gpt-4o\", \"anthropic:claude-3-5-sonnet\")\n * @param renderer - Renderer to use for converting fragments to text\n * @param fragments - Context fragments to estimate\n */\nexport async function estimate(\n modelId: Models,\n renderer: ContextRenderer,\n ...fragments: ContextFragment[]\n): Promise<EstimateResult> {\n const registry = getModelsRegistry();\n await registry.load();\n\n // Calculate total (all fragments rendered together)\n const input = renderer.render(fragments);\n const model = registry.get(modelId);\n if (!model) {\n throw new Error(\n `Model \"${modelId}\" not found. Call load() first or check model ID.`,\n );\n }\n\n const tokenizer = registry.getTokenizer(modelId);\n const totalTokens = tokenizer.count(input);\n const totalCost = (totalTokens / 1_000_000) * model.cost.input;\n\n // Calculate per-fragment estimates\n const fragmentEstimates: FragmentEstimate[] = fragments.map((fragment) => {\n const rendered = renderer.render([fragment]);\n const tokens = tokenizer.count(rendered);\n const cost = (tokens / 1_000_000) * model.cost.input;\n return {\n id: fragment.id,\n name: fragment.name,\n tokens,\n cost,\n };\n });\n\n return {\n model: model.id,\n provider: model.provider,\n tokens: totalTokens,\n cost: totalCost,\n limits: {\n context: model.limit.context,\n output: model.limit.output,\n exceedsContext: totalTokens > model.limit.context,\n },\n fragments: fragmentEstimates,\n };\n}\n", "import { type UIMessage, generateId } from 'ai';\n\nimport type { FragmentCodec } from './codec.ts';\n\n/**\n * Fragment type identifier.\n * - 'fragment': Regular context fragment (default)\n * - 'message': Conversation message (user/assistant)\n */\nexport type FragmentType = 'fragment' | 'message';\n\n/**\n * A context fragment containing a name and associated data.\n */\nexport interface ContextFragment<T extends FragmentData = FragmentData> {\n /**\n * Unique identifier for this fragment.\n * Auto-generated for user/assistant messages, optional for other fragments.\n */\n id?: string;\n name: string;\n data: T;\n /**\n * Fragment type for categorization.\n * Messages use 'message' type and are handled separately during resolve().\n */\n type?: FragmentType;\n /**\n * When true, this fragment will be persisted to the store on save().\n */\n persist?: boolean;\n /**\n * Codec for encoding/decoding this fragment.\n * Used by resolve() to convert to AI SDK format.\n */\n codec?: FragmentCodec;\n}\n\n/**\n * Fragment data can be a primitive, array, object, or nested fragment.\n */\nexport type FragmentData =\n | string\n | number\n | boolean\n | ContextFragment\n | FragmentData[]\n | { [key: string]: FragmentData };\n\n/**\n * Type guard to check if data is a ContextFragment.\n */\nexport function isFragment(data: unknown): data is ContextFragment {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'name' in data &&\n 'data' in data &&\n typeof (data as ContextFragment).name === 'string'\n );\n}\n\n/**\n * A plain object with string keys and FragmentData values.\n */\nexport type FragmentObject = Record<string, FragmentData>;\n\n/**\n * Type guard to check if data is a plain object (not array, not fragment, not primitive).\n */\nexport function isFragmentObject(data: unknown): data is FragmentObject {\n return (\n typeof data === 'object' &&\n data !== null &&\n !Array.isArray(data) &&\n !isFragment(data)\n );\n}\n\n/**\n * Type guard to check if a fragment is a message fragment.\n */\nexport function isMessageFragment(fragment: ContextFragment): boolean {\n return fragment.type === 'message';\n}\n\nexport function fragment(\n name: string,\n ...children: ContextFragment[]\n): ContextFragment {\n return {\n name,\n data: children,\n };\n}\n\n/**\n * Create a role fragment for system prompt instructions.\n */\nexport function role(content: string): ContextFragment {\n return {\n name: 'role',\n data: content,\n };\n}\n\n/**\n * Create a user message fragment.\n * Message fragments are separated from regular fragments during resolve().\n *\n * @param content - The message content\n * @param options - Optional settings (id)\n *\n * @example\n * ```ts\n * context.set(user('Hello')); // Auto-generated ID\n * context.set(user('Hello', { id: 'msg-1' })); // Custom ID\n * ```\n */\nexport function user(content: string | UIMessage): ContextFragment {\n const message =\n typeof content === 'string'\n ? {\n id: generateId(),\n role: 'user',\n parts: [{ type: 'text', text: content }],\n }\n : content;\n return {\n id: message.id,\n name: 'user',\n data: 'content',\n type: 'message',\n persist: true,\n codec: {\n decode() {\n return message;\n },\n encode() {\n return message;\n },\n },\n };\n}\n\n/**\n * Create an assistant message fragment.\n * Message fragments are separated from regular fragments during resolve().\n *\n * @param message - The message content\n * @param options - Optional settings (id)\n *\n * @example\n * ```ts\n * context.set(assistant('Hi there!')); // Auto-generated ID\n * context.set(assistant('Hi there!', { id: 'resp-1' })); // Custom ID\n * ```\n */\nexport function assistant(message: UIMessage): ContextFragment {\n return {\n id: message.id,\n name: 'assistant',\n data: 'content',\n type: 'message',\n persist: true,\n codec: {\n decode() {\n return message;\n },\n encode() {\n return message;\n },\n },\n };\n}\nexport function message(content: string | UIMessage): ContextFragment {\n const message =\n typeof content === 'string'\n ? {\n id: generateId(),\n role: 'user',\n parts: [{ type: 'text', text: content }],\n }\n : content;\n return {\n id: message.id,\n name: 'message',\n data: 'content',\n type: 'message',\n persist: true,\n codec: {\n decode() {\n return message;\n },\n encode() {\n return message;\n },\n },\n };\n}\n\n/**\n * Create an assistant message fragment from text content.\n * Convenience wrapper that creates a UIMessage internally.\n *\n * @param content - The message text content\n * @param options - Optional settings (id)\n *\n * @example\n * ```ts\n * context.set(assistantText('Hi there!')); // Auto-generated ID\n * context.set(assistantText('Hi there!', { id: 'resp-1' })); // Custom ID\n * ```\n */\nexport function assistantText(\n content: string,\n options?: { id?: string },\n): ContextFragment {\n const id = options?.id ?? crypto.randomUUID();\n return assistant({\n id,\n role: 'assistant',\n parts: [{ type: 'text', text: content }],\n });\n}\n", "import pluralize from 'pluralize';\nimport { titlecase } from 'stringcase';\n\nimport {\n type ContextFragment,\n type FragmentData,\n type FragmentObject,\n isFragment,\n isFragmentObject,\n} from '../fragments.ts';\n\n/**\n * Render context passed through the template method.\n */\nexport interface RenderContext {\n depth: number;\n path: string[];\n}\n\n/**\n * Options for renderers.\n */\nexport interface RendererOptions {\n /**\n * When true, fragments with the same name are grouped under a pluralized parent tag.\n * e.g., multiple <hint> become <hints><hint>...</hint><hint>...</hint></hints>\n */\n groupFragments?: boolean;\n}\n\n/**\n * Base renderer implementing the Template Method pattern.\n * Subclasses implement the specific formatting hooks.\n */\nexport abstract class ContextRenderer {\n protected options: RendererOptions;\n\n constructor(options: RendererOptions = {}) {\n this.options = options;\n }\n\n abstract render(fragments: ContextFragment[]): string;\n\n /**\n * Check if data is a primitive (string, number, boolean).\n */\n protected isPrimitive(data: FragmentData): data is string | number | boolean {\n return (\n typeof data === 'string' ||\n typeof data === 'number' ||\n typeof data === 'boolean'\n );\n }\n\n /**\n * Group fragments by name for groupFragments option.\n */\n protected groupByName(\n fragments: ContextFragment[],\n ): Map<string, ContextFragment[]> {\n const groups = new Map<string, ContextFragment[]>();\n for (const fragment of fragments) {\n const existing = groups.get(fragment.name) ?? [];\n existing.push(fragment);\n groups.set(fragment.name, existing);\n }\n return groups;\n }\n\n /**\n * Template method - dispatches value to appropriate handler.\n */\n protected renderValue(\n key: string,\n value: unknown,\n ctx: RenderContext,\n ): string {\n if (value == null) {\n return '';\n }\n if (isFragment(value)) {\n return this.renderFragment(value, ctx);\n }\n if (Array.isArray(value)) {\n return this.renderArray(key, value, ctx);\n }\n if (isFragmentObject(value)) {\n return this.renderObject(key, value, ctx);\n }\n return this.renderPrimitive(key, String(value), ctx);\n }\n\n /**\n * Render a nested fragment - subclasses implement this.\n */\n protected abstract renderFragment(\n fragment: ContextFragment,\n ctx: RenderContext,\n ): string;\n\n /**\n * Render all entries of an object.\n */\n protected renderEntries(data: FragmentObject, ctx: RenderContext): string[] {\n return Object.entries(data)\n .map(([key, value]) => this.renderValue(key, value, ctx))\n .filter(Boolean);\n }\n\n // Hooks - subclasses implement these\n protected abstract renderPrimitive(\n key: string,\n value: string,\n ctx: RenderContext,\n ): string;\n protected abstract renderArray(\n key: string,\n items: FragmentData[],\n ctx: RenderContext,\n ): string;\n protected abstract renderObject(\n key: string,\n obj: FragmentObject,\n ctx: RenderContext,\n ): string;\n}\n\n/**\n * Renders context fragments as XML.\n */\nexport class XmlRenderer extends ContextRenderer {\n render(fragments: ContextFragment[]): string {\n return fragments\n .map((f) => this.#renderTopLevel(f))\n .filter(Boolean)\n .join('\\n');\n }\n\n #renderTopLevel(fragment: ContextFragment): string {\n if (this.isPrimitive(fragment.data)) {\n return this.#leafRoot(fragment.name, String(fragment.data));\n }\n if (Array.isArray(fragment.data)) {\n return this.#renderArray(fragment.name, fragment.data, 0);\n }\n if (isFragment(fragment.data)) {\n const child = this.renderFragment(fragment.data, { depth: 1, path: [] });\n return this.#wrap(fragment.name, [child]);\n }\n return this.#wrap(\n fragment.name,\n this.renderEntries(fragment.data, { depth: 1, path: [] }),\n );\n }\n\n #renderArray(name: string, items: FragmentData[], depth: number): string {\n const fragmentItems = items.filter(isFragment);\n const nonFragmentItems = items.filter((item) => !isFragment(item));\n\n const children: string[] = [];\n\n // Render non-fragment items\n for (const item of nonFragmentItems) {\n if (item != null) {\n children.push(\n this.#leaf(pluralize.singular(name), String(item), depth + 1),\n );\n }\n }\n\n // Render fragment items (possibly grouped)\n if (this.options.groupFragments && fragmentItems.length > 0) {\n const groups = this.groupByName(fragmentItems);\n for (const [groupName, groupFragments] of groups) {\n const groupChildren = groupFragments.map((frag) =>\n this.renderFragment(frag, { depth: depth + 2, path: [] }),\n );\n const pluralName = pluralize.plural(groupName);\n children.push(this.#wrapIndented(pluralName, groupChildren, depth + 1));\n }\n } else {\n for (const frag of fragmentItems) {\n children.push(\n this.renderFragment(frag, { depth: depth + 1, path: [] }),\n );\n }\n }\n\n return this.#wrap(name, children);\n }\n\n #leafRoot(tag: string, value: string): string {\n const safe = this.#escape(value);\n if (safe.includes('\\n')) {\n return `<${tag}>\\n${this.#indent(safe, 2)}\\n</${tag}>`;\n }\n return `<${tag}>${safe}</${tag}>`;\n }\n\n protected renderFragment(\n fragment: ContextFragment,\n ctx: RenderContext,\n ): string {\n const { name, data } = fragment;\n if (this.isPrimitive(data)) {\n return this.#leaf(name, String(data), ctx.depth);\n }\n if (isFragment(data)) {\n const child = this.renderFragment(data, { ...ctx, depth: ctx.depth + 1 });\n return this.#wrapIndented(name, [child], ctx.depth);\n }\n if (Array.isArray(data)) {\n return this.#renderArrayIndented(name, data, ctx.depth);\n }\n const children = this.renderEntries(data, { ...ctx, depth: ctx.depth + 1 });\n return this.#wrapIndented(name, children, ctx.depth);\n }\n\n #renderArrayIndented(\n name: string,\n items: FragmentData[],\n depth: number,\n ): string {\n const fragmentItems = items.filter(isFragment);\n const nonFragmentItems = items.filter((item) => !isFragment(item));\n\n const children: string[] = [];\n\n // Render non-fragment items\n for (const item of nonFragmentItems) {\n if (item != null) {\n children.push(\n this.#leaf(pluralize.singular(name), String(item), depth + 1),\n );\n }\n }\n\n // Render fragment items (possibly grouped)\n if (this.options.groupFragments && fragmentItems.length > 0) {\n const groups = this.groupByName(fragmentItems);\n for (const [groupName, groupFragments] of groups) {\n const groupChildren = groupFragments.map((frag) =>\n this.renderFragment(frag, { depth: depth + 2, path: [] }),\n );\n const pluralName = pluralize.plural(groupName);\n children.push(this.#wrapIndented(pluralName, groupChildren, depth + 1));\n }\n } else {\n for (const frag of fragmentItems) {\n children.push(\n this.renderFragment(frag, { depth: depth + 1, path: [] }),\n );\n }\n }\n\n return this.#wrapIndented(name, children, depth);\n }\n\n protected renderPrimitive(\n key: string,\n value: string,\n ctx: RenderContext,\n ): string {\n return this.#leaf(key, value, ctx.depth);\n }\n\n protected renderArray(\n key: string,\n items: FragmentData[],\n ctx: RenderContext,\n ): string {\n if (!items.length) {\n return '';\n }\n const itemTag = pluralize.singular(key);\n const children = items\n .filter((item) => item != null)\n .map((item) => this.#leaf(itemTag, String(item), ctx.depth + 1));\n return this.#wrapIndented(key, children, ctx.depth);\n }\n\n protected renderObject(\n key: string,\n obj: FragmentObject,\n ctx: RenderContext,\n ): string {\n const children = this.renderEntries(obj, { ...ctx, depth: ctx.depth + 1 });\n return this.#wrapIndented(key, children, ctx.depth);\n }\n\n #escape(value: string): string {\n if (value == null) {\n return '';\n }\n return value\n .replaceAll(/&/g, '&amp;')\n .replaceAll(/</g, '&lt;')\n .replaceAll(/>/g, '&gt;')\n .replaceAll(/\"/g, '&quot;')\n .replaceAll(/'/g, '&apos;');\n }\n\n #indent(text: string, spaces: number): string {\n if (!text.trim()) {\n return '';\n }\n const padding = ' '.repeat(spaces);\n return text\n .split('\\n')\n .map((line) => (line.length ? padding + line : padding))\n .join('\\n');\n }\n\n #leaf(tag: string, value: string, depth: number): string {\n const safe = this.#escape(value);\n const pad = ' '.repeat(depth);\n if (safe.includes('\\n')) {\n return `${pad}<${tag}>\\n${this.#indent(safe, (depth + 1) * 2)}\\n${pad}</${tag}>`;\n }\n return `${pad}<${tag}>${safe}</${tag}>`;\n }\n\n #wrap(tag: string, children: string[]): string {\n const content = children.filter(Boolean).join('\\n');\n if (!content) {\n return '';\n }\n return `<${tag}>\\n${content}\\n</${tag}>`;\n }\n\n #wrapIndented(tag: string, children: string[], depth: number): string {\n const content = children.filter(Boolean).join('\\n');\n if (!content) {\n return '';\n }\n const pad = ' '.repeat(depth);\n return `${pad}<${tag}>\\n${content}\\n${pad}</${tag}>`;\n }\n}\n\n/**\n * Renders context fragments as Markdown.\n */\nexport class MarkdownRenderer extends ContextRenderer {\n render(fragments: ContextFragment[]): string {\n return fragments\n .map((f) => {\n const title = `## ${titlecase(f.name)}`;\n if (this.isPrimitive(f.data)) {\n return `${title}\\n${String(f.data)}`;\n }\n if (Array.isArray(f.data)) {\n return `${title}\\n${this.#renderArray(f.data, 0)}`;\n }\n if (isFragment(f.data)) {\n return `${title}\\n${this.renderFragment(f.data, { depth: 0, path: [] })}`;\n }\n return `${title}\\n${this.renderEntries(f.data, { depth: 0, path: [] }).join('\\n')}`;\n })\n .join('\\n\\n');\n }\n\n #renderArray(items: FragmentData[], depth: number): string {\n const fragmentItems = items.filter(isFragment);\n const nonFragmentItems = items.filter((item) => !isFragment(item));\n\n const lines: string[] = [];\n\n // Render non-fragment items\n for (const item of nonFragmentItems) {\n if (item != null) {\n lines.push(`${this.#pad(depth)}- ${String(item)}`);\n }\n }\n\n // Render fragment items (possibly grouped)\n if (this.options.groupFragments && fragmentItems.length > 0) {\n const groups = this.groupByName(fragmentItems);\n for (const [groupName, groupFragments] of groups) {\n const pluralName = pluralize.plural(groupName);\n lines.push(`${this.#pad(depth)}- **${titlecase(pluralName)}**:`);\n for (const frag of groupFragments) {\n lines.push(this.renderFragment(frag, { depth: depth + 1, path: [] }));\n }\n }\n } else {\n for (const frag of fragmentItems) {\n lines.push(this.renderFragment(frag, { depth, path: [] }));\n }\n }\n\n return lines.join('\\n');\n }\n\n #pad(depth: number): string {\n return ' '.repeat(depth);\n }\n\n #leaf(key: string, value: string, depth: number): string {\n return `${this.#pad(depth)}- **${key}**: ${value}`;\n }\n\n #arrayItem(item: unknown, depth: number): string {\n if (isFragment(item)) {\n return this.renderFragment(item, { depth, path: [] });\n }\n if (isFragmentObject(item)) {\n return this.renderEntries(item, {\n depth,\n path: [],\n }).join('\\n');\n }\n return `${this.#pad(depth)}- ${String(item)}`;\n }\n\n protected renderFragment(\n fragment: ContextFragment,\n ctx: RenderContext,\n ): string {\n const { name, data } = fragment;\n const header = `${this.#pad(ctx.depth)}- **${name}**:`;\n if (this.isPrimitive(data)) {\n return `${this.#pad(ctx.depth)}- **${name}**: ${String(data)}`;\n }\n if (isFragment(data)) {\n const child = this.renderFragment(data, { ...ctx, depth: ctx.depth + 1 });\n return [header, child].join('\\n');\n }\n if (Array.isArray(data)) {\n const children = data\n .filter((item) => item != null)\n .map((item) => this.#arrayItem(item, ctx.depth + 1));\n return [header, ...children].join('\\n');\n }\n const children = this.renderEntries(data, {\n ...ctx,\n depth: ctx.depth + 1,\n }).join('\\n');\n return [header, children].join('\\n');\n }\n\n protected renderPrimitive(\n key: string,\n value: string,\n ctx: RenderContext,\n ): string {\n return this.#leaf(key, value, ctx.depth);\n }\n\n protected renderArray(\n key: string,\n items: FragmentData[],\n ctx: RenderContext,\n ): string {\n const header = `${this.#pad(ctx.depth)}- **${key}**:`;\n const children = items\n .filter((item) => item != null)\n .map((item) => this.#arrayItem(item, ctx.depth + 1));\n return [header, ...children].join('\\n');\n }\n\n protected renderObject(\n key: string,\n obj: FragmentObject,\n ctx: RenderContext,\n ): string {\n const header = `${this.#pad(ctx.depth)}- **${key}**:`;\n const children = this.renderEntries(obj, {\n ...ctx,\n depth: ctx.depth + 1,\n }).join('\\n');\n return [header, children].join('\\n');\n }\n}\n\n/**\n * Renders context fragments as TOML.\n */\nexport class TomlRenderer extends ContextRenderer {\n render(fragments: ContextFragment[]): string {\n return fragments\n .map((f) => {\n if (this.isPrimitive(f.data)) {\n return `${f.name} = ${this.#formatValue(f.data)}`;\n }\n if (Array.isArray(f.data)) {\n return this.#renderTopLevelArray(f.name, f.data);\n }\n if (isFragment(f.data)) {\n return [\n `[${f.name}]`,\n this.renderFragment(f.data, { depth: 0, path: [f.name] }),\n ].join('\\n');\n }\n const entries = this.#renderObjectEntries(f.data, [f.name]);\n return [`[${f.name}]`, ...entries].join('\\n');\n })\n .join('\\n\\n');\n }\n\n #renderTopLevelArray(name: string, items: FragmentData[]): string {\n const fragmentItems = items.filter(isFragment);\n const nonFragmentItems = items.filter(\n (item) => !isFragment(item) && item != null,\n );\n\n // If array contains fragments, render as sections\n if (fragmentItems.length > 0) {\n const parts: string[] = [`[${name}]`];\n for (const frag of fragmentItems) {\n parts.push(this.renderFragment(frag, { depth: 0, path: [name] }));\n }\n return parts.join('\\n');\n }\n\n // Otherwise render as inline array\n const values = nonFragmentItems.map((item) => this.#formatValue(item));\n return `${name} = [${values.join(', ')}]`;\n }\n\n /**\n * Override renderValue to preserve type information for TOML formatting.\n */\n protected override renderValue(\n key: string,\n value: unknown,\n ctx: RenderContext,\n ): string {\n if (value == null) {\n return '';\n }\n if (isFragment(value)) {\n return this.renderFragment(value, ctx);\n }\n if (Array.isArray(value)) {\n return this.renderArray(key, value, ctx);\n }\n if (isFragmentObject(value)) {\n return this.renderObject(key, value, ctx);\n }\n // Preserve original type for TOML formatting\n return `${key} = ${this.#formatValue(value)}`;\n }\n\n protected renderPrimitive(\n key: string,\n value: string,\n _ctx: RenderContext,\n ): string {\n return `${key} = ${this.#formatValue(value)}`;\n }\n\n protected renderArray(\n key: string,\n items: FragmentData[],\n _ctx: RenderContext,\n ): string {\n const values = items\n .filter((item) => item != null)\n .map((item) => this.#formatValue(item));\n return `${key} = [${values.join(', ')}]`;\n }\n\n protected renderObject(\n key: string,\n obj: FragmentObject,\n ctx: RenderContext,\n ): string {\n const newPath = [...ctx.path, key];\n const entries = this.#renderObjectEntries(obj, newPath);\n return ['', `[${newPath.join('.')}]`, ...entries].join('\\n');\n }\n\n #renderObjectEntries(obj: FragmentObject, path: string[]): string[] {\n return Object.entries(obj)\n .map(([key, value]) => {\n if (value == null) {\n return '';\n }\n if (isFragmentObject(value)) {\n const newPath = [...path, key];\n const entries = this.#renderObjectEntries(value, newPath);\n return ['', `[${newPath.join('.')}]`, ...entries].join('\\n');\n }\n if (Array.isArray(value)) {\n const values = value\n .filter((item) => item != null)\n .map((item) => this.#formatValue(item));\n return `${key} = [${values.join(', ')}]`;\n }\n return `${key} = ${this.#formatValue(value)}`;\n })\n .filter(Boolean);\n }\n\n protected renderFragment(\n fragment: ContextFragment,\n ctx: RenderContext,\n ): string {\n const { name, data } = fragment;\n const newPath = [...ctx.path, name];\n if (this.isPrimitive(data)) {\n return `${name} = ${this.#formatValue(data)}`;\n }\n if (isFragment(data)) {\n return [\n '',\n `[${newPath.join('.')}]`,\n this.renderFragment(data, { ...ctx, path: newPath }),\n ].join('\\n');\n }\n if (Array.isArray(data)) {\n const fragmentItems = data.filter(isFragment);\n const nonFragmentItems = data.filter(\n (item) => !isFragment(item) && item != null,\n );\n\n if (fragmentItems.length > 0) {\n const parts: string[] = ['', `[${newPath.join('.')}]`];\n for (const frag of fragmentItems) {\n parts.push(this.renderFragment(frag, { ...ctx, path: newPath }));\n }\n return parts.join('\\n');\n }\n\n const values = nonFragmentItems.map((item) => this.#formatValue(item));\n return `${name} = [${values.join(', ')}]`;\n }\n const entries = this.#renderObjectEntries(data, newPath);\n return ['', `[${newPath.join('.')}]`, ...entries].join('\\n');\n }\n\n #escape(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n }\n\n #formatValue(value: unknown): string {\n if (typeof value === 'string') {\n return `\"${this.#escape(value)}\"`;\n }\n if (typeof value === 'boolean' || typeof value === 'number') {\n return String(value);\n }\n if (typeof value === 'object' && value !== null) {\n return JSON.stringify(value);\n }\n return `\"${String(value)}\"`;\n }\n}\n\n/**\n * Renders context fragments as TOON (Token-Oriented Object Notation).\n * TOON is a compact, token-efficient format for LLM prompts that combines\n * YAML-like indentation with CSV-like tabular arrays.\n */\nexport class ToonRenderer extends ContextRenderer {\n render(fragments: ContextFragment[]): string {\n return fragments\n .map((f) => this.#renderTopLevel(f))\n .filter(Boolean)\n .join('\\n');\n }\n\n #renderTopLevel(fragment: ContextFragment): string {\n const { name, data } = fragment;\n if (this.isPrimitive(data)) {\n return `${name}: ${this.#formatValue(data)}`;\n }\n if (Array.isArray(data)) {\n return this.#renderArrayField(name, data, 0);\n }\n if (isFragment(data)) {\n const child = this.renderFragment(data, { depth: 1, path: [] });\n return `${name}:\\n${child}`;\n }\n if (isFragmentObject(data)) {\n const entries = this.#renderObjectEntries(data, 1);\n if (!entries) {\n return `${name}:`;\n }\n return `${name}:\\n${entries}`;\n }\n return `${name}:`;\n }\n\n #renderArrayField(key: string, items: FragmentData[], depth: number): string {\n const filtered = items.filter((item) => item != null);\n if (filtered.length === 0) {\n return `${this.#pad(depth)}${key}[0]:`;\n }\n\n // Check for ContextFragment items\n const fragmentItems = filtered.filter(isFragment);\n if (fragmentItems.length > 0) {\n return this.#renderMixedArray(key, filtered, depth);\n }\n\n // Check if all items are primitives\n if (filtered.every((item) => this.#isPrimitiveValue(item))) {\n return this.#renderPrimitiveArray(key, filtered, depth);\n }\n\n // Check if tabular (uniform objects with primitive values)\n if (this.#isTabularArray(filtered)) {\n return this.#renderTabularArray(key, filtered, depth);\n }\n\n // Mixed array\n return this.#renderMixedArray(key, filtered, depth);\n }\n\n #isPrimitiveValue(value: unknown): boolean {\n return (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n );\n }\n\n #isTabularArray(items: FragmentData[]): items is FragmentObject[] {\n if (items.length === 0) return false;\n\n // All items must be objects (not arrays, not primitives, not fragments)\n const objects = items.filter(isFragmentObject);\n if (objects.length !== items.length) return false;\n\n // Get keys from first object\n const firstKeys = Object.keys(objects[0]).sort().join(',');\n\n // All objects must have same keys\n for (const obj of objects) {\n if (Object.keys(obj).sort().join(',') !== firstKeys) {\n return false;\n }\n // All values must be primitives\n for (const value of Object.values(obj)) {\n if (!this.#isPrimitiveValue(value) && value !== null) {\n return false;\n }\n }\n }\n\n return true;\n }\n\n #renderPrimitiveArray(\n key: string,\n items: FragmentData[],\n depth: number,\n ): string {\n const values = items.map((item) => this.#formatValue(item)).join(',');\n return `${this.#pad(depth)}${key}[${items.length}]: ${values}`;\n }\n\n #renderTabularArray(\n key: string,\n items: FragmentObject[],\n depth: number,\n ): string {\n if (items.length === 0) {\n return `${this.#pad(depth)}${key}[0]:`;\n }\n\n const fields = Object.keys(items[0]);\n const header = `${this.#pad(depth)}${key}[${items.length}]{${fields.join(',')}}:`;\n\n const rows = items.map((obj) => {\n const values = fields.map((f) => this.#formatValue(obj[f]));\n return `${this.#pad(depth + 1)}${values.join(',')}`;\n });\n\n return [header, ...rows].join('\\n');\n }\n\n #renderMixedArray(key: string, items: FragmentData[], depth: number): string {\n const header = `${this.#pad(depth)}${key}[${items.length}]:`;\n const lines = items.map((item) => this.#renderListItem(item, depth + 1));\n return [header, ...lines].join('\\n');\n }\n\n #renderListItem(item: FragmentData, depth: number): string {\n if (this.#isPrimitiveValue(item)) {\n return `${this.#pad(depth)}- ${this.#formatValue(item)}`;\n }\n if (isFragment(item)) {\n const rendered = this.renderFragment(item, {\n depth: depth + 1,\n path: [],\n });\n // For fragments, render key: value on same line as hyphen if primitive\n if (this.isPrimitive(item.data)) {\n return `${this.#pad(depth)}- ${item.name}: ${this.#formatValue(item.data)}`;\n }\n return `${this.#pad(depth)}- ${item.name}:\\n${rendered.split('\\n').slice(1).join('\\n')}`;\n }\n if (Array.isArray(item)) {\n // Nested array\n const content = this.#renderArrayField('', item, depth + 1);\n return `${this.#pad(depth)}-${content.trimStart()}`;\n }\n if (isFragmentObject(item)) {\n // Object in list\n const entries = this.#renderObjectEntries(item, depth + 1);\n if (!entries) {\n return `${this.#pad(depth)}-`;\n }\n // First line on same line as hyphen\n const lines = entries.split('\\n');\n const first = lines[0].trimStart();\n const rest = lines.slice(1).join('\\n');\n return rest\n ? `${this.#pad(depth)}- ${first}\\n${rest}`\n : `${this.#pad(depth)}- ${first}`;\n }\n return `${this.#pad(depth)}- ${this.#formatValue(item)}`;\n }\n\n #renderObjectEntries(obj: FragmentObject, depth: number): string {\n const lines: string[] = [];\n for (const [key, value] of Object.entries(obj)) {\n if (value == null) continue;\n\n if (this.#isPrimitiveValue(value)) {\n lines.push(`${this.#pad(depth)}${key}: ${this.#formatValue(value)}`);\n } else if (Array.isArray(value)) {\n lines.push(this.#renderArrayField(key, value, depth));\n } else if (isFragmentObject(value)) {\n const nested = this.#renderObjectEntries(value, depth + 1);\n if (nested) {\n lines.push(`${this.#pad(depth)}${key}:\\n${nested}`);\n } else {\n lines.push(`${this.#pad(depth)}${key}:`);\n }\n }\n }\n return lines.join('\\n');\n }\n\n protected renderFragment(\n fragment: ContextFragment,\n ctx: RenderContext,\n ): string {\n const { name, data } = fragment;\n if (this.isPrimitive(data)) {\n return `${this.#pad(ctx.depth)}${name}: ${this.#formatValue(data)}`;\n }\n if (isFragment(data)) {\n const child = this.renderFragment(data, {\n ...ctx,\n depth: ctx.depth + 1,\n });\n return `${this.#pad(ctx.depth)}${name}:\\n${child}`;\n }\n if (Array.isArray(data)) {\n return this.#renderArrayField(name, data, ctx.depth);\n }\n if (isFragmentObject(data)) {\n const entries = this.#renderObjectEntries(data, ctx.depth + 1);\n if (!entries) {\n return `${this.#pad(ctx.depth)}${name}:`;\n }\n return `${this.#pad(ctx.depth)}${name}:\\n${entries}`;\n }\n return `${this.#pad(ctx.depth)}${name}:`;\n }\n\n protected renderPrimitive(\n key: string,\n value: string,\n ctx: RenderContext,\n ): string {\n return `${this.#pad(ctx.depth)}${key}: ${this.#formatValue(value)}`;\n }\n\n protected renderArray(\n key: string,\n items: FragmentData[],\n ctx: RenderContext,\n ): string {\n return this.#renderArrayField(key, items, ctx.depth);\n }\n\n protected renderObject(\n key: string,\n obj: FragmentObject,\n ctx: RenderContext,\n ): string {\n const entries = this.#renderObjectEntries(obj, ctx.depth + 1);\n if (!entries) {\n return `${this.#pad(ctx.depth)}${key}:`;\n }\n return `${this.#pad(ctx.depth)}${key}:\\n${entries}`;\n }\n\n #pad(depth: number): string {\n return ' '.repeat(depth);\n }\n\n #needsQuoting(value: string): boolean {\n if (value === '') return true;\n if (value !== value.trim()) return true;\n if (['true', 'false', 'null'].includes(value.toLowerCase())) return true;\n if (/^-?\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?$/i.test(value)) return true;\n if (/[:\\\\\"'[\\]{}|,\\t\\n\\r]/.test(value)) return true;\n if (value.startsWith('-')) return true;\n return false;\n }\n\n #escape(value: string): string {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\t/g, '\\\\t');\n }\n\n #canonicalizeNumber(n: number): string {\n if (!Number.isFinite(n)) return 'null';\n if (Object.is(n, -0)) return '0';\n return String(n);\n }\n\n #formatValue(value: unknown): string {\n if (value === null) return 'null';\n if (typeof value === 'boolean') return String(value);\n if (typeof value === 'number') return this.#canonicalizeNumber(value);\n if (typeof value === 'string') {\n if (this.#needsQuoting(value)) {\n return `\"${this.#escape(value)}\"`;\n }\n return value;\n }\n // Fallback for objects/arrays in primitive context\n return `\"${this.#escape(JSON.stringify(value))}\"`;\n }\n}\n", "/**\n * Graph-based context store types and abstract interface.\n *\n * The storage model uses a DAG (Directed Acyclic Graph) for messages:\n * - Messages are immutable nodes with parentId forming the graph\n * - Branches are pointers to head (tip) messages\n * - Checkpoints are pointers to specific messages\n * - History is preserved through branching (rewind creates new branch)\n */\n\n// ============================================================================\n// Chat Types\n// ============================================================================\n\n/**\n * Data for creating/storing a chat.\n */\nexport interface ChatData {\n id: string;\n title?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Stored chat data returned from database (includes timestamps).\n */\nexport interface StoredChatData extends ChatData {\n createdAt: number;\n updatedAt: number;\n}\n\n/**\n * Information about a chat for listing.\n */\nexport interface ChatInfo {\n id: string;\n title?: string;\n messageCount: number;\n branchCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\n// ============================================================================\n// Message Types (Graph Nodes)\n// ============================================================================\n\n/**\n * Data for creating/storing a message (graph node).\n */\nexport interface MessageData {\n id: string;\n chatId: string;\n parentId: string | null; // null for root messages\n name: string; // 'user', 'assistant', 'role', 'hint', etc.\n type?: string; // 'message', 'fragment'\n data: unknown; // JSON-serializable content\n createdAt: number;\n}\n\n/**\n * Message with computed properties for listing.\n */\nexport interface MessageInfo extends MessageData {\n hasChildren: boolean;\n}\n\n// ============================================================================\n// Branch Types\n// ============================================================================\n\n/**\n * Data for creating/storing a branch.\n * A branch is a pointer to a head message in the graph.\n */\nexport interface BranchData {\n id: string;\n chatId: string;\n name: string; // 'main', 'alt-1', etc.\n headMessageId: string | null; // null if branch is empty\n isActive: boolean;\n createdAt: number;\n}\n\n/**\n * Information about a branch for listing.\n */\nexport interface BranchInfo {\n id: string;\n name: string;\n headMessageId: string | null;\n isActive: boolean;\n messageCount: number; // count of messages in this branch's chain\n createdAt: number;\n}\n\n// ============================================================================\n// Checkpoint Types\n// ============================================================================\n\n/**\n * Data for creating/storing a checkpoint.\n * A checkpoint is a pointer to a specific message in the graph.\n */\nexport interface CheckpointData {\n id: string;\n chatId: string;\n name: string;\n messageId: string;\n createdAt: number;\n}\n\n/**\n * Information about a checkpoint for listing.\n */\nexport interface CheckpointInfo {\n id: string;\n name: string;\n messageId: string;\n createdAt: number;\n}\n\n// ============================================================================\n// Search Types\n// ============================================================================\n\n/**\n * Options for searching messages.\n */\nexport interface SearchOptions {\n /** Only search in specific roles (e.g., ['user', 'assistant']) */\n roles?: string[];\n /** Maximum results to return (default: 20) */\n limit?: number;\n}\n\n/**\n * Search result with relevance ranking.\n */\nexport interface SearchResult {\n /** The matched message */\n message: MessageData;\n /** BM25 relevance score (lower = more relevant) */\n rank: number;\n /** Highlighted snippet with matched terms */\n snippet?: string;\n}\n\n// ============================================================================\n// Graph Visualization Types\n// ============================================================================\n\n/**\n * A node in the visualization graph.\n */\nexport interface GraphNode {\n id: string;\n parentId: string | null;\n role: string; // 'user', 'assistant', etc.\n content: string; // Truncated preview of message content\n createdAt: number;\n}\n\n/**\n * A branch pointer for visualization.\n */\nexport interface GraphBranch {\n name: string;\n headMessageId: string | null;\n isActive: boolean;\n}\n\n/**\n * A checkpoint pointer for visualization.\n */\nexport interface GraphCheckpoint {\n name: string;\n messageId: string;\n}\n\n/**\n * Complete graph data for visualization.\n */\nexport interface GraphData {\n chatId: string;\n nodes: GraphNode[];\n branches: GraphBranch[];\n checkpoints: GraphCheckpoint[];\n}\n\n// ============================================================================\n// Abstract Store Interface\n// ============================================================================\n\n/**\n * Abstract base class for graph-based context storage.\n *\n * Implementations provide persistence for the message graph, branches,\n * and checkpoints. The graph model enables:\n * - Branching: rewind creates a new branch, original stays intact\n * - Checkpoints: pointers to specific messages for easy restore\n * - No data loss: soft delete only, all history preserved\n */\nexport abstract class ContextStore {\n // ==========================================================================\n // Chat Operations\n // ==========================================================================\n\n /**\n * Create a new chat.\n */\n abstract createChat(chat: ChatData): Promise<void>;\n\n /**\n * Create a chat if it doesn't exist, or return existing one.\n * Returns the stored chat data with timestamps.\n */\n abstract upsertChat(chat: ChatData): Promise<StoredChatData>;\n\n /**\n * Get a chat by ID.\n */\n abstract getChat(chatId: string): Promise<StoredChatData | undefined>;\n\n /**\n * Update chat metadata.\n * Note: updatedAt is automatically managed by database triggers.\n * Returns the updated chat data.\n */\n abstract updateChat(\n chatId: string,\n updates: Partial<Pick<ChatData, 'title' | 'metadata'>>,\n ): Promise<StoredChatData>;\n\n /**\n * List all chats, sorted by updatedAt descending.\n */\n abstract listChats(): Promise<ChatInfo[]>;\n\n // ==========================================================================\n // Message Operations (Graph Nodes)\n // ==========================================================================\n\n /**\n * Add a message to the graph.\n */\n abstract addMessage(message: MessageData): Promise<void>;\n\n /**\n * Get a message by ID.\n */\n abstract getMessage(messageId: string): Promise<MessageData | undefined>;\n\n /**\n * Walk up the parent chain from a head message, returning messages in\n * chronological order (root first).\n */\n abstract getMessageChain(headId: string): Promise<MessageData[]>;\n\n /**\n * Check if a message has children (is a fork point).\n */\n abstract hasChildren(messageId: string): Promise<boolean>;\n\n // ==========================================================================\n // Branch Operations\n // ==========================================================================\n\n /**\n * Create a new branch.\n */\n abstract createBranch(branch: BranchData): Promise<void>;\n\n /**\n * Get a branch by chat ID and name.\n */\n abstract getBranch(\n chatId: string,\n name: string,\n ): Promise<BranchData | undefined>;\n\n /**\n * Get the active branch for a chat.\n */\n abstract getActiveBranch(chatId: string): Promise<BranchData | undefined>;\n\n /**\n * Set a branch as active (and deactivate others).\n */\n abstract setActiveBranch(chatId: string, branchId: string): Promise<void>;\n\n /**\n * Update a branch's head message.\n */\n abstract updateBranchHead(\n branchId: string,\n messageId: string | null,\n ): Promise<void>;\n\n /**\n * List all branches for a chat.\n */\n abstract listBranches(chatId: string): Promise<BranchInfo[]>;\n\n // ==========================================================================\n // Checkpoint Operations\n // ==========================================================================\n\n /**\n * Create a checkpoint.\n */\n abstract createCheckpoint(checkpoint: CheckpointData): Promise<void>;\n\n /**\n * Get a checkpoint by chat ID and name.\n */\n abstract getCheckpoint(\n chatId: string,\n name: string,\n ): Promise<CheckpointData | undefined>;\n\n /**\n * List all checkpoints for a chat.\n */\n abstract listCheckpoints(chatId: string): Promise<CheckpointInfo[]>;\n\n /**\n * Delete a checkpoint.\n */\n abstract deleteCheckpoint(chatId: string, name: string): Promise<void>;\n\n // ==========================================================================\n // Search Operations\n // ==========================================================================\n\n /**\n * Search messages using full-text search.\n *\n * @param chatId - The chat to search in\n * @param query - FTS5 query string (supports AND, OR, NOT, phrases, prefix*)\n * @param options - Search options\n * @returns Search results ordered by relevance (lower rank = more relevant)\n */\n abstract searchMessages(\n chatId: string,\n query: string,\n options?: SearchOptions,\n ): Promise<SearchResult[]>;\n\n // ==========================================================================\n // Visualization Operations\n // ==========================================================================\n\n /**\n * Get the complete graph data for a chat.\n * Returns all messages, branches, and checkpoints.\n */\n abstract getGraph(chatId: string): Promise<GraphData>;\n}\n", "import {\n type EstimateResult,\n type FragmentEstimate,\n getModelsRegistry,\n} from './estimate.ts';\nimport type { ContextFragment } from './fragments.ts';\nimport { isMessageFragment, message } from './fragments.ts';\nimport type { Models } from './models.generated.ts';\nimport {\n type ContextRenderer,\n XmlRenderer,\n} from './renderers/abstract.renderer.ts';\nimport {\n type BranchData,\n type BranchInfo,\n type ChatData,\n type CheckpointData,\n type CheckpointInfo,\n ContextStore,\n type GraphData,\n type MessageData,\n type StoredChatData,\n} from './store/store.ts';\n\n/**\n * Result of resolving context - ready for AI SDK consumption.\n */\nexport interface ResolveResult {\n /** Rendered non-message fragments for system prompt */\n systemPrompt: string;\n /** Message fragments decoded to AI SDK format */\n messages: unknown[];\n}\n\n/**\n * Options for resolve().\n */\nexport interface ResolveOptions {\n /** Renderer to use for system prompt (defaults to XmlRenderer) */\n renderer: ContextRenderer;\n}\n\n/**\n * Options for creating a ContextEngine.\n */\nexport interface ContextEngineOptions {\n /** Store for persisting fragments (required) */\n store: ContextStore;\n /** Unique identifier for this chat (required) */\n chatId: string;\n /** Branch name (defaults to 'main') */\n branch?: string;\n}\n\n/**\n * Metadata about a chat.\n */\nexport interface ChatMeta {\n /** Unique chat identifier */\n id: string;\n /** When the chat was created */\n createdAt: number;\n /** When the chat was last updated */\n updatedAt: number;\n /** Optional user-provided title */\n title?: string;\n /** Optional custom metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Options for context inspection.\n */\nexport interface InspectOptions {\n /** Model ID for cost estimation (required) */\n modelId: Models;\n /** Renderer for estimation (required) */\n renderer: ContextRenderer;\n}\n\n/**\n * Result of inspecting context state.\n * Provides a comprehensive JSON-serializable snapshot for debugging.\n */\nexport interface InspectResult {\n /** Token usage and cost estimation */\n estimate: EstimateResult;\n /** Rendered output using the provided renderer */\n rendered: string;\n /** Fragment structure breakdown */\n fragments: {\n /** Non-message fragments (role, hints, etc.) */\n context: ContextFragment[];\n /** Pending messages not yet saved to store */\n pending: ContextFragment[];\n /** Persisted messages from the store */\n persisted: MessageData[];\n };\n /** Conversation graph with branches and checkpoints */\n graph: GraphData;\n /** Inspection metadata */\n meta: {\n chatId: string;\n branch: string;\n timestamp: number;\n };\n}\n\n/**\n * Context engine for managing AI conversation context with graph-based storage.\n *\n * The engine uses a DAG (Directed Acyclic Graph) model for messages:\n * - Messages are immutable nodes with parentId forming the graph\n * - Branches are pointers to head (tip) messages\n * - Checkpoints are pointers to specific messages\n * - History is preserved through branching (rewind creates new branch)\n */\nexport class ContextEngine {\n /** Non-message fragments (role, hints, etc.) - not persisted in graph */\n #fragments: ContextFragment[] = [];\n /** Pending message fragments to be added to graph */\n #pendingMessages: ContextFragment[] = [];\n #store: ContextStore;\n #chatId: string;\n #branchName: string;\n #branch: BranchData | null = null;\n #chatData: StoredChatData | null = null;\n #initialized = false;\n\n constructor(options: ContextEngineOptions) {\n if (!options.chatId) {\n throw new Error('chatId is required');\n }\n this.#store = options.store;\n this.#chatId = options.chatId;\n this.#branchName = options.branch ?? 'main';\n }\n\n /**\n * Initialize the chat and branch if they don't exist.\n */\n async #ensureInitialized(): Promise<void> {\n if (this.#initialized) {\n return;\n }\n\n this.#chatData = await this.#store.upsertChat({ id: this.#chatId });\n\n const existingBranch = await this.#store.getBranch(\n this.#chatId,\n this.#branchName,\n );\n if (existingBranch) {\n this.#branch = existingBranch;\n } else {\n this.#branch = {\n id: crypto.randomUUID(),\n chatId: this.#chatId,\n name: this.#branchName,\n headMessageId: null,\n isActive: true,\n createdAt: Date.now(),\n };\n await this.#store.createBranch(this.#branch);\n }\n\n this.#initialized = true;\n }\n\n /**\n * Create a new branch from a specific message.\n * Shared logic between rewind() and btw().\n */\n async #createBranchFrom(\n messageId: string,\n switchTo: boolean,\n ): Promise<BranchInfo> {\n // Generate branch name based on same-prefix count (e.g., main-v2, main-v3)\n const branches = await this.#store.listBranches(this.#chatId);\n const samePrefix = branches.filter(\n (b) =>\n b.name === this.#branchName ||\n b.name.startsWith(`${this.#branchName}-v`),\n );\n const newBranchName = `${this.#branchName}-v${samePrefix.length + 1}`;\n\n // Create new branch pointing to the target message\n const newBranch: BranchData = {\n id: crypto.randomUUID(),\n chatId: this.#chatId,\n name: newBranchName,\n headMessageId: messageId,\n isActive: false,\n createdAt: Date.now(),\n };\n await this.#store.createBranch(newBranch);\n\n if (switchTo) {\n // Switch to the new branch\n await this.#store.setActiveBranch(this.#chatId, newBranch.id);\n this.#branch = { ...newBranch, isActive: true };\n this.#branchName = newBranchName;\n // Clear pending messages (they were for the old branch)\n this.#pendingMessages = [];\n }\n\n // Get message count for branch info\n const chain = await this.#store.getMessageChain(messageId);\n\n return {\n id: newBranch.id,\n name: newBranch.name,\n headMessageId: newBranch.headMessageId,\n isActive: switchTo,\n messageCount: chain.length,\n createdAt: newBranch.createdAt,\n };\n }\n\n /**\n * Get the current chat ID.\n */\n public get chatId(): string {\n return this.#chatId;\n }\n\n /**\n * Get the current branch name.\n */\n public get branch(): string {\n return this.#branchName;\n }\n\n /**\n * Get metadata for the current chat.\n * Returns null if the chat hasn't been initialized yet.\n */\n public get chat(): ChatMeta | null {\n if (!this.#chatData) {\n return null;\n }\n return {\n id: this.#chatData.id,\n createdAt: this.#chatData.createdAt,\n updatedAt: this.#chatData.updatedAt,\n title: this.#chatData.title,\n metadata: this.#chatData.metadata,\n };\n }\n\n /**\n * Add fragments to the context.\n *\n * - Message fragments (user/assistant) are queued for persistence\n * - Non-message fragments (role/hint) are kept in memory for system prompt\n */\n public set(...fragments: ContextFragment[]) {\n for (const fragment of fragments) {\n if (isMessageFragment(fragment)) {\n this.#pendingMessages.push(fragment);\n } else {\n this.#fragments.push(fragment);\n }\n }\n return this;\n }\n\n // Unset a fragment by ID (not implemented yet)\n public unset(fragmentId: string) {\n //\n }\n\n /**\n * Render all fragments using the provided renderer.\n * @internal Use resolve() instead for public API.\n */\n public render(renderer: ContextRenderer) {\n return renderer.render(this.#fragments);\n }\n\n /**\n * Resolve context into AI SDK-ready format.\n *\n * - Initializes chat and branch if needed\n * - Loads message history from the graph (walking parent chain)\n * - Separates context fragments for system prompt\n * - Combines with pending messages\n *\n * @example\n * ```ts\n * const context = new ContextEngine({ store, chatId: 'chat-1' })\n * .set(role('You are helpful'), user('Hello'));\n *\n * const { systemPrompt, messages } = await context.resolve();\n * await generateText({ system: systemPrompt, messages });\n * ```\n */\n public async resolve(options: ResolveOptions): Promise<ResolveResult> {\n await this.#ensureInitialized();\n\n const systemPrompt = options.renderer.render(this.#fragments);\n\n // Get persisted messages from graph\n const messages: unknown[] = [];\n if (this.#branch?.headMessageId) {\n const chain = await this.#store.getMessageChain(\n this.#branch.headMessageId,\n );\n\n for (const msg of chain) {\n messages.push(message(msg.data as never).codec?.decode());\n }\n }\n\n // Add pending messages (not yet saved)\n for (const fragment of this.#pendingMessages) {\n const decoded = fragment.codec!.decode();\n messages.push(decoded);\n }\n\n return { systemPrompt, messages };\n }\n\n /**\n * Save pending messages to the graph.\n *\n * Each message is added as a node with parentId pointing to the previous message.\n * The branch head is updated to point to the last message.\n *\n * @example\n * ```ts\n * context.set(user('Hello'));\n * // AI responds...\n * context.set(assistant('Hi there!'));\n * await context.save(); // Persist to graph\n * ```\n */\n public async save(): Promise<void> {\n await this.#ensureInitialized();\n\n if (this.#pendingMessages.length === 0) {\n return;\n }\n\n let parentId = this.#branch!.headMessageId;\n const now = Date.now();\n\n // Add each pending message to the graph\n for (const fragment of this.#pendingMessages) {\n const messageData: MessageData = {\n id: fragment.id ?? crypto.randomUUID(),\n chatId: this.#chatId,\n parentId,\n name: fragment.name,\n type: fragment.type,\n data: fragment.codec!.encode(),\n createdAt: now,\n };\n\n await this.#store.addMessage(messageData);\n parentId = messageData.id;\n }\n\n // Update branch head to last message\n await this.#store.updateBranchHead(this.#branch!.id, parentId);\n this.#branch!.headMessageId = parentId;\n\n // Clear pending messages\n this.#pendingMessages = [];\n }\n\n /**\n * Estimate token count and cost for the full context.\n *\n * Includes:\n * - System prompt fragments (role, hints, etc.)\n * - Persisted chat messages (from store)\n * - Pending messages (not yet saved)\n *\n * @param modelId - Model ID (e.g., \"openai:gpt-4o\", \"anthropic:claude-3-5-sonnet\")\n * @param options - Optional settings\n * @returns Estimate result with token counts, costs, and per-fragment breakdown\n */\n public async estimate(\n modelId: Models,\n options: {\n renderer?: ContextRenderer;\n } = {},\n ): Promise<EstimateResult> {\n await this.#ensureInitialized();\n\n const renderer = options.renderer ?? new XmlRenderer();\n const registry = getModelsRegistry();\n await registry.load();\n\n const model = registry.get(modelId);\n if (!model) {\n throw new Error(\n `Model \"${modelId}\" not found. Call load() first or check model ID.`,\n );\n }\n\n const tokenizer = registry.getTokenizer(modelId);\n const fragmentEstimates: FragmentEstimate[] = [];\n\n // 1. Estimate context fragments (system prompt)\n for (const fragment of this.#fragments) {\n const rendered = renderer.render([fragment]);\n const tokens = tokenizer.count(rendered);\n const cost = (tokens / 1_000_000) * model.cost.input;\n fragmentEstimates.push({\n id: fragment.id,\n name: fragment.name,\n tokens,\n cost,\n });\n }\n\n // 2. Estimate persisted messages from store\n if (this.#branch?.headMessageId) {\n const chain = await this.#store.getMessageChain(\n this.#branch.headMessageId,\n );\n for (const msg of chain) {\n const content = String(msg.data);\n const tokens = tokenizer.count(content);\n const cost = (tokens / 1_000_000) * model.cost.input;\n fragmentEstimates.push({\n name: msg.name,\n id: msg.id,\n tokens,\n cost,\n });\n }\n }\n\n // 3. Estimate pending messages (not yet saved)\n for (const fragment of this.#pendingMessages) {\n const content = String(fragment.data);\n const tokens = tokenizer.count(content);\n const cost = (tokens / 1_000_000) * model.cost.input;\n fragmentEstimates.push({\n name: fragment.name,\n id: fragment.id,\n tokens,\n cost,\n });\n }\n\n // Calculate totals\n const totalTokens = fragmentEstimates.reduce((sum, f) => sum + f.tokens, 0);\n const totalCost = fragmentEstimates.reduce((sum, f) => sum + f.cost, 0);\n\n return {\n model: model.id,\n provider: model.provider,\n tokens: totalTokens,\n cost: totalCost,\n limits: {\n context: model.limit.context,\n output: model.limit.output,\n exceedsContext: totalTokens > model.limit.context,\n },\n fragments: fragmentEstimates,\n };\n }\n\n /**\n * Rewind to a specific message by ID.\n *\n * Creates a new branch from that message, preserving the original branch.\n * The new branch becomes active.\n *\n * @param messageId - The message ID to rewind to\n * @returns The new branch info\n *\n * @example\n * ```ts\n * context.set(user('What is 2 + 2?', { id: 'q1' }));\n * context.set(assistant('The answer is 5.', { id: 'wrong' })); // Oops!\n * await context.save();\n *\n * // Rewind to the question, creates new branch\n * const newBranch = await context.rewind('q1');\n *\n * // Now add correct answer on new branch\n * context.set(assistant('The answer is 4.'));\n * await context.save();\n * ```\n */\n public async rewind(messageId: string): Promise<BranchInfo> {\n await this.#ensureInitialized();\n\n // Verify the message exists\n const message = await this.#store.getMessage(messageId);\n if (!message) {\n throw new Error(`Message \"${messageId}\" not found`);\n }\n if (message.chatId !== this.#chatId) {\n throw new Error(`Message \"${messageId}\" belongs to a different chat`);\n }\n\n return this.#createBranchFrom(messageId, true);\n }\n\n /**\n * Create a checkpoint at the current position.\n *\n * A checkpoint is a named pointer to the current branch head.\n * Use restore() to return to this point later.\n *\n * @param name - Name for the checkpoint\n * @returns The checkpoint info\n *\n * @example\n * ```ts\n * context.set(user('I want to learn a new skill.'));\n * context.set(assistant('Would you like coding or cooking?'));\n * await context.save();\n *\n * // Save checkpoint before user's choice\n * const cp = await context.checkpoint('before-choice');\n * ```\n */\n public async checkpoint(name: string): Promise<CheckpointInfo> {\n await this.#ensureInitialized();\n\n if (!this.#branch?.headMessageId) {\n throw new Error('Cannot create checkpoint: no messages in conversation');\n }\n\n const checkpoint: CheckpointData = {\n id: crypto.randomUUID(),\n chatId: this.#chatId,\n name,\n messageId: this.#branch.headMessageId,\n createdAt: Date.now(),\n };\n\n await this.#store.createCheckpoint(checkpoint);\n\n return {\n id: checkpoint.id,\n name: checkpoint.name,\n messageId: checkpoint.messageId,\n createdAt: checkpoint.createdAt,\n };\n }\n\n /**\n * Restore to a checkpoint by creating a new branch from that point.\n *\n * @param name - Name of the checkpoint to restore\n * @returns The new branch info\n *\n * @example\n * ```ts\n * // User chose cooking, but wants to try coding path\n * await context.restore('before-choice');\n *\n * context.set(user('I want to learn coding.'));\n * context.set(assistant('Python is a great starting language!'));\n * await context.save();\n * ```\n */\n public async restore(name: string): Promise<BranchInfo> {\n await this.#ensureInitialized();\n\n const checkpoint = await this.#store.getCheckpoint(this.#chatId, name);\n if (!checkpoint) {\n throw new Error(\n `Checkpoint \"${name}\" not found in chat \"${this.#chatId}\"`,\n );\n }\n\n // Rewind to the checkpoint's message\n return this.rewind(checkpoint.messageId);\n }\n\n /**\n * Switch to a different branch by name.\n *\n * @param name - Branch name to switch to\n *\n * @example\n * ```ts\n * // List branches (via store)\n * const branches = await store.listBranches(context.chatId);\n * console.log(branches); // [{name: 'main', ...}, {name: 'main-v2', ...}]\n *\n * // Switch to original branch\n * await context.switchBranch('main');\n * ```\n */\n public async switchBranch(name: string): Promise<void> {\n await this.#ensureInitialized();\n\n const branch = await this.#store.getBranch(this.#chatId, name);\n if (!branch) {\n throw new Error(`Branch \"${name}\" not found in chat \"${this.#chatId}\"`);\n }\n\n await this.#store.setActiveBranch(this.#chatId, branch.id);\n this.#branch = { ...branch, isActive: true };\n this.#branchName = name;\n\n // Clear pending messages (they were for the old branch)\n this.#pendingMessages = [];\n }\n\n /**\n * Create a parallel branch from the current position (\"by the way\").\n *\n * Use this when you want to fork the conversation without leaving\n * the current branch. Common use case: user wants to ask another\n * question while waiting for the model to respond.\n *\n * Unlike rewind(), this method:\n * - Uses the current HEAD (no messageId needed)\n * - Does NOT switch to the new branch\n * - Keeps pending messages intact\n *\n * @returns The new branch info (does not switch to it)\n * @throws Error if no messages exist in the conversation\n *\n * @example\n * ```ts\n * // User asked a question, model is generating...\n * context.set(user('What is the weather?'));\n * await context.save();\n *\n * // User wants to ask something else without waiting\n * const newBranch = await context.btw();\n * // newBranch = { name: 'main-v2', ... }\n *\n * // Later, switch to the new branch and add the question\n * await context.switchBranch(newBranch.name);\n * context.set(user('Also, what time is it?'));\n * await context.save();\n * ```\n */\n public async btw(): Promise<BranchInfo> {\n await this.#ensureInitialized();\n\n if (!this.#branch?.headMessageId) {\n throw new Error('Cannot create btw branch: no messages in conversation');\n }\n\n return this.#createBranchFrom(this.#branch.headMessageId, false);\n }\n\n /**\n * Update metadata for the current chat.\n *\n * @param updates - Partial metadata to merge (title, metadata)\n *\n * @example\n * ```ts\n * await context.updateChat({\n * title: 'Coding Help Session',\n * metadata: { tags: ['python', 'debugging'] }\n * });\n * ```\n */\n public async updateChat(\n updates: Partial<Pick<ChatMeta, 'title' | 'metadata'>>,\n ): Promise<void> {\n await this.#ensureInitialized();\n\n const storeUpdates: Partial<Pick<ChatData, 'title' | 'metadata'>> = {};\n\n if (updates.title !== undefined) {\n storeUpdates.title = updates.title;\n }\n if (updates.metadata !== undefined) {\n // Merge with existing metadata\n storeUpdates.metadata = {\n ...this.#chatData?.metadata,\n ...updates.metadata,\n };\n }\n\n this.#chatData = await this.#store.updateChat(this.#chatId, storeUpdates);\n }\n\n /**\n * Consolidate context fragments (no-op for now).\n *\n * This is a placeholder for future functionality that merges context fragments\n * using specific rules. Currently, it does nothing.\n *\n * @experimental\n */\n public consolidate(): void {\n return void 0;\n }\n\n /**\n * Inspect the full context state for debugging.\n * Returns a comprehensive JSON-serializable object with all context information.\n *\n * @param options - Inspection options (modelId and renderer required)\n * @returns Complete inspection data including estimates, rendered output, fragments, and graph\n *\n * @example\n * ```ts\n * const inspection = await context.inspect({\n * modelId: 'openai:gpt-4o',\n * renderer: new XmlRenderer(),\n * });\n * console.log(JSON.stringify(inspection, null, 2));\n *\n * // Or write to file for analysis\n * await fs.writeFile('context-debug.json', JSON.stringify(inspection, null, 2));\n * ```\n */\n public async inspect(options: InspectOptions): Promise<InspectResult> {\n await this.#ensureInitialized();\n\n const { renderer } = options;\n\n // Get token/cost estimation\n const estimateResult = await this.estimate(options.modelId, { renderer });\n\n // Render using provided renderer\n const rendered = renderer.render(this.#fragments);\n\n // Get persisted messages from store\n const persistedMessages: MessageData[] = [];\n if (this.#branch?.headMessageId) {\n const chain = await this.#store.getMessageChain(\n this.#branch.headMessageId,\n );\n persistedMessages.push(...chain);\n }\n\n // Get conversation graph\n const graph = await this.#store.getGraph(this.#chatId);\n\n return {\n estimate: estimateResult,\n rendered,\n fragments: {\n context: [...this.#fragments],\n pending: [...this.#pendingMessages],\n persisted: persistedMessages,\n },\n graph,\n meta: {\n chatId: this.#chatId,\n branch: this.#branchName,\n timestamp: Date.now(),\n },\n };\n }\n}\n", "import type { ContextFragment } from '../fragments.ts';\n\n/**\n * Domain knowledge fragment builders.\n *\n * These fragments capture domain-specific knowledge that can be injected\n * into AI prompts. Use with renderers (XML, Markdown, TOML, TOON) to format.\n *\n * @example\n * ```ts\n * import { term, hint, guardrail } from '@deepagents/context';\n *\n * context.set(\n * term('NPL', 'non-performing loan'),\n * hint('Always filter by status'),\n * guardrail({ rule: 'Never expose PII' }),\n * );\n * ```\n */\n\n/**\n * Define domain-specific vocabulary and business terminology.\n *\n * Use this to define simple, direct mappings between business terms and their meanings.\n * The system will understand these terms when users mention them in queries.\n *\n * @param name - The business term or acronym to define\n * @param definition - What the term means in your domain\n *\n * @example\n * // Logistics/Transportation dataset\n * term(\"deadhead miles\", \"distance driven with empty truck between deliveries\")\n * term(\"dwell time\", \"total time a truck spends at a loading dock or warehouse\")\n * term(\"LTL\", \"less than truckload - shipment that doesn't fill entire truck\")\n *\n * @example\n * // Education/University dataset\n * term(\"matriculation\", \"students who completed enrollment and started classes\")\n * term(\"DFW rate\", \"percentage of students receiving D, F, or Withdrawal in a course\")\n * term(\"cohort\", \"group of students who entered the same semester or academic year\")\n *\n * @example\n * // Finance/Banking dataset\n * term(\"NPL\", \"non-performing loan - loan past due 90+ days\")\n * term(\"basis points\", \"one hundredth of a percentage point (1% = 100 bps)\")\n * term(\"AUM\", \"assets under management - total market value of client investments\")\n */\nexport function term(name: string, definition: string): ContextFragment {\n return {\n name: 'term',\n data: { name, definition },\n };\n}\n\n/**\n * Define behavioral rules and constraints that should always apply.\n *\n * Use this for business logic, data quality rules, or query preferences that should\n * be automatically applied to all relevant queries.\n *\n * @param text - The rule or constraint to follow (use imperative language)\n *\n * @example\n * // Manufacturing/Supply Chain dataset\n * hint(\"Always exclude work orders with status = 'simulation' from production metrics\")\n * hint(\"When calculating OEE (overall equipment effectiveness), only count scheduled production time\")\n * hint(\"Defect rates should be calculated per batch, not per individual unit, for consistency\")\n *\n * @example\n * // Real Estate/Property dataset\n * hint(\"Never include properties with listing_status = 'draft' in market analysis\")\n * hint(\"Always filter out duplicate MLS listings - use the earliest listing_date for each property_id\")\n * hint(\"Square footage comparisons must specify if including or excluding basement/garage\")\n *\n * @example\n * // Social Media/Content Platform dataset\n * hint(\"Engagement metrics should exclude bot accounts identified by is_verified_human = false\")\n * hint(\"View counts reset daily - always use cumulative_views for historical analysis\")\n * hint(\"Default content filters to published_status = 'public' unless analyzing drafts\")\n */\nexport function hint(text: string): ContextFragment {\n return {\n name: 'hint',\n data: text,\n };\n}\n\n/**\n * Define hard guardrails, safety rules, and compliance boundaries.\n *\n * Use this for \"never do\" rules, sensitive data handling, and required behaviors when\n * certain conditions occur. Guardrails should be explicit and action-oriented.\n *\n * @param input.rule - The guardrail or restriction to enforce\n * @param input.reason - Why this guardrail exists (compliance, security, performance)\n * @param input.action - What to do when this guardrail is triggered\n *\n * @example\n * // Healthcare dataset\n * guardrail({\n * rule: \"Never return PHI like SSN, MRN, or full address in query results\",\n * reason: \"HIPAA compliance\",\n * action: \"If asked, state that identifiable patient data cannot be shared; offer de-identified aggregates instead\"\n * })\n *\n * @example\n * // Finance dataset\n * guardrail({\n * rule: \"Block any query exposing employee-level compensation by name\",\n * reason: \"Confidential payroll data\",\n * action: \"Provide ranges grouped by department or level instead of individual salaries\"\n * })\n *\n * @example\n * // E-commerce dataset\n * guardrail({\n * rule: \"Warn when a query would scan more than 10 million rows; require a narrower date range\",\n * reason: \"Performance and cost control\",\n * action: \"Ask the user to add filters (recent timeframe, specific categories) before proceeding\"\n * })\n */\nexport function guardrail(input: {\n rule: string;\n reason?: string;\n action?: string;\n}): ContextFragment {\n return {\n name: 'guardrail',\n data: {\n rule: input.rule,\n ...(input.reason && { reason: input.reason }),\n ...(input.action && { action: input.action }),\n },\n };\n}\n\n/**\n * Define a rich understanding of a single concept using metaphors and explanations.\n *\n * Use this when a simple term definition isn't enough - when you need to convey deeper\n * understanding about how to think about and calculate a metric or concept.\n *\n * @param input.concept - The concept being explained\n * @param input.explanation - A metaphor or detailed explanation\n * @param input.therefore - Optional actionable instruction based on this understanding\n *\n * @example\n * // Gaming/Entertainment dataset\n * explain({\n * concept: \"daily active users to monthly active users ratio\",\n * explanation: \"like measuring how many club members visit daily vs just once a month - shows stickiness\",\n * therefore: \"Calculate as DAU / MAU, where higher ratio (closer to 1) means more engaged user base\"\n * })\n *\n * @example\n * // HR/Employee Management dataset\n * explain({\n * concept: \"time to fill\",\n * explanation: \"like measuring how long a house sits on the market - from posting job to accepting offer\",\n * therefore: \"Calculate as days between job_posted_date and offer_accepted_date, exclude cancelled requisitions\"\n * })\n *\n * @example\n * // Telecommunications dataset\n * explain({\n * concept: \"network congestion ratio\",\n * explanation: \"like rush hour traffic density - measures actual usage vs total capacity at peak times\",\n * therefore: \"Calculate as (peak_hour_bandwidth_used / total_bandwidth_capacity) during busiest hour of day\"\n * })\n */\nexport function explain(input: {\n concept: string;\n explanation: string;\n therefore?: string;\n}): ContextFragment {\n return {\n name: 'explain',\n data: {\n concept: input.concept,\n explanation: input.explanation,\n ...(input.therefore && { therefore: input.therefore }),\n },\n };\n}\n\n/**\n * Define concrete examples of question \u2192 answer pairs.\n *\n * Use this for few-shot learning - show the system exactly how to translate\n * specific types of questions. Great for establishing patterns.\n *\n * @param input.question - The natural language question or request\n * @param input.answer - The correct answer that responds to the question\n * @param input.note - Optional note or explanation about the example\n *\n * @example\n * // Energy/Utilities dataset\n * example({\n * question: \"show me peak demand hours for the last week\",\n * answer: \"SELECT DATE_TRUNC('hour', reading_timestamp) as hour, MAX(consumption_kwh) as peak_demand FROM meter_readings WHERE reading_timestamp >= CURRENT_DATE - INTERVAL '7 days' GROUP BY hour ORDER BY peak_demand DESC LIMIT 10\"\n * })\n *\n * @example\n * // Agriculture/Farm Management dataset\n * example({\n * question: \"what is the average yield per acre by crop type this season\",\n * answer: \"SELECT crop_type, AVG(harvest_quantity / field_acres) as yield_per_acre FROM harvests WHERE harvest_date >= '2024-01-01' GROUP BY crop_type ORDER BY yield_per_acre DESC\"\n * })\n *\n * @example\n * // Travel/Hospitality dataset\n * example({\n * question: \"show me hotel occupancy rate for this month\",\n * answer: \"SELECT hotel_name, (SUM(occupied_rooms) / SUM(total_rooms)) * 100 as occupancy_rate FROM daily_occupancy WHERE date >= DATE_TRUNC('month', CURRENT_DATE) GROUP BY hotel_id, hotel_name ORDER BY occupancy_rate DESC\",\n * note: \"Occupancy rate is a percentage - multiply by 100 for readable output\"\n * })\n */\nexport function example(input: {\n question: string;\n answer: string;\n note?: string;\n}): ContextFragment {\n return {\n name: 'example',\n data: {\n question: input.question,\n answer: input.answer,\n ...(input.note && { note: input.note }),\n },\n };\n}\n\n/**\n * Define when and what to ask for clarification.\n *\n * Use this to handle ambiguous terms or situations where the system should\n * proactively ask the user for more information.\n *\n * @param input.when - The condition or trigger that should prompt clarification\n * @param input.ask - The question to ask the user\n * @param input.reason - Why this clarification is necessary\n *\n * @example\n * // Marketing/Advertising dataset\n * clarification({\n * when: \"user asks for 'conversion rate'\",\n * ask: \"Which conversion: click-to-lead, lead-to-opportunity, or opportunity-to-customer?\",\n * reason: \"Conversion rate means different things at each funnel stage - need to specify which metric\"\n * })\n *\n * @example\n * // Food Delivery dataset\n * clarification({\n * when: \"user asks about 'delivery time'\",\n * ask: \"Do you mean estimated time at order, actual delivery time, or time from kitchen to door?\",\n * reason: \"Multiple time metrics exist - estimated vs actual impacts customer satisfaction differently\"\n * })\n *\n * @example\n * // Fitness/Gym Management dataset\n * clarification({\n * when: \"user mentions 'active members'\",\n * ask: \"Do you mean paid memberships or members who actually visited in last 30 days?\",\n * reason: \"Many paid members don't use facilities - different metrics for revenue vs utilization\"\n * })\n */\nexport function clarification(input: {\n when: string;\n ask: string;\n reason: string;\n}): ContextFragment {\n return {\n name: 'clarification',\n data: {\n when: input.when,\n ask: input.ask,\n reason: input.reason,\n },\n };\n}\n\n/**\n * Define multi-step analytical processes that require sequential logic.\n *\n * Use this for complex analytical tasks that require multiple steps or specific\n * methodologies. Workflows teach the system HOW to approach a type of analysis.\n *\n * @param input.task - Name of the analytical task\n * @param input.steps - Sequential steps to execute\n * @param input.triggers - Optional phrases that should activate this workflow\n * @param input.notes - Optional additional context, warnings, or guidance\n *\n * @example\n * // Insurance dataset\n * workflow({\n * task: \"Claims Loss Ratio Analysis\",\n * triggers: [\"loss ratio\", \"claims ratio\", \"underwriting performance\"],\n * steps: [\n * \"Calculate total claims paid for each policy period\",\n * \"Calculate total premiums earned for same period\",\n * \"Compute loss ratio as (claims_paid / premiums_earned) * 100\",\n * \"Segment by policy type, geography, and underwriter\",\n * \"Identify policies with loss ratio > 100% (losing money)\",\n * \"Calculate trend over time using rolling 12-month windows\"\n * ],\n * notes: \"Use incurred date for claims, not paid date. Exclude reinsurance recoveries from claims total.\"\n * })\n *\n * @example\n * // Media/Publishing dataset\n * workflow({\n * task: \"Content Performance Funnel\",\n * triggers: [\"content funnel\", \"engagement funnel\", \"content performance\"],\n * steps: [\n * \"Count total impressions (articles shown) per content piece\",\n * \"Count click-throughs (articles opened)\",\n * \"Count scroll depth > 50% (meaningful engagement)\",\n * \"Count shares, comments, or saves (viral actions)\",\n * \"Calculate conversion rate at each funnel stage\",\n * \"Identify top-performing content by final conversion rate\"\n * ],\n * notes: \"Requires multiple event types. Join events table multiple times or use conditional aggregation.\"\n * })\n *\n * @example\n * // Sports Analytics dataset\n * workflow({\n * task: \"Player Performance Rating Calculation\",\n * triggers: [\"player rating\", \"performance score\", \"player analytics\"],\n * steps: [\n * \"Aggregate per-game stats: points, assists, rebounds, turnovers\",\n * \"Calculate efficiency metrics: shooting percentage, plus/minus\",\n * \"Normalize each metric using z-scores vs league average\",\n * \"Apply position-specific weights to each metric\",\n * \"Combine weighted scores into overall performance rating (0-100)\",\n * \"Rank players within position group and overall\"\n * ],\n * notes: \"Requires league-wide statistics for normalization. Update weights each season based on game trends.\"\n * })\n */\nexport function workflow(input: {\n task: string;\n steps: string[];\n triggers?: string[];\n notes?: string;\n}): ContextFragment {\n return {\n name: 'workflow',\n data: {\n task: input.task,\n steps: input.steps,\n ...(input.triggers?.length && { triggers: input.triggers }),\n ...(input.notes && { notes: input.notes }),\n },\n };\n}\n\n/**\n * Define data quirks, edge cases, or database-specific issues and their workarounds.\n *\n * Use this to document weird data patterns, database limitations, or special handling\n * required for specific scenarios.\n *\n * @param input.issue - Description of the quirk, edge case, or problem\n * @param input.workaround - How to handle or work around this issue\n *\n * @example\n * // Government/Public Services dataset\n * quirk({\n * issue: \"Citizen IDs contain leading zeros but are stored as integers, losing the zeros\",\n * workaround: \"Always cast to VARCHAR and use LPAD(citizen_id::VARCHAR, 10, '0') to restore leading zeros\"\n * })\n *\n * @example\n * // Aviation dataset\n * quirk({\n * issue: \"Flight times crossing midnight show as negative duration (landing before takeoff)\",\n * workaround: \"Add 24 hours when calculated duration < 0: CASE WHEN duration < 0 THEN duration + INTERVAL '24 hours' ELSE duration END\"\n * })\n *\n * @example\n * // Automotive/Dealership dataset\n * quirk({\n * issue: \"VIN numbers with letter 'O' were incorrectly entered as zero '0' in legacy data\",\n * workaround: \"When searching by VIN, use REPLACE(vin, '0', 'O') or fuzzy matching to handle both cases\"\n * })\n */\nexport function quirk(input: {\n issue: string;\n workaround: string;\n}): ContextFragment {\n return {\n name: 'quirk',\n data: {\n issue: input.issue,\n workaround: input.workaround,\n },\n };\n}\n\n/**\n * Define style preferences and coding standards.\n *\n * Use this to enforce consistent formatting, naming conventions, and best practices\n * specific to your team or organization.\n *\n * @param input.prefer - Preferred style or pattern\n * @param input.never - Optional anti-pattern to avoid\n * @param input.always - Optional rule that must always be followed\n *\n * @example\n * // Non-profit/Charity dataset\n * styleGuide({\n * prefer: \"Use donor-centric language in column aliases: 'donor_name' not 'customer_name'\",\n * never: \"Never expose internal donor IDs in external reports - use public gift IDs\",\n * always: \"Always include fiscal year in date-based aggregations (FY starts July 1)\"\n * })\n *\n * @example\n * // Legal/Law Firm dataset\n * styleGuide({\n * prefer: \"Use billable_hours with 2 decimal precision for accurate client billing\",\n * never: \"Never include attorney_rate in queries visible to paralegals - confidential data\",\n * always: \"Always filter by matter_status = 'open' unless specifically analyzing closed cases\"\n * })\n *\n * @example\n * // Inventory/Warehouse dataset\n * styleGuide({\n * prefer: \"Use location_id in joins rather than location_name (duplicates exist across warehouses)\",\n * never: \"Never aggregate inventory without grouping by warehouse_id first\",\n * always: \"Always use inventory_on_hand - inventory_reserved for available stock calculations\"\n * })\n */\nexport function styleGuide(input: {\n prefer: string;\n never?: string;\n always?: string;\n}): ContextFragment {\n return {\n name: 'styleGuide',\n data: {\n prefer: input.prefer,\n ...(input.never && { never: input.never }),\n ...(input.always && { always: input.always }),\n },\n };\n}\n\n/**\n * Define comparisons between related concepts through real-world analogies.\n *\n * Use this to teach relational understanding between concepts by drawing comparisons\n * to familiar real-world scenarios.\n *\n * @param input.concepts - Array of related concepts to compare\n * @param input.relationship - The comparison/analogy using real-world examples\n * @param input.insight - Optional key insight the analogy reveals\n * @param input.therefore - Optional actionable instruction\n * @param input.pitfall - Optional common mistake to avoid\n *\n * @example\n * // E-commerce dataset\n * analogy({\n * concepts: [\"cart abandonment\", \"browse abandonment\"],\n * relationship: \"Cart abandonment is like leaving items at a checkout counter, browse abandonment is like window shopping without picking anything up\",\n * insight: \"Cart abandonment shows purchase intent (added to cart), browse abandonment shows only interest\",\n * therefore: \"Prioritize cart abandonment recovery campaigns - higher conversion potential than browse\",\n * pitfall: \"Don't combine both into generic 'abandonment rate' - they need different marketing strategies\"\n * })\n *\n * @example\n * // SaaS dataset\n * analogy({\n * concepts: [\"logo churn\", \"revenue churn\"],\n * relationship: \"Logo churn is like counting how many customers left the store, revenue churn is how much money walked out\",\n * insight: \"Losing 10 small customers (high logo churn) might hurt less than losing 1 enterprise customer (high revenue churn)\",\n * therefore: \"Always report both metrics - logo churn for customer satisfaction, revenue churn for financial health\",\n * pitfall: \"Don't use logo churn to predict revenue impact - customer size distribution matters\"\n * })\n *\n * @example\n * // Healthcare dataset\n * analogy({\n * concepts: [\"incidence\", \"prevalence\"],\n * relationship: \"Incidence is like new house sales this month, prevalence is total houses currently occupied\",\n * insight: \"Incidence measures new cases over time, prevalence measures all existing cases at a point in time\",\n * therefore: \"For tracking disease outbreaks use incidence rate, for resource planning use prevalence\",\n * pitfall: \"Don't sum incidence rates across time periods - it's a rate not a count\"\n * })\n */\nexport function analogy(input: {\n concepts: string[];\n relationship: string;\n insight?: string;\n therefore?: string;\n pitfall?: string;\n}): ContextFragment {\n return {\n name: 'analogy',\n data: {\n concepts: input.concepts,\n relationship: input.relationship,\n ...(input.insight && { insight: input.insight }),\n ...(input.therefore && { therefore: input.therefore }),\n ...(input.pitfall && { pitfall: input.pitfall }),\n },\n };\n}\n\n/**\n * Map business terms directly to expressions or fragments.\n *\n * Use this to teach the system how to CALCULATE or QUERY specific business concepts.\n * The system will substitute these patterns when users mention the term.\n *\n * **Glossary vs Alias:**\n * - `alias` = user vocabulary \u2192 table/column name (\"the big table\" \u2192 \"orders table\")\n * - `glossary` = business term \u2192 SQL expression (\"revenue\" \u2192 \"SUM(orders.total_amount)\")\n *\n * In short: alias renames, glossary computes.\n *\n * @param entries - Record mapping business terms to their expressions\n *\n * @example\n * glossary({\n * \"revenue\": \"SUM(orders.total_amount)\",\n * \"average order value\": \"AVG(orders.total_amount)\",\n * \"active user\": \"last_login > NOW() - INTERVAL '30 days'\",\n * \"churned\": \"status = 'churned'\",\n * \"power user\": \"order_count > 10\",\n * \"net revenue\": \"SUM(orders.total_amount) - SUM(refunds.amount)\",\n * })\n */\nexport function glossary(entries: Record<string, string>): ContextFragment {\n return {\n name: 'glossary',\n data: Object.entries(entries).map(([term, expression]) => ({\n term,\n expression,\n })),\n };\n}\n", "import type { ContextFragment } from '../fragments.ts';\n\n/**\n * User-specific fragment builders.\n *\n * These fragments capture user context, preferences, and personalization data\n * that can be injected into AI prompts to tailor responses.\n *\n * @example\n * ```ts\n * import { identity, persona, preference } from '@deepagents/context';\n *\n * context.set(\n * identity({ name: 'John', role: 'VP of Sales' }),\n * persona({ name: 'Freya', role: 'Data Assistant', tone: 'professional' }),\n * preference('date format', 'YYYY-MM-DD'),\n * );\n * ```\n */\n\n/**\n * Define the user's identity including name and/or role.\n *\n * Use this to capture who the user is and what lens they view data through.\n * Helps tailor explanations, terminology, and focus areas.\n *\n * @param input.name - The user's name (optional)\n * @param input.role - The user's role or position (optional)\n *\n * @example\n * identity({ name: \"John\", role: \"VP of Sales\" })\n * identity({ role: \"Data analyst in the marketing team\" })\n * identity({ name: \"Sarah\" })\n * identity({ role: \"Finance manager focused on cost optimization\" })\n */\nexport function identity(input: {\n name?: string;\n role?: string;\n}): ContextFragment {\n return {\n name: 'identity',\n data: {\n ...(input.name && { name: input.name }),\n ...(input.role && { role: input.role }),\n },\n };\n}\n\n/**\n * Define an AI persona with a name, role, and communication tone.\n *\n * Use this to customize the assistant's personality and how it communicates.\n * The persona influences the style and approach of responses.\n *\n * @param input.name - The persona's name\n * @param input.role - The persona's role or expertise\n * @param input.tone - The communication style (e.g., friendly, professional, concise)\n *\n * @example\n * persona({ name: \"DataBot\", role: \"SQL Expert\", tone: \"friendly and encouraging\" })\n * persona({ name: \"QueryMaster\", role: \"Database Analyst\", tone: \"professional and concise\" })\n * persona({ name: \"SQLHelper\", role: \"Data Assistant\", tone: \"casual and approachable\" })\n */\nexport function persona(input: {\n name: string;\n role: string;\n tone?: string;\n}): ContextFragment {\n return {\n name: 'persona',\n data: {\n name: input.name,\n role: input.role,\n ...(input.tone && { tone: input.tone }),\n },\n };\n}\n\n/**\n * Define user-specific term meanings and vocabulary.\n *\n * Use this when the user has their own definitions for terms that might\n * differ from standard or domain definitions. Like `term()` but personal.\n *\n * @param term - The term the user uses\n * @param meaning - What the user means by this term\n *\n * @example\n * alias(\"revenue\", \"gross revenue before deductions, not net\")\n * alias(\"active users\", \"users who logged in within the last 30 days\")\n * alias(\"the big table\", \"the orders table\")\n * alias(\"Q4\", \"October through December, not fiscal Q4\")\n */\nexport function alias(term: string, meaning: string): ContextFragment {\n return {\n name: 'alias',\n data: { term, meaning },\n };\n}\n\n/**\n * Define how the user prefers results presented.\n *\n * Use this to capture output formatting, style, and behavioral preferences\n * that should apply to all interactions with this user.\n *\n * @param aspect - What aspect of output this preference applies to\n * @param value - The user's preference\n *\n * @example\n * preference(\"date format\", \"YYYY-MM-DD\")\n * preference(\"output style\", \"tables over charts unless trend data\")\n * preference(\"detail level\", \"always show the SQL query in responses\")\n * preference(\"row limit\", \"default to 50 rows unless I ask for more\")\n * preference(\"explanation style\", \"brief and to the point\")\n */\nexport function preference(aspect: string, value: string): ContextFragment {\n return {\n name: 'preference',\n data: { aspect, value },\n };\n}\n\n/**\n * Define the user's current working focus or project.\n *\n * Use this to capture temporary context that helps inform defaults,\n * assumptions, and suggestions. Should be updated as focus changes.\n *\n * @param description - What the user is currently working on\n *\n * @example\n * userContext(\"Preparing Q4 board presentation\")\n * userContext(\"Investigating drop in signups last week\")\n * userContext(\"Working on EMEA regional analysis for strategy meeting\")\n * userContext(\"Debugging discrepancy in revenue numbers\")\n */\nexport function userContext(description: string): ContextFragment {\n return {\n name: 'userContext',\n data: description,\n };\n}\n\n/**\n * Record a correction the user made to previous understanding.\n *\n * Use this when the user corrects a misunderstanding about data, columns,\n * or business logic. Prevents repeating the same mistake.\n *\n * @param subject - What was misunderstood\n * @param clarification - The correct understanding\n *\n * @example\n * correction(\"status column\", \"1 = active, 0 = inactive, not boolean true/false\")\n * correction(\"orders table\", \"Use orders_v2, not the deprecated legacy_orders table\")\n * correction(\"date field\", \"order_date is when order was placed, ship_date is when shipped\")\n * correction(\"revenue calculation\", \"Must exclude refunds and chargebacks\")\n */\nexport function correction(\n subject: string,\n clarification: string,\n): ContextFragment {\n return {\n name: 'correction',\n data: { subject, clarification },\n };\n}\n", "/**\n * Guardrail system for real-time stream interception and self-correction.\n *\n * Guardrails inspect streaming parts and can either:\n * - `pass(part)`: Allow the part through (optionally modified)\n * - `fail(feedback)`: Abort the stream and retry with self-correction feedback\n *\n * When a guardrail fails, the accumulated text is combined with the feedback\n * to create a \"self-correction\" that appears as if the agent caught itself.\n *\n * @example\n * ```typescript\n * const safetyGuardrail: Guardrail = {\n * id: 'safety',\n * name: 'Safety Filter',\n * handle: (part, context) => {\n * if (part.type === 'text-delta' && part.delta.includes('unsafe')) {\n * return fail('I should not provide this information. Let me help differently.');\n * }\n * if (part.type === 'error' && context.availableTools.length > 0) {\n * return fail(`Try using: ${context.availableTools.join(', ')}`);\n * }\n * return pass(part);\n * },\n * };\n *\n * const agent = agent({\n * name: 'safe_assistant',\n * context,\n * model,\n * guardrails: [safetyGuardrail],\n * });\n * ```\n */\nimport type { InferUIMessageChunk, UIDataTypes, UIMessage } from 'ai';\n\n/**\n * Type alias for stream parts from the AI SDK's UI message stream.\n * This is the full chunk type that includes text-delta, error, reasoning-delta, etc.\n */\nexport type StreamPart = InferUIMessageChunk<\n UIMessage<unknown, UIDataTypes, Record<string, never>>\n>;\n\n/**\n * Result of a guardrail check.\n * - `pass`: The part is allowed through (optionally modified)\n * - `fail`: The stream should abort and retry with feedback\n */\nexport type GuardrailResult =\n | { type: 'pass'; part: StreamPart }\n | { type: 'fail'; feedback: string };\n\n/**\n * Context passed to guardrails during stream processing.\n * Provides information about the agent's capabilities.\n */\nexport interface GuardrailContext {\n /** Names of tools available to the agent */\n availableTools: string[];\n}\n\n/**\n * A guardrail that inspects streaming parts.\n */\nexport interface Guardrail {\n /** Unique identifier for this guardrail */\n id: string;\n /** Human-readable name for logging/debugging */\n name: string;\n /**\n * Handle a stream part.\n *\n * @param part - The full stream part to inspect (text-delta, error, etc.)\n * @param context - Context with agent capabilities (available tools, etc.)\n * @returns Either `pass(part)` to allow or `fail(feedback)` to abort and retry\n */\n handle: (part: StreamPart, context: GuardrailContext) => GuardrailResult;\n}\n\n/**\n * Configuration for guardrail behavior.\n */\nexport interface GuardrailConfig {\n /** Maximum number of retry attempts when guardrails fail (default: 3) */\n maxRetries?: number;\n}\n\n/**\n * Allow a part to pass through the guardrail.\n *\n * @param part - The part to pass (can be modified from original)\n * @returns A pass result\n *\n * @example\n * ```typescript\n * handle: (part) => {\n * // Pass through unchanged\n * return pass(part);\n *\n * // Or modify text-delta before passing\n * if (part.type === 'text-delta') {\n * return pass({ ...part, delta: part.delta.replace('bad', 'good') });\n * }\n * return pass(part);\n * }\n * ```\n */\nexport function pass(part: StreamPart): GuardrailResult {\n return { type: 'pass', part };\n}\n\n/**\n * Fail the guardrail check and trigger a retry with feedback.\n *\n * The feedback will be appended to the accumulated assistant text,\n * making it appear as if the agent \"caught itself\" and self-corrected.\n *\n * @param feedback - The self-correction feedback to append\n * @returns A fail result\n *\n * @example\n * ```typescript\n * handle: (part) => {\n * if (part.type === 'text-delta' && part.delta.includes('hack')) {\n * return fail('I should not provide hacking instructions. Let me suggest ethical alternatives.');\n * }\n * if (part.type === 'error') {\n * return fail('An error occurred. Let me try a different approach.');\n * }\n * return pass(part);\n * }\n * ```\n */\nexport function fail(feedback: string): GuardrailResult {\n return { type: 'fail', feedback };\n}\n\n/**\n * Run a part through a chain of guardrails sequentially.\n *\n * @param part - The stream part to check\n * @param guardrails - Array of guardrails to run in order\n * @param context - Context with agent capabilities (available tools, etc.)\n * @returns The final result after all guardrails pass, or the first failure\n */\nexport function runGuardrailChain(\n part: StreamPart,\n guardrails: Guardrail[],\n context: GuardrailContext,\n): GuardrailResult {\n let currentPart = part;\n\n for (const guardrail of guardrails) {\n const result = guardrail.handle(currentPart, context);\n\n if (result.type === 'fail') {\n return result;\n }\n\n // Pass the (possibly modified) part to the next guardrail\n currentPart = result.part;\n }\n\n return pass(currentPart);\n}\n", "import { defineCommand, type CustomCommand } from 'just-bash';\nimport spawn from 'nano-spawn';\nimport * as path from 'path';\nimport { existsSync } from 'fs';\n\nexport interface BinaryBridgeConfig {\n /** Command name in the sandbox (what the agent types) */\n name: string;\n /** Actual binary path on the host system (defaults to name) */\n binaryPath?: string;\n /** Optional regex to restrict allowed arguments for security */\n allowedArgs?: RegExp;\n}\n\nexport type BinaryBridgeInput = string | BinaryBridgeConfig;\n\n/**\n * Creates custom commands that bridge to real system binaries.\n *\n * This allows just-bash sandboxed environments to execute specific\n * host system binaries while maintaining control over which binaries\n * are accessible.\n *\n * @example\n * // Simple - just strings (name === binaryPath)\n * createBinaryBridges('presenterm', 'node', 'cargo')\n *\n * @example\n * // Mixed - strings and config objects\n * createBinaryBridges(\n * 'presenterm',\n * { name: 'python', binaryPath: 'python3' },\n * { name: 'git', allowedArgs: /^(status|log|diff)/ }\n * )\n */\nexport function createBinaryBridges(\n ...binaries: BinaryBridgeInput[]\n): CustomCommand[] {\n return binaries.map((input) => {\n const config: BinaryBridgeConfig =\n typeof input === 'string' ? { name: input } : input;\n\n const { name, binaryPath = name, allowedArgs } = config;\n\n return defineCommand(name, async (args, ctx) => {\n // Validate args against pattern if specified\n if (allowedArgs) {\n const invalidArg = args.find((arg) => !allowedArgs.test(arg));\n if (invalidArg) {\n return {\n stdout: '',\n stderr: `${name}: argument '${invalidArg}' not allowed by security policy`,\n exitCode: 1,\n };\n }\n }\n\n try {\n // Resolve the real working directory from the virtual filesystem\n // just-bash uses virtual paths like /home/user, we need the real host path\n const realCwd = resolveRealCwd(ctx);\n\n // Resolve file paths in arguments relative to the real cwd\n const resolvedArgs = args.map((arg) => {\n // Skip flags and options\n if (arg.startsWith('-')) {\n return arg;\n }\n\n // Check if arg looks like a path:\n // 1. Has a file extension (e.g., file.md, script.py)\n // 2. Contains path separator (e.g., src/file, dir\\file)\n // 3. Is a relative path starting with . (e.g., ., .., ./foo)\n const hasExtension = path.extname(arg) !== '';\n const hasPathSep = arg.includes(path.sep) || arg.includes('/');\n const isRelative = arg.startsWith('.');\n\n if (hasExtension || hasPathSep || isRelative) {\n // Resolve relative to the real cwd\n return path.resolve(realCwd, arg);\n }\n\n return arg;\n });\n\n // Merge environments but preserve process.env.PATH for binary resolution\n // ctx.env.PATH is the virtual PATH (/bin:/usr/bin) which doesn't include host binaries\n const mergedEnv = {\n ...process.env,\n ...ctx.env,\n PATH: process.env.PATH, // Always use host PATH for binary bridges\n };\n\n const result = await spawn(binaryPath, resolvedArgs, {\n cwd: realCwd,\n env: mergedEnv,\n });\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: 0,\n };\n } catch (error) {\n // nano-spawn throws SubprocessError for non-zero exits\n if (error && typeof error === 'object' && 'exitCode' in error) {\n const subprocessError = error as {\n exitCode?: number;\n stdout: string;\n stderr: string;\n };\n return {\n stdout: subprocessError.stdout ?? '',\n stderr: subprocessError.stderr ?? '',\n exitCode: subprocessError.exitCode ?? 1,\n };\n }\n\n // Unknown error (e.g., binary not found)\n return {\n stdout: '',\n stderr: `${name}: ${error instanceof Error ? error.message : String(error)}`,\n exitCode: 127,\n };\n }\n });\n });\n}\n\n/**\n * Resolves the real filesystem path from a just-bash virtual path.\n *\n * just-bash filesystems (ReadWriteFs, OverlayFs) use virtual paths like /home/user\n * but we need the actual host filesystem path for spawning processes.\n */\nfunction resolveRealCwd(ctx: {\n cwd: string;\n fs: unknown;\n}): string {\n const fs = ctx.fs as {\n toRealPath?: (p: string) => string | null;\n root?: string;\n getMountPoint?: () => string;\n };\n\n let realCwd: string;\n\n if (fs.root) {\n // ReadWriteFs - virtual paths are relative to root\n // e.g., root=/Users/x/project, cwd=/ -> /Users/x/project\n realCwd = path.join(fs.root, ctx.cwd);\n } else if (typeof fs.getMountPoint === 'function' && typeof fs.toRealPath === 'function') {\n // OverlayFs - use toRealPath for proper path mapping\n const real = fs.toRealPath(ctx.cwd);\n realCwd = real ?? process.cwd();\n } else {\n // Fallback for InMemoryFs or unknown filesystems\n realCwd = process.cwd();\n }\n\n // Verify the path exists, fall back to process.cwd() if not\n if (!existsSync(realCwd)) {\n realCwd = process.cwd();\n }\n\n return realCwd;\n}\n", "import { type CommandResult, type Sandbox } from 'bash-tool';\nimport spawn from 'nano-spawn';\nimport { createHash } from 'node:crypto';\nimport { existsSync, readFileSync } from 'node:fs';\n\n// Re-export types from bash-tool for convenience\nexport type { CommandResult as ExecResult, Sandbox } from 'bash-tool';\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Error Classes\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Base error for all Docker sandbox operations.\n */\nexport class DockerSandboxError extends Error {\n readonly containerId?: string;\n\n constructor(message: string, containerId?: string) {\n super(message);\n this.name = 'DockerSandboxError';\n this.containerId = containerId;\n }\n}\n\n/**\n * Thrown when Docker daemon is not available.\n */\nexport class DockerNotAvailableError extends DockerSandboxError {\n constructor() {\n super('Docker is not available. Ensure Docker daemon is running.');\n this.name = 'DockerNotAvailableError';\n }\n}\n\n/**\n * Thrown when container creation fails.\n */\nexport class ContainerCreationError extends DockerSandboxError {\n readonly image: string;\n override cause?: Error;\n\n constructor(message: string, image: string, cause?: Error) {\n super(`Failed to create container from image \"${image}\": ${message}`);\n this.name = 'ContainerCreationError';\n this.image = image;\n this.cause = cause;\n }\n}\n\n/**\n * Thrown when package installation fails.\n */\nexport class PackageInstallError extends DockerSandboxError {\n readonly packages: string[];\n readonly image: string;\n readonly packageManager: 'apk' | 'apt-get';\n readonly stderr: string;\n\n constructor(\n packages: string[],\n image: string,\n packageManager: 'apk' | 'apt-get',\n stderr: string,\n containerId?: string,\n ) {\n super(\n `Package installation failed for [${packages.join(', ')}] ` +\n `using ${packageManager} on ${image}: ${stderr}`,\n containerId,\n );\n this.name = 'PackageInstallError';\n this.packages = packages;\n this.image = image;\n this.packageManager = packageManager;\n this.stderr = stderr;\n }\n}\n\n/**\n * Thrown when a binary installation from URL fails.\n */\nexport class BinaryInstallError extends DockerSandboxError {\n readonly binaryName: string;\n readonly url: string;\n readonly reason: string;\n\n constructor(\n binaryName: string,\n url: string,\n reason: string,\n containerId?: string,\n ) {\n super(\n `Failed to install binary \"${binaryName}\" from ${url}: ${reason}`,\n containerId,\n );\n this.name = 'BinaryInstallError';\n this.binaryName = binaryName;\n this.url = url;\n this.reason = reason;\n }\n}\n\n/**\n * Thrown when a mount path doesn't exist on the host.\n */\nexport class MountPathError extends DockerSandboxError {\n readonly hostPath: string;\n readonly containerPath: string;\n\n constructor(hostPath: string, containerPath: string) {\n super(\n `Mount path does not exist on host: \"${hostPath}\" -> \"${containerPath}\"`,\n );\n this.name = 'MountPathError';\n this.hostPath = hostPath;\n this.containerPath = containerPath;\n }\n}\n\n/**\n * Thrown when Dockerfile build fails.\n */\nexport class DockerfileBuildError extends DockerSandboxError {\n readonly stderr: string;\n\n constructor(stderr: string) {\n super(`Dockerfile build failed: ${stderr}`);\n this.name = 'DockerfileBuildError';\n this.stderr = stderr;\n }\n}\n\n/**\n * Thrown when docker compose up fails.\n */\nexport class ComposeStartError extends DockerSandboxError {\n readonly composeFile: string;\n readonly stderr: string;\n\n constructor(composeFile: string, stderr: string) {\n super(`Docker Compose failed to start: ${stderr}`);\n this.name = 'ComposeStartError';\n this.composeFile = composeFile;\n this.stderr = stderr;\n }\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Interfaces\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Configuration for mounting a host directory into the container.\n */\nexport interface DockerMount {\n /** Absolute path on the host machine */\n hostPath: string;\n /** Path inside the container */\n containerPath: string;\n /** Whether the mount is read-only (default: true) */\n readOnly?: boolean;\n}\n\n/**\n * Resource limits for the container.\n */\nexport interface DockerResources {\n /** Memory limit (e.g., '1g', '512m') */\n memory?: string;\n /** CPU limit (number of CPUs) */\n cpus?: number;\n}\n\n/**\n * Architecture-specific URL mapping for binary downloads.\n * Maps container architecture (from `uname -m`) to download URLs.\n */\nexport interface ArchitectureUrls {\n /** URL for x86_64 architecture (amd64) */\n x86_64?: string;\n /** URL for ARM64 architecture (aarch64) */\n aarch64?: string;\n /** URL for ARMv7 architecture */\n armv7l?: string;\n}\n\n/**\n * Configuration for installing a binary from a URL.\n *\n * Binaries are downloaded, extracted (if tar.gz), and installed to /usr/local/bin.\n */\nexport interface BinaryInstall {\n /** Name of the binary (used for the final executable name) */\n name: string;\n /**\n * URL or architecture-specific URLs.\n * - If a string, used for all architectures\n * - If ArchitectureUrls, selects based on container architecture\n */\n url: string | ArchitectureUrls;\n /**\n * Optional: The binary filename inside the archive if different from `name`.\n * Useful when the archive contains versioned binaries like \"presenterm-0.15.1\".\n */\n binaryPath?: string;\n}\n\n/**\n * Options for RuntimeStrategy - installs packages/binaries at container runtime.\n */\nexport interface RuntimeSandboxOptions {\n /** Docker image to use (default: 'alpine:latest') */\n image?: string;\n /** Packages to install in the container via package manager (apk/apt) */\n packages?: string[];\n /** Binaries to install from URLs (for tools not in package managers) */\n binaries?: BinaryInstall[];\n /** Directories to mount from host */\n mounts?: DockerMount[];\n /** Resource limits */\n resources?: DockerResources;\n}\n\n/**\n * Options for DockerfileStrategy - builds custom image from Dockerfile.\n */\nexport interface DockerfileSandboxOptions {\n /** Dockerfile content (if contains newlines) or path to Dockerfile */\n dockerfile: string;\n /** Build context directory (default: '.') */\n context?: string;\n /** Directories to mount from host */\n mounts?: DockerMount[];\n /** Resource limits */\n resources?: DockerResources;\n}\n\n/**\n * Options for ComposeStrategy - manages multi-container environments.\n */\nexport interface ComposeSandboxOptions {\n /** Path to docker-compose.yml file */\n compose: string;\n /** Service name to execute commands in (required) */\n service: string;\n /** Resource limits (applied to target service only) */\n resources?: DockerResources;\n // Note: mounts must be defined in compose file, not here\n}\n\n/**\n * Union type for Docker sandbox options.\n * - RuntimeSandboxOptions: Runtime package/binary installation\n * - DockerfileSandboxOptions: Pre-built images from Dockerfile\n * - ComposeSandboxOptions: Multi-container environments via Docker Compose\n */\nexport type DockerSandboxOptions =\n | RuntimeSandboxOptions\n | DockerfileSandboxOptions\n | ComposeSandboxOptions;\n\n/**\n * Extended sandbox interface with disposal method.\n */\nexport interface DockerSandbox extends Sandbox {\n /** Stop and remove the container */\n dispose(): Promise<void>;\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Helper Functions\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Detects if the image is Debian-based (uses apt-get) or Alpine-based (uses apk).\n */\nfunction isDebianBased(image: string): boolean {\n const debianPatterns = ['debian', 'ubuntu', 'node', 'python'];\n return debianPatterns.some((pattern) =>\n image.toLowerCase().includes(pattern),\n );\n}\n\n/**\n * Type guard to determine if options are for DockerfileStrategy.\n */\nexport function isDockerfileOptions(\n opts: DockerSandboxOptions,\n): opts is DockerfileSandboxOptions {\n return 'dockerfile' in opts;\n}\n\n/**\n * Type guard to determine if options are for ComposeStrategy.\n */\nexport function isComposeOptions(\n opts: DockerSandboxOptions,\n): opts is ComposeSandboxOptions {\n return 'compose' in opts;\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Strategy Pattern - Base Class\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Internal context shared across strategy methods.\n */\ninterface StrategyContext {\n containerId: string;\n image: string;\n}\n\n/**\n * Abstract base class for Docker sandbox creation strategies.\n *\n * Uses the Template Method pattern to define the skeleton of the sandbox\n * creation algorithm, deferring specific steps to subclasses.\n *\n * @example Extending the strategy\n * ```typescript\n * class CustomStrategy extends DockerSandboxStrategy {\n * protected async getImage(): Promise<string> {\n * // Custom image resolution logic\n * return 'my-custom-image:latest';\n * }\n *\n * protected async configure(): Promise<void> {\n * // Custom configuration after container starts\n * }\n * }\n * ```\n */\nexport abstract class DockerSandboxStrategy {\n protected context!: StrategyContext;\n protected mounts: DockerMount[];\n protected resources: DockerResources;\n\n constructor(mounts: DockerMount[] = [], resources: DockerResources = {}) {\n this.mounts = mounts;\n this.resources = resources;\n }\n\n /**\n * Template method - defines the algorithm skeleton for creating a sandbox.\n *\n * Steps:\n * 1. Validate mount paths exist on host\n * 2. Get/build the Docker image (strategy-specific)\n * 3. Start the container\n * 4. Configure the container (strategy-specific)\n * 5. Create and return sandbox methods\n */\n async create(): Promise<DockerSandbox> {\n this.validateMounts();\n const image = await this.getImage();\n const containerId = await this.startContainer(image);\n this.context = { containerId, image };\n\n try {\n await this.configure();\n } catch (error) {\n // Clean up container if configuration fails\n await this.stopContainer(containerId);\n throw error;\n }\n\n return this.createSandboxMethods();\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Common implementations (shared by all strategies)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Validates that all mount paths exist on the host filesystem.\n */\n protected validateMounts(): void {\n for (const mount of this.mounts) {\n if (!existsSync(mount.hostPath)) {\n throw new MountPathError(mount.hostPath, mount.containerPath);\n }\n }\n }\n\n /**\n * Builds the docker run command arguments.\n */\n protected buildDockerArgs(image: string, containerId: string): string[] {\n const { memory = '1g', cpus = 2 } = this.resources;\n\n const args: string[] = [\n 'run',\n '-d', // Detached mode\n '--rm', // Remove container when stopped\n '--name',\n containerId,\n `--memory=${memory}`,\n `--cpus=${cpus}`,\n '-w',\n '/workspace', // Set working directory\n ];\n\n // Add mounts\n for (const mount of this.mounts) {\n const mode = mount.readOnly !== false ? 'ro' : 'rw';\n args.push('-v', `${mount.hostPath}:${mount.containerPath}:${mode}`);\n }\n\n // Add image and command to keep container alive\n args.push(image, 'tail', '-f', '/dev/null');\n\n return args;\n }\n\n /**\n * Starts a Docker container with the given image.\n */\n protected async startContainer(image: string): Promise<string> {\n const containerId = `sandbox-${crypto.randomUUID().slice(0, 8)}`;\n const args = this.buildDockerArgs(image, containerId);\n\n try {\n await spawn('docker', args);\n } catch (error) {\n const err = error as Error & { stderr?: string };\n if (\n err.message?.includes('Cannot connect') ||\n err.message?.includes('docker daemon') ||\n err.stderr?.includes('Cannot connect')\n ) {\n throw new DockerNotAvailableError();\n }\n throw new ContainerCreationError(err.message || String(err), image, err);\n }\n\n return containerId;\n }\n\n /**\n * Stops a Docker container.\n */\n protected async stopContainer(containerId: string): Promise<void> {\n try {\n await spawn('docker', ['stop', containerId]);\n } catch {\n // Container may already be stopped, ignore errors\n }\n }\n\n /**\n * Executes a command in the container.\n */\n protected async exec(command: string): Promise<CommandResult> {\n try {\n const result = await spawn('docker', [\n 'exec',\n this.context.containerId,\n 'sh',\n '-c',\n command,\n ]);\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: 0,\n };\n } catch (error) {\n const err = error as Error & {\n stdout?: string;\n stderr?: string;\n exitCode?: number;\n };\n return {\n stdout: err.stdout || '',\n stderr: err.stderr || err.message || '',\n exitCode: err.exitCode ?? 1,\n };\n }\n }\n\n /**\n * Creates the DockerSandbox interface with all methods.\n */\n protected createSandboxMethods(): DockerSandbox {\n const { containerId } = this.context;\n\n const sandbox: DockerSandbox = {\n executeCommand: async (command: string): Promise<CommandResult> => {\n return this.exec(command);\n },\n\n readFile: async (path: string): Promise<string> => {\n // Use base64 encoding to preserve exact content (including trailing newlines)\n // nano-spawn strips trailing newlines from stdout, so we encode/decode\n const result = await sandbox.executeCommand(`base64 \"${path}\"`);\n if (result.exitCode !== 0) {\n throw new Error(`Failed to read file \"${path}\": ${result.stderr}`);\n }\n return Buffer.from(result.stdout, 'base64').toString('utf-8');\n },\n\n writeFiles: async (\n files: Array<{ path: string; content: string }>,\n ): Promise<void> => {\n for (const file of files) {\n // Create parent directories\n const dir = file.path.substring(0, file.path.lastIndexOf('/'));\n if (dir) {\n await sandbox.executeCommand(`mkdir -p \"${dir}\"`);\n }\n\n // Use base64 encoding for binary-safe file writes\n const base64Content = Buffer.from(file.content).toString('base64');\n const result = await sandbox.executeCommand(\n `echo \"${base64Content}\" | base64 -d > \"${file.path}\"`,\n );\n\n if (result.exitCode !== 0) {\n throw new Error(\n `Failed to write file \"${file.path}\": ${result.stderr}`,\n );\n }\n }\n },\n\n dispose: async (): Promise<void> => {\n await this.stopContainer(containerId);\n },\n };\n\n return sandbox;\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Strategy-specific hooks (to be implemented by subclasses)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Returns the Docker image to use for the container.\n * For RuntimeStrategy: returns the image name directly.\n * For DockerfileStrategy: builds the image and returns the tag.\n */\n protected abstract getImage(): Promise<string>;\n\n /**\n * Configures the container after it starts.\n * For RuntimeStrategy: installs packages and binaries.\n * For DockerfileStrategy: no-op (Dockerfile already configured).\n */\n protected abstract configure(): Promise<void>;\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// RuntimeStrategy - Installs packages/binaries at container runtime\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Strategy that uses an existing Docker image and installs packages/binaries\n * at container runtime.\n *\n * This is the \"configure-on-demand\" approach - starts a vanilla image and\n * customizes it by executing installation commands.\n *\n * @example\n * ```typescript\n * const strategy = new RuntimeStrategy(\n * 'alpine:latest',\n * ['curl', 'jq'],\n * [{ name: 'presenterm', url: {...} }],\n * );\n * const sandbox = await strategy.create();\n * ```\n */\nexport class RuntimeStrategy extends DockerSandboxStrategy {\n private image: string;\n private packages: string[];\n private binaries: BinaryInstall[];\n\n constructor(\n image = 'alpine:latest',\n packages: string[] = [],\n binaries: BinaryInstall[] = [],\n mounts?: DockerMount[],\n resources?: DockerResources,\n ) {\n super(mounts, resources);\n this.image = image;\n this.packages = packages;\n this.binaries = binaries;\n }\n\n protected async getImage(): Promise<string> {\n return this.image;\n }\n\n protected async configure(): Promise<void> {\n await this.installPackages();\n await this.installBinaries();\n }\n\n /**\n * Installs packages using the appropriate package manager (apk/apt-get).\n */\n private async installPackages(): Promise<void> {\n if (this.packages.length === 0) return;\n\n const useApt = isDebianBased(this.image);\n const installCmd = useApt\n ? `apt-get update && apt-get install -y ${this.packages.join(' ')}`\n : `apk add --no-cache ${this.packages.join(' ')}`;\n\n try {\n await spawn('docker', [\n 'exec',\n this.context.containerId,\n 'sh',\n '-c',\n installCmd,\n ]);\n } catch (error) {\n const err = error as Error & { stderr?: string };\n throw new PackageInstallError(\n this.packages,\n this.image,\n useApt ? 'apt-get' : 'apk',\n err.stderr || err.message,\n this.context.containerId,\n );\n }\n }\n\n /**\n * Installs binaries from URLs.\n */\n private async installBinaries(): Promise<void> {\n if (this.binaries.length === 0) return;\n\n // Ensure curl is available for downloading\n await this.ensureCurl();\n\n // Detect container architecture\n const arch = await this.detectArchitecture();\n\n // Install each binary\n for (const binary of this.binaries) {\n await this.installBinary(binary, arch);\n }\n }\n\n /**\n * Ensures curl is installed in the container.\n */\n private async ensureCurl(): Promise<void> {\n const checkResult = await spawn('docker', [\n 'exec',\n this.context.containerId,\n 'which',\n 'curl',\n ]).catch(() => null);\n\n if (checkResult) return; // curl already installed\n\n const useApt = isDebianBased(this.image);\n const curlInstallCmd = useApt\n ? 'apt-get update && apt-get install -y curl'\n : 'apk add --no-cache curl';\n\n try {\n await spawn('docker', [\n 'exec',\n this.context.containerId,\n 'sh',\n '-c',\n curlInstallCmd,\n ]);\n } catch (error) {\n const err = error as Error & { stderr?: string };\n throw new BinaryInstallError(\n 'curl',\n 'package-manager',\n `Required for binary downloads: ${err.stderr || err.message}`,\n this.context.containerId,\n );\n }\n }\n\n /**\n * Detects the container's CPU architecture.\n */\n private async detectArchitecture(): Promise<string> {\n try {\n const result = await spawn('docker', [\n 'exec',\n this.context.containerId,\n 'uname',\n '-m',\n ]);\n return result.stdout.trim();\n } catch (error) {\n const err = error as Error & { stderr?: string };\n throw new DockerSandboxError(\n `Failed to detect container architecture: ${err.stderr || err.message}`,\n this.context.containerId,\n );\n }\n }\n\n /**\n * Installs a single binary from URL.\n */\n private async installBinary(\n binary: BinaryInstall,\n arch: string,\n ): Promise<void> {\n // Resolve URL based on architecture\n let url: string;\n if (typeof binary.url === 'string') {\n url = binary.url;\n } else {\n const archUrl = binary.url[arch as keyof ArchitectureUrls];\n if (!archUrl) {\n throw new BinaryInstallError(\n binary.name,\n `arch:${arch}`,\n `No URL provided for architecture \"${arch}\". Available: ${Object.keys(binary.url).join(', ')}`,\n this.context.containerId,\n );\n }\n url = archUrl;\n }\n\n // Download and install the binary\n const isTarGz = url.endsWith('.tar.gz') || url.endsWith('.tgz');\n let installCmd: string;\n\n if (isTarGz) {\n const binaryPathInArchive = binary.binaryPath || binary.name;\n installCmd = `\n set -e\n TMPDIR=$(mktemp -d)\n cd \"$TMPDIR\"\n curl -fsSL \"${url}\" -o archive.tar.gz\n tar -xzf archive.tar.gz\n BINARY_FILE=$(find . -name \"${binaryPathInArchive}\" -o -name \"${binary.name}\" | head -1)\n if [ -z \"$BINARY_FILE\" ]; then\n echo \"Binary not found in archive. Contents:\" >&2\n find . -type f >&2\n exit 1\n fi\n chmod +x \"$BINARY_FILE\"\n mv \"$BINARY_FILE\" /usr/local/bin/${binary.name}\n cd /\n rm -rf \"$TMPDIR\"\n `;\n } else {\n installCmd = `\n curl -fsSL \"${url}\" -o /usr/local/bin/${binary.name}\n chmod +x /usr/local/bin/${binary.name}\n `;\n }\n\n try {\n await spawn('docker', [\n 'exec',\n this.context.containerId,\n 'sh',\n '-c',\n installCmd,\n ]);\n } catch (error) {\n const err = error as Error & { stderr?: string };\n throw new BinaryInstallError(\n binary.name,\n url,\n err.stderr || err.message,\n this.context.containerId,\n );\n }\n }\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// DockerfileStrategy - Builds image from Dockerfile\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Strategy that builds a custom Docker image from a Dockerfile.\n *\n * This is the \"build-once, run-many\" approach - builds the image upfront\n * (with caching) and runs containers from the pre-configured image.\n *\n * Image caching: Uses a deterministic tag based on Dockerfile content hash.\n * If the same Dockerfile is used, the existing image is reused (cache hit).\n *\n * @example Inline Dockerfile\n * ```typescript\n * const strategy = new DockerfileStrategy(`\n * FROM alpine:latest\n * RUN apk add --no-cache curl jq\n * `);\n * const sandbox = await strategy.create();\n * ```\n *\n * @example Dockerfile path\n * ```typescript\n * const strategy = new DockerfileStrategy(\n * './Dockerfile.sandbox',\n * './docker', // build context\n * );\n * const sandbox = await strategy.create();\n * ```\n */\nexport class DockerfileStrategy extends DockerSandboxStrategy {\n private imageTag: string;\n private dockerfile: string;\n private dockerContext: string;\n\n constructor(\n dockerfile: string,\n dockerContext = '.',\n mounts?: DockerMount[],\n resources?: DockerResources,\n ) {\n super(mounts, resources);\n this.dockerfile = dockerfile;\n this.dockerContext = dockerContext;\n this.imageTag = this.computeImageTag();\n }\n\n /**\n * Computes a deterministic image tag based on Dockerfile content.\n * Same Dockerfile \u2192 same tag \u2192 Docker skips rebuild if image exists.\n */\n private computeImageTag(): string {\n const content = this.isInlineDockerfile()\n ? this.dockerfile\n : readFileSync(this.dockerfile, 'utf-8');\n const hash = createHash('sha256')\n .update(content)\n .digest('hex')\n .slice(0, 12);\n return `sandbox-${hash}`;\n }\n\n /**\n * Checks if the dockerfile property is inline content or a file path.\n */\n private isInlineDockerfile(): boolean {\n return this.dockerfile.includes('\\n');\n }\n\n protected async getImage(): Promise<string> {\n // Check if image already exists (cache hit)\n const exists = await this.imageExists();\n if (!exists) {\n await this.buildImage();\n }\n return this.imageTag;\n }\n\n protected async configure(): Promise<void> {\n // No-op - Dockerfile already configured the image\n }\n\n /**\n * Checks if the image already exists locally.\n */\n private async imageExists(): Promise<boolean> {\n try {\n await spawn('docker', ['image', 'inspect', this.imageTag]);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Builds the Docker image from the Dockerfile.\n */\n private async buildImage(): Promise<void> {\n try {\n if (this.isInlineDockerfile()) {\n // Inline Dockerfile - use heredoc via shell\n const buildCmd = `echo '${this.dockerfile.replace(/'/g, \"'\\\\''\")}' | docker build -t ${this.imageTag} -f - ${this.dockerContext}`;\n await spawn('sh', ['-c', buildCmd]);\n } else {\n // Path to Dockerfile\n await spawn('docker', [\n 'build',\n '-t',\n this.imageTag,\n '-f',\n this.dockerfile,\n this.dockerContext,\n ]);\n }\n } catch (error) {\n const err = error as Error & { stderr?: string };\n throw new DockerfileBuildError(err.stderr || err.message);\n }\n }\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// ComposeStrategy - Multi-container environments via Docker Compose\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Strategy that manages multi-container environments using Docker Compose.\n *\n * Unlike other strategies that manage a single container, ComposeStrategy\n * orchestrates multiple services as a unit using docker compose commands.\n *\n * @example\n * ```typescript\n * const strategy = new ComposeStrategy(\n * './docker-compose.yml',\n * 'app', // Service to execute commands in\n * );\n * const sandbox = await strategy.create();\n *\n * // Commands run in the 'app' service\n * await sandbox.executeCommand('node --version');\n *\n * // Can communicate with other services via service names\n * await sandbox.executeCommand('curl http://api:3000/health');\n *\n * // Stops ALL services\n * await sandbox.dispose();\n * ```\n */\nexport class ComposeStrategy extends DockerSandboxStrategy {\n private projectName: string;\n private composeFile: string;\n private service: string;\n\n constructor(\n composeFile: string,\n service: string,\n resources?: DockerResources,\n ) {\n // Pass empty mounts - compose handles its own volumes\n super([], resources);\n this.composeFile = composeFile;\n this.service = service;\n this.projectName = this.computeProjectName();\n }\n\n /**\n * Deterministic project name based on compose file content for caching.\n * Same compose file \u2192 same project name \u2192 faster subsequent startups.\n */\n private computeProjectName(): string {\n const content = readFileSync(this.composeFile, 'utf-8');\n const hash = createHash('sha256').update(content).digest('hex').slice(0, 8);\n return `sandbox-${hash}`;\n }\n\n /**\n * Override: No image to get - compose manages its own images.\n */\n protected async getImage(): Promise<string> {\n return ''; // Not used for compose\n }\n\n /**\n * Override: Start all services with docker compose up.\n */\n protected override async startContainer(_image: string): Promise<string> {\n try {\n await spawn('docker', [\n 'compose',\n '-f',\n this.composeFile,\n '-p',\n this.projectName,\n 'up',\n '-d',\n ]);\n } catch (error) {\n const err = error as Error & { stderr?: string };\n if (err.stderr?.includes('Cannot connect')) {\n throw new DockerNotAvailableError();\n }\n throw new ComposeStartError(this.composeFile, err.stderr || err.message);\n }\n\n // Return project name as the \"container ID\" for context\n return this.projectName;\n }\n\n protected async configure(): Promise<void> {\n // No additional configuration - compose file defines everything\n }\n\n /**\n * Override: Execute commands in the target service.\n */\n protected override async exec(command: string): Promise<CommandResult> {\n try {\n const result = await spawn('docker', [\n 'compose',\n '-f',\n this.composeFile,\n '-p',\n this.projectName,\n 'exec',\n '-T', // -T disables pseudo-TTY\n this.service,\n 'sh',\n '-c',\n command,\n ]);\n return { stdout: result.stdout, stderr: result.stderr, exitCode: 0 };\n } catch (error) {\n const err = error as Error & {\n stdout?: string;\n stderr?: string;\n exitCode?: number;\n };\n return {\n stdout: err.stdout || '',\n stderr: err.stderr || err.message || '',\n exitCode: err.exitCode ?? 1,\n };\n }\n }\n\n /**\n * Override: Stop all services with docker compose down.\n */\n protected override async stopContainer(_containerId: string): Promise<void> {\n try {\n await spawn('docker', [\n 'compose',\n '-f',\n this.composeFile,\n '-p',\n this.projectName,\n 'down',\n ]);\n } catch {\n // Ignore cleanup errors\n }\n }\n}\n\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Factory Function\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Creates a Docker-based sandbox for executing commands in an isolated container.\n *\n * Supports three strategies:\n * - **RuntimeStrategy**: Uses existing image, installs packages/binaries at runtime\n * - **DockerfileStrategy**: Builds custom image from Dockerfile (with caching)\n * - **ComposeStrategy**: Multi-container environments via Docker Compose\n *\n * @example RuntimeStrategy (default)\n * ```typescript\n * const sandbox = await createDockerSandbox({\n * image: 'alpine:latest',\n * packages: ['curl', 'jq'],\n * binaries: [{ name: 'presenterm', url: {...} }],\n * });\n * await sandbox.executeCommand('curl --version');\n * await sandbox.dispose();\n * ```\n *\n * @example DockerfileStrategy\n * ```typescript\n * const sandbox = await createDockerSandbox({\n * dockerfile: `\n * FROM alpine:latest\n * RUN apk add --no-cache curl jq\n * `,\n * context: '.',\n * });\n * await sandbox.executeCommand('curl --version');\n * await sandbox.dispose();\n * ```\n *\n * @example ComposeStrategy\n * ```typescript\n * const sandbox = await createDockerSandbox({\n * compose: './docker-compose.yml',\n * service: 'app',\n * });\n * // Commands run in the 'app' service\n * await sandbox.executeCommand('node --version');\n * // Can reach other services by name\n * await sandbox.executeCommand('curl http://db:5432');\n * await sandbox.dispose(); // Stops ALL services\n * ```\n */\nexport async function createDockerSandbox(\n options: DockerSandboxOptions = {},\n): Promise<DockerSandbox> {\n let strategy: DockerSandboxStrategy;\n\n if (isComposeOptions(options)) {\n strategy = new ComposeStrategy(\n options.compose,\n options.service,\n options.resources,\n );\n } else if (isDockerfileOptions(options)) {\n strategy = new DockerfileStrategy(\n options.dockerfile,\n options.context,\n options.mounts,\n options.resources,\n );\n } else {\n strategy = new RuntimeStrategy(\n options.image,\n options.packages,\n options.binaries,\n options.mounts,\n options.resources,\n );\n }\n\n return strategy.create();\n}\n\n/**\n * Execute a function with a Docker sandbox that auto-disposes on completion.\n * Ensures cleanup even if the function throws.\n *\n * @example\n * ```typescript\n * const output = await useSandbox(\n * { packages: ['curl', 'jq'] },\n * async (sandbox) => {\n * const result = await sandbox.executeCommand('curl --version');\n * return result.stdout;\n * },\n * );\n * // Container is automatically disposed - no try/finally needed\n * ```\n */\nexport async function useSandbox<T>(\n options: DockerSandboxOptions,\n fn: (sandbox: DockerSandbox) => Promise<T>,\n): Promise<T> {\n const sandbox = await createDockerSandbox(options);\n try {\n return await fn(sandbox);\n } finally {\n await sandbox.dispose();\n }\n}\n", "import {\n createBashTool,\n type CreateBashToolOptions,\n type BashToolkit,\n} from 'bash-tool';\n\nimport {\n createDockerSandbox,\n isComposeOptions,\n isDockerfileOptions,\n type BinaryInstall,\n type DockerMount,\n type DockerResources,\n type DockerSandbox,\n type DockerSandboxOptions,\n} from './docker-sandbox.ts';\n\n/**\n * Base options shared by RuntimeContainerToolOptions and DockerfileContainerToolOptions.\n */\ninterface BaseContainerToolOptions\n extends Omit<CreateBashToolOptions, 'sandbox' | 'uploadDirectory'> {\n /** Directories to mount from host into the container */\n mounts?: DockerMount[];\n /** Resource limits for the container */\n resources?: DockerResources;\n}\n\n/**\n * Options for container tool using RuntimeStrategy.\n * Installs packages/binaries at container runtime.\n */\nexport interface RuntimeContainerToolOptions extends BaseContainerToolOptions {\n /** Docker image to use (default: 'alpine:latest') */\n image?: string;\n /** Packages to install in the container via package manager (apk/apt) */\n packages?: string[];\n /** Binaries to install from URLs (for tools not in package managers) */\n binaries?: BinaryInstall[];\n}\n\n/**\n * Options for container tool using DockerfileStrategy.\n * Builds custom image from Dockerfile (with caching).\n */\nexport interface DockerfileContainerToolOptions extends BaseContainerToolOptions {\n /** Dockerfile content (if contains newlines) or path to Dockerfile */\n dockerfile: string;\n /** Build context directory (default: '.') */\n context?: string;\n}\n\n/**\n * Options for container tool using ComposeStrategy.\n * Manages multi-container environments via Docker Compose.\n */\nexport interface ComposeContainerToolOptions\n extends Omit<CreateBashToolOptions, 'sandbox' | 'uploadDirectory'> {\n /** Path to docker-compose.yml file */\n compose: string;\n /** Service name to execute commands in (required) */\n service: string;\n /** Resource limits for the container */\n resources?: DockerResources;\n // Note: mounts must be defined in compose file, not here\n}\n\n/**\n * Union type for container tool options.\n * - RuntimeContainerToolOptions: Runtime package/binary installation\n * - DockerfileContainerToolOptions: Pre-built images from Dockerfile\n * - ComposeContainerToolOptions: Multi-container environments via Docker Compose\n */\nexport type ContainerToolOptions =\n | RuntimeContainerToolOptions\n | DockerfileContainerToolOptions\n | ComposeContainerToolOptions;\n\n/**\n * Result of creating a container tool.\n * Extends BashToolkit but with DockerSandbox (which has dispose()) instead of base Sandbox.\n */\nexport type ContainerToolResult = Omit<BashToolkit, 'sandbox'> & {\n sandbox: DockerSandbox;\n};\n\n/**\n * Creates a bash tool that runs in a Docker container.\n *\n * This is a high-level wrapper that combines `createDockerSandbox()` and\n * `createBashTool()` into a single call. It provides a convenient way to\n * get a bash tool that executes real binaries in an isolated container.\n *\n * Supports three strategies:\n * - **RuntimeStrategy**: Uses existing image, installs packages/binaries at runtime\n * - **DockerfileStrategy**: Builds custom image from Dockerfile (with caching)\n * - **ComposeStrategy**: Multi-container environments via Docker Compose\n *\n * @example RuntimeStrategy (default)\n * ```typescript\n * const { bash, tools, sandbox } = await createContainerTool({\n * packages: ['curl', 'jq'],\n * mounts: [{\n * hostPath: process.cwd(),\n * containerPath: '/workspace',\n * readOnly: false,\n * }],\n * });\n *\n * // Use with AI SDK\n * const response = await generateText({\n * model: yourModel,\n * tools,\n * prompt: 'Fetch the weather data and parse it with jq',\n * });\n *\n * // Clean up when done\n * await sandbox.dispose();\n * ```\n *\n * @example DockerfileStrategy\n * ```typescript\n * const { bash, tools, sandbox } = await createContainerTool({\n * dockerfile: `\n * FROM python:3.11-slim\n * RUN pip install pandas numpy\n * `,\n * context: '.',\n * mounts: [{\n * hostPath: process.cwd(),\n * containerPath: '/workspace',\n * }],\n * });\n * ```\n *\n * @example ComposeStrategy\n * ```typescript\n * const { bash, tools, sandbox } = await createContainerTool({\n * compose: './docker-compose.yml',\n * service: 'app',\n * });\n * // Commands run in the 'app' service, can reach other services by name\n * await sandbox.dispose(); // Stops ALL services\n * ```\n *\n * @example With hooks for logging\n * ```typescript\n * const { bash, sandbox } = await createContainerTool({\n * packages: ['python3'],\n * onBeforeBashCall: ({ command }) => {\n * console.log('Running:', command);\n * },\n * onAfterBashCall: ({ command, result }) => {\n * console.log(`Exit code: ${result.exitCode}`);\n * },\n * });\n * ```\n */\nexport async function createContainerTool(\n options: ContainerToolOptions = {},\n): Promise<ContainerToolResult> {\n // Extract sandbox options from bash tool options\n let sandboxOptions: DockerSandboxOptions;\n let bashOptions: Omit<CreateBashToolOptions, 'sandbox' | 'uploadDirectory'>;\n\n if (isComposeOptions(options)) {\n const { compose, service, resources, ...rest } = options;\n sandboxOptions = { compose, service, resources };\n bashOptions = rest;\n } else if (isDockerfileOptions(options)) {\n const { dockerfile, context, mounts, resources, ...rest } = options;\n sandboxOptions = { dockerfile, context, mounts, resources };\n bashOptions = rest;\n } else {\n const { image, packages, binaries, mounts, resources, ...rest } = options;\n sandboxOptions = { image, packages, binaries, mounts, resources };\n bashOptions = rest;\n }\n\n // Create the Docker sandbox\n const sandbox = await createDockerSandbox(sandboxOptions);\n\n // Create the bash tool with our Docker sandbox\n const toolkit = await createBashTool({\n ...bashOptions,\n sandbox,\n });\n\n return {\n bash: toolkit.bash,\n tools: toolkit.tools,\n sandbox,\n };\n}\n", "import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport YAML from 'yaml';\nimport type { ParsedSkillMd, SkillMetadata } from './types.ts';\n\n/**\n * Parse YAML frontmatter from a SKILL.md file content.\n *\n * Frontmatter format:\n * ```\n * ---\n * name: skill-name\n * description: Skill description here\n * ---\n *\n * # Markdown body\n * ```\n */\nexport function parseFrontmatter(content: string): ParsedSkillMd {\n const frontmatterRegex = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n?([\\s\\S]*)$/;\n const match = content.match(frontmatterRegex);\n\n if (!match) {\n throw new Error('Invalid SKILL.md: missing or malformed frontmatter');\n }\n\n const [, yamlContent, body] = match;\n const frontmatter = YAML.parse(yamlContent) as Record<string, unknown>;\n\n if (!frontmatter.name || typeof frontmatter.name !== 'string') {\n throw new Error('Invalid SKILL.md: frontmatter must have a \"name\" field');\n }\n\n if (!frontmatter.description || typeof frontmatter.description !== 'string') {\n throw new Error('Invalid SKILL.md: frontmatter must have a \"description\" field');\n }\n\n return {\n frontmatter: frontmatter as ParsedSkillMd['frontmatter'],\n body: body.trim(),\n };\n}\n\n/**\n * Load skill metadata from a SKILL.md file.\n * Only parses frontmatter, does not load full body into memory.\n * This is the core of progressive disclosure - metadata only at startup.\n */\nexport function loadSkillMetadata(skillMdPath: string): SkillMetadata {\n const content = fs.readFileSync(skillMdPath, 'utf-8');\n const parsed = parseFrontmatter(content);\n const skillDir = path.dirname(skillMdPath);\n\n return {\n name: parsed.frontmatter.name,\n description: parsed.frontmatter.description,\n path: skillDir,\n skillMdPath,\n };\n}\n\n/**\n * Discover all skills in a directory.\n * Looks for subdirectories containing SKILL.md files.\n * Only loads metadata - full content is read by LLM when needed.\n */\nexport function discoverSkillsInDirectory(directory: string): SkillMetadata[] {\n const skills: SkillMetadata[] = [];\n\n // Expand ~ to home directory\n const expandedDir = directory.startsWith('~')\n ? path.join(process.env.HOME || '', directory.slice(1))\n : directory;\n\n if (!fs.existsSync(expandedDir)) {\n return skills;\n }\n\n const entries = fs.readdirSync(expandedDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const skillMdPath = path.join(expandedDir, entry.name, 'SKILL.md');\n if (!fs.existsSync(skillMdPath)) continue;\n\n try {\n const metadata = loadSkillMetadata(skillMdPath);\n skills.push(metadata);\n } catch (error) {\n // Skip invalid skills, log warning\n console.warn(`Warning: Failed to load skill at ${skillMdPath}:`, error);\n }\n }\n\n return skills;\n}\n", "import type { ContextFragment } from '../fragments.ts';\nimport { discoverSkillsInDirectory } from './loader.ts';\nimport type { SkillMetadata, SkillsFragmentOptions } from './types.ts';\n\n/**\n * Create a context fragment containing available skills metadata.\n *\n * Follows Anthropic's progressive disclosure pattern:\n * - At startup: only skill metadata (name, description, path) is injected\n * - At runtime: LLM reads full SKILL.md using file tools when relevant\n *\n * @param options - Configuration including paths to scan and optional filtering\n *\n * @example\n * ```ts\n * const context = new ContextEngine({ store, chatId: 'demo' })\n * .set(\n * role('You are a helpful assistant.'),\n * skills({ paths: ['./skills'] }), // Injects skill metadata into system prompt\n * );\n *\n * // LLM now sees skill metadata and can read full SKILL.md when needed\n * ```\n */\nexport function skills(options: SkillsFragmentOptions): ContextFragment {\n // Discover skills from all paths (later paths override earlier ones)\n const skillsMap = new Map<string, SkillMetadata>();\n for (const dir of options.paths) {\n const discovered = discoverSkillsInDirectory(dir);\n for (const skill of discovered) {\n skillsMap.set(skill.name, skill);\n }\n }\n const allSkills = Array.from(skillsMap.values());\n\n // Apply filtering\n let filteredSkills = allSkills;\n if (options.include) {\n filteredSkills = allSkills.filter((s) => options.include!.includes(s.name));\n }\n if (options.exclude) {\n filteredSkills = filteredSkills.filter(\n (s) => !options.exclude!.includes(s.name),\n );\n }\n\n // Convert skills to ContextFragments for proper rendering\n const skillFragments: ContextFragment[] = filteredSkills.map((skill) => ({\n name: 'skill',\n data: {\n name: skill.name,\n path: skill.skillMdPath,\n description: skill.description,\n },\n }));\n\n return {\n name: 'available_skills',\n data: [\n {\n name: 'instructions',\n data: SKILLS_INSTRUCTIONS,\n } as ContextFragment,\n ...skillFragments,\n ],\n };\n}\n\n/**\n * Instructions for the LLM on how to use available skills.\n * Follows Anthropic's progressive disclosure - LLM reads files when needed.\n */\nconst SKILLS_INSTRUCTIONS = `When a user's request matches one of the skills listed below, read the skill's SKILL.md file to get detailed instructions before proceeding. Skills provide specialized knowledge and workflows for specific tasks.\n\nTo use a skill:\n1. Identify if the user's request matches a skill's description\n2. Read the SKILL.md file at the skill's path to load full instructions\n3. Follow the skill's guidance to complete the task\n\nSkills are only loaded when relevant - don't read skill files unless needed.`;\n", "import { DatabaseSync, type SQLInputValue } from 'node:sqlite';\n\nimport type {\n BranchData,\n BranchInfo,\n ChatData,\n ChatInfo,\n CheckpointData,\n CheckpointInfo,\n GraphBranch,\n GraphCheckpoint,\n GraphData,\n GraphNode,\n MessageData,\n SearchOptions,\n SearchResult,\n StoredChatData,\n} from './store.ts';\nimport { ContextStore } from './store.ts';\n\nconst STORE_DDL = `\n-- Chats table\n-- createdAt/updatedAt: DEFAULT for insert, inline SET for updates\nCREATE TABLE IF NOT EXISTS chats (\n id TEXT PRIMARY KEY,\n title TEXT,\n metadata TEXT,\n createdAt INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000),\n updatedAt INTEGER NOT NULL DEFAULT (strftime('%s', 'now') * 1000)\n);\n\nCREATE INDEX IF NOT EXISTS idx_chats_updatedAt ON chats(updatedAt);\n\n-- Messages table (nodes in the DAG)\nCREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n chatId TEXT NOT NULL,\n parentId TEXT,\n name TEXT NOT NULL,\n type TEXT,\n data TEXT NOT NULL,\n createdAt INTEGER NOT NULL,\n FOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADE,\n FOREIGN KEY (parentId) REFERENCES messages(id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_messages_chatId ON messages(chatId);\nCREATE INDEX IF NOT EXISTS idx_messages_parentId ON messages(parentId);\n\n-- Branches table (pointers to head messages)\nCREATE TABLE IF NOT EXISTS branches (\n id TEXT PRIMARY KEY,\n chatId TEXT NOT NULL,\n name TEXT NOT NULL,\n headMessageId TEXT,\n isActive INTEGER NOT NULL DEFAULT 0,\n createdAt INTEGER NOT NULL,\n FOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADE,\n FOREIGN KEY (headMessageId) REFERENCES messages(id),\n UNIQUE(chatId, name)\n);\n\nCREATE INDEX IF NOT EXISTS idx_branches_chatId ON branches(chatId);\n\n-- Checkpoints table (pointers to message nodes)\nCREATE TABLE IF NOT EXISTS checkpoints (\n id TEXT PRIMARY KEY,\n chatId TEXT NOT NULL,\n name TEXT NOT NULL,\n messageId TEXT NOT NULL,\n createdAt INTEGER NOT NULL,\n FOREIGN KEY (chatId) REFERENCES chats(id) ON DELETE CASCADE,\n FOREIGN KEY (messageId) REFERENCES messages(id),\n UNIQUE(chatId, name)\n);\n\nCREATE INDEX IF NOT EXISTS idx_checkpoints_chatId ON checkpoints(chatId);\n\n-- FTS5 virtual table for full-text search\n-- messageId/chatId/name are UNINDEXED (stored but not searchable, used for filtering/joining)\n-- Only 'content' is indexed for full-text search\nCREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(\n messageId UNINDEXED,\n chatId UNINDEXED,\n name UNINDEXED,\n content,\n tokenize='porter unicode61'\n);\n`;\n\n/**\n * SQLite-based context store using graph model.\n *\n * Uses node:sqlite's synchronous DatabaseSync for persistence.\n * Messages are stored as nodes in a DAG with parentId links.\n */\nexport class SqliteContextStore extends ContextStore {\n #db: DatabaseSync;\n\n constructor(path: string) {\n super();\n this.#db = new DatabaseSync(path);\n this.#db.exec('PRAGMA foreign_keys = ON');\n this.#db.exec(STORE_DDL);\n }\n\n // ==========================================================================\n // Chat Operations\n // ==========================================================================\n\n async createChat(chat: ChatData): Promise<void> {\n // createdAt and updatedAt are auto-set by SQLite DEFAULT\n this.#db\n .prepare(\n `INSERT INTO chats (id, title, metadata)\n VALUES (?, ?, ?)`,\n )\n .run(\n chat.id,\n chat.title ?? null,\n chat.metadata ? JSON.stringify(chat.metadata) : null,\n );\n }\n\n async upsertChat(chat: ChatData): Promise<StoredChatData> {\n // Insert if not exists, no-op update if exists (to trigger RETURNING)\n const row = this.#db\n .prepare(\n `INSERT INTO chats (id, title, metadata)\n VALUES (?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET id = excluded.id\n RETURNING *`,\n )\n .get(\n chat.id,\n chat.title ?? null,\n chat.metadata ? JSON.stringify(chat.metadata) : null,\n ) as {\n id: string;\n title: string | null;\n metadata: string | null;\n createdAt: number;\n updatedAt: number;\n };\n\n return {\n id: row.id,\n title: row.title ?? undefined,\n metadata: row.metadata ? JSON.parse(row.metadata) : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n }\n\n async getChat(chatId: string): Promise<StoredChatData | undefined> {\n const row = this.#db\n .prepare('SELECT * FROM chats WHERE id = ?')\n .get(chatId) as\n | {\n id: string;\n title: string | null;\n metadata: string | null;\n createdAt: number;\n updatedAt: number;\n }\n | undefined;\n\n if (!row) {\n return undefined;\n }\n\n return {\n id: row.id,\n title: row.title ?? undefined,\n metadata: row.metadata ? JSON.parse(row.metadata) : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n }\n\n async updateChat(\n chatId: string,\n updates: Partial<Pick<ChatData, 'title' | 'metadata'>>,\n ): Promise<StoredChatData> {\n const setClauses: string[] = [\"updatedAt = strftime('%s', 'now') * 1000\"];\n const params: SQLInputValue[] = [];\n\n if (updates.title !== undefined) {\n setClauses.push('title = ?');\n params.push(updates.title ?? null);\n }\n if (updates.metadata !== undefined) {\n setClauses.push('metadata = ?');\n params.push(JSON.stringify(updates.metadata));\n }\n\n params.push(chatId);\n const row = this.#db\n .prepare(\n `UPDATE chats SET ${setClauses.join(', ')} WHERE id = ? RETURNING *`,\n )\n .get(...params) as {\n id: string;\n title: string | null;\n metadata: string | null;\n createdAt: number;\n updatedAt: number;\n };\n\n return {\n id: row.id,\n title: row.title ?? undefined,\n metadata: row.metadata ? JSON.parse(row.metadata) : undefined,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n }\n\n async listChats(): Promise<ChatInfo[]> {\n const rows = this.#db\n .prepare(\n `SELECT\n c.id,\n c.title,\n c.createdAt,\n c.updatedAt,\n COUNT(DISTINCT m.id) as messageCount,\n COUNT(DISTINCT b.id) as branchCount\n FROM chats c\n LEFT JOIN messages m ON m.chatId = c.id\n LEFT JOIN branches b ON b.chatId = c.id\n GROUP BY c.id\n ORDER BY c.updatedAt DESC`,\n )\n .all() as {\n id: string;\n title: string | null;\n createdAt: number;\n updatedAt: number;\n messageCount: number;\n branchCount: number;\n }[];\n\n return rows.map((row) => ({\n id: row.id,\n title: row.title ?? undefined,\n messageCount: row.messageCount,\n branchCount: row.branchCount,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n }));\n }\n\n // ==========================================================================\n // Message Operations (Graph Nodes)\n // ==========================================================================\n\n async addMessage(message: MessageData): Promise<void> {\n // Upsert the message\n this.#db\n .prepare(\n `INSERT INTO messages (id, chatId, parentId, name, type, data, createdAt)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET\n parentId = excluded.parentId,\n name = excluded.name,\n type = excluded.type,\n data = excluded.data`,\n )\n .run(\n message.id,\n message.chatId,\n message.parentId,\n message.name,\n message.type ?? null,\n JSON.stringify(message.data),\n message.createdAt,\n );\n\n // Index in FTS for search\n const content =\n typeof message.data === 'string'\n ? message.data\n : JSON.stringify(message.data);\n\n // Delete existing FTS entry if any (for upsert), then insert new one\n this.#db\n .prepare(`DELETE FROM messages_fts WHERE messageId = ?`)\n .run(message.id);\n this.#db\n .prepare(\n `INSERT INTO messages_fts(messageId, chatId, name, content)\n VALUES (?, ?, ?, ?)`,\n )\n .run(message.id, message.chatId, message.name, content);\n }\n\n async getMessage(messageId: string): Promise<MessageData | undefined> {\n const row = this.#db\n .prepare('SELECT * FROM messages WHERE id = ?')\n .get(messageId) as\n | {\n id: string;\n chatId: string;\n parentId: string | null;\n name: string;\n type: string | null;\n data: string;\n createdAt: number;\n }\n | undefined;\n\n if (!row) {\n return undefined;\n }\n\n return {\n id: row.id,\n chatId: row.chatId,\n parentId: row.parentId,\n name: row.name,\n type: row.type ?? undefined,\n data: JSON.parse(row.data),\n createdAt: row.createdAt,\n };\n }\n\n async getMessageChain(headId: string): Promise<MessageData[]> {\n // Walk up the parent chain using recursive CTE with depth tracking\n // The CTE walks from head (newest) to root (oldest), so we track depth\n // and order by depth DESC to get chronological order (root first)\n const rows = this.#db\n .prepare(\n `WITH RECURSIVE chain AS (\n SELECT *, 0 as depth FROM messages WHERE id = ?\n UNION ALL\n SELECT m.*, c.depth + 1 FROM messages m\n INNER JOIN chain c ON m.id = c.parentId\n )\n SELECT * FROM chain\n ORDER BY depth DESC`,\n )\n .all(headId) as {\n id: string;\n chatId: string;\n parentId: string | null;\n name: string;\n type: string | null;\n data: string;\n createdAt: number;\n depth: number;\n }[];\n\n return rows.map((row) => ({\n id: row.id,\n chatId: row.chatId,\n parentId: row.parentId,\n name: row.name,\n type: row.type ?? undefined,\n data: JSON.parse(row.data),\n createdAt: row.createdAt,\n }));\n }\n\n async hasChildren(messageId: string): Promise<boolean> {\n const row = this.#db\n .prepare(\n 'SELECT EXISTS(SELECT 1 FROM messages WHERE parentId = ?) as hasChildren',\n )\n .get(messageId) as { hasChildren: number };\n\n return row.hasChildren === 1;\n }\n\n // ==========================================================================\n // Branch Operations\n // ==========================================================================\n\n async createBranch(branch: BranchData): Promise<void> {\n this.#db\n .prepare(\n `INSERT INTO branches (id, chatId, name, headMessageId, isActive, createdAt)\n VALUES (?, ?, ?, ?, ?, ?)`,\n )\n .run(\n branch.id,\n branch.chatId,\n branch.name,\n branch.headMessageId,\n branch.isActive ? 1 : 0,\n branch.createdAt,\n );\n }\n\n async getBranch(\n chatId: string,\n name: string,\n ): Promise<BranchData | undefined> {\n const row = this.#db\n .prepare('SELECT * FROM branches WHERE chatId = ? AND name = ?')\n .get(chatId, name) as\n | {\n id: string;\n chatId: string;\n name: string;\n headMessageId: string | null;\n isActive: number;\n createdAt: number;\n }\n | undefined;\n\n if (!row) {\n return undefined;\n }\n\n return {\n id: row.id,\n chatId: row.chatId,\n name: row.name,\n headMessageId: row.headMessageId,\n isActive: row.isActive === 1,\n createdAt: row.createdAt,\n };\n }\n\n async getActiveBranch(chatId: string): Promise<BranchData | undefined> {\n const row = this.#db\n .prepare('SELECT * FROM branches WHERE chatId = ? AND isActive = 1')\n .get(chatId) as\n | {\n id: string;\n chatId: string;\n name: string;\n headMessageId: string | null;\n isActive: number;\n createdAt: number;\n }\n | undefined;\n\n if (!row) {\n return undefined;\n }\n\n return {\n id: row.id,\n chatId: row.chatId,\n name: row.name,\n headMessageId: row.headMessageId,\n isActive: true,\n createdAt: row.createdAt,\n };\n }\n\n async setActiveBranch(chatId: string, branchId: string): Promise<void> {\n // Deactivate all branches for this chat\n this.#db\n .prepare('UPDATE branches SET isActive = 0 WHERE chatId = ?')\n .run(chatId);\n\n // Activate the specified branch\n this.#db\n .prepare('UPDATE branches SET isActive = 1 WHERE id = ?')\n .run(branchId);\n }\n\n async updateBranchHead(\n branchId: string,\n messageId: string | null,\n ): Promise<void> {\n this.#db\n .prepare('UPDATE branches SET headMessageId = ? WHERE id = ?')\n .run(messageId, branchId);\n }\n\n async listBranches(chatId: string): Promise<BranchInfo[]> {\n // Get branches with message count by walking the chain\n const branches = this.#db\n .prepare(\n `SELECT\n b.id,\n b.name,\n b.headMessageId,\n b.isActive,\n b.createdAt\n FROM branches b\n WHERE b.chatId = ?\n ORDER BY b.createdAt ASC`,\n )\n .all(chatId) as {\n id: string;\n name: string;\n headMessageId: string | null;\n isActive: number;\n createdAt: number;\n }[];\n\n // For each branch, count messages in the chain\n const result: BranchInfo[] = [];\n for (const branch of branches) {\n let messageCount = 0;\n if (branch.headMessageId) {\n const countRow = this.#db\n .prepare(\n `WITH RECURSIVE chain AS (\n SELECT id, parentId FROM messages WHERE id = ?\n UNION ALL\n SELECT m.id, m.parentId FROM messages m\n INNER JOIN chain c ON m.id = c.parentId\n )\n SELECT COUNT(*) as count FROM chain`,\n )\n .get(branch.headMessageId) as { count: number };\n messageCount = countRow.count;\n }\n\n result.push({\n id: branch.id,\n name: branch.name,\n headMessageId: branch.headMessageId,\n isActive: branch.isActive === 1,\n messageCount,\n createdAt: branch.createdAt,\n });\n }\n\n return result;\n }\n\n // ==========================================================================\n // Checkpoint Operations\n // ==========================================================================\n\n async createCheckpoint(checkpoint: CheckpointData): Promise<void> {\n this.#db\n .prepare(\n `INSERT INTO checkpoints (id, chatId, name, messageId, createdAt)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(chatId, name) DO UPDATE SET\n messageId = excluded.messageId,\n createdAt = excluded.createdAt`,\n )\n .run(\n checkpoint.id,\n checkpoint.chatId,\n checkpoint.name,\n checkpoint.messageId,\n checkpoint.createdAt,\n );\n }\n\n async getCheckpoint(\n chatId: string,\n name: string,\n ): Promise<CheckpointData | undefined> {\n const row = this.#db\n .prepare('SELECT * FROM checkpoints WHERE chatId = ? AND name = ?')\n .get(chatId, name) as\n | {\n id: string;\n chatId: string;\n name: string;\n messageId: string;\n createdAt: number;\n }\n | undefined;\n\n if (!row) {\n return undefined;\n }\n\n return {\n id: row.id,\n chatId: row.chatId,\n name: row.name,\n messageId: row.messageId,\n createdAt: row.createdAt,\n };\n }\n\n async listCheckpoints(chatId: string): Promise<CheckpointInfo[]> {\n const rows = this.#db\n .prepare(\n `SELECT id, name, messageId, createdAt\n FROM checkpoints\n WHERE chatId = ?\n ORDER BY createdAt DESC`,\n )\n .all(chatId) as {\n id: string;\n name: string;\n messageId: string;\n createdAt: number;\n }[];\n\n return rows.map((row) => ({\n id: row.id,\n name: row.name,\n messageId: row.messageId,\n createdAt: row.createdAt,\n }));\n }\n\n async deleteCheckpoint(chatId: string, name: string): Promise<void> {\n this.#db\n .prepare('DELETE FROM checkpoints WHERE chatId = ? AND name = ?')\n .run(chatId, name);\n }\n\n // ==========================================================================\n // Search Operations\n // ==========================================================================\n\n async searchMessages(\n chatId: string,\n query: string,\n options?: SearchOptions,\n ): Promise<SearchResult[]> {\n const limit = options?.limit ?? 20;\n const roles = options?.roles;\n\n // Build the query dynamically based on options\n let sql = `\n SELECT\n m.id,\n m.chatId,\n m.parentId,\n m.name,\n m.type,\n m.data,\n m.createdAt,\n fts.rank,\n snippet(messages_fts, 3, '<mark>', '</mark>', '...', 32) as snippet\n FROM messages_fts fts\n JOIN messages m ON m.id = fts.messageId\n WHERE messages_fts MATCH ?\n AND fts.chatId = ?\n `;\n\n const params: SQLInputValue[] = [query, chatId];\n\n if (roles && roles.length > 0) {\n const placeholders = roles.map(() => '?').join(', ');\n sql += ` AND fts.name IN (${placeholders})`;\n params.push(...roles);\n }\n\n sql += ' ORDER BY fts.rank LIMIT ?';\n params.push(limit);\n\n const rows = this.#db.prepare(sql).all(...params) as {\n id: string;\n chatId: string;\n parentId: string | null;\n name: string;\n type: string | null;\n data: string;\n createdAt: number;\n rank: number;\n snippet: string;\n }[];\n\n return rows.map((row) => ({\n message: {\n id: row.id,\n chatId: row.chatId,\n parentId: row.parentId,\n name: row.name,\n type: row.type ?? undefined,\n data: JSON.parse(row.data),\n createdAt: row.createdAt,\n },\n rank: row.rank,\n snippet: row.snippet,\n }));\n }\n\n // ==========================================================================\n // Visualization Operations\n // ==========================================================================\n\n async getGraph(chatId: string): Promise<GraphData> {\n // Get all messages for complete graph\n const messageRows = this.#db\n .prepare(\n `SELECT id, parentId, name, data, createdAt\n FROM messages\n WHERE chatId = ?\n ORDER BY createdAt ASC`,\n )\n .all(chatId) as {\n id: string;\n parentId: string | null;\n name: string;\n data: string;\n createdAt: number;\n }[];\n\n const nodes: GraphNode[] = messageRows.map((row) => {\n const data = JSON.parse(row.data);\n const content = typeof data === 'string' ? data : JSON.stringify(data);\n return {\n id: row.id,\n parentId: row.parentId,\n role: row.name,\n content: content.length > 50 ? content.slice(0, 50) + '...' : content,\n createdAt: row.createdAt,\n };\n });\n\n // Get all branches\n const branchRows = this.#db\n .prepare(\n `SELECT name, headMessageId, isActive\n FROM branches\n WHERE chatId = ?\n ORDER BY createdAt ASC`,\n )\n .all(chatId) as {\n name: string;\n headMessageId: string | null;\n isActive: number;\n }[];\n\n const branches: GraphBranch[] = branchRows.map((row) => ({\n name: row.name,\n headMessageId: row.headMessageId,\n isActive: row.isActive === 1,\n }));\n\n // Get all checkpoints\n const checkpointRows = this.#db\n .prepare(\n `SELECT name, messageId\n FROM checkpoints\n WHERE chatId = ?\n ORDER BY createdAt ASC`,\n )\n .all(chatId) as {\n name: string;\n messageId: string;\n }[];\n\n const checkpoints: GraphCheckpoint[] = checkpointRows.map((row) => ({\n name: row.name,\n messageId: row.messageId,\n }));\n\n return {\n chatId,\n nodes,\n branches,\n checkpoints,\n };\n }\n}\n", "import { SqliteContextStore } from './sqlite.store.ts';\n\n/**\n * In-memory context store.\n *\n * Uses SQLite's :memory: database for non-persistent storage.\n * Useful for testing and short-lived sessions.\n */\nexport class InMemoryContextStore extends SqliteContextStore {\n constructor() {\n super(':memory:');\n }\n}\n", "import type { GraphData, GraphNode } from './store/store.ts';\n\n/**\n * Render a graph as ASCII art.\n *\n * @param data - The graph data to visualize\n * @returns ASCII art representation of the graph\n *\n * @example\n * ```ts\n * const graph = await store.getGraph('my-chat');\n * console.log(visualizeGraph(graph));\n * ```\n */\nexport function visualizeGraph(data: GraphData): string {\n if (data.nodes.length === 0) {\n return `[chat: ${data.chatId}]\\n\\n(empty)`;\n }\n\n // Build lookup maps\n const childrenByParentId = new Map<string | null, GraphNode[]>();\n const branchHeads = new Map<string, string[]>(); // messageId -> branch names\n const checkpointsByMessageId = new Map<string, string[]>(); // messageId -> checkpoint names\n\n for (const node of data.nodes) {\n const children = childrenByParentId.get(node.parentId) ?? [];\n children.push(node);\n childrenByParentId.set(node.parentId, children);\n }\n\n for (const branch of data.branches) {\n if (branch.headMessageId) {\n const heads = branchHeads.get(branch.headMessageId) ?? [];\n heads.push(branch.isActive ? `${branch.name} *` : branch.name);\n branchHeads.set(branch.headMessageId, heads);\n }\n }\n\n for (const checkpoint of data.checkpoints) {\n const cps = checkpointsByMessageId.get(checkpoint.messageId) ?? [];\n cps.push(checkpoint.name);\n checkpointsByMessageId.set(checkpoint.messageId, cps);\n }\n\n // Find root nodes (parentId === null)\n const roots = childrenByParentId.get(null) ?? [];\n\n const lines: string[] = [`[chat: ${data.chatId}]`, ''];\n\n // Recursively render the tree\n function renderNode(\n node: GraphNode,\n prefix: string,\n isLast: boolean,\n isRoot: boolean,\n ): void {\n const connector = isRoot ? '' : isLast ? '\u2514\u2500\u2500 ' : '\u251C\u2500\u2500 ';\n const contentPreview = node.content.replace(/\\n/g, ' ');\n\n let line = `${prefix}${connector}${node.id.slice(0, 8)} (${node.role}): \"${contentPreview}\"`;\n\n // Add branch markers\n const branches = branchHeads.get(node.id);\n if (branches) {\n line += ` <- [${branches.join(', ')}]`;\n }\n\n // Add checkpoint markers\n const checkpoints = checkpointsByMessageId.get(node.id);\n if (checkpoints) {\n line += ` {${checkpoints.join(', ')}}`;\n }\n\n lines.push(line);\n\n // Render children\n const children = childrenByParentId.get(node.id) ?? [];\n const childPrefix = isRoot ? '' : prefix + (isLast ? ' ' : '\u2502 ');\n\n for (let i = 0; i < children.length; i++) {\n renderNode(children[i], childPrefix, i === children.length - 1, false);\n }\n }\n\n // Render each root\n for (let i = 0; i < roots.length; i++) {\n renderNode(roots[i], '', i === roots.length - 1, true);\n }\n\n // Add legend\n lines.push('');\n lines.push('Legend: * = active branch, {...} = checkpoint');\n\n return lines.join('\\n');\n}\n", "import {\n Output,\n type StreamTextResult,\n type StreamTextTransform,\n type ToolChoice,\n type ToolSet,\n convertToModelMessages,\n createUIMessageStream,\n generateId,\n generateText,\n smoothStream,\n stepCountIs,\n streamText,\n} from 'ai';\nimport chalk from 'chalk';\nimport z from 'zod';\n\nimport { type AgentModel } from '@deepagents/agent';\n\nimport { type ContextEngine, XmlRenderer } from '../index.ts';\nimport { assistantText } from './fragments.ts';\nimport {\n type Guardrail,\n type GuardrailContext,\n type StreamPart,\n runGuardrailChain,\n} from './guardrail.ts';\n\nexport interface CreateAgent<CIn, COut = CIn> {\n name: string;\n context?: ContextEngine;\n tools?: ToolSet;\n model?: AgentModel;\n toolChoice?: ToolChoice<Record<string, COut>>;\n providerOptions?: Parameters<typeof generateText>[0]['providerOptions'];\n logging?: boolean;\n /**\n * Guardrails to apply during streaming.\n * Each guardrail inspects text chunks and can trigger self-correction retries.\n */\n guardrails?: Guardrail[];\n /**\n * Maximum number of retry attempts when guardrails fail (default: 3).\n */\n maxGuardrailRetries?: number;\n}\n\nclass Agent<CIn, COut = CIn> {\n #options: CreateAgent<CIn, COut>;\n #guardrails: Guardrail[] = [];\n readonly tools: ToolSet;\n constructor(options: CreateAgent<CIn, COut>) {\n this.#options = options;\n this.tools = options.tools || {};\n this.#guardrails = options.guardrails || [];\n }\n\n public async generate<COut, CIn = COut>(\n contextVariables: CIn,\n config?: {\n abortSignal?: AbortSignal;\n },\n ) {\n if (!this.#options.context) {\n throw new Error(`Agent ${this.#options.name} is missing a context.`);\n }\n if (!this.#options.model) {\n throw new Error(`Agent ${this.#options.name} is missing a model.`);\n }\n const { messages, systemPrompt } = await this.#options.context.resolve({\n renderer: new XmlRenderer(),\n });\n return generateText({\n abortSignal: config?.abortSignal,\n providerOptions: this.#options.providerOptions,\n model: this.#options.model,\n system: systemPrompt,\n messages: convertToModelMessages(messages as never),\n stopWhen: stepCountIs(25),\n tools: this.#options.tools,\n experimental_context: contextVariables,\n toolChoice: this.#options.toolChoice,\n onStepFinish: (step) => {\n const toolCall = step.toolCalls.at(-1);\n if (toolCall) {\n console.log(\n `Debug: ${chalk.yellow('ToolCalled')}: ${toolCall.toolName}(${JSON.stringify(toolCall.input)})`,\n );\n }\n },\n });\n }\n\n /**\n * Stream a response from the agent.\n *\n * When guardrails are configured, `toUIMessageStream()` is wrapped to provide\n * self-correction behavior. Direct access to fullStream/textStream bypasses guardrails.\n *\n * @example\n * ```typescript\n * const stream = await agent.stream({});\n *\n * // With guardrails - use toUIMessageStream for protection\n * await printer.readableStream(stream.toUIMessageStream());\n *\n * // Or use printer.stdout which uses toUIMessageStream internally\n * await printer.stdout(stream);\n * ```\n */\n public async stream<COut, CIn = COut>(\n contextVariables: CIn,\n config?: {\n abortSignal?: AbortSignal;\n transform?: StreamTextTransform<ToolSet> | StreamTextTransform<ToolSet>[];\n maxRetries?: number;\n },\n ): Promise<StreamTextResult<ToolSet, never>> {\n if (!this.#options.context) {\n throw new Error(`Agent ${this.#options.name} is missing a context.`);\n }\n if (!this.#options.model) {\n throw new Error(`Agent ${this.#options.name} is missing a model.`);\n }\n\n const result = await this.#createRawStream(contextVariables, config);\n\n if (this.#guardrails.length === 0) {\n return result;\n }\n\n return this.#wrapWithGuardrails(result, contextVariables, config);\n }\n\n /**\n * Create a raw stream without guardrail processing.\n */\n async #createRawStream<COut, CIn = COut>(\n contextVariables: CIn,\n config?: {\n abortSignal?: AbortSignal;\n transform?: StreamTextTransform<ToolSet> | StreamTextTransform<ToolSet>[];\n },\n ) {\n const { messages, systemPrompt } = await this.#options.context!.resolve({\n renderer: new XmlRenderer(),\n });\n const runId = generateId();\n return streamText({\n abortSignal: config?.abortSignal,\n providerOptions: this.#options.providerOptions,\n model: this.#options.model!,\n system: systemPrompt,\n messages: convertToModelMessages(messages as never),\n stopWhen: stepCountIs(25),\n experimental_transform: config?.transform ?? smoothStream(),\n tools: this.#options.tools,\n experimental_context: contextVariables,\n toolChoice: this.#options.toolChoice,\n onStepFinish: (step) => {\n const toolCall = step.toolCalls.at(-1);\n if (toolCall) {\n console.log(\n `Debug: (${runId}) ${chalk.bold.yellow('ToolCalled')}: ${toolCall.toolName}(${JSON.stringify(toolCall.input)})`,\n );\n }\n },\n });\n }\n\n /**\n * Wrap a StreamTextResult with guardrail protection on toUIMessageStream().\n *\n * When a guardrail fails:\n * 1. Accumulated text + feedback is appended as the assistant's self-correction\n * 2. The feedback is written to the output stream (user sees the correction)\n * 3. A new stream is started and the model continues from the correction\n */\n #wrapWithGuardrails<CIn>(\n result: StreamTextResult<ToolSet, never>,\n contextVariables: CIn,\n config?: {\n abortSignal?: AbortSignal;\n transform?: StreamTextTransform<ToolSet> | StreamTextTransform<ToolSet>[];\n maxRetries?: number;\n },\n ): StreamTextResult<ToolSet, never> {\n const maxRetries =\n config?.maxRetries ?? this.#options.maxGuardrailRetries ?? 3;\n const context = this.#options.context!;\n\n // Save original method BEFORE override (prevents infinite recursion)\n const originalToUIMessageStream = result.toUIMessageStream.bind(result);\n\n // Override toUIMessageStream with guardrail logic\n result.toUIMessageStream = (options) => {\n return createUIMessageStream({\n generateId,\n execute: async ({ writer }) => {\n let currentResult: StreamTextResult<ToolSet, never> = result;\n let attempt = 0;\n\n // Create guardrail context with available tools\n const guardrailContext: GuardrailContext = {\n availableTools: Object.keys(this.tools),\n };\n\n while (attempt < maxRetries) {\n // Check if request was cancelled before starting new attempt\n if (config?.abortSignal?.aborted) {\n writer.write({ type: 'finish' });\n return;\n }\n\n attempt++;\n let accumulatedText = '';\n let guardrailFailed = false;\n let failureFeedback = '';\n\n // Use original method for first result (avoids recursion), new results have their own original\n const uiStream =\n currentResult === result\n ? originalToUIMessageStream(options)\n : currentResult.toUIMessageStream(options);\n\n // Iterate over toUIMessageStream() - run ALL parts through guardrails\n for await (const part of uiStream) {\n // Run through guardrail chain - guardrails can handle any part type\n const checkResult = runGuardrailChain(\n part as StreamPart,\n this.#guardrails,\n guardrailContext,\n );\n\n if (checkResult.type === 'fail') {\n guardrailFailed = true;\n failureFeedback = checkResult.feedback;\n\n console.log(\n chalk.yellow(\n `[${this.#options.name}] Guardrail triggered (attempt ${attempt}/${maxRetries}): ${failureFeedback.slice(0, 50)}...`,\n ),\n );\n\n break; // Exit stream processing\n }\n\n // Guardrail passed - track text for self-correction context\n if (checkResult.part.type === 'text-delta') {\n accumulatedText += (checkResult.part as { delta: string })\n .delta;\n }\n\n // Write the (possibly modified) part to output\n writer.write(checkResult.part as typeof part);\n }\n\n if (!guardrailFailed) {\n // Stream completed successfully\n writer.write({ type: 'finish' });\n return;\n }\n\n // Check if we've exceeded max retries BEFORE writing feedback\n if (attempt >= maxRetries) {\n console.error(\n chalk.red(\n `[${this.#options.name}] Guardrail retry limit (${maxRetries}) exceeded.`,\n ),\n );\n writer.write({ type: 'finish' });\n return;\n }\n\n // Guardrail failed but we have retries left - prepare for retry\n // Write the self-correction feedback to the output stream\n writer.write({\n type: 'text-delta',\n id: generateId(),\n delta: ` ${failureFeedback}`,\n });\n\n // Add the partial assistant message + feedback to context\n const selfCorrectionText = accumulatedText + ' ' + failureFeedback;\n context.set(assistantText(selfCorrectionText));\n\n // Save to persist the self-correction (prevents duplicate messages on next resolve)\n await context.save();\n\n // Create new stream for retry\n currentResult = await this.#createRawStream(\n contextVariables,\n config,\n );\n }\n },\n onError: (error) => {\n const message =\n error instanceof Error ? error.message : String(error);\n return `Stream failed: ${message}`;\n },\n });\n };\n\n return result;\n }\n\n clone(overrides?: Partial<CreateAgent<CIn, COut>>): Agent<CIn, COut> {\n return new Agent<CIn, COut>({\n ...this.#options,\n ...overrides,\n });\n }\n}\n\nexport function agent<CIn, COut = CIn>(\n options: CreateAgent<CIn, COut>,\n): Agent<CIn, COut> {\n return new Agent(options);\n}\n\n/**\n * Options for creating a structured output handler.\n */\nexport interface StructuredOutputOptions<TSchema extends z.ZodType> {\n name: string;\n context?: ContextEngine;\n model?: AgentModel;\n schema: TSchema;\n providerOptions?: Parameters<typeof generateText>[0]['providerOptions'];\n}\n\n/**\n * Create a structured output handler that provides simplified access to structured output.\n *\n * @param options - Configuration options including schema\n * @returns Object with generate() and stream() methods\n *\n * @example\n * ```typescript\n * const output = structuredOutput({\n * name: 'extractor',\n * model: groq('...'),\n * context,\n * schema: z.object({\n * name: z.string(),\n * age: z.number(),\n * }),\n * });\n *\n * // Generate - returns only the structured output\n * const result = await output.generate({});\n * // result: { name: string, age: number }\n *\n * // Stream - returns the full stream\n * const stream = await output.stream({});\n * ```\n */\nexport function structuredOutput<TSchema extends z.ZodType>(\n options: StructuredOutputOptions<TSchema>,\n) {\n return {\n async generate<CIn>(\n contextVariables?: CIn,\n config?: { abortSignal?: AbortSignal },\n ): Promise<z.infer<TSchema>> {\n if (!options.context) {\n throw new Error(\n `structuredOutput \"${options.name}\" is missing a context.`,\n );\n }\n if (!options.model) {\n throw new Error(\n `structuredOutput \"${options.name}\" is missing a model.`,\n );\n }\n\n const { messages, systemPrompt } = await options.context.resolve({\n renderer: new XmlRenderer(),\n });\n\n const result = await generateText({\n abortSignal: config?.abortSignal,\n providerOptions: options.providerOptions,\n model: options.model,\n system: systemPrompt,\n messages: convertToModelMessages(messages as never),\n stopWhen: stepCountIs(25),\n experimental_context: contextVariables,\n experimental_output: Output.object({ schema: options.schema }),\n });\n\n return result.experimental_output as z.infer<TSchema>;\n },\n\n async stream<CIn>(\n contextVariables?: CIn,\n config?: {\n abortSignal?: AbortSignal;\n transform?:\n | StreamTextTransform<ToolSet>\n | StreamTextTransform<ToolSet>[];\n },\n ) {\n if (!options.context) {\n throw new Error(\n `structuredOutput \"${options.name}\" is missing a context.`,\n );\n }\n if (!options.model) {\n throw new Error(\n `structuredOutput \"${options.name}\" is missing a model.`,\n );\n }\n\n const { messages, systemPrompt } = await options.context.resolve({\n renderer: new XmlRenderer(),\n });\n\n return streamText({\n abortSignal: config?.abortSignal,\n providerOptions: options.providerOptions,\n model: options.model,\n system: systemPrompt,\n messages: convertToModelMessages(messages as never),\n stopWhen: stepCountIs(25),\n experimental_transform: config?.transform ?? smoothStream(),\n experimental_context: contextVariables,\n experimental_output: Output.object({ schema: options.schema }),\n });\n },\n };\n}\n", "import { groq } from '@ai-sdk/groq';\nimport dedent from 'dedent';\nimport z from 'zod';\n\nimport { agent } from '@deepagents/agent';\n\nexport const explainerAgent = agent<{ explanation: string }, { sql: string }>({\n name: 'explainer',\n model: groq('openai/gpt-oss-20b'),\n prompt: (state) => dedent`\n You are an expert SQL tutor.\n Explain the following SQL query in plain English to a non-technical user.\n Focus on the intent and logic, not the syntax.\n\n <sql>\n ${state?.sql}\n </sql>\n `,\n output: z.object({\n explanation: z.string().describe('The explanation of the SQL query.'),\n }),\n});\n", "import { groq } from '@ai-sdk/groq';\nimport dedent from 'dedent';\nimport z from 'zod';\n\nimport { agent, thirdPersonPrompt } from '@deepagents/agent';\n\nimport type { Introspection } from '../adapters/adapter.ts';\nimport { databaseSchemaPrompt } from '../prompt.ts';\n\ntype SuggestionsAgentContext = {\n context?: string;\n adapterInfo?: string;\n};\ntype SuggestionsAgentOutput = {\n suggestions: {\n question: string;\n sql: string;\n businessValue: string;\n }[];\n};\n\nexport const suggestionsAgent = agent<\n SuggestionsAgentOutput,\n SuggestionsAgentContext\n>({\n name: 'text2sql-suggestions',\n model: groq('openai/gpt-oss-20b'),\n output: z.object({\n suggestions: z\n .array(\n z.object({\n question: z\n .string()\n .describe('A complex, high-impact business question.'),\n sql: z\n .string()\n .describe('The SQL statement needed to answer the question.'),\n businessValue: z\n .string()\n .describe('Why the question matters to stakeholders.'),\n }),\n )\n .min(1)\n .max(5)\n .describe('A set of up to two advanced question + SQL pairs.'),\n }),\n prompt: (state) => {\n return dedent`\n ${thirdPersonPrompt()}\n\n <identity>\n You are a senior analytics strategist who proposes ambitious business questions\n and drafts the SQL needed to answer them. You specialize in identifying ideas\n that combine multiple tables, apply segmentation or time analysis, and surface\n metrics that drive executive decisions.\n </identity>\n\n\n <instructions>\n - Recommend one or two UNIQUE questions that go beyond simple counts or listings.\n - Favor questions that require joins, aggregates, time comparisons, cohort analysis,\n or window functions.\n - For each question, explain the business reason stakeholders care about it.\n - Provide the complete SQL query that could answer the question in the given schema.\n - Keep result sets scoped with LIMIT clauses (max 50 rows) when returning raw rows.\n - Ensure table/column names match the provided schema exactly.\n - Use columns marked [LowCardinality: ...] to identify meaningful categorical filters or segmentations.\n - Leverage table [rows / size] hints to determine whether to aggregate (large tables) or inspect detailed data (tiny tables).\n - Reference PK/Indexed annotations and the Indexes list to recommend queries that use efficient join/filter paths.\n - Column annotations may expose ranges/null percentages\u2014use them to suggest realistic thresholds or quality checks.\n - Consult <relationship_examples> to anchor your recommendations in the actual join paths between tables.\n - Output only information grounded in the schema/context provided.\n </instructions>\n\n <response-format>\n Return valid JSON that satisfies the defined output schema.\n </response-format>\n `;\n },\n});\n", "import { groq } from '@ai-sdk/groq';\nimport { type Tool, tool } from 'ai';\nimport z from 'zod';\n\nimport { toState } from '@deepagents/agent';\nimport { agent } from '@deepagents/context';\nimport { scratchpad_tool } from '@deepagents/toolbox';\n\nimport type { Adapter } from '../adapters/adapter.ts';\n\nexport type RenderingTools = Record<string, Tool<unknown, never>>;\n\nconst tools = {\n validate_query: tool({\n description: `Validate SQL query syntax before execution. Use this to check if your SQL is valid before running db_query. This helps catch errors early and allows you to correct the query if needed.`,\n inputSchema: z.object({\n sql: z.string().describe('The SQL query to validate.'),\n }),\n execute: async ({ sql }, options) => {\n const state = toState<{ adapter: Adapter }>(options);\n const result = await state.adapter.validate(sql);\n if (typeof result === 'string') {\n return `Validation Error: ${result}`;\n }\n return 'Query is valid.';\n },\n }),\n db_query: tool({\n description: `Internal tool to fetch data from the store's database. Write a SQL query to retrieve the information needed to answer the user's question. The results will be returned as data that you can then present to the user in natural language.`,\n inputSchema: z.object({\n reasoning: z\n .string()\n .describe(\n 'Your reasoning for why this SQL query is relevant to the user request.',\n ),\n sql: z\n .string()\n .min(1, { message: 'SQL query cannot be empty.' })\n .refine(\n (sql) =>\n sql.trim().toUpperCase().startsWith('SELECT') ||\n sql.trim().toUpperCase().startsWith('WITH'),\n {\n message: 'Only read-only SELECT or WITH queries are allowed.',\n },\n )\n .describe('The SQL query to execute against the database.'),\n }),\n execute: ({ sql }, options) => {\n const state = toState<{ adapter: Adapter }>(options);\n return state.adapter.execute(sql);\n },\n }),\n scratchpad: scratchpad_tool,\n};\n\n/**\n * Chain of Thought prompt for text-to-SQL.\n *\n * Research-backed approach:\n * - Keep reasoning concise to avoid error propagation (EMNLP 2023)\n * - Focus on schema linking and database operations (Struct-SQL 2025)\n * - Use intermediate representations for complex queries\n *\n * @see https://arxiv.org/abs/2305.14215\n * @see https://arxiv.org/html/2512.17053\n */\nconst chainOfThoughtPrompt = `\n## Query Reasoning Process\n\nLet's think step by step before writing SQL:\n\n1. **Schema Link**: Which tables and columns are relevant? Verify they exist in the schema.\n2. **Join Path**: If multiple tables, what relationships connect them?\n3. **Filters**: What WHERE conditions are needed?\n4. **Aggregation**: Is COUNT, SUM, AVG, GROUP BY, or HAVING required?\n5. **Output**: What columns to SELECT and any ORDER BY or LIMIT?\n6. **Verify**: Do all referenced tables and columns exist in the schema above?\n\nFor simple queries, steps 2-4 may not apply\u2014skip them.\n\nFor complex queries requiring multiple data points, decompose into sub-questions:\n- Break the question into simpler parts (Q1, Q2, ...)\n- Determine if each part needs a subquery or CTE\n- Combine the parts into the final query\n\nKeep reasoning brief. Verbose explanations cause errors.\n`;\n\n/**\n * Few-shot examples demonstrating the CoT reasoning process.\n * Uses abstract placeholders (table_a, column_x) for maximum generalization.\n */\nconst fewShotExamples = `\n## Examples\n\n### Example 1: Simple Filter\nQuestion: \"How many records in table_a have column_x equal to 'value'?\"\nReasoning:\n- Schema Link: table_a, column_x\n- Filters: column_x = 'value'\n- Aggregation: COUNT(*)\nSQL: SELECT COUNT(*) FROM table_a WHERE column_x = 'value'\n\n### Example 2: JOIN Query\nQuestion: \"Show column_y from table_b for each record in table_a where column_x is 'value'\"\nReasoning:\n- Schema Link: table_a (column_x, id), table_b (column_y, fk_a)\n- Join Path: table_a.id \u2192 table_b.fk_a\n- Filters: column_x = 'value'\n- Output: column_y from table_b\nSQL: SELECT b.column_y FROM table_a a JOIN table_b b ON b.fk_a = a.id WHERE a.column_x = 'value'\n\n### Example 3: Aggregation with GROUP BY\nQuestion: \"What is the total of column_y grouped by column_x?\"\nReasoning:\n- Schema Link: table_a (column_x, column_y)\n- Aggregation: SUM(column_y), GROUP BY column_x\n- Output: column_x, sum\nSQL: SELECT column_x, SUM(column_y) as total FROM table_a GROUP BY column_x\n\n### Example 4: Complex Aggregation\nQuestion: \"Which values of column_x have more than 10 records, sorted by count descending?\"\nReasoning:\n- Schema Link: table_a (column_x)\n- Aggregation: COUNT(*), GROUP BY column_x, HAVING > 10\n- Output: column_x, count, ORDER BY count DESC\nSQL: SELECT column_x, COUNT(*) as cnt FROM table_a GROUP BY column_x HAVING COUNT(*) > 10 ORDER BY cnt DESC\n\n### Example 5: Subquery (Decomposition)\nQuestion: \"Show records from table_a where column_y is above average\"\nReasoning:\n- Decompose:\n - Q1: What is the average of column_y?\n - Q2: Which records have column_y above that value?\n- Schema Link: table_a (column_y)\n- Filters: column_y > (result of Q1)\n- Output: all columns from matching records\n- Verify: table_a and column_y exist \u2713\nSQL: SELECT * FROM table_a WHERE column_y > (SELECT AVG(column_y) FROM table_a)\n\n### Example 6: Complex Multi-Join (Decomposition)\nQuestion: \"Find the top 3 categories by total sales amount for orders placed last month\"\nReasoning:\n- Decompose:\n - Q1: Which orders were placed last month?\n - Q2: What is the total sales per category for those orders?\n - Q3: Which 3 categories have the highest totals?\n- Schema Link: orders (order_date, id), order_items (order_id, amount, product_id), products (id, category_id), categories (id, name)\n- Join Path: orders \u2192 order_items \u2192 products \u2192 categories\n- Filters: order_date within last month\n- Aggregation: SUM(amount), GROUP BY category\n- Output: category name, total, ORDER BY total DESC, LIMIT 3\n- Verify: all tables and columns exist \u2713\nSQL: SELECT c.name, SUM(oi.amount) as total FROM orders o JOIN order_items oi ON oi.order_id = o.id JOIN products p ON p.id = oi.product_id JOIN categories c ON c.id = p.category_id WHERE o.order_date >= DATE('now', '-1 month') GROUP BY c.id, c.name ORDER BY total DESC LIMIT 3\n`;\n\n/**\n * An agent that does Table Augmented Generation for Text-to-SQL tasks.\n */\nexport const t_a_g = agent<\n { sql: string },\n {\n introspection: string;\n teachings: string;\n }\n>({\n model: groq('openai/gpt-oss-20b'),\n tools,\n name: 'text2sql',\n // prompt: (state) => {\n // return `\n // ${state?.teachings || ''}\n // ${state?.introspection || ''}\n\n // ${chainOfThoughtPrompt}\n\n // ${fewShotExamples}\n // `;\n // },\n});\n", "import { createHash } from 'node:crypto';\nimport { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport pLimit from 'p-limit';\n\nexport interface CheckpointOptions {\n /** Path to the checkpoint file */\n path: string;\n /** Hash to detect config changes - if changed, checkpoint is invalidated */\n configHash?: string;\n}\n\n/**\n * Codec for encoding/decoding values during checkpoint operations.\n * Use this when storing objects with methods (like Teachables) that need\n * to be serialized to plain JSON and restored with their methods.\n */\nexport interface Codec<T, TSerialized = unknown> {\n /** Convert runtime value to JSON-serializable format */\n encode: (value: T) => TSerialized;\n /** Convert stored JSON back to runtime value */\n decode: (serialized: TSerialized) => T;\n}\n\ninterface PointEntry {\n inputHash: string;\n output: unknown;\n}\n\ninterface PointData {\n committed: boolean;\n entries: PointEntry[];\n}\n\ninterface CheckpointFile {\n configHash?: string;\n points: Record<string, PointData>;\n}\n\nexport class Checkpoint {\n private points: Record<string, PointData>;\n\n private constructor(\n private path: string,\n private configHash: string | undefined,\n points: Record<string, PointData>,\n ) {\n this.points = points;\n }\n\n /**\n * Load checkpoint from file, or return empty checkpoint if none exists.\n * Handles corrupted files and config changes gracefully.\n */\n static async load(options: CheckpointOptions): Promise<Checkpoint> {\n const { path, configHash } = options;\n\n if (existsSync(path)) {\n try {\n const content = readFileSync(path, 'utf-8');\n const file: CheckpointFile = JSON.parse(content);\n\n // Check if config changed\n if (configHash && file.configHash && file.configHash !== configHash) {\n console.log('\u26A0 Config changed, starting fresh');\n return new Checkpoint(path, configHash, {});\n }\n\n const points = file.points ?? {};\n const totalEntries = Object.values(points).reduce(\n (sum, p) => sum + p.entries.length,\n 0,\n );\n console.log(`\u2713 Resuming from checkpoint (${totalEntries} entries)`);\n return new Checkpoint(path, configHash, points);\n } catch {\n console.log('\u26A0 Checkpoint corrupted, starting fresh');\n return new Checkpoint(path, configHash, {});\n }\n }\n\n console.log('Starting new checkpoint');\n return new Checkpoint(path, configHash, {});\n }\n\n /**\n * Run a single computation with checkpointing.\n * If already completed, returns cached value.\n *\n * @param key - Unique identifier for this computation\n * @param computation - Async function that produces the value\n * @param codec - Optional codec for encoding/decoding non-primitive values\n */\n async run<T>(\n key: string,\n computation: () => Promise<T>,\n codec?: Codec<T>,\n ): Promise<T> {\n const point = this.point<T>(key);\n\n // Use fixed input hash for single-value runs\n return point.through(\n 'single',\n async () => {\n const result = await computation();\n return codec ? (codec.encode(result) as T) : result;\n },\n codec,\n );\n }\n\n /**\n * Create a resumable checkpoint point for iterative operations.\n *\n * @param step - Unique identifier for this checkpoint point\n */\n point<T>(step: string): Point<T> {\n this.points[step] ??= { committed: false, entries: [] };\n return new Point<T>(this.points[step], () => this.save());\n }\n\n /**\n * Process each input with automatic checkpointing and concurrency.\n *\n * @param step - Unique identifier for this checkpoint\n * @param inputs - Items to process\n * @param process - Function to process each input\n * @param options - Optional settings like concurrency\n * @returns All outputs (use `.flat()` if outputs are arrays)\n */\n async each<I, O>(\n step: string,\n inputs: Iterable<I>,\n process: (input: I) => Promise<O>,\n options?: { concurrency?: number },\n ): Promise<O[]> {\n const point = this.point<O>(step);\n const limit = pLimit(options?.concurrency ?? 1);\n\n const inputArray = Array.from(inputs);\n await Promise.all(\n inputArray.map((input) =>\n limit(() => point.through(input, () => process(input))),\n ),\n );\n\n await point.commit();\n return point.values();\n }\n\n /**\n * Get clean output from all completed points.\n * Single-entry points return the value directly, multi-entry return arrays.\n */\n getOutput(): Record<string, unknown> {\n const output: Record<string, unknown> = {};\n for (const [key, pointData] of Object.entries(this.points)) {\n if (pointData.entries.length === 1) {\n output[key] = pointData.entries[0].output;\n } else {\n output[key] = pointData.entries.map((e) => e.output);\n }\n }\n return output;\n }\n\n /** Get the file path where checkpoint is stored */\n getPath(): string {\n return this.path;\n }\n\n private async save(): Promise<void> {\n const file: CheckpointFile = {\n configHash: this.configHash,\n points: this.points,\n };\n const content = JSON.stringify(file, null, 2);\n\n // Atomic write: write to temp file, then rename\n const tempPath = `${this.path}.tmp`;\n writeFileSync(tempPath, content);\n renameSync(tempPath, this.path);\n }\n}\n\nfunction hash(value: unknown): string {\n return createHash('md5').update(JSON.stringify(value)).digest('hex');\n}\n\n/**\n * A checkpoint point for tracking iterative operations.\n * Uses input hashing to determine if an operation was already processed.\n */\nexport class Point<T> {\n #cache: Map<string, T>;\n\n constructor(\n private data: PointData,\n private persist: () => Promise<void>,\n ) {\n this.#cache = new Map(\n data.entries.map((e) => [e.inputHash, e.output as T]),\n );\n }\n\n /**\n * Execute computation if input wasn't processed before.\n * Returns cached output if input hash exists, otherwise executes, saves, and returns.\n */\n async through<I, O>(\n input: I,\n compute: () => Promise<O>,\n codec?: Codec<O>,\n ): Promise<O> {\n const inputHash = hash(input);\n\n if (this.#cache.has(inputHash)) {\n const cached = this.#cache.get(inputHash) as O;\n return codec ? codec.decode(cached) : cached;\n }\n\n const output = await compute();\n this.data.entries.push({ inputHash, output });\n this.#cache.set(inputHash, output as T);\n await this.persist();\n return codec ? codec.decode(output) : output;\n }\n\n /** Mark this point as complete. */\n async commit(): Promise<void> {\n this.data.committed = true;\n await this.persist();\n }\n\n /** Check if this point has been committed. */\n isCommitted(): boolean {\n return this.data.committed;\n }\n\n /** Get all outputs from this point. */\n values(): T[] {\n return this.data.entries.map((e) => e.output as T);\n }\n}\n\n/**\n * Generate a hash from a config object for checkpoint invalidation.\n * If config changes, the checkpoint will be invalidated and pipeline restarts.\n */\nexport function hashConfig(config: Record<string, unknown>): string {\n return createHash('md5').update(JSON.stringify(config)).digest('hex');\n}\n", "import { createHash } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport path from 'node:path';\n\nexport class FileCache {\n public path: string;\n constructor(watermark: string, extension = '.txt') {\n const hash = createHash('md5').update(watermark).digest('hex');\n this.path = path.join(tmpdir(), `text2sql-${hash}${extension}`);\n }\n\n async get() {\n if (existsSync(this.path)) {\n return readFile(this.path, 'utf-8');\n }\n return null;\n }\n\n set(content: string) {\n return writeFile(this.path, content, 'utf-8');\n }\n}\n\nexport class JsonCache<T> extends FileCache {\n constructor(watermark: string) {\n super(watermark, '.json');\n }\n\n async read(): Promise<T | null> {\n const content = await this.get();\n if (content) {\n return JSON.parse(content) as T;\n }\n return null;\n }\n\n write(data: T) {\n return this.set(JSON.stringify(data));\n }\n}\n", "import {\n APICallError,\n InvalidToolInputError,\n NoSuchToolError,\n ToolCallRepairError,\n type UIMessage,\n generateId,\n} from 'ai';\n\nimport { type AgentModel } from '@deepagents/agent';\nimport {\n ContextEngine,\n type ContextFragment,\n type ContextStore,\n agent,\n assistant,\n hint,\n styleGuide,\n user as userFragment,\n} from '@deepagents/context';\n\nimport type { Adapter } from './adapters/adapter.ts';\nimport developerExports from './agents/developer.agent.ts';\nimport { toSql } from './agents/sql.agent.ts';\nimport { type RenderingTools, t_a_g } from './agents/text2sql.agent.ts';\nimport { JsonCache } from './file-cache.ts';\nimport { type ExtractedPair, type PairProducer } from './synthesis/types.ts';\nimport { type TeachingsOptions, guidelines } from './teach/teachings.ts';\n\nexport class Text2Sql {\n #config: {\n model: AgentModel;\n adapter: Adapter;\n store: ContextStore;\n tools?: RenderingTools;\n instructions: ContextFragment[];\n introspection: JsonCache<ContextFragment[]>;\n };\n\n constructor(config: {\n adapter: Adapter;\n store: ContextStore;\n version: string;\n tools?: RenderingTools;\n instructions?: ContextFragment[];\n model: AgentModel;\n /**\n * Configure teachings behavior\n * @see TeachingsOptions\n */\n teachingsOptions?: TeachingsOptions;\n }) {\n this.#config = {\n adapter: config.adapter,\n store: config.store,\n instructions: [\n ...guidelines(config.teachingsOptions),\n ...(config.instructions ?? []),\n ],\n tools: config.tools ?? {},\n model: config.model,\n introspection: new JsonCache<ContextFragment[]>(\n 'introspection-' + config.version,\n ),\n };\n }\n\n public async toSql(input: string): Promise<string> {\n const schemaFragments = await this.index();\n\n const result = await toSql({\n input,\n adapter: this.#config.adapter,\n schemaFragments,\n instructions: this.#config.instructions,\n model: this.#config.model,\n });\n\n return result.sql;\n }\n\n /**\n * Introspect the database schema and return context fragments.\n * Results are cached to avoid repeated introspection.\n */\n public async index(): Promise<ContextFragment[]> {\n const cached = await this.#config.introspection.read();\n if (cached) {\n return cached;\n }\n const fragments = await this.#config.adapter.introspect();\n await this.#config.introspection.write(fragments);\n return fragments;\n }\n\n /**\n * Generate training data pairs using a producer factory.\n * The factory receives the configured adapter, so users don't need to pass it manually.\n *\n * @example\n * // Generate questions for existing SQL\n * const pairs = await text2sql.toPairs(\n * (adapter) => new SqlExtractor(sqls, adapter, { validateSql: true })\n * );\n *\n * @example\n * // Extract from chat history with validation\n * const pairs = await text2sql.toPairs(\n * (adapter) => new ValidatedProducer(\n * new MessageExtractor(messages),\n * adapter\n * )\n * );\n */\n public async toPairs<T extends PairProducer>(\n factory: (adapter: Adapter) => T,\n ): Promise<ExtractedPair[]> {\n const producer = factory(this.#config.adapter);\n return producer.toPairs();\n }\n\n /**\n * Build instructions for rendering tools (hint + styleGuide).\n * Returns fragments to include when render_* tools are available.\n */\n #buildRenderingInstructions(): ContextFragment[] {\n const renderToolNames = Object.keys(this.#config.tools ?? {}).filter(\n (name) => name.startsWith('render_'),\n );\n\n if (!renderToolNames.length) {\n return [];\n }\n\n return [\n hint(`Rendering tools available: ${renderToolNames.join(', ')}.`),\n styleGuide({\n prefer:\n 'Use render_* tools for trend/over time/monthly requests or chart asks',\n always:\n 'Include text insight alongside visualizations. Prefer line charts for time-based data.',\n }),\n ];\n }\n\n public async chat(\n messages: UIMessage[],\n params: {\n chatId: string;\n userId: string;\n },\n ) {\n const schemaFragments = await this.index();\n\n const context = new ContextEngine({\n store: this.#config.store,\n chatId: params.chatId,\n }).set(\n ...this.#config.instructions,\n ...this.#buildRenderingInstructions(),\n ...schemaFragments,\n );\n\n const userMsg = messages.at(-1);\n if (userMsg) {\n context.set(userFragment(userMsg));\n await context.save();\n }\n\n const chatAgent = t_a_g.clone({\n model: this.#config.model,\n context,\n tools: { ...t_a_g.tools, ...this.#config.tools },\n });\n\n const result = await chatAgent.stream({});\n\n return result.toUIMessageStream({\n onError: (error) => this.#formatError(error),\n sendStart: true,\n sendFinish: true,\n sendReasoning: true,\n sendSources: true,\n generateMessageId: generateId,\n onFinish: async ({ responseMessage }) => {\n context.set(assistant(responseMessage));\n await context.save();\n },\n });\n }\n\n /**\n * Developer chat interface - power-user mode for SQL generation.\n * Uses db_query tool for direct SQL execution (LLM writes SQL).\n */\n public async developer(\n messages: UIMessage[],\n params: {\n chatId: string;\n userId: string;\n },\n ) {\n const schemaFragments = await this.index();\n\n const context = new ContextEngine({\n store: this.#config.store,\n chatId: params.chatId,\n }).set(\n ...developerExports.fragments,\n ...this.#config.instructions,\n ...schemaFragments,\n );\n\n const userMsg = messages.at(-1);\n if (userMsg) {\n context.set(userFragment(userMsg));\n await context.save();\n }\n\n const developerAgent = agent({\n name: 'developer',\n model: this.#config.model,\n context,\n tools: developerExports.tools,\n });\n\n const result = await developerAgent.stream({\n adapter: this.#config.adapter,\n });\n\n return result.toUIMessageStream({\n onError: (error) => this.#formatError(error),\n sendStart: true,\n sendFinish: true,\n sendReasoning: true,\n sendSources: true,\n generateMessageId: generateId,\n onFinish: async ({ responseMessage }) => {\n context.set(assistant(responseMessage));\n await context.save();\n },\n });\n }\n\n #formatError(error: unknown): string {\n if (NoSuchToolError.isInstance(error)) {\n return 'The model tried to call an unknown tool.';\n } else if (InvalidToolInputError.isInstance(error)) {\n return 'The model called a tool with invalid arguments.';\n } else if (ToolCallRepairError.isInstance(error)) {\n return 'The model tried to call a tool with invalid arguments, but it was repaired.';\n } else if (APICallError.isInstance(error)) {\n console.error('Upstream API call failed:', error);\n return `Upstream API call failed with status ${(error as APICallError).statusCode}: ${(error as APICallError).message}`;\n }\n return JSON.stringify(error);\n }\n}\n", "import { groq } from '@ai-sdk/groq';\nimport {\n APICallError,\n JSONParseError,\n NoContentGeneratedError,\n NoObjectGeneratedError,\n NoOutputGeneratedError,\n TypeValidationError,\n defaultSettingsMiddleware,\n wrapLanguageModel,\n} from 'ai';\nimport { Console } from 'node:console';\nimport { createWriteStream } from 'node:fs';\nimport pRetry from 'p-retry';\nimport z from 'zod';\n\nimport { type AgentModel } from '@deepagents/agent';\nimport {\n ContextEngine,\n type ContextFragment,\n InMemoryContextStore,\n XmlRenderer,\n persona,\n structuredOutput,\n user,\n} from '@deepagents/context';\n\nimport type { Adapter } from '../adapters/adapter.ts';\n\nexport interface ToSqlOptions {\n /** The natural language input to convert to SQL */\n input: string;\n /** Database adapter for validation */\n adapter: Adapter;\n /** Schema fragments from adapter introspection */\n schemaFragments: ContextFragment[];\n /** Instructions/teachings to include */\n instructions: ContextFragment[];\n /** Optional model override */\n model?: AgentModel;\n /** Maximum retry attempts on validation failure (default: 3) */\n maxRetries?: number;\n}\n\nexport interface ToSqlResult {\n /** The generated SQL query */\n sql: string;\n /** Number of attempts made */\n attempts: number;\n /** Validation errors encountered (if any retries occurred) */\n errors?: string[];\n}\n\nconst logger = new Console({\n stdout: createWriteStream('./sql-agent.log', { flags: 'a' }),\n stderr: createWriteStream('./sql-agent-error.log', { flags: 'a' }),\n inspectOptions: { depth: null },\n});\n\n/** Temperature progression for retries: deterministic first, then increasingly exploratory */\nconst RETRY_TEMPERATURES = [0, 0.2, 0.3];\n\n/** Extract SQL from markdown fenced code block if present */\nfunction extractSql(output: string): string {\n const match = output.match(/```sql\\n?([\\s\\S]*?)```/);\n return match ? match[1].trim() : output.trim();\n}\n\nconst marker = Symbol('SQLValidationError');\n/**\n * Error thrown when SQL validation fails.\n */\nexport class SQLValidationError extends Error {\n [marker]: true;\n constructor(message: string) {\n super(message);\n this.name = 'SQLValidationError';\n this[marker] = true;\n }\n static isInstance(error: unknown): error is SQLValidationError {\n return error instanceof SQLValidationError && error[marker] === true;\n }\n}\n\n/**\n * Error thrown when the question cannot be answered with the given schema.\n */\nexport class UnanswerableSQLError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'UnanswerableSQLError';\n }\n static isInstance(error: unknown): error is UnanswerableSQLError {\n return error instanceof UnanswerableSQLError;\n }\n}\n\nexport async function toSql(options: ToSqlOptions): Promise<ToSqlResult> {\n const { maxRetries = 3 } = options;\n\n return withRetry(\n async (attemptNumber, errors, attempts) => {\n const context = new ContextEngine({\n store: new InMemoryContextStore(),\n chatId: `sql-gen-${crypto.randomUUID()}`,\n });\n\n context.set(\n persona({\n name: 'Freya',\n role: 'You are an expert SQL query generator. You translate natural language questions into precise, efficient SQL queries based on the provided database schema.',\n }),\n ...options.instructions,\n ...options.schemaFragments,\n );\n\n // Add user message(s)\n if (errors.length) {\n context.set(\n user(options.input),\n user(\n `<validation_error>Your previous SQL query had the following error: ${errors.at(-1)?.message}. Please fix the query.</validation_error>`,\n ),\n );\n } else {\n context.set(user(options.input));\n }\n\n // Create structured output with schema\n const sqlOutput = structuredOutput({\n name: 'text2sql',\n model: wrapLanguageModel({\n model: options.model ?? groq('openai/gpt-oss-20b'),\n middleware: defaultSettingsMiddleware({\n settings: {\n temperature: RETRY_TEMPERATURES[attemptNumber - 1] ?? 0.3,\n topP: 1,\n },\n }),\n }),\n context,\n schema: z.union([\n z.object({\n sql: z.string().describe('The SQL query that answers the question'),\n reasoning: z\n .string()\n .optional()\n .describe('The reasoning steps taken to generate the SQL'),\n }),\n z.object({\n error: z\n .string()\n .describe(\n 'Error message explaining why the question cannot be answered with the given schema',\n ),\n }),\n ]),\n });\n\n const output = await sqlOutput.generate();\n\n // Handle error responses (question is unanswerable with given schema)\n if ('error' in output) {\n throw new UnanswerableSQLError(output.error);\n }\n\n const sql = extractSql(output.sql);\n\n // Validate the generated SQL\n const validationError = await options.adapter.validate(sql);\n if (validationError) {\n throw new SQLValidationError(validationError);\n }\n\n return {\n attempts,\n sql,\n errors: errors.length ? errors.map(formatErrorMessage) : undefined,\n };\n },\n { retries: maxRetries - 1 },\n );\n}\n\nfunction formatErrorMessage(error: Error) {\n if (APICallError.isInstance(error)) {\n if (error.message.startsWith('Failed to validate JSON')) {\n return `Schema validation failed: ${error.message}`;\n }\n return error.message;\n }\n if (SQLValidationError.isInstance(error)) {\n return `SQL Validation Error: ${error.message}`;\n }\n return error.message;\n}\n\nasync function withRetry<T>(\n computation: (\n attemptNumber: number,\n errors: Error[],\n attempts: number,\n ) => Promise<T>,\n options: { retries: number } = { retries: 3 },\n) {\n const errors: Error[] = [];\n let attempts = 0;\n return pRetry(\n (attemptNumber) => {\n return computation(attemptNumber, errors, ++attempts);\n },\n {\n retries: options.retries,\n shouldRetry: (context) => {\n // Don't retry if unanswerable - it's intentional\n if (UnanswerableSQLError.isInstance(context.error)) {\n return false;\n }\n // Retry on validation errors\n if (SQLValidationError.isInstance(context.error)) {\n return true;\n }\n console.log({\n NoObjectGeneratedError: NoObjectGeneratedError.isInstance(\n context.error,\n ),\n NoOutputGeneratedError: NoOutputGeneratedError.isInstance(\n context.error,\n ),\n APICallError: APICallError.isInstance(context.error),\n JSONParseError: JSONParseError.isInstance(context.error),\n TypeValidationError: TypeValidationError.isInstance(context.error),\n NoContentGeneratedError: NoContentGeneratedError.isInstance(\n context.error,\n ),\n });\n // Retry on AI SDK errors\n return (\n APICallError.isInstance(context.error) ||\n JSONParseError.isInstance(context.error) ||\n TypeValidationError.isInstance(context.error) ||\n NoObjectGeneratedError.isInstance(context.error) ||\n NoOutputGeneratedError.isInstance(context.error) ||\n NoContentGeneratedError.isInstance(context.error)\n );\n },\n onFailedAttempt(context) {\n logger.error(`toSQL`, context.error);\n console.log(\n `Attempt ${context.attemptNumber} failed. There are ${context.retriesLeft} retries left.`,\n );\n // console.dir(context.error, { depth: null });\n errors.push(context.error);\n },\n },\n );\n}\n", "import {\n type ContextFragment,\n clarification,\n guardrail,\n hint,\n styleGuide,\n workflow,\n} from '@deepagents/context';\n\nexport interface TeachingsOptions {\n /**\n * Controls date/time clarification behavior:\n * - 'strict': Ask for clarification when date range is missing (production default)\n * - false: Skip date clarifications, assume all matching data (useful for evals/benchmarks)\n */\n date?: 'strict' | false;\n}\n\nexport function guidelines(options: TeachingsOptions = {}): ContextFragment[] {\n const { date = 'strict' } = options;\n\n const baseTeachings: ContextFragment[] = [\n // Schema adherence\n hint(\n 'Use only tables and columns that exist in the schema. Never reference non-existent entities.',\n ),\n hint(\n 'If the user asks to show a table or entity without specifying columns, use SELECT *.',\n ),\n hint(\n 'When showing items associated with another entity, include the item ID and the related details requested.',\n ),\n hint(\n 'When asked to \"show\" items, list them unless the user explicitly asks to count or total.',\n ),\n hint(\n 'Use canonical/LowCardinality values verbatim for filtering; [rows/size] hints suggest when to aggregate instead of listing.',\n ),\n\n // Joins and relationships\n hint(\n 'Use appropriate JOINs based on the relationships defined in the schema.',\n ),\n hint(\n 'Favor PK/indexed columns for joins and filters; follow relationship metadata for join direction and cardinality.',\n ),\n\n // Aggregations and calculations\n hint(\n 'Apply proper aggregations (COUNT, SUM, AVG, etc.) when the question implies summarization.',\n ),\n hint(\n 'When asked \"how many X are there\" about types/categories/statuses (e.g., \"how many statuses are there?\"), use COUNT(DISTINCT column). This asks about variety, not row count.',\n ),\n hint(\n 'Use window functions when the question requires ranking, running totals, or comparisons across rows.',\n ),\n\n // Query semantics\n hint(\n 'Words like \"reach\", \"reached\", \"hit\" with a value (e.g., \"temperature reach 80\") mean >= (greater than or equal), not = (exact match).',\n ),\n hint(\n 'For \"shared by\" two groups or mutually exclusive conditions (e.g., population > 1500 AND < 500), use INTERSECT between separate queries. A single WHERE with contradictory AND returns nothing.',\n ),\n hint(\n 'When filtering by a specific value from a joined table (e.g., \"students who registered course statistics\"), always include that WHERE condition. Do not omit mentioned filters.',\n ),\n hint(\n 'Handle NULL values appropriately using IS NULL, IS NOT NULL, or COALESCE.',\n ),\n\n // Style and readability\n styleGuide({\n prefer:\n 'For table aliases, use the full table name (e.g., \"FROM users AS users\", \"JOIN order_items AS order_items\"). For column aliases, use descriptive names that reflect the data (e.g., \"COUNT(*) AS total_orders\").',\n never:\n 'Use abbreviated table aliases (u, oi, ca) or generic positional aliases (t1, t2, a, b).',\n }),\n styleGuide({\n prefer:\n 'Summaries should be concise, business-friendly, highlight key comparisons, and add a short helpful follow-up when useful.',\n }),\n\n // Guardrails - Query safety\n guardrail({\n rule: 'Generate ONLY valid, executable SQL.',\n reason: 'Invalid SQL wastes resources and confuses users.',\n action: 'Validate syntax and schema references before returning.',\n }),\n guardrail({\n rule: 'Only generate SELECT/WITH statements (read-only queries).',\n reason: 'Prevents accidental data modification.',\n action:\n 'Never generate INSERT, UPDATE, DELETE, DROP, or other DDL/DML statements.',\n }),\n guardrail({\n rule: 'Avoid unbounded scans on large tables.',\n reason: 'Protects performance and prevents runaway queries.',\n action:\n 'Ensure filters are applied on indexed columns before querying broad fact tables.',\n }),\n guardrail({\n rule: 'Do not add LIMIT unless explicitly requested.',\n action:\n 'Only add LIMIT when user explicitly asks for \"top N\", \"first N\", or similar. Do NOT add LIMIT for \"list all\", \"show all\", or simple \"list\" queries.',\n reason: 'Adding arbitrary limits changes query semantics.',\n }),\n guardrail({\n rule: 'Add ORDER BY where appropriate for deterministic results.',\n reason: 'Ensures consistent query output.',\n action:\n 'Include ORDER BY when results have a natural ordering or when combined with LIMIT.',\n }),\n guardrail({\n rule: 'Prevent cartesian or guesswork joins.',\n reason: 'Protect correctness and performance.',\n action:\n 'If join keys are missing or unclear, inspect relationships and ask for the intended join path before executing.',\n }),\n guardrail({\n rule: 'Ensure the query is optimized for the schema.',\n reason: 'Better performance and resource usage.',\n action:\n 'Use indexed columns for filtering, avoid SELECT * on large joins, prefer specific column selection when appropriate.',\n }),\n guardrail({\n rule: 'When facing genuine ambiguity with multiple valid interpretations, seek clarification.',\n reason: 'Prevents incorrect assumptions in edge cases.',\n action:\n 'Ask a focused clarifying question before proceeding with a guess.',\n }),\n\n // Clarifications\n clarification({\n when: 'The request uses ambiguous scoring or ranking language (e.g., \"top\", \"best\", \"active\") without a metric.',\n ask: 'Clarify the ranking metric or definition before writing the query.',\n reason: 'Ensures the correct aggregation/ordering is used.',\n }),\n\n // Workflow\n workflow({\n task: 'SQL generation plan',\n steps: [\n 'Scan column names for terms matching the question. If a phrase like \"total X\" or \"number of Y\" matches a column name (e.g., Total_X, Num_Y), select that column directly instead of aggregating.',\n 'Translate the question into SQL patterns (aggregation, segmentation, time range, ranking) only if no column name match.',\n 'Choose tables/relations that satisfy those patterns; note lookup tables and filter values implied by schema hints.',\n 'Sketch join/filter/aggregation order considering table sizes, indexes, and stats.',\n 'Generate precise, validated SQL that answers the question.',\n ],\n }),\n ];\n\n // Date-specific clarifications (only when strict)\n if (date === 'strict') {\n baseTeachings.push(\n clarification({\n when: 'The request targets time-based data without a date range.',\n ask: 'Confirm the intended timeframe (e.g., last 30/90 days, YTD, specific year).',\n reason: 'Prevents large scans and irrelevant results.',\n }),\n );\n } else {\n // When date is false, assume all matching data without asking\n baseTeachings.push(\n hint(\n 'When a month, day, or time period is mentioned without a year (e.g., \"in August\", \"on Monday\"), assume ALL occurrences of that period in the data. Do not ask for year clarification.',\n ),\n );\n }\n\n return baseTeachings;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["fragments", "c", "table", "dedent", "z", "spawn", "generateId", "fragment", "message", "fragments", "fragment", "fragments", "fragment", "message", "guardrail", "path", "message", "generateId", "message", "agent", "z", "dedent", "groq", "dedent", "z", "agent", "agent", "groq", "z", "dedent", "groq", "tool", "z", "toState", "tools", "tool", "z", "toState", "groq", "tools", "path", "process", "createHash", "existsSync", "hash", "APICallError", "generateId", "groq", "z", "message", "groq", "z", "fragments", "generateId", "APICallError"]
7
7
  }