@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robota-sdk/agent-command",
3
- "version": "3.0.0-beta.69",
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.69",
28
- "@robota-sdk/agent-framework": "3.0.0-beta.69"
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",
@@ -27,6 +27,8 @@ function createSessionRuntime(): ICommandSessionRuntime {
27
27
  getMessageCount: () => 0,
28
28
  getSessionAllowedTools: () => [],
29
29
  getAutoCompactThreshold: () => false,
30
+ getFullHistory: () => [],
31
+ getHistory: () => [],
30
32
  };
31
33
  }
32
34
 
@@ -35,6 +35,8 @@ function createRuntime(beforeCount = 10, afterCount = 3): ICommandSessionRuntime
35
35
  getMessageCount,
36
36
  getSessionAllowedTools: () => [],
37
37
  getAutoCompactThreshold: () => 0.835,
38
+ getFullHistory: () => [],
39
+ getHistory: () => [],
38
40
  };
39
41
  }
40
42
 
@@ -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(state: { threshold: number | false }): ICommandSessionRuntime {
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] 42 B');
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] 200 B',
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('Context reference added: AGENTS.md [manual, active] 42 B.');
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('Context reference removed: AGENTS.md [manual, active] 42 B.');
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] 1,024 B');
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 no context references message when only system refs are absent', async () => {
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).toBe('No context references.');
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(listCommandContextReferences(context)),
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: listCommandContextReferences(context),
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 formatContextReferenceList(listCommandContextReferences(context));
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
- function formatContextReferenceList(references: readonly IContextReferenceItem[]): ICommandResult {
282
- if (references.length === 0) {
283
- return { success: true, message: 'No context references.', data: { references } };
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
- return {
287
- success: true,
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
- `${reference.byteLength.toLocaleString()} B`,
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
  }
@@ -19,6 +19,8 @@ function createCommandSessionRuntime(): ICommandSessionRuntime {
19
19
  getMessageCount: () => 0,
20
20
  getSessionAllowedTools: () => [],
21
21
  getAutoCompactThreshold: () => false,
22
+ getFullHistory: () => [],
23
+ getHistory: () => [],
22
24
  };
23
25
  }
24
26
 
@@ -22,6 +22,8 @@ function createCommandSessionRuntime(): ICommandSessionRuntime {
22
22
  getMessageCount: () => 0,
23
23
  getSessionAllowedTools: () => [],
24
24
  getAutoCompactThreshold: () => false,
25
+ getFullHistory: () => [],
26
+ getHistory: () => [],
25
27
  };
26
28
  }
27
29
 
@@ -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
  }
@@ -40,6 +40,8 @@ function createCommandSessionRuntime(): ICommandSessionRuntime {
40
40
  getMessageCount: () => 0,
41
41
  getSessionAllowedTools: () => [],
42
42
  getAutoCompactThreshold: () => false,
43
+ getFullHistory: () => [],
44
+ getHistory: () => [],
43
45
  };
44
46
  }
45
47
 
@@ -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
  }
@@ -19,6 +19,8 @@ function createRuntime(): ICommandSessionRuntime {
19
19
  getMessageCount: () => 5,
20
20
  getSessionAllowedTools: () => [],
21
21
  getAutoCompactThreshold: () => false,
22
+ getFullHistory: () => [],
23
+ getHistory: () => [],
22
24
  };
23
25
  }
24
26
 
@@ -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
  }