@vellumai/assistant 0.5.6 → 0.5.7

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 (305) hide show
  1. package/.env.example +16 -2
  2. package/ARCHITECTURE.md +6 -75
  3. package/Dockerfile +1 -1
  4. package/README.md +0 -2
  5. package/bun.lock +0 -414
  6. package/docs/architecture/keychain-broker.md +45 -240
  7. package/docs/architecture/security.md +0 -17
  8. package/docs/credential-execution-service.md +2 -2
  9. package/node_modules/@vellumai/ces-contracts/package.json +1 -0
  10. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +119 -0
  11. package/node_modules/@vellumai/credential-storage/package.json +1 -0
  12. package/node_modules/@vellumai/egress-proxy/package.json +1 -0
  13. package/package.json +2 -3
  14. package/src/__tests__/actor-token-service.test.ts +0 -114
  15. package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
  16. package/src/__tests__/browser-skill-endstate.test.ts +6 -5
  17. package/src/__tests__/btw-routes.test.ts +0 -39
  18. package/src/__tests__/call-domain.test.ts +0 -128
  19. package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
  20. package/src/__tests__/channel-approval-routes.test.ts +0 -5
  21. package/src/__tests__/channel-readiness-service.test.ts +1 -60
  22. package/src/__tests__/checker.test.ts +4 -2
  23. package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
  24. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  25. package/src/__tests__/config-schema.test.ts +1 -1
  26. package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
  27. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  28. package/src/__tests__/conversation-skill-tools.test.ts +0 -54
  29. package/src/__tests__/conversation-title-service.test.ts +87 -0
  30. package/src/__tests__/credential-execution-feature-gates.test.ts +28 -14
  31. package/src/__tests__/credential-execution-managed-contract.test.ts +33 -18
  32. package/src/__tests__/credential-security-e2e.test.ts +0 -66
  33. package/src/__tests__/credential-security-invariants.test.ts +4 -45
  34. package/src/__tests__/credentials-cli.test.ts +78 -0
  35. package/src/__tests__/db-migration-rollback.test.ts +2015 -1
  36. package/src/__tests__/docker-signing-key-bootstrap.test.ts +34 -143
  37. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
  38. package/src/__tests__/guardian-routing-state.test.ts +0 -5
  39. package/src/__tests__/host-shell-tool.test.ts +6 -7
  40. package/src/__tests__/http-user-message-parity.test.ts +3 -103
  41. package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
  42. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
  43. package/src/__tests__/intent-routing.test.ts +0 -13
  44. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
  45. package/src/__tests__/keychain-broker-client.test.ts +161 -22
  46. package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
  47. package/src/__tests__/migration-export-http.test.ts +2 -2
  48. package/src/__tests__/migration-import-commit-http.test.ts +2 -2
  49. package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
  50. package/src/__tests__/migration-validate-http.test.ts +2 -2
  51. package/src/__tests__/non-member-access-request.test.ts +0 -5
  52. package/src/__tests__/notification-decision-fallback.test.ts +4 -0
  53. package/src/__tests__/notification-decision-identity.test.ts +4 -0
  54. package/src/__tests__/permission-types.test.ts +1 -0
  55. package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
  56. package/src/__tests__/qdrant-manager.test.ts +28 -2
  57. package/src/__tests__/registry.test.ts +0 -6
  58. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
  59. package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
  60. package/src/__tests__/secure-keys.test.ts +83 -263
  61. package/src/__tests__/shell-identity.test.ts +96 -6
  62. package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
  63. package/src/__tests__/skill-feature-flags.test.ts +46 -45
  64. package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
  65. package/src/__tests__/skill-load-inline-command.test.ts +8 -12
  66. package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
  67. package/src/__tests__/skill-load-tool.test.ts +0 -2
  68. package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
  69. package/src/__tests__/skills.test.ts +0 -2
  70. package/src/__tests__/slack-inbound-verification.test.ts +0 -4
  71. package/src/__tests__/suggestion-routes.test.ts +1 -32
  72. package/src/__tests__/system-prompt.test.ts +0 -1
  73. package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
  74. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
  75. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
  76. package/src/__tests__/update-bulletin.test.ts +0 -2
  77. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
  78. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -6
  79. package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
  80. package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +218 -0
  81. package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
  82. package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
  83. package/src/calls/audio-store.test.ts +97 -0
  84. package/src/calls/audio-store.ts +205 -0
  85. package/src/calls/call-controller.ts +85 -7
  86. package/src/calls/call-domain.ts +3 -0
  87. package/src/calls/call-store.ts +10 -3
  88. package/src/calls/fish-audio-client.ts +117 -0
  89. package/src/calls/relay-server.ts +27 -0
  90. package/src/calls/twilio-routes.ts +2 -1
  91. package/src/calls/types.ts +1 -0
  92. package/src/calls/voice-ingress-preflight.ts +0 -42
  93. package/src/calls/voice-quality.ts +26 -5
  94. package/src/calls/voice-session-bridge.ts +6 -12
  95. package/src/cli/commands/config.ts +1 -4
  96. package/src/cli/commands/credentials.ts +34 -4
  97. package/src/cli/commands/oauth/index.ts +7 -0
  98. package/src/cli/commands/oauth/platform.ts +179 -0
  99. package/src/cli/commands/platform.ts +3 -3
  100. package/src/config/assistant-feature-flags.ts +186 -5
  101. package/src/config/bundled-skills/messaging/SKILL.md +5 -5
  102. package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
  103. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  104. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
  105. package/src/config/bundled-tool-registry.ts +1 -11
  106. package/src/config/env-registry.ts +1 -1
  107. package/src/config/env.ts +8 -14
  108. package/src/config/feature-flag-registry.json +48 -8
  109. package/src/config/loader.ts +98 -31
  110. package/src/config/schema.ts +4 -13
  111. package/src/config/schemas/calls.ts +13 -0
  112. package/src/config/schemas/fish-audio.ts +39 -0
  113. package/src/config/schemas/security.ts +0 -4
  114. package/src/config/types.ts +0 -1
  115. package/src/contacts/contact-store.ts +39 -0
  116. package/src/contacts/types.ts +2 -0
  117. package/src/credential-execution/approval-bridge.ts +1 -0
  118. package/src/credential-execution/executable-discovery.ts +28 -4
  119. package/src/credential-execution/feature-gates.ts +16 -0
  120. package/src/credential-execution/process-manager.ts +38 -0
  121. package/src/daemon/assistant-attachments.ts +9 -0
  122. package/src/daemon/config-watcher.ts +5 -0
  123. package/src/daemon/conversation-tool-setup.ts +0 -105
  124. package/src/daemon/conversation.ts +10 -1
  125. package/src/daemon/handlers/config-vercel.ts +92 -0
  126. package/src/daemon/handlers/skills.ts +2 -15
  127. package/src/daemon/install-symlink.ts +195 -0
  128. package/src/daemon/lifecycle.ts +227 -51
  129. package/src/daemon/message-types/conversations.ts +3 -4
  130. package/src/daemon/message-types/diagnostics.ts +3 -22
  131. package/src/daemon/message-types/messages.ts +0 -2
  132. package/src/daemon/message-types/upgrades.ts +8 -0
  133. package/src/daemon/server.ts +30 -92
  134. package/src/events/domain-events.ts +2 -1
  135. package/src/inbound/platform-callback-registration.ts +3 -3
  136. package/src/instrument.ts +8 -5
  137. package/src/memory/conversation-title-service.ts +50 -1
  138. package/src/memory/db-init.ts +12 -0
  139. package/src/memory/items-extractor.ts +15 -1
  140. package/src/memory/job-handlers/conversation-starters.ts +4 -1
  141. package/src/memory/jobs-store.ts +30 -5
  142. package/src/memory/jobs-worker.ts +31 -7
  143. package/src/memory/migrations/001-job-deferrals.ts +19 -0
  144. package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
  145. package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
  146. package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
  147. package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
  148. package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
  149. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
  150. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
  151. package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
  152. package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
  153. package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
  154. package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
  155. package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
  156. package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
  157. package/src/memory/migrations/116-messages-fts.ts +106 -1
  158. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
  159. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
  160. package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
  161. package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
  162. package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
  163. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
  164. package/src/memory/migrations/141-rename-verification-table.ts +54 -0
  165. package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
  166. package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
  167. package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
  168. package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
  169. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
  170. package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
  171. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
  172. package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
  173. package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
  174. package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
  175. package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
  176. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
  177. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
  178. package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
  179. package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
  180. package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
  181. package/src/memory/migrations/index.ts +4 -0
  182. package/src/memory/migrations/registry.ts +90 -0
  183. package/src/memory/migrations/validate-migration-state.ts +137 -11
  184. package/src/memory/qdrant-circuit-breaker.ts +9 -0
  185. package/src/memory/qdrant-manager.ts +64 -7
  186. package/src/memory/schema/calls.ts +1 -0
  187. package/src/memory/schema/contacts.ts +1 -0
  188. package/src/notifications/decision-engine.ts +4 -1
  189. package/src/oauth/connection-resolver.ts +6 -4
  190. package/src/permissions/checker.ts +0 -38
  191. package/src/permissions/shell-identity.ts +76 -22
  192. package/src/permissions/types.ts +4 -2
  193. package/src/platform/client.ts +35 -7
  194. package/src/prompts/persona-resolver.ts +138 -0
  195. package/src/prompts/system-prompt.ts +36 -4
  196. package/src/prompts/templates/users/default.md +1 -0
  197. package/src/providers/registry.ts +27 -40
  198. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
  199. package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
  200. package/src/runtime/auth/external-assistant-id.ts +13 -59
  201. package/src/runtime/auth/route-policy.ts +15 -1
  202. package/src/runtime/auth/token-service.ts +43 -138
  203. package/src/runtime/channel-readiness-service.ts +1 -16
  204. package/src/runtime/http-server.ts +27 -2
  205. package/src/runtime/middleware/error-handler.ts +1 -9
  206. package/src/runtime/routes/audio-routes.ts +40 -0
  207. package/src/runtime/routes/btw-routes.ts +0 -17
  208. package/src/runtime/routes/conversation-query-routes.ts +63 -1
  209. package/src/runtime/routes/conversation-routes.ts +4 -44
  210. package/src/runtime/routes/diagnostics-routes.ts +1 -477
  211. package/src/runtime/routes/identity-routes.ts +18 -29
  212. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
  213. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
  214. package/src/runtime/routes/integrations/vercel.ts +89 -0
  215. package/src/runtime/routes/log-export-routes.ts +5 -0
  216. package/src/runtime/routes/memory-item-routes.ts +24 -6
  217. package/src/runtime/routes/migration-rollback-routes.ts +209 -0
  218. package/src/runtime/routes/migration-routes.ts +17 -1
  219. package/src/runtime/routes/notification-routes.ts +58 -0
  220. package/src/runtime/routes/schedule-routes.ts +65 -0
  221. package/src/runtime/routes/settings-routes.ts +41 -1
  222. package/src/runtime/routes/tts-routes.ts +86 -0
  223. package/src/runtime/routes/upgrade-broadcast-routes.ts +26 -2
  224. package/src/runtime/routes/workspace-commit-routes.ts +62 -0
  225. package/src/runtime/routes/workspace-routes.test.ts +22 -1
  226. package/src/runtime/routes/workspace-routes.ts +1 -1
  227. package/src/runtime/routes/workspace-utils.ts +86 -2
  228. package/src/security/ces-credential-client.ts +59 -22
  229. package/src/security/ces-rpc-credential-backend.ts +85 -0
  230. package/src/security/credential-backend.ts +12 -88
  231. package/src/security/keychain-broker-client.ts +10 -2
  232. package/src/security/secure-keys.ts +94 -113
  233. package/src/skills/catalog-install.ts +13 -7
  234. package/src/telemetry/usage-telemetry-reporter.ts +4 -2
  235. package/src/tools/calls/call-start.ts +1 -0
  236. package/src/tools/executor.ts +0 -4
  237. package/src/tools/network/script-proxy/session-manager.ts +19 -4
  238. package/src/tools/network/web-fetch.ts +3 -1
  239. package/src/tools/skills/execute.ts +1 -1
  240. package/src/tools/types.ts +0 -8
  241. package/src/util/errors.ts +0 -12
  242. package/src/util/platform.ts +3 -50
  243. package/src/workspace/git-service.ts +5 -2
  244. package/src/workspace/migrations/001-avatar-rename.ts +15 -0
  245. package/src/workspace/migrations/003-seed-device-id.ts +17 -1
  246. package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
  247. package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
  248. package/src/workspace/migrations/006-services-config.ts +49 -0
  249. package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
  250. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
  251. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
  252. package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
  253. package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
  254. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
  255. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
  256. package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
  257. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
  258. package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
  259. package/src/workspace/migrations/017-seed-persona-dirs.ts +95 -0
  260. package/src/workspace/migrations/migrate-to-workspace-volume.ts +23 -1
  261. package/src/workspace/migrations/registry.ts +8 -0
  262. package/src/workspace/migrations/runner.ts +106 -2
  263. package/src/workspace/migrations/types.ts +4 -0
  264. package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
  265. package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
  266. package/src/__tests__/diagnostics-export.test.ts +0 -288
  267. package/src/__tests__/local-gateway-health.test.ts +0 -209
  268. package/src/__tests__/secret-ingress-handler.test.ts +0 -120
  269. package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
  270. package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
  271. package/src/__tests__/swarm-orchestrator.test.ts +0 -463
  272. package/src/__tests__/swarm-plan-validator.test.ts +0 -384
  273. package/src/__tests__/swarm-recursion.test.ts +0 -197
  274. package/src/__tests__/swarm-router-planner.test.ts +0 -234
  275. package/src/__tests__/swarm-tool.test.ts +0 -185
  276. package/src/__tests__/swarm-worker-backend.test.ts +0 -144
  277. package/src/__tests__/swarm-worker-runner.test.ts +0 -288
  278. package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
  279. package/src/commands/cc-command-registry.ts +0 -248
  280. package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
  281. package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
  282. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
  283. package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
  284. package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
  285. package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
  286. package/src/config/schemas/swarm.ts +0 -82
  287. package/src/logfire.ts +0 -135
  288. package/src/runtime/local-gateway-health.ts +0 -275
  289. package/src/security/secret-ingress.ts +0 -68
  290. package/src/swarm/backend-claude-code.ts +0 -225
  291. package/src/swarm/checkpoint.ts +0 -137
  292. package/src/swarm/graph-utils.ts +0 -53
  293. package/src/swarm/index.ts +0 -55
  294. package/src/swarm/limits.ts +0 -66
  295. package/src/swarm/orchestrator.ts +0 -424
  296. package/src/swarm/plan-validator.ts +0 -117
  297. package/src/swarm/router-planner.ts +0 -162
  298. package/src/swarm/router-prompts.ts +0 -39
  299. package/src/swarm/synthesizer.ts +0 -81
  300. package/src/swarm/types.ts +0 -72
  301. package/src/swarm/worker-backend.ts +0 -131
  302. package/src/swarm/worker-prompts.ts +0 -80
  303. package/src/swarm/worker-runner.ts +0 -170
  304. package/src/tools/claude-code/claude-code.ts +0 -610
  305. package/src/tools/swarm/delegate.ts +0 -205
