@vellumai/assistant 0.3.19 → 0.3.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.
Files changed (199) hide show
  1. package/ARCHITECTURE.md +151 -15
  2. package/Dockerfile +1 -0
  3. package/README.md +40 -4
  4. package/bun.lock +139 -2
  5. package/docs/architecture/integrations.md +7 -11
  6. package/package.json +2 -1
  7. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +54 -0
  8. package/src/__tests__/approval-primitive.test.ts +540 -0
  9. package/src/__tests__/assistant-feature-flag-guard.test.ts +206 -0
  10. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +198 -0
  11. package/src/__tests__/assistant-feature-flags-integration.test.ts +272 -0
  12. package/src/__tests__/call-controller.test.ts +439 -108
  13. package/src/__tests__/channel-invite-transport.test.ts +264 -0
  14. package/src/__tests__/cli.test.ts +42 -1
  15. package/src/__tests__/config-schema.test.ts +11 -127
  16. package/src/__tests__/config-watcher.test.ts +0 -8
  17. package/src/__tests__/daemon-lifecycle.test.ts +1 -0
  18. package/src/__tests__/daemon-server-session-init.test.ts +8 -2
  19. package/src/__tests__/diff.test.ts +22 -0
  20. package/src/__tests__/guardian-action-copy-generator.test.ts +5 -0
  21. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +300 -32
  22. package/src/__tests__/guardian-action-late-reply.test.ts +546 -1
  23. package/src/__tests__/guardian-actions-endpoint.test.ts +774 -0
  24. package/src/__tests__/guardian-control-plane-policy.test.ts +36 -3
  25. package/src/__tests__/guardian-dispatch.test.ts +124 -0
  26. package/src/__tests__/guardian-grant-minting.test.ts +6 -17
  27. package/src/__tests__/inbound-invite-redemption.test.ts +367 -0
  28. package/src/__tests__/invite-redemption-service.test.ts +306 -0
  29. package/src/__tests__/ipc-snapshot.test.ts +57 -0
  30. package/src/__tests__/notification-decision-fallback.test.ts +88 -0
  31. package/src/__tests__/sandbox-diagnostics.test.ts +6 -249
  32. package/src/__tests__/sandbox-host-parity.test.ts +6 -13
  33. package/src/__tests__/scoped-approval-grants.test.ts +6 -6
  34. package/src/__tests__/scoped-grant-security-matrix.test.ts +5 -4
  35. package/src/__tests__/script-proxy-session-manager.test.ts +1 -19
  36. package/src/__tests__/session-load-history-repair.test.ts +169 -2
  37. package/src/__tests__/session-runtime-assembly.test.ts +33 -5
  38. package/src/__tests__/skill-feature-flags-integration.test.ts +171 -0
  39. package/src/__tests__/skill-feature-flags.test.ts +188 -0
  40. package/src/__tests__/skill-load-feature-flag.test.ts +141 -0
  41. package/src/__tests__/skill-mirror-parity.test.ts +1 -0
  42. package/src/__tests__/skill-projection-feature-flag.test.ts +363 -0
  43. package/src/__tests__/system-prompt.test.ts +1 -1
  44. package/src/__tests__/terminal-sandbox.test.ts +142 -9
  45. package/src/__tests__/terminal-tools.test.ts +2 -93
  46. package/src/__tests__/thread-seed-composer.test.ts +18 -0
  47. package/src/__tests__/tool-approval-handler.test.ts +350 -0
  48. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +8 -10
  49. package/src/__tests__/voice-scoped-grant-consumer.test.ts +46 -84
  50. package/src/agent/loop.ts +36 -1
  51. package/src/approvals/approval-primitive.ts +381 -0
  52. package/src/approvals/guardian-decision-primitive.ts +191 -0
  53. package/src/calls/call-controller.ts +252 -209
  54. package/src/calls/call-domain.ts +44 -6
  55. package/src/calls/guardian-dispatch.ts +48 -0
  56. package/src/calls/types.ts +1 -1
  57. package/src/calls/voice-session-bridge.ts +46 -30
  58. package/src/cli/core-commands.ts +0 -4
  59. package/src/cli/mcp.ts +58 -0
  60. package/src/cli.ts +76 -34
  61. package/src/config/__tests__/feature-flag-registry-guard.test.ts +179 -0
  62. package/src/config/assistant-feature-flags.ts +162 -0
  63. package/src/config/bundled-skills/api-mapping/icon.svg +18 -0
  64. package/src/config/bundled-skills/messaging/TOOLS.json +30 -0
  65. package/src/config/bundled-skills/messaging/tools/slack-delete-message.ts +24 -0
  66. package/src/config/bundled-skills/notifications/SKILL.md +1 -1
  67. package/src/config/bundled-skills/reminder/SKILL.md +49 -2
  68. package/src/config/bundled-skills/time-based-actions/SKILL.md +49 -2
  69. package/src/config/bundled-skills/voice-setup/SKILL.md +122 -0
  70. package/src/config/core-schema.ts +1 -1
  71. package/src/config/env-registry.ts +10 -0
  72. package/src/config/feature-flag-registry.json +61 -0
  73. package/src/config/loader.ts +22 -1
  74. package/src/config/mcp-schema.ts +46 -0
  75. package/src/config/sandbox-schema.ts +0 -39
  76. package/src/config/schema.ts +18 -2
  77. package/src/config/skill-state.ts +34 -0
  78. package/src/config/skills-schema.ts +0 -1
  79. package/src/config/skills.ts +9 -0
  80. package/src/config/system-prompt.ts +110 -46
  81. package/src/config/templates/SOUL.md +1 -1
  82. package/src/config/types.ts +19 -1
  83. package/src/config/vellum-skills/catalog.json +1 -1
  84. package/src/config/vellum-skills/guardian-verify-setup/SKILL.md +1 -0
  85. package/src/config/vellum-skills/sms-setup/SKILL.md +1 -1
  86. package/src/config/vellum-skills/telegram-setup/SKILL.md +6 -5
  87. package/src/config/vellum-skills/trusted-contacts/SKILL.md +105 -3
  88. package/src/config/vellum-skills/twilio-setup/SKILL.md +1 -1
  89. package/src/daemon/config-watcher.ts +0 -1
  90. package/src/daemon/daemon-control.ts +1 -1
  91. package/src/daemon/guardian-invite-intent.ts +124 -0
  92. package/src/daemon/handlers/avatar.ts +68 -0
  93. package/src/daemon/handlers/browser.ts +2 -2
  94. package/src/daemon/handlers/guardian-actions.ts +120 -0
  95. package/src/daemon/handlers/index.ts +4 -0
  96. package/src/daemon/handlers/sessions.ts +19 -0
  97. package/src/daemon/handlers/shared.ts +3 -1
  98. package/src/daemon/install-cli-launchers.ts +58 -13
  99. package/src/daemon/ipc-contract/guardian-actions.ts +53 -0
  100. package/src/daemon/ipc-contract/sessions.ts +8 -2
  101. package/src/daemon/ipc-contract/settings.ts +25 -2
  102. package/src/daemon/ipc-contract-inventory.json +10 -0
  103. package/src/daemon/ipc-contract.ts +4 -0
  104. package/src/daemon/lifecycle.ts +14 -2
  105. package/src/daemon/main.ts +1 -0
  106. package/src/daemon/providers-setup.ts +26 -1
  107. package/src/daemon/server.ts +1 -0
  108. package/src/daemon/session-lifecycle.ts +52 -7
  109. package/src/daemon/session-memory.ts +45 -0
  110. package/src/daemon/session-process.ts +258 -432
  111. package/src/daemon/session-runtime-assembly.ts +12 -0
  112. package/src/daemon/session-skill-tools.ts +14 -1
  113. package/src/daemon/session-tool-setup.ts +5 -0
  114. package/src/daemon/session.ts +11 -0
  115. package/src/daemon/shutdown-handlers.ts +11 -0
  116. package/src/daemon/tool-side-effects.ts +35 -9
  117. package/src/index.ts +2 -2
  118. package/src/mcp/client.ts +152 -0
  119. package/src/mcp/manager.ts +139 -0
  120. package/src/memory/conversation-display-order-migration.ts +44 -0
  121. package/src/memory/conversation-queries.ts +2 -0
  122. package/src/memory/conversation-store.ts +91 -0
  123. package/src/memory/db-init.ts +5 -1
  124. package/src/memory/embedding-local.ts +13 -8
  125. package/src/memory/guardian-action-store.ts +125 -2
  126. package/src/memory/ingress-invite-store.ts +95 -1
  127. package/src/memory/migrations/035-guardian-action-supersession.ts +23 -0
  128. package/src/memory/migrations/index.ts +2 -1
  129. package/src/memory/schema.ts +5 -1
  130. package/src/memory/scoped-approval-grants.ts +14 -5
  131. package/src/messaging/providers/slack/client.ts +12 -0
  132. package/src/messaging/providers/slack/types.ts +5 -0
  133. package/src/notifications/decision-engine.ts +49 -12
  134. package/src/notifications/emit-signal.ts +7 -0
  135. package/src/notifications/signal.ts +7 -0
  136. package/src/notifications/thread-seed-composer.ts +2 -1
  137. package/src/runtime/channel-approval-types.ts +16 -6
  138. package/src/runtime/channel-approvals.ts +19 -15
  139. package/src/runtime/channel-invite-transport.ts +85 -0
  140. package/src/runtime/channel-invite-transports/telegram.ts +105 -0
  141. package/src/runtime/guardian-action-grant-minter.ts +92 -35
  142. package/src/runtime/guardian-action-message-composer.ts +30 -0
  143. package/src/runtime/guardian-decision-types.ts +91 -0
  144. package/src/runtime/http-server.ts +23 -1
  145. package/src/runtime/ingress-service.ts +22 -0
  146. package/src/runtime/invite-redemption-service.ts +181 -0
  147. package/src/runtime/invite-redemption-templates.ts +39 -0
  148. package/src/runtime/routes/call-routes.ts +2 -1
  149. package/src/runtime/routes/guardian-action-routes.ts +206 -0
  150. package/src/runtime/routes/guardian-approval-interception.ts +66 -190
  151. package/src/runtime/routes/identity-routes.ts +73 -0
  152. package/src/runtime/routes/inbound-message-handler.ts +486 -394
  153. package/src/runtime/routes/pairing-routes.ts +4 -0
  154. package/src/security/encrypted-store.ts +31 -17
  155. package/src/security/keychain.ts +176 -2
  156. package/src/security/secure-keys.ts +97 -0
  157. package/src/security/tool-approval-digest.ts +1 -1
  158. package/src/tools/browser/browser-execution.ts +2 -2
  159. package/src/tools/browser/browser-manager.ts +46 -32
  160. package/src/tools/browser/browser-screencast.ts +2 -2
  161. package/src/tools/calls/call-start.ts +1 -1
  162. package/src/tools/executor.ts +22 -17
  163. package/src/tools/mcp/mcp-tool-factory.ts +100 -0
  164. package/src/tools/network/script-proxy/session-manager.ts +1 -5
  165. package/src/tools/registry.ts +64 -1
  166. package/src/tools/skills/load.ts +22 -8
  167. package/src/tools/system/avatar-generator.ts +119 -0
  168. package/src/tools/system/navigate-settings.ts +65 -0
  169. package/src/tools/system/open-system-settings.ts +75 -0
  170. package/src/tools/system/voice-config.ts +121 -32
  171. package/src/tools/terminal/backends/native.ts +40 -19
  172. package/src/tools/terminal/backends/types.ts +3 -3
  173. package/src/tools/terminal/parser.ts +1 -1
  174. package/src/tools/terminal/sandbox-diagnostics.ts +6 -87
  175. package/src/tools/terminal/sandbox.ts +1 -12
  176. package/src/tools/terminal/shell.ts +3 -31
  177. package/src/tools/tool-approval-handler.ts +141 -3
  178. package/src/tools/tool-manifest.ts +6 -0
  179. package/src/tools/types.ts +10 -2
  180. package/src/util/diff.ts +36 -13
  181. package/Dockerfile.sandbox +0 -5
  182. package/src/__tests__/doordash-client.test.ts +0 -187
  183. package/src/__tests__/doordash-session.test.ts +0 -154
  184. package/src/__tests__/signup-e2e.test.ts +0 -354
  185. package/src/__tests__/terminal-sandbox-docker.test.ts +0 -1065
  186. package/src/__tests__/terminal-sandbox.integration.test.ts +0 -180
  187. package/src/cli/doordash.ts +0 -1057
  188. package/src/config/bundled-skills/doordash/SKILL.md +0 -163
  189. package/src/config/templates/LOOKS.md +0 -25
  190. package/src/doordash/cart-queries.ts +0 -787
  191. package/src/doordash/client.ts +0 -1016
  192. package/src/doordash/order-queries.ts +0 -85
  193. package/src/doordash/queries.ts +0 -13
  194. package/src/doordash/query-extractor.ts +0 -94
  195. package/src/doordash/search-queries.ts +0 -203
  196. package/src/doordash/session.ts +0 -84
  197. package/src/doordash/store-queries.ts +0 -246
  198. package/src/doordash/types.ts +0 -367
  199. package/src/tools/terminal/backends/docker.ts +0 -379
