@vellumai/assistant 0.11.6-dev.202608252309.48526e7 → 0.11.6-staging.2

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 (145) hide show
  1. package/ARCHITECTURE.md +1 -1
  2. package/docs/flux-turn-detection-spike.md +7 -8
  3. package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +0 -32
  4. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -18
  5. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +5 -0
  6. package/node_modules/@vellumai/gateway-client/src/channel-permission-contract.ts +1 -3
  7. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -7
  8. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +0 -8
  9. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -11
  10. package/openapi.yaml +6 -74
  11. package/package.json +1 -1
  12. package/src/__tests__/compactor-call-site-logging.test.ts +0 -61
  13. package/src/__tests__/config-loader-backfill.test.ts +0 -69
  14. package/src/__tests__/config-schema.test.ts +1 -0
  15. package/src/__tests__/conversation-agent-loop.test.ts +0 -238
  16. package/src/__tests__/conversation-error.test.ts +0 -44
  17. package/src/__tests__/conversation-runtime-assembly.test.ts +0 -23
  18. package/src/__tests__/conversation-slash.test.ts +0 -9
  19. package/src/__tests__/conversation-title-service.test.ts +0 -97
  20. package/src/__tests__/credential-routes.test.ts +1 -17
  21. package/src/__tests__/llm-resolver.test.ts +0 -20
  22. package/src/__tests__/managed-profile-guard.test.ts +0 -28
  23. package/src/__tests__/notification-decision-fallback.test.ts +0 -106
  24. package/src/__tests__/provider-usage-tracking.test.ts +0 -56
  25. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +2 -108
  26. package/src/__tests__/voice-config-update.test.ts +0 -43
  27. package/src/agent/loop.ts +2 -31
  28. package/src/backup/__tests__/paths.test.ts +2 -6
  29. package/src/backup/paths.ts +4 -6
  30. package/src/cli/commands/backup.help.ts +13 -10
  31. package/src/cli/commands/credentials.help.ts +1 -1
  32. package/src/cli/commands/memory/memory-retrospective.ts +0 -1
  33. package/src/cli/commands/stt.help.ts +2 -2
  34. package/src/config/__tests__/backup-schema.test.ts +1 -1
  35. package/src/config/__tests__/default-profile-catalog.test.ts +1 -77
  36. package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +1 -1
  37. package/src/config/bundled-skills/settings/TOOLS.json +5 -11
  38. package/src/config/bundled-skills/settings/tools/open-system-settings.ts +8 -33
  39. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +3 -54
  40. package/src/config/default-profile-catalog.ts +10 -195
  41. package/src/config/default-profile-names.ts +0 -41
  42. package/src/config/inference-profile-validation.ts +2 -11
  43. package/src/config/llm-resolver.ts +0 -1
  44. package/src/config/loader.ts +0 -3
  45. package/src/config/managed-speech-defaults.ts +8 -53
  46. package/src/config/schemas/__tests__/live-voice.test.ts +3 -4
  47. package/src/config/schemas/backup.ts +1 -1
  48. package/src/config/schemas/live-voice.ts +3 -5
  49. package/src/config/schemas/llm.ts +10 -256
  50. package/src/config/schemas/services.ts +0 -24
  51. package/src/config/schemas/stt.ts +5 -29
  52. package/src/config/seed-inference-profiles.ts +3 -32
  53. package/src/context/compactor.ts +1 -74
  54. package/src/daemon/conversation-agent-loop-handlers.ts +0 -15
  55. package/src/daemon/conversation-agent-loop.ts +3 -40
  56. package/src/daemon/conversation-error.ts +0 -25
  57. package/src/daemon/conversation-runtime-assembly.ts +7 -19
  58. package/src/daemon/conversation-slash.ts +2 -2
  59. package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +2 -5
  60. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +11 -73
  61. package/src/live-voice/__tests__/live-voice-session-preflight.test.ts +2 -148
  62. package/src/live-voice/__tests__/live-voice-stt.test.ts +0 -3
  63. package/src/live-voice/__tests__/protocol.test.ts +0 -169
  64. package/src/live-voice/live-voice-session-manager.ts +2 -39
  65. package/src/live-voice/live-voice-session.ts +6 -188
  66. package/src/live-voice/protocol.ts +1 -157
  67. package/src/notifications/adapters/slack.ts +1 -6
  68. package/src/notifications/approval-card-data.ts +1 -94
  69. package/src/notifications/broadcaster.ts +9 -3
  70. package/src/notifications/decision-engine.ts +0 -55
  71. package/src/notifications/guardian-question-mode.ts +0 -57
  72. package/src/oauth/seed-providers.ts +0 -265
  73. package/src/persistence/conversation-title-service.ts +29 -43
  74. package/src/plugin-api/model-profiles.test.ts +2 -2
  75. package/src/plugin-api/model-profiles.ts +7 -7
  76. package/src/plugins/defaults/compaction/window-manager.ts +0 -4
  77. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +33 -125
  78. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +31 -21
  79. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +9 -13
  80. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +4 -31
  81. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
  82. package/src/plugins/defaults/memory/memory-retrospective-job.ts +107 -140
  83. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +13 -13
  84. package/src/plugins/defaults/memory/src/memory-v2-routes.ts +2 -2
  85. package/src/providers/connection-resolution.ts +17 -2
  86. package/src/providers/inference/adapter-factory.ts +3 -225
  87. package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -22
  88. package/src/providers/openai/api-error-normalization.ts +0 -13
  89. package/src/providers/openai/chat-completions-provider.ts +0 -80
  90. package/src/providers/retry.ts +68 -938
  91. package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +0 -42
  92. package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +0 -136
  93. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -120
  94. package/src/providers/speech-to-text/__tests__/resolve.test.ts +12 -97
  95. package/src/providers/speech-to-text/deepgram-flux-frames.ts +3 -78
  96. package/src/providers/speech-to-text/deepgram-flux-realtime.ts +4 -132
  97. package/src/providers/speech-to-text/provider-catalog.ts +3 -159
  98. package/src/providers/speech-to-text/resolve.ts +15 -66
  99. package/src/providers/types.ts +0 -31
  100. package/src/providers/usage-tracking.ts +1 -12
  101. package/src/runtime/__tests__/agent-wake.test.ts +3 -105
  102. package/src/runtime/agent-wake.ts +5 -44
  103. package/src/runtime/routes/__tests__/backup-routes.test.ts +5 -9
  104. package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -7
  105. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -96
  106. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +0 -37
  107. package/src/runtime/routes/backup-routes.ts +2 -2
  108. package/src/runtime/routes/contact-routes.ts +15 -20
  109. package/src/runtime/routes/conversation-query-routes.ts +10 -98
  110. package/src/runtime/routes/conversation-routes.ts +2 -2
  111. package/src/runtime/routes/credential-routes.ts +1 -2
  112. package/src/runtime/routes/inference-profile-session-handler.ts +2 -2
  113. package/src/runtime/routes/inference-profiles-routes.ts +7 -12
  114. package/src/runtime/routes/inference-send-routes.ts +2 -2
  115. package/src/runtime/routes/llm-call-sites-routes.ts +2 -2
  116. package/src/runtime/routes/stt-routes.ts +1 -6
  117. package/src/runtime/routes/wake-conversation-routes.ts +1 -8
  118. package/src/stt/daemon-batch-transcriber.ts +1 -4
  119. package/src/stt/types.ts +3 -33
  120. package/src/telemetry/__tests__/live-voice-funnel.test.ts +0 -34
  121. package/src/telemetry/live-voice-funnel.ts +2 -12
  122. package/src/tools/workflows/manage-workflows.ts +2 -2
  123. package/src/tools/workflows/run-workflow.test.ts +1 -2
  124. package/src/util/errors.ts +0 -1
  125. package/src/util/provider-error-patterns.ts +0 -20
  126. package/src/workspace/migrations/registry.ts +0 -8
  127. package/src/__tests__/default-profile-catalog-fallback.test.ts +0 -289
  128. package/src/__tests__/fallback-breaker.test.ts +0 -1335
  129. package/src/__tests__/llm-schema-fallback-profile.test.ts +0 -359
  130. package/src/__tests__/managed-fallback-dispatch.test.ts +0 -430
  131. package/src/__tests__/retry-fallback-escalation.test.ts +0 -1093
  132. package/src/__tests__/workspace-migration-147-rename-colliding-backup-profile-names.test.ts +0 -480
  133. package/src/__tests__/workspace-migration-148-strip-unsupported-fallback-profiles.test.ts +0 -167
  134. package/src/__tests__/workspace-migration-149-repoint-backup-profile-selections.test.ts +0 -144
  135. package/src/config/bundled-skills/settings/tools/open-system-settings.test.ts +0 -85
  136. package/src/live-voice/__tests__/live-voice-text-turn.test.ts +0 -354
  137. package/src/providers/fallback-breaker.ts +0 -389
  138. package/src/providers/openai/__tests__/chat-template-flatten.test.ts +0 -198
  139. package/src/providers/provider-resolvability.ts +0 -20
  140. package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +0 -296
  141. package/src/workspace/migrations/147-rename-colliding-backup-profile-names.ts +0 -360
  142. package/src/workspace/migrations/148-strip-unsupported-fallback-profiles.ts +0 -117
  143. package/src/workspace/migrations/149-repoint-backup-profile-selections.ts +0 -204
  144. package/src/workspace/migrations/150-stt-flux-provider-to-model-family.ts +0 -139
  145. package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +0 -160