@@ -0,0 +1,40 @@
1
+ /**
2
+ * HTTP route handler for serving synthesized TTS audio.
3
+ *
4
+ * GET /v1/audio/:audioId — retrieve a previously stored audio segment.
5
+ *
6
+ * This endpoint is unauthenticated because Twilio fetches audio URLs
7
+ * directly; the audioId itself is an unguessable UUID that acts as a
8
+ * capability token.
9
+ */
10
+
11
+ import { getAudio } from "../../calls/audio-store.js";
12
+ import { httpError } from "../http-errors.js";
13
+
14
+ /**
15
+ * Handle GET /v1/audio/:audioId.
16
+ *
17
+ * Returns the audio with its stored Content-Type. For complete audio,
18
+ * includes Content-Length for efficient playback. For in-progress
19
+ * streaming entries, uses chunked transfer encoding.
20
+ */
21
+ export function handleGetAudio(audioId: string): Response {
22
+ const entry = getAudio(audioId);
23
+ if (!entry) {
24
+ return httpError("NOT_FOUND", "Audio not found", 404);
25
+ }
26
+ if (entry.type === "buffer") {
27
+ return new Response(new Uint8Array(entry.buffer), {
28
+ status: 200,
29
+ headers: {
30
+ "Content-Type": entry.contentType,
31
+ "Content-Length": entry.buffer.length.toString(),
32
+ },
33
+ });
34
+ }
35
+ // Streaming — Content-Length unknown, chunked transfer encoding
36
+ return new Response(entry.stream, {
37
+ status: 200,
38
+ headers: { "Content-Type": entry.contentType },
39
+ });
40
+ }
@@ -15,7 +15,6 @@
15
15
  import { existsSync, readFileSync } from "node:fs";
