@robota-sdk/agent-command 3.0.0-beta.69 → 3.0.0-beta.70
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 +1 -0
- package/src/compact/__tests__/compact-command-module.test.ts +1 -0
- package/src/context/__tests__/context-command-module.test.ts +22 -8
- package/src/context/context-command.ts +193 -13
- package/src/exit/exit-command-module.ts +6 -0
- package/src/help/__tests__/help-command-module.test.ts +1 -0
- package/src/help/__tests__/help-command.test.ts +1 -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 +1 -0
- package/src/provider/provider-command-module.ts +14 -0
- package/src/session/__tests__/session-command-module.test.ts +1 -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.70",
|
|
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.70",
|
|
28
|
+
"@robota-sdk/agent-framework": "3.0.0-beta.70"
|
|
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,7 @@ function createRuntime(state: { threshold: number | false }): ICommandSessionRun
|
|
|
71
75
|
getMessageCount: () => 1,
|
|
72
76
|
getSessionAllowedTools: () => [],
|
|
73
77
|
getAutoCompactThreshold: () => state.threshold,
|
|
78
|
+
getFullHistory: () => history,
|
|
74
79
|
setAutoCompactThreshold: (threshold) => {
|
|
75
80
|
state.threshold = threshold;
|
|
76
81
|
},
|
|
@@ -202,9 +207,9 @@ describe('createContextCommandModule', () => {
|
|
|
202
207
|
const result = await createExecutor().execute('context', context, 'list');
|
|
203
208
|
|
|
204
209
|
expect(result?.success).toBe(true);
|
|
205
|
-
expect(result?.message).toContain('AGENTS.md [manual, active]
|
|
210
|
+
expect(result?.message).toContain('AGENTS.md [manual, active] ~11 tokens');
|
|
206
211
|
expect(result?.message).toContain(
|
|
207
|
-
'packages/agent-sdk/docs/SPEC.md [prompt-reference, observed]
|
|
212
|
+
'packages/agent-sdk/docs/SPEC.md [prompt-reference, observed] ~50 tokens',
|
|
208
213
|
);
|
|
209
214
|
expect(result?.data?.references).toEqual([MANUAL_REFERENCE, PROMPT_REFERENCE]);
|
|
210
215
|
});
|
|
@@ -215,7 +220,9 @@ describe('createContextCommandModule', () => {
|
|
|
215
220
|
const result = await createExecutor().execute('context', context, 'add AGENTS.md');
|
|
216
221
|
|
|
217
222
|
expect(result?.success).toBe(true);
|
|
218
|
-
expect(result?.message).toContain(
|
|
223
|
+
expect(result?.message).toContain(
|
|
224
|
+
'Context reference added: AGENTS.md [manual, active] ~11 tokens.',
|
|
225
|
+
);
|
|
219
226
|
expect(context.references[0]?.relativePath).toBe('AGENTS.md');
|
|
220
227
|
});
|
|
221
228
|
|
|
@@ -226,7 +233,9 @@ describe('createContextCommandModule', () => {
|
|
|
226
233
|
const result = await createExecutor().execute('context', context, 'remove AGENTS.md');
|
|
227
234
|
|
|
228
235
|
expect(result?.success).toBe(true);
|
|
229
|
-
expect(result?.message).toBe(
|
|
236
|
+
expect(result?.message).toBe(
|
|
237
|
+
'Context reference removed: AGENTS.md [manual, active] ~11 tokens.',
|
|
238
|
+
);
|
|
230
239
|
expect(context.references).toEqual([]);
|
|
231
240
|
});
|
|
232
241
|
|
|
@@ -311,7 +320,7 @@ describe('createContextCommandModule', () => {
|
|
|
311
320
|
const result = await createExecutor().execute('context', context, 'list');
|
|
312
321
|
|
|
313
322
|
expect(result?.success).toBe(true);
|
|
314
|
-
expect(result?.message).toContain('AGENTS.md [system, active]
|
|
323
|
+
expect(result?.message).toContain('AGENTS.md [system, active] ~256 tokens');
|
|
315
324
|
expect(result?.data?.references).toEqual([SYSTEM_REFERENCE]);
|
|
316
325
|
});
|
|
317
326
|
|
|
@@ -325,12 +334,17 @@ describe('createContextCommandModule', () => {
|
|
|
325
334
|
expect(result?.message).toContain('References: 2 active, 0 observed');
|
|
326
335
|
});
|
|
327
336
|
|
|
328
|
-
it('shows
|
|
337
|
+
it('shows full context breakdown with empty sections when no references', async () => {
|
|
329
338
|
const context = createCommandHostContext();
|
|
330
339
|
|
|
331
340
|
const result = await createExecutor().execute('context', context, 'list');
|
|
332
341
|
|
|
333
342
|
expect(result?.success).toBe(true);
|
|
334
|
-
expect(result?.message).
|
|
343
|
+
expect(result?.message).toContain('System prompt (active every turn):');
|
|
344
|
+
expect(result?.message).toContain('Conversation history — 0 turns:');
|
|
345
|
+
expect(result?.message).toContain('Manually added:');
|
|
346
|
+
expect(result?.message).toContain('Prompt references (@-syntax):');
|
|
347
|
+
// All sections empty
|
|
348
|
+
expect(result?.message).not.toContain('~');
|
|
335
349
|
});
|
|
336
350
|
});
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
writeAutoCompactThresholdSetting,
|
|
13
13
|
} from '@robota-sdk/agent-framework';
|
|
14
14
|
|
|
15
|
+
import type { IHistoryEntry } 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 analysis = analyzeHistory(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: ${analysis.turnCount} turn${analysis.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,197 @@ 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
|
+
tokens: number;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
interface IHistoryAnalysis {
|
|
311
|
+
turnCount: number;
|
|
312
|
+
userCount: number;
|
|
313
|
+
userTokens: number;
|
|
314
|
+
assistantCount: number;
|
|
315
|
+
assistantTokens: number;
|
|
316
|
+
toolResults: IToolResultSummary[];
|
|
317
|
+
totalTokens: number;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function parseToolCallArgs(argsJson: string): Record<string, unknown> | null {
|
|
321
|
+
try {
|
|
322
|
+
return JSON.parse(argsJson) as Record<string, unknown>;
|
|
323
|
+
} catch {
|
|
324
|
+
// allow-fallback: tool call arguments JSON may be malformed; display-only degradation, not a terminal path
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function extractFirstToolArg(argsJson: string): string {
|
|
330
|
+
const parsed = parseToolCallArgs(argsJson);
|
|
331
|
+
if (parsed === null) return '';
|
|
332
|
+
const first = Object.values(parsed)[0];
|
|
333
|
+
const raw = typeof first === 'string' ? first : JSON.stringify(first);
|
|
334
|
+
return raw.length > TOOL_ARG_MAX_LEN ? `${raw.slice(0, TOOL_ARG_MAX_LEN)}…` : raw;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function analyzeHistory(history: IHistoryEntry[]): IHistoryAnalysis {
|
|
338
|
+
type TToolCallEntry = { name: string; firstArg: string };
|
|
339
|
+
const toolCallMap = new Map<string, TToolCallEntry>();
|
|
340
|
+
|
|
341
|
+
for (const entry of history) {
|
|
342
|
+
if (entry.category !== 'chat' || entry.type !== 'assistant') continue;
|
|
343
|
+
const data = entry.data as {
|
|
344
|
+
toolCalls?: Array<{ id: string; function: { name: string; arguments: string } }>;
|
|
345
|
+
};
|
|
346
|
+
for (const tc of data.toolCalls ?? []) {
|
|
347
|
+
toolCallMap.set(tc.id, {
|
|
348
|
+
name: tc.function.name,
|
|
349
|
+
firstArg: extractFirstToolArg(tc.function.arguments),
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
let userCount = 0;
|
|
355
|
+
let userTokens = 0;
|
|
356
|
+
let assistantCount = 0;
|
|
357
|
+
let assistantTokens = 0;
|
|
358
|
+
const toolResultMap = new Map<string, IToolResultSummary>();
|
|
359
|
+
|
|
360
|
+
for (const entry of history) {
|
|
361
|
+
if (entry.category !== 'chat') continue;
|
|
362
|
+
if (entry.type === 'user') {
|
|
363
|
+
const data = entry.data as { content?: string };
|
|
364
|
+
userCount++;
|
|
365
|
+
userTokens += estimateTokens((data.content ?? '').length);
|
|
366
|
+
} else if (entry.type === 'assistant') {
|
|
367
|
+
const data = entry.data as { content?: string | null; toolCalls?: unknown[] };
|
|
368
|
+
assistantCount++;
|
|
369
|
+
assistantTokens += estimateTokens(
|
|
370
|
+
(data.content ?? '').length + (data.toolCalls ? JSON.stringify(data.toolCalls).length : 0),
|
|
371
|
+
);
|
|
372
|
+
} else if (entry.type === 'tool') {
|
|
373
|
+
const data = entry.data as { content?: string; toolCallId?: string };
|
|
374
|
+
const tc = toolCallMap.get(data.toolCallId ?? '');
|
|
375
|
+
const toolName = tc?.name ?? 'tool';
|
|
376
|
+
const displayArg = tc?.firstArg ?? '';
|
|
377
|
+
const tokens = estimateTokens((data.content ?? '').length);
|
|
378
|
+
toolResultMap.set(`${toolName}:${displayArg}`, { toolName, displayArg, tokens });
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const toolResults = [...toolResultMap.values()];
|
|
383
|
+
const toolTokens = toolResults.reduce((s, t) => s + t.tokens, 0);
|
|
384
|
+
return {
|
|
385
|
+
turnCount: userCount,
|
|
386
|
+
userCount,
|
|
387
|
+
userTokens,
|
|
388
|
+
assistantCount,
|
|
389
|
+
assistantTokens,
|
|
390
|
+
toolResults,
|
|
391
|
+
totalTokens: userTokens + assistantTokens + toolTokens,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// ── Full context breakdown (for /context list) ──────────────────────────────
|
|
396
|
+
|
|
397
|
+
function formatSection(title: string, tokens: number, lines: string[]): string {
|
|
398
|
+
const tokenLabel = tokens > 0 ? ` — ~${tokens.toLocaleString()} tokens` : '';
|
|
399
|
+
const header = `${title}${tokenLabel}:`;
|
|
400
|
+
return lines.length === 0
|
|
401
|
+
? `${header}\n (none)`
|
|
402
|
+
: [header, ...lines.map((l) => ` ${l}`)].join('\n');
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function formatFullContextBreakdown(context: ICommandHostContext): ICommandResult {
|
|
406
|
+
const state = readCommandContextState(context);
|
|
407
|
+
const autoCompactThreshold = readAutoCompactThreshold(context);
|
|
408
|
+
const autoCompactThresholdSource = readAutoCompactThresholdSource(context);
|
|
409
|
+
const history = context.getSession().getFullHistory();
|
|
410
|
+
const analysis = analyzeHistory(history);
|
|
411
|
+
const references = listCommandContextReferences(context);
|
|
412
|
+
|
|
413
|
+
const systemRefs = references.filter((r) => r.loadType === 'system');
|
|
414
|
+
const manualRefs = references.filter((r) => r.loadType === 'manual');
|
|
415
|
+
const promptRefs = references.filter((r) => r.loadType === 'prompt-reference');
|
|
416
|
+
|
|
417
|
+
const systemTokens = systemRefs.reduce((s, r) => s + estimateTokens(r.byteLength), 0);
|
|
418
|
+
const manualTokens = manualRefs.reduce((s, r) => s + estimateTokens(r.byteLength), 0);
|
|
419
|
+
const promptRefTokens = promptRefs.reduce((s, r) => s + estimateTokens(r.byteLength), 0);
|
|
420
|
+
|
|
421
|
+
const convTurnLabel =
|
|
422
|
+
analysis.turnCount === 0
|
|
423
|
+
? 'Conversation history — 0 turns'
|
|
424
|
+
: `Conversation history — ${analysis.turnCount} turn${analysis.turnCount !== 1 ? 's' : ''} | ~${analysis.totalTokens.toLocaleString()} tokens`;
|
|
425
|
+
|
|
426
|
+
const toolResultLines = analysis.toolResults.map(
|
|
427
|
+
(t) =>
|
|
428
|
+
`${t.toolName}${t.displayArg ? `: ${t.displayArg}` : ''} — ~${t.tokens.toLocaleString()} tokens`,
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
const conversationLines: string[] =
|
|
432
|
+
analysis.turnCount === 0
|
|
433
|
+
? []
|
|
434
|
+
: [
|
|
435
|
+
`User (${analysis.userCount}): ~${analysis.userTokens.toLocaleString()} tokens`,
|
|
436
|
+
`Assistant (${analysis.assistantCount}): ~${analysis.assistantTokens.toLocaleString()} tokens`,
|
|
437
|
+
analysis.toolResults.length > 0
|
|
438
|
+
? [
|
|
439
|
+
`Tool results (${analysis.toolResults.length}):`,
|
|
440
|
+
...toolResultLines.map((l) => ` ${l}`),
|
|
441
|
+
].join('\n')
|
|
442
|
+
: `Tool results (0): (none)`,
|
|
443
|
+
];
|
|
444
|
+
|
|
445
|
+
const convSection =
|
|
446
|
+
analysis.turnCount === 0
|
|
447
|
+
? `${convTurnLabel}:\n (none)`
|
|
448
|
+
: [`${convTurnLabel}:`, ...conversationLines.map((l) => ` ${l}`)].join('\n');
|
|
449
|
+
|
|
450
|
+
const message = [
|
|
451
|
+
`Context: ${state.usedTokens.toLocaleString()} / ${state.maxTokens.toLocaleString()} tokens (${Math.round(state.usedPercentage)}%)`,
|
|
452
|
+
formatAutoCompactLine(autoCompactThreshold, autoCompactThresholdSource),
|
|
453
|
+
'',
|
|
454
|
+
formatSection(
|
|
455
|
+
'System prompt (active every turn)',
|
|
456
|
+
systemTokens,
|
|
457
|
+
systemRefs.map(formatContextReferenceLine),
|
|
458
|
+
),
|
|
459
|
+
'',
|
|
460
|
+
convSection,
|
|
461
|
+
'',
|
|
462
|
+
formatSection('Manually added', manualTokens, manualRefs.map(formatContextReferenceLine)),
|
|
463
|
+
'',
|
|
464
|
+
formatSection(
|
|
465
|
+
'Prompt references (@-syntax)',
|
|
466
|
+
promptRefTokens,
|
|
467
|
+
promptRefs.map(formatContextReferenceLine),
|
|
468
|
+
),
|
|
469
|
+
].join('\n');
|
|
470
|
+
|
|
471
|
+
return {
|
|
472
|
+
success: true,
|
|
473
|
+
message,
|
|
474
|
+
data: {
|
|
475
|
+
references,
|
|
476
|
+
history: { turnCount: analysis.turnCount, toolResults: analysis.toolResults },
|
|
477
|
+
},
|
|
478
|
+
};
|
|
479
|
+
}
|
|
@@ -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
|
}
|