jev-recipes 0.0.1 → 0.0.4

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 (56) hide show
  1. package/CHANGELOG.md +7 -2
  2. package/README.md +95 -105
  3. package/dist/catalog/index.d.ts +211 -0
  4. package/dist/catalog/index.js +31 -0
  5. package/dist/catalog/recipes.d.ts +351 -0
  6. package/dist/catalog/recipes.js +50 -0
  7. package/dist/catalog/schema.d.ts +19 -0
  8. package/dist/catalog/schema.js +9 -0
  9. package/dist/cli/index.js +32 -16
  10. package/dist/cli/schema.d.ts +23 -8
  11. package/dist/cli/schema.js +10 -10
  12. package/dist/examples/support/index.d.ts +1 -0
  13. package/dist/examples/support/index.js +37 -0
  14. package/dist/examples/support/schema.d.ts +566 -0
  15. package/dist/examples/support/schema.js +76 -0
  16. package/dist/examples/support/workflow.d.ts +3 -0
  17. package/dist/examples/support/workflow.js +85 -0
  18. package/dist/recipes/answerability/index.d.ts +5 -0
  19. package/dist/recipes/answerability/index.js +32 -0
  20. package/dist/recipes/answerability/metadata.d.ts +8 -0
  21. package/dist/recipes/answerability/metadata.js +11 -0
  22. package/dist/recipes/answerability/schema.d.ts +47 -0
  23. package/dist/recipes/answerability/schema.js +25 -0
  24. package/dist/recipes/clarify/index.d.ts +5 -0
  25. package/dist/recipes/clarify/index.js +46 -0
  26. package/dist/recipes/clarify/metadata.d.ts +8 -0
  27. package/dist/recipes/clarify/metadata.js +11 -0
  28. package/dist/recipes/clarify/schema.d.ts +55 -0
  29. package/dist/recipes/clarify/schema.js +27 -0
  30. package/dist/recipes/handoff/index.d.ts +5 -0
  31. package/dist/recipes/handoff/index.js +50 -0
  32. package/dist/recipes/handoff/metadata.d.ts +8 -0
  33. package/dist/recipes/handoff/metadata.js +11 -0
  34. package/dist/recipes/handoff/schema.d.ts +59 -0
  35. package/dist/recipes/handoff/schema.js +27 -0
  36. package/dist/recipes/rerank/metadata.d.ts +8 -0
  37. package/dist/recipes/rerank/metadata.js +11 -0
  38. package/dist/recipes/route/metadata.d.ts +8 -0
  39. package/dist/recipes/route/metadata.js +11 -0
  40. package/dist/recipes/verify/metadata.d.ts +8 -0
  41. package/dist/recipes/verify/metadata.js +11 -0
  42. package/dist/src/index.d.ts +8 -0
  43. package/dist/src/index.js +4 -0
  44. package/dist/src/schema.d.ts +19 -0
  45. package/dist/src/schema.js +9 -0
  46. package/examples/support/README.md +60 -0
  47. package/examples/support/demo.json +156 -0
  48. package/package.json +26 -7
  49. package/recipes/answerability/README.md +29 -0
  50. package/recipes/answerability/demo.json +31 -0
  51. package/recipes/clarify/README.md +32 -0
  52. package/recipes/clarify/demo.json +45 -0
  53. package/recipes/handoff/README.md +35 -0
  54. package/recipes/handoff/demo.json +30 -0
  55. package/dist/cli/recipes.d.ts +0 -53
  56. package/dist/cli/recipes.js +0 -20
