@vellumai/assistant 0.4.19 → 0.4.21

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.
@@ -15,81 +15,94 @@
15
15
  * - session-usage.ts — recordUsage
16
16
  */
17
17
 
18
- import { AgentLoop, type ResolvedSystemPrompt } from '../agent/loop.js';
19
- import type { TurnChannelContext, TurnInterfaceContext } from '../channels/types.js';
20
- import { getConfig } from '../config/loader.js';
21
- import { buildSystemPrompt } from '../config/system-prompt.js';
22
- import { ContextWindowManager } from '../context/window-manager.js';
23
- import { EventBus } from '../events/bus.js';
24
- import type { AssistantDomainEvents } from '../events/domain-events.js';
25
- import { createToolAuditListener } from '../events/tool-audit-listener.js';
26
- import { createToolDomainEventPublisher } from '../events/tool-domain-event-publisher.js';
27
- import { registerToolMetricsLoggingListener } from '../events/tool-metrics-listener.js';
28
- import { registerToolNotificationListener } from '../events/tool-notification-listener.js';
29
- import { registerToolProfilingListener,ToolProfiler } from '../events/tool-profiling-listener.js';
30
- import { registerToolTraceListener } from '../events/tool-trace-listener.js';
31
- import { getHookManager } from '../hooks/manager.js';
32
- import { PermissionPrompter } from '../permissions/prompter.js';
33
- import { SecretPrompter } from '../permissions/secret-prompter.js';
34
- import type { UserDecision } from '../permissions/types.js';
35
- import type { Message } from '../providers/types.js';
36
- import type { Provider } from '../providers/types.js';
37
- import type { AuthContext } from '../runtime/auth/types.js';
38
- import * as approvalOverrides from '../runtime/session-approval-overrides.js';
39
- import { ToolExecutor } from '../tools/executor.js';
40
- import type { AssistantAttachmentDraft } from './assistant-attachments.js';
41
- import type { AssistantActivityState, ConfirmationStateChanged } from './ipc-contract/messages.js';
42
- import type { ServerMessage, SurfaceData,SurfaceType, UsageStats, UserMessageAttachment } from './ipc-protocol.js';
18
+ import { AgentLoop, type ResolvedSystemPrompt } from "../agent/loop.js";
19
+ import type {
20
+ TurnChannelContext,
21
+ TurnInterfaceContext,
22
+ } from "../channels/types.js";
23
+ import { getConfig } from "../config/loader.js";
24
+ import { buildSystemPrompt } from "../config/system-prompt.js";
25
+ import { ContextWindowManager } from "../context/window-manager.js";
26
+ import { EventBus } from "../events/bus.js";
27
+ import type { AssistantDomainEvents } from "../events/domain-events.js";
28
+ import { createToolAuditListener } from "../events/tool-audit-listener.js";
29
+ import { createToolDomainEventPublisher } from "../events/tool-domain-event-publisher.js";
30
+ import { registerToolMetricsLoggingListener } from "../events/tool-metrics-listener.js";
31
+ import { registerToolNotificationListener } from "../events/tool-notification-listener.js";
43
32
  import {
44
- classifyResponseTierAsync,
45
- classifyResponseTierDetailed,
46
- resolveWithHint,
47
- type SessionTierHint,
48
- tierMaxTokens,
49
- tierModel,
50
- } from './response-tier.js';
51
- import { runAgentLoopImpl } from './session-agent-loop.js';
52
- import { ConflictGate } from './session-conflict-gate.js';
33
+ registerToolProfilingListener,
34
+ ToolProfiler,
35
+ } from "../events/tool-profiling-listener.js";
36
+ import { registerToolTraceListener } from "../events/tool-trace-listener.js";
37
+ import { getHookManager } from "../hooks/manager.js";
38
+ import { PermissionPrompter } from "../permissions/prompter.js";
39
+ import { SecretPrompter } from "../permissions/secret-prompter.js";
40
+ import type { UserDecision } from "../permissions/types.js";
41
+ import type { Message } from "../providers/types.js";
42
+ import type { Provider } from "../providers/types.js";
43
+ import type { AuthContext } from "../runtime/auth/types.js";
44
+ import * as approvalOverrides from "../runtime/session-approval-overrides.js";
45
+ import { ToolExecutor } from "../tools/executor.js";
46
+ import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
47
+ import type {
48
+ AssistantActivityState,
49
+ ConfirmationStateChanged,
50
+ } from "./ipc-contract/messages.js";
51
+ import type {
52
+ ServerMessage,
53
+ SurfaceData,
54
+ SurfaceType,
55
+ UsageStats,
56
+ UserMessageAttachment,
57
+ } from "./ipc-protocol.js";
58
+ import { runAgentLoopImpl } from "./session-agent-loop.js";
59
+ import { ConflictGate } from "./session-conflict-gate.js";
53
60
  import {
54
61
  type HistorySessionContext,
55
62
  regenerate as regenerateImpl,
56
63
  undo as undoImpl,
57
- } from './session-history.js';
64
+ } from "./session-history.js";
58
65
  import {
59
66
  abortSession,
60
67
  disposeSession,
61
68
  loadFromDb as loadFromDbImpl,
62
- } from './session-lifecycle.js';
69
+ } from "./session-lifecycle.js";
63
70
  import {
64
71
  enqueueMessage as enqueueMessageImpl,
65
72
  persistUserMessage as persistUserMessageImpl,
66
73
  redirectToSecurePrompt as redirectToSecurePromptImpl,
67
74
  type RedirectToSecurePromptOptions,
68
- } from './session-messaging.js';
75
+ } from "./session-messaging.js";
69
76
  // Extracted modules
