@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.
Files changed (103) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +253 -0
  3. package/bin/cli.js +2 -0
  4. package/dist/auto-update-BbNHbSU1.mjs +3 -0
  5. package/dist/browser/index.d.mts +262 -0
  6. package/dist/browser/index.d.mts.map +1 -0
  7. package/dist/browser/index.mjs +755 -0
  8. package/dist/browser/index.mjs.map +1 -0
  9. package/dist/chrome-backend-C5Un08O4.mjs +771 -0
  10. package/dist/chrome-backend-C5Un08O4.mjs.map +1 -0
  11. package/dist/chrome-backend-CtwPENIW.mjs +3 -0
  12. package/dist/chunk-Ct1HF2bE.mjs +7 -0
  13. package/dist/cli.d.mts +1 -0
  14. package/dist/cli.mjs +7078 -0
  15. package/dist/cli.mjs.map +1 -0
  16. package/dist/frameworks/express.d.mts +22 -0
  17. package/dist/frameworks/express.d.mts.map +1 -0
  18. package/dist/frameworks/express.mjs +123 -0
  19. package/dist/frameworks/express.mjs.map +1 -0
  20. package/dist/frameworks/fastify.d.mts +11 -0
  21. package/dist/frameworks/fastify.d.mts.map +1 -0
  22. package/dist/frameworks/fastify.mjs +73 -0
  23. package/dist/frameworks/fastify.mjs.map +1 -0
  24. package/dist/frameworks/hono.d.mts +14 -0
  25. package/dist/frameworks/hono.d.mts.map +1 -0
  26. package/dist/frameworks/hono.mjs +82 -0
  27. package/dist/frameworks/hono.mjs.map +1 -0
  28. package/dist/frameworks/next.d.mts +31 -0
  29. package/dist/frameworks/next.d.mts.map +1 -0
  30. package/dist/frameworks/next.mjs +116 -0
  31. package/dist/frameworks/next.mjs.map +1 -0
  32. package/dist/frameworks/react.d.mts +56 -0
  33. package/dist/frameworks/react.d.mts.map +1 -0
  34. package/dist/frameworks/react.mjs +172 -0
  35. package/dist/frameworks/react.mjs.map +1 -0
  36. package/dist/frameworks/trpc.d.mts +12 -0
  37. package/dist/frameworks/trpc.d.mts.map +1 -0
  38. package/dist/frameworks/trpc.mjs +80 -0
  39. package/dist/frameworks/trpc.mjs.map +1 -0
  40. package/dist/gerbil-BfnsFWRE.mjs +644 -0
  41. package/dist/gerbil-BfnsFWRE.mjs.map +1 -0
  42. package/dist/gerbil-BjW-z7Fq.mjs +5 -0
  43. package/dist/gerbil-DZ1k3ChC.d.mts +138 -0
  44. package/dist/gerbil-DZ1k3ChC.d.mts.map +1 -0
  45. package/dist/index.d.mts +223 -0
  46. package/dist/index.d.mts.map +1 -0
  47. package/dist/index.mjs +13 -0
  48. package/dist/index.mjs.map +1 -0
  49. package/dist/integrations/ai-sdk.d.mts +78 -0
  50. package/dist/integrations/ai-sdk.d.mts.map +1 -0
  51. package/dist/integrations/ai-sdk.mjs +199 -0
  52. package/dist/integrations/ai-sdk.mjs.map +1 -0
  53. package/dist/integrations/langchain.d.mts +41 -0
  54. package/dist/integrations/langchain.d.mts.map +1 -0
  55. package/dist/integrations/langchain.mjs +93 -0
  56. package/dist/integrations/langchain.mjs.map +1 -0
  57. package/dist/integrations/llamaindex.d.mts +45 -0
  58. package/dist/integrations/llamaindex.d.mts.map +1 -0
  59. package/dist/integrations/llamaindex.mjs +86 -0
  60. package/dist/integrations/llamaindex.mjs.map +1 -0
  61. package/dist/integrations/mcp-client.d.mts +206 -0
  62. package/dist/integrations/mcp-client.d.mts.map +1 -0
  63. package/dist/integrations/mcp-client.mjs +507 -0
  64. package/dist/integrations/mcp-client.mjs.map +1 -0
  65. package/dist/integrations/mcp.d.mts +177 -0
  66. package/dist/integrations/mcp.d.mts.map +1 -0
  67. package/dist/integrations/mcp.mjs +8 -0
  68. package/dist/mcp-R8kRLIKb.mjs +348 -0
  69. package/dist/mcp-R8kRLIKb.mjs.map +1 -0
  70. package/dist/models-DKULvhOr.mjs +136 -0
  71. package/dist/models-DKULvhOr.mjs.map +1 -0
  72. package/dist/models-De2-_GmQ.d.mts +22 -0
  73. package/dist/models-De2-_GmQ.d.mts.map +1 -0
  74. package/dist/one-liner-BUQR0nqq.mjs +98 -0
  75. package/dist/one-liner-BUQR0nqq.mjs.map +1 -0
  76. package/dist/skills/index.d.mts +390 -0
  77. package/dist/skills/index.d.mts.map +1 -0
  78. package/dist/skills/index.mjs +7 -0
  79. package/dist/skills-D3CEpgDc.mjs +630 -0
  80. package/dist/skills-D3CEpgDc.mjs.map +1 -0
  81. package/dist/tools-BsiEE6f2.mjs +567 -0
  82. package/dist/tools-BsiEE6f2.mjs.map +1 -0
  83. package/dist/types-BS1N92Jt.d.mts +183 -0
  84. package/dist/types-BS1N92Jt.d.mts.map +1 -0
  85. package/dist/utils-7vXqtq2Q.mjs +63 -0
  86. package/dist/utils-7vXqtq2Q.mjs.map +1 -0
  87. package/docs/ai-sdk.md +80 -0
  88. package/docs/architecture/README.md +84 -0
  89. package/docs/architecture/caching.md +227 -0
  90. package/docs/architecture/inference.md +176 -0
  91. package/docs/architecture/overview.md +179 -0
  92. package/docs/architecture/streaming.md +261 -0
  93. package/docs/architecture/webgpu.md +213 -0
  94. package/docs/browser.md +328 -0
  95. package/docs/cli.md +155 -0
  96. package/docs/frameworks.md +90 -0
  97. package/docs/mcp-client.md +224 -0
  98. package/docs/mcp.md +109 -0
  99. package/docs/memory.md +229 -0
  100. package/docs/repl.md +473 -0
  101. package/docs/skills.md +261 -0
  102. package/docs/tools.md +304 -0
  103. package/package.json +207 -0
