@vellumai/assistant 0.8.11 → 0.8.12-staging.1

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 (219) hide show
  1. package/ARCHITECTURE.md +15 -17
  2. package/README.md +0 -6
  3. package/bun.lock +6 -122
  4. package/node_modules/@vellumai/gateway-client/bun.lock +1 -0
  5. package/node_modules/@vellumai/gateway-client/package.json +3 -1
  6. package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +1 -1
  7. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +87 -0
  8. package/node_modules/@vellumai/gateway-client/src/index.ts +3 -5
  9. package/openapi.yaml +126 -4
  10. package/package.json +1 -3
  11. package/src/__tests__/adaptive-thinking-repair.test.ts +185 -0
  12. package/src/__tests__/agent-loop-compaction-events.test.ts +7 -6
  13. package/src/__tests__/anthropic-provider.test.ts +129 -0
  14. package/src/__tests__/background-workers-disk-pressure.test.ts +4 -1
  15. package/src/__tests__/btw-routes.test.ts +7 -34
  16. package/src/__tests__/checker.test.ts +6 -12
  17. package/src/__tests__/config-loader-backfill.test.ts +4 -2
  18. package/src/__tests__/config-loader-quarantine-notice.test.ts +167 -0
  19. package/src/__tests__/config-watcher.test.ts +2 -2
  20. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  21. package/src/__tests__/conversation-error.test.ts +2 -6
  22. package/src/__tests__/conversation-history-web-search.test.ts +8 -0
  23. package/src/__tests__/conversation-title-service.test.ts +2 -1
  24. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  25. package/src/__tests__/disk-pressure-tools.test.ts +1 -1
  26. package/src/__tests__/exploration-drift-hook.test.ts +692 -0
  27. package/src/__tests__/filing-service.test.ts +8 -3
  28. package/src/__tests__/guardian-action-store.test.ts +0 -167
  29. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +1 -1
  30. package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -1
  31. package/src/__tests__/heartbeat-service.test.ts +5 -2
  32. package/src/__tests__/identity-intro-cache.test.ts +12 -5
  33. package/src/__tests__/identity-routes.test.ts +16 -57
  34. package/src/__tests__/injector-chain.test.ts +8 -3
  35. package/src/__tests__/injector-config-quarantine-notice.test.ts +115 -0
  36. package/src/__tests__/llm-usage-store.test.ts +11 -0
  37. package/src/__tests__/memory-v2-static-injector.test.ts +22 -0
  38. package/src/__tests__/model-intents.test.ts +1 -1
  39. package/src/__tests__/oauth-cli.test.ts +19 -8
  40. package/src/__tests__/openai-provider.test.ts +34 -0
  41. package/src/__tests__/prechat-onboarding-contract.test.ts +0 -1
  42. package/src/__tests__/recurrence-engine.test.ts +45 -0
  43. package/src/__tests__/schedule-routes.test.ts +34 -0
  44. package/src/__tests__/scheduler-disk-pressure.test.ts +1 -1
  45. package/src/__tests__/script-proxy-conversation-manager.test.ts +10 -5
  46. package/src/__tests__/skill-tool-factory.test.ts +49 -0
  47. package/src/__tests__/subagent-role-registry.test.ts +24 -1
  48. package/src/__tests__/subagent-tools.test.ts +1 -0
  49. package/src/__tests__/system-prompt.test.ts +109 -11
  50. package/src/__tests__/tool-error-hook.test.ts +1 -0
  51. package/src/__tests__/tool-result-spool.test.ts +337 -0
  52. package/src/__tests__/tool-result-truncate-hook.test.ts +1 -0
  53. package/src/__tests__/validate-input.test.ts +95 -1
  54. package/src/__tests__/workspace-migration-098-remove-stale-updates-bulletin-file.test.ts +65 -0
  55. package/src/__tests__/workspace-migration-099-disable-cache-one-shot-callsites.test.ts +139 -0
  56. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +45 -95
  57. package/src/agent/loop.ts +81 -24
  58. package/src/api/events/usage-progress.ts +28 -0
  59. package/src/api/index.ts +6 -0
  60. package/src/background-wake/wake-intent-hooks.test.ts +2 -0
  61. package/src/bundler/app-bundler.ts +25 -42
  62. package/src/calls/call-controller.ts +1 -1
  63. package/src/cli/commands/plugins.ts +248 -15
  64. package/src/cli/lib/__tests__/inspect-plugin.test.ts +318 -0
  65. package/src/cli/lib/__tests__/install-from-github.test.ts +16 -9
  66. package/src/cli/lib/__tests__/plugin-artifact.test.ts +183 -0
  67. package/src/cli/lib/__tests__/plugin-details.test.ts +158 -0
  68. package/src/cli/lib/__tests__/plugin-fingerprint.test.ts +245 -0
  69. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +301 -0
  70. package/src/cli/lib/inspect-plugin.ts +252 -0
  71. package/src/cli/lib/install-from-github.ts +214 -21
  72. package/src/cli/lib/list-installed-plugins.ts +17 -6
  73. package/src/cli/lib/plugin-artifact.ts +103 -0
  74. package/src/cli/lib/plugin-details.ts +18 -1
  75. package/src/cli/lib/plugin-fingerprint.ts +197 -0
  76. package/src/cli/lib/upgrade-plugin.ts +219 -0
  77. package/src/config/bundled-skills/subagent/SKILL.md +2 -0
  78. package/src/config/bundled-skills/subagent/TOOLS.json +8 -2
  79. package/src/config/call-site-defaults.ts +13 -2
  80. package/src/config/feature-flag-registry.json +8 -16
  81. package/src/config/loader.ts +52 -59
  82. package/src/config/schema.ts +0 -2
  83. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  84. package/src/config/schemas/__tests__/memory-v3.test.ts +10 -0
  85. package/src/config/schemas/llm.ts +10 -0
  86. package/src/config/schemas/memory-v2.ts +13 -0
  87. package/src/config/schemas/memory-v3.ts +92 -0
  88. package/src/context/post-turn-tool-result-truncation.ts +32 -18
  89. package/src/context/tool-result-spool.ts +104 -0
  90. package/src/credential-execution/feature-gates.ts +0 -1
  91. package/src/daemon/conversation-agent-loop-handlers.ts +41 -16
  92. package/src/daemon/conversation-error.ts +6 -15
  93. package/src/daemon/conversation.ts +9 -0
  94. package/src/daemon/disk-pressure-policy.ts +0 -1
  95. package/src/daemon/lifecycle.ts +1 -20
  96. package/src/daemon/message-types/conversations.ts +2 -15
  97. package/src/daemon/trust-context.ts +1 -1
  98. package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
  99. package/src/home/__tests__/home-content-refresh.test.ts +114 -0
  100. package/src/home/__tests__/suggested-prompts.test.ts +86 -5
  101. package/src/home/home-content-refresh.ts +43 -31
  102. package/src/home/home-greeting-cache.ts +8 -1
  103. package/src/home/home-greeting.ts +13 -9
  104. package/src/home/suggested-prompts.ts +77 -24
  105. package/src/ipc/routes/trust-rules.test.ts +66 -72
  106. package/src/media/image-credentials.ts +2 -2
  107. package/src/memory/__tests__/compaction-log-store-clickhouse.test.ts +432 -0
  108. package/src/memory/{compaction-log-writer-clickhouse.ts → compaction-log-store-clickhouse.ts} +264 -55
  109. package/src/memory/conversation-attention-store.ts +1 -0
  110. package/src/memory/conversation-bootstrap.ts +18 -9
  111. package/src/memory/conversation-crud.ts +12 -2
  112. package/src/memory/conversation-title-service.ts +53 -9
  113. package/src/memory/delivery-channels.ts +0 -69
  114. package/src/memory/graph/extraction-job.ts +0 -15
  115. package/src/memory/guardian-action-store.ts +1 -376
  116. package/src/memory/llm-usage-store.ts +5 -1
  117. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +2 -2
  118. package/src/memory/v2/__tests__/consolidation-job.test.ts +183 -2
  119. package/src/memory/v2/__tests__/injection.test.ts +70 -0
  120. package/src/memory/v2/__tests__/static-context.test.ts +12 -0
  121. package/src/memory/v2/consolidation-job.ts +93 -9
  122. package/src/memory/v2/injection.ts +53 -0
  123. package/src/memory/v2/prompts/consolidation.ts +1 -0
  124. package/src/memory/v2/static-context.ts +13 -1
  125. package/src/memory/v2/sweep-job.ts +1 -1
  126. package/src/memory/v2/types.ts +5 -0
  127. package/src/plugin-api/types.ts +7 -0
  128. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +300 -0
  129. package/src/plugins/defaults/exploration-drift/package.json +15 -0
  130. package/src/plugins/defaults/index.ts +25 -0
  131. package/src/plugins/defaults/memory-retrieval/injectors.ts +132 -4
  132. package/src/plugins/defaults/memory-v3-shadow/__tests__/card.test.ts +92 -0
  133. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +2 -1
  134. package/src/plugins/defaults/memory-v3-shadow/__tests__/fresh-set.test.ts +52 -0
  135. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
  136. package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +2 -1
  137. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +136 -5
  138. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +17 -0
  139. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +6 -0
  140. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +5 -1
  141. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +68 -4
  142. package/src/plugins/defaults/memory-v3-shadow/card.ts +49 -5
  143. package/src/plugins/defaults/memory-v3-shadow/fresh-set.ts +59 -0
  144. package/src/plugins/defaults/memory-v3-shadow/injector.ts +4 -2
  145. package/src/plugins/defaults/memory-v3-shadow/learned-edges.test.ts +169 -0
  146. package/src/plugins/defaults/memory-v3-shadow/learned-edges.ts +178 -0
  147. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +115 -26
  148. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -9
  149. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +144 -22
  150. package/src/plugins/defaults/memory-v3-shadow/types.ts +24 -6
  151. package/src/plugins/defaults/title-generate/hooks/stop.ts +13 -0
  152. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +16 -0
  153. package/src/prompts/cache-boundary.ts +17 -0
  154. package/src/prompts/sections.ts +50 -17
  155. package/src/prompts/system-prompt.ts +12 -4
  156. package/src/prompts/templates/system-sections.ts +22 -0
  157. package/src/providers/anthropic/client.ts +74 -28
  158. package/src/providers/gemini/client.ts +5 -1
  159. package/src/providers/minimax/client.ts +9 -0
  160. package/src/providers/model-intents.ts +2 -2
  161. package/src/providers/openai/chat-completions-provider.ts +2 -1
  162. package/src/providers/openai/responses-provider.ts +5 -1
  163. package/src/providers/retry.ts +8 -0
  164. package/src/providers/types.ts +11 -0
  165. package/src/runtime/AGENTS.md +6 -0
  166. package/src/runtime/__tests__/agent-wake.test.ts +2 -2
  167. package/src/runtime/agent-wake.ts +5 -5
  168. package/src/runtime/background-job-runner.ts +2 -2
  169. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +150 -3
  170. package/src/runtime/migrations/vbundle-import-analyzer.ts +29 -6
  171. package/src/runtime/migrations/vbundle-import-policy.ts +23 -0
  172. package/src/runtime/migrations/vbundle-importer.ts +9 -4
  173. package/src/runtime/migrations/vbundle-streaming-importer.ts +8 -3
  174. package/src/runtime/pre-first-message-gate.ts +1 -1
  175. package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +241 -0
  176. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +97 -185
  177. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +17 -0
  178. package/src/runtime/routes/__tests__/plugins-routes.test.ts +1 -0
  179. package/src/runtime/routes/__tests__/task-routes.test.ts +3 -3
  180. package/src/runtime/routes/btw-routes.ts +0 -14
  181. package/src/runtime/routes/conversation-compaction-routes.ts +86 -19
  182. package/src/runtime/routes/conversation-list-routes.ts +77 -5
  183. package/src/runtime/routes/conversation-management-routes.ts +54 -0
  184. package/src/runtime/routes/gateway-log-routes.ts +14 -64
  185. package/src/runtime/routes/home-feed-routes.ts +10 -0
  186. package/src/runtime/routes/identity-intro-cache.ts +1 -1
  187. package/src/runtime/routes/identity-routes.ts +76 -20
  188. package/src/runtime/routes/inbound-message-handler.ts +0 -36
  189. package/src/runtime/routes/plugins-routes.ts +21 -0
  190. package/src/runtime/routes/schedule-routes.ts +19 -2
  191. package/src/runtime/routes/trust-rules-routes.ts +14 -67
  192. package/src/schedule/recurrence-engine.ts +34 -0
  193. package/src/schedule/scheduler.ts +1 -0
  194. package/src/skills/validate-input.ts +41 -1
  195. package/src/subagent/types.ts +26 -1
  196. package/src/telemetry/types.ts +15 -1
  197. package/src/telemetry/usage-telemetry-reporter.test.ts +6 -1
  198. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  199. package/src/tools/apps/executors.ts +1 -1
  200. package/src/tools/skills/skill-tool-factory.ts +19 -8
  201. package/src/usage/types.ts +8 -1
  202. package/src/util/platform.ts +16 -0
  203. package/src/watcher/engine.ts +1 -0
  204. package/src/workspace/adaptive-thinking-repair.ts +113 -0
  205. package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +70 -67
  206. package/src/workspace/migrations/098-remove-stale-updates-bulletin-file.ts +31 -0
  207. package/src/workspace/migrations/099-disable-cache-one-shot-callsites.ts +81 -0
  208. package/src/workspace/migrations/registry.ts +4 -0
  209. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +0 -202
  210. package/src/__tests__/conversation-starters-cadence.test.ts +0 -161
  211. package/src/__tests__/guardian-action-followup-executor.test.ts +0 -322
  212. package/src/__tests__/guardian-action-followup-store.test.ts +0 -373
  213. package/src/__tests__/guardian-action-late-reply.test.ts +0 -1083
  214. package/src/__tests__/update-bulletin-job.test.ts +0 -292
  215. package/src/config/schemas/updates.ts +0 -14
  216. package/src/memory/__tests__/compaction-log-writer-clickhouse.test.ts +0 -227
  217. package/src/memory/conversation-starters-cadence.ts +0 -78
  218. package/src/prompts/update-bulletin-job.ts +0 -180
  219. package/src/runtime/guardian-action-followup-executor.ts +0 -306
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Shared IPC contracts for assistant-to-gateway gateway-owned reads.
3
+ */
4
+
5
+ import { z } from "zod";
6
+
7
+ export const GATEWAY_LOG_LEVEL_NAMES = [
8
+ "trace",
9
+ "debug",
10
+ "info",
11
+ "warn",
12
+ "error",
13
+ "fatal",
14
+ ] as const;
15
+ export type GatewayLogLevelName = (typeof GATEWAY_LOG_LEVEL_NAMES)[number];
16
+
17
+ const GatewayLogsTailIpcParamsShape = {
18
+ n: z.number().int().min(1).max(1000).optional(),
19
+ level: z.enum(GATEWAY_LOG_LEVEL_NAMES).optional(),
20
+ module: z.string().optional(),
21
+ };
22
+
23
+ export const GatewayLogsTailIpcParamsSchema = z
24
+ .object(GatewayLogsTailIpcParamsShape)
25
+ .strict()
26
+ .default({});
27
+
28
+ export type GatewayLogsTailIpcParams = z.infer<
29
+ typeof GatewayLogsTailIpcParamsSchema
30
+ >;
31
+
32
+ export const GatewayLogsTailRouteParamsSchema = z
33
+ .object({
34
+ ...GatewayLogsTailIpcParamsShape,
35
+ n: z.coerce.number().int().min(1).max(1000).optional(),
36
+ })
37
+ .strict();
38
+
39
+ export type GatewayLogsTailRouteParams = z.infer<
40
+ typeof GatewayLogsTailRouteParamsSchema
41
+ >;
42
+
43
+ export const GatewayLogsTailIpcResponseSchema = z.object({
44
+ lines: z.array(z.record(z.string(), z.unknown())),
45
+ truncated: z.boolean(),
46
+ });
47
+
48
+ export type GatewayLogsTailIpcResponse = z.infer<
49
+ typeof GatewayLogsTailIpcResponseSchema
50
+ >;
51
+
52
+ export const TrustRulesListIpcParamsSchema = z
53
+ .object({
54
+ origin: z.string().optional(),
55
+ tool: z.string().optional(),
56
+ include_all: z.boolean().optional(),
57
+ include_deleted: z.boolean().optional(),
58
+ })
59
+ .strict()
60
+ .default({});
61
+
62
+ export type TrustRulesListIpcParams = z.infer<
63
+ typeof TrustRulesListIpcParamsSchema
64
+ >;
65
+
66
+ export const TrustRuleSchema = z.object({
67
+ id: z.string(),
68
+ tool: z.string(),
69
+ pattern: z.string(),
70
+ risk: z.enum(["low", "medium", "high"]),
71
+ description: z.string(),
72
+ origin: z.enum(["default", "user_defined"]),
73
+ userModified: z.boolean(),
74
+ deleted: z.boolean(),
75
+ createdAt: z.string(),
76
+ updatedAt: z.string(),
77
+ });
78
+
79
+ export type TrustRule = z.infer<typeof TrustRuleSchema>;
80
+
81
+ export const TrustRulesListIpcResponseSchema = z.object({
82
+ rules: z.array(TrustRuleSchema),
83
+ });
84
+
85
+ export type TrustRulesListIpcResponse = z.infer<
86
+ typeof TrustRulesListIpcResponseSchema
87
+ >;
@@ -15,11 +15,9 @@ export {
15
15
  deliverChannelReply,
16
16
  } from "./http-delivery.js";