@@ -9,6 +9,13 @@ export interface VoiceConfigUpdateRequest {
9
9
  activationKey: string;
10
10
  }
11
11
 
12
+ /** Request from the client to generate a custom avatar via Gemini. */
13
+ export interface GenerateAvatarRequest {
14
+ type: 'generate_avatar';
15
+ /** Text description of the desired avatar appearance. */
16
+ description: string;
17
+ }
18
+
12
19
  // === Server → Client ===
13
20
 
14
21
  /** Sent by the daemon to update a client-side setting (e.g. activation key). */
@@ -20,7 +27,23 @@ export interface ClientSettingsUpdate {
20
27
  value: string;
21
28
  }
22
29
 
30
+ /** Sent by the daemon after the avatar image has been regenerated and saved to disk. */
31
+ export interface AvatarUpdated {
32
+ type: 'avatar_updated';
33
+ /** Absolute path to the updated avatar image file. */
34
+ avatarPath: string;
35
+ }
36
+
37
+ /** Response to a generate_avatar request indicating success or failure. */
38
+ export interface GenerateAvatarResponse {
39
+ type: 'generate_avatar_response';
40
+ /** Whether the avatar was generated successfully. */
41
+ success: boolean;
42
+ /** Error message when success is false. */
43
+ error?: string;
44
+ }
45
+
23
46
  // --- Domain-level union aliases (consumed by the barrel file) ---
