@tryhamster/gerbil 1.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +253 -0
- package/bin/cli.js +2 -0
- package/dist/auto-update-BbNHbSU1.mjs +3 -0
- package/dist/browser/index.d.mts +262 -0
- package/dist/browser/index.d.mts.map +1 -0
- package/dist/browser/index.mjs +755 -0
- package/dist/browser/index.mjs.map +1 -0
- package/dist/chrome-backend-C5Un08O4.mjs +771 -0
- package/dist/chrome-backend-C5Un08O4.mjs.map +1 -0
- package/dist/chrome-backend-CtwPENIW.mjs +3 -0
- package/dist/chunk-Ct1HF2bE.mjs +7 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +7078 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/frameworks/express.d.mts +22 -0
- package/dist/frameworks/express.d.mts.map +1 -0
- package/dist/frameworks/express.mjs +123 -0
- package/dist/frameworks/express.mjs.map +1 -0
- package/dist/frameworks/fastify.d.mts +11 -0
- package/dist/frameworks/fastify.d.mts.map +1 -0
- package/dist/frameworks/fastify.mjs +73 -0
- package/dist/frameworks/fastify.mjs.map +1 -0
- package/dist/frameworks/hono.d.mts +14 -0
- package/dist/frameworks/hono.d.mts.map +1 -0
- package/dist/frameworks/hono.mjs +82 -0
- package/dist/frameworks/hono.mjs.map +1 -0
- package/dist/frameworks/next.d.mts +31 -0
- package/dist/frameworks/next.d.mts.map +1 -0
- package/dist/frameworks/next.mjs +116 -0
- package/dist/frameworks/next.mjs.map +1 -0
- package/dist/frameworks/react.d.mts +56 -0
- package/dist/frameworks/react.d.mts.map +1 -0
- package/dist/frameworks/react.mjs +172 -0
- package/dist/frameworks/react.mjs.map +1 -0
- package/dist/frameworks/trpc.d.mts +12 -0
- package/dist/frameworks/trpc.d.mts.map +1 -0
- package/dist/frameworks/trpc.mjs +80 -0
- package/dist/frameworks/trpc.mjs.map +1 -0
- package/dist/gerbil-BfnsFWRE.mjs +644 -0
- package/dist/gerbil-BfnsFWRE.mjs.map +1 -0
- package/dist/gerbil-BjW-z7Fq.mjs +5 -0
- package/dist/gerbil-DZ1k3ChC.d.mts +138 -0
- package/dist/gerbil-DZ1k3ChC.d.mts.map +1 -0
- package/dist/index.d.mts +223 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +13 -0
- package/dist/index.mjs.map +1 -0
- package/dist/integrations/ai-sdk.d.mts +78 -0
- package/dist/integrations/ai-sdk.d.mts.map +1 -0
- package/dist/integrations/ai-sdk.mjs +199 -0
- package/dist/integrations/ai-sdk.mjs.map +1 -0
- package/dist/integrations/langchain.d.mts +41 -0
- package/dist/integrations/langchain.d.mts.map +1 -0
- package/dist/integrations/langchain.mjs +93 -0
- package/dist/integrations/langchain.mjs.map +1 -0
- package/dist/integrations/llamaindex.d.mts +45 -0
- package/dist/integrations/llamaindex.d.mts.map +1 -0
- package/dist/integrations/llamaindex.mjs +86 -0
- package/dist/integrations/llamaindex.mjs.map +1 -0
- package/dist/integrations/mcp-client.d.mts +206 -0
- package/dist/integrations/mcp-client.d.mts.map +1 -0
- package/dist/integrations/mcp-client.mjs +507 -0
- package/dist/integrations/mcp-client.mjs.map +1 -0
- package/dist/integrations/mcp.d.mts +177 -0
- package/dist/integrations/mcp.d.mts.map +1 -0
- package/dist/integrations/mcp.mjs +8 -0
- package/dist/mcp-R8kRLIKb.mjs +348 -0
- package/dist/mcp-R8kRLIKb.mjs.map +1 -0
- package/dist/models-DKULvhOr.mjs +136 -0
- package/dist/models-DKULvhOr.mjs.map +1 -0
- package/dist/models-De2-_GmQ.d.mts +22 -0
- package/dist/models-De2-_GmQ.d.mts.map +1 -0
- package/dist/one-liner-BUQR0nqq.mjs +98 -0
- package/dist/one-liner-BUQR0nqq.mjs.map +1 -0
- package/dist/skills/index.d.mts +390 -0
- package/dist/skills/index.d.mts.map +1 -0
- package/dist/skills/index.mjs +7 -0
- package/dist/skills-D3CEpgDc.mjs +630 -0
- package/dist/skills-D3CEpgDc.mjs.map +1 -0
- package/dist/tools-BsiEE6f2.mjs +567 -0
- package/dist/tools-BsiEE6f2.mjs.map +1 -0
- package/dist/types-BS1N92Jt.d.mts +183 -0
- package/dist/types-BS1N92Jt.d.mts.map +1 -0
- package/dist/utils-7vXqtq2Q.mjs +63 -0
- package/dist/utils-7vXqtq2Q.mjs.map +1 -0
- package/docs/ai-sdk.md +80 -0
- package/docs/architecture/README.md +84 -0
- package/docs/architecture/caching.md +227 -0
- package/docs/architecture/inference.md +176 -0
- package/docs/architecture/overview.md +179 -0
- package/docs/architecture/streaming.md +261 -0
- package/docs/architecture/webgpu.md +213 -0
- package/docs/browser.md +328 -0
- package/docs/cli.md +155 -0
- package/docs/frameworks.md +90 -0
- package/docs/mcp-client.md +224 -0
- package/docs/mcp.md +109 -0
- package/docs/memory.md +229 -0
- package/docs/repl.md +473 -0
- package/docs/skills.md +261 -0
- package/docs/tools.md +304 -0
- package/package.json +207 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-D3CEpgDc.mjs","names":["ctx: SkillContext<TInput>","loaded: string[]"],"sources":["../src/skills/registry.ts","../src/skills/loader.ts","../src/skills/builtin/commit.ts","../src/skills/builtin/explain.ts","../src/skills/builtin/extract.ts","../src/skills/builtin/review.ts","../src/skills/builtin/summarize.ts","../src/skills/builtin/test.ts","../src/skills/builtin/title.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 \"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(\"path\");\n const fs = await import(\"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(\"fs\");\n const path = await import(\"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(\"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 console.warn(`No valid skill found in ${filePath}`);\n return null;\n }\n\n // Register with source tracking\n registerSkillWithSource(skill, resolvedPath);\n\n return skill;\n } catch (error) {\n console.error(`Failed to load skill from ${filePath}:`, 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 * 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(\"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 * Explain Skill\n *\n * Explain code or concepts at various levels.\n */\n\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\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\nexport const explain = defineSkill({\n name: \"explain\",\n description: \"Explain code or concepts at various levels\",\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 } = 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 return result.text;\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 * 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 * 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 * 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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"}
|
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
import { n as zodToJsonSchema } from "./utils-7vXqtq2Q.mjs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/core/docs.ts
|
|
5
|
+
/**
|
|
6
|
+
* Gerbil Documentation Content
|
|
7
|
+
*
|
|
8
|
+
* Documentation strings used by the gerbil_docs tool
|
|
9
|
+
* for answering questions about Gerbil features.
|
|
10
|
+
*/
|
|
11
|
+
const GERBIL_DOCS = {
|
|
12
|
+
quickstart: `Gerbil Quick Start:
|
|
13
|
+
\`\`\`typescript
|
|
14
|
+
import { Gerbil } from "gerbil";
|
|
15
|
+
|
|
16
|
+
const g = new Gerbil();
|
|
17
|
+
await g.loadModel("qwen3-0.6b");
|
|
18
|
+
|
|
19
|
+
// Generate text
|
|
20
|
+
const result = await g.generate("Write a haiku");
|
|
21
|
+
console.log(result.text);
|
|
22
|
+
|
|
23
|
+
// Stream responses
|
|
24
|
+
for await (const chunk of g.stream("Tell me a story")) {
|
|
25
|
+
process.stdout.write(chunk);
|
|
26
|
+
}
|
|
27
|
+
\`\`\``,
|
|
28
|
+
generate: `Generate text with options:
|
|
29
|
+
\`\`\`typescript
|
|
30
|
+
const result = await gerbil.generate(prompt, {
|
|
31
|
+
maxTokens: 256, // Max tokens to generate
|
|
32
|
+
temperature: 0.7, // 0-2, higher = more creative
|
|
33
|
+
topP: 0.9, // Nucleus sampling
|
|
34
|
+
topK: 50, // Top-k sampling
|
|
35
|
+
thinking: false, // Enable reasoning mode (Qwen3)
|
|
36
|
+
system: "You are...", // System prompt
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Result contains:
|
|
40
|
+
result.text // Generated text
|
|
41
|
+
result.thinking // Reasoning (if thinking=true)
|
|
42
|
+
result.tokensGenerated
|
|
43
|
+
result.tokensPerSecond
|
|
44
|
+
result.totalTime
|
|
45
|
+
\`\`\``,
|
|
46
|
+
stream: `Streaming responses:
|
|
47
|
+
\`\`\`typescript
|
|
48
|
+
for await (const chunk of gerbil.stream("Hello")) {
|
|
49
|
+
process.stdout.write(chunk);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// With options
|
|
53
|
+
const stream = gerbil.stream("Explain React", {
|
|
54
|
+
maxTokens: 500,
|
|
55
|
+
onToken: (token) => console.log(token),
|
|
56
|
+
});
|
|
57
|
+
\`\`\``,
|
|
58
|
+
json: `Structured JSON output with Zod validation:
|
|
59
|
+
\`\`\`typescript
|
|
60
|
+
import { z } from "zod";
|
|
61
|
+
|
|
62
|
+
const PersonSchema = z.object({
|
|
63
|
+
name: z.string(),
|
|
64
|
+
age: z.number(),
|
|
65
|
+
city: z.string(),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const data = await gerbil.json("Extract: John is 32 and lives in NYC", {
|
|
69
|
+
schema: PersonSchema,
|
|
70
|
+
retries: 3, // Retry on validation failure
|
|
71
|
+
temperature: 0.3, // Lower = more consistent
|
|
72
|
+
});
|
|
73
|
+
// { name: "John", age: 32, city: "NYC" }
|
|
74
|
+
\`\`\``,
|
|
75
|
+
thinking: `Thinking mode (chain-of-thought reasoning) - Qwen3 models:
|
|
76
|
+
\`\`\`typescript
|
|
77
|
+
const result = await gerbil.generate("What is 127 × 43?", {
|
|
78
|
+
thinking: true,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
console.log(result.thinking);
|
|
82
|
+
// "Let me calculate step by step: 127 × 43 = 127 × 40 + 127 × 3..."
|
|
83
|
+
|
|
84
|
+
console.log(result.text);
|
|
85
|
+
// "5461"
|
|
86
|
+
\`\`\`
|
|
87
|
+
|
|
88
|
+
Enable in chat with /no_think or /think commands, or enable_thinking parameter.`,
|
|
89
|
+
embed: `Generate embeddings:
|
|
90
|
+
\`\`\`typescript
|
|
91
|
+
// Single text
|
|
92
|
+
const { vector } = await gerbil.embed("Hello world");
|
|
93
|
+
// vector: number[] (384 dimensions by default)
|
|
94
|
+
|
|
95
|
+
// Batch
|
|
96
|
+
const results = await gerbil.embedBatch(["Hello", "World"]);
|
|
97
|
+
\`\`\``,
|
|
98
|
+
models: `Available models:
|
|
99
|
+
|
|
100
|
+
| Model | Size | Best For |
|
|
101
|
+
|-------|------|----------|
|
|
102
|
+
| qwen3-0.6b | ~400MB | General use, reasoning (thinking mode) |
|
|
103
|
+
| qwen2.5-0.5b | ~350MB | Fast and capable |
|
|
104
|
+
| qwen2.5-coder-0.5b | ~400MB | Code generation |
|
|
105
|
+
| smollm2-360m | ~250MB | Very fast, simple tasks |
|
|
106
|
+
| smollm2-135m | ~100MB | Fastest, basic generation |
|
|
107
|
+
| phi-3-mini | ~2.1GB | High quality, larger |
|
|
108
|
+
|
|
109
|
+
Load any HuggingFace model:
|
|
110
|
+
\`\`\`typescript
|
|
111
|
+
await gerbil.loadModel("hf:org/model");
|
|
112
|
+
await gerbil.loadModel("onnx-community/Qwen3-0.6B-ONNX");
|
|
113
|
+
\`\`\``,
|
|
114
|
+
load: `Loading models:
|
|
115
|
+
\`\`\`typescript
|
|
116
|
+
await gerbil.loadModel("qwen3-0.6b", {
|
|
117
|
+
device: "auto", // "auto" | "gpu" | "cpu"
|
|
118
|
+
dtype: "q4", // "q4" | "q8" | "fp16" | "fp32"
|
|
119
|
+
onProgress: (p) => {
|
|
120
|
+
console.log(p.status, p.progress, p.file);
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
\`\`\``,
|
|
124
|
+
"ai-sdk": `Vercel AI SDK v5 integration:
|
|
125
|
+
\`\`\`typescript
|
|
126
|
+
import { generateText, streamText } from "ai";
|
|
127
|
+
import { gerbil } from "gerbil/ai";
|
|
128
|
+
|
|
129
|
+
// Generate
|
|
130
|
+
const { text } = await generateText({
|
|
131
|
+
model: gerbil("qwen3-0.6b"),
|
|
132
|
+
prompt: "Write a commit message",
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Stream
|
|
136
|
+
const stream = streamText({
|
|
137
|
+
model: gerbil("qwen3-0.6b"),
|
|
138
|
+
prompt: "Explain React hooks",
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
for await (const chunk of stream.textStream) {
|
|
142
|
+
process.stdout.write(chunk);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// With thinking mode
|
|
146
|
+
const { text } = await generateText({
|
|
147
|
+
model: gerbil("qwen3-0.6b", { thinking: true }),
|
|
148
|
+
prompt: "What is 127 × 43?",
|
|
149
|
+
});
|
|
150
|
+
\`\`\``,
|
|
151
|
+
next: `Next.js App Router integration:
|
|
152
|
+
\`\`\`typescript
|
|
153
|
+
// app/api/chat/route.ts
|
|
154
|
+
import { gerbil } from "gerbil/next";
|
|
155
|
+
|
|
156
|
+
export const POST = gerbil.handler({
|
|
157
|
+
model: "qwen3-0.6b",
|
|
158
|
+
maxTokens: 500,
|
|
159
|
+
});
|
|
160
|
+
\`\`\``,
|
|
161
|
+
express: `Express.js integration:
|
|
162
|
+
\`\`\`typescript
|
|
163
|
+
import express from "express";
|
|
164
|
+
import { gerbil } from "gerbil/express";
|
|
165
|
+
|
|
166
|
+
const app = express();
|
|
167
|
+
app.use("/ai", gerbil()());
|
|
168
|
+
|
|
169
|
+
// Endpoints created:
|
|
170
|
+
// POST /ai/generate - Generate text
|
|
171
|
+
// POST /ai/stream - Stream text
|
|
172
|
+
// POST /ai/json - Structured output
|
|
173
|
+
// POST /ai/embed - Embeddings
|
|
174
|
+
\`\`\``,
|
|
175
|
+
react: `React hooks:
|
|
176
|
+
\`\`\`typescript
|
|
177
|
+
import { useGerbil, useChat } from "gerbil/react";
|
|
178
|
+
|
|
179
|
+
function Chat() {
|
|
180
|
+
const { generate, isLoading } = useGerbil();
|
|
181
|
+
|
|
182
|
+
const handleSubmit = async (prompt: string) => {
|
|
183
|
+
const result = await generate(prompt);
|
|
184
|
+
console.log(result.text);
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
\`\`\``,
|
|
188
|
+
hono: `Hono integration:
|
|
189
|
+
\`\`\`typescript
|
|
190
|
+
import { Hono } from "hono";
|
|
191
|
+
import { gerbil } from "gerbil/hono";
|
|
192
|
+
|
|
193
|
+
const app = new Hono();
|
|
194
|
+
app.route("/ai", await gerbil()());
|
|
195
|
+
\`\`\``,
|
|
196
|
+
langchain: `LangChain integration:
|
|
197
|
+
\`\`\`typescript
|
|
198
|
+
import { GerbilLLM, GerbilEmbeddings } from "gerbil/langchain";
|
|
199
|
+
|
|
200
|
+
const llm = new GerbilLLM({ model: "qwen3-0.6b" });
|
|
201
|
+
const embeddings = new GerbilEmbeddings();
|
|
202
|
+
|
|
203
|
+
// Use with chains
|
|
204
|
+
const chain = new LLMChain({ llm, prompt: template });
|
|
205
|
+
\`\`\``,
|
|
206
|
+
mcp: `MCP Server for Claude Desktop & Cursor:
|
|
207
|
+
\`\`\`bash
|
|
208
|
+
gerbil serve --mcp
|
|
209
|
+
\`\`\`
|
|
210
|
+
|
|
211
|
+
Skills are automatically exposed as MCP tools:
|
|
212
|
+
- gerbil_generate
|
|
213
|
+
- gerbil_commit
|
|
214
|
+
- gerbil_summarize
|
|
215
|
+
- gerbil_explain
|
|
216
|
+
- etc.`,
|
|
217
|
+
skills: `Skills are reusable AI tasks with Zod validation:
|
|
218
|
+
\`\`\`typescript
|
|
219
|
+
import { commit, summarize, explain, review } from "gerbil/skills";
|
|
220
|
+
|
|
221
|
+
// Generate commit message
|
|
222
|
+
const msg = await commit({ type: "conventional", maxLength: 72 });
|
|
223
|
+
|
|
224
|
+
// Summarize content
|
|
225
|
+
const summary = await summarize({
|
|
226
|
+
content: doc,
|
|
227
|
+
length: "short",
|
|
228
|
+
format: "bullets"
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Explain code
|
|
232
|
+
const explanation = await explain({
|
|
233
|
+
content: code,
|
|
234
|
+
level: "beginner"
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Code review
|
|
238
|
+
const feedback = await review({
|
|
239
|
+
code,
|
|
240
|
+
focus: ["security", "performance"]
|
|
241
|
+
});
|
|
242
|
+
\`\`\`
|
|
243
|
+
|
|
244
|
+
Built-in skills: commit, summarize, explain, review, test, translate, extract, title`,
|
|
245
|
+
"define-skill": `Create custom skills:
|
|
246
|
+
\`\`\`typescript
|
|
247
|
+
import { defineSkill } from "gerbil/skills";
|
|
248
|
+
import { z } from "zod";
|
|
249
|
+
|
|
250
|
+
export const sentiment = defineSkill({
|
|
251
|
+
name: "sentiment",
|
|
252
|
+
description: "Analyze text sentiment",
|
|
253
|
+
input: z.object({
|
|
254
|
+
text: z.string(),
|
|
255
|
+
detailed: z.boolean().default(false)
|
|
256
|
+
}),
|
|
257
|
+
output: z.object({
|
|
258
|
+
sentiment: z.enum(["positive", "negative", "neutral"]),
|
|
259
|
+
confidence: z.number(),
|
|
260
|
+
}),
|
|
261
|
+
temperature: 0.3,
|
|
262
|
+
maxTokens: 100,
|
|
263
|
+
|
|
264
|
+
async run({ input, gerbil }) {
|
|
265
|
+
return gerbil.json(\`Sentiment of: \${input.text}\`, {
|
|
266
|
+
schema: this.output,
|
|
267
|
+
});
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
\`\`\``,
|
|
271
|
+
"load-skills": `Load skills from files:
|
|
272
|
+
\`\`\`typescript
|
|
273
|
+
import { loadSkills, useSkill, listSkills } from "gerbil/skills";
|
|
274
|
+
|
|
275
|
+
// Load from directory (*.skill.ts files)
|
|
276
|
+
await loadSkills("./skills");
|
|
277
|
+
|
|
278
|
+
// Use by name
|
|
279
|
+
const skill = useSkill("my-skill");
|
|
280
|
+
const result = await skill({ text: "Hello" });
|
|
281
|
+
|
|
282
|
+
// List all
|
|
283
|
+
console.log(listSkills()); // ["commit", "summarize", ...]
|
|
284
|
+
\`\`\``,
|
|
285
|
+
cli: `CLI commands:
|
|
286
|
+
\`\`\`bash
|
|
287
|
+
gerbil "Write a haiku" # Generate text
|
|
288
|
+
gerbil -m qwen3-0.6b "prompt" # Specify model
|
|
289
|
+
gerbil --thinking "127 × 43" # Enable reasoning
|
|
290
|
+
|
|
291
|
+
gerbil commit # Git commit message
|
|
292
|
+
gerbil summarize README.md # Summarize file
|
|
293
|
+
gerbil explain src/index.ts # Explain code
|
|
294
|
+
|
|
295
|
+
gerbil chat # Interactive chat
|
|
296
|
+
gerbil chat --thinking # With reasoning
|
|
297
|
+
|
|
298
|
+
gerbil serve # HTTP server
|
|
299
|
+
gerbil serve --mcp # MCP server
|
|
300
|
+
|
|
301
|
+
gerbil models # List models
|
|
302
|
+
gerbil cache # Show cached models
|
|
303
|
+
gerbil bench # Benchmark
|
|
304
|
+
gerbil info # System info
|
|
305
|
+
|
|
306
|
+
gerbil repl # Interactive TUI
|
|
307
|
+
\`\`\``,
|
|
308
|
+
tools: `Gerbil supports tool calling with Qwen3 models:
|
|
309
|
+
\`\`\`typescript
|
|
310
|
+
import { defineTool, executeToolCall } from "gerbil";
|
|
311
|
+
|
|
312
|
+
const weatherTool = defineTool({
|
|
313
|
+
name: "get_weather",
|
|
314
|
+
description: "Get current weather for a city",
|
|
315
|
+
parameters: z.object({
|
|
316
|
+
city: z.string(),
|
|
317
|
+
}),
|
|
318
|
+
execute: async ({ city }) => {
|
|
319
|
+
return \`Weather in \${city}: 72°F, sunny\`;
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
\`\`\`
|
|
323
|
+
|
|
324
|
+
In the REPL, use Agent mode (Tab → Agent) to enable tools.`
|
|
325
|
+
};
|
|
326
|
+
/**
|
|
327
|
+
* Get all available documentation topics
|
|
328
|
+
*/
|
|
329
|
+
function getDocTopics() {
|
|
330
|
+
return Object.keys(GERBIL_DOCS);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Search documentation by topic
|
|
334
|
+
*/
|
|
335
|
+
function searchDocs(query) {
|
|
336
|
+
const keyWords = query.toLowerCase().split(/\s+/).filter((w) => w.length > 2);
|
|
337
|
+
for (const [key, content] of Object.entries(GERBIL_DOCS)) {
|
|
338
|
+
const keyNorm = key.replace(/-/g, "");
|
|
339
|
+
for (const word of keyWords) if (keyNorm === word || key === word || keyNorm.includes(word)) return content;
|
|
340
|
+
}
|
|
341
|
+
for (const word of keyWords) for (const [key, content] of Object.entries(GERBIL_DOCS)) if (key.includes(word) || word.includes(key.replace(/-/g, ""))) return content;
|
|
342
|
+
const matches = [];
|
|
343
|
+
for (const [key, content] of Object.entries(GERBIL_DOCS)) for (const word of keyWords) if (content.toLowerCase().includes(word)) {
|
|
344
|
+
matches.push(`## ${key}\n${content}`);
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
if (matches.length > 0) return matches.slice(0, 2).join("\n\n---\n\n");
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
//#endregion
|
|
352
|
+
//#region src/core/tools.ts
|
|
353
|
+
/**
|
|
354
|
+
* Tool Calling System for Gerbil
|
|
355
|
+
*
|
|
356
|
+
* Enables LLMs to call functions/tools during generation.
|
|
357
|
+
* Compatible with Qwen3's tool calling format.
|
|
358
|
+
*/
|
|
359
|
+
let toolContext = null;
|
|
360
|
+
/**
|
|
361
|
+
* Set the tool context (call this after loading a model)
|
|
362
|
+
*/
|
|
363
|
+
function setToolContext(ctx) {
|
|
364
|
+
toolContext = ctx;
|
|
365
|
+
}
|
|
366
|
+
const toolRegistry = /* @__PURE__ */ new Map();
|
|
367
|
+
/**
|
|
368
|
+
* Define a tool
|
|
369
|
+
*/
|
|
370
|
+
function defineTool(def) {
|
|
371
|
+
const tool = async (params) => {
|
|
372
|
+
if (def.parameters) {
|
|
373
|
+
const parsed = def.parameters.parse(params);
|
|
374
|
+
return def.execute(parsed, toolContext);
|
|
375
|
+
}
|
|
376
|
+
return def.execute(params, toolContext);
|
|
377
|
+
};
|
|
378
|
+
tool.definition = def;
|
|
379
|
+
toolRegistry.set(def.name, tool);
|
|
380
|
+
return tool;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Get tool by name
|
|
384
|
+
*/
|
|
385
|
+
function getTool(name) {
|
|
386
|
+
return toolRegistry.get(name);
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Get all tool definitions for prompt injection
|
|
390
|
+
*/
|
|
391
|
+
function getToolDefinitions() {
|
|
392
|
+
return Array.from(toolRegistry.values()).map((t) => t.definition);
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Load tools from a directory
|
|
396
|
+
* Tools are simple .ts files with a default export config object
|
|
397
|
+
* No module imports - we eval the execute function directly
|
|
398
|
+
*/
|
|
399
|
+
async function loadTools(dir) {
|
|
400
|
+
const fs = await import("fs");
|
|
401
|
+
const pathModule = await import("path");
|
|
402
|
+
if (!fs.existsSync(dir)) return [];
|
|
403
|
+
const files = fs.readdirSync(dir).filter((f) => f.endsWith(".tool.ts") || f.endsWith(".tool.js"));
|
|
404
|
+
const results = [];
|
|
405
|
+
for (const file of files) {
|
|
406
|
+
const filePath = pathModule.join(dir, file);
|
|
407
|
+
const toolName = file.replace(/\.tool\.(ts|js)$/, "");
|
|
408
|
+
try {
|
|
409
|
+
const config = parseToolFile(fs.readFileSync(filePath, "utf-8"), toolName);
|
|
410
|
+
if (config) {
|
|
411
|
+
defineTool({
|
|
412
|
+
name: config.name,
|
|
413
|
+
description: config.description,
|
|
414
|
+
execute: async (params, ctx) => {
|
|
415
|
+
const executeFn = config.execute;
|
|
416
|
+
const result = await executeFn(params, ctx);
|
|
417
|
+
return typeof result === "string" ? result : String(result);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
results.push({
|
|
421
|
+
name: config.name,
|
|
422
|
+
loaded: true,
|
|
423
|
+
path: filePath
|
|
424
|
+
});
|
|
425
|
+
} else results.push({
|
|
426
|
+
name: toolName,
|
|
427
|
+
loaded: false,
|
|
428
|
+
error: "Could not parse tool config",
|
|
429
|
+
path: filePath
|
|
430
|
+
});
|
|
431
|
+
} catch (e) {
|
|
432
|
+
const errorMsg = e instanceof Error ? e.message.split("\n")[0] : String(e);
|
|
433
|
+
results.push({
|
|
434
|
+
name: toolName,
|
|
435
|
+
loaded: false,
|
|
436
|
+
error: errorMsg,
|
|
437
|
+
path: filePath
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return results;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Parse a simple tool file and extract the config
|
|
445
|
+
* Expected format:
|
|
446
|
+
* ```
|
|
447
|
+
* export default {
|
|
448
|
+
* name: "tool_name",
|
|
449
|
+
* description: "...",
|
|
450
|
+
* execute: async (params) => { ... }
|
|
451
|
+
* }
|
|
452
|
+
* ```
|
|
453
|
+
*/
|
|
454
|
+
function parseToolFile(content, fallbackName) {
|
|
455
|
+
try {
|
|
456
|
+
let cleaned = content.replace(/:\s*\{[^}]+\}/g, "").replace(/:\s*Record<[^>]+>/g, "").replace(/:\s*string\b/g, "").replace(/:\s*number\b/g, "").replace(/:\s*boolean\b/g, "").replace(/:\s*any\b/g, "").replace(/:\s*Promise<[^>]+>/g, "").replace(/export\s+default\s+/, "return ");
|
|
457
|
+
cleaned = cleaned.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
458
|
+
const config = new Function(cleaned)();
|
|
459
|
+
if (config && typeof config === "object" && config.name && config.execute) return {
|
|
460
|
+
name: config.name || fallbackName,
|
|
461
|
+
description: config.description || "No description",
|
|
462
|
+
execute: config.execute
|
|
463
|
+
};
|
|
464
|
+
return null;
|
|
465
|
+
} catch (e) {
|
|
466
|
+
console.error("Failed to parse tool file:", e);
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Load tools from project .gerbil/tools directory
|
|
472
|
+
*/
|
|
473
|
+
async function loadProjectTools() {
|
|
474
|
+
return loadTools((await import("path")).join(process.cwd(), ".gerbil", "tools"));
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Format tools for Qwen3 prompt
|
|
478
|
+
*/
|
|
479
|
+
function formatToolsForPrompt(tools) {
|
|
480
|
+
if (tools.length === 0) return "";
|
|
481
|
+
return `You are a helpful assistant with access to tools.
|
|
482
|
+
|
|
483
|
+
# Tools
|
|
484
|
+
|
|
485
|
+
${tools.map((t) => {
|
|
486
|
+
const params = t.parameters ? zodToJsonSchema(t.parameters) : {
|
|
487
|
+
type: "object",
|
|
488
|
+
properties: {}
|
|
489
|
+
};
|
|
490
|
+
return `## ${t.name}
|
|
491
|
+
|
|
492
|
+
Description: ${t.description}
|
|
493
|
+
Parameters: ${JSON.stringify(params, null, 2)}`;
|
|
494
|
+
}).join("\n\n")}
|
|
495
|
+
|
|
496
|
+
## How to call tools
|
|
497
|
+
|
|
498
|
+
To call a tool, use this exact format:
|
|
499
|
+
<tool_call>
|
|
500
|
+
{"name": "tool_name", "arguments": {"param": "value"}}
|
|
501
|
+
</tool_call>
|
|
502
|
+
|
|
503
|
+
When 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.
|
|
504
|
+
|
|
505
|
+
For other questions, respond normally without calling tools.`;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Parse tool call from response
|
|
509
|
+
*/
|
|
510
|
+
function parseToolCall(response) {
|
|
511
|
+
try {
|
|
512
|
+
const toolCallMatch = response.match(/<tool_call>\s*([\s\S]*?)\s*<\/tool_call>/);
|
|
513
|
+
if (toolCallMatch) {
|
|
514
|
+
const parsed = JSON.parse(toolCallMatch[1]);
|
|
515
|
+
if (parsed.name) return {
|
|
516
|
+
tool: parsed.name,
|
|
517
|
+
params: parsed.arguments || {}
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
const nameArgsMatch = response.match(/\{\s*"name"\s*:\s*"([^"]+)"[^}]*"arguments"\s*:\s*(\{[^}]*\})/);
|
|
521
|
+
if (nameArgsMatch) return {
|
|
522
|
+
tool: nameArgsMatch[1],
|
|
523
|
+
params: JSON.parse(nameArgsMatch[2])
|
|
524
|
+
};
|
|
525
|
+
const toolParamsMatch = response.match(/\{\s*"tool"\s*:\s*"([^"]+)"[^}]*"params"\s*:\s*(\{[^}]*\})/);
|
|
526
|
+
if (toolParamsMatch) return {
|
|
527
|
+
tool: toolParamsMatch[1],
|
|
528
|
+
params: JSON.parse(toolParamsMatch[2])
|
|
529
|
+
};
|
|
530
|
+
const simpleMatch = response.match(/\{\s*"(?:tool|name)"\s*:\s*"([^"]+)"/);
|
|
531
|
+
if (simpleMatch) return {
|
|
532
|
+
tool: simpleMatch[1],
|
|
533
|
+
params: {}
|
|
534
|
+
};
|
|
535
|
+
} catch {}
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Execute a tool call
|
|
540
|
+
*/
|
|
541
|
+
async function executeToolCall(toolName, params) {
|
|
542
|
+
const tool = getTool(toolName);
|
|
543
|
+
if (!tool) return `Error: Unknown tool "${toolName}"`;
|
|
544
|
+
try {
|
|
545
|
+
return await tool(params);
|
|
546
|
+
} catch (e) {
|
|
547
|
+
return `Error executing ${toolName}: ${e}`;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Docs tool - searches gerbil documentation
|
|
552
|
+
* Documentation content is in core/docs.ts
|
|
553
|
+
*/
|
|
554
|
+
const docsTool = defineTool({
|
|
555
|
+
name: "gerbil_docs",
|
|
556
|
+
description: "Search Gerbil documentation for information about features, API, integrations, skills, and usage examples",
|
|
557
|
+
parameters: z.object({ query: z.string().optional().default("quickstart").describe("Topic: quickstart, generate, stream, json, thinking, embed, models, ai-sdk, next, express, react, skills, define-skill, cli, tools") }),
|
|
558
|
+
execute: async ({ query = "quickstart" }) => {
|
|
559
|
+
const result = searchDocs(query);
|
|
560
|
+
if (result) return result;
|
|
561
|
+
return `No documentation found for "${query}". Available topics: ${getDocTopics().join(", ")}`;
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
//#endregion
|
|
566
|
+
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 };
|
|
567
|
+
//# sourceMappingURL=tools-BsiEE6f2.mjs.map
|