17
17
 
18
- export {
19
- ipcCall,
20
- IpcCallError,
21
- PersistentIpcClient,
22
- } from "./ipc-client.js";
18
+ export * from "./gateway-ipc-contracts.js";
19
+
20
+ export { ipcCall, IpcCallError, PersistentIpcClient } from "./ipc-client.js";
23
21
 
24
22
  export type {
25
23
  ApprovalActionOption,
package/openapi.yaml CHANGED
@@ -3,7 +3,7 @@
3
3
  openapi: 3.1.0
4
4
  info:
5
5
  title: Vellum Assistant API
6
- version: 0.8.11
6
+ version: 0.8.12
7
7
  description: Auto-generated OpenAPI specification for the Vellum Assistant runtime HTTP server.
8
8
  servers:
9
9
  - url: http://127.0.0.1:7821
@@ -5937,6 +5937,7 @@ paths:
5937
5937
  - macos_notification_view
5938
5938
  - macos_conversation_opened
5939
5939
  - ios_conversation_opened
5940
+ - web_bulk_mark_read
5940
5941
  - telegram_inbound_message
5941
5942
  - telegram_callback
5942
5943
  - slack_inbound_message
@@ -6300,6 +6301,7 @@ paths:
6300
6301
  - macos_notification_view
6301
6302
  - macos_conversation_opened
6302
6303
  - ios_conversation_opened
6304
+ - web_bulk_mark_read
6303
6305
  - telegram_inbound_message
6304
6306
  - telegram_callback
6305
6307
  - slack_inbound_message
@@ -6500,6 +6502,7 @@ paths:
6500
6502
  - macos_notification_view
6501
6503
  - macos_conversation_opened
6502
6504
  - ios_conversation_opened
6505
+ - web_bulk_mark_read
6503
6506
  - telegram_inbound_message
6504
6507
  - telegram_callback
6505
6508
  - slack_inbound_message
@@ -6628,9 +6631,10 @@ paths:
6628
6631
  description:
6629
6632
  Return the chronological list of compaction events that ran in the same agent turn as the call identified
6630
6633
  by `callId`. Turn bounds are walked from the `messages` table (real user messages — tool-result user messages
6631
- are not boundaries). Projected from `llm_request_logs` rows where `call_site = "compactionAgent"`. When the
6632
- conversation has no other messages around the selected call, every compaction strictly before the call's
6633
- `createdAt` is in scope. Drives the Inspector's Compaction tab.
6634
+ are not boundaries). Served from the first-class compaction log when `compactionLogs.destination = "clickhouse"`
6635
+ is configured, falling back to the legacy projection over `llm_request_logs` rows where `call_site =
6636
+ "compactionAgent"`. When the conversation has no other messages around the selected call, every compaction
6637
+ strictly before the call's `createdAt` is in scope. Drives the Inspector's Compaction tab.
6634
6638
  tags:
6635
6639
  - conversations
6636
6640
  responses:
@@ -7095,6 +7099,44 @@ paths:
7095
7099
  required: true
7096
7100
  schema:
7097
7101
  type: string
7102
+ /v1/conversations/archive/bulk:
7103
+ post:
7104
+ operationId: conversations_archive_bulk_post
7105
+ summary: Bulk archive conversations
7106
+ description: Archive multiple conversations in one request. Emits a single sync invalidation for the entire batch.
7107
+ tags:
7108
+ - conversations
7109
+ responses:
7110
+ "200":
7111
+ description: Successful response
7112
+ content:
7113
+ application/json:
7114
+ schema:
7115
+ type: object
7116
+ properties:
7117
+ ok:
7118
+ type: boolean
7119
+ archived:
7120
+ type: number
7121
+ required:
7122
+ - ok
7123
+ - archived
7124
+ additionalProperties: false
7125
+ requestBody:
7126
+ required: true
7127
+ content:
7128
+ application/json:
7129
+ schema:
7130
+ type: object
7131
+ properties:
7132
+ conversationIds:
7133
+ minItems: 1
7134
+ type: array
7135
+ items:
7136
+ type: string
7137
+ required:
7138
+ - conversationIds
7139
+ additionalProperties: false
7098
7140
  /v1/conversations/attention:
7099
7141
  get:
7100
7142
  operationId: conversations_attention_get
@@ -7515,6 +7557,7 @@ paths:
7515
7557
  - macos_notification_view
7516
7558
  - macos_conversation_opened
7517
7559
  - ios_conversation_opened
7560
+ - web_bulk_mark_read
7518
7561
  - telegram_inbound_message
7519
7562
  - telegram_callback
7520
7563
  - slack_inbound_message
@@ -8522,6 +8565,46 @@ paths:
8522
8565
  required:
8523
8566
  - conversationId
8524
8567
  additionalProperties: false
8568
+ /v1/conversations/seen/bulk:
8569
+ post:
8570
+ operationId: conversations_seen_bulk_post
8571
+ summary: Bulk mark conversations as seen
8572
+ description:
8573
+ Mark multiple conversations as seen in one request. Emits a single sync invalidation for the entire batch
8574
+ instead of per-conversation events.
8575
+ tags:
8576
+ - conversations
8577
+ responses:
8578
+ "200":
8579
+ description: Successful response
8580
+ content:
8581
+ application/json:
8582
+ schema:
8583
+ type: object
8584
+ properties:
8585
+ ok:
8586
+ type: boolean
8587
+ updated:
8588
+ type: number
8589
+ required:
8590
+ - ok
8591
+ - updated
8592
+ additionalProperties: false
8593
+ requestBody:
8594
+ required: true
8595
+ content:
8596
+ application/json:
8597
+ schema:
8598
+ type: object
8599
+ properties:
8600
+ conversationIds:
8601
+ minItems: 1
8602
+ type: array
8603
+ items:
8604
+ type: string
8605
+ required:
8606
+ - conversationIds
8607
+ additionalProperties: false
8525
8608
  /v1/conversations/switch:
8526
8609
  post:
8527
8610
  operationId: conversations_switch_post
@@ -12920,6 +13003,23 @@ paths:
12920
13003
  - source
12921
13004
  - refreshing
12922
13005
  additionalProperties: false
13006
+ parameters:
13007
+ - name: localHour
13008
+ in: query
13009
+ required: false
13010
+ schema:
13011
+ type: integer
13012
+ minimum: 0
13013
+ maximum: 23
13014
+ description: Optional client-local hour of day used only when refreshing generated greetings.
13015
+ - name: localMinute
13016
+ in: query
13017
+ required: false
13018
+ schema:
13019
+ type: integer
13020
+ minimum: 0
13021
+ maximum: 59
13022
+ description: Optional client-local minute used only when refreshing generated greetings.
12923
13023
  /v1/image-generation/generate:
12924
13024
  post:
12925
13025
  operationId: imagegeneration_generate_post
@@ -19464,6 +19564,27 @@ paths:
19464
19564
  ref:
19465
19565
  type: string
19466
19566
  description: Git ref the catalog metadata / README were resolved at.
19567
+ artifact:
19568
+ anyOf:
19569
+ - type: object
19570
+ properties:
19571
+ url:
19572
+ type: string
19573
+ description: HTTPS URL the prebuilt client artifact is downloaded from.
19574
+ sha256:
19575
+ type: string
19576
+ description: Lowercase 64-char hex SHA-256 the download is verified against.
19577
+ label:
19578
+ description: Optional human label for the download (e.g. "Download for macOS"); absent when the plugin doesn't name it.
19579
+ type: string
19580
+ required:
19581
+ - url
19582
+ - sha256
19583
+ additionalProperties: false
19584
+ - type: "null"
19585
+ description:
19586
+ Prebuilt client artifact from `package.json` `vellum.artifact`, or null when the plugin ships none or its
19587
+ descriptor is incomplete (e.g. a placeholder sha256).
19467
19588
  required:
19468
19589
  - name
19469
19590
  - installed
@@ -19474,6 +19595,7 @@ paths:
19474
19595
  - source
19475
19596
  - readme
19476
19597
  - ref