24
47
 
25
- export type _SettingsClientMessages = VoiceConfigUpdateRequest;
26
- export type _SettingsServerMessages = ClientSettingsUpdate;
48
+ export type _SettingsClientMessages = VoiceConfigUpdateRequest | GenerateAvatarRequest;
49
+ export type _SettingsServerMessages = ClientSettingsUpdate | AvatarUpdated | GenerateAvatarResponse;
@@ -5,6 +5,7 @@
5
5
  "_ComputerUseClientMessages",
6
6
  "_DiagnosticsClientMessages",
7
7
  "_DocumentsClientMessages",
8
+ "_GuardianActionsClientMessages",
8
9
  "_InboxClientMessages",
9
10
  "_IntegrationsClientMessages",
10
11
  "_MessagesClientMessages",
@@ -28,6 +29,7 @@
28
29
  "_ComputerUseServerMessages",
29
30
  "_DiagnosticsServerMessages",
30
31
  "_DocumentsServerMessages",
32
+ "_GuardianActionsServerMessages",
31
33
  "_InboxServerMessages",
32
34
  "_IntegrationsServerMessages",
33
35
  "_MemoryServerMessages",
@@ -86,7 +88,10 @@
86
88
  "fork_shared_app",
87
89
  "gallery_install",
88
90
  "gallery_list",
