@outputai/cli 0.11.1-next.b3beef1.0 → 0.11.1-next.da26845.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/docker/docker-compose-dev.yml +1 -1
- package/dist/generated/framework_version.json +1 -1
- package/dist/services/cost_calculator.js +93 -14
- package/dist/services/cost_calculator.spec.js +206 -14
- package/dist/templates/project/src/workflows/blog_evaluator/prompts/signal_noise@v1.prompt.template +1 -1
- package/dist/templates/workflow/README.md.template +2 -2
- package/dist/templates/workflow/prompts/example@v1.prompt.template +1 -1
- package/dist/types/cost.d.ts +3 -2
- package/oclif.manifest.json +1 -1
- package/package.json +4 -4
|
@@ -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
|
-
//
|
|
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:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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)
|
|
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('
|
|
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('
|
|
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', '
|
|
468
|
+
llmEventNode('llm-1', 'gpt-4.1-mini-20250514', llmLines(1_000_000, 9, 1_000_000, 9))
|
|
323
469
|
]
|
|
324
470
|
};
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
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
|
|
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: [
|
|
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
|
-
|
|
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', () => {
|
|
@@ -178,7 +178,7 @@ 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
|
|
181
|
+
- Include YAML frontmatter with provider, model, temperature, and maxOutputTokens
|
|
182
182
|
- Use LiquidJS syntax for variables: `{{ variableName }}`
|
|
183
183
|
- Start the rendered body with a role tag for message mode, or with plain text for instruction mode
|
|
184
184
|
|
|
@@ -193,7 +193,7 @@ provider: anthropic
|
|
|
193
193
|
# current as of 2026-05-04 — run output-dev-model-selection for the latest
|
|
194
194
|
model: claude-sonnet-4-6
|
|
195
195
|
temperature: 0.3
|
|
196
|
-
|
|
196
|
+
maxOutputTokens: 1024
|
|
197
197
|
---
|
|
198
198
|
|
|
199
199
|
<system>
|
package/dist/types/cost.d.ts
CHANGED
|
@@ -13,8 +13,7 @@ export interface TokenUsage {
|
|
|
13
13
|
cachedInputTokens?: number;
|
|
14
14
|
reasoningTokens?: number;
|
|
15
15
|
}
|
|
16
|
-
import type {
|
|
17
|
-
export type LLMUsageEvent = Omit<LiveLLMUsageEvent, 'addUsage'>;
|
|
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
|
}
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@outputai/cli",
|
|
3
|
-
"version": "0.11.1-next.
|
|
3
|
+
"version": "0.11.1-next.da26845.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.
|
|
40
|
-
"@outputai/evals": "0.11.1-next.
|
|
41
|
-
"@outputai/llm": "0.11.1-next.
|
|
39
|
+
"@outputai/credentials": "0.11.1-next.da26845.0",
|
|
40
|
+
"@outputai/evals": "0.11.1-next.da26845.0",
|
|
41
|
+
"@outputai/llm": "0.11.1-next.da26845.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/cli-progress": "3.11.6",
|