@@ -0,0 +1,351 @@
1
+ import type { RecipeOptions } from '../src/schema.js';
2
+ export declare const recipes: {
3
+ route: {
4
+ metadata: {
5
+ id: string;
6
+ title: string;
7
+ description: string;
8
+ category: "workflow";
9
+ tags: string[];
10
+ limitations: string[];
11
+ };
12
+ inputSchema: import("zod").ZodObject<{
13
+ request: import("zod").ZodString;
14
+ routes: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodString>;
15
+ minConfidence: import("zod").ZodOptional<import("zod").ZodNumber>;
16
+ }, import("zod/v4/core").$strip>;
17
+ resultSchema: import("zod").ZodObject<{
18
+ model: import("zod").ZodString;
19
+ usage: import("zod").ZodObject<{
20
+ input_tokens: import("zod").ZodNumber;
21
+ output_tokens: import("zod").ZodNumber;
22
+ }, import("zod/v4/core").$strip>;
23
+ status: import("zod").ZodEnum<{
24
+ ready: "ready";
25
+ review: "review";
26
+ }>;
27
+ route: import("zod").ZodNullable<import("zod").ZodString>;
28
+ suggestedRoute: import("zod").ZodNullable<import("zod").ZodString>;
29
+ confidence: import("zod").ZodNumber;
30
+ probabilities: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodNumber>;
31
+ }, import("zod/v4/core").$strip>;
32
+ run: (input: unknown, options?: RecipeOptions) => Promise<{
33
+ model: string;
34
+ usage: {
35
+ input_tokens: number;
36
+ output_tokens: number;
37
+ };
38
+ status: "ready" | "review";
39
+ route: string | null;
40
+ suggestedRoute: string | null;
41
+ confidence: number;
42
+ probabilities: Record<string, number>;
43
+ }>;
44
+ };
45
+ rerank: {
46
+ metadata: {
47
+ id: string;
48
+ title: string;
49
+ description: string;
50
+ category: "retrieval";
51
+ tags: string[];
52
+ limitations: string[];
53
+ };
54
+ inputSchema: import("zod").ZodObject<{
55
+ query: import("zod").ZodString;
56
+ items: import("zod").ZodArray<import("zod").ZodObject<{
57
+ id: import("zod").ZodString;
58
+ text: import("zod").ZodString;
59
+ }, import("zod/v4/core").$strip>>;
60
+ topK: import("zod").ZodOptional<import("zod").ZodNumber>;
61
+ minRelevance: import("zod").ZodOptional<import("zod").ZodNumber>;
62
+ }, import("zod/v4/core").$strip>;
63
+ resultSchema: import("zod").ZodObject<{
64
+ model: import("zod").ZodString;
65
+ usage: import("zod").ZodObject<{
66
+ input_tokens: import("zod").ZodNumber;
67
+ output_tokens: import("zod").ZodNumber;
68
+ }, import("zod/v4/core").$strip>;
69
+ status: import("zod").ZodEnum<{
70
+ ready: "ready";
71
+ review: "review";
72
+ }>;
73
+ items: import("zod").ZodArray<import("zod").ZodObject<{
74
+ id: import("zod").ZodString;
75
+ text: import("zod").ZodString;
76
+ relevance: import("zod").ZodNumber;
77
+ }, import("zod/v4/core").$strip>>;
78
+ evaluated: import("zod").ZodNumber;
79
+ }, import("zod/v4/core").$strip>;
80
+ run: (input: unknown, options?: RecipeOptions) => Promise<{
81
+ model: string;
82
+ usage: {
83
+ input_tokens: number;
84
+ output_tokens: number;
85
+ };
86
+ status: "ready" | "review";
87
+ items: {
88
+ id: string;
89
+ text: string;
90
+ relevance: number;
91
+ }[];
92
+ evaluated: number;
93
+ }>;
94
+ };
95
+ verify: {
96
+ metadata: {
97
+ id: string;
98
+ title: string;
99
+ description: string;
100
+ category: "retrieval";
101
+ tags: string[];
102
+ limitations: string[];
103
+ };
104
+ inputSchema: import("zod").ZodObject<{
105
+ claims: import("zod").ZodArray<import("zod").ZodObject<{
106
+ id: import("zod").ZodString;
107
+ claim: import("zod").ZodString;
108
+ evidence: import("zod").ZodString;
109
+ }, import("zod/v4/core").$strip>>;
110
+ minConfidence: import("zod").ZodOptional<import("zod").ZodNumber>;
111
+ }, import("zod/v4/core").$strip>;
112
+ resultSchema: import("zod").ZodObject<{
113
+ model: import("zod").ZodString;
114
+ usage: import("zod").ZodObject<{
115
+ input_tokens: import("zod").ZodNumber;
116
+ output_tokens: import("zod").ZodNumber;
117
+ }, import("zod/v4/core").$strip>;
118
+ checks: import("zod").ZodArray<import("zod").ZodObject<{
119
+ id: import("zod").ZodString;
120
+ status: import("zod").ZodEnum<{
121
+ ready: "ready";
122
+ review: "review";
123
+ }>;
124
+ verdict: import("zod").ZodEnum<{
125
+ supported: "supported";
126
+ contradicted: "contradicted";
127
+ unsupported: "unsupported";
128
+ }>;
129
+ confidence: import("zod").ZodNumber;
130
+ probabilities: import("zod").ZodRecord<import("zod").ZodEnum<{
131
+ supported: "supported";
132
+ contradicted: "contradicted";
133
+ unsupported: "unsupported";
134
+ }>, import("zod").ZodNumber>;
135
+ }, import("zod/v4/core").$strip>>;
136
+ allSupported: import("zod").ZodBoolean;
137
+ }, import("zod/v4/core").$strip>;
138
+ run: (input: unknown, options?: RecipeOptions) => Promise<{
139
+ model: string;
140
+ usage: {
141
+ input_tokens: number;
142
+ output_tokens: number;
143
+ };
144
+ checks: {
145
+ id: string;
146
+ status: "ready" | "review";
147
+ verdict: "supported" | "contradicted" | "unsupported";
148
+ confidence: number;
149
+ probabilities: Record<"supported" | "contradicted" | "unsupported", number>;
150
+ }[];
151
+ allSupported: boolean;
152
+ }>;
153
+ };
154
+ answerability: {
155
+ metadata: {
156
+ id: string;
157
+ title: string;
158
+ description: string;
159
+ category: "retrieval";
160
+ tags: string[];
161
+ limitations: string[];
162
+ };
163
+ inputSchema: import("zod").ZodObject<{
164
+ question: import("zod").ZodString;
165
+ evidence: import("zod").ZodArray<import("zod").ZodObject<{
166
+ id: import("zod").ZodString;
167
+ text: import("zod").ZodString;
168
+ }, import("zod/v4/core").$strip>>;
169
+ minConfidence: import("zod").ZodOptional<import("zod").ZodNumber>;
170
+ }, import("zod/v4/core").$strip>;
171
+ resultSchema: import("zod").ZodObject<{
172
+ model: import("zod").ZodString;
173
+ usage: import("zod").ZodObject<{
174
+ input_tokens: import("zod").ZodNumber;
175
+ output_tokens: import("zod").ZodNumber;
176
+ }, import("zod/v4/core").$strip>;
177
+ status: import("zod").ZodEnum<{
178
+ ready: "ready";
179
+ review: "review";
180
+ }>;
181
+ verdict: import("zod").ZodEnum<{
182
+ sufficient: "sufficient";
183
+ partial: "partial";
184
+ insufficient: "insufficient";
185
+ conflicting: "conflicting";
186
+ }>;
187
+ canAnswer: import("zod").ZodBoolean;
188
+ confidence: import("zod").ZodNumber;
189
+ probabilities: import("zod").ZodRecord<import("zod").ZodEnum<{
190
+ sufficient: "sufficient";
191
+ partial: "partial";
192
+ insufficient: "insufficient";
193
+ conflicting: "conflicting";
194
+ }>, import("zod").ZodNumber>;
195
+ }, import("zod/v4/core").$strip>;
196
+ run: (input: unknown, options?: RecipeOptions) => Promise<{
197
+ model: string;
198
+ usage: {
199
+ input_tokens: number;
200
+ output_tokens: number;
201
+ };
202
+ status: "ready" | "review";
203
+ verdict: "sufficient" | "partial" | "insufficient" | "conflicting";
204
+ canAnswer: boolean;
205
+ confidence: number;
206
+ probabilities: Record<"sufficient" | "partial" | "insufficient" | "conflicting", number>;
207
+ }>;
208
+ };
209
+ clarify: {
210
+ metadata: {
211
+ id: string;
212
+ title: string;
213
+ description: string;
214
+ category: "conversation";
215
+ tags: string[];
216
+ limitations: string[];
217
+ };
218
+ inputSchema: import("zod").ZodObject<{
219
+ request: import("zod").ZodString;
220
+ context: import("zod").ZodOptional<import("zod").ZodString>;
221
+ requirements: import("zod").ZodArray<import("zod").ZodObject<{
222
+ id: import("zod").ZodString;
223
+ description: import("zod").ZodString;
224
+ }, import("zod/v4/core").$strip>>;
225
+ minConfidence: import("zod").ZodOptional<import("zod").ZodNumber>;
226
+ }, import("zod/v4/core").$strip>;
227
+ resultSchema: import("zod").ZodObject<{
228
+ model: import("zod").ZodString;
229
+ usage: import("zod").ZodObject<{
230
+ input_tokens: import("zod").ZodNumber;
231
+ output_tokens: import("zod").ZodNumber;
232
+ }, import("zod/v4/core").$strip>;
233
+ status: import("zod").ZodEnum<{
234
+ ready: "ready";
235
+ review: "review";
236
+ }>;
237
+ canProceed: import("zod").ZodBoolean;
238
+ missing: import("zod").ZodArray<import("zod").ZodString>;
239
+ ambiguous: import("zod").ZodArray<import("zod").ZodString>;
240
+ checks: import("zod").ZodArray<import("zod").ZodObject<{
241
+ id: import("zod").ZodString;
242
+ status: import("zod").ZodEnum<{
243
+ ready: "ready";
244
+ review: "review";
245
+ }>;
246
+ verdict: import("zod").ZodEnum<{
247
+ present: "present";
248
+ missing: "missing";
249
+ ambiguous: "ambiguous";
250
+ }>;
251
+ confidence: import("zod").ZodNumber;
252
+ probabilities: import("zod").ZodRecord<import("zod").ZodEnum<{
253
+ present: "present";
254
+ missing: "missing";
255
+ ambiguous: "ambiguous";
256
+ }>, import("zod").ZodNumber>;
257
+ }, import("zod/v4/core").$strip>>;
258
+ }, import("zod/v4/core").$strip>;
259
+ run: (input: unknown, options?: RecipeOptions) => Promise<{
260
+ model: string;
261
+ usage: {
262
+ input_tokens: number;
263
+ output_tokens: number;
264
+ };
265
+ status: "ready" | "review";
266
+ canProceed: boolean;
267
+ missing: string[];
268
+ ambiguous: string[];
269
+ checks: {
270
+ id: string;
271
+ status: "ready" | "review";
272
+ verdict: "present" | "missing" | "ambiguous";
273
+ confidence: number;
274
+ probabilities: Record<"present" | "missing" | "ambiguous", number>;
275
+ }[];
276
+ }>;
277
+ };
278
+ handoff: {
279
+ metadata: {
280
+ id: string;
281
+ title: string;
282
+ description: string;
283
+ category: "workflow";
284
+ tags: string[];
285
+ limitations: string[];
286
+ };
287
+ inputSchema: import("zod").ZodObject<{
288
+ request: import("zod").ZodString;
289
+ context: import("zod").ZodOptional<import("zod").ZodString>;
290
+ rules: import("zod").ZodArray<import("zod").ZodObject<{
291
+ id: import("zod").ZodString;
292
+ description: import("zod").ZodString;
293
+ }, import("zod/v4/core").$strip>>;
294
+ minConfidence: import("zod").ZodOptional<import("zod").ZodNumber>;
295
+ }, import("zod/v4/core").$strip>;
296
+ resultSchema: import("zod").ZodObject<{
297
+ model: import("zod").ZodString;
298
+ usage: import("zod").ZodObject<{
299
+ input_tokens: import("zod").ZodNumber;
300
+ output_tokens: import("zod").ZodNumber;
301
+ }, import("zod/v4/core").$strip>;
302
+ status: import("zod").ZodEnum<{
303
+ ready: "ready";
304
+ review: "review";
305
+ }>;
306
+ decision: import("zod").ZodEnum<{
307
+ review: "review";
308
+ human: "human";
309
+ continue: "continue";
310
+ }>;
311
+ matchedRules: import("zod").ZodArray<import("zod").ZodString>;
312
+ uncertainRules: import("zod").ZodArray<import("zod").ZodString>;
313
+ checks: import("zod").ZodArray<import("zod").ZodObject<{
314
+ id: import("zod").ZodString;
315
+ status: import("zod").ZodEnum<{
316
+ ready: "ready";
317
+ review: "review";
318
+ }>;
319
+ verdict: import("zod").ZodEnum<{
320
+ matches: "matches";
321
+ does_not_match: "does_not_match";
322
+ unclear: "unclear";
323
+ }>;
324
+ confidence: import("zod").ZodNumber;
325
+ probabilities: import("zod").ZodRecord<import("zod").ZodEnum<{
326
+ matches: "matches";
327
+ does_not_match: "does_not_match";
328
+ unclear: "unclear";
329
+ }>, import("zod").ZodNumber>;
330
+ }, import("zod/v4/core").$strip>>;
331
+ }, import("zod/v4/core").$strip>;
332
+ run: (input: unknown, options?: RecipeOptions) => Promise<{
333
+ model: string;
334
+ usage: {
335
+ input_tokens: number;
336
+ output_tokens: number;
337
+ };
338
+ status: "ready" | "review";
339
+ decision: "review" | "human" | "continue";
340
+ matchedRules: string[];
341
+ uncertainRules: string[];
342
+ checks: {
343
+ id: string;
344
+ status: "ready" | "review";
345
+ verdict: "matches" | "does_not_match" | "unclear";
346
+ confidence: number;
347
+ probabilities: Record<"matches" | "does_not_match" | "unclear", number>;
348
+ }[];
349
+ }>;
350
+ };
351
+ };
@@ -0,0 +1,50 @@
1
+ import { route, routeInputSchema, routeResultSchema } from '../recipes/route/index.js';
2
+ import { metadata as routeMetadata } from '../recipes/route/metadata.js';
3
+ import { rerank, rerankInputSchema, rerankResultSchema } from '../recipes/rerank/index.js';
4
+ import { metadata as rerankMetadata } from '../recipes/rerank/metadata.js';
5
+ import { verify, verifyInputSchema, verifyResultSchema } from '../recipes/verify/index.js';
6
+ import { metadata as verifyMetadata } from '../recipes/verify/metadata.js';
7
+ import { answerability, answerabilityInputSchema, answerabilityResultSchema, } from '../recipes/answerability/index.js';
8
+ import { metadata as answerabilityMetadata } from '../recipes/answerability/metadata.js';
9
+ import { clarify, clarifyInputSchema, clarifyResultSchema } from '../recipes/clarify/index.js';
10
+ import { metadata as clarifyMetadata } from '../recipes/clarify/metadata.js';
11
+ import { handoff, handoffInputSchema, handoffResultSchema } from '../recipes/handoff/index.js';
12
+ import { metadata as handoffMetadata } from '../recipes/handoff/metadata.js';
13
+ export const recipes = {
14
+ route: {
15
+ metadata: routeMetadata,
16
+ inputSchema: routeInputSchema,
17
+ resultSchema: routeResultSchema,
18
+ run: (input, options) => route(routeInputSchema.parse(input), options),
19
+ },
20
+ rerank: {
21
+ metadata: rerankMetadata,
22
+ inputSchema: rerankInputSchema,
23
+ resultSchema: rerankResultSchema,
24
+ run: (input, options) => rerank(rerankInputSchema.parse(input), options),
25
+ },
26
+ verify: {
27
+ metadata: verifyMetadata,
28
+ inputSchema: verifyInputSchema,
29
+ resultSchema: verifyResultSchema,
30
+ run: (input, options) => verify(verifyInputSchema.parse(input), options),
31
+ },
32
+ answerability: {
33
+ metadata: answerabilityMetadata,
34
+ inputSchema: answerabilityInputSchema,
35
+ resultSchema: answerabilityResultSchema,
36
+ run: (input, options) => answerability(answerabilityInputSchema.parse(input), options),
37
+ },
38
+ clarify: {
39
+ metadata: clarifyMetadata,
40
+ inputSchema: clarifyInputSchema,
41
+ resultSchema: clarifyResultSchema,
42
+ run: (input, options) => clarify(clarifyInputSchema.parse(input), options),
43
+ },
44
+ handoff: {
45
+ metadata: handoffMetadata,
46
+ inputSchema: handoffInputSchema,
47
+ resultSchema: handoffResultSchema,
48
+ run: (input, options) => handoff(handoffInputSchema.parse(input), options),
49
+ },
50
+ };
@@ -0,0 +1,19 @@
1
+ import { z } from 'zod';
2
+ export declare const recipeNameSchema: z.ZodEnum<{
3
+ route: "route";
4
+ answerability: "answerability";
5
+ rerank: "rerank";
6
+ verify: "verify";
7
+ clarify: "clarify";
8
+ handoff: "handoff";
9
+ }>;
10
+ export declare const recipeFiltersSchema: z.ZodObject<{
11
+ query: z.ZodOptional<z.ZodString>;
12
+ category: z.ZodOptional<z.ZodEnum<{
13
+ retrieval: "retrieval";
14
+ conversation: "conversation";
15
+ workflow: "workflow";
16
+ }>>;
17
+ }, z.core.$strip>;
18
+ export type RecipeName = z.infer<typeof recipeNameSchema>;
19
+ export type RecipeFilters = z.infer<typeof recipeFiltersSchema>;
@@ -0,0 +1,9 @@
1
+ import { z } from 'zod';
2
+ import { nonEmptyText, recipeCategorySchema } from '../src/schema.js';
3
+ import { recipes } from './recipes.js';
4
+ const recipeNames = Object.keys(recipes);
5
+ export const recipeNameSchema = z.enum(recipeNames);
6
+ export const recipeFiltersSchema = z.object({
7
+ query: nonEmptyText.optional(),
8
+ category: recipeCategorySchema.optional(),
9
+ });
package/dist/cli/index.js CHANGED
@@ -2,7 +2,8 @@
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import { stdin, stdout, stderr } from 'node:process';
4
4
  import { z } from 'zod';
