@vellumai/assistant 0.4.3 → 0.4.4

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.
Files changed (183) hide show
  1. package/.env.example +3 -0
  2. package/ARCHITECTURE.md +40 -3
  3. package/README.md +43 -35
  4. package/package.json +1 -1
  5. package/scripts/ipc/generate-swift.ts +1 -0
  6. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +58 -120
  7. package/src/__tests__/actor-token-service.test.ts +1099 -0
  8. package/src/__tests__/agent-loop.test.ts +51 -0
  9. package/src/__tests__/approval-routes-http.test.ts +2 -0
  10. package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -5
  11. package/src/__tests__/assistant-id-boundary-guard.test.ts +125 -0
  12. package/src/__tests__/call-controller.test.ts +49 -0
  13. package/src/__tests__/call-pointer-message-composer.test.ts +171 -0
  14. package/src/__tests__/call-pointer-messages.test.ts +93 -3
  15. package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +42 -0
  16. package/src/__tests__/callback-handoff-copy.test.ts +186 -0
  17. package/src/__tests__/channel-approval-routes.test.ts +133 -12
  18. package/src/__tests__/channel-guardian.test.ts +0 -87
  19. package/src/__tests__/channel-readiness-service.test.ts +10 -16
  20. package/src/__tests__/checker.test.ts +33 -12
  21. package/src/__tests__/config-schema.test.ts +4 -0
  22. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +410 -0
  23. package/src/__tests__/conversation-routes-guardian-reply.test.ts +256 -0
  24. package/src/__tests__/conversation-routes.test.ts +12 -3
  25. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  26. package/src/__tests__/daemon-server-session-init.test.ts +4 -0
  27. package/src/__tests__/guardian-actions-endpoint.test.ts +19 -14
  28. package/src/__tests__/guardian-dispatch.test.ts +8 -0
  29. package/src/__tests__/guardian-outbound-http.test.ts +4 -4
  30. package/src/__tests__/guardian-question-mode.test.ts +200 -0
  31. package/src/__tests__/guardian-routing-invariants.test.ts +178 -0
  32. package/src/__tests__/guardian-routing-state.test.ts +525 -0
  33. package/src/__tests__/handle-user-message-secret-resume.test.ts +2 -0
  34. package/src/__tests__/handlers-telegram-config.test.ts +0 -83
  35. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +55 -0
  36. package/src/__tests__/headless-browser-navigate.test.ts +2 -0
  37. package/src/__tests__/ipc-snapshot.test.ts +18 -51
  38. package/src/__tests__/non-member-access-request.test.ts +131 -8
  39. package/src/__tests__/notification-decision-fallback.test.ts +129 -4
  40. package/src/__tests__/notification-decision-strategy.test.ts +62 -2
  41. package/src/__tests__/notification-guardian-path.test.ts +3 -0
  42. package/src/__tests__/recording-intent-handler.test.ts +1 -0
  43. package/src/__tests__/relay-server.test.ts +841 -39
  44. package/src/__tests__/send-endpoint-busy.test.ts +5 -0
  45. package/src/__tests__/session-agent-loop.test.ts +1 -0
  46. package/src/__tests__/session-confirmation-signals.test.ts +523 -0
  47. package/src/__tests__/session-init.benchmark.test.ts +0 -1
  48. package/src/__tests__/session-surfaces-task-progress.test.ts +1 -1
  49. package/src/__tests__/session-tool-setup-app-refresh.test.ts +81 -2
  50. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -1
  51. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -1
  52. package/src/__tests__/tool-executor.test.ts +21 -2
  53. package/src/__tests__/tool-grant-request-escalation.test.ts +333 -27
  54. package/src/__tests__/trusted-contact-approval-notifier.test.ts +678 -0
  55. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1064 -0
  56. package/src/__tests__/twilio-config.test.ts +2 -13
  57. package/src/agent/loop.ts +1 -1
  58. package/src/approvals/guardian-decision-primitive.ts +10 -2
  59. package/src/approvals/guardian-request-resolvers.ts +128 -9
  60. package/src/calls/call-constants.ts +21 -0
  61. package/src/calls/call-controller.ts +9 -2
  62. package/src/calls/call-domain.ts +28 -7
  63. package/src/calls/call-pointer-message-composer.ts +154 -0
  64. package/src/calls/call-pointer-messages.ts +106 -27
  65. package/src/calls/guardian-dispatch.ts +4 -2
  66. package/src/calls/relay-server.ts +424 -12
  67. package/src/calls/twilio-config.ts +4 -11
  68. package/src/calls/twilio-routes.ts +1 -1
  69. package/src/calls/types.ts +3 -1
  70. package/src/cli.ts +5 -4
  71. package/src/config/bundled-skills/agentmail/SKILL.md +4 -0
  72. package/src/config/bundled-skills/app-builder/SKILL.md +146 -10
  73. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -1
  74. package/src/config/bundled-skills/email-setup/SKILL.md +1 -1
  75. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +105 -81
  76. package/src/config/bundled-skills/messaging/SKILL.md +61 -12
  77. package/src/config/bundled-skills/messaging/TOOLS.json +58 -0
  78. package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +6 -1
  79. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +35 -0
  80. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +52 -0
  81. package/src/config/bundled-skills/phone-calls/SKILL.md +30 -39
  82. package/src/config/bundled-skills/twitter/SKILL.md +3 -3
  83. package/src/config/bundled-skills/vercel-token-setup/SKILL.md +1 -0
  84. package/src/config/calls-schema.ts +24 -0
  85. package/src/config/env.ts +22 -0
  86. package/src/config/feature-flag-registry.json +8 -0
  87. package/src/config/schema.ts +2 -2
  88. package/src/config/skills.ts +11 -0
  89. package/src/config/system-prompt.ts +11 -1
  90. package/src/config/templates/SOUL.md +2 -0
  91. package/src/config/vellum-skills/sms-setup/SKILL.md +71 -82
  92. package/src/config/vellum-skills/trusted-contacts/SKILL.md +10 -9
  93. package/src/config/vellum-skills/twilio-setup/SKILL.md +88 -73
  94. package/src/daemon/call-pointer-generators.ts +59 -0
  95. package/src/daemon/computer-use-session.ts +2 -5
  96. package/src/daemon/handlers/apps.ts +76 -20
  97. package/src/daemon/handlers/config-channels.ts +5 -55
  98. package/src/daemon/handlers/config-inbox.ts +9 -3
  99. package/src/daemon/handlers/config-ingress.ts +28 -3
  100. package/src/daemon/handlers/config-telegram.ts +12 -0
  101. package/src/daemon/handlers/config.ts +2 -6
  102. package/src/daemon/handlers/pairing.ts +2 -0
  103. package/src/daemon/handlers/sessions.ts +48 -3
  104. package/src/daemon/handlers/shared.ts +17 -2
  105. package/src/daemon/ipc-contract/integrations.ts +1 -99
  106. package/src/daemon/ipc-contract/messages.ts +47 -1
  107. package/src/daemon/ipc-contract/notifications.ts +11 -0
  108. package/src/daemon/ipc-contract-inventory.json +2 -4
  109. package/src/daemon/lifecycle.ts +17 -0
  110. package/src/daemon/server.ts +14 -1
  111. package/src/daemon/session-agent-loop-handlers.ts +20 -0
  112. package/src/daemon/session-agent-loop.ts +22 -11
  113. package/src/daemon/session-lifecycle.ts +1 -1
  114. package/src/daemon/session-process.ts +11 -1
  115. package/src/daemon/session-runtime-assembly.ts +3 -0
  116. package/src/daemon/session-surfaces.ts +3 -2
  117. package/src/daemon/session.ts +88 -1
  118. package/src/daemon/tool-side-effects.ts +22 -0
  119. package/src/home-base/prebuilt/brain-graph.html +1483 -0
  120. package/src/home-base/prebuilt/index.html +40 -0
  121. package/src/inbound/platform-callback-registration.ts +157 -0
  122. package/src/memory/canonical-guardian-store.ts +1 -1
  123. package/src/memory/db-init.ts +4 -0
  124. package/src/memory/migrations/038-actor-token-records.ts +39 -0
  125. package/src/memory/migrations/index.ts +1 -0
  126. package/src/memory/schema.ts +16 -0
  127. package/src/messaging/provider-types.ts +24 -0
  128. package/src/messaging/provider.ts +7 -0
  129. package/src/messaging/providers/gmail/adapter.ts +127 -0
  130. package/src/messaging/providers/sms/adapter.ts +40 -37
  131. package/src/notifications/adapters/macos.ts +45 -2
  132. package/src/notifications/broadcaster.ts +16 -0
  133. package/src/notifications/copy-composer.ts +39 -1
  134. package/src/notifications/decision-engine.ts +22 -9
  135. package/src/notifications/destination-resolver.ts +16 -2
  136. package/src/notifications/emit-signal.ts +16 -8
  137. package/src/notifications/guardian-question-mode.ts +419 -0
  138. package/src/notifications/signal.ts +14 -3
  139. package/src/permissions/checker.ts +13 -1
  140. package/src/permissions/prompter.ts +14 -0
  141. package/src/providers/anthropic/client.ts +20 -0
  142. package/src/providers/provider-send-message.ts +15 -3
  143. package/src/runtime/access-request-helper.ts +71 -1
  144. package/src/runtime/actor-token-service.ts +234 -0
  145. package/src/runtime/actor-token-store.ts +236 -0
  146. package/src/runtime/channel-approvals.ts +5 -3
  147. package/src/runtime/channel-readiness-service.ts +23 -64
  148. package/src/runtime/channel-readiness-types.ts +3 -4
  149. package/src/runtime/channel-retry-sweep.ts +4 -1
  150. package/src/runtime/confirmation-request-guardian-bridge.ts +197 -0
  151. package/src/runtime/guardian-action-followup-executor.ts +1 -1
  152. package/src/runtime/guardian-context-resolver.ts +82 -0
  153. package/src/runtime/guardian-outbound-actions.ts +0 -3
  154. package/src/runtime/guardian-reply-router.ts +67 -30
  155. package/src/runtime/guardian-vellum-migration.ts +57 -0
  156. package/src/runtime/http-server.ts +65 -12
  157. package/src/runtime/http-types.ts +13 -0
  158. package/src/runtime/invite-redemption-service.ts +8 -0
  159. package/src/runtime/local-actor-identity.ts +76 -0
  160. package/src/runtime/middleware/actor-token.ts +271 -0
  161. package/src/runtime/routes/approval-routes.ts +82 -7
  162. package/src/runtime/routes/brain-graph-routes.ts +222 -0
  163. package/src/runtime/routes/channel-readiness-routes.ts +71 -0
  164. package/src/runtime/routes/conversation-routes.ts +140 -52
  165. package/src/runtime/routes/events-routes.ts +20 -5
  166. package/src/runtime/routes/guardian-action-routes.ts +45 -3
  167. package/src/runtime/routes/guardian-approval-interception.ts +29 -0
  168. package/src/runtime/routes/guardian-bootstrap-routes.ts +145 -0
  169. package/src/runtime/routes/inbound-message-handler.ts +143 -2
  170. package/src/runtime/routes/integration-routes.ts +7 -15
  171. package/src/runtime/routes/pairing-routes.ts +163 -0
  172. package/src/runtime/routes/twilio-routes.ts +934 -0
  173. package/src/runtime/tool-grant-request-helper.ts +3 -1
  174. package/src/security/oauth2.ts +27 -2
  175. package/src/security/token-manager.ts +46 -10
  176. package/src/tools/browser/browser-execution.ts +4 -3
  177. package/src/tools/browser/browser-handoff.ts +10 -18
  178. package/src/tools/browser/browser-manager.ts +80 -25
  179. package/src/tools/browser/browser-screencast.ts +35 -119
  180. package/src/tools/permission-checker.ts +15 -4
  181. package/src/tools/tool-approval-handler.ts +242 -18
  182. package/src/__tests__/handlers-twilio-config.test.ts +0 -1928
  183. package/src/daemon/handlers/config-twilio.ts +0 -1082