16
16
 
17
17
  import { getConversationByKey } from "../../memory/conversation-key-store.js";
18
- import { checkIngressForSecrets } from "../../security/secret-ingress.js";
19
18
  import { getLogger } from "../../util/logger.js";
20
19
  import { getWorkspacePromptPath } from "../../util/platform.js";
21
20
  import type { AuthContext } from "../auth/types.js";
@@ -89,22 +88,6 @@ async function handleBtw(
89
88
  }
90
89
 
91
90
  const trimmedContent = content.trim();
92
- const ingressCheck = checkIngressForSecrets(trimmedContent);
93
- if (ingressCheck.blocked) {
94
- log.warn(
95
- { detectedTypes: ingressCheck.detectedTypes },
96
- "Blocked /v1/btw message containing secrets",
97
- );
98
- return Response.json(
99
- {
100
- accepted: false,
101
- error: "secret_blocked",
102
- message: ingressCheck.userNotice,
103
- detectedTypes: ingressCheck.detectedTypes,
104
- },
105
- { status: 422 },
106
- );
107
- }
108
91
 
109
92
  // ----- Identity intro fast-path -----
110
93
  // When the client requests the identity intro, check SOUL.md first (persisted
@@ -12,13 +12,20 @@
12
12
  * PUT /v1/config/embeddings — set embedding provider/model