91
+ "generate_avatar",
89
92
  "get_signing_identity_response",
93
+ "guardian_action_decision",
94
+ "guardian_actions_pending_request",
90
95
  "guardian_verification",
91
96
  "heartbeat_checklist_read",
92
97
  "heartbeat_checklist_write",
@@ -124,6 +129,7 @@
124
129
  "reminder_cancel",
125
130
  "reminders_list",
126
131
  "remove_trust_rule",
132
+ "reorder_threads",
127
133
  "ride_shotgun_start",
128
134
  "ride_shotgun_stop",
129
135
  "sandbox_set",
@@ -210,6 +216,7 @@
210
216
  "assistant_text_delta",
211
217
  "assistant_thinking_delta",
212
218
  "auth_result",
219
+ "avatar_updated",
213
220
  "browser_cdp_request",
214
221
  "browser_frame",
215
222
  "browser_handoff_request",
@@ -236,9 +243,12 @@
236
243
  "fork_shared_app_response",
237
244
  "gallery_install_response",
238
245
  "gallery_list_response",
246
+ "generate_avatar_response",
239
247
  "generation_cancelled",
240
248
  "generation_handoff",
241
249
  "get_signing_identity",
250
+ "guardian_action_decision_response",
251
+ "guardian_actions_pending_response",
242
252
  "guardian_verification_response",