19598
+ - artifact
19477
19599
  additionalProperties: false
19478
19600
  "400":
19479
19601
  description: The plugin name failed sanitization (e.g. contained slashes, dots, or uppercase letters).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/assistant",
3
- "version": "0.8.11",
3
+ "version": "0.8.12-staging.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -50,7 +50,6 @@
50
50
  "@vellumai/skill-host-contracts": "file:../packages/skill-host-contracts",
51
51
  "@vellumai/slack-text": "file:../packages/slack-text",
52
52
  "@vellumai/twilio-client": "file:../packages/twilio-client",
53
- "archiver": "7.0.1",
54
53
  "commander": "13.1.0",
55
54
  "croner": "10.0.1",
56
55
  "dotenv": "17.3.1",
@@ -97,7 +96,6 @@
97
96
  },
98
97
  "devDependencies": {
99
98
  "@microsoft/api-extractor": "7.58.8",
100
- "@types/archiver": "7.0.0",
101
99
  "@types/bun": "1.3.10",
102
100
  "@types/node": "25.5.0",
103
101
  "@types/semver": "7.5.8",
@@ -0,0 +1,185 @@
1
+ import {
2
+ existsSync,
3
+ mkdirSync,
4
+ readFileSync,
5
+ rmSync,
6
+ writeFileSync,
7
+ } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
+
12
+ import { repairAdaptiveThinkingOnManagedProfiles } from "../workspace/adaptive-thinking-repair.js";
13
+ import { enableAdaptiveThinkingManagedProfilesMigration } from "../workspace/migrations/097-enable-adaptive-thinking-managed-profiles.js";
14
+
15
+ const ADAPTIVE = { enabled: true, streamThinking: true };
16
+
17
+ let workspaceDir: string;
18
+
19
+ beforeEach(() => {
20
+ workspaceDir = join(
21
+ tmpdir(),
22
+ `vellum-adaptive-thinking-repair-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
23
+ );
24
+ mkdirSync(workspaceDir, { recursive: true });
25
+ });
26
+
27
+ afterEach(() => {
28
+ if (existsSync(workspaceDir)) {
29
+ rmSync(workspaceDir, { recursive: true, force: true });
30
+ }
31
+ });
32
+
33
+ function writeConfig(data: Record<string, unknown>): void {
34
+ writeFileSync(
35
+ join(workspaceDir, "config.json"),
36
+ JSON.stringify(data, null, 2) + "\n",
37
+ );
38
+ }
39
+
40
+ function readConfig(): Record<string, unknown> {
41
+ return JSON.parse(readFileSync(join(workspaceDir, "config.json"), "utf-8"));
42
+ }
43
+
44
+ function profile(name: string): Record<string, unknown> {
45
+ const config = readConfig();
46
+ const llm = config.llm as Record<string, unknown>;
47
+ const profiles = llm.profiles as Record<string, unknown>;
48
+ return profiles[name] as Record<string, unknown>;
49
+ }
50
+
51
+ // The startup repair and migration 097 keep frozen copies of the same logic
52
+ // (migration modules must stay self-contained). Run every scenario against
53
+ // both so the copies can't drift.
54
+ const implementations: Array<[string, (dir: string) => void]> = [
55
+ ["startup repair", repairAdaptiveThinkingOnManagedProfiles],
56
+ [
57
+ "migration 097",
58
+ (dir) => enableAdaptiveThinkingManagedProfilesMigration.run(dir),
59
+ ],
60
+ ];
61
+
62
+ describe.each(implementations)("%s", (_label, run) => {
63
+ test("patches managed Anthropic profiles missing thinking", () => {
64
+ writeConfig({
65
+ llm: {
66
+ default: { provider: "anthropic", model: "claude-sonnet-4-6" },
67
+ profiles: {
68
+ balanced: { source: "managed", provider: "anthropic" },
69
+ "quality-optimized": {
70
+ source: "managed",
71
+ provider: "anthropic",
72
+ thinking: { enabled: false },
73
+ },
74
+ },
75
+ },
76
+ });
77
+
78
+ run(workspaceDir);
79
+
80
+ expect(profile("balanced").thinking).toEqual(ADAPTIVE);
81
+ expect(profile("quality-optimized").thinking).toEqual(ADAPTIVE);
82
+ });
83
+
84
+ test("skips source-less empty shells when llm.default.provider is non-Anthropic", () => {
85
+ // Migration 052 seeds empty {} shells (no source, no provider) on legacy
86
+ // non-Anthropic workspaces. They inherit the non-Anthropic provider from
87
+ // llm.default and must stay off the Anthropic-specific repair.
88
+ writeConfig({
89
+ llm: {
90
+ default: { provider: "gemini", model: "gemini-2.5-pro" },
91
+ profiles: {
92
+ balanced: {},
93
+ "quality-optimized": {},
94
+ },
95
+ },
96
+ });
97
+
98
+ run(workspaceDir);
99
+
100
+ expect(profile("balanced")).toEqual({});
101
+ expect(profile("quality-optimized")).toEqual({});
102
+ });
103
+
104
+ test("treats absent llm.default.provider as Anthropic for source-less profiles", () => {
105
+ writeConfig({
106
+ llm: {
107
+ default: { model: "claude-sonnet-4-6" },
108
+ profiles: {
109
+ balanced: {},
110
+ },
111
+ },
112
+ });
113
+
114
+ run(workspaceDir);
115
+
116
+ expect(profile("balanced").thinking).toEqual(ADAPTIVE);
117
+ });
118
+
119
+ test("explicit Anthropic provider on the profile wins over a non-Anthropic default", () => {
120
+ writeConfig({
121
+ llm: {
122
+ default: { provider: "gemini" },
123
+ profiles: {
124
+ balanced: { provider: "anthropic" },
125
+ },
126
+ },
127
+ });
128
+
129
+ run(workspaceDir);
130
+
131
+ expect(profile("balanced").thinking).toEqual(ADAPTIVE);
132
+ });
133
+
134
+ test("skips profiles with an explicit non-Anthropic provider", () => {
135
+ writeConfig({
136
+ llm: {
137
+ default: { provider: "anthropic" },
138
+ profiles: {
139
+ balanced: { provider: "gemini" },
140
+ },
141
+ },
142
+ });
143
+
144
+ run(workspaceDir);
145
+
146
+ expect(profile("balanced").thinking).toBeUndefined();
147
+ });
148
+
149
+ test("skips source: user profiles", () => {
150
+ writeConfig({
151
+ llm: {
152
+ default: { provider: "anthropic" },
153
+ profiles: {
154
+ balanced: { source: "user", provider: "anthropic" },
155
+ },
156
+ },
157
+ });
158
+
159
+ run(workspaceDir);
160
+
161
+ expect(profile("balanced").thinking).toBeUndefined();
162
+ });
163
+
164
+ test("is idempotent when thinking is already enabled", () => {
165
+ const config = {
166
+ llm: {
167
+ default: { provider: "anthropic" },
168
+ profiles: {
169
+ balanced: {
170
+ source: "managed",
171
+ thinking: { enabled: true, streamThinking: false },
172
+ },
173
+ },
174
+ },
175
+ };
176
+ writeConfig(config);
177
+
178
+ run(workspaceDir);
179
+
180
+ expect(profile("balanced").thinking).toEqual({
181
+ enabled: true,
182
+ streamThinking: false,
183
+ });
184
+ });
185
+ });
@@ -4,8 +4,9 @@
4
4
  * The compaction pipeline between `context_compacting` (start) and
5
5
  * `compaction_completed` (end) is plugin-owned, so consumers reconstruct a
6
6
  * compaction attempt purely from the pair — correlated by `compactionId`.
7
- * These tests pin the pairing contract: shared id, trigger, timestamps, and
8
- * pre-compaction state on the start event.
7
+ * These tests pin the pairing contract: shared id, trigger, timestamps,
8
+ * pre-compaction state on the start event, and the unnested
9
+ * `ContextWindowResult` fields on the end event.
9
10
  */
10
11
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
12
 
@@ -185,11 +186,11 @@ describe("AgentLoop compaction start/end event pair", () => {
185
186
  expect(end!.finishedAt).toBeGreaterThanOrEqual(end!.startedAt);
186
187
  expect(end!.finishedAt).toBeLessThanOrEqual(after);
187
188
 
188
- // Start carries the pre-compaction history; end carries the result and
189
- // the stripped history the summary was built from.
189
+ // Start carries the pre-compaction history; end carries the
190
+ // ContextWindowResult fields unnested on the event.
190
191
  expect(start!.messages.length).toBeGreaterThan(0);
191
- expect(end!.result.compacted).toBe(true);
192
- expect(end!.messages.length).toBeGreaterThan(0);
192
+ expect(end!.compacted).toBe(true);
193
+ expect(end!.exhausted).toBe(false);
193
194
 
194
195
  // Start precedes end in the event stream.
195
196
  expect(events.indexOf(start!)).toBeLessThan(events.indexOf(end!));
@@ -106,6 +106,7 @@ mock.module("@anthropic-ai/sdk", () => ({
106
106
  }));
107
107
 
108
108
  // Import after mocking
109
+ import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../prompts/cache-boundary.js";
109
110
  import { AnthropicProvider } from "../providers/anthropic/client.js";
110
111
  import {
111
112
  isPlaceholderSentinelText,
@@ -308,6 +309,91 @@ describe("AnthropicProvider — Cache-Control Characterization", () => {
308
309
  });
309
310
  });
310
311
 
312
+ test("splits a boundary-carrying system prompt into two cached blocks and drops the tool breakpoint", async () => {
313
+ /**
314
+ * Tests that the SYSTEM_PROMPT_CACHE_BOUNDARY marker yields two
315
+ * independently cached system blocks, and that the explicit
316
+ * last-tool breakpoint is suppressed (the first system breakpoint
317
+ * already covers tools) so the total stays within Anthropic's
318
+ * 4-breakpoint budget.
319
+ */
320
+ // GIVEN a system prompt carrying a cache boundary, plus tools and a
321
+ // tool-use loop (so turn-start and tail breakpoints also apply)
322
+ const prompt = `stable sections${SYSTEM_PROMPT_CACHE_BOUNDARY}volatile sections`;
323
+ const messages: Message[] = [
324
+ userMsg("Do something"),
325
+ toolUseMsg("tu_1", "bash"),
326
+ toolResultMsg("tu_1", "output"),
327
+ ];
328
+
329
+ // WHEN the message is sent
330
+ await provider.sendMessage(messages, {
331
+ tools: sampleTools,
332
+ systemPrompt: prompt,
333
+ });
334
+
335
+ // THEN the system prompt is split into two blocks, each 1h-cached
336
+ const system = lastStreamParams!.system as Array<{
337
+ type: string;
338
+ text: string;
339
+ cache_control?: { type: string; ttl?: string };
340
+ }>;
341
+ expect(system).toHaveLength(2);
342
+ expect(system[0].text).toBe("stable sections");
343
+ expect(system[1].text).toBe("volatile sections");
344
+ expect(system[0].cache_control).toEqual({ type: "ephemeral", ttl: "1h" });
345
+ expect(system[1].cache_control).toEqual({ type: "ephemeral", ttl: "1h" });
346
+
347
+ // AND no tool carries a breakpoint (system block 1 covers them)
348
+ const tools = lastStreamParams!.tools as Array<{
349
+ cache_control?: { type: string; ttl?: string };
350
+ }>;
351
+ for (const tool of tools) {
352
+ expect(tool.cache_control).toBeUndefined();
353
+ }
354
+
355
+ // AND the turn-start and tail message breakpoints are unchanged,
356
+ // keeping the total at the 4-breakpoint cap
357
+ const sent = lastStreamParams!.messages as Array<{
358
+ role: string;
359
+ content: Array<{
360
+ type: string;
361
+ cache_control?: { type: string; ttl?: string };
362
+ }>;
363
+ }>;
364
+ const turnStart = sent[0];
365
+ expect(
366
+ turnStart.content[turnStart.content.length - 1].cache_control,
367
+ ).toEqual({ type: "ephemeral", ttl: "1h" });
368
+ const lastMsg = sent[sent.length - 1];
369
+ expect(lastMsg.content[lastMsg.content.length - 1].cache_control).toEqual({
370
+ type: "ephemeral",
371
+ ttl: "5m",
372
+ });
373
+ });
374
+
375
+ test("keeps the last-tool breakpoint when the system prompt has no boundary", async () => {
376
+ /**
377
+ * Tests that a boundary-free system prompt preserves the explicit
378
+ * tool breakpoint (single system block leaves budget for it).
379
+ */
380
+ // GIVEN a system prompt without a cache boundary and tools
381
+ // WHEN the message is sent
382
+ await provider.sendMessage([userMsg("Hi")], {
383
+ tools: sampleTools,
384
+ systemPrompt: "You are helpful.",
385
+ });
386
+
387
+ // THEN the last tool keeps its breakpoint
388
+ const tools = lastStreamParams!.tools as Array<{
389
+ cache_control?: { type: string; ttl?: string };
390
+ }>;
391
+ expect(tools[tools.length - 1].cache_control).toEqual({
392
+ type: "ephemeral",
393
+ ttl: "1h",
394
+ });
395
+ });
396
+
311
397
  // -----------------------------------------------------------------------
312
398
  // Tool cache control
313
399
  // -----------------------------------------------------------------------
@@ -389,6 +475,49 @@ describe("AnthropicProvider — Cache-Control Characterization", () => {
389
475
  ).not.toContain("extended-cache-ttl-2025-04-11");
390
476
  });
391
477
 
478
+ test("disableCache sends no cache_control anywhere and strips caller-stamped block markers", async () => {
479
+ // A one-shot call site that opted out of prompt caching: no breakpoint
480
+ // on system, tools, turn-start, or tail — and a caller-stamped block
481
+ // marker is removed rather than forwarded.
482
+ const messages: Message[] = [
483
+ {
484
+ role: "user",
485
+ content: [
486
+ cachedPrefixBlock("stable pages block"),
487
+ { type: "text", text: "Do something" },
488
+ ],
489
+ },
490
+ toolUseMsg("tu_1", "bash"),
491
+ toolResultMsg("tu_1", "output"),
492
+ ];
493
+ await provider.sendMessage(messages, {
494
+ tools: sampleTools,
495
+ systemPrompt: "You are a helpful assistant.",
496
+ config: { disableCache: true },
497
+ });
498
+
499
+ const system = lastStreamParams!.system as Array<{
500
+ cache_control?: unknown;
501
+ }>;
502
+ expect(system[0].cache_control).toBeUndefined();
503
+
504
+ const tools = lastStreamParams!.tools as Array<{
505
+ cache_control?: unknown;
506
+ }>;
507
+ for (const tool of tools) {
508
+ expect(tool.cache_control).toBeUndefined();
509
+ }
510
+
511
+ const sent = lastStreamParams!.messages as Array<{
512
+ content: Array<{ cache_control?: unknown }>;
513
+ }>;
514
+ for (const message of sent) {
515
+ for (const block of message.content) {
516
+ expect(block.cache_control).toBeUndefined();
517
+ }
518
+ }
519
+ });
520
+
392
521
  test("v3-shape call (system + tools + cached prefix block) stays within the 4-breakpoint cap", async () => {
393
522
  // Mirrors a v3 L2 selector call: a system prompt, a forced tool, and a user
394
523
  // message whose stable <pages> block carries a cache_control breakpoint