@outputai/cli 0.11.1-next.90d8cc0.0 → 0.11.1-next.a07f3e4.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.
@@ -80,7 +80,7 @@ services:
80
80
  condition: service_healthy
81
81
  worker:
82
82
  condition: service_healthy
83
- image: outputai/api:${OUTPUT_API_VERSION:-0.11.1-next.90d8cc0.0}
83
+ image: outputai/api:${OUTPUT_API_VERSION:-0.11.1-next.a07f3e4.0}
84
84
  init: true
85
85
  networks:
86
86
  - main
@@ -1,3 +1,3 @@
1
1
  {
2
- "framework": "0.11.1-next.90d8cc0.0"
2
+ "framework": "0.11.1-next.a07f3e4.0"
3
3
  }
@@ -15,6 +15,8 @@ function lineRate(type, pricing) {
15
15
  const rates = {
16
16
  input: pricing.input ?? 0,
17
17
  input_cached: pricing.cached_input ?? 0,
18
+ input_cache_read: pricing.cached_input ?? pricing.input ?? 0,
19
+ input_cache_write: pricing.input ?? 0,
18
20
  output: pricing.output ?? 0,
19
21
  reasoning: pricing.reasoning ?? pricing.output ?? 0
20
22
  };
@@ -42,6 +44,81 @@ function eventTokenUsage(lines) {
42
44
  reasoningTokens: sumOf('reasoning')
43
45
  };
44
46
  }