243
253
  "heartbeat_alert",
244
254
  "heartbeat_checklist_response",
@@ -18,6 +18,7 @@ export * from './ipc-contract/browser.js';
18
18
  export * from './ipc-contract/computer-use.js';
19
19
  export * from './ipc-contract/diagnostics.js';
20
20
  export * from './ipc-contract/documents.js';
21
+ export * from './ipc-contract/guardian-actions.js';
21
22
  export * from './ipc-contract/inbox.js';
22
23
  export * from './ipc-contract/integrations.js';
23
24
  export * from './ipc-contract/memory.js';
@@ -42,6 +43,7 @@ import type { _BrowserClientMessages, _BrowserServerMessages } from './ipc-contr
42
43
  import type { _ComputerUseClientMessages, _ComputerUseServerMessages } from './ipc-contract/computer-use.js';
43
44
  import type { _DiagnosticsClientMessages, _DiagnosticsServerMessages } from './ipc-contract/diagnostics.js';
44
45
  import type { _DocumentsClientMessages, _DocumentsServerMessages } from './ipc-contract/documents.js';
46
+ import type { _GuardianActionsClientMessages, _GuardianActionsServerMessages } from './ipc-contract/guardian-actions.js';
45
47
  import type { _InboxClientMessages, _InboxServerMessages } from './ipc-contract/inbox.js';
46
48
  import type { _IntegrationsClientMessages, _IntegrationsServerMessages } from './ipc-contract/integrations.js';
47
49
  import type { _MemoryServerMessages } from './ipc-contract/memory.js';
@@ -83,6 +85,7 @@ export type ClientMessage =
83
85
  | _BrowserClientMessages
84
86
  | _SubagentsClientMessages
85
87
  | _DocumentsClientMessages
88
+ | _GuardianActionsClientMessages
86
89
  | _WorkspaceClientMessages
87
90
  | _SchedulesClientMessages
88
91
  | _DiagnosticsClientMessages
@@ -107,6 +110,7 @@ export type ServerMessage =
107
110
  | _BrowserServerMessages
108
111
  | _SubagentsServerMessages
109
112
  | _DocumentsServerMessages
113
+ | _GuardianActionsServerMessages
110
114
  | _MemoryServerMessages
111
115
  | _WorkspaceServerMessages
112
116
  | _SchedulesServerMessages
