@vellumai/assistant 0.5.5 → 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 (382) hide show
  1. package/.env.example +16 -2
  2. package/ARCHITECTURE.md +6 -75
  3. package/Dockerfile +4 -5
  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 +1 -2
  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 +3 -3
  26. package/src/__tests__/context-window-manager.test.ts +78 -0
  27. package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
  28. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  29. package/src/__tests__/conversation-skill-tools.test.ts +0 -54
  30. package/src/__tests__/conversation-title-service.test.ts +117 -1
  31. package/src/__tests__/credential-execution-feature-gates.test.ts +28 -14
  32. package/src/__tests__/credential-execution-managed-contract.test.ts +33 -18
  33. package/src/__tests__/credential-security-e2e.test.ts +0 -66
  34. package/src/__tests__/credential-security-invariants.test.ts +4 -45
  35. package/src/__tests__/credentials-cli.test.ts +78 -0
  36. package/src/__tests__/db-migration-rollback.test.ts +2015 -1
  37. package/src/__tests__/docker-signing-key-bootstrap.test.ts +98 -0
  38. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
  39. package/src/__tests__/guardian-routing-state.test.ts +0 -5
  40. package/src/__tests__/host-shell-tool.test.ts +6 -7
  41. package/src/__tests__/http-user-message-parity.test.ts +3 -103
  42. package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
  43. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
  44. package/src/__tests__/intent-routing.test.ts +0 -13
  45. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
  46. package/src/__tests__/keychain-broker-client.test.ts +161 -22
  47. package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
  48. package/src/__tests__/memory-regressions.test.ts +8 -30
  49. package/src/__tests__/migration-export-http.test.ts +2 -2
  50. package/src/__tests__/migration-import-commit-http.test.ts +2 -2
  51. package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
  52. package/src/__tests__/migration-validate-http.test.ts +2 -2
  53. package/src/__tests__/non-member-access-request.test.ts +0 -5
  54. package/src/__tests__/notification-decision-fallback.test.ts +4 -0
  55. package/src/__tests__/notification-decision-identity.test.ts +4 -0
  56. package/src/__tests__/permission-types.test.ts +1 -0
  57. package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
  58. package/src/__tests__/qdrant-manager.test.ts +28 -2
  59. package/src/__tests__/registry.test.ts +0 -6
  60. package/src/__tests__/require-fresh-approval.test.ts +4 -0
  61. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
  62. package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
  63. package/src/__tests__/secure-keys.test.ts +83 -263
  64. package/src/__tests__/shell-identity.test.ts +96 -6
  65. package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
  66. package/src/__tests__/skill-feature-flags.test.ts +46 -45
  67. package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
  68. package/src/__tests__/skill-load-inline-command.test.ts +8 -12
  69. package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
  70. package/src/__tests__/skill-load-tool.test.ts +0 -2
  71. package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
  72. package/src/__tests__/skills.test.ts +0 -2
  73. package/src/__tests__/slack-inbound-verification.test.ts +0 -4
  74. package/src/__tests__/suggestion-routes.test.ts +1 -32
  75. package/src/__tests__/system-prompt.test.ts +0 -1
  76. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -0
  77. package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
  78. package/src/__tests__/tool-executor.test.ts +4 -0
  79. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
  80. package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
  81. package/src/__tests__/update-bulletin.test.ts +0 -2
  82. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
  83. package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -6
  84. package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
  85. package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +218 -0
  86. package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
  87. package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
  88. package/src/calls/audio-store.test.ts +97 -0
  89. package/src/calls/audio-store.ts +205 -0
  90. package/src/calls/call-controller.ts +85 -7
  91. package/src/calls/call-domain.ts +3 -0
  92. package/src/calls/call-store.ts +10 -3
  93. package/src/calls/fish-audio-client.ts +117 -0
  94. package/src/calls/relay-server.ts +27 -0
  95. package/src/calls/twilio-routes.ts +2 -1
  96. package/src/calls/types.ts +1 -0
  97. package/src/calls/voice-ingress-preflight.ts +0 -42
  98. package/src/calls/voice-quality.ts +26 -5
  99. package/src/calls/voice-session-bridge.ts +6 -12
  100. package/src/cli/commands/config.ts +1 -4
  101. package/src/cli/commands/conversations.ts +0 -18
  102. package/src/cli/commands/credentials.ts +34 -4
  103. package/src/cli/commands/oauth/index.ts +7 -0
  104. package/src/cli/commands/oauth/platform.ts +179 -0
  105. package/src/cli/commands/platform.ts +3 -3
  106. package/src/config/assistant-feature-flags.ts +186 -5
  107. package/src/config/bundled-skills/messaging/SKILL.md +5 -5
  108. package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
  109. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  110. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
  111. package/src/config/bundled-tool-registry.ts +1 -11
  112. package/src/config/env-registry.ts +1 -1
  113. package/src/config/env.ts +16 -16
  114. package/src/config/feature-flag-registry.json +48 -16
  115. package/src/config/loader.ts +98 -31
  116. package/src/config/schema.ts +4 -25
  117. package/src/config/schemas/calls.ts +13 -0
  118. package/src/config/schemas/fish-audio.ts +39 -0
  119. package/src/config/schemas/memory.ts +0 -4
  120. package/src/config/schemas/platform.ts +1 -1
  121. package/src/config/schemas/security.ts +4 -4
  122. package/src/config/types.ts +0 -1
  123. package/src/contacts/contact-store.ts +39 -0
  124. package/src/contacts/types.ts +2 -0
  125. package/src/context/window-manager.ts +53 -2
  126. package/src/credential-execution/approval-bridge.ts +1 -0
  127. package/src/credential-execution/executable-discovery.ts +28 -4
  128. package/src/credential-execution/feature-gates.ts +16 -0
  129. package/src/credential-execution/process-manager.ts +38 -0
  130. package/src/daemon/assistant-attachments.ts +9 -0
  131. package/src/daemon/config-watcher.ts +6 -4
  132. package/src/daemon/conversation-agent-loop.ts +0 -60
  133. package/src/daemon/conversation-memory.ts +0 -117
  134. package/src/daemon/conversation-runtime-assembly.ts +0 -2
  135. package/src/daemon/conversation-tool-setup.ts +0 -105
  136. package/src/daemon/conversation.ts +10 -1
  137. package/src/daemon/handlers/config-vercel.ts +92 -0
  138. package/src/daemon/handlers/conversations.ts +0 -11
  139. package/src/daemon/handlers/skills.ts +2 -15
  140. package/src/daemon/install-symlink.ts +195 -0
  141. package/src/daemon/lifecycle.ts +229 -96
  142. package/src/daemon/message-types/conversations.ts +3 -4
  143. package/src/daemon/message-types/diagnostics.ts +3 -22
  144. package/src/daemon/message-types/messages.ts +0 -2
  145. package/src/daemon/message-types/upgrades.ts +8 -0
  146. package/src/daemon/server.ts +30 -92
  147. package/src/events/domain-events.ts +2 -1
  148. package/src/followups/followup-store.ts +5 -2
  149. package/src/inbound/platform-callback-registration.ts +3 -3
  150. package/src/instrument.ts +8 -5
  151. package/src/memory/conversation-crud.ts +0 -236
  152. package/src/memory/conversation-title-service.ts +76 -11
  153. package/src/memory/db-init.ts +15 -11
  154. package/src/memory/indexer.ts +15 -106
  155. package/src/memory/items-extractor.ts +15 -1
  156. package/src/memory/job-handlers/conversation-starters.ts +4 -1
  157. package/src/memory/job-handlers/embedding.ts +0 -79
  158. package/src/memory/job-utils.ts +1 -1
  159. package/src/memory/jobs-store.ts +30 -13
  160. package/src/memory/jobs-worker.ts +31 -27
  161. package/src/memory/migrations/001-job-deferrals.ts +19 -0
  162. package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
  163. package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
  164. package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
  165. package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
  166. package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
  167. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
  168. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
  169. package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
  170. package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
  171. package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
  172. package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
  173. package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
  174. package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
  175. package/src/memory/migrations/116-messages-fts.ts +106 -1
  176. package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
  177. package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
  178. package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
  179. package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
  180. package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
  181. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
  182. package/src/memory/migrations/141-rename-verification-table.ts +54 -0
  183. package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
  184. package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
  185. package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
  186. package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
  187. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
  188. package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
  189. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
  190. package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
  191. package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
  192. package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
  193. package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
  194. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
  195. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
  196. package/src/memory/migrations/189-drop-simplified-memory.ts +42 -0
  197. package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
  198. package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
  199. package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
  200. package/src/memory/migrations/index.ts +5 -3
  201. package/src/memory/migrations/registry.ts +90 -0
  202. package/src/memory/migrations/validate-migration-state.ts +137 -11
  203. package/src/memory/qdrant-circuit-breaker.ts +9 -0
  204. package/src/memory/qdrant-client.ts +4 -6
  205. package/src/memory/qdrant-manager.ts +64 -7
  206. package/src/memory/schema/calls.ts +1 -0
  207. package/src/memory/schema/contacts.ts +1 -0
  208. package/src/memory/schema/conversations.ts +0 -3
  209. package/src/memory/schema/index.ts +0 -2
  210. package/src/messaging/draft-store.ts +2 -2
  211. package/src/notifications/decision-engine.ts +4 -1
  212. package/src/oauth/connection-resolver.ts +6 -4
  213. package/src/permissions/checker.ts +0 -38
  214. package/src/permissions/defaults.ts +3 -3
  215. package/src/permissions/shell-identity.ts +76 -22
  216. package/src/permissions/trust-client.ts +2 -13
  217. package/src/permissions/trust-store.ts +8 -3
  218. package/src/permissions/types.ts +4 -2
  219. package/src/platform/client.ts +35 -7
  220. package/src/prompts/persona-resolver.ts +138 -0
  221. package/src/prompts/system-prompt.ts +36 -4
  222. package/src/prompts/templates/users/default.md +1 -0
  223. package/src/providers/registry.ts +27 -40
  224. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
  225. package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
  226. package/src/runtime/auth/external-assistant-id.ts +13 -59
  227. package/src/runtime/auth/route-policy.ts +29 -1
  228. package/src/runtime/auth/token-service.ts +53 -15
  229. package/src/runtime/channel-readiness-service.ts +1 -16
  230. package/src/runtime/http-server.ts +29 -2
  231. package/src/runtime/middleware/error-handler.ts +1 -9
  232. package/src/runtime/routes/audio-routes.ts +40 -0
  233. package/src/runtime/routes/btw-routes.ts +0 -17
  234. package/src/runtime/routes/conversation-management-routes.ts +0 -36
  235. package/src/runtime/routes/conversation-query-routes.ts +106 -2
  236. package/src/runtime/routes/conversation-routes.ts +4 -43
  237. package/src/runtime/routes/diagnostics-routes.ts +1 -477
  238. package/src/runtime/routes/identity-routes.ts +18 -29
  239. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
  240. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
  241. package/src/runtime/routes/integrations/vercel.ts +89 -0
  242. package/src/runtime/routes/log-export-routes.ts +5 -0
  243. package/src/runtime/routes/memory-item-routes.test.ts +221 -3
  244. package/src/runtime/routes/memory-item-routes.ts +144 -4
  245. package/src/runtime/routes/migration-rollback-routes.ts +209 -0
  246. package/src/runtime/routes/migration-routes.ts +17 -1
  247. package/src/runtime/routes/notification-routes.ts +58 -0
  248. package/src/runtime/routes/schedule-routes.ts +65 -0
  249. package/src/runtime/routes/settings-routes.ts +41 -1
  250. package/src/runtime/routes/tts-routes.ts +86 -0
  251. package/src/runtime/routes/upgrade-broadcast-routes.ts +175 -0
  252. package/src/runtime/routes/workspace-commit-routes.ts +62 -0
  253. package/src/runtime/routes/workspace-routes.test.ts +22 -1
  254. package/src/runtime/routes/workspace-routes.ts +1 -1
  255. package/src/runtime/routes/workspace-utils.ts +86 -2
  256. package/src/schedule/schedule-store.ts +0 -21
  257. package/src/security/ces-credential-client.ts +59 -22
  258. package/src/security/ces-rpc-credential-backend.ts +85 -0
  259. package/src/security/credential-backend.ts +12 -88
  260. package/src/security/keychain-broker-client.ts +10 -2
  261. package/src/security/secure-keys.ts +94 -113
  262. package/src/skills/catalog-install.ts +13 -7
  263. package/src/skills/inline-command-render.ts +5 -1
  264. package/src/skills/inline-command-runner.ts +30 -2
  265. package/src/telemetry/usage-telemetry-reporter.ts +4 -2
  266. package/src/tools/calls/call-start.ts +1 -0
  267. package/src/tools/executor.ts +0 -4
  268. package/src/tools/memory/handlers.ts +1 -129
  269. package/src/tools/network/script-proxy/session-manager.ts +19 -4
  270. package/src/tools/network/web-fetch.ts +3 -1
  271. package/src/tools/permission-checker.ts +18 -0
  272. package/src/tools/skills/execute.ts +1 -1
  273. package/src/tools/skills/load.ts +9 -2
  274. package/src/tools/types.ts +0 -8
  275. package/src/util/errors.ts +0 -12
  276. package/src/util/platform.ts +8 -55
  277. package/src/util/xml.ts +8 -0
  278. package/src/workspace/git-service.ts +5 -2
  279. package/src/workspace/heartbeat-service.ts +5 -24
  280. package/src/workspace/migrations/001-avatar-rename.ts +15 -0
  281. package/src/workspace/migrations/003-seed-device-id.ts +17 -1
  282. package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
  283. package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
  284. package/src/workspace/migrations/006-services-config.ts +49 -0
  285. package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
  286. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
  287. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
  288. package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
  289. package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
  290. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
  291. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
  292. package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
  293. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
  294. package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
  295. package/src/workspace/migrations/017-seed-persona-dirs.ts +95 -0
  296. package/src/workspace/migrations/migrate-to-workspace-volume.ts +23 -1
  297. package/src/workspace/migrations/registry.ts +8 -0
  298. package/src/workspace/migrations/runner.ts +106 -2
  299. package/src/workspace/migrations/types.ts +4 -0
  300. package/src/__tests__/archive-recall.test.ts +0 -560
  301. package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
  302. package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
  303. package/src/__tests__/conversation-memory-dirty-tail.test.ts +0 -150
  304. package/src/__tests__/conversation-switch-memory-reduction.test.ts +0 -474
  305. package/src/__tests__/db-memory-archive-migration.test.ts +0 -372
  306. package/src/__tests__/db-memory-brief-state-migration.test.ts +0 -213
  307. package/src/__tests__/db-memory-reducer-checkpoints.test.ts +0 -273
  308. package/src/__tests__/diagnostics-export.test.ts +0 -288
  309. package/src/__tests__/local-gateway-health.test.ts +0 -209
  310. package/src/__tests__/memory-brief-open-loops.test.ts +0 -530
  311. package/src/__tests__/memory-brief-time.test.ts +0 -285
  312. package/src/__tests__/memory-brief-wrapper.test.ts +0 -311
  313. package/src/__tests__/memory-chunk-archive.test.ts +0 -400
  314. package/src/__tests__/memory-chunk-dual-write.test.ts +0 -453
  315. package/src/__tests__/memory-episode-archive.test.ts +0 -370
  316. package/src/__tests__/memory-episode-dual-write.test.ts +0 -626
  317. package/src/__tests__/memory-observation-archive.test.ts +0 -375
  318. package/src/__tests__/memory-observation-dual-write.test.ts +0 -318
  319. package/src/__tests__/memory-reducer-job.test.ts +0 -538
  320. package/src/__tests__/memory-reducer-scheduling.test.ts +0 -473
  321. package/src/__tests__/memory-reducer-store.test.ts +0 -728
  322. package/src/__tests__/memory-reducer-types.test.ts +0 -707
  323. package/src/__tests__/memory-reducer.test.ts +0 -704
  324. package/src/__tests__/memory-simplified-config.test.ts +0 -281
  325. package/src/__tests__/secret-ingress-handler.test.ts +0 -120
  326. package/src/__tests__/simplified-memory-e2e.test.ts +0 -666
  327. package/src/__tests__/simplified-memory-runtime.test.ts +0 -616
  328. package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
  329. package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
  330. package/src/__tests__/swarm-orchestrator.test.ts +0 -463
  331. package/src/__tests__/swarm-plan-validator.test.ts +0 -384
  332. package/src/__tests__/swarm-recursion.test.ts +0 -197
  333. package/src/__tests__/swarm-router-planner.test.ts +0 -234
  334. package/src/__tests__/swarm-tool.test.ts +0 -185
  335. package/src/__tests__/swarm-worker-backend.test.ts +0 -144
  336. package/src/__tests__/swarm-worker-runner.test.ts +0 -288
  337. package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
  338. package/src/commands/cc-command-registry.ts +0 -248
  339. package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
  340. package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
  341. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
  342. package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
  343. package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
  344. package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
  345. package/src/config/schemas/memory-simplified.ts +0 -101
  346. package/src/config/schemas/swarm.ts +0 -82
  347. package/src/logfire.ts +0 -135
  348. package/src/memory/archive-recall.ts +0 -516
  349. package/src/memory/archive-store.ts +0 -400
  350. package/src/memory/brief-formatting.ts +0 -33
  351. package/src/memory/brief-open-loops.ts +0 -266
  352. package/src/memory/brief-time.ts +0 -162
  353. package/src/memory/brief.ts +0 -75
  354. package/src/memory/job-handlers/backfill-simplified-memory.ts +0 -462
  355. package/src/memory/job-handlers/reduce-conversation-memory.ts +0 -229
  356. package/src/memory/migrations/185-memory-brief-state.ts +0 -52
  357. package/src/memory/migrations/186-memory-archive.ts +0 -109
  358. package/src/memory/migrations/187-memory-reducer-checkpoints.ts +0 -19
  359. package/src/memory/reducer-scheduler.ts +0 -242
  360. package/src/memory/reducer-store.ts +0 -271
  361. package/src/memory/reducer-types.ts +0 -106
  362. package/src/memory/reducer.ts +0 -467
  363. package/src/memory/schema/memory-archive.ts +0 -121
  364. package/src/memory/schema/memory-brief.ts +0 -55
  365. package/src/runtime/local-gateway-health.ts +0 -275
  366. package/src/security/secret-ingress.ts +0 -68
  367. package/src/swarm/backend-claude-code.ts +0 -225
  368. package/src/swarm/checkpoint.ts +0 -137
  369. package/src/swarm/graph-utils.ts +0 -53
  370. package/src/swarm/index.ts +0 -55
  371. package/src/swarm/limits.ts +0 -66
  372. package/src/swarm/orchestrator.ts +0 -424
  373. package/src/swarm/plan-validator.ts +0 -117
  374. package/src/swarm/router-planner.ts +0 -162
  375. package/src/swarm/router-prompts.ts +0 -39
  376. package/src/swarm/synthesizer.ts +0 -81
  377. package/src/swarm/types.ts +0 -72
  378. package/src/swarm/worker-backend.ts +0 -131
  379. package/src/swarm/worker-prompts.ts +0 -80
  380. package/src/swarm/worker-runner.ts +0 -170
  381. package/src/tools/claude-code/claude-code.ts +0 -610
  382. package/src/tools/swarm/delegate.ts +0 -205
@@ -1,707 +0,0 @@
1
- import { describe, expect, mock, test } from "bun:test";
2
-
3
- // ---------------------------------------------------------------------------
4
- // Mocks — declared before imports that depend on logger
5
- // ---------------------------------------------------------------------------
6
-
7
- function makeLoggerStub(): Record<string, unknown> {
8
- const stub: Record<string, unknown> = {};
9
- for (const m of [
10
- "info",
11
- "warn",
12
- "error",
13
- "debug",
14
- "trace",
15
- "fatal",
16
- "silent",
17
- "child",
18
- ]) {
19
- stub[m] = m === "child" ? () => makeLoggerStub() : () => {};
20
- }
21
- return stub;
22
- }
23
-
24
- mock.module("../util/logger.js", () => ({
25
- getLogger: () => makeLoggerStub(),
26
- }));
27
-
28
- import { parseReducerOutput } from "../memory/reducer.js";
29
- import { EMPTY_REDUCER_RESULT } from "../memory/reducer-types.js";
30
-
31
- // ---------------------------------------------------------------------------
32
- // Helpers
33
- // ---------------------------------------------------------------------------
34
-
35
- /** Wrap a JS object through JSON.stringify so parseReducerOutput can consume it. */
36
- function toRaw(obj: unknown): string {
37
- return JSON.stringify(obj);
38
- }
39
-
40
- // ---------------------------------------------------------------------------
41
- // Tests: EMPTY_REDUCER_RESULT
42
- // ---------------------------------------------------------------------------
43
-
44
- describe("EMPTY_REDUCER_RESULT", () => {
45
- test("has all four arrays empty", () => {
46
- expect(EMPTY_REDUCER_RESULT.timeContexts).toEqual([]);
47
- expect(EMPTY_REDUCER_RESULT.openLoops).toEqual([]);
48
- expect(EMPTY_REDUCER_RESULT.archiveObservations).toEqual([]);
49
- expect(EMPTY_REDUCER_RESULT.archiveEpisodes).toEqual([]);
50
- });
51
-
52
- test("is frozen (immutable)", () => {
53
- expect(Object.isFrozen(EMPTY_REDUCER_RESULT)).toBe(true);
54
- });
55
- });
56
-
57
- // ---------------------------------------------------------------------------
58
- // Tests: parseReducerOutput — invalid inputs
59
- // ---------------------------------------------------------------------------
60
-
61
- describe("parseReducerOutput — invalid inputs", () => {
62
- test("returns empty result for non-JSON string", () => {
63
- expect(parseReducerOutput("not json at all")).toBe(EMPTY_REDUCER_RESULT);
64
- });
65
-
66
- test("returns empty result for empty string", () => {
67
- expect(parseReducerOutput("")).toBe(EMPTY_REDUCER_RESULT);
68
- });
69
-
70
- test("returns empty result for JSON array", () => {
71
- expect(parseReducerOutput("[]")).toBe(EMPTY_REDUCER_RESULT);
72
- });
73
-
74
- test("returns empty result for JSON null", () => {
75
- expect(parseReducerOutput("null")).toBe(EMPTY_REDUCER_RESULT);
76
- });
77
-
78
- test("returns empty result for JSON number", () => {
79
- expect(parseReducerOutput("42")).toBe(EMPTY_REDUCER_RESULT);
80
- });
81
-
82
- test("returns empty result for JSON string", () => {
83
- expect(parseReducerOutput('"hello"')).toBe(EMPTY_REDUCER_RESULT);
84
- });
85
-
86
- test("returns empty result for object with no recognized arrays", () => {
87
- expect(parseReducerOutput(toRaw({ foo: "bar" }))).toEqual({
88
- timeContexts: [],
89
- openLoops: [],
90
- archiveObservations: [],
91
- archiveEpisodes: [],
92
- });
93
- });
94
-
95
- test("returns empty result when all recognized keys are not arrays", () => {
96
- expect(
97
- parseReducerOutput(
98
- toRaw({
99
- timeContexts: "not an array",
100
- openLoops: 42,
101
- archiveObservations: null,
102
- archiveEpisodes: true,
103
- }),
104
- ),
105
- ).toEqual({
106
- timeContexts: [],
107
- openLoops: [],
108
- archiveObservations: [],
109
- archiveEpisodes: [],
110
- });
111
- });
112
- });
113
-
114
- // ---------------------------------------------------------------------------
115
- // Tests: parseReducerOutput — valid full output
116
- // ---------------------------------------------------------------------------
117
-
118
- describe("parseReducerOutput — valid full output", () => {
119
- test("parses a complete valid reducer output", () => {
120
- const raw: Record<string, unknown> = {
121
- timeContexts: [
122
- {
123
- action: "create",
124
- summary: "User traveling next week",
125
- source: "conversation",
126
- activeFrom: 1700000000000,
127
- activeUntil: 1700604800000,
128
- },
129
- {
130
- action: "update",
131
- id: "tc-1",
132
- summary: "Updated travel dates",
133
- },
134
- {
135
- action: "resolve",
136
- id: "tc-2",
137
- },
138
- ],
139
- openLoops: [
140
- {
141
- action: "create",
142
- summary: "Follow up with Bob",
143
- source: "conversation",
144
- dueAt: 1700172800000,
145
- },
146
- {
147
- action: "update",
148
- id: "ol-1",
149
- summary: "Bob replied — need to review",
150
- },
151
- {
152
- action: "resolve",
153
- id: "ol-2",
154
- status: "resolved",
155
- },
156
- ],
157
- archiveObservations: [
158
- {
159
- content: "User prefers dark mode",
160
- role: "user",
161
- modality: "text",
162
- source: "vellum",
163
- },
164
- ],
165
- archiveEpisodes: [
166
- {
167
- title: "Setup discussion",
168
- summary: "User configured their workspace preferences",
169
- source: "vellum",
170
- },
171
- ],
172
- };
173
-
174
- const result = parseReducerOutput(toRaw(raw));
175
-
176
- expect(result.timeContexts).toHaveLength(3);
177
- expect(result.timeContexts[0]).toEqual({
178
- action: "create",
179
- summary: "User traveling next week",
180
- source: "conversation",
181
- activeFrom: 1700000000000,
182
- activeUntil: 1700604800000,
183
- });
184
- expect(result.timeContexts[1]).toEqual({
185
- action: "update",
186
- id: "tc-1",
187
- summary: "Updated travel dates",
188
- });
189
- expect(result.timeContexts[2]).toEqual({
190
- action: "resolve",
191
- id: "tc-2",
192
- });
193
-
194
- expect(result.openLoops).toHaveLength(3);
195
- expect(result.openLoops[0]).toEqual({
196
- action: "create",
197
- summary: "Follow up with Bob",
198
- source: "conversation",
199
- dueAt: 1700172800000,
200
- });
201
- expect(result.openLoops[1]).toEqual({
202
- action: "update",
203
- id: "ol-1",
204
- summary: "Bob replied — need to review",
205
- });
206
- expect(result.openLoops[2]).toEqual({
207
- action: "resolve",
208
- id: "ol-2",
209
- status: "resolved",
210
- });
211
-
212
- expect(result.archiveObservations).toHaveLength(1);
213
- expect(result.archiveObservations[0]).toEqual({
214
- content: "User prefers dark mode",
215
- role: "user",
216
- modality: "text",
217
- source: "vellum",
218
- });
219
-
220
- expect(result.archiveEpisodes).toHaveLength(1);
221
- expect(result.archiveEpisodes[0]).toEqual({
222
- title: "Setup discussion",
223
- summary: "User configured their workspace preferences",
224
- source: "vellum",
225
- });
226
- });
227
- });
228
-
229
- // ---------------------------------------------------------------------------
230
- // Tests: parseReducerOutput — partial outputs
231
- // ---------------------------------------------------------------------------
232
-
233
- describe("parseReducerOutput — partial outputs", () => {
234
- test("accepts output with only timeContexts", () => {
235
- const result = parseReducerOutput(
236
- toRaw({
237
- timeContexts: [
238
- {
239
- action: "create",
240
- summary: "Deadline Friday",
241
- source: "conversation",
242
- activeFrom: 1700000000000,
243
- activeUntil: 1700604800000,
244
- },
245
- ],
246
- }),
247
- );
248
- expect(result.timeContexts).toHaveLength(1);
249
- expect(result.openLoops).toHaveLength(0);
250
- expect(result.archiveObservations).toHaveLength(0);
251
- expect(result.archiveEpisodes).toHaveLength(0);
252
- });
253
-
254
- test("accepts output with only openLoops", () => {
255
- const result = parseReducerOutput(
256
- toRaw({
257
- openLoops: [
258
- {
259
- action: "create",
260
- summary: "Need to reply to Alice",
261
- source: "conversation",
262
- },
263
- ],
264
- }),
265
- );
266
- expect(result.openLoops).toHaveLength(1);
267
- expect(result.timeContexts).toHaveLength(0);
268
- });
269
-
270
- test("accepts output with only archiveObservations", () => {
271
- const result = parseReducerOutput(
272
- toRaw({
273
- archiveObservations: [{ content: "User likes coffee", role: "user" }],
274
- }),
275
- );
276
- expect(result.archiveObservations).toHaveLength(1);
277
- expect(result.archiveObservations[0]).toEqual({
278
- content: "User likes coffee",
279
- role: "user",
280
- });
281
- });
282
-
283
- test("accepts output with only archiveEpisodes", () => {
284
- const result = parseReducerOutput(
285
- toRaw({
286
- archiveEpisodes: [{ title: "Onboarding", summary: "First session" }],
287
- }),
288
- );
289
- expect(result.archiveEpisodes).toHaveLength(1);
290
- expect(result.archiveEpisodes[0]).toEqual({
291
- title: "Onboarding",
292
- summary: "First session",
293
- });
294
- });
295
-
296
- test("accepts empty arrays for all keys", () => {
297
- const result = parseReducerOutput(
298
- toRaw({
299
- timeContexts: [],
300
- openLoops: [],
301
- archiveObservations: [],
302
- archiveEpisodes: [],
303
- }),
304
- );
305
- expect(result.timeContexts).toHaveLength(0);
306
- expect(result.openLoops).toHaveLength(0);
307
- expect(result.archiveObservations).toHaveLength(0);
308
- expect(result.archiveEpisodes).toHaveLength(0);
309
- // Should be a fresh object, not EMPTY_REDUCER_RESULT reference
310
- expect(result).not.toBe(EMPTY_REDUCER_RESULT);
311
- });
312
-
313
- test("drops invalid individual operations while keeping valid ones", () => {
314
- const result = parseReducerOutput(
315
- toRaw({
316
- timeContexts: [
317
- // valid create
318
- {
319
- action: "create",
320
- summary: "Valid",
321
- source: "conversation",
322
- activeFrom: 1000,
323
- activeUntil: 2000,
324
- },
325
- // invalid — missing summary
326
- {
327
- action: "create",
328
- source: "conversation",
329
- activeFrom: 1000,
330
- activeUntil: 2000,
331
- },
332
- // invalid — unknown action
333
- { action: "delete", id: "tc-1" },
334
- // valid resolve
335
- { action: "resolve", id: "tc-3" },
336
- ],
337
- openLoops: [
338
- // valid create
339
- {
340
- action: "create",
341
- summary: "Valid loop",
342
- source: "conversation",
343
- },
344
- // invalid resolve — missing status
345
- { action: "resolve", id: "ol-1" },
346
- // invalid resolve — invalid status
347
- { action: "resolve", id: "ol-2", status: "cancelled" },
348
- // null entry
349
- null,
350
- ],
351
- }),
352
- );
353
-
354
- expect(result.timeContexts).toHaveLength(2);
355
- expect(result.timeContexts[0].action).toBe("create");
356
- expect(result.timeContexts[1].action).toBe("resolve");
357
-
358
- expect(result.openLoops).toHaveLength(1);
359
- expect(result.openLoops[0].action).toBe("create");
360
- });
361
- });
362
-
363
- // ---------------------------------------------------------------------------
364
- // Tests: parseReducerOutput — time-context validation edge cases
365
- // ---------------------------------------------------------------------------
366
-
367
- describe("parseReducerOutput — time-context validation", () => {
368
- test("rejects create with empty summary", () => {
369
- const result = parseReducerOutput(
370
- toRaw({
371
- timeContexts: [
372
- {
373
- action: "create",
374
- summary: "",
375
- source: "conversation",
376
- activeFrom: 1000,
377
- activeUntil: 2000,
378
- },
379
- ],
380
- }),
381
- );
382
- expect(result.timeContexts).toHaveLength(0);
383
- });
384
-
385
- test("rejects create with non-string summary", () => {
386
- const result = parseReducerOutput(
387
- toRaw({
388
- timeContexts: [
389
- {
390
- action: "create",
391
- summary: 123,
392
- source: "conversation",
393
- activeFrom: 1000,
394
- activeUntil: 2000,
395
- },
396
- ],
397
- }),
398
- );
399
- expect(result.timeContexts).toHaveLength(0);
400
- });
401
-
402
- test("rejects create with negative activeUntil", () => {
403
- const result = parseReducerOutput(
404
- toRaw({
405
- timeContexts: [
406
- {
407
- action: "create",
408
- summary: "Test",
409
- source: "conversation",
410
- activeFrom: 1000,
411
- activeUntil: -1,
412
- },
413
- ],
414
- }),
415
- );
416
- expect(result.timeContexts).toHaveLength(0);
417
- });
418
-
419
- test("accepts create with activeFrom of 0 (epoch)", () => {
420
- const result = parseReducerOutput(
421
- toRaw({
422
- timeContexts: [
423
- {
424
- action: "create",
425
- summary: "From epoch",
426
- source: "conversation",
427
- activeFrom: 0,
428
- activeUntil: 1000,
429
- },
430
- ],
431
- }),
432
- );
433
- expect(result.timeContexts).toHaveLength(1);
434
- });
435
-
436
- test("rejects update with no updatable fields", () => {
437
- const result = parseReducerOutput(
438
- toRaw({
439
- timeContexts: [{ action: "update", id: "tc-1" }],
440
- }),
441
- );
442
- expect(result.timeContexts).toHaveLength(0);
443
- });
444
-
445
- test("accepts update with only summary", () => {
446
- const result = parseReducerOutput(
447
- toRaw({
448
- timeContexts: [
449
- { action: "update", id: "tc-1", summary: "New summary" },
450
- ],
451
- }),
452
- );
453
- expect(result.timeContexts).toHaveLength(1);
454
- const op = result.timeContexts[0];
455
- expect(op.action).toBe("update");
456
- if (op.action === "update") {
457
- expect(op.summary).toBe("New summary");
458
- expect(op.activeFrom).toBeUndefined();
459
- expect(op.activeUntil).toBeUndefined();
460
- }
461
- });
462
-
463
- test("rejects resolve with missing id", () => {
464
- const result = parseReducerOutput(
465
- toRaw({
466
- timeContexts: [{ action: "resolve" }],
467
- }),
468
- );
469
- expect(result.timeContexts).toHaveLength(0);
470
- });
471
- });
472
-
473
- // ---------------------------------------------------------------------------
474
- // Tests: parseReducerOutput — open-loop validation edge cases
475
- // ---------------------------------------------------------------------------
476
-
477
- describe("parseReducerOutput — open-loop validation", () => {
478
- test("accepts create without optional dueAt", () => {
479
- const result = parseReducerOutput(
480
- toRaw({
481
- openLoops: [
482
- {
483
- action: "create",
484
- summary: "No deadline",
485
- source: "conversation",
486
- },
487
- ],
488
- }),
489
- );
490
- expect(result.openLoops).toHaveLength(1);
491
- if (result.openLoops[0].action === "create") {
492
- expect(result.openLoops[0].dueAt).toBeUndefined();
493
- }
494
- });
495
-
496
- test("accepts create with dueAt", () => {
497
- const result = parseReducerOutput(
498
- toRaw({
499
- openLoops: [
500
- {
501
- action: "create",
502
- summary: "With deadline",
503
- source: "conversation",
504
- dueAt: 1700000000000,
505
- },
506
- ],
507
- }),
508
- );
509
- expect(result.openLoops).toHaveLength(1);
510
- if (result.openLoops[0].action === "create") {
511
- expect(result.openLoops[0].dueAt).toBe(1700000000000);
512
- }
513
- });
514
-
515
- test("rejects create with missing source", () => {
516
- const result = parseReducerOutput(
517
- toRaw({
518
- openLoops: [{ action: "create", summary: "Missing source" }],
519
- }),
520
- );
521
- expect(result.openLoops).toHaveLength(0);
522
- });
523
-
524
- test("rejects update with no updatable fields", () => {
525
- const result = parseReducerOutput(
526
- toRaw({
527
- openLoops: [{ action: "update", id: "ol-1" }],
528
- }),
529
- );
530
- expect(result.openLoops).toHaveLength(0);
531
- });
532
-
533
- test("accepts update with only dueAt", () => {
534
- const result = parseReducerOutput(
535
- toRaw({
536
- openLoops: [{ action: "update", id: "ol-1", dueAt: 1700000000000 }],
537
- }),
538
- );
539
- expect(result.openLoops).toHaveLength(1);
540
- });
541
-
542
- test("accepts resolve with status 'expired'", () => {
543
- const result = parseReducerOutput(
544
- toRaw({
545
- openLoops: [{ action: "resolve", id: "ol-1", status: "expired" }],
546
- }),
547
- );
548
- expect(result.openLoops).toHaveLength(1);
549
- if (result.openLoops[0].action === "resolve") {
550
- expect(result.openLoops[0].status).toBe("expired");
551
- }
552
- });
553
-
554
- test("rejects resolve with invalid status value", () => {
555
- const result = parseReducerOutput(
556
- toRaw({
557
- openLoops: [{ action: "resolve", id: "ol-1", status: "deleted" }],
558
- }),
559
- );
560
- expect(result.openLoops).toHaveLength(0);
561
- });
562
- });
563
-
564
- // ---------------------------------------------------------------------------
565
- // Tests: parseReducerOutput — archive observation validation
566
- // ---------------------------------------------------------------------------
567
-
568
- describe("parseReducerOutput — archive observation validation", () => {
569
- test("rejects observation with missing content", () => {
570
- const result = parseReducerOutput(
571
- toRaw({
572
- archiveObservations: [{ role: "user" }],
573
- }),
574
- );
575
- expect(result.archiveObservations).toHaveLength(0);
576
- });
577
-
578
- test("rejects observation with missing role", () => {
579
- const result = parseReducerOutput(
580
- toRaw({
581
- archiveObservations: [{ content: "Something" }],
582
- }),
583
- );
584
- expect(result.archiveObservations).toHaveLength(0);
585
- });
586
-
587
- test("includes optional modality and source when present", () => {
588
- const result = parseReducerOutput(
589
- toRaw({
590
- archiveObservations: [
591
- {
592
- content: "User likes tea",
593
- role: "user",
594
- modality: "voice",
595
- source: "phone",
596
- },
597
- ],
598
- }),
599
- );
600
- expect(result.archiveObservations).toHaveLength(1);
601
- expect(result.archiveObservations[0].modality).toBe("voice");
602
- expect(result.archiveObservations[0].source).toBe("phone");
603
- });
604
-
605
- test("omits modality and source when not valid strings", () => {
606
- const result = parseReducerOutput(
607
- toRaw({
608
- archiveObservations: [
609
- {
610
- content: "Fact",
611
- role: "user",
612
- modality: 123,
613
- source: false,
614
- },
615
- ],
616
- }),
617
- );
618
- expect(result.archiveObservations).toHaveLength(1);
619
- expect(result.archiveObservations[0].modality).toBeUndefined();
620
- expect(result.archiveObservations[0].source).toBeUndefined();
621
- });
622
- });
623
-
624
- // ---------------------------------------------------------------------------
625
- // Tests: parseReducerOutput — archive episode validation
626
- // ---------------------------------------------------------------------------
627
-
628
- describe("parseReducerOutput — archive episode validation", () => {
629
- test("rejects episode with missing title", () => {
630
- const result = parseReducerOutput(
631
- toRaw({
632
- archiveEpisodes: [{ summary: "Some summary" }],
633
- }),
634
- );
635
- expect(result.archiveEpisodes).toHaveLength(0);
636
- });
637
-
638
- test("rejects episode with missing summary", () => {
639
- const result = parseReducerOutput(
640
- toRaw({
641
- archiveEpisodes: [{ title: "Some title" }],
642
- }),
643
- );
644
- expect(result.archiveEpisodes).toHaveLength(0);
645
- });
646
-
647
- test("includes optional source when present", () => {
648
- const result = parseReducerOutput(
649
- toRaw({
650
- archiveEpisodes: [
651
- { title: "Chat", summary: "A chat happened", source: "telegram" },
652
- ],
653
- }),
654
- );
655
- expect(result.archiveEpisodes).toHaveLength(1);
656
- expect(result.archiveEpisodes[0].source).toBe("telegram");
657
- });
658
-
659
- test("omits source when not a valid string", () => {
660
- const result = parseReducerOutput(
661
- toRaw({
662
- archiveEpisodes: [
663
- { title: "Chat", summary: "A chat happened", source: 42 },
664
- ],
665
- }),
666
- );
667
- expect(result.archiveEpisodes).toHaveLength(1);
668
- expect(result.archiveEpisodes[0].source).toBeUndefined();
669
- });
670
- });
671
-
672
- // ---------------------------------------------------------------------------
673
- // Tests: parseReducerOutput — extra/unknown keys are tolerated
674
- // ---------------------------------------------------------------------------
675
-
676
- describe("parseReducerOutput — tolerates extra keys", () => {
677
- test("ignores unknown top-level keys", () => {
678
- const result = parseReducerOutput(
679
- toRaw({
680
- timeContexts: [],
681
- unknownKey: "whatever",
682
- anotherOne: [1, 2, 3],
683
- }),
684
- );
685
- expect(result).not.toBe(EMPTY_REDUCER_RESULT);
686
- expect(result.timeContexts).toHaveLength(0);
687
- });
688
-
689
- test("ignores extra fields on individual operations", () => {
690
- const result = parseReducerOutput(
691
- toRaw({
692
- openLoops: [
693
- {
694
- action: "create",
695
- summary: "Valid",
696
- source: "conversation",
697
- extraField: true,
698
- nested: { deep: 1 },
699
- },
700
- ],
701
- }),
702
- );
703
- expect(result.openLoops).toHaveLength(1);
704
- // Extra fields should NOT be present on the validated result
705
- expect((result.openLoops[0] as any).extraField).toBeUndefined();
706
- });
707
- });