70
- import { registerSessionNotifiers } from './session-notifiers.js';
77
+ import { registerSessionNotifiers } from "./session-notifiers.js";
71
78
  import {
72
79
  drainQueue as drainQueueImpl,
73
80
  processMessage as processMessageImpl,
74
81
  type ProcessSessionContext,
75
- } from './session-process.js';
76
- import type { QueueDrainReason, QueueMetrics } from './session-queue-manager.js';
77
- import { MessageQueue } from './session-queue-manager.js';
78
- import type { ChannelCapabilities, GuardianRuntimeContext } from './session-runtime-assembly.js';
79
- import type { SkillProjectionCache } from './session-skill-tools.js';
82
+ } from "./session-process.js";
83
+ import type {
84
+ QueueDrainReason,
85
+ QueueMetrics,
86
+ } from "./session-queue-manager.js";
87
+ import { MessageQueue } from "./session-queue-manager.js";
88
+ import type {
89
+ ChannelCapabilities,
90
+ GuardianRuntimeContext,
91
+ } from "./session-runtime-assembly.js";
92
+ import type { SkillProjectionCache } from "./session-skill-tools.js";
80
93
  import {
81
94
  createSurfaceMutex,
82
95
  handleSurfaceAction as handleSurfaceActionImpl,
83
96
  handleSurfaceUndo as handleSurfaceUndoImpl,
84
- } from './session-surfaces.js';
97
+ } from "./session-surfaces.js";
85
98
  import {
86
99
  buildToolDefinitions,
87
100
  createResolveToolsCallback,
88
101
  createToolExecutor,
89
102
  type ToolSetupContext,
90
- } from './session-tool-setup.js';
91
- import { refreshWorkspaceTopLevelContextIfNeeded as refreshWorkspaceImpl } from './session-workspace.js';
92
- import { TraceEmitter } from './trace-emitter.js';
103
+ } from "./session-tool-setup.js";
104
+ import { refreshWorkspaceTopLevelContextIfNeeded as refreshWorkspaceImpl } from "./session-workspace.js";
105
+ import { TraceEmitter } from "./trace-emitter.js";
93
106
 