5
- import { recipes } from './recipes.js';
5
+ import { recipes } from '../catalog/recipes.js';
6
+ import { listRecipes, describeRecipe, recipeCategorySchema } from '../catalog/index.js';
6
7
  import { commandArgumentsSchema, demoFixtureSchema } from './schema.js';
7
8
  async function main() {
8
9
  const command = parseCommandArguments(process.argv.slice(2));
@@ -13,11 +14,13 @@ async function main() {
13
14
  case '--version':
14
15
  return printVersion();
15
16
  case 'list':
16
- return printRecipeList();
17
+ return printRecipeList(command.slice(1));
18
+ case 'describe':
19
+ return printRecipeDescription(command[1]);
17
20
  case 'example':
18
21
  return printExampleInput(command[1]);
19
22
  case 'demo':
20
- return runOfflineRecipe(command[1]);
23
+ return runOfflineRecipes(command[1]);
21
24
  case 'run':
22
25
  return runLiveRecipe(command[1], command[2]);
23
26
  }
@@ -31,12 +34,15 @@ function parseCommandArguments(args) {
31
34
  function printHelp() {
32
35
  stdout.write(`jev-recipes
33
36
 
34
- jev-recipes list List recipes
35
- jev-recipes demo <recipe> Run an offline fixture (no model call)
36
- jev-recipes example <recipe> Print example input as JSON
37
- jev-recipes run <recipe> <file|-> Run live with a JSON file or stdin
37
+ jev-recipes list [query] [--category <category>]
38
+ Discover recipes (all search terms must match)
39
+ jev-recipes describe <recipe> Print metadata, JSON schemas, and example input
40
+ jev-recipes demo <recipe|all> Run offline fixtures (no model calls)
41
+ jev-recipes example <recipe> Print example input as JSON
42
+ jev-recipes run <recipe> <file|-> Run live with a JSON file or stdin
38
43
  jev-recipes --version
39
44
 
45
+ Categories: retrieval, conversation, workflow. Quote multi-word search queries.
40
46
  Live runs send your input to TypeSafe and require TYPESAFE_API_KEY.
41
47
  Output is JSON. Errors go to stderr and exit with code 1.
42
48
  Review outcomes are successful evaluations; inspect status before acting.
@@ -47,26 +53,36 @@ async function printVersion() {
47
53
  const { version } = JSON.parse(packageJson);
48
54
  stdout.write(`${version}\n`);
49
55
  }
50
- function printRecipeList() {
51
- const recipeList = Object.entries(recipes).map(([id, recipe]) => ({
52
- id,
53
- description: recipe.description,
54
- }));
55
- printJson(recipeList);
56
+ function printRecipeList(args) {
57
+ const categoryPosition = args.indexOf('--category');
58
+ const query = args[0] === '--category' ? undefined : args[0];
59
+ const category = categoryPosition === -1 ? undefined : recipeCategorySchema.parse(args[categoryPosition + 1]);
60
+ printJson(listRecipes({ query, category }));
61
+ }
62
+ async function printRecipeDescription(name) {
63
+ const fixture = await readDemoFixture(name);
64
+ printJson({ ...describeRecipe(name), example: fixture.input });
56
65
  }
57
66
  async function printExampleInput(name) {
58
67
  const fixture = await readDemoFixture(name);
59
68
  printJson(fixture.input);
60
69
  }
61
- async function runOfflineRecipe(name) {
70
+ async function runOfflineRecipes(name) {
71
+ const output = name === 'all'
72
+ ? await Promise.all(listRecipes().map((recipe) => evaluateOfflineRecipe(recipe.id)))
73
+ : await evaluateOfflineRecipe(name);
74
+ printJson(output);
75
+ }
76
+ async function evaluateOfflineRecipe(name) {
62
77
  const fixture = await readDemoFixture(name);
63
78
  const fixtureClient = { systemOne: async () => fixture.response };
64
79
  const result = await recipes[name].run(fixture.input, { client: fixtureClient });
65
- printJson({
80
+ return {
66
81
  mode: 'demo',
82
+ recipe: name,
67
83
  note: 'Hand-authored fixture. No model was called; this does not measure accuracy.',
68
84
  result,
69
- });
85
+ };
70
86
  }
71
87
  async function runLiveRecipe(name, source) {
72
88
  const inputJson = source === '-' ? await readStandardInput() : await readFile(source, 'utf8');
@@ -1,23 +1,39 @@
1
1
  import { z } from 'zod';
2
- export declare const recipeNameSchema: z.ZodEnum<{
3
- route: "route";
4
- rerank: "rerank";
5
- verify: "verify";
6
- }>;
7
2
  export declare const commandArgumentsSchema: z.ZodUnion<readonly [z.ZodTuple<[z.ZodEnum<{
8
3
  "--help": "--help";
9
4
  "-h": "-h";
10
- }>], null>, z.ZodTuple<[z.ZodLiteral<"--version">], null>, z.ZodTuple<[z.ZodLiteral<"list">], null>, z.ZodTuple<[z.ZodEnum<{
11
- demo: "demo";
5
+ }>], null>, z.ZodTuple<[z.ZodLiteral<"--version">], null>, z.ZodTuple<[z.ZodLiteral<"list">], null>, z.ZodTuple<[z.ZodLiteral<"list">, z.ZodString], null>, z.ZodTuple<[z.ZodLiteral<"list">, z.ZodLiteral<"--category">, z.ZodEnum<{
6
+ retrieval: "retrieval";
7
+ conversation: "conversation";
8
+ workflow: "workflow";
9
+ }>], null>, z.ZodTuple<[z.ZodLiteral<"list">, z.ZodString, z.ZodLiteral<"--category">, z.ZodEnum<{
10
+ retrieval: "retrieval";
11
+ conversation: "conversation";
12
+ workflow: "workflow";
13
+ }>], null>, z.ZodTuple<[z.ZodLiteral<"demo">, z.ZodUnion<readonly [z.ZodEnum<{
14
+ route: "route";
15
+ answerability: "answerability";
16
+ rerank: "rerank";
17
+ verify: "verify";
18
+ clarify: "clarify";
19
+ handoff: "handoff";
20
+ }>, z.ZodLiteral<"all">]>], null>, z.ZodTuple<[z.ZodEnum<{
12
21
  example: "example";
22
+ describe: "describe";
13
23
  }>, z.ZodEnum<{
14
24
  route: "route";
25
+ answerability: "answerability";
15
26
  rerank: "rerank";
16
27
  verify: "verify";
28
+ clarify: "clarify";
29
+ handoff: "handoff";
17
30
  }>], null>, z.ZodTuple<[z.ZodLiteral<"run">, z.ZodEnum<{
18
31
  route: "route";
32
+ answerability: "answerability";
19
33
  rerank: "rerank";
20
34
  verify: "verify";
35
+ clarify: "clarify";
36
+ handoff: "handoff";
21
37
  }>, z.ZodString], null>]>;
22
38
  export declare const demoFixtureSchema: z.ZodObject<{
23
39
  input: z.ZodUnknown;
@@ -30,4 +46,3 @@ export declare const demoFixtureSchema: z.ZodObject<{
30
46
  answers: z.ZodRecord<z.ZodString, z.ZodUnknown>;
31
47
  }, z.core.$strip>;
32
48
  }, z.core.$strip>;
33
- export type RecipeName = z.infer<typeof recipeNameSchema>;
@@ -1,16 +1,16 @@
1
1
  import { z } from 'zod';
2
- import { decisionResponseSchema } from '../src/schema.js';
3
- import { recipes } from './recipes.js';
4
- const recipeNames = Object.keys(recipes);
5
- export const recipeNameSchema = z.enum(recipeNames);
2
+ import { decisionResponseSchema, nonEmptyText, recipeCategorySchema } from '../src/schema.js';
3
+ import { recipeNameSchema } from '../catalog/schema.js';
4
+ const searchQuery = nonEmptyText.refine((query) => !query.startsWith('--'), 'Expected a search query.');
6
5
  export const commandArgumentsSchema = z.union([
7
6
  z.tuple([z.enum(['--help', '-h'])]),
8
7
  z.tuple([z.literal('--version')]),
9
8
  z.tuple([z.literal('list')]),
10
- z.tuple([z.enum(['demo', 'example']), recipeNameSchema]),
11
- z.tuple([z.literal('run'), recipeNameSchema, z.string().min(1)]),
9
+ z.tuple([z.literal('list'), searchQuery]),
10
+ z.tuple([z.literal('list'), z.literal('--category'), recipeCategorySchema]),
11
+ z.tuple([z.literal('list'), searchQuery, z.literal('--category'), recipeCategorySchema]),
12
+ z.tuple([z.literal('demo'), z.union([recipeNameSchema, z.literal('all')])]),
13
+ z.tuple([z.enum(['example', 'describe']), recipeNameSchema]),
14
+ z.tuple([z.literal('run'), recipeNameSchema, nonEmptyText]),
12
15
  ]);
13
- export const demoFixtureSchema = z.object({
14
- input: z.unknown(),
15
- response: decisionResponseSchema,
16
- });
16
+ export const demoFixtureSchema = z.object({ input: z.unknown(), response: decisionResponseSchema });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { z } from 'zod';
3
+ import { createClient } from '../../src/client.js';
4
+ import { answerSupportRequest } from './workflow.js';
5
+ import { supportFixtureSchema } from './schema.js';
6
+ async function main() {
7
+ const args = z.union([z.tuple([]), z.tuple([z.literal('--live')])]).parse(process.argv.slice(2));
8
+ const fixtureJson = await readFile(new URL('../../../examples/support/demo.json', import.meta.url), 'utf8');
9
+ const fixture = supportFixtureSchema.parse(JSON.parse(fixtureJson));
10
+ const live = args[0] === '--live';
11
+ const client = live
12
+ ? createClient({ timeout: 20_000, retry: { maxRetries: 0 } })
13
+ : createFixtureClient(fixture.responses);
14
+ const result = await answerSupportRequest(fixture.input, async () => fixture.draft, { client });
15
+ process.stdout.write(`${JSON.stringify({
16
+ mode: live ? 'live' : 'demo',
17
+ note: live
18
+ ? 'Live Jev decisions with a saved draft answer. No generative model was called.'
19
+ : 'Hand-authored decision fixtures and a saved draft. No model was called; this does not measure accuracy.',
20
+ result,
21
+ }, null, 2)}\n`);
22
+ }
23
+ function createFixtureClient(responses) {
24
+ return {
25
+ systemOne: async (request) => {
26
+ const key = Object.keys(request.questions).join(',');
27
+ const response = responses[key];
28
+ if (response === undefined)
29
+ throw new Error(`No offline response for questions: ${key}`);
30
+ return response;
31
+ },
32
+ };
33
+ }
34
+ main().catch((error) => {
35
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
36
+ process.exitCode = 1;
37
+ });