@vellumai/assistant 0.5.7 → 0.5.9

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 (205) hide show
  1. package/Dockerfile +2 -1
  2. package/docker-entrypoint.sh +9 -0
  3. package/docs/architecture/memory.md +13 -11
  4. package/eslint.config.mjs +0 -31
  5. package/node_modules/@vellumai/ces-contracts/src/error.ts +1 -1
  6. package/node_modules/@vellumai/ces-contracts/src/grants.ts +1 -1
  7. package/node_modules/@vellumai/ces-contracts/src/handles.ts +1 -1
  8. package/node_modules/@vellumai/ces-contracts/src/index.ts +1 -1
  9. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +1 -1
  10. package/package.json +1 -1
  11. package/src/__tests__/approval-cascade.test.ts +0 -1
  12. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  13. package/src/__tests__/call-controller.test.ts +0 -1
  14. package/src/__tests__/ces-rpc-credential-backend.test.ts +3 -3
  15. package/src/__tests__/ces-startup-timeout.test.ts +40 -0
  16. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  17. package/src/__tests__/config-schema.test.ts +2 -0
  18. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -1
  19. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
  20. package/src/__tests__/conversation-agent-loop.test.ts +2 -4
  21. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -1
  22. package/src/__tests__/conversation-error.test.ts +15 -1
  23. package/src/__tests__/conversation-messaging-secret-redirect.test.ts +1 -1
  24. package/src/__tests__/conversation-pre-run-repair.test.ts +0 -1
  25. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -1
  26. package/src/__tests__/conversation-queue.test.ts +0 -1
  27. package/src/__tests__/conversation-runtime-assembly.test.ts +227 -0
  28. package/src/__tests__/conversation-slash-queue.test.ts +0 -1
  29. package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
  30. package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
  31. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
  32. package/src/__tests__/credential-execution-client.test.ts +5 -2
  33. package/src/__tests__/credential-execution-feature-gates.test.ts +31 -16
  34. package/src/__tests__/credential-execution-managed-contract.test.ts +2 -2
  35. package/src/__tests__/credential-security-e2e.test.ts +1 -1
  36. package/src/__tests__/credential-security-invariants.test.ts +2 -5
  37. package/src/__tests__/credentials-cli.test.ts +4 -3
  38. package/src/__tests__/daemon-credential-client.test.ts +123 -0
  39. package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -0
  40. package/src/__tests__/gateway-client-managed-outbound.test.ts +79 -1
  41. package/src/__tests__/journal-context.test.ts +335 -0
  42. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -3
  43. package/src/__tests__/memory-lifecycle-e2e.test.ts +70 -25
  44. package/src/__tests__/memory-recall-quality.test.ts +48 -17
  45. package/src/__tests__/memory-regressions.test.ts +408 -363
  46. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -3
  47. package/src/__tests__/non-member-access-request.test.ts +2 -2
  48. package/src/__tests__/notification-decision-strategy.test.ts +71 -0
  49. package/src/__tests__/oauth-cli.test.ts +5 -1
  50. package/src/__tests__/provider-commit-message-generator.test.ts +0 -37
  51. package/src/__tests__/provider-error-scenarios.test.ts +0 -267
  52. package/src/__tests__/provider-streaming.benchmark.test.ts +2 -81
  53. package/src/__tests__/relay-server.test.ts +1 -2
  54. package/src/__tests__/script-proxy-injection-runtime.test.ts +1 -1
  55. package/src/__tests__/secret-onetime-send.test.ts +1 -1
  56. package/src/__tests__/secure-keys.test.ts +18 -15
  57. package/src/__tests__/skill-memory.test.ts +17 -3
  58. package/src/__tests__/stale-approval-dedup.test.ts +171 -0
  59. package/src/__tests__/stt-hints.test.ts +437 -0
  60. package/src/__tests__/task-memory-cleanup.test.ts +14 -0
  61. package/src/__tests__/twilio-routes-twiml.test.ts +139 -1
  62. package/src/__tests__/voice-quality.test.ts +58 -0
  63. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
  64. package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +5 -3
  65. package/src/acp/agent-process.ts +9 -1
  66. package/src/agent/loop.ts +1 -1
  67. package/src/approvals/guardian-request-resolvers.ts +164 -38
  68. package/src/calls/__tests__/tts-text-sanitizer.test.ts +254 -0
  69. package/src/calls/call-controller.ts +9 -5
  70. package/src/calls/fish-audio-client.ts +26 -14
  71. package/src/calls/stt-hints.ts +189 -0
  72. package/src/calls/tts-text-sanitizer.ts +61 -0
  73. package/src/calls/twilio-routes.ts +32 -4
  74. package/src/calls/voice-quality.ts +15 -3
  75. package/src/calls/voice-session-bridge.ts +1 -0
  76. package/src/cli/commands/avatar.ts +2 -2
  77. package/src/cli/commands/credentials.ts +110 -94
  78. package/src/cli/commands/doctor.ts +2 -2
  79. package/src/cli/commands/keys.ts +7 -7
  80. package/src/cli/commands/memory.ts +1 -1
  81. package/src/cli/commands/oauth/connections.ts +11 -29
  82. package/src/cli/commands/oauth/platform.ts +389 -43
  83. package/src/cli/lib/daemon-credential-client.ts +284 -0
  84. package/src/cli.ts +1 -1
  85. package/src/config/bundled-skills/AGENTS.md +34 -0
  86. package/src/config/bundled-skills/acp/SKILL.md +10 -0
  87. package/src/config/bundled-skills/app-builder/SKILL.md +0 -4
  88. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
  89. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -0
  90. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -0
  91. package/src/config/bundled-skills/settings/SKILL.md +15 -2
  92. package/src/config/bundled-skills/settings/TOOLS.json +46 -1
  93. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +59 -0
  94. package/src/config/bundled-skills/settings/tools/avatar-update.ts +80 -0
  95. package/src/config/bundled-skills/slack/SKILL.md +1 -1
  96. package/src/config/bundled-tool-registry.ts +4 -0
  97. package/src/config/defaults.ts +0 -2
  98. package/src/config/env-registry.ts +4 -4
  99. package/src/config/env.ts +14 -1
  100. package/src/config/feature-flag-registry.json +1 -1
  101. package/src/config/loader.ts +8 -11
  102. package/src/config/schema.ts +5 -16
  103. package/src/config/schemas/calls.ts +17 -0
  104. package/src/config/schemas/inference.ts +2 -2
  105. package/src/config/schemas/journal.ts +16 -0
  106. package/src/config/schemas/memory-processing.ts +2 -2
  107. package/src/config/types.ts +1 -0
  108. package/src/contacts/contact-store.ts +2 -2
  109. package/src/credential-execution/executable-discovery.ts +1 -1
  110. package/src/credential-execution/startup-timeout.ts +36 -0
  111. package/src/daemon/approval-generators.ts +3 -9
  112. package/src/daemon/conversation-agent-loop.ts +6 -0
  113. package/src/daemon/conversation-error.ts +13 -1
  114. package/src/daemon/conversation-memory.ts +1 -2
  115. package/src/daemon/conversation-process.ts +18 -1
  116. package/src/daemon/conversation-runtime-assembly.ts +61 -1
  117. package/src/daemon/conversation-surfaces.ts +30 -1
  118. package/src/daemon/conversation.ts +20 -9
  119. package/src/daemon/guardian-action-generators.ts +3 -9
  120. package/src/daemon/lifecycle.ts +18 -11
  121. package/src/daemon/message-types/conversations.ts +1 -0
  122. package/src/daemon/server.ts +2 -3
  123. package/src/memory/app-store.ts +31 -0
  124. package/src/memory/db-init.ts +4 -0
  125. package/src/memory/indexer.ts +19 -10
  126. package/src/memory/items-extractor.ts +315 -322
  127. package/src/memory/job-handlers/summarization.ts +26 -16
  128. package/src/memory/jobs-store.ts +33 -1
  129. package/src/memory/journal-memory.ts +214 -0
  130. package/src/memory/migrations/193-add-source-type-columns.ts +81 -0
  131. package/src/memory/migrations/index.ts +1 -0
  132. package/src/memory/migrations/registry.ts +8 -0
  133. package/src/memory/retriever.test.ts +37 -25
  134. package/src/memory/retriever.ts +24 -49
  135. package/src/memory/schema/memory-core.ts +2 -0
  136. package/src/memory/search/formatting.ts +7 -44
  137. package/src/memory/search/staleness.ts +4 -0
  138. package/src/memory/search/tier-classifier.ts +10 -2
  139. package/src/memory/search/types.ts +2 -5
  140. package/src/memory/task-memory-cleanup.ts +4 -3
  141. package/src/notifications/adapters/slack.ts +168 -6
  142. package/src/notifications/broadcaster.ts +1 -0
  143. package/src/notifications/copy-composer.ts +59 -2
  144. package/src/notifications/signal.ts +2 -0
  145. package/src/notifications/types.ts +2 -0
  146. package/src/prompts/journal-context.ts +133 -0
  147. package/src/prompts/persona-resolver.ts +80 -24
  148. package/src/prompts/system-prompt.ts +30 -0
  149. package/src/prompts/templates/NOW.md +26 -0
  150. package/src/prompts/templates/SOUL.md +20 -0
  151. package/src/prompts/update-bulletin-format.ts +0 -2
  152. package/src/providers/provider-send-message.ts +3 -32
  153. package/src/providers/registry.ts +2 -139
  154. package/src/providers/types.ts +1 -1
  155. package/src/runtime/access-request-helper.ts +4 -0
  156. package/src/runtime/auth/__tests__/guard-tests.test.ts +9 -50
  157. package/src/runtime/auth/route-policy.ts +2 -0
  158. package/src/runtime/gateway-client.ts +47 -4
  159. package/src/runtime/guardian-decision-types.ts +45 -4
  160. package/src/runtime/http-server.ts +5 -2
  161. package/src/runtime/routes/access-request-decision.ts +2 -2
  162. package/src/runtime/routes/app-management-routes.ts +2 -1
  163. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +219 -30
  164. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +37 -14
  165. package/src/runtime/routes/channel-readiness-routes.ts +9 -4
  166. package/src/runtime/routes/debug-routes.ts +12 -9
  167. package/src/runtime/routes/guardian-approval-interception.ts +168 -11
  168. package/src/runtime/routes/guardian-approval-prompt.ts +6 -1
  169. package/src/runtime/routes/guardian-approval-reply-helpers.ts +103 -21
  170. package/src/runtime/routes/identity-routes.ts +1 -1
  171. package/src/runtime/routes/inbound-message-handler.ts +31 -1
  172. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +64 -5
  173. package/src/runtime/routes/inbound-stages/background-dispatch.ts +52 -40
  174. package/src/runtime/routes/integrations/twilio.ts +52 -10
  175. package/src/runtime/routes/memory-item-routes.test.ts +3 -3
  176. package/src/runtime/routes/memory-item-routes.ts +25 -11
  177. package/src/runtime/routes/secret-routes.ts +141 -10
  178. package/src/runtime/routes/tts-routes.ts +11 -1
  179. package/src/security/ces-credential-client.ts +18 -9
  180. package/src/security/ces-rpc-credential-backend.ts +4 -3
  181. package/src/security/credential-backend.ts +10 -4
  182. package/src/security/secure-keys.ts +21 -4
  183. package/src/skills/catalog-install.ts +4 -36
  184. package/src/skills/inline-command-expansions.ts +7 -7
  185. package/src/skills/skill-memory.ts +1 -0
  186. package/src/subagent/manager.ts +2 -5
  187. package/src/tools/acp/spawn.ts +78 -1
  188. package/src/tools/credentials/vault.ts +5 -3
  189. package/src/tools/memory/definitions.ts +3 -2
  190. package/src/tools/memory/handlers.ts +10 -7
  191. package/src/tools/sensitive-output-placeholders.ts +2 -2
  192. package/src/tools/terminal/safe-env.ts +1 -0
  193. package/src/util/browser.ts +15 -0
  194. package/src/util/platform.ts +1 -1
  195. package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +4 -4
  196. package/src/workspace/migrations/017-seed-persona-dirs.ts +2 -1
  197. package/src/workspace/migrations/018-rekey-compound-credential-keys.ts +184 -0
  198. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +103 -0
  199. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -4
  200. package/src/workspace/migrations/registry.ts +4 -0
  201. package/src/workspace/provider-commit-message-generator.ts +12 -21
  202. package/src/__tests__/provider-fail-open-selection.test.ts +0 -271
  203. package/src/__tests__/provider-failover-actual-provider.test.ts +0 -66
  204. package/src/memory/search/lexical.ts +0 -48
  205. package/src/providers/failover.ts +0 -186
