{"version":3,"file":"index.mjs","names":[],"sources":["../src/provider.ts","../src/token-pool.ts","../src/tools.ts","../src/antrhopic.ts","../src/open-ai.ts","../src/helpers.ts","../src/kd-tree.ts","../src/memory.ts","../src/llm.ts","../src/audio.ts","../src/vision.ts","../src/ai.ts"],"sourcesContent":["import {AbortablePromise} from './ai.ts';\nimport {LLMRequest} from './llm.ts';\n\nexport abstract class LLMProvider {\n\tabstract ask(message: string, options: LLMRequest): AbortablePromise<string>;\n}\n","const DEFAULT_COOLDOWN = 15 * 60 * 1000;\n\ntype TokenState = {\n\ttoken: string;\n\tcooldownUntil: number; // 0 = available now\n\tlastError?: {code: number, message: string};\n};\n\nexport class TokenPoolExhaustedError extends Error {\n\tconstructor(public tokens: Record<string, {code: number, message: string}>) {\n\t\tsuper(`All tokens exhausted:\\n${Object.entries(tokens).map(([t, e]) => `${t}: [${e.code}] ${e.message}`).join('\\n')}`);\n\t\tthis.name = 'TokenPoolExhaustedError';\n\t}\n}\n\nexport class TokenPool {\n\tprivate states: TokenState[];\n\n\tconstructor(...tokens: string[]) {\n\t\tthis.states = tokens.map(token => ({token, cooldownUntil: 0}));\n\t}\n\n\tprivate preview(token: string): string {\n\t\treturn token.length <= 8 ? '****' : `${token.slice(0, 4)}...${token.slice(-4)}`;\n\t}\n\n\t/** Anthropic & OpenAI SDKs both attach `status` to thrown errors */\n\tprivate statusCode(err: any): number {\n\t\treturn err?.status ?? err?.response?.status ?? err?.statusCode;\n\t}\n\n\tprivate retryAfter(err: any): number {\n\t\tconst headers = err?.headers || err?.response?.headers;\n\t\tconst raw = headers?.get?.('retry-after') ?? headers?.['retry-after'];\n\t\tif(raw) {\n\t\t\tconst seconds = Number(raw);\n\t\t\tif(!isNaN(seconds)) return Date.now() + seconds * 1000;\n\t\t\tconst date = new Date(raw).getTime();\n\t\t\tif(!isNaN(date)) return date;\n\t\t}\n\t\treturn Date.now() + DEFAULT_COOLDOWN;\n\t}\n\n\tasync run<T>(fn: (token: string) => Promise<T>): Promise<T> {\n\t\tconst now = Date.now();\n\t\tfor(const state of this.states) {\n\t\t\tif(state.cooldownUntil > now) continue;\n\t\t\ttry {\n\t\t\t\tconst result = await fn(state.token);\n\t\t\t\tstate.cooldownUntil = 0;\n\t\t\t\tstate.lastError = undefined;\n\t\t\t\treturn result;\n\t\t\t} catch(err: any) {\n\t\t\t\tconst code = this.statusCode(err);\n\t\t\t\tif(![401, 403, 429].includes(code)) throw err;\n\t\t\t\tstate.cooldownUntil = code === 429 ? this.retryAfter(err) : Date.now() + DEFAULT_COOLDOWN;\n\t\t\t\tstate.lastError = {code, message: err?.message || 'Unknown error'};\n\t\t\t}\n\t\t}\n\n\t\tconst failures: Record<string, {code: number, message: string}> = {};\n\t\tthis.states.forEach(s => { if(s.lastError) failures[this.preview(s.token)] = s.lastError; });\n\t\tthrow new TokenPoolExhaustedError(failures);\n\t}\n}\n","import  * as cheerio from 'cheerio';\nimport {$Sync} from '@ztimson/node-utils';\nimport {ASet, consoleInterceptor, Http, fn as Fn, decodeHtml, objectMap} from '@ztimson/utils';\nimport * as os from 'node:os';\nimport {Ai} from './ai.ts';\nimport {LLMRequest} from './llm.ts';\n\nconst UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)';\n\nconst getShell = () => {\n\tif(os.platform() == 'win32') return 'cmd';\n\treturn $Sync`echo $SHELL`?.split('/').pop() || 'bash';\n}\n\nexport type AiToolArg = {[key: string]: {\n\t/** Argument type */\n\ttype: 'array' | 'boolean' | 'number' | 'object' | 'string',\n\t/** Argument description */\n\tdescription: string,\n\t/** Required argument */\n\trequired?: boolean;\n\t/** Default value */\n\tdefault?: any,\n\t/** Options */\n\tenum?: string[],\n\t/** Minimum value or length */\n\tmin?: number,\n\t/** Maximum value or length */\n\tmax?: number,\n\t/** Match pattern */\n\tpattern?: string,\n\t/** Child arguments */\n\titems?: {[key: string]: AiToolArg}\n}}\n\nexport type AiTool = {\n\t/** Tool ID / Name - Must be snail_case */\n\tname: string,\n\t/** Tool description / prompt */\n\tdescription: string,\n\t/** Tool arguments */\n\targs?: AiToolArg,\n\t/** Callback function */\n\tfn: (args: any, stream: LLMRequest['stream'], ai: Ai, toolId?: string) => any | Promise<any>,\n};\n\nexport function convertSchema(schema: any): any {\n\tif(!schema) return null;\n\n\tconst convertProp = (prop: any): any => {\n\t\tconst converted: any = {\n\t\t\ttype: prop.type || 'string',\n\t\t};\n\n\t\tif(prop.description) converted.description = prop.description;\n\t\tif(prop.default !== undefined) converted.default = prop.default;\n\t\tif(prop.enum) converted.enum = prop.enum;\n\t\tif(prop.pattern) converted.pattern = prop.pattern;\n\n\t\t// Handle array items\n\t\tif(prop.type === 'array' && prop.items) {\n\t\t\tconverted.items = convertProp(prop.items);\n\t\t}\n\n\t\t// Handle object properties\n\t\tif(prop.type === 'object' && prop.items) {\n\t\t\tconverted.properties = objectMap(prop.items, (key, value) => convertProp(value));\n\t\t\tconst required = Object.entries(prop.items).filter(([_, v]: any) => v.required).map(([k]) => k);\n\t\t\tif(required.length) converted.required = required;\n\t\t\tconverted.additionalProperties = false;\n\t\t}\n\n\t\t// Handle min/max based on type\n\t\tif(prop.min !== undefined) {\n\t\t\tif(prop.type === 'string' || prop.type === 'array') converted.minLength = prop.min;\n\t\t\telse converted.minimum = prop.min;\n\t\t}\n\t\tif(prop.max !== undefined) {\n\t\t\tif(prop.type === 'string' || prop.type === 'array') converted.maxLength = prop.max;\n\t\t\telse converted.maximum = prop.max;\n\t\t}\n\n\t\treturn converted;\n\t};\n\n\treturn {\n\t\ttype: 'object',\n\t\tproperties: objectMap(schema, (key, value) => convertProp(value)),\n\t\trequired: Object.entries(schema).filter(([_, v]: any) => v.required).map(([k]) => k),\n\t\tadditionalProperties: false\n\t};\n}\n\nexport const ExecCliTool: AiTool = {\n\tname: 'cli',\n\tdescription: 'Use the command line interface, returns any output',\n\targs: {command: {type: 'string', description: 'Command to run', required: true}},\n\tfn: (args: {command: string}) => $Sync`${args.command}`\n}\n\nexport const ExecJSTool: AiTool = {\n\tname: 'exec_javascript',\n\tdescription: 'Execute commonjs javascript',\n\targs: {\n\t\tcode: {type: 'string', description: 'CommonJS javascript', required: true}\n\t},\n\tfn: async (args: {code: string}) => {\n\t\tconst c = consoleInterceptor(null);\n\t\tconst resp = await Fn<any>({console: c}, args.code, true).catch((err: any) => c.output.error.push(err));\n\t\treturn {...c.output, return: resp, stdout: undefined, stderr: undefined};\n\t}\n}\n\nexport const ExecPythonTool: AiTool = {\n\tname: 'exec_python',\n\tdescription: 'Execute commonjs javascript',\n\targs: {\n\t\tcode: {type: 'string', description: 'CommonJS javascript', required: true}\n\t},\n\tfn: async (args: {code: string}) => ({result: $Sync`python -c \"${args.code}\"`})\n}\n\nexport const ExecTool: AiTool = {\n\tname: 'exec',\n\tdescription: 'Run code/scripts',\n\targs: {\n\t\tlanguage: {type: 'string', description: `Execution language (CLI: ${getShell()})`, enum: ['cli', 'node', 'python'], required: true},\n\t\tcode: {type: 'string', description: 'Code to execute', required: true}\n\t},\n\tfn: async (args, stream, ai) => {\n\t\ttry {\n\t\t\tswitch(args.language) {\n\t\t\t\tcase 'cli':\n\t\t\t\t\treturn await ExecCliTool.fn({command: args.code}, stream, ai);\n\t\t\t\tcase 'node':\n\t\t\t\t\treturn await ExecJSTool.fn({code: args.code}, stream, ai);\n\t\t\t\tcase 'python':\n\t\t\t\t\treturn await ExecPythonTool.fn({code: args.code}, stream, ai);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(`Unsupported language: ${args.language}`);\n\t\t\t}\n\t\t} catch(err: any) {\n\t\t\treturn {error: err?.message || err.toString()};\n\t\t}\n\t}\n}\n\nexport const FsDeleteTool = (whitelist: null | string[] = null): AiTool => {\n\treturn {\n\t\tname: 'fs_delete',\n\t\tdescription: 'Delete a file or directory',\n\t\targs: {\n\t\t\tpath: {type: 'string', description: 'Path to file or directory', required: true},\n\t\t\trecursive: {type: 'boolean', description: 'Delete all children', required: false}\n\t\t},\n\t\tfn: async ({path, recursive = false}) => {\n\t\t\tconst {existsSync, rmSync} = await import('fs');\n\t\t\tconst normalizePath = p => p.replace(/\\\\/g, '/');\n\n\t\t\tpath = normalizePath(path);\n\t\t\tif(whitelist && !whitelist.some(p => path.startsWith(p))) return {error: 'Permission denied'};\n\t\t\tif(!existsSync(path)) return {error: 'Path does not exist'};\n\n\t\t\trmSync(path, {recursive, force: true});\n\t\t\treturn {success: true, path};\n\t\t}\n\t}\n}\n\nexport const FsMoveTool = (whitelist: null | string[] = null): AiTool => {\n\treturn {\n\t\tname: 'fs_move',\n\t\tdescription: 'Move or rename a file or directory',\n\t\targs: {\n\t\t\tsource: {type: 'string', description: 'Path to source file or directory', required: true},\n\t\t\tdestination: {type: 'string', description: 'Path to destination file or directory', required: true}\n\t\t},\n\t\tfn: async ({source, destination}) => {\n\t\t\tconst {existsSync, renameSync} = await import('fs');\n\t\t\tconst normalizePath = p => p.replace(/\\\\/g, '/');\n\n\t\t\tsource = normalizePath(source);\n\t\t\tdestination = normalizePath(destination);\n\t\t\tif(whitelist && !whitelist.some(p => source.startsWith(p) && destination.startsWith(p))) return {error: 'Permission denied'};\n\n\t\t\tif(!existsSync(source)) return {error: 'Source path does not exist'};\n\t\t\tif(existsSync(destination)) return {error: 'Destination path already exists'};\n\n\t\t\trenameSync(source, destination);\n\t\t\treturn {success: true, source, destination};\n\t\t}\n\t}\n}\n\nexport const FsReadTool = (whitelist: null | string[] = null): AiTool => {\n\treturn {\n\t\tname: 'fs_read',\n\t\tdescription: 'Read the contents of a provided path. Works with files and directories',\n\t\targs: {path: {type: 'string', description: 'Path to file or directory', required: true}},\n\t\tfn: async ({path}) => {\n\t\t\tconst {existsSync, lstatSync, readdirSync, readFileSync} = await import('fs');\n\t\t\tconst {join} = await import('path');\n\t\t\tconst normalizePath = p => p.replace(/\\\\/g, '/');\n\n\t\t\tpath = normalizePath(path);\n\t\t\tif(whitelist && !whitelist.some(p => path.startsWith(p))) return {error: 'Permission denied'};\n\n\t\t\tif(!existsSync(path)) return {error: 'Path does not exist'};\n\t\t\tconst stats = lstatSync(path);\n\t\t\tif(stats.isDirectory()) {\n\t\t\t\tconst children = readdirSync(path).map(name => {\n\t\t\t\t\tconst childPath = normalizePath(join(path, name));\n\t\t\t\t\tconst childStats = lstatSync(childPath);\n\t\t\t\t\treturn {name, type: childStats.isDirectory() ? 'directory' : 'file', size: childStats.size};\n\t\t\t\t});\n\t\t\t\treturn {type: 'directory', children};\n\t\t\t}\n\t\t\tconst content = readFileSync(path, 'utf-8');\n\t\t\treturn {type: 'file', content};\n\t\t}\n\t}\n}\n\nexport const FsSearchTool = (whitelist: null | string[] = null): AiTool => {\n\treturn {\n\t\tname: 'fs_search',\n\t\tdescription: 'Scan a directory for matching glob patterns (e.g. \"**/*.js\", \"src/**/*.test.ts\")',\n\t\targs: {\n\t\t\tpattern: {type: 'string', description: 'Glob pattern to match against paths', required: true},\n\t\t\troot: {type: 'string', description: 'Directory to search from', required: false, default: '.'}\n\t\t},\n\t\tfn: async ({pattern, root = '.'}) => {\n\t\t\tconst {existsSync, lstatSync, readdirSync} = await import('fs');\n\t\t\tconst {join, relative} = await import('path');\n\t\t\tconst normalizePath = p => p.replace(/\\\\/g, '/');\n\n\t\t\troot = normalizePath(root);\n\t\t\tif(!existsSync(root)) return {error: 'Root path does not exist'};\n\t\t\tif(!lstatSync(root).isDirectory()) return {error: 'Root path is not a directory'};\n\n\t\t\tif(whitelist && !whitelist.some(p => root.startsWith(p))) return {error: 'Permission denied'};\n\n\t\t\tconst globToRegex = (glob) => {\n\t\t\t\tlet re = '';\n\t\t\t\tfor(let i = 0; i < glob.length; i++) {\n\t\t\t\t\tconst c = glob[i];\n\t\t\t\t\tif(c === '*') {\n\t\t\t\t\t\tif(glob[i + 1] === '*') {\n\t\t\t\t\t\t\tconst isSlash = glob[i + 2] === '/';\n\t\t\t\t\t\t\tre += '.*';\n\t\t\t\t\t\t\ti += isSlash ? 2 : 1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tre += '[^/]*';\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if(c === '?') {\n\t\t\t\t\t\tre += '[^/]';\n\t\t\t\t\t} else if('.+^$(){}|[]\\\\'.includes(c)) {\n\t\t\t\t\t\tre += '\\\\' + c;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tre += c;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn new RegExp('^' + re + '$');\n\t\t\t};\n\t\t\tconst regex = globToRegex(pattern);\n\n\t\t\tconst results: any = [];\n\t\t\tconst walk = (dir) => {\n\t\t\t\tfor(const name of readdirSync(dir)) {\n\t\t\t\t\tconst fullPath = normalizePath(join(dir, name));\n\t\t\t\t\tconst stats = lstatSync(fullPath);\n\t\t\t\t\tconst relPath = normalizePath(relative(root, fullPath));\n\t\t\t\t\tif(regex.test(relPath)) {\n\t\t\t\t\t\tresults.push({path: relPath, type: stats.isDirectory() ? 'directory' : 'file', size: stats.size});\n\t\t\t\t\t}\n\t\t\t\t\tif(stats.isDirectory()) walk(fullPath);\n\t\t\t\t}\n\t\t\t};\n\t\t\twalk(root);\n\n\t\t\treturn results;\n\t\t}\n\t}\n}\n\nexport const FsWriteTool = (whitelist: null | string[] = null): AiTool => {\n\treturn {\n\t\tname: 'fs_write',\n\t\tdescription: 'Create a directory, write content to a file or preform a find & replace',\n\t\targs: {\n\t\t\tpath: {type: 'string', description: 'Path to file or directory', required: true},\n\t\t\tcontent: {type: 'string', description: 'Content to write or replace (Omit to create a directory)'},\n\t\t\tfind: {type: 'string', description: 'Text or regex pattern to match (regex must match pattern: \"/pattern/g\")'}\n\t\t},\n\t\tfn: async ({path, content, find}) => {\n\t\t\tconst {existsSync, mkdirSync, readFileSync, writeFileSync} = await import('fs');\n\t\t\tconst {dirname} = await import('path');\n\t\t\tconst normalizePath = p => p.replace(/\\\\/g, '/');\n\n\t\t\tpath = normalizePath(path);\n\t\t\tif(whitelist && !whitelist.some(p => path.startsWith(p))) return {error: 'Permission denied'};\n\n\t\t\tif(content === undefined) {\n\t\t\t\tmkdirSync(path, {recursive: true});\n\t\t\t\treturn {success: true, type: 'directory', path};\n\t\t\t}\n\n\t\t\tconst dir = normalizePath(dirname(path));\n\t\t\tif(!existsSync(dir)) mkdirSync(dir, {recursive: true});\n\n\t\t\tif(find && existsSync(path)) {\n\t\t\t\tconst existing = readFileSync(path, 'utf-8');\n\t\t\t\tconst regexMatch = find.match(/^\\/(.+)\\/([gimuy]*)$/);\n\t\t\t\tconst pattern = regexMatch ? new RegExp(regexMatch[1], regexMatch[2]) : find;\n\n\t\t\t\tif(!existing.match(pattern)) return {error: 'Find pattern not found in file'};\n\n\t\t\t\tconst updated = existing.replace(pattern, content);\n\t\t\t\twriteFileSync(path, updated, 'utf-8');\n\t\t\t\treturn {success: true, type: 'file', path, replaced: true, content: updated};\n\t\t\t}\n\n\t\t\twriteFileSync(path, content, 'utf-8');\n\t\t\treturn {success: true, type: 'file', path, content};\n\t\t}\n\t}\n}\n\nexport const GetPathsTool: AiTool = {\n\tname: 'get_paths',\n\tdescription: 'Get the current working directory, and paths to the users home directory',\n\tfn: async () => {\n\t\treturn {\n\t\t\thome: os.homedir(),\n\t\t\tcwd: process.cwd()\n\t\t};\n\t}\n}\n\nexport const GetDatetimeTool: AiTool = {\n\tname: 'get_datetime',\n\tdescription: 'Get local/UTC timestamp',\n\targs: {\n\t\ttimezone: {type: 'string', description: 'Which timezone to return, defaults to local', enum: ['local', 'utc'], default: 'local'}\n\t},\n\tfn: ({timezone}) => new Date()[timezone === 'local' ? 'toString' : 'toUTCString']()\n}\n\nexport const GetDevice: AiTool = {\n\tname: 'get_device',\n\tdescription: 'Get comprehensive system information including hostname, specs, load, storage, and network status',\n\targs: {},\n\tfn: async () => {\n\t\tconst platform = os.platform();\n\t\tconst hostname = os.hostname();\n\n\t\t// CPU Info\n\t\tconst cpus = os.cpus();\n\t\tconst cpuModel = cpus[0].model;\n\t\tconst cpuCores = cpus.length;\n\n\t\t// Memory Info\n\t\tconst totalMem: any = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2);\n\t\tconst freeMem: any = (os.freemem() / 1024 / 1024 / 1024).toFixed(2);\n\t\tconst usedMem: any = (totalMem - freeMem).toFixed(2);\n\t\tconst memUsage: any = ((usedMem / totalMem) * 100).toFixed(1);\n\n\t\t// Load Average (not available on Windows)\n\t\tconst loadAvg = platform === 'win32' ? ['N/A', 'N/A', 'N/A'] : os.loadavg().map(l => l.toFixed(2));\n\n\t\t// Storage Usage\n\t\tlet storage = {};\n\t\tif(platform === 'win32') {\n\t\t\tconst ps = $Sync`powershell \"Get-PSDrive C | Select-Object Used,Free | ConvertTo-Json\"`.trim();\n\t\t\tconst drive = JSON.parse(ps);\n\t\t\tconst used: any = (drive.Used / 1024 / 1024 / 1024).toFixed(2);\n\t\t\tconst free: any = (drive.Free / 1024 / 1024 / 1024).toFixed(2);\n\t\t\tconst total: any = (parseFloat(used) + parseFloat(free)).toFixed(2);\n\t\t\tconst usage: any = ((used / total) * 100).toFixed(1);\n\t\t\tstorage = {\n\t\t\t\tfilesystem: 'C:',\n\t\t\t\tsize: `${total} GB`,\n\t\t\t\tused: `${used} GB`,\n\t\t\t\tavailable: `${free} GB`,\n\t\t\t\tusage: `${usage}%`\n\t\t\t};\n\t\t} else {\n\t\t\tconst df = $Sync`df -h / | tail -1`.trim();\n\t\t\tconst s = df.split(/\\s+/);\n\t\t\tstorage = {\n\t\t\t\tfilesystem: s[0],\n\t\t\t\tsize: s[1],\n\t\t\t\tused: s[2],\n\t\t\t\tavailable: s[3],\n\t\t\t\tusage: s[4]\n\t\t\t};\n\t\t}\n\n\t\t// Network Status\n\t\tconst interfaces = os.networkInterfaces();\n\t\tconst activeIfaces = Object.entries(interfaces)\n\t\t\t.filter(([name]) => name !== 'lo' && !name.includes('Loopback'))\n\t\t\t.map(([name, addrs]) => {\n\t\t\t\tconst ipv4 = addrs?.find(a => a.family === 'IPv4');\n\t\t\t\treturn ipv4 ? {name, ip: ipv4.address} : null;\n\t\t\t})\n\t\t\t.filter(Boolean);\n\n\t\t// Internet connectivity check\n\t\tlet internet = false;\n\t\ttry {\n\t\t\tif(platform === 'win32') {\n\t\t\t\t$Sync`powershell \"Test-Connection -ComputerName 8.8.8.8 -Count 1 -Quiet\"`;\n\t\t\t} else {\n\t\t\t\t$Sync`ping -c 1 -W 2 8.8.8.8 > /dev/null 2>&1`;\n\t\t\t}\n\t\t\tinternet = true;\n\t\t} catch {}\n\n\t\t// Uptime\n\t\tconst uptime = os.uptime();\n\t\tconst days = Math.floor(uptime / 86400);\n\t\tconst hours = Math.floor((uptime % 86400) / 3600);\n\t\tconst minutes = Math.floor((uptime % 3600) / 60);\n\n\t\treturn {\n\t\t\thostname,\n\t\t\tcpu: {\n\t\t\t\tmodel: cpuModel,\n\t\t\t\tcores: cpuCores\n\t\t\t},\n\t\t\tmemory: {\n\t\t\t\ttotal: `${totalMem} GB`,\n\t\t\t\tused: `${usedMem} GB`,\n\t\t\t\tfree: `${freeMem} GB`,\n\t\t\t\tusage: `${memUsage}%`\n\t\t\t},\n\t\t\tload: {\n\t\t\t\t'1min': loadAvg[0],\n\t\t\t\t'5min': loadAvg[1],\n\t\t\t\t'15min': loadAvg[2]\n\t\t\t},\n\t\t\tstorage,\n\t\t\tnetwork: {\n\t\t\t\tinterfaces: activeIfaces,\n\t\t\t\tinternet: internet ? 'connected' : 'disconnected'\n\t\t\t},\n\t\t\tuptime: `${days}d ${hours}h ${minutes}m`,\n\t\t\tplatform: `${os.type()} ${os.release()}`\n\t\t};\n\t}\n}\n\nexport const GetWikipediaTool: AiTool = {\n\tname: 'get_wikipedia',\n\tdescription: 'Search Wikipedia for matching articles',\n\targs: {\n\t\tquery: {type: 'string', description: 'Search term or article title', required: true},\n\t\tmode: {type: 'string', description: 'search - look for articles, summary - intro of first found article (default), full - complete first found article', enum: ['search', 'summary', 'full'], default: 'summary'},\n\t\tua: {type: 'string', description: 'User Agent'},\n\t},\n\tfn: async ({query, mode, ua}) => {\n\t\tclass WikipediaClient {\n\t\t\tuseragent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)';\n\n\t\t\tconstructor(useragent: string) {\n\t\t\t\tthis.useragent = useragent;\n\t\t\t}\n\n\t\t\tasync get(url) {\n\t\t\t\tconst resp = await fetch(url, {headers: {'User-Agent': this.useragent}});\n\t\t\t\treturn resp.json();\n\t\t\t}\n\n\t\t\tapi(params) {\n\t\t\t\tconst qs = new URLSearchParams({...params, format: 'json', utf8: '1'}).toString();\n\t\t\t\treturn this.get(`https://en.wikipedia.org/w/api.php?${qs}`);\n\t\t\t}\n\n\t\t\tclean(text) {\n\t\t\t\tconst cutoffs = ['== See also ==', '== References ==', '== Bibliography ==', '== External links =='];\n\t\t\t\tfor (const marker of cutoffs) {\n\t\t\t\t\tconst idx = text.indexOf(marker);\n\t\t\t\t\tif (idx !== -1) text = text.slice(0, idx);\n\t\t\t\t}\n\n\t\t\t\treturn text\n\t\t\t\t\t.replace(/^={4}\\s*(.+?)\\s*={4}$/gm, '#### $1')\n\t\t\t\t\t.replace(/^={3}\\s*(.+?)\\s*={3}$/gm, '### $1')\n\t\t\t\t\t.replace(/^={2}\\s*(.+?)\\s*={2}$/gm, '## $1')\n\t\t\t\t\t.replace(/\\n{3,}/g, '\\n\\n')\n\t\t\t\t\t.replace(/ {2,}/g, ' ')\n\t\t\t\t\t.replace(/\\[\\d+]/g, '')\n\t\t\t\t\t.trim();\n\t\t\t}\n\n\t\t\tasync searchTitles(query: string, limit = 6) {\n\t\t\t\tconst data = await this.api({action: 'query', list: 'search', srsearch: query, srlimit: limit, srprop: 'snippet'});\n\t\t\t\treturn data.query?.search || [];\n\t\t\t}\n\n\t\t\tasync fetchExtract(title: string, introOnly = false) {\n\t\t\t\tconst params: any = {action: 'query', prop: 'extracts', titles: title, explaintext: 1, redirects: 1};\n\t\t\t\tif(introOnly) params.exintro = 1;\n\t\t\t\tconst data = await this.api(params);\n\t\t\t\tconst page: any = Object.values(data.query?.pages || {})[0];\n\t\t\t\treturn this.clean(page?.extract || '');\n\t\t\t}\n\n\t\t\tpageUrl(title: string) {\n\t\t\t\treturn `https://en.wikipedia.org/wiki/${encodeURIComponent(title.replace(/ /g, '_'))}`;\n\t\t\t}\n\n\t\t\tstripHtml(text: string) {\n\t\t\t\treturn text.replace(/<[^>]+>/g, '');\n\t\t\t}\n\n\t\t\tasync lookup(query: string, detail = 'summary') {\n\t\t\t\tconst results = await this.searchTitles(query, 6);\n\t\t\t\tif(!results.length) return `❌ No Wikipedia articles found for \"${query}\"`;\n\t\t\t\tconst title = results[0].title;\n\t\t\t\tconst url = this.pageUrl(title);\n\t\t\t\tconst introOnly = detail !== 'full';\n\t\t\t\tconst content = await this.fetchExtract(title, introOnly);\n\t\t\t\treturn `## ${title}\\n🔗 ${url}\\n\\n${content}`;\n\t\t\t}\n\n\t\t\tasync search(query: string) {\n\t\t\t\tconst results = await this.searchTitles(query, 8);\n\t\t\t\tif(!results.length) return `❌ No results for \"${query}\"`;\n\t\t\t\tconst lines = [`### Search results for \"${query}\"\\n`];\n\t\t\t\tfor(let i = 0; i < results.length; i++) {\n\t\t\t\t\tconst r = results[i];\n\t\t\t\t\tconst snippet = this.stripHtml(r.snippet || '').trim();\n\t\t\t\t\tlines.push(`**${i + 1}. ${r.title}**\\n${snippet}\\n${this.pageUrl(r.title)}`);\n\t\t\t\t}\n\t\t\t\treturn lines.join('\\n\\n');\n\t\t\t}\n\t\t}\n\n\t\tconst wiki = new WikipediaClient(ua);\n\t\tif(mode === 'search') return wiki.search(query);\n\t\treturn wiki.lookup(query, mode || 'summary');\n\t}\n};\n\nexport const GeoCodeTool: AiTool = {\n\tname: 'geo_code',\n\tdescription: 'Converts coordinates to address OR vice versa',\n\targs: {\n\t\tquery: {type: 'string', description: 'Search query - coordinates (lat,lon) or address string', required: true},\n\t},\n\tfn: async ({query}) => {\n\t\tconst coordinates = /(-?\\d+(?:\\.\\d+)?).*?,.*?(-?\\d+(?:\\.\\d+)?)/.exec(query);\n\t\tif(coordinates) { // Geolocate\n\t\t\tconst url = `https://nominatim.openstreetmap.org/reverse?format=json&lat=${encodeURIComponent(coordinates[1])}&lon=${encodeURIComponent(coordinates[2])}`;\n\t\t\tconst response = await fetch(url, {headers: {'User-Agent': 'OpenSight/1.0', 'Accept-Language': 'en'}});\n\t\t\tconst data = await response.json();\n\t\t\tif(data.display_name) return {address: data.display_name, mode: 'geolocate'};\n\t\t} else { // Geocode\n\t\t\tconst url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(query)}`;\n\t\t\tconst response = await fetch(url, {headers: {'User-Agent': 'OpenSight/1.0'}});\n\t\t\tconst data = await response.json();\n\t\t\tif(data[0]) return {latitude: parseFloat(data[0].lat), longitude: parseFloat(data[0].lon), mode: 'geocode'};\n\t\t}\n\t\treturn {error: 'Not found'};\n\t},\n}\n\nexport const GeoWeatherTool: AiTool = {\n\tname: 'geo_weather',\n\tdescription: 'Gets weather and air quality info for a location and time',\n\targs: {\n\t\tquery: {type: 'string', description: 'Location - address or place name', required: true},\n\t\tday: {type: 'string', description: 'Date to retrieve (YYYY-MM-DD), defaults to today'},\n\t},\n\tfn: async ({query, day}) => {\n\t\tday = day || new Date().toISOString().slice(0, 10);\n\n\t\tconst geoUrl = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(query)}`;\n\t\tconst geoResponse = await fetch(geoUrl, {headers: {'User-Agent': 'OpenSight/1.0'}});\n\t\tconst geoData = await geoResponse.json();\n\t\tif(!geoData[0]) return {error: 'Location not found'};\n\n\t\tconst lat = parseFloat(geoData[0].lat);\n\t\tconst lon = parseFloat(geoData[0].lon);\n\n\t\tconst weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}&start_date=${day}&end_date=${day}&daily=weathercode,temperature_2m_max,temperature_2m_min,apparent_temperature_max,apparent_temperature_min,precipitation_sum,precipitation_probability_max,windspeed_10m_max,winddirection_10m_dominant,uv_index_max,sunrise,sunset&timezone=auto`;\n\t\tconst airUrl = `https://air-quality-api.open-meteo.com/v1/air-quality?latitude=${lat}&longitude=${lon}&start_date=${day}&end_date=${day}&hourly=us_aqi,european_aqi,pm10,pm2_5&timezone=auto`;\n\n\t\tconst [weatherResponse, airResponse] = await Promise.all([fetch(weatherUrl), fetch(airUrl)]);\n\t\tconst weatherData = await weatherResponse.json();\n\t\tconst airData = await airResponse.json();\n\n\t\tconst avg = arr => (arr && arr.length) ? arr.reduce((a, b) => a + b, 0) / arr.length : null;\n\n\t\treturn {\n\t\t\tlocation: geoData[0].display_name,\n\t\t\tlatitude: lat,\n\t\t\tlongitude: lon,\n\t\t\televation: weatherData.elevation,\n\t\t\tdate: day,\n\t\t\tweatherCode: weatherData.daily?.weathercode?.[0],\n\t\t\ttempMax: weatherData.daily?.temperature_2m_max?.[0],\n\t\t\ttempMin: weatherData.daily?.temperature_2m_min?.[0],\n\t\t\tfeelsLikeMax: weatherData.daily?.apparent_temperature_max?.[0],\n\t\t\tfeelsLikeMin: weatherData.daily?.apparent_temperature_min?.[0],\n\t\t\tprecipitation: weatherData.daily?.precipitation_sum?.[0],\n\t\t\tprecipitationChance: weatherData.daily?.precipitation_probability_max?.[0],\n\t\t\twindSpeedMax: weatherData.daily?.windspeed_10m_max?.[0],\n\t\t\twindDirection: weatherData.daily?.winddirection_10m_dominant?.[0],\n\t\t\tuvIndexMax: weatherData.daily?.uv_index_max?.[0],\n\t\t\tsunrise: weatherData.daily?.sunrise?.[0],\n\t\t\tsunset: weatherData.daily?.sunset?.[0],\n\t\t\tusAqi: avg(airData.hourly?.us_aqi),\n\t\t\teuropeanAqi: avg(airData.hourly?.european_aqi),\n\t\t\tpm10: avg(airData.hourly?.pm10),\n\t\t\tpm2_5: avg(airData.hourly?.pm2_5),\n\t\t};\n\t},\n}\n\nexport const WebFetchTool: AiTool = {\n\tname: 'web_fetch',\n\tdescription: 'Make HTTP request to URL',\n\targs: {\n\t\turl: {type: 'string', description: 'URL to fetch', required: true},\n\t\tmethod: {type: 'string', description: 'HTTP method to use', enum: ['GET', 'POST', 'PUT', 'DELETE'], default: 'GET'},\n\t\theaders: {type: 'object', description: 'HTTP headers to send', default: {}},\n\t\tbody: {type: 'object', description: 'HTTP body to send'},\n\t},\n\tfn: (args: {\n\t\turl: string;\n\t\tmethod: 'GET' | 'POST' | 'PUT' | 'DELETE';\n\t\theaders: {[key: string]: string};\n\t\tbody: any;\n\t}) => new Http({url: args.url, headers: args.headers}).request({method: args.method || 'GET', body: args.body})\n}\n\nexport const WebFlareSolverTool = (host: string) => {\n\treturn {\n\t\tname: 'web_flaresolverr',\n\t\tdescription: 'Use a flaresolverr proxy to bypass cloudflare bot detection',\n\t\targs: {\n\t\t\turl: {type: 'string', description: 'URL to fetch', required: true},\n\t\t\tcmd: {type: 'string', description: 'Flaresolverr cmd', enum: ['request.get', 'request.post'], default: 'request.get'},\n\t\t\tmaxTimeout: {type: 'number', description: 'Fetch time limit', default: 60_000},\n\t\t\tpostData: {type: 'object', description: 'Data to send during request.post requests'},\n\t\t},\n\t\tfn: async ({url, cmd, maxTimeout, postData}) => {\n\t\t\tfunction toFormUrlEncoded(obj, prefix = '') {\n\t\t\t\tconst pairs: any = [];\n\t\t\t\tfor (const key in obj) {\n\t\t\t\t\tif (!obj.hasOwnProperty(key)) continue;\n\n\t\t\t\t\tconst value = obj[key];\n\t\t\t\t\tconst encodedKey = prefix\n\t\t\t\t\t\t? `${prefix}[${encodeURIComponent(key)}]`\n\t\t\t\t\t\t: encodeURIComponent(key);\n\n\t\t\t\t\tif (value === null || value === undefined) {\n\t\t\t\t\t\tpairs.push(`${encodedKey}=`);\n\t\t\t\t\t} else if (typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t\t\t\tpairs.push(toFormUrlEncoded(value, encodedKey));\n\t\t\t\t\t} else if (Array.isArray(value)) {\n\t\t\t\t\t\tvalue.forEach(item => {\n\t\t\t\t\t\t\tpairs.push(`${encodedKey}[]=${encodeURIComponent(item)}`);\n\t\t\t\t\t\t});\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpairs.push(`${encodedKey}=${encodeURIComponent(value)}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn pairs.join('&');\n\t\t\t}\n\n\t\t\tconst res = await fetch(host + '/v1', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {'Content-Type': 'application/json'},\n\t\t\t\tbody: JSON.stringify({cmd, url, maxTimeout, postData: postData ? toFormUrlEncoded(postData) : undefined}),\n\t\t\t});\n\n\t\t\tif(!res.ok) throw new Error(`FlareSolverr HTTP error: ${res.status} ${res.statusText}`);\n\t\t\tconst data = await res.json();\n\t\t\tif(data.status !== 'ok') throw new Error(`FlareSolverr error: ${data.message ?? data.status}`);\n\t\t\treturn data.solution.response;\n\t\t}\n\t}\n}\n\nexport const WebReadTool: AiTool = {\n\tname: 'web_read',\n\tdescription: 'Extract clean content from webpages, or convert media/documents to accessible formats',\n\targs: {\n\t\turl: {type: 'string', description: 'URL to read', required: true},\n\t\tmimeRegex: {type: 'string', description: 'Optional regex to filter MIME types (e.g., \"^image/\", \"text/\")'}\n\t},\n\tfn: async (args: {url: string; mimeRegex?: string}) => {\n\t\tconst ua = 'AiTools-Webpage/1.0';\n\t\tconst maxSize = 10 * 1024 * 1024;\n\n\t\tconst response = await fetch(args.url, {\n\t\t\theaders: {\n\t\t\t\t'User-Agent': ua,\n\t\t\t\t'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',\n\t\t\t\t'Accept-Language': 'en-US,en;q=0.5'\n\t\t\t},\n\t\t\tredirect: 'follow'\n\t\t}).catch(err => {throw new Error(`Failed to fetch: ${err.message}`)});\n\n\t\tconst contentType = response.headers.get('content-type') || '';\n\t\tconst mimeType = contentType.split(';')[0].trim().toLowerCase();\n\n\t\tif(args.mimeRegex && !new RegExp(args.mimeRegex, 'i').test(mimeType)) {\n\t\t\treturn `❌ MIME type rejected: ${mimeType} (filter: ${args.mimeRegex})`;\n\t\t}\n\n\t\tif(mimeType.match(/^(image|audio|video)\\//)) {\n\t\t\tconst buffer = await response.arrayBuffer();\n\t\t\tif(buffer.byteLength > maxSize) {\n\t\t\t\treturn `❌ File too large: ${(buffer.byteLength / 1024 / 1024).toFixed(1)}MB (max 10MB)\\nType: ${mimeType}`;\n\t\t\t}\n\t\t\tconst base64 = Buffer.from(buffer).toString('base64');\n\t\t\treturn `## Media File\\n**Type:** ${mimeType}\\n**Size:** ${(buffer.byteLength / 1024).toFixed(1)}KB\\n**Data URL:** \\`data:${mimeType};base64,${base64.slice(0, 100)}...\\``;\n\t\t}\n\n\t\tif(mimeType.match(/^text\\/(plain|csv|xml)/) || args.url.match(/\\.(txt|csv|xml|md|yaml|yml)$/i)) {\n\t\t\tconst text = await response.text();\n\t\t\tconst truncated = text.length > 50000 ? text.slice(0, 50000) : text;\n\t\t\treturn `## Text File\\n**Type:** ${mimeType}\\n**URL:** ${args.url}\\n\\n${truncated}`;\n\t\t}\n\n\t\tif(mimeType.match(/application\\/(json|xml|csv)/)) {\n\t\t\tconst text = await response.text();\n\t\t\tconst truncated = text.length > 50000 ? text.slice(0, 50000) : text;\n\t\t\treturn `## Structured Data\\n**Type:** ${mimeType}\\n**URL:** ${args.url}\\n\\n\\`\\`\\`\\n${truncated}\\n\\`\\`\\``;\n\t\t}\n\n\t\tif(mimeType === 'application/pdf' || (mimeType.startsWith('application/') && !mimeType.includes('html'))) {\n\t\t\tconst buffer = await response.arrayBuffer();\n\t\t\tif(buffer.byteLength > maxSize) {\n\t\t\t\treturn `❌ File too large: ${(buffer.byteLength / 1024 / 1024).toFixed(1)}MB (max 10MB)\\nType: ${mimeType}`;\n\t\t\t}\n\t\t\tconst base64 = Buffer.from(buffer).toString('base64');\n\t\t\treturn `## Binary File\\n**Type:** ${mimeType}\\n**Size:** ${(buffer.byteLength / 1024).toFixed(1)}KB\\n**Data URL:** \\`data:${mimeType};base64,${base64.slice(0, 100)}...\\``;\n\t\t}\n\n\t\t// HTML\n\t\tconst html = await response.text();\n\t\tconst $ = cheerio.load(html);\n\t\t$('script, style, nav, footer, header, aside, iframe, noscript, svg').remove();\n\t\t$('[role=\"navigation\"], [role=\"banner\"], [role=\"complementary\"]').remove();\n\t\t$('[aria-hidden=\"true\"], [hidden], .visually-hidden, .sr-only, .screen-reader-text').remove();\n\t\t$('.ad, .ads, .advertisement, .cookie, .popup, .modal, .sidebar, .related, .comments, .social-share').remove();\n\t\t$('button, [class*=\"share\"], [class*=\"follow\"], [class*=\"social\"]').remove();\n\t\tconst title = $('meta[property=\"og:title\"]').attr('content') || $('title').text().trim() || '';\n\t\tconst description = $('meta[name=\"description\"]').attr('content') || $('meta[property=\"og:description\"]').attr('content') || '';\n\t\tconst author = $('meta[name=\"author\"]').attr('content') || '';\n\t\tlet content = '';\n\t\tconst selectors = ['article', 'main', '[role=\"main\"]', '.content', '.post-content', '.entry-content', '.article-content'];\n\t\tfor(const sel of selectors) {\n\t\t\tconst el = $(sel).first();\n\t\t\tif(el.length && el.text().trim().length > 200) {\n\t\t\t\tconst paragraphs: string[] = [];\n\t\t\t\tel.find('p').each((_, p) => {\n\t\t\t\t\tconst text = $(p).text().trim();\n\t\t\t\t\tif(text.length > 80) paragraphs.push(text);\n\t\t\t\t});\n\t\t\t\tif(paragraphs.length > 2) {\n\t\t\t\t\tcontent = paragraphs.join('\\n\\n');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(!content) {\n\t\t\tconst paragraphs: string[] = [];\n\t\t\t$('body p').each((_, p) => {\n\t\t\t\tconst text = $(p).text().trim();\n\t\t\t\tif(text.length > 80) paragraphs.push(text);\n\t\t\t});\n\t\t\tcontent = paragraphs.slice(0, 30).join('\\n\\n');\n\t\t}\n\n\t\t// Decode escaped newlines and clean\n\t\tconst parts = [`## ${title || 'Webpage'}`];\n\t\tif(description) parts.push(`_${description}_`);\n\t\tif(author) parts.push(`👤 ${author}`);\n\t\tparts.push(`🔗 ${args.url}\\n`);\n\t\tparts.push(content);\n\t\treturn decodeHtml(parts.join('\\n\\n').replaceAll(/\\n{3,}/g, '\\n\\n'));\n\t}\n};\n\nexport const WebSearchTool: AiTool = {\n\tname: 'web_search',\n\tdescription: 'Use duckduckgo (anonymous) to find find relevant online resources. Returns a list of URLs that works great with the `read_webpage` tool',\n\targs: {\n\t\tquery: {type: 'string', description: 'Search string', required: true},\n\t\tlength: {type: 'string', description: 'Number of results to return', default: 5},\n\t},\n\tfn: async (args: {\n\t\tquery: string;\n\t\tlength: number;\n\t}) => {\n\t\tconst html = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(args.query)}`, {\n\t\t\theaders: {\"User-Agent\": UA, \"Accept-Language\": \"en-US,en;q=0.9\"}\n\t\t}).then(resp => resp.text());\n\t\tlet match, regex = /<a .*?href=\"(.+?)\".+?<\\/a>/g;\n\t\tconst results = new ASet<string>();\n\t\twhile((match = regex.exec(html)) !== null) {\n\t\t\tlet url = /uddg=(.+)&amp?/.exec(decodeURIComponent(match[1]))?.[1];\n\t\t\tif(url) url = decodeURIComponent(url);\n\t\t\tif(url) results.add(url);\n\t\t\tif(results.size >= (args.length || 5)) break;\n\t\t}\n\t\treturn results;\n\t}\n}\n","import {Anthropic as anthropic} from '@anthropic-ai/sdk';\nimport {findByProp, objectMap, JSONSanitize, JSONAttemptParse, makeArray} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\nimport {LLMProvider} from './provider.ts';\nimport {TokenPool} from './token-pool.ts';\nimport {convertSchema} from './tools.ts';\n\nexport class Anthropic extends LLMProvider {\n\tprivate clients = new Map<string, anthropic>();\n\ttokenPool!: TokenPool;\n\n\tconstructor(public readonly ai: Ai, public readonly apiToken: string | string[], public model: string) {\n\t\tsuper();\n\t\tthis.tokenPool = new TokenPool(...makeArray(apiToken).filter(Boolean));\n\t}\n\n\tprivate getClient(token: string): anthropic {\n\t\tlet client = this.clients.get(token);\n\t\tif(!client) {\n\t\t\tclient = new anthropic({apiKey: token});\n\t\t\tthis.clients.set(token, client);\n\t\t}\n\t\treturn client;\n\t}\n\n\tprivate toWireContent(content: any): any {\n\t\tif(!Array.isArray(content)) return content;\n\t\treturn content.map(c => c.type === 'image'\n\t\t\t? {type: 'image', source: {type: 'base64', media_type: c.mime, data: c.data}}\n\t\t\t: {type: 'text', text: c.text});\n\t}\n\n\t/** Convert standard history -> Anthropic wire format */\n\tprivate toWire(history: LLMMessage[]): any[] {\n\t\tconst wire: any[] = [];\n\t\tfor(const h of history) {\n\t\t\tif(h.role === 'tool') {\n\t\t\t\twire.push(\n\t\t\t\t\t{role: 'assistant', content: [{type: 'tool_use', id: h.id, name: h.name, input: h.args}]},\n\t\t\t\t\t{role: 'user', content: [{type: 'tool_result', tool_use_id: h.id, is_error: !!h.error, content: h.error || h.content || ''}]}\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\twire.push({role: h.role, content: this.toWireContent(h.content)});\n\t\t\t}\n\t\t}\n\t\treturn wire;\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string | any> {\n\t\tconst controller = new AbortController();\n\t\treturn Object.assign(new Promise<any>(async (res, rej) => {\n\t\t\tif(!options.history) options.history = [];\n\t\t\tconst history = options.history;\n\t\t\tif(message) history.push({role: 'user', content: message, timestamp: Date.now()});\n\n\t\t\tconst tools = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst requestParams: any = {\n\t\t\t\tmodel: options.model || this.model,\n\t\t\t\tmax_tokens: options.maxTokens || this.ai.options.llm?.maxTokens || 4096,\n\t\t\t\tsystem: options.system || this.ai.options.llm?.system || '',\n\t\t\t\ttemperature: options.temperature || this.ai.options.llm?.temperature || undefined,\n\t\t\t\ttools: tools.map(t => ({\n\t\t\t\t\tname: t.name,\n\t\t\t\t\tdescription: t.description,\n\t\t\t\t\tinput_schema: {\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tproperties: t.args ? objectMap(t.args, (key, value) => ({...value, required: undefined})) : {},\n\t\t\t\t\t\trequired: t.args ? Object.entries(t.args).filter(t => t[1].required).map(t => t[0]) : []\n\t\t\t\t\t}\n\t\t\t\t})),\n\t\t\t\tstream: !!options.stream,\n\t\t\t};\n\n\t\t\tif(options.schema) {\n\t\t\t\trequestParams.output_config = {format: {type: 'json_schema', schema: convertSchema(options.schema)}};\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tlet terminal = false;\n\t\t\t\tdo {\n\t\t\t\t\trequestParams.messages = this.toWire(history.filter(h => h.role !== 'system'));\n\n\t\t\t\t\tconst callStart = Date.now();\n\t\t\t\t\tconst resp: any = await this.tokenPool.run(token => this.getClient(token).messages.create(requestParams)).catch(err => {\n\t\t\t\t\t\terr.message += `\\n\\nMessages:\\n${JSON.stringify(requestParams.messages, null, 2)}`;\n\t\t\t\t\t\tthrow err;\n\t\t\t\t\t});\n\n\t\t\t\t\tlet usage: any, content: any[] = [];\n\t\t\t\t\tif(options.stream) {\n\t\t\t\t\t\tfor await (const chunk of resp) {\n\t\t\t\t\t\t\tif(controller.signal.aborted) break;\n\t\t\t\t\t\t\tif(chunk.type === 'content_block_start') {\n\t\t\t\t\t\t\t\tif(chunk.content_block.type === 'text') content.push({type: 'text', text: ''});\n\t\t\t\t\t\t\t\telse if(chunk.content_block.type === 'tool_use') content.push({type: 'tool_use', id: chunk.content_block.id, name: chunk.content_block.name, input: ''});\n\t\t\t\t\t\t\t} else if(chunk.type === 'content_block_delta') {\n\t\t\t\t\t\t\t\tif(chunk.delta.type === 'text_delta') {\n\t\t\t\t\t\t\t\t\tcontent.at(-1).text += chunk.delta.text;\n\t\t\t\t\t\t\t\t\toptions.stream({text: chunk.delta.text});\n\t\t\t\t\t\t\t\t} else if(chunk.delta.type === 'input_json_delta') {\n\t\t\t\t\t\t\t\t\tcontent.at(-1).input += chunk.delta.partial_json;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if(chunk.type === 'content_block_stop') {\n\t\t\t\t\t\t\t\tconst last = content.at(-1);\n\t\t\t\t\t\t\t\tif(last?.type === 'tool_use') last.input = last.input ? JSONAttemptParse(last.input, {}) : {};\n\t\t\t\t\t\t\t} else if(chunk.type === 'message_delta') {\n\t\t\t\t\t\t\t\tif(chunk.usage) usage = chunk.usage;\n\t\t\t\t\t\t\t} else if(chunk.type === 'message_stop') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tusage = resp.usage;\n\t\t\t\t\t\tcontent = resp.content;\n\t\t\t\t\t}\n\t\t\t\t\tconst duration = Date.now() - callStart;\n\t\t\t\t\tconst tps = usage?.output_tokens && duration > 0 ? usage.output_tokens / (duration / 1000) : 0;\n\n\t\t\t\t\tconst toolCalls = content.filter((c: any) => c.type === 'tool_use');\n\t\t\t\t\tif(toolCalls.length && !controller.signal.aborted) {\n\t\t\t\t\t\tconst text = content.filter((c: any) => c.type === 'text').map((c: any) => c.text).join('\\n\\n').trim();\n\t\t\t\t\t\tif(text) history.push({role: 'assistant', content: text, timestamp: Date.now(), duration, tps});\n\n\t\t\t\t\t\tconst entries = toolCalls.map((tc: any) => {\n\t\t\t\t\t\t\tconst entry: any = {role: 'tool', id: tc.id, name: tc.name, args: tc.input, content: undefined, timestamp: Date.now()};\n\t\t\t\t\t\t\thistory.push(entry);\n\t\t\t\t\t\t\treturn {tc, entry};\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tawait Promise.all(entries.map(async ({tc, entry}: any) => {\n\t\t\t\t\t\t\tconst tool = tools.find(findByProp('name', tc.name));\n\t\t\t\t\t\t\tif(options.stream) options.stream({tool: tc.name});\n\t\t\t\t\t\t\tif(!tool) { entry.error = 'Tool not found'; return; }\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst toolStream = options.stream && ((chunk: any) => {\n\t\t\t\t\t\t\t\t\tif(chunk.done) { terminal = true; return; }\n\t\t\t\t\t\t\t\t\toptions.stream!(chunk);\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tconst result = await tool.fn(entry.args, toolStream, this.ai, tc.id);\n\t\t\t\t\t\t\t\tentry.content = typeof result === 'object' ? JSONSanitize(result) : result;\n\t\t\t\t\t\t\t} catch(err: any) {\n\t\t\t\t\t\t\t\tentry.error = err?.message || err?.toString() || 'Unknown';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tterminal = true;\n\t\t\t\t\t\tconst text = content.filter((c: any) => c.type === 'text').map((c: any) => c.text).join('\\n\\n').trim();\n\t\t\t\t\t\tif(text) history.push({role: 'assistant', content: text, timestamp: Date.now(), duration, tps});\n\t\t\t\t\t}\n\t\t\t\t} while(!terminal && !controller.signal.aborted);\n\n\t\t\t\tif(options.stream) options.stream({done: true});\n\n\t\t\t\tconst turnStart = history.map(h => h.role).lastIndexOf('user');\n\t\t\t\tconst finalContent = history.slice(turnStart + 1).reduce((str, h) => h.role === 'assistant' ? str + (h.content || '') : str, '').trim();\n\t\t\t\tres(options.schema ? JSONAttemptParse(finalContent, finalContent) : finalContent);\n\t\t\t} catch(err) {\n\t\t\t\trej(err);\n\t\t\t}\n\t\t}), {abort: () => controller.abort()});\n\t}\n}\n","import {OpenAI as openAI} from 'openai';\nimport {findByProp, objectMap, JSONSanitize, JSONAttemptParse, clean, makeArray} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {LLMMessage, LLMRequest} from './llm.ts';\nimport {LLMProvider} from './provider.ts';\nimport {TokenPool} from './token-pool.ts';\nimport {convertSchema} from './tools.ts';\n\nexport class OpenAi extends LLMProvider {\n\ttokenPool!: TokenPool;\n\tprivate clients = new Map<string, openAI>();\n\n\tconstructor(public readonly ai: Ai, public readonly host: string | null, public readonly token: string | string[], public model: string) {\n\t\tsuper();\n\t\tconst tokens = makeArray(token).filter(Boolean);\n\t\tthis.tokenPool = new TokenPool(...(tokens.length ? tokens : [host ? 'ignored' : '']));\n\t}\n\n\tprivate getClient(token: string): openAI {\n\t\tlet client = this.clients.get(token);\n\t\tif(!client) {\n\t\t\tclient = new openAI(clean({baseURL: this.host, apiKey: token || undefined}));\n\t\t\tthis.clients.set(token, client);\n\t\t}\n\t\treturn client;\n\t}\n\n\tprivate toWireContent(content: any): any {\n\t\tif(!Array.isArray(content)) return content;\n\t\treturn content.map(c => c.type === 'image'\n\t\t\t? {type: 'image_url', image_url: {url: `data:${c.mime};base64,${c.data}`}}\n\t\t\t: {type: 'text', text: c.text});\n\t}\n\n\t/** Convert standard history -> OpenAI wire format */\n\tprivate toWire(history: LLMMessage[], system?: string): any[] {\n\t\tconst wire: any[] = [];\n\t\tif(system) wire.push({role: 'system', content: system});\n\n\t\tfor(let i = 0; i < history.length; i++) {\n\t\t\tconst h = history[i];\n\n\t\t\tif(h.role !== 'tool') {\n\t\t\t\twire.push({role: h.role, content: this.toWireContent(h.content)});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst calls: any[] = [];\n\t\t\tconst results: any[] = [];\n\n\t\t\twhile(i < history.length && history[i].role === 'tool') {\n\t\t\t\tconst tool: any = history[i];\n\n\t\t\t\tcalls.push({\n\t\t\t\t\tid: tool.id,\n\t\t\t\t\ttype: 'function',\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: tool.name,\n\t\t\t\t\t\targuments: JSON.stringify(tool.args || {})\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tresults.push({\n\t\t\t\t\trole: 'tool',\n\t\t\t\t\ttool_call_id: tool.id,\n\t\t\t\t\tcontent: tool.error || tool.content || ''\n\t\t\t\t});\n\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\twire.push({\n\t\t\t\trole: 'assistant',\n\t\t\t\tcontent: null,\n\t\t\t\ttool_calls: calls\n\t\t\t});\n\n\t\t\twire.push(...results);\n\t\t\ti--;\n\t\t}\n\n\t\treturn wire;\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string | any> {\n\t\tconst controller = new AbortController();\n\t\treturn Object.assign(new Promise<any>(async (res, rej) => {\n\t\t\tif(!options.history) options.history = [];\n\t\t\tconst history = options.history;\n\t\t\tif(message) history.push({role: 'user', content: message, timestamp: Date.now()});\n\t\t\tconst tools = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst requestParams: any = {\n\t\t\t\tmodel: options.model || this.model,\n\t\t\t\tstream: !!options.stream,\n\t\t\t\tmax_completion_tokens: options.maxTokens ?? this.ai.options.llm?.maxTokens,\n\t\t\t\ttemperature: options.temperature ?? this.ai.options.llm?.temperature,\n\t\t\t\ttools: tools.map(t => ({\n\t\t\t\t\ttype: 'function',\n\t\t\t\t\tfunction: {\n\t\t\t\t\t\tname: t.name,\n\t\t\t\t\t\tdescription: t.description,\n\t\t\t\t\t\tparameters: {\n\t\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\t\tproperties: t.args\n\t\t\t\t\t\t\t\t? objectMap(t.args, (key, value) => ({...value, required: undefined}))\n\t\t\t\t\t\t\t\t: {},\n\t\t\t\t\t\t\trequired: t.args\n\t\t\t\t\t\t\t\t? Object.entries(t.args).filter(t => t[1].required).map(t => t[0])\n\t\t\t\t\t\t\t\t: []\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t};\n\n\t\t\tif(options.schema) {\n\t\t\t\tconst schema = convertSchema(options.schema);\n\t\t\t\trequestParams.response_format = {\n\t\t\t\t\ttype: 'json_schema',\n\t\t\t\t\tjson_schema: {name: 'response', strict: true, schema}\n\t\t\t\t};\n\t\t\t}\n\t\t\tif(options.stream) requestParams.stream_options = {include_usage: true};\n\n\t\t\ttry {\n\t\t\t\tlet terminal = false;\n\t\t\t\tlet iteration = 0;\n\n\t\t\t\tdo {\n\t\t\t\t\titeration++;\n\t\t\t\t\trequestParams.messages = this.toWire(history.filter(h => h.role !== 'system'), options.system);\n\n\t\t\t\t\tconst callStart = Date.now();\n\t\t\t\t\tconst resp: any = await this.tokenPool.run(token =>\n\t\t\t\t\t\tthis.getClient(token).chat.completions.create(requestParams)\n\t\t\t\t\t).catch(err => {\n\t\t\t\t\t\terr.message += `\\n\\nMessages:\\n${JSON.stringify(requestParams.messages, null, 2)}`;\n\t\t\t\t\t\tthrow err;\n\t\t\t\t\t});\n\n\t\t\t\t\tlet usage: any;\n\t\t\t\t\tlet finishReason: string | undefined;\n\t\t\t\t\tlet msg: any = {content: '', tool_calls: []};\n\t\t\t\t\tlet streamedChars = 0;\n\n\t\t\t\t\tif(options.stream) {\n\t\t\t\t\t\tlet streamCompleted = false;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tfor await (const chunk of resp) {\n\t\t\t\t\t\t\t\tif(controller.signal.aborted) break;\n\t\t\t\t\t\t\t\tif(chunk.usage) usage = chunk.usage;\n\n\t\t\t\t\t\t\t\tconst choice = chunk.choices?.[0];\n\t\t\t\t\t\t\t\tif(choice?.finish_reason) finishReason = choice.finish_reason;\n\n\t\t\t\t\t\t\t\tif(choice?.delta?.content) {\n\t\t\t\t\t\t\t\t\tmsg.content += choice.delta.content;\n\t\t\t\t\t\t\t\t\tstreamedChars += choice.delta.content.length;\n\t\t\t\t\t\t\t\t\toptions.stream({text: choice.delta.content});\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif(choice?.delta?.tool_calls) {\n\t\t\t\t\t\t\t\t\tfor(const deltaTC of choice.delta.tool_calls) {\n\t\t\t\t\t\t\t\t\t\tconst index = deltaTC.index ?? msg.tool_calls.length;\n\t\t\t\t\t\t\t\t\t\tlet existing = msg.tool_calls.find((tc: any) => tc.index === index);\n\n\t\t\t\t\t\t\t\t\t\tif(!existing) {\n\t\t\t\t\t\t\t\t\t\t\texisting = {index, id: '', function: {name: '', arguments: ''}};\n\t\t\t\t\t\t\t\t\t\t\tmsg.tool_calls.push(existing);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.id) existing.id = deltaTC.id;\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.function?.name) existing.function.name = deltaTC.function.name;\n\t\t\t\t\t\t\t\t\t\tif(deltaTC.function?.arguments) existing.function.arguments += deltaTC.function.arguments;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tstreamCompleted = true;\n\t\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\t\tif(!controller.signal.aborted) throw err;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif(streamCompleted && !finishReason) finishReason = msg.tool_calls.length ? 'tool_calls' : 'stop';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tusage = resp.usage;\n\t\t\t\t\t\tfinishReason = resp.choices[0].finish_reason;\n\t\t\t\t\t\tmsg = resp.choices[0].message;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst duration = Date.now() - callStart;\n\t\t\t\t\tconst tps = usage?.completion_tokens && duration > 0 ? usage.completion_tokens / (duration / 1000) : 0;\n\n\t\t\t\t\tif(finishReason === 'length' && !controller.signal.aborted) {\n\t\t\t\t\t\tif(msg.content?.trim()) history.push({role: 'assistant', content: msg.content.trim(), timestamp: Date.now(), duration, tps});\n\t\t\t\t\t\tthrow new Error(`[OpenAI] Response hit token limit before completing`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif(!finishReason && !controller.signal.aborted) {\n\t\t\t\t\t\tthrow new Error('[OpenAI] Completion ended without a usable response');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst toolCalls = msg.tool_calls || [];\n\n\t\t\t\t\tif(toolCalls.length && !controller.signal.aborted) {\n\t\t\t\t\t\tif(msg.content?.trim()) history.push({role: 'assistant', content: msg.content.trim(), timestamp: Date.now(), duration, tps});\n\n\t\t\t\t\t\tconst entries = toolCalls.map((tc: any) => {\n\t\t\t\t\t\t\tconst entry: any = {\n\t\t\t\t\t\t\t\trole: 'tool',\n\t\t\t\t\t\t\t\tid: tc.id,\n\t\t\t\t\t\t\t\tname: tc.function.name,\n\t\t\t\t\t\t\t\targs: JSONAttemptParse(tc.function.arguments, {}),\n\t\t\t\t\t\t\t\tcontent: undefined,\n\t\t\t\t\t\t\t\ttimestamp: Date.now()\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\thistory.push(entry);\n\t\t\t\t\t\t\treturn {tc, entry};\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tawait Promise.all(entries.map(async ({tc, entry}: any) => {\n\t\t\t\t\t\t\tconst tool = tools.find(findByProp('name', tc.function.name));\n\t\t\t\t\t\t\tif(options.stream) options.stream({tool: tc.function.name});\n\t\t\t\t\t\t\tif(!tool) return entry.error = 'Tool not found';\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst toolStream = options.stream && ((chunk: any) => {\n\t\t\t\t\t\t\t\t\tif(chunk.done) return;\n\t\t\t\t\t\t\t\t\toptions.stream!(chunk);\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\tconst result = await tool.fn(entry.args, toolStream, this.ai, tc.id);\n\t\t\t\t\t\t\t\tentry.content = typeof result === 'object' ? JSONSanitize(result) : result;\n\t\t\t\t\t\t\t} catch(err: any) {\n\t\t\t\t\t\t\t\tentry.error = err?.message || err?.toString() || 'Unknown';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tterminal = true;\n\t\t\t\t\t\tconst text = (msg.content || '').trim();\n\t\t\t\t\t\tif(text) history.push({role: 'assistant', content: text, timestamp: Date.now(), duration, tps});\n\t\t\t\t\t}\n\t\t\t\t} while(!terminal && !controller.signal.aborted);\n\n\t\t\t\tif(options.stream) options.stream({done: true});\n\t\t\t\tconst turnStart = history.map(h => h.role).lastIndexOf('user');\n\t\t\t\tconst finalContent = history.slice(turnStart + 1).reduce((str, h) => h.role === 'assistant' ? str + (h.content || '') : str, '').trim();\n\t\t\t\tres(options.schema ? JSONAttemptParse(finalContent, finalContent) : finalContent);\n\t\t\t} catch(err) {\n\t\t\t\trej(err);\n\t\t\t}\n\t\t}), {abort: () => controller.abort()});\n\t}\n}\n","import {Memory, MemoryCache} from './memory.ts';\n\nexport type MemoryNode = {\n\tname: string;\n\tmissing: boolean;\n\tlinks: string[];\n\tbacklinks: string[];\n}\n\nexport function extractLinks(content: string): string[] {\n\tif (!content) return [];\n\tconst matches = content.matchAll(/\\[\\[([^\\]|]+)(?:\\|[^\\]]*)?\\]\\]/g);\n\treturn [...new Set([...matches].map(m => m[1].trim()))];\n}\n\n/**\n * Incrementally patch the graph for a set of changed memories, instead of\n * re-scanning every document. Only the changed memories' own content is\n * re-parsed for links; affected targets have their backlinks patched.\n * Does NOT handle node deletion — full rebuildGraph() is still required\n * when a memory is removed, since that needs a backlink sweep across\n * everyone who might reference it.\n */\nexport function patchGraph(mems: Memory[], nodes: MemoryNode[], changed: Memory[]): MemoryNode[] {\n\tconst nameSet = new Set(mems.map(m => m.name));\n\tconst byName = new Map(nodes.map(n => [n.name, n]));\n\n\tconst ensureNode = (name: string): MemoryNode => {\n\t\tlet n = byName.get(name);\n\t\tif (!n) {\n\t\t\tn = {name, missing: !nameSet.has(name), links: [], backlinks: []};\n\t\t\tbyName.set(name, n);\n\t\t}\n\t\treturn n;\n\t};\n\n\tfor (const m of changed) {\n\t\tconst node = ensureNode(m.name);\n\t\tnode.missing = false; // real memory, promotes any pre-existing ghost entry\n\t\tconst oldLinks = m.links ?? [];\n\t\tconst newLinks = extractLinks(m.content).filter(l => l !== m.name);\n\n\t\tfor (const target of oldLinks.filter(l => !newLinks.includes(l))) {\n\t\t\tconst t = byName.get(target);\n\t\t\tif (!t) continue;\n\t\t\tt.backlinks = t.backlinks.filter(n => n !== m.name);\n\t\t\tif (t.missing && !t.backlinks.length) byName.delete(target); // fully dereferenced ghost\n\t\t}\n\t\tfor (const target of newLinks.filter(l => !oldLinks.includes(l))) {\n\t\t\tconst t = ensureNode(target);\n\t\t\tif (!t.backlinks.includes(m.name)) t.backlinks.push(m.name);\n\t\t}\n\n\t\tm.links = newLinks;\n\t\tnode.links = newLinks;\n\t}\n\n\tfor (const m of mems) {\n\t\tconst n = byName.get(m.name);\n\t\tif (n) m.backlinks = n.backlinks;\n\t}\n\n\treturn [...byName.values()];\n}\n\nexport function rebuildGraph(memories: Memory[] | MemoryCache): MemoryNode[] {\n\tconst mems = memories instanceof MemoryCache ? memories.memories : memories;\n\tconst nameSet = new Set(mems.map(m => m.name));\n\n\tfor (const m of mems) m.links = extractLinks(m.content).filter(l => l !== m.name);\n\tfor (const m of mems) m.backlinks = [];\n\tfor (const m of mems) {\n\t\tfor (const link of m.links) {\n\t\t\tconst target = mems.find(t => t.name === link);\n\t\t\tif (target) target.backlinks.push(m.name);\n\t\t}\n\t}\n\n\tconst nodes: MemoryNode[] = mems.map(m => ({\n\t\tname: m.name,\n\t\tmissing: false,\n\t\tlinks: m.links,\n\t\tbacklinks: m.backlinks,\n\t}));\n\n\tconst ghosts = new Set<string>();\n\tfor (const node of nodes) {\n\t\tfor (const link of node.links) {\n\t\t\tif (!nameSet.has(link)) ghosts.add(link);\n\t\t}\n\t}\n\n\treturn [\n\t\t...nodes,\n\t\t...[...ghosts].map(name => ({\n\t\t\tname,\n\t\t\tmissing: true,\n\t\t\tlinks: [],\n\t\t\tbacklinks: nodes.filter(n => n.links.includes(name)).map(n => n.name),\n\t\t})),\n\t];\n}\n\nexport function renderMemoryGraph(nodes: MemoryNode[]): string {\n\tif (!nodes.length) return 'No memories yet.';\n\n\tconst groups = new Map<string, (MemoryNode & {label: string})[]>();\n\tfor (const node of nodes) {\n\t\tconst [prefix, ...rest] = node.name.split('/');\n\t\tconst group = rest.length ? prefix : 'Root';\n\t\tconst label = rest.length ? rest.join('/') : node.name;\n\t\tif (!groups.has(group)) groups.set(group, []);\n\t\tgroups.get(group)!.push({...node, label});\n\t}\n\n\tconst ghostCount = nodes.filter(n => n.missing).length;\n\tconst lines = [`Memory Graph (${nodes.length} nodes, ${ghostCount} ghost${ghostCount === 1 ? '' : 's'})`, ''];\n\n\tfor (const group of [...groups.keys()].sort()) {\n\t\tconst items = groups.get(group)!.sort((a, b) => a.label.localeCompare(b.label));\n\t\tlines.push(`${group}/`);\n\t\titems.forEach((n, i) => {\n\t\t\tconst last = i === items.length - 1;\n\t\t\tconst branch = last ? '└─' : '├─';\n\t\t\tconst pad = last ? '  ' : '│ ';\n\t\t\tconst tag = n.missing ? ' (ghost)' : '';\n\t\t\tlines.push(`  ${branch} ${n.label}${tag}`);\n\t\t\tif (n.links.length) lines.push(`  ${pad}   → ${n.links.join(', ')}`);\n\t\t\tif (n.backlinks.length) lines.push(`  ${pad}   ← ${n.backlinks.join(', ')}`);\n\t\t});\n\t\tlines.push('');\n\t}\n\n\treturn lines.join('\\n').trimEnd();\n}\n","export type DistanceMetric = \"euclidean\" | \"cosine\";\n\nexport interface KDPoint<T = unknown> {\n\tvector: number[];\n\tpayload: T;\n}\n\nexport interface KNNResult<T = unknown> {\n\tpoint: KDPoint<T>;\n\tdistance: number;\n}\n\ninterface KDNode<T> {\n\tpoint: KDPoint<T>;\n\taxis: number;\n\tleft: KDNode<T> | null;\n\tright: KDNode<T> | null;\n\tdeleted?: boolean;\n}\n\n// ─── Distance helpers ─────────────────────────────────────────────────────────\n\nfunction euclidean(a: number[], b: number[]): number {\n\tlet sum = 0;\n\tfor (let i = 0; i < a.length; i++) {\n\t\tconst d = a[i] - b[i];\n\t\tsum += d * d;\n\t}\n\treturn Math.sqrt(sum);\n}\n\nfunction cosine(a: number[], b: number[]): number {\n\tlet dot = 0, normA = 0, normB = 0;\n\tfor (let i = 0; i < a.length; i++) {\n\t\tdot   += a[i] * b[i];\n\t\tnormA += a[i] * a[i];\n\t\tnormB += b[i] * b[i];\n\t}\n\tconst denom = Math.sqrt(normA) * Math.sqrt(normB);\n\treturn denom === 0 ? 1 : 1 - dot / denom; // distance = 1 - similarity\n}\n\n/**\n * Keeps the k closest candidates in memory, evicts the furthest when full\n */\nclass BoundedMaxHeap<T> {\n\tprivate heap: KNNResult<T>[] = [];\n\n\tconstructor(private readonly k: number) {}\n\n\tget size(): number { return this.heap.length; }\n\n\tget worstDistance(): number {\n\t\treturn this.heap.length < this.k ? Infinity : this.heap[0].distance;\n\t}\n\n\tpush(item: KNNResult<T>): void {\n\t\tif (this.heap.length < this.k) {\n\t\t\tthis.heap.push(item);\n\t\t\tthis.bubbleUp(this.heap.length - 1);\n\t\t} else if (item.distance < this.heap[0].distance) {\n\t\t\tthis.heap[0] = item;\n\t\t\tthis.sinkDown(0);\n\t\t}\n\t}\n\n\ttoSortedArray(): KNNResult<T>[] {\n\t\treturn [...this.heap].sort((a, b) => a.distance - b.distance);\n\t}\n\n\tprivate bubbleUp(i: number): void {\n\t\twhile (i > 0) {\n\t\t\tconst parent = (i - 1) >> 1;\n\t\t\tif (this.heap[parent].distance >= this.heap[i].distance) break;\n\t\t\t[this.heap[parent], this.heap[i]] = [this.heap[i], this.heap[parent]];\n\t\t\ti = parent;\n\t\t}\n\t}\n\n\tprivate sinkDown(i: number): void {\n\t\tconst n = this.heap.length;\n\t\twhile (true) {\n\t\t\tlet largest = i;\n\t\t\tconst l = 2 * i + 1, r = 2 * i + 2;\n\t\t\tif (l < n && this.heap[l].distance > this.heap[largest].distance) largest = l;\n\t\t\tif (r < n && this.heap[r].distance > this.heap[largest].distance) largest = r;\n\t\t\tif (largest === i) break;\n\t\t\t[this.heap[largest], this.heap[i]] = [this.heap[i], this.heap[largest]];\n\t\t\ti = largest;\n\t\t}\n\t}\n}\n\n/**\n * K-D Tree for efficient nearest-neighbor search over high-dimensional vectors / embeddings.\n *\n * Supports:\n *  - Insertion of labeled points\n *  - Lazy (tombstone) removal, physically purged on rebalance()\n *  - k-nearest-neighbor (KNN) search\n *  - Radius search (all points within a given distance)\n *  - Euclidean and cosine distance metrics\n *  - Bulk construction (balanced tree) for best query performance\n */\nexport class KDTree<T = unknown> {\n\tprivate root: KDNode<T> | null = null;\n\tprivate _size = 0;\n\tprivate _tombstones = 0;\n\tprivate readonly distanceFn: (a: number[], b: number[]) => number;\n\n\treadonly dims: number;\n\n\t/**\n\t * @param dims           Dimensionality of all vectors (must be consistent).\n\t * @param metric         Distance metric to use. Default: \"euclidean\".\n\t * @param points         Optional initial set of points. Builds a balanced tree\n\t *                       in O(n log² n) — prefer this over inserting one-by-one\n\t *                       when you have a large corpus.\n\t */\n\tconstructor(\n\t\tdims: number,\n\t\tmetric: DistanceMetric = \"euclidean\",\n\t\tpoints?: KDPoint<T>[]\n\t) {\n\t\tthis.dims = dims;\n\t\tthis.distanceFn = metric === \"cosine\" ? cosine : euclidean;\n\n\t\tif (points && points.length > 0) {\n\t\t\tthis.validateAll(points);\n\t\t\tthis.root = this.buildBalanced([...points], 0);\n\t\t\tthis._size = points.length;\n\t\t}\n\t}\n\n\t/** Total number of live points stored in the tree (excludes tombstoned). */\n\tget size(): number { return this._size; }\n\n\t/** Fraction of physical nodes that are tombstoned (pending removal on next rebalance). */\n\tget tombstoneRatio(): number {\n\t\tconst total = this._size + this._tombstones;\n\t\treturn total ? this._tombstones / total : 0;\n\t}\n\n\t// ── Insertion ──────────────────────────────────────────────────────────────\n\n\t/**\n\t * Insert a single point. O(log n) average, O(n) worst case on skewed data.\n\t * For bulk loading prefer passing points to the constructor.\n\t */\n\tinsert(point: KDPoint<T>): void {\n\t\tthis.validate(point);\n\t\tthis.root = this.insertNode(this.root, point, 0);\n\t\tthis._size++;\n\t}\n\n\t// ── Removal ────────────────────────────────────────────────────────────────\n\n\t/**\n\t * Lazily remove all live points whose payload matches `predicate`.\n\t * O(n) traversal, but avoids a full tree rebuild. Call `rebalance()`\n\t * periodically (e.g. once tombstoneRatio crosses ~0.25) to reclaim space\n\t * and restore optimal query depth.\n\t * @returns number of points removed\n\t */\n\tremove(predicate: (payload: T) => boolean): number {\n\t\tlet removed = 0;\n\t\tconst visit = (node: KDNode<T> | null): void => {\n\t\t\tif (!node) return;\n\t\t\tif (!node.deleted && predicate(node.point.payload)) {\n\t\t\t\tnode.deleted = true;\n\t\t\t\tremoved++;\n\t\t\t}\n\t\t\tvisit(node.left);\n\t\t\tvisit(node.right);\n\t\t};\n\t\tvisit(this.root);\n\t\tthis._size -= removed;\n\t\tthis._tombstones += removed;\n\t\treturn removed;\n\t}\n\n\t// ── KNN search ─────────────────────────────────────────────────────────────\n\n\t/**\n\t * Find the k nearest live neighbors to `query`.\n\t * Returns results sorted by distance ascending.\n\t */\n\tknn(query: number[], k: number): KNNResult<T>[] {\n\t\tif (k <= 0) throw new RangeError(\"k must be a positive integer\");\n\t\tthis.validateVector(query);\n\n\t\tconst heap = new BoundedMaxHeap<T>(k);\n\t\tthis.searchKNN(this.root, query, k, heap, 0);\n\t\treturn heap.toSortedArray();\n\t}\n\n\t/**\n\t * Nearest single neighbor. Convenience wrapper around knn(query, 1).\n\t * Returns null if the tree is empty.\n\t */\n\tnearest(query: number[]): KNNResult<T> | null {\n\t\tconst results = this.knn(query, 1);\n\t\treturn results[0] ?? null;\n\t}\n\n\t// ── Radius search ──────────────────────────────────────────────────────────\n\n\t/**\n\t * Return all live points whose distance to `query` is ≤ `radius`,\n\t * sorted by distance ascending.\n\t */\n\tradiusSearch(query: number[], radius: number): KNNResult<T>[] {\n\t\tif (radius < 0) throw new RangeError(\"radius must be non-negative\");\n\t\tthis.validateVector(query);\n\n\t\tconst results: KNNResult<T>[] = [];\n\t\tthis.searchRadius(this.root, query, radius, results, 0);\n\t\tresults.sort((a, b) => a.distance - b.distance);\n\t\treturn results;\n\t}\n\n\t// ── Conversion ─────────────────────────────────────────────────────────────\n\n\t/** Collect all live points in the tree (order not guaranteed). */\n\ttoArray(): KDPoint<T>[] {\n\t\tconst out: KDPoint<T>[] = [];\n\t\tthis.collect(this.root, out);\n\t\treturn out;\n\t}\n\n\t/**\n\t * Rebuild the tree from its current live points as a balanced tree.\n\t * Physically purges tombstones and restores O(log n) query time.\n\t */\n\trebalance(): void {\n\t\tconst points = this.toArray();\n\t\tthis.root = points.length ? this.buildBalanced(points, 0) : null;\n\t\tthis._size = points.length;\n\t\tthis._tombstones = 0;\n\t}\n\n\t// ── Private: build ─────────────────────────────────────────────────────────\n\n\tprivate buildBalanced(points: KDPoint<T>[], depth: number): KDNode<T> {\n\t\tconst axis = depth % this.dims;\n\t\tpoints.sort((a, b) => a.vector[axis] - b.vector[axis]);\n\n\t\tconst mid = Math.floor(points.length / 2);\n\t\treturn {\n\t\t\tpoint: points[mid],\n\t\t\taxis,\n\t\t\tleft:  points.slice(0, mid).length\n\t\t\t\t? this.buildBalanced(points.slice(0, mid), depth + 1)\n\t\t\t\t: null,\n\t\t\tright: points.slice(mid + 1).length\n\t\t\t\t? this.buildBalanced(points.slice(mid + 1), depth + 1)\n\t\t\t\t: null,\n\t\t};\n\t}\n\n\t// ── Private: insert ────────────────────────────────────────────────────────\n\n\tprivate insertNode(\n\t\tnode: KDNode<T> | null,\n\t\tpoint: KDPoint<T>,\n\t\tdepth: number\n\t): KDNode<T> {\n\t\tif (node === null) {\n\t\t\treturn { point, axis: depth % this.dims, left: null, right: null };\n\t\t}\n\t\tconst axis = depth % this.dims;\n\t\tif (point.vector[axis] < node.point.vector[axis]) {\n\t\t\tnode.left = this.insertNode(node.left, point, depth + 1);\n\t\t} else {\n\t\t\tnode.right = this.insertNode(node.right, point, depth + 1);\n\t\t}\n\t\treturn node;\n\t}\n\n\t// ── Private: KNN traversal ─────────────────────────────────────────────────\n\n\tprivate searchKNN(\n\t\tnode: KDNode<T> | null,\n\t\tquery: number[],\n\t\tk: number,\n\t\theap: BoundedMaxHeap<T>,\n\t\tdepth: number\n\t): void {\n\t\tif (node === null) return;\n\n\t\tif (!node.deleted) {\n\t\t\tconst dist = this.distanceFn(query, node.point.vector);\n\t\t\theap.push({ point: node.point, distance: dist });\n\t\t}\n\n\t\tconst axis = node.axis;\n\t\tconst diff = query[axis] - node.point.vector[axis];\n\t\tconst [near, far] = diff <= 0\n\t\t\t? [node.left, node.right]\n\t\t\t: [node.right, node.left];\n\n\t\tthis.searchKNN(near, query, k, heap, depth + 1);\n\n\t\t// Only explore the far side if it could contain a closer point.\n\t\t// For cosine distance we can't prune by axis gap alone, so always explore.\n\t\tconst shouldExplore =\n\t\t\tthis.distanceFn === cosine\n\t\t\t\t? true\n\t\t\t\t: Math.abs(diff) < heap.worstDistance;\n\n\t\tif (shouldExplore) {\n\t\t\tthis.searchKNN(far, query, k, heap, depth + 1);\n\t\t}\n\t}\n\n\t// ── Private: radius traversal ──────────────────────────────────────────────\n\n\tprivate searchRadius(\n\t\tnode: KDNode<T> | null,\n\t\tquery: number[],\n\t\tradius: number,\n\t\tresults: KNNResult<T>[],\n\t\tdepth: number\n\t): void {\n\t\tif (node === null) return;\n\n\t\tif (!node.deleted) {\n\t\t\tconst dist = this.distanceFn(query, node.point.vector);\n\t\t\tif (dist <= radius) {\n\t\t\t\tresults.push({ point: node.point, distance: dist });\n\t\t\t}\n\t\t}\n\n\t\tconst axis = node.axis;\n\t\tconst diff = query[axis] - node.point.vector[axis];\n\t\tconst [near, far] = diff <= 0\n\t\t\t? [node.left, node.right]\n\t\t\t: [node.right, node.left];\n\n\t\tthis.searchRadius(near, query, radius, results, depth + 1);\n\n\t\tconst shouldExplore =\n\t\t\tthis.distanceFn === cosine ? true : Math.abs(diff) <= radius;\n\n\t\tif (shouldExplore) {\n\t\t\tthis.searchRadius(far, query, radius, results, depth + 1);\n\t\t}\n\t}\n\n\t// ── Private: collect ───────────────────────────────────────────────────────\n\n\tprivate collect(node: KDNode<T> | null, out: KDPoint<T>[]): void {\n\t\tif (node === null) return;\n\t\tif (!node.deleted) out.push(node.point);\n\t\tthis.collect(node.left, out);\n\t\tthis.collect(node.right, out);\n\t}\n\n\t// ── Private: validation ────────────────────────────────────────────────────\n\n\tprivate validateVector(v: number[]): void {\n\t\tif (v.length !== this.dims) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`Vector length ${v.length} does not match tree dimensionality ${this.dims}`\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate validate(point: KDPoint<T>): void {\n\t\tthis.validateVector(point.vector);\n\t}\n\n\tprivate validateAll(points: KDPoint<T>[]): void {\n\t\tfor (const p of points) this.validate(p);\n\t}\n}\n","import {MemoryNode, patchGraph, rebuildGraph} from './helpers.ts';\nimport {LLMRequest, LLMMessage} from './llm.ts';\nimport {AiTool} from './tools.ts';\nimport {KDTree} from './kd-tree.ts';\n\nconst FACT_SIMILARITY_THRESHOLD = 0.62;\nconst PENDING_HEADING = '## Pending';\nconst TODO_HEADING = '## Todo list';\nconst TREE_TOMBSTONE_LIMIT = 0.25;\nconst ALIAS_MATCH_THRESHOLD = 0.55;\n\nexport type Memory = {\n\tname: string;\n\tdescription: string;\n\tcontent: string;\n\tembedding: number[];\n\ttitleEmbedding?: number[];\n\tbodyEmbeddings?: number[][];\n\tlinks: string[];\n\tbacklinks: string[];\n}\n\ntype MemoryRef = {\n\tname: string;\n\tdescription: string;\n\tdistance?: number;\n}\n\ntype FactBucket = {\n\tsubject: string;\n\tfacts: string[];\n}\n\ntype MemoryTask = {\n\t/** Exact node name / new persistent entity path this task belongs to, or '' for a personal task with no entity (goes to the journal) */\n\tsubject: string;\n\ttask: string;\n\tdone: boolean;\n}\n\ntype FactAgentResult = {\n\tbuckets: FactBucket[];\n\tjournal: string;\n\ttasks: MemoryTask[];\n}\n\nfunction dedupeFacts(facts: string[]): string[] {\n\tconst seen = new Map<string, string>();\n\tfor(const f of facts) {\n\t\tconst clean = f.trim();\n\t\tif(clean) seen.set(clean.toLowerCase(), clean);\n\t}\n\treturn [...seen.values()];\n}\n\nfunction cosineDistance(a: number[], b: number[]): number {\n\tlet dot = 0, normA = 0, normB = 0;\n\tfor(let i = 0; i < a.length; i++) {\n\t\tdot += a[i] * b[i];\n\t\tnormA += a[i] * a[i];\n\t\tnormB += b[i] * b[i];\n\t}\n\tconst denom = Math.sqrt(normA) * Math.sqrt(normB);\n\treturn denom === 0 ? 1 : 1 - dot / denom;\n}\n\nfunction cosineSearch(query: number[], memories: Memory[], limit: number): MemoryRef[] {\n\treturn memories\n\t\t.filter(m => m.embedding?.length)\n\t\t.map(m => ({name: m.name, description: m.description, distance: cosineDistance(query, m.embedding)}))\n\t\t.sort((a, b) => a.distance - b.distance)\n\t\t.slice(0, limit);\n}\n\nasync function embedMemoryFields(node: Memory, llm: any): Promise<void> {\n\tconst body = stripHeader(node.content);\n\tconst [titleE] = await llm.embedding(node.name.split('/').pop() || node.name);\n\tconst [descE] = await llm.embedding(node.description || '');\n\tconst bodyChunks = body ? await llm.embedding(body) : [];\n\tif(titleE) node.titleEmbedding = titleE.embedding;\n\tif(descE) node.embedding = descE.embedding;\n\tnode.bodyEmbeddings = bodyChunks.map((c: any) => c.embedding).filter(Boolean);\n}\n\nexport function stripHeader(content: string): string {\n\treturn content.replace(/^---[\\s\\S]*?\\n---\\n?/, '').trimStart();\n}\n\n/** True if a task has no persistent entity of its own and belongs in the journal instead. */\nfunction isPersonalTask(t: MemoryTask): boolean {\n\tconst s = (t.subject ?? '').trim().toLowerCase();\n\treturn !s || s === 'journal' || s.startsWith('journal/');\n}\n\nexport class MemoryCache {\n\tprivate tree!: KDTree<MemoryRef>;\n\tprivate indexed = new Map<string, number[]>();\n\tpublic memories: Memory[];\n\tpublic nodes: MemoryNode[] = [];\n\n\tget length() { return this.memories.length; }\n\n\tconstructor(memories: Memory[]) {\n\t\tthis.memories = memories;\n\t\tthis.tree = new KDTree<MemoryRef>(0);\n\t\tthis.rebuild();\n\t}\n\n\tprivate syncTree(): void {\n\t\tconst current = new Set(this.memories.map(m => m.name));\n\n\t\tfor(const [name, emb] of [...this.indexed]) {\n\t\t\tconst mem = this.memories.find(m => m.name === name);\n\t\t\tif(!mem || !current.has(name) || mem.embedding !== emb) {\n\t\t\t\tthis.tree.remove(p => p.name === name);\n\t\t\t\tthis.indexed.delete(name);\n\t\t\t}\n\t\t}\n\n\t\tfor(const mem of this.memories) {\n\t\t\tif(!mem.embedding?.length || this.indexed.has(mem.name)) continue;\n\t\t\tif(this.tree.dims === 0) this.tree = new KDTree<MemoryRef>(mem.embedding.length, 'cosine');\n\t\t\tif(mem.embedding.length !== this.tree.dims) continue; // guard against embedding model/dim drift\n\t\t\tthis.tree.insert({vector: mem.embedding, payload: {name: mem.name, description: mem.description}});\n\t\t\tthis.indexed.set(mem.name, mem.embedding);\n\t\t}\n\n\t\tif(this.tree.tombstoneRatio > TREE_TOMBSTONE_LIMIT) this.tree.rebalance();\n\t}\n\n\tsearch(query: number[], limit: number): MemoryRef[] {\n\t\tif(!this.tree || this.tree.dims === 0) return [];\n\t\treturn this.tree.knn(query, limit).map(r => ({...r.point.payload, distance: r.distance}));\n\t}\n\n\tadd(memory: Memory): void {\n\t\tthis.memories.push(memory);\n\t\tthis.rebuild([memory]);\n\t}\n\n\tupdate(memory: Memory): void {\n\t\tconst existing = this.memories.find(m => m.name === memory.name);\n\t\tif(existing) Object.assign(existing, memory);\n\t\telse this.memories.push(memory);\n\t\tthis.rebuild([existing ?? memory]);\n\t}\n\n\tremove(name: string): void {\n\t\tconst idx = this.memories.findIndex(m => m.name === name);\n\t\tif(idx !== -1) {\n\t\t\tthis.memories.splice(idx, 1);\n\t\t\tthis.rebuild();\n\t\t}\n\t}\n\n\trebuild(changed?: Memory[]): void {\n\t\tthis.nodes = (changed?.length && this.nodes.length)\n\t\t\t? patchGraph(this.memories, this.nodes, changed)\n\t\t\t: rebuildGraph(this.memories);\n\t\tthis.syncTree();\n\t}\n}\n\nclass MemoryAccessor {\n\treadonly list: Memory[];\n\tprivate readonly cache: MemoryCache | null;\n\n\tconstructor(memories: Memory[] | MemoryCache) {\n\t\tthis.cache = memories instanceof MemoryCache ? memories : null;\n\t\tthis.list = this.cache ? this.cache.memories : <Memory[]>memories;\n\t}\n\n\tfind(name: string): Memory | undefined {\n\t\treturn this.list.find(m => m.name === name);\n\t}\n\n\tcommit(changed?: Memory[]): MemoryNode[] {\n\t\tif(this.cache) {\n\t\t\tthis.cache.rebuild(changed);\n\t\t\treturn this.cache.nodes;\n\t\t}\n\t\treturn rebuildGraph(this.list);\n\t}\n\n\tghosts(): string[] {\n\t\tconst nodes = this.cache ? this.cache.nodes : rebuildGraph(this.list);\n\t\treturn nodes.filter(n => n.missing).map(n => n.name);\n\t}\n\n\tsearch(vector: number[], limit: number): MemoryRef[] {\n\t\treturn this.cache ? this.cache.search(vector, limit) : cosineSearch(vector, this.list, limit);\n\t}\n\n\tforget(name: string): boolean {\n\t\tconst idx = this.list.findIndex(m => m.name === name);\n\t\tif(idx === -1) return false;\n\t\tthis.list.splice(idx, 1);\n\t\tthis.commit();\n\t\treturn true;\n\t}\n\n\tasync backfillEmbeddings(llm: any): Promise<number> {\n\t\tconst missing = this.list.filter(m => !m.embedding?.length);\n\t\tif(!missing.length) return 0;\n\t\tawait Promise.all(missing.map(node => embedMemoryFields(node, llm)));\n\t\tthis.commit();\n\t\treturn missing.length;\n\t}\n}\n\nexport type MemoryOptions = {\n\t/** Memory object */\n\tmemory: Memory[] | MemoryCache;\n\t/** Inject N memories into the system prompt */\n\tinject?: boolean;\n\t/** expose recall tool to LLM */\n\ttool?: boolean;\n\t/** Update memory on compression */\n\tupdate?: boolean;\n\t/** Max context size of memories to inject to each call (removed immediately after use) */\n\tmaxTokens?: number;\n}\n\nexport class MemoryManager {\n\tprivate mergeLock: Promise<any> = Promise.resolve();\n\tprivate queues = new Map<string, {\n\t\tdirty: boolean,\n\t\trequest: {abort?: () => void} | null,\n\t\ttask: Promise<void>,\n\t}>();\n\tprivate recentlyTouched = new Map<string, number>();\n\n\ttools = {\n\t\tforget: (memories: Memory[] | MemoryCache): AiTool => ({\n\t\t\tname: 'memory_forget',\n\t\t\tdescription: 'Permanently delete a memory document and clean up all references to it',\n\t\t\targs: {\n\t\t\t\tname: {type: 'string', description: 'Exact memory name to forget', required: true}\n\t\t\t},\n\t\t\tfn: (args: any) => {\n\t\t\t\tconst result = this.forget(args.name, memories);\n\t\t\t\treturn result ? `Forgotten: ${args.name}` : `Not found: ${args.name}`;\n\t\t\t},\n\t\t}),\n\n\t\tread: (memories: Memory[] | MemoryCache): AiTool => ({\n\t\t\tname: 'memory_recall',\n\t\t\tdescription: 'Read the full content of a memory document',\n\t\t\targs: {\n\t\t\t\tname: {type: 'string', description: 'Exact memory name', required: true}\n\t\t\t},\n\t\t\tfn: (args: any) => {\n\t\t\t\tconst mem = new MemoryAccessor(memories).find(args.name);\n\t\t\t\tif(!mem) return 'Document not found';\n\t\t\t\tthis.touch(mem.name);\n\t\t\t\treturn mem.content;\n\t\t\t},\n\t\t}),\n\n\t\tsearch: (memories: Memory[] | MemoryCache): AiTool => ({\n\t\t\tname: 'memory_search',\n\t\t\tdescription: 'Use embeddings to find the MOST relevant memories, even if NOT relevant',\n\t\t\targs: {\n\t\t\t\tquery: {type: 'string', description: 'What to look for in the memories', required: true},\n\t\t\t\tlimit: {type: 'number', description: 'Number of memories to return', default: 1},\n\t\t\t},\n\t\t\tfn: async ({query, limit}) => {\n\t\t\t\tconst mem = await this.recollect(query, memories, limit);\n\t\t\t\treturn mem.map(m => `Memory: ${m.name}\nDescription: ${m.description}\nLinks: ${[...m.links, ...m.backlinks].join(', ')}\n\\`\\`\\`\n${m.content}\n\\`\\`\\``).join('\\n\\n');\n\t\t\t},\n\t\t}),\n\t};\n\n\tconstructor(private llm: any) {}\n\n\tstatic normalize(m?: Memory[] | MemoryCache | MemoryOptions) {\n\t\tif(!m) return null;\n\t\tconst raw = m instanceof MemoryCache || Array.isArray(m);\n\t\treturn raw ? {memory: <Memory[] | MemoryCache>m, inject: true, tool: true, update: true} : {inject: true, tool: true, update: true, ...m};\n\t}\n\n\tprivate stage(node: Memory, block: string): void {\n\t\tif(!node.content) {\n\t\t\tconst title = node.name.split('/').pop() ?? node.name;\n\t\t\tnode.content = this.touchHeader(node, `# ${title}\\n`);\n\t\t}\n\t\tconst body = stripHeader(node.content);\n\t\tconst idx = body.indexOf(PENDING_HEADING);\n\t\tconst newBody = idx === -1\n\t\t\t? `${body.trimEnd()}\\n\\n${PENDING_HEADING}\\n${block}\\n`\n\t\t\t: `${body.slice(0, idx + PENDING_HEADING.length)}\\n${block}${body.slice(idx + PENDING_HEADING.length)}`;\n\t\tnode.content = this.touchHeader(node, newBody);\n\t}\n\n\tprivate resolveSubject(subject: string, store: MemoryAccessor): string {\n\t\tfunction normalize(name: string): string {\n\t\t\treturn name.trim().toLowerCase().replace(/\\s+/g, ' ');\n\t\t}\n\n\t\tconst trimmed = subject.trim();\n\t\tconst exact = store.find(trimmed);\n\t\tif(exact) return exact.name;\n\n\t\tconst normalized = normalize(trimmed);\n\t\tconst caseInsensitive = store.list.find(m => normalize(m.name) === normalized);\n\t\tif(caseInsensitive) return caseInsensitive.name;\n\n\t\tconst root = trimmed.split('/')[0];\n\t\tconst leaf = trimmed.split('/').slice(1).join('/') || trimmed;\n\t\tconst candidates = store.list.filter(m => m.name.split('/')[0] === root && m.name !== trimmed);\n\t\tif(!candidates.length) return trimmed;\n\n\t\tconst leaves = candidates.map(m => m.name.split('/').slice(1).join('/') || m.name);\n\t\tconst probe = leaves.length > 1 ? leaves : [...leaves, ''];\n\t\tconst {max, similarities} = this.llm.fuzzyMatch(leaf, ...probe);\n\t\tif(max >= ALIAS_MATCH_THRESHOLD) return candidates[similarities.indexOf(max)].name;\n\n\t\treturn trimmed;\n\t}\n\n\tprivate async factAgent(conversation: string, store: MemoryAccessor, options: LLMRequest): Promise<FactAgentResult> {\n\t\tconst ghosts = store.ghosts();\n\n\t\tconst response = await this.llm.ask(conversation, {\n\t\t\tmodel: options.model,\n\t\t\ttemperature: 0.2,\n\t\t\tsystem: `Turn this conversation into a persistent memory file by extracting information into organized bullet points\n\nThink of this like an Obsidian vault with a clear division of responsibility:\n- The JOURNAL is a timeline. It answers \"what happened, and when\" and is the only place with a sense of time.\n- ENTITY DOSSIERS are a wiki. They answer \"what is currently true about this subject\", with no sense of time — only current state.\n- Never blur the two: a one-off event, conversation, or debugging session is a journal entry, not an entity, even if it's detailed.\n\n1. Journal Log\n- A chronological, skimmable log of what actually happened: real discussions, decisions made, progress on projects, problems worked through\n- This is NOT a transcript, and it is NOT a step-by-step record, its a compressed log of notable events & developments\n- One line per development is usually enough: what was worked on and the outcome, not the blow-by-blow of how\n- Skip small talk and trivial exchanges entirely. Skip anything that's a todo item (goes in Todo Tasks) or a durable fact about a subject (goes in Entity Dossiers)\n\n2. Todo Tasks\n- Extract concrete tasks the user says need to be done, should be done, or were completed\n- Return the task text and whether it is still todo or is done\n- A completed task should be marked done, not recreated as a new todo\n- Only extract actionable tasks, not general goals or observations, if none - omit returning a tasks array\n- Assign each task a subject:\n    - If the task belongs to a persistent entity (a project, a class, etc.), use that entity's exact node name, or a new entity path if it doesn't exist yet\n    - If it's a personal/life task with no entity of its own (reach out to someone, reply to an email, pay a bill, etc.), leave subject as an empty string — it belongs in the journal, not a new document\n\n3. Entity Dossiers\n- Detailed dossiers with all factual information regarding a subject\n- Record the final/end state, not intermediate changes\n- Ignore assistant claims, guesses, greetings, or temporary details\n- NEVER create a dossier for something I wouldnt find in a wiki site: temporary information, debugging, guesses, conversations (this is all journal entry stuff!)\n- identify its HOME ENTITY:\n    - The HOME ENTITY name should always be a [abstract|pro]noun\n    - The grammatical subject/owner of the fact is the strongest clue\n    - Always preference an existing entity over creating a new one\n    - New child entities are appropriate only when they are themselves distinct persistent entities\n    - A document represents a persistent entity, not a topic, feature, bug, event, decision, setting, or conversation fragment\n    - Put project facts under the project they belong to, person facts under the person, etc\n\nExample Entity Naming Convention:\n- Projects/[Name]\n- People/[Name]\n- History/[Name]\n- Science/[Name]\n- [Subject]/[Name]\n- Class/[Name]/[Chapter]\n\nUse [[WikiLinks]] to express relationships between entities. NEVER create documents just to hold relationships\nKeep journal material in the journal; don't turn journal events into entities unless they represent something persistent\n\nAvailable nodes:\n${this.listNodes(store.list).map(n => `- ${n.name}: ${n.description}`).join('\\n') || 'None yet.'}\n${ghosts.length ? `${ghosts.map(g => `- ${g}: (Ghost)`).join('\\n')}` : ''}`,\n\t\t\tschema: {\n\t\t\t\tjournal: {type: 'string', description: 'Short bullet point recap, omit if nothing notable happened'},\n\t\t\t\ttasks: {\n\t\t\t\t\ttype: 'array', description: 'Concrete tasks mentioned or completed in the conversation, omit if none', items: {\n\t\t\t\t\t\ttype: 'object', items: {\n\t\t\t\t\t\t\tsubject: {type: 'string', description: 'Exact node name / new persistent entity path this task belongs to, or an empty string if this is a personal task with no entity of its own (those go in the journal)', required: true},\n\t\t\t\t\t\t\ttask: {type: 'string', description: 'Concise actionable task', required: true},\n\t\t\t\t\t\t\tdone: {type: 'boolean', description: 'Whether the task is completed', required: true},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tbuckets: {\n\t\t\t\t\ttype: 'array', description: 'Groups of facts to remember; omit if none', items: {\n\t\t\t\t\t\ttype: 'object', items: {\n\t\t\t\t\t\t\tsubject: {type: 'string', description: 'Exact node name or new persistent entity path', required: true},\n\t\t\t\t\t\t\tfacts: {type: 'array', description: 'Facts to store here', items: {type: 'string'}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\n\t\tconst buckets = new Map<string, string[]>();\n\t\tfor(const bucket of response.buckets ?? []) {\n\t\t\tconst subject = bucket.subject.trim();\n\t\t\tconst facts = buckets.get(subject) ?? [];\n\t\t\tfacts.push(...dedupeFacts(bucket.facts));\n\t\t\tbuckets.set(subject, facts);\n\t\t}\n\n\t\treturn {\n\t\t\tbuckets: buckets.entries().toArray().map(([subject, facts]) => ({subject, facts})),\n\t\t\tjournal: (response.journal ?? '').trim(),\n\t\t\ttasks: response.tasks ?? [],\n\t\t};\n\t}\n\n\tprivate getWeekStart(date: Date = new Date()): string {\n\t\tconst d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));\n\t\tconst day = d.getUTCDay();\n\t\tconst diff = day === 0 ? -6 : 1 - day;\n\t\td.setUTCDate(d.getUTCDate() + diff);\n\t\treturn d.toISOString().slice(0, 10);\n\t}\n\n\tprivate journalDescription(journalName?: string): string {\n\t\tconst start = journalName?.split('/').pop() || this.getWeekStart();\n\t\tconst d = new Date(`${start}T00:00:00Z`);\n\t\td.setUTCDate(d.getUTCDate() + 6);\n\t\tconst end = d.toISOString().slice(0, 10);\n\t\treturn `Log from ${start} - ${end}`;\n\t}\n\n\tprivate getIncompleteTodos(content: string): string[] {\n\t\tconst body = stripHeader(content);\n\t\tconst match = body.match(/## Todo list\\n([\\s\\S]*?)(?=\\n## |$)/i);\n\t\tif(!match) return [];\n\t\treturn match[1].split('\\n')\n\t\t\t.map(line => line.match(/^\\s*-\\s*\\[([ xX])\\]\\s+(.+?)\\s*$/))\n\t\t\t.filter((m): m is RegExpMatchArray => !!m && m[1].toLowerCase() !== 'x')\n\t\t\t.map(m => m[2].trim());\n\t}\n\n\tprivate listNodes(memories: Memory[]): MemoryRef[] {\n\t\treturn memories.map(m => ({name: m.name, description: m.description}));\n\t}\n\n\tprivate async mergeAgent(node: Memory, memories: Memory[] | MemoryCache, options: LLMRequest): Promise<Memory | null> {\n\t\tfunction factSimilarity(a: Memory, b: Memory): number {\n\t\t\tif(!a.bodyEmbeddings?.length || !b.bodyEmbeddings?.length) return 0;\n\t\t\tlet best = 0;\n\t\t\tfor(const av of a.bodyEmbeddings) {\n\t\t\t\tfor(const bv of b.bodyEmbeddings) best = Math.max(best, 1 - cosineDistance(av, bv));\n\t\t\t}\n\t\t\treturn best;\n\t\t}\n\n\t\tif(!node.embedding?.length || node.name.startsWith('Journal/')) return null;\n\t\tconst store = new MemoryAccessor(memories);\n\t\tconst candidates = store.list\n\t\t\t.filter(m => m.name !== node.name && !m.name.startsWith('Journal/'))\n\t\t\t.filter(m => factSimilarity(node, m) >= FACT_SIMILARITY_THRESHOLD);\n\n\t\tif(!candidates.length) return null;\n\t\tconst closest = candidates.sort((a, b) => factSimilarity(node, b) - factSimilarity(node, a))[0];\n\t\tconst result = await this.llm.ask('', {\n\t\t\tmodel: options.model,\n\t\t\ttemperature: 0.3,\n\t\t\tschema: {\n\t\t\t\taContent: {type: 'string', description: 'Updated document A body in markdown, without frontmatter.', required: true},\n\t\t\t\tbContent: {type: 'string', description: 'Updated document B body in markdown, without frontmatter.', required: true},\n\t\t\t},\n\t\t\tsystem: `Maintain these two persistent knowledge-base documents like a wiki.\n\nDo NOT merge, rename, or delete either document. Both represent entities that should remain independently addressable.\n\nThe documents were selected because their facts may overlap. Your job is to reconcile duplicated information and connect the documents:\n- Decide which document is the HOME for each duplicated fact.\n- Keep the authoritative copy in that home document.\n- In the other document, replace the information with a short preamble and [[WikiLink]] to the home entity explaining the relationship.\n- If the documents are distinct entities but merely related, keep their distinct facts and add useful [[WikiLinks]] between them.\n- Do not delete useful entity-specific facts just because they are similar.\n- Do not invent relationships or facts.\n- Preserve useful history, technical specifics, structure, and existing [[WikiLinks]].\n- Most current truth wins when facts conflict.\n- Keep both documents concise and information-dense.\n- No frontmatter, preamble, filler, or AI commentary.\n\nDocument A (\"${node.name}\"):\n\\`\\`\\`markdown\n${stripHeader(node.content)}\n\\`\\`\\`\n\nDocument B (\"${closest.name}\"):\n\\`\\`\\`markdown\n${stripHeader(closest.content)}\n\\`\\`\\``,\n\t\t});\n\t\tconst a = store.find(node.name);\n\t\tconst b = store.find(closest.name);\n\t\tif(!a || !b || !result?.aContent || !result?.bContent) return null;\n\t\ta.content = this.touchHeader(a, result.aContent);\n\t\tb.content = this.touchHeader(b, result.bContent);\n\t\tawait Promise.all([embedMemoryFields(a, this.llm), embedMemoryFields(b, this.llm)]);\n\t\treturn a;\n\t}\n\n\tprivate reconcile(node: Memory, memories: Memory[] | MemoryCache, options: LLMRequest): Promise<void> {\n\t\tconst key = node.name;\n\t\tconst existing = this.queues.get(key);\n\t\tif(existing) {\n\t\t\texisting.dirty = true;\n\t\t\texisting.request?.abort?.();\n\t\t\treturn existing.task;\n\t\t}\n\n\t\tconst entry = {dirty: false, request: null, task: Promise.resolve()};\n\t\tthis.queues.set(key, entry);\n\t\tconst store = new MemoryAccessor(memories);\n\t\tentry.task = (async () => {\n\t\t\tlet current = node;\n\t\t\ttry {\n\t\t\t\tdo {\n\t\t\t\t\tentry.dirty = false;\n\t\t\t\t\tawait this.docAgent(current, store.list, options, entry);\n\t\t\t\t\tthis.mergeLock = this.mergeLock.then(() => this.mergeAgent(current, memories, options));\n\t\t\t\t\tconst result = await this.mergeLock;\n\t\t\t\t\tif(result) current = result;\n\t\t\t\t} while(entry.dirty);\n\t\t\t} finally {\n\t\t\t\tstore.commit([node]);\n\t\t\t\tthis.queues.delete(key);\n\t\t\t}\n\t\t})();\n\t\treturn entry.task;\n\t}\n\n\tprivate async docAgent(node: Memory, memories: Memory[], options: LLMRequest, entry: {request: {abort?: () => void} | null}): Promise<void> {\n\t\tif(!memories.includes(node)) return;\n\t\tconst currentBody = stripHeader(node.content);\n\t\tconst journal = node.name.startsWith('Journal/');\n\t\tconst system = (journal\n\t\t\t? `You maintain one persistent journal document\n\nRewrite the ENTIRE journal, folding \"## Pending\" into the existing content removing the heading\n\nJournal design:\n- Preserve the chronological daily log\n- Maintain a single \\`## Todo list\\` section for this entity: reconcile tasks semantically (merge equivalent tasks, remove duplicates, preserve incomplete tasks, check off completed ones), and keep it distinct from the narrative/fact sections\n- Group information by day under a date heading\n- Keep journal entries high level and concise: what was worked on and the outcome, not a step-by-step record of how — that detail lives in conversation history, not here\n- Use [[WikiLinks]] for persistent entities; don't turn ordinary journal events into entities\n- No frontmatter, preamble, filler, or AI commentary`\n\t\t\t: `You maintain one persistent knowledge-base entity document\n\nRewrite the ENTIRE document, folding \"## Pending\" into the existing content. Remove the Pending section when finished.\n\nDocument design:\n- The document represents one persistent entity. Keep information about that entity together and organized into sections\n- Merge any pending information in, newest fact wins conflicts; remove redundant content\n- Maintain a single \\`## Todo list\\` section for this entity: reconcile tasks semantically (merge equivalent tasks, remove duplicates, preserve incomplete tasks, check off completed ones), and keep it distinct from the narrative/fact sections\n- Let the structure fit the entity; there is NO fixed template\n- Add headings only when they meaningfully organize recurring information; don't create headings for one-off facts\n- Keep the document concise and information-dense without removing useful technical specifics\n- Current truth wins when facts conflict. Preserve older conflict as context, only when it adds useful meaning\n- No frontmatter, preamble, filler, or AI commentary`) + `\n\nAvailable nodes to link to:\n${this.listNodes(memories).filter(n => n.name !== node.name).map(n => n.name).join(', ') || 'none'}\n\nCurrent document:\n\\`\\`\\`markdown\n${currentBody}\n\\`\\`\\``;\n\t\tlet update;\n\t\ttry {\n\t\t\tfor(let i = 0; i < 2 && !update?.content; i++) {\n\t\t\t\tconst request = this.llm.ask(currentBody, {\n\t\t\t\t\tmodel: options.model,\n\t\t\t\t\ttemperature: 0.3,\n\t\t\t\t\tschema: {\n\t\t\t\t\t\tdescription: {type: 'string', description: 'One factual sentence describing the document\\'s ENTIRE SUBJECT MATTER — for use as a search/merge fingerprint', required: true},\n\t\t\t\t\t\tcontent: {type: 'string', description: 'Rewritten document body in markdown, without the frontmatter block', required: true},\n\t\t\t\t\t},\n\t\t\t\t\tsystem,\n\t\t\t\t});\n\t\t\t\tentry.request = request;\n\t\t\t\tupdate = await request;\n\t\t\t}\n\t\t} catch(err: any) {\n\t\t\tif(err?.name === 'AbortError') return;\n\t\t\tthrow err;\n\t\t} finally {\n\t\t\tentry.request = null;\n\t\t}\n\n\t\tif(!update?.content) return;\n\t\tnode.description = node.name.startsWith('Journal/') ? this.journalDescription(node.name) : node.name !== 'People/User' ? update.description.replaceAll(/[\\n:]/g, '') : 'All information about the current user';\n\t\tnode.content = this.touchHeader(node, update.content);\n\t\tawait embedMemoryFields(node, this.llm);\n\t}\n\n\tprivate parseFrontmatter(content: string): {fm: Map<string, string>, body: string} {\n\t\tconst match = content.match(/^---\\n([\\s\\S]*?)\\n---\\n?([\\s\\S]*)$/);\n\t\tif(!match) return {fm: new Map(), body: content};\n\t\tconst fm = new Map<string, string>();\n\t\tfor(const line of match[1].split('\\n')) {\n\t\t\tconst i = line.indexOf(':');\n\t\t\tif(i === -1) continue;\n\t\t\tconst key = line.slice(0, i).trim();\n\t\t\tconst raw = line.slice(i + 1).trim();\n\t\t\tlet value = raw;\n\t\t\ttry { value = JSON.parse(raw); } catch { }\n\t\t\tfm.set(key, value);\n\t\t}\n\t\treturn {fm, body: match[2]};\n\t}\n\n\tprivate touchHeader(node: Memory, body: string): string {\n\t\tconst {fm} = this.parseFrontmatter(node.content);\n\t\tfm.set('name', node.name);\n\t\tfm.set('description', (node.name.startsWith('Journal/') ? this.journalDescription(node.name) : node.description) || 'Persistent memory document');\n\t\tfm.set('modified', new Date().toISOString());\n\t\treturn this.writeFrontmatter(fm, stripHeader(body));\n\t}\n\n\tprivate writeFrontmatter(fm: Map<string, string>, body: string): string {\n\t\tconst lines = [...fm.entries()].map(([k, v]) => `${k}: ${JSON.stringify(String(v).replace(/\\s+/g, ' ').trim())}`);\n\t\treturn `---\\n${lines.join('\\n')}\\n---\\n\\n${body.trimStart()}`;\n\t}\n\n\tdecay() {\n\t\tfor(const [name, ttl] of this.recentlyTouched) {\n\t\t\tif(ttl <= 1) this.recentlyTouched.delete(name);\n\t\t\telse this.recentlyTouched.set(name, ttl - 1);\n\t\t}\n\t}\n\n\ttouch(name: string, ttl = 2) {\n\t\tthis.recentlyTouched.set(name, ttl);\n\t}\n\n\tforget(name: string, memories: Memory[] | MemoryCache): boolean {\n\t\treturn new MemoryAccessor(memories).forget(name);\n\t}\n\n\tasync recollect(query: string, memories: Memory[] | MemoryCache, limit = 5, graphDepth = 1): Promise<Memory[]> {\n\t\tfunction rank(query: number[], candidates: Memory[], limit: number): Memory[] {\n\t\t\tconst scored = candidates.map(m => {\n\t\t\t\tconst titleSim = m.titleEmbedding?.length ? 1 - cosineDistance(query, m.titleEmbedding) : 0;\n\t\t\t\tconst descSim = m.embedding?.length ? 1 - cosineDistance(query, m.embedding) : 0;\n\t\t\t\tconst bodySim = m.bodyEmbeddings?.length\n\t\t\t\t\t? Math.max(...m.bodyEmbeddings.map(b => 1 - cosineDistance(query, b)))\n\t\t\t\t\t: 0;\n\t\t\t\treturn {memory: m, score: titleSim * 0.5 + descSim * 0.35 + bodySim * 0.15};\n\t\t\t});\n\t\t\treturn scored.sort((a, b) => b.score - a.score).slice(0, limit).map(s => s.memory);\n\t\t}\n\n\t\tconst store = new MemoryAccessor(memories);\n\t\tif(!store.list.length) return [];\n\t\tawait store.backfillEmbeddings(this.llm);\n\n\t\tconst [e] = await this.llm.embedding(query);\n\t\tif(!e) return [];\n\n\t\tconst pool = store.search(e.embedding, Math.max(limit * 3, limit));\n\t\tconst poolMemories = pool.map(r => store.find(r.name)).filter((m): m is Memory => !!m);\n\t\tconst ranked = rank(e.embedding, poolMemories, limit);\n\t\tconst found = new Set<string>(ranked.map(m => m.name));\n\n\t\tif(graphDepth > 0) {\n\t\t\tlet frontier = [...found];\n\t\t\tfor(let depth = 0; depth < graphDepth && frontier.length; depth++) {\n\t\t\t\tconst next: string[] = [];\n\t\t\t\tfor(const name of frontier) {\n\t\t\t\t\tconst node = store.find(name);\n\t\t\t\t\tif(!node) continue;\n\t\t\t\t\tfor(const link of node.links) {\n\t\t\t\t\t\tif(!found.has(link) && store.find(link)) {\n\t\t\t\t\t\t\tfound.add(link);\n\t\t\t\t\t\t\tnext.push(link);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfrontier = next;\n\t\t\t}\n\t\t}\n\n\t\tconst rankedOrder = ranked.map(m => m.name);\n\t\tconst graphExpansions = [...found].filter(n => !rankedOrder.includes(n));\n\t\treturn [...rankedOrder, ...graphExpansions].map(n => store.find(n)!).filter(Boolean);\n\t}\n\n\tasync memorize(history: LLMMessage[], memories: Memory[] | MemoryCache, options: LLMRequest): Promise<Memory[]> {\n\t\tconst conversation = history\n\t\t\t.filter(h => h.role === 'user' || h.role === 'assistant')\n\t\t\t.map(h => `[${h.role}]: ${h.content}`).join('\\n\\n').trim();\n\t\tif(!conversation) return [];\n\n\t\tconst uid = `${Date.now()}_${Math.random().toString(36).slice(2)}`;\n\t\tconst pending = {role: 'tool', name: 'memory_process', id: uid, content: conversation} as unknown as LLMMessage;\n\t\thistory.push(pending);\n\n\t\tconst store = new MemoryAccessor(memories);\n\t\tconst {buckets, journal, tasks} = await this.factAgent(conversation, store, options);\n\t\tconst touched: Memory[] = [];\n\n\t\tconst personalTasks = tasks.filter(isPersonalTask);\n\t\tconst entityTasks = tasks.filter(t => !isPersonalTask(t));\n\n\t\tif(journal || personalTasks.length) {\n\t\t\tconst journalName = `Journal/${this.getWeekStart()}`;\n\t\t\tlet jnode = store.find(journalName);\n\t\t\tconst isNew = !jnode;\n\t\t\tif(!jnode) {\n\t\t\t\tjnode = {\n\t\t\t\t\tname: journalName,\n\t\t\t\t\tdescription: this.journalDescription(),\n\t\t\t\t\tcontent: '',\n\t\t\t\t\tembedding: [],\n\t\t\t\t\tlinks: [],\n\t\t\t\t\tbacklinks: [],\n\t\t\t\t};\n\t\t\t\tstore.list.push(jnode);\n\t\t\t}\n\n\t\t\tconst blocks: string[] = [];\n\t\t\tif(journal) blocks.push(`### ${new Date().toISOString().slice(0, 10)}\\n${journal}`);\n\t\t\tif(isNew) {\n\t\t\t\tconst previousDate = new Date(`${this.getWeekStart()}T00:00:00Z`);\n\t\t\t\tpreviousDate.setUTCDate(previousDate.getUTCDate() - 7);\n\t\t\t\tconst previous = store.find(`Journal/${previousDate.toISOString().slice(0, 10)}`);\n\t\t\t\tif(previous) {\n\t\t\t\t\tconst todos = this.getIncompleteTodos(previous.content);\n\t\t\t\t\tif(todos.length) blocks.push(`${TODO_HEADING}\\n${todos.map(task => `- [ ] ${task}`).join('\\n')}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(personalTasks.length) blocks.push(`${TODO_HEADING}\\n${personalTasks.map(task => `- [${task.done ? 'x' : ' '}] ${task.task}`).join('\\n')}`);\n\t\t\tif(blocks.length) this.stage(jnode, blocks.join('\\n\\n'));\n\t\t\ttouched.push(jnode);\n\t\t}\n\n\t\tconst entityStaging = new Map<string, {facts: string[], tasks: MemoryTask[]}>();\n\t\tfor(const {subject, facts} of buckets) {\n\t\t\tconst resolved = this.resolveSubject(subject, store);\n\t\t\tconst entry = entityStaging.get(resolved) ?? {facts: [], tasks: []};\n\t\t\tentry.facts.push(...facts);\n\t\t\tentityStaging.set(resolved, entry);\n\t\t}\n\t\tfor(const task of entityTasks) {\n\t\t\tconst resolved = this.resolveSubject(task.subject, store);\n\t\t\tconst entry = entityStaging.get(resolved) ?? {facts: [], tasks: []};\n\t\t\tentry.tasks.push(task);\n\t\t\tentityStaging.set(resolved, entry);\n\t\t}\n\n\t\tfor(const [resolved, {facts, tasks: subjectTasks}] of entityStaging) {\n\t\t\tlet node = store.find(resolved);\n\t\t\tif(!node) {\n\t\t\t\tnode = {name: resolved, description: 'Persistent memory document', content: '', embedding: [], links: [], backlinks: []};\n\t\t\t\tstore.list.push(node);\n\t\t\t}\n\t\t\tconst blocks: string[] = [];\n\t\t\tif(facts.length) blocks.push(facts.map(f => `- ${f}`).join('\\n'));\n\t\t\tif(subjectTasks.length) blocks.push(`${TODO_HEADING}\\n${subjectTasks.map(t => `- [${t.done ? 'x' : ' '}] ${t.task}`).join('\\n')}`);\n\t\t\tif(blocks.length) this.stage(node, blocks.join('\\n\\n'));\n\t\t\ttouched.push(node);\n\t\t}\n\n\t\tawait Promise.all(touched.map(async node => {\n\t\t\tawait embedMemoryFields(node, this.llm);\n\t\t\tthis.touch(node.name);\n\t\t}));\n\n\t\tif(touched.length) {\n\t\t\tstore.commit(touched);\n\t\t\t(pending as any).content = `Saved to ${touched.map(n => `[[${n.name}]]`).join(', ')}`;\n\t\t\tPromise.all(touched.map(node => this.reconcile(node, memories, options).catch(() => {})));\n\t\t} else {\n\t\t\t(pending as any).content = 'Nothing worth remembering.';\n\t\t}\n\n\t\t(touched as any).uid = uid;\n\t\treturn touched;\n\t}\n\n\tasync reconcileAll(memories: Memory[] | MemoryCache, options: LLMRequest, scope: 'touched' | 'all' = 'touched'): Promise<void> {\n\t\tconst store = new MemoryAccessor(memories);\n\t\tconst targets = scope === 'all' ? store.list : store.list.filter(m => m.content.includes(PENDING_HEADING));\n\t\tawait Promise.all(targets.map(node => this.reconcile(node, memories, options)));\n\t\tstore.commit();\n\t}\n}\n","import {clean, makeUnique, snakeCase} from '@ztimson/utils';\nimport {AbortablePromise, Ai} from './ai.ts';\nimport {Anthropic} from './antrhopic.ts';\nimport {OpenAi} from './open-ai.ts';\nimport {LLMProvider} from './provider.ts';\nimport {AiTool, AiToolArg} from './tools.ts';\nimport {fileURLToPath} from 'url';\nimport {spawn} from 'node:child_process';\nimport {Memory, MemoryCache, MemoryManager, MemoryOptions, stripHeader} from './memory.ts';\nimport {mkdtempSync} from 'node:fs';\nimport fs from 'node:fs/promises';\nimport {tmpdir} from 'node:os';\nimport {dirname, join, basename, extname} from 'path';\nimport { PDFParse } from 'pdf-parse';\n\nconst MAX_AGENT_DEPTH = 5;\nconst PDF_OCR_PAGE_THRESHOLD = 12; // above this many pages, OCR scanned pages instead of feeding images to the model\n\nexport type AnthropicConfig = {proto: 'anthropic', token: string | string[]};\nexport type OpenAiConfig = {proto: 'openai', host?: string, token: string | string[]};\n\nexport type AgentRef = {\n\tname: string;\n\tdescription?: string;\n\tdelegate?: boolean;\n\tfn: () => Agent | null | Promise<Agent | null>;\n}\n\nexport type Agent = {\n\tname: string;\n\tdescription?: string;\n\tmodel?: string | null;\n\ttemperature?: number;\n\tsystem: string;\n\tdelegate?: boolean;\n\tskills?: Skill[] | null;\n\ttools?: AiTool[] | null;\n\tmcp?: McpServer[] | null;\n\tagents?: AgentRef[] | null;\n}\n\nexport type LLMFile = {\n\t/** Path to file on disk */\n\tpath?: string;\n\t/** File content: raw text, base64-encoded binary, or a Buffer */\n\tcontent?: string | Buffer;\n\t/** Original filename, used to infer type from extension */\n\tname?: string;\n\t/** Mime type override, inferred from extension if omitted */\n\tmime?: string;\n\t/** @internal set once extraction has run, skips re-processing next turn */\n\textracted?: boolean;\n};\n\nexport type LLMMessage = {\n\t/** Message originator */\n\trole: 'assistant' | 'system' | 'user';\n\t/** Message content */\n\tcontent: string | any;\n\t/** Files attached to request */\n\tfiles?: LLMFile[];\n\t/** Timestamp */\n\ttimestamp?: number;\n\t/** Response duration in ms */\n\tduration?: number;\n\t/** Tokens per second */\n\ttps?: number;\n} | {\n\t/** Tool call */\n\trole: 'tool';\n\t/** Unique ID for call */\n\tid: string;\n\t/** Tool that was run */\n\tname: string;\n\t/** Tool arguments */\n\targs: any;\n\t/** Tool result */\n\tcontent: undefined | string;\n\t/** Tool error */\n\terror?: undefined | string;\n\t/** Timestamp */\n\ttimestamp?: number;\n\t/** Response duration in ms */\n\tduration?: number;\n\t/** Tokens per second */\n\ttps?: number;\n}\n\nexport type LLMRequest = {\n\t/** Return a parsed JSON object that matches the schema */\n\tschema?: AiToolArg;\n\t/** System prompt */\n\tsystem?: string;\n\t/** Message history */\n\thistory?: LLMMessage[];\n\t/** Max tokens for request */\n\tmaxTokens?: number;\n\t/** 0 = Rigid Logic, 1 = Balanced, 2 = Hyper Creative **/\n\ttemperature?: number;\n\t/** Available tools */\n\ttools?: AiTool[];\n\t/** LLM  model */\n\tmodel?: string;\n\t/** Stream response */\n\tstream?: (chunk: {text?: string, tool?: string, done?: true}) => any;\n\t/** Compress old messages in the chat to free up context */\n\tcompress?: {max: number; min: number};\n\t/** User's memory documents - RAG injected automatically each turn */\n\tmemory?: Memory[] | MemoryCache | MemoryOptions;\n\t/** Model to use for memory operations */\n\tmemoryModel?: string;\n\t/** Skill documents the AI can browse and read on demand */\n\tskills?: Skill[];\n\t/** MCP servers to connect and expose as tools */\n\tmcp?: McpServer[];\n\t/** Subagents exposed as delegatable/wrapped tools, resolved lazily via their `fn` */\n\tagents?: AgentRef[];\n\t/** Attach files to request */\n\tfiles?: LLMFile[];\n\t/** @internal recursion guard for nested agent delegation */\n\t_agentDepth?: number;\n}\n\nexport type McpServer = {\n\t/** MCP server name for humans */\n\tname: string;\n\t/** Host URL */\n\thost: string;\n\t/** Server access token */\n\ttoken?: string;\n}\n\nexport type Skill = {\n\t/** Name of skill for humans */\n\tname: string;\n\t/** Description LLM will use to decide to learn a skill */\n\tdescription: string;\n\t/** Skill instructions */\n\tcontent: string;\n}\n\nclass LLM {\n\tprivate static AUDIO_EXT = ['wav','mp3','m4a','flac','ogg','aac','wma'];\n\tprivate static IMAGE_EXT = ['png','jpg','jpeg','bmp','gif','tiff','webp'];\n\tprivate static TEXT_EXT = ['txt','md','csv','json','xml','html','js','ts','py','yaml','yml','log'];\n\tprivate static PDF_EXT = ['pdf'];\n\n\tprivate memoryManager!: MemoryManager;\n\n\tdefaultModel!: string;\n\tmodels: {[model: string]: LLMProvider} = {};\n\n\tconstructor(public readonly ai: Ai) {\n\t\tif(!ai.options.llm?.models) return;\n\t\tObject.entries(ai.options.llm.models).forEach(([model, config]) => {\n\t\t\tif(!this.defaultModel) this.defaultModel = model;\n\t\t\tif(config.proto == 'anthropic') this.models[model] = new Anthropic(this.ai, config.token, model);\n\t\t\telse if(config.proto == 'openai') this.models[model] = new OpenAi(this.ai, config.host || null, config.token, model);\n\t\t});\n\t\tthis.memoryManager = new MemoryManager(this);\n\t}\n\n\tprivate async loadBuffer(file: LLMFile, asText: boolean): Promise<Buffer> {\n\t\tif(file.path) return fs.readFile(file.path);\n\t\tif(Buffer.isBuffer(file.content)) return file.content;\n\t\tif(typeof file.content === 'string') return Buffer.from(file.content, asText ? 'utf-8' : 'base64');\n\t\tthrow new Error('No path or content provided');\n\t}\n\n\tprivate async writeTemp(name: string, buffer: Buffer): Promise<string> {\n\t\tconst path = join(mkdtempSync(join(tmpdir(), 'ai-file-')), name);\n\t\tawait fs.writeFile(path, buffer);\n\t\treturn path;\n\t}\n\n\t/**\n\t * Extract text from a PDF. Pages with no text layer (scanned/image-only) are handled as either:\n\t * - Rendered to images and returned alongside the text so the (vision-capable) model can read them directly\n\t * - OCR'd via Tesseract when the doc is too large to reasonably pass as images\n\t */\n\tprivate async resolvePdf(buffer: Buffer): Promise<{text: string, images: {mime: string, data: string}[]}> {\n\t\tconst parser = new PDFParse({data: buffer});\n\t\ttry {\n\t\t\tconst {text, pages} = await parser.getText();\n\t\t\tconst scanned = (pages || []).filter(p => !p.text?.trim());\n\t\t\tif(!scanned.length) return {text: text.trim() || '[Empty PDF]', images: []};\n\t\t\tconst total = pages.length;\n\t\t\tconst pageNums = scanned.map(p => p.num);\n\t\t\tconst {pages: shots} = await parser.getScreenshot({partial: pageNums});\n\t\t\tif(total <= PDF_OCR_PAGE_THRESHOLD) {\n\t\t\t\treturn {\n\t\t\t\t\ttext: text.trim(),\n\t\t\t\t\timages: shots.map(s => ({mime: 'image/png', data: Buffer.from(s.data).toString('base64')}))\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst ocrText = await Promise.all(shots.map(async (s, i) => {\n\t\t\t\tconst path = await this.writeTemp(`page-${pageNums[i]}.png`, Buffer.from(s.data));\n\t\t\t\ttry {\n\t\t\t\t\treturn await this.ai.vision.ocr(path) || '';\n\t\t\t\t} finally {\n\t\t\t\t\tfs.rm(dirname(path), {recursive: true, force: true}).catch(() => {});\n\t\t\t\t}\n\t\t\t}));\n\t\t\treturn {text: [text.trim(), ...ocrText].filter(Boolean).join('\\n\\n'), images: []};\n\t\t} finally {\n\t\t\tawait parser.destroy();\n\t\t}\n\t}\n\n\tprivate async resolveFile(file: LLMFile): Promise<{text?: string, images?: {mime: string, data: string}[]}> {\n\t\tconst name = file.name || (file.path ? basename(file.path) : 'file');\n\n\t\t// Already resolved on a previous turn, reuse cached text\n\t\tif(file.extracted) return {text: `<file name=\"${name}\">\\n${file.content}\\n</file>`};\n\n\t\tconst ext = extname(name).slice(1).toLowerCase();\n\t\tconst mime = file.mime || '';\n\t\tconst isAudio = mime.startsWith('audio/') || LLM.AUDIO_EXT.includes(ext);\n\t\tconst isImage = mime.startsWith('image/') || LLM.IMAGE_EXT.includes(ext);\n\t\tconst isPdf = mime === 'application/pdf' || LLM.PDF_EXT.includes(ext);\n\t\tconst isText = mime.startsWith('text/') || LLM.TEXT_EXT.includes(ext);\n\n\t\tlet tmpDir: string | null = null;\n\t\ttry {\n\t\t\tif(isImage) {\n\t\t\t\tconst data = (await this.loadBuffer(file, false)).toString('base64');\n\t\t\t\treturn {images: [{mime: mime || `image/${ext === 'jpg' ? 'jpeg' : ext}`, data}]};\n\t\t\t}\n\n\t\t\tif(isPdf) {\n\t\t\t\tconst {text, images} = await this.resolvePdf(await this.loadBuffer(file, false));\n\t\t\t\t// Only cache/skip re-processing when we didn't need to hand off images (OCR'd or fully text-based)\n\t\t\t\tif(!images.length) {\n\t\t\t\t\tfile.content = text;\n\t\t\t\t\tfile.extracted = true;\n\t\t\t\t\tdelete file.path;\n\t\t\t\t}\n\t\t\t\treturn {text: `<file name=\"${name}\">\\n${text || '[Scanned PDF - see attached page images]'}\\n</file>`, images};\n\t\t\t}\n\n\t\t\tlet text: string;\n\t\t\tif(isAudio) {\n\t\t\t\tlet path = file.path;\n\t\t\t\tif(!path) {\n\t\t\t\t\tconst buffer = await this.loadBuffer(file, false);\n\t\t\t\t\tpath = await this.writeTemp(name, buffer);\n\t\t\t\t\ttmpDir = dirname(path);\n\t\t\t\t}\n\t\t\t\ttext = await this.ai.audio.asr(path) || '';\n\t\t\t} else if(isText) {\n\t\t\t\ttext = (await this.loadBuffer(file, true)).toString('utf-8');\n\t\t\t} else {\n\t\t\t\ttext = typeof file.content === 'string' ? file.content : `[Binary file, unable to extract: ${name}]`;\n\t\t\t}\n\t\t\tfile.content = text;\n\t\t\tfile.extracted = true;\n\t\t\tdelete file.path;\n\n\t\t\treturn {text: `<file name=\"${name}\">\\n${text}\\n</file>`};\n\t\t} catch(err: any) {\n\t\t\treturn {text: `<file name=\"${name}\">Failed to process: ${err.message}</file>`};\n\t\t} finally {\n\t\t\tif(tmpDir) fs.rm(tmpDir, {recursive: true, force: true}).catch(() => {});\n\t\t}\n\t}\n\n\tprivate async resolveFiles(files: LLMFile[]): Promise<{text: string, images: {mime: string, data: string}[]}> {\n\t\tconst resolved = await Promise.all(files.map(f => this.resolveFile(f)));\n\t\treturn {\n\t\t\ttext: resolved.filter(r => r.text).map(r => r.text).join('\\n\\n'),\n\t\t\timages: resolved.flatMap(r => r.images || [])\n\t\t};\n\t}\n\n\tprivate setupAgent(stubs: AgentRef[] = [], history: LLMMessage[], aborts: ((keep?: boolean) => void)[], depth = 0, delegateState: {resp: string | null}): AiTool[] {\n\t\treturn stubs.map(stub => {\n\t\t\tconst toolName = `${stub.delegate ? '' : 'sub'}agent_${snakeCase(stub.name)}`;\n\t\t\treturn {\n\t\t\t\tname: toolName,\n\t\t\t\tdescription: `${stub.delegate ? 'Delegate to ' : ''}Subagent: ${stub.description || stub.name}`,\n\t\t\t\targs: clean<any>({\n\t\t\t\t\tcontext: !stub.delegate ? {type: 'string', description: 'Summary of related messages, samples, files, etc...', required: true} : undefined,\n\t\t\t\t\tinstructions: {type: 'string', description: 'Detailed instructions for subagent to complete', required: true},\n\t\t\t\t}),\n\t\t\t\tfn: async (args: any, stream: any, ai: any, id?: string) => {\n\t\t\t\t\tif(depth >= MAX_AGENT_DEPTH) return 'Max agent delegation depth exceeded';\n\n\t\t\t\t\tconst a = await stub.fn();\n\t\t\t\t\tif(!a) return `Agent \"${stub.name}\" could not be resolved`;\n\n\t\t\t\t\tconst q = a.delegate ? '' : `${args.instructions}${args.context ? `\\n\\n<context>${args.context}</context>` : ''}`;\n\n\t\t\t\t\tconst request = this.ask(q, {\n\t\t\t\t\t\tsystem: `You are a specialized subagent being called from an orchestrator\n${a.delegate ? 'Your output streams directly to the user for the remainder of this turn. You are mid conversation' : 'You are wrapped in a tool call that will be analysis by an LLM'}\nDispense with greetings and focus on your instructions using available tools and returning only the final result unless specifically instructed to converse\n\n${a.system}`,\n\t\t\t\t\t\tmodel: a.model || undefined,\n\t\t\t\t\t\ttemperature: a.temperature,\n\t\t\t\t\t\tstream: a.delegate ? stream : undefined,\n\t\t\t\t\t\thistory: a.delegate ? history : [],\n\t\t\t\t\t\tmcp: a.mcp || undefined,\n\t\t\t\t\t\tskills: a.skills || undefined,\n\t\t\t\t\t\ttools: a.tools || undefined,\n\t\t\t\t\t\tagents: a.agents || [],\n\t\t\t\t\t\t_agentDepth: depth + 1,\n\t\t\t\t\t} as any);\n\t\t\t\t\taborts.push(request.abort);\n\t\t\t\t\tconst resp = await request;\n\n\t\t\t\t\tif(a.delegate) {\n\t\t\t\t\t\tdelegateState.resp = resp;\n\t\t\t\t\t\treturn '';\n\t\t\t\t\t}\n\t\t\t\t\treturn resp;\n\t\t\t\t}\n\t\t\t};\n\t\t});\n\t}\n\n\tprivate async setupMcp(servers: McpServer[] = []): Promise<{prompt: string, tools: AiTool[]}> {\n\t\tif(!servers?.length) return {prompt: '', tools: []};\n\t\tconst allTools: AiTool[] = [];\n\t\tawait Promise.all(servers.map(async server => {\n\t\t\tconst res = await fetch(`${server.host}/tools`, {headers: server.token ? {Authorization: `Bearer ${server.token}`} : {}});\n\t\t\tconst mcp: any = await res.json();\n\t\t\tif(!mcp?.tools) return;\n\t\t\tfor(const t of mcp.tools) {\n\t\t\t\tconst args: Record<string, any> = {};\n\t\t\t\tif(t.inputSchema?.properties) {\n\t\t\t\t\tfor(const [key, val] of Object.entries<any>(t.inputSchema.properties)) {\n\t\t\t\t\t\targs[key] = {type: val.type || 'string', description: val.description || '', required: t.inputSchema.required?.includes(key)};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tallTools.push({\n\t\t\t\t\tname: `${server.name}_${t.name}`,\n\t\t\t\t\tdescription: t.description || '',\n\t\t\t\t\targs,\n\t\t\t\t\tfn: async (a: any) => {\n\t\t\t\t\t\tconst r = await fetch(`${server.host}/tools/call`, {\n\t\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\t\theaders: {'Content-Type': 'application/json', ...(server.token ? {Authorization: `Bearer ${server.token}`} : {})},\n\t\t\t\t\t\t\tbody: JSON.stringify({name: t.name, arguments: a})\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst data: any = await r.json();\n\t\t\t\t\t\treturn data?.content?.[0]?.text ?? JSON.stringify(data);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}));\n\n\t\tconst list = allTools.map(t => `- ${t.name}: ${t.description}`).join('\\n');\n\t\treturn {\n\t\t\tprompt: `## MCP\\nYou have access to the following MCP tools:\\n${list}`,\n\t\t\ttools: allTools\n\t\t};\n\t}\n\n\tprivate setupSkills(skills: Skill[] = []): {prompt: string, tools: AiTool[]} {\n\t\tif(!skills?.length) return {prompt: '', tools: []};\n\t\tconst list = skills.map(s => `- ${s.name}: ${s.description}`).join('\\n');\n\t\treturn {\n\t\t\tprompt: `## Skills\\nYou have access to the following skill documents, whenever there is overlap between a question and a skill file, use \\`skill_read\\` to get instructions and background knowledge:\\n${list}`,\n\t\t\ttools: [{\n\t\t\t\tname: 'skill_read',\n\t\t\t\tdescription: 'Read the full content of a skill/knowledge document',\n\t\t\t\targs: {\n\t\t\t\t\tname: {type: 'string', description: 'Exact skill name', required: true}\n\t\t\t\t},\n\t\t\t\tfn: (args: any) => {\n\t\t\t\t\tconst skill = skills.find(s => s.name === args.name);\n\t\t\t\t\tif(!skill) return `Skill not found. Available:\\n${list}`;\n\t\t\t\t\treturn `# ${skill.name}\\n${skill.content}`;\n\t\t\t\t}\n\t\t\t}]\n\t\t}\n\t}\n\n\tprivate wrapToolTiming(tools: AiTool[], timings: Map<string, {duration: number, tps: number}>): AiTool[] {\n\t\treturn tools.map(t => ({\n\t\t\t...t,\n\t\t\tfn: async (args: any, stream: any, ai: any, id?: string) => {\n\t\t\t\tconst start = Date.now();\n\t\t\t\tconst result = await t.fn(args, stream, ai, id);\n\t\t\t\tconst duration = Date.now() - start;\n\t\t\t\tconst tps = duration > 0 ? this.estimateTokens(result) / (duration / 1000) : 0;\n\t\t\t\tif(id) timings.set(id, {duration, tps});\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}));\n\t}\n\n\task(message: string, options: LLMRequest = {}): AbortablePromise<string> {\n\t\toptions = <any>{\n\t\t\tsystem: '',\n\t\t\t...this.ai.options.llm,\n\t\t\tmodels: undefined,\n\t\t\thistory: [],\n\t\t\t...options,\n\t\t}\n\t\tconst m = options.model || this.defaultModel;\n\t\tif(!this.models[m]) throw new Error(`Model does not exist: ${m}`);\n\t\tlet request: AbortablePromise<string> | null = null;\n\t\tlet aborted = false;\n\t\tlet keepOnAbort = true;\n\t\tconst nestedAborts: ((keep?: boolean) => void)[] = [];\n\t\tconst abort = (keep = true) => {\n\t\t\taborted = true;\n\t\t\tkeepOnAbort = keep;\n\t\t\trequest?.abort?.(keep);\n\t\t\tnestedAborts.forEach(a => a(keep));\n\t\t};\n\n\t\tlet promise: any;\n\t\tconst requestStart = Date.now();\n\n\t\tpromise = (async () => {\n\t\t\tlet tools: AiTool[] = options.tools || this.ai.options.llm?.tools || [];\n\t\t\tconst prompts: string[] = [];\n\t\t\tlet history = options.history || [];\n\t\t\tconst historyStart = history.length;\n\t\t\tconst files = options.files || [];\n\t\t\tif(message || files.length) history.push({role: 'user', content: message || '', timestamp: Date.now()});\n\n\t\t\t// Accumulate streamed text so it can be committed to history if aborted mid-generation\n\t\t\tlet partialText = '';\n\t\t\tconst onStream = options.stream;\n\t\t\tconst stream = (chunk: {text?: string, tool?: string, done?: true}) => {\n\t\t\t\tif(chunk.text) partialText += chunk.text;\n\t\t\t\treturn onStream?.(chunk);\n\t\t\t};\n\n\t\t\t/** Commit (keep) or discard this turn's progress on abort, then throw */\n\t\t\tconst abortNow = (): never => {\n\t\t\t\tif(keepOnAbort) { if(partialText) history.push({role: 'assistant', content: partialText, timestamp: Date.now()}); }\n\t\t\t\telse history.splice(historyStart, history.length - historyStart);\n\t\t\t\tthrow Object.assign(new Error('Aborted'), {name: 'AbortError'});\n\t\t\t};\n\n\t\t\t// MCP\n\t\t\tconst mcp = options.mcp || this.ai.options?.llm?.mcp;\n\t\t\tif(mcp?.length) {\n\t\t\t\tconst m = await this.setupMcp(mcp);\n\t\t\t\tprompts.unshift(m.prompt);\n\t\t\t\ttools.push(...m.tools);\n\t\t\t}\n\n\t\t\t// Skills\n\t\t\tconst skills = options.skills || this.ai.options?.llm?.skills;\n\t\t\tif(skills?.length) {\n\t\t\t\tconst s = this.setupSkills(skills);\n\t\t\t\tprompts.unshift(s.prompt);\n\t\t\t\ttools.push(...s.tools);\n\t\t\t}\n\n\t\t\t// Agents\n\t\t\tconst agents = options.agents || this.ai.options?.llm?.agents;\n\t\t\tconst delegateState: {resp: string | null} = {resp: null};\n\t\t\tif(agents?.length) tools.push(...this.setupAgent(agents, history, nestedAborts, options._agentDepth || 0, delegateState));\n\n\t\t\t// Memory\n\t\t\tconst mem = MemoryManager.normalize(options.memory);\n\t\t\tif(mem) {\n\t\t\t\tconst mems = mem.memory instanceof MemoryCache ? mem.memory.memories : mem.memory;\n\t\t\t\tif(mems.length) {\n\t\t\t\t\tif(mem.inject) {\n\t\t\t\t\t\tconst pool = 15;\n\t\t\t\t\t\tconst budget = mem.maxTokens ?? 2000;\n\t\t\t\t\t\tconst relevant = await this.memoryManager.recollect(message, mem.memory, pool);\n\n\t\t\t\t\t\tlet used = 0;\n\t\t\t\t\t\tconst preloaded: typeof relevant = [];\n\t\t\t\t\t\tconst listed: typeof relevant = [];\n\t\t\t\t\t\tfor(const r of relevant) {\n\t\t\t\t\t\t\tconst t = this.estimateTokens(r.content);\n\t\t\t\t\t\t\tif(used + t <= budget || preloaded.length === 0) {\n\t\t\t\t\t\t\t\tpreloaded.push(r);\n\t\t\t\t\t\t\t\tused += t;\n\t\t\t\t\t\t\t} else listed.push(r);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tprompts.unshift(`## Memory\nYou have a background memory process which has prefetched relevant information${mem.update ? ' and will create new memories from this conversation' : ''} for you\nAssume it is perfect and never mention this process to anyone ever\nAlways use your memories to craft a personalized response, they contain links / [[wiki links]] which you use navigate between them\n${mem.tool ? `You can access memory files via the \\`memory_search\\` and \\`memory_recall\\` tools\nWhen you need information about the user, \\`memory_recall\\` \\`People/User\\` before asking (fetch if not included bellow)\nWhen you need information not provided, attempt 1-3 \\`memory_search\\` calls with distinct queries before asking` : ''}\n\n${preloaded.length ? `### Prefetched Memories (Most relevant first):\n\n${preloaded.map(r => `Memory: ${r.name}\nDescription: ${r.description}\nLinked: ${makeUnique([...r.links, ...r.backlinks]).join(', ')}\n\\`\\`\\`\n${stripHeader(r.content)}\n\\`\\`\\``).join('\\n\\n')}` : ''}\n${mem.tool && listed.length ? '\\n' + listed.map(r => `Memory: ${r.name}\nDescription: ${r.description}\nLinked: ${makeUnique([...r.links, ...r.backlinks]).join(', ')}\n<!-- Truncated -->`).join('\\n\\n') : ''}`.trim())\n\t\t\t\t\t}\n\t\t\t\t\tif(mem.tool) tools.push(this.memoryManager.tools.read(mem.memory));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(aborted) abortNow();\n\n\t\t\tconst lastMsg = history[history.length - 1];\n\t\t\tif(files.length && lastMsg?.role === 'user') lastMsg.files = files;\n\t\t\tconst restores: {msg: LLMMessage, content: any}[] = [];\n\t\t\tfor(const msg of history) {\n\t\t\t\tif(msg.role !== 'user' || !msg.files?.length) continue;\n\t\t\t\tconst {text, images} = await this.resolveFiles(msg.files);\n\t\t\t\tif(!text && !images.length) continue;\n\t\t\t\trestores.push({msg, content: msg.content});\n\t\t\t\tconst merged = text ? [msg.content, text].filter(Boolean).join('\\n\\n') : msg.content;\n\t\t\t\tmsg.content = images.length\n\t\t\t\t\t? [...images.map(i => ({type: 'image', mime: i.mime, data: i.data})), {type: 'text', text: merged}]\n\t\t\t\t\t: merged;\n\t\t\t}\n\n\t\t\tconst toolTimings = new Map<string, {duration: number, tps: number}>();\n\t\t\ttools = this.wrapToolTiming(tools, toolTimings);\n\n\t\t\tif(aborted) abortNow();\n\n\t\t\tprompts.unshift(options.system || this.ai.options.llm?.system || '');\n\t\t\trequest = this.models[m].ask('', {...options, tools, stream, system: prompts.filter(Boolean).join('\\n\\n')});\n\t\t\tlet resp: string;\n\t\t\ttry {\n\t\t\t\tresp = await request;\n\t\t\t} catch(err: any) {\n\t\t\t\tif(aborted) return abortNow();\n\t\t\t\tthrow err;\n\t\t\t}\n\n\t\t\t// Strip the file injection shim\n\t\t\trestores.forEach(({msg, content}) => msg.content = content);\n\n\t\t\t// Capture meta (duration / tps)\n\t\t\tfor(const h of history) {\n\t\t\t\tif(h.role === 'tool' && toolTimings.has(h.id)) Object.assign(h, toolTimings.get(h.id));\n\t\t\t}\n\n\t\t\tif(typeof resp === 'string' && !resp.trim() && delegateState.resp !== null) resp = delegateState.resp;\n\n\t\t\tif(mem?.tool) history.splice(0, history.length, ...history.filter(h => h.role !== 'tool' || h.name !== 'memory_recall'));\n\t\t\tif(options.compress && this.estimateTokens(history) >= options.compress.max) {\n\t\t\t\tif(mem?.update) await this.memoryManager.memorize(history, mem.memory, {model: options.memoryModel || this.defaultModel, ...options});\n\t\t\t\tconst compressed = await this.compressHistory(history, options.compress.max, options.compress.min, options);\n\t\t\t\tif(options.history) options.history.splice(0, options.history.length, ...compressed);\n\t\t\t}\n\n\t\t\tconst requestDuration = Date.now() - requestStart;\n\t\t\tconst totalTokens = history\n\t\t\t\t.filter((h: any) => h.role === 'assistant' && h.duration && h.tps)\n\t\t\t\t.reduce((sum: number, h: any) => sum + h.tps * (h.duration / 1000), 0);\n\t\t\tconst requestTps = requestDuration > 0 ? totalTokens / (requestDuration / 1000) : 0;\n\t\t\tObject.assign(promise, {duration: requestDuration, tps: requestTps});\n\n\t\t\treturn resp;\n\t\t})();\n\n\t\treturn Object.assign(promise, {abort});\n\t}\n\n\t/**\n\t * Compress chat history to reduce context size\n\t * @param {LLMMessage[]} history Chatlog that will be compressed\n\t * @param max Trigger compression once context is larger than max\n\t * @param min Leave messages less than the token minimum, summarize the rest\n\t * @param {LLMRequest} options LLM options\n\t * @returns {Promise<LLMMessage[]>} New chat history will summary at index 0\n\t */\n\tasync compressHistory(history: LLMMessage[], max: number, min: number, options?: LLMRequest): Promise<LLMMessage[]> {\n\t\tif(this.estimateTokens(history) < max) return history;\n\t\tlet keep = 0, tokens = 0;\n\t\tfor(let m of history.toReversed()) {\n\t\t\ttokens += this.estimateTokens(m.content);\n\t\t\tif(tokens < min) keep++;\n\t\t\telse break;\n\t\t}\n\t\tif(history.length <= keep) return history;\n\t\tconst system = history[0].role == 'system' ? history[0] : null,\n\t\t\trecent = keep == 0 ? [] : history.slice(-keep),\n\t\t\tprocess = (keep == 0 ? history : history.slice(0, -keep)).filter(h => h.role === 'assistant' || h.role === 'user');\n\n\t\tconst summary: any = await this.summarize(process.map(m => `[${m.role}]: ${m.content}`).join('\\n\\n'), 500, options);\n\t\tconst d = Date.now();\n\t\tconst h = [{role: <any>'tool', name: 'summary', id: `summary_` + d, args: {}, content: `Conversation Summary: ${summary?.summary}`, timestamp: d}, ...recent];\n\t\tif(system) h.splice(0, 0, system);\n\t\treturn h;\n\t}\n\n\t/**\n\t * Compare the difference between embeddings (calculates the angle between two vectors)\n\t * @param {number[]} v1 First embedding / vector comparison\n\t * @param {number[]} v2 Second embedding / vector for comparison\n\t * @returns {number} Similarity values 0-1: 0 = unique, 1 = identical\n\t */\n\tcosineSimilarity(v1: number[], v2: number[]): number {\n\t\tif (v1.length !== v2.length) throw new Error('Vectors must be same length');\n\t\tlet dotProduct = 0, normA = 0, normB = 0;\n\t\tfor (let i = 0; i < v1.length; i++) {\n\t\t\tdotProduct += v1[i] * v2[i];\n\t\t\tnormA += v1[i] * v1[i];\n\t\t\tnormB += v2[i] * v2[i];\n\t\t}\n\t\tconst denominator = Math.sqrt(normA) * Math.sqrt(normB);\n\t\treturn denominator === 0 ? 0 : dotProduct / denominator;\n\t}\n\n\t/**\n\t * Chunk text into parts for AI digestion\n\t * @param {object | string} target Item that will be chunked (objects get converted)\n\t * @param {number} maxTokens Chunking size. More = better context, less = more specific (Search by paragraphs or lines)\n\t * @param {number} overlapTokens Includes previous X tokens to provide continuity to AI (In addition to max tokens)\n\t * @returns {string[]} Chunked strings\n\t */\n\tchunk(target: object | string, maxTokens = 500, overlapTokens = 50): string[] {\n\t\tconst objString = (obj: any, path = ''): string[] => {\n\t\t\tif(!obj) return [];\n\t\t\treturn Object.entries(obj).flatMap(([key, value]) => {\n\t\t\t\tconst p = path ? `${path}${isNaN(+key) ? `.${key}` : `[${key}]`}` : key;\n\t\t\t\tif(typeof value === 'object' && !Array.isArray(value)) return objString(value, p);\n\t\t\t\treturn `${p}: ${Array.isArray(value) ? value.join(', ') : value}`;\n\t\t\t});\n\t\t};\n\t\tconst lines = typeof target === 'object' ? objString(target) : target.toString().split('\\n');\n\t\tconst tokens = lines.flatMap(l => [...l.split(/\\s+/).filter(Boolean), '\\n']);\n\t\tconst chunks: string[] = [];\n\t\tfor(let i = 0; i < tokens.length;) {\n\t\t\tlet text = '', j = i;\n\t\t\twhile(j < tokens.length) {\n\t\t\t\tconst next = text + (text ? ' ' : '') + tokens[j];\n\t\t\t\tif(this.estimateTokens(next.replace(/\\s*\\n\\s*/g, '\\n')) > maxTokens && text) break;\n\t\t\t\ttext = next;\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tconst clean = text.replace(/\\s*\\n\\s*/g, '\\n').trim();\n\t\t\tif(clean) chunks.push(clean);\n\t\t\ti = Math.max(j - overlapTokens, j === i ? i + 1 : j);\n\t\t}\n\t\treturn chunks;\n\t}\n\n\t/**\n\t * Create a vector representation of a string\n\t * @param {object | string} target Item that will be embedded (objects get converted)\n\t * @param {maxTokens?: number, overlapTokens?: number} opts Options for embedding such as chunk sizes\n\t * @returns {Promise<Awaited<{index: number, embedding: number[], text: string, tokens: number}>[]>} Chunked embeddings\n\t */\n\tembedding(target: object | string, opts: {maxTokens?: number, overlapTokens?: number} = {}): AbortablePromise<{index: number, embedding: number[], text: string, tokens: number}[]> {\n\t\tlet {maxTokens = 500, overlapTokens = 50} = opts;\n\t\tlet aborted = false;\n\t\tconst abort = () => { aborted = true; };\n\n\t\tconst embed = (text: string): Promise<number[]> => {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif(aborted) return reject(new Error('Aborted'));\n\t\t\t\tconst args: string[] = [\n\t\t\t\t\tjoin(dirname(fileURLToPath(import.meta.url)), 'embedder.js'),\n\t\t\t\t\t<string>this.ai.options.path,\n\t\t\t\t\tthis.ai.options?.embedder || 'bge-small-en-v1.5'\n\t\t\t\t];\n\t\t\t\tconst proc = spawn('node', args, {stdio: ['pipe', 'pipe', 'ignore']});\n\t\t\t\tproc.stdin.write(text);\n\t\t\t\tproc.stdin.end();\n\t\t\t\tlet output = '';\n\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\tproc.on('close', (code: number) => {\n\t\t\t\t\tif(aborted) return reject(new Error('Aborted'));\n\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst result = JSON.parse(output);\n\t\t\t\t\t\t\tresolve(result.embedding);\n\t\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\t\treject(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(new Error(`Embedder process exited with code ${code}`));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tproc.on('error', reject);\n\t\t\t});\n\t\t};\n\n\t\tconst p = (async () => {\n\t\t\tconst chunks = this.chunk(target, maxTokens, overlapTokens), results: any[] = [];\n\t\t\tfor(let i = 0; i < chunks.length; i++) {\n\t\t\t\tif(aborted) break;\n\t\t\t\tconst text = chunks[i];\n\t\t\t\tconst embedding = await embed(text);\n\t\t\t\tresults.push({index: i, embedding, text, tokens: this.estimateTokens(text)});\n\t\t\t}\n\t\t\treturn results;\n\t\t})();\n\t\treturn <any>Object.assign(p, {abort});\n\t}\n\n\t/**\n\t * Estimate variable as tokens\n\t * @param history Object to size\n\t * @returns {number} Rough token count\n\t */\n\testimateTokens(history: any): number {\n\t\tconst text = JSON.stringify(history);\n\t\treturn Math.ceil((text.length / 4) * 1.2);\n\t}\n\n\t/**\n\t * Compare the difference between two strings using tensor math\n\t * @param target Text that will be checked\n\t * @param {string} searchTerms Multiple search terms to check against target\n\t * @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical\n\t */\n\tfuzzyMatch(target, ...searchTerms) {\n\t\tif (searchTerms.length < 2) throw new Error('Requires at least 2 strings to compare');\n\t\tconst levenshtein = (a, b) => {\n\t\t\tconst m = a.length, n = b.length;\n\t\t\tif (!m) return n;\n\t\t\tif (!n) return m;\n\t\t\tconst dp = Array.from({length: m + 1}, (_, i) => [i, ...Array(n).fill(0)]);\n\t\t\tfor (let j = 0; j <= n; j++) dp[0][j] = j;\n\t\t\tfor (let i = 1; i <= m; i++) {\n\t\t\t\tfor (let j = 1; j <= n; j++) {\n\t\t\t\t\tdp[i][j] = a[i - 1] === b[j - 1]\n\t\t\t\t\t\t? dp[i - 1][j - 1]\n\t\t\t\t\t\t: 1 + Math.min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn dp[m][n];\n\t\t};\n\t\tconst similarity = (a, b) => {\n\t\t\ta = a.toLowerCase(); b = b.toLowerCase();\n\t\t\treturn 1 - levenshtein(a, b) / Math.max(a.length, b.length, 1);\n\t\t};\n\t\tconst similarities = searchTerms.map(t => similarity(target, t));\n\t\treturn {\n\t\t\tavg: similarities.reduce((acc, s) => acc + s, 0) / similarities.length,\n\t\t\tmax: Math.max(...similarities),\n\t\t\tsimilarities\n\t\t};\n\t}\n\n\t/**\n\t * Digest full conversation history into memory documents.\n\t * Call on session end to persist the conversation.\n\t */\n\tasync memorize(history: LLMMessage[], memories: Memory[] | MemoryCache, options: LLMRequest = {}): Promise<Memory[]> {\n\t\treturn this.memoryManager.memorize(history, memories, {model: this.defaultModel, ...options});\n\t}\n\n\t/**\n\t * Create a summary of some text\n\t * @param {string} text Text to summarize\n\t * @param {number} length Max number of words\n\t * @param options LLM request options\n\t * @returns {Promise<string>} Summary\n\t */\n\tasync summarize(text: string, length: number = 500, options?: LLMRequest): Promise<string | null> {\n\t\tlet system = `Your job is to summarize the users message using tool calls. Call the \\`submit\\` tool at least once with the shortest summary possible that's <= ${length} words. The tool call will respond with the token count. Responses are ignored`;\n\t\tif(options?.system) system += '\\n\\n' + options.system;\n\t\treturn new Promise(async (resolve, reject) => {\n\t\t\tlet done = false;\n\t\t\tconst resp = await this.ask(text, {\n\t\t\t\ttemperature: 0.3,\n\t\t\t\t...options,\n\t\t\t\tsystem,\n\t\t\t\ttools: [{\n\t\t\t\t\tname: 'submit',\n\t\t\t\t\tdescription: 'Submit summary',\n\t\t\t\t\targs: {summary: {type: 'string', description: 'Text summarization', required: true}},\n\t\t\t\t\tfn: (args) => {\n\t\t\t\t\t\tif(!args.summary) return 'No summary provided';\n\t\t\t\t\t\tconst count = args.summary.split(' ').length;\n\t\t\t\t\t\tif(count > length) return `Too long: ${length} words`;\n\t\t\t\t\t\tdone = true;\n\t\t\t\t\t\tresolve(args.summary || null);\n\t\t\t\t\t\treturn `Saved: ${length} words`;\n\t\t\t\t\t}\n\t\t\t\t}, ...(options?.tools || [])],\n\t\t\t});\n\t\t\tif(!done) reject(`AI failed to create summary:\\n${resp}`);\n\t\t});\n\t}\n\n\taddModel(name: string, config: AnthropicConfig | OpenAiConfig, setDefault = false) {\n\t\tif(config.proto == 'anthropic') this.models[name] = new Anthropic(this.ai, config.token, name);\n\t\telse if(config.proto == 'openai') this.models[name] = new OpenAi(this.ai, config.host || null, config.token, name);\n\t\tif(setDefault || !this.defaultModel) this.defaultModel = name;\n\t}\n\n\tremoveModel(name: string) {\n\t\tdelete this.models[name];\n\t\tif(this.defaultModel === name) {\n\t\t\tthis.defaultModel = Object.keys(this.models)[0] ?? '';\n\t\t}\n\t}\n\n\tsetModels(models: {[model: string]: AnthropicConfig | OpenAiConfig}, replace = true) {\n\t\tif(replace) this.models = {};\n\t\tObject.entries(models).forEach(([model, config]) => {\n\t\t\tif(!this.defaultModel) this.defaultModel = model;\n\t\t\tif(config.proto == 'anthropic') this.models[model] = new Anthropic(this.ai, config.token, model);\n\t\t\telse if(config.proto == 'openai') this.models[model] = new OpenAi(this.ai, config.host || null, config.token, model);\n\t\t});\n\t\tthis.defaultModel = Object.keys(this.models)[0] ?? '';\n\t}\n}\n\nexport default LLM;\n","import {execSync, spawn} from 'node:child_process';\nimport {mkdtempSync} from 'node:fs';\nimport fs from 'node:fs/promises';\nimport {tmpdir} from 'node:os';\nimport Path, {join} from 'node:path';\nimport {AbortablePromise, Ai} from './ai.ts';\n\nexport class Audio {\n\tprivate downloads: {[key: string]: Promise<string>} = {};\n\tprivate pyannote!: string;\n\tprivate whisperModel!: string;\n\n\tconstructor(private ai: Ai) {\n\t\tif(ai.options.whisper) {\n\t\t\tthis.whisperModel = ai.options.asr || 'ggml-base.en.bin';\n\t\t\tthis.downloadAsrModel();\n\t\t}\n\n\t\tthis.pyannote = `\nimport sys\nimport json\nimport os\nfrom pyannote.audio import Pipeline\n\nos.environ['TORCH_HOME'] = r\"${ai.options.path}\"\npipeline = Pipeline.from_pretrained(\"pyannote/speaker-diarization-3.1\", token=\"${ai.options.hfToken}\")\noutput = pipeline(sys.argv[1])\n\nsegments = []\nfor turn, speaker in output.speaker_diarization:\n    segments.append({\"start\": turn.start, \"end\": turn.end, \"speaker\": speaker})\n\nprint(json.dumps(segments))\n`;\n\t}\n\n\tprivate async addPunctuation(timestampData: any, llm?: boolean, cadence = 150): Promise<string> {\n\t\tconst countSyllables = (word: string): number => {\n\t\t\tword = word.toLowerCase().replace(/[^a-z]/g, '');\n\t\t\tif(word.length <= 3) return 1;\n\t\t\tconst matches = word.match(/[aeiouy]+/g);\n\t\t\tlet count = matches ? matches.length : 1;\n\t\t\tif(word.endsWith('e')) count--;\n\t\t\treturn Math.max(1, count);\n\t\t};\n\n\t\tlet result = '';\n\t\ttimestampData.transcription.filter((word, i) => {\n\t\t\tlet skip = false;\n\t\t\tconst prevWord = timestampData.transcription[i - 1];\n\t\t\tconst nextWord = timestampData.transcription[i + 1];\n\t\t\tif(!word.text && nextWord) {\n\t\t\t\tnextWord.offsets.from = word.offsets.from;\n\t\t\t\tnextWord.timestamps.from = word.offsets.from;\n\t\t\t} else if(word.text && word.text[0] != ' ' && prevWord) {\n\t\t\t\tprevWord.offsets.to = word.offsets.to;\n\t\t\t\tprevWord.timestamps.to = word.timestamps.to;\n\t\t\t\tprevWord.text += word.text;\n\t\t\t\tskip = true;\n\t\t\t}\n\t\t\treturn !!word.text && !skip;\n\t\t}).forEach((word: any) => {\n\t\t\tconst capital = /^[A-Z]/.test(word.text.trim());\n\t\t\tconst length = word.offsets.to - word.offsets.from;\n\t\t\tconst syllables = countSyllables(word.text.trim());\n\t\t\tconst expected = syllables * cadence;\n\t\t\tif(capital && length > expected * 2 && word.text[0] == ' ') result += '.';\n\t\t\tresult += word.text;\n\t\t});\n\t\tif(!llm) return result.trim();\n\t\treturn this.ai.language.ask(result, {\n\t\t\tsystem: 'Remove any misplaced punctuation from the following ASR transcript using the replace tool. Avoid modifying words unless there is an obvious typo',\n\t\t\ttemperature: 0.1,\n\t\t\ttools: [{\n\t\t\t\tname: 'replace',\n\t\t\t\tdescription: 'Use find and replace to fix errors',\n\t\t\t\targs: {\n\t\t\t\t\tfind: {type: 'string', description: 'Text to find', required: true},\n\t\t\t\t\treplace: {type: 'string', description: 'Text to replace', required: true}\n\t\t\t\t},\n\t\t\t\tfn: (args) => result = result.replace(args.find, args.replace)\n\t\t\t}]\n\t\t}).then(() => result);\n\t}\n\n\tprivate async diarizeTranscript(timestampData: any, speakers: any[], llm: boolean): Promise<string> {\n\t\tconst speakerMap = new Map();\n\t\tlet speakerCount = 0;\n\t\tspeakers.forEach((seg: any) => {\n\t\t\tif(!speakerMap.has(seg.speaker)) speakerMap.set(seg.speaker, ++speakerCount);\n\t\t});\n\n\t\tconst punctuatedText = await this.addPunctuation(timestampData, llm);\n\t\tconst sentences = punctuatedText.match(/[^.!?]+[.!?]+/g) || [punctuatedText];\n\t\tconst words = timestampData.transcription.filter((w: any) => w.text.trim());\n\n\t\t// Assign speaker to each sentence\n\t\tconst sentencesWithSpeakers = sentences.map(sentence => {\n\t\t\tsentence = sentence.trim();\n\t\t\tif(!sentence) return null;\n\n\t\t\tconst sentenceWords = sentence.toLowerCase().replace(/[^\\w\\s]/g, '').split(/\\s+/);\n\t\t\tconst speakerWordCount = new Map<number, number>();\n\n\t\t\tsentenceWords.forEach(sw => {\n\t\t\t\tconst word = words.find((w: any) => sw === w.text.trim().toLowerCase().replace(/[^\\w]/g, ''));\n\t\t\t\tif(!word) return;\n\n\t\t\t\tconst wordTime = word.offsets.from / 1000;\n\t\t\t\tconst speaker = speakers.find((seg: any) => wordTime >= seg.start && wordTime <= seg.end);\n\t\t\t\tif(speaker) {\n\t\t\t\t\tconst spkNum = speakerMap.get(speaker.speaker);\n\t\t\t\t\tspeakerWordCount.set(spkNum, (speakerWordCount.get(spkNum) || 0) + 1);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tlet bestSpeaker = 1;\n\t\t\tlet maxWords = 0;\n\t\t\tspeakerWordCount.forEach((count, speaker) => {\n\t\t\t\tif(count > maxWords) {\n\t\t\t\t\tmaxWords = count;\n\t\t\t\t\tbestSpeaker = speaker;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn {speaker: bestSpeaker, text: sentence};\n\t\t}).filter(s => s !== null);\n\n\t\t// Merge adjacent sentences from same speaker\n\t\tconst merged: Array<{speaker: number, text: string}> = [];\n\t\tsentencesWithSpeakers.forEach(item => {\n\t\t\tconst last = merged[merged.length - 1];\n\t\t\tif(last && last.speaker === item.speaker) {\n\t\t\t\tlast.text += ' ' + item.text;\n\t\t\t} else {\n\t\t\t\tmerged.push({...item});\n\t\t\t}\n\t\t});\n\n\t\tlet transcript = merged.map(item => `[Speaker ${item.speaker}]: ${item.text}`).join('\\n').trim();\n\t\tif(!llm) return transcript;\n\t\tlet chunks = this.ai.language.chunk(transcript, 500, 0);\n\t\tif(chunks.length > 4) chunks = [...chunks.slice(0, 3), <string>chunks.at(-1)];\n\t\tawait this.ai.language.ask(chunks.join('\\n'), {\n\t\t\tsystem: 'Read the following transcript and attempt to identify every speaker. For every positively identified speaker, call the \\`identify\\` tool with the speaker\\'s ID number & the identified name exactly once.',\n\t\t\ttemperature: 0.1,\n\t\t\ttools: [\n\t\t\t\t{name: 'identify', description: 'Identify a speaker', args: {\n\t\t\t\t\tspeaker: {type: 'number', description: 'Speaker number', required: true},\n\t\t\t\t\tname: {type: 'string', description: 'Inferred name', required: true},\n\t\t\t\t}, fn: ({speaker, name}) => {\n\t\t\t\t\ttranscript = transcript.replaceAll(`[Speaker ${speaker}]`, `[${name}]`);\n\t\t\t\t}}\n\t\t\t]\n\t\t});\n\t\treturn transcript;\n\t}\n\n\tprivate runAsr(file: string, opts: {model?: string, diarization?: boolean} = {}): AbortablePromise<any> {\n\t\tlet proc: any;\n\t\tconst p = new Promise<any>((resolve, reject) => {\n\t\t\tthis.downloadAsrModel(opts.model).then(m => {\n\t\t\t\tif(opts.diarization) {\n\t\t\t\t\tlet output = join(Path.dirname(file), 'transcript');\n\t\t\t\t\tproc = spawn(<string>this.ai.options.whisper,\n\t\t\t\t\t\t['-m', m, '-f', file, '-np', '-ml', '1', '-oj', '-of', output],\n\t\t\t\t\t\t{stdio: ['ignore', 'ignore', 'pipe']}\n\t\t\t\t\t);\n\t\t\t\t\tproc.on('error', (err: Error) => reject(err));\n\t\t\t\t\tproc.on('close', async (code: number) => {\n\t\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\t\toutput = await fs.readFile(output + '.json', 'utf-8');\n\t\t\t\t\t\t\tfs.rm(output + '.json').catch(() => { });\n\t\t\t\t\t\t\ttry { resolve(JSON.parse(output)); }\n\t\t\t\t\t\t\tcatch(e) { reject(new Error('Failed to parse whisper JSON')); }\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treject(new Error(`Exit code ${code}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tlet output = '';\n\t\t\t\t\tproc = spawn(<string>this.ai.options.whisper, ['-m', m, '-f', file, '-np', '-nt']);\n\t\t\t\t\tproc.on('error', (err: Error) => reject(err));\n\t\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\t\tproc.on('close', async (code: number) => {\n\t\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\t\tresolve(output.trim() || null);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treject(new Error(`Exit code ${code}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\treturn <any>Object.assign(p, {abort: () => proc?.kill('SIGTERM')});\n\t}\n\n\tprivate runDiarization(file: string): AbortablePromise<any> {\n\t\tlet aborted = false, abort = () => { aborted = true; };\n\t\tconst checkPython = (cmd: string) => {\n\t\t\treturn new Promise<boolean>((resolve) => {\n\t\t\t\tconst proc = spawn(cmd, ['-W', 'ignore', '-c', 'import pyannote.audio']);\n\t\t\t\tproc.on('close', (code: number) => resolve(code === 0));\n\t\t\t\tproc.on('error', () => resolve(false));\n\t\t\t});\n\t\t};\n\t\tconst p = Promise.all<any>([\n\t\t\tcheckPython('python'),\n\t\t\tcheckPython('python3'),\n\t\t]).then(<any>(async ([p, p3]: [boolean, boolean]) => {\n\t\t\tif(aborted) return;\n\t\t\tif(!p && !p3) throw new Error('Pyannote is not installed: pip install pyannote.audio');\n\t\t\tconst binary = p3 ? 'python3' : 'python';\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif(aborted) return;\n\t\t\t\tlet output = '';\n\t\t\t\tconst proc = spawn(binary, ['-W', 'ignore', '-c', this.pyannote, file]);\n\t\t\t\tproc.stdout.on('data', (data: Buffer) => output += data.toString());\n\t\t\t\tproc.stderr.on('data', (data: Buffer) => console.error(data.toString()));\n\t\t\t\tproc.on('close', (code: number) => {\n\t\t\t\t\tif(code === 0) {\n\t\t\t\t\t\ttry { resolve(JSON.parse(output)); }\n\t\t\t\t\t\tcatch (err) { reject(new Error('Failed to parse diarization output')); }\n\t\t\t\t\t} else {\n\t\t\t\t\t\treject(new Error(`Python process exited with code ${code}`));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tproc.on('error', reject);\n\t\t\t\tabort = () => proc.kill('SIGTERM');\n\t\t\t});\n\t\t}));\n\t\treturn <any>Object.assign(p, {abort});\n\t}\n\n\tasr(path: string, options: { model?: string; diarization?: boolean | 'llm' } = {}): AbortablePromise<string | null> {\n\t\tif(!this.ai.options.whisper) throw new Error('Whisper not configured');\n\n\t\tconst tmp = join(mkdtempSync(join(tmpdir(), 'audio-')), 'converted.wav');\n\t\texecSync(`ffmpeg -i \"${path}\" -ar 16000 -ac 1 -f wav \"${tmp}\"`, { stdio: 'ignore' });\n\t\tconst clean = () => fs.rm(Path.dirname(tmp), {recursive: true, force: true}).catch(() => {});\n\n\t\tif(!options.diarization) return this.runAsr(tmp, {model: options.model});\n\t\tconst timestamps = this.runAsr(tmp, {model: options.model, diarization: true});\n\t\tconst diarization = this.runDiarization(tmp);\n\t\tlet aborted = false, abort = () => {\n\t\t\taborted = true;\n\t\t\ttimestamps.abort();\n\t\t\tdiarization.abort();\n\t\t\tclean();\n\t\t};\n\n\t\tconst response = Promise.allSettled([timestamps, diarization]).then(async ([ts, d]) => {\n\t\t\tif(ts.status == 'rejected') throw new Error('Whisper.cpp timestamps:\\n' + ts.reason);\n\t\t\tif(d.status == 'rejected') throw new Error('Pyannote:\\n' + d.reason);\n\t\t\tif(aborted || !options.diarization) return ts.value;\n\t\t\treturn this.diarizeTranscript(ts.value, d.value, options.diarization == 'llm');\n\t\t}).finally(() => clean());\n\t\treturn <any>Object.assign(response, {abort});\n\t}\n\n\tasync downloadAsrModel(model: string = this.whisperModel): Promise<string> {\n\t\tif(!this.ai.options.whisper) throw new Error('Whisper not configured');\n\t\tif(!model.endsWith('.bin')) model += '.bin';\n\t\tconst p = Path.join(<string>this.ai.options.path, model);\n\t\tif(await fs.stat(p).then(() => true).catch(() => false)) return p;\n\t\tif(!!this.downloads[model]) return this.downloads[model];\n\t\tthis.downloads[model] = fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${model}`)\n\t\t\t.then(resp => resp.arrayBuffer())\n\t\t\t.then(arr => Buffer.from(arr)).then(async buffer => {\n\t\t\t\tawait fs.writeFile(p, buffer);\n\t\t\t\tdelete this.downloads[model];\n\t\t\t\treturn p;\n\t\t\t});\n\t\treturn this.downloads[model];\n\t}\n}\n","import {createWorker} from 'tesseract.js';\nimport {AbortablePromise, Ai} from './ai.ts';\n\nexport class Vision {\n\n\tconstructor(private ai: Ai) {}\n\n\t/**\n\t * Convert image to text using Optical Character Recognition\n\t * @param {string} path Path to image\n\t * @returns {AbortablePromise<string | null>} Promise of extracted text with abort method\n\t */\n\tocr(path: string): AbortablePromise<string | null> {\n\t\tlet worker: any;\n\t\tlet reject: (err: any) => void;\n\n\t\tconst handler = (err: Error) => {\n\t\t\tif(err.stack?.includes('tesseract.js')) {\n\t\t\t\tprocess.off('uncaughtException', handler);\n\t\t\t\treject?.(err);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow err;\n\t\t};\n\t\tprocess.on('uncaughtException', handler);\n\n\t\tconst p = (async () => {\n\t\t\tworker = await createWorker(this.ai.options.ocr || 'eng', 2, {cachePath: this.ai.options.path});\n\t\t\treturn await new Promise<string | null>((res, rej) => {\n\t\t\t\treject = rej;\n\t\t\t\tworker.recognize(path)\n\t\t\t\t\t.then(({data}: any) => res(data.text.trim() || null))\n\t\t\t\t\t.catch(rej);\n\t\t\t});\n\t\t})().finally(() => {\n\t\t\tprocess.off('uncaughtException', handler);\n\t\t\tworker?.terminate();\n\t\t});\n\n\t\treturn Object.assign(p, {abort: () => worker?.terminate()});\n\t}\n}\n","import * as os from 'node:os';\nimport LLM, {AnthropicConfig, OpenAiConfig, LLMRequest} from './llm';\nimport { Audio } from './audio.ts';\nimport {Vision} from './vision.ts';\n\nexport type AbortablePromise<T> = Promise<T> & {\n\tabort: (keep?: boolean) => any\n};\n\nexport type AiOptions = {\n\t/** Token to pull diarization models from hugging face */\n\thfToken?: string;\n\t/** Path to models */\n\tpath?: string;\n\t/** Whisper ASR model: ggml-tiny.en.bin, ggml-base.en.bin */\n\tasr?: string;\n\t/** Embedding model: all-MiniLM-L6-v2, bge-small-en-v1.5, bge-large-en-v1.5 */\n\tembedder?: string;\n\t/** Large language models, first is default */\n\tllm?: Omit<LLMRequest, 'model'> & {\n\t\tmodels: {[model: string]: AnthropicConfig | OpenAiConfig};\n\t}\n\t/** OCR model: eng, eng_best, eng_fast */\n\tocr?: string;\n\t/** Whisper binary */\n\twhisper?: string;\n}\n\nexport class Ai {\n\t/** Audio processing AI */\n\taudio!: Audio;\n\t/** Language processing AI */\n\tlanguage!: LLM;\n\t/** Vision processing AI */\n\tvision!: Vision;\n\n\tconstructor(public readonly options: AiOptions) {\n\t\tif(!options.path) options.path = os.tmpdir();\n\t\tprocess.env.TRANSFORMERS_CACHE = options.path;\n\t\tthis.audio = new Audio(this);\n\t\tthis.language = new LLM(this);\n\t\tthis.vision = new Vision(this);\n\t}\n}\n"],"mappings":"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"}