@vellumai/assistant 0.4.32 → 0.4.34

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 (186) hide show
  1. package/docs/architecture/memory.md +1 -1
  2. package/package.json +1 -1
  3. package/src/__tests__/access-request-decision.test.ts +85 -4
  4. package/src/__tests__/actor-token-service.test.ts +4 -12
  5. package/src/__tests__/approval-primitive.test.ts +0 -45
  6. package/src/__tests__/approval-routes-http.test.ts +0 -1
  7. package/src/__tests__/assistant-id-boundary-guard.test.ts +150 -0
  8. package/src/__tests__/call-controller.test.ts +0 -1
  9. package/src/__tests__/call-routes-http.test.ts +0 -1
  10. package/src/__tests__/callback-handoff-copy.test.ts +0 -1
  11. package/src/__tests__/channel-approval-routes.test.ts +5 -45
  12. package/src/__tests__/channel-guardian.test.ts +122 -346
  13. package/src/__tests__/channel-invite-transport.test.ts +52 -40
  14. package/src/__tests__/commit-message-enrichment-service.test.ts +4 -38
  15. package/src/__tests__/computer-use-session-working-dir.test.ts +0 -1
  16. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -3
  17. package/src/__tests__/contacts-tools.test.ts +4 -5
  18. package/src/__tests__/conversation-attention-store.test.ts +2 -65
  19. package/src/__tests__/conversation-attention-telegram.test.ts +0 -2
  20. package/src/__tests__/conversation-pairing.test.ts +0 -1
  21. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  22. package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -3
  23. package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -7
  24. package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
  25. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -74
  26. package/src/__tests__/guardian-action-late-reply.test.ts +1 -8
  27. package/src/__tests__/guardian-dispatch.test.ts +0 -1
  28. package/src/__tests__/guardian-grant-minting.test.ts +0 -1
  29. package/src/__tests__/guardian-outbound-http.test.ts +0 -1
  30. package/src/__tests__/guardian-routing-state.test.ts +0 -3
  31. package/src/__tests__/handlers-telegram-config.test.ts +0 -1
  32. package/src/__tests__/inbound-invite-redemption.test.ts +1 -7
  33. package/src/__tests__/ingress-reconcile.test.ts +3 -36
  34. package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1
  35. package/src/__tests__/migration-export-http.test.ts +0 -1
  36. package/src/__tests__/migration-import-commit-http.test.ts +0 -1
  37. package/src/__tests__/migration-import-preflight-http.test.ts +0 -1
  38. package/src/__tests__/migration-validate-http.test.ts +0 -1
  39. package/src/__tests__/non-member-access-request.test.ts +0 -8
  40. package/src/__tests__/notification-broadcaster.test.ts +1 -2
  41. package/src/__tests__/notification-decision-fallback.test.ts +0 -2
  42. package/src/__tests__/notification-decision-strategy.test.ts +0 -1
  43. package/src/__tests__/notification-guardian-path.test.ts +0 -1
  44. package/src/__tests__/notification-telegram-adapter.test.ts +0 -4
  45. package/src/__tests__/relay-server.test.ts +151 -80
  46. package/src/__tests__/sandbox-host-parity.test.ts +5 -2
  47. package/src/__tests__/scoped-approval-grants.test.ts +9 -40
  48. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -36
  49. package/src/__tests__/send-endpoint-busy.test.ts +0 -1
  50. package/src/__tests__/send-notification-tool.test.ts +0 -1
  51. package/src/__tests__/session-init.benchmark.test.ts +0 -2
  52. package/src/__tests__/slack-channel-config.test.ts +0 -1
  53. package/src/__tests__/slack-inbound-verification.test.ts +2 -5
  54. package/src/__tests__/sms-messaging-provider.test.ts +0 -4
  55. package/src/__tests__/terminal-tools.test.ts +5 -2
  56. package/src/__tests__/thread-seed-composer.test.ts +0 -1
  57. package/src/__tests__/tool-approval-handler.test.ts +0 -1
  58. package/src/__tests__/tool-grant-request-escalation.test.ts +0 -4
  59. package/src/__tests__/trusted-contact-approval-notifier.test.ts +65 -77
  60. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  61. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +1 -18
  62. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -14
  63. package/src/__tests__/trusted-contact-verification.test.ts +3 -16
  64. package/src/__tests__/twilio-routes.test.ts +2 -3
  65. package/src/__tests__/update-bulletin.test.ts +0 -2
  66. package/src/__tests__/user-reference.test.ts +47 -1
  67. package/src/__tests__/voice-invite-redemption.test.ts +0 -1
  68. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -38
  69. package/src/__tests__/workspace-git-service.test.ts +2 -2
  70. package/src/approvals/approval-primitive.ts +0 -15
  71. package/src/approvals/guardian-decision-primitive.ts +0 -3
  72. package/src/approvals/guardian-request-resolvers.ts +0 -5
  73. package/src/calls/call-domain.ts +0 -3
  74. package/src/calls/call-store.ts +0 -3
  75. package/src/calls/guardian-action-sweep.ts +2 -1
  76. package/src/calls/guardian-dispatch.ts +1 -2
  77. package/src/calls/relay-access-wait.ts +0 -4
  78. package/src/calls/relay-server.ts +8 -66
  79. package/src/calls/relay-setup-router.ts +1 -2
  80. package/src/calls/relay-verification.ts +0 -1
  81. package/src/calls/twilio-routes.ts +0 -3
  82. package/src/calls/types.ts +0 -1
  83. package/src/calls/voice-session-bridge.ts +0 -1
  84. package/src/channels/config.ts +41 -2
  85. package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -1
  86. package/src/config/bundled-skills/slack/SKILL.md +2 -0
  87. package/src/config/bundled-skills/slack-digest-setup/SKILL.md +164 -0
  88. package/src/config/env.ts +0 -4
  89. package/src/config/feature-flag-registry.json +4 -4
  90. package/src/config/user-reference.ts +47 -9
  91. package/src/contacts/contact-store.ts +13 -88
  92. package/src/contacts/contacts-write.ts +3 -11
  93. package/src/contacts/types.ts +0 -1
  94. package/src/daemon/handlers/config-channels.ts +19 -44
  95. package/src/daemon/handlers/config-inbox.ts +6 -6
  96. package/src/daemon/handlers/contacts.ts +8 -12
  97. package/src/daemon/handlers/index.ts +0 -2
  98. package/src/daemon/lifecycle.ts +18 -26
  99. package/src/daemon/session-process.ts +0 -4
  100. package/src/memory/channel-delivery-store.ts +1 -0
  101. package/src/memory/conversation-attention-store.ts +4 -19
  102. package/src/memory/conversation-crud.ts +0 -2
  103. package/src/memory/db-init.ts +8 -0
  104. package/src/memory/delivery-crud.ts +13 -0
  105. package/src/memory/guardian-action-store.ts +0 -12
  106. package/src/memory/guardian-approvals.ts +35 -80
  107. package/src/memory/guardian-rate-limits.ts +1 -14
  108. package/src/memory/guardian-verification.ts +6 -34
  109. package/src/memory/invite-store.ts +76 -15
  110. package/src/memory/migrations/040-invite-code-hash-column.ts +16 -0
  111. package/src/memory/migrations/134-contacts-notes-column.ts +64 -45
  112. package/src/memory/migrations/136-drop-assistant-id-columns.ts +263 -0
  113. package/src/memory/migrations/index.ts +2 -0
  114. package/src/memory/migrations/registry.ts +14 -1
  115. package/src/memory/schema/calls.ts +0 -7
  116. package/src/memory/schema/contacts.ts +2 -8
  117. package/src/memory/schema/guardian.ts +0 -5
  118. package/src/memory/schema/infrastructure.ts +0 -2
  119. package/src/memory/schema/notifications.ts +3 -17
  120. package/src/memory/scoped-approval-grants.ts +2 -24
  121. package/src/notifications/adapters/sms.ts +2 -1
  122. package/src/notifications/broadcaster.ts +1 -6
  123. package/src/notifications/decision-engine.ts +3 -4
  124. package/src/notifications/deliveries-store.ts +0 -4
  125. package/src/notifications/destination-resolver.ts +4 -6
  126. package/src/notifications/deterministic-checks.ts +1 -6
  127. package/src/notifications/emit-signal.ts +4 -11
  128. package/src/notifications/events-store.ts +7 -17
  129. package/src/notifications/preference-summary.ts +2 -2
  130. package/src/notifications/preferences-store.ts +2 -9
  131. package/src/notifications/signal.ts +0 -1
  132. package/src/notifications/thread-candidates.ts +1 -11
  133. package/src/notifications/types.ts +0 -3
  134. package/src/runtime/access-request-helper.ts +3 -10
  135. package/src/runtime/actor-refresh-token-store.ts +0 -6
  136. package/src/runtime/actor-token-store.ts +3 -16
  137. package/src/runtime/actor-trust-resolver.ts +1 -4
  138. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -9
  139. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -3
  140. package/src/runtime/auth/credential-service.ts +1 -15
  141. package/src/runtime/auth/require-bound-guardian.ts +1 -4
  142. package/src/runtime/auth/token-service.ts +50 -0
  143. package/src/runtime/channel-guardian-service.ts +16 -49
  144. package/src/runtime/channel-invite-transport.ts +129 -34
  145. package/src/runtime/channel-invite-transports/email.ts +54 -0
  146. package/src/runtime/channel-invite-transports/slack.ts +87 -0
  147. package/src/runtime/channel-invite-transports/sms.ts +74 -0
  148. package/src/runtime/channel-invite-transports/telegram.ts +35 -11
  149. package/src/runtime/channel-invite-transports/voice.ts +12 -12
  150. package/src/runtime/confirmation-request-guardian-bridge.ts +0 -1
  151. package/src/runtime/guardian-action-followup-executor.ts +3 -2
  152. package/src/runtime/guardian-action-grant-minter.ts +0 -1
  153. package/src/runtime/guardian-outbound-actions.ts +2 -12
  154. package/src/runtime/guardian-vellum-migration.ts +2 -3
  155. package/src/runtime/http-server.ts +0 -1
  156. package/src/runtime/invite-redemption-service.ts +191 -11
  157. package/src/runtime/invite-redemption-templates.ts +6 -6
  158. package/src/runtime/invite-service.ts +81 -11
  159. package/src/runtime/local-actor-identity.ts +2 -5
  160. package/src/runtime/routes/access-request-decision.ts +52 -7
  161. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +6 -9
  162. package/src/runtime/routes/channel-readiness-routes.ts +29 -18
  163. package/src/runtime/routes/contact-routes.ts +48 -46
  164. package/src/runtime/routes/conversation-attention-routes.ts +0 -2
  165. package/src/runtime/routes/global-search-routes.ts +0 -2
  166. package/src/runtime/routes/guardian-bootstrap-routes.ts +6 -12
  167. package/src/runtime/routes/guardian-expiry-sweep.ts +3 -2
  168. package/src/runtime/routes/inbound-message-handler.ts +1 -6
  169. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +296 -47
  170. package/src/runtime/routes/inbound-stages/background-dispatch.ts +6 -42
  171. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +1 -6
  172. package/src/runtime/routes/inbound-stages/edit-intercept.ts +10 -0
  173. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +0 -1
  174. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +0 -1
  175. package/src/runtime/routes/inbound-stages/verification-intercept.ts +3 -7
  176. package/src/runtime/routes/invite-routes.ts +1 -0
  177. package/src/runtime/routes/pairing-routes.ts +4 -4
  178. package/src/runtime/tool-grant-request-helper.ts +0 -1
  179. package/src/tools/browser/browser-manager.ts +22 -12
  180. package/src/tools/browser/runtime-check.ts +110 -3
  181. package/src/tools/calls/call-start.ts +1 -3
  182. package/src/tools/followups/followup_create.ts +1 -2
  183. package/src/tools/shared/shell-output.ts +7 -2
  184. package/src/tools/tool-approval-handler.ts +0 -2
  185. package/src/util/platform.ts +0 -4
  186. package/src/workspace/git-service.ts +10 -4