@@ -28,6 +28,10 @@ import {
28
28
  CesUnavailableError,
29
29
  createCesProcessManager,
30
30
  } from "../credential-execution/process-manager.js";
31
+ import {
32
+ awaitCesClientWithTimeout,
33
+ DEFAULT_CES_STARTUP_TIMEOUT_MS,
34
+ } from "../credential-execution/startup-timeout.js";
31
35
  import { HeartbeatService } from "../heartbeat/heartbeat-service.js";
32
36
  import { getHookManager } from "../hooks/manager.js";
33
37
  import { installTemplates } from "../hooks/templates.js";
@@ -161,7 +165,8 @@ export interface CesStartupResult {
161
165
  export async function startCesProcess(
162
166
  config: AssistantConfig,
163
167
  ): Promise<CesStartupResult> {
164
- const shouldStartCes = isCesToolsEnabled(config) || isCesCredentialBackendEnabled(config);
168
+ const shouldStartCes =
169
+ isCesToolsEnabled(config) || isCesCredentialBackendEnabled(config);
165
170
  if (!shouldStartCes) {
166
171
  return {
167
172
  client: undefined,
@@ -456,23 +461,25 @@ export async function runDaemon(): Promise<void> {
456
461
 
457
462
  // When the credential backend flag is enabled, CES startup must complete
458
463
  // BEFORE provider initialization so credential reads can go through CES.
459
- // Block with a 3-second timeout — fall back to direct credential store
464
+ // Block with a 20-second timeout — fall back to direct credential store
460
465
  // on timeout.
461
466
  if (isCesCredentialBackendEnabled(config)) {
462
467
  const cesResult = await cesStartupPromise;
463
468
  // startCesProcess() returns immediately — the actual handshake runs
464
- // inside clientPromise. Await it (with a 3s timeout) so the CES client
469
+ // inside clientPromise. Await it (with a 20s timeout) so the CES client
465
470
  // is available before provider initialization.
466
471
  if (cesResult.clientPromise) {
467
- const client = await Promise.race([
472
+ const client = await awaitCesClientWithTimeout(
468
473
  cesResult.clientPromise,
469
- new Promise<undefined>((resolve) =>
470
- setTimeout(() => {
471
- log.warn("CES handshake timed out after 3s — falling back to direct credential store");
472
- resolve(undefined);
473
- }, 3000),
474
- ),
475
- ]);
474
+ {
475
+ timeoutMs: DEFAULT_CES_STARTUP_TIMEOUT_MS,
476
+ onTimeout: () => {
477
+ log.warn(
478
+ "CES handshake timed out after 20s — falling back to direct credential store",
479
+ );
480
+ },
481
+ },
482
+ );
476
483
  if (client) {
477
484
  setCesClient(client);
478
485
  }
@@ -371,6 +371,7 @@ export type ConversationErrorCode =
371
371
  | "PROVIDER_BILLING"
372
372
  | "PROVIDER_ORDERING"
373
373
  | "PROVIDER_WEB_SEARCH"
374
+ | "PROVIDER_NOT_CONFIGURED"
374
375
  | "CONTEXT_TOO_LARGE"
375
376
  | "CONVERSATION_ABORTED"
376
377
  | "CONVERSATION_PROCESSING_FAILED"
@@ -41,7 +41,7 @@ import { getOrCreateConversation } from "../memory/conversation-key-store.js";
41
41
  import { buildSystemPrompt } from "../prompts/system-prompt.js";
42
42
  import { RateLimitProvider } from "../providers/ratelimit.js";
43
43
  import {
44
- getFailoverProvider,
44
+ getProvider,
45
45
  initializeProviders,
46
46
  } from "../providers/registry.js";
47
47
  import { buildAssistantEvent } from "../runtime/assistant-event.js";
@@ -702,9 +702,8 @@ export class DaemonServer {
702
702
 
703
703
  const createPromise = (async () => {
704
704
  const config = getConfig();
705
- let provider = getFailoverProvider(
705
+ let provider = getProvider(
706
706
  config.services.inference.provider,
707
- config.providerOrder,
708
707
  );
709
708
  const { rateLimit } = config;
710
709
  if (rateLimit.maxRequestsPerMinute > 0) {
@@ -64,6 +64,37 @@ export function isMultifileApp(app: AppDefinition): boolean {
64
64
  return app.formatVersion === 2;
65
65
  }
66
66
 
67
+ /**
68
+ * Inline dist assets (main.js, main.css) into the compiled HTML so it can be
69
+ * delivered as a self-contained string via loadHTMLString/SSE without needing
70
+ * the client to resolve external script/stylesheet URLs.
71
+ */
72
+ export function inlineDistAssets(appDir: string, html: string): string {
73
+ const distDir = join(appDir, "dist");
74
+
75
+ // Inline main.js
76
+ const jsPath = join(distDir, "main.js");
77
+ if (existsSync(jsPath)) {
78
+ const js = readFileSync(jsPath, "utf-8");
79
+ html = html.replace(
80
+ /<script\s+type="module"\s+src="main\.js"\s*><\/script>/,
81
+ `<script type="module">${js}</script>`,
82
+ );
83
+ }
84
+
85
+ // Inline main.css
86
+ const cssPath = join(distDir, "main.css");
87
+ if (existsSync(cssPath)) {
88
+ const css = readFileSync(cssPath, "utf-8");
89
+ html = html.replace(
90
+ /<link\s+rel="stylesheet"\s+href="main\.css"\s*>/,
91
+ `<style>${css}</style>`,
92
+ );
93
+ }
94
+
95
+ return html;
96
+ }
97
+
67
98
  export interface AppRecord {
68
99
  id: string;
69
100
  appId: string;
@@ -34,6 +34,7 @@ import {
34
34
  createSequenceTables,
35
35
  createTasksAndWorkItemsTables,
36
36
  createWatchersAndLogsTables,
37
+ migrateAddSourceTypeColumns,
37
38
  migrateAssistantContactMetadata,
38
39
  migrateBackfillAudioAttachmentMimeTypes,
39
40
  migrateBackfillContactInteractionStats,
@@ -504,6 +505,9 @@ export function initializeDb(): void {
504
505
  // 89. Add user_file column to contacts for per-user persona file mapping
505
506
  migrateContactsUserFileColumn(database);
506
507
 
508
+ // 90. Add source_type and source_message_role columns to memory_items
509
+ migrateAddSourceTypeColumns(database);
510
+
507
511
  validateMigrationState(database);
508
512
 
509
513
  if (process.env.BUN_TEST === "1") {
@@ -7,7 +7,7 @@ import type { TrustClass } from "../runtime/actor-trust-resolver.js";
7
7
  import { getLogger } from "../util/logger.js";
8
8
  import { getDb } from "./db.js";
9
9
  import { selectedBackendSupportsMultimodal } from "./embedding-backend.js";
10
- import { enqueueMemoryJob } from "./jobs-store.js";
10
+ import { enqueueMemoryJob, upsertDebouncedJob } from "./jobs-store.js";
11
11
  import {
12
12
  extractMediaBlockMeta,
13
13
  extractTextFromStoredMessageContent,
@@ -17,6 +17,11 @@ import { segmentText } from "./segmenter.js";
17
17
 
18
18
  const log = getLogger("memory-indexer");
19
19
 
20
+ /** Delay before a conversation summary job becomes eligible to run.
21
+ * Each new message in the same conversation resets the timer, so the
22
+ * summary is only built once the conversation has been idle for this long. */
23
+ const SUMMARY_DEBOUNCE_MS = 3 * 60 * 1000; // 3 minutes
24
+
20
25
  export interface IndexMessageInput {
21
26
  messageId: string;
22
27
  conversationId: string;
@@ -54,9 +59,11 @@ export async function indexMessageNow(
54
59
 
55
60
  const text = extractTextFromStoredMessageContent(input.content);
56
61
  if (text.length === 0) {
57
- enqueueMemoryJob("build_conversation_summary", {
58
- conversationId: input.conversationId,
59
- });
62
+ upsertDebouncedJob(
63
+ "build_conversation_summary",
64
+ { conversationId: input.conversationId },
65
+ Date.now() + SUMMARY_DEBOUNCE_MS,
66
+ );
60
67
  return { indexedSegments: 0, enqueuedJobs: 1 };
61
68
  }
62
69
 
@@ -152,14 +159,16 @@ export async function indexMessageNow(
152
159
  tx,
153
160
  );
154
161
  }
155
- enqueueMemoryJob(
156
- "build_conversation_summary",
157
- { conversationId: input.conversationId },
158
- Date.now(),
159
- tx,
160
- );
161
162
  });
162
163
 
164
+ // Debounced outside the transaction — each new message pushes the summary
165
+ // job's runAfter forward so it only fires once the conversation is idle.
166
+ upsertDebouncedJob(
167
+ "build_conversation_summary",
168
+ { conversationId: input.conversationId },
169
+ Date.now() + SUMMARY_DEBOUNCE_MS,
170
+ );
171
+
163
172
  if (skippedEmbedJobs > 0) {
164
173
  log.debug(
165
174
  `Skipped ${skippedEmbedJobs}/${segments.length} embed_segment jobs (content unchanged)`,