@@ -36,6 +36,7 @@ import type { Message } from '../providers/types.js';
36
36
  import type { Provider } from '../providers/types.js';
37
37
  import { ToolExecutor } from '../tools/executor.js';
38
38
  import type { AssistantAttachmentDraft } from './assistant-attachments.js';
39
+ import type { AssistantActivityState, ConfirmationStateChanged } from './ipc-contract/messages.js';
39
40
  import type { ServerMessage, SurfaceData,SurfaceType, UsageStats, UserMessageAttachment } from './ipc-protocol.js';
40
41
  import {
41
42
  classifyResponseTierAsync,
@@ -146,7 +147,7 @@ export class Session {
146
147
  /** @internal */ commandIntent?: { type: string; payload?: string; languageCode?: string };
147
148
  /** @internal */ pendingSurfaceActions = new Map<string, { surfaceType: SurfaceType }>();
148
149
  /** @internal */ lastSurfaceAction = new Map<string, { actionId: string; data?: Record<string, unknown> }>();
149
- /** @internal */ surfaceState = new Map<string, { surfaceType: SurfaceType; data: SurfaceData }>();
150
+ /** @internal */ surfaceState = new Map<string, { surfaceType: SurfaceType; data: SurfaceData; title?: string }>();
150
151
  /** @internal */ surfaceUndoStacks = new Map<string, string[]>();
151
152
  /** @internal */ withSurface = createSurfaceMutex();
152
153
  /** @internal */ currentTurnSurfaces: Array<{ surfaceId: string; surfaceType: SurfaceType; title?: string; data: SurfaceData; actions?: Array<{ id: string; label: string; style?: string }>; display?: string }> = [];
@@ -161,6 +162,16 @@ export class Session {
161
162
  public lastAttachmentWarnings: string[] = [];
162
163
  /** @internal */ currentTurnChannelContext: TurnChannelContext | null = null;
163
164
  /** @internal */ currentTurnInterfaceContext: TurnInterfaceContext | null = null;
165
+ /** @internal */ activityVersion = 0;
166
+ /**
167
+ * Optional callback invoked whenever a server-authoritative state signal
168
+ * (confirmation_state_changed or assistant_activity_state) is emitted.
169
+ *
170
+ * HTTP/SSE sessions set this so the hub publisher receives these events —
171
+ * without it, the signals only travel through `sendToClient`, which is a
172
+ * no-op for socketless sessions.
173
+ */
174
+ private onStateSignal?: (msg: ServerMessage) => void;
164
175
 
165
176
  constructor(
166
177
  conversationId: string,
@@ -180,6 +191,22 @@ export class Session {
180
191
  this.memoryPolicy = memoryPolicy ? { ...memoryPolicy } : { ...DEFAULT_MEMORY_POLICY };
181
192
  this.traceEmitter = new TraceEmitter(conversationId, sendToClient);
182
193
  this.prompter = new PermissionPrompter(sendToClient);
194
+ this.prompter.setOnStateChanged((requestId, state, source) => {
195
+ // Route through emitConfirmationStateChanged so the onStateSignal
196
+ // listener publishes to the SSE hub for HTTP/SSE consumers.
197
+ this.emitConfirmationStateChanged({
198
+ sessionId: this.conversationId,
199
+ requestId,
200
+ state,
201
+ source,
202
+ });
203
+ // Emit activity state transitions for confirmation lifecycle
204
+ if (state === 'pending') {
205
+ this.emitActivityState('awaiting_confirmation', 'confirmation_requested', 'assistant_turn');
206
+ } else if (state === 'timed_out') {
207
+ this.emitActivityState('thinking', 'confirmation_resolved', 'assistant_turn');
208
+ }
209
+ });
183
210
  this.secretPrompter = new SecretPrompter(sendToClient);
184
211
 
185
212
  // Register watch/call notifiers (reads ctx properties lazily)
@@ -356,6 +383,17 @@ export class Session {
356
383
  return this.sendToClient;
357
384
  }
358
385
 
386
+ /**
387
+ * Register a callback for server-authoritative state signals
388
+ * (confirmation_state_changed, assistant_activity_state).
389
+ *
390
+ * This enables HTTP/SSE sessions to receive these events through the
391
+ * hub publisher, since `sendToClient` is a no-op for socketless sessions.
392
+ */
393
+ setStateSignalListener(listener: (msg: ServerMessage) => void): void {
394
+ this.onStateSignal = listener;
395
+ }
396
+
359
397
  setSandboxOverride(enabled: boolean | undefined): void {
360
398
  this.sandboxOverride = enabled;
361
399
  }
@@ -453,6 +491,11 @@ export class Session {
453
491
  selectedPattern?: string,
454
492
  selectedScope?: string,
455
493
  decisionContext?: string,
494
+ emissionContext?: {
495
+ source?: ConfirmationStateChanged['source'];
496
+ causedByRequestId?: string;
497
+ decisionText?: string;
498
+ },
456
499
  ): void {
457
500
  this.prompter.resolveConfirmation(
458
501
  requestId,
@@ -461,12 +504,56 @@ export class Session {
461
504
  selectedScope,
462
505
  decisionContext,
463
506
  );
507
+
508
+ // Emit authoritative confirmation state and activity transition centrally
509
+ // so ALL callers (IPC handlers, /v1/confirm, channel bridges) get
510
+ // consistent events without duplicating emission logic.
511
+ const resolvedState = (decision === 'deny' || decision === 'always_deny')
512
+ ? 'denied' as const
513
+ : 'approved' as const;
514
+ this.emitConfirmationStateChanged({
515
+ sessionId: this.conversationId,
516
+ requestId,
517
+ state: resolvedState,
518
+ source: emissionContext?.source ?? 'button',
519
+ ...(emissionContext?.causedByRequestId ? { causedByRequestId: emissionContext.causedByRequestId } : {}),
520
+ ...(emissionContext?.decisionText ? { decisionText: emissionContext.decisionText } : {}),
521
+ });
522
+ this.emitActivityState('thinking', 'confirmation_resolved', 'assistant_turn');
464
523
  }
465
524
 
466
525
  handleSecretResponse(requestId: string, value?: string, delivery?: 'store' | 'transient_send'): void {
467
526
  this.secretPrompter.resolveSecret(requestId, value, delivery);
468
527
  }
469
528
 
529
+ // ── Server-authoritative state signals ─────────────────────────────
530
+
531
+ emitConfirmationStateChanged(params: Omit<ConfirmationStateChanged, 'type'>): void {
532
+ const msg: ServerMessage = { type: 'confirmation_state_changed', ...params } as ServerMessage;
533
+ this.sendToClient(msg);
534
+ this.onStateSignal?.(msg);
535
+ }
536
+
537
+ emitActivityState(
538
+ phase: AssistantActivityState['phase'],
539
+ reason: AssistantActivityState['reason'],
540
+ anchor: AssistantActivityState['anchor'] = 'assistant_turn',
541
+ requestId?: string,
542
+ ): void {
543
+ this.activityVersion++;
544
+ const msg: ServerMessage = {
545
+ type: 'assistant_activity_state',
546
+ sessionId: this.conversationId,
547
+ activityVersion: this.activityVersion,
548
+ phase,
549
+ anchor,
550
+ requestId,
551
+ reason,
552
+ } as ServerMessage;
553
+ this.sendToClient(msg);
554
+ this.onStateSignal?.(msg);
555
+ }
556
+
470
557
  setChannelCapabilities(caps: ChannelCapabilities | null): void {
471
558
  this.channelCapabilities = caps ?? undefined;
472
559
  }
@@ -68,6 +68,19 @@ function registerHook(toolNames: string | string[], hook: PostExecutionHook): vo
68
68
  }
69
69
  }
70
70
 
71
+ // Broadcast app_files_changed when a new app is created so clients
72
+ // (e.g. macOS "Things" sidebar) refresh their app list immediately.
73
+ registerHook('app_create', (_name, _input, result, { ctx, broadcastToAllClients }) => {
74
+ try {
75
+ const parsed = JSON.parse(result.content) as { id?: string };
76
+ if (parsed.id) {
77
+ handleAppChange(ctx, parsed.id, broadcastToAllClients);
78
+ }
79
+ } catch {
80
+ // Result wasn't valid JSON — skip the broadcast.
81
+ }
82
+ });
83
+
71
84
  // Auto-refresh workspace surfaces when a persisted app is updated.
72
85
  // If no surface is currently showing the app, auto-open it.
73
86
  registerHook('app_update', (_name, input, _result, { ctx, broadcastToAllClients }) => {
@@ -77,6 +90,15 @@ registerHook('app_update', (_name, input, _result, { ctx, broadcastToAllClients
77
90
  }
78
91
  });
79
92
 
93
+ // Broadcast app_files_changed when an app is deleted so clients remove it
94
+ // from their cached app lists.
95
+ registerHook('app_delete', (_name, input, _result, { broadcastToAllClients }) => {
96
+ const appId = input.app_id as string | undefined;
97
+ if (appId) {
98
+ broadcastToAllClients?.({ type: 'app_files_changed', appId });
99
+ }
100
+ });
101
+
80
102
  // Broadcast tasks_changed so connected clients (e.g. macOS Tasks window)
81
103
  // auto-refresh when the LLM mutates the task queue via tools
82
104
  registerHook(