@robota-sdk/agent-command 3.0.0-beta.75 → 3.0.0-beta.76
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/node/index.cjs +25 -25
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +34 -34
- package/dist/node/index.js.map +1 -1
- package/package.json +5 -5
- package/src/context/context-command.ts +4 -4
- package/src/preset/__tests__/preset-command-module.test.ts +7 -7
- package/src/preset/preset-command.ts +5 -2
- package/src/session/model-pricing.ts +7 -60
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robota-sdk/agent-command",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.76",
|
|
4
4
|
"description": "Consolidated command module implementations for Robota SDK CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/node/index.js",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"src"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@robota-sdk/agent-core": "3.0.0-beta.
|
|
28
|
-
"@robota-sdk/agent-framework": "3.0.0-beta.
|
|
29
|
-
"@robota-sdk/agent-interface-transport": "3.0.0-beta.
|
|
30
|
-
"@robota-sdk/agent-preset": "3.0.0-beta.
|
|
27
|
+
"@robota-sdk/agent-core": "3.0.0-beta.76",
|
|
28
|
+
"@robota-sdk/agent-framework": "3.0.0-beta.76",
|
|
29
|
+
"@robota-sdk/agent-interface-transport": "3.0.0-beta.76",
|
|
30
|
+
"@robota-sdk/agent-preset": "3.0.0-beta.76"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.19.21",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CONTEXT_ESTIMATE_CHARS_PER_TOKEN } from '@robota-sdk/agent-core';
|
|
1
2
|
import {
|
|
2
3
|
addCommandContextReference,
|
|
3
4
|
clearCommandContextReferences,
|
|
@@ -282,12 +283,11 @@ function formatContextReferenceSummary(references: readonly IContextReferenceIte
|
|
|
282
283
|
return `References: ${active} active, ${observed} observed`;
|
|
283
284
|
}
|
|
284
285
|
|
|
285
|
-
// 1 token ≈ 4 chars —
|
|
286
|
-
const CHARS_PER_TOKEN = 4;
|
|
286
|
+
// 1 token ≈ 4 chars — sourced from the agent-core estimation SSOT.
|
|
287
287
|
const TOOL_ARG_MAX_LEN = 60;
|
|
288
288
|
|
|
289
289
|
function estimateTokens(charLength: number): number {
|
|
290
|
-
return Math.ceil(charLength /
|
|
290
|
+
return Math.ceil(charLength / CONTEXT_ESTIMATE_CHARS_PER_TOKEN);
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
function formatContextReferenceLine(reference: IContextReferenceItem): string {
|
|
@@ -349,7 +349,7 @@ function computeMessageTokensByRole(rawMessages: TUniversalMessage[]): IMessageT
|
|
|
349
349
|
let toolCallCount = 0;
|
|
350
350
|
|
|
351
351
|
for (const msg of rawMessages) {
|
|
352
|
-
const t = Math.ceil(JSON.stringify(msg).length /
|
|
352
|
+
const t = Math.ceil(JSON.stringify(msg).length / CONTEXT_ESTIMATE_CHARS_PER_TOKEN);
|
|
353
353
|
if (msg.role === 'system') {
|
|
354
354
|
systemTokens += t;
|
|
355
355
|
} else if (msg.role === 'user') {
|
|
@@ -78,16 +78,16 @@ function createCommandHostContext(
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
describe('preset command module', () => {
|
|
81
|
-
it('exposes a single preset system command (structure)', () => {
|
|
81
|
+
it('exposes a single preset system command (structure)', async () => {
|
|
82
82
|
const module = createPresetCommandModule();
|
|
83
83
|
expect(module.systemCommands?.map((command) => command.name)).toContain('preset');
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
it('TC-01: lists every preset and marks the active one', () => {
|
|
86
|
+
it('TC-01: lists every preset and marks the active one', async () => {
|
|
87
87
|
const runtime = createSessionRuntime({ getActivePresetId: () => 'autonomous-builder' });
|
|
88
88
|
const context = createCommandHostContext(runtime);
|
|
89
89
|
|
|
90
|
-
const result = executePresetCommand(context, '');
|
|
90
|
+
const result = await executePresetCommand(context, '');
|
|
91
91
|
|
|
92
92
|
expect(result.success).toBe(true);
|
|
93
93
|
for (const preset of listPresets()) {
|
|
@@ -99,7 +99,7 @@ describe('preset command module', () => {
|
|
|
99
99
|
expect(result.data?.active).toBe('autonomous-builder');
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
-
it('TC-02: switches to a valid preset and drives the live re-apply seams', () => {
|
|
102
|
+
it('TC-02: switches to a valid preset and drives the live re-apply seams', async () => {
|
|
103
103
|
const setActivePresetId = vi.fn();
|
|
104
104
|
const setPermissionMode = vi.fn();
|
|
105
105
|
const applyModelOptions = vi.fn();
|
|
@@ -110,7 +110,7 @@ describe('preset command module', () => {
|
|
|
110
110
|
});
|
|
111
111
|
const context = createCommandHostContext(runtime);
|
|
112
112
|
|
|
113
|
-
const result = executePresetCommand(context, 'careful-reviewer');
|
|
113
|
+
const result = await executePresetCommand(context, 'careful-reviewer');
|
|
114
114
|
|
|
115
115
|
expect(result.success).toBe(true);
|
|
116
116
|
expect(result.message).toBe('Switched to preset: careful-reviewer');
|
|
@@ -122,12 +122,12 @@ describe('preset command module', () => {
|
|
|
122
122
|
expect(applyModelOptions).toHaveBeenCalledWith(expect.objectContaining({ effort: 'high' }));
|
|
123
123
|
});
|
|
124
124
|
|
|
125
|
-
it('TC-04: rejects an unknown preset id without switching', () => {
|
|
125
|
+
it('TC-04: rejects an unknown preset id without switching', async () => {
|
|
126
126
|
const setActivePresetId = vi.fn();
|
|
127
127
|
const runtime = createSessionRuntime({ setActivePresetId });
|
|
128
128
|
const context = createCommandHostContext(runtime);
|
|
129
129
|
|
|
130
|
-
const result = executePresetCommand(context, '__nope__');
|
|
130
|
+
const result = await executePresetCommand(context, '__nope__');
|
|
131
131
|
|
|
132
132
|
expect(result.success).toBe(false);
|
|
133
133
|
for (const preset of listPresets()) {
|
|
@@ -29,7 +29,10 @@ function formatUnknownPresetMessage(id: string): string {
|
|
|
29
29
|
return `Unknown preset: ${id}. Available: ${ids}`;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function executePresetCommand(
|
|
32
|
+
export async function executePresetCommand(
|
|
33
|
+
context: ICommandHostContext,
|
|
34
|
+
args: string,
|
|
35
|
+
): Promise<ICommandResult> {
|
|
33
36
|
const id = args.trim().split(/\s+/)[0];
|
|
34
37
|
|
|
35
38
|
if (id === undefined || id.length === 0 || id === 'list') {
|
|
@@ -49,7 +52,7 @@ export function executePresetCommand(context: ICommandHostContext, args: string)
|
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
const resolved = resolvePreset(id);
|
|
52
|
-
applyPresetToSession(context, id, resolved);
|
|
55
|
+
await applyPresetToSession(context, id, resolved);
|
|
53
56
|
return {
|
|
54
57
|
message: `Switched to preset: ${id}`,
|
|
55
58
|
success: true,
|
|
@@ -1,69 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
interface IModelPrice {
|
|
3
|
-
inputPerMillion: number;
|
|
4
|
-
outputPerMillion: number;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
const MODEL_PRICES: Record<string, IModelPrice> = {
|
|
8
|
-
// Anthropic Claude 4
|
|
9
|
-
'claude-opus-4-7': { inputPerMillion: 15, outputPerMillion: 75 },
|
|
10
|
-
'claude-opus-4-5': { inputPerMillion: 15, outputPerMillion: 75 },
|
|
11
|
-
'claude-sonnet-4-6': { inputPerMillion: 3, outputPerMillion: 15 },
|
|
12
|
-
'claude-sonnet-4-5': { inputPerMillion: 3, outputPerMillion: 15 },
|
|
13
|
-
'claude-haiku-4-5': { inputPerMillion: 0.8, outputPerMillion: 4 },
|
|
14
|
-
// Anthropic Claude 3
|
|
15
|
-
'claude-3-5-sonnet-20241022': { inputPerMillion: 3, outputPerMillion: 15 },
|
|
16
|
-
'claude-3-5-haiku-20241022': { inputPerMillion: 0.8, outputPerMillion: 4 },
|
|
17
|
-
'claude-3-opus-20240229': { inputPerMillion: 15, outputPerMillion: 75 },
|
|
18
|
-
// OpenAI
|
|
19
|
-
'gpt-4o': { inputPerMillion: 2.5, outputPerMillion: 10 },
|
|
20
|
-
'gpt-4o-mini': { inputPerMillion: 0.15, outputPerMillion: 0.6 },
|
|
21
|
-
o1: { inputPerMillion: 15, outputPerMillion: 60 },
|
|
22
|
-
'o1-mini': { inputPerMillion: 3, outputPerMillion: 12 },
|
|
23
|
-
o3: { inputPerMillion: 10, outputPerMillion: 40 },
|
|
24
|
-
'o3-mini': { inputPerMillion: 1.1, outputPerMillion: 4.4 },
|
|
25
|
-
// DeepSeek
|
|
26
|
-
'deepseek-chat': { inputPerMillion: 0.14, outputPerMillion: 0.28 },
|
|
27
|
-
'deepseek-reasoner': { inputPerMillion: 0.55, outputPerMillion: 2.19 },
|
|
28
|
-
// Google Gemini
|
|
29
|
-
'gemini-2.0-flash': { inputPerMillion: 0.1, outputPerMillion: 0.4 },
|
|
30
|
-
'gemini-2.0-flash-thinking': { inputPerMillion: 0.35, outputPerMillion: 3.5 },
|
|
31
|
-
'gemini-1.5-pro': { inputPerMillion: 1.25, outputPerMillion: 5 },
|
|
32
|
-
'gemini-1.5-flash': { inputPerMillion: 0.075, outputPerMillion: 0.3 },
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const PATTERN_PRICES: Array<{ pattern: RegExp; price: IModelPrice }> = [
|
|
36
|
-
{ pattern: /claude-opus/i, price: { inputPerMillion: 15, outputPerMillion: 75 } },
|
|
37
|
-
{ pattern: /claude-sonnet/i, price: { inputPerMillion: 3, outputPerMillion: 15 } },
|
|
38
|
-
{ pattern: /claude-haiku/i, price: { inputPerMillion: 0.8, outputPerMillion: 4 } },
|
|
39
|
-
{ pattern: /gpt-4o-mini/i, price: { inputPerMillion: 0.15, outputPerMillion: 0.6 } },
|
|
40
|
-
{ pattern: /gpt-4/i, price: { inputPerMillion: 2.5, outputPerMillion: 10 } },
|
|
41
|
-
{ pattern: /deepseek/i, price: { inputPerMillion: 0.14, outputPerMillion: 0.28 } },
|
|
42
|
-
{ pattern: /gemini-2/i, price: { inputPerMillion: 0.1, outputPerMillion: 0.4 } },
|
|
43
|
-
{ pattern: /gemini-1/i, price: { inputPerMillion: 1.25, outputPerMillion: 5 } },
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
function lookupPrice(modelId: string): IModelPrice | undefined {
|
|
47
|
-
const exact = MODEL_PRICES[modelId];
|
|
48
|
-
if (exact) return exact;
|
|
49
|
-
for (const { pattern, price } of PATTERN_PRICES) {
|
|
50
|
-
if (pattern.test(modelId)) return price;
|
|
51
|
-
}
|
|
52
|
-
return undefined;
|
|
53
|
-
}
|
|
1
|
+
import { calculateModelCost } from '@robota-sdk/agent-core';
|
|
54
2
|
|
|
55
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Returns USD cost, or undefined if the model is not in the pricing table.
|
|
5
|
+
* Delegates to the agent-core pricing SSOT (`calculateModelCost`); this package owns only the
|
|
6
|
+
* command-facing display helpers below.
|
|
7
|
+
*/
|
|
56
8
|
export function calculateCost(
|
|
57
9
|
modelId: string,
|
|
58
10
|
inputTokens: number,
|
|
59
11
|
outputTokens: number,
|
|
60
12
|
): number | undefined {
|
|
61
|
-
|
|
62
|
-
if (!price) return undefined;
|
|
63
|
-
return (
|
|
64
|
-
(inputTokens / 1_000_000) * price.inputPerMillion +
|
|
65
|
-
(outputTokens / 1_000_000) * price.outputPerMillion
|
|
66
|
-
);
|
|
13
|
+
return calculateModelCost(modelId, inputTokens, outputTokens);
|
|
67
14
|
}
|
|
68
15
|
|
|
69
16
|
/** Format a USD amount for display (e.g. "$0.0043"). */
|