package/ARCHITECTURE.md CHANGED
@@ -84,7 +84,7 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
84
84
 
85
85
  **Identity lifecycle:**
86
86
 
87
- 1. **Bootstrap (loopback-only, desktop)**: On first launch, the desktop client calls `POST /v1/guardian/init` with `{ platform, deviceId }`. The endpoint is loopback-only and mints a JWT access token + refresh token pair. Returns `{ guardianPrincipalId, accessToken, accessTokenExpiresAt, refreshToken, refreshTokenExpiresAt, refreshAfter, isNew }`. The CLI obtains its bearer token during `hatch` and does not perform a separate bootstrap step.
87
+ 1. **Bootstrap (loopback-only, macOS)** — On first launch, the macOS client calls `POST /v1/guardian/init` with `{ platform, deviceId }`. The endpoint is loopback-only and mints a JWT access token + refresh token pair. Returns `{ guardianPrincipalId, accessToken, accessTokenExpiresAt, refreshToken, refreshTokenExpiresAt, refreshAfter, isNew }`. The CLI obtains its bearer token during `hatch` and does not perform a separate bootstrap step.
88
88
 
89
89
  2. **Refresh** — `POST /v1/guardian/refresh` accepts `{ refreshToken }` and returns a new access/refresh token pair. Single-use rotation with replay detection and family-based revocation.