package/docs/skills.md ADDED
@@ -0,0 +1,261 @@
1
+ # Gerbil Skills
2
+
3
+ Skills are reusable AI tasks with Zod-validated inputs and outputs.
4
+
5
+ ## Built-in Skills
6
+
7
+ ```typescript
8
+ import {
9
+ commit, summarize, explain, review,
10
+ test, translate, extract, title
11
+ } from "@tryhamster/gerbil/skills";
12
+ ```
13
+
14
+ ### commit
15
+
16
+ Generate git commit messages from staged changes.
17
+
18
+ ```typescript
19
+ const msg = await commit({
20
+ type: "conventional", // "conventional" | "simple" | "detailed"
21
+ maxLength: 72
22
+ });
23
+ ```
24
+
25
+ ### summarize
26
+
27
+ Summarize content.
28
+
29
+ ```typescript
30
+ const summary = await summarize({
31
+ content: document,
32
+ length: "short", // "short" | "medium" | "long"
33
+ format: "bullets", // "paragraph" | "bullets"
34
+ focus: ["key points"]
35
+ });
36
+ ```
37
+
38
+ ### explain
39
+
40
+ Explain code or concepts.
41
+
42
+ ```typescript
43
+ const explanation = await explain({
44
+ content: code,
45
+ level: "beginner", // "beginner" | "intermediate" | "expert"
46
+ language: "typescript"
47
+ });
48
+ ```
49
+
50
+ ### review
51
+
52
+ Code review.
53
+
54
+ ```typescript
55
+ const feedback = await review({
56
+ code,
57
+ focus: ["security", "performance"], // "security" | "performance" | "style" | "bugs" | "all"
58
+ format: "detailed" // "inline" | "summary" | "detailed"
59
+ });
60
+ ```
61
+
62
+ ### test
63
+
64
+ Generate tests.
65
+
66
+ ```typescript
67
+ const tests = await test({
68
+ code,
69
+ framework: "vitest", // "jest" | "vitest" | "mocha" | "playwright"
70
+ style: "unit" // "unit" | "integration" | "e2e"
71
+ });
72
+ ```
73
+
74
+ ### translate
75
+
76
+ Translate text.
77
+
78
+ ```typescript
79
+ const spanish = await translate({
80
+ text,
81
+ to: "es",
82
+ from: "en", // optional, auto-detected
83
+ preserveFormatting: true
84
+ });
85
+ ```
86
+
87
+ ### extract
88
+
89
+ Extract structured data.
90
+
91
+ ```typescript
92
+ const data = await extract({
93
+ content: "John is 32 and lives in NYC",
94
+ schema: z.object({ name: z.string(), age: z.number(), city: z.string() }),
95
+ context: "Extract person info"
96
+ });
97
+ ```
98
+
99
+ ### title
100
+
101
+ Generate titles.
102
+
103
+ ```typescript
104
+ const heading = await title({
105
+ content: article,
106
+ style: "seo", // "professional" | "clickbait" | "seo" | "simple"
107
+ maxLength: 60
108
+ });
109
+ ```
110
+
111
+ ## Custom Skills
112
+
113
+ ### defineSkill
114
+
115
+ Create a custom skill:
116
+
117
+ ```typescript
118
+ import { defineSkill } from "@tryhamster/gerbil/skills";
119
+ import { z } from "zod";
120
+
121
+ export const sentiment = defineSkill({
122
+ // Required
123
+ name: "sentiment", // kebab-case
124
+ description: "Analyze text sentiment",
125
+
126
+ // Input/Output validation
127
+ input: z.object({
128
+ text: z.string(),
129
+ detailed: z.boolean().default(false)
130
+ }),
131
+ output: z.object({
132
+ sentiment: z.enum(["positive", "negative", "neutral"]),
133
+ confidence: z.number(),
134
+ keywords: z.array(z.string()).optional()
135
+ }),
136
+
137
+ // Defaults
138
+ temperature: 0.3,
139
+ maxTokens: 100,
140
+ thinking: false,
141
+
142
+ // Model (skill loads this automatically if different from current)
143
+ model: "qwen2.5-coder-0.5b",
144
+
145
+ // Metadata
146
+ version: "1.0.0",
147
+ author: "your-name",
148
+
149
+ // Implementation - receives (input, gerbil)
150
+ async run(input, gerbil) {
151
+ const prompt = input.detailed
152
+ ? `Analyze sentiment with keywords: ${input.text}`
153
+ : `What is the sentiment: ${input.text}`;
154
+
155
+ return gerbil.json(prompt, { schema: this.output });
156
+ },
157
+ });
158
+ ```
159
+
160
+ ### File Convention
161
+
162
+ Skills can be loaded from files matching `*.skill.ts` or `*.skill.js`:
163
+
164
+ ```typescript
165
+ // skills/sentiment.skill.ts
166
+ import { defineSkill } from "@tryhamster/gerbil/skills";
167
+
168
+ export default defineSkill({
169
+ name: "sentiment",
170
+ // ...
171
+ });
172
+ ```
173
+
174
+ ### Loading Skills
175
+
176
+ ```typescript
177
+ import { loadSkills, loadSkillPackage, useSkill } from "@tryhamster/gerbil/skills";
178
+
179
+ // Load from directory
180
+ await loadSkills("./skills"); // loads *.skill.ts files
181
+
182
+ // Load from npm package
183
+ await loadSkillPackage("gerbil-skills-extra");
184
+
185
+ // Use by name
186
+ const sentiment = useSkill("sentiment");
187
+ const result = await sentiment({ text: "I love this!" });
188
+ ```
189
+
190
+ ### Skill-Specific Models
191
+
192
+ Skills can specify which model they prefer:
193
+
194
+ ```typescript
195
+ export const codeReview = defineSkill({
196
+ name: "code-review",
197
+ description: "Review code for issues",
198
+ model: "qwen2.5-coder-0.5b", // Uses coder model
199
+
200
+ async run(input, gerbil) {
201
+ // gerbil is already loaded with qwen2.5-coder-0.5b
202
+ return gerbil.generate(`Review this code: ${input.code}`);
203
+ },
204
+ });
205
+ ```
206
+
207
+ When a skill specifies a different model than the currently loaded one, Gerbil automatically switches models. To avoid this overhead, you can pre-load the skill's model or pass your own Gerbil instance:
208
+
209
+ ```typescript
210
+ // Option 1: Let skill switch automatically (may incur loading time)
211
+ const result = await codeReview({ code: myCode });
212
+
213
+ // Option 2: Pass pre-loaded Gerbil instance
214
+ const g = new Gerbil();
215
+ await g.loadModel("qwen2.5-coder-0.5b");
216
+ const result = await codeReview.run({ code: myCode }, g);
217
+ ```
218
+
219
+ ### Registry API
220
+
221
+ ```typescript
222
+ import {
223
+ listSkills, // Get all skill names
224
+ getSkillInfo, // Get skill metadata
225
+ hasSkill, // Check if skill exists
226
+ removeSkill, // Unregister a skill
227
+ clearSkills // Clear all skills
228
+ } from "@tryhamster/gerbil/skills";
229
+
230
+ console.log(listSkills());
231
+ // ["commit", "summarize", "explain", "review", ...]
232
+
233
+ const info = getSkillInfo("commit");
234
+ // { name, description, version, author, builtin: true }
235
+ ```
236
+
237
+ ## REPL Skills View
238
+
239
+ In the Gerbil REPL, press `2` or navigate to **Skills** to access all available skills.
240
+
241
+ **Controls:**
242
+ - **Up/Down** — Navigate skill list
243
+ - **Enter** — Select and run a skill
244
+ - **c** — Create a new skill (opens wizard)
245
+ - **Esc** — Back to menu
246
+
247
+ The first option **"+ Create new skill"** opens a guided wizard that helps you build a custom skill step-by-step.
248
+
249
+ ---
250
+
251
+ ## MCP Integration
252
+
253
+ Skills are automatically exposed as MCP tools:
254
+
255
+ ```bash
256
+ gerbil serve --mcp
257
+ ```
258
+
259
+ Each skill becomes a tool: `gerbil_commit`, `gerbil_summarize`, etc.
260
+
261
+ Custom skills loaded via `loadSkills()` are also exposed.
package/docs/tools.md ADDED
@@ -0,0 +1,304 @@
1
+ # Gerbil Tools & Agents
2
+
3
+ Gerbil supports tool calling with Qwen3 models, enabling agentic workflows where the LLM can call functions to accomplish tasks.
4
+
5
+ ## Quick Start
6
+
7
+ ### Simple Tool (Recommended)
8
+
9
+ Create a file in `.gerbil/tools/` with the `.tool.ts` extension:
10
+
11
+ ```typescript
12
+ // .gerbil/tools/get_weather.tool.ts
13
+
14
+ export default {
15
+ name: "get_weather",
16
+ description: "Get current weather for a city",
17
+ parameters: {
18
+ city: { type: "string", description: "City name" },
19
+ },
20
+ execute: async (params: { city: string }) => {
21
+ return `Weather in ${params.city}: 72°F, sunny`;
22
+ },
23
+ };
24
+ ```
25
+
26
+ That's it! Gerbil automatically loads tools from `.gerbil/tools/` when the REPL starts.
27
+
28
+ ### Advanced Tool (with Zod)
29
+
30
+ For more complex validation, use `defineTool` with Zod schemas:
31
+
32
+ ```typescript
33
+ import { defineTool } from "@tryhamster/gerbil";
34
+ import { z } from "zod";
35
+
36
+ export const weatherTool = defineTool({
37
+ name: "get_weather",
38
+ description: "Get current weather for a city",
39
+ parameters: z.object({
40
+ city: z.string().describe("City name"),
41
+ units: z.enum(["celsius", "fahrenheit"]).optional().default("fahrenheit"),
42
+ }),
43
+ execute: async ({ city, units }) => {
44
+ return `Weather in ${city}: ${units === "celsius" ? "22°C" : "72°F"}, sunny`;
45
+ },
46
+ });
47
+ ```
48
+
49
+ ## Project Tools
50
+
51
+ Store your custom tools in `.gerbil/tools/`:
52
+
53
+ ```
54
+ .gerbil/
55
+ └── tools/
56
+ ├── get_weather.tool.ts
57
+ ├── search_docs.tool.ts
58
+ └── calculator.tool.ts
59
+ ```
60
+
61
+ ### Tool File Format
62
+
63
+ Each `.tool.ts` file exports a config object:
64
+
65
+ ```typescript
66
+ // .gerbil/tools/my_tool.tool.ts
67
+
68
+ export default {
69
+ name: "my_tool", // Tool name (snake_case)
70
+ description: "What the tool does", // LLM uses this to decide when to call
71
+ parameters: { // Optional input parameters
72
+ param1: { type: "string", description: "First param" },
73
+ param2: { type: "number", optional: true },
74
+ },
75
+ execute: async (params) => {
76
+ // Your implementation
77
+ return "result string";
78
+ },
79
+ };
80
+ ```
81
+
82
+ ### Managing Tools in REPL
83
+
84
+ Press `3` or select **Tools** from the menu to:
85
+ - View all registered tools (builtin + project)
86
+ - Create new tools with the guided wizard
87
+ - Execute tools directly with `x`
88
+ - Open tool files in VS Code with `o`
89
+
90
+ ## Built-in Tools
91
+
92
+ ### `gerbil_docs`
93
+
94
+ Search Gerbil documentation for any topic.
95
+
96
+ ```typescript
97
+ import { docsTool } from "@tryhamster/gerbil";
98
+
99
+ const result = await docsTool({ query: "streaming" });
100
+ // Returns documentation about streaming responses
101
+ ```
102
+
103
+ **Available topics:**
104
+ - `quickstart` — Getting started
105
+ - `generate` — Text generation options
106
+ - `stream` — Streaming responses
107
+ - `json` — Structured JSON output
108
+ - `thinking` — Chain-of-thought reasoning
109
+ - `embed` — Embeddings
110
+ - `models` — Available models
111
+ - `ai-sdk` — Vercel AI SDK integration
112
+ - `next`, `express`, `react`, `hono` — Framework integrations
113
+ - `skills` — Skills system
114
+ - `cli` — CLI commands
115
+ - `tools` — Tool calling
116
+
117
+ ## Tool Examples
118
+
119
+ ### Calculator
120
+
121
+ ```typescript
122
+ // .gerbil/tools/calculator.tool.ts
123
+
124
+ export default {
125
+ name: "calculator",
126
+ description: "Perform basic math calculations",
127
+ parameters: {
128
+ expression: { type: "string", description: "Math expression like '2 + 2'" },
129
+ },
130
+ execute: async (params: { expression: string }) => {
131
+ try {
132
+ // Simple evaluator (use a proper math lib in production)
133
+ const result = Function(`return ${params.expression}`)();
134
+ return `${params.expression} = ${result}`;
135
+ } catch {
136
+ return `Error: Invalid expression "${params.expression}"`;
137
+ }
138
+ },
139
+ };
140
+ ```
141
+
142
+ ### File Reader
143
+
144
+ ```typescript
145
+ // .gerbil/tools/read_file.tool.ts
146
+
147
+ import fs from "fs/promises";
148
+
149
+ export default {
150
+ name: "read_file",
151
+ description: "Read contents of a file",
152
+ parameters: {
153
+ path: { type: "string", description: "File path to read" },
154
+ },
155
+ execute: async (params: { path: string }) => {
156
+ try {
157
+ const content = await fs.readFile(params.path, "utf-8");
158
+ return content.slice(0, 2000); // Limit output size
159
+ } catch (e) {
160
+ return `Error reading file: ${e}`;
161
+ }
162
+ },
163
+ };
164
+ ```
165
+
166
+ ### API Caller
167
+
168
+ ```typescript
169
+ // .gerbil/tools/fetch_url.tool.ts
170
+
171
+ export default {
172
+ name: "fetch_url",
173
+ description: "Fetch content from a URL",
174
+ parameters: {
175
+ url: { type: "string", description: "URL to fetch" },
176
+ },
177
+ execute: async (params: { url: string }) => {
178
+ try {
179
+ const res = await fetch(params.url);
180
+ const text = await res.text();
181
+ return text.slice(0, 2000);
182
+ } catch (e) {
183
+ return `Error fetching URL: ${e}`;
184
+ }
185
+ },
186
+ };
187
+ ```
188
+
189
+ ### Joke Generator
190
+
191
+ ```typescript
192
+ // .gerbil/tools/generate_joke.tool.ts
193
+
194
+ export default {
195
+ name: "generate_joke",
196
+ description: "Generates a joke based on a theme",
197
+ parameters: {
198
+ theme: { type: "string", description: "The theme (optional)", optional: true },
199
+ },
200
+ execute: async (params: { theme?: string }) => {
201
+ const theme = params?.theme || "programming";
202
+ const jokes: Record<string, string> = {
203
+ programming: "Why do programmers prefer dark mode? Because light attracts bugs!",
204
+ coffee: "Why do Java developers wear glasses? Because they can't C#!",
205
+ ai: "Why did the neural network break up with the algorithm? Too many trust issues!",
206
+ };
207
+ return jokes[theme.toLowerCase()] || `Why did the ${theme} cross the road? To optimize the other side!`;
208
+ },
209
+ };
210
+ ```
211
+
212
+ ## Tool Registry API
213
+
214
+ ```typescript
215
+ import {
216
+ defineTool,
217
+ getTool,
218
+ listTools,
219
+ getToolDefinitions,
220
+ loadProjectTools
221
+ } from "@tryhamster/gerbil";
222
+
223
+ // Load tools from .gerbil/tools/
224
+ await loadProjectTools();
225
+
226
+ // Get tool by name
227
+ const tool = getTool("get_weather");
228
+ await tool({ city: "NYC" });
229
+
230
+ // List all tool names
231
+ console.log(listTools());
232
+ // ["gerbil_docs", "get_weather", "calculator"]
233
+
234
+ // Get all definitions (for prompt injection)
235
+ const definitions = getToolDefinitions();
236
+ ```
237
+
238
+ ## Using Tools in Chat
239
+
240
+ ### REPL Agent Mode
241
+
242
+ The easiest way to use tools is in the REPL's Agent mode:
243
+
244
+ ```bash
245
+ gerbil repl
246
+ # Press ⌘A (Cmd+A) to toggle agent mode
247
+ ```
248
+
249
+ **Toggle shortcuts:**
250
+ - **⌘A (Cmd+A)**: Toggle agent mode on/off (works anywhere)
251
+ - **⌘T (Cmd+T)**: Toggle thinking mode on/off
252
+
253
+ When agent mode is enabled:
254
+ - Shows `+tools` badge in the header
255
+ - Tool calls display in cyan boxes with results
256
+ - Works with any chat persona
257
+
258
+ In Agent mode, the model can:
259
+ 1. See available tools in its system prompt
260
+ 2. Call tools using the `<tool_call>` format
261
+ 3. Receive tool results and synthesize a response
262
+
263
+ ### Programmatic Usage
264
+
265
+ ```typescript
266
+ import {
267
+ formatToolsForPrompt,
268
+ parseToolCall,
269
+ executeToolCall,
270
+ getToolDefinitions
271
+ } from "@tryhamster/gerbil";
272
+
273
+ // Add tools to system prompt
274
+ const tools = getToolDefinitions();
275
+ const systemPrompt = `You are a helpful assistant.\n\n${formatToolsForPrompt(tools)}`;
276
+
277
+ // Generate response
278
+ const response = await gerbil.generate(userQuery, { system: systemPrompt });
279
+
280
+ // Check for tool calls
281
+ const toolCall = parseToolCall(response.text);
282
+ if (toolCall) {
283
+ const result = await executeToolCall(toolCall.tool, toolCall.params);
284
+ // Continue conversation with tool result
285
+ }
286
+ ```
287
+
288
+ ## Best Practices
289
+
290
+ 1. **Clear descriptions** — The model uses descriptions to decide when to call tools
291
+ 2. **Handle missing params** — Use defaults for optional parameters
292
+ 3. **Limit output size** — Long tool outputs consume context (aim for <2000 chars)
293
+ 4. **Return strings** — Execute function must return a string
294
+ 5. **Graceful errors** — Catch exceptions and return helpful error messages
295
+ 6. **Snake_case names** — Use `get_weather` not `getWeather`
296
+
297
+ ## Model Compatibility
298
+
299
+ Tool calling works best with:
300
+ - **Qwen3-0.6B** — Excellent tool calling support, fast
301
+ - **Qwen3-1.7B** — Better reasoning, still fast
302
+ - **Qwen2.5 models** — Good support
303
+
304
+ Smaller models (SmolLM2) may struggle with consistent tool call formatting.