@@ -54,10 +54,11 @@ import { createGuardianActionCopyGenerator, createGuardianFollowUpConversationGe
54
54
  import { initPairingHandlers } from './handlers/pairing.js';
55
55
  import { installCliLaunchers } from './install-cli-launchers.js';
56
56
  import type { ServerMessage } from './ipc-protocol.js';
57
+ import { getMcpServerManager } from '../mcp/manager.js';
57
58
  import { initializeProvidersAndTools, registerMessagingProviders,registerWatcherProviders } from './providers-setup.js';
58
59
  import { seedInterfaceFiles } from './seed-files.js';
59
60
  import { DaemonServer } from './server.js';
60
- import { setGuardianActionCopyGenerator, setGuardianFollowUpConversationGenerator } from './session-process.js';
61
+ import { setApprovalConversationGenerator, setGuardianActionCopyGenerator, setGuardianFollowUpConversationGenerator } from './session-process.js';
61
62
  import { initSlashPairingContext } from './session-slash.js';
62
63
  import { installShutdownHandlers } from './shutdown-handlers.js';
63
64
 
@@ -307,7 +308,11 @@ export async function runDaemon(): Promise<void> {
307
308
  server.persistAndProcessMessage(conversationId, content, attachmentIds, options, sourceChannel, sourceInterface),
308
309
  interfacesDir: getInterfacesDir(),
309
310
  approvalCopyGenerator: createApprovalCopyGenerator(),
310
- approvalConversationGenerator: createApprovalConversationGenerator(),
311
+ approvalConversationGenerator: (() => {
312
+ const gen = createApprovalConversationGenerator();
313
+ setApprovalConversationGenerator(gen);
314
+ return gen;
315
+ })(),
311
316
  guardianActionCopyGenerator: (() => {
312
317
  const gen = createGuardianActionCopyGenerator();
313
318
  setGuardianActionCopyGenerator(gen);
@@ -394,6 +399,12 @@ export async function runDaemon(): Promise<void> {
394
399
  server.setHeartbeatService(heartbeat);
395
400
  log.info({ enabled: heartbeatConfig.enabled, intervalMs: heartbeatConfig.intervalMs }, 'Heartbeat service configured');
396
401
 
402
+ // Retrieve the MCP manager if MCP servers were configured.
403
+ // The manager is a singleton created during initializeProvidersAndTools().
404
+ const mcpManager = config.mcp?.servers && Object.keys(config.mcp.servers).length > 0
405
+ ? getMcpServerManager()
406
+ : null;
407
+
397
408
  installShutdownHandlers({
398
409
  server,
399
410
  workspaceHeartbeat,
@@ -403,6 +414,7 @@ export async function runDaemon(): Promise<void> {
403
414
  scheduler,
404
415
  memoryWorker,
405
416
  qdrantManager,
417
+ mcpManager,
406
418
  cleanupPidFile,
407
419
  });
408
420
  } catch (err) {
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env bun
2
+ process.title = 'vellum-daemon';
2
3
  import * as Sentry from '@sentry/node';
3
4
 
4
5
  import { getLogger } from '../util/logger.js';
@@ -1,4 +1,5 @@
1
1
  import type { AssistantConfig } from '../config/types.js';
2
+ import { getMcpServerManager } from '../mcp/manager.js';
2
3
  import { gmailMessagingProvider } from '../messaging/providers/gmail/adapter.js';
3
4
  import { slackProvider as slackMessagingProvider } from '../messaging/providers/slack/adapter.js';
4
5
  import { smsMessagingProvider } from '../messaging/providers/sms/adapter.js';
@@ -6,7 +7,8 @@ import { telegramBotMessagingProvider } from '../messaging/providers/telegram-bo
6
7
  import { whatsappMessagingProvider } from '../messaging/providers/whatsapp/adapter.js';
7
8
  import { registerMessagingProvider } from '../messaging/registry.js';
8
9
  import { initializeProviders } from '../providers/registry.js';
9
- import { initializeTools } from '../tools/registry.js';
10
+ import { createMcpToolsFromServer } from '../tools/mcp/mcp-tool-factory.js';
11
+ import { initializeTools, registerMcpTools } from '../tools/registry.js';
10
12
  import { getLogger } from '../util/logger.js';
11
13
  import { initWatcherEngine } from '../watcher/engine.js';
12
14
  import { registerWatcherProvider } from '../watcher/provider-registry.js';
@@ -19,9 +21,32 @@ import { slackProvider as slackWatcherProvider } from '../watcher/providers/slac
19
21
  const log = getLogger('lifecycle');
20
22
 
21
23
  export async function initializeProvidersAndTools(config: AssistantConfig): Promise<void> {
24
+ console.log('[Daemon] Initializing providers and tools...');
22
25
  log.info('Daemon startup: initializing providers and tools');
23
26
  initializeProviders(config);
27
+ console.log('[Daemon] Providers initialized');
24
28
  await initializeTools();
29
+ console.log('[Daemon] Tools initialized');
30
+
31
+ // Start MCP servers and register their tools
32
+ if (config.mcp?.servers && Object.keys(config.mcp.servers).length > 0) {
33
+ console.log('[MCP] Initializing MCP servers:', Object.keys(config.mcp.servers).join(', '));
34
+ const manager = getMcpServerManager();
35
+ try {
36
+ const serverToolInfos = await manager.start(config.mcp);
37
+ for (const { serverId, serverConfig, tools } of serverToolInfos) {
38
+ console.log(`[MCP] Server "${serverId}" connected — discovered ${tools.length} tools:`, tools.map(t => t.name).join(', '));
39
+ const mcpTools = createMcpToolsFromServer(tools, serverId, serverConfig, manager);
40
+ registerMcpTools(mcpTools);
41
+ console.log(`[MCP] Registered ${mcpTools.length} tools from "${serverId}":`, mcpTools.map(t => t.name).join(', '));
42
+ }
43
+ } catch (err) {
44
+ console.error('[MCP] Server initialization failed:', err);
45
+ log.error({ err }, 'MCP server initialization failed — continuing without MCP tools');
46
+ }
47
+ }
48
+
49
+ console.log('[Daemon] Providers and tools initialization complete');
25
50
  log.info('Daemon startup: providers and tools initialized');
26
51
  }
27
52
 
@@ -795,6 +795,7 @@ export class DaemonServer {
795
795
  const resolvedInterface = resolveTurnInterface(sourceInterface);
796
796
  session.setAssistantId(options?.assistantId ?? 'self');
797
797
  session.setGuardianContext(options?.guardianContext ?? null);
798
+ await session.ensureActorScopedHistory();
798
799
  session.setChannelCapabilities(resolveChannelCapabilities(sourceChannel, sourceInterface));
799
800
  session.setCommandIntent(options?.commandIntent ?? null);
800
801
  session.setTurnChannelContext({
@@ -19,10 +19,38 @@ import { repairHistory } from './history-repair.js';
19
19
  import type { SurfaceData,SurfaceType, UsageStats } from './ipc-protocol.js';
20
20
  import { unregisterCallNotifiers,unregisterWatchNotifiers } from './session-notifiers.js';
21
21
  import type { MessageQueue } from './session-queue-manager.js';
22
+ import type { GuardianRuntimeContext } from './session-runtime-assembly.js';
22
23
  import { resetSkillToolProjection } from './session-skill-tools.js';
23
24
 
24
25
  const log = getLogger('session-lifecycle');
25
26
 
27
+ type GuardianActorRole = GuardianRuntimeContext['actorRole'];
28
+
29
+ function parseProvenanceActorRole(metadata: string | null): GuardianActorRole | undefined {
30
+ if (!metadata) return undefined;
31
+ try {
32
+ const parsed = JSON.parse(metadata) as { provenanceActorRole?: unknown };
33
+ const role = parsed?.provenanceActorRole;
34
+ if (role === 'guardian' || role === 'non-guardian' || role === 'unverified_channel') {
35
+ return role;
36
+ }
37
+ } catch {
38
+ // Ignore malformed metadata and treat as unknown provenance.
39
+ }
40
+ return undefined;
41
+ }
42
+
43
+ function isUntrustedActorRole(role: GuardianActorRole | undefined): boolean {
44
+ return role === 'non-guardian' || role === 'unverified_channel';
45
+ }
46
+
47
+ function filterMessagesForUntrustedActor(messages: conversationStore.MessageRow[]): conversationStore.MessageRow[] {
48
+ return messages.filter((m) => {
49
+ const provenanceRole = parseProvenanceActorRole(m.metadata);
50
+ return provenanceRole === 'non-guardian' || provenanceRole === 'unverified_channel';
51
+ });
52
+ }
53
+
26
54
  // ── Context Interfaces ───────────────────────────────────────────────
27
55
 
28
56
  export interface LoadFromDbContext {
@@ -31,6 +59,8 @@ export interface LoadFromDbContext {
31
59
  usageStats: UsageStats;
32
60
  contextCompactedMessageCount: number;
33
61
  contextCompactedAt: number | null;
62
+ guardianContext?: { actorRole: GuardianActorRole };
63
+ loadedHistoryActorRole?: GuardianActorRole;
34
64
  }
35
65
 
36
66
  export interface AbortContext {
@@ -59,15 +89,28 @@ export interface DisposeContext extends AbortContext {
59
89
  // ── loadFromDb ───────────────────────────────────────────────────────
60
90
 
61
91
  export async function loadFromDb(ctx: LoadFromDbContext): Promise<void> {
62
- const dbMessages = conversationStore.getMessages(ctx.conversationId);
92
+ const actorRole = ctx.guardianContext?.actorRole;
93
+ const allDbMessages = conversationStore.getMessages(ctx.conversationId);
94
+ const dbMessages = isUntrustedActorRole(actorRole)
95
+ ? filterMessagesForUntrustedActor(allDbMessages)
96
+ : allDbMessages;
63
97
 
64
98
  const conv = conversationStore.getConversation(ctx.conversationId);
65
- const contextSummary = conv?.contextSummary?.trim() || null;
66
- ctx.contextCompactedMessageCount = Math.max(
67
- 0,
68
- Math.min(conv?.contextCompactedMessageCount ?? 0, dbMessages.length),
69
- );
70
- ctx.contextCompactedAt = conv?.contextCompactedAt ?? null;
99
+ const contextSummary = !isUntrustedActorRole(actorRole)
100
+ ? conv?.contextSummary?.trim() || null
101
+ : null;
102
+ if (isUntrustedActorRole(actorRole)) {
103
+ // Compacted summaries may include trusted/guardian-only details, so we
104
+ // disable summary-based context for untrusted actor views.
105
+ ctx.contextCompactedMessageCount = 0;
106
+ ctx.contextCompactedAt = null;
107
+ } else {
108
+ ctx.contextCompactedMessageCount = Math.max(
109
+ 0,
110
+ Math.min(conv?.contextCompactedMessageCount ?? 0, dbMessages.length),
111
+ );
112
+ ctx.contextCompactedAt = conv?.contextCompactedAt ?? null;
113
+ }
71
114
 
72
115
  const parsedMessages: Message[] = dbMessages
73
116
  .slice(ctx.contextCompactedMessageCount)
@@ -102,6 +145,8 @@ export async function loadFromDb(ctx: LoadFromDbContext): Promise<void> {
102
145
  };
103
146
  }
104
147
 
148
+ ctx.loadedHistoryActorRole = actorRole;
149
+
105
150
  log.info({ conversationId: ctx.conversationId, count: ctx.messages.length }, 'Loaded messages from DB');
106
151
  }
107
152
 
@@ -39,6 +39,16 @@ export interface MemoryPrepareContext {
39
39
  isInteractive?: boolean;
40
40
  }
41
41
 
42
+ /**
43
+ * Returns true when the latest user turn is an internal tool-result-only
44
+ * message (no user-authored text/image content).
45
+ */
46
+ function isToolResultOnlyUserTurn(message: Message | undefined): boolean {
47
+ return message?.role === 'user'
48
+ && message.content.length > 0
49
+ && message.content.every((block) => block.type === 'tool_result');
50
+ }
51
+
42
52
  /**
43
53
  * Build memory recall, dynamic profile, and conflict gate evaluation
44
54
  * for a single agent loop turn. Returns the augmented run messages and
@@ -86,6 +96,41 @@ export async function prepareMemoryContext(
86
96
  };
87
97
  }
88
98
 
99
+ // Internal tool-result turns (assistant tool loop) should not trigger
100
+ // memory retrieval/profile injection. Injecting memory here repeats the
101
+ // same long recall block on every tool step and dramatically inflates
102
+ // per-step prompt size/latency.
103
+ const latestMessage = ctx.messages[ctx.messages.length - 1];
104
+ if (isToolResultOnlyUserTurn(latestMessage)) {
105
+ return {
106
+ runMessages: ctx.messages,
107
+ recall: {
108
+ enabled: false,
109
+ degraded: false,
110
+ injectedText: '',
111
+ lexicalHits: 0,
112
+ semanticHits: 0,
113
+ recencyHits: 0,
114
+ entityHits: 0,
115
+ relationSeedEntityCount: 0,
116
+ relationTraversedEdgeCount: 0,
117
+ relationNeighborEntityCount: 0,
118
+ relationExpandedItemCount: 0,
119
+ earlyTerminated: false,
120
+ mergedCount: 0,
121
+ selectedCount: 0,
122
+ rerankApplied: false,
123
+ injectedTokens: 0,
124
+ latencyMs: 0,
125
+ topCandidates: [],
126
+ } as Awaited<ReturnType<typeof buildMemoryRecall>>,
127
+ dynamicProfile: { text: '' },
128
+ softConflictInstruction: null,
129
+ recallInjectionStrategy: 'prepend_user_block',
130
+ conflictClarification: null,
131
+ };
132
+ }
133
+
89
134
  const runtimeConfig = getConfig();
90
135
  const memoryEnabled = runtimeConfig.memory?.enabled !== false;
91
136