@qodo/sdk 0.4.0 → 0.5.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/.claude/skills/qodo-agent/SKILL.md +658 -0
- package/.claude/skills/qodo-agent/assets/programmatic-agent.ts +317 -0
- package/.claude/skills/qodo-agent/references/builtin-tools.md +342 -0
- package/.claude/skills/qodo-agent/references/common-issues.md +430 -0
- package/dist/api/agent.d.ts +0 -1
- package/dist/api/agent.d.ts.map +1 -1
- package/dist/api/agent.js +5 -127
- package/dist/api/agent.js.map +1 -1
- package/dist/bin/install-skill.d.ts +14 -0
- package/dist/bin/install-skill.d.ts.map +1 -0
- package/dist/bin/install-skill.js +125 -0
- package/dist/bin/install-skill.js.map +1 -0
- package/dist/mcp/MCPManager.d.ts +0 -16
- package/dist/mcp/MCPManager.d.ts.map +1 -1
- package/dist/mcp/MCPManager.js +0 -41
- package/dist/mcp/MCPManager.js.map +1 -1
- package/dist/mcp/builtinServers.d.ts.map +1 -1
- package/dist/mcp/builtinServers.js +0 -12
- package/dist/mcp/builtinServers.js.map +1 -1
- package/dist/mcp/index.d.ts +0 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +0 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/servers/filesystem.d.ts +0 -31
- package/dist/mcp/servers/filesystem.d.ts.map +1 -1
- package/dist/mcp/servers/filesystem.js +0 -222
- package/dist/mcp/servers/filesystem.js.map +1 -1
- package/dist/mcp/servers/shell.d.ts.map +1 -1
- package/dist/mcp/servers/shell.js +21 -105
- package/dist/mcp/servers/shell.js.map +1 -1
- package/dist/mcp/serversRegistry.js +2 -2
- package/dist/mcp/serversRegistry.js.map +1 -1
- package/dist/mcp/toolProcessor.d.ts.map +1 -1
- package/dist/mcp/toolProcessor.js +0 -43
- package/dist/mcp/toolProcessor.js.map +1 -1
- package/dist/sdk/QodoSDK.d.ts.map +1 -1
- package/dist/sdk/QodoSDK.js +0 -9
- package/dist/sdk/QodoSDK.js.map +1 -1
- package/package.json +5 -1
- package/dist/mcp/servers/gerrit.d.ts +0 -19
- package/dist/mcp/servers/gerrit.d.ts.map +0 -1
- package/dist/mcp/servers/gerrit.js +0 -515
- package/dist/mcp/servers/gerrit.js.map +0 -1
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qodo-agent
|
|
3
|
+
description: Development companion for building AI-powered agents with @qodo/sdk. Use when working with QodoSDK, sdkAgent(), sdkCommand(), agent.toml, or any Qodo agent development tasks.
|
|
4
|
+
compatibility: Requires Node.js >= 18, npm, and zod package for schema definitions.
|
|
5
|
+
metadata:
|
|
6
|
+
author: qodo
|
|
7
|
+
version: "1.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Qodo SDK Development Companion
|
|
11
|
+
|
|
12
|
+
Use this skill when working with `@qodo/sdk` to build AI-powered agents. This skill helps you:
|
|
13
|
+
|
|
14
|
+
- **Create** agent configurations (TypeScript and TOML)
|
|
15
|
+
- **Scaffold** Zod schemas with proper patterns and descriptions
|
|
16
|
+
- **Extend** existing agents with new commands, tools, and capabilities
|
|
17
|
+
- **Debug** streaming events, schema validation, and tool execution issues
|
|
18
|
+
- **Refactor** between config formats and improve type safety
|
|
19
|
+
|
|
20
|
+
## Quick Reference
|
|
21
|
+
|
|
22
|
+
### Core Exports
|
|
23
|
+
|
|
24
|
+
| Export | Purpose |
|
|
25
|
+
|--------|---------|
|
|
26
|
+
| `QodoSDK` | Main SDK class - initialize and run agents |
|
|
27
|
+
| `sdkAgent()` | Build agent config programmatically |
|
|
28
|
+
| `sdkCommand()` | Build command config with Zod schemas |
|
|
29
|
+
| `sdkArgs()` | Convenience wrapper for `z.object()` |
|
|
30
|
+
|
|
31
|
+
### Schema Helpers
|
|
32
|
+
|
|
33
|
+
| Export | Purpose |
|
|
34
|
+
|--------|---------|
|
|
35
|
+
| `zodOutputSchema()` | Convert Zod to JSON Schema for output |
|
|
36
|
+
| `zJsonValue()` | Flexible primitive type (string \| number \| boolean \| null) |
|
|
37
|
+
| `zJsonAny()` | Flexible any type (primitives + arrays + objects) |
|
|
38
|
+
| `zCoerce` | CLI-style input coercion (boolean, number, jsonArray, jsonObject) |
|
|
39
|
+
| `parseArgsWithSchema()` | Validate args with Zod, get typed result |
|
|
40
|
+
| `QodoSchemaError` | Schema validation error class |
|
|
41
|
+
|
|
42
|
+
### Event Handling
|
|
43
|
+
|
|
44
|
+
| Export | Purpose |
|
|
45
|
+
|--------|---------|
|
|
46
|
+
| `SdkEventType` | Event type constants (Init, MessageDelta, Final, etc.) |
|
|
47
|
+
| `matchSdkEvent()` | Type-safe event router |
|
|
48
|
+
|
|
49
|
+
### Clients
|
|
50
|
+
|
|
51
|
+
| Export | Purpose |
|
|
52
|
+
|--------|---------|
|
|
53
|
+
| `QodoInfoClient` | Backend info (models, capabilities) |
|
|
54
|
+
| `QodoSessionsClient` | Session history management |
|
|
55
|
+
|
|
56
|
+
### Errors
|
|
57
|
+
|
|
58
|
+
| Export | Purpose |
|
|
59
|
+
|--------|---------|
|
|
60
|
+
| `QodoSchemaError` | Schema validation failures |
|
|
61
|
+
| `QodoAuthError` | Authentication failures |
|
|
62
|
+
| `QodoBackendBootstrapError` | Backend initialization failures |
|
|
63
|
+
|
|
64
|
+
### Built-in Tools
|
|
65
|
+
|
|
66
|
+
Use these in `available_tools` to give your agent capabilities:
|
|
67
|
+
|
|
68
|
+
| Tool | Purpose | Common Use Cases |
|
|
69
|
+
|------|---------|------------------|
|
|
70
|
+
| `filesystem` | File operations | Read/write files, navigate directories, edit code |
|
|
71
|
+
| `git` | Version control | Check status, view diffs, commit changes |
|
|
72
|
+
| `ripgrep` | Code search | Find patterns, locate definitions, search codebase |
|
|
73
|
+
| `shell` | Run commands | Build tools, scripts, system commands |
|
|
74
|
+
|
|
75
|
+
**Example:**
|
|
76
|
+
```typescript
|
|
77
|
+
sdkCommand({
|
|
78
|
+
name: 'analyze',
|
|
79
|
+
available_tools: ['filesystem', 'ripgrep'], // Read files + search
|
|
80
|
+
// ...
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Common Combinations:**
|
|
85
|
+
- **Code analysis**: `['filesystem', 'ripgrep']`
|
|
86
|
+
- **Code review**: `['git', 'filesystem']`
|
|
87
|
+
- **Full development**: `['filesystem', 'git', 'ripgrep', 'shell']`
|
|
88
|
+
|
|
89
|
+
See [references/builtin-tools.md](references/builtin-tools.md) for detailed documentation on each tool.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Critical Rules
|
|
94
|
+
|
|
95
|
+
### For SDK Users (Building Apps)
|
|
96
|
+
|
|
97
|
+
1. **Every output property needs `.describe()`**
|
|
98
|
+
```typescript
|
|
99
|
+
// WRONG - will throw QodoSchemaError
|
|
100
|
+
const output = z.object({
|
|
101
|
+
summary: z.string(),
|
|
102
|
+
score: z.number(),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// CORRECT
|
|
106
|
+
const output = z.object({
|
|
107
|
+
summary: z.string().describe('Brief summary of the analysis'),
|
|
108
|
+
score: z.number().describe('Quality score from 0-100'),
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
2. **Never use `z.any()` in output schemas**
|
|
113
|
+
```typescript
|
|
114
|
+
// WRONG - produces invalid JSON Schema
|
|
115
|
+
const output = z.object({
|
|
116
|
+
data: z.any().describe('The data'),
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// CORRECT - use zJsonValue() or zJsonAny()
|
|
120
|
+
import { zJsonValue, zJsonAny } from '@qodo/sdk';
|
|
121
|
+
|
|
122
|
+
const output = z.object({
|
|
123
|
+
// For primitives only:
|
|
124
|
+
value: zJsonValue().describe('A primitive value'),
|
|
125
|
+
// For any JSON (including objects/arrays):
|
|
126
|
+
data: zJsonAny().describe('Any JSON data'),
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
3. **Always call `sdk.dispose()`**
|
|
131
|
+
```typescript
|
|
132
|
+
const sdk = new QodoSDK({ ... });
|
|
133
|
+
try {
|
|
134
|
+
const result = await sdk.run('analyze', { args: { path: './src' } });
|
|
135
|
+
console.log(result.structured_output);
|
|
136
|
+
} finally {
|
|
137
|
+
await sdk.dispose(); // Cleanup MCP servers and connections
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
4. **Handle errors appropriately**
|
|
142
|
+
```typescript
|
|
143
|
+
import { QodoSchemaError, QodoAuthError } from '@qodo/sdk';
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const result = await sdk.run('analyze');
|
|
147
|
+
} catch (e) {
|
|
148
|
+
if (e instanceof QodoSchemaError) {
|
|
149
|
+
console.error('Schema validation failed:', e.message);
|
|
150
|
+
} else if (e instanceof QodoAuthError) {
|
|
151
|
+
console.error('Authentication failed:', e.message);
|
|
152
|
+
} else {
|
|
153
|
+
throw e;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### For SDK Contributors (Modifying @qodo/sdk)
|
|
159
|
+
|
|
160
|
+
1. **Never use `process.exit()`** - throw errors instead (library code)
|
|
161
|
+
2. **Use `.js` extensions** in imports - ESM requirement
|
|
162
|
+
3. **Export types separately** - TypeScript best practice
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Usage Patterns
|
|
167
|
+
|
|
168
|
+
### Pattern 1: Simple Prompt (No Config)
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { QodoSDK } from '@qodo/sdk';
|
|
172
|
+
|
|
173
|
+
const sdk = new QodoSDK();
|
|
174
|
+
try {
|
|
175
|
+
const result = await sdk.prompt('Explain how async/await works in JavaScript');
|
|
176
|
+
console.log(result.final_output);
|
|
177
|
+
} finally {
|
|
178
|
+
await sdk.dispose();
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Pattern 2: Programmatic Agent with Zod
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import { QodoSDK, sdkAgent, sdkCommand, sdkArgs } from '@qodo/sdk';
|
|
186
|
+
import { z } from 'zod';
|
|
187
|
+
|
|
188
|
+
const agent = sdkAgent({
|
|
189
|
+
instructions: 'You are a code analysis assistant.',
|
|
190
|
+
commands: {
|
|
191
|
+
analyze: sdkCommand({
|
|
192
|
+
name: 'analyze',
|
|
193
|
+
description: 'Analyze code quality',
|
|
194
|
+
instructions: 'Analyze the code and provide a quality assessment.',
|
|
195
|
+
available_tools: ['filesystem', 'ripgrep'],
|
|
196
|
+
args: sdkArgs({
|
|
197
|
+
path: z.string().describe('Path to analyze'),
|
|
198
|
+
depth: z.number().optional().default(3).describe('Max directory depth'),
|
|
199
|
+
}),
|
|
200
|
+
output: z.object({
|
|
201
|
+
summary: z.string().describe('Overall assessment'),
|
|
202
|
+
issues: z.array(z.object({
|
|
203
|
+
file: z.string().describe('File path'),
|
|
204
|
+
line: z.number().describe('Line number'),
|
|
205
|
+
severity: z.enum(['low', 'medium', 'high']).describe('Issue severity'),
|
|
206
|
+
message: z.string().describe('Issue description'),
|
|
207
|
+
})).describe('List of issues found'),
|
|
208
|
+
score: z.number().describe('Quality score 0-100'),
|
|
209
|
+
}),
|
|
210
|
+
}),
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
const sdk = QodoSDK.fromAgent(agent);
|
|
215
|
+
try {
|
|
216
|
+
const result = await sdk.run('analyze', {
|
|
217
|
+
args: { path: './src', depth: 5 },
|
|
218
|
+
});
|
|
219
|
+
console.log('Score:', result.structured_output?.score);
|
|
220
|
+
console.log('Issues:', result.structured_output?.issues);
|
|
221
|
+
} finally {
|
|
222
|
+
await sdk.dispose();
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Pattern 3: TOML Configuration
|
|
227
|
+
|
|
228
|
+
Create `agent.toml`:
|
|
229
|
+
```toml
|
|
230
|
+
version = "1.0"
|
|
231
|
+
instructions = "You are a helpful coding assistant."
|
|
232
|
+
|
|
233
|
+
[commands.review]
|
|
234
|
+
name = "review"
|
|
235
|
+
description = "Review code changes"
|
|
236
|
+
instructions = "Review the provided code changes and suggest improvements."
|
|
237
|
+
available_tools = ["filesystem", "git", "ripgrep"]
|
|
238
|
+
|
|
239
|
+
[commands.review.output_schema]
|
|
240
|
+
type = "json_schema"
|
|
241
|
+
|
|
242
|
+
[commands.review.output_schema.json_schema]
|
|
243
|
+
name = "review_output"
|
|
244
|
+
strict = true
|
|
245
|
+
|
|
246
|
+
[commands.review.output_schema.json_schema.schema]
|
|
247
|
+
type = "object"
|
|
248
|
+
required = ["summary", "suggestions"]
|
|
249
|
+
|
|
250
|
+
[commands.review.output_schema.json_schema.schema.properties.summary]
|
|
251
|
+
type = "string"
|
|
252
|
+
description = "Overall review summary"
|
|
253
|
+
|
|
254
|
+
[commands.review.output_schema.json_schema.schema.properties.suggestions]
|
|
255
|
+
type = "array"
|
|
256
|
+
description = "List of improvement suggestions"
|
|
257
|
+
|
|
258
|
+
[commands.review.output_schema.json_schema.schema.properties.suggestions.items]
|
|
259
|
+
type = "object"
|
|
260
|
+
required = ["file", "suggestion"]
|
|
261
|
+
|
|
262
|
+
[commands.review.output_schema.json_schema.schema.properties.suggestions.items.properties.file]
|
|
263
|
+
type = "string"
|
|
264
|
+
description = "File path"
|
|
265
|
+
|
|
266
|
+
[commands.review.output_schema.json_schema.schema.properties.suggestions.items.properties.suggestion]
|
|
267
|
+
type = "string"
|
|
268
|
+
description = "The suggestion"
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Then use it:
|
|
272
|
+
```typescript
|
|
273
|
+
import { QodoSDK } from '@qodo/sdk';
|
|
274
|
+
|
|
275
|
+
const sdk = new QodoSDK({
|
|
276
|
+
agentFile: './agent.toml',
|
|
277
|
+
});
|
|
278
|
+
try {
|
|
279
|
+
const result = await sdk.run('review');
|
|
280
|
+
console.log(result.structured_output);
|
|
281
|
+
} finally {
|
|
282
|
+
await sdk.dispose();
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Pattern 4: Streaming Events
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import { QodoSDK, SdkEventType, matchSdkEvent } from '@qodo/sdk';
|
|
290
|
+
|
|
291
|
+
const sdk = new QodoSDK();
|
|
292
|
+
try {
|
|
293
|
+
for await (const event of sdk.streamPrompt('Write a haiku about coding')) {
|
|
294
|
+
matchSdkEvent(event, {
|
|
295
|
+
[SdkEventType.MessageDelta]: (e) => {
|
|
296
|
+
process.stdout.write(e.data.delta);
|
|
297
|
+
},
|
|
298
|
+
[SdkEventType.ToolRequested]: (e) => {
|
|
299
|
+
console.log(`\nTool: ${e.data.server_name}.${e.data.tool_name}`);
|
|
300
|
+
},
|
|
301
|
+
[SdkEventType.ToolExecuted]: (e) => {
|
|
302
|
+
console.log(`Tool result: ${e.data.result.isError ? 'error' : 'success'}`);
|
|
303
|
+
},
|
|
304
|
+
[SdkEventType.Error]: (e) => {
|
|
305
|
+
console.error('Error:', e.data.message);
|
|
306
|
+
},
|
|
307
|
+
[SdkEventType.Final]: (e) => {
|
|
308
|
+
console.log('\n\nDone! Success:', e.data.success);
|
|
309
|
+
},
|
|
310
|
+
default: () => {}, // Ignore other events
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
} finally {
|
|
314
|
+
await sdk.dispose();
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Pattern 5: Custom Tool Approval
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { QodoSDK } from '@qodo/sdk';
|
|
322
|
+
import * as readline from 'readline';
|
|
323
|
+
|
|
324
|
+
const sdk = new QodoSDK({
|
|
325
|
+
autoApproveTools: false,
|
|
326
|
+
toolApproval: async ({ tool_name, server_name, tool_args }) => {
|
|
327
|
+
const rl = readline.createInterface({
|
|
328
|
+
input: process.stdin,
|
|
329
|
+
output: process.stdout,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
return new Promise((resolve) => {
|
|
333
|
+
rl.question(
|
|
334
|
+
`Allow ${server_name}.${tool_name}(${JSON.stringify(tool_args)})? [y/N] `,
|
|
335
|
+
(answer) => {
|
|
336
|
+
rl.close();
|
|
337
|
+
resolve(answer.toLowerCase() === 'y');
|
|
338
|
+
}
|
|
339
|
+
);
|
|
340
|
+
});
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
const result = await sdk.prompt('List files in current directory');
|
|
346
|
+
console.log(result.final_output);
|
|
347
|
+
} finally {
|
|
348
|
+
await sdk.dispose();
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Pattern 6: Session Continuity
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { QodoSDK } from '@qodo/sdk';
|
|
356
|
+
|
|
357
|
+
// First conversation
|
|
358
|
+
const sdk1 = new QodoSDK();
|
|
359
|
+
let sessionId: string;
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
for await (const event of sdk1.streamPrompt('Remember: my favorite color is blue')) {
|
|
363
|
+
if (event.type === 'sdk.run.started') {
|
|
364
|
+
sessionId = event.data.session_id;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
} finally {
|
|
368
|
+
await sdk1.dispose();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Continue the conversation
|
|
372
|
+
const sdk2 = new QodoSDK().withSession(sessionId!);
|
|
373
|
+
try {
|
|
374
|
+
const result = await sdk2.prompt('What is my favorite color?');
|
|
375
|
+
console.log(result.final_output); // Should mention "blue"
|
|
376
|
+
} finally {
|
|
377
|
+
await sdk2.dispose();
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Pattern 7: Multi-Agent Orchestration
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
import { QodoSDK, sdkAgent, sdkCommand } from '@qodo/sdk';
|
|
385
|
+
import { z } from 'zod';
|
|
386
|
+
|
|
387
|
+
// Agent 1: Code analyzer
|
|
388
|
+
const analyzerAgent = sdkAgent({
|
|
389
|
+
instructions: 'You analyze code and identify issues.',
|
|
390
|
+
commands: {
|
|
391
|
+
analyze: sdkCommand({
|
|
392
|
+
name: 'analyze',
|
|
393
|
+
description: 'Analyze code',
|
|
394
|
+
available_tools: ['filesystem', 'ripgrep'],
|
|
395
|
+
output: z.object({
|
|
396
|
+
issues: z.array(z.string().describe('Issue description')).describe('Issues found'),
|
|
397
|
+
}),
|
|
398
|
+
}),
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Agent 2: Code fixer
|
|
403
|
+
const fixerAgent = sdkAgent({
|
|
404
|
+
instructions: 'You fix code issues.',
|
|
405
|
+
commands: {
|
|
406
|
+
fix: sdkCommand({
|
|
407
|
+
name: 'fix',
|
|
408
|
+
description: 'Fix code issues',
|
|
409
|
+
available_tools: ['filesystem'],
|
|
410
|
+
args: sdkArgs({
|
|
411
|
+
issues: z.array(z.string()).describe('Issues to fix'),
|
|
412
|
+
}),
|
|
413
|
+
output: z.object({
|
|
414
|
+
fixed: z.array(z.string().describe('Fixed issue')).describe('Issues that were fixed'),
|
|
415
|
+
}),
|
|
416
|
+
}),
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// Orchestrate
|
|
421
|
+
const analyzer = QodoSDK.fromAgent(analyzerAgent);
|
|
422
|
+
const fixer = QodoSDK.fromAgent(fixerAgent);
|
|
423
|
+
|
|
424
|
+
try {
|
|
425
|
+
// Step 1: Analyze
|
|
426
|
+
const analysis = await analyzer.run('analyze');
|
|
427
|
+
const issues = analysis.structured_output?.issues || [];
|
|
428
|
+
|
|
429
|
+
// Step 2: Fix
|
|
430
|
+
if (issues.length > 0) {
|
|
431
|
+
const fixes = await fixer.run('fix', { args: { issues } });
|
|
432
|
+
console.log('Fixed:', fixes.structured_output?.fixed);
|
|
433
|
+
}
|
|
434
|
+
} finally {
|
|
435
|
+
await Promise.all([analyzer.dispose(), fixer.dispose()]);
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Zod Schema Patterns
|
|
442
|
+
|
|
443
|
+
### Basic Types with Descriptions
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
import { z } from 'zod';
|
|
447
|
+
|
|
448
|
+
const output = z.object({
|
|
449
|
+
// Primitives
|
|
450
|
+
name: z.string().describe('The name'),
|
|
451
|
+
count: z.number().describe('Total count'),
|
|
452
|
+
enabled: z.boolean().describe('Whether enabled'),
|
|
453
|
+
|
|
454
|
+
// Optional fields
|
|
455
|
+
notes: z.string().optional().describe('Optional notes'),
|
|
456
|
+
|
|
457
|
+
// With defaults
|
|
458
|
+
priority: z.number().default(5).describe('Priority level 1-10'),
|
|
459
|
+
|
|
460
|
+
// Enums
|
|
461
|
+
status: z.enum(['pending', 'done', 'failed']).describe('Current status'),
|
|
462
|
+
|
|
463
|
+
// Arrays
|
|
464
|
+
tags: z.array(z.string().describe('Tag name')).describe('List of tags'),
|
|
465
|
+
|
|
466
|
+
// Nested objects
|
|
467
|
+
metadata: z.object({
|
|
468
|
+
created: z.string().describe('Creation date'),
|
|
469
|
+
author: z.string().describe('Author name'),
|
|
470
|
+
}).describe('Metadata information'),
|
|
471
|
+
});
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Flexible Types with zJsonValue and zJsonAny
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
import { z } from 'zod';
|
|
478
|
+
import { zJsonValue, zJsonAny } from '@qodo/sdk';
|
|
479
|
+
|
|
480
|
+
const output = z.object({
|
|
481
|
+
// When you need a primitive but don't know which type
|
|
482
|
+
// Allows: string | number | boolean | null
|
|
483
|
+
dynamicValue: zJsonValue().describe('A dynamic primitive value'),
|
|
484
|
+
|
|
485
|
+
// When you need truly flexible data (including objects/arrays)
|
|
486
|
+
// Allows: primitives + arrays of primitives + objects with primitive values
|
|
487
|
+
rawData: zJsonAny().describe('Raw data in any JSON format'),
|
|
488
|
+
|
|
489
|
+
// Array of mixed primitives
|
|
490
|
+
mixedArray: z.array(zJsonValue()).describe('Array of mixed primitive values'),
|
|
491
|
+
});
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Coerced Input Types
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
import { z } from 'zod';
|
|
498
|
+
import { zCoerce } from '@qodo/sdk';
|
|
499
|
+
|
|
500
|
+
// For CLI-style string inputs that need type conversion
|
|
501
|
+
const args = z.object({
|
|
502
|
+
// "true"/"false" strings -> boolean
|
|
503
|
+
verbose: zCoerce.boolean().describe('Enable verbose output'),
|
|
504
|
+
|
|
505
|
+
// "123" string -> number
|
|
506
|
+
limit: zCoerce.number().describe('Result limit'),
|
|
507
|
+
|
|
508
|
+
// '["a","b"]' string -> string[]
|
|
509
|
+
files: zCoerce.jsonArray(z.string()).describe('Files to process'),
|
|
510
|
+
|
|
511
|
+
// '{"key":"value"}' string -> object
|
|
512
|
+
config: zCoerce.jsonObject({ key: z.string() }).describe('Configuration'),
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## Event Types Reference
|
|
519
|
+
|
|
520
|
+
| Event Type | When Emitted | Key Data Fields |
|
|
521
|
+
|------------|--------------|-----------------|
|
|
522
|
+
| `sdk.init` | SDK initialized | `sdk_version`, `backend.base_url`, `model` |
|
|
523
|
+
| `sdk.run.started` | Run begins | `session_id`, `command`, `prompt_mode`, `cwd` |
|
|
524
|
+
| `sdk.message.delta` | Streaming text | `delta`, `message_id`, `role` |
|
|
525
|
+
| `sdk.message.full` | Full message update | `messages.langchain`, `messages.openai` |
|
|
526
|
+
| `sdk.progress` | Progress update | `title`, `status`, `percent` |
|
|
527
|
+
| `sdk.tool.requested` | Tool call requested | `tool_call_id`, `server_name`, `tool_name`, `tool_args`, `pending_approval` |
|
|
528
|
+
| `sdk.tool.approved` | Tool approved/denied | `tool_call_id`, `approved`, `reason` |
|
|
529
|
+
| `sdk.tool.executed` | Tool finished | `tool_call_id`, `result.isError`, `result.content` |
|
|
530
|
+
| `sdk.error` | Error occurred | `message`, `cause` |
|
|
531
|
+
| `sdk.final` | Run completed | `success`, `result.structured_output`, `result.final_output`, `messages` |
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## QodoSDK Options Reference
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
interface QodoSDKOptions {
|
|
539
|
+
// Agent configuration (mutually exclusive)
|
|
540
|
+
agentFile?: string; // Path to agent.toml/yaml
|
|
541
|
+
agentContent?: string; // Raw TOML/YAML content
|
|
542
|
+
agentObject?: AIAssistantConfig; // Programmatic config
|
|
543
|
+
|
|
544
|
+
// MCP servers
|
|
545
|
+
mcpFile?: string; // Path to mcp.json
|
|
546
|
+
mcpServers?: Record<string, MCPConfig>; // Inline server configs
|
|
547
|
+
|
|
548
|
+
// Execution settings
|
|
549
|
+
model?: string; // Model override
|
|
550
|
+
projectPath?: string; // Working directory
|
|
551
|
+
additionalPaths?: string[]; // Extra accessible paths
|
|
552
|
+
|
|
553
|
+
// Tool handling
|
|
554
|
+
autoApproveTools?: boolean; // Auto-approve tools (default: true)
|
|
555
|
+
toolApproval?: (req) => Promise<boolean> | boolean; // Custom approval
|
|
556
|
+
|
|
557
|
+
// Session
|
|
558
|
+
contextSessionIds?: string[]; // Previous sessions for context
|
|
559
|
+
|
|
560
|
+
// Backend
|
|
561
|
+
backend?: { baseUrl?: string }; // Backend URL override
|
|
562
|
+
|
|
563
|
+
// Debugging
|
|
564
|
+
debug?: boolean; // Enable debug logging
|
|
565
|
+
logger?: QodoSDKLogger; // Custom logger
|
|
566
|
+
|
|
567
|
+
// Mode
|
|
568
|
+
interactiveMode?: boolean; // Enable interactive clarifications
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
## Common Tasks
|
|
575
|
+
|
|
576
|
+
### Adding a New Command to an Existing Agent
|
|
577
|
+
|
|
578
|
+
1. Define the command with `sdkCommand()`:
|
|
579
|
+
```typescript
|
|
580
|
+
const newCommand = sdkCommand({
|
|
581
|
+
name: 'newCommand',
|
|
582
|
+
description: 'What this command does',
|
|
583
|
+
instructions: 'Detailed instructions for the AI',
|
|
584
|
+
available_tools: ['filesystem', 'ripgrep'],
|
|
585
|
+
args: sdkArgs({
|
|
586
|
+
// Define your args
|
|
587
|
+
}),
|
|
588
|
+
output: z.object({
|
|
589
|
+
// Define your output with .describe() on every field
|
|
590
|
+
}),
|
|
591
|
+
});
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
2. Add to agent's commands:
|
|
595
|
+
```typescript
|
|
596
|
+
const agent = sdkAgent({
|
|
597
|
+
commands: {
|
|
598
|
+
existingCommand,
|
|
599
|
+
newCommand, // Add here
|
|
600
|
+
},
|
|
601
|
+
});
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### Converting TOML to Programmatic TypeScript
|
|
605
|
+
|
|
606
|
+
Read the TOML and translate each section:
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
// From TOML:
|
|
610
|
+
// [commands.analyze]
|
|
611
|
+
// name = "analyze"
|
|
612
|
+
// description = "Analyze code"
|
|
613
|
+
// available_tools = ["filesystem"]
|
|
614
|
+
|
|
615
|
+
// To TypeScript:
|
|
616
|
+
import { sdkCommand, sdkArgs } from '@qodo/sdk';
|
|
617
|
+
import { z } from 'zod';
|
|
618
|
+
|
|
619
|
+
const analyze = sdkCommand({
|
|
620
|
+
name: 'analyze',
|
|
621
|
+
description: 'Analyze code',
|
|
622
|
+
available_tools: ['filesystem'],
|
|
623
|
+
args: sdkArgs({ /* from [commands.analyze.arguments] */ }),
|
|
624
|
+
output: z.object({ /* from [commands.analyze.output_schema] */ }),
|
|
625
|
+
});
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Debugging Schema Validation Errors
|
|
629
|
+
|
|
630
|
+
When you see `QodoSchemaError: output schema is missing description for: fieldName`:
|
|
631
|
+
|
|
632
|
+
1. Find the field in your Zod schema
|
|
633
|
+
2. Add `.describe('...')` to it
|
|
634
|
+
3. Check nested objects - all properties need descriptions
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
// Before (error)
|
|
638
|
+
z.object({
|
|
639
|
+
items: z.array(z.object({
|
|
640
|
+
name: z.string(), // Missing description!
|
|
641
|
+
})),
|
|
642
|
+
})
|
|
643
|
+
|
|
644
|
+
// After (fixed)
|
|
645
|
+
z.object({
|
|
646
|
+
items: z.array(z.object({
|
|
647
|
+
name: z.string().describe('Item name'),
|
|
648
|
+
})).describe('List of items'),
|
|
649
|
+
})
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
---
|
|
653
|
+
|
|
654
|
+
## Additional Resources
|
|
655
|
+
|
|
656
|
+
- [assets/programmatic-agent.ts](assets/programmatic-agent.ts) - Complete working TypeScript agent template
|
|
657
|
+
- [references/builtin-tools.md](references/builtin-tools.md) - Detailed guide to filesystem, git, ripgrep, and shell tools
|
|
658
|
+
- [references/common-issues.md](references/common-issues.md) - Troubleshooting guide for common problems
|