@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robota-sdk/agent-command",
3
- "version": "3.0.0-beta.75",
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.75",
28
- "@robota-sdk/agent-framework": "3.0.0-beta.75",
29
- "@robota-sdk/agent-interface-transport": "3.0.0-beta.75",
30
- "@robota-sdk/agent-preset": "3.0.0-beta.75"
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 — same approximation used across the codebase (limits-helpers.ts)
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 / CHARS_PER_TOKEN);
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 / CHARS_PER_TOKEN);
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(context: ICommandHostContext, args: string): ICommandResult {
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
- /** USD prices per 1,000,000 tokens (as of May 2026 — update when providers change rates). */
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
- /** Returns USD cost, or undefined if the model is not in the pricing table. */
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
- const price = lookupPrice(modelId);
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"). */