@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/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.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.69",
28
- "@robota-sdk/agent-framework": "3.0.0-beta.69"
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",
@@ -27,6 +27,7 @@ function createSessionRuntime(): ICommandSessionRuntime {
27
27
  getMessageCount: () => 0,
28
28
  getSessionAllowedTools: () => [],
29
29
  getAutoCompactThreshold: () => false,
30
+ getFullHistory: () => [],
30
31
  };
31
32
  }
32
33
 
@@ -35,6 +35,7 @@ function createRuntime(beforeCount = 10, afterCount = 3): ICommandSessionRuntime
35
35
  getMessageCount,
36
36
  getSessionAllowedTools: () => [],
37
37
  getAutoCompactThreshold: () => 0.835,
38
+ getFullHistory: () => [],
38
39
  };
39
40
  }
40
41
 
@@ -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,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] 42 B');
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] 200 B',
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('Context reference added: AGENTS.md [manual, active] 42 B.');
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('Context reference removed: AGENTS.md [manual, active] 42 B.');
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] 1,024 B');
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 no context references message when only system refs are absent', async () => {
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).toBe('No context references.');
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(listCommandContextReferences(context)),
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: 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,197 @@ 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
+ 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
  }
@@ -19,6 +19,7 @@ function createCommandSessionRuntime(): ICommandSessionRuntime {
19
19
  getMessageCount: () => 0,
20
20
  getSessionAllowedTools: () => [],
21
21
  getAutoCompactThreshold: () => false,
22
+ getFullHistory: () => [],
22
23
  };
23
24
  }
24
25
 
@@ -22,6 +22,7 @@ function createCommandSessionRuntime(): ICommandSessionRuntime {
22
22
  getMessageCount: () => 0,
23
23
  getSessionAllowedTools: () => [],
24
24
  getAutoCompactThreshold: () => false,
25
+ getFullHistory: () => [],
25
26
  };
26
27
  }
27
28
 
@@ -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,7 @@ function createCommandSessionRuntime(): ICommandSessionRuntime {
40
40
  getMessageCount: () => 0,
41
41
  getSessionAllowedTools: () => [],
42
42
  getAutoCompactThreshold: () => false,
43
+ getFullHistory: () => [],
43
44
  };
44
45
  }
45
46
 
@@ -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,7 @@ function createRuntime(): ICommandSessionRuntime {
19
19
  getMessageCount: () => 5,
20
20
  getSessionAllowedTools: () => [],
21
21
  getAutoCompactThreshold: () => false,
22
+ getFullHistory: () => [],
22
23
  };
23
24
  }
24
25
 
@@ -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
  }