@jaypie/mcp 0.2.3 → 0.2.5
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/index.js +1 -1
- package/package.json +1 -1
- package/prompts/Jaypie_CDK_Constructs_and_Patterns.md +51 -0
- package/prompts/Jaypie_DynamoDB_Package.md +662 -0
- package/prompts/Jaypie_Express_Package.md +91 -0
- package/prompts/Jaypie_Init_Lambda_Package.md +134 -1
- package/prompts/Jaypie_Llm_Calls.md +77 -0
- package/prompts/Jaypie_Llm_Tools.md +26 -3
- package/prompts/Jaypie_Vocabulary_Commander.md +411 -0
- package/prompts/Jaypie_Vocabulary_LLM.md +312 -0
- package/prompts/Jaypie_Vocabulary_Lambda.md +310 -0
- package/prompts/Jaypie_Vocabulary_MCP.md +296 -0
- package/prompts/Jaypie_Vocabulary_Package.md +141 -183
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Commander.js CLI integration with serviceHandler callbacks (onMessage, onComplete, onError, onFatal)
|
|
3
|
+
include: "**/cli/**"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Jaypie Vocabulary Commander Adapter
|
|
7
|
+
|
|
8
|
+
The Commander adapter (`@jaypie/vocabulary/commander`) integrates Jaypie service handlers with Commander.js CLI applications, providing automatic option generation, type coercion, and callback hooks for progress reporting.
|
|
9
|
+
|
|
10
|
+
**See also:** [Jaypie_Vocabulary_Package.md](Jaypie_Vocabulary_Package.md) for core serviceHandler documentation.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @jaypie/vocabulary commander
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { Command } from "commander";
|
|
22
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
23
|
+
import { registerServiceCommand } from "@jaypie/vocabulary/commander";
|
|
24
|
+
|
|
25
|
+
const handler = serviceHandler({
|
|
26
|
+
alias: "greet",
|
|
27
|
+
description: "Greet a user",
|
|
28
|
+
input: {
|
|
29
|
+
userName: { type: String, flag: "user", letter: "u" },
|
|
30
|
+
loud: { type: Boolean, letter: "l", default: false },
|
|
31
|
+
},
|
|
32
|
+
service: ({ loud, userName }) => {
|
|
33
|
+
const greeting = `Hello, ${userName}!`;
|
|
34
|
+
console.log(loud ? greeting.toUpperCase() : greeting);
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const program = new Command();
|
|
39
|
+
registerServiceCommand({ handler, program });
|
|
40
|
+
program.parse();
|
|
41
|
+
// Usage: greet --user Alice -l
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## registerServiceCommand
|
|
45
|
+
|
|
46
|
+
The primary function for registering a service handler as a Commander command.
|
|
47
|
+
|
|
48
|
+
### Options
|
|
49
|
+
|
|
50
|
+
| Option | Type | Description |
|
|
51
|
+
|--------|------|-------------|
|
|
52
|
+
| `handler` | `ServiceHandlerFunction` | Required. The service handler to register |
|
|
53
|
+
| `program` | `Command` | Required. Commander program or command |
|
|
54
|
+
| `name` | `string` | Override command name (default: handler.alias) |
|
|
55
|
+
| `description` | `string` | Override description (default: handler.description) |
|
|
56
|
+
| `exclude` | `string[]` | Field names to exclude from CLI options |
|
|
57
|
+
| `onComplete` | `OnCompleteCallback` | Called with handler's return value on success |
|
|
58
|
+
| `onError` | `OnErrorCallback` | Receives errors reported via `context.onError()` |
|
|
59
|
+
| `onFatal` | `OnFatalCallback` | Receives fatal errors (thrown or via `context.onFatal()`) |
|
|
60
|
+
| `onMessage` | `OnMessageCallback` | Receives messages from `context.sendMessage` |
|
|
61
|
+
| `overrides` | `Record<string, override>` | Per-field option overrides |
|
|
62
|
+
|
|
63
|
+
## Callback Hooks
|
|
64
|
+
|
|
65
|
+
### onMessage
|
|
66
|
+
|
|
67
|
+
Receives progress messages sent by the service via `context.sendMessage`:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { Command } from "commander";
|
|
71
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
72
|
+
import { registerServiceCommand } from "@jaypie/vocabulary/commander";
|
|
73
|
+
|
|
74
|
+
const handler = serviceHandler({
|
|
75
|
+
alias: "process",
|
|
76
|
+
input: { jobId: { type: String, letter: "j" } },
|
|
77
|
+
service: async ({ jobId }, context) => {
|
|
78
|
+
// Send progress messages during execution
|
|
79
|
+
context?.sendMessage?.({ content: `Starting job ${jobId}` });
|
|
80
|
+
|
|
81
|
+
// Simulate work
|
|
82
|
+
await doStep1();
|
|
83
|
+
context?.sendMessage?.({ content: "Step 1 complete", level: "debug" });
|
|
84
|
+
|
|
85
|
+
await doStep2();
|
|
86
|
+
context?.sendMessage?.({ content: "Step 2 complete", level: "debug" });
|
|
87
|
+
|
|
88
|
+
context?.sendMessage?.({ content: "Job finished!", level: "info" });
|
|
89
|
+
return { jobId, status: "complete" };
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const program = new Command();
|
|
94
|
+
registerServiceCommand({
|
|
95
|
+
handler,
|
|
96
|
+
program,
|
|
97
|
+
onMessage: (msg) => {
|
|
98
|
+
// msg: { content: string, level?: "trace"|"debug"|"info"|"warn"|"error" }
|
|
99
|
+
const level = msg.level || "info";
|
|
100
|
+
console[level](msg.content);
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
program.parse();
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Important:** Errors in `onMessage` are swallowed to ensure messaging failures never halt service execution.
|
|
107
|
+
|
|
108
|
+
### onComplete
|
|
109
|
+
|
|
110
|
+
Called with the handler's return value on successful completion:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
registerServiceCommand({
|
|
114
|
+
handler,
|
|
115
|
+
program,
|
|
116
|
+
onComplete: (response) => {
|
|
117
|
+
// Called after service completes successfully
|
|
118
|
+
console.log("Result:", JSON.stringify(response, null, 2));
|
|
119
|
+
|
|
120
|
+
// Common patterns:
|
|
121
|
+
// - Save results to file
|
|
122
|
+
// - Display formatted output
|
|
123
|
+
// - Trigger follow-up actions
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### onError
|
|
129
|
+
|
|
130
|
+
Receives errors that the service explicitly reports via `context.onError()`. Use this for recoverable errors that don't halt execution:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
registerServiceCommand({
|
|
134
|
+
handler,
|
|
135
|
+
program,
|
|
136
|
+
onError: (error) => {
|
|
137
|
+
// Log recoverable errors
|
|
138
|
+
console.warn("Warning:", error.message);
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### onFatal
|
|
144
|
+
|
|
145
|
+
Receives fatal errors - either thrown errors or errors reported via `context.onFatal()`. Any error that escapes the service (is thrown) is treated as fatal:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
registerServiceCommand({
|
|
149
|
+
handler,
|
|
150
|
+
program,
|
|
151
|
+
onFatal: (error) => {
|
|
152
|
+
console.error("Fatal error:", error.message);
|
|
153
|
+
process.exit(1);
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Error handling priority:**
|
|
159
|
+
1. If `onFatal` is provided, thrown errors go to `onFatal`
|
|
160
|
+
2. If only `onError` is provided, thrown errors fall back to `onError`
|
|
161
|
+
3. If neither is provided, errors are re-thrown
|
|
162
|
+
|
|
163
|
+
## Complete Example with All Callbacks
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { Command } from "commander";
|
|
167
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
168
|
+
import { registerServiceCommand } from "@jaypie/vocabulary/commander";
|
|
169
|
+
|
|
170
|
+
const evaluateHandler = serviceHandler({
|
|
171
|
+
alias: "evaluate",
|
|
172
|
+
description: "Run an evaluation job",
|
|
173
|
+
input: {
|
|
174
|
+
jobId: {
|
|
175
|
+
type: String,
|
|
176
|
+
flag: "job",
|
|
177
|
+
letter: "j",
|
|
178
|
+
description: "Job identifier",
|
|
179
|
+
},
|
|
180
|
+
priority: {
|
|
181
|
+
type: [1, 2, 3, 4, 5],
|
|
182
|
+
default: 3,
|
|
183
|
+
letter: "p",
|
|
184
|
+
description: "Job priority (1-5)",
|
|
185
|
+
},
|
|
186
|
+
tags: {
|
|
187
|
+
type: [String],
|
|
188
|
+
letter: "t",
|
|
189
|
+
required: false,
|
|
190
|
+
description: "Tags to apply",
|
|
191
|
+
},
|
|
192
|
+
dryRun: {
|
|
193
|
+
type: Boolean,
|
|
194
|
+
letter: "d",
|
|
195
|
+
default: false,
|
|
196
|
+
description: "Run without executing",
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
service: async ({ dryRun, jobId, priority, tags }, context) => {
|
|
200
|
+
context?.sendMessage?.({ content: `Initializing job ${jobId}...` });
|
|
201
|
+
|
|
202
|
+
if (dryRun) {
|
|
203
|
+
context?.sendMessage?.({ content: "Dry run mode - skipping execution", level: "warn" });
|
|
204
|
+
return { jobId, status: "dry-run", skipped: true };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Handle recoverable errors without throwing
|
|
208
|
+
try {
|
|
209
|
+
await riskyOperation();
|
|
210
|
+
} catch (err) {
|
|
211
|
+
context?.onError?.(err); // Reports error but continues
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
context?.sendMessage?.({ content: `Running with priority ${priority}` });
|
|
215
|
+
|
|
216
|
+
if (tags?.length) {
|
|
217
|
+
context?.sendMessage?.({ content: `Applying tags: ${tags.join(", ")}`, level: "debug" });
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Simulate processing
|
|
221
|
+
for (let i = 1; i <= 5; i++) {
|
|
222
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
223
|
+
context?.sendMessage?.({ content: `Progress: ${i * 20}%`, level: "debug" });
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
context?.sendMessage?.({ content: "Evaluation complete!" });
|
|
227
|
+
return { jobId, status: "complete", results: 42 };
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const program = new Command();
|
|
232
|
+
program.version("1.0.0").description("Evaluation CLI");
|
|
233
|
+
|
|
234
|
+
registerServiceCommand({
|
|
235
|
+
handler: evaluateHandler,
|
|
236
|
+
program,
|
|
237
|
+
onMessage: (msg) => {
|
|
238
|
+
const prefix = msg.level === "warn" ? "WARNING: " :
|
|
239
|
+
msg.level === "error" ? "ERROR: " : "";
|
|
240
|
+
console.log(`${prefix}${msg.content}`);
|
|
241
|
+
},
|
|
242
|
+
onComplete: (response) => {
|
|
243
|
+
console.log("\n--- Results ---");
|
|
244
|
+
console.log(JSON.stringify(response, null, 2));
|
|
245
|
+
},
|
|
246
|
+
onError: (error) => {
|
|
247
|
+
// Recoverable errors reported via context.onError()
|
|
248
|
+
console.warn("Warning:", error.message);
|
|
249
|
+
},
|
|
250
|
+
onFatal: (error) => {
|
|
251
|
+
// Fatal errors (thrown or via context.onFatal())
|
|
252
|
+
console.error("\nFatal:", error.message);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
program.parse();
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Usage:
|
|
261
|
+
```bash
|
|
262
|
+
# Basic execution
|
|
263
|
+
cli evaluate --job abc123
|
|
264
|
+
|
|
265
|
+
# With all options
|
|
266
|
+
cli evaluate -j abc123 -p 1 -t urgent -t critical --dry-run
|
|
267
|
+
|
|
268
|
+
# Help
|
|
269
|
+
cli evaluate --help
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Input Flag and Letter Properties
|
|
273
|
+
|
|
274
|
+
Define CLI flags directly in input definitions:
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
input: {
|
|
278
|
+
userName: {
|
|
279
|
+
type: String,
|
|
280
|
+
flag: "user", // Long flag: --user (instead of --user-name)
|
|
281
|
+
letter: "u", // Short flag: -u
|
|
282
|
+
description: "User name to greet",
|
|
283
|
+
},
|
|
284
|
+
verbose: {
|
|
285
|
+
type: Boolean,
|
|
286
|
+
letter: "v", // -v
|
|
287
|
+
},
|
|
288
|
+
}
|
|
289
|
+
// Generates: --user <userName>, -u and --verbose, -v
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Naming Convention
|
|
293
|
+
|
|
294
|
+
| Property | CLI Flag | Example |
|
|
295
|
+
|----------|----------|---------|
|
|
296
|
+
| `userName` (camelCase) | `--user-name` | Default behavior |
|
|
297
|
+
| `flag: "user"` | `--user` | Override long flag |
|
|
298
|
+
| `letter: "u"` | `-u` | Short flag |
|
|
299
|
+
|
|
300
|
+
## Boolean Flag Behavior
|
|
301
|
+
|
|
302
|
+
Commander.js automatically handles boolean flags:
|
|
303
|
+
- `--verbose` sets to `true`
|
|
304
|
+
- `--no-verbose` sets to `false` (for flags with `default: true`)
|
|
305
|
+
|
|
306
|
+
## Manual Integration
|
|
307
|
+
|
|
308
|
+
For more control, use `createCommanderOptions` and `parseCommanderOptions`:
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
import { Command } from "commander";
|
|
312
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
313
|
+
import {
|
|
314
|
+
createCommanderOptions,
|
|
315
|
+
parseCommanderOptions,
|
|
316
|
+
} from "@jaypie/vocabulary/commander";
|
|
317
|
+
|
|
318
|
+
const handler = serviceHandler({
|
|
319
|
+
input: {
|
|
320
|
+
userName: { type: String, description: "User name" },
|
|
321
|
+
maxRetries: { type: Number, default: 3 },
|
|
322
|
+
verbose: { type: Boolean },
|
|
323
|
+
},
|
|
324
|
+
service: (input) => console.log(input),
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
const program = new Command();
|
|
328
|
+
|
|
329
|
+
// Create options from handler input
|
|
330
|
+
const { options } = createCommanderOptions(handler.input, {
|
|
331
|
+
exclude: ["internalField"],
|
|
332
|
+
overrides: {
|
|
333
|
+
userName: { short: "u", description: "Override description" },
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
options.forEach((opt) => program.addOption(opt));
|
|
337
|
+
|
|
338
|
+
// Wire up action
|
|
339
|
+
program.action(async (opts) => {
|
|
340
|
+
const input = parseCommanderOptions(opts, { input: handler.input });
|
|
341
|
+
await handler(input);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
program.parse();
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## TypeScript Types
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
import type {
|
|
351
|
+
CommanderOptionOverride,
|
|
352
|
+
CreateCommanderOptionsConfig,
|
|
353
|
+
CreateCommanderOptionsResult,
|
|
354
|
+
OnCompleteCallback,
|
|
355
|
+
OnErrorCallback,
|
|
356
|
+
OnFatalCallback,
|
|
357
|
+
OnMessageCallback,
|
|
358
|
+
ParseCommanderOptionsConfig,
|
|
359
|
+
RegisterServiceCommandConfig,
|
|
360
|
+
RegisterServiceCommandResult,
|
|
361
|
+
} from "@jaypie/vocabulary/commander";
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Callback Type Definitions
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
// Message received from context.sendMessage
|
|
368
|
+
interface Message {
|
|
369
|
+
content: string;
|
|
370
|
+
level?: "trace" | "debug" | "info" | "warn" | "error";
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// onMessage callback
|
|
374
|
+
type OnMessageCallback = (message: Message) => void | Promise<void>;
|
|
375
|
+
|
|
376
|
+
// onComplete callback - receives handler return value
|
|
377
|
+
type OnCompleteCallback<T = unknown> = (response: T) => void | Promise<void>;
|
|
378
|
+
|
|
379
|
+
// onError callback - receives errors from context.onError()
|
|
380
|
+
type OnErrorCallback = (error: unknown) => void | Promise<void>;
|
|
381
|
+
|
|
382
|
+
// onFatal callback - receives fatal errors (thrown or context.onFatal())
|
|
383
|
+
type OnFatalCallback = (error: unknown) => void | Promise<void>;
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Exports
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
// @jaypie/vocabulary/commander
|
|
390
|
+
export { createCommanderOptions } from "./createCommanderOptions.js";
|
|
391
|
+
export { parseCommanderOptions } from "./parseCommanderOptions.js";
|
|
392
|
+
export { registerServiceCommand } from "./registerServiceCommand.js";
|
|
393
|
+
|
|
394
|
+
export type {
|
|
395
|
+
CommanderOptionOverride,
|
|
396
|
+
CreateCommanderOptionsConfig,
|
|
397
|
+
CreateCommanderOptionsResult,
|
|
398
|
+
OnCompleteCallback,
|
|
399
|
+
OnErrorCallback,
|
|
400
|
+
OnFatalCallback,
|
|
401
|
+
OnMessageCallback,
|
|
402
|
+
ParseCommanderOptionsConfig,
|
|
403
|
+
RegisterServiceCommandConfig,
|
|
404
|
+
RegisterServiceCommandResult,
|
|
405
|
+
} from "./types.js";
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## Related
|
|
409
|
+
|
|
410
|
+
- [Jaypie_Commander_CLI_Package.md](Jaypie_Commander_CLI_Package.md) - Setting up a Commander CLI project from scratch
|
|
411
|
+
- [Jaypie_Vocabulary_Package.md](Jaypie_Vocabulary_Package.md) - Core serviceHandler and type coercion
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: LLM tool creation from serviceHandler for use with @jaypie/llm Toolkit
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Jaypie Vocabulary LLM Adapter
|
|
6
|
+
|
|
7
|
+
The LLM adapter (`@jaypie/vocabulary/llm`) creates LLM tools from Jaypie service handlers for use with `@jaypie/llm` Toolkit, automatically generating JSON Schema from input definitions.
|
|
8
|
+
|
|
9
|
+
**See also:** [Jaypie_Vocabulary_Package.md](Jaypie_Vocabulary_Package.md) for core serviceHandler documentation.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @jaypie/vocabulary @jaypie/llm
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
21
|
+
import { createLlmTool } from "@jaypie/vocabulary/llm";
|
|
22
|
+
import { Toolkit } from "@jaypie/llm";
|
|
23
|
+
|
|
24
|
+
const handler = serviceHandler({
|
|
25
|
+
alias: "greet",
|
|
26
|
+
description: "Greet a user by name",
|
|
27
|
+
input: {
|
|
28
|
+
userName: { type: String, description: "The user's name" },
|
|
29
|
+
loud: { type: Boolean, default: false, description: "Shout the greeting" },
|
|
30
|
+
},
|
|
31
|
+
service: ({ userName, loud }) => {
|
|
32
|
+
const greeting = `Hello, ${userName}!`;
|
|
33
|
+
return loud ? greeting.toUpperCase() : greeting;
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const { tool } = createLlmTool({ handler });
|
|
38
|
+
const toolkit = new Toolkit([tool]);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## createLlmTool
|
|
42
|
+
|
|
43
|
+
Creates an LLM tool from a serviceHandler.
|
|
44
|
+
|
|
45
|
+
### Options
|
|
46
|
+
|
|
47
|
+
| Option | Type | Description |
|
|
48
|
+
|--------|------|-------------|
|
|
49
|
+
| `handler` | `ServiceHandlerFunction` | Required. The service handler to adapt |
|
|
50
|
+
| `name` | `string` | Override tool name (defaults to handler.alias) |
|
|
51
|
+
| `description` | `string` | Override tool description (defaults to handler.description) |
|
|
52
|
+
| `message` | `string \| function` | Custom message for logging |
|
|
53
|
+
| `exclude` | `string[]` | Fields to exclude from tool parameters |
|
|
54
|
+
| `onComplete` | `OnCompleteCallback` | Called with tool's return value on success |
|
|
55
|
+
| `onError` | `OnErrorCallback` | Receives errors reported via `context.onError()` in service |
|
|
56
|
+
| `onFatal` | `OnFatalCallback` | Receives fatal errors (thrown or via `context.onFatal()`) |
|
|
57
|
+
| `onMessage` | `OnMessageCallback` | Receives messages from `context.sendMessage` in service |
|
|
58
|
+
|
|
59
|
+
### Basic Usage
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
63
|
+
import { createLlmTool } from "@jaypie/vocabulary/llm";
|
|
64
|
+
|
|
65
|
+
const calculateHandler = serviceHandler({
|
|
66
|
+
alias: "calculate",
|
|
67
|
+
description: "Perform a mathematical calculation",
|
|
68
|
+
input: {
|
|
69
|
+
operation: { type: ["add", "subtract", "multiply", "divide"] },
|
|
70
|
+
a: { type: Number, description: "First operand" },
|
|
71
|
+
b: { type: Number, description: "Second operand" },
|
|
72
|
+
},
|
|
73
|
+
service: ({ operation, a, b }) => {
|
|
74
|
+
switch (operation) {
|
|
75
|
+
case "add": return a + b;
|
|
76
|
+
case "subtract": return a - b;
|
|
77
|
+
case "multiply": return a * b;
|
|
78
|
+
case "divide": return a / b;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const { tool } = createLlmTool({ handler: calculateHandler });
|
|
84
|
+
|
|
85
|
+
// Tool has these properties:
|
|
86
|
+
// tool.name: "calculate"
|
|
87
|
+
// tool.description: "Perform a mathematical calculation"
|
|
88
|
+
// tool.parameters: JSON Schema for inputs
|
|
89
|
+
// tool.function: The callable function
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Overriding Name and Description
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const { tool } = createLlmTool({
|
|
96
|
+
handler,
|
|
97
|
+
name: "math_calculator",
|
|
98
|
+
description: "A tool for performing basic math operations",
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Excluding Fields
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const handler = serviceHandler({
|
|
106
|
+
alias: "search",
|
|
107
|
+
input: {
|
|
108
|
+
query: { type: String },
|
|
109
|
+
limit: { type: Number, default: 10 },
|
|
110
|
+
_internalId: { type: String }, // Internal field
|
|
111
|
+
},
|
|
112
|
+
service: async (params) => { /* ... */ },
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const { tool } = createLlmTool({
|
|
116
|
+
handler,
|
|
117
|
+
exclude: ["_internalId"], // Not exposed to LLM
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Lifecycle Callbacks
|
|
122
|
+
|
|
123
|
+
Services can use context callbacks to report progress, errors, and completion:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const handler = serviceHandler({
|
|
127
|
+
alias: "evaluate",
|
|
128
|
+
input: { jobId: { type: String } },
|
|
129
|
+
service: async ({ jobId }, context) => {
|
|
130
|
+
context?.sendMessage?.({ content: `Processing ${jobId}` });
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
await riskyOperation();
|
|
134
|
+
} catch (err) {
|
|
135
|
+
context?.onError?.(err); // Reports error but continues
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return { jobId, status: "complete" };
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const { tool } = createLlmTool({
|
|
143
|
+
handler,
|
|
144
|
+
onComplete: (result) => console.log("Tool completed:", result),
|
|
145
|
+
onError: (error) => console.warn("Recoverable error:", error),
|
|
146
|
+
onFatal: (error) => console.error("Fatal error:", error),
|
|
147
|
+
onMessage: (msg) => console.log(`[${msg.level || "info"}] ${msg.content}`),
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Error handling**: Services receive `context.onError()` and `context.onFatal()` callbacks to report errors without throwing. Any error that escapes the service (is thrown) is treated as fatal and routes to `onFatal`. If `onFatal` is not provided, thrown errors fall back to `onError`. Callback errors are swallowed to ensure failures never halt service execution.
|
|
152
|
+
|
|
153
|
+
## inputToJsonSchema
|
|
154
|
+
|
|
155
|
+
Converts vocabulary input definitions to JSON Schema:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { inputToJsonSchema } from "@jaypie/vocabulary/llm";
|
|
159
|
+
|
|
160
|
+
const schema = inputToJsonSchema({
|
|
161
|
+
userName: { type: String, description: "User's name" },
|
|
162
|
+
age: { type: Number, required: false },
|
|
163
|
+
role: { type: ["admin", "user", "guest"], default: "user" },
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Returns:
|
|
167
|
+
{
|
|
168
|
+
type: "object",
|
|
169
|
+
properties: {
|
|
170
|
+
userName: { type: "string", description: "User's name" },
|
|
171
|
+
age: { type: "number" },
|
|
172
|
+
role: { type: "string", enum: ["admin", "user", "guest"] },
|
|
173
|
+
},
|
|
174
|
+
required: ["userName"],
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Type Mappings
|
|
179
|
+
|
|
180
|
+
| Vocabulary Type | JSON Schema |
|
|
181
|
+
|-----------------|-------------|
|
|
182
|
+
| `String` | `{ type: "string" }` |
|
|
183
|
+
| `Number` | `{ type: "number" }` |
|
|
184
|
+
| `Boolean` | `{ type: "boolean" }` |
|
|
185
|
+
| `Array` | `{ type: "array" }` |
|
|
186
|
+
| `Object` | `{ type: "object" }` |
|
|
187
|
+
| `[String]` | `{ type: "array", items: { type: "string" } }` |
|
|
188
|
+
| `[Number]` | `{ type: "array", items: { type: "number" } }` |
|
|
189
|
+
| `/regex/` | `{ type: "string", pattern: "..." }` |
|
|
190
|
+
| `["a", "b"]` | `{ type: "string", enum: ["a", "b"] }` |
|
|
191
|
+
| `[1, 2, 3]` | `{ type: "number", enum: [1, 2, 3] }` |
|
|
192
|
+
|
|
193
|
+
### Excluding Fields
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const schema = inputToJsonSchema(handler.input, {
|
|
197
|
+
exclude: ["internalField", "debugMode"],
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Complete Example
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { serviceHandler } from "@jaypie/vocabulary";
|
|
205
|
+
import { createLlmTool } from "@jaypie/vocabulary/llm";
|
|
206
|
+
import { Llm, Toolkit } from "@jaypie/llm";
|
|
207
|
+
|
|
208
|
+
// Define service handlers
|
|
209
|
+
const weatherHandler = serviceHandler({
|
|
210
|
+
alias: "get_weather",
|
|
211
|
+
description: "Get current weather for a location",
|
|
212
|
+
input: {
|
|
213
|
+
location: { type: String, description: "City name or coordinates" },
|
|
214
|
+
units: { type: ["celsius", "fahrenheit"], default: "celsius" },
|
|
215
|
+
},
|
|
216
|
+
service: async ({ location, units }) => {
|
|
217
|
+
const weather = await fetchWeather(location);
|
|
218
|
+
return {
|
|
219
|
+
location,
|
|
220
|
+
temperature: units === "celsius" ? weather.tempC : weather.tempF,
|
|
221
|
+
units,
|
|
222
|
+
conditions: weather.conditions,
|
|
223
|
+
};
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const searchHandler = serviceHandler({
|
|
228
|
+
alias: "search_web",
|
|
229
|
+
description: "Search the web for information",
|
|
230
|
+
input: {
|
|
231
|
+
query: { type: String, description: "Search query" },
|
|
232
|
+
maxResults: { type: Number, default: 5, description: "Maximum results" },
|
|
233
|
+
},
|
|
234
|
+
service: async ({ query, maxResults }) => {
|
|
235
|
+
return await performSearch(query, maxResults);
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Create tools
|
|
240
|
+
const { tool: weatherTool } = createLlmTool({ handler: weatherHandler });
|
|
241
|
+
const { tool: searchTool } = createLlmTool({ handler: searchHandler });
|
|
242
|
+
|
|
243
|
+
// Use with Toolkit
|
|
244
|
+
const toolkit = new Toolkit([weatherTool, searchTool]);
|
|
245
|
+
const llm = new Llm({ toolkit });
|
|
246
|
+
|
|
247
|
+
const response = await llm.ask("What's the weather in Tokyo?");
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## TypeScript Types
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
import type {
|
|
254
|
+
CreateLlmToolConfig,
|
|
255
|
+
CreateLlmToolResult,
|
|
256
|
+
LlmTool,
|
|
257
|
+
OnCompleteCallback,
|
|
258
|
+
OnErrorCallback,
|
|
259
|
+
OnFatalCallback,
|
|
260
|
+
OnMessageCallback,
|
|
261
|
+
} from "@jaypie/vocabulary/llm";
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Type Definitions
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
interface LlmTool {
|
|
268
|
+
name: string;
|
|
269
|
+
description: string;
|
|
270
|
+
parameters: JsonSchema;
|
|
271
|
+
function: (params: Record<string, unknown>) => Promise<unknown>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
interface CreateLlmToolConfig {
|
|
275
|
+
handler: ServiceHandlerFunction;
|
|
276
|
+
name?: string;
|
|
277
|
+
description?: string;
|
|
278
|
+
message?: string | ((params: Record<string, unknown>) => string);
|
|
279
|
+
exclude?: string[];
|
|
280
|
+
onComplete?: OnCompleteCallback;
|
|
281
|
+
onError?: OnErrorCallback;
|
|
282
|
+
onFatal?: OnFatalCallback;
|
|
283
|
+
onMessage?: OnMessageCallback;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
interface CreateLlmToolResult {
|
|
287
|
+
tool: LlmTool;
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Exports
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// @jaypie/vocabulary/llm
|
|
295
|
+
export { createLlmTool } from "./createLlmTool.js";
|
|
296
|
+
export { inputToJsonSchema } from "./inputToJsonSchema.js";
|
|
297
|
+
|
|
298
|
+
export type {
|
|
299
|
+
CreateLlmToolConfig,
|
|
300
|
+
CreateLlmToolResult,
|
|
301
|
+
LlmTool,
|
|
302
|
+
OnCompleteCallback,
|
|
303
|
+
OnErrorCallback,
|
|
304
|
+
OnFatalCallback,
|
|
305
|
+
OnMessageCallback,
|
|
306
|
+
} from "./types.js";
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Related
|
|
310
|
+
|
|
311
|
+
- [Jaypie_Vocabulary_Package.md](Jaypie_Vocabulary_Package.md) - Core serviceHandler and type coercion
|
|
312
|
+
- [Jaypie_Llm_Tools.md](Jaypie_Llm_Tools.md) - LLM tools and Toolkit usage
|