@vellumai/assistant 0.4.33 → 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 (137) hide show
  1. package/package.json +1 -1
  2. package/src/__tests__/access-request-decision.test.ts +2 -3
  3. package/src/__tests__/actor-token-service.test.ts +4 -11
  4. package/src/__tests__/approval-primitive.test.ts +0 -45
  5. package/src/__tests__/assistant-id-boundary-guard.test.ts +150 -0
  6. package/src/__tests__/callback-handoff-copy.test.ts +0 -1
  7. package/src/__tests__/channel-approval-routes.test.ts +5 -45
  8. package/src/__tests__/channel-guardian.test.ts +122 -345
  9. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -3
  10. package/src/__tests__/contacts-tools.test.ts +4 -5
  11. package/src/__tests__/conversation-attention-store.test.ts +2 -65
  12. package/src/__tests__/conversation-attention-telegram.test.ts +0 -2
  13. package/src/__tests__/conversation-pairing.test.ts +0 -1
  14. package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -2
  15. package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -7
  16. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -74
  17. package/src/__tests__/guardian-action-late-reply.test.ts +1 -8
  18. package/src/__tests__/guardian-grant-minting.test.ts +0 -1
  19. package/src/__tests__/guardian-routing-state.test.ts +0 -3
  20. package/src/__tests__/inbound-invite-redemption.test.ts +0 -3
  21. package/src/__tests__/non-member-access-request.test.ts +0 -7
  22. package/src/__tests__/notification-broadcaster.test.ts +1 -2
  23. package/src/__tests__/notification-decision-fallback.test.ts +0 -2
  24. package/src/__tests__/notification-decision-strategy.test.ts +0 -1
  25. package/src/__tests__/relay-server.test.ts +11 -83
  26. package/src/__tests__/scoped-approval-grants.test.ts +9 -40
  27. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -36
  28. package/src/__tests__/send-endpoint-busy.test.ts +0 -1
  29. package/src/__tests__/send-notification-tool.test.ts +0 -1
  30. package/src/__tests__/slack-inbound-verification.test.ts +2 -4
  31. package/src/__tests__/thread-seed-composer.test.ts +0 -1
  32. package/src/__tests__/tool-approval-handler.test.ts +0 -1
  33. package/src/__tests__/tool-grant-request-escalation.test.ts +0 -4
  34. package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -5
  35. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +1 -17
  36. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -13
  37. package/src/__tests__/trusted-contact-verification.test.ts +3 -15
  38. package/src/__tests__/twilio-routes.test.ts +2 -2
  39. package/src/__tests__/voice-invite-redemption.test.ts +0 -1
  40. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -37
  41. package/src/approvals/approval-primitive.ts +0 -15
  42. package/src/approvals/guardian-decision-primitive.ts +0 -3
  43. package/src/approvals/guardian-request-resolvers.ts +0 -5
  44. package/src/calls/call-domain.ts +0 -3
  45. package/src/calls/call-store.ts +0 -3
  46. package/src/calls/guardian-action-sweep.ts +2 -1
  47. package/src/calls/guardian-dispatch.ts +1 -2
  48. package/src/calls/relay-access-wait.ts +0 -4
  49. package/src/calls/relay-server.ts +3 -11
  50. package/src/calls/relay-setup-router.ts +1 -2
  51. package/src/calls/relay-verification.ts +0 -1
  52. package/src/calls/twilio-routes.ts +0 -3
  53. package/src/calls/types.ts +0 -1
  54. package/src/calls/voice-session-bridge.ts +0 -1
  55. package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -1
  56. package/src/contacts/contact-store.ts +13 -88
  57. package/src/contacts/contacts-write.ts +3 -11
  58. package/src/contacts/types.ts +0 -1
  59. package/src/daemon/handlers/config-channels.ts +16 -42
  60. package/src/daemon/handlers/config-inbox.ts +6 -6
  61. package/src/daemon/handlers/contacts.ts +3 -11
  62. package/src/daemon/handlers/index.ts +0 -2
  63. package/src/daemon/session-process.ts +0 -4
  64. package/src/memory/conversation-attention-store.ts +4 -19
  65. package/src/memory/conversation-crud.ts +0 -2
  66. package/src/memory/db-init.ts +4 -0
  67. package/src/memory/guardian-action-store.ts +0 -12
  68. package/src/memory/guardian-approvals.ts +35 -80
  69. package/src/memory/guardian-rate-limits.ts +1 -14
  70. package/src/memory/guardian-verification.ts +6 -34
  71. package/src/memory/invite-store.ts +5 -14
  72. package/src/memory/migrations/134-contacts-notes-column.ts +64 -45
  73. package/src/memory/migrations/136-drop-assistant-id-columns.ts +263 -0
  74. package/src/memory/migrations/index.ts +1 -0
  75. package/src/memory/migrations/registry.ts +14 -1
  76. package/src/memory/schema/calls.ts +0 -7
  77. package/src/memory/schema/contacts.ts +0 -8
  78. package/src/memory/schema/guardian.ts +0 -5
  79. package/src/memory/schema/infrastructure.ts +0 -2
  80. package/src/memory/schema/notifications.ts +3 -17
  81. package/src/memory/scoped-approval-grants.ts +2 -24
  82. package/src/notifications/adapters/sms.ts +2 -1
  83. package/src/notifications/broadcaster.ts +1 -6
  84. package/src/notifications/decision-engine.ts +3 -4
  85. package/src/notifications/deliveries-store.ts +0 -4
  86. package/src/notifications/destination-resolver.ts +4 -6
  87. package/src/notifications/deterministic-checks.ts +1 -6
  88. package/src/notifications/emit-signal.ts +4 -11
  89. package/src/notifications/events-store.ts +7 -17
  90. package/src/notifications/preference-summary.ts +2 -2
  91. package/src/notifications/preferences-store.ts +2 -9
  92. package/src/notifications/signal.ts +0 -1
  93. package/src/notifications/thread-candidates.ts +1 -11
  94. package/src/notifications/types.ts +0 -3
  95. package/src/runtime/access-request-helper.ts +3 -10
  96. package/src/runtime/actor-refresh-token-store.ts +0 -6
  97. package/src/runtime/actor-token-store.ts +3 -16
  98. package/src/runtime/actor-trust-resolver.ts +1 -4
  99. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -9
  100. package/src/runtime/auth/credential-service.ts +1 -15
  101. package/src/runtime/auth/require-bound-guardian.ts +1 -4
  102. package/src/runtime/channel-guardian-service.ts +15 -46
  103. package/src/runtime/channel-invite-transport.ts +8 -0
  104. package/src/runtime/channel-invite-transports/email.ts +4 -0
  105. package/src/runtime/channel-invite-transports/slack.ts +6 -0
  106. package/src/runtime/channel-invite-transports/sms.ts +4 -0
  107. package/src/runtime/channel-invite-transports/telegram.ts +6 -0
  108. package/src/runtime/confirmation-request-guardian-bridge.ts +0 -1
  109. package/src/runtime/guardian-action-followup-executor.ts +3 -2
  110. package/src/runtime/guardian-action-grant-minter.ts +0 -1
  111. package/src/runtime/guardian-outbound-actions.ts +2 -12
  112. package/src/runtime/guardian-vellum-migration.ts +2 -3
  113. package/src/runtime/http-server.ts +0 -1
  114. package/src/runtime/invite-redemption-service.ts +1 -14
  115. package/src/runtime/local-actor-identity.ts +2 -5
  116. package/src/runtime/routes/access-request-decision.ts +0 -1
  117. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +0 -9
  118. package/src/runtime/routes/channel-readiness-routes.ts +29 -18
  119. package/src/runtime/routes/contact-routes.ts +15 -40
  120. package/src/runtime/routes/conversation-attention-routes.ts +0 -2
  121. package/src/runtime/routes/global-search-routes.ts +0 -2
  122. package/src/runtime/routes/guardian-bootstrap-routes.ts +5 -6
  123. package/src/runtime/routes/guardian-expiry-sweep.ts +3 -2
  124. package/src/runtime/routes/inbound-message-handler.ts +0 -3
  125. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -43
  126. package/src/runtime/routes/inbound-stages/background-dispatch.ts +1 -4
  127. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +1 -6
  128. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +0 -1
  129. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +0 -1
  130. package/src/runtime/routes/inbound-stages/verification-intercept.ts +3 -7
  131. package/src/runtime/routes/pairing-routes.ts +4 -4
  132. package/src/runtime/tool-grant-request-helper.ts +0 -1
  133. package/src/tools/browser/browser-manager.ts +22 -21
  134. package/src/tools/browser/runtime-check.ts +111 -6
  135. package/src/tools/calls/call-start.ts +1 -3
  136. package/src/tools/followups/followup_create.ts +1 -2
  137. package/src/tools/tool-approval-handler.ts +0 -2
