@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
package/Dockerfile CHANGED
@@ -92,6 +92,7 @@ ENV IS_CONTAINERIZED=true
92
92
 
93
93
  # Copy from builder
94
94
  COPY --from=builder /app /app
95
+ RUN chmod +x /app/assistant/docker-entrypoint.sh
95
96
 
96
97
  # Run the daemon + http server
97
- CMD ["bun", "run", "src/daemon/main.ts"]
98
+ CMD ["/app/assistant/docker-entrypoint.sh"]
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ if [ "$(id -u)" = "0" ] && [ "${VELLUM_WORKSPACE_DIR:-}" = "/workspace" ] && [ -d /workspace ]; then
5
+ git config --global --add safe.directory /workspace >/dev/null 2>&1 || true
6
+ git config --global --add safe.directory '/workspace/*' >/dev/null 2>&1 || true
7
+ fi
8
+
9
+ exec bun run src/daemon/main.ts
@@ -273,7 +273,7 @@ The key distinction: normal compaction is a cost-optimized background process th
273
273
 
274
274
  1. Run a recall-heavy turn and inspect `memory_recalled` events in the client trace stream.
275
275
  2. Validate baseline counters:
276
- - `semanticHits`, `recencyHits`
276
+ - `semanticHits`
277
277
  - `tier1Count`, `tier2Count`
278
278
  - `hybridSearchLatencyMs`
279
279
  - `mergedCount`, `selectedCount`, `injectedTokens`, `latencyMs`
@@ -304,16 +304,18 @@ stateDiagram-v2
304
304
  Superseded --> Cleanup : cleanup_stale_superseded_items\n(delete from DB + Qdrant)
