@robota-sdk/agent-command 3.0.0-beta.69 → 3.0.0-beta.71
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 +34 -31
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +34 -31
- package/dist/node/index.js.map +1 -1
- package/package.json +3 -3
- package/src/background/__tests__/background-command-module.test.ts +2 -0
- package/src/compact/__tests__/compact-command-module.test.ts +2 -0
- package/src/context/__tests__/context-command-module.test.ts +23 -8
- package/src/context/context-command.ts +229 -13
- package/src/exit/exit-command-module.ts +6 -0
- package/src/help/__tests__/help-command-module.test.ts +2 -0
- package/src/help/__tests__/help-command.test.ts +2 -0
- package/src/language/language-command-module.ts +14 -0
- package/src/mode/mode-command-module.ts +14 -0
- package/src/plugin/__tests__/plugin-command-module.test.ts +2 -0
- package/src/provider/provider-command-module.ts +14 -0
- package/src/session/__tests__/session-command-module.test.ts +2 -0
- package/src/session/session-command-module.ts +6 -0
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.71",
|
|
4
4
|
"description": "Consolidated command module implementations for Robota SDK CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/node/index.js",
|
|
@@ -24,8 +24,8 @@
|
|
|
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.
|
|
27
|
+
"@robota-sdk/agent-core": "3.0.0-beta.71",
|
|
28
|
+
"@robota-sdk/agent-framework": "3.0.0-beta.71"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^22.14.0",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import type { IHistoryEntry } from '@robota-sdk/agent-core';
|
|
2
3
|
import type {
|
|
3
4
|
ICommandHostContext,
|
|
4
5
|
IContextReferenceAddResult,
|
|
@@ -57,7 +58,10 @@ const SYSTEM_REFERENCE: IContextReferenceItem = {
|
|
|
57
58
|
lastUsedAt: '2026-05-05T00:00:00.000Z',
|
|
58
59
|
};
|
|
59
60
|
|
|
60
|
-
function createRuntime(
|
|
61
|
+
function createRuntime(
|
|
62
|
+
state: { threshold: number | false },
|
|
63
|
+
history: IHistoryEntry[] = [],
|
|
64
|
+
): ICommandSessionRuntime {
|
|
61
65
|
let mode: TPermissionMode = 'default';
|
|
62
66
|
return {
|
|
63
67
|
clearHistory: vi.fn(),
|
|
@@ -71,6 +75,8 @@ function createRuntime(state: { threshold: number | false }): ICommandSessionRun
|
|
|
71
75
|
getMessageCount: () => 1,
|
|
72
76
|
getSessionAllowedTools: () => [],
|
|
73
77
|
getAutoCompactThreshold: () => state.threshold,
|
|
78
|
+
getFullHistory: () => history,
|
|
79
|
+
getHistory: () => [],
|
|
74
80
|
setAutoCompactThreshold: (threshold) => {
|
|
75
81
|
state.threshold = threshold;
|
|
76
82
|
},
|
|
@@ -202,9 +208,9 @@ describe('createContextCommandModule', () => {
|
|
|
202
208
|
const result = await createExecutor().execute('context', context, 'list');
|
|
203
209
|
|
|
204
210
|
expect(result?.success).toBe(true);
|
|
205
|
-
expect(result?.message).toContain('AGENTS.md [manual, active]
|
|
211
|
+
expect(result?.message).toContain('AGENTS.md [manual, active] ~11 tokens');
|
|
206
212
|
expect(result?.message).toContain(
|
|
207
|
-
'packages/agent-sdk/docs/SPEC.md [prompt-reference, observed]
|
|
213
|
+
'packages/agent-sdk/docs/SPEC.md [prompt-reference, observed] ~50 tokens',
|
|
208
214
|
);
|
|
209
215
|
expect(result?.data?.references).toEqual([MANUAL_REFERENCE, PROMPT_REFERENCE]);
|
|
210
216
|
});
|
|
@@ -215,7 +221,9 @@ describe('createContextCommandModule', () => {
|
|
|
215
221
|
const result = await createExecutor().execute('context', context, 'add AGENTS.md');
|
|
216
222
|
|
|
217
223
|
expect(result?.success).toBe(true);
|
|
218
|
-
expect(result?.message).toContain(
|
|
224
|
+
expect(result?.message).toContain(
|
|
225
|
+
'Context reference added: AGENTS.md [manual, active] ~11 tokens.',
|
|
226
|
+
);
|
|
219
227
|
expect(context.references[0]?.relativePath).toBe('AGENTS.md');
|
|
220
228
|
});
|
|
221
229
|
|
|
@@ -226,7 +234,9 @@ describe('createContextCommandModule', () => {
|
|
|
226
234
|
const result = await createExecutor().execute('context', context, 'remove AGENTS.md');
|
|
227
235
|
|
|
228
236
|
expect(result?.success).toBe(true);
|
|
229
|
-
expect(result?.message).toBe(
|
|
237
|
+
expect(result?.message).toBe(
|
|
238
|
+
'Context reference removed: AGENTS.md [manual, active] ~11 tokens.',
|
|
239
|
+
);
|
|
230
240
|
expect(context.references).toEqual([]);
|
|
231
241
|
});
|
|
232
242
|
|
|
@@ -311,7 +321,7 @@ describe('createContextCommandModule', () => {
|
|
|
311
321
|
const result = await createExecutor().execute('context', context, 'list');
|
|
312
322
|
|
|
313
323
|
expect(result?.success).toBe(true);
|
|
314
|
-
expect(result?.message).toContain('AGENTS.md [system, active]
|
|
324
|
+
expect(result?.message).toContain('AGENTS.md [system, active] ~256 tokens');
|
|
315
325
|
expect(result?.data?.references).toEqual([SYSTEM_REFERENCE]);
|
|
316
326
|
});
|
|
317
327
|
|
|
@@ -325,12 +335,17 @@ describe('createContextCommandModule', () => {
|
|
|
325
335
|
expect(result?.message).toContain('References: 2 active, 0 observed');
|
|
326
336
|
});
|
|
327
337
|
|
|
328
|
-
it('shows
|
|
338
|
+
it('shows full context breakdown with empty sections when no references', async () => {
|
|
329
339
|
const context = createCommandHostContext();
|
|
330
340
|
|
|
331
341
|
const result = await createExecutor().execute('context', context, 'list');
|
|
332
342
|
|
|
333
343
|
expect(result?.success).toBe(true);
|
|
334
|
-
expect(result?.message).
|
|
344
|
+
expect(result?.message).toContain('System prompt (active every turn):');
|
|
345
|
+
expect(result?.message).toContain('Conversation history — 0 turns:');
|
|
346
|
+
expect(result?.message).toContain('Manually added:');
|
|
347
|
+
expect(result?.message).toContain('Prompt references (@-syntax):');
|
|
348
|
+
// All sections empty
|
|
349
|
+
expect(result?.message).not.toContain('~');
|
|
335
350
|
});
|
|
336
351
|
});
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
writeAutoCompactThresholdSetting,
|
|
13
13
|
} from '@robota-sdk/agent-framework';
|
|
14
14
|
|
|
15
|
+
import type { IHistoryEntry, TUniversalMessage } from '@robota-sdk/agent-core';
|
|
15
16
|
import type {
|
|
16
17
|
ICommandHostContext,
|
|
17
18
|
ICommandResult,
|
|
@@ -63,11 +64,15 @@ export async function executeContextCommand(
|
|
|
63
64
|
const state = readCommandContextState(context);
|
|
64
65
|
const autoCompactThreshold = readAutoCompactThreshold(context);
|
|
65
66
|
const autoCompactThresholdSource = readAutoCompactThresholdSource(context);
|
|
67
|
+
const history = context.getSession().getFullHistory();
|
|
68
|
+
const display = buildToolDisplayList(history);
|
|
69
|
+
const references = listCommandContextReferences(context);
|
|
66
70
|
return {
|
|
67
71
|
message: [
|
|
68
72
|
`Context: ${state.usedTokens.toLocaleString()} / ${state.maxTokens.toLocaleString()} tokens (${Math.round(state.usedPercentage)}%)`,
|
|
69
73
|
formatAutoCompactLine(autoCompactThreshold, autoCompactThresholdSource),
|
|
70
|
-
formatContextReferenceSummary(
|
|
74
|
+
formatContextReferenceSummary(references),
|
|
75
|
+
`History: ${display.turnCount} turn${display.turnCount !== 1 ? 's' : ''}`,
|
|
71
76
|
].join('\n'),
|
|
72
77
|
success: true,
|
|
73
78
|
data: {
|
|
@@ -76,7 +81,7 @@ export async function executeContextCommand(
|
|
|
76
81
|
percentage: state.usedPercentage,
|
|
77
82
|
autoCompactThreshold,
|
|
78
83
|
autoCompactThresholdSource,
|
|
79
|
-
references
|
|
84
|
+
references,
|
|
80
85
|
},
|
|
81
86
|
};
|
|
82
87
|
}
|
|
@@ -88,7 +93,7 @@ async function executeContextSubcommand(
|
|
|
88
93
|
const [subcommand, ...rest] = parts;
|
|
89
94
|
if (subcommand === 'list') {
|
|
90
95
|
if (rest.length > 0) return { success: false, message: USAGE };
|
|
91
|
-
return
|
|
96
|
+
return formatFullContextBreakdown(context);
|
|
92
97
|
}
|
|
93
98
|
if (subcommand === 'add') {
|
|
94
99
|
return executeAddContextReference(context, rest);
|
|
@@ -278,22 +283,233 @@ function formatContextReferenceSummary(references: readonly IContextReferenceIte
|
|
|
278
283
|
return `References: ${active} active, ${observed} observed`;
|
|
279
284
|
}
|
|
280
285
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
286
|
+
// 1 token ≈ 4 chars — same approximation used across the codebase (limits-helpers.ts)
|
|
287
|
+
const CHARS_PER_TOKEN = 4;
|
|
288
|
+
const TOOL_ARG_MAX_LEN = 60;
|
|
285
289
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
message: ['Context references:', ...references.map(formatContextReferenceLine)].join('\n'),
|
|
289
|
-
data: { references },
|
|
290
|
-
};
|
|
290
|
+
function estimateTokens(charLength: number): number {
|
|
291
|
+
return Math.ceil(charLength / CHARS_PER_TOKEN);
|
|
291
292
|
}
|
|
292
293
|
|
|
293
294
|
function formatContextReferenceLine(reference: IContextReferenceItem): string {
|
|
294
295
|
return [
|
|
295
296
|
reference.relativePath,
|
|
296
297
|
`[${reference.loadType}, ${reference.status}]`,
|
|
297
|
-
|
|
298
|
+
`~${estimateTokens(reference.byteLength).toLocaleString()} tokens`,
|
|
298
299
|
].join(' ');
|
|
299
300
|
}
|
|
301
|
+
|
|
302
|
+
// ── History analysis ────────────────────────────────────────────────────────
|
|
303
|
+
|
|
304
|
+
interface IToolResultSummary {
|
|
305
|
+
toolName: string;
|
|
306
|
+
displayArg: string;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
interface IMessageTokensByRole {
|
|
310
|
+
systemTokens: number;
|
|
311
|
+
userTokens: number;
|
|
312
|
+
userCount: number;
|
|
313
|
+
assistantTokens: number;
|
|
314
|
+
assistantCount: number;
|
|
315
|
+
toolTokens: number;
|
|
316
|
+
toolCallCount: number;
|
|
317
|
+
totalTokens: number;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
interface IToolDisplayList {
|
|
321
|
+
turnCount: number;
|
|
322
|
+
toolResults: IToolResultSummary[];
|
|
323
|
+
totalToolCallCount: number;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function parseToolCallArgs(argsJson: string): Record<string, unknown> | null {
|
|
327
|
+
try {
|
|
328
|
+
return JSON.parse(argsJson) as Record<string, unknown>;
|
|
329
|
+
} catch {
|
|
330
|
+
// allow-fallback: tool call arguments JSON may be malformed; display-only degradation, not a terminal path
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function extractFirstToolArg(argsJson: string): string {
|
|
336
|
+
const parsed = parseToolCallArgs(argsJson);
|
|
337
|
+
if (parsed === null) return '';
|
|
338
|
+
const first = Object.values(parsed)[0];
|
|
339
|
+
const raw = typeof first === 'string' ? first : JSON.stringify(first);
|
|
340
|
+
return raw.length > TOOL_ARG_MAX_LEN ? `${raw.slice(0, TOOL_ARG_MAX_LEN)}…` : raw;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function computeMessageTokensByRole(rawMessages: TUniversalMessage[]): IMessageTokensByRole {
|
|
344
|
+
let systemTokens = 0;
|
|
345
|
+
let userTokens = 0;
|
|
346
|
+
let userCount = 0;
|
|
347
|
+
let assistantTokens = 0;
|
|
348
|
+
let assistantCount = 0;
|
|
349
|
+
let toolTokens = 0;
|
|
350
|
+
let toolCallCount = 0;
|
|
351
|
+
|
|
352
|
+
for (const msg of rawMessages) {
|
|
353
|
+
const t = Math.ceil(JSON.stringify(msg).length / CHARS_PER_TOKEN);
|
|
354
|
+
if (msg.role === 'system') {
|
|
355
|
+
systemTokens += t;
|
|
356
|
+
} else if (msg.role === 'user') {
|
|
357
|
+
userTokens += t;
|
|
358
|
+
userCount++;
|
|
359
|
+
} else if (msg.role === 'assistant') {
|
|
360
|
+
assistantTokens += t;
|
|
361
|
+
assistantCount++;
|
|
362
|
+
} else if (msg.role === 'tool') {
|
|
363
|
+
toolTokens += t;
|
|
364
|
+
toolCallCount++;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
systemTokens,
|
|
370
|
+
userTokens,
|
|
371
|
+
userCount,
|
|
372
|
+
assistantTokens,
|
|
373
|
+
assistantCount,
|
|
374
|
+
toolTokens,
|
|
375
|
+
toolCallCount,
|
|
376
|
+
totalTokens: systemTokens + userTokens + assistantTokens + toolTokens,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function buildToolDisplayList(history: IHistoryEntry[]): IToolDisplayList {
|
|
381
|
+
type TToolCallEntry = { name: string; firstArg: string };
|
|
382
|
+
const toolCallMap = new Map<string, TToolCallEntry>();
|
|
383
|
+
|
|
384
|
+
for (const entry of history) {
|
|
385
|
+
if (entry.category !== 'chat' || entry.type !== 'assistant') continue;
|
|
386
|
+
const data = entry.data as {
|
|
387
|
+
toolCalls?: Array<{ id: string; function: { name: string; arguments: string } }>;
|
|
388
|
+
};
|
|
389
|
+
for (const tc of data.toolCalls ?? []) {
|
|
390
|
+
toolCallMap.set(tc.id, {
|
|
391
|
+
name: tc.function.name,
|
|
392
|
+
firstArg: extractFirstToolArg(tc.function.arguments),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
let turnCount = 0;
|
|
398
|
+
let totalToolCallCount = 0;
|
|
399
|
+
const toolDisplayMap = new Map<string, IToolResultSummary>();
|
|
400
|
+
|
|
401
|
+
for (const entry of history) {
|
|
402
|
+
if (entry.category !== 'chat') continue;
|
|
403
|
+
if (entry.type === 'user') {
|
|
404
|
+
turnCount++;
|
|
405
|
+
} else if (entry.type === 'tool') {
|
|
406
|
+
const data = entry.data as { toolCallId?: string };
|
|
407
|
+
const tc = toolCallMap.get(data.toolCallId ?? '');
|
|
408
|
+
const toolName = tc?.name ?? 'tool';
|
|
409
|
+
const displayArg = tc?.firstArg ?? '';
|
|
410
|
+
totalToolCallCount++;
|
|
411
|
+
toolDisplayMap.set(`${toolName}:${displayArg}`, { toolName, displayArg });
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return {
|
|
416
|
+
turnCount,
|
|
417
|
+
toolResults: [...toolDisplayMap.values()],
|
|
418
|
+
totalToolCallCount,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// ── Full context breakdown (for /context list) ──────────────────────────────
|
|
423
|
+
|
|
424
|
+
function formatSection(title: string, tokens: number, lines: string[]): string {
|
|
425
|
+
const tokenLabel = tokens > 0 ? ` — ~${tokens.toLocaleString()} tokens` : '';
|
|
426
|
+
const header = `${title}${tokenLabel}:`;
|
|
427
|
+
return lines.length === 0
|
|
428
|
+
? `${header}\n (none)`
|
|
429
|
+
: [header, ...lines.map((l) => ` ${l}`)].join('\n');
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function formatFullContextBreakdown(context: ICommandHostContext): ICommandResult {
|
|
433
|
+
const state = readCommandContextState(context);
|
|
434
|
+
const autoCompactThreshold = readAutoCompactThreshold(context);
|
|
435
|
+
const autoCompactThresholdSource = readAutoCompactThresholdSource(context);
|
|
436
|
+
const rawMessages = context.getSession().getHistory();
|
|
437
|
+
const msgTokens = computeMessageTokensByRole(rawMessages);
|
|
438
|
+
const display = buildToolDisplayList(context.getSession().getFullHistory());
|
|
439
|
+
const references = listCommandContextReferences(context);
|
|
440
|
+
|
|
441
|
+
const systemRefs = references.filter((r) => r.loadType === 'system');
|
|
442
|
+
const manualRefs = references.filter((r) => r.loadType === 'manual');
|
|
443
|
+
const promptRefs = references.filter((r) => r.loadType === 'prompt-reference');
|
|
444
|
+
|
|
445
|
+
const systemRefTokens = systemRefs.reduce((s, r) => s + estimateTokens(r.byteLength), 0);
|
|
446
|
+
const manualTokens = manualRefs.reduce((s, r) => s + estimateTokens(r.byteLength), 0);
|
|
447
|
+
const promptRefTokens = promptRefs.reduce((s, r) => s + estimateTokens(r.byteLength), 0);
|
|
448
|
+
|
|
449
|
+
const convTurnLabel =
|
|
450
|
+
display.turnCount === 0
|
|
451
|
+
? 'Conversation history — 0 turns'
|
|
452
|
+
: `Conversation history — ${display.turnCount} turn${display.turnCount !== 1 ? 's' : ''} | ~${msgTokens.totalTokens.toLocaleString()} tokens`;
|
|
453
|
+
|
|
454
|
+
const toolResultLines = display.toolResults.map(
|
|
455
|
+
(t) => `${t.toolName}${t.displayArg ? `: ${t.displayArg}` : ''}`,
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
const uniqueToolCount = display.toolResults.length;
|
|
459
|
+
const totalToolCallCount = display.totalToolCallCount;
|
|
460
|
+
const toolResultsLabel =
|
|
461
|
+
totalToolCallCount === 0
|
|
462
|
+
? 'Tool results (0): (none)'
|
|
463
|
+
: uniqueToolCount < totalToolCallCount
|
|
464
|
+
? `Tool results (${uniqueToolCount} unique / ${totalToolCallCount} calls, ~${msgTokens.toolTokens.toLocaleString()} tokens):`
|
|
465
|
+
: `Tool results (${uniqueToolCount}, ~${msgTokens.toolTokens.toLocaleString()} tokens):`;
|
|
466
|
+
|
|
467
|
+
const conversationLines: string[] =
|
|
468
|
+
display.turnCount === 0
|
|
469
|
+
? []
|
|
470
|
+
: [
|
|
471
|
+
`User (${msgTokens.userCount}): ~${msgTokens.userTokens.toLocaleString()} tokens`,
|
|
472
|
+
`Assistant (${msgTokens.assistantCount}): ~${msgTokens.assistantTokens.toLocaleString()} tokens`,
|
|
473
|
+
...(msgTokens.systemTokens > 0
|
|
474
|
+
? [`System messages: ~${msgTokens.systemTokens.toLocaleString()} tokens`]
|
|
475
|
+
: []),
|
|
476
|
+
totalToolCallCount > 0
|
|
477
|
+
? [toolResultsLabel, ...toolResultLines.map((l) => ` ${l}`)].join('\n')
|
|
478
|
+
: toolResultsLabel,
|
|
479
|
+
];
|
|
480
|
+
|
|
481
|
+
const convSection =
|
|
482
|
+
display.turnCount === 0
|
|
483
|
+
? `${convTurnLabel}:\n (none)`
|
|
484
|
+
: [`${convTurnLabel}:`, ...conversationLines.map((l) => ` ${l}`)].join('\n');
|
|
485
|
+
|
|
486
|
+
const message = [
|
|
487
|
+
`Context: ${state.usedTokens.toLocaleString()} / ${state.maxTokens.toLocaleString()} tokens (${Math.round(state.usedPercentage)}%)`,
|
|
488
|
+
formatAutoCompactLine(autoCompactThreshold, autoCompactThresholdSource),
|
|
489
|
+
'',
|
|
490
|
+
formatSection(
|
|
491
|
+
'System prompt (active every turn)',
|
|
492
|
+
systemRefTokens,
|
|
493
|
+
systemRefs.map(formatContextReferenceLine),
|
|
494
|
+
),
|
|
495
|
+
'',
|
|
496
|
+
convSection,
|
|
497
|
+
'',
|
|
498
|
+
formatSection('Manually added', manualTokens, manualRefs.map(formatContextReferenceLine)),
|
|
499
|
+
'',
|
|
500
|
+
formatSection(
|
|
501
|
+
'Prompt references (@-syntax)',
|
|
502
|
+
promptRefTokens,
|
|
503
|
+
promptRefs.map(formatContextReferenceLine),
|
|
504
|
+
),
|
|
505
|
+
].join('\n');
|
|
506
|
+
|
|
507
|
+
return {
|
|
508
|
+
success: true,
|
|
509
|
+
message,
|
|
510
|
+
data: {
|
|
511
|
+
references,
|
|
512
|
+
history: { turnCount: display.turnCount, toolResults: display.toolResults },
|
|
513
|
+
},
|
|
514
|
+
};
|
|
515
|
+
}
|
|
@@ -4,6 +4,7 @@ import { executeExitCommand } from './exit-command.js';
|
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
6
|
ICommand,
|
|
7
|
+
ICommandInteractionHint,
|
|
7
8
|
ICommandModule,
|
|
8
9
|
ICommandSource,
|
|
9
10
|
ISystemCommand,
|
|
@@ -41,10 +42,15 @@ export class ExitCommandSource implements ICommandSource {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
const EXIT_INTERACTION_HINTS: Record<string, ICommandInteractionHint> = {
|
|
46
|
+
exit: { type: 'confirm', message: 'Exit the session?' },
|
|
47
|
+
};
|
|
48
|
+
|
|
44
49
|
export function createExitCommandModule(): ICommandModule {
|
|
45
50
|
return {
|
|
46
51
|
name: 'agent-command-exit',
|
|
47
52
|
commandSources: [new ExitCommandSource()],
|
|
48
53
|
systemCommands: [createExitSystemCommand()],
|
|
54
|
+
interactionHints: EXIT_INTERACTION_HINTS,
|
|
49
55
|
};
|
|
50
56
|
}
|
|
@@ -8,6 +8,7 @@ import { executeLanguageCommand } from './language-command.js';
|
|
|
8
8
|
|
|
9
9
|
import type {
|
|
10
10
|
ICommand,
|
|
11
|
+
ICommandInteractionHint,
|
|
11
12
|
ICommandModule,
|
|
12
13
|
ICommandSource,
|
|
13
14
|
ISystemCommand,
|
|
@@ -49,10 +50,23 @@ export class LanguageCommandSource implements ICommandSource {
|
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
const LANGUAGE_INTERACTION_HINTS: Record<string, ICommandInteractionHint> = {
|
|
54
|
+
language: {
|
|
55
|
+
type: 'pick',
|
|
56
|
+
getItems: () =>
|
|
57
|
+
buildLanguageCommandSubcommands().map((sub) => ({
|
|
58
|
+
label: `${sub.name} ${sub.description ?? ''}`.trimEnd(),
|
|
59
|
+
value: sub.name,
|
|
60
|
+
description: sub.description,
|
|
61
|
+
})),
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
52
65
|
export function createLanguageCommandModule(): ICommandModule {
|
|
53
66
|
return {
|
|
54
67
|
name: 'agent-command-language',
|
|
55
68
|
commandSources: [new LanguageCommandSource()],
|
|
56
69
|
systemCommands: [createLanguageSystemCommand()],
|
|
70
|
+
interactionHints: LANGUAGE_INTERACTION_HINTS,
|
|
57
71
|
};
|
|
58
72
|
}
|
|
@@ -8,6 +8,7 @@ import { executeModeCommand } from './mode-command.js';
|
|
|
8
8
|
|
|
9
9
|
import type {
|
|
10
10
|
ICommand,
|
|
11
|
+
ICommandInteractionHint,
|
|
11
12
|
ICommandModule,
|
|
12
13
|
ICommandSource,
|
|
13
14
|
ISystemCommand,
|
|
@@ -49,10 +50,23 @@ export class ModeCommandSource implements ICommandSource {
|
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
const MODE_INTERACTION_HINTS: Record<string, ICommandInteractionHint> = {
|
|
54
|
+
mode: {
|
|
55
|
+
type: 'pick',
|
|
56
|
+
getItems: () =>
|
|
57
|
+
buildPermissionModeSubcommands().map((sub) => ({
|
|
58
|
+
label: sub.name,
|
|
59
|
+
value: sub.name,
|
|
60
|
+
description: sub.description,
|
|
61
|
+
})),
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
52
65
|
export function createModeCommandModule(): ICommandModule {
|
|
53
66
|
return {
|
|
54
67
|
name: 'agent-command-mode',
|
|
55
68
|
commandSources: [new ModeCommandSource()],
|
|
56
69
|
systemCommands: [createModeSystemCommand()],
|
|
70
|
+
interactionHints: MODE_INTERACTION_HINTS,
|
|
57
71
|
};
|
|
58
72
|
}
|
|
@@ -2,6 +2,7 @@ import { executeProviderCommand } from './provider-command-execution.js';
|
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
4
|
ICommand,
|
|
5
|
+
ICommandInteractionHint,
|
|
5
6
|
ICommandModule as TCommandModule,
|
|
6
7
|
ICommandSource,
|
|
7
8
|
IProviderCommandModuleOptions,
|
|
@@ -57,6 +58,18 @@ function createProviderSystemCommand(options: IProviderCommandModuleOptions): TS
|
|
|
57
58
|
};
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
const PROVIDER_INTERACTION_HINTS: Record<string, ICommandInteractionHint> = {
|
|
62
|
+
provider: {
|
|
63
|
+
type: 'pick',
|
|
64
|
+
getItems: () =>
|
|
65
|
+
buildProviderSubcommands().map((sub) => ({
|
|
66
|
+
label: sub.name,
|
|
67
|
+
value: sub.name,
|
|
68
|
+
description: sub.description,
|
|
69
|
+
})),
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
60
73
|
export function createProviderCommandModule(
|
|
61
74
|
options: IProviderCommandModuleOptions,
|
|
62
75
|
): TCommandModule {
|
|
@@ -64,5 +77,6 @@ export function createProviderCommandModule(
|
|
|
64
77
|
name: 'agent-command-provider',
|
|
65
78
|
commandSources: [new ProviderCommandSource()],
|
|
66
79
|
systemCommands: [createProviderSystemCommand(options)],
|
|
80
|
+
interactionHints: PROVIDER_INTERACTION_HINTS,
|
|
67
81
|
};
|
|
68
82
|
}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
|
|
17
17
|
import type {
|
|
18
18
|
ICommand,
|
|
19
|
+
ICommandInteractionHint,
|
|
19
20
|
ICommandModule,
|
|
20
21
|
ICommandSource,
|
|
21
22
|
ISystemCommand,
|
|
@@ -155,6 +156,10 @@ export class SessionCommandSource implements ICommandSource {
|
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
|
|
159
|
+
const SESSION_INTERACTION_HINTS: Record<string, ICommandInteractionHint> = {
|
|
160
|
+
clear: { type: 'confirm', message: 'Clear conversation history?' },
|
|
161
|
+
};
|
|
162
|
+
|
|
158
163
|
export function createSessionCommandModule(): ICommandModule {
|
|
159
164
|
return {
|
|
160
165
|
name: 'agent-command-session',
|
|
@@ -166,5 +171,6 @@ export function createSessionCommandModule(): ICommandModule {
|
|
|
166
171
|
createCostSystemCommand(),
|
|
167
172
|
createValidateSessionSystemCommand(),
|
|
168
173
|
],
|
|
174
|
+
interactionHints: SESSION_INTERACTION_HINTS,
|
|
169
175
|
};
|
|
170
176
|
}
|