@@ -8,7 +8,6 @@
8
8
 
9
9
  import type { ChannelId } from "../channels/types.js";
10
10
  import type { GuardianBinding } from "../memory/channel-guardian-store.js";
11
- import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
12
11
  import { canonicalizeInboundIdentity } from "../util/canonicalize-identity.js";
13
12
  import { getLogger } from "../util/logger.js";
14
13
  import { emitContactChange } from "./contact-events.js";
@@ -58,7 +57,6 @@ function parseDisplayNameFromMetadata(
58
57
  * (so callers expecting binding.id still work).
59
58
  */
60
59
  export function createGuardianBinding(params: {
61
- assistantId: string;
62
60
  channel: string;
63
61
  guardianExternalUserId: string;
64
62
  guardianDeliveryChatId: string;
@@ -81,7 +79,6 @@ export function createGuardianBinding(params: {
81
79
  role: "guardian",
82
80
  notes: "guardian",
83
81
  principalId: params.guardianPrincipalId,
84
- assistantId: params.assistantId,
85
82
  channels: [
86
83
  {
87
84
  type: params.channel,
@@ -98,7 +95,7 @@ export function createGuardianBinding(params: {
98
95
  const now = Date.now();
99
96
  const result: GuardianBinding = {
100
97
  id: `contact-binding-${params.channel}`,
101
- assistantId: params.assistantId,
98
+ assistantId: "self",
102
99
  channel: params.channel,
103
100
  guardianExternalUserId: params.guardianExternalUserId,
104
101
  guardianDeliveryChatId: params.guardianDeliveryChatId,
@@ -118,11 +115,8 @@ export function createGuardianBinding(params: {
118
115
  * Revoke a guardian binding by updating the contacts table.
119
116
  * Returns true when a guardian channel was found and revoked, false otherwise.
120
117
  */
121
- export function revokeGuardianBinding(
122
- assistantId: string,
123
- channel: string,
124
- ): boolean {
125
- const guardian = findGuardianForChannel(channel, assistantId);
118
+ export function revokeGuardianBinding(channel: string): boolean {
119
+ const guardian = findGuardianForChannel(channel);
126
120
  if (!guardian) return false;
127
121
 
128
122
  updateChannelStatus(guardian.channel.id, {
@@ -150,7 +144,6 @@ export function upsertMember(params: {
150
144
  status?: string;
151
145
  inviteId?: string;
152
146
  createdBySessionId?: string;
153
- assistantId?: string;
154
147
  }): ContactWriteResult | null {
155
148
  let address: string;
156
149
 
@@ -179,7 +172,6 @@ export function upsertMember(params: {
179
172
 
180
173
  upsertContact({
181
174
  displayName,
182
- assistantId: params.assistantId ?? DAEMON_INTERNAL_ASSISTANT_ID,
183
175
  channels: [
184
176
  {
185
177
  type: params.sourceChannel,
@@ -44,7 +44,6 @@ export interface Contact {
44
44
  * identified by channel address instead.
45
45
  */
46
46
  principalId: string | null;
47
- assistantId: string | null;
48
47
  }
49
48
 
50
49
  export type ChannelStatus =
@@ -2,7 +2,10 @@ import * as net from "node:net";
2
2
 
3
3
  import type { ChannelId } from "../../channels/types.js";
4
4
  import { resolveGuardianName } from "../../config/user-reference.js";
5
- import { findContactChannel } from "../../contacts/contact-store.js";
5
+ import {
6
+ findContactChannel,
7
+ findGuardianForChannel,
8
+ } from "../../contacts/contact-store.js";
6
9
  import { revokeMember } from "../../contacts/contacts-write.js";
7
10
  import type { ChannelStatus } from "../../contacts/types.js";
8
11
  import * as externalConversationStore from "../../memory/external-conversation-store.js";
@@ -88,11 +91,7 @@ export function createGuardianChallenge(
88
91
  };
89
92
  }
90
93
 
91
- const result = createVerificationChallenge(
92
- resolvedAssistantId,
93
- resolvedChannel,
94
- sessionId,
95
- );
94
+ const result = createVerificationChallenge(resolvedChannel, sessionId);
96
95
 
97
96
  return {
98
97
  success: true,
@@ -110,36 +109,15 @@ export function getGuardianStatus(
110
109
 
111
110
  const binding = getGuardianBinding(resolvedAssistantId, resolvedChannel);
112
111
 
113
- // Resolve guardianUsername and displayName from binding metadata or
114
- // external conversation store. The displayName is passed to
115
- // resolveGuardianName() as a fallback for when USER.md is missing/empty
116
- // (e.g. pre-onboarding).
117
- let guardianUsername: string | undefined;
118
- let bindingDisplayName: string | undefined;
119
- if (binding?.metadataJson) {
120
- try {
121
- const parsed = JSON.parse(binding.metadataJson) as Record<
122
- string,
123
- unknown
124
- >;
125
- if (
126
- typeof parsed.username === "string" &&
127
- parsed.username.trim().length > 0
128
- ) {
129
- guardianUsername = parsed.username.trim();
130
- }
131
- if (
132
- typeof parsed.displayName === "string" &&
133
- parsed.displayName.trim().length > 0
134
- ) {
135
- bindingDisplayName = parsed.displayName.trim();
136
- }
137
- } catch {
138
- // ignore malformed metadata
139
- }
140
- }
112
+ // Read the contact directly to get displayName getGuardianBinding is a
113
+ // compatibility shim that doesn't carry metadataJson.
114
+ const guardianResult = findGuardianForChannel(resolvedChannel);
115
+ const bindingDisplayName = guardianResult?.contact.displayName;
141
116
  const guardianDisplayName = resolveGuardianName(bindingDisplayName);
142
- if (binding?.guardianDeliveryChatId && !guardianUsername) {
117
+
118
+ // Resolve username from external conversation store.
119
+ let guardianUsername: string | undefined;
120
+ if (binding?.guardianDeliveryChatId) {
143
121
  const ext = externalConversationStore.getBindingByChannelChat(
144
122
  resolvedChannel,
145
123
  binding.guardianDeliveryChatId,
@@ -148,15 +126,11 @@ export function getGuardianStatus(
148
126
  guardianUsername = ext.username;
149
127
  }
150
128
  }
151
- const hasPendingChallenge =
152
- getPendingChallenge(resolvedAssistantId, resolvedChannel) != null;
129
+ const hasPendingChallenge = getPendingChallenge(resolvedChannel) != null;
153
130
 
154
131
  // Include active outbound session state so the UI can resume
155
132
  // after app restart and detect bootstrap completion.
156
- const activeOutboundSession = findActiveSession(
157
- resolvedAssistantId,
158
- resolvedChannel,
159
- );
133
+ const activeOutboundSession = findActiveSession(resolvedChannel);
160
134
  const outboundFields: Record<string, unknown> = {};
161
135
  if (activeOutboundSession) {
162
136
  outboundFields.verificationSessionId = activeOutboundSession.id;
@@ -195,7 +169,7 @@ export function revokeGuardianForChannel(
195
169
  // Always revoke pending challenges first — the macOS app uses
196
170
  // action: "revoke" to cancel an in-flight challenge even before
197
171
  // a binding exists (e.g. during verification setup).
198
- revokePendingChallenges(assistantId, resolvedChannel);
172
+ revokePendingChallenges(resolvedChannel);
199
173
 
200
174
  // Capture binding before revoking so we can revoke the guardian's
201
175
  // contact record — without this, the guardian would still pass
@@ -12,6 +12,7 @@ import {
12
12
  } from "../../memory/channel-guardian-store.js";
13
13
  import { addMessage, getMessages } from "../../memory/conversation-store.js";
14
14
  import { getBindingByConversation } from "../../memory/external-conversation-store.js";
15
+ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../../runtime/assistant-scope.js";
15
16
  import { mintDaemonDeliveryToken } from "../../runtime/auth/token-service.js";
16
17
  import { deliverChannelReply } from "../../runtime/gateway-client.js";
17
18
  import {
@@ -153,7 +154,6 @@ export function handleInboxEscalation(
153
154
  switch (msg.action) {
154
155
  case "list": {
155
156
  const escalations = listPendingApprovalRequests({
156
- assistantId: msg.assistantId,
157
157
  status: (msg.status as ApprovalRequestStatus) ?? undefined,
158
158
  });
159
159
  ctx.send(socket, {
@@ -279,7 +279,7 @@ async function executeApprove(
279
279
  approval: GuardianApprovalRequest,
280
280
  ctx: HandlerContext,
281
281
  ): Promise<void> {
282
- const { conversationId, assistantId, channel } = approval;
282
+ const { conversationId, channel } = approval;
283
283
 
284
284
  // Recover the original message content from the stored payload
285
285
  const payload = getLatestStoredPayload(conversationId);
@@ -316,7 +316,7 @@ async function executeApprove(
316
316
  });
317
317
  }
318
318
  }
319
- session.setAssistantId(assistantId);
319
+ session.setAssistantId(DAEMON_INTERNAL_ASSISTANT_ID);
320
320
  // The guardian already approved this escalation via the inbox, so we
321
321
  // directly set guardian trust. Going through resolveLocalIpcTrustContext
322
322
  // would look up the vellum binding's guardian ID and compare it against
@@ -368,7 +368,7 @@ async function executeApprove(
368
368
  {
369
369
  chatId: externalChatId,
370
370
  text: rendered.text,
371
- assistantId,
371
+ assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
372
372
  },
373
373
  bearerToken,
374
374
  );
@@ -388,7 +388,7 @@ async function executeDeny(
388
388
  approval: GuardianApprovalRequest,
389
389
  reason: string | undefined,
390
390
  ): Promise<void> {
391
- const { conversationId, assistantId, channel } = approval;
391
+ const { conversationId, channel } = approval;
392
392
 
393
393
  const binding = getBindingByConversation(conversationId);
394
394
  if (!binding) {
@@ -423,7 +423,7 @@ async function executeDeny(
423
423
  {
424
424
  chatId: binding.externalChatId,
425
425
  text: denialText,
426
- assistantId,
426
+ assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
427
427
  },
428
428
  bearerToken,
429
429
  );
@@ -7,7 +7,6 @@ import {
7
7
  updateChannelStatus,
8
8
  } from "../../contacts/contact-store.js";
9
9
  import type { ContactWithChannels } from "../../contacts/types.js";
10
- import { DAEMON_INTERNAL_ASSISTANT_ID } from "../../runtime/assistant-scope.js";
11
10
  import type {
12
11
  ContactChannelPayload,
13
12
  ContactPayload,
@@ -58,11 +57,7 @@ export function handleContacts(
58
57
  try {
59
58
  switch (msg.action) {
60
59
  case "list": {
61
- const results = listContacts(
62
- DAEMON_INTERNAL_ASSISTANT_ID,
63
- msg.limit ?? 50,
64
- msg.role,
65
- );
60
+ const results = listContacts(msg.limit ?? 50, msg.role);
66
61
  ctx.send(socket, {
67
62
  type: "contacts_response",
68
63
  success: true,
@@ -80,7 +75,7 @@ export function handleContacts(
80
75
  });
81
76
  return;
82
77
  }
83
- const contact = getContact(msg.contactId, DAEMON_INTERNAL_ASSISTANT_ID);
78
+ const contact = getContact(msg.contactId);
84
79
  if (!contact) {
85
80
  ctx.send(socket, {
86
81
  type: "contacts_response",
@@ -131,10 +126,7 @@ export function handleContacts(
131
126
  return;
132
127
  }
133
128
  // Return the parent contact with all channels so the client has the full picture
134
- const parentContact = getContact(
135
- updated.contactId,
136
- DAEMON_INTERNAL_ASSISTANT_ID,
137
- );
129
+ const parentContact = getContact(updated.contactId);
138
130
  ctx.send(socket, {
139
131
  type: "contacts_response",
140
132
  success: true,
@@ -6,7 +6,6 @@ import {
6
6
  type SignalType,
7
7
  } from "../../memory/conversation-attention-store.js";
8
8
  import { updateDeliveryClientOutcome } from "../../notifications/deliveries-store.js";
9
- import { DAEMON_INTERNAL_ASSISTANT_ID } from "../../runtime/assistant-scope.js";
10
9
  import type { ClientMessage } from "../ipc-protocol.js";
11
10
  import {
12
11
  handleRideShotgunStart,
@@ -120,7 +119,6 @@ const inlineHandlers = defineHandlers({
120
119
  try {
121
120
  recordConversationSeenSignal({
122
121
  conversationId: msg.conversationId,
123
- assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
124
122
  sourceChannel: msg.sourceChannel,
125
123
  signalType: msg.signalType as SignalType,
126
124
  confidence: msg.confidence as Confidence,
@@ -434,13 +434,11 @@ export async function drainQueue(
434
434
  // Fire-and-forget: detect notification preferences in the queued message
435
435
  // and persist any that are found, mirroring the logic in processMessage.
436
436
  if (session.assistantId) {
437
- const aid = session.assistantId;
438
437
  extractPreferences(resolvedContent)
439
438
  .then((result) => {
440
439
  if (!result.detected) return;
441
440
  for (const pref of result.preferences) {
442
441
  createPreference({
443
- assistantId: aid,
444
442
  preferenceText: pref.preferenceText,
445
443
  appliesWhen: pref.appliesWhen,
446
444
  priority: pref.priority,
@@ -735,13 +733,11 @@ export async function processMessage(
735
733
  // and persist any that are found. Runs in the background so it doesn't
736
734
  // block the main conversation flow.
737
735
  if (session.assistantId) {
738
- const aid = session.assistantId;
739
736
  extractPreferences(resolvedContent)
740
737
  .then((result) => {
741
738
  if (!result.detected) return;
742
739
  for (const pref of result.preferences) {
743
740
  createPreference({
744
- assistantId: aid,
745
741
  preferenceText: pref.preferenceText,
746
742
  appliesWhen: pref.appliesWhen,
747
743
  priority: pref.priority,
@@ -32,7 +32,6 @@ export type Confidence = "explicit" | "inferred";
32
32
  export interface AttentionEvent {
33
33
  id: string;
34
34
  conversationId: string;
35
- assistantId: string;
36
35
  sourceChannel: string;
37
36
  signalType: SignalType;
38
37
  confidence: Confidence;
@@ -45,7 +44,6 @@ export interface AttentionEvent {
45
44
 
46
45
  export interface AttentionState {
47
46
  conversationId: string;
48
- assistantId: string;
49
47
  latestAssistantMessageId: string | null;
50
48
  latestAssistantMessageAt: number | null;
51
49
  lastSeenAssistantMessageId: string | null;
@@ -68,7 +66,6 @@ function rowToEvent(
68
66
  return {
69
67
  id: row.id,
70
68
  conversationId: row.conversationId,
71
- assistantId: row.assistantId,
72
69
  sourceChannel: row.sourceChannel,
73
70
  signalType: row.signalType as SignalType,
74
71
  confidence: row.confidence as Confidence,
@@ -85,7 +82,6 @@ function rowToState(
85
82
  ): AttentionState {
86
83
  return {
87
84
  conversationId: row.conversationId,
88
- assistantId: row.assistantId,
89
85
  latestAssistantMessageId: row.latestAssistantMessageId,
90
86
  latestAssistantMessageAt: row.latestAssistantMessageAt,
91
87
  lastSeenAssistantMessageId: row.lastSeenAssistantMessageId,
@@ -109,11 +105,10 @@ function rowToState(
109
105
  */
110
106
  export function projectAssistantMessage(params: {
111
107
  conversationId: string;
112
- assistantId: string;
113
108
  messageId: string;
114
109
  messageAt: number;
115
110
  }): void {
116
- const { conversationId, assistantId, messageId, messageAt } = params;
111
+ const { conversationId, messageId, messageAt } = params;
117
112
  const db = getDb();
118
113
  const now = Date.now();
119
114
 
@@ -129,7 +124,6 @@ export function projectAssistantMessage(params: {
129
124
  db.insert(conversationAssistantAttentionState)
130
125
  .values({
131
126
  conversationId,
132
- assistantId,
133
127
  latestAssistantMessageId: messageId,
134
128
  latestAssistantMessageAt: messageAt,
135
129
  lastSeenAssistantMessageId: null,
@@ -175,7 +169,6 @@ export function projectAssistantMessage(params: {
175
169
  */
176
170
  export function recordConversationSeenSignal(params: {
177
171
  conversationId: string;
178
- assistantId: string;
179
172
  sourceChannel: string;
180
173
  signalType: SignalType;
181
174
  confidence: Confidence;
@@ -186,7 +179,6 @@ export function recordConversationSeenSignal(params: {
186
179
  }): AttentionEvent {
187
180
  const {
188
181
  conversationId,
189
- assistantId,
190
182
  sourceChannel,
191
183
  signalType,
192
184
  confidence,
@@ -205,7 +197,6 @@ export function recordConversationSeenSignal(params: {
205
197
  const event: typeof conversationAttentionEvents.$inferInsert = {
206
198
  id: eventId,
207
199
  conversationId,
208
- assistantId,
209
200
  sourceChannel,
210
201
  signalType,
211
202
  confidence,
@@ -252,7 +243,6 @@ export function recordConversationSeenSignal(params: {
252
243
  tx.insert(conversationAssistantAttentionState)
253
244
  .values({
254
245
  conversationId,
255
- assistantId,
256
246
  latestAssistantMessageId: latestMsgId,
257
247
  latestAssistantMessageAt: latestMsgAt,
258
248
  lastSeenAssistantMessageId: latestMsgId,
@@ -348,7 +338,6 @@ export function getAttentionStateByConversationIds(
348
338
  export type AttentionFilterState = "seen" | "unseen" | "all";
349
339
 
350
340
  export interface ListConversationAttentionParams {
351
- assistantId: string;
352
341
  state?: AttentionFilterState;
353
342
  sourceChannel?: string;
354
343
  source?: string;
@@ -364,7 +353,6 @@ export function listConversationAttention(
364
353
  params: ListConversationAttentionParams,
365
354
  ): AttentionState[] {
366
355
  const {
367
- assistantId,
368
356
  state: filterState = "all",
369
357
  sourceChannel,
370
358
  source,
@@ -373,9 +361,8 @@ export function listConversationAttention(
373
361
  } = params;
374
362
 
375
363
  const db = getDb();
376
- const conditions = [
377
- eq(conversationAssistantAttentionState.assistantId, assistantId),
378
- ];
364
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
365
+ const conditions: any[] = [];
379
366
 
380
367
  if (sourceChannel) {
381
368
  conditions.push(eq(conversations.originChannel, sourceChannel));
@@ -415,7 +402,6 @@ export function listConversationAttention(
415
402
  let query = db
416
403
  .select({
417
404
  conversationId: conversationAssistantAttentionState.conversationId,
418
- assistantId: conversationAssistantAttentionState.assistantId,
419
405
  latestAssistantMessageId:
420
406
  conversationAssistantAttentionState.latestAssistantMessageId,
421
407
  latestAssistantMessageAt:
@@ -448,8 +434,7 @@ export function listConversationAttention(
448
434
  );
449
435
  }
450
436
 
451
- const rows = query
452
- .where(and(...conditions))
437
+ const rows = (conditions.length > 0 ? query.where(and(...conditions)) : query)
453
438
  .orderBy(desc(conversationAssistantAttentionState.latestAssistantMessageAt))
454
439
  .limit(limit)
455
440
  .all();
@@ -7,7 +7,6 @@ import { parseChannelId, parseInterfaceId } from "../channels/types.js";
7
7
  import { CHANNEL_IDS, INTERFACE_IDS, isChannelId } from "../channels/types.js";
8
8
  import { getConfig } from "../config/loader.js";
9
9
  import type { TrustContext } from "../daemon/session-runtime-assembly.js";
10
- import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
11
10
  import { getLogger } from "../util/logger.js";
12
11
  import { createRowMapper } from "../util/row-mapper.js";
13
12
  import { deleteOrphanAttachments } from "./attachments-store.js";
@@ -394,7 +393,6 @@ export async function addMessage(
394
393
  try {
395
394
  projectAssistantMessage({
396
395
  conversationId,
397
- assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
398
396
  messageId: message.id,
399
397
  messageAt: message.createdAt,
400
398
  });
@@ -36,6 +36,7 @@ import {
36
36
  migrateBackfillContactInteractionStats,
37
37
  migrateBackfillGuardianPrincipalId,
38
38
  migrateCallSessionMode,
39
+ migrateDropAssistantIdColumns,
39
40
  migrateCanonicalGuardianDeliveriesDestinationIndex,
40
41
  migrateCanonicalGuardianRequesterChatId,
41
42
  migrateChannelInboundDeliveredSegments,
@@ -289,6 +290,9 @@ export function initializeDb(): void {
289
290
  // 39. Backfill contact interaction stats from channel lastSeenAt
290
291
  migrateBackfillContactInteractionStats(database);
291
292
 
293
+ // 40. Drop assistant_id columns from all 16 daemon tables
294
+ migrateDropAssistantIdColumns(database);
295
+
292
296
  validateMigrationState(database);
293
297
 
294
298
  if (process.env.BUN_TEST === "1") {
@@ -10,7 +10,6 @@
10
10
  import { and, desc, eq, inArray, lt } from "drizzle-orm";
11
11
  import { v4 as uuid } from "uuid";
12
12
 
13
- import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
14
13
  import { getLogger } from "../util/logger.js";
15
14
  import { getDb, rawChanges } from "./db.js";
16
15
  import { guardianActionDeliveries, guardianActionRequests } from "./schema.js";
@@ -49,7 +48,6 @@ export type FollowupAction = "call_back" | "message_back" | "decline";
49
48
 
50
49
  export interface GuardianActionRequest {
51
50
  id: string;
52
- assistantId: string;
53
51
  kind: string;
54
52
  sourceChannel: string;
55
53
  sourceConversationId: string;
@@ -101,7 +99,6 @@ function rowToRequest(
101
99
  ): GuardianActionRequest {
102
100
  return {
103
101
  id: row.id,
104
- assistantId: row.assistantId,
105
102
  kind: row.kind,
106
103
  sourceChannel: row.sourceChannel,
107
104
  sourceConversationId: row.sourceConversationId,
@@ -165,7 +162,6 @@ function generateRequestCode(): string {
165
162
  * legacy guardian action rows continue to compile.
166
163
  */
167
164
  export function createGuardianActionRequest(params: {
168
- assistantId?: string;
169
165
  kind: string;
170
166
  sourceChannel: string;
171
167
  sourceConversationId: string;
@@ -182,7 +178,6 @@ export function createGuardianActionRequest(params: {
182
178
 
183
179
  const row = {
184
180
  id,
185
- assistantId: params.assistantId ?? DAEMON_INTERNAL_ASSISTANT_ID,
186
181
  kind: params.kind,
187
182
  sourceChannel: params.sourceChannel,
188
183
  sourceConversationId: params.sourceConversationId,
@@ -693,14 +688,12 @@ export function createGuardianActionDelivery(params: {
693
688
  * Used by inbound message routing to match incoming answers to deliveries.
694
689
  */
695
690
  export function getPendingDeliveriesByDestination(
696
- assistantId: string,
697
691
  channel: string,
698
692
  chatId: string,
699
693
  ): GuardianActionDelivery[] {
700
694
  try {
701
695
  const db = getDb();
702
696
 
703
- // Join deliveries with requests to filter by assistantId
704
697
  const rows = db
705
698
  .select({
706
699
  delivery: guardianActionDeliveries,
@@ -712,7 +705,6 @@ export function getPendingDeliveriesByDestination(
712
705
  )
713
706
  .where(
714
707
  and(
715
- eq(guardianActionRequests.assistantId, assistantId),
716
708
  eq(guardianActionRequests.status, "pending"),
717
709
  eq(guardianActionDeliveries.destinationChannel, channel),
718
710
  eq(guardianActionDeliveries.destinationChatId, chatId),
@@ -784,7 +776,6 @@ export function getPendingDeliveriesByConversation(
784
776
  * Used by inbound message routing to match late guardian answers to expired requests.
785
777
  */
786
778
  export function getExpiredDeliveriesByDestination(
787
- assistantId: string,
788
779
  channel: string,
789
780
  chatId: string,
790
781
  ): GuardianActionDelivery[] {
@@ -802,7 +793,6 @@ export function getExpiredDeliveriesByDestination(
802
793
  )
803
794
  .where(
804
795
  and(
805
- eq(guardianActionRequests.assistantId, assistantId),
806
796
  eq(guardianActionRequests.status, "expired"),
807
797
  eq(guardianActionRequests.followupState, "none"),
808
798
  eq(guardianActionDeliveries.destinationChannel, channel),
@@ -877,7 +867,6 @@ export function getExpiredDeliveriesByConversation(
877
867
  * on channel paths (Telegram, SMS).
878
868
  */
879
869
  export function getFollowupDeliveriesByDestination(
880
- assistantId: string,
881
870
  channel: string,
882
871
  chatId: string,
883
872
  ): GuardianActionDelivery[] {
@@ -895,7 +884,6 @@ export function getFollowupDeliveriesByDestination(
895
884
  )
896
885
  .where(
897
886
  and(
898
- eq(guardianActionRequests.assistantId, assistantId),
899
887
  eq(guardianActionRequests.status, "expired"),
900
888
  eq(guardianActionRequests.followupState, "awaiting_guardian_choice"),
901
889
  eq(guardianActionDeliveries.destinationChannel, channel),