305
305
  ```
306
306
 
307
- **Item extraction** uses LLM-powered extraction (with pattern-based fallback) to identify memorable information from conversation messages. Each extracted item belongs to one of six kinds:
308
-
309
- | Kind | Description | Base Lifetime |
310
- | ------------ | ------------------------------------------------- | ------------- |
311
- | `identity` | Personal info, facts, relationships | 6 months |
312
- | `preference` | Likes, dislikes, preferred approaches/tools | 3 months |
313
- | `constraint` | Rules, requirements, directives | 1 month |
314
- | `project` | Project details, repos, tech stacks, action items | 2 weeks |
315
- | `decision` | Choices made, approaches selected | 2 weeks |
316
- | `event` | Deadlines, milestones, meetings, dates | 3 days |
307
+ **Item extraction** uses LLM-powered extraction (with pattern-based fallback) to identify memorable information from conversation messages. Each extracted item belongs to one of eight kinds:
308
+
309
+ | Kind | Description | Base Lifetime |
310
+ | ------------ | ------------------------------------------------------------------ | ------------- |
311
+ | `identity` | Personal info, facts, relationships | 6 months |
312
+ | `preference` | Likes, dislikes, preferred approaches/tools | 3 months |
313
+ | `journal` | Experiential reflections, journal-style notes, forward-looking items | 3 months |
314
+ | `constraint` | Rules, requirements, directives | 1 month |
315
+ | `project` | Project details, repos, tech stacks, action items | 2 weeks |
316
+ | `decision` | Choices made, approaches selected | 2 weeks |
317
+ | `event` | Deadlines, milestones, meetings, dates | 3 days |
318
+ | `capability` | Skill catalog entries (system-generated, not LLM-extracted) | never expires |
317
319
 
318
320
  **Supersession chains** replace the old conflict resolution system. When the LLM extracts a new item that updates an existing one, it sets `supersedes` to the old item's ID and `overrideConfidence` to one of three levels:
319
321
 
package/eslint.config.mjs CHANGED
@@ -29,37 +29,6 @@ const eslintConfig = defineConfig([
29
29
  { argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
30
30
  ],
31
31
  "@typescript-eslint/no-explicit-any": "error",
32
-
33
- // Standardize on `undefined` only — avoid `null` in new code.
34
- // Prefer `=== undefined`, `?? fallback`, or `?.` optional chaining
35
- // instead of `=== null`.
36
- "no-restricted-syntax": [
37
- "error",
38
- {
39
- selector:
40
- "BinaryExpression[operator='==='][right.type='Literal'][right.raw='null']",
41
- message:
42
- "Avoid `=== null`. Prefer `=== undefined`, `?? fallback`, or optional chaining `?.` instead.",
43
- },
44
- {
45
- selector:
46
- "BinaryExpression[operator='==='][left.type='Literal'][left.raw='null']",
47
- message:
48
- "Avoid `null ===`. Prefer `=== undefined`, `?? fallback`, or optional chaining `?.` instead.",
49
- },
50
- {
51
- selector:
52
- "BinaryExpression[operator='!=='][right.type='Literal'][right.raw='null']",
53
- message:
54
- "Avoid `!== null`. Prefer `!== undefined`, nullish coalescing `??`, or optional chaining `?.` instead.",
55
- },
56
- {
57
- selector:
58
- "BinaryExpression[operator='!=='][left.type='Literal'][left.raw='null']",
59
- message:
60
- "Avoid `null !==`. Prefer `!== undefined`, nullish coalescing `??`, or optional chaining `?.` instead.",
61
- },
62
- ],
63
32
  },
64
33
  },
65
34
  {
@@ -3,7 +3,7 @@
3
3
  * dependencies between index.ts and rpc.ts.
4
4
  */
5
5
 
6
- import { z } from "zod/v4";
6
+ import { z } from "zod";
7
7
 
8
8
  export const RpcErrorSchema = z.object({
9
9
  code: z.string(),
@@ -9,7 +9,7 @@
9
9
  * - Audit record summaries (materialization events)
10
10
  */
11
11
 
12
- import { z } from "zod/v4";
12
+ import { z } from "zod";
13
13
 
14
14
  // ---------------------------------------------------------------------------
15
15
  // Grant proposal types
@@ -20,7 +20,7 @@
20
20
  * is the platform-assigned connection identifier.
21
21
  */
22
22
 
23
- import { z } from "zod/v4";
23
+ import { z } from "zod";
24
24
 
25
25
  // ---------------------------------------------------------------------------
26
26
  // Handle type discriminator
@@ -7,7 +7,7 @@
7
7
  * module so that both sides can depend on it without circular references.
8
8
  */
9
9
 
10
- import { z } from "zod/v4";
10
+ import { z } from "zod";
11
11
  import { RpcErrorSchema } from "./error.js";
12
12
 
13
13
  // ---------------------------------------------------------------------------
@@ -33,7 +33,7 @@
33
33
  * - `list_credentials` — List all credential account names
34
34
  */
35
35
 
36
- import { z } from "zod/v4";
36
+ import { z } from "zod";
37
37
  import {
38
38
  AuditRecordSummarySchema,
39
39
  GrantProposalSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/assistant",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -162,7 +162,6 @@ mock.module("../memory/retriever.js", () => ({
162
162
  injectedText: "",
163
163
 
164
164
  semanticHits: 0,
165
- recencyHits: 0,
166
165
  injectedTokens: 0,
167
166
  latencyMs: 0,
168
167
  }),
@@ -61,7 +61,7 @@ mock.module("../security/secure-keys.js", () => ({
61
61
  getSecureKeyAsync: async (...args: unknown[]) => mockGetSecureKey(...args),
62
62
  setSecureKeyAsync: async () => true,
63
63
  deleteSecureKeyAsync: async () => "deleted",
64
- listSecureKeysAsync: async () => [],
64
+ listSecureKeysAsync: async () => ({ accounts: [], unreachable: false }),
65
65
  _resetBackend: () => {},
66
66
  }));
67
67
 
@@ -42,7 +42,6 @@ mock.module("../config/loader.js", () => {
42
42
  ui: {},
43
43
 
44
44
  provider: "anthropic",
45
- providerOrder: ["anthropic"],
46
45
  calls: {
47
46
  enabled: true,
48
47
  provider: "twilio",
@@ -185,15 +185,15 @@ describe("CesRpcCredentialBackend", () => {
185
185
  const result = await backend.list();
186
186
 
187
187
  expect(callFn).toHaveBeenCalledWith(CesRpcMethod.ListCredentials, {});
188
- expect(result).toEqual(["account-a", "account-b"]);
188
+ expect(result).toEqual({ accounts: ["account-a", "account-b"], unreachable: false });
189
189
  });
190
190
 
191
- test("returns empty array when RPC call throws", async () => {
191
+ test("returns unreachable when RPC call throws", async () => {
192
192
  callFn.mockRejectedValue(new Error("transport error"));
193
193
 
194
194
  const result = await backend.list();
195
195
 
196
- expect(result).toEqual([]);
196
+ expect(result).toEqual({ accounts: [], unreachable: true });
197
197
  });
198
198
  });
199
199
  });
@@ -0,0 +1,40 @@
1
+ import { describe, expect, mock, test } from "bun:test";
2
+
3
+ import type { CesClient } from "../credential-execution/client.js";
4
+ import {
5
+ awaitCesClientWithTimeout,
6
+ DEFAULT_CES_STARTUP_TIMEOUT_MS,
7
+ } from "../credential-execution/startup-timeout.js";
8
+
9
+ describe("awaitCesClientWithTimeout", () => {
10
+ test("clears the fallback timer when the CES client resolves first", async () => {
11
+ const onTimeout = mock(() => {});
12
+ const client = { isReady: () => true } as unknown as CesClient;
13
+
14
+ const result = await awaitCesClientWithTimeout(Promise.resolve(client), {
15
+ timeoutMs: 25,
16
+ onTimeout,
17
+ });
18
+
19
+ expect(result).toBe(client);
20
+
21
+ await new Promise((resolve) => setTimeout(resolve, 40));
22
+ expect(onTimeout).not.toHaveBeenCalled();
23
+ });
24
+
25
+ test("returns undefined and runs the fallback handler when the timeout wins", async () => {
26
+ const onTimeout = mock(() => {});
27
+
28
+ const result = await awaitCesClientWithTimeout(new Promise(() => {}), {
29
+ timeoutMs: 10,
30
+ onTimeout,
31
+ });
32
+
33
+ expect(result).toBeUndefined();
34
+ expect(onTimeout).toHaveBeenCalledTimes(1);
35
+ });
36
+
37
+ test("exports the daemon CES startup timeout constant", () => {
38
+ expect(DEFAULT_CES_STARTUP_TIMEOUT_MS).toBe(20_000);
39
+ });
40
+ });
@@ -204,7 +204,6 @@ describe("z.toJSONSchema integration", () => {
204
204
  expect(properties).toBeDefined();
205
205
  // Check that top-level keys are present
206
206
  expect(properties.services).toBeDefined();
207
- expect(properties.providerOrder).toBeDefined();
208
207
  expect(properties.maxTokens).toBeDefined();
209
208
  expect(properties.calls).toBeDefined();
210
209
  expect(properties.memory).toBeDefined();
@@ -638,6 +638,8 @@ describe("AssistantConfigSchema", () => {
638
638
  language: "en-US",
639
639
  transcriptionProvider: "Deepgram",
640
640
  ttsProvider: "elevenlabs",
641
+ hints: [],
642
+ interruptSensitivity: "low",
641
643
  },
642
644
  callerIdentity: {
643
645
  allowPerCallOverride: true,
@@ -129,7 +129,6 @@ mock.module("../memory/retriever.js", () => ({
129
129
  injectedText: "",
130
130
 
131
131
  semanticHits: 0,
132
- recencyHits: 0,
133
132
  injectedTokens: 0,
134
133
  latencyMs: 0,
135
134
  }),
@@ -168,7 +168,6 @@ mock.module("../memory/retriever.js", () => ({
168
168
  injectedText: "",
169
169
 
170
170
  semanticHits: 0,
171
- recencyHits: 0,
172
171
  injectedTokens: 0,
173
172
  latencyMs: 0,
174
173
  }),
@@ -199,7 +198,6 @@ mock.module("../daemon/conversation-memory.js", () => ({
199
198
  injectedText: "",
200
199
 
201
200
  semanticHits: 0,
202
- recencyHits: 0,
203
201
  injectedTokens: 0,
204
202
  latencyMs: 0,
205
203
  tier1Count: 0,
@@ -158,7 +158,6 @@ mock.module("../memory/retriever.js", () => ({
158
158
  injectedText: "",
159
159
 
160
160
  semanticHits: 0,
161
- recencyHits: 0,
162
161
  injectedTokens: 0,
163
162
  latencyMs: 0,
164
163
  }),
@@ -189,7 +188,6 @@ mock.module("../daemon/conversation-memory.js", () => ({
189
188
  injectedText: "",
190
189
 
191
190
  semanticHits: 0,
192
- recencyHits: 0,
193
191
  injectedTokens: 0,
194
192
  latencyMs: 0,
195
193
  tier1Count: 0,
@@ -614,7 +612,7 @@ describe("session-agent-loop", () => {
614
612
  });
615
613
 
616
614
  describe("LLM request log persistence", () => {
617
- test("record request log prefers the actual provider from failover", async () => {
615
+ test("record request log captures the actual provider name", async () => {
618
616
  const events: ServerMessage[] = [];
619
617
  const rawRequest = {
620
618
  model: "gpt-4.1",
@@ -768,7 +766,7 @@ describe("session-agent-loop", () => {
768
766
  });
769
767
 
770
768
  describe("usage accounting", () => {
771
- test("records the actual provider for failover-served usage", async () => {
769
+ test("records the actual provider for usage accounting", async () => {
772
770
  const events: ServerMessage[] = [];
773
771
 
774
772
  const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
@@ -154,7 +154,6 @@ mock.module("../memory/retriever.js", () => ({
154
154
  injectedText: "",
155
155
 
156
156
  semanticHits: 0,
157
- recencyHits: 0,
158
157
  injectedTokens: 0,
159
158
  latencyMs: 0,
160
159
  }),
@@ -6,7 +6,7 @@ import {
6
6
  classifyConversationError,
7
7
  isUserCancellation,
8
8
  } from "../daemon/conversation-error.js";
9
- import { ProviderError } from "../util/errors.js";
9
+ import { ProviderError, ProviderNotConfiguredError } from "../util/errors.js";
10
10
 
11
11
  describe("isUserCancellation", () => {
12
12
  it("returns false for non-AbortError even when abort flag is set", () => {
@@ -278,6 +278,20 @@ describe("classifyConversationError", () => {
278
278
  });
279
279
  });
280
280
 
281
+ describe("provider not configured errors", () => {
282
+ it("classifies ProviderNotConfiguredError as PROVIDER_NOT_CONFIGURED", () => {
283
+ const err = new ProviderNotConfiguredError("anthropic", []);
284
+ const result = classifyConversationError(err, baseCtx);
285
+ expect(result.code).toBe("PROVIDER_NOT_CONFIGURED");
286
+ expect(result.userMessage).toBe(
287
+ "No API key configured for inference. Add one in Settings to start chatting.",
288
+ );
289
+ expect(result.retryable).toBe(true);
290
+ expect(result.errorCategory).toBe("provider_not_configured");
291
+ expect(result.debugDetails).toBeDefined();
292
+ });
293
+ });
294
+
281
295
  describe("streaming corruption errors", () => {
282
296
  const cases = [
283
297
  "Unexpected event order, got message_start before receiving message_stop",
@@ -28,7 +28,7 @@ mock.module("../security/secure-keys.js", () => ({
28
28
  setSecureKeyAsync: async (key?: string, value?: string) =>
29
29
  setSecureKeyMock(key, value),
30
30
  deleteSecureKeyAsync: async () => "deleted" as const,
31
- listSecureKeysAsync: async () => [],
31
+ listSecureKeysAsync: async () => ({ accounts: [], unreachable: false }),
32
32
  _resetBackend: () => {},
33
33
  }));
34
34
 
@@ -119,7 +119,6 @@ mock.module("../memory/retriever.js", () => ({
119
119
  injectedText: "",
120
120
 
121
121
  semanticHits: 0,
122
- recencyHits: 0,
123
122
  injectedTokens: 0,
124
123
  latencyMs: 0,
125
124
  }),
@@ -188,7 +188,6 @@ mock.module("../memory/retriever.js", () => ({
188
188
  injectedText: "",
189
189
 
190
190
  semanticHits: 0,
191
- recencyHits: 0,
192
191
  injectedTokens: 0,
193
192
  latencyMs: 0,
194
193
  }),
@@ -204,7 +204,6 @@ mock.module("../memory/retriever.js", () => ({
204
204
  injectedText: "",
205
205
 
206
206
  semanticHits: 0,
207
- recencyHits: 0,
208
207
  injectedTokens: 0,
209
208
  latencyMs: 0,
210
209
  }),