13
13
  * GET /v1/config/permissions/skip — dangerouslySkipPermissions status
14
14
  * PUT /v1/config/permissions/skip — toggle dangerouslySkipPermissions
15
+ * GET /v1/config — full raw workspace config
16
+ * PATCH /v1/config — deep-merge partial config
15
17
  * GET /v1/conversations/search — search conversations
16
18
  * GET /v1/messages/:id/content — full message content
17
19
  * GET /v1/messages/:id/llm-context — LLM request logs for a message
18
20
  * DELETE /v1/messages/queued/:id — delete queued message
19
21
  */
20
22
 
21
- import { getConfig, loadRawConfig, saveRawConfig } from "../../config/loader.js";
23
+ import {
24
+ deepMergeOverwrite,
25
+ getConfig,
26
+ loadRawConfig,
27
+ saveRawConfig,
28
+ } from "../../config/loader.js";
22
29
  import { VALID_MEMORY_EMBEDDING_PROVIDERS } from "../../config/schemas/memory-storage.js";
23
30
  import { VALID_INFERENCE_PROVIDERS } from "../../config/schemas/services.js";
24
31
  import {
@@ -292,6 +299,61 @@ export function conversationQueryRouteDefinitions(
292
299
  },
293
300
  },
294
301
 
302
+ // ── Full config read ─────────────────────────────────────────────
303
+ {
304
+ endpoint: "config",
305
+ method: "GET",
306
+ policyKey: "config",
307
+ handler: () => {
308
+ try {
309
+ const raw = loadRawConfig();
310
+ return Response.json(raw);
311
+ } catch (err) {
312
+ const message = err instanceof Error ? err.message : String(err);
313
+ return httpError(
314
+ "INTERNAL_ERROR",
315
+ `Failed to read config: ${message}`,
316
+ 500,
317
+ );
318
+ }
319
+ },
320
+ },
321
+
322
+ // ── Generic config patch ──────────────────────────────────────────
323
+ {
324
+ endpoint: "config",
325
+ method: "PATCH",
326
+ policyKey: "config",
327
+ handler: async ({ req }) => {
328
+ const body = (await req.json()) as Record<string, unknown>;
329
+ if (
330
+ body == null ||
331
+ typeof body !== "object" ||
332
+ Array.isArray(body) ||
333
+ Object.keys(body).length === 0
334
+ ) {
335
+ return httpError(
336
+ "BAD_REQUEST",
337
+ "Body must be a non-empty JSON object",
338
+ 400,
339
+ );
340
+ }
341
+ try {
342
+ const raw = loadRawConfig();
343
+ deepMergeOverwrite(raw, body);
344
+ saveRawConfig(raw);
345
+ return Response.json({ ok: true });
346
+ } catch (err) {
347
+ const message = err instanceof Error ? err.message : String(err);
348
+ return httpError(
349
+ "INTERNAL_ERROR",
350
+ `Failed to patch config: ${message}`,
351
+ 500,
352
+ );
353
+ }
354
+ },
355
+ },
356
+
295
357
  // ── Conversation search ───────────────────────────────────────────
