@vellumai/assistant 0.3.4 → 0.3.6

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 (506) hide show
  1. package/Dockerfile +2 -0
  2. package/README.md +88 -2
  3. package/eslint.config.mjs +31 -0
  4. package/package.json +1 -1
  5. package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
  6. package/scripts/ipc/generate-swift.ts +31 -2
  7. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +438 -1
  8. package/src/__tests__/approval-conversation-turn.test.ts +214 -0
  9. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +41 -0
  10. package/src/__tests__/approval-message-composer.test.ts +253 -0
  11. package/src/__tests__/browser-manager.test.ts +1 -0
  12. package/src/__tests__/call-conversation-messages.test.ts +130 -0
  13. package/src/__tests__/call-domain.test.ts +12 -2
  14. package/src/__tests__/call-orchestrator.test.ts +799 -249
  15. package/src/__tests__/call-pointer-messages.test.ts +148 -0
  16. package/src/__tests__/call-recovery.test.ts +3 -0
  17. package/src/__tests__/call-routes-http.test.ts +32 -2
  18. package/src/__tests__/call-store.test.ts +3 -0
  19. package/src/__tests__/channel-approval-routes.test.ts +1277 -98
  20. package/src/__tests__/channel-approval.test.ts +37 -0
  21. package/src/__tests__/channel-approvals.test.ts +36 -50
  22. package/src/__tests__/channel-guardian.test.ts +630 -22
  23. package/src/__tests__/channel-readiness-service.test.ts +324 -0
  24. package/src/__tests__/checker.test.ts +14 -7
  25. package/src/__tests__/clarification-resolver.test.ts +44 -24
  26. package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
  27. package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
  28. package/src/__tests__/config-schema.test.ts +14 -8
  29. package/src/__tests__/context-window-manager.test.ts +30 -2
  30. package/src/__tests__/contradiction-checker.test.ts +20 -5
  31. package/src/__tests__/credential-security-invariants.test.ts +7 -2
  32. package/src/__tests__/daemon-lifecycle.test.ts +13 -12
  33. package/src/__tests__/db-migration-rollback.test.ts +752 -0
  34. package/src/__tests__/dictation-mode-detection.test.ts +63 -0
  35. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
  36. package/src/__tests__/entity-search.test.ts +615 -0
  37. package/src/__tests__/fuzzy-match-property.test.ts +5 -5
  38. package/src/__tests__/guardian-action-store.test.ts +123 -0
  39. package/src/__tests__/guardian-action-sweep.test.ts +277 -0
  40. package/src/__tests__/guardian-dispatch.test.ts +389 -0
  41. package/src/__tests__/guardian-question-copy.test.ts +47 -0
  42. package/src/__tests__/handlers-telegram-config.test.ts +4 -2
  43. package/src/__tests__/handlers-twilio-config.test.ts +533 -0
  44. package/src/__tests__/intent-routing.test.ts +2 -0
  45. package/src/__tests__/ipc-snapshot.test.ts +291 -1
  46. package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
  47. package/src/__tests__/messaging-send-tool.test.ts +65 -0
  48. package/src/__tests__/model-intents.test.ts +96 -0
  49. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
  50. package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
  51. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
  52. package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
  53. package/src/__tests__/provider-error-scenarios.test.ts +621 -0
  54. package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
  55. package/src/__tests__/qdrant-manager.test.ts +27 -20
  56. package/src/__tests__/relay-server.test.ts +779 -40
  57. package/src/__tests__/run-orchestrator-assistant-events.test.ts +6 -0
  58. package/src/__tests__/run-orchestrator.test.ts +42 -4
  59. package/src/__tests__/runtime-runs-http.test.ts +17 -1
  60. package/src/__tests__/runtime-runs.test.ts +16 -0
  61. package/src/__tests__/schedule-store.test.ts +18 -4
  62. package/src/__tests__/scheduler-recurrence.test.ts +13 -4
  63. package/src/__tests__/session-abort-tool-results.test.ts +6 -0
  64. package/src/__tests__/session-agent-loop.test.ts +857 -0
  65. package/src/__tests__/session-conflict-gate.test.ts +6 -0
  66. package/src/__tests__/session-pre-run-repair.test.ts +6 -0
  67. package/src/__tests__/session-profile-injection.test.ts +6 -0
  68. package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
  69. package/src/__tests__/session-queue.test.ts +6 -0
  70. package/src/__tests__/session-runtime-assembly.test.ts +321 -13
  71. package/src/__tests__/session-slash-known.test.ts +6 -0
  72. package/src/__tests__/session-slash-queue.test.ts +6 -0
  73. package/src/__tests__/session-slash-unknown.test.ts +6 -0
  74. package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
  75. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
  76. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
  77. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
  78. package/src/__tests__/session-workspace-injection.test.ts +6 -0
  79. package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
  80. package/src/__tests__/skills.test.ts +2 -0
  81. package/src/__tests__/sms-messaging-provider.test.ts +126 -0
  82. package/src/__tests__/starter-task-flow.test.ts +2 -0
  83. package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
  84. package/src/__tests__/system-prompt.test.ts +2 -0
  85. package/src/__tests__/task-management-tools.test.ts +2 -2
  86. package/src/__tests__/task-runner.test.ts +14 -4
  87. package/src/__tests__/terminal-tools.test.ts +25 -19
  88. package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
  89. package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
  90. package/src/__tests__/tool-executor.test.ts +23 -24
  91. package/src/__tests__/trust-store.test.ts +3 -3
  92. package/src/__tests__/twilio-rest.test.ts +29 -0
  93. package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
  94. package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
  95. package/src/__tests__/twilio-routes.test.ts +167 -11
  96. package/src/__tests__/twitter-cli-error-shaping.test.ts +2 -2
  97. package/src/__tests__/user-reference.test.ts +2 -0
  98. package/src/__tests__/voice-quality.test.ts +222 -0
  99. package/src/__tests__/web-search.test.ts +46 -30
  100. package/src/__tests__/work-item-output.test.ts +110 -0
  101. package/src/agent/loop.ts +1 -1
  102. package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
  103. package/src/amazon/client.ts +1418 -0
  104. package/src/amazon/request-extractor.ts +135 -0
  105. package/src/amazon/session.ts +109 -0
  106. package/src/autonomy/autonomy-store.ts +5 -5
  107. package/src/browser-extension-relay/client.ts +124 -0
  108. package/src/browser-extension-relay/protocol.ts +63 -0
  109. package/src/browser-extension-relay/server.ts +177 -0
  110. package/src/bundler/app-bundler.ts +3 -3
  111. package/src/bundler/bundle-signer.ts +1 -1
  112. package/src/bundler/signature-verifier.ts +1 -1
  113. package/src/calls/call-conversation-messages.ts +33 -0
  114. package/src/calls/call-domain.ts +114 -10
  115. package/src/calls/call-orchestrator.ts +268 -59
  116. package/src/calls/call-pointer-messages.ts +53 -0
  117. package/src/calls/call-recovery.ts +3 -8
  118. package/src/calls/call-store.ts +69 -87
  119. package/src/calls/elevenlabs-config.ts +3 -2
  120. package/src/calls/guardian-action-sweep.ts +105 -0
  121. package/src/calls/guardian-dispatch.ts +203 -0
  122. package/src/calls/guardian-question-copy.ts +133 -0
  123. package/src/calls/relay-server.ts +466 -8
  124. package/src/calls/speaker-identification.ts +1 -1
  125. package/src/calls/twilio-config.ts +22 -14
  126. package/src/calls/twilio-provider.ts +6 -4
  127. package/src/calls/twilio-rest.ts +308 -7
  128. package/src/calls/twilio-routes.ts +65 -12
  129. package/src/calls/types.ts +3 -1
  130. package/src/channels/types.ts +25 -0
  131. package/src/cli/amazon.ts +815 -0
  132. package/src/cli/config-commands.ts +2 -2
  133. package/src/cli/core-commands.ts +4 -3
  134. package/src/cli/influencer.ts +244 -0
  135. package/src/cli/map.ts +89 -6
  136. package/src/cli.ts +1 -1
  137. package/src/config/agent-schema.ts +171 -0
  138. package/src/config/bundled-skills/amazon/SKILL.md +127 -0
  139. package/src/config/bundled-skills/amazon/icon.svg +13 -0
  140. package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
  141. package/src/config/bundled-skills/browser/SKILL.md +1 -0
  142. package/src/config/bundled-skills/browser/TOOLS.json +17 -0
  143. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
  144. package/src/config/bundled-skills/doordash/SKILL.md +51 -51
  145. package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
  146. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
  147. package/src/config/bundled-skills/influencer/SKILL.md +144 -0
  148. package/src/config/bundled-skills/knowledge-graph/SKILL.md +15 -0
  149. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +56 -0
  150. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +185 -0
  151. package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
  152. package/src/config/bundled-skills/media-processing/SKILL.md +176 -0
  153. package/src/config/bundled-skills/media-processing/TOOLS.json +230 -0
  154. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
  155. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
  156. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
  157. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
  158. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
  159. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
  160. package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
  161. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +259 -0
  162. package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
  163. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +136 -0
  164. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +59 -0
  165. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +195 -0
  166. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +197 -0
  167. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +143 -0
  168. package/src/config/bundled-skills/media-processing/tools/media-status.ts +75 -0
  169. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +65 -0
  170. package/src/config/bundled-skills/messaging/SKILL.md +33 -8
  171. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
  172. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
  173. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -1
  174. package/src/config/bundled-skills/phone-calls/SKILL.md +88 -23
  175. package/src/config/bundled-skills/twitter/SKILL.md +19 -3
  176. package/src/config/bundled-skills/twitter/icon.svg +14 -0
  177. package/src/config/bundled-tool-registry.ts +310 -0
  178. package/src/config/calls-schema.ts +181 -0
  179. package/src/config/core-schema.ts +309 -0
  180. package/src/config/defaults.ts +28 -3
  181. package/src/config/env-registry.ts +162 -0
  182. package/src/config/env.ts +175 -0
  183. package/src/config/loader.ts +6 -6
  184. package/src/config/memory-schema.ts +528 -0
  185. package/src/config/sandbox-schema.ts +55 -0
  186. package/src/config/schema.ts +158 -1133
  187. package/src/config/skill-state.ts +1 -1
  188. package/src/config/skills-schema.ts +32 -0
  189. package/src/config/skills.ts +35 -24
  190. package/src/config/system-prompt.ts +131 -56
  191. package/src/config/templates/IDENTITY.md +2 -2
  192. package/src/config/templates/SOUL.md +1 -1
  193. package/src/config/types.ts +1 -0
  194. package/src/config/user-reference.ts +4 -9
  195. package/src/config/vellum-skills/catalog.json +6 -7
  196. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
  197. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +4 -3
  198. package/src/config/vellum-skills/sms-setup/SKILL.md +216 -0
  199. package/src/config/vellum-skills/twilio-setup/SKILL.md +40 -8
  200. package/src/context/window-manager.ts +27 -7
  201. package/src/daemon/approval-generators.ts +186 -0
  202. package/src/daemon/approved-devices-store.ts +140 -0
  203. package/src/daemon/assistant-attachments.ts +1 -1
  204. package/src/daemon/classifier.ts +35 -32
  205. package/src/daemon/config-watcher.ts +1 -1
  206. package/src/daemon/daemon-control.ts +217 -0
  207. package/src/daemon/handlers/apps.ts +2 -3
  208. package/src/daemon/handlers/config-channels.ts +158 -0
  209. package/src/daemon/handlers/config-inbox.ts +540 -0
  210. package/src/daemon/handlers/config-ingress.ts +231 -0
  211. package/src/daemon/handlers/config-integrations.ts +258 -0
  212. package/src/daemon/handlers/config-model.ts +143 -0
  213. package/src/daemon/handlers/config-parental.ts +163 -0
  214. package/src/daemon/handlers/config-scheduling.ts +172 -0
  215. package/src/daemon/handlers/config-slack.ts +92 -0
  216. package/src/daemon/handlers/config-telegram.ts +301 -0
  217. package/src/daemon/handlers/config-tools.ts +177 -0
  218. package/src/daemon/handlers/config-trust.ts +104 -0
  219. package/src/daemon/handlers/config-twilio.ts +1080 -0
  220. package/src/daemon/handlers/config.ts +53 -1689
  221. package/src/daemon/handlers/diagnostics.ts +1 -1
  222. package/src/daemon/handlers/dictation.ts +180 -0
  223. package/src/daemon/handlers/documents.ts +18 -32
  224. package/src/daemon/handlers/identity.ts +14 -23
  225. package/src/daemon/handlers/index.ts +11 -0
  226. package/src/daemon/handlers/misc.ts +3 -5
  227. package/src/daemon/handlers/pairing.ts +98 -0
  228. package/src/daemon/handlers/sessions.ts +56 -5
  229. package/src/daemon/handlers/shared.ts +6 -1
  230. package/src/daemon/handlers/skills.ts +1 -1
  231. package/src/daemon/handlers/twitter-auth.ts +2 -0
  232. package/src/daemon/handlers/work-items.ts +17 -9
  233. package/src/daemon/handlers/workspace-files.ts +4 -3
  234. package/src/daemon/install-cli-launchers.ts +113 -0
  235. package/src/daemon/ipc-contract/apps.ts +356 -0
  236. package/src/daemon/ipc-contract/browser.ts +74 -0
  237. package/src/daemon/ipc-contract/computer-use.ts +151 -0
  238. package/src/daemon/ipc-contract/diagnostics.ts +56 -0
  239. package/src/daemon/ipc-contract/documents.ts +74 -0
  240. package/src/daemon/ipc-contract/inbox.ts +209 -0
  241. package/src/daemon/ipc-contract/integrations.ts +284 -0
  242. package/src/daemon/ipc-contract/memory.ts +48 -0
  243. package/src/daemon/ipc-contract/messages.ts +211 -0
  244. package/src/daemon/ipc-contract/pairing.ts +45 -0
  245. package/src/daemon/ipc-contract/parental-control.ts +95 -0
  246. package/src/daemon/ipc-contract/schedules.ts +97 -0
  247. package/src/daemon/ipc-contract/sessions.ts +315 -0
  248. package/src/daemon/ipc-contract/shared.ts +42 -0
  249. package/src/daemon/ipc-contract/skills.ts +120 -0
  250. package/src/daemon/ipc-contract/subagents.ts +58 -0
  251. package/src/daemon/ipc-contract/surfaces.ts +250 -0
  252. package/src/daemon/ipc-contract/trust.ts +60 -0
  253. package/src/daemon/ipc-contract/work-items.ts +225 -0
  254. package/src/daemon/ipc-contract/workspace.ts +113 -0
  255. package/src/daemon/ipc-contract-inventory.json +70 -0
  256. package/src/daemon/ipc-contract-inventory.ts +55 -29
  257. package/src/daemon/ipc-contract.ts +229 -2426
  258. package/src/daemon/ipc-protocol.ts +1 -1
  259. package/src/daemon/ipc-validate.ts +7 -0
  260. package/src/daemon/lifecycle.ts +97 -377
  261. package/src/daemon/pairing-store.ts +177 -0
  262. package/src/daemon/providers-setup.ts +43 -0
  263. package/src/daemon/ride-shotgun-handler.ts +68 -3
  264. package/src/daemon/server.ts +66 -46
  265. package/src/daemon/session-agent-loop-handlers.ts +421 -0
  266. package/src/daemon/session-agent-loop.ts +117 -275
  267. package/src/daemon/session-dynamic-profile.ts +1 -1
  268. package/src/daemon/session-history.ts +1 -1
  269. package/src/daemon/session-media-retry.ts +1 -1
  270. package/src/daemon/session-messaging.ts +37 -2
  271. package/src/daemon/session-notifiers.ts +5 -25
  272. package/src/daemon/session-process.ts +99 -59
  273. package/src/daemon/session-queue-manager.ts +96 -4
  274. package/src/daemon/session-runtime-assembly.ts +199 -10
  275. package/src/daemon/session-surfaces.ts +19 -4
  276. package/src/daemon/session-tool-setup.ts +30 -30
  277. package/src/daemon/session-workspace.ts +1 -1
  278. package/src/daemon/session.ts +35 -2
  279. package/src/daemon/shutdown-handlers.ts +122 -0
  280. package/src/daemon/trace-emitter.ts +1 -1
  281. package/src/daemon/watch-handler.ts +36 -33
  282. package/src/doordash/cart-queries.ts +787 -0
  283. package/src/doordash/client.ts +144 -127
  284. package/src/doordash/order-queries.ts +85 -0
  285. package/src/doordash/queries.ts +10 -1308
  286. package/src/doordash/search-queries.ts +203 -0
  287. package/src/doordash/session.ts +3 -2
  288. package/src/doordash/store-queries.ts +246 -0
  289. package/src/doordash/types.ts +367 -0
  290. package/src/email/providers/agentmail.ts +2 -1
  291. package/src/email/providers/index.ts +3 -2
  292. package/src/email/service.ts +3 -2
  293. package/src/errors.ts +43 -0
  294. package/src/home-base/prebuilt/seed.ts +1 -1
  295. package/src/hooks/cli.ts +6 -5
  296. package/src/hooks/config.ts +6 -8
  297. package/src/hooks/discovery.ts +6 -5
  298. package/src/hooks/manager.ts +4 -3
  299. package/src/hooks/runner.ts +2 -2
  300. package/src/hooks/templates.ts +5 -5
  301. package/src/inbound/public-ingress-urls.ts +6 -4
  302. package/src/index.ts +4 -2
  303. package/src/influencer/client.ts +1104 -0
  304. package/src/instrument.ts +4 -3
  305. package/src/logfire.ts +4 -3
  306. package/src/memory/admin.ts +25 -35
  307. package/src/memory/attachments-store.ts +4 -7
  308. package/src/memory/channel-delivery-store.ts +30 -1
  309. package/src/memory/channel-guardian-store.ts +202 -2
  310. package/src/memory/clarification-resolver.ts +37 -33
  311. package/src/memory/conflict-store.ts +67 -61
  312. package/src/memory/contradiction-checker.ts +141 -117
  313. package/src/memory/conversation-store.ts +335 -51
  314. package/src/memory/db-connection.ts +27 -4
  315. package/src/memory/db-init.ts +265 -4
  316. package/src/memory/db.ts +14 -1
  317. package/src/memory/embedding-backend.ts +27 -5
  318. package/src/memory/embedding-ollama.ts +2 -1
  319. package/src/memory/entity-extractor.ts +38 -35
  320. package/src/memory/guardian-action-store.ts +430 -0
  321. package/src/memory/inbox-escalation-projection.ts +59 -0
  322. package/src/memory/inbox-thread-store.ts +218 -0
  323. package/src/memory/ingress-invite-store.ts +338 -0
  324. package/src/memory/ingress-member-store.ts +350 -0
  325. package/src/memory/items-extractor.ts +91 -97
  326. package/src/memory/job-handlers/index-maintenance.ts +3 -3
  327. package/src/memory/job-handlers/media-processing.ts +69 -0
  328. package/src/memory/job-handlers/summarization.ts +32 -26
  329. package/src/memory/job-utils.ts +3 -10
  330. package/src/memory/jobs-store.ts +8 -10
  331. package/src/memory/jobs-worker.ts +55 -36
  332. package/src/memory/media-store.ts +759 -0
  333. package/src/memory/migrations/001-job-deferrals.ts +45 -0
  334. package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
  335. package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
  336. package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
  337. package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
  338. package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
  339. package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
  340. package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
  341. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
  342. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
  343. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
  344. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
  345. package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
  346. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
  347. package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
  348. package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
  349. package/src/memory/migrations/017-memory-items-indexes.ts +10 -0
  350. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
  351. package/src/memory/migrations/index.ts +24 -0
  352. package/src/memory/migrations/registry.ts +79 -0
  353. package/src/memory/migrations/validate-migration-state.ts +69 -0
  354. package/src/memory/qdrant-manager.ts +49 -8
  355. package/src/memory/query-builder.ts +1 -1
  356. package/src/memory/raw-query.ts +119 -0
  357. package/src/memory/recall-cache.ts +4 -1
  358. package/src/memory/retriever.ts +165 -47
  359. package/src/memory/schema-migration.ts +25 -984
  360. package/src/memory/schema.ts +228 -7
  361. package/src/memory/search/entity.ts +205 -31
  362. package/src/memory/search/lexical.ts +81 -52
  363. package/src/memory/search/ranking.ts +27 -23
  364. package/src/memory/search/semantic.ts +157 -19
  365. package/src/memory/search/types.ts +24 -0
  366. package/src/memory/shared-app-links-store.ts +4 -5
  367. package/src/memory/validation.ts +19 -0
  368. package/src/messaging/draft-store.ts +5 -6
  369. package/src/messaging/provider-types.ts +2 -0
  370. package/src/messaging/providers/sms/adapter.ts +201 -0
  371. package/src/messaging/providers/sms/client.ts +93 -0
  372. package/src/messaging/providers/sms/types.ts +7 -0
  373. package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
  374. package/src/messaging/providers/whatsapp/adapter.ts +136 -0
  375. package/src/messaging/providers/whatsapp/client.ts +67 -0
  376. package/src/messaging/style-analyzer.ts +5 -4
  377. package/src/messaging/thread-summarizer.ts +61 -69
  378. package/src/messaging/triage-engine.ts +62 -71
  379. package/src/migrations/config-merge.ts +53 -0
  380. package/src/migrations/data-layout.ts +68 -0
  381. package/src/migrations/data-merge.ts +33 -0
  382. package/src/migrations/hooks-merge.ts +90 -0
  383. package/src/migrations/index.ts +6 -0
  384. package/src/migrations/log.ts +23 -0
  385. package/src/migrations/skills-merge.ts +33 -0
  386. package/src/migrations/workspace-layout.ts +79 -0
  387. package/src/permissions/checker.ts +133 -11
  388. package/src/permissions/prompter.ts +14 -0
  389. package/src/permissions/shell-identity.ts +31 -1
  390. package/src/permissions/trust-store.ts +21 -1
  391. package/src/providers/anthropic/client.ts +4 -4
  392. package/src/providers/failover.ts +2 -2
  393. package/src/providers/model-intents.ts +70 -0
  394. package/src/providers/ollama/client.ts +2 -1
  395. package/src/providers/provider-send-message.ts +176 -0
  396. package/src/providers/registry.ts +71 -30
  397. package/src/providers/retry.ts +35 -1
  398. package/src/providers/types.ts +12 -1
  399. package/src/runtime/approval-conversation-turn.ts +97 -0
  400. package/src/runtime/approval-message-composer.ts +253 -0
  401. package/src/runtime/channel-approval-parser.ts +36 -2
  402. package/src/runtime/channel-approvals.ts +11 -24
  403. package/src/runtime/channel-guardian-service.ts +88 -21
  404. package/src/runtime/channel-readiness-service.ts +418 -0
  405. package/src/runtime/channel-readiness-types.ts +35 -0
  406. package/src/runtime/channel-retry-sweep.ts +184 -0
  407. package/src/runtime/guardian-context-resolver.ts +108 -0
  408. package/src/runtime/http-server.ts +275 -717
  409. package/src/runtime/http-types.ts +59 -3
  410. package/src/runtime/middleware/auth.ts +116 -0
  411. package/src/runtime/middleware/error-handler.ts +33 -0
  412. package/src/runtime/middleware/twilio-validation.ts +127 -0
  413. package/src/runtime/routes/app-routes.ts +1 -1
  414. package/src/runtime/routes/call-routes.ts +51 -7
  415. package/src/runtime/routes/channel-delivery-routes.ts +170 -0
  416. package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
  417. package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
  418. package/src/runtime/routes/channel-route-shared.ts +144 -0
  419. package/src/runtime/routes/channel-routes.ts +32 -1588
  420. package/src/runtime/routes/conversation-routes.ts +50 -7
  421. package/src/runtime/routes/events-routes.ts +2 -2
  422. package/src/runtime/routes/identity-routes.ts +126 -0
  423. package/src/runtime/routes/pairing-routes.ts +143 -0
  424. package/src/runtime/routes/run-routes.ts +15 -1
  425. package/src/runtime/run-orchestrator.ts +86 -35
  426. package/src/schedule/schedule-store.ts +36 -32
  427. package/src/schedule/scheduler.ts +3 -3
  428. package/src/security/encrypted-store.ts +5 -7
  429. package/src/security/oauth2.ts +45 -15
  430. package/src/security/parental-control-store.ts +183 -0
  431. package/src/security/secret-allowlist.ts +4 -3
  432. package/src/security/secret-scanner.ts +5 -5
  433. package/src/security/secure-keys.ts +1 -1
  434. package/src/security/token-manager.ts +3 -2
  435. package/src/services/vercel-deploy.ts +6 -2
  436. package/src/skills/tool-manifest.ts +3 -3
  437. package/src/skills/vellum-catalog-remote.ts +75 -16
  438. package/src/slack/slack-webhook.ts +2 -1
  439. package/src/swarm/orchestrator.ts +92 -1
  440. package/src/swarm/router-planner.ts +6 -9
  441. package/src/swarm/worker-prompts.ts +9 -12
  442. package/src/tasks/task-compiler.ts +19 -28
  443. package/src/tasks/task-runner.ts +1 -1
  444. package/src/tools/assets/materialize.ts +2 -2
  445. package/src/tools/assets/search.ts +15 -14
  446. package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
  447. package/src/tools/browser/auto-navigate.ts +1 -0
  448. package/src/tools/browser/browser-execution.ts +10 -1
  449. package/src/tools/browser/browser-manager.ts +119 -4
  450. package/src/tools/browser/network-recorder.ts +5 -0
  451. package/src/tools/calls/call-start.ts +1 -0
  452. package/src/tools/credentials/broker.ts +11 -2
  453. package/src/tools/credentials/metadata-store.ts +18 -14
  454. package/src/tools/credentials/post-connect-hooks.ts +61 -0
  455. package/src/tools/credentials/vault.ts +49 -23
  456. package/src/tools/execution-target.ts +11 -1
  457. package/src/tools/executor.ts +68 -9
  458. package/src/tools/host-terminal/cli-discover.ts +1 -1
  459. package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
  460. package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
  461. package/src/tools/network/script-proxy/server.ts +1 -1
  462. package/src/tools/network/script-proxy/session-manager.ts +6 -5
  463. package/src/tools/network/web-fetch.ts +18 -2
  464. package/src/tools/network/web-search.ts +8 -4
  465. package/src/tools/reminder/reminder-store.ts +14 -15
  466. package/src/tools/schedule/create.ts +1 -0
  467. package/src/tools/schedule/list.ts +2 -1
  468. package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
  469. package/src/tools/skills/skill-script-runner.ts +24 -9
  470. package/src/tools/skills/skill-tool-factory.ts +1 -0
  471. package/src/tools/tasks/work-item-enqueue.ts +2 -2
  472. package/src/tools/terminal/evaluate-typescript.ts +21 -12
  473. package/src/tools/terminal/parser.ts +50 -0
  474. package/src/tools/types.ts +2 -0
  475. package/src/tools/watcher/delete.ts +6 -0
  476. package/src/tools/weather/service.ts +1 -1
  477. package/src/twitter/client.ts +190 -24
  478. package/src/twitter/router.ts +1 -1
  479. package/src/twitter/session.ts +4 -3
  480. package/src/util/clipboard.ts +1 -1
  481. package/src/util/errors.ts +65 -8
  482. package/src/util/fs.ts +40 -0
  483. package/src/util/json.ts +10 -0
  484. package/src/util/log-redact.ts +189 -0
  485. package/src/util/logger.ts +19 -17
  486. package/src/util/object.ts +3 -0
  487. package/src/util/platform.ts +105 -363
  488. package/src/util/pricing.ts +1 -1
  489. package/src/util/promise-guard.ts +1 -1
  490. package/src/util/retry.ts +19 -0
  491. package/src/util/row-mapper.ts +79 -0
  492. package/src/util/silently.ts +21 -0
  493. package/src/watcher/engine.ts +5 -1
  494. package/src/watcher/provider-types.ts +20 -0
  495. package/src/watcher/providers/github.ts +156 -0
  496. package/src/watcher/providers/gmail.ts +1 -0
  497. package/src/watcher/providers/google-calendar.ts +1 -0
  498. package/src/watcher/providers/linear.ts +460 -0
  499. package/src/watcher/providers/slack.ts +1 -0
  500. package/src/work-items/work-item-runner.ts +1 -1
  501. package/src/workspace/git-service.ts +1 -1
  502. package/src/workspace/provider-commit-message-generator.ts +51 -22
  503. package/src/__tests__/call-bridge.test.ts +0 -517
  504. package/src/__tests__/session-process-bridge.test.ts +0 -244
  505. package/src/calls/call-bridge.ts +0 -168
  506. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