@@ -31,7 +31,6 @@ mock.module("../util/platform.js", () => ({
31
31
  getDbPath: () => join(testDir, "test.db"),
32
32
  getLogPath: () => join(testDir, "test.log"),
33
33
  ensureDataDir: () => {},
34
- readHttpToken: () => "test-bearer-token",
35
34
  }));
36
35
 
37
36
  mock.module("../util/logger.js", () => ({
@@ -92,7 +91,6 @@ describe("trusted contact verification → member activation", () => {
92
91
  test("successful verification creates active member with allow policy", () => {
93
92
  // Simulate M3: guardian approves, outbound session created for the requester
94
93
  const session = createOutboundSession({
95
- assistantId: "self",
96
94
  channel: "telegram",
97
95
  expectedExternalUserId: "requester-user-123",
98
96
  expectedChatId: "requester-chat-123",
@@ -103,7 +101,6 @@ describe("trusted contact verification → member activation", () => {
103
101
 
104
102
  // Requester enters the 6-digit code
105
103
  const result = validateAndConsumeChallenge(
106
- "self",
107
104
  "telegram",
108
105
  session.secret,
109
106
  "requester-user-123",
@@ -238,7 +235,6 @@ describe("trusted contact verification → member activation", () => {
238
235
  test("post-verify message is accepted (ACL check passes)", () => {
239
236
  // Create and verify a trusted contact
240
237
  const session = createOutboundSession({
241
- assistantId: "self",
242
238
  channel: "telegram",
243
239
  expectedExternalUserId: "requester-user-456",
244
240
  expectedChatId: "requester-chat-456",
@@ -248,7 +244,6 @@ describe("trusted contact verification → member activation", () => {
248
244
  });
249
245
 
250
246
  validateAndConsumeChallenge(
251
- "self",
252
247
  "telegram",
253
248
  session.secret,
254
249
  "requester-user-456",
@@ -279,7 +274,6 @@ describe("trusted contact verification → member activation", () => {
279
274
  test("member lookup is scoped by channel type", () => {
280
275
  // Create member on the telegram channel
281
276
  const session = createOutboundSession({
282
- assistantId: "self",
283
277
  channel: "telegram",
284
278
  expectedExternalUserId: "user-cross-test",
285
279
  expectedChatId: "chat-cross-test",
@@ -289,7 +283,6 @@ describe("trusted contact verification → member activation", () => {
289
283
  });
290
284
 
291
285
  validateAndConsumeChallenge(
292
- "self",
293
286
  "telegram",
294
287
  session.secret,
295
288
  "user-cross-test",
@@ -346,7 +339,6 @@ describe("trusted contact verification → member activation", () => {
346
339
 
347
340
  // Guardian re-approves, new outbound session created
348
341
  const session = createOutboundSession({
349
- assistantId: "self",
350
342
  channel: "telegram",
351
343
  expectedExternalUserId: "user-revoked",
352
344
  expectedChatId: "chat-revoked",
@@ -357,7 +349,6 @@ describe("trusted contact verification → member activation", () => {
357
349
 
358
350
  // Requester enters the new code
359
351
  const result = validateAndConsumeChallenge(
360
- "self",
361
352
  "telegram",
362
353
  session.secret,
363
354
  "user-revoked",
@@ -390,7 +381,6 @@ describe("trusted contact verification → member activation", () => {
390
381
  test("trusted contact verification does NOT create a guardian binding", () => {
391
382
  // Ensure there's an existing guardian binding we want to preserve
392
383
  createGuardianBinding({
393
- assistantId: "self",
394
384
  channel: "telegram",
395
385
  guardianExternalUserId: "guardian-user-original",
396
386
  guardianDeliveryChatId: "guardian-chat-original",
@@ -401,7 +391,6 @@ describe("trusted contact verification → member activation", () => {
401
391
 
402
392
  // Create an outbound session for a requester (different user than guardian)
403
393
  const session = createOutboundSession({
404
- assistantId: "self",
405
394
  channel: "telegram",
406
395
  expectedExternalUserId: "requester-user-789",
407
396
  expectedChatId: "requester-chat-789",
@@ -411,7 +400,6 @@ describe("trusted contact verification → member activation", () => {
411
400
  });
412
401
 
413
402
  const result = validateAndConsumeChallenge(
414
- "self",
415
403
  "telegram",
416
404
  session.secret,
417
405
  "requester-user-789",
@@ -426,7 +414,7 @@ describe("trusted contact verification → member activation", () => {
426
414
  }
427
415
 
428
416
  // The original guardian binding should remain intact
429
- const guardianResult = findGuardianForChannel("telegram", "self");
417
+ const guardianResult = findGuardianForChannel("telegram");
430
418
  expect(guardianResult).not.toBeNull();
431
419
  expect(guardianResult!.channel.externalUserId).toBe(
432
420
  "guardian-user-original",
@@ -438,10 +426,9 @@ describe("trusted contact verification → member activation", () => {
438
426
 
439
427
  const { createVerificationChallenge } =
440
428
  await import("../runtime/channel-guardian-service.js");
441
- const { secret } = createVerificationChallenge("self", "telegram");
429
+ const { secret } = createVerificationChallenge("telegram");
442
430
 
443
431
  const result = validateAndConsumeChallenge(
444
- "self",
445
432
  "telegram",
446
433
  secret,
447
434
  "guardian-user",
@@ -453,7 +440,7 @@ describe("trusted contact verification → member activation", () => {
453
440
  expect(result.verificationType).toBe("guardian");
454
441
  }
455
442
 
456
- const guardianResult = findGuardianForChannel("telegram", "self");
443
+ const guardianResult = findGuardianForChannel("telegram");
457
444
  expect(guardianResult).toBeNull();
458
445
  });
459
446
  });
@@ -43,7 +43,6 @@ mock.module("../util/platform.js", () => ({
43
43
  getDbPath: () => join(testDir, "test.db"),
44
44
  getLogPath: () => join(testDir, "test.log"),
45
45
  ensureDataDir: () => {},
46
- readHttpToken: () => null,
47
46
  }));
48
47
 
49
48
  mock.module("../util/logger.js", () => ({
@@ -818,8 +817,8 @@ describe("twilio webhook routes", () => {
818
817
  expect(res.status).toBe(200);
819
818
  const session = getCallSessionByCallSid("CA_inbound_assist_1");
820
819
  expect(session).not.toBeNull();
821
- // Daemon always uses internal scope external assistant IDs are not leaked into session state.
822
- expect(session!.assistantId).toBe("self");
820
+ // Session was created for the inbound call.
821
+ expect(session!.status).toBe("initiated");
823
822
  });
824
823
 
825
824
  test("outbound call flow remains non-regressed with callSessionId present", async () => {
@@ -57,7 +57,6 @@ mock.module("../util/platform.js", () => ({
57
57
  getHooksDir: () => "",
58
58
  getSocketPath: () => "",
59
59
  getSessionTokenPath: () => "",
60
- getHttpTokenPath: () => "",
61
60
  getPlatformTokenPath: () => "",
62
61
  getPidPath: () => "",
63
62
  getWorkspaceConfigPath: () => "",
@@ -72,7 +71,6 @@ mock.module("../util/platform.js", () => ({
72
71
  writeLockfile: () => {},
73
72
  readPlatformToken: () => null,
74
73
  readSessionToken: () => null,
75
- readHttpToken: () => null,
76
74
  removeSocketFile: () => {},
77
75
  getTCPPort: () => 8765,
78
76
  isTCPEnabled: () => false,
@@ -26,7 +26,8 @@ mock.module("node:fs", () => ({
26
26
  }));
27
27
 
28
28
  // Import after mocks are in place
29
- const { resolveUserReference } = await import("../config/user-reference.js");
29
+ const { resolveUserReference, resolveGuardianName, DEFAULT_USER_REFERENCE } =
30
+ await import("../config/user-reference.js");
30
31
 
31
32
  describe("resolveUserReference", () => {
32
33
  beforeEach(() => {
@@ -69,3 +70,48 @@ describe("resolveUserReference", () => {
69
70
  expect(resolveUserReference()).toBe("Alice");
70
71
  });
71
72
  });
73
+
74
+ describe("resolveGuardianName", () => {
75
+ beforeEach(() => {
76
+ mockFileExists = false;
77
+ mockFileContent = "";
78
+ });
79
+
80
+ test("returns USER.md name when present, ignoring guardianDisplayName", () => {
81
+ mockFileExists = true;
82
+ mockFileContent = [
83
+ "## Onboarding Snapshot",
84
+ "",
85
+ "- Preferred name/reference: John",
86
+ ].join("\n");
87
+ expect(resolveGuardianName("Jane")).toBe("John");
88
+ });
89
+
90
+ test('returns "my human" when USER.md explicitly sets name to default value', () => {
91
+ mockFileExists = true;
92
+ mockFileContent = [
93
+ "## Onboarding Snapshot",
94
+ "",
95
+ "- Preferred name/reference: my human",
96
+ ].join("\n");
97
+ // The user's explicit choice must be respected even though it matches the default sentinel
98
+ expect(resolveGuardianName("Jane")).toBe("my human");
99
+ });
100
+
101
+ test("falls back to guardianDisplayName when USER.md is empty", () => {
102
+ mockFileExists = false;
103
+ expect(resolveGuardianName("Jane")).toBe("Jane");
104
+ });
105
+
106
+ test("falls back to DEFAULT_USER_REFERENCE when both are empty", () => {
107
+ mockFileExists = false;
108
+ expect(resolveGuardianName()).toBe(DEFAULT_USER_REFERENCE);
109
+ expect(resolveGuardianName(null)).toBe(DEFAULT_USER_REFERENCE);
110
+ expect(resolveGuardianName("")).toBe(DEFAULT_USER_REFERENCE);
111
+ });
112
+
113
+ test("trims whitespace on guardianDisplayName fallback", () => {
114
+ mockFileExists = false;
115
+ expect(resolveGuardianName(" Jane ")).toBe("Jane");
116
+ });
117
+ });
@@ -147,7 +147,6 @@ describe("redeemVoiceInviteCode", () => {
147
147
  const codeHash = hashVoiceCode(code);
148
148
 
149
149
  const { invite } = createInvite({
150
- assistantId: opts.assistantId ?? "self",
151
150
  sourceChannel: "voice",
152
151
  maxUses: opts.maxUses ?? 1,
153
152
  expiresInMs: opts.expiresInMs,
@@ -38,7 +38,6 @@ mock.module("../util/platform.js", () => ({
38
38
  getDbPath: () => join(testDir, "test.db"),
39
39
  getLogPath: () => join(testDir, "test.log"),
40
40
  ensureDataDir: () => {},
41
- readHttpToken: () => null,
42
41
  }));
43
42
 
44
43
  mock.module("../util/logger.js", () => ({
@@ -255,7 +254,6 @@ function grantParams(
255
254
  ): CreateScopedApprovalGrantParams {
256
255
  const futureExpiry = new Date(Date.now() + 60_000).toISOString();
257
256
  return {
258
- assistantId: ASSISTANT_ID,
259
257
  scopeMode: "tool_signature",
260
258
  toolName: TOOL_NAME,
261
259
  inputDigest: computeToolApprovalDigest(TOOL_NAME, TOOL_INPUT),
@@ -423,42 +421,6 @@ describe("voice bridge confirmation handling (grant consumption via primitive)",
423
421
  expect(decision!.reason).toContain("guardian voice call");
424
422
  });
425
423
 
426
- test("non-guardian with grant for different assistantId: auto-denied", async () => {
427
- // Create a grant scoped to a different assistant
428
- createScopedApprovalGrant(
429
- grantParams({
430
- assistantId: "other-assistant",
431
- }),
432
- );
433
-
434
- const mockData = createMockSession();
435
- setupBridgeDeps(() => mockData.session);
436
-
437
- const trustContext: TrustContext = {
438
- sourceChannel: "voice",
439
- trustClass: "trusted_contact",
440
- requesterExternalUserId: "caller-123",
441
- };
442
-
443
- await startVoiceTurn({
444
- conversationId: CONVERSATION_ID,
445
- callSessionId: CALL_SESSION_ID,
446
- content: "test utterance",
447
- assistantId: ASSISTANT_ID,
448
- trustContext,
449
- isInbound: true,
450
- onTextDelta: () => {},
451
- onComplete: () => {},
452
- onError: () => {},
453
- });
454
-
455
- await new Promise((resolve) => setTimeout(resolve, 100));
456
-
457
- const decision = mockData.getConfirmationDecision();
458
- expect(decision).not.toBeNull();
459
- expect(decision!.decision).toBe("deny");
460
- });
461
-
462
424
  test("grants revoked when revokeScopedApprovalGrantsForContext is called with callSessionId", () => {
463
425
  const db = getDb();
464
426
  const testCallSessionId = "call-session-revoke-test";
@@ -655,7 +655,7 @@ describe("WorkspaceGitService", () => {
655
655
  cwd: testDir,
656
656
  });
657
657
  const oldGitignore =
658
- "# Runtime state - excluded from git tracking\ndata/\nlogs/\n*.log\n*.sock\n*.pid\n*.sqlite\n*.sqlite-journal\n*.sqlite-wal\n*.sqlite-shm\n*.db\n*.db-journal\n*.db-wal\n*.db-shm\nvellum.sock\nvellum.pid\nsession-token\nhttp-token\n";
658
+ "# Runtime state - excluded from git tracking\ndata/\nlogs/\n*.log\n*.sock\n*.pid\n*.sqlite\n*.sqlite-journal\n*.sqlite-wal\n*.sqlite-shm\n*.db\n*.db-journal\n*.db-wal\n*.db-shm\nvellum.sock\nvellum.pid\nsession-token\n";
659
659
  writeFileSync(join(testDir, ".gitignore"), oldGitignore);
660
660
  writeFileSync(join(testDir, "file.txt"), "content");
661
661
  execFileSync("git", ["add", "-A"], { cwd: testDir });
@@ -725,7 +725,7 @@ describe("WorkspaceGitService", () => {
725
725
  cwd: testDir,
726
726
  });
727
727
  const gitignoreContent =
728
- "# Runtime state - excluded from git tracking\ndata/db/\ndata/qdrant/\ndata/ipc-blobs/\nlogs/\n*.log\n*.sock\n*.pid\n*.sqlite\n*.sqlite-journal\n*.sqlite-wal\n*.sqlite-shm\n*.db\n*.db-journal\n*.db-wal\n*.db-shm\nvellum.sock\nvellum.pid\nsession-token\nhttp-token\n";
728
+ "# Runtime state - excluded from git tracking\ndata/db/\ndata/qdrant/\ndata/ipc-blobs/\nlogs/\n*.log\n*.sock\n*.pid\n*.sqlite\n*.sqlite-journal\n*.sqlite-wal\n*.sqlite-shm\n*.db\n*.db-journal\n*.db-wal\n*.db-shm\nvellum.sock\nvellum.pid\nsession-token\n";
729
729
  writeFileSync(join(testDir, ".gitignore"), gitignoreContent);
730
730
  writeFileSync(join(testDir, "file.txt"), "content");
731
731
  execFileSync("git", ["add", "-A"], { cwd: testDir });
@@ -32,7 +32,6 @@ const log = getLogger("approval-primitive");
32
32
  // ---------------------------------------------------------------------------
33
33
 
34
34
  export interface MintGrantParams {
35
- assistantId: string;
36
35
  scopeMode: "request_id" | "tool_signature";
37
36
  requestId?: string | null;
38
37
  toolName?: string | null;
@@ -76,7 +75,6 @@ export function mintGrantFromDecision(
76
75
  event: "approval_primitive_mint_rejected",
77
76
  reason: "missing_request_id",
78
77
  scopeMode: params.scopeMode,
79
- assistantId: params.assistantId,
80
78
  requestChannel: params.requestChannel,
81
79
  decisionChannel: params.decisionChannel,
82
80
  },
@@ -96,7 +94,6 @@ export function mintGrantFromDecision(
96
94
  scopeMode: params.scopeMode,
97
95
  toolName: params.toolName ?? null,
98
96
  inputDigest: params.inputDigest ?? null,
99
- assistantId: params.assistantId,
100
97
  requestChannel: params.requestChannel,
101
98
  decisionChannel: params.decisionChannel,
102
99
  },
@@ -107,7 +104,6 @@ export function mintGrantFromDecision(
107
104
 
108
105
  try {
109
106
  const grant = createScopedApprovalGrant({
110
- assistantId: params.assistantId,
111
107
  scopeMode: params.scopeMode,
112
108
  requestId: params.requestId ?? null,
113
109
  toolName: params.toolName ?? null,
@@ -129,7 +125,6 @@ export function mintGrantFromDecision(
129
125
  scopeMode: params.scopeMode,
130
126
  toolName: params.toolName ?? null,
131
127
  requestId: params.requestId ?? null,
132
- assistantId: params.assistantId,
133
128
  requestChannel: params.requestChannel,
134
129
  decisionChannel: params.decisionChannel,
135
130
  conversationId: params.conversationId ?? null,
@@ -146,7 +141,6 @@ export function mintGrantFromDecision(
146
141
  event: "approval_primitive_mint_error",
147
142
  scopeMode: params.scopeMode,
148
143
  toolName: params.toolName ?? null,
149
- assistantId: params.assistantId,
150
144
  err: error,
151
145
  },
152
146
  "Failed to mint approval grant (storage error)",
@@ -162,7 +156,6 @@ export function mintGrantFromDecision(
162
156
  export interface ConsumeByRequestIdParams {
163
157
  requestId: string;
164
158
  consumingRequestId: string;
165
- assistantId: string;
166
159
  now?: string;
167
160
  }
168
161
 
@@ -170,7 +163,6 @@ export interface ConsumeByToolSignatureParams {
170
163
  toolName: string;
171
164
  inputDigest: string;
172
165
  consumingRequestId: string;
173
- assistantId?: string;
174
166
  executionChannel?: string;
175
167
  conversationId?: string;
176
168
  callSessionId?: string;
@@ -195,7 +187,6 @@ export interface ConsumeGrantParams {
195
187
  toolName: string;
196
188
  inputDigest: string;
197
189
  consumingRequestId: string;
198
- assistantId: string;
199
190
  executionChannel?: string;
200
191
  conversationId?: string;
201
192
  callSessionId?: string;
@@ -221,7 +212,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
221
212
  consumeScopedApprovalGrantByRequestId(
222
213
  params.requestId,
223
214
  params.consumingRequestId,
224
- params.assistantId,
225
215
  params.now,
226
216
  );
227
217
 
@@ -233,7 +223,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
233
223
  grantId: reqResult.grant.id,
234
224
  requestId: params.requestId,
235
225
  consumingRequestId: params.consumingRequestId,
236
- assistantId: params.assistantId,
237
226
  toolName: params.toolName,
238
227
  },
239
228
  "Approval grant consumed via request_id",
@@ -248,7 +237,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
248
237
  reason: "no_match",
249
238
  requestId: params.requestId,
250
239
  consumingRequestId: params.consumingRequestId,
251
- assistantId: params.assistantId,
252
240
  toolName: params.toolName,
253
241
  },
254
242
  "No request_id grant match, falling through to tool_signature",
@@ -261,7 +249,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
261
249
  toolName: params.toolName,
262
250
  inputDigest: params.inputDigest,
263
251
  consumingRequestId: params.consumingRequestId,
264
- assistantId: params.assistantId,
265
252
  executionChannel: params.executionChannel,
266
253
  conversationId: params.conversationId,
267
254
  callSessionId: params.callSessionId,
@@ -277,7 +264,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
277
264
  grantId: sigResult.grant.id,
278
265
  toolName: params.toolName,
279
266
  consumingRequestId: params.consumingRequestId,
280
- assistantId: params.assistantId,
281
267
  conversationId: params.conversationId ?? null,
282
268
  callSessionId: params.callSessionId ?? null,
283
269
  },
@@ -293,7 +279,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
293
279
  reason: "no_match",
294
280
  toolName: params.toolName,
295
281
  consumingRequestId: params.consumingRequestId,
296
- assistantId: params.assistantId,
297
282
  conversationId: params.conversationId ?? null,
298
283
  callSessionId: params.callSessionId ?? null,
299
284
  executionChannel: params.executionChannel ?? null,
@@ -36,7 +36,6 @@ import {
36
36
  type GuardianApprovalRequest,
37
37
  updateApprovalDecision,
38
38
  } from "../memory/channel-guardian-store.js";
39
- import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
40
39
  import type {
41
40
  ApprovalAction,
42
41
  ApprovalDecisionResult,
@@ -107,7 +106,6 @@ export function tryMintToolApprovalGrant(params: {
107
106
  }
108
107
 
109
108
  const result = mintGrantFromDecision({
110
- assistantId: approval.assistantId,
111
109
  scopeMode: "tool_signature",
112
110
  toolName: approvalInfo.toolName,
113
111
  inputDigest,
@@ -277,7 +275,6 @@ export function mintCanonicalRequestGrant(params: {
277
275
  }
278
276
 
279
277
  const result = mintGrantFromDecision({
280
- assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
281
278
  scopeMode: "tool_signature",
282
279
  toolName: request.toolName,
283
280
  inputDigest: request.inputDigest,
@@ -393,7 +393,6 @@ const accessRequestResolver: GuardianRequestResolver = {
393
393
  sourceEventName: "ingress.trusted_contact.guardian_decision",
394
394
  sourceChannel: channel,
395
395
  sourceSessionId: request.conversationId ?? "",
396
- assistantId,
397
396
  attentionHints: {
398
397
  requiresAction: false,
399
398
  urgency: "medium",
@@ -408,7 +407,6 @@ const accessRequestResolver: GuardianRequestResolver = {
408
407
  sourceEventName: "ingress.trusted_contact.denied",
409
408
  sourceChannel: channel,
410
409
  sourceSessionId: request.conversationId ?? "",
411
- assistantId,
412
410
  attentionHints: {
413
411
  requiresAction: false,
414
412
  urgency: "low",
@@ -454,7 +452,6 @@ const accessRequestResolver: GuardianRequestResolver = {
454
452
  if (channel === "voice") {
455
453
  try {
456
454
  upsertMember({
457
- assistantId,
458
455
  sourceChannel: "voice",
459
456
  externalUserId: requesterExternalUserId,
460
457
  externalChatId: requesterChatId,
@@ -484,7 +481,6 @@ const accessRequestResolver: GuardianRequestResolver = {
484
481
  // Non-voice approvals: mint an identity-bound verification session so the
485
482
  // requester can verify their identity.
486
483
  const session = createOutboundSession({
487
- assistantId,
488
484
  channel,
489
485
  expectedExternalUserId: requesterExternalUserId,
490
486
  expectedChatId: requesterChatId,
@@ -582,7 +578,6 @@ const accessRequestResolver: GuardianRequestResolver = {
582
578
  sourceEventName: "ingress.trusted_contact.verification_sent",
583
579
  sourceChannel: channel,
584
580
  sourceSessionId: request.conversationId ?? "",
585
- assistantId,
586
581
  attentionHints: {
587
582
  requiresAction: false,
588
583
  urgency: "low",
@@ -290,7 +290,6 @@ export function createInboundVoiceSession(
290
290
  provider: "twilio",
291
291
  fromNumber,
292
292
  toNumber,
293
- assistantId,
294
293
  });
295
294
 
296
295
  updateCallSession(session.id, { providerCallSid: callSid });
@@ -411,7 +410,6 @@ export async function startCall(
411
410
  task: callContext ? `${task}\n\nContext: ${callContext}` : task,
412
411
  callerIdentityMode: identityResult.mode,
413
412
  callerIdentitySource: identityResult.source,
414
- assistantId,
415
413
  initiatedFromConversationId: conversationId,
416
414
  });
417
415
  sessionId = session.id;
@@ -935,7 +933,6 @@ export async function startGuardianVerificationCall(
935
933
  toNumber: phoneNumber,
936
934
  callMode: "guardian_verification",
937
935
  guardianVerificationSessionId,
938
- assistantId,
939
936
  initiatedFromConversationId: originConversationId,
940
937
  });
941
938
  sessionId = session.id;
@@ -38,7 +38,6 @@ const parseCallSession = createRowMapper<
38
38
  guardianVerificationSessionId: "guardianVerificationSessionId",
39
39
  callerIdentityMode: "callerIdentityMode",
40
40
  callerIdentitySource: "callerIdentitySource",
41
- assistantId: "assistantId",
42
41
  initiatedFromConversationId: "initiatedFromConversationId",
43
42
  startedAt: "startedAt",
44
43
  endedAt: "endedAt",
@@ -83,7 +82,6 @@ export function createCallSession(opts: {
83
82
  guardianVerificationSessionId?: string;
84
83
  callerIdentityMode?: string;
85
84
  callerIdentitySource?: string;
86
- assistantId?: string;
87
85
  initiatedFromConversationId?: string;
88
86
  }): CallSession {
89
87
  const db = getDb();
@@ -101,7 +99,6 @@ export function createCallSession(opts: {
101
99
  guardianVerificationSessionId: opts.guardianVerificationSessionId ?? null,
102
100
  callerIdentityMode: opts.callerIdentityMode ?? null,
103
101
  callerIdentitySource: opts.callerIdentitySource ?? null,
104
- assistantId: opts.assistantId ?? null,
105
102
  initiatedFromConversationId: opts.initiatedFromConversationId ?? null,
106
103
  startedAt: null,
107
104
  endedAt: null,
@@ -15,6 +15,7 @@ import {
15
15
  getDeliveriesByRequestId,
16
16
  getExpiredGuardianActionRequests,
17
17
  } from "../memory/guardian-action-store.js";
18
+ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
18
19
  import { deliverChannelReply } from "../runtime/gateway-client.js";
19
20
  import { composeGuardianActionMessageGenerative } from "../runtime/guardian-action-message-composer.js";
20
21
  import type { GuardianActionCopyGenerator } from "../runtime/http-types.js";
@@ -132,7 +133,7 @@ export async function sweepExpiredGuardianActions(
132
133
 
133
134
  await sendGuardianExpiryNotices(
134
135
  deliveries,
135
- request.assistantId,
136
+ DAEMON_INTERNAL_ASSISTANT_ID,
136
137
  gatewayBaseUrl,
137
138
  mintBearerToken,
138
139
  guardianActionCopyGenerator,
@@ -101,7 +101,7 @@ async function dispatchGuardianQuestionInner(
101
101
  // level guardian identity. Resolve the principal from the contacts table.
102
102
  let guardianPrincipalId: string | undefined;
103
103
 
104
- const guardianResult = findGuardianForChannel("vellum", assistantId);
104
+ const guardianResult = findGuardianForChannel("vellum");
105
105
  if (guardianResult?.contact.principalId) {
106
106
  guardianPrincipalId = guardianResult.contact.principalId;
107
107
  }
@@ -205,7 +205,6 @@ async function dispatchGuardianQuestionInner(
205
205
  sourceEventName: "guardian.question",
206
206
  sourceChannel: "voice",
207
207
  sourceSessionId: callSessionId,
208
- assistantId,
209
208
  attentionHints: {
210
209
  requiresAction: true,
211
210
  urgency: "high",
@@ -9,7 +9,6 @@
9
9
  import { findContactChannel } from "../contacts/contact-store.js";
10
10
  import { getCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
11
11
  import { emitNotificationSignal } from "../notifications/emit-signal.js";
12
- import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
13
12
  import { getLogger } from "../util/logger.js";
14
13
  import {
15
14
  getGuardianWaitUpdateInitialIntervalMs,
@@ -240,8 +239,6 @@ export function emitAccessRequestCallbackHandoff(
240
239
  return { emitted: false, callbackHandoffNotified: true };
241
240
  }
242
241
 
243
- const assistantId =
244
- params.accessRequestAssistantId ?? DAEMON_INTERNAL_ASSISTANT_ID;
245
242
  const fromNumber = params.accessRequestFromNumber ?? null;
246
243
 
247
244
  // Resolve canonical request for requestCode and conversationId
@@ -282,7 +279,6 @@ export function emitAccessRequestCallbackHandoff(
282
279
  sourceEventName: "ingress.access_request.callback_handoff",
283
280
  sourceChannel: "voice",
284
281
  sourceSessionId,
285
- assistantId,
286
282
  attentionHints: {
287
283
  requiresAction: false,
288
284
  urgency: "medium",