296
358
  {
297
359
  endpoint: "conversations/search",
@@ -56,7 +56,6 @@ import {
56
56
  import { searchConversations } from "../../memory/conversation-queries.js";
57
57
  import { getConfiguredProvider } from "../../providers/provider-send-message.js";
58
58
  import type { Provider } from "../../providers/types.js";
59
- import { checkIngressForSecrets } from "../../security/secret-ingress.js";
60
59
  import { getLogger } from "../../util/logger.js";
61
60
  import { silentlyWithLog } from "../../util/silently.js";
62
61
  import { buildAssistantEvent } from "../assistant-event.js";
@@ -637,7 +636,6 @@ export async function handleSendMessage(
637
636
  interface?: string;
638
637
  conversationType?: string;
639
638
  automated?: boolean;
640
- bypassSecretCheck?: boolean;
641
639
  };
642
640
 
643
641
  const { conversationKey, content, attachmentIds } = body;
@@ -705,29 +703,6 @@ export async function handleSendMessage(
705
703
  }
706
704
  }
707
705
 
708
- // Block inbound messages containing secrets before they reach the model.
709
- // This mirrors the legacy handleUserMessage behavior: secrets are
710
- // detected and the message is rejected with a safe notice. The client
711
- // should prompt the user to use the secure credential flow instead.
712
- if (trimmedContent.length > 0 && !body.bypassSecretCheck) {
713
- const ingressCheck = checkIngressForSecrets(trimmedContent);
714
- if (ingressCheck.blocked) {
715
- log.warn(
716
- { detectedTypes: ingressCheck.detectedTypes },
717
- "Blocked user message containing secrets (POST /v1/messages)",
718
- );
719
- return Response.json(
720
- {
721
- accepted: false,
722
- error: "secret_blocked",
723
- message: ingressCheck.userNotice,
724
- detectedTypes: ingressCheck.detectedTypes,
725
- },
726
- { status: 422 },
727
- );
728
- }
729
- }
730
-
731
706
  if (!deps.sendMessageDeps) {
732
707
  return httpError(
733
708
  "SERVICE_UNAVAILABLE",
@@ -1259,12 +1234,12 @@ async function generateLlmSuggestion(
1259
1234
  const truncated =
1260
1235
  assistantText.length > 2000 ? assistantText.slice(-2000) : assistantText;
1261
1236
 
1262
- const prompt = `Given this assistant message, write a very short tab-complete suggestion (max 50 chars) the user could send next to keep the conversation going. Be casual, curious, or actionable — like a quick reply, not a formal request. Reply with ONLY the suggestion text.\n\nAssistant's message:\n${truncated}`;
1237
+ const prompt = `Given this assistant message, write a very short tab-complete suggestion the user could send next to keep the conversation going. Be casual, curious, or actionable — like a quick reply, not a formal request. Reply with ONLY the suggestion text.\n\nAssistant's message:\n${truncated}`;
1263
1238
  const response = await provider.sendMessage(
1264
1239
  [{ role: "user", content: [{ type: "text", text: prompt }] }],
1265
1240
  [], // no tools
1266
1241
  undefined, // no system prompt
1267
- { config: { max_tokens: 40, modelIntent: "latency-optimized" } },
1242
+ { config: { modelIntent: "latency-optimized" } },
1268
1243
  );
1269
1244
 
1270
1245
  const textBlock = response.content.find((b) => b.type === "text");
@@ -1276,7 +1251,7 @@ async function generateLlmSuggestion(
1276
1251
  return null;
1277
1252
  }
1278
1253
 
1279
- // Take first line only, then enforce the length cap
1254
+ // Take first line only
1280
1255
  const firstLine = stripped.split("\n")[0].trim();
1281
1256
  if (!firstLine) {
1282
1257
  log.debug(
@@ -1285,22 +1260,7 @@ async function generateLlmSuggestion(
1285
1260
  );
1286
1261
  return null;
1287
1262
  }
1288
- if (firstLine.length <= 50) return firstLine;
1289
- // Truncate at last word boundary within 50 chars.
1290
- // Only strip the trailing partial word if the slice actually cut mid-word;
1291
- // if the character right after the cut is whitespace, the slice is already clean.
1292
- const sliced = firstLine.slice(0, 50);
1293
- const wordTruncated = (
1294
- /\s/.test(firstLine[50]) ? sliced : sliced.replace(/\s+\S*$/, "")
1295
- ).trim();
1296
- if (wordTruncated.length < 15) {
1297
- log.debug(
1298
- { rawLength: firstLine.length, truncatedLength: wordTruncated.length },
1299
- "Suggestion rejected: too short after word-boundary truncation",
1300
- );
1301
- return null;
1302
- }
1303
- return wordTruncated;
1263
+ return firstLine;
1304
1264
  }
1305
1265
 
1306
1266
  export async function handleGetSuggestion(