90
90
 
@@ -59,7 +59,7 @@ If it does not, set the Deepgram key the ordinary way (client Settings, Speech-t
59
59
 
60
60
  ## 2. Enable Flux
61
61
 
62
- > **Putting a provider on the `flux` model family turns off batch transcription for the whole workspace, not just live voice.** `services.stt.provider` plus `services.stt.providers.<provider>.model` is the single source of truth for every STT route, and Flux is the only family in the catalog with no `daemon-batch` boundary. For as long as it is set, these all stop working: voice-message and inbound-attachment transcription, the `transcribe` skill, the `media-processing` skill's audio segments, `POST /v1/stt/transcribe`, and phone-call transcription. Each reports a message naming Flux as the cause rather than failing silently, but they do not fall back to `deepgram` on their own. **Set `services.stt.providers.deepgram.model` back to `nova-3` when the spike is over**, and do not run the spike on an assistant that is also taking calls or handling voice messages.
62
+ > **Setting `services.stt.provider` to `deepgram-flux` turns off batch transcription for the whole workspace, not just live voice.** `services.stt.provider` is the single source of truth for every STT route, and Flux is the only provider in the catalog with no `daemon-batch` boundary. For as long as it is set, these all stop working: voice-message and inbound-attachment transcription, the `transcribe` skill, the `media-processing` skill's audio segments, `POST /v1/stt/transcribe`, and phone-call transcription. Each reports a message naming Flux as the cause rather than failing silently, but they do not fall back to `deepgram` on their own. **Set `services.stt.provider` back to `deepgram` when the spike is over**, and do not run the spike on an assistant that is also taking calls or handling voice messages.
63
63
 
64
64
  Two keys in `config.json`, which lives at `$VELLUM_WORKSPACE_DIR/config.json` (default `~/.vellum/workspace/config.json`):
65
65
 
@@ -67,8 +67,7 @@ Two keys in `config.json`, which lives at `$VELLUM_WORKSPACE_DIR/config.json` (d
67
67
  {
68
68
  "services": {
69
69
  "stt": {
70
- "provider": "deepgram",
71
- "providers": { "deepgram": { "model": "flux" } }
70
+ "provider": "deepgram-flux"
72
71
  }
73
72
  },
74
73
  "liveVoice": {
@@ -94,12 +93,12 @@ The rest of `liveVoice.flux` is optional and defaulted (`config/schemas/live-voi
94
93
 
95
94
  ## 3. Run the A/B
96
95
 
97
- **Flip `turnEnd.enabled` between runs and leave the `flux` model family selected in both arms.** That holds the STT engine, the model, the socket, and the transcriber lifecycle constant, so the only thing that changes is which signal commits the turn.
96
+ **Flip `turnEnd.enabled` between runs and leave `services.stt.provider` on `deepgram-flux` in both arms.** That holds the STT engine, the model, the socket, and the transcriber lifecycle constant, so the only thing that changes is which signal commits the turn.
98
97
 
99
- - **Arm A (control):** `providers.deepgram.model: "flux"`, `turnEnd.enabled: false`. Flux transcribes; the four turn-detection events are ignored; the local silence boundary and the front-door hold path run exactly as they do today.
100
- - **Arm B (treatment):** `providers.deepgram.model: "flux"`, `turnEnd.enabled: true`.
98
+ - **Arm A (control):** `provider: "deepgram-flux"`, `turnEnd.enabled: false`. Flux transcribes; the four turn-detection events are ignored; the local silence boundary and the front-door hold path run exactly as they do today.
99
+ - **Arm B (treatment):** `provider: "deepgram-flux"`, `turnEnd.enabled: true`.
101
100
 
102
- **Do not A/B by switching the model family between `nova-3` and `flux`.** That confounds two changes at once:
101
+ **Do not A/B by switching the provider between `deepgram` and `deepgram-flux`.** That confounds two changes at once:
103
102
 
104
103
  1. It swaps the STT model. `deepgram` runs `nova-2` (`DEFAULT_MODEL`, `deepgram-realtime.ts`), so any transcript-quality or first-partial difference lands in your latency numbers.
105
104
  2. It swaps the transcriber lifecycle. `deepgram` implements `finalizeUtterance`, so the session adopts it as a persistent stream shared across the whole session (`sharedTranscriber`) and never tears it down between turns. Flux implements no `finalizeUtterance`, so every utterance owns its own `/v2/listen` socket and every release closes it. That per-turn socket churn is inside `roundTripMs` and `totalMs` on the Flux side and absent on the `deepgram` side, so a naive provider-swap A/B attributes it to turn detection. The next section is what it costs and why it cannot be removed.
@@ -231,7 +230,7 @@ Check these if you port the spike anywhere else, because a run that violates eit
231
230
 
232
231
  ## 8. Falling back
233
232
 
234
- Set `liveVoice.flux.turnEnd.enabled` back to `false` (or delete the key) and restart. That is the whole rollback: the latch goes down, the turn-detection events become no-ops, and the silence-boundary path runs unchanged. You can leave the `flux` family selected or move back to `nova-3`; either is a working configuration.
233
+ Set `liveVoice.flux.turnEnd.enabled` back to `false` (or delete the key) and restart. That is the whole rollback: the latch goes down, the turn-detection events become no-ops, and the silence-boundary path runs unchanged. You can leave `services.stt.provider` on `deepgram-flux` or move it back to `deepgram`; either is a working configuration.
235
234
 
236
235
  Runtime fallback needs no action. A Flux stream that never emits `turn-end` is caught by the fail-open deadline and the utterance replays onto the silence path, so an outage degrades to today's behavior rather than to a hung turn.
237
236
 
@@ -20,7 +20,6 @@ describe("contact read contracts", () => {
20
20
  contactType: "human",
21
21
  lastInteraction: 1700000000,
22
22
  interactionCount: 12,
23
- autoApproveThreshold: "medium",
24
23
  createdAt: 1699000000,
25
24
  updatedAt: 1700000000,
26
25
  channels: [
@@ -47,7 +46,6 @@ describe("contact read contracts", () => {
47
46
  const parsed = ContactReadSchema.parse(contact);
48
47
  expect(parsed.createdAt).toBe(1699000000);
49
48
  expect(parsed.updatedAt).toBe(1700000000);
50
- expect(parsed.autoApproveThreshold).toBe("medium");
51
49
  });
52
50
 
53
51
  test("ContactReadSchema accepts null interactionCount (daemon-native gateway-telemetry outage fail-soft)", () => {
@@ -84,36 +82,6 @@ describe("contact read contracts", () => {
84
82
  const parsed = ContactReadSchema.parse(contact);
85
83
  expect(parsed.interactionCount).toBeNull();
86
84
  expect(parsed.channels[0].interactionCount).toBeNull();
87
- expect(parsed.autoApproveThreshold).toBeUndefined();
88
- });
89
-
90
- test("ContactReadSchema accepts a null auto-approve threshold", () => {
91
- const contact = {
92
- id: "c1",
93
- displayName: "Example User",
94
- role: "contact",
95
- interactionCount: 0,
96
- autoApproveThreshold: null,
97
- createdAt: 1699000000,
98
- updatedAt: 1700000000,
99
- channels: [],
100
- };
101
- expect(ContactReadSchema.parse(contact).autoApproveThreshold).toBeNull();
102
- });
103
-
104
- test("ContactReadSchema rejects an unknown auto-approve threshold", () => {
105
- expect(() =>
106
- ContactReadSchema.parse({
107
- id: "c1",
108
- displayName: "Example User",
109
- role: "contact",
110
- interactionCount: 0,
111
- autoApproveThreshold: "full",
112
- createdAt: 1699000000,
113
- updatedAt: 1700000000,
114
- channels: [],
115
- }),
116
- ).toThrow();
117
85
  });
118
86
 
119
87
  test("ContactReadSchema requires createdAt/updatedAt", () => {
@@ -31,7 +31,6 @@ const fullVerdict: TrustVerdict = {
31
31
  verifiedAt: 1699999999,
32
32
  interactionCount: 12,
33
33
  memberDisplayName: "Member Name",
34
- autoApproveThreshold: "high",
35
34
  };
36
35
 
37
36
  describe("TrustVerdictSchema", () => {
@@ -39,23 +38,6 @@ describe("TrustVerdictSchema", () => {
39
38
  expect(TrustVerdictSchema.parse(fullVerdict)).toEqual(fullVerdict);
40
39
  });
41
40
 
42
- test("parses a verdict with a null contact auto-approve threshold", () => {
43
- const verdict = {
44
- ...fullVerdict,
45
- autoApproveThreshold: null,
46
- } satisfies TrustVerdict;
47
- expect(TrustVerdictSchema.parse(verdict)).toEqual(verdict);
48
- });
49
-
50
- test("rejects an unknown contact auto-approve threshold", () => {
51
- expect(() =>
52
- TrustVerdictSchema.parse({
53
- ...fullVerdict,
54
- autoApproveThreshold: "full",
55
- }),
56
- ).toThrow();
57
- });
58
-
59
41
  test("parses a minimal verdict", () => {
60
42
  const minimal = {
61
43
  trustClass: "unknown",
@@ -82,10 +82,15 @@ export function isAdmissionPolicyExemptChannel(channelType: string): boolean {
82
82
  * `vellum` is the local desktop/web client surface; the guardian is always
83
83
  * max-rank there, so the seed default admits them regardless of the floor.
84
84
  *
85
+ * `discord` has no ingress implementation, so there is nothing for a floor to
86
+ * gate and nothing for the user to configure. Hiding keeps it pinned at the
87
+ * seed default rather than offering a Channel Trust Floors row for a channel
88
+ * that receives nothing.
85
89
  */
86
90
  export const ADMISSION_POLICY_HIDDEN_CHANNELS: ReadonlySet<string> = new Set([
87
91
  "vellum",
88
92
  "whatsapp",
93
+ "discord",
89
94
  ]);
90
95
 
91
96
  export function isAdmissionPolicyHiddenChannel(channelType: string): boolean {
@@ -10,9 +10,7 @@
10
10
  *
11
11
  * Storage lives in the gateway DB (`channel_permission_overrides`) so the
12
12
  * assistant cannot tamper with it, matching `channel_admission_policy` and
13
- * `auto_approve_thresholds`. A contact-level ceiling can live on
14
- * `contacts.auto_approve_threshold` and is stamped on the trust verdict;
15
- * that override is not a matrix cell.
13
+ * `auto_approve_thresholds`.
16
14
  */
17
15
 
18
16
  import { z } from "zod";
@@ -5,8 +5,6 @@
5
5
  import { CHANNEL_IDS } from "@vellumai/service-contracts/channels";
6
6
  import { z } from "zod";
7
7
 
8
- import { RiskThresholdSchema } from "./channel-permission-contract.js";
9
-
10
8
  export const GATEWAY_LOG_LEVEL_NAMES = [
11
9
  "trace",
12
10
  "debug",
@@ -277,11 +275,6 @@ export const ContactReadSchema = z.object({
277
275
  contactType: z.string().nullable().optional(),
278
276
  lastInteraction: z.number().nullable().optional(),
279
277
  interactionCount: z.number().nullable(),
280
- /**
281
- * Per-contact auto-approve ceiling. Null when unset (inherit cascade).
282
- * Optional on the wire for version skew; gateway reads always emit it.
283
- */
284
- autoApproveThreshold: RiskThresholdSchema.nullable().optional(),
285
278
  createdAt: z.number(),
286
279
  updatedAt: z.number(),
287
280
  channels: z.array(ContactReadChannelSchema),
@@ -61,14 +61,6 @@ export const ApprovalUIMetadataSchema = z.object({
61
61
  actions: z.array(ApprovalActionOptionSchema),
62
62
  plainTextFallback: z.string(),
63
63
  permissionDetails: PermissionRequestDetailsSchema.optional(),
64
- /**
65
- * What the recipient is being asked to do, so a renderer can head the card
66
- * with the right verb. Resolved once by the producer; a renderer that reads
67
- * the actions to work it out would be parsing a payload it is meant only to
68
- * draw. Absent means an approval, which is what every existing producer
69
- * sends and what a renderer without this field already assumes.
70
- */
71
- intent: z.enum(["approval", "question"]).optional(),
72
64
  });
73
65
 
74
66
  export type ApprovalUIMetadata = z.infer<typeof ApprovalUIMetadataSchema>;
@@ -78,17 +78,6 @@ export const TrustVerdictSchema = z.object({
78
78
  policy: z.string().optional(),
79
79
  verifiedAt: z.number().nullable().optional(),
80
80
  memberDisplayName: z.string().optional(),
81
- /**
82
- * Contact-level auto-approve ceiling from the gateway `contacts` row.
83
- * Present when a member channel resolves. Null means the contact has no
84
- * explicit override (inherit the room / trust-class cascade).
85
- * Same vocabulary as `RiskThreshold` (`none` | `low` | `medium` | `high`).
86
- * Inlined here so this leaf contract does not import the permission matrix.
87
- */
88
- autoApproveThreshold: z
89
- .enum(["none", "low", "medium", "high"])
90
- .nullable()
91
- .optional(),
92
81
 
93
82
  // Gateway-owned interaction telemetry (a trust signal, not an info field per
94
83
  // the 2×2) — carried straight off the member `contact_channels` row.
package/openapi.yaml CHANGED
@@ -2766,8 +2766,8 @@ paths:
2766
2766
  operationId: backup_destinations_get
2767
2767
  summary: List configured offsite backup destinations
2768
2768
  description:
2769
- Returns the current offsite destinations array. When no explicit array is configured, macOS materializes
2770
- its encrypted iCloud Drive default while Windows and Linux return no implicit destination.
2769
+ Returns the current offsite destinations array, materializing the iCloud Drive default when no explicit
2770
+ array is configured.
2771
2771
  tags:
2772
2772
  - backups
2773
2773
  responses:
@@ -2799,8 +2799,8 @@ paths:
2799
2799
  operationId: backup_destinations_add_post
2800
2800
  summary: Add an offsite backup destination
2801
2801
  description:
2802
- Appends a new destination. Materializes the platform default first if destinations is currently null.
2803
- Errors if the path already exists.
2802
+ Appends a new destination. Materializes the iCloud default first if destinations is currently null. Errors
2803
+ if the path already exists.
2804
2804
  tags:
2805
2805
  - backups
2806
2806
  requestBody:
@@ -4342,15 +4342,6 @@ paths:
4342
4342
  - type: "null"
4343
4343
  memberDisplayName:
4344
4344
  type: string
4345
- autoApproveThreshold:
4346
- anyOf:
4347
- - type: string
4348
- enum:
4349
- - none
4350
- - low
4351
- - medium
4352
- - high
4353
- - type: "null"
4354
4345
  interactionCount:
4355
4346
  type: number
4356
4347
  hasInterceptableVerificationSession:
@@ -5232,10 +5223,6 @@ paths:
5232
5223
  required:
5233
5224
  - profile
5234
5225
  - weight
5235
- fallbackProfile:
5236
- readOnly: true
5237
- type: string
5238
- minLength: 1
5239
5226
  responses:
5240
5227
  "200":
5241
5228
  description: Successful response
@@ -5606,15 +5593,6 @@ paths:
5606
5593
  anyOf:
5607
5594
  - type: number
5608
5595
  - type: "null"
5609
- autoApproveThreshold:
5610
- anyOf:
5611
- - type: string
5612
- enum:
5613
- - none
5614
- - low
5615
- - medium
5616
- - high
5617
- - type: "null"
5618
5596
  createdAt:
5619
5597
  type: number
5620
5598
  updatedAt:
@@ -5779,15 +5757,6 @@ paths:
5779
5757
  anyOf:
5780
5758
  - type: number
5781
5759
  - type: "null"
5782
- autoApproveThreshold:
5783
- anyOf:
5784
- - type: string
5785
- enum:
5786
- - none
5787
- - low
5788
- - medium
5789
- - high
5790
- - type: "null"
5791
5760
  createdAt:
5792
5761
  type: number
5793
5762
  updatedAt:
@@ -5921,15 +5890,6 @@ paths:
5921
5890
  anyOf:
5922
5891
  - type: number
5923
5892
  - type: "null"
5924
- autoApproveThreshold:
5925
- anyOf:
5926
- - type: string
5927
- enum:
5928
- - none
5929
- - low
5930
- - medium
5931
- - high
5932
- - type: "null"
5933
5893
  createdAt:
5934
5894
  type: number
5935
5895
  updatedAt:
@@ -6334,15 +6294,6 @@ paths:
6334
6294
  anyOf:
6335
6295
  - type: number
6336
6296
  - type: "null"
6337
- autoApproveThreshold:
6338
- anyOf:
6339
- - type: string
6340
- enum:
6341
- - none
6342
- - low
6343
- - medium
6344
- - high
6345
- - type: "null"
6346
6297
  createdAt:
6347
6298
  type: number
6348
6299
  updatedAt:
@@ -6542,15 +6493,6 @@ paths:
6542
6493
  anyOf:
6543
6494
  - type: number
6544
6495
  - type: "null"
6545
- autoApproveThreshold:
6546
- anyOf:
6547
- - type: string
6548
- enum:
6549
- - none
6550
- - low
6551
- - medium
6552
- - high
6553
- - type: "null"
6554
6496
  createdAt:
6555
6497
  type: number
6556
6498
  updatedAt:
@@ -15046,8 +14988,8 @@ paths:
15046
14988
  description: Profile not found
15047
14989
  "409":
15048
14990
  description:
15049
- Profile is still referenced by activeProfile, advisorProfile, a call site, a default-tier override, a mix
15050
- arm, or another profile's fallbackProfile
14991
+ Profile is still referenced by activeProfile, advisorProfile, a call site, a default-tier override, or a
14992
+ mix arm
15051
14993
  get:
15052
14994
  operationId: inference_profiles_by_name_get
15053
14995
  summary: Get an effective inference profile
@@ -34816,12 +34758,6 @@ components:
34816
34758
  - profile
34817
34759
  - weight
34818
34760
  - type: "null"
34819
- fallbackProfile:
34820
- anyOf:
34821
- - readOnly: true
34822
- type: string
34823
- minLength: 1
34824
- - type: "null"
34825
34761
  additionalProperties: {}
34826
34762
  ProfileStatus:
34827
34763
  type: string
@@ -35593,10 +35529,6 @@ components:
35593
35529
  - profile
35594
35530
  - weight
35595
35531
  additionalProperties: false
35596
- fallbackProfile:
35597
- readOnly: true
35598
- type: string
35599
- minLength: 1
35600
35532
  supportsVision:
35601
35533
  type: boolean
35602
35534
  invariant:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/assistant",
3
- "version": "0.11.6-dev.202608252309.48526e7",
3
+ "version": "0.11.6-staging.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -194,64 +194,3 @@ describe("compactor records llm_request_logs with call_site=compactionAgent", ()
194
194
  expect(recordRequestLogCalls[0]!.callSite).toBe("compactionAgent");
195
195
  });
196
196
  });
197
-
198
- describe("compaction result reports what actually served the summary", () => {
199
- beforeEach(() => {
200
- recordRequestLogCalls.length = 0;
201
- });
202
-
203
- test("rerouted summary carries the backup provider and profile", async () => {
204
- // `RetryProvider` escalated the summary call to a backup profile on
205
- // another provider and stamped the response, so the result must report
206
- // the backup even though the compactor resolved `primaryProfile`.
207
- const provider: Provider = {
208
- name: "openai",
209
- sendMessage: async () => ({
210
- content: [{ type: "text", text: compactionResponse }],
211
- model: "claude-sonnet-5",
212
- actualProvider: "anthropic",
213
- actualInferenceProfile: "backupProfile",
214
- usage: { inputTokens: 100, outputTokens: 50 },
215
- stopReason: "end_turn",
216
- rawRequest: RAW_REQUEST,
217
- rawResponse: RAW_RESPONSE,
218
- }),
219
- };
220
-
221
- const result = await runAssistantDrivenCompaction({
222
- ...args(provider),
223
- overrideProfile: "primaryProfile",
224
- });
225
-
226
- expect(result.summaryModel).toBe("claude-sonnet-5");
227
- expect(result.summaryActualProvider).toBe("anthropic");
228
- expect(result.summaryActualInferenceProfile).toBe("backupProfile");
229
- // The primary's resolution is still reported, just outranked downstream.
230
- expect(result.summaryOverrideProfile).toBe("primaryProfile");
231
- // Same value the request log recorded: one source of truth, not two.
232
- expect(recordRequestLogCalls[0]!.provider).toBe("anthropic");
233
- });
234
-
235
- test("non-rerouted summary carries the configured provider and no profile", async () => {
236
- const provider: Provider = {
237
- name: "openai",
238
- sendMessage: async () => ({
239
- content: [{ type: "text", text: compactionResponse }],
240
- model: "mock-model",
241
- usage: { inputTokens: 100, outputTokens: 50 },
242
- stopReason: "end_turn",
243
- rawRequest: RAW_REQUEST,
244
- rawResponse: RAW_RESPONSE,
245
- }),
246
- };
247
-
248
- const result = await runAssistantDrivenCompaction({
249
- ...args(provider),
250
- overrideProfile: "primaryProfile",
251
- });
252
-
253
- expect(result.summaryActualProvider).toBe("openai");
254
- expect(result.summaryActualInferenceProfile).toBeUndefined();
255
- expect(result.summaryOverrideProfile).toBe("primaryProfile");
256
- });
257
- });
@@ -1411,71 +1411,6 @@ describe("loadConfig startup behavior", () => {
1411
1411
  expect(effective.balanced?.provider_connection).toBe("anthropic-personal");
1412
1412
  });
1413
1413
 
1414
- test("an active managed backup profile survives a reload", () => {
1415
- // A managed backup resolves from the code catalog without being
1416
- // materialized in `llm.profiles`, so selecting one persists nothing but
1417
- // the reference. If the schema did not treat backup keys as
1418
- // always-available references, the strip-and-reparse in `loadConfig`
1419
- // would drop `activeProfile` and the seeder would reset the user's
1420
- // chat-model selection to `balanced` on the next boot.
1421
- writeConfig({
1422
- llm: {
1423
- defaultProvider: { provider: "vellum" },
1424
- profiles: {},
1425
- activeProfile: "balanced-backup",
1426
- },
1427
- });
1428
-
1429
- const config = loadConfig();
1430
- expect(config.llm.activeProfile).toBe("balanced-backup");
1431
-
1432
- mergeDefaultConfigAndSeedInferenceProfiles();
1433
-
1434
- const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
1435
- expect(raw.llm.activeProfile).toBe("balanced-backup");
1436
- expect(raw.llm.profiles["balanced-backup"]).toBeUndefined();
1437
- });
1438
-
1439
- test("an active managed backup profile is repaired on a BYOK install", () => {
1440
- // Backups live on the managed column alone, so under a BYOK default
1441
- // provider the selection names a profile that resolves to nothing. The
1442
- // schema rejects the reference on load and the seeder, which resolves
1443
- // availability through the same provider-aware view, repairs the stored
1444
- // selection instead of preserving a dead pointer.
1445
- writeConfig({
1446
- llm: {
1447
- defaultProvider: { provider: "anthropic" },
1448
- profiles: {},
1449
- activeProfile: "balanced-backup",
1450
- },
1451
- });
1452
-
1453
- const config = loadConfig();
1454
- expect(config.llm.activeProfile).toBeUndefined();
1455
-
1456
- mergeDefaultConfigAndSeedInferenceProfiles();
1457
-
1458
- const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
1459
- expect(raw.llm.activeProfile).toBe("balanced");
1460
- });
1461
-
1462
- test("a call site pinned to a managed backup profile survives a reload", () => {
1463
- writeConfig({
1464
- llm: {
1465
- defaultProvider: { provider: "vellum" },
1466
- profiles: {},
1467
- activeProfile: "balanced",
1468
- callSites: { recall: { profile: "cost-optimized-backup" } },
1469
- },
1470
- });
1471
-
1472
- const config = loadConfig();
1473
- expect(config.llm.callSites.recall?.profile).toBe("cost-optimized-backup");
1474
-
1475
- const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
1476
- expect(raw.llm.callSites.recall.profile).toBe("cost-optimized-backup");
1477
- });
1478
-
1479
1414
  test("still quarantines corrupt JSON", () => {
1480
1415
  // Corrupt-config quarantine is a recovery path: the broken file is
1481
1416
  // renamed to `config.json.corrupt-<ts>.json` and the daemon proceeds
@@ -1865,10 +1800,6 @@ describe("seedInferenceProfiles BYOK-mode default profiles", () => {
1865
1800
  "quality-optimized",
1866
1801
  "cost-optimized",
1867
1802
  "latency-optimized",
1868
- "balanced-backup",
1869
- "quality-optimized-backup",
1870
- "cost-optimized-backup",
1871
- "latency-optimized-backup",
1872
1803
  "my-custom",
1873
1804
  ]);
1874
1805
  });
@@ -960,6 +960,7 @@ describe("AssistantConfigSchema", () => {
960
960
  },
961
961
  flux: {
962
962
  turnEnd: { enabled: false },
963
+ model: "flux-general-en",
963
964
  eotThreshold: 0.7,
964
965
  eotTimeoutMs: 5000,
965
966
  },