@tryhamster/gerbil 1.0.0-rc.9 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +318 -104
- package/dist/architectures-C1I5V3Dt.mjs +6070 -0
- package/dist/architectures-C1I5V3Dt.mjs.map +1 -0
- package/dist/browser/index.d.ts +276 -590
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +592 -2334
- package/dist/browser/index.js.map +1 -1
- package/dist/cli.mjs +625 -1098
- package/dist/cli.mjs.map +1 -1
- package/dist/defaults-9komdrbY.mjs +24 -0
- package/dist/defaults-9komdrbY.mjs.map +1 -0
- package/dist/frameworks/express.d.mts +1 -3
- package/dist/frameworks/express.d.mts.map +1 -1
- package/dist/frameworks/express.mjs +7 -7
- package/dist/frameworks/express.mjs.map +1 -1
- package/dist/frameworks/fastify.d.mts +1 -1
- package/dist/frameworks/fastify.d.mts.map +1 -1
- package/dist/frameworks/fastify.mjs +3 -3
- package/dist/frameworks/fastify.mjs.map +1 -1
- package/dist/frameworks/hono.d.mts +1 -1
- package/dist/frameworks/hono.d.mts.map +1 -1
- package/dist/frameworks/hono.mjs +4 -4
- package/dist/frameworks/hono.mjs.map +1 -1
- package/dist/frameworks/next.d.mts +3 -2
- package/dist/frameworks/next.d.mts.map +1 -1
- package/dist/frameworks/next.mjs +4 -4
- package/dist/frameworks/next.mjs.map +1 -1
- package/dist/frameworks/react.d.mts +1 -1
- package/dist/frameworks/trpc.d.mts +1 -1
- package/dist/frameworks/trpc.d.mts.map +1 -1
- package/dist/frameworks/trpc.mjs +4 -4
- package/dist/frameworks/trpc.mjs.map +1 -1
- package/dist/gerbil-BetB5xb0.d.mts +488 -0
- package/dist/gerbil-BetB5xb0.d.mts.map +1 -0
- package/dist/gerbil-CTZUa8EZ.mjs +4 -0
- package/dist/gerbil-DNniplr4.mjs +1656 -0
- package/dist/gerbil-DNniplr4.mjs.map +1 -0
- package/dist/gpu/hooks.d.mts +640 -0
- package/dist/gpu/hooks.d.mts.map +1 -0
- package/dist/gpu/hooks.mjs +1369 -0
- package/dist/gpu/hooks.mjs.map +1 -0
- package/dist/gpu/index.d.mts +2 -0
- package/dist/gpu/index.mjs +6 -0
- package/dist/gpu-DFuglcEx.mjs +3790 -0
- package/dist/gpu-DFuglcEx.mjs.map +1 -0
- package/dist/index-Dgmb2kE3.d.mts +245 -0
- package/dist/index-Dgmb2kE3.d.mts.map +1 -0
- package/dist/index-DukkJRMj.d.mts +2114 -0
- package/dist/index-DukkJRMj.d.mts.map +1 -0
- package/dist/index.d.mts +22 -487
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +13 -8
- package/dist/index.mjs.map +1 -1
- package/dist/indexeddb-store-BWIMtxxH.mjs +103 -0
- package/dist/indexeddb-store-BWIMtxxH.mjs.map +1 -0
- package/dist/indexeddb-store-ClH12Xnl.mjs +4 -0
- package/dist/integrations/ai-sdk.d.mts +75 -6
- package/dist/integrations/ai-sdk.d.mts.map +1 -1
- package/dist/integrations/ai-sdk.mjs +131 -15
- package/dist/integrations/ai-sdk.mjs.map +1 -1
- package/dist/integrations/langchain.d.mts +1 -1
- package/dist/integrations/langchain.d.mts.map +1 -1
- package/dist/integrations/langchain.mjs +5 -5
- package/dist/integrations/langchain.mjs.map +1 -1
- package/dist/integrations/llamaindex.d.mts +1 -1
- package/dist/integrations/llamaindex.d.mts.map +1 -1
- package/dist/integrations/llamaindex.mjs +5 -5
- package/dist/integrations/llamaindex.mjs.map +1 -1
- package/dist/integrations/mcp-client.mjs +3 -3
- package/dist/integrations/mcp-client.mjs.map +1 -1
- package/dist/integrations/mcp.d.mts +3 -2
- package/dist/integrations/mcp.d.mts.map +1 -1
- package/dist/integrations/mcp.mjs +5 -5
- package/dist/{mcp-BvbriaBy.mjs → mcp-D2vvH1Xc.mjs} +4 -4
- package/dist/mcp-D2vvH1Xc.mjs.map +1 -0
- package/dist/memory/index.d.mts +3 -0
- package/dist/memory/index.mjs +6 -0
- package/dist/memory-D1P7Tmda.mjs +4 -0
- package/dist/memory-DVN0MnIG.mjs +132 -0
- package/dist/memory-DVN0MnIG.mjs.map +1 -0
- package/dist/memory-Dj0J1v88.mjs +294 -0
- package/dist/memory-Dj0J1v88.mjs.map +1 -0
- package/dist/moonshine-stt-17dpP1kr.mjs +4 -0
- package/dist/moonshine-stt-4ojLtMq7.mjs +11962 -0
- package/dist/moonshine-stt-4ojLtMq7.mjs.map +1 -0
- package/dist/{one-liner-s-lD8rCC.mjs → one-liner-JhdIPxzF.mjs} +14 -16
- package/dist/one-liner-JhdIPxzF.mjs.map +1 -0
- package/dist/repl-BDRkwPGX.mjs +9 -0
- package/dist/skills/index.d.mts +270 -320
- package/dist/skills/index.d.mts.map +1 -1
- package/dist/skills/index.mjs +5 -5
- package/dist/{skills-CD3Orlex.mjs → skills-CU694Dc8.mjs} +187 -32
- package/dist/skills-CU694Dc8.mjs.map +1 -0
- package/dist/{tools-Bi1P7Xoy.mjs → tools-DQ1mPUw5.mjs} +34 -22
- package/dist/tools-DQ1mPUw5.mjs.map +1 -0
- package/dist/types-DQBe2lFo.d.mts +165 -0
- package/dist/types-DQBe2lFo.d.mts.map +1 -0
- package/dist/{types-CiTc7ez3.d.mts → types-LlyYILII.d.mts} +112 -14
- package/dist/types-LlyYILII.d.mts.map +1 -0
- package/dist/{utils-CZBZ8dgR.mjs → utils-DKO55ZmZ.mjs} +1 -1
- package/dist/{utils-CZBZ8dgR.mjs.map → utils-DKO55ZmZ.mjs.map} +1 -1
- package/dist/vector-B0panuy6.mjs +95 -0
- package/dist/vector-B0panuy6.mjs.map +1 -0
- package/docs/PROJECT-STATE.md +321 -0
- package/docs/adding-a-model-family.md +280 -0
- package/docs/ai-sdk.md +70 -61
- package/docs/architecture/overview.md +17 -7
- package/docs/browser.md +203 -8
- package/docs/embeddings.md +156 -0
- package/docs/gerbil-site-native-migration.md +217 -0
- package/docs/gpu-engine/architectures.md +398 -0
- package/docs/gpu-engine/ir.md +372 -0
- package/docs/gpu-engine/kernels.md +718 -0
- package/docs/gpu-engine/paper.html +1759 -0
- package/docs/gpu-engine/paper.md +2109 -0
- package/docs/gpu-engine/safetensors.md +312 -0
- package/docs/gpu-engine/tokenizer.md +302 -0
- package/docs/memory-rag.md +91 -0
- package/docs/metal-safari-intel.md +190 -0
- package/docs/mobile-failure-diagnosis.md +124 -0
- package/docs/mobile.md +99 -0
- package/docs/observability.md +230 -0
- package/docs/onnx-removal-plan.md +339 -0
- package/docs/research/autoresearch-portable.md +904 -0
- package/docs/research/dispatch-reduction-hivemind.md +84 -0
- package/docs/research/ios-safari-model-caching.md +117 -0
- package/docs/research/mobile-webgpu-speed-fusion.md +135 -0
- package/docs/research/native-stt-model-selection.md +49 -0
- package/docs/research/native-tts-model-selection.md +90 -0
- package/docs/research/native-vs-chromium-decision.md +152 -0
- package/docs/research/nemotron-mamba2-inference.md +910 -0
- package/docs/research/qwen35-multimodal.md +293 -0
- package/docs/research/qwen36-gemma4-targets.md +337 -0
- package/docs/research/sota-embedding-models.md +179 -0
- package/docs/research/sota-mobile-models-2026.md +263 -0
- package/docs/research/sota-modality-models.md +202 -0
- package/docs/research/tps-baselines.md +71 -0
- package/docs/research/webgpu-m4-reference.md +104 -0
- package/docs/site-update-plan.md +155 -0
- package/docs/structured-output.md +123 -0
- package/docs/stt.md +63 -446
- package/docs/tts.md +77 -499
- package/docs/vision.md +100 -338
- package/package.json +22 -7
- package/dist/chrome-backend-CORwaIyC.mjs +0 -1212
- package/dist/chrome-backend-CORwaIyC.mjs.map +0 -1
- package/dist/chrome-backend-DIKYoWj-.mjs +0 -3
- package/dist/gerbil-CJ3ifloF.mjs +0 -4
- package/dist/gerbil-Dw4Qj77e.mjs +0 -1631
- package/dist/gerbil-Dw4Qj77e.mjs.map +0 -1
- package/dist/gerbil-qOTe1nl2.d.mts +0 -431
- package/dist/gerbil-qOTe1nl2.d.mts.map +0 -1
- package/dist/kokoro-BNTb6egA.mjs +0 -20210
- package/dist/kokoro-BNTb6egA.mjs.map +0 -1
- package/dist/kokoro-CMOGDSgT.js +0 -20212
- package/dist/kokoro-CMOGDSgT.js.map +0 -1
- package/dist/mcp-BvbriaBy.mjs.map +0 -1
- package/dist/one-liner-s-lD8rCC.mjs.map +0 -1
- package/dist/repl-DveXw36T.mjs +0 -9
- package/dist/skills-CD3Orlex.mjs.map +0 -1
- package/dist/stt-Bu-E23Sc.js +0 -433
- package/dist/stt-Bu-E23Sc.js.map +0 -1
- package/dist/stt-CpLYbGFd.mjs +0 -433
- package/dist/stt-CpLYbGFd.mjs.map +0 -1
- package/dist/stt-DRPLEEHB.mjs +0 -3
- package/dist/tools-Bi1P7Xoy.mjs.map +0 -1
- package/dist/transformers.web-DiD1gTwk.js +0 -44695
- package/dist/transformers.web-DiD1gTwk.js.map +0 -1
- package/dist/transformers.web-u34VxRFM.js +0 -3
- package/dist/tts-CqroPaSK.js +0 -724
- package/dist/tts-CqroPaSK.js.map +0 -1
- package/dist/tts-DXgsKGCe.mjs +0 -3
- package/dist/tts-DeGANMNV.mjs +0 -730
- package/dist/tts-DeGANMNV.mjs.map +0 -1
- package/dist/types-CiTc7ez3.d.mts.map +0 -1
- /package/dist/{auto-update-S9s5-g0C.mjs → auto-update-BVaLXcDE.mjs} +0 -0
- /package/dist/{chunk-CkXuGtQK.mjs → chunk-B9cbKln6.mjs} +0 -0
- /package/dist/{microphone-DaMZFRuR.mjs → microphone-Bqmoz9_K.mjs} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-CU694Dc8.mjs","names":["ctx: SkillContext<TInput>","path","fs","loaded: string[]","analysisPrompts: Record<string, string>","stylePrompts: Record<string, string>","saveWav","join","tmpdir","captionPrompts: Record<string, string>","lengthGuides: Record<string, number>","platformGuides: Record<string, string>","execSync","comparisonPrompts: Record<string, string>","focusPrompts: Record<string, string>","detailLengths: Record<string, number>","saveWav","playAudio","speak","extractionPrompts: Record<string, string>","formatInstructions: Record<string, string>","extract","headers: Record<string, string>","format: ModelInspection[\"format\"]","quantization: ModelInspection[\"quantization\"]","textOnlyBytes: number | null","skippedComponents: string[]","notes: string[]","saveWav","existsSync","textToRead: string","readFileSync","join","tmpdir","join","tmpdir","existsSync","readFileSync","text: string"],"sources":["../src/skills/registry.ts","../src/skills/loader.ts","../src/skills/builtin/analyze-screenshot.ts","../src/skills/builtin/announce.ts","../src/skills/builtin/caption-image.ts","../src/skills/builtin/commit.ts","../src/skills/builtin/compare-images.ts","../src/skills/builtin/describe-image.ts","../src/skills/builtin/explain.ts","../src/skills/builtin/extract.ts","../src/skills/builtin/extract-from-image.ts","../src/skills/builtin/inspect-model.ts","../src/skills/builtin/read-aloud.ts","../src/skills/builtin/review.ts","../src/skills/builtin/speak.ts","../src/skills/builtin/summarize.ts","../src/skills/builtin/test.ts","../src/skills/builtin/title.ts","../src/skills/builtin/transcribe.ts","../src/skills/builtin/translate.ts"],"sourcesContent":["/**\n * Skill Registry\n *\n * Central registry for all skills (built-in and custom).\n */\n\nimport type { Gerbil } from \"../core/gerbil.js\";\nimport { getInstance } from \"../core/one-liner.js\";\nimport type { Skill, SkillContext, SkillDefinition, SkillInfo } from \"./types.js\";\n\n// ============================================\n// Registry Storage\n// ============================================\n\nconst registry = new Map<string, Skill>();\nconst skillSources = new Map<string, string>(); // name -> source file\n\n// Reserved names that cannot be used for custom skills (CLI commands/views)\n// Note: Built-in skills like \"commit\", \"summarize\" ARE allowed because they\n// have dedicated CLI commands, but new skills cannot use these view names\nconst RESERVED_NAMES = new Set([\n // REPL views (would conflict with CLI shortcuts)\n \"repl\",\n \"chat\",\n \"skills\",\n \"tools\",\n \"model\",\n \"integrate\",\n \"benchmark\",\n \"info\",\n \"serve\",\n \"cache\",\n // CLI commands\n \"generate\",\n \"models\",\n \"bench\",\n // Aliases\n \"r\",\n \"c\",\n \"g\",\n // Other reserved\n \"help\",\n \"version\",\n \"gerbil\",\n]);\n\n// ============================================\n// Define Skill\n// ============================================\n\n/**\n * Define and register a skill\n *\n * @example\n * ```ts\n * const sentiment = defineSkill({\n * name: \"sentiment\",\n * description: \"Analyze sentiment of text\",\n * input: z.object({ text: z.string() }),\n * output: z.object({ sentiment: z.enum([\"positive\", \"negative\", \"neutral\"]) }),\n * async run({ input, gerbil }) {\n * return gerbil.json(`Analyze sentiment: ${input.text}`, { schema: this.output });\n * }\n * });\n * ```\n */\nexport function defineSkill<TInput, TOutput>(\n definition: SkillDefinition<TInput, TOutput>,\n): Skill<TInput, TOutput> {\n // Validate name format\n if (!/^[a-z][a-z0-9-]*$/.test(definition.name)) {\n throw new Error(`Skill name must be kebab-case starting with a letter: ${definition.name}`);\n }\n\n // Check for reserved names (CLI commands)\n if (RESERVED_NAMES.has(definition.name)) {\n throw new Error(\n `Skill name \"${definition.name}\" is reserved for CLI commands. Choose a different name.`,\n );\n }\n\n // Create the skill function\n const execute = async (input: TInput): Promise<TOutput> => skill.run(input);\n\n // Create the skill object\n const skill = Object.assign(execute, {\n definition,\n\n async run(input: TInput, gerbil?: Gerbil): Promise<TOutput> {\n // Get or create Gerbil instance\n const g = gerbil ?? (await getInstance(definition.model));\n\n // Validate input if schema provided\n let validatedInput = input;\n if (definition.input) {\n const parsed = definition.input.safeParse(input);\n if (!parsed.success) {\n throw new Error(`Invalid input for skill \"${definition.name}\": ${parsed.error.message}`);\n }\n validatedInput = parsed.data;\n }\n\n // Create context\n const ctx: SkillContext<TInput> = {\n input: validatedInput,\n gerbil: g,\n rawInput: input,\n definition: definition as SkillDefinition<TInput, unknown>,\n };\n\n // Run the skill\n const result = await definition.run.call(definition, ctx);\n\n // Validate output if schema provided\n if (definition.output && typeof result !== \"string\") {\n const parsed = definition.output.safeParse(result);\n if (!parsed.success) {\n throw new Error(\n `Invalid output from skill \"${definition.name}\": ${parsed.error.message}`,\n );\n }\n return parsed.data;\n }\n\n return result as TOutput;\n },\n }) as Skill<TInput, TOutput>;\n\n // Register the skill\n registry.set(definition.name, skill as Skill);\n\n return skill;\n}\n\n// ============================================\n// Use Skill\n// ============================================\n\n/**\n * Get a skill by name\n *\n * @example\n * ```ts\n * const sentiment = useSkill(\"sentiment\");\n * const result = await sentiment({ text: \"I love this!\" });\n * ```\n */\nexport function useSkill<TInput = unknown, TOutput = unknown>(\n name: string,\n): Skill<TInput, TOutput> {\n const skill = registry.get(name);\n if (!skill) {\n throw new Error(`Skill not found: \"${name}\". Available: ${listSkills().join(\", \") || \"none\"}`);\n }\n return skill as Skill<TInput, TOutput>;\n}\n\n// ============================================\n// Registry Operations\n// ============================================\n\n/**\n * List all registered skill names\n */\nexport function listSkills(): string[] {\n return Array.from(registry.keys()).sort();\n}\n\n/**\n * Get skill metadata\n */\nexport function getSkillInfo(name: string): SkillInfo | undefined {\n const skill = registry.get(name);\n if (!skill) {\n return;\n }\n\n return {\n name: skill.definition.name,\n description: skill.definition.description,\n version: skill.definition.version,\n author: skill.definition.author,\n builtin: !skillSources.has(name),\n source: skillSources.get(name),\n };\n}\n\n/**\n * Check if a skill exists\n */\nexport function hasSkill(name: string): boolean {\n return registry.has(name);\n}\n\n/**\n * Remove a skill from registry\n */\nexport function removeSkill(name: string): boolean {\n skillSources.delete(name);\n return registry.delete(name);\n}\n\n/**\n * Clear all skills from registry\n */\nexport function clearSkills(): void {\n registry.clear();\n skillSources.clear();\n}\n\n/**\n * Get all skill info\n */\nexport function getAllSkillInfo(): SkillInfo[] {\n return listSkills().map((name) => getSkillInfo(name)!);\n}\n\n/**\n * Check if a name is reserved (cannot be used for custom skills)\n */\nexport function isReservedName(name: string): boolean {\n return RESERVED_NAMES.has(name);\n}\n\n/**\n * Get list of reserved names\n */\nexport function getReservedNames(): string[] {\n return Array.from(RESERVED_NAMES).sort();\n}\n\n// ============================================\n// Internal: Register with source\n// ============================================\n\n/**\n * Register a skill with its source file (used by loader)\n * @internal\n */\nexport function registerSkillWithSource(skill: Skill, source: string): void {\n registry.set(skill.definition.name, skill);\n skillSources.set(skill.definition.name, source);\n}\n","/**\n * Skill Loader\n *\n * Load skills from files, directories, and packages.\n */\n\nimport { pathToFileURL } from \"node:url\";\nimport { registerSkillWithSource } from \"./registry.js\";\nimport type { LoadSkillsOptions, Skill } from \"./types.js\";\n\n// ============================================\n// Auto-Load Project Skills\n// ============================================\n\n/**\n * Load skills from the project's .gerbil/skills/ directory\n *\n * This is the standard location for project-specific skills.\n * Creates the directory structure if it doesn't exist.\n *\n * @example\n * ```ts\n * // Load from .gerbil/skills/ in current working directory\n * const loaded = await loadProjectSkills();\n * console.log(`Loaded ${loaded.length} project skills`);\n * ```\n */\nexport async function loadProjectSkills(cwd: string = process.cwd()): Promise<string[]> {\n const path = await import(\"node:path\");\n const fs = await import(\"node:fs\");\n\n const gerbilDir = path.join(cwd, \".gerbil\");\n const skillsDir = path.join(gerbilDir, \"skills\");\n\n // If .gerbil/skills doesn't exist, that's fine - just return empty\n if (!fs.existsSync(skillsDir)) {\n return [];\n }\n\n return loadSkills(skillsDir);\n}\n\n// ============================================\n// Load from Directory\n// ============================================\n\n/**\n * Load all skills from a directory\n *\n * @example\n * ```ts\n * // Load all *.skill.ts and *.skill.js files\n * const loaded = await loadSkills(\"./skills\");\n * console.log(`Loaded ${loaded.length} skills`);\n * ```\n */\nexport async function loadSkills(dir: string, options: LoadSkillsOptions = {}): Promise<string[]> {\n const { patterns = [\"*.skill.ts\", \"*.skill.js\"] } = options;\n const loaded: string[] = [];\n\n try {\n const fs = await import(\"node:fs\");\n const path = await import(\"node:path\");\n\n const resolvedDir = path.resolve(dir);\n\n if (!fs.existsSync(resolvedDir)) {\n throw new Error(`Skills directory not found: ${dir}`);\n }\n\n const files = fs.readdirSync(resolvedDir);\n\n for (const file of files) {\n const matches = patterns.some((pattern) => {\n const regex = new RegExp(`^${pattern.replace(/\\*/g, \".*\").replace(/\\./g, \"\\\\.\")}$`);\n return regex.test(file);\n });\n\n if (matches) {\n const filePath = path.join(resolvedDir, file);\n const skill = await loadSkill(filePath);\n if (skill) {\n loaded.push(skill.definition.name);\n }\n }\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"MODULE_NOT_FOUND\") {\n throw new Error(`Skills directory not found: ${dir}`);\n }\n throw error;\n }\n\n return loaded;\n}\n\n// ============================================\n// Load Single Skill\n// ============================================\n\n/**\n * Load a single skill from a file\n *\n * @example\n * ```ts\n * const skill = await loadSkill(\"./skills/sentiment.skill.ts\");\n * if (skill) {\n * const result = await skill({ text: \"Hello\" });\n * }\n * ```\n */\nexport async function loadSkill(filePath: string): Promise<Skill | null> {\n try {\n const path = await import(\"node:path\");\n const resolvedPath = path.resolve(filePath);\n\n // Use dynamic import with file URL for ESM compatibility\n const fileUrl = pathToFileURL(resolvedPath).href;\n const module = await import(fileUrl);\n\n // Get the default export\n const skill = module.default as Skill;\n\n if (!skill?.definition) {\n return null;\n }\n\n // Register with source tracking\n registerSkillWithSource(skill, resolvedPath);\n\n return skill;\n } catch (_error) {\n return null;\n }\n}\n\n// ============================================\n// Load from Package\n// ============================================\n\n/**\n * Load skills from an npm package\n *\n * @example\n * ```ts\n * // Load skills from a package\n * const loaded = await loadSkillPackage(\"gerbil-skills-extra\");\n * ```\n */\nexport async function loadSkillPackage(packageName: string): Promise<string[]> {\n try {\n const module = await import(packageName);\n const loaded: string[] = [];\n\n // Look for exported skills\n for (const [_key, value] of Object.entries(module)) {\n if (isSkill(value)) {\n const skill = value as Skill;\n registerSkillWithSource(skill, `npm:${packageName}`);\n loaded.push(skill.definition.name);\n }\n }\n\n // Also check default export if it's an object of skills\n if (module.default && typeof module.default === \"object\") {\n for (const [_key, value] of Object.entries(module.default)) {\n if (isSkill(value)) {\n const skill = value as Skill;\n registerSkillWithSource(skill, `npm:${packageName}`);\n loaded.push(skill.definition.name);\n }\n }\n }\n\n return loaded;\n } catch (error) {\n throw new Error(`Failed to load skill package \"${packageName}\": ${error}`);\n }\n}\n\n// ============================================\n// Helpers\n// ============================================\n\n/**\n * Check if a value is a Skill\n */\nfunction isSkill(value: unknown): value is Skill {\n return (\n typeof value === \"function\" &&\n typeof (value as Skill).definition === \"object\" &&\n typeof (value as Skill).definition.name === \"string\" &&\n typeof (value as Skill).definition.run === \"function\"\n );\n}\n","/**\n * Analyze Screenshot Skill\n *\n * Analyze a UI screenshot for design, accessibility, or QA purposes.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst AnalyzeScreenshotInput = z.object({\n /** Screenshot URL or data URI */\n image: z.string(),\n\n /** Analysis type */\n type: z\n .enum([\"ui-review\", \"accessibility\", \"suggestions\", \"qa\", \"ux-audit\", \"mobile-check\"])\n .default(\"ui-review\"),\n\n /** Specific areas to focus on (optional) */\n focus: z.array(z.string()).optional(),\n});\n\nexport type AnalyzeScreenshotInput = z.infer<typeof AnalyzeScreenshotInput>;\n\nconst analysisPrompts: Record<string, string> = {\n \"ui-review\": `Review this UI screenshot as a design expert. Analyze:\n- Visual hierarchy and layout\n- Typography and readability\n- Color scheme and contrast\n- Spacing and alignment\n- Component consistency\n- Overall design quality\n\nProvide specific observations and suggestions.`,\n\n accessibility: `Analyze this screenshot for accessibility issues. Check for:\n- Color contrast ratios\n- Text size and readability\n- Touch target sizes\n- Visual affordances for interactive elements\n- Potential issues for users with visual impairments\n- Missing alt text indicators\n\nList specific issues found and how to fix them.`,\n\n suggestions: `As a senior UX designer, review this UI and suggest improvements:\n- Modern design patterns that could be applied\n- Usability improvements\n- Visual polish opportunities\n- User experience enhancements\n- Ways to make it more engaging\n\nBe specific and actionable.`,\n\n qa: `Perform QA analysis on this screenshot. Look for:\n- Visual bugs or glitches\n- Alignment and spacing issues\n- Broken or missing elements\n- Inconsistencies with design standards\n- Text overflow or truncation issues\n- Responsive design problems\n\nReport each issue with its location and severity.`,\n\n \"ux-audit\": `Conduct a UX audit of this interface:\n- User flow clarity\n- Call-to-action visibility\n- Information architecture\n- Cognitive load assessment\n- Error prevention\n- User feedback mechanisms\n\nProvide a structured audit report.`,\n\n \"mobile-check\": `Evaluate this UI for mobile usability:\n- Touch target sizes (minimum 44x44px)\n- Thumb-zone accessibility\n- Content priority on small screens\n- Gesture affordances\n- Loading indicators\n- Mobile-specific patterns\n\nIdentify mobile-specific issues and recommendations.`,\n};\n\nexport const analyzeScreenshot = defineSkill({\n name: \"analyze-screenshot\",\n description: \"Analyze a UI screenshot for design, accessibility, or QA\",\n version: \"1.0.0\",\n model: \"ministral-3b\",\n input: AnalyzeScreenshotInput,\n maxTokens: 1200,\n temperature: 0.3,\n\n async run({ input, gerbil }) {\n const { image, type = \"ui-review\", focus } = input;\n\n if (!gerbil.supportsVision()) {\n throw new Error(\n `Current model doesn't support vision. Load a vision model like \"ministral-3b\" first.`,\n );\n }\n\n let prompt = analysisPrompts[type];\n\n if (focus && focus.length > 0) {\n prompt += `\\n\\nPay special attention to: ${focus.join(\", \")}.`;\n }\n\n const result = await gerbil.generate(prompt, {\n images: [{ source: image }],\n maxTokens: this.maxTokens,\n temperature: this.temperature,\n });\n\n return result.text;\n },\n});\n","/**\n * Announce Skill\n *\n * Generate and speak an announcement using AI.\n * Useful for scripts that need to give voice updates.\n */\n\nimport { execSync } from \"child_process\";\nimport { unlinkSync, writeFileSync } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst AnnounceInput = z.object({\n /** What to announce (will be rephrased by AI) */\n message: z.string(),\n\n /** Announcement style */\n style: z.enum([\"casual\", \"formal\", \"excited\", \"calm\", \"urgent\"]).default(\"casual\"),\n\n /** Voice ID */\n voice: z\n .enum([\"af_heart\", \"af_bella\", \"af_nicole\", \"am_fenrir\", \"am_michael\", \"bf_emma\", \"bm_george\"])\n .default(\"af_heart\"),\n\n /** Speech speed */\n speed: z.number().min(0.5).max(2.0).default(1.0),\n\n /** Just generate text, don't speak */\n textOnly: z.boolean().default(false),\n});\n\nexport type AnnounceInput = z.infer<typeof AnnounceInput>;\n\nconst stylePrompts: Record<string, string> = {\n casual: \"Rephrase this as a casual, friendly announcement. Keep it natural and conversational.\",\n formal: \"Rephrase this as a professional, formal announcement. Be clear and dignified.\",\n excited: \"Rephrase this as an excited, enthusiastic announcement! Add energy and positivity.\",\n calm: \"Rephrase this as a calm, soothing announcement. Be gentle and reassuring.\",\n urgent: \"Rephrase this as an urgent announcement. Be direct and emphasize importance.\",\n};\n\nfunction saveWav(filename: string, audio: Float32Array, sampleRate: number): void {\n const buffer = Buffer.alloc(44 + audio.length * 2);\n buffer.write(\"RIFF\", 0);\n buffer.writeUInt32LE(36 + audio.length * 2, 4);\n buffer.write(\"WAVE\", 8);\n buffer.write(\"fmt \", 12);\n buffer.writeUInt32LE(16, 16);\n buffer.writeUInt16LE(1, 20);\n buffer.writeUInt16LE(1, 22);\n buffer.writeUInt32LE(sampleRate, 24);\n buffer.writeUInt32LE(sampleRate * 2, 28);\n buffer.writeUInt16LE(2, 32);\n buffer.writeUInt16LE(16, 34);\n buffer.write(\"data\", 36);\n buffer.writeUInt32LE(audio.length * 2, 40);\n\n for (let i = 0; i < audio.length; i++) {\n const s = Math.max(-1, Math.min(1, audio[i]));\n buffer.writeInt16LE(Math.round(s * 32767), 44 + i * 2);\n }\n\n writeFileSync(filename, buffer);\n}\n\nexport const announce = defineSkill({\n name: \"announce\",\n description: \"Generate and speak an AI-crafted announcement\",\n version: \"1.0.0\",\n input: AnnounceInput,\n temperature: 0.7,\n maxTokens: 150,\n\n async run({ input, gerbil }) {\n const { message, style = \"casual\", voice = \"af_heart\", speed = 1.0, textOnly = false } = input;\n\n // Generate announcement text using AI\n const result = await gerbil.generate(message, {\n system: `${stylePrompts[style]}\nKeep it brief (1-2 sentences max). \nOutput only the announcement text, nothing else.`,\n temperature: this.temperature,\n maxTokens: this.maxTokens,\n });\n\n const announcementText = result.text.trim();\n\n if (textOnly) {\n return announcementText;\n }\n\n // Speak the announcement\n const speechResult = await gerbil.speak(announcementText, { voice, speed });\n\n // Play audio\n const tempFile = join(tmpdir(), `gerbil-announce-${Date.now()}.wav`);\n saveWav(tempFile, speechResult.audio, speechResult.sampleRate);\n\n try {\n const platform = process.platform;\n if (platform === \"darwin\") {\n execSync(`afplay \"${tempFile}\"`, { stdio: \"inherit\" });\n } else if (platform === \"linux\") {\n try {\n execSync(`aplay \"${tempFile}\"`, { stdio: \"inherit\" });\n } catch {\n execSync(`paplay \"${tempFile}\"`, { stdio: \"inherit\" });\n }\n } else if (platform === \"win32\") {\n execSync(`powershell -c \"(New-Object Media.SoundPlayer '${tempFile}').PlaySync()\"`, {\n stdio: \"inherit\",\n });\n }\n } finally {\n try {\n unlinkSync(tempFile);\n } catch {\n // Ignore\n }\n }\n\n return announcementText;\n },\n});\n","/**\n * Caption Image Skill\n *\n * Generate captions, alt text, or social media descriptions for images.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst CaptionImageInput = z.object({\n /** Image URL or data URI */\n image: z.string(),\n\n /** Caption type */\n type: z\n .enum([\"alt-text\", \"caption\", \"social-media\", \"seo\", \"artistic\", \"technical\"])\n .default(\"caption\"),\n\n /** Tone/style for the caption */\n tone: z\n .enum([\"professional\", \"casual\", \"playful\", \"formal\", \"descriptive\"])\n .default(\"professional\"),\n\n /** Maximum length hint */\n maxLength: z.enum([\"short\", \"medium\", \"long\"]).default(\"medium\"),\n\n /** Platform hint for social media captions */\n platform: z.enum([\"twitter\", \"instagram\", \"linkedin\", \"facebook\"]).optional(),\n});\n\nexport type CaptionImageInput = z.infer<typeof CaptionImageInput>;\n\nconst captionPrompts: Record<string, string> = {\n \"alt-text\": `Generate accessible alt text for this image.\n- Describe the essential content concisely\n- Include relevant details for screen reader users\n- Avoid starting with \"Image of\" or \"Picture of\"\n- Be factual and objective`,\n\n caption: `Write a caption for this image.\n- Capture the essence of the image\n- Make it engaging and informative\n- Consider the context and mood`,\n\n \"social-media\": `Create a social media caption for this image.\n- Make it engaging and shareable\n- Include relevant emoji where appropriate\n- Suggest hashtags if applicable\n- Optimize for engagement`,\n\n seo: `Write SEO-optimized alt text and description for this image.\n- Include relevant keywords naturally\n- Be descriptive but concise\n- Focus on searchable terms\n- Maintain readability`,\n\n artistic: `Write an artistic, evocative caption for this image.\n- Capture the mood and emotion\n- Use creative language\n- Tell a micro-story if appropriate\n- Be memorable and unique`,\n\n technical: `Write a technical description of this image.\n- Describe components and elements precisely\n- Use appropriate technical terminology\n- Note measurements or specifications if visible\n- Be objective and detailed`,\n};\n\nconst lengthGuides: Record<string, number> = {\n short: 100,\n medium: 200,\n long: 400,\n};\n\nconst platformGuides: Record<string, string> = {\n twitter: \"Keep under 280 characters. Make it punchy and tweetable.\",\n instagram: \"Include relevant hashtags. Can be longer and more storytelling.\",\n linkedin: \"Keep it professional. Focus on value and insights.\",\n facebook: \"Can be conversational. Ask questions to encourage engagement.\",\n};\n\nexport const captionImage = defineSkill({\n name: \"caption-image\",\n description: \"Generate captions, alt text, or social media descriptions for images\",\n version: \"1.0.0\",\n model: \"ministral-3b\",\n input: CaptionImageInput,\n temperature: 0.7,\n\n async run({ input, gerbil }) {\n const {\n image,\n type = \"caption\",\n tone = \"professional\",\n maxLength = \"medium\",\n platform,\n } = input;\n\n if (!gerbil.supportsVision()) {\n throw new Error(\n `Current model doesn't support vision. Load a vision model like \"ministral-3b\" first.`,\n );\n }\n\n let prompt = captionPrompts[type];\n prompt += `\\n\\nTone: ${tone}`;\n\n if (platform && type === \"social-media\") {\n prompt += `\\n\\nPlatform: ${platform}. ${platformGuides[platform]}`;\n }\n\n const result = await gerbil.generate(prompt, {\n images: [{ source: image }],\n maxTokens: lengthGuides[maxLength],\n temperature: this.temperature,\n });\n\n return result.text;\n },\n});\n","/**\n * Commit Skill\n *\n * Generate git commit messages from staged changes.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst CommitInput = z.object({\n /** Git diff (auto-detected if not provided) */\n diff: z.string().optional(),\n\n /** Commit style */\n type: z.enum([\"conventional\", \"simple\", \"detailed\"]).default(\"conventional\"),\n\n /** Max length for commit message */\n maxLength: z.number().default(72),\n});\n\nexport type CommitInput = z.infer<typeof CommitInput>;\n\nasync function getGitDiff(): Promise<string> {\n try {\n const { execSync } = await import(\"node:child_process\");\n return execSync(\"git diff --staged\", { encoding: \"utf-8\" });\n } catch {\n return \"\";\n }\n}\n\nfunction getSystemPrompt(type: CommitInput[\"type\"]): string {\n switch (type) {\n case \"conventional\":\n return `Generate a git commit message following the Conventional Commits format.\nUse one of these types: feat, fix, docs, style, refactor, perf, test, chore.\nFormat: type(scope): description\nKeep it under 72 characters.\nNo period at the end.\nOnly output the commit message, nothing else.`;\n\n case \"detailed\":\n return `Generate a detailed git commit message with a subject line and body.\nSubject: under 72 chars, imperative mood\nBody: explain what and why\nOnly output the commit message, nothing else.`;\n\n default:\n return `Generate a concise git commit message.\nUse imperative mood (e.g., \"Add\", \"Fix\", \"Update\").\nKeep it under 72 characters.\nNo period at the end.\nOnly output the commit message, nothing else.`;\n }\n}\n\nexport const commit = defineSkill({\n name: \"commit\",\n description: \"Generate a git commit message from staged changes\",\n version: \"1.0.0\",\n input: CommitInput,\n temperature: 0.3,\n maxTokens: 100,\n\n async run({ input, gerbil }) {\n const { diff, type = \"conventional\", maxLength = 72 } = input;\n\n // Get diff from git if not provided\n const actualDiff = diff || (await getGitDiff());\n\n if (!actualDiff || actualDiff.trim().length === 0) {\n throw new Error(\"No changes staged. Run `git add` first.\");\n }\n\n const result = await gerbil.generate(\n `Generate a commit message for the following diff:\\n\\n${actualDiff}`,\n {\n system: getSystemPrompt(type),\n maxTokens: this.maxTokens,\n temperature: this.temperature,\n },\n );\n\n // Clean and truncate\n let message = result.text.trim();\n message = message.replace(/<think>[\\s\\S]*?<\\/think>/g, \"\").trim(); // Remove think tags\n message = message.replace(/<\\/?think>/g, \"\").trim(); // Remove unclosed tags\n message = message.replace(/^[\"']|[\"']$/g, \"\"); // Remove quotes\n message = message.split(\"\\n\")[0]; // First line only\n if (message.length > maxLength) {\n message = `${message.substring(0, maxLength - 3)}...`;\n }\n\n return message;\n },\n});\n","/**\n * Compare Images Skill\n *\n * Compare two images and describe their differences.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst CompareImagesInput = z.object({\n /** First image URL or data URI */\n image1: z.string(),\n\n /** Second image URL or data URI */\n image2: z.string(),\n\n /** Comparison type */\n type: z\n .enum([\"visual-diff\", \"design-comparison\", \"before-after\", \"a-b-test\", \"version-diff\"])\n .default(\"visual-diff\"),\n\n /** Specific aspects to compare */\n focus: z.array(z.string()).optional(),\n});\n\nexport type CompareImagesInput = z.infer<typeof CompareImagesInput>;\n\nconst comparisonPrompts: Record<string, string> = {\n \"visual-diff\": `Compare these two images and identify all visual differences.\n- List specific elements that differ\n- Note position, color, size, and content changes\n- Identify additions and removals\n- Rate the significance of each change`,\n\n \"design-comparison\": `Compare these two designs as a design expert.\n- Analyze layout differences\n- Compare typography and colors\n- Evaluate which design is more effective\n- Suggest which elements work better in each`,\n\n \"before-after\": `Analyze these before and after images.\n- Describe what changed\n- Evaluate if the changes are improvements\n- Note any unintended consequences\n- Summarize the overall transformation`,\n\n \"a-b-test\": `Analyze these two variants for A/B testing purposes.\n- Identify the key differences being tested\n- Predict which might perform better and why\n- Note potential user experience impacts\n- Suggest what metrics to measure`,\n\n \"version-diff\": `Compare these two versions of the UI.\n- Document all changes between versions\n- Categorize changes (bug fix, feature, style)\n- Identify breaking changes\n- Note any regressions`,\n};\n\nexport const compareImages = defineSkill({\n name: \"compare-images\",\n description: \"Compare two images and describe their differences\",\n version: \"1.0.0\",\n model: \"ministral-3b\",\n input: CompareImagesInput,\n maxTokens: 1500,\n temperature: 0.3,\n\n async run({ input, gerbil }) {\n const { image1, image2, type = \"visual-diff\", focus } = input;\n\n if (!gerbil.supportsVision()) {\n throw new Error(\n `Current model doesn't support vision. Load a vision model like \"ministral-3b\" first.`,\n );\n }\n\n let prompt = `I'm showing you two images for comparison.\\n\\n${comparisonPrompts[type]}`;\n\n if (focus && focus.length > 0) {\n prompt += `\\n\\nFocus specifically on: ${focus.join(\", \")}.`;\n }\n\n prompt += \"\\n\\nThe first image is shown first, followed by the second image.\";\n\n const result = await gerbil.generate(prompt, {\n images: [{ source: image1 }, { source: image2 }],\n maxTokens: this.maxTokens,\n temperature: this.temperature,\n });\n\n return result.text;\n },\n});\n","/**\n * Describe Image Skill\n *\n * Describe an image using vision AI.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst DescribeImageInput = z.object({\n /** Image URL or data URI */\n image: z.string(),\n\n /** What to focus on */\n focus: z.enum([\"general\", \"details\", \"text\", \"objects\", \"scene\", \"colors\"]).default(\"general\"),\n\n /** Output format */\n format: z.enum([\"paragraph\", \"bullets\", \"structured\"]).default(\"paragraph\"),\n\n /** Maximum detail level */\n detail: z.enum([\"brief\", \"normal\", \"comprehensive\"]).default(\"normal\"),\n});\n\nexport type DescribeImageInput = z.infer<typeof DescribeImageInput>;\n\nconst focusPrompts: Record<string, string> = {\n general:\n \"Describe this image comprehensively, covering the main subject, context, and notable elements.\",\n details:\n \"Describe this image in detail, including colors, textures, lighting, and small elements.\",\n text: \"Extract and describe any text visible in this image. Include the text content and its context.\",\n objects:\n \"List and describe all objects you can identify in this image, including their positions.\",\n scene: \"Describe the scene, setting, and atmosphere of this image. What story does it tell?\",\n colors: \"Analyze the color palette and visual composition of this image.\",\n};\n\nconst detailLengths: Record<string, number> = {\n brief: 150,\n normal: 400,\n comprehensive: 800,\n};\n\nexport const describeImage = defineSkill({\n name: \"describe-image\",\n description: \"Describe an image using vision AI\",\n version: \"1.0.0\",\n model: \"ministral-3b\",\n input: DescribeImageInput,\n temperature: 0.5,\n\n async run({ input, gerbil }) {\n const { image, focus = \"general\", format = \"paragraph\", detail = \"normal\" } = input;\n\n // Check if model supports vision\n if (!gerbil.supportsVision()) {\n throw new Error(\n `Current model doesn't support vision. Load a vision model like \"ministral-3b\" first.`,\n );\n }\n\n const formatInstructions: Record<string, string> = {\n paragraph: \"Write your description as natural flowing paragraphs.\",\n bullets: \"Format your description as clear bullet points.\",\n structured:\n \"Structure your description with sections: Overview, Main Elements, Details, Observations.\",\n };\n\n const prompt = `${focusPrompts[focus]}\\n\\n${formatInstructions[format]}`;\n\n const result = await gerbil.generate(prompt, {\n images: [{ source: image }],\n maxTokens: detailLengths[detail],\n temperature: this.temperature,\n });\n\n return result.text;\n },\n});\n","/**\n * Explain Skill\n *\n * Explain code or concepts at various levels.\n * Optionally speaks the explanation aloud.\n */\n\nimport { execSync } from \"node:child_process\";\nimport { unlinkSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst ExplainInput = z.object({\n /** Content to explain */\n content: z.string(),\n\n /** Explanation level */\n level: z.enum([\"beginner\", \"intermediate\", \"expert\"]).default(\"intermediate\"),\n\n /** Programming language (for code) */\n language: z.string().optional(),\n\n /** Speak the explanation aloud using TTS */\n speak: z.boolean().default(false),\n\n /** Voice for TTS (if speak is true) */\n voice: z.enum([\"af_heart\", \"af_bella\", \"bf_emma\", \"am_fenrir\"]).default(\"af_heart\"),\n});\n\nexport type ExplainInput = z.infer<typeof ExplainInput>;\n\nconst levelGuide = {\n beginner: \"Explain like I'm new to programming. Use simple terms and analogies.\",\n intermediate: \"Explain for someone with programming experience.\",\n expert: \"Explain with technical depth, including implementation details.\",\n};\n\nfunction saveWav(filename: string, audio: Float32Array, sampleRate: number): void {\n const buffer = Buffer.alloc(44 + audio.length * 2);\n buffer.write(\"RIFF\", 0);\n buffer.writeUInt32LE(36 + audio.length * 2, 4);\n buffer.write(\"WAVE\", 8);\n buffer.write(\"fmt \", 12);\n buffer.writeUInt32LE(16, 16);\n buffer.writeUInt16LE(1, 20);\n buffer.writeUInt16LE(1, 22);\n buffer.writeUInt32LE(sampleRate, 24);\n buffer.writeUInt32LE(sampleRate * 2, 28);\n buffer.writeUInt16LE(2, 32);\n buffer.writeUInt16LE(16, 34);\n buffer.write(\"data\", 36);\n buffer.writeUInt32LE(audio.length * 2, 40);\n\n for (let i = 0; i < audio.length; i++) {\n const s = Math.max(-1, Math.min(1, audio[i]));\n buffer.writeInt16LE(Math.round(s * 32767), 44 + i * 2);\n }\n\n writeFileSync(filename, buffer);\n}\n\nfunction playAudio(audioFile: string): void {\n const platform = process.platform;\n if (platform === \"darwin\") {\n execSync(`afplay \"${audioFile}\"`, { stdio: \"inherit\" });\n } else if (platform === \"linux\") {\n try {\n execSync(`aplay \"${audioFile}\"`, { stdio: \"inherit\" });\n } catch {\n execSync(`paplay \"${audioFile}\"`, { stdio: \"inherit\" });\n }\n } else if (platform === \"win32\") {\n execSync(`powershell -c \"(New-Object Media.SoundPlayer '${audioFile}').PlaySync()\"`, {\n stdio: \"inherit\",\n });\n }\n}\n\nexport const explain = defineSkill({\n name: \"explain\",\n description: \"Explain code or concepts at various levels (optionally speak aloud)\",\n version: \"1.0.0\",\n input: ExplainInput,\n temperature: 0.5,\n maxTokens: 500,\n\n async run({ input, gerbil }) {\n const { content, level = \"intermediate\", language, speak = false, voice = \"af_heart\" } = input;\n\n let systemPrompt = `You are a patient teacher.\n${levelGuide[level]}`;\n\n if (language) {\n systemPrompt += `\\nThis is ${language} code.`;\n }\n\n systemPrompt += \"\\nBe clear and concise.\";\n\n const result = await gerbil.generate(`Explain this:\\n\\n${content}`, {\n system: systemPrompt,\n maxTokens: this.maxTokens,\n temperature: this.temperature,\n });\n\n const explanation = result.text;\n\n // Optionally speak the explanation\n if (speak) {\n // Split into sentences for smoother playback\n const sentences = explanation.split(/(?<=[.!?])\\s+/).filter((s) => s.trim());\n\n for (const sentence of sentences) {\n if (!sentence.trim()) continue;\n\n const speechResult = await gerbil.speak(sentence, { voice });\n const tempFile = join(tmpdir(), `gerbil-explain-${Date.now()}.wav`);\n saveWav(tempFile, speechResult.audio, speechResult.sampleRate);\n\n try {\n playAudio(tempFile);\n } finally {\n try {\n unlinkSync(tempFile);\n } catch {\n // Ignore\n }\n }\n }\n }\n\n return explanation;\n },\n});\n","/**\n * Extract Skill\n *\n * Extract structured data from content.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst ExtractInput = z.object({\n /** Content to extract from */\n content: z.string(),\n\n /** Zod schema for extraction (passed at runtime) */\n schema: z.any(),\n\n /** Additional context */\n context: z.string().optional(),\n});\n\nexport type ExtractInput = z.infer<typeof ExtractInput>;\n\nexport const extract = defineSkill({\n name: \"extract\",\n description: \"Extract structured data from content\",\n version: \"1.0.0\",\n input: ExtractInput,\n temperature: 0.3,\n\n async run({ input, gerbil }) {\n const { content, schema, context } = input;\n\n let prompt = \"Extract structured data from the following content.\";\n\n if (context) {\n prompt += `\\nContext: ${context}`;\n }\n\n prompt += `\\n\\nContent:\\n${content}`;\n\n return gerbil.json(prompt, { schema });\n },\n});\n","/**\n * Extract from Image Skill\n *\n * Extract text, code, data, or structured information from images.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst ExtractFromImageInput = z.object({\n /** Image URL or data URI */\n image: z.string(),\n\n /** What to extract */\n extract: z.enum([\"text\", \"code\", \"data\", \"table\", \"diagram\", \"form\", \"receipt\"]).default(\"text\"),\n\n /** Output format */\n outputFormat: z.enum([\"raw\", \"json\", \"markdown\", \"csv\"]).default(\"raw\"),\n\n /** Language hint for code extraction */\n language: z.string().optional(),\n});\n\nexport type ExtractFromImageInput = z.infer<typeof ExtractFromImageInput>;\n\nconst extractionPrompts: Record<string, string> = {\n text: `Extract all visible text from this image.\n- Preserve the original formatting and structure as much as possible\n- Include headings, paragraphs, and any labels\n- Note any text that's unclear or partially visible\n- Maintain the reading order`,\n\n code: `Extract the code visible in this image.\n- Preserve exact syntax, indentation, and formatting\n- Include comments if visible\n- Note any parts that are unclear\n- Format as a proper code block`,\n\n data: `Extract all data, numbers, and structured information from this image.\n- Include labels and their associated values\n- Preserve numerical precision\n- Note units and currencies\n- Identify any patterns or relationships`,\n\n table: `Extract the table data from this image.\n- Identify all columns and rows\n- Preserve cell alignment where meaningful\n- Handle merged cells appropriately\n- Include headers and any totals`,\n\n diagram: `Describe and extract information from this diagram or flowchart.\n- List all nodes/boxes and their labels\n- Describe connections and their directions\n- Note any annotations or legends\n- Explain the flow or relationships`,\n\n form: `Extract form fields and their values from this image.\n- List each field label and its value\n- Note required fields if indicated\n- Include dropdown selections\n- Preserve the form structure`,\n\n receipt: `Extract receipt/invoice information from this image.\n- Vendor/store name\n- Date and time\n- Line items with quantities and prices\n- Subtotals, taxes, and total\n- Payment method if shown`,\n};\n\nconst formatInstructions: Record<string, string> = {\n raw: \"Output the extracted content as plain text.\",\n json: \"Output the extracted content as valid JSON with appropriate structure.\",\n markdown: \"Format the output as Markdown with proper headings and formatting.\",\n csv: \"Output tabular data in CSV format with proper quoting.\",\n};\n\nexport const extractFromImage = defineSkill({\n name: \"extract-from-image\",\n description: \"Extract text, code, tables, or data from images\",\n version: \"1.0.0\",\n model: \"ministral-3b\",\n input: ExtractFromImageInput,\n maxTokens: 2000,\n temperature: 0.1, // Low temp for accuracy\n\n async run({ input, gerbil }) {\n const { image, extract = \"text\", outputFormat = \"raw\", language } = input;\n\n if (!gerbil.supportsVision()) {\n throw new Error(\n `Current model doesn't support vision. Load a vision model like \"ministral-3b\" first.`,\n );\n }\n\n let prompt = extractionPrompts[extract];\n\n if (language && extract === \"code\") {\n prompt += `\\n\\nThe code appears to be ${language}.`;\n }\n\n prompt += `\\n\\n${formatInstructions[outputFormat]}`;\n\n const result = await gerbil.generate(prompt, {\n images: [{ source: image }],\n maxTokens: this.maxTokens,\n temperature: this.temperature,\n });\n\n return result.text;\n },\n});\n","/**\n * Inspect Model Skill\n *\n * Inspects a HuggingFace model repo to determine its quantization format,\n * architecture compatibility, and estimated download size for Gerbil's\n * native WebGPU engine.\n *\n * Supports: MLX 4-bit (affine), GPTQ, F32/F16/BF16 models.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst InspectModelInput = z.object({\n /** HuggingFace repo ID (e.g. \"mlx-community/Qwen3.5-0.8B-4bit\") */\n repo: z.string(),\n\n /** HF revision/branch (default: \"main\") */\n revision: z.string().default(\"main\"),\n\n /** HF API token for gated models */\n token: z.string().optional(),\n});\n\nexport type InspectModelInput = z.infer<typeof InspectModelInput>;\n\ninterface ModelInspection {\n repo: string;\n architecture: string;\n supported: boolean;\n format: \"mlx-4bit\" | \"gptq\" | \"float\" | \"unknown\";\n quantization: {\n method: string;\n bits: number;\n groupSize: number;\n mode?: string;\n } | null;\n textConfig: {\n vocabSize: number;\n hiddenSize: number;\n numLayers: number;\n numHeads: number;\n intermediateSize: number;\n tiedEmbeddings: boolean;\n } | null;\n download: {\n totalBytes: number;\n totalMB: string;\n textOnlyBytes: number | null;\n textOnlyMB: string | null;\n skippedComponents: string[];\n };\n adapter: string;\n notes: string[];\n}\n\nconst SUPPORTED_ARCHITECTURES = [\n \"Qwen2ForCausalLM\",\n \"Qwen3ForCausalLM\",\n \"Qwen3_5ForConditionalGeneration\",\n];\n\nexport const inspectModel = defineSkill({\n name: \"inspect-model\",\n description: \"Inspect a HuggingFace model for Gerbil WebGPU engine compatibility\",\n version: \"1.0.0\",\n input: InspectModelInput,\n\n async run({ input }): Promise<ModelInspection> {\n const { repo, revision = \"main\", token } = input;\n const baseURL = `https://huggingface.co/${repo}/resolve/${revision}`;\n const headers: Record<string, string> = {};\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n\n // Fetch config.json\n const configRes = await fetch(`${baseURL}/config.json`, { headers });\n if (!configRes.ok) {\n throw new Error(`Failed to fetch config.json from ${repo}: ${configRes.status}`);\n }\n const config = (await configRes.json()) as Record<string, unknown>;\n\n const architectureName = ((config.architectures as string[]) ?? [])[0] ?? \"unknown\";\n const supported = SUPPORTED_ARCHITECTURES.includes(architectureName);\n\n // Detect quantization format\n const quantConfig = config.quantization_config as Record<string, unknown> | undefined;\n const isGPTQ = quantConfig?.quant_method === \"gptq\";\n const isMLX = !isGPTQ && quantConfig?.bits === 4 && (quantConfig?.mode as string) === \"affine\";\n\n let format: ModelInspection[\"format\"] = \"unknown\";\n let adapter = \"none\";\n let quantization: ModelInspection[\"quantization\"] = null;\n\n if (isMLX) {\n format = \"mlx-4bit\";\n adapter = \"mlx-adapter (repackMLX)\";\n quantization = {\n method: \"mlx\",\n bits: (quantConfig!.bits as number) ?? 4,\n groupSize: (quantConfig!.group_size as number) ?? 64,\n mode: quantConfig!.mode as string,\n };\n } else if (isGPTQ) {\n format = \"gptq\";\n adapter = \"gptq-adapter (repackGPTQ)\";\n quantization = {\n method: \"gptq\",\n bits: (quantConfig!.bits as number) ?? 4,\n groupSize: (quantConfig!.group_size as number) ?? 128,\n };\n } else if (quantConfig) {\n format = \"unknown\";\n adapter = \"unsupported — needs new adapter\";\n quantization = {\n method: (quantConfig.quant_method as string) ?? \"unknown\",\n bits: (quantConfig.bits as number) ?? 0,\n groupSize: (quantConfig.group_size as number) ?? 0,\n };\n } else {\n format = \"float\";\n adapter = \"none (direct F32/F16/BF16 load, on-the-fly Q4 optional)\";\n }\n\n // Extract text config\n const textCfg = (config.text_config as Record<string, unknown>) ?? config;\n const textConfig = {\n vocabSize: (textCfg.vocab_size as number) ?? 0,\n hiddenSize: (textCfg.hidden_size as number) ?? 0,\n numLayers: (textCfg.num_hidden_layers as number) ?? 0,\n numHeads: (textCfg.num_attention_heads as number) ?? 0,\n intermediateSize: (textCfg.intermediate_size as number) ?? 0,\n tiedEmbeddings:\n (textCfg.tie_word_embeddings as boolean) ??\n (config.tie_word_embeddings as boolean) ??\n false,\n };\n\n // Fetch weight index to estimate sizes\n let totalBytes = 0;\n let textOnlyBytes: number | null = null;\n const skippedComponents: string[] = [];\n const notes: string[] = [];\n\n try {\n const indexRes = await fetch(`${baseURL}/model.safetensors.index.json`, { headers });\n if (indexRes.ok) {\n const index = (await indexRes.json()) as {\n metadata?: { total_size?: number };\n weight_map?: Record<string, string>;\n };\n totalBytes = index.metadata?.total_size ?? 0;\n\n if (index.weight_map) {\n // Estimate text-only size by filtering known non-text prefixes\n const skipPrefixes = [\"model.visual.\", \"vision_tower.\", \"mtp.\", \"visual.\"];\n let skippedBytes = 0;\n const allKeys = Object.keys(index.weight_map);\n const skippedKeys = allKeys.filter((k) => skipPrefixes.some((p) => k.startsWith(p)));\n\n if (skippedKeys.length > 0) {\n skippedComponents.push(\n ...new Set(\n skippedKeys.map((k) => {\n const prefix = skipPrefixes.find((p) => k.startsWith(p));\n return prefix?.replace(/\\.$/, \"\") ?? k;\n }),\n ),\n );\n // Rough estimate: assume skipped tensors are proportional\n // (Exact byte counting would need header parsing)\n const skipRatio = skippedKeys.length / allKeys.length;\n skippedBytes = Math.round(totalBytes * skipRatio);\n textOnlyBytes = totalBytes - skippedBytes;\n }\n }\n } else {\n // Single file model\n const headRes = await fetch(`${baseURL}/model.safetensors`, {\n method: \"HEAD\",\n headers,\n });\n if (headRes.ok) {\n totalBytes = Number(headRes.headers.get(\"content-length\") || 0);\n }\n }\n } catch {\n notes.push(\"Could not fetch weight index — download size unknown\");\n }\n\n // Add format-specific notes\n if (isMLX) {\n notes.push(\n `MLX affine quantization: w = scale * nibble + bias → Gerbil: (nibble - zero) * scale`,\n );\n notes.push(\n `Group size ${quantization!.groupSize}: ${Math.ceil((textConfig.vocabSize * textConfig.hiddenSize) / quantization!.groupSize)} embedding groups`,\n );\n if (architectureName === \"Qwen3_5ForConditionalGeneration\") {\n notes.push(\"MLX norms already absorb (1+weight) offset — no +1 applied by loader\");\n notes.push(\"Fused q_proj will be deinterleaved for full attention layers\");\n }\n }\n\n if (isGPTQ) {\n notes.push(\"GPTQ packing [K/8, N] needs nibble transpose → Gerbil flat [N*K/8]\");\n notes.push(\"Stored qzeros = actual_zero - 1 (standard GPTQ convention)\");\n if (!textConfig.tiedEmbeddings) {\n notes.push(\"Embeddings NOT quantized in GPTQ — F16, quantized on-the-fly to Q4\");\n }\n }\n\n if (textConfig.tiedEmbeddings) {\n notes.push(\"Tied embeddings: lm_head reuses embed_tokens Q4 tensors (no extra weight)\");\n }\n\n if (!supported) {\n notes.push(`Architecture \"${architectureName}\" is NOT supported by Gerbil's engine`);\n }\n\n const totalMB = totalBytes > 0 ? `${(totalBytes / 1048576).toFixed(0)} MB` : \"unknown\";\n const textOnlyMB = textOnlyBytes !== null ? `${(textOnlyBytes / 1048576).toFixed(0)} MB` : null;\n\n return {\n repo,\n architecture: architectureName,\n supported,\n format,\n quantization,\n textConfig,\n download: {\n totalBytes,\n totalMB,\n textOnlyBytes,\n textOnlyMB,\n skippedComponents,\n },\n adapter,\n notes,\n };\n },\n});\n","/**\n * Read Aloud Skill\n *\n * Read text or file content aloud using TTS.\n * Supports streaming for long content.\n */\n\nimport { execSync } from \"child_process\";\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst ReadAloudInput = z.object({\n /** File path to read, or text content if no file */\n content: z.string(),\n\n /** Treat content as file path (default: auto-detect) */\n isFile: z.boolean().optional(),\n\n /** Voice ID */\n voice: z\n .enum([\"af_heart\", \"af_bella\", \"af_nicole\", \"am_fenrir\", \"am_michael\", \"bf_emma\", \"bm_george\"])\n .default(\"af_heart\"),\n\n /** Speech speed */\n speed: z.number().min(0.5).max(2.0).default(1.0),\n\n /** Maximum characters to read (default: 5000) */\n maxLength: z.number().default(5000),\n\n /** Summarize if content exceeds maxLength instead of truncating */\n summarizeIfLong: z.boolean().default(false),\n});\n\nexport type ReadAloudInput = z.infer<typeof ReadAloudInput>;\n\nfunction saveWav(filename: string, audio: Float32Array, sampleRate: number): void {\n const buffer = Buffer.alloc(44 + audio.length * 2);\n buffer.write(\"RIFF\", 0);\n buffer.writeUInt32LE(36 + audio.length * 2, 4);\n buffer.write(\"WAVE\", 8);\n buffer.write(\"fmt \", 12);\n buffer.writeUInt32LE(16, 16);\n buffer.writeUInt16LE(1, 20);\n buffer.writeUInt16LE(1, 22);\n buffer.writeUInt32LE(sampleRate, 24);\n buffer.writeUInt32LE(sampleRate * 2, 28);\n buffer.writeUInt16LE(2, 32);\n buffer.writeUInt16LE(16, 34);\n buffer.write(\"data\", 36);\n buffer.writeUInt32LE(audio.length * 2, 40);\n\n for (let i = 0; i < audio.length; i++) {\n const s = Math.max(-1, Math.min(1, audio[i]));\n buffer.writeInt16LE(Math.round(s * 32767), 44 + i * 2);\n }\n\n writeFileSync(filename, buffer);\n}\n\nfunction playAudio(audioFile: string): void {\n const platform = process.platform;\n if (platform === \"darwin\") {\n execSync(`afplay \"${audioFile}\"`, { stdio: \"inherit\" });\n } else if (platform === \"linux\") {\n try {\n execSync(`aplay \"${audioFile}\"`, { stdio: \"inherit\" });\n } catch {\n execSync(`paplay \"${audioFile}\"`, { stdio: \"inherit\" });\n }\n } else if (platform === \"win32\") {\n execSync(`powershell -c \"(New-Object Media.SoundPlayer '${audioFile}').PlaySync()\"`, {\n stdio: \"inherit\",\n });\n }\n}\n\nexport const readAloud = defineSkill({\n name: \"read-aloud\",\n description: \"Read text or file content aloud using TTS\",\n version: \"1.0.0\",\n input: ReadAloudInput,\n\n async run({ input, gerbil }) {\n const {\n content,\n isFile,\n voice = \"af_heart\",\n speed = 1.0,\n maxLength = 5000,\n summarizeIfLong = false,\n } = input;\n\n // Determine if content is a file path\n const shouldReadFile = isFile ?? existsSync(content);\n\n let textToRead: string;\n\n if (shouldReadFile) {\n if (!existsSync(content)) {\n throw new Error(`File not found: ${content}`);\n }\n textToRead = readFileSync(content, \"utf-8\");\n } else {\n textToRead = content;\n }\n\n // Handle long content\n if (textToRead.length > maxLength) {\n if (summarizeIfLong) {\n // Use AI to summarize\n const summary = await gerbil.generate(\n `Summarize this content in a way that's good for reading aloud (2-3 paragraphs max):\\n\\n${textToRead.slice(0, 10000)}`,\n {\n system: \"You are a skilled narrator. Create a clear, spoken-word friendly summary.\",\n maxTokens: 500,\n temperature: 0.3,\n },\n );\n textToRead = summary.text;\n } else {\n // Truncate\n textToRead = textToRead.slice(0, maxLength) + \"...\";\n }\n }\n\n // Generate and play speech using streaming for long content\n const sentences = textToRead.split(/(?<=[.!?])\\s+/).filter((s) => s.trim());\n let totalDuration = 0;\n\n for (const sentence of sentences) {\n if (!sentence.trim()) continue;\n\n const result = await gerbil.speak(sentence, { voice, speed });\n totalDuration += result.duration;\n\n // Play this chunk\n const tempFile = join(tmpdir(), `gerbil-read-${Date.now()}.wav`);\n saveWav(tempFile, result.audio, result.sampleRate);\n\n try {\n playAudio(tempFile);\n } finally {\n try {\n unlinkSync(tempFile);\n } catch {\n // Ignore\n }\n }\n }\n\n const charCount = textToRead.length;\n const source = shouldReadFile ? `file \"${content}\"` : \"text\";\n\n return `Read ${charCount} characters from ${source} (${totalDuration.toFixed(1)}s audio)`;\n },\n});\n","/**\n * Review Skill\n *\n * Code review with configurable focus areas.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst ReviewInput = z.object({\n /** Code to review */\n code: z.string(),\n\n /** Focus areas */\n focus: z.array(z.enum([\"security\", \"performance\", \"style\", \"bugs\", \"all\"])).default([\"all\"]),\n\n /** Output format */\n format: z.enum([\"inline\", \"summary\", \"detailed\"]).default(\"summary\"),\n});\n\nexport type ReviewInput = z.infer<typeof ReviewInput>;\n\nexport const review = defineSkill({\n name: \"review\",\n description: \"Code review with configurable focus areas\",\n version: \"1.0.0\",\n input: ReviewInput,\n temperature: 0.3,\n maxTokens: 600,\n\n async run({ input, gerbil }) {\n const { code, focus = [\"all\"], format = \"summary\" } = input;\n\n let systemPrompt = `You are a senior code reviewer.\nReview the code for:`;\n\n if (focus.includes(\"all\")) {\n systemPrompt +=\n \"\\n- Security vulnerabilities\\n- Performance issues\\n- Code style and readability\\n- Potential bugs\";\n } else {\n if (focus.includes(\"security\")) {\n systemPrompt += \"\\n- Security vulnerabilities\";\n }\n if (focus.includes(\"performance\")) {\n systemPrompt += \"\\n- Performance issues\";\n }\n if (focus.includes(\"style\")) {\n systemPrompt += \"\\n- Code style and readability\";\n }\n if (focus.includes(\"bugs\")) {\n systemPrompt += \"\\n- Potential bugs\";\n }\n }\n\n if (format === \"summary\") {\n systemPrompt += \"\\n\\nProvide a brief summary of issues found.\";\n } else if (format === \"detailed\") {\n systemPrompt += \"\\n\\nProvide detailed feedback with suggestions.\";\n } else {\n systemPrompt += \"\\n\\nProvide inline-style comments.\";\n }\n\n const result = await gerbil.generate(`Review this code:\\n\\n${code}`, {\n system: systemPrompt,\n maxTokens: this.maxTokens,\n temperature: this.temperature,\n });\n\n return result.text;\n },\n});\n","/**\n * Speak Skill\n *\n * Convert text to speech using on-device TTS.\n */\n\nimport { execSync } from \"child_process\";\nimport { unlinkSync, writeFileSync } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst SpeakInput = z.object({\n /** Text to speak */\n text: z.string(),\n\n /** Voice ID (default: af_heart) */\n voice: z\n .enum([\n \"af_heart\",\n \"af_bella\",\n \"af_nicole\",\n \"af_sarah\",\n \"am_fenrir\",\n \"am_michael\",\n \"bf_emma\",\n \"bf_isabella\",\n \"bm_george\",\n \"bm_lewis\",\n ])\n .default(\"af_heart\"),\n\n /** Speech speed 0.5-2.0 (default: 1.0) */\n speed: z.number().min(0.5).max(2.0).default(1.0),\n\n /** Save to file instead of playing */\n output: z.string().optional(),\n});\n\nexport type SpeakInput = z.infer<typeof SpeakInput>;\n\n/**\n * Save Float32Array as WAV file\n */\nfunction saveWav(filename: string, audio: Float32Array, sampleRate: number): void {\n const buffer = Buffer.alloc(44 + audio.length * 2);\n\n // WAV header\n buffer.write(\"RIFF\", 0);\n buffer.writeUInt32LE(36 + audio.length * 2, 4);\n buffer.write(\"WAVE\", 8);\n buffer.write(\"fmt \", 12);\n buffer.writeUInt32LE(16, 16);\n buffer.writeUInt16LE(1, 20);\n buffer.writeUInt16LE(1, 22);\n buffer.writeUInt32LE(sampleRate, 24);\n buffer.writeUInt32LE(sampleRate * 2, 28);\n buffer.writeUInt16LE(2, 32);\n buffer.writeUInt16LE(16, 34);\n buffer.write(\"data\", 36);\n buffer.writeUInt32LE(audio.length * 2, 40);\n\n for (let i = 0; i < audio.length; i++) {\n const s = Math.max(-1, Math.min(1, audio[i]));\n buffer.writeInt16LE(Math.round(s * 32767), 44 + i * 2);\n }\n\n writeFileSync(filename, buffer);\n}\n\nexport const speak = defineSkill({\n name: \"speak\",\n description: \"Convert text to speech using on-device TTS (Kokoro-82M)\",\n version: \"1.0.0\",\n input: SpeakInput,\n\n async run({ input, gerbil }) {\n const { text, voice = \"af_heart\", speed = 1.0, output } = input;\n\n // Generate speech\n const result = await gerbil.speak(text, { voice, speed });\n\n if (output) {\n // Save to specified file\n saveWav(output, result.audio, result.sampleRate);\n return `Saved ${result.duration.toFixed(1)}s of audio to ${output}`;\n }\n\n // Play audio using system player\n const tempFile = join(tmpdir(), `gerbil-speak-${Date.now()}.wav`);\n saveWav(tempFile, result.audio, result.sampleRate);\n\n try {\n // Detect platform and use appropriate player\n const platform = process.platform;\n if (platform === \"darwin\") {\n execSync(`afplay \"${tempFile}\"`, { stdio: \"inherit\" });\n } else if (platform === \"linux\") {\n // Try common Linux audio players\n try {\n execSync(`aplay \"${tempFile}\"`, { stdio: \"inherit\" });\n } catch {\n try {\n execSync(`paplay \"${tempFile}\"`, { stdio: \"inherit\" });\n } catch {\n execSync(`play \"${tempFile}\"`, { stdio: \"inherit\" });\n }\n }\n } else if (platform === \"win32\") {\n execSync(`powershell -c \"(New-Object Media.SoundPlayer '${tempFile}').PlaySync()\"`, {\n stdio: \"inherit\",\n });\n }\n } finally {\n // Clean up temp file\n try {\n unlinkSync(tempFile);\n } catch {\n // Ignore cleanup errors\n }\n }\n\n return `Spoke ${result.duration.toFixed(1)}s of audio (voice: ${voice}, speed: ${speed}x)`;\n },\n});\n","/**\n * Summarize Skill\n *\n * Summarize content in various lengths and formats.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst SummarizeInput = z.object({\n /** Content to summarize */\n content: z.string(),\n\n /** Summary length */\n length: z.enum([\"short\", \"medium\", \"long\"]).default(\"medium\"),\n\n /** Output format */\n format: z.enum([\"paragraph\", \"bullets\"]).default(\"paragraph\"),\n\n /** Focus areas */\n focus: z.array(z.string()).optional(),\n});\n\nexport type SummarizeInput = z.infer<typeof SummarizeInput>;\n\nconst lengthGuide = {\n short: \"2-3 sentences\",\n medium: \"1 paragraph (4-6 sentences)\",\n long: \"2-3 paragraphs\",\n};\n\nconst maxTokensGuide = {\n short: 100,\n medium: 200,\n long: 400,\n};\n\nexport const summarize = defineSkill({\n name: \"summarize\",\n description: \"Summarize content in various lengths and formats\",\n version: \"1.0.0\",\n input: SummarizeInput,\n temperature: 0.3,\n\n async run({ input, gerbil }) {\n const { content, length = \"medium\", format = \"paragraph\", focus } = input;\n\n let systemPrompt = `You are a summarization expert.\nSummarize the content in ${lengthGuide[length]}.`;\n\n if (format === \"bullets\") {\n systemPrompt += \"\\nUse bullet points.\";\n }\n\n if (focus && focus.length > 0) {\n systemPrompt += `\\nFocus on: ${focus.join(\", \")}.`;\n }\n\n systemPrompt += \"\\nOnly output the summary, nothing else.\";\n\n const result = await gerbil.generate(`Summarize this:\\n\\n${content}`, {\n system: systemPrompt,\n maxTokens: maxTokensGuide[length],\n temperature: this.temperature,\n });\n\n return result.text;\n },\n});\n","/**\n * Test Skill\n *\n * Generate tests for code.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst TestInput = z.object({\n /** Code to test */\n code: z.string(),\n\n /** Test framework */\n framework: z.enum([\"jest\", \"vitest\", \"mocha\", \"playwright\"]).default(\"vitest\"),\n\n /** Test style */\n style: z.enum([\"unit\", \"integration\", \"e2e\"]).default(\"unit\"),\n});\n\nexport type TestInput = z.infer<typeof TestInput>;\n\nexport const test = defineSkill({\n name: \"test\",\n description: \"Generate tests for code\",\n version: \"1.0.0\",\n input: TestInput,\n temperature: 0.3,\n maxTokens: 800,\n\n async run({ input, gerbil }) {\n const { code, framework, style } = input;\n\n const systemPrompt = `You are a test engineer.\nGenerate ${style} tests using ${framework} for the provided code.\nInclude edge cases and error scenarios.\nOnly output the test code, no explanations.`;\n\n const result = await gerbil.generate(`Generate tests for:\\n\\n${code}`, {\n system: systemPrompt,\n maxTokens: this.maxTokens,\n temperature: this.temperature,\n });\n\n return result.text;\n },\n});\n","/**\n * Title Skill\n *\n * Generate titles for content.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst TitleInput = z.object({\n /** Content to generate title for */\n content: z.string(),\n\n /** Title style */\n style: z.enum([\"professional\", \"clickbait\", \"seo\", \"simple\"]).default(\"professional\"),\n\n /** Max length */\n maxLength: z.number().default(60),\n});\n\nexport type TitleInput = z.infer<typeof TitleInput>;\n\nconst styleGuide = {\n professional: \"Clear, informative, and professional\",\n clickbait: \"Engaging and curiosity-inducing\",\n seo: \"SEO-optimized with relevant keywords\",\n simple: \"Simple and straightforward\",\n};\n\nexport const title = defineSkill({\n name: \"title\",\n description: \"Generate titles for content\",\n version: \"1.0.0\",\n input: TitleInput,\n temperature: 0.7,\n maxTokens: 30,\n\n async run({ input, gerbil }) {\n const { content, style = \"professional\", maxLength = 60 } = input;\n\n const systemPrompt = `Generate a title for the content.\nStyle: ${styleGuide[style]}\nMax length: ${maxLength} characters\nOnly output the title, nothing else.`;\n\n const result = await gerbil.generate(`Generate a title for:\\n\\n${content.substring(0, 1000)}`, {\n system: systemPrompt,\n maxTokens: this.maxTokens,\n temperature: this.temperature,\n });\n\n let generatedTitle = result.text.trim();\n generatedTitle = generatedTitle.replace(/^[\"']|[\"']$/g, \"\");\n\n if (generatedTitle.length > maxLength) {\n generatedTitle = `${generatedTitle.substring(0, maxLength - 3)}...`;\n }\n\n return generatedTitle;\n },\n});\n","/**\n * Transcribe Skill\n *\n * Convert audio to text using on-device STT (Whisper).\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { resolve } from \"path\";\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst TranscribeInput = z.object({\n /** Audio file path (WAV, MP3, etc.) or URL */\n audio: z.string(),\n\n /** STT model ID (default: whisper-tiny.en) */\n model: z\n .enum([\"whisper-tiny.en\", \"whisper-base.en\", \"whisper-small.en\", \"whisper-large-v3-turbo\"])\n .default(\"whisper-tiny.en\"),\n\n /** Language hint for multilingual models */\n language: z.string().optional(),\n\n /** Include timestamps in output */\n timestamps: z.boolean().default(false),\n\n /** Save transcription to file */\n output: z.string().optional(),\n});\n\nexport type TranscribeInput = z.infer<typeof TranscribeInput>;\n\nexport const transcribe = defineSkill({\n name: \"transcribe\",\n description: \"Transcribe audio to text using on-device STT (Whisper)\",\n version: \"1.0.0\",\n input: TranscribeInput,\n\n async run({ input, gerbil }) {\n const { audio, model = \"whisper-tiny.en\", language, timestamps = false, output } = input;\n\n // Load audio file\n const filePath = resolve(audio);\n if (!existsSync(filePath)) {\n throw new Error(`Audio file not found: ${filePath}`);\n }\n\n const audioData = new Uint8Array(readFileSync(filePath));\n\n // Load the specified STT model\n await gerbil.loadSTT(model);\n\n // Transcribe\n const result = await gerbil.transcribe(audioData, {\n language,\n timestamps,\n });\n\n // Format output\n let text: string;\n if (timestamps && result.segments) {\n text = result.segments\n .map((seg) => `[${seg.start.toFixed(1)}s - ${seg.end.toFixed(1)}s] ${seg.text}`)\n .join(\"\\n\");\n } else {\n text = result.text;\n }\n\n // Save to file if requested\n if (output) {\n writeFileSync(output, text);\n return `Transcribed ${result.duration.toFixed(1)}s of audio to ${output}`;\n }\n\n return text;\n },\n});\n","/**\n * Translate Skill\n *\n * Translate text between languages.\n */\n\nimport { z } from \"zod\";\nimport { defineSkill } from \"../registry.js\";\n\nconst TranslateInput = z.object({\n /** Text to translate */\n text: z.string(),\n\n /** Source language (auto-detected if not provided) */\n from: z.string().optional(),\n\n /** Target language */\n to: z.string(),\n\n /** Preserve formatting */\n preserveFormatting: z.boolean().default(true),\n});\n\nexport type TranslateInput = z.infer<typeof TranslateInput>;\n\nexport const translate = defineSkill({\n name: \"translate\",\n description: \"Translate text between languages\",\n version: \"1.0.0\",\n input: TranslateInput,\n temperature: 0.3,\n\n async run({ input, gerbil }) {\n const { text, from, to, preserveFormatting } = input;\n\n let systemPrompt = `You are a professional translator.\nTranslate the text to ${to}.`;\n\n if (from) {\n systemPrompt += `\\nThe source language is ${from}.`;\n }\n\n if (preserveFormatting) {\n systemPrompt += \"\\nPreserve the original formatting (paragraphs, lists, etc.).\";\n }\n\n systemPrompt += \"\\nOnly output the translation, nothing else.\";\n\n const result = await gerbil.generate(`Translate:\\n\\n${text}`, {\n system: systemPrompt,\n maxTokens: Math.ceil(text.length / 2),\n temperature: this.temperature,\n });\n\n return result.text;\n },\n});\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as zodToJsonSchema } from "./utils-
|
|
1
|
+
import { n as zodToJsonSchema } from "./utils-DKO55ZmZ.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
//#region src/core/docs.ts
|
|
@@ -14,7 +14,7 @@ const GERBIL_DOCS = {
|
|
|
14
14
|
import { Gerbil } from "gerbil";
|
|
15
15
|
|
|
16
16
|
const g = new Gerbil();
|
|
17
|
-
await g.loadModel("qwen3-0.
|
|
17
|
+
await g.loadModel("qwen3.5-0.8b");
|
|
18
18
|
|
|
19
19
|
// Generate text
|
|
20
20
|
const result = await g.generate("Write a haiku");
|
|
@@ -72,6 +72,22 @@ const data = await gerbil.json("Extract: John is 32 and lives in NYC", {
|
|
|
72
72
|
});
|
|
73
73
|
// { name: "John", age: 32, city: "NYC" }
|
|
74
74
|
\`\`\``,
|
|
75
|
+
"generate-object": `Structured object output with retries (generateObject):
|
|
76
|
+
\`\`\`typescript
|
|
77
|
+
import { generateObject } from "@tryhamster/gerbil";
|
|
78
|
+
|
|
79
|
+
// Validate with a minimal { required } schema or a predicate; omit to accept any JSON.
|
|
80
|
+
const { object, attempts } = await generateObject(
|
|
81
|
+
'Extract {name, age} from: "I am Sarah, 28"',
|
|
82
|
+
{ schema: { required: ["name", "age"] }, maxRetries: 4 },
|
|
83
|
+
);
|
|
84
|
+
// object === { name: "Sarah", age: 28 }
|
|
85
|
+
\`\`\`
|
|
86
|
+
|
|
87
|
+
Also on the Gerbil class (g.generateObject), the engine
|
|
88
|
+
(WebGPUEngine.generateObject), the useObject React hook, and the CLI
|
|
89
|
+
(gerbil object "..." --schema person.json). Unlike json() (Zod), this uses a
|
|
90
|
+
predicate/required-keys validator and retries with a corrective nudge.`,
|
|
75
91
|
thinking: `Thinking mode (chain-of-thought reasoning) - Qwen3 models:
|
|
76
92
|
\`\`\`typescript
|
|
77
93
|
const result = await gerbil.generate("What is 127 × 43?", {
|
|
@@ -95,27 +111,23 @@ const { vector } = await gerbil.embed("Hello world");
|
|
|
95
111
|
// Batch
|
|
96
112
|
const results = await gerbil.embedBatch(["Hello", "World"]);
|
|
97
113
|
\`\`\``,
|
|
98
|
-
models: `Available models:
|
|
114
|
+
models: `Available models (native WebGPU engine, INT4 on-device):
|
|
99
115
|
|
|
100
116
|
| Model | Size | Best For |
|
|
101
117
|
|-------|------|----------|
|
|
102
|
-
| qwen3-0.
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
| phi-3-mini | ~2.1GB | High quality, larger |
|
|
108
|
-
|
|
109
|
-
Load any HuggingFace model:
|
|
118
|
+
| qwen3.5-0.8b | ~1.6GB | Default — fast, multimodal, 262k context, thinking mode |
|
|
119
|
+
| qwen3.5-2b | ~4GB | Best quality, multimodal, 262k context, thinking mode |
|
|
120
|
+
| lfm2.5-1.2b-thinking | ~2.4GB | Efficient reasoning, 128k context |
|
|
121
|
+
|
|
122
|
+
Load any HuggingFace model with a supported architecture (Qwen2/Qwen3/Qwen3.5/LFM2):
|
|
110
123
|
\`\`\`typescript
|
|
111
124
|
await gerbil.loadModel("hf:org/model");
|
|
112
|
-
await gerbil.loadModel("
|
|
125
|
+
await gerbil.loadModel("Qwen/Qwen3.5-0.8B");
|
|
113
126
|
\`\`\``,
|
|
114
127
|
load: `Loading models:
|
|
115
128
|
\`\`\`typescript
|
|
116
|
-
await gerbil.loadModel("qwen3-0.
|
|
117
|
-
device: "
|
|
118
|
-
dtype: "q4", // "q4" | "q8" | "fp16" | "fp32"
|
|
129
|
+
await gerbil.loadModel("qwen3.5-0.8b", {
|
|
130
|
+
device: "webgpu", // native WebGPU engine (Dawn in Node, WebGPU in browser)
|
|
119
131
|
onProgress: (p) => {
|
|
120
132
|
console.log(p.status, p.progress, p.file);
|
|
121
133
|
},
|
|
@@ -128,13 +140,13 @@ import { gerbil } from "gerbil/ai";
|
|
|
128
140
|
|
|
129
141
|
// Generate
|
|
130
142
|
const { text } = await generateText({
|
|
131
|
-
model: gerbil("qwen3-0.
|
|
143
|
+
model: gerbil("qwen3.5-0.8b"),
|
|
132
144
|
prompt: "Write a commit message",
|
|
133
145
|
});
|
|
134
146
|
|
|
135
147
|
// Stream
|
|
136
148
|
const stream = streamText({
|
|
137
|
-
model: gerbil("qwen3-0.
|
|
149
|
+
model: gerbil("qwen3.5-0.8b"),
|
|
138
150
|
prompt: "Explain React hooks",
|
|
139
151
|
});
|
|
140
152
|
|
|
@@ -144,7 +156,7 @@ for await (const chunk of stream.textStream) {
|
|
|
144
156
|
|
|
145
157
|
// With thinking mode
|
|
146
158
|
const { text } = await generateText({
|
|
147
|
-
model: gerbil("qwen3-0.
|
|
159
|
+
model: gerbil("qwen3.5-0.8b", { thinking: true }),
|
|
148
160
|
prompt: "What is 127 × 43?",
|
|
149
161
|
});
|
|
150
162
|
\`\`\``,
|
|
@@ -154,7 +166,7 @@ const { text } = await generateText({
|
|
|
154
166
|
import { gerbil } from "gerbil/next";
|
|
155
167
|
|
|
156
168
|
export const POST = gerbil.handler({
|
|
157
|
-
model: "qwen3-0.
|
|
169
|
+
model: "qwen3.5-0.8b",
|
|
158
170
|
maxTokens: 500,
|
|
159
171
|
});
|
|
160
172
|
\`\`\``,
|
|
@@ -197,7 +209,7 @@ app.route("/ai", await gerbil()());
|
|
|
197
209
|
\`\`\`typescript
|
|
198
210
|
import { GerbilLLM, GerbilEmbeddings } from "gerbil/langchain";
|
|
199
211
|
|
|
200
|
-
const llm = new GerbilLLM({ model: "qwen3-0.
|
|
212
|
+
const llm = new GerbilLLM({ model: "qwen3.5-0.8b" });
|
|
201
213
|
const embeddings = new GerbilEmbeddings();
|
|
202
214
|
|
|
203
215
|
// Use with chains
|
|
@@ -285,7 +297,7 @@ console.log(listSkills()); // ["commit", "summarize", ...]
|
|
|
285
297
|
cli: `CLI commands:
|
|
286
298
|
\`\`\`bash
|
|
287
299
|
gerbil "Write a haiku" # Generate text
|
|
288
|
-
gerbil -m qwen3-0.
|
|
300
|
+
gerbil -m qwen3.5-0.8b "prompt" # Specify model
|
|
289
301
|
gerbil --thinking "127 × 43" # Enable reasoning
|
|
290
302
|
|
|
291
303
|
gerbil commit # Git commit message
|
|
@@ -563,4 +575,4 @@ const docsTool = defineTool({
|
|
|
563
575
|
|
|
564
576
|
//#endregion
|
|
565
577
|
export { getToolDefinitions as a, setToolContext as c, getTool as i, executeToolCall as n, loadProjectTools as o, formatToolsForPrompt as r, parseToolCall as s, defineTool as t };
|
|
566
|
-
//# sourceMappingURL=tools-
|
|
578
|
+
//# sourceMappingURL=tools-DQ1mPUw5.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools-DQ1mPUw5.mjs","names":["GERBIL_DOCS: Record<string, string>","matches: string[]","toolContext: ToolContext | null","results: LoadedToolResult[]"],"sources":["../src/core/docs.ts","../src/core/tools.ts"],"sourcesContent":["/**\n * Gerbil Documentation Content\n *\n * Documentation strings used by the gerbil_docs tool\n * for answering questions about Gerbil features.\n */\n\nexport const GERBIL_DOCS: Record<string, string> = {\n // Core\n quickstart: `Gerbil Quick Start:\n\\`\\`\\`typescript\nimport { Gerbil } from \"gerbil\";\n\nconst g = new Gerbil();\nawait g.loadModel(\"qwen3.5-0.8b\");\n\n// Generate text\nconst result = await g.generate(\"Write a haiku\");\nconsole.log(result.text);\n\n// Stream responses\nfor await (const chunk of g.stream(\"Tell me a story\")) {\n process.stdout.write(chunk);\n}\n\\`\\`\\``,\n\n generate: `Generate text with options:\n\\`\\`\\`typescript\nconst result = await gerbil.generate(prompt, {\n maxTokens: 256, // Max tokens to generate\n temperature: 0.7, // 0-2, higher = more creative\n topP: 0.9, // Nucleus sampling\n topK: 50, // Top-k sampling\n thinking: false, // Enable reasoning mode (Qwen3)\n system: \"You are...\", // System prompt\n});\n\n// Result contains:\nresult.text // Generated text\nresult.thinking // Reasoning (if thinking=true)\nresult.tokensGenerated\nresult.tokensPerSecond\nresult.totalTime\n\\`\\`\\``,\n\n stream: `Streaming responses:\n\\`\\`\\`typescript\nfor await (const chunk of gerbil.stream(\"Hello\")) {\n process.stdout.write(chunk);\n}\n\n// With options\nconst stream = gerbil.stream(\"Explain React\", {\n maxTokens: 500,\n onToken: (token) => console.log(token),\n});\n\\`\\`\\``,\n\n json: `Structured JSON output with Zod validation:\n\\`\\`\\`typescript\nimport { z } from \"zod\";\n\nconst PersonSchema = z.object({\n name: z.string(),\n age: z.number(),\n city: z.string(),\n});\n\nconst data = await gerbil.json(\"Extract: John is 32 and lives in NYC\", {\n schema: PersonSchema,\n retries: 3, // Retry on validation failure\n temperature: 0.3, // Lower = more consistent\n});\n// { name: \"John\", age: 32, city: \"NYC\" }\n\\`\\`\\``,\n\n \"generate-object\": `Structured object output with retries (generateObject):\n\\`\\`\\`typescript\nimport { generateObject } from \"@tryhamster/gerbil\";\n\n// Validate with a minimal { required } schema or a predicate; omit to accept any JSON.\nconst { object, attempts } = await generateObject(\n 'Extract {name, age} from: \"I am Sarah, 28\"',\n { schema: { required: [\"name\", \"age\"] }, maxRetries: 4 },\n);\n// object === { name: \"Sarah\", age: 28 }\n\\`\\`\\`\n\nAlso on the Gerbil class (g.generateObject), the engine\n(WebGPUEngine.generateObject), the useObject React hook, and the CLI\n(gerbil object \"...\" --schema person.json). Unlike json() (Zod), this uses a\npredicate/required-keys validator and retries with a corrective nudge.`,\n\n thinking: `Thinking mode (chain-of-thought reasoning) - Qwen3 models:\n\\`\\`\\`typescript\nconst result = await gerbil.generate(\"What is 127 × 43?\", {\n thinking: true,\n});\n\nconsole.log(result.thinking);\n// \"Let me calculate step by step: 127 × 43 = 127 × 40 + 127 × 3...\"\n\nconsole.log(result.text);\n// \"5461\"\n\\`\\`\\`\n\nEnable in chat with /no_think or /think commands, or enable_thinking parameter.`,\n\n embed: `Generate embeddings:\n\\`\\`\\`typescript\n// Single text\nconst { vector } = await gerbil.embed(\"Hello world\");\n// vector: number[] (384 dimensions by default)\n\n// Batch\nconst results = await gerbil.embedBatch([\"Hello\", \"World\"]);\n\\`\\`\\``,\n\n // Models\n models: `Available models (native WebGPU engine, INT4 on-device):\n\n| Model | Size | Best For |\n|-------|------|----------|\n| qwen3.5-0.8b | ~1.6GB | Default — fast, multimodal, 262k context, thinking mode |\n| qwen3.5-2b | ~4GB | Best quality, multimodal, 262k context, thinking mode |\n| lfm2.5-1.2b-thinking | ~2.4GB | Efficient reasoning, 128k context |\n\nLoad any HuggingFace model with a supported architecture (Qwen2/Qwen3/Qwen3.5/LFM2):\n\\`\\`\\`typescript\nawait gerbil.loadModel(\"hf:org/model\");\nawait gerbil.loadModel(\"Qwen/Qwen3.5-0.8B\");\n\\`\\`\\``,\n\n load: `Loading models:\n\\`\\`\\`typescript\nawait gerbil.loadModel(\"qwen3.5-0.8b\", {\n device: \"webgpu\", // native WebGPU engine (Dawn in Node, WebGPU in browser)\n onProgress: (p) => {\n console.log(p.status, p.progress, p.file);\n },\n});\n\\`\\`\\``,\n\n // AI SDK\n \"ai-sdk\": `Vercel AI SDK v5 integration:\n\\`\\`\\`typescript\nimport { generateText, streamText } from \"ai\";\nimport { gerbil } from \"gerbil/ai\";\n\n// Generate\nconst { text } = await generateText({\n model: gerbil(\"qwen3.5-0.8b\"),\n prompt: \"Write a commit message\",\n});\n\n// Stream\nconst stream = streamText({\n model: gerbil(\"qwen3.5-0.8b\"),\n prompt: \"Explain React hooks\",\n});\n\nfor await (const chunk of stream.textStream) {\n process.stdout.write(chunk);\n}\n\n// With thinking mode\nconst { text } = await generateText({\n model: gerbil(\"qwen3.5-0.8b\", { thinking: true }),\n prompt: \"What is 127 × 43?\",\n});\n\\`\\`\\``,\n\n // Frameworks\n next: `Next.js App Router integration:\n\\`\\`\\`typescript\n// app/api/chat/route.ts\nimport { gerbil } from \"gerbil/next\";\n\nexport const POST = gerbil.handler({ \n model: \"qwen3.5-0.8b\",\n maxTokens: 500,\n});\n\\`\\`\\``,\n\n express: `Express.js integration:\n\\`\\`\\`typescript\nimport express from \"express\";\nimport { gerbil } from \"gerbil/express\";\n\nconst app = express();\napp.use(\"/ai\", gerbil()());\n\n// Endpoints created:\n// POST /ai/generate - Generate text\n// POST /ai/stream - Stream text\n// POST /ai/json - Structured output\n// POST /ai/embed - Embeddings\n\\`\\`\\``,\n\n react: `React hooks:\n\\`\\`\\`typescript\nimport { useGerbil, useChat } from \"gerbil/react\";\n\nfunction Chat() {\n const { generate, isLoading } = useGerbil();\n \n const handleSubmit = async (prompt: string) => {\n const result = await generate(prompt);\n console.log(result.text);\n };\n}\n\\`\\`\\``,\n\n hono: `Hono integration:\n\\`\\`\\`typescript\nimport { Hono } from \"hono\";\nimport { gerbil } from \"gerbil/hono\";\n\nconst app = new Hono();\napp.route(\"/ai\", await gerbil()());\n\\`\\`\\``,\n\n langchain: `LangChain integration:\n\\`\\`\\`typescript\nimport { GerbilLLM, GerbilEmbeddings } from \"gerbil/langchain\";\n\nconst llm = new GerbilLLM({ model: \"qwen3.5-0.8b\" });\nconst embeddings = new GerbilEmbeddings();\n\n// Use with chains\nconst chain = new LLMChain({ llm, prompt: template });\n\\`\\`\\``,\n\n mcp: `MCP Server for Claude Desktop & Cursor:\n\\`\\`\\`bash\ngerbil serve --mcp\n\\`\\`\\`\n\nSkills are automatically exposed as MCP tools:\n- gerbil_generate\n- gerbil_commit\n- gerbil_summarize\n- gerbil_explain\n- etc.`,\n\n // Skills\n skills: `Skills are reusable AI tasks with Zod validation:\n\\`\\`\\`typescript\nimport { commit, summarize, explain, review } from \"gerbil/skills\";\n\n// Generate commit message\nconst msg = await commit({ type: \"conventional\", maxLength: 72 });\n\n// Summarize content\nconst summary = await summarize({ \n content: doc, \n length: \"short\",\n format: \"bullets\" \n});\n\n// Explain code\nconst explanation = await explain({ \n content: code, \n level: \"beginner\" \n});\n\n// Code review\nconst feedback = await review({ \n code, \n focus: [\"security\", \"performance\"] \n});\n\\`\\`\\`\n\nBuilt-in skills: commit, summarize, explain, review, test, translate, extract, title`,\n\n \"define-skill\": `Create custom skills:\n\\`\\`\\`typescript\nimport { defineSkill } from \"gerbil/skills\";\nimport { z } from \"zod\";\n\nexport const sentiment = defineSkill({\n name: \"sentiment\",\n description: \"Analyze text sentiment\",\n input: z.object({ \n text: z.string(),\n detailed: z.boolean().default(false)\n }),\n output: z.object({\n sentiment: z.enum([\"positive\", \"negative\", \"neutral\"]),\n confidence: z.number(),\n }),\n temperature: 0.3,\n maxTokens: 100,\n \n async run({ input, gerbil }) {\n return gerbil.json(\\`Sentiment of: \\${input.text}\\`, {\n schema: this.output,\n });\n },\n});\n\\`\\`\\``,\n\n \"load-skills\": `Load skills from files:\n\\`\\`\\`typescript\nimport { loadSkills, useSkill, listSkills } from \"gerbil/skills\";\n\n// Load from directory (*.skill.ts files)\nawait loadSkills(\"./skills\");\n\n// Use by name\nconst skill = useSkill(\"my-skill\");\nconst result = await skill({ text: \"Hello\" });\n\n// List all\nconsole.log(listSkills()); // [\"commit\", \"summarize\", ...]\n\\`\\`\\``,\n\n // CLI\n cli: `CLI commands:\n\\`\\`\\`bash\ngerbil \"Write a haiku\" # Generate text\ngerbil -m qwen3.5-0.8b \"prompt\" # Specify model\ngerbil --thinking \"127 × 43\" # Enable reasoning\n\ngerbil commit # Git commit message\ngerbil summarize README.md # Summarize file\ngerbil explain src/index.ts # Explain code\n\ngerbil chat # Interactive chat\ngerbil chat --thinking # With reasoning\n\ngerbil serve # HTTP server\ngerbil serve --mcp # MCP server\n\ngerbil models # List models\ngerbil cache # Show cached models\ngerbil bench # Benchmark\ngerbil info # System info\n\ngerbil repl # Interactive TUI\n\\`\\`\\``,\n\n // Tools/Agents\n tools: `Gerbil supports tool calling with Qwen3 models:\n\\`\\`\\`typescript\nimport { defineTool, executeToolCall } from \"gerbil\";\n\nconst weatherTool = defineTool({\n name: \"get_weather\",\n description: \"Get current weather for a city\",\n parameters: z.object({\n city: z.string(),\n }),\n execute: async ({ city }) => {\n return \\`Weather in \\${city}: 72°F, sunny\\`;\n },\n});\n\\`\\`\\`\n\nIn the REPL, use Agent mode (Tab → Agent) to enable tools.`,\n};\n\n/**\n * Get all available documentation topics\n */\nexport function getDocTopics(): string[] {\n return Object.keys(GERBIL_DOCS);\n}\n\n/**\n * Search documentation by topic\n */\nexport function searchDocs(query: string): string | null {\n const words = query.toLowerCase().split(/\\s+/);\n const keyWords = words.filter((w) => w.length > 2);\n\n // Direct key match first\n for (const [key, content] of Object.entries(GERBIL_DOCS)) {\n const keyNorm = key.replace(/-/g, \"\");\n for (const word of keyWords) {\n if (keyNorm === word || key === word || keyNorm.includes(word)) {\n return content;\n }\n }\n }\n\n // Try each word as a potential topic\n for (const word of keyWords) {\n for (const [key, content] of Object.entries(GERBIL_DOCS)) {\n if (key.includes(word) || word.includes(key.replace(/-/g, \"\"))) {\n return content;\n }\n }\n }\n\n // Fallback: search content\n const matches: string[] = [];\n for (const [key, content] of Object.entries(GERBIL_DOCS)) {\n for (const word of keyWords) {\n if (content.toLowerCase().includes(word)) {\n matches.push(`## ${key}\\n${content}`);\n break;\n }\n }\n }\n\n if (matches.length > 0) {\n return matches.slice(0, 2).join(\"\\n\\n---\\n\\n\");\n }\n\n return null;\n}\n","/**\n * Tool Calling System for Gerbil\n *\n * Enables LLMs to call functions/tools during generation.\n * Compatible with Qwen3's tool calling format.\n */\n\nimport { z } from \"zod\";\nimport { getDocTopics, searchDocs } from \"./docs.js\";\nimport { zodToJsonSchema } from \"./utils.js\";\n\n// ============================================\n// Tool Context (for passing gerbil to tools)\n// ============================================\n\nexport type ToolContext = {\n /** Generate text using the loaded model */\n generate: (prompt: string) => Promise<string>;\n};\n\nlet toolContext: ToolContext | null = null;\n\n/**\n * Set the tool context (call this after loading a model)\n */\nexport function setToolContext(ctx: ToolContext): void {\n toolContext = ctx;\n}\n\n/**\n * Get the tool context for use in tools\n */\nexport function getToolContext(): ToolContext | null {\n return toolContext;\n}\n\n// ============================================\n// Tool Definition\n// ============================================\n\nexport type ToolDefinition<TParams = unknown> = {\n /** Tool name (function name) */\n name: string;\n\n /** Description for the LLM */\n description: string;\n\n /** Zod schema for parameters */\n parameters?: z.ZodType<TParams>;\n\n /** The function to execute (receives params and optional context) */\n execute: (params: TParams, ctx?: ToolContext | null) => Promise<string>;\n};\n\nexport type Tool<TParams = unknown> = {\n definition: ToolDefinition<TParams>;\n (params: TParams): Promise<string>;\n};\n\n// ============================================\n// Tool Registry\n// ============================================\n\nconst toolRegistry = new Map<string, Tool<any>>();\n\n/**\n * Define a tool\n */\nexport function defineTool<TParams>(def: ToolDefinition<TParams>): Tool<TParams> {\n const tool = async (params: TParams): Promise<string> => {\n // Validate params if schema provided\n if (def.parameters) {\n const parsed = def.parameters.parse(params);\n return def.execute(parsed, toolContext);\n }\n return def.execute(params, toolContext);\n };\n\n (tool as Tool<TParams>).definition = def;\n\n // Auto-register\n toolRegistry.set(def.name, tool as Tool<any>);\n\n return tool as Tool<TParams>;\n}\n\n/**\n * Get tool by name\n */\nexport function getTool(name: string): Tool<any> | undefined {\n return toolRegistry.get(name);\n}\n\n/**\n * List all tools\n */\nexport function listTools(): string[] {\n return Array.from(toolRegistry.keys());\n}\n\n/**\n * Get all tool definitions for prompt injection\n */\nexport function getToolDefinitions(): ToolDefinition<any>[] {\n return Array.from(toolRegistry.values()).map((t) => t.definition);\n}\n\nexport type LoadedToolResult = {\n name: string;\n loaded: boolean;\n error?: string;\n path: string;\n};\n\n/**\n * Simple tool config (no imports needed in tool files)\n */\nexport type SimpleToolConfig = {\n name: string;\n description: string;\n execute: (params: Record<string, any>) => Promise<string> | string;\n};\n\n/**\n * Load tools from a directory\n * Tools are simple .ts files with a default export config object\n * No module imports - we eval the execute function directly\n */\nexport async function loadTools(dir: string): Promise<LoadedToolResult[]> {\n const fs = await import(\"node:fs\");\n const pathModule = await import(\"node:path\");\n\n if (!fs.existsSync(dir)) {\n return [];\n }\n\n const files = fs.readdirSync(dir).filter((f) => f.endsWith(\".tool.ts\") || f.endsWith(\".tool.js\"));\n const results: LoadedToolResult[] = [];\n\n for (const file of files) {\n const filePath = pathModule.join(dir, file);\n const toolName = file.replace(/\\.tool\\.(ts|js)$/, \"\");\n\n try {\n // Read file content directly\n const content = fs.readFileSync(filePath, \"utf-8\");\n\n // Extract the config object using simple parsing\n const config = parseToolFile(content, toolName);\n\n if (config) {\n // Register the tool\n defineTool({\n name: config.name,\n description: config.description,\n execute: async (params, ctx) => {\n // Project tools may or may not accept ctx parameter\n const executeFn = config.execute as any;\n const result = await executeFn(params, ctx);\n return typeof result === \"string\" ? result : String(result);\n },\n });\n results.push({ name: config.name, loaded: true, path: filePath });\n } else {\n results.push({\n name: toolName,\n loaded: false,\n error: \"Could not parse tool config\",\n path: filePath,\n });\n }\n } catch (e) {\n const errorMsg = e instanceof Error ? e.message.split(\"\\n\")[0] : String(e);\n results.push({ name: toolName, loaded: false, error: errorMsg, path: filePath });\n }\n }\n\n return results;\n}\n\n/**\n * Parse a simple tool file and extract the config\n * Expected format:\n * ```\n * export default {\n * name: \"tool_name\",\n * description: \"...\",\n * execute: async (params) => { ... }\n * }\n * ```\n */\nfunction parseToolFile(content: string, fallbackName: string): SimpleToolConfig | null {\n try {\n // Remove TypeScript type annotations for eval\n let cleaned = content\n .replace(/:\\s*\\{[^}]+\\}/g, \"\") // Remove type objects like : { theme?: string }\n .replace(/:\\s*Record<[^>]+>/g, \"\") // Remove Record types\n .replace(/:\\s*string\\b/g, \"\")\n .replace(/:\\s*number\\b/g, \"\")\n .replace(/:\\s*boolean\\b/g, \"\")\n .replace(/:\\s*any\\b/g, \"\")\n .replace(/:\\s*Promise<[^>]+>/g, \"\")\n .replace(/export\\s+default\\s+/, \"return \");\n\n // Remove comments\n cleaned = cleaned.replace(/\\/\\/.*$/gm, \"\").replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n\n // Wrap in function and evaluate\n const fn = new Function(cleaned);\n const config = fn();\n\n if (config && typeof config === \"object\" && config.name && config.execute) {\n return {\n name: config.name || fallbackName,\n description: config.description || \"No description\",\n execute: config.execute,\n };\n }\n return null;\n } catch (_e) {\n return null;\n }\n}\n\n/**\n * Load tools from project .gerbil/tools directory\n */\nexport async function loadProjectTools(): Promise<LoadedToolResult[]> {\n const pathModule = await import(\"node:path\");\n const toolsDir = pathModule.join(process.cwd(), \".gerbil\", \"tools\");\n return loadTools(toolsDir);\n}\n\n// Re-export for backwards compatibility\nexport { zodToJsonSchema } from \"./utils.js\";\n\n/**\n * Format tools for Qwen3 prompt\n */\nexport function formatToolsForPrompt(tools: ToolDefinition<any>[]): string {\n if (tools.length === 0) {\n return \"\";\n }\n\n const toolDefs = tools\n .map((t) => {\n const params = t.parameters\n ? zodToJsonSchema(t.parameters)\n : { type: \"object\", properties: {} };\n return `## ${t.name}\n\nDescription: ${t.description}\nParameters: ${JSON.stringify(params, null, 2)}`;\n })\n .join(\"\\n\\n\");\n\n return `You are a helpful assistant with access to tools.\n\n# Tools\n\n${toolDefs}\n\n## How to call tools\n\nTo call a tool, use this exact format:\n<tool_call>\n{\"name\": \"tool_name\", \"arguments\": {\"param\": \"value\"}}\n</tool_call>\n\nWhen the user asks about Gerbil (documentation, features, how to use), call gerbil_docs with a topic like: tools, skills, ai-sdk, next, express, generate, stream, models, cli.\n\nFor other questions, respond normally without calling tools.`;\n}\n\n/**\n * Parse tool call from response\n */\nexport function parseToolCall(response: string): { tool: string; params: any } | null {\n try {\n // Try <tool_call> format first (Qwen style)\n const toolCallMatch = response.match(/<tool_call>\\s*([\\s\\S]*?)\\s*<\\/tool_call>/);\n if (toolCallMatch) {\n const parsed = JSON.parse(toolCallMatch[1]);\n if (parsed.name) {\n return { tool: parsed.name, params: parsed.arguments || {} };\n }\n }\n\n // Fallback: look for {\"name\": \"...\", \"arguments\": ...} pattern\n const nameArgsMatch = response.match(\n /\\{\\s*\"name\"\\s*:\\s*\"([^\"]+)\"[^}]*\"arguments\"\\s*:\\s*(\\{[^}]*\\})/,\n );\n if (nameArgsMatch) {\n return { tool: nameArgsMatch[1], params: JSON.parse(nameArgsMatch[2]) };\n }\n\n // Fallback: {\"tool\": \"...\", \"params\": ...} pattern\n const toolParamsMatch = response.match(\n /\\{\\s*\"tool\"\\s*:\\s*\"([^\"]+)\"[^}]*\"params\"\\s*:\\s*(\\{[^}]*\\})/,\n );\n if (toolParamsMatch) {\n return { tool: toolParamsMatch[1], params: JSON.parse(toolParamsMatch[2]) };\n }\n\n // Simple fallback\n const simpleMatch = response.match(/\\{\\s*\"(?:tool|name)\"\\s*:\\s*\"([^\"]+)\"/);\n if (simpleMatch) {\n return { tool: simpleMatch[1], params: {} };\n }\n } catch {}\n return null;\n}\n\n/**\n * Execute a tool call\n */\nexport async function executeToolCall(toolName: string, params: any): Promise<string> {\n const tool = getTool(toolName);\n if (!tool) {\n return `Error: Unknown tool \"${toolName}\"`;\n }\n\n try {\n return await tool(params);\n } catch (e) {\n return `Error executing ${toolName}: ${e}`;\n }\n}\n\n// ============================================\n// Built-in Tools\n// ============================================\n\n/**\n * Docs tool - searches gerbil documentation\n * Documentation content is in core/docs.ts\n */\nexport const docsTool = defineTool({\n name: \"gerbil_docs\",\n description:\n \"Search Gerbil documentation for information about features, API, integrations, skills, and usage examples\",\n parameters: z.object({\n query: z\n .string()\n .optional()\n .default(\"quickstart\")\n .describe(\n \"Topic: quickstart, generate, stream, json, thinking, embed, models, ai-sdk, next, express, react, skills, define-skill, cli, tools\",\n ),\n }),\n execute: async ({ query = \"quickstart\" }) => {\n const result = searchDocs(query);\n if (result) {\n return result;\n }\n const topics = getDocTopics().join(\", \");\n return `No documentation found for \"${query}\". Available topics: ${topics}`;\n },\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
//#region src/memory/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Type definitions for Gerbil's memory / RAG module.
|
|
4
|
+
*
|
|
5
|
+
* The module is engine-agnostic: it stores text + embeddings behind a
|
|
6
|
+
* pluggable {@link MemoryStore} and embeds text via an injected
|
|
7
|
+
* {@link Embedder}. Gerbil's native embeddings are wired in via a tiny
|
|
8
|
+
* adapter (see `gerbil-embedder.ts`).
|
|
9
|
+
*/
|
|
10
|
+
/** Arbitrary JSON-serializable metadata attached to a memory record. */
|
|
11
|
+
type MemoryMetadata = Record<string, unknown>;
|
|
12
|
+
/**
|
|
13
|
+
* A single stored memory.
|
|
14
|
+
*
|
|
15
|
+
* Vectors are stored L2-normalized so that cosine similarity reduces to a
|
|
16
|
+
* dot product. `embedding` may be omitted for records awaiting embedding.
|
|
17
|
+
*/
|
|
18
|
+
type MemoryRecord = {
|
|
19
|
+
/** Stable unique id (generated on insert if not supplied). */
|
|
20
|
+
id: string;
|
|
21
|
+
/** The raw text content of this memory. */
|
|
22
|
+
text: string;
|
|
23
|
+
/** L2-normalized embedding vector. Omitted only before embedding. */
|
|
24
|
+
embedding?: Float32Array;
|
|
25
|
+
/** Arbitrary metadata for filtering and provenance. */
|
|
26
|
+
metadata: MemoryMetadata;
|
|
27
|
+
/** Epoch milliseconds when the record was created. */
|
|
28
|
+
createdAt: number;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Embeds one or more texts into vectors.
|
|
32
|
+
*
|
|
33
|
+
* Implementations should return one vector per input text, in order.
|
|
34
|
+
* Gerbil's native embeddings satisfy this via {@link createGerbilEmbedder}.
|
|
35
|
+
*/
|
|
36
|
+
type Embedder = (texts: string[]) => Promise<Float32Array[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Predicate or transform applied to text on write to redact sensitive data.
|
|
39
|
+
*
|
|
40
|
+
* - A {@link RegExp} replaces all matches with `[REDACTED]`.
|
|
41
|
+
* - A function returns the redacted string.
|
|
42
|
+
*/
|
|
43
|
+
type Redactor = RegExp | ((text: string) => string);
|
|
44
|
+
/** A hit returned from a vector search. */
|
|
45
|
+
type MemorySearchResult = {
|
|
46
|
+
/** The matched record. */
|
|
47
|
+
record: MemoryRecord;
|
|
48
|
+
/** Cosine similarity score in [-1, 1] (typically [0, 1]). */
|
|
49
|
+
score: number;
|
|
50
|
+
};
|
|
51
|
+
/** Filter applied to record metadata. Each key must match exactly. */
|
|
52
|
+
type MetadataFilter = Record<string, unknown>;
|
|
53
|
+
/** Options for {@link MemoryStore.search}. */
|
|
54
|
+
type StoreSearchOptions = {
|
|
55
|
+
/** Maximum number of results (default 5). */
|
|
56
|
+
k?: number;
|
|
57
|
+
/** Exact-match metadata filter applied before ranking. */
|
|
58
|
+
filter?: MetadataFilter;
|
|
59
|
+
/** Minimum score to include (default: no minimum). */
|
|
60
|
+
minScore?: number;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Pluggable persistence + retrieval backend.
|
|
64
|
+
*
|
|
65
|
+
* Backends are engine-agnostic and store pre-normalized embeddings. The
|
|
66
|
+
* default in-memory store works in Node and the browser; an IndexedDB store
|
|
67
|
+
* adds browser durability and a file store adds Node durability.
|
|
68
|
+
*/
|
|
69
|
+
type MemoryStore = {
|
|
70
|
+
/** Insert or replace a record by id. */
|
|
71
|
+
add(record: MemoryRecord): Promise<void>;
|
|
72
|
+
/** Insert or replace many records (may be faster than per-record adds). */
|
|
73
|
+
addMany(records: MemoryRecord[]): Promise<void>;
|
|
74
|
+
/** Fetch a record by id, or `undefined` if absent. */
|
|
75
|
+
get(id: string): Promise<MemoryRecord | undefined>;
|
|
76
|
+
/** Cosine top-k search over a query vector. */
|
|
77
|
+
search(queryVector: Float32Array, options?: StoreSearchOptions): Promise<MemorySearchResult[]>;
|
|
78
|
+
/** Delete a record by id. Returns `true` if it existed. */
|
|
79
|
+
delete(id: string): Promise<boolean>;
|
|
80
|
+
/** List all records (optionally filtered by metadata). */
|
|
81
|
+
list(filter?: MetadataFilter): Promise<MemoryRecord[]>;
|
|
82
|
+
/** Remove all records. */
|
|
83
|
+
clear(): Promise<void>;
|
|
84
|
+
/** Total number of stored records. */
|
|
85
|
+
size(): Promise<number>;
|
|
86
|
+
};
|
|
87
|
+
/** Serializable snapshot of a store for import/export. */
|
|
88
|
+
type MemoryExport = {
|
|
89
|
+
/** Schema version for forward compatibility. */
|
|
90
|
+
version: 1;
|
|
91
|
+
/** Exported records (embeddings serialized as plain number arrays). */
|
|
92
|
+
records: SerializedRecord[];
|
|
93
|
+
};
|
|
94
|
+
/** A record with its embedding serialized as a plain array for JSON. */
|
|
95
|
+
type SerializedRecord = {
|
|
96
|
+
id: string;
|
|
97
|
+
text: string;
|
|
98
|
+
embedding?: number[];
|
|
99
|
+
metadata: MemoryMetadata;
|
|
100
|
+
createdAt: number;
|
|
101
|
+
};
|
|
102
|
+
/** Options controlling document chunking before embedding. */
|
|
103
|
+
type ChunkOptions = {
|
|
104
|
+
/** Target chunk size in characters (default 1000). */
|
|
105
|
+
chunkSize?: number;
|
|
106
|
+
/** Overlap between consecutive chunks in characters (default 200). */
|
|
107
|
+
overlap?: number;
|
|
108
|
+
};
|
|
109
|
+
/** Options for {@link Memory.add}. */
|
|
110
|
+
type AddOptions = {
|
|
111
|
+
/** Metadata to attach to every resulting record. */
|
|
112
|
+
metadata?: MemoryMetadata;
|
|
113
|
+
/** Explicit id (single-chunk adds only). Auto-generated otherwise. */
|
|
114
|
+
id?: string;
|
|
115
|
+
/**
|
|
116
|
+
* Split long text into overlapping chunks before embedding.
|
|
117
|
+
* Pass `true` for defaults or an object to configure. Default: no chunking.
|
|
118
|
+
*/
|
|
119
|
+
chunk?: boolean | ChunkOptions;
|
|
120
|
+
};
|
|
121
|
+
/** Options for {@link Memory.search}. */
|
|
122
|
+
type SearchOptions = {
|
|
123
|
+
/** Maximum number of results (default 5). */
|
|
124
|
+
k?: number;
|
|
125
|
+
/** Exact-match metadata filter. */
|
|
126
|
+
filter?: MetadataFilter;
|
|
127
|
+
/** Minimum cosine score to include. */
|
|
128
|
+
minScore?: number;
|
|
129
|
+
};
|
|
130
|
+
/** Options for {@link Memory.recall} (token-budgeted context packing). */
|
|
131
|
+
type RecallOptions = {
|
|
132
|
+
/** Maximum tokens of context to pack (default 1024). */
|
|
133
|
+
tokenBudget?: number;
|
|
134
|
+
/** Candidate pool size to retrieve before packing (default 20). */
|
|
135
|
+
k?: number;
|
|
136
|
+
/** Exact-match metadata filter. */
|
|
137
|
+
filter?: MetadataFilter;
|
|
138
|
+
/** Minimum cosine score for a candidate to be considered. */
|
|
139
|
+
minScore?: number;
|
|
140
|
+
/** Separator placed between packed memories (default "\n\n"). */
|
|
141
|
+
separator?: string;
|
|
142
|
+
};
|
|
143
|
+
/** Result of {@link Memory.recall}: a packed context block plus provenance. */
|
|
144
|
+
type RecallResult = {
|
|
145
|
+
/** The token-budgeted context block, ready to prepend to a prompt. */
|
|
146
|
+
context: string;
|
|
147
|
+
/** The records included in the context, in packed order. */
|
|
148
|
+
records: MemoryRecord[];
|
|
149
|
+
/** Approximate token count of {@link RecallResult.context}. */
|
|
150
|
+
tokensUsed: number;
|
|
151
|
+
};
|
|
152
|
+
/** Configuration for {@link createMemory}. */
|
|
153
|
+
type MemoryOptions = {
|
|
154
|
+
/** Embedder used to vectorize text. Required. */
|
|
155
|
+
embed: Embedder;
|
|
156
|
+
/** Persistence backend. Defaults to an in-memory store. */
|
|
157
|
+
store?: MemoryStore;
|
|
158
|
+
/** Redaction applied to text on write. */
|
|
159
|
+
redact?: Redactor;
|
|
160
|
+
/** Default chunking applied to {@link Memory.add} when `chunk` is true. */
|
|
161
|
+
chunk?: ChunkOptions;
|
|
162
|
+
};
|
|
163
|
+
//#endregion
|
|
164
|
+
export { MemoryMetadata as a, MemorySearchResult as c, RecallOptions as d, RecallResult as f, StoreSearchOptions as g, SerializedRecord as h, MemoryExport as i, MemoryStore as l, SearchOptions as m, ChunkOptions as n, MemoryOptions as o, Redactor as p, Embedder as r, MemoryRecord as s, AddOptions as t, MetadataFilter as u };
|
|
165
|
+
//# sourceMappingURL=types-DQBe2lFo.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-DQBe2lFo.d.mts","names":[],"sources":["../src/memory/types.ts"],"sourcesContent":[],"mappings":";;AAUA;AAQA;AAmBA;AAQA;AAGA;AAQA;AAGA;AAgBA;AAEc,KAnEF,cAAA,GAAiB,MAmEf,CAAA,MAAA,EAAA,OAAA,CAAA;;;;;;;AAMgC,KAjElC,YAAA,GAiEkC;EAA6B;EAAR,EAAA,EAAA,MAAA;EAE7C;EAEN,IAAA,EAAA,MAAA;EAAyB;EAAR,SAAA,CAAA,EA/DnB,YA+DmB;EAEtB;EAED,QAAA,EAjEE,cAiEF;EAAO;EAIL,SAAA,EAAA,MAAY;AAQxB,CAAA;AASA;AAQA;AAaA;AAUA;AAcA;AAUA;AAES,KApIG,QAAA,GAoIH,CAAA,KAAA,EAAA,MAAA,EAAA,EAAA,GApImC,OAoInC,CApI2C,YAoI3C,EAAA,CAAA;;;;;;;KA5HG,QAAA,GAAW;;KAGX,kBAAA;;UAEF;;;;;KAME,cAAA,GAAiB;;KAGjB,kBAAA;;;;WAID;;;;;;;;;;;KAYC,WAAA;;cAEE,eAAe;;mBAEV,iBAAiB;;mBAEjB,QAAQ;;sBAEL,wBAAwB,qBAAqB,QAAQ;;sBAErD;;gBAEN,iBAAiB,QAAQ;;WAE9B;;UAED;;;KAIE,YAAA;;;;WAID;;;KAIC,gBAAA;;;;YAIA;;;;KAKA,YAAA;;;;;;;KAQA,UAAA;;aAEC;;;;;;;oBAOO;;;KAIR,aAAA;;;;WAID;;;;;KAMC,aAAA;;;;;;WAMD;;;;;;;KAQC,YAAA;;;;WAID;;;;;KAMC,aAAA;;SAEH;;UAEC;;WAEC;;UAED"}
|