@vibe-agent-toolkit/vat-development-agents 0.1.13 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/resources/skills/SKILL.d.ts +1 -0
- package/dist/generated/resources/skills/SKILL.js +14 -9
- package/dist/skills/vibe-agent-toolkit/SKILL.md +62 -18
- package/dist/skills/vibe-agent-toolkit/resources/CLAUDE.md +577 -0
- package/dist/skills/vibe-agent-toolkit/resources/adding-runtime-adapters.md +628 -0
- package/dist/skills/vibe-agent-toolkit/resources/agent-authoring.md +905 -0
- package/dist/skills/vibe-agent-toolkit/resources/agent-skills-best-practices.md +594 -0
- package/dist/skills/vibe-agent-toolkit/resources/audit.md +325 -0
- package/dist/skills/vibe-agent-toolkit/resources/getting-started.md +360 -0
- package/dist/skills/vibe-agent-toolkit/resources/import.md +389 -0
- package/dist/skills/vibe-agent-toolkit/resources/orchestration.md +859 -0
- package/dist/skills/vibe-agent-toolkit/resources/rag-usage-guide.md +770 -0
- package/dist/skills/vibe-agent-toolkit/resources/rag.md +542 -0
- package/package.json +3 -4
- package/dist/skills/vibe-agent-toolkit/README.md +0 -279
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
# Adding Runtime Adapters
|
|
2
|
+
|
|
3
|
+
This guide documents best practices for adding new runtime adapters to the Vibe Agent Toolkit.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
A runtime adapter converts VAT agents into runtime-specific formats (tools, functions, etc.) for use with specific LLM frameworks (Vercel AI SDK, LangChain, OpenAI SDK, Claude Agent SDK, etc.).
|
|
8
|
+
|
|
9
|
+
## Quick Start Checklist
|
|
10
|
+
|
|
11
|
+
- [ ] Create package structure in `packages/runtime-{name}/`
|
|
12
|
+
- [ ] Use shared test factories (zero code duplication)
|
|
13
|
+
- [ ] Use shared demo infrastructure (common-demo.ts)
|
|
14
|
+
- [ ] Add TypeScript project reference
|
|
15
|
+
- [ ] Implement both pure function and LLM analyzer adapters
|
|
16
|
+
- [ ] Write comprehensive tests with test helpers
|
|
17
|
+
- [ ] Create demo showcasing both providers (if applicable)
|
|
18
|
+
- [ ] Update root tsconfig.json
|
|
19
|
+
|
|
20
|
+
## Package Structure
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
packages/runtime-{name}/
|
|
24
|
+
├── src/
|
|
25
|
+
│ ├── adapters/
|
|
26
|
+
│ │ ├── common-helpers.ts # Shared utilities across adapters
|
|
27
|
+
│ │ ├── pure-function.ts # Pure function agent adapter
|
|
28
|
+
│ │ └── llm-analyzer.ts # LLM analyzer agent adapter
|
|
29
|
+
│ ├── types.ts # TypeScript type definitions
|
|
30
|
+
│ └── index.ts # Public API exports
|
|
31
|
+
├── test/
|
|
32
|
+
│ ├── pure-function.test.ts # Pure function adapter tests
|
|
33
|
+
│ ├── llm-analyzer.test.ts # LLM analyzer adapter tests
|
|
34
|
+
│ └── test-helpers.ts # Test utilities (extract when 2-3+ tests)
|
|
35
|
+
├── examples/
|
|
36
|
+
│ └── demo.ts # Demo using common-demo infrastructure
|
|
37
|
+
├── package.json
|
|
38
|
+
├── tsconfig.json
|
|
39
|
+
└── README.md
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 1. Package Configuration
|
|
43
|
+
|
|
44
|
+
### package.json
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"name": "@vibe-agent-toolkit/runtime-{name}",
|
|
49
|
+
"version": "0.1.1",
|
|
50
|
+
"description": "{Runtime Name} runtime adapter for VAT agents",
|
|
51
|
+
"type": "module",
|
|
52
|
+
"exports": {
|
|
53
|
+
".": {
|
|
54
|
+
"types": "./dist/index.d.ts",
|
|
55
|
+
"default": "./dist/index.js"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"files": ["dist"],
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "tsc",
|
|
61
|
+
"demo": "tsx examples/demo.ts",
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"test:watch": "vitest",
|
|
64
|
+
"typecheck": "tsc --noEmit"
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"@vibe-agent-toolkit/agent-runtime": "workspace:*",
|
|
68
|
+
"zod": "^3.24.1",
|
|
69
|
+
"{runtime-sdk}": "^x.y.z"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@types/node": "^22.10.5",
|
|
73
|
+
"@vibe-agent-toolkit/dev-tools": "workspace:*",
|
|
74
|
+
"@vibe-agent-toolkit/vat-example-cat-agents": "workspace:*",
|
|
75
|
+
"tsx": "^4.19.2",
|
|
76
|
+
"typescript": "^5.7.3",
|
|
77
|
+
"vitest": "^2.1.8"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Key points:**
|
|
83
|
+
- Use `workspace:*` for all internal dependencies
|
|
84
|
+
- Add runtime SDK as dependency
|
|
85
|
+
- Include dev-tools for test factories
|
|
86
|
+
- Include vat-example-cat-agents for testing
|
|
87
|
+
|
|
88
|
+
### tsconfig.json
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"extends": "../../tsconfig.base.json",
|
|
93
|
+
"compilerOptions": {
|
|
94
|
+
"composite": true,
|
|
95
|
+
"outDir": "./dist",
|
|
96
|
+
"rootDir": "./src"
|
|
97
|
+
},
|
|
98
|
+
"include": ["src/**/*"],
|
|
99
|
+
"references": [
|
|
100
|
+
{ "path": "../agent-runtime" },
|
|
101
|
+
{ "path": "../utils" }
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Key points:**
|
|
107
|
+
- Always set `composite: true` for monorepo builds
|
|
108
|
+
- Add references for packages you depend on
|
|
109
|
+
- Use `../../tsconfig.base.json` for consistency
|
|
110
|
+
|
|
111
|
+
### Root tsconfig.json
|
|
112
|
+
|
|
113
|
+
Add your package to the root tsconfig.json references:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"references": [
|
|
118
|
+
// ... existing packages
|
|
119
|
+
{ "path": "./packages/runtime-{name}" }
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## 2. Adapter Implementation
|
|
125
|
+
|
|
126
|
+
### Common Pattern
|
|
127
|
+
|
|
128
|
+
Both pure function and LLM analyzer adapters follow similar patterns:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// src/adapters/pure-function.ts
|
|
132
|
+
import type { PureFunctionAgent } from '@vibe-agent-toolkit/agent-runtime';
|
|
133
|
+
import type { z } from 'zod';
|
|
134
|
+
|
|
135
|
+
export function convertPureFunctionToTool<TInput, TOutput>(
|
|
136
|
+
agent: PureFunctionAgent<TInput, TOutput>,
|
|
137
|
+
inputSchema: z.ZodType<TInput>,
|
|
138
|
+
outputSchema: z.ZodType<TOutput>,
|
|
139
|
+
) {
|
|
140
|
+
// 1. Extract agent manifest
|
|
141
|
+
const { manifest } = agent;
|
|
142
|
+
|
|
143
|
+
// 2. Create runtime-specific tool/function
|
|
144
|
+
const tool = createRuntimeTool(
|
|
145
|
+
manifest.name,
|
|
146
|
+
manifest.description,
|
|
147
|
+
inputSchema,
|
|
148
|
+
async (input: TInput) => {
|
|
149
|
+
// 3. Validate input
|
|
150
|
+
const validatedInput = inputSchema.parse(input);
|
|
151
|
+
|
|
152
|
+
// 4. Execute agent
|
|
153
|
+
const result = await agent.execute(validatedInput);
|
|
154
|
+
|
|
155
|
+
// 5. Validate output
|
|
156
|
+
const validatedOutput = outputSchema.parse(result);
|
|
157
|
+
|
|
158
|
+
// 6. Return in runtime-specific format
|
|
159
|
+
return formatOutput(validatedOutput);
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// 7. Return tool with metadata
|
|
164
|
+
return {
|
|
165
|
+
tool,
|
|
166
|
+
metadata: {
|
|
167
|
+
name: manifest.name,
|
|
168
|
+
description: manifest.description,
|
|
169
|
+
version: manifest.version,
|
|
170
|
+
archetype: 'pure-function',
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### LLM Analyzer Adapter Pattern
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// src/adapters/llm-analyzer.ts
|
|
180
|
+
export function convertLLMAnalyzerToTool<TInput, TOutput>(
|
|
181
|
+
agent: Agent<TInput, TOutput>,
|
|
182
|
+
inputSchema: z.ZodType<TInput>,
|
|
183
|
+
outputSchema: z.ZodType<TOutput>,
|
|
184
|
+
llmConfig: RuntimeLLMConfig,
|
|
185
|
+
) {
|
|
186
|
+
// 1. Create LLM client
|
|
187
|
+
const client = createLLMClient(llmConfig);
|
|
188
|
+
|
|
189
|
+
// 2. Create callLLM function
|
|
190
|
+
const callLLM = async (prompt: string): Promise<string> => {
|
|
191
|
+
const response = await client.generate({ prompt, ...llmConfig });
|
|
192
|
+
return response.text;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// 3. Create tool that provides context
|
|
196
|
+
const tool = createRuntimeTool(
|
|
197
|
+
agent.manifest.name,
|
|
198
|
+
agent.manifest.description,
|
|
199
|
+
inputSchema,
|
|
200
|
+
async (input: TInput) => {
|
|
201
|
+
const context = {
|
|
202
|
+
mockable: false,
|
|
203
|
+
model: llmConfig.model,
|
|
204
|
+
temperature: llmConfig.temperature,
|
|
205
|
+
callLLM,
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const result = await agent.execute(input, context);
|
|
209
|
+
return outputSchema.parse(result);
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
return { tool, metadata: { ... } };
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Common Helpers
|
|
218
|
+
|
|
219
|
+
Extract shared logic to `common-helpers.ts`:
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
// src/adapters/common-helpers.ts
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Creates metadata object for single agent conversion
|
|
226
|
+
*/
|
|
227
|
+
export function createSingleToolMetadata(
|
|
228
|
+
manifest: { name: string; description: string; version: string },
|
|
229
|
+
archetype: string,
|
|
230
|
+
) {
|
|
231
|
+
return {
|
|
232
|
+
name: manifest.name,
|
|
233
|
+
description: manifest.description,
|
|
234
|
+
version: manifest.version,
|
|
235
|
+
archetype,
|
|
236
|
+
toolName: `${manifest.name}`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Creates metadata object for batch conversion
|
|
242
|
+
*/
|
|
243
|
+
export function createBatchToolMetadata(
|
|
244
|
+
key: string,
|
|
245
|
+
manifest: { name: string; description: string; version: string },
|
|
246
|
+
archetype: string,
|
|
247
|
+
) {
|
|
248
|
+
return {
|
|
249
|
+
name: manifest.name,
|
|
250
|
+
description: manifest.description,
|
|
251
|
+
version: manifest.version,
|
|
252
|
+
archetype,
|
|
253
|
+
toolName: key,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## 3. Testing with Shared Factories
|
|
259
|
+
|
|
260
|
+
**CRITICAL: Use shared test factories from dev-tools to maintain zero code duplication.**
|
|
261
|
+
|
|
262
|
+
### Pure Function Tests
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
// test/pure-function.test.ts
|
|
266
|
+
import { createPureFunctionTestSuite } from '@vibe-agent-toolkit/dev-tools';
|
|
267
|
+
import { HaikuSchema, HaikuValidationResultSchema, haikuValidatorAgent } from '@vibe-agent-toolkit/vat-example-cat-agents';
|
|
268
|
+
|
|
269
|
+
import { convertPureFunctionToTool, convertPureFunctionsToTools } from '../src/adapters/pure-function.js';
|
|
270
|
+
|
|
271
|
+
// Generate complete test suite using factory
|
|
272
|
+
createPureFunctionTestSuite({
|
|
273
|
+
runtimeName: 'Your Runtime Name',
|
|
274
|
+
convertPureFunctionToTool,
|
|
275
|
+
convertPureFunctionsToTools: (configs) => {
|
|
276
|
+
// Convert and return tools/functions
|
|
277
|
+
const result = convertPureFunctionsToTools(configs);
|
|
278
|
+
return extractExecutableFunctions(result);
|
|
279
|
+
},
|
|
280
|
+
agent: haikuValidatorAgent,
|
|
281
|
+
inputSchema: HaikuSchema,
|
|
282
|
+
outputSchema: HaikuValidationResultSchema,
|
|
283
|
+
getToolFromResult: (result) => result.tool,
|
|
284
|
+
executeFunction: async (result, input) => {
|
|
285
|
+
// Execute the tool/function
|
|
286
|
+
return await result.tool.execute(input);
|
|
287
|
+
},
|
|
288
|
+
parseOutput: (output) => output,
|
|
289
|
+
assertToolStructure: (result) => {
|
|
290
|
+
expect(result.tool).toBeDefined();
|
|
291
|
+
expect(result.metadata.name).toBe('haiku-validator');
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### LLM Analyzer Tests
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// test/llm-analyzer.test.ts
|
|
300
|
+
import { createLLMAnalyzerTestSuite } from '@vibe-agent-toolkit/dev-tools';
|
|
301
|
+
import { nameGeneratorAgent, NameGeneratorInputSchema, NameSuggestionSchema } from '@vibe-agent-toolkit/vat-example-cat-agents';
|
|
302
|
+
|
|
303
|
+
import { convertLLMAnalyzerToTool, convertLLMAnalyzersToTools } from '../src/adapters/llm-analyzer.js';
|
|
304
|
+
|
|
305
|
+
createLLMAnalyzerTestSuite({
|
|
306
|
+
runtimeName: 'Your Runtime Name',
|
|
307
|
+
convertLLMAnalyzerToFunction: (agent, inputSchema, outputSchema, llmConfig) => {
|
|
308
|
+
const { tool } = convertLLMAnalyzerToTool(agent, inputSchema, outputSchema, llmConfig);
|
|
309
|
+
return (input) => tool.execute(input);
|
|
310
|
+
},
|
|
311
|
+
convertLLMAnalyzersToFunctions: (configs, llmConfig) => {
|
|
312
|
+
const { tools } = convertLLMAnalyzersToTools(configs, llmConfig);
|
|
313
|
+
return convertToolsToFunctions(tools);
|
|
314
|
+
},
|
|
315
|
+
agent: nameGeneratorAgent,
|
|
316
|
+
inputSchema: NameGeneratorInputSchema,
|
|
317
|
+
outputSchema: NameSuggestionSchema,
|
|
318
|
+
llmConfig: {
|
|
319
|
+
apiKey: 'test-key',
|
|
320
|
+
model: 'test-model',
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Test Helpers (Extract Early!)
|
|
326
|
+
|
|
327
|
+
**Rule: Extract test helpers after 2-3 similar tests to avoid duplication.**
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
// test/test-helpers.ts
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Executes a runtime tool and returns the result
|
|
334
|
+
*/
|
|
335
|
+
export async function executeToolHandler(
|
|
336
|
+
handler: (input: unknown) => Promise<unknown>,
|
|
337
|
+
input: unknown,
|
|
338
|
+
): Promise<unknown> {
|
|
339
|
+
const response = await handler(input);
|
|
340
|
+
return parseToolResponse(response);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Creates an executor function for a single tool
|
|
345
|
+
*/
|
|
346
|
+
export function createToolExecutor(
|
|
347
|
+
tool: RuntimeTool,
|
|
348
|
+
): (input: unknown) => Promise<unknown> {
|
|
349
|
+
return async (input: unknown) => {
|
|
350
|
+
return await executeToolHandler(tool.handler, input);
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Creates executor functions for multiple tools
|
|
356
|
+
*/
|
|
357
|
+
export function createBatchToolExecutors(
|
|
358
|
+
tools: Record<string, RuntimeTool>,
|
|
359
|
+
): Record<string, (input: unknown) => Promise<unknown>> {
|
|
360
|
+
const executors: Record<string, (input: unknown) => Promise<unknown>> = {};
|
|
361
|
+
|
|
362
|
+
for (const [key, tool] of Object.entries(tools)) {
|
|
363
|
+
executors[key] = createToolExecutor(tool);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return executors;
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## 4. Demo with Common Infrastructure
|
|
371
|
+
|
|
372
|
+
**CRITICAL: Use shared common-demo infrastructure to avoid duplicating demo code.**
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
// examples/demo.ts
|
|
376
|
+
import { convertLLMAnalyzerToTool } from '../src/adapters/llm-analyzer.js';
|
|
377
|
+
import { convertPureFunctionToTool, convertPureFunctionsToTools } from '../src/adapters/pure-function.js';
|
|
378
|
+
|
|
379
|
+
import type { RuntimeAdapter } from '../../runtime-vercel-ai-sdk/examples/common-demo.js';
|
|
380
|
+
import { runCommonDemo } from '../../runtime-vercel-ai-sdk/examples/common-demo.js';
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Your Runtime Adapter implementation
|
|
384
|
+
*/
|
|
385
|
+
const yourRuntimeAdapter: RuntimeAdapter = {
|
|
386
|
+
name: 'Your Runtime Name',
|
|
387
|
+
|
|
388
|
+
convertPureFunctionToTool: convertPureFunctionToTool as unknown as RuntimeAdapter['convertPureFunctionToTool'],
|
|
389
|
+
|
|
390
|
+
convertPureFunctionsToTools: convertPureFunctionsToTools as unknown as RuntimeAdapter['convertPureFunctionsToTools'],
|
|
391
|
+
|
|
392
|
+
convertLLMAnalyzerToFunction: (agent, inputSchema, outputSchema, llmConfig) => {
|
|
393
|
+
const { tool } = convertLLMAnalyzerToTool(agent, inputSchema, outputSchema, llmConfig);
|
|
394
|
+
return (input) => tool.execute(input);
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
createPrimaryLLMConfig: () => ({
|
|
398
|
+
provider: 'primary-provider',
|
|
399
|
+
apiKey: process.env['PRIMARY_API_KEY'],
|
|
400
|
+
model: 'primary-model',
|
|
401
|
+
temperature: 0.9,
|
|
402
|
+
}),
|
|
403
|
+
|
|
404
|
+
// Optional: Add secondary provider for comparison
|
|
405
|
+
createSecondaryLLMConfig: () => ({
|
|
406
|
+
provider: 'secondary-provider',
|
|
407
|
+
apiKey: process.env['SECONDARY_API_KEY'],
|
|
408
|
+
model: 'secondary-model',
|
|
409
|
+
temperature: 0.9,
|
|
410
|
+
}),
|
|
411
|
+
|
|
412
|
+
// Optional: Add tool calling demo if your runtime supports it
|
|
413
|
+
demoToolCalling: async (tool, prompt) => {
|
|
414
|
+
const result = await yourRuntime.callWithTools({
|
|
415
|
+
tools: [tool],
|
|
416
|
+
prompt,
|
|
417
|
+
});
|
|
418
|
+
return {
|
|
419
|
+
text: result.text,
|
|
420
|
+
toolCalls: result.toolCalls,
|
|
421
|
+
toolResults: result.toolResults,
|
|
422
|
+
};
|
|
423
|
+
},
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// Run the common demo with your runtime adapter
|
|
427
|
+
runCommonDemo(yourRuntimeAdapter).catch(console.error);
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Demo benefits:**
|
|
431
|
+
- ✅ No duplicated demo code across runtimes
|
|
432
|
+
- ✅ Consistent demo experience
|
|
433
|
+
- ✅ Automatic multi-provider support
|
|
434
|
+
- ✅ Tool calling demo (if supported)
|
|
435
|
+
- ✅ Formatted output with colors
|
|
436
|
+
|
|
437
|
+
## 5. Best Practices
|
|
438
|
+
|
|
439
|
+
### Zero Code Duplication
|
|
440
|
+
|
|
441
|
+
**CRITICAL: Maintain zero code duplication across all tests.**
|
|
442
|
+
|
|
443
|
+
**When to extract helpers:**
|
|
444
|
+
1. After writing 2-3 similar test blocks
|
|
445
|
+
2. When you copy-paste test setup code
|
|
446
|
+
3. When you see similar assertion patterns
|
|
447
|
+
|
|
448
|
+
**Example - Before extraction:**
|
|
449
|
+
```typescript
|
|
450
|
+
// ❌ BAD: Duplicated across 3 test files
|
|
451
|
+
describe('Pure Function Tests', () => {
|
|
452
|
+
beforeEach(async () => {
|
|
453
|
+
tempDir = await mkdtemp(join(tmpdir(), 'test-'));
|
|
454
|
+
// ... 8 more lines of setup
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
afterEach(async () => {
|
|
458
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
459
|
+
// ... cleanup logic
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
**Example - After extraction:**
|
|
465
|
+
```typescript
|
|
466
|
+
// ✅ GOOD: Shared helper
|
|
467
|
+
const suite = setupTestSuite('my-test-');
|
|
468
|
+
|
|
469
|
+
describe('Pure Function Tests', () => {
|
|
470
|
+
beforeEach(suite.beforeEach);
|
|
471
|
+
afterEach(suite.afterEach);
|
|
472
|
+
|
|
473
|
+
it('should work', () => {
|
|
474
|
+
// Use suite.tempDir, suite.registry, etc.
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### TypeScript Best Practices
|
|
480
|
+
|
|
481
|
+
1. **Always use `composite: true`** in tsconfig.json
|
|
482
|
+
2. **Always add project references** for dependencies
|
|
483
|
+
3. **Use `workspace:*`** for internal dependencies in package.json
|
|
484
|
+
4. **Export types** from `types.ts`, not inline
|
|
485
|
+
5. **Use Zod schemas** for runtime validation
|
|
486
|
+
|
|
487
|
+
### Testing Best Practices
|
|
488
|
+
|
|
489
|
+
1. **Use shared test factories** from dev-tools
|
|
490
|
+
2. **Extract helpers early** (2-3 rule)
|
|
491
|
+
3. **Test both single and batch conversions**
|
|
492
|
+
4. **Test with real agent examples** from vat-example-cat-agents
|
|
493
|
+
5. **Run `bun run duplication-check`** before committing
|
|
494
|
+
|
|
495
|
+
### Adapter Design Principles
|
|
496
|
+
|
|
497
|
+
1. **Keep it synchronous if possible** - async adapters complicate testing
|
|
498
|
+
2. **Validate inputs and outputs** - use Zod schemas
|
|
499
|
+
3. **Extract common logic** to common-helpers.ts
|
|
500
|
+
4. **Support batch conversion** - multiple agents in one call
|
|
501
|
+
5. **Return structured metadata** - name, version, archetype, etc.
|
|
502
|
+
|
|
503
|
+
## 6. Validation Checklist
|
|
504
|
+
|
|
505
|
+
Before committing your new runtime adapter:
|
|
506
|
+
|
|
507
|
+
```bash
|
|
508
|
+
# Build
|
|
509
|
+
bun run build
|
|
510
|
+
|
|
511
|
+
# Type check
|
|
512
|
+
bun run typecheck
|
|
513
|
+
|
|
514
|
+
# Lint (must pass with zero warnings)
|
|
515
|
+
bun run lint
|
|
516
|
+
|
|
517
|
+
# Test
|
|
518
|
+
bun run test:unit
|
|
519
|
+
|
|
520
|
+
# Check for duplication (MUST be zero!)
|
|
521
|
+
bun run duplication-check
|
|
522
|
+
|
|
523
|
+
# Run demo
|
|
524
|
+
cd packages/runtime-{name}
|
|
525
|
+
bun run demo
|
|
526
|
+
|
|
527
|
+
# Full validation
|
|
528
|
+
vv validate
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**CRITICAL: `duplication-check` must pass with 0 clones before committing.**
|
|
532
|
+
|
|
533
|
+
## 7. Common Pitfalls
|
|
534
|
+
|
|
535
|
+
### ❌ Don't: Duplicate demo code
|
|
536
|
+
```typescript
|
|
537
|
+
// BAD: Don't create custom demo from scratch
|
|
538
|
+
console.log('Testing pure functions...');
|
|
539
|
+
const result = await agent.execute(input);
|
|
540
|
+
console.log(`Result: ${JSON.stringify(result)}`);
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### ✅ Do: Use common demo infrastructure
|
|
544
|
+
```typescript
|
|
545
|
+
// GOOD: Use RuntimeAdapter interface
|
|
546
|
+
const adapter: RuntimeAdapter = {
|
|
547
|
+
name: 'Your Runtime',
|
|
548
|
+
// ... implement interface
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
runCommonDemo(adapter);
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### ❌ Don't: Duplicate test setup
|
|
555
|
+
```typescript
|
|
556
|
+
// BAD: Repeated in multiple test files
|
|
557
|
+
beforeEach(async () => {
|
|
558
|
+
tempDir = await mkdtemp(join(tmpdir(), 'test-'));
|
|
559
|
+
// ... more setup
|
|
560
|
+
});
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### ✅ Do: Extract to test helper
|
|
564
|
+
```typescript
|
|
565
|
+
// GOOD: Shared setup function
|
|
566
|
+
const suite = setupTestSuite('my-test-');
|
|
567
|
+
beforeEach(suite.beforeEach);
|
|
568
|
+
afterEach(suite.afterEach);
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### ❌ Don't: Create async adapters unless necessary
|
|
572
|
+
```typescript
|
|
573
|
+
// BAD: Unnecessary async
|
|
574
|
+
export async function convertPureFunctionToTool(...) {
|
|
575
|
+
// Makes testing harder, breaks interface compatibility
|
|
576
|
+
}
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
### ✅ Do: Keep adapters synchronous when possible
|
|
580
|
+
```typescript
|
|
581
|
+
// GOOD: Synchronous adapter
|
|
582
|
+
export function convertPureFunctionToTool(...) {
|
|
583
|
+
// Simpler testing, better compatibility
|
|
584
|
+
}
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
## 8. Examples to Reference
|
|
588
|
+
|
|
589
|
+
**Best Practice Implementations:**
|
|
590
|
+
|
|
591
|
+
1. **Claude Agent SDK** (`packages/runtime-claude-agent-sdk/`)
|
|
592
|
+
- Clean synchronous adapter (Anthropic-only)
|
|
593
|
+
- Multi-provider demo (Anthropic + OpenAI wrapper)
|
|
594
|
+
- Zero test duplication with helpers
|
|
595
|
+
- Uses shared test factories
|
|
596
|
+
|
|
597
|
+
2. **Vercel AI SDK** (`packages/runtime-vercel-ai-sdk/`)
|
|
598
|
+
- Multi-provider support (OpenAI + Anthropic)
|
|
599
|
+
- Tool calling demo
|
|
600
|
+
- Common demo infrastructure
|
|
601
|
+
- Shared test factories
|
|
602
|
+
|
|
603
|
+
3. **LangChain** (`packages/runtime-langchain/`)
|
|
604
|
+
- LangChain tool format
|
|
605
|
+
- Uses common demo
|
|
606
|
+
- Shared test factories
|
|
607
|
+
|
|
608
|
+
## 9. Getting Help
|
|
609
|
+
|
|
610
|
+
- Review existing runtime packages for patterns
|
|
611
|
+
- Check dev-tools test factories for test infrastructure
|
|
612
|
+
- See common-demo.ts for demo infrastructure
|
|
613
|
+
- Run `bun run duplication-check` frequently
|
|
614
|
+
- Ask questions early rather than duplicating code
|
|
615
|
+
|
|
616
|
+
## Summary
|
|
617
|
+
|
|
618
|
+
**Key Takeaways:**
|
|
619
|
+
1. ✅ Use shared test factories from dev-tools (zero duplication)
|
|
620
|
+
2. ✅ Use common-demo infrastructure for demos
|
|
621
|
+
3. ✅ Extract test helpers after 2-3 similar tests
|
|
622
|
+
4. ✅ Keep adapters synchronous when possible
|
|
623
|
+
5. ✅ Always run duplication-check (must be 0 clones)
|
|
624
|
+
6. ✅ Use `workspace:*` for internal dependencies
|
|
625
|
+
7. ✅ Add project references to tsconfig.json
|
|
626
|
+
8. ✅ Support both single and batch conversion
|
|
627
|
+
|
|
628
|
+
**This guide will evolve as we learn more. PRs welcome!**
|