47
+ function normalizedItemType(item) {
48
+ if (item.group === 'input') {
49
+ if (item.label === null || item.label === 'no_cache') {
50
+ return 'input';
51
+ }
52
+ if (item.label === 'cache_read') {
53
+ return 'input_cache_read';
54
+ }
55
+ if (item.label === 'cache_write') {
56
+ return 'input_cache_write';
57
+ }
58
+ }
59
+ if (item.group === 'output') {
60
+ if (item.label === null || item.label === 'text') {
61
+ return 'output';
62
+ }
63
+ if (item.label === 'reasoning') {
64
+ return 'reasoning';
65
+ }
66
+ }
67
+ return item.label ? `${item.group}_${item.label}` : item.group;
68
+ }
69
+ function normalizedItemTokenUsage(items) {
70
+ const sumOf = (group, labels) => items
71
+ .filter(item => item.group === group && (!labels || labels.includes(item.label)))
72
+ .reduce((sum, item) => sum + item.amount, 0);
73
+ return {
74
+ inputTokens: sumOf('input'),
75
+ cachedInputTokens: sumOf('input', ['cache_read']),
76
+ outputTokens: sumOf('output', [null, 'output', 'text']),
77
+ reasoningTokens: sumOf('output', ['reasoning'])
78
+ };
79
+ }
80
+ function parseLegacyLLMUsageEvent(node, stepName, event) {
81
+ return {
82
+ stepName: stepName || node.name || 'unknown',
83
+ llmName: node.name || 'llm',
84
+ model: event.modelId || 'unknown',
85
+ usage: eventTokenUsage(event.usage ?? []),
86
+ originalCost: event.total,
87
+ lines: event.usage ?? []
88
+ };
89
+ }
90
+ function parseNormalizedLLMUsage(node, stepName, event) {
91
+ const lines = event.items.map(item => ({
92
+ type: normalizedItemType(item),
93
+ ppm: 0,
94
+ amount: item.amount,
95
+ total: 0
96
+ }));
97
+ return {
98
+ stepName: stepName || node.name || 'unknown',
99
+ llmName: node.name || 'llm',
100
+ model: event.modelId || 'unknown',
101
+ usage: normalizedItemTokenUsage(event.items),
102
+ originalCost: 0,
103
+ lines
104
+ };
105
+ }
106
+ function parseLLMCostEvent(node, stepName, event) {
107
+ const lines = event.items.map(item => ({
108
+ type: normalizedItemType(item),
109
+ ppm: item.ppm ?? 0,
110
+ amount: item.amount,
111
+ total: item.total ?? 0
112
+ }));
113
+ return {
114
+ stepName: stepName || node.name || 'unknown',
115
+ llmName: node.name || 'llm',
116
+ model: event.modelId || 'unknown',
117
+ usage: normalizedItemTokenUsage(event.items),
118
+ originalCost: event.total ?? 0,
119
+ lines
120
+ };
121
+ }
45
122
  export function extractValue(obj, path) {
46
123
  if (!path || !obj) {
47
124
  return obj;
@@ -106,20 +183,20 @@ function findCalls(node, match, extract, parentStepName = null, seenIds = new Se
106
183
  }
107
184
  return calls;
108
185
  }
109
- // Only nodes carrying an llm:usage event are priced the event holds the
110
- // as-charged cost and the per-token-type amounts. Traces from SDKs that
111
- // predate cost attributes report no LLM costs.
186
+ // Prefer generation cost, then normalized generation usage, then legacy usage.
112
187
  export function findLLMCalls(node, parentStepName = null, seenIds = new Set()) {
113
- return findCalls(node, n => n.kind === 'llm' && !!n.attributes?.['llm:usage'], (n, stepName) => {
114
- const event = n.attributes['llm:usage'];
115
- return {
116
- stepName: stepName || n.name || 'unknown',
117
- llmName: n.name || 'llm',
118
- model: event.modelId || 'unknown',
119
- usage: eventTokenUsage(event.usage ?? []),
120
- originalCost: event.total,
121
- lines: event.usage ?? []
122
- };
188
+ return findCalls(node, n => n.kind === 'llm' && !!(n.attributes?.['llm:generation:cost'] ||
189
+ n.attributes?.['llm:generation:usage'] ||
190
+ n.attributes?.['llm:usage']), (n, stepName) => {
191
+ const cost = n.attributes?.['llm:generation:cost'];
192
+ if (cost) {
193
+ return parseLLMCostEvent(n, stepName, cost);
194
+ }
195
+ const usage = n.attributes?.['llm:generation:usage'];
196
+ if (usage) {
197
+ return parseNormalizedLLMUsage(n, stepName, usage);
198
+ }
199
+ return parseLegacyLLMUsageEvent(n, stepName, n.attributes['llm:usage']);
123
200
  }, parentStepName, seenIds);
124
201
  }
125
202
  export function findHTTPCalls(node, parentStepName = null, seenIds = new Set()) {
@@ -360,7 +437,9 @@ function findModelPricing(model, models) {
360
437
  if (models[model]) {
361
438
  return models[model];
362
439
  }
363
- return Object.entries(models).find(([key]) => model.startsWith(key))?.[1];
440
+ return Object.entries(models)
441
+ .filter(([key]) => model.startsWith(key))
442
+ .sort(([left], [right]) => right.length - left.length)[0]?.[1];
364
443
  }
365
444
  function aggregateLLMCosts(llmCalls, config) {
366
445
  const results = [];
@@ -37,6 +37,50 @@ function llmEventNode(id, model, lines) {
37
37
  }
38
38
  };
39
39
  }
40
+ function llmCostNode(id, model, items) {
41
+ const totalOf = (group) => items.filter(item => item.group === group).reduce((sum, item) => sum + (item.total ?? 0), 0);
42
+ const input = totalOf('input');
43
+ const output = totalOf('output');
44
+ return {
45
+ id,
46
+ kind: 'llm',
47
+ name: 'gen',
48
+ attributes: {
49
+ 'llm:generation:cost': {
50
+ type: 'llm:generation:cost',
51
+ providerId: 'test-provider',
52
+ modelId: model,
53
+ input,
54
+ output,
55
+ total: input + output,
56
+ status: 'precise',
57
+ items
58
+ }
59
+ }
60
+ };
61
+ }
62
+ function llmUsageNode(id, model, items) {
63
+ const totalOf = (group) => items.filter(item => item.group === group).reduce((sum, item) => sum + item.amount, 0);
64
+ const input = totalOf('input');
65
+ const output = totalOf('output');
66
+ return {
67
+ id,
68
+ kind: 'llm',
69
+ name: 'gen',
70
+ attributes: {
71
+ 'llm:generation:usage': {
72
+ type: 'llm:generation:usage',
73
+ providerId: 'test-provider',
74
+ modelId: model,
75
+ input,
76
+ output,
77
+ total: input + output,
78
+ status: 'complete',
79
+ items
80
+ }
81
+ }
82
+ };
83
+ }
40
84
  function httpEventNode(id, url, method, total, output = { status: 200, body: {} }, inputBody) {
41
85
  return {
42
86
  id,
@@ -182,7 +226,109 @@ describe('findLLMCalls', () => {
182
226
  expect(calls[0].usage.outputTokens).toBe(7275);
183
227
  expect(calls[0].originalCost).toBeCloseTo(0.35525, 5);
184
228
  });
185
- it('ignores llm nodes without a llm:usage event', () => {
229
+ it('does not interpret transitional component names in legacy llm:usage events', () => {
230
+ const node = llmEventNode('transitional-components', 'legacy-model', [
231
+ { type: 'input', ppm: 1, amount: 10, total: 0.00001 },
232
+ { type: 'input_cached', ppm: 0.1, amount: 20, total: 0.000002 },
233
+ { type: 'output', ppm: 5, amount: 30, total: 0.00015 },
234
+ { type: 'reasoning', ppm: 5, amount: 40, total: 0.0002 },
235
+ { type: 'input_cache_read', ppm: 0.1, amount: 100, total: 0.00001 },
236
+ { type: 'input_cache_write', ppm: 1.25, amount: 200, total: 0.00025 },
237
+ { type: 'output_text', ppm: 5, amount: 300, total: 0.0015 },
238
+ { type: 'output_reasoning', ppm: 5, amount: 400, total: 0.002 }
239
+ ]);
240
+ const calls = findLLMCalls({ kind: 'workflow', children: [node] });
241
+ expect(calls[0].usage).toEqual({
242
+ inputTokens: 30,
243
+ cachedInputTokens: 20,
244
+ outputTokens: 30,
245
+ reasoningTokens: 40
246
+ });
247
+ });
248
+ it('reads every supported item from an llm:generation:cost attribute', () => {
249
+ const items = [
250
+ { group: 'input', label: null, amount: 100, ppm: 1, total: 0.0001, status: 'ok' },
251
+ { group: 'input', label: 'no_cache', amount: 200, ppm: 1, total: 0.0002, status: 'ok' },
252
+ { group: 'input', label: 'cache_write', amount: 300, ppm: 1.25, total: 0.000375, status: 'ok' },
253
+ { group: 'input', label: 'cache_read', amount: 400, ppm: 0.1, total: 0.00004, status: 'ok' },
254
+ { group: 'output', label: null, amount: 50, ppm: 5, total: 0.00025, status: 'ok' },
255
+ { group: 'output', label: 'text', amount: 60, ppm: 5, total: 0.0003, status: 'ok' },
256
+ { group: 'output', label: 'reasoning', amount: 70, ppm: 10, total: 0.0007, status: 'ok' }
257
+ ];
258
+ const calls = findLLMCalls({
259
+ kind: 'workflow',
260
+ children: [llmCostNode('llm-cost', 'new-model', items)]
261
+ });
262
+ expect(calls).toHaveLength(1);
263
+ expect(calls[0]).toMatchObject({
264
+ model: 'new-model',
265
+ usage: {
266
+ inputTokens: 1000,
267
+ cachedInputTokens: 400,
268
+ outputTokens: 110,
269
+ reasoningTokens: 70
270
+ }
271
+ });
272
+ expect(calls[0].lines.map(line => line.type)).toEqual([
273
+ 'input',
274
+ 'input',
275
+ 'input_cache_write',
276
+ 'input_cache_read',
277
+ 'output',
278
+ 'output',
279
+ 'reasoning'
280
+ ]);
281
+ expect(calls[0].originalCost).toBeCloseTo(0.001965, 8);
282
+ });
283
+ it('reads normalized usage without interpreting token totals as cost', () => {
284
+ const items = [
285
+ { group: 'input', label: null, amount: 100 },
286
+ { group: 'input', label: 'no_cache', amount: 200 },
287
+ { group: 'input', label: 'cache_write', amount: 300 },
288
+ { group: 'input', label: 'cache_read', amount: 400 },
289
+ { group: 'output', label: null, amount: 50 },
290
+ { group: 'output', label: 'text', amount: 60 },
291
+ { group: 'output', label: 'reasoning', amount: 70 }
292
+ ];
293
+ const calls = findLLMCalls({
294
+ kind: 'workflow',
295
+ children: [llmUsageNode('llm-usage', 'new-model', items)]
296
+ });
297
+ expect(calls).toHaveLength(1);
298
+ expect(calls[0]).toMatchObject({
299
+ model: 'new-model',
300
+ usage: {
301
+ inputTokens: 1000,
302
+ cachedInputTokens: 400,
303
+ outputTokens: 110,
304
+ reasoningTokens: 70
305
+ },
306
+ originalCost: 0
307
+ });
308
+ expect(calls[0].lines).toEqual([
309
+ { type: 'input', ppm: 0, amount: 100, total: 0 },
310
+ { type: 'input', ppm: 0, amount: 200, total: 0 },
311
+ { type: 'input_cache_write', ppm: 0, amount: 300, total: 0 },
312
+ { type: 'input_cache_read', ppm: 0, amount: 400, total: 0 },
313
+ { type: 'output', ppm: 0, amount: 50, total: 0 },
314
+ { type: 'output', ppm: 0, amount: 60, total: 0 },
315
+ { type: 'reasoning', ppm: 0, amount: 70, total: 0 }
316
+ ]);
317
+ });
318
+ it('prefers generation cost when both generation attributes are present', () => {
319
+ const node = llmCostNode('both', 'new-model', [
320
+ { group: 'input', label: null, amount: 100, ppm: 1, total: 0.0001, status: 'ok' }
321
+ ]);
322
+ node.attributes['llm:generation:usage'] = llmUsageNode('usage', 'usage-model', [
323
+ { group: 'input', label: null, amount: 10 }
324
+ ])
325
+ .attributes['llm:generation:usage'];
326
+ const calls = findLLMCalls({ kind: 'workflow', children: [node] });
327
+ expect(calls).toHaveLength(1);
328
+ expect(calls[0].model).toBe('new-model');
329
+ expect(calls[0].originalCost).toBe(0.0001);
330
+ });
331
+ it('ignores llm nodes without a cost event', () => {
186
332
  const trace = {
187
333
  kind: 'workflow',
188
334
  name: 'test',
@@ -314,20 +460,67 @@ describe('calculateCost', () => {
314
460
  const report = calculateCost(duplicateTrace, testConfig, 'test.json');
315
461
  expect(report.llmCalls).toHaveLength(1);
316
462
  });
317
- it('matches versioned model names by prefix', () => {
463
+ it('uses the longest matching prefix for versioned model names', () => {
318
464
  const trace = {
319
465
  kind: 'workflow',
320
466
  name: 'test',
321
467
  children: [
322
- llmEventNode('llm-1', 'claude-sonnet-4-5-20250514', llmLines(1000, 3, 500, 15))
468
+ llmEventNode('llm-1', 'gpt-4.1-mini-20250514', llmLines(1_000_000, 9, 1_000_000, 9))
323
469
  ]
324
470
  };
325
- const report = calculateCost(trace, testConfig, 'test.json');
326
- // priced at the claude-sonnet-4-5 prefix rates: 1000@$3/M + 500@$15/M
327
- expect(report.llmCalls[0].adjustedCost).toBeCloseTo(0.0105, 5);
471
+ const config = {
472
+ ...testConfig,
473
+ models: {
474
+ 'gpt-4.1': { provider: 'openai', input: 2, output: 8 },
475
+ 'gpt-4.1-mini': { provider: 'openai', input: 0.4, output: 1.6 }
476
+ }
477
+ };
478
+ const report = calculateCost(trace, config, 'test.json');
479
+ expect(report.llmCalls[0].adjustedCost).toBeCloseTo(2, 8);
328
480
  });
329
481
  });
330
482
  describe('event-driven LLM costs (original vs adjusted)', () => {
483
+ it('re-prices normalized usage when generation cost is absent', () => {
484
+ const trace = {
485
+ kind: 'workflow',
486
+ name: 'test',
487
+ children: [llmUsageNode('usage-only', 'claude-sonnet-4-5', [
488
+ { group: 'input', label: 'no_cache', amount: 1_000_000 },
489
+ { group: 'input', label: 'cache_read', amount: 1_000_000 },
490
+ { group: 'input', label: 'cache_write', amount: 1_000_000 },
491
+ { group: 'output', label: 'text', amount: 1_000_000 },
492
+ { group: 'output', label: 'reasoning', amount: 1_000_000 }
493
+ ])]
494
+ };
495
+ const report = calculateCost(trace, testConfig, 'test.json');
496
+ expect(report.llmCalls[0]).toMatchObject({
497
+ input: 3_000_000,
498
+ cached: 1_000_000,
499
+ output: 1_000_000,
500
+ reasoning: 1_000_000,
501
+ originalCost: 0,
502
+ adjustedCost: 36.3
503
+ });
504
+ expect(report.llmOriginalCost).toBe(0);
505
+ expect(report.llmAdjustedCost).toBeCloseTo(36.3, 8);
506
+ });
507
+ it('falls back to input pricing for normalized cache reads', () => {
508
+ const trace = {
509
+ kind: 'workflow',
510
+ name: 'test',
511
+ children: [llmUsageNode('cache-read', 'cache-model', [
512
+ { group: 'input', label: 'cache_read', amount: 1_000_000 }
513
+ ])]
514
+ };
515
+ const config = {
516
+ ...testConfig,
517
+ models: {
518
+ 'cache-model': { provider: 'test', input: 2, output: 10 }
519
+ }
520
+ };
521
+ const report = calculateCost(trace, config, 'test.json');
522
+ expect(report.llmCalls[0].adjustedCost).toBeCloseTo(2, 8);
523
+ });
331
524
  it('matches original when costs.yml rate equals the event rate', () => {
332
525
  // haiku event priced at the same rate as testConfig (input 1 / output 5)
333
526
  const trace = {
@@ -362,19 +555,18 @@ describe('event-driven LLM costs (original vs adjusted)', () => {
362
555
  expect(report.llmCalls[0].originalCost).toBeCloseTo(0.35525, 5);
363
556
  expect(report.llmCalls[0].adjustedCost).toBeCloseTo(0.35525, 5);
364
557
  });
365
- it('prices an unknown line type at its as-charged total, not $0', () => {
366
- const lines = [
367
- ...llmLines(1_000_000, 1, 1_000_000, 5),
368
- { type: 'input_cache_write', ppm: 1.25, amount: 200_000, total: 0.25 }
369
- ];
558
+ it('re-prices normalized cache writes at the configured input rate', () => {
370
559
  const trace = {
371
560
  kind: 'workflow',
372
561
  name: 'test',
373
- children: [llmEventNode('cw', 'claude-haiku-4-5', lines)]
562
+ children: [llmCostNode('cw', 'claude-haiku-4-5', [
563
+ { group: 'input', label: 'no_cache', amount: 1_000_000, ppm: 1, total: 1, status: 'ok' },
564
+ { group: 'input', label: 'cache_write', amount: 200_000, ppm: 1.25, total: 0.25, status: 'ok' },
565
+ { group: 'output', label: 'text', amount: 1_000_000, ppm: 5, total: 5, status: 'ok' }
566
+ ])]
374
567
  };
375
568
  const report = calculateCost(trace, testConfig, 'test.json');
376
- // known lines reprice to $6 at config rates; unknown line passes through at $0.25
377
- expect(report.llmCalls[0].adjustedCost).toBeCloseTo(6.25, 5);
569
+ expect(report.llmCalls[0].adjustedCost).toBeCloseTo(6.2, 5);
378
570
  expect(report.llmCalls[0].originalCost).toBeCloseTo(6.25, 5);
379
571
  });
380
572
  it('reports inputTokens including cached tokens for event traces', () => {
@@ -1,6 +1,6 @@
1
1
  import { evaluator, EvaluationNumberResult } from '@outputai/core';
2
2
  import type { EvaluationResultArgs } from '@outputai/core';
3
- import { generateText, Output } from '@outputai/llm';
3
+ import { generateText, aiSdk } from '@outputai/llm';
4
4
  import { blogContentSchema } from './types.js';
5
5
  import type { BlogContent } from './types.js';
6
6
 
@@ -15,7 +15,7 @@ export const evaluateSignalToNoise = evaluator( {
15
15
  title: input.title,
16
16
  content: input.content
17
17
  },
18
- output: Output.object( { schema: EvaluationNumberResult.schema } )
18
+ output: aiSdk.Output.object( { schema: EvaluationNumberResult.schema } )
19
19
  } );
20
20
 
21
21
  return new EvaluationNumberResult( output as EvaluationResultArgs<number> );
@@ -3,7 +3,7 @@ provider: anthropic
3
3
  # current as of 2026-05-04 — run output-dev-model-selection for the latest
4
4
  model: claude-sonnet-4-6
5
5
  temperature: 0.3
6
- maxTokens: 4096
6
+ maxOutputTokens: 4096
7
7
  ---
8
8
 
9
9
  <system>
@@ -123,7 +123,7 @@ Define steps in `steps.ts` with schemas:
123
123
 
124
124
  ```typescript
125
125
  import { step, z } from '@outputai/core';
126
- import { generateText, Output } from '@outputai/llm';
126
+ import { generateText, aiSdk } from '@outputai/llm';
127
127
 
128
128
  export const myStep = step( {
129
129
  name: 'my_step',
@@ -138,7 +138,7 @@ export const myStep = step( {
138
138
  const { output } = await generateText( {
139
139
  prompt: 'my_prompt@v1',
140
140
  variables: { text },
141
- output: Output.object( {
141
+ output: aiSdk.Output.object( {
142
142
  schema: z.object( { result: z.string() } )
143
143
  } )
144
144
  } );
@@ -153,7 +153,7 @@ Define evaluators in `evaluators.ts`:
153
153
 
154
154
  ```typescript
155
155
  import { evaluator, z, EvaluationVerdictResult } from '@outputai/core';
156
- import { generateText, Output } from '@outputai/llm';
156
+ import { generateText, aiSdk } from '@outputai/llm';
157
157
 
158
158
  export const evaluateQuality = evaluator( {
159
159
  name: 'evaluate_quality',
@@ -166,7 +166,7 @@ export const evaluateQuality = evaluator( {
166
166
  const { output: evaluation } = await generateText( {
167
167
  prompt: 'evaluate@v1',
168
168
  variables: { input, output },
169
- output: Output.object( { schema: EvaluationVerdictResult.schema } )
169
+ output: aiSdk.Output.object( { schema: EvaluationVerdictResult.schema } )
170
170
  } );
171
171
 
172
172
  return new EvaluationVerdictResult( evaluation );
@@ -178,8 +178,13 @@ export const evaluateQuality = evaluator( {
178
178
 
179
179
  Create prompt files in `prompts/` following the pattern:
180
180
  - File naming: `promptName@v1.prompt`
181
- - Include YAML frontmatter with provider, model, temperature, and maxTokens
181
+ - Include YAML frontmatter with provider, model, temperature, and maxOutputTokens
182
182
  - Use LiquidJS syntax for variables: `{{ variableName }}`
183
+ - Start the rendered body with a role tag for message mode, or with plain text for instruction mode
184
+
185
+ In message mode, use only `<system>`, `<user>`, and `<assistant>` at the top level. Keep all prose inside those blocks, close every block, and escape literal same-role examples such as `&lt;user&gt;...&lt;/user&gt;`.
186
+
187
+ Structured tool messages are runtime history supplied through Agent `messages` or `messageStore`; they are not authored in prompt files.
183
188
 
184
189
  Example prompt file:
185
190
  ```
@@ -188,7 +193,7 @@ provider: anthropic
188
193
  # current as of 2026-05-04 — run output-dev-model-selection for the latest
189
194
  model: claude-sonnet-4-6
190
195
  temperature: 0.3
191
- maxTokens: 1024
196
+ maxOutputTokens: 1024
192
197
  ---
193
198
 
194
199
  <system>
@@ -1,5 +1,5 @@
1
1
  import { evaluator, z, EvaluationVerdictResult } from '@outputai/core';
2
- import { generateText, Output } from '@outputai/llm';
2
+ import { generateText, aiSdk } from '@outputai/llm';
3
3
 
4
4
  // TODO: Update the evaluator to assess your workflow's output quality
5
5
  export const evaluate{{WorkflowName}} = evaluator( {
@@ -13,7 +13,7 @@ export const evaluate{{WorkflowName}} = evaluator( {
13
13
  const { output: evaluation } = await generateText( {
14
14
  prompt: 'example@v1',
15
15
  variables: { text: `Input: ${input}\nOutput: ${output}\n\nDoes the output adequately address the input?` },
16
- output: Output.object( { schema: EvaluationVerdictResult.schema } )
16
+ output: aiSdk.Output.object( { schema: EvaluationVerdictResult.schema } )
17
17
  } );
18
18
 
19
19
  return new EvaluationVerdictResult( evaluation );
@@ -3,7 +3,7 @@ provider: anthropic
3
3
  # current as of 2026-05-04 — run output-dev-model-selection for the latest
4
4
  model: claude-sonnet-4-6
5
5
  temperature: 0.3
6
- maxTokens: 4096
6
+ maxOutputTokens: 4096
7
7
  ---
8
8
 
9
9
  <system>
@@ -13,8 +13,7 @@ export interface TokenUsage {
13
13
  cachedInputTokens?: number;
14
14
  reasoningTokens?: number;
15
15
  }
16
- export type { LLMUsageEvent } from '@outputai/llm';
17
- import type { LLMUsageEvent } from '@outputai/llm';
16
+ import type { LLMGenerationCost, LLMGenerationUsage, LLMUsageEvent } from '@outputai/llm';
18
17
  export type LLMUsageLine = LLMUsageEvent['usage'][number];
19
18
  export interface HTTPCostEvent {
20
19
  type: 'http:request:cost';
@@ -29,6 +28,8 @@ export interface HTTPCountEvent {
29
28
  }
30
29
  export interface NodeAttributes {
31
30
  'llm:usage'?: LLMUsageEvent;
31
+ 'llm:generation:usage'?: LLMGenerationUsage;
32
+ 'llm:generation:cost'?: LLMGenerationCost;
32
33
  'http:request:cost'?: HTTPCostEvent;
33
34
  'http:request:count'?: HTTPCountEvent;
34
35
  }
@@ -1752,5 +1752,5 @@
1752
1752
  ]
1753
1753
  }
1754
1754
  },
1755
- "version": "0.11.1-next.90d8cc0.0"
1755
+ "version": "0.11.1-next.a07f3e4.0"
1756
1756
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outputai/cli",
3
- "version": "0.11.1-next.90d8cc0.0",
3
+ "version": "0.11.1-next.a07f3e4.0",
4
4
  "description": "CLI for Output.ai workflow generation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -36,9 +36,9 @@
36
36
  "react": "19.2.5",
37
37
  "semver": "7.7.4",
38
38
  "undici": "8.9.0",
39
- "@outputai/credentials": "0.11.1-next.90d8cc0.0",
40
- "@outputai/evals": "0.11.1-next.90d8cc0.0",
41
- "@outputai/llm": "0.11.1-next.90d8cc0.0"
39
+ "@outputai/evals": "0.11.1-next.a07f3e4.0",
40
+ "@outputai/credentials": "0.11.1-next.a07f3e4.0",
41
+ "@outputai/llm": "0.11.1-next.a07f3e4.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/cli-progress": "3.11.6",