94
107
  export interface SessionMemoryPolicy {
95
108
  scopeId: string;
@@ -97,14 +110,19 @@ export interface SessionMemoryPolicy {
97
110
  strictSideEffects: boolean;
98
111
  }
99
112
 
100
- export const DEFAULT_MEMORY_POLICY: Readonly<SessionMemoryPolicy> = Object.freeze({
101
- scopeId: 'default',
102
- includeDefaultFallback: false,
103
- strictSideEffects: false,
104
- });
113
+ export const DEFAULT_MEMORY_POLICY: Readonly<SessionMemoryPolicy> =
114
+ Object.freeze({
115
+ scopeId: "default",
116
+ includeDefaultFallback: false,
117
+ strictSideEffects: false,
118
+ });
105
119
 
106
- export { findLastUndoableUserMessageIndex } from './session-history.js';
107
- export { MAX_QUEUE_DEPTH, type QueueDrainReason, type QueuePolicy } from './session-queue-manager.js';
120
+ export { findLastUndoableUserMessageIndex } from "./session-history.js";
121
+ export {
122
+ MAX_QUEUE_DEPTH,
123
+ type QueueDrainReason,
124
+ type QueuePolicy,
125
+ } from "./session-queue-manager.js";
108
126
 
109
127
  export class Session {
110
128
  public readonly conversationId: string;
@@ -128,7 +146,11 @@ export class Session {
128
146
  /** @internal */ coreToolNames: Set<string>;
129
147
  /** @internal */ readonly skillProjectionState = new Map<string, string>();
130
148
  /** @internal */ readonly skillProjectionCache: SkillProjectionCache = {};
131
- /** @internal */ usageStats: UsageStats = { inputTokens: 0, outputTokens: 0, estimatedCost: 0 };
149
+ /** @internal */ usageStats: UsageStats = {
150
+ inputTokens: 0,
151
+ outputTokens: 0,
152
+ estimatedCost: 0,
153
+ };
132
154
  /** @internal */ readonly systemPrompt: string;
133
155
  /** @internal */ contextWindowManager: ContextWindowManager;
134
156
  /** @internal */ contextCompactedMessageCount = 0;
@@ -145,18 +167,41 @@ export class Session {
145
167
  /** @internal */ channelCapabilities?: ChannelCapabilities;
146
168
  /** @internal */ guardianContext?: GuardianRuntimeContext;
147
169
  /** @internal */ authContext?: AuthContext;
148
- /** @internal */ loadedHistoryTrustClass?: GuardianRuntimeContext['trustClass'];
170
+ /** @internal */ loadedHistoryTrustClass?: GuardianRuntimeContext["trustClass"];
149
171
  /** @internal */ voiceCallControlPrompt?: string;
150
172
  /** @internal */ assistantId?: string;
151
- /** @internal */ commandIntent?: { type: string; payload?: string; languageCode?: string };
173
+ /** @internal */ commandIntent?: {
174
+ type: string;
175
+ payload?: string;
176
+ languageCode?: string;
177
+ };
152
178
  /** @internal */ surfaceActionRequestIds = new Set<string>();
153
- /** @internal */ pendingSurfaceActions = new Map<string, { surfaceType: SurfaceType }>();
154
- /** @internal */ lastSurfaceAction = new Map<string, { actionId: string; data?: Record<string, unknown> }>();
155
- /** @internal */ surfaceState = new Map<string, { surfaceType: SurfaceType; data: SurfaceData; title?: string }>();
179
+ /** @internal */ pendingSurfaceActions = new Map<
180
+ string,
181
+ { surfaceType: SurfaceType }
182
+ >();
183
+ /** @internal */ lastSurfaceAction = new Map<
184
+ string,
185
+ { actionId: string; data?: Record<string, unknown> }
186
+ >();
187
+ /** @internal */ surfaceState = new Map<
188
+ string,
189
+ { surfaceType: SurfaceType; data: SurfaceData; title?: string }
190
+ >();
156
191
  /** @internal */ surfaceUndoStacks = new Map<string, string[]>();
157
192
  /** @internal */ withSurface = createSurfaceMutex();
158
- /** @internal */ currentTurnSurfaces: Array<{ surfaceId: string; surfaceType: SurfaceType; title?: string; data: SurfaceData; actions?: Array<{ id: string; label: string; style?: string }>; display?: string }> = [];
159
- /** @internal */ onEscalateToComputerUse?: (task: string, sourceSessionId: string) => boolean;
193
+ /** @internal */ currentTurnSurfaces: Array<{
194
+ surfaceId: string;
195
+ surfaceType: SurfaceType;
196
+ title?: string;
197
+ data: SurfaceData;
198
+ actions?: Array<{ id: string; label: string; style?: string }>;
199
+ display?: string;
200
+ }> = [];
201
+ /** @internal */ onEscalateToComputerUse?: (
202
+ task: string,
203
+ sourceSessionId: string,
204
+ ) => boolean;
160
205
  /** @internal */ workspaceTopLevelContext: string | null = null;
161
206
  /** @internal */ workspaceTopLevelDirty = true;
162
207
  public readonly traceEmitter: TraceEmitter;
@@ -166,7 +211,8 @@ export class Session {
166
211
  public lastAssistantAttachments: AssistantAttachmentDraft[] = [];
167
212
  public lastAttachmentWarnings: string[] = [];
168
213
  /** @internal */ currentTurnChannelContext: TurnChannelContext | null = null;
169
- /** @internal */ currentTurnInterfaceContext: TurnInterfaceContext | null = null;
214
+ /** @internal */ currentTurnInterfaceContext: TurnInterfaceContext | null =
215
+ null;
170
216
  /** @internal */ activityVersion = 0;
171
217
  /**
172
218
  * Optional callback invoked whenever a server-authoritative state signal
@@ -193,7 +239,9 @@ export class Session {
193
239
  this.provider = provider;
194
240
  this.workingDir = workingDir;
195
241
  this.sendToClient = sendToClient;
196
- this.memoryPolicy = memoryPolicy ? { ...memoryPolicy } : { ...DEFAULT_MEMORY_POLICY };
242
+ this.memoryPolicy = memoryPolicy
243
+ ? { ...memoryPolicy }
244
+ : { ...DEFAULT_MEMORY_POLICY };
197
245
  this.traceEmitter = new TraceEmitter(conversationId, sendToClient);
198
246
  this.prompter = new PermissionPrompter(sendToClient);
199
247
  this.prompter.setOnStateChanged((requestId, state, source) => {
@@ -206,10 +254,20 @@ export class Session {
206
254
  source,
207
255
  });
208
256
  // Emit activity state transitions for confirmation lifecycle
209
- if (state === 'pending') {
210
- this.emitActivityState('awaiting_confirmation', 'confirmation_requested', 'assistant_turn');
211
- } else if (state === 'timed_out') {
212
- this.emitActivityState('thinking', 'confirmation_resolved', 'assistant_turn', undefined, 'Resuming after timeout');
257
+ if (state === "pending") {
258
+ this.emitActivityState(
259
+ "awaiting_confirmation",
260
+ "confirmation_requested",
261
+ "assistant_turn",
262
+ );
263
+ } else if (state === "timed_out") {
264
+ this.emitActivityState(
265
+ "thinking",
266
+ "confirmation_resolved",
267
+ "assistant_turn",
268
+ undefined,
269
+ "Resuming after timeout",
270
+ );
213
271
  }
214
272
  });
215
273
  this.secretPrompter = new SecretPrompter(sendToClient);
@@ -221,12 +279,18 @@ export class Session {
221
279
  this.executor = new ToolExecutor(this.prompter);
222
280
  this.profiler = new ToolProfiler();
223
281
  registerToolMetricsLoggingListener(this.eventBus);
224
- registerToolNotificationListener(this.eventBus, (msg) => this.sendToClient(msg));
282
+ registerToolNotificationListener(this.eventBus, (msg) =>
283
+ this.sendToClient(msg),
284
+ );
225
285
  registerToolTraceListener(this.eventBus, this.traceEmitter);
226
286
  registerToolProfilingListener(this.eventBus, this.profiler);
227
287
  const auditToolLifecycleEvent = createToolAuditListener();
228
- const publishToolDomainEvent = createToolDomainEventPublisher(this.eventBus);
229
- const handleToolLifecycleEvent = (event: import('../tools/types.js').ToolLifecycleEvent) => {
288
+ const publishToolDomainEvent = createToolDomainEventPublisher(
289
+ this.eventBus,
290
+ );
291
+ const handleToolLifecycleEvent = (
292
+ event: import("../tools/types.js").ToolLifecycleEvent,
293
+ ) => {
230
294
  auditToolLifecycleEvent(event);
231
295
  return publishToolDomainEvent(event);
232
296
  };
@@ -247,105 +311,31 @@ export class Session {
247
311
  const resolveTools = createResolveToolsCallback(toolDefs, this);
248
312
 
249
313
  const configuredMaxTokens = maxTokens;
250
- // When a systemPromptOverride was provided, skip tier-based prompt
251
- // rebuilding and use the override as-is only scale maxTokens and model.
314
+ // When a systemPromptOverride was provided, use it as-is; otherwise
315
+ // rebuild the full prompt each turn (picks up any workspace file changes).
252
316
  const hasSystemPromptOverride = systemPrompt !== buildSystemPrompt();
253
317
 
254
- // Known runtime-injected XML context block prefixes. Using an explicit
255
- // list avoids false-positives on user messages that start with HTML/XML.
256
- const INJECTED_PREFIXES = [
257
- '<channel_capabilities>',
258
- '<channel_command_context>',
259
- '<channel_turn_context>',
260
- '<temporal_context>',
261
- '<guardian_context>',
262
- '<inbound_actor_context>',
263
- '<voice_call_control>',
264
- '<workspace_top_level>',
265
- '<active_workspace>',
266
- '<active_dynamic_page>',
267
- '<dynamic-profile-context>',
268
- '<memory_recall',
269
- '<memory source=',
270
- '<memory',
271
- '<system_notice>',
272
- '<interface_turn_context>',
273
- ];
274
-
275
- // Track the last user-message tier so tool-use continuation turns
276
- // (where user text is empty — only tool_result blocks) inherit it
277
- // instead of falling to 'low'.
278
- let lastUserMessageTier: import('./response-tier.js').ResponseTier = 'high';
279
- let sessionTierHint: SessionTierHint | null = null;
280
- const recentUserTexts: string[] = []; // circular buffer, max 3
281
- const MAX_RECENT_TEXTS = 3;
282
-
283
- const resolveSystemPromptCallback = (history: import('../providers/types.js').Message[]): ResolvedSystemPrompt => {
284
- // Extract last user message text, ignoring runtime-injected context blocks
285
- const lastUserMsg = [...history].reverse().find((m) => m.role === 'user');
286
- let userText = '';
287
- let isToolResultOnly = false;
288
- if (lastUserMsg) {
289
- const _hasToolResult = lastUserMsg.content.some((b) => b.type === 'tool_result');
290
- for (const block of lastUserMsg.content) {
291
- if (block.type === 'text') {
292
- const trimmed = block.text.trimStart();
293
- if (!INJECTED_PREFIXES.some((p) => trimmed.startsWith(p))) {
294
- userText += block.text;
295
- }
296
- }
297
- }
298
- // Inherit previous tier when there's no real user text — either
299
- // tool_result-only messages or system nudges where all text was
300
- // filtered out as injected context.
301
- isToolResultOnly = userText.trim().length === 0;
302
- }
303
-
304
- let tier: import('./response-tier.js').ResponseTier;
305
-
306
- if (isToolResultOnly) {
307
- // Tool-use continuation: inherit previous tier
308
- tier = lastUserMessageTier;
309
- } else {
310
- const classification = classifyResponseTierDetailed(userText, this.turnCount);
311
- tier = resolveWithHint(classification, sessionTierHint, this.turnCount);
312
- lastUserMessageTier = tier;
313
-
314
- // Update recent user texts buffer
315
- const trimmedText = userText.trim();
316
- if (trimmedText) {
317
- if (recentUserTexts.length >= MAX_RECENT_TEXTS) {
318
- recentUserTexts.shift();
319
- }
320
- recentUserTexts.push(trimmedText);
321
- }
322
-
323
- // Fire background Haiku classification when confidence is low
324
- if (classification.confidence === 'low') {
325
- void classifyResponseTierAsync([...recentUserTexts]).then((asyncTier) => {
326
- if (asyncTier) {
327
- sessionTierHint = {
328
- tier: asyncTier,
329
- turn: this.turnCount,
330
- timestamp: Date.now(),
331
- };
332
- }
333
- });
334
- }
335
- }
336
-
337
- const model = tierModel(tier, provider.name);
338
- return {
339
- systemPrompt: hasSystemPromptOverride ? systemPrompt : buildSystemPrompt(tier),
340
- maxTokens: tierMaxTokens(tier, configuredMaxTokens),
341
- model,
318
+ const resolveSystemPromptCallback = (
319
+ _history: import("../providers/types.js").Message[],
320
+ ): ResolvedSystemPrompt => {
321
+ const resolved = {
322
+ systemPrompt: hasSystemPromptOverride
323
+ ? systemPrompt
324
+ : buildSystemPrompt(),
325
+ maxTokens: configuredMaxTokens,
342
326
  };
327
+ return resolved;
343
328
  };
344
329
 
345
330
  this.agentLoop = new AgentLoop(
346
331
  provider,
347
332
  systemPrompt,
348
- { maxTokens, maxInputTokens: config.contextWindow.maxInputTokens, thinking: config.thinking, maxToolUseTurns: config.maxToolUseTurns },
333
+ {
334
+ maxTokens,
335
+ maxInputTokens: config.contextWindow.maxInputTokens,
336
+ thinking: config.thinking,
337
+ maxToolUseTurns: config.maxToolUseTurns,
338
+ },
349
339
  toolDefs.length > 0 ? toolDefs : undefined,
350
340
  toolDefs.length > 0 ? toolExecutor : undefined,
351
341
  resolveTools,
@@ -357,7 +347,7 @@ export class Session {
357
347
  config.contextWindow,
358
348
  );
359
349
 
360
- void getHookManager().trigger('session-start', {
350
+ void getHookManager().trigger("session-start", {
361
351
  sessionId: this.conversationId,
362
352
  workingDir: this.workingDir,
363
353
  });
@@ -375,7 +365,10 @@ export class Session {
375
365
  await this.loadFromDb();
376
366
  }
377
367
 
378
- updateClient(sendToClient: (msg: ServerMessage) => void, hasNoClient = false): void {
368
+ updateClient(
369
+ sendToClient: (msg: ServerMessage) => void,
370
+ hasNoClient = false,
371
+ ): void {
379
372
  this.sendToClient = sendToClient;
380
373
  this.hasNoClient = hasNoClient;
381
374
  this.prompter.updateSender(sendToClient);
@@ -403,7 +396,9 @@ export class Session {
403
396
  this.sandboxOverride = enabled;
404
397
  }
405
398
 
406
- setEscalationHandler(handler: (task: string, sourceSessionId: string) => boolean): void {
399
+ setEscalationHandler(
400
+ handler: (task: string, sourceSessionId: string) => boolean,
401
+ ): void {
407
402
  this.onEscalateToComputerUse = handler;
408
403
  }
409
404
 
@@ -437,8 +432,16 @@ export class Session {
437
432
 
438
433
  // ── Messaging ────────────────────────────────────────────────────
439
434
 
440
- redirectToSecurePrompt(detectedTypes: string[], options?: RedirectToSecurePromptOptions): void {
441
- redirectToSecurePromptImpl(this.conversationId, this.secretPrompter, detectedTypes, options);
435
+ redirectToSecurePrompt(
436
+ detectedTypes: string[],
437
+ options?: RedirectToSecurePromptOptions,
438
+ ): void {
439
+ redirectToSecurePromptImpl(
440
+ this.conversationId,
441
+ this.secretPrompter,
442
+ detectedTypes,
443
+ options,
444
+ );
442
445
  }
443
446
 
444
447
  enqueueMessage(
@@ -452,7 +455,18 @@ export class Session {
452
455
  options?: { isInteractive?: boolean },
453
456
  displayContent?: string,
454
457
  ): { queued: boolean; rejected?: boolean; requestId: string } {
455
- return enqueueMessageImpl(this, content, attachments, onEvent, requestId, activeSurfaceId, currentPage, metadata, options, displayContent);
458
+ return enqueueMessageImpl(
459
+ this,
460
+ content,
461
+ attachments,
462
+ onEvent,
463
+ requestId,
464
+ activeSurfaceId,
465
+ currentPage,
466
+ metadata,
467
+ options,
468
+ displayContent,
469
+ );
456
470
  }
457
471
 
458
472
  getQueueDepth(): number {
@@ -498,7 +512,7 @@ export class Session {
498
512
  selectedScope?: string,
499
513
  decisionContext?: string,
500
514
  emissionContext?: {
501
- source?: ConfirmationStateChanged['source'];
515
+ source?: ConfirmationStateChanged["source"];
502
516
  causedByRequestId?: string;
503
517
  decisionText?: string;
504
518
  },
@@ -525,42 +539,62 @@ export class Session {
525
539
  // Emit authoritative confirmation state and activity transition centrally
526
540
  // so ALL callers (IPC handlers, /v1/confirm, channel bridges) get
527
541
  // consistent events without duplicating emission logic.
528
- const resolvedState = (decision === 'deny' || decision === 'always_deny')
529
- ? 'denied' as const
530
- : 'approved' as const;
542
+ const resolvedState =
543
+ decision === "deny" || decision === "always_deny"
544
+ ? ("denied" as const)
545
+ : ("approved" as const);
531
546
  this.emitConfirmationStateChanged({
532
547
  sessionId: this.conversationId,
533
548
  requestId,
534
549
  state: resolvedState,
535
- source: emissionContext?.source ?? 'button',
536
- ...(emissionContext?.causedByRequestId ? { causedByRequestId: emissionContext.causedByRequestId } : {}),
537
- ...(emissionContext?.decisionText ? { decisionText: emissionContext.decisionText } : {}),
550
+ source: emissionContext?.source ?? "button",
551
+ ...(emissionContext?.causedByRequestId
552
+ ? { causedByRequestId: emissionContext.causedByRequestId }
553
+ : {}),
554
+ ...(emissionContext?.decisionText
555
+ ? { decisionText: emissionContext.decisionText }
556
+ : {}),
538
557
  });
539
- this.emitActivityState('thinking', 'confirmation_resolved', 'assistant_turn', undefined, 'Resuming after approval');
558
+ this.emitActivityState(
559
+ "thinking",
560
+ "confirmation_resolved",
561
+ "assistant_turn",
562
+ undefined,
563
+ "Resuming after approval",
564
+ );
540
565
  }
541
566
 
542
- handleSecretResponse(requestId: string, value?: string, delivery?: 'store' | 'transient_send'): void {
567
+ handleSecretResponse(
568
+ requestId: string,
569
+ value?: string,
570
+ delivery?: "store" | "transient_send",
571
+ ): void {
543
572
  this.secretPrompter.resolveSecret(requestId, value, delivery);
544
573
  }
545
574
 
546
575
  // ── Server-authoritative state signals ─────────────────────────────
547
576
 
548
- emitConfirmationStateChanged(params: Omit<ConfirmationStateChanged, 'type'>): void {
549
- const msg: ServerMessage = { type: 'confirmation_state_changed', ...params } as ServerMessage;
577
+ emitConfirmationStateChanged(
578
+ params: Omit<ConfirmationStateChanged, "type">,
579
+ ): void {
580
+ const msg: ServerMessage = {
581
+ type: "confirmation_state_changed",
582
+ ...params,
583
+ } as ServerMessage;
550
584
  this.sendToClient(msg);
551
585
  this.onStateSignal?.(msg);
552
586
  }
553
587
 
554
588
  emitActivityState(
555
- phase: AssistantActivityState['phase'],
556
- reason: AssistantActivityState['reason'],
557
- anchor: AssistantActivityState['anchor'] = 'assistant_turn',
589
+ phase: AssistantActivityState["phase"],
590
+ reason: AssistantActivityState["reason"],
591
+ anchor: AssistantActivityState["anchor"] = "assistant_turn",
558
592
  requestId?: string,
559
593
  statusText?: string,
560
594
  ): void {
561
595
  this.activityVersion++;
562
596
  const msg: ServerMessage = {
563
- type: 'assistant_activity_state',
597
+ type: "assistant_activity_state",
564
598
  sessionId: this.conversationId,
565
599
  activityVersion: this.activityVersion,
566
600
  phase,
@@ -597,7 +631,9 @@ export class Session {
597
631
  this.assistantId = assistantId ?? undefined;
598
632
  }
599
633
 
600
- setCommandIntent(intent: { type: string; payload?: string; languageCode?: string } | null): void {
634
+ setCommandIntent(
635
+ intent: { type: string; payload?: string; languageCode?: string } | null,
636
+ ): void {
601
637
  this.commandIntent = intent ?? undefined;
602
638
  }
603
639
 
@@ -631,7 +667,14 @@ export class Session {
631
667
  if (!this.processing) {
632
668
  await this.ensureActorScopedHistory();
633
669
  }
634
- return persistUserMessageImpl(this, content, attachments, requestId, metadata, displayContent);
670
+ return persistUserMessageImpl(
671
+ this,
672
+ content,
673
+ attachments,
674
+ requestId,
675
+ metadata,
676
+ displayContent,
677
+ );
635
678
  }
636
679
 
637
680
  // ── Agent Loop ───────────────────────────────────────────────────
@@ -640,13 +683,17 @@ export class Session {
640
683
  content: string,
641
684
  userMessageId: string,
642
685
  onEvent: (msg: ServerMessage) => void,
643
- options?: { skipPreMessageRollback?: boolean; isInteractive?: boolean; isUserMessage?: boolean; titleText?: string },
686
+ options?: {
687
+ skipPreMessageRollback?: boolean;
688
+ isInteractive?: boolean;
689
+ isUserMessage?: boolean;
690
+ titleText?: string;
691
+ },
644
692
  ): Promise<void> {
645
693
  return runAgentLoopImpl(this, content, userMessageId, onEvent, options);
646
694
  }
647
695
 
648
-
649
- drainQueue(reason: QueueDrainReason = 'loop_complete'): Promise<void> {
696
+ drainQueue(reason: QueueDrainReason = "loop_complete"): Promise<void> {
650
697
  return drainQueueImpl(this as ProcessSessionContext, reason);
651
698
  }
652
699
 
@@ -660,7 +707,17 @@ export class Session {
660
707
  options?: { isInteractive?: boolean },
661
708
  displayContent?: string,
662
709
  ): Promise<string> {
663
- return processMessageImpl(this as ProcessSessionContext, content, attachments, onEvent, requestId, activeSurfaceId, currentPage, options, displayContent);
710
+ return processMessageImpl(
711
+ this as ProcessSessionContext,
712
+ content,
713
+ attachments,
714
+ onEvent,
715
+ requestId,
716
+ activeSurfaceId,
717
+ currentPage,
718
+ options,
719
+ displayContent,
720
+ );
664
721
  }
665
722
 
666
723
  // ── History ──────────────────────────────────────────────────────
@@ -673,13 +730,20 @@ export class Session {
673
730
  return undoImpl(this as HistorySessionContext);
674
731
  }
675
732
 
676
- async regenerate(onEvent: (msg: ServerMessage) => void, requestId?: string): Promise<void> {
733
+ async regenerate(
734
+ onEvent: (msg: ServerMessage) => void,
735
+ requestId?: string,
736
+ ): Promise<void> {
677
737
  return regenerateImpl(this as HistorySessionContext, onEvent, requestId);
678
738
  }
679
739
 
680
740
  // ── Surfaces ─────────────────────────────────────────────────────
681
741
 
682
- handleSurfaceAction(surfaceId: string, actionId: string, data?: Record<string, unknown>): void {
742
+ handleSurfaceAction(
743
+ surfaceId: string,
744
+ actionId: string,
745
+ data?: Record<string, unknown>,
746
+ ): void {
683
747
  handleSurfaceActionImpl(this, surfaceId, actionId, data);
684
748
  }
685
749