@@ -0,0 +1,176 @@
1
+ ---
2
+ name: "Media Processing"
3
+ description: "Ingest and process media files (video, audio, image) through a 3-phase pipeline: preprocess, map (Gemini), and reduce (Claude)"
4
+ metadata: {"vellum": {"emoji": "🎬"}}
5
+ ---
6
+
7
+ Ingest and track processing of media files (video, audio, images) through a configurable 3-phase pipeline.
8
+
9
+ ## End-to-End Workflow
10
+
11
+ The processing pipeline follows a sequential 3-phase flow:
12
+
13
+ 1. **Ingest** (`ingest_media`) — Register a media file, detect MIME type, extract duration, deduplicate by content hash.
14
+ 2. **Preprocess** (`extract_keyframes`) — Detect dead time, segment the video into windows, extract downscaled keyframes, build a subject registry, and write a pipeline manifest.
15
+ 3. **Map** (`analyze_keyframes`) — Send each segment's frames to Gemini 2.5 Flash with assistant-provided extraction instructions and a JSON Schema for guaranteed structured output. Supports concurrency pooling, cost tracking, resumability, and automatic retries.
16
+ 4. **Reduce / Query** (`query_media`) — Send all map output to Claude for intelligent analysis and Q&A. Supports arbitrary natural language queries about video content.
17
+ 5. **Clip** (`generate_clip`) — Extract video clips around specific moments.
18
+
19
+ The processing pipeline service (`services/processing-pipeline.ts`) orchestrates phases 2-4 automatically with retries, resumability, and cancellation support.
20
+
21
+ ## Tools
22
+
23
+ ### ingest_media
24
+
25
+ Register a media file for processing. Accepts an absolute file path, validates the file exists, detects MIME type, extracts duration (for video/audio via ffprobe), and registers the asset with content-hash deduplication.
26
+
27
+ ### media_status
28
+
29
+ Query the processing status of a media asset. Returns the asset metadata along with per-stage progress details. Use this to monitor pipeline progress.
30
+
31
+ ### extract_keyframes
32
+
33
+ Preprocess a video asset: detect dead time via mpdecimate, segment the video into windows, extract downscaled keyframes at regular intervals, build a subject registry, and write a pipeline manifest.
34
+
35
+ Parameters:
36
+ - `asset_id` (required) — ID of the media asset.
37
+ - `interval_seconds` — Interval between keyframes (default: 3s).
38
+ - `segment_duration` — Duration of each segment window (default: 20s).
39
+ - `dead_time_threshold` — Sensitivity for dead-time detection (default: 0.02).
40
+ - `section_config` — Path to a JSON file with manual section boundaries.
41
+ - `skip_dead_time` — Whether to detect and skip dead time (default: true).
42
+ - `short_edge` — Short edge resolution for downscaled frames in pixels (default: 480).
43
+
44
+ ### analyze_keyframes
45
+
46
+ Map video segments through Gemini's structured output API. Reads frames from the preprocess manifest, sends each segment to Gemini with assistant-provided extraction instructions and a JSON Schema for guaranteed structured output. Supports concurrency pooling, cost tracking, resumability (skips segments with existing results), and automatic retries with exponential backoff.
47
+
48
+ Parameters:
49
+ - `asset_id` (required) — ID of the media asset.
50
+ - `system_prompt` (required) — Extraction instructions for Gemini.
51
+ - `output_schema` (required) — JSON Schema for structured output.
52
+ - `context` — Additional context to include in the prompt.
53
+ - `model` — Gemini model to use (default: `gemini-2.5-flash`).
54
+ - `concurrency` — Maximum concurrent API requests (default: 10).
55
+ - `max_retries` — Retry attempts per segment on failure (default: 3).
56
+
57
+ ### query_media
58
+
59
+ Query video analysis data using natural language. Sends map output (from analyze_keyframes) to Claude for intelligent analysis and Q&A. Supports arbitrary questions about video content.
60
+
61
+ Parameters:
62
+ - `asset_id` (required) — ID of the media asset.
63
+ - `query` (required) — Natural language query about the video data.
64
+ - `system_prompt` — Optional system prompt for Claude.
65
+ - `model` — LLM model to use (default: `claude-sonnet-4-6`).
66
+
67
+ ### generate_clip
68
+
69
+ Extract a video clip from a media asset using ffmpeg. Applies configurable pre/post-roll padding (clamped to file boundaries), outputs the clip as a temporary file.
70
+
71
+ ### media_diagnostics
72
+
73
+ Get a diagnostic report for a media asset. Returns:
74
+ - **Processing stats**: total keyframes extracted.
75
+ - **Per-stage status and timing**: which stages (preprocess, map, reduce) have run, how long each took, current progress.
76
+ - **Failure reasons**: last error from any failed stage.
77
+ - **Cost estimation**: based on segment count and Gemini 2.5 Flash pricing, plus a note about Claude reduce costs.
78
+
79
+ ## Services
80
+
81
+ ### Processing Pipeline (services/processing-pipeline.ts)
82
+
83
+ Orchestrates the full processing pipeline with reliability features:
84
+ - **Sequential execution**: preprocess, map, reduce.
85
+ - **Retries**: Each stage is retried with exponential backoff and jitter (configurable max retries and base delay).
86
+ - **Resumability**: Checks processing_stages to find the last completed stage and resumes from there. Safe to restart after crashes.
87
+ - **Cancellation**: Cooperative cancellation via asset status. Set asset status to `cancelled` and the pipeline stops between stages.
88
+ - **Idempotency**: Re-ingesting the same file hash is a no-op. Re-running a fully completed pipeline is also a no-op.
89
+ - **Graceful degradation**: If a stage fails mid-batch (e.g., Gemini API errors), partial results are saved. The stage is marked as failed with the error details, and the pipeline stops without losing work.
90
+
91
+ ### Preprocess (services/preprocess.ts)
92
+
93
+ Handles dead-time detection, video segmentation, keyframe extraction, and subject registry building. Writes a pipeline manifest consumed by the Map phase.
94
+
95
+ ### Gemini Map (services/gemini-map.ts)
96
+
97
+ Sends video segments to Gemini 2.5 Flash with structured output schemas. Handles concurrency pooling, cost tracking, resumability, and retries.
98
+
99
+ ### Reduce (services/reduce.ts)
100
+
101
+ Sends Map output to Claude as text for analysis. Two modes:
102
+ - **One-shot merge**: assembles all Map results and sends to Claude with a system prompt.
103
+ - **Interactive Q&A**: loads existing map output + user query, sends to Claude.
104
+
105
+ ### Concurrency Pool (services/concurrency-pool.ts)
106
+
107
+ Limits concurrent API calls during the Map phase to avoid rate limiting.
108
+
109
+ ### Cost Tracker (services/cost-tracker.ts)
110
+
111
+ Tracks estimated API costs during pipeline execution.
112
+
113
+ ## Operator Runbook
114
+
115
+ ### Monitoring Progress
116
+
117
+ Use `media_status` to check the current state of any asset:
118
+ - **registered** — Ingested but not yet processed.
119
+ - **processing** — Pipeline is running.
120
+ - **indexed** — All stages completed successfully.
121
+ - **failed** — A stage failed. Check stage details for the error.
122
+
123
+ The response includes per-stage progress (0-100%) so you can see exactly where processing stands.
124
+
125
+ ### Diagnosing Failures
126
+
127
+ Use `media_diagnostics` to get a full diagnostic report:
128
+ 1. Check the `stages` array for any stage with `status: "failed"`.
129
+ 2. Read the `lastError` field for that stage to understand what went wrong.
130
+ 3. Check `durationMs` to see if a stage timed out or ran unusually long.
131
+ 4. Common failure causes:
132
+ - **preprocess**: ffmpeg not installed, corrupt video file, disk full.
133
+ - **map**: Gemini API key not configured, API rate limits, network errors.
134
+ - **reduce**: No LLM provider configured, no map output exists.
135
+
136
+ After fixing the root cause, re-run the failed stage. The pipeline is resumable — it picks up from where it left off.
137
+
138
+ ### Cost Expectations
139
+
140
+ The Map phase (Gemini 2.5 Flash) is the primary cost driver. Cost scales with video duration, keyframe interval, and segment size:
141
+
142
+ | Video Duration | Interval | Keyframes | Segments (~10 frames each) | Estimated Map Cost |
143
+ |----------------|----------|-----------|----------------------------|--------------------|
144
+ | 30 min | 3s | ~600 | ~60 | ~$0.06 |
145
+ | 60 min | 3s | ~1,200 | ~120 | ~$0.12 |
146
+ | 90 min | 3s | ~1,800 | ~180 | ~$0.18 |
147
+ | 90 min | 5s | ~1,080 | ~108 | ~$0.11 |
148
+
149
+ The Reduce phase (Claude) adds a small additional cost per query. The `media_diagnostics` tool provides per-asset cost estimates.
150
+
151
+ ### Known Limitations
152
+
153
+ - **ffmpeg required**: Keyframe extraction and clip generation require ffmpeg to be installed on the host.
154
+ - **Single-file ingestion**: Each `ingest_media` call processes one file. Batch ingestion is not yet supported.
155
+ - **Gemini rate limits**: The Map phase uses concurrency pooling (default 10) to stay within API limits. Reduce concurrency if you hit 429 errors.
156
+ - **No real-time processing**: The pipeline processes pre-recorded media files. Live/streaming video is not supported.
157
+
158
+ ### Troubleshooting
159
+
160
+ | Symptom | Likely Cause | Fix |
161
+ |---------|-------------|-----|
162
+ | "No keyframes found" | extract_keyframes not run or failed | Check preprocess stage status; re-run if needed |
163
+ | "No map output found" | analyze_keyframes not run | Run analyze_keyframes with appropriate system_prompt and output_schema |
164
+ | "No LLM provider available" | API key not configured | Add one in Settings |
165
+ | Map phase slow | Large video, small interval | Increase interval_seconds or reduce concurrency |
166
+ | Gemini returns errors | Rate limits or schema issues | Check max_retries setting; simplify output_schema if needed |
167
+ | Pipeline stuck at "processing" | Stage crashed without updating status | Use `media_diagnostics` to find the stuck stage; re-run manually |
168
+
169
+ ## Usage Notes
170
+
171
+ - The `ingest_media` tool requires an absolute path to a local file.
172
+ - Supported media types: video (mp4, mov, avi, mkv, webm, etc.), audio (mp3, wav, m4a, etc.), and images (png, jpg, gif, webp, etc.).
173
+ - For video and audio files, duration is automatically extracted via ffprobe (requires ffmpeg to be installed).
174
+ - Duplicate files are detected by content hash and return the existing asset record.
175
+ - The `analyze_keyframes` tool is marked as medium risk because it makes external API calls to Gemini, which incur costs.
176
+ - All schema tables, services, and tool interfaces are media-generic. Domain-specific interpretation belongs in the system_prompt and output_schema parameters.
@@ -0,0 +1,230 @@
1
+ {
2
+ "version": 1,
3
+ "tools": [
4
+ {
5
+ "name": "ingest_media",
6
+ "description": "Ingest a media file (video, audio, or image) for processing. Validates the file, detects MIME type, extracts duration for video/audio, registers the asset with content-hash dedup, and enqueues an initial processing job.",
7
+ "category": "media",
8
+ "risk": "low",
9
+ "input_schema": {
10
+ "type": "object",
11
+ "properties": {
12
+ "file_path": {
13
+ "type": "string",
14
+ "description": "Absolute path to a local media file (video, audio, or image)"
15
+ },
16
+ "title": {
17
+ "type": "string",
18
+ "description": "Optional human-readable title for the media asset. Defaults to the filename."
19
+ },
20
+ "metadata": {
21
+ "type": "object",
22
+ "description": "Optional JSON metadata to attach to the asset (e.g., pipeline config, source info)"
23
+ }
24
+ },
25
+ "required": ["file_path"]
26
+ },
27
+ "executor": "tools/ingest-media.ts",
28
+ "execution_target": "host"
29
+ },
30
+ {
31
+ "name": "media_status",
32
+ "description": "Query the processing status of one or more media assets, including per-stage progress details.",
33
+ "category": "media",
34
+ "risk": "low",
35
+ "input_schema": {
36
+ "type": "object",
37
+ "properties": {
38
+ "asset_id": {
39
+ "type": "string",
40
+ "description": "ID of a specific media asset to query"
41
+ },
42
+ "file_path": {
43
+ "type": "string",
44
+ "description": "File path to look up a media asset by its original path"
45
+ },
46
+ "status_filter": {
47
+ "type": "string",
48
+ "enum": ["registered", "processing", "indexed", "failed"],
49
+ "description": "Filter assets by processing status"
50
+ }
51
+ }
52
+ },
53
+ "executor": "tools/media-status.ts",
54
+ "execution_target": "host"
55
+ },
56
+ {
57
+ "name": "extract_keyframes",
58
+ "description": "Preprocess a video asset: detect dead time, segment into windows, extract downscaled keyframes, build a subject registry, and write a pipeline manifest. Replaces the old simple keyframe extraction with a full Phase 0 preprocess pipeline.",
59
+ "category": "media",
60
+ "risk": "low",
61
+ "input_schema": {
62
+ "type": "object",
63
+ "properties": {
64
+ "asset_id": {
65
+ "type": "string",
66
+ "description": "ID of the media asset (must be a video)"
67
+ },
68
+ "interval_seconds": {
69
+ "type": "number",
70
+ "description": "Interval between keyframes in seconds. Default: 3"
71
+ },
72
+ "segment_duration": {
73
+ "type": "number",
74
+ "description": "Duration of each segment window in seconds. Default: 20"
75
+ },
76
+ "dead_time_threshold": {
77
+ "type": "number",
78
+ "description": "Sensitivity threshold for mpdecimate dead-time detection. Default: 0.02"
79
+ },
80
+ "section_config": {
81
+ "type": "string",
82
+ "description": "Path to a JSON file with manual section boundary definitions"
83
+ },
84
+ "skip_dead_time": {
85
+ "type": "boolean",
86
+ "description": "Whether to detect and skip dead time. Default: true"
87
+ },
88
+ "short_edge": {
89
+ "type": "number",
90
+ "description": "Short edge resolution for downscaled frames in pixels. Default: 480"
91
+ }
92
+ },
93
+ "required": ["asset_id"]
94
+ },
95
+ "executor": "tools/extract-keyframes.ts",
96
+ "execution_target": "host"
97
+ },
98
+ {
99
+ "name": "analyze_keyframes",
100
+ "description": "Map video segments through Gemini's structured output API for vision-based analysis. Reads frames from the preprocess manifest, sends each segment to Gemini with assistant-provided extraction instructions and a JSON Schema for guaranteed structured output. Supports concurrency pooling, cost tracking, resumability (skips segments with existing results), and automatic retries with exponential backoff.",
101
+ "category": "media",
102
+ "risk": "medium",
103
+ "input_schema": {
104
+ "type": "object",
105
+ "properties": {
106
+ "asset_id": {
107
+ "type": "string",
108
+ "description": "ID of the media asset whose segments to analyze"
109
+ },
110
+ "system_prompt": {
111
+ "type": "string",
112
+ "description": "Assistant-provided extraction instructions for Gemini (e.g., what to look for in the frames)"
113
+ },
114
+ "output_schema": {
115
+ "type": "object",
116
+ "description": "JSON Schema for structured output — Gemini will enforce this schema on the response"
117
+ },
118
+ "context": {
119
+ "type": "object",
120
+ "description": "Additional context to include in the prompt (e.g., subject registry, domain-specific info)"
121
+ },
122
+ "model": {
123
+ "type": "string",
124
+ "description": "Gemini model to use. Default: 'gemini-2.5-flash'"
125
+ },
126
+ "concurrency": {
127
+ "type": "number",
128
+ "minimum": 1,
129
+ "description": "Maximum concurrent Gemini API requests. Default: 10"
130
+ },
131
+ "max_retries": {
132
+ "type": "number",
133
+ "minimum": 0,
134
+ "description": "Maximum retry attempts per segment on failure. Default: 3"
135
+ }
136
+ },
137
+ "required": ["asset_id", "system_prompt", "output_schema"]
138
+ },
139
+ "executor": "tools/analyze-keyframes.ts",
140
+ "execution_target": "host"
141
+ },
142
+ {
143
+ "name": "query_media",
144
+ "description": "Query video analysis data using natural language. Sends map output (from analyze_keyframes) to Claude for intelligent analysis and Q&A. Supports arbitrary questions about video content — Claude reads the full structured analysis and answers based on the data.",
145
+ "category": "media",
146
+ "risk": "low",
147
+ "input_schema": {
148
+ "type": "object",
149
+ "properties": {
150
+ "asset_id": {
151
+ "type": "string",
152
+ "description": "ID of the media asset to query"
153
+ },
154
+ "query": {
155
+ "type": "string",
156
+ "description": "Natural language query about the video data (e.g., 'What happens at the 5 minute mark?', 'Summarize the key events', 'Are there any scoring plays?')"
157
+ },
158
+ "system_prompt": {
159
+ "type": "string",
160
+ "description": "Optional system prompt for Claude to customize analysis behavior"
161
+ },
162
+ "model": {
163
+ "type": "string",
164
+ "description": "LLM model to use for analysis. Default: 'claude-sonnet-4-6'"
165
+ }
166
+ },
167
+ "required": ["asset_id", "query"]
168
+ },
169
+ "executor": "tools/query-media-events.ts",
170
+ "execution_target": "host"
171
+ },
172
+ {
173
+ "name": "generate_clip",
174
+ "description": "Extract a video clip from a media asset using ffmpeg. Applies configurable pre/post-roll padding (clamped to file boundaries), outputs the clip as a temporary file, and registers it as an attachment for in-chat delivery.",
175
+ "category": "media",
176
+ "risk": "low",
177
+ "input_schema": {
178
+ "type": "object",
179
+ "properties": {
180
+ "asset_id": {
181
+ "type": "string",
182
+ "description": "ID of the media asset (must be a video)"
183
+ },
184
+ "start_time": {
185
+ "type": "number",
186
+ "description": "Start time of the clip in seconds"
187
+ },
188
+ "end_time": {
189
+ "type": "number",
190
+ "description": "End time of the clip in seconds"
191
+ },
192
+ "pre_roll": {
193
+ "type": "number",
194
+ "description": "Seconds of padding before start_time. Default: 3"
195
+ },
196
+ "post_roll": {
197
+ "type": "number",
198
+ "description": "Seconds of padding after end_time. Default: 2"
199
+ },
200
+ "output_format": {
201
+ "type": "string",
202
+ "enum": ["mp4", "webm", "mov"],
203
+ "description": "Output video format. Default: 'mp4'"
204
+ }
205
+ },
206
+ "required": ["asset_id", "start_time", "end_time"]
207
+ },
208
+ "executor": "tools/generate-clip.ts",
209
+ "execution_target": "host"
210
+ },
211
+ {
212
+ "name": "media_diagnostics",
213
+ "description": "Get a diagnostic report for a media asset including processing stats, per-stage timing (preprocess/map/reduce), failure reasons, and Gemini-based cost estimation.",
214
+ "category": "media",
215
+ "risk": "low",
216
+ "input_schema": {
217
+ "type": "object",
218
+ "properties": {
219
+ "asset_id": {
220
+ "type": "string",
221
+ "description": "ID of the media asset to diagnose"
222
+ }
223
+ },
224
+ "required": ["asset_id"]
225
+ },
226
+ "executor": "tools/media-diagnostics.ts",
227
+ "execution_target": "host"
228
+ }
229
+ ]
230
+ }
@@ -0,0 +1,77 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import { ConcurrencyPool } from '../services/concurrency-pool.js';
3
+
4
+ describe('ConcurrencyPool', () => {
5
+ it('allows up to maxConcurrency tasks to run simultaneously', async () => {
6
+ const pool = new ConcurrencyPool(2);
7
+
8
+ await pool.acquire();
9
+ await pool.acquire();
10
+
11
+ expect(pool.activeCount).toBe(2);
12
+ expect(pool.waitingCount).toBe(0);
13
+
14
+ // Third acquire should not resolve immediately
15
+ let thirdResolved = false;
16
+ const thirdPromise = pool.acquire().then(() => {
17
+ thirdResolved = true;
18
+ });
19
+
20
+ // Yield the microtask queue so the promise chain can settle if it were going to
21
+ await Promise.resolve();
22
+ expect(thirdResolved).toBe(false);
23
+ expect(pool.waitingCount).toBe(1);
24
+
25
+ // Release one slot — third should now resolve
26
+ pool.release();
27
+ await thirdPromise;
28
+ expect(thirdResolved).toBe(true);
29
+ expect(pool.activeCount).toBe(2);
30
+ expect(pool.waitingCount).toBe(0);
31
+ });
32
+
33
+ it('releases slots on error so the pool does not leak', async () => {
34
+ const pool = new ConcurrencyPool(1);
35
+
36
+ const runTask = async () => {
37
+ await pool.acquire();
38
+ try {
39
+ throw new Error('simulated failure');
40
+ } finally {
41
+ pool.release();
42
+ }
43
+ };
44
+
45
+ // First task errors and releases its slot
46
+ await expect(runTask()).rejects.toThrow('simulated failure');
47
+ expect(pool.activeCount).toBe(0);
48
+
49
+ // Pool should still be usable after the error
50
+ await pool.acquire();
51
+ expect(pool.activeCount).toBe(1);
52
+ pool.release();
53
+ });
54
+
55
+ it('rejects maxConcurrency less than 1', () => {
56
+ expect(() => new ConcurrencyPool(0)).toThrow('maxConcurrency must be at least 1');
57
+ });
58
+
59
+ it('defaults to maxConcurrency of 10', async () => {
60
+ const pool = new ConcurrencyPool();
61
+
62
+ // Acquire 10 slots — all should resolve immediately
63
+ for (let i = 0; i < 10; i++) {
64
+ await pool.acquire();
65
+ }
66
+ expect(pool.activeCount).toBe(10);
67
+
68
+ // 11th should queue
69
+ let eleventhResolved = false;
70
+ pool.acquire().then(() => {
71
+ eleventhResolved = true;
72
+ });
73
+ await Promise.resolve();
74
+ expect(eleventhResolved).toBe(false);
75
+ expect(pool.waitingCount).toBe(1);
76
+ });
77
+ });
@@ -0,0 +1,69 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import { CostTracker } from '../services/cost-tracker.js';
3
+
4
+ describe('CostTracker', () => {
5
+ it('accumulates costs across multiple segments', () => {
6
+ const tracker = new CostTracker();
7
+
8
+ tracker.record({
9
+ segmentId: 'seg-001',
10
+ model: 'gemini-2.5-flash',
11
+ inputTokens: 1_000_000,
12
+ outputTokens: 0,
13
+ });
14
+
15
+ tracker.record({
16
+ segmentId: 'seg-002',
17
+ model: 'gemini-2.5-flash',
18
+ inputTokens: 0,
19
+ outputTokens: 1_000_000,
20
+ });
21
+
22
+ const summary = tracker.getSummary();
23
+ expect(summary.segmentCount).toBe(2);
24
+ expect(summary.totalInputTokens).toBe(1_000_000);
25
+ expect(summary.totalOutputTokens).toBe(1_000_000);
26
+ // $0.15 for 1M input + $0.60 for 1M output = $0.75
27
+ expect(summary.totalEstimatedUSD).toBeCloseTo(0.75, 6);
28
+ });
29
+
30
+ it('computes per-entry costs using Gemini 2.5 Flash pricing', () => {
31
+ const tracker = new CostTracker();
32
+
33
+ const entry = tracker.record({
34
+ segmentId: 'seg-010',
35
+ model: 'gemini-2.5-flash',
36
+ inputTokens: 200_000,
37
+ outputTokens: 50_000,
38
+ });
39
+
40
+ // Input: 200k * ($0.15 / 1M) = $0.03
41
+ // Output: 50k * ($0.60 / 1M) = $0.03
42
+ // Total: $0.06
43
+ expect(entry.estimatedUSD).toBeCloseTo(0.06, 6);
44
+ expect(entry.segmentId).toBe('seg-010');
45
+ expect(entry.model).toBe('gemini-2.5-flash');
46
+ });
47
+
48
+ it('returns an empty summary when no entries have been recorded', () => {
49
+ const tracker = new CostTracker();
50
+ const summary = tracker.getSummary();
51
+
52
+ expect(summary.segmentCount).toBe(0);
53
+ expect(summary.totalInputTokens).toBe(0);
54
+ expect(summary.totalOutputTokens).toBe(0);
55
+ expect(summary.totalEstimatedUSD).toBe(0);
56
+ expect(summary.entries).toHaveLength(0);
57
+ });
58
+
59
+ it('preserves entry order in summary', () => {
60
+ const tracker = new CostTracker();
61
+
62
+ tracker.record({ segmentId: 'a', model: 'm', inputTokens: 100, outputTokens: 200 });
63
+ tracker.record({ segmentId: 'b', model: 'm', inputTokens: 300, outputTokens: 400 });
64
+ tracker.record({ segmentId: 'c', model: 'm', inputTokens: 500, outputTokens: 600 });
65
+
66
+ const ids = tracker.getSummary().entries.map((e) => e.segmentId);
67
+ expect(ids).toEqual(['a', 'b', 'c']);
68
+ });
69
+ });