frontend-agent 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +0 -3
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -111,11 +111,8 @@ declare function createAgent(config: AgentConfig): Session;
|
|
|
111
111
|
|
|
112
112
|
/** Reference to a GGUF published on the Hugging Face Hub. */
|
|
113
113
|
interface HFModelRef {
|
|
114
|
-
/** `owner/name`. Default `lazos/lfm2.5-230m-frontend-agent`. */
|
|
115
114
|
repo?: string;
|
|
116
|
-
/** Release/version tag embedded in the filename. Default `v1.0.0`. */
|
|
117
115
|
version?: string;
|
|
118
|
-
/** Quantization suffix. Default `Q4_K_M`. */
|
|
119
116
|
quant?: string;
|
|
120
117
|
}
|
|
121
118
|
type EngineStatus = 'idle' | 'downloading' | 'loading' | 'ready';
|
package/dist/index.js
CHANGED
|
@@ -293,15 +293,13 @@ function renderToolCalls(calls) {
|
|
|
293
293
|
// src/engine/wllamaEngine.ts
|
|
294
294
|
var DEFAULT_MODEL = {
|
|
295
295
|
repo: "lazos/lfm2.5-230m-frontend-agent",
|
|
296
|
-
version: "
|
|
297
|
-
// Q6_K is the quality sweet spot for this 230M model: it matches Q8 on held-out eval (96.3%) while
|
|
298
|
-
// Q4_K_M drops ~2 pts (worse query formulation / grounding). ~191 MB.
|
|
296
|
+
version: "main",
|
|
299
297
|
quant: "Q6_K"
|
|
300
298
|
};
|
|
301
299
|
function resolveModelUrl(ref = {}) {
|
|
302
300
|
const { repo, version, quant } = { ...DEFAULT_MODEL, ...ref };
|
|
303
301
|
const basename = repo.split("/").pop() ?? repo;
|
|
304
|
-
return `https://huggingface.co/${repo}/resolve
|
|
302
|
+
return `https://huggingface.co/${repo}/resolve/${version}/${basename}-${quant}.gguf`;
|
|
305
303
|
}
|
|
306
304
|
async function detectWebGPU() {
|
|
307
305
|
try {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engine/gbnf.ts","../src/limits.ts","../src/loop/agent.ts","../src/parsing/toolCallParser.ts","../src/parsing/renderToolCalls.ts","../src/engine/wllamaEngine.ts","../src/engine/stubEngine.ts","../src/prompt/pyJson.ts","../src/prompt/systemPrompt.ts","../src/tools/registry.ts"],"names":["instance","text"],"mappings":"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","file":"index.js","sourcesContent":["import type { ToolSchema } from '../tools/types'\n\n/**\n * Generate a GBNF grammar that constrains LFM2.5 tool-call decoding to the injected tool schema.\n * TS port of training/kbft/gbnf.py (kept in lockstep - validated against llama.cpp).\n *\n * The model supplies the POLICY (which tool, when, which id semantically); the grammar GUARANTEES the\n * STRUCTURE at decode time: only valid tool names, that tool's arg keys/types, enum values, and - when\n * `validIds` (the ids present in results so far) is given - the id argument is forced to one of those,\n * so id-grounding becomes unfaultable (a truncated/hallucinated id is impossible to emit). Applied via\n * wllama's `grammar` sampling param. `allowText` keeps a free-text reply branch so normal answers work.\n */\n\nfunction lit(s: string): string {\n return '\"' + s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"') + '\"'\n}\nfunction sq(s: string): string {\n return lit(\"'\" + s + \"'\")\n}\nfunction rn(name: string): string {\n // GBNF rule names take hyphens, not underscores\n return name.replace(/[^A-Za-z0-9]/g, '-')\n}\n\nfunction valueRule(\n tname: string,\n key: string,\n spec: Record<string, unknown>,\n validIds: string[] | undefined,\n idKeys: string[],\n): string {\n if (idKeys.includes(key) && validIds && validIds.length) return `${rn(tname)}-${rn(key)}-id`\n const en = (spec as { enum?: unknown[] }).enum\n if (Array.isArray(en)) return '( ' + en.map((v) => sq(String(v))).join(' | ') + ' )'\n const t = (spec as { type?: string }).type\n if (t === 'integer' || t === 'number') return 'numval'\n if (t === 'boolean') return 'boolval'\n return 'strval'\n}\n\nexport function buildToolGrammar(\n tools: ToolSchema[],\n validIds?: string[],\n idKeys: string[] = ['id'],\n allowText = true,\n): string {\n const rules: string[] = ['sep ::= \",\" \" \"?']\n const callAlts: string[] = []\n const idAltsNeeded: [string, string][] = []\n\n for (const t of tools) {\n const name = t.name\n const props = (t.parameters?.properties ?? {}) as Record<string, Record<string, unknown>>\n const required = t.parameters?.required ?? []\n const r = rn(name)\n const reqFrags: string[] = []\n const optFrags: string[] = []\n for (const [key, spec] of Object.entries(props)) {\n const val = valueRule(name, key, spec, validIds, idKeys)\n if (idKeys.includes(key) && validIds && validIds.length) idAltsNeeded.push([name, key])\n const frag = `${r}-${rn(key)}`\n rules.push(`${frag} ::= ${lit(key + '=')} ${val}`)\n ;(required.includes(key) ? reqFrags : optFrags).push(frag)\n }\n // required args in order, comma-joined; optionals each appended optionally (matches the model)\n let seq = reqFrags.join(' sep ')\n for (const o of optFrags) seq = (seq ? seq + ' ' : '') + `( sep ${o} )?`\n rules.push(`${r}-call ::= ${lit(name + '(')} ${seq} ${lit(')')}`.replace(/ {2}/g, ' '))\n callAlts.push(`${r}-call`)\n }\n\n // One or more calls, comma-joined (`[fn1(...), fn2(...)]`); a single call is N=1. Mirrors kbft/gbnf.py.\n rules.push('call ::= ( ' + callAlts.join(' | ') + ' )')\n rules.push('toolcall ::= ' + lit('[') + ' call ( sep call )* ' + lit(']'))\n rules.push(\n 'wrapped ::= ( ' + lit('<|tool_call_start|>') + ' )? toolcall ( ' + lit('<|tool_call_end|>') + ' )?',\n )\n for (const [name, key] of idAltsNeeded) {\n rules.push(`${rn(name)}-${rn(key)}-id ::= ` + (validIds as string[]).map(sq).join(' | '))\n }\n if (allowText) {\n // a free-text reply: first char isn't a tool-call opener, then any chars (incl. newlines)\n rules.push('reply ::= [^\\\\[<] [^\\\\x00]*')\n rules.push('root ::= wrapped | reply')\n } else {\n rules.push('root ::= wrapped')\n }\n rules.push(`strval ::= \"'\" [^']* \"'\"`)\n rules.push('numval ::= \"-\"? [0-9]+ (\".\" [0-9]+)?')\n rules.push('boolval ::= \"True\" | \"False\"')\n return rules.join('\\n')\n}\n\n/** Collect string values under `id` keys from an arbitrary tool result (search results carry them). */\nexport function collectIds(value: unknown, into: Set<string>): void {\n if (Array.isArray(value)) {\n for (const v of value) collectIds(v, into)\n } else if (value && typeof value === 'object') {\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (k === 'id' && typeof v === 'string' && v) into.add(v)\n else collectIds(v, into)\n }\n }\n}\n","// Shared runtime limits for the on-device agent. Centralized so context caps and budgeting\n// stay consistent across the engine and the agent loop.\n\nexport const N_CTX = 8192 // wllama context window\nexport const MAX_OUTPUT_TOKENS = 320 // max tokens generated per assistant turn\n\n// Warn if the injected system prompt (persona + catalog + tool list) exceeds this fraction of\n// the context window - a signal that a growing catalog/KB is crowding out room for the\n// conversation. Configurable.\nexport const SYSTEM_CTX_WARN_FRACTION = 0.15\n\n// Token budget for accumulated conversation history (everything after the system prompt). Leaves\n// room for the system prompt (up to the warn fraction), one full answer, and a safety margin, so\n// the assembled prompt never overflows N_CTX - on overflow llama.cpp drops tokens from the FRONT,\n// which is the catalog the model grounds slugs on.\nexport const HISTORY_TOKEN_BUDGET =\n N_CTX - Math.ceil(N_CTX * SYSTEM_CTX_WARN_FRACTION) - MAX_OUTPUT_TOKENS - 256\n\n// Rough token estimate (~chars/4) - good enough for history budgeting without a tokenizer.\nexport const estimateTokens = (text: string | undefined): number => Math.ceil((text?.length ?? 0) / 4)\n","import { buildToolGrammar, collectIds } from '../engine/gbnf'\nimport { HISTORY_TOKEN_BUDGET, estimateTokens } from '../limits'\nimport type { AgentEngine, ChatMessage } from '../engine/types'\nimport type { ToolRegistry } from '../tools/registry'\n\nexport interface ToolCall {\n name: string\n args: Record<string, unknown>\n}\n\n/** Events emitted while a turn runs. Subscribe with `session.on(...)`. */\nexport type AgentEvent =\n | { type: 'status'; status: 'thinking' | 'ready' | 'aborted' | 'error' }\n | { type: 'assistant'; text: string }\n | { type: 'tool_call'; call: ToolCall }\n | { type: 'tool_result'; name: string; result: unknown }\n | { type: 'done' }\n | { type: 'error'; error: unknown }\n\nexport interface AgentConfig {\n engine: AgentEngine\n /** The tool set (schemas + handlers). Build with `buildRegistry(referenceTools(...))` or `buildRegistry(yourTools)`. */\n tools: ToolRegistry\n /** The system prompt, or a provider called once per `submit`. */\n systemPrompt: string | (() => string | Promise<string>)\n /** Max tool-loop cycles per turn. Default 8 (the longest trained multi-step flow). */\n maxIterations?: number\n /** Arg keys constrained to seen result ids by the grammar. Default `['id']`. */\n idKeys?: string[]\n /** History token budget (system prompt excluded). Default derived from N_CTX. */\n historyBudgetTokens?: number\n /**\n * Per-generation watchdog (ms). Some WASM engines can hang or crash a worker thread without\n * ever rejecting the in-flight promise (e.g. a trap on a secondary compute thread that leaves\n * the main thread waiting on a futex forever) - without this, that turn would sit in\n * 'thinking' indefinitely with no error surfaced. Default 90s; set 0 to disable.\n */\n generationTimeoutMs?: number\n}\n\nclass GenerationTimeoutError extends Error {\n constructor(ms: number) {\n super(`Generation timed out after ${ms}ms - the engine may have crashed or hung.`)\n this.name = 'GenerationTimeoutError'\n }\n}\n\n/** Race a promise against a timeout, without leaking the timer once either settles. */\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n if (!ms) return promise\n let timer: ReturnType<typeof setTimeout>\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new GenerationTimeoutError(ms)), ms)\n })\n return Promise.race([promise, timeout]).finally(() => clearTimeout(timer))\n}\n\nexport interface SubmitOptions {\n signal?: AbortSignal\n}\n\nexport interface Session {\n /**\n * The single programmatic entry point: feed user text from anywhere - a text box, an external\n * API, or STT output - and run the tool loop to completion. Emits events as it goes.\n */\n submit(text: string, opts?: SubmitOptions): Promise<void>\n /** Abort the in-flight turn (best-effort: stops between generations/tool calls). */\n abort(): void\n /** Subscribe to events. Returns an unsubscribe function. */\n on(listener: (event: AgentEvent) => void): () => void\n /** The model-format conversation so far (assistant turns include raw tool-call markers). */\n readonly history: ChatMessage[]\n /** Clear the conversation. */\n reset(): void\n}\n\nconst GIVE_UP =\n \"I'm having trouble completing this - let me know if you'd like to try a simpler request.\"\n\nclass AbortError extends Error {\n constructor() {\n super('aborted')\n this.name = 'AbortError'\n }\n}\n\nexport function createAgent(config: AgentConfig): Session {\n const maxIterations = config.maxIterations ?? 8\n const idKeys = config.idKeys ?? ['id']\n const budget = config.historyBudgetTokens ?? HISTORY_TOKEN_BUDGET\n const generationTimeoutMs = config.generationTimeoutMs ?? 90_000\n const history: ChatMessage[] = []\n const listeners = new Set<(e: AgentEvent) => void>()\n let controller: AbortController | null = null\n\n const emit = (e: AgentEvent) => {\n for (const l of listeners) l(e)\n }\n\n async function runToolCall(call: ToolCall): Promise<unknown> {\n const handler = config.tools.handlers[call.name]\n if (!handler) return { error: 'unknown_tool', name: call.name }\n try {\n return await handler(call.args)\n } catch (err) {\n return { error: 'tool_execution_failed', message: (err as Error).message }\n }\n }\n\n async function runLoop(system: string, signal: AbortSignal): Promise<void> {\n const seenIds = new Set<string>()\n for (let i = 0; i < maxIterations; i++) {\n if (signal.aborted) throw new AbortError()\n trimHistory(history, budget)\n const messages: ChatMessage[] = [{ role: 'system', content: system }, ...history]\n const grammar = buildToolGrammar(\n config.tools.schemas,\n seenIds.size ? [...seenIds] : undefined,\n idKeys,\n )\n const result = await withTimeout(config.engine.generate(messages, grammar), generationTimeoutMs)\n if (signal.aborted) throw new AbortError()\n\n if (result.toolCalls.length === 0) {\n history.push({ role: 'assistant', content: result.raw })\n emit({ type: 'assistant', text: result.text })\n emit({ type: 'status', status: 'ready' })\n return\n }\n\n history.push({ role: 'assistant', content: result.raw })\n if (result.text) emit({ type: 'assistant', text: result.text })\n\n for (const call of result.toolCalls) {\n emit({ type: 'tool_call', call })\n const toolResult = await runToolCall(call)\n collectIds(toolResult, seenIds)\n emit({ type: 'tool_result', name: call.name, result: toolResult })\n history.push({ role: 'tool', content: JSON.stringify(toolResult) })\n }\n }\n history.push({ role: 'assistant', content: GIVE_UP })\n emit({ type: 'assistant', text: GIVE_UP })\n emit({ type: 'status', status: 'ready' })\n }\n\n return {\n history,\n on(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n abort() {\n controller?.abort()\n },\n reset() {\n history.length = 0\n },\n async submit(text, opts) {\n controller = new AbortController()\n const signal = opts?.signal\n ? AbortSignal.any([controller.signal, opts.signal])\n : controller.signal\n history.push({ role: 'user', content: text })\n emit({ type: 'status', status: 'thinking' })\n try {\n const system =\n typeof config.systemPrompt === 'function' ? await config.systemPrompt() : config.systemPrompt\n await runLoop(system, signal)\n emit({ type: 'done' })\n } catch (err) {\n if (err instanceof AbortError || signal.aborted) {\n emit({ type: 'status', status: 'aborted' })\n emit({ type: 'done' })\n } else {\n emit({ type: 'error', error: err })\n emit({ type: 'status', status: 'error' })\n }\n } finally {\n controller = null\n }\n },\n }\n}\n\n/**\n * Bound accumulated history so system prompt + conversation never overflows the context window\n * (overflow drops tokens from the FRONT - the catalog the model grounds on). Drops whole oldest\n * turns from the front, never leaving a dangling `tool`/assistant continuation at the head, and\n * always keeps the most recent messages.\n */\nexport function trimHistory(history: ChatMessage[], budget: number): void {\n const tokens = () => history.reduce((n, m) => n + estimateTokens(m.content), 0)\n while (history.length > 2 && tokens() > budget) {\n history.shift()\n // don't start the remaining history on an orphaned tool result / non-user continuation\n while (history.length > 1 && history[0]!.role === 'tool') history.shift()\n }\n}\n","export interface ParsedToolCall {\n name: string\n args: Record<string, unknown>\n}\n\nexport interface ParseResult {\n text: string\n toolCalls: ParsedToolCall[]\n}\n\nconst CALL_BLOCK_RE = /<\\|tool_call_start\\|>([\\s\\S]*?)<\\|tool_call_end\\|>/g\n\n/**\n * Extracts pythonic tool calls (e.g. `[search_products(query=\"x\"), add_to_cart(slug=\"y\", quantity=2)]`)\n * from LFM2.5's tool_call_start/end markers, and returns the remaining plain text.\n * Never uses eval - parses the restricted call grammar by hand.\n */\nexport function parseToolCalls(raw: string): ParseResult {\n const toolCalls: ParsedToolCall[] = []\n const text = raw.replace(CALL_BLOCK_RE, (_match, inner: string) => {\n toolCalls.push(...parseCallList(inner.trim()))\n return ''\n })\n return { text: text.trim(), toolCalls }\n}\n\nfunction parseCallList(block: string): ParsedToolCall[] {\n const inner = block.startsWith('[') && block.endsWith(']') ? block.slice(1, -1) : block\n const calls: ParsedToolCall[] = []\n for (const piece of splitTopLevel(inner, ',')) {\n const trimmed = piece.trim()\n if (!trimmed) continue\n const call = parseSingleCall(trimmed)\n if (call) calls.push(call)\n }\n return calls\n}\n\nfunction parseSingleCall(expr: string): ParsedToolCall | null {\n const match = expr.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\\((.*)\\)$/s)\n if (!match) return null\n const [, name, argsSrc] = match\n const args: Record<string, unknown> = {}\n for (const piece of splitTopLevel(argsSrc, ',')) {\n const trimmed = piece.trim()\n if (!trimmed) continue\n const eq = trimmed.indexOf('=')\n if (eq === -1) continue\n const key = trimmed.slice(0, eq).trim()\n const valueSrc = trimmed.slice(eq + 1).trim()\n args[key] = parseValue(valueSrc)\n }\n return { name, args }\n}\n\nfunction parseValue(src: string): unknown {\n if (src === 'True') return true\n if (src === 'False') return false\n if (src === 'None') return null\n if (/^-?\\d+$/.test(src)) return parseInt(src, 10)\n if (/^-?\\d+\\.\\d+$/.test(src)) return parseFloat(src)\n if (\n (src.startsWith('\"') && src.endsWith('\"')) ||\n (src.startsWith(\"'\") && src.endsWith(\"'\"))\n ) {\n return src.slice(1, -1)\n }\n return src\n}\n\n/** Splits on a delimiter, ignoring delimiters inside quotes/parens/brackets. */\nfunction splitTopLevel(src: string, delimiter: string): string[] {\n const parts: string[] = []\n let depth = 0\n let quote: string | null = null\n let current = ''\n for (const ch of src) {\n if (quote) {\n current += ch\n if (ch === quote) quote = null\n continue\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch\n current += ch\n continue\n }\n if (ch === '(' || ch === '[') depth++\n if (ch === ')' || ch === ']') depth--\n if (ch === delimiter && depth === 0) {\n parts.push(current)\n current = ''\n continue\n }\n current += ch\n }\n if (current.trim()) parts.push(current)\n return parts\n}\n","import type { ParsedToolCall } from './toolCallParser'\n\n// Inverse of toolCallParser: render parsed calls back into the exact LFM2.5 wire format\n// (mirrors the chat template's render_tool_calls macro) so a tool-call turn can be replayed\n// verbatim into the next generation's context.\n\nfunction formatArg(value: unknown): string {\n if (typeof value === 'string') return `'${value}'`\n if (value === null) return 'None'\n if (typeof value === 'boolean') return value ? 'True' : 'False'\n if (typeof value === 'object') return JSON.stringify(value)\n return String(value)\n}\n\nexport function renderToolCalls(calls: ParsedToolCall[]): string {\n const rendered = calls.map((c) => {\n const args = Object.entries(c.args)\n .map(([k, v]) => `${k}=${formatArg(v)}`)\n .join(', ')\n return `${c.name}(${args})`\n })\n return `<|tool_call_start|>[${rendered.join(', ')}]<|tool_call_end|>`\n}\n","import { Wllama, type AssetsPathConfig } from '@wllama/wllama'\nimport { parseToolCalls } from '../parsing/toolCallParser'\nimport { renderToolCalls } from '../parsing/renderToolCalls'\nimport { N_CTX, MAX_OUTPUT_TOKENS, SYSTEM_CTX_WARN_FRACTION, estimateTokens } from '../limits'\nimport type { AgentEngine, ChatMessage, EngineGenerateResult } from './types'\n\n/** Reference to a GGUF published on the Hugging Face Hub. */\nexport interface HFModelRef {\n /** `owner/name`. Default `lazos/lfm2.5-230m-frontend-agent`. */\n repo?: string\n /** Release/version tag embedded in the filename. Default `v1.0.0`. */\n version?: string\n /** Quantization suffix. Default `Q4_K_M`. */\n quant?: string\n}\n\nexport type EngineStatus = 'idle' | 'downloading' | 'loading' | 'ready'\n\nexport interface WllamaEngineConfig {\n /** Load the GGUF from Hugging Face (default). Ignored if `modelUrl` is set. */\n model?: HFModelRef\n /** Full GGUF URL - self-host escape hatch; overrides `model`. */\n modelUrl?: string\n /** wllama WASM asset config, e.g. `{ 'single-thread/wllama.wasm': url, 'multi-thread/wllama.wasm': url }`. */\n wllamaAssets: AssetsPathConfig\n /** Context window. Default 8192. */\n nCtx?: number\n /** Max tokens per assistant turn. Default 320. */\n maxTokens?: number\n /** Backend preference. `'auto'` uses WebGPU when a real adapter is present. Default `'auto'`. */\n backend?: 'auto' | 'webgpu' | 'cpu'\n onStatus?: (status: EngineStatus) => void\n onProgress?: (progress: { loaded: number; total: number }) => void\n /** Reports whether a usable WebGPU adapter was detected (after load). */\n onBackend?: (info: { webgpu: boolean; using: 'webgpu' | 'cpu' }) => void\n}\n\nconst DEFAULT_MODEL: Required<HFModelRef> = {\n repo: 'lazos/lfm2.5-230m-frontend-agent',\n version: 'v1.0.0',\n // Q6_K is the quality sweet spot for this 230M model: it matches Q8 on held-out eval (96.3%) while\n // Q4_K_M drops ~2 pts (worse query formulation / grounding). ~191 MB.\n quant: 'Q6_K',\n}\n\n/** Resolve a HF model ref to its `resolve/main` GGUF URL: `{basename}-{version}-{quant}.gguf`. */\nexport function resolveModelUrl(ref: HFModelRef = {}): string {\n const { repo, version, quant } = { ...DEFAULT_MODEL, ...ref }\n const basename = repo.split('/').pop() ?? repo\n return `https://huggingface.co/${repo}/resolve/main/${basename}-${version}-${quant}.gguf`\n}\n\nasync function detectWebGPU(): Promise<boolean> {\n try {\n const gpu = (navigator as unknown as { gpu?: { requestAdapter?: () => Promise<unknown> } }).gpu\n if (!gpu?.requestAdapter) return false\n return (await gpu.requestAdapter()) != null\n } catch {\n return false\n }\n}\n\n/**\n * Real engine: runs the GGUF in-browser via wllama (llama.cpp WASM/WebGPU). Loads the model from\n * Hugging Face by default (configurable), caches it in OPFS, and applies the GBNF grammar at decode.\n * Framework-agnostic - reports lifecycle via callbacks, no store coupling.\n */\nexport class WllamaEngine implements AgentEngine {\n private wllamaPromise: Promise<Wllama> | null = null\n private warnedSystemSize = false\n private readonly url: string\n private readonly nCtx: number\n private readonly maxTokens: number\n\n constructor(private readonly config: WllamaEngineConfig) {\n this.url = config.modelUrl ?? resolveModelUrl(config.model)\n this.nCtx = config.nCtx ?? N_CTX\n this.maxTokens = config.maxTokens ?? MAX_OUTPUT_TOKENS\n }\n\n async load(): Promise<void> {\n await this.getWllama()\n }\n\n /** Tear down the loaded model so it can be reloaded (e.g. on a backend switch). OPFS-cached. */\n async reset(): Promise<void> {\n const p = this.wllamaPromise\n this.wllamaPromise = null\n try {\n const inst = p ? await p : null\n await (inst as unknown as { exit?: () => Promise<void> })?.exit?.()\n } catch {\n /* ignore teardown errors */\n }\n }\n\n private getWllama(): Promise<Wllama> {\n if (this.wllamaPromise) return this.wllamaPromise\n this.wllamaPromise = (async () => {\n const { onStatus, onProgress, onBackend, backend = 'auto', wllamaAssets } = this.config\n const hasWebGPU = await detectWebGPU()\n const useGPU = hasWebGPU && backend !== 'cpu'\n onBackend?.({ webgpu: hasWebGPU, using: useGPU ? 'webgpu' : 'cpu' })\n\n const load = async (nThreads?: number): Promise<Wllama> => {\n const instance = new Wllama(wllamaAssets)\n onStatus?.('downloading')\n // wllama has no separate hook for \"download done, now initializing\" - the progress\n // callback stalling at 100% while loadModelFromUrl hasn't resolved yet IS that gap, so\n // infer the transition from it (once) rather than leaving the caller stuck on a stale\n // \"downloading 100%\" label through however long GGUF parsing/context init takes.\n let announcedLoading = false\n await instance.loadModelFromUrl(this.url, {\n n_ctx: this.nCtx,\n n_gpu_layers: useGPU ? 99999 : 0,\n ...(nThreads ? { n_threads: nThreads } : {}),\n progressCallback: ({ loaded, total }) => {\n onProgress?.({ loaded, total })\n if (!announcedLoading && total > 0 && loaded >= total) {\n announcedLoading = true\n onStatus?.('loading')\n }\n },\n })\n return instance\n }\n\n // Try the fast path (auto = WebGPU / multi-thread WASM); on a threads-build trap, fall back\n // once to single-thread. Reacts to the actual failure, not a UA string. OPFS-cached, so the\n // retry never re-downloads.\n let instance: Wllama\n try {\n instance = await load()\n } catch (err) {\n console.warn('[frontend-agent] multi-thread load failed; retrying single-thread:', err)\n instance = await load(1)\n }\n onStatus?.('ready')\n return instance\n })()\n return this.wllamaPromise\n }\n\n async generate(messages: ChatMessage[], grammar?: string): Promise<EngineGenerateResult> {\n const wllama = await this.getWllama()\n\n if (!this.warnedSystemSize) {\n const sys = messages.find((m) => m.role === 'system')?.content ?? ''\n const tokenize = (wllama as { tokenize?: (s: string) => Promise<number[]> }).tokenize\n let sysTokens: number\n try {\n sysTokens = tokenize ? (await tokenize.call(wllama, sys)).length : estimateTokens(sys)\n } catch {\n sysTokens = estimateTokens(sys)\n }\n if (sysTokens > this.nCtx * SYSTEM_CTX_WARN_FRACTION) {\n this.warnedSystemSize = true\n console.warn(\n `[frontend-agent] system prompt is ${sysTokens} tokens - over ` +\n `${Math.round(SYSTEM_CTX_WARN_FRACTION * 100)}% of the ${this.nCtx}-token context. ` +\n 'A larger catalog/KB is crowding out the conversation; trim the injected catalog or raise nCtx.',\n )\n }\n }\n\n // Full system text (persona + catalog + \"List of tools: [...]\") is baked into the system message,\n // so we pass NO `tools` - wllama's chat template renders turns/markers. The GBNF grammar (when\n // supplied) guarantees a structurally-valid call + id-grounding at decode time.\n const response = await wllama.createChatCompletion({\n messages: messages as never,\n max_tokens: this.maxTokens,\n temperature: 0,\n ...(grammar ? { grammar } : {}),\n } as never)\n const message = (response as { choices: { message: WllamaMessage }[] }).choices[0]!.message\n\n if (message.tool_calls && message.tool_calls.length > 0) {\n const toolCalls = message.tool_calls.map((c) => ({\n name: c.function.name,\n args: safeJson(c.function.arguments),\n }))\n return { text: message.content ?? '', toolCalls, raw: renderToolCalls(toolCalls) }\n }\n\n const rawContent = message.content ?? ''\n const parsed = parseToolCalls(rawContent)\n return { text: parsed.text, toolCalls: parsed.toolCalls, raw: rawContent }\n }\n}\n\ninterface WllamaMessage {\n content?: string\n tool_calls?: { function: { name: string; arguments: string } }[]\n}\n\nfunction safeJson(s: string): Record<string, unknown> {\n try {\n return JSON.parse(s || '{}')\n } catch {\n return {}\n }\n}\n","import { renderToolCalls } from '../parsing/renderToolCalls'\nimport type { AgentEngine, ChatMessage, EngineGenerateResult } from './types'\n\n/**\n * Fixture engine with no model weights - for building/testing the loop, tools, and UI without\n * loading the real model. Emits calls on the current v1.0.0 contract (`search_catalog`,\n * `search_knowledge`, `add_to_cart(id)`). Ignores the grammar.\n */\nexport class StubEngine implements AgentEngine {\n async generate(messages: ChatMessage[], _grammar?: string): Promise<EngineGenerateResult> {\n void _grammar\n const lastUserIdx = messages.map((m) => m.role).lastIndexOf('user')\n const trailingToolResults = messages.slice(lastUserIdx + 1).filter((m) => m.role === 'tool')\n const userText = (messages[lastUserIdx]?.content ?? '').toLowerCase()\n\n if (trailingToolResults.length > 0) {\n const last = trailingToolResults[trailingToolResults.length - 1]\n const text = `Here's what I found: ${last?.content ?? ''}`\n return { text, toolCalls: [], raw: text }\n }\n\n const call = (name: string, args: Record<string, unknown>): EngineGenerateResult => {\n const toolCalls = [{ name, args }]\n return { text: '', toolCalls, raw: renderToolCalls(toolCalls) }\n }\n\n const quotedId = userText.match(/['\"]([a-z0-9-]+)['\"]/)\n if (userText.includes('cart') && quotedId) {\n const quantity = Number(userText.match(/(\\d+)\\s*(unit|x\\b)/)?.[1] ?? '1')\n return call('add_to_cart', { id: quotedId[1], quantity })\n }\n if (/(compat|pair|guide|how|descal|clean)/.test(userText)) {\n return call('search_knowledge', { query: userText.slice(0, 60) })\n }\n if (/(find|search|show|any|looking|need|grinder|machine|accessor)/.test(userText)) {\n return call('search_catalog', { query: userText.slice(0, 60) })\n }\n\n const text =\n 'I can search the catalog, look things up in the knowledge base, or manage your cart. What would you like to do?'\n return { text, toolCalls: [], raw: text }\n }\n}\n","/**\n * Serialize a value the way Python's json.dumps (and Jinja2's `tojson`) does by default:\n * \", \" between items and \": \" after keys. The model's chat template renders the tool list\n * with these separators, so the browser must match them byte-for-byte for train/inference\n * parity. (Our tool schemas are ASCII with no <,>,& so htmlsafe escaping never triggers.)\n */\nexport function pyJson(v: unknown): string {\n if (v === null) return 'null'\n if (typeof v === 'string') return JSON.stringify(v)\n if (typeof v === 'number' || typeof v === 'boolean') return String(v)\n if (Array.isArray(v)) return '[' + v.map(pyJson).join(', ') + ']'\n if (typeof v === 'object') {\n const entries = Object.entries(v as Record<string, unknown>)\n return '{' + entries.map(([k, val]) => `${JSON.stringify(k)}: ${pyJson(val)}`).join(', ') + '}'\n }\n return JSON.stringify(v)\n}\n","import { pyJson } from './pyJson'\nimport type { ToolSchema } from '../tools/types'\n\nexport interface SystemPromptConfig {\n /** 1-2 line persona/rules for this deployment (who the assistant is, grounding + refusal rules). */\n persona: string\n /** The tool schemas to advertise (same array the loop dispatches). */\n toolSchemas: ToolSchema[]\n /** A short \"headline entities\" hint (`Title [id]; ...`) or a provider for it. Optional. */\n catalogHint?: string | (() => string | Promise<string>)\n /** Label before the hint. Defaults to the trained `\"Example catalog items\"`. */\n hintLabel?: string\n}\n\n/**\n * Reproduce the exact v1.0.0 system message the model was trained on:\n * `{persona}\\n\\n{hintLabel}: {hint}\\nList of tools: [{fn-json}, ...]`\n * The tool list uses Python `json.dumps` separators (`pyJson`) for byte-for-byte train/inference\n * parity. The full system text is baked here (pass NO `tools` array to the engine's chat template).\n */\nexport async function buildSystemPrompt(cfg: SystemPromptConfig): Promise<string> {\n const label = cfg.hintLabel ?? 'Example catalog items'\n const hint =\n typeof cfg.catalogHint === 'function' ? await cfg.catalogHint() : cfg.catalogHint\n const head = hint ? `${cfg.persona}\\n\\n${label}: ${hint}` : cfg.persona\n const tools = cfg.toolSchemas.map((s) => pyJson({ type: 'function', function: s }))\n return `${head}\\nList of tools: [${tools.join(', ')}]`\n}\n","import type { ToolDefinition, ToolHandler, ToolSchema } from './types'\n\nexport interface ToolRegistry {\n /** Tool schemas, in order - injected into the system prompt (order is contract-significant). */\n schemas: ToolSchema[]\n /** name → handler dispatch map. */\n handlers: Record<string, ToolHandler>\n}\n\n/** Build a registry from a consumer-supplied tool set. Bring your own tools, or use `referenceTools`. */\nexport function buildRegistry(definitions: ToolDefinition[]): ToolRegistry {\n return {\n schemas: definitions.map((d) => d.schema),\n handlers: Object.fromEntries(definitions.map((d) => [d.schema.name, d.handler])),\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/engine/gbnf.ts","../src/limits.ts","../src/loop/agent.ts","../src/parsing/toolCallParser.ts","../src/parsing/renderToolCalls.ts","../src/engine/wllamaEngine.ts","../src/engine/stubEngine.ts","../src/prompt/pyJson.ts","../src/prompt/systemPrompt.ts","../src/tools/registry.ts"],"names":["instance","text"],"mappings":"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","file":"index.js","sourcesContent":["import type { ToolSchema } from '../tools/types'\n\n/**\n * Generate a GBNF grammar that constrains LFM2.5 tool-call decoding to the injected tool schema.\n * TS port of training/kbft/gbnf.py (kept in lockstep - validated against llama.cpp).\n *\n * The model supplies the POLICY (which tool, when, which id semantically); the grammar GUARANTEES the\n * STRUCTURE at decode time: only valid tool names, that tool's arg keys/types, enum values, and - when\n * `validIds` (the ids present in results so far) is given - the id argument is forced to one of those,\n * so id-grounding becomes unfaultable (a truncated/hallucinated id is impossible to emit). Applied via\n * wllama's `grammar` sampling param. `allowText` keeps a free-text reply branch so normal answers work.\n */\n\nfunction lit(s: string): string {\n return '\"' + s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"') + '\"'\n}\nfunction sq(s: string): string {\n return lit(\"'\" + s + \"'\")\n}\nfunction rn(name: string): string {\n // GBNF rule names take hyphens, not underscores\n return name.replace(/[^A-Za-z0-9]/g, '-')\n}\n\nfunction valueRule(\n tname: string,\n key: string,\n spec: Record<string, unknown>,\n validIds: string[] | undefined,\n idKeys: string[],\n): string {\n if (idKeys.includes(key) && validIds && validIds.length) return `${rn(tname)}-${rn(key)}-id`\n const en = (spec as { enum?: unknown[] }).enum\n if (Array.isArray(en)) return '( ' + en.map((v) => sq(String(v))).join(' | ') + ' )'\n const t = (spec as { type?: string }).type\n if (t === 'integer' || t === 'number') return 'numval'\n if (t === 'boolean') return 'boolval'\n return 'strval'\n}\n\nexport function buildToolGrammar(\n tools: ToolSchema[],\n validIds?: string[],\n idKeys: string[] = ['id'],\n allowText = true,\n): string {\n const rules: string[] = ['sep ::= \",\" \" \"?']\n const callAlts: string[] = []\n const idAltsNeeded: [string, string][] = []\n\n for (const t of tools) {\n const name = t.name\n const props = (t.parameters?.properties ?? {}) as Record<string, Record<string, unknown>>\n const required = t.parameters?.required ?? []\n const r = rn(name)\n const reqFrags: string[] = []\n const optFrags: string[] = []\n for (const [key, spec] of Object.entries(props)) {\n const val = valueRule(name, key, spec, validIds, idKeys)\n if (idKeys.includes(key) && validIds && validIds.length) idAltsNeeded.push([name, key])\n const frag = `${r}-${rn(key)}`\n rules.push(`${frag} ::= ${lit(key + '=')} ${val}`)\n ;(required.includes(key) ? reqFrags : optFrags).push(frag)\n }\n // required args in order, comma-joined; optionals each appended optionally (matches the model)\n let seq = reqFrags.join(' sep ')\n for (const o of optFrags) seq = (seq ? seq + ' ' : '') + `( sep ${o} )?`\n rules.push(`${r}-call ::= ${lit(name + '(')} ${seq} ${lit(')')}`.replace(/ {2}/g, ' '))\n callAlts.push(`${r}-call`)\n }\n\n // One or more calls, comma-joined (`[fn1(...), fn2(...)]`); a single call is N=1. Mirrors kbft/gbnf.py.\n rules.push('call ::= ( ' + callAlts.join(' | ') + ' )')\n rules.push('toolcall ::= ' + lit('[') + ' call ( sep call )* ' + lit(']'))\n rules.push(\n 'wrapped ::= ( ' + lit('<|tool_call_start|>') + ' )? toolcall ( ' + lit('<|tool_call_end|>') + ' )?',\n )\n for (const [name, key] of idAltsNeeded) {\n rules.push(`${rn(name)}-${rn(key)}-id ::= ` + (validIds as string[]).map(sq).join(' | '))\n }\n if (allowText) {\n // a free-text reply: first char isn't a tool-call opener, then any chars (incl. newlines)\n rules.push('reply ::= [^\\\\[<] [^\\\\x00]*')\n rules.push('root ::= wrapped | reply')\n } else {\n rules.push('root ::= wrapped')\n }\n rules.push(`strval ::= \"'\" [^']* \"'\"`)\n rules.push('numval ::= \"-\"? [0-9]+ (\".\" [0-9]+)?')\n rules.push('boolval ::= \"True\" | \"False\"')\n return rules.join('\\n')\n}\n\n/** Collect string values under `id` keys from an arbitrary tool result (search results carry them). */\nexport function collectIds(value: unknown, into: Set<string>): void {\n if (Array.isArray(value)) {\n for (const v of value) collectIds(v, into)\n } else if (value && typeof value === 'object') {\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (k === 'id' && typeof v === 'string' && v) into.add(v)\n else collectIds(v, into)\n }\n }\n}\n","// Shared runtime limits for the on-device agent. Centralized so context caps and budgeting\n// stay consistent across the engine and the agent loop.\n\nexport const N_CTX = 8192 // wllama context window\nexport const MAX_OUTPUT_TOKENS = 320 // max tokens generated per assistant turn\n\n// Warn if the injected system prompt (persona + catalog + tool list) exceeds this fraction of\n// the context window - a signal that a growing catalog/KB is crowding out room for the\n// conversation. Configurable.\nexport const SYSTEM_CTX_WARN_FRACTION = 0.15\n\n// Token budget for accumulated conversation history (everything after the system prompt). Leaves\n// room for the system prompt (up to the warn fraction), one full answer, and a safety margin, so\n// the assembled prompt never overflows N_CTX - on overflow llama.cpp drops tokens from the FRONT,\n// which is the catalog the model grounds slugs on.\nexport const HISTORY_TOKEN_BUDGET =\n N_CTX - Math.ceil(N_CTX * SYSTEM_CTX_WARN_FRACTION) - MAX_OUTPUT_TOKENS - 256\n\n// Rough token estimate (~chars/4) - good enough for history budgeting without a tokenizer.\nexport const estimateTokens = (text: string | undefined): number => Math.ceil((text?.length ?? 0) / 4)\n","import { buildToolGrammar, collectIds } from '../engine/gbnf'\nimport { HISTORY_TOKEN_BUDGET, estimateTokens } from '../limits'\nimport type { AgentEngine, ChatMessage } from '../engine/types'\nimport type { ToolRegistry } from '../tools/registry'\n\nexport interface ToolCall {\n name: string\n args: Record<string, unknown>\n}\n\n/** Events emitted while a turn runs. Subscribe with `session.on(...)`. */\nexport type AgentEvent =\n | { type: 'status'; status: 'thinking' | 'ready' | 'aborted' | 'error' }\n | { type: 'assistant'; text: string }\n | { type: 'tool_call'; call: ToolCall }\n | { type: 'tool_result'; name: string; result: unknown }\n | { type: 'done' }\n | { type: 'error'; error: unknown }\n\nexport interface AgentConfig {\n engine: AgentEngine\n /** The tool set (schemas + handlers). Build with `buildRegistry(referenceTools(...))` or `buildRegistry(yourTools)`. */\n tools: ToolRegistry\n /** The system prompt, or a provider called once per `submit`. */\n systemPrompt: string | (() => string | Promise<string>)\n /** Max tool-loop cycles per turn. Default 8 (the longest trained multi-step flow). */\n maxIterations?: number\n /** Arg keys constrained to seen result ids by the grammar. Default `['id']`. */\n idKeys?: string[]\n /** History token budget (system prompt excluded). Default derived from N_CTX. */\n historyBudgetTokens?: number\n /**\n * Per-generation watchdog (ms). Some WASM engines can hang or crash a worker thread without\n * ever rejecting the in-flight promise (e.g. a trap on a secondary compute thread that leaves\n * the main thread waiting on a futex forever) - without this, that turn would sit in\n * 'thinking' indefinitely with no error surfaced. Default 90s; set 0 to disable.\n */\n generationTimeoutMs?: number\n}\n\nclass GenerationTimeoutError extends Error {\n constructor(ms: number) {\n super(`Generation timed out after ${ms}ms - the engine may have crashed or hung.`)\n this.name = 'GenerationTimeoutError'\n }\n}\n\n/** Race a promise against a timeout, without leaking the timer once either settles. */\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n if (!ms) return promise\n let timer: ReturnType<typeof setTimeout>\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new GenerationTimeoutError(ms)), ms)\n })\n return Promise.race([promise, timeout]).finally(() => clearTimeout(timer))\n}\n\nexport interface SubmitOptions {\n signal?: AbortSignal\n}\n\nexport interface Session {\n /**\n * The single programmatic entry point: feed user text from anywhere - a text box, an external\n * API, or STT output - and run the tool loop to completion. Emits events as it goes.\n */\n submit(text: string, opts?: SubmitOptions): Promise<void>\n /** Abort the in-flight turn (best-effort: stops between generations/tool calls). */\n abort(): void\n /** Subscribe to events. Returns an unsubscribe function. */\n on(listener: (event: AgentEvent) => void): () => void\n /** The model-format conversation so far (assistant turns include raw tool-call markers). */\n readonly history: ChatMessage[]\n /** Clear the conversation. */\n reset(): void\n}\n\nconst GIVE_UP =\n \"I'm having trouble completing this - let me know if you'd like to try a simpler request.\"\n\nclass AbortError extends Error {\n constructor() {\n super('aborted')\n this.name = 'AbortError'\n }\n}\n\nexport function createAgent(config: AgentConfig): Session {\n const maxIterations = config.maxIterations ?? 8\n const idKeys = config.idKeys ?? ['id']\n const budget = config.historyBudgetTokens ?? HISTORY_TOKEN_BUDGET\n const generationTimeoutMs = config.generationTimeoutMs ?? 90_000\n const history: ChatMessage[] = []\n const listeners = new Set<(e: AgentEvent) => void>()\n let controller: AbortController | null = null\n\n const emit = (e: AgentEvent) => {\n for (const l of listeners) l(e)\n }\n\n async function runToolCall(call: ToolCall): Promise<unknown> {\n const handler = config.tools.handlers[call.name]\n if (!handler) return { error: 'unknown_tool', name: call.name }\n try {\n return await handler(call.args)\n } catch (err) {\n return { error: 'tool_execution_failed', message: (err as Error).message }\n }\n }\n\n async function runLoop(system: string, signal: AbortSignal): Promise<void> {\n const seenIds = new Set<string>()\n for (let i = 0; i < maxIterations; i++) {\n if (signal.aborted) throw new AbortError()\n trimHistory(history, budget)\n const messages: ChatMessage[] = [{ role: 'system', content: system }, ...history]\n const grammar = buildToolGrammar(\n config.tools.schemas,\n seenIds.size ? [...seenIds] : undefined,\n idKeys,\n )\n const result = await withTimeout(config.engine.generate(messages, grammar), generationTimeoutMs)\n if (signal.aborted) throw new AbortError()\n\n if (result.toolCalls.length === 0) {\n history.push({ role: 'assistant', content: result.raw })\n emit({ type: 'assistant', text: result.text })\n emit({ type: 'status', status: 'ready' })\n return\n }\n\n history.push({ role: 'assistant', content: result.raw })\n if (result.text) emit({ type: 'assistant', text: result.text })\n\n for (const call of result.toolCalls) {\n emit({ type: 'tool_call', call })\n const toolResult = await runToolCall(call)\n collectIds(toolResult, seenIds)\n emit({ type: 'tool_result', name: call.name, result: toolResult })\n history.push({ role: 'tool', content: JSON.stringify(toolResult) })\n }\n }\n history.push({ role: 'assistant', content: GIVE_UP })\n emit({ type: 'assistant', text: GIVE_UP })\n emit({ type: 'status', status: 'ready' })\n }\n\n return {\n history,\n on(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n abort() {\n controller?.abort()\n },\n reset() {\n history.length = 0\n },\n async submit(text, opts) {\n controller = new AbortController()\n const signal = opts?.signal\n ? AbortSignal.any([controller.signal, opts.signal])\n : controller.signal\n history.push({ role: 'user', content: text })\n emit({ type: 'status', status: 'thinking' })\n try {\n const system =\n typeof config.systemPrompt === 'function' ? await config.systemPrompt() : config.systemPrompt\n await runLoop(system, signal)\n emit({ type: 'done' })\n } catch (err) {\n if (err instanceof AbortError || signal.aborted) {\n emit({ type: 'status', status: 'aborted' })\n emit({ type: 'done' })\n } else {\n emit({ type: 'error', error: err })\n emit({ type: 'status', status: 'error' })\n }\n } finally {\n controller = null\n }\n },\n }\n}\n\n/**\n * Bound accumulated history so system prompt + conversation never overflows the context window\n * (overflow drops tokens from the FRONT - the catalog the model grounds on). Drops whole oldest\n * turns from the front, never leaving a dangling `tool`/assistant continuation at the head, and\n * always keeps the most recent messages.\n */\nexport function trimHistory(history: ChatMessage[], budget: number): void {\n const tokens = () => history.reduce((n, m) => n + estimateTokens(m.content), 0)\n while (history.length > 2 && tokens() > budget) {\n history.shift()\n // don't start the remaining history on an orphaned tool result / non-user continuation\n while (history.length > 1 && history[0]!.role === 'tool') history.shift()\n }\n}\n","export interface ParsedToolCall {\n name: string\n args: Record<string, unknown>\n}\n\nexport interface ParseResult {\n text: string\n toolCalls: ParsedToolCall[]\n}\n\nconst CALL_BLOCK_RE = /<\\|tool_call_start\\|>([\\s\\S]*?)<\\|tool_call_end\\|>/g\n\n/**\n * Extracts pythonic tool calls (e.g. `[search_products(query=\"x\"), add_to_cart(slug=\"y\", quantity=2)]`)\n * from LFM2.5's tool_call_start/end markers, and returns the remaining plain text.\n * Never uses eval - parses the restricted call grammar by hand.\n */\nexport function parseToolCalls(raw: string): ParseResult {\n const toolCalls: ParsedToolCall[] = []\n const text = raw.replace(CALL_BLOCK_RE, (_match, inner: string) => {\n toolCalls.push(...parseCallList(inner.trim()))\n return ''\n })\n return { text: text.trim(), toolCalls }\n}\n\nfunction parseCallList(block: string): ParsedToolCall[] {\n const inner = block.startsWith('[') && block.endsWith(']') ? block.slice(1, -1) : block\n const calls: ParsedToolCall[] = []\n for (const piece of splitTopLevel(inner, ',')) {\n const trimmed = piece.trim()\n if (!trimmed) continue\n const call = parseSingleCall(trimmed)\n if (call) calls.push(call)\n }\n return calls\n}\n\nfunction parseSingleCall(expr: string): ParsedToolCall | null {\n const match = expr.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\\((.*)\\)$/s)\n if (!match) return null\n const [, name, argsSrc] = match\n const args: Record<string, unknown> = {}\n for (const piece of splitTopLevel(argsSrc, ',')) {\n const trimmed = piece.trim()\n if (!trimmed) continue\n const eq = trimmed.indexOf('=')\n if (eq === -1) continue\n const key = trimmed.slice(0, eq).trim()\n const valueSrc = trimmed.slice(eq + 1).trim()\n args[key] = parseValue(valueSrc)\n }\n return { name, args }\n}\n\nfunction parseValue(src: string): unknown {\n if (src === 'True') return true\n if (src === 'False') return false\n if (src === 'None') return null\n if (/^-?\\d+$/.test(src)) return parseInt(src, 10)\n if (/^-?\\d+\\.\\d+$/.test(src)) return parseFloat(src)\n if (\n (src.startsWith('\"') && src.endsWith('\"')) ||\n (src.startsWith(\"'\") && src.endsWith(\"'\"))\n ) {\n return src.slice(1, -1)\n }\n return src\n}\n\n/** Splits on a delimiter, ignoring delimiters inside quotes/parens/brackets. */\nfunction splitTopLevel(src: string, delimiter: string): string[] {\n const parts: string[] = []\n let depth = 0\n let quote: string | null = null\n let current = ''\n for (const ch of src) {\n if (quote) {\n current += ch\n if (ch === quote) quote = null\n continue\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch\n current += ch\n continue\n }\n if (ch === '(' || ch === '[') depth++\n if (ch === ')' || ch === ']') depth--\n if (ch === delimiter && depth === 0) {\n parts.push(current)\n current = ''\n continue\n }\n current += ch\n }\n if (current.trim()) parts.push(current)\n return parts\n}\n","import type { ParsedToolCall } from './toolCallParser'\n\n// Inverse of toolCallParser: render parsed calls back into the exact LFM2.5 wire format\n// (mirrors the chat template's render_tool_calls macro) so a tool-call turn can be replayed\n// verbatim into the next generation's context.\n\nfunction formatArg(value: unknown): string {\n if (typeof value === 'string') return `'${value}'`\n if (value === null) return 'None'\n if (typeof value === 'boolean') return value ? 'True' : 'False'\n if (typeof value === 'object') return JSON.stringify(value)\n return String(value)\n}\n\nexport function renderToolCalls(calls: ParsedToolCall[]): string {\n const rendered = calls.map((c) => {\n const args = Object.entries(c.args)\n .map(([k, v]) => `${k}=${formatArg(v)}`)\n .join(', ')\n return `${c.name}(${args})`\n })\n return `<|tool_call_start|>[${rendered.join(', ')}]<|tool_call_end|>`\n}\n","import { Wllama, type AssetsPathConfig } from '@wllama/wllama'\nimport { parseToolCalls } from '../parsing/toolCallParser'\nimport { renderToolCalls } from '../parsing/renderToolCalls'\nimport { N_CTX, MAX_OUTPUT_TOKENS, SYSTEM_CTX_WARN_FRACTION, estimateTokens } from '../limits'\nimport type { AgentEngine, ChatMessage, EngineGenerateResult } from './types'\n\n/** Reference to a GGUF published on the Hugging Face Hub. */\nexport interface HFModelRef {\n repo?: string\n version?: string\n quant?: string\n}\n\nexport type EngineStatus = 'idle' | 'downloading' | 'loading' | 'ready'\n\nexport interface WllamaEngineConfig {\n /** Load the GGUF from Hugging Face (default). Ignored if `modelUrl` is set. */\n model?: HFModelRef\n /** Full GGUF URL - self-host escape hatch; overrides `model`. */\n modelUrl?: string\n /** wllama WASM asset config, e.g. `{ 'single-thread/wllama.wasm': url, 'multi-thread/wllama.wasm': url }`. */\n wllamaAssets: AssetsPathConfig\n /** Context window. Default 8192. */\n nCtx?: number\n /** Max tokens per assistant turn. Default 320. */\n maxTokens?: number\n /** Backend preference. `'auto'` uses WebGPU when a real adapter is present. Default `'auto'`. */\n backend?: 'auto' | 'webgpu' | 'cpu'\n onStatus?: (status: EngineStatus) => void\n onProgress?: (progress: { loaded: number; total: number }) => void\n /** Reports whether a usable WebGPU adapter was detected (after load). */\n onBackend?: (info: { webgpu: boolean; using: 'webgpu' | 'cpu' }) => void\n}\n\nconst DEFAULT_MODEL: Required<HFModelRef> = {\n repo: 'lazos/lfm2.5-230m-frontend-agent',\n version: 'main',\n quant: 'Q6_K',\n}\n\n/** Resolve a HF model ref to its `resolve/main` GGUF URL: `{basename}-{version}-{quant}.gguf`. */\nexport function resolveModelUrl(ref: HFModelRef = {}): string {\n const { repo, version, quant } = { ...DEFAULT_MODEL, ...ref }\n const basename = repo.split('/').pop() ?? repo\n return `https://huggingface.co/${repo}/resolve/${version}/${basename}-${quant}.gguf`\n}\n\nasync function detectWebGPU(): Promise<boolean> {\n try {\n const gpu = (navigator as unknown as { gpu?: { requestAdapter?: () => Promise<unknown> } }).gpu\n if (!gpu?.requestAdapter) return false\n return (await gpu.requestAdapter()) != null\n } catch {\n return false\n }\n}\n\n/**\n * Real engine: runs the GGUF in-browser via wllama (llama.cpp WASM/WebGPU). Loads the model from\n * Hugging Face by default (configurable), caches it in OPFS, and applies the GBNF grammar at decode.\n * Framework-agnostic - reports lifecycle via callbacks, no store coupling.\n */\nexport class WllamaEngine implements AgentEngine {\n private wllamaPromise: Promise<Wllama> | null = null\n private warnedSystemSize = false\n private readonly url: string\n private readonly nCtx: number\n private readonly maxTokens: number\n\n constructor(private readonly config: WllamaEngineConfig) {\n this.url = config.modelUrl ?? resolveModelUrl(config.model)\n this.nCtx = config.nCtx ?? N_CTX\n this.maxTokens = config.maxTokens ?? MAX_OUTPUT_TOKENS\n }\n\n async load(): Promise<void> {\n await this.getWllama()\n }\n\n /** Tear down the loaded model so it can be reloaded (e.g. on a backend switch). OPFS-cached. */\n async reset(): Promise<void> {\n const p = this.wllamaPromise\n this.wllamaPromise = null\n try {\n const inst = p ? await p : null\n await (inst as unknown as { exit?: () => Promise<void> })?.exit?.()\n } catch {\n /* ignore teardown errors */\n }\n }\n\n private getWllama(): Promise<Wllama> {\n if (this.wllamaPromise) return this.wllamaPromise\n this.wllamaPromise = (async () => {\n const { onStatus, onProgress, onBackend, backend = 'auto', wllamaAssets } = this.config\n const hasWebGPU = await detectWebGPU()\n const useGPU = hasWebGPU && backend !== 'cpu'\n onBackend?.({ webgpu: hasWebGPU, using: useGPU ? 'webgpu' : 'cpu' })\n\n const load = async (nThreads?: number): Promise<Wllama> => {\n const instance = new Wllama(wllamaAssets)\n onStatus?.('downloading')\n // wllama has no separate hook for \"download done, now initializing\" - the progress\n // callback stalling at 100% while loadModelFromUrl hasn't resolved yet IS that gap, so\n // infer the transition from it (once) rather than leaving the caller stuck on a stale\n // \"downloading 100%\" label through however long GGUF parsing/context init takes.\n let announcedLoading = false\n await instance.loadModelFromUrl(this.url, {\n n_ctx: this.nCtx,\n n_gpu_layers: useGPU ? 99999 : 0,\n ...(nThreads ? { n_threads: nThreads } : {}),\n progressCallback: ({ loaded, total }) => {\n onProgress?.({ loaded, total })\n if (!announcedLoading && total > 0 && loaded >= total) {\n announcedLoading = true\n onStatus?.('loading')\n }\n },\n })\n return instance\n }\n\n // Try the fast path (auto = WebGPU / multi-thread WASM); on a threads-build trap, fall back\n // once to single-thread. Reacts to the actual failure, not a UA string. OPFS-cached, so the\n // retry never re-downloads.\n let instance: Wllama\n try {\n instance = await load()\n } catch (err) {\n console.warn('[frontend-agent] multi-thread load failed; retrying single-thread:', err)\n instance = await load(1)\n }\n onStatus?.('ready')\n return instance\n })()\n return this.wllamaPromise\n }\n\n async generate(messages: ChatMessage[], grammar?: string): Promise<EngineGenerateResult> {\n const wllama = await this.getWllama()\n\n if (!this.warnedSystemSize) {\n const sys = messages.find((m) => m.role === 'system')?.content ?? ''\n const tokenize = (wllama as { tokenize?: (s: string) => Promise<number[]> }).tokenize\n let sysTokens: number\n try {\n sysTokens = tokenize ? (await tokenize.call(wllama, sys)).length : estimateTokens(sys)\n } catch {\n sysTokens = estimateTokens(sys)\n }\n if (sysTokens > this.nCtx * SYSTEM_CTX_WARN_FRACTION) {\n this.warnedSystemSize = true\n console.warn(\n `[frontend-agent] system prompt is ${sysTokens} tokens - over ` +\n `${Math.round(SYSTEM_CTX_WARN_FRACTION * 100)}% of the ${this.nCtx}-token context. ` +\n 'A larger catalog/KB is crowding out the conversation; trim the injected catalog or raise nCtx.',\n )\n }\n }\n\n // Full system text (persona + catalog + \"List of tools: [...]\") is baked into the system message,\n // so we pass NO `tools` - wllama's chat template renders turns/markers. The GBNF grammar (when\n // supplied) guarantees a structurally-valid call + id-grounding at decode time.\n const response = await wllama.createChatCompletion({\n messages: messages as never,\n max_tokens: this.maxTokens,\n temperature: 0,\n ...(grammar ? { grammar } : {}),\n } as never)\n const message = (response as { choices: { message: WllamaMessage }[] }).choices[0]!.message\n\n if (message.tool_calls && message.tool_calls.length > 0) {\n const toolCalls = message.tool_calls.map((c) => ({\n name: c.function.name,\n args: safeJson(c.function.arguments),\n }))\n return { text: message.content ?? '', toolCalls, raw: renderToolCalls(toolCalls) }\n }\n\n const rawContent = message.content ?? ''\n const parsed = parseToolCalls(rawContent)\n return { text: parsed.text, toolCalls: parsed.toolCalls, raw: rawContent }\n }\n}\n\ninterface WllamaMessage {\n content?: string\n tool_calls?: { function: { name: string; arguments: string } }[]\n}\n\nfunction safeJson(s: string): Record<string, unknown> {\n try {\n return JSON.parse(s || '{}')\n } catch {\n return {}\n }\n}\n","import { renderToolCalls } from '../parsing/renderToolCalls'\nimport type { AgentEngine, ChatMessage, EngineGenerateResult } from './types'\n\n/**\n * Fixture engine with no model weights - for building/testing the loop, tools, and UI without\n * loading the real model. Emits calls on the current v1.0.0 contract (`search_catalog`,\n * `search_knowledge`, `add_to_cart(id)`). Ignores the grammar.\n */\nexport class StubEngine implements AgentEngine {\n async generate(messages: ChatMessage[], _grammar?: string): Promise<EngineGenerateResult> {\n void _grammar\n const lastUserIdx = messages.map((m) => m.role).lastIndexOf('user')\n const trailingToolResults = messages.slice(lastUserIdx + 1).filter((m) => m.role === 'tool')\n const userText = (messages[lastUserIdx]?.content ?? '').toLowerCase()\n\n if (trailingToolResults.length > 0) {\n const last = trailingToolResults[trailingToolResults.length - 1]\n const text = `Here's what I found: ${last?.content ?? ''}`\n return { text, toolCalls: [], raw: text }\n }\n\n const call = (name: string, args: Record<string, unknown>): EngineGenerateResult => {\n const toolCalls = [{ name, args }]\n return { text: '', toolCalls, raw: renderToolCalls(toolCalls) }\n }\n\n const quotedId = userText.match(/['\"]([a-z0-9-]+)['\"]/)\n if (userText.includes('cart') && quotedId) {\n const quantity = Number(userText.match(/(\\d+)\\s*(unit|x\\b)/)?.[1] ?? '1')\n return call('add_to_cart', { id: quotedId[1], quantity })\n }\n if (/(compat|pair|guide|how|descal|clean)/.test(userText)) {\n return call('search_knowledge', { query: userText.slice(0, 60) })\n }\n if (/(find|search|show|any|looking|need|grinder|machine|accessor)/.test(userText)) {\n return call('search_catalog', { query: userText.slice(0, 60) })\n }\n\n const text =\n 'I can search the catalog, look things up in the knowledge base, or manage your cart. What would you like to do?'\n return { text, toolCalls: [], raw: text }\n }\n}\n","/**\n * Serialize a value the way Python's json.dumps (and Jinja2's `tojson`) does by default:\n * \", \" between items and \": \" after keys. The model's chat template renders the tool list\n * with these separators, so the browser must match them byte-for-byte for train/inference\n * parity. (Our tool schemas are ASCII with no <,>,& so htmlsafe escaping never triggers.)\n */\nexport function pyJson(v: unknown): string {\n if (v === null) return 'null'\n if (typeof v === 'string') return JSON.stringify(v)\n if (typeof v === 'number' || typeof v === 'boolean') return String(v)\n if (Array.isArray(v)) return '[' + v.map(pyJson).join(', ') + ']'\n if (typeof v === 'object') {\n const entries = Object.entries(v as Record<string, unknown>)\n return '{' + entries.map(([k, val]) => `${JSON.stringify(k)}: ${pyJson(val)}`).join(', ') + '}'\n }\n return JSON.stringify(v)\n}\n","import { pyJson } from './pyJson'\nimport type { ToolSchema } from '../tools/types'\n\nexport interface SystemPromptConfig {\n /** 1-2 line persona/rules for this deployment (who the assistant is, grounding + refusal rules). */\n persona: string\n /** The tool schemas to advertise (same array the loop dispatches). */\n toolSchemas: ToolSchema[]\n /** A short \"headline entities\" hint (`Title [id]; ...`) or a provider for it. Optional. */\n catalogHint?: string | (() => string | Promise<string>)\n /** Label before the hint. Defaults to the trained `\"Example catalog items\"`. */\n hintLabel?: string\n}\n\n/**\n * Reproduce the exact v1.0.0 system message the model was trained on:\n * `{persona}\\n\\n{hintLabel}: {hint}\\nList of tools: [{fn-json}, ...]`\n * The tool list uses Python `json.dumps` separators (`pyJson`) for byte-for-byte train/inference\n * parity. The full system text is baked here (pass NO `tools` array to the engine's chat template).\n */\nexport async function buildSystemPrompt(cfg: SystemPromptConfig): Promise<string> {\n const label = cfg.hintLabel ?? 'Example catalog items'\n const hint =\n typeof cfg.catalogHint === 'function' ? await cfg.catalogHint() : cfg.catalogHint\n const head = hint ? `${cfg.persona}\\n\\n${label}: ${hint}` : cfg.persona\n const tools = cfg.toolSchemas.map((s) => pyJson({ type: 'function', function: s }))\n return `${head}\\nList of tools: [${tools.join(', ')}]`\n}\n","import type { ToolDefinition, ToolHandler, ToolSchema } from './types'\n\nexport interface ToolRegistry {\n /** Tool schemas, in order - injected into the system prompt (order is contract-significant). */\n schemas: ToolSchema[]\n /** name → handler dispatch map. */\n handlers: Record<string, ToolHandler>\n}\n\n/** Build a registry from a consumer-supplied tool set. Bring your own tools, or use `referenceTools`. */\nexport function buildRegistry(definitions: ToolDefinition[]): ToolRegistry {\n return {\n schemas: definitions.map((d) => d.schema),\n handlers: Object.fromEntries(definitions.map((d) => [d.schema.name, d.handler])),\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frontend-agent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Drive the LFM2.5-230M frontend-agent model in the browser: tool-calling + RAG-grounded answering, fully typed. Loads the GGUF from Hugging Face via wllama.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|