@vellumai/assistant 0.3.5 → 0.3.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 (487) hide show
  1. package/README.md +51 -0
  2. package/eslint.config.mjs +31 -0
  3. package/package.json +1 -1
  4. package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
  5. package/scripts/ipc/generate-swift.ts +18 -2
  6. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +338 -1
  7. package/src/__tests__/approval-conversation-turn.test.ts +214 -0
  8. package/src/__tests__/browser-manager.test.ts +1 -0
  9. package/src/__tests__/call-conversation-messages.test.ts +130 -0
  10. package/src/__tests__/call-orchestrator.test.ts +752 -271
  11. package/src/__tests__/call-pointer-messages.test.ts +148 -0
  12. package/src/__tests__/call-recovery.test.ts +3 -0
  13. package/src/__tests__/call-routes-http.test.ts +5 -0
  14. package/src/__tests__/call-store.test.ts +3 -0
  15. package/src/__tests__/channel-approval-routes.test.ts +1260 -85
  16. package/src/__tests__/channel-approval.test.ts +37 -0
  17. package/src/__tests__/channel-approvals.test.ts +4 -65
  18. package/src/__tests__/channel-guardian.test.ts +556 -0
  19. package/src/__tests__/channel-readiness-service.test.ts +74 -7
  20. package/src/__tests__/checker.test.ts +14 -7
  21. package/src/__tests__/clarification-resolver.test.ts +44 -24
  22. package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
  23. package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
  24. package/src/__tests__/config-schema.test.ts +12 -7
  25. package/src/__tests__/context-window-manager.test.ts +30 -2
  26. package/src/__tests__/contradiction-checker.test.ts +20 -5
  27. package/src/__tests__/credential-security-invariants.test.ts +6 -2
  28. package/src/__tests__/db-migration-rollback.test.ts +752 -0
  29. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
  30. package/src/__tests__/fuzzy-match-property.test.ts +5 -5
  31. package/src/__tests__/guardian-action-store.test.ts +123 -0
  32. package/src/__tests__/guardian-action-sweep.test.ts +277 -0
  33. package/src/__tests__/guardian-dispatch.test.ts +389 -0
  34. package/src/__tests__/guardian-question-copy.test.ts +47 -0
  35. package/src/__tests__/handlers-telegram-config.test.ts +4 -2
  36. package/src/__tests__/handlers-twilio-config.test.ts +126 -0
  37. package/src/__tests__/intent-routing.test.ts +2 -0
  38. package/src/__tests__/ipc-snapshot.test.ts +228 -1
  39. package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
  40. package/src/__tests__/model-intents.test.ts +96 -0
  41. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
  42. package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
  43. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
  44. package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
  45. package/src/__tests__/provider-error-scenarios.test.ts +621 -0
  46. package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
  47. package/src/__tests__/qdrant-manager.test.ts +27 -20
  48. package/src/__tests__/relay-server.test.ts +779 -40
  49. package/src/__tests__/run-orchestrator-assistant-events.test.ts +2 -0
  50. package/src/__tests__/run-orchestrator.test.ts +20 -4
  51. package/src/__tests__/runtime-runs-http.test.ts +17 -1
  52. package/src/__tests__/runtime-runs.test.ts +16 -0
  53. package/src/__tests__/schedule-store.test.ts +18 -4
  54. package/src/__tests__/scheduler-recurrence.test.ts +13 -4
  55. package/src/__tests__/session-abort-tool-results.test.ts +6 -0
  56. package/src/__tests__/session-agent-loop.test.ts +857 -0
  57. package/src/__tests__/session-conflict-gate.test.ts +6 -0
  58. package/src/__tests__/session-pre-run-repair.test.ts +6 -0
  59. package/src/__tests__/session-profile-injection.test.ts +6 -0
  60. package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
  61. package/src/__tests__/session-queue.test.ts +6 -0
  62. package/src/__tests__/session-runtime-assembly.test.ts +237 -13
  63. package/src/__tests__/session-slash-known.test.ts +6 -0
  64. package/src/__tests__/session-slash-queue.test.ts +6 -0
  65. package/src/__tests__/session-slash-unknown.test.ts +6 -0
  66. package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
  67. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
  68. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
  69. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
  70. package/src/__tests__/session-workspace-injection.test.ts +6 -0
  71. package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
  72. package/src/__tests__/skills.test.ts +2 -0
  73. package/src/__tests__/sms-messaging-provider.test.ts +2 -1
  74. package/src/__tests__/starter-task-flow.test.ts +2 -0
  75. package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
  76. package/src/__tests__/system-prompt.test.ts +2 -0
  77. package/src/__tests__/task-management-tools.test.ts +2 -2
  78. package/src/__tests__/task-runner.test.ts +14 -4
  79. package/src/__tests__/terminal-tools.test.ts +25 -19
  80. package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
  81. package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
  82. package/src/__tests__/tool-executor.test.ts +23 -24
  83. package/src/__tests__/trust-store.test.ts +3 -3
  84. package/src/__tests__/twilio-rest.test.ts +29 -0
  85. package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
  86. package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
  87. package/src/__tests__/twilio-routes.test.ts +141 -21
  88. package/src/__tests__/user-reference.test.ts +2 -0
  89. package/src/__tests__/voice-quality.test.ts +222 -0
  90. package/src/__tests__/web-search.test.ts +45 -29
  91. package/src/agent/loop.ts +1 -1
  92. package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
  93. package/src/amazon/client.ts +1418 -0
  94. package/src/amazon/request-extractor.ts +135 -0
  95. package/src/amazon/session.ts +109 -0
  96. package/src/autonomy/autonomy-store.ts +5 -5
  97. package/src/browser-extension-relay/client.ts +124 -0
  98. package/src/browser-extension-relay/protocol.ts +63 -0
  99. package/src/browser-extension-relay/server.ts +177 -0
  100. package/src/bundler/app-bundler.ts +3 -3
  101. package/src/bundler/bundle-signer.ts +1 -1
  102. package/src/bundler/signature-verifier.ts +1 -1
  103. package/src/calls/call-conversation-messages.ts +33 -0
  104. package/src/calls/call-domain.ts +106 -5
  105. package/src/calls/call-orchestrator.ts +252 -54
  106. package/src/calls/call-pointer-messages.ts +53 -0
  107. package/src/calls/call-recovery.ts +3 -8
  108. package/src/calls/call-store.ts +69 -87
  109. package/src/calls/elevenlabs-config.ts +3 -2
  110. package/src/calls/guardian-action-sweep.ts +105 -0
  111. package/src/calls/guardian-dispatch.ts +203 -0
  112. package/src/calls/guardian-question-copy.ts +133 -0
  113. package/src/calls/relay-server.ts +466 -8
  114. package/src/calls/speaker-identification.ts +1 -1
  115. package/src/calls/twilio-config.ts +7 -5
  116. package/src/calls/twilio-provider.ts +6 -4
  117. package/src/calls/twilio-rest.ts +40 -15
  118. package/src/calls/twilio-routes.ts +60 -45
  119. package/src/calls/types.ts +3 -1
  120. package/src/channels/types.ts +25 -0
  121. package/src/cli/amazon.ts +815 -0
  122. package/src/cli/config-commands.ts +2 -2
  123. package/src/cli/core-commands.ts +4 -3
  124. package/src/cli/influencer.ts +244 -0
  125. package/src/cli/map.ts +89 -6
  126. package/src/cli.ts +1 -1
  127. package/src/config/agent-schema.ts +171 -0
  128. package/src/config/bundled-skills/amazon/SKILL.md +127 -0
  129. package/src/config/bundled-skills/amazon/icon.svg +13 -0
  130. package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
  131. package/src/config/bundled-skills/browser/SKILL.md +1 -0
  132. package/src/config/bundled-skills/browser/TOOLS.json +17 -0
  133. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
  134. package/src/config/bundled-skills/doordash/SKILL.md +51 -51
  135. package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
  136. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
  137. package/src/config/bundled-skills/influencer/SKILL.md +144 -0
  138. package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
  139. package/src/config/bundled-skills/media-processing/SKILL.md +72 -95
  140. package/src/config/bundled-skills/media-processing/TOOLS.json +57 -147
  141. package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
  142. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
  143. package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
  144. package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
  145. package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
  146. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
  147. package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
  148. package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +7 -9
  149. package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
  150. package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +88 -253
  151. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +22 -153
  152. package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
  153. package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +28 -51
  154. package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +35 -270
  155. package/src/config/bundled-skills/messaging/SKILL.md +12 -2
  156. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
  157. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
  158. package/src/config/bundled-skills/phone-calls/SKILL.md +86 -21
  159. package/src/config/bundled-skills/twitter/icon.svg +14 -0
  160. package/src/config/bundled-tool-registry.ts +310 -0
  161. package/src/config/calls-schema.ts +181 -0
  162. package/src/config/core-schema.ts +309 -0
  163. package/src/config/defaults.ts +27 -3
  164. package/src/config/env-registry.ts +169 -0
  165. package/src/config/env.ts +175 -0
  166. package/src/config/loader.ts +6 -6
  167. package/src/config/memory-schema.ts +528 -0
  168. package/src/config/sandbox-schema.ts +55 -0
  169. package/src/config/schema.ts +157 -1138
  170. package/src/config/skill-state.ts +1 -1
  171. package/src/config/skills-schema.ts +32 -0
  172. package/src/config/skills.ts +35 -24
  173. package/src/config/system-prompt.ts +107 -56
  174. package/src/config/templates/SOUL.md +1 -1
  175. package/src/config/types.ts +1 -0
  176. package/src/config/user-reference.ts +4 -9
  177. package/src/config/vellum-skills/catalog.json +0 -7
  178. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
  179. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +1 -0
  180. package/src/config/vellum-skills/sms-setup/SKILL.md +112 -14
  181. package/src/context/window-manager.ts +27 -7
  182. package/src/daemon/approval-generators.ts +186 -0
  183. package/src/daemon/approved-devices-store.ts +140 -0
  184. package/src/daemon/assistant-attachments.ts +1 -1
  185. package/src/daemon/classifier.ts +35 -32
  186. package/src/daemon/config-watcher.ts +1 -1
  187. package/src/daemon/daemon-control.ts +254 -0
  188. package/src/daemon/handlers/apps.ts +2 -3
  189. package/src/daemon/handlers/config-channels.ts +158 -0
  190. package/src/daemon/handlers/config-inbox.ts +540 -0
  191. package/src/daemon/handlers/config-ingress.ts +231 -0
  192. package/src/daemon/handlers/config-integrations.ts +258 -0
  193. package/src/daemon/handlers/config-model.ts +143 -0
  194. package/src/daemon/handlers/config-parental.ts +163 -0
  195. package/src/daemon/handlers/config-scheduling.ts +172 -0
  196. package/src/daemon/handlers/config-slack.ts +92 -0
  197. package/src/daemon/handlers/config-telegram.ts +301 -0
  198. package/src/daemon/handlers/config-tools.ts +177 -0
  199. package/src/daemon/handlers/config-trust.ts +104 -0
  200. package/src/daemon/handlers/config-twilio.ts +1080 -0
  201. package/src/daemon/handlers/config.ts +53 -2463
  202. package/src/daemon/handlers/diagnostics.ts +1 -1
  203. package/src/daemon/handlers/dictation.ts +4 -6
  204. package/src/daemon/handlers/documents.ts +18 -32
  205. package/src/daemon/handlers/index.ts +9 -0
  206. package/src/daemon/handlers/misc.ts +3 -5
  207. package/src/daemon/handlers/pairing.ts +98 -0
  208. package/src/daemon/handlers/sessions.ts +74 -5
  209. package/src/daemon/handlers/shared.ts +3 -1
  210. package/src/daemon/handlers/skills.ts +1 -1
  211. package/src/daemon/handlers/twitter-auth.ts +2 -0
  212. package/src/daemon/handlers/work-items.ts +2 -2
  213. package/src/daemon/handlers/workspace-files.ts +4 -3
  214. package/src/daemon/install-cli-launchers.ts +113 -0
  215. package/src/daemon/ipc-contract/apps.ts +356 -0
  216. package/src/daemon/ipc-contract/browser.ts +74 -0
  217. package/src/daemon/ipc-contract/computer-use.ts +151 -0
  218. package/src/daemon/ipc-contract/diagnostics.ts +56 -0
  219. package/src/daemon/ipc-contract/documents.ts +74 -0
  220. package/src/daemon/ipc-contract/inbox.ts +209 -0
  221. package/src/daemon/ipc-contract/integrations.ts +284 -0
  222. package/src/daemon/ipc-contract/memory.ts +48 -0
  223. package/src/daemon/ipc-contract/messages.ts +211 -0
  224. package/src/daemon/ipc-contract/pairing.ts +45 -0
  225. package/src/daemon/ipc-contract/parental-control.ts +95 -0
  226. package/src/daemon/ipc-contract/schedules.ts +97 -0
  227. package/src/daemon/ipc-contract/sessions.ts +321 -0
  228. package/src/daemon/ipc-contract/shared.ts +42 -0
  229. package/src/daemon/ipc-contract/skills.ts +120 -0
  230. package/src/daemon/ipc-contract/subagents.ts +58 -0
  231. package/src/daemon/ipc-contract/surfaces.ts +250 -0
  232. package/src/daemon/ipc-contract/trust.ts +60 -0
  233. package/src/daemon/ipc-contract/work-items.ts +225 -0
  234. package/src/daemon/ipc-contract/workspace.ts +113 -0
  235. package/src/daemon/ipc-contract-inventory.json +62 -0
  236. package/src/daemon/ipc-contract-inventory.ts +55 -29
  237. package/src/daemon/ipc-contract.ts +227 -2527
  238. package/src/daemon/ipc-protocol.ts +1 -1
  239. package/src/daemon/ipc-validate.ts +7 -0
  240. package/src/daemon/lifecycle.ts +97 -379
  241. package/src/daemon/pairing-store.ts +177 -0
  242. package/src/daemon/providers-setup.ts +43 -0
  243. package/src/daemon/ride-shotgun-handler.ts +67 -2
  244. package/src/daemon/server.ts +60 -44
  245. package/src/daemon/session-agent-loop-handlers.ts +421 -0
  246. package/src/daemon/session-agent-loop.ts +113 -275
  247. package/src/daemon/session-dynamic-profile.ts +1 -1
  248. package/src/daemon/session-history.ts +1 -1
  249. package/src/daemon/session-media-retry.ts +1 -1
  250. package/src/daemon/session-messaging.ts +37 -2
  251. package/src/daemon/session-notifiers.ts +5 -25
  252. package/src/daemon/session-process.ts +99 -59
  253. package/src/daemon/session-queue-manager.ts +98 -4
  254. package/src/daemon/session-runtime-assembly.ts +149 -15
  255. package/src/daemon/session-surfaces.ts +26 -4
  256. package/src/daemon/session-tool-setup.ts +28 -30
  257. package/src/daemon/session-workspace.ts +1 -1
  258. package/src/daemon/session.ts +24 -1
  259. package/src/daemon/shutdown-handlers.ts +122 -0
  260. package/src/daemon/trace-emitter.ts +1 -1
  261. package/src/daemon/watch-handler.ts +36 -33
  262. package/src/doordash/cart-queries.ts +787 -0
  263. package/src/doordash/client.ts +144 -127
  264. package/src/doordash/order-queries.ts +85 -0
  265. package/src/doordash/queries.ts +10 -1308
  266. package/src/doordash/search-queries.ts +203 -0
  267. package/src/doordash/session.ts +3 -2
  268. package/src/doordash/store-queries.ts +246 -0
  269. package/src/doordash/types.ts +367 -0
  270. package/src/email/providers/agentmail.ts +2 -1
  271. package/src/email/providers/index.ts +3 -2
  272. package/src/email/service.ts +3 -2
  273. package/src/errors.ts +43 -0
  274. package/src/home-base/prebuilt/seed.ts +1 -1
  275. package/src/hooks/cli.ts +6 -5
  276. package/src/hooks/config.ts +6 -8
  277. package/src/hooks/discovery.ts +6 -5
  278. package/src/hooks/manager.ts +4 -3
  279. package/src/hooks/runner.ts +2 -2
  280. package/src/hooks/templates.ts +5 -5
  281. package/src/inbound/public-ingress-urls.ts +3 -1
  282. package/src/index.ts +4 -2
  283. package/src/influencer/client.ts +1104 -0
  284. package/src/instrument.ts +4 -3
  285. package/src/logfire.ts +4 -3
  286. package/src/memory/admin.ts +25 -35
  287. package/src/memory/attachments-store.ts +4 -7
  288. package/src/memory/channel-delivery-store.ts +30 -1
  289. package/src/memory/channel-guardian-store.ts +200 -1
  290. package/src/memory/clarification-resolver.ts +37 -33
  291. package/src/memory/conflict-store.ts +67 -61
  292. package/src/memory/contradiction-checker.ts +141 -117
  293. package/src/memory/conversation-store.ts +335 -51
  294. package/src/memory/db-connection.ts +27 -4
  295. package/src/memory/db-init.ts +121 -4
  296. package/src/memory/db.ts +14 -1
  297. package/src/memory/embedding-backend.ts +27 -5
  298. package/src/memory/embedding-ollama.ts +2 -1
  299. package/src/memory/entity-extractor.ts +38 -35
  300. package/src/memory/guardian-action-store.ts +430 -0
  301. package/src/memory/inbox-escalation-projection.ts +59 -0
  302. package/src/memory/inbox-thread-store.ts +218 -0
  303. package/src/memory/ingress-invite-store.ts +338 -0
  304. package/src/memory/ingress-member-store.ts +350 -0
  305. package/src/memory/items-extractor.ts +91 -97
  306. package/src/memory/job-handlers/index-maintenance.ts +3 -3
  307. package/src/memory/job-handlers/media-processing.ts +11 -42
  308. package/src/memory/job-handlers/summarization.ts +32 -26
  309. package/src/memory/job-utils.ts +3 -10
  310. package/src/memory/jobs-store.ts +6 -9
  311. package/src/memory/jobs-worker.ts +51 -36
  312. package/src/memory/migrations/001-job-deferrals.ts +45 -0
  313. package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
  314. package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
  315. package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
  316. package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
  317. package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
  318. package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
  319. package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
  320. package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
  321. package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
  322. package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
  323. package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
  324. package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
  325. package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
  326. package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
  327. package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
  328. package/src/memory/migrations/017-memory-items-indexes.ts +12 -0
  329. package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
  330. package/src/memory/migrations/index.ts +24 -0
  331. package/src/memory/migrations/registry.ts +79 -0
  332. package/src/memory/migrations/validate-migration-state.ts +69 -0
  333. package/src/memory/qdrant-manager.ts +49 -8
  334. package/src/memory/query-builder.ts +1 -1
  335. package/src/memory/raw-query.ts +119 -0
  336. package/src/memory/recall-cache.ts +4 -1
  337. package/src/memory/retriever.ts +163 -47
  338. package/src/memory/schema-migration.ts +25 -984
  339. package/src/memory/schema.ts +130 -7
  340. package/src/memory/search/entity.ts +10 -19
  341. package/src/memory/search/lexical.ts +81 -52
  342. package/src/memory/search/ranking.ts +21 -22
  343. package/src/memory/search/semantic.ts +157 -19
  344. package/src/memory/shared-app-links-store.ts +4 -5
  345. package/src/memory/validation.ts +19 -0
  346. package/src/messaging/draft-store.ts +5 -6
  347. package/src/messaging/providers/sms/adapter.ts +3 -6
  348. package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
  349. package/src/messaging/providers/whatsapp/adapter.ts +136 -0
  350. package/src/messaging/providers/whatsapp/client.ts +67 -0
  351. package/src/messaging/style-analyzer.ts +5 -4
  352. package/src/messaging/thread-summarizer.ts +61 -69
  353. package/src/messaging/triage-engine.ts +62 -71
  354. package/src/migrations/config-merge.ts +53 -0
  355. package/src/migrations/data-layout.ts +68 -0
  356. package/src/migrations/data-merge.ts +33 -0
  357. package/src/migrations/hooks-merge.ts +90 -0
  358. package/src/migrations/index.ts +6 -0
  359. package/src/migrations/log.ts +23 -0
  360. package/src/migrations/skills-merge.ts +33 -0
  361. package/src/migrations/workspace-layout.ts +79 -0
  362. package/src/permissions/checker.ts +126 -11
  363. package/src/permissions/prompter.ts +14 -0
  364. package/src/permissions/shell-identity.ts +31 -1
  365. package/src/permissions/trust-store.ts +21 -1
  366. package/src/providers/anthropic/client.ts +4 -4
  367. package/src/providers/failover.ts +2 -2
  368. package/src/providers/model-intents.ts +70 -0
  369. package/src/providers/ollama/client.ts +2 -1
  370. package/src/providers/provider-send-message.ts +176 -0
  371. package/src/providers/registry.ts +71 -30
  372. package/src/providers/retry.ts +35 -1
  373. package/src/providers/types.ts +12 -1
  374. package/src/runtime/approval-conversation-turn.ts +97 -0
  375. package/src/runtime/approval-message-composer.ts +115 -5
  376. package/src/runtime/assistant-event-hub.ts +3 -1
  377. package/src/runtime/channel-approval-parser.ts +36 -2
  378. package/src/runtime/channel-approvals.ts +0 -21
  379. package/src/runtime/channel-guardian-service.ts +48 -7
  380. package/src/runtime/channel-readiness-service.ts +160 -34
  381. package/src/runtime/channel-readiness-types.ts +10 -4
  382. package/src/runtime/channel-retry-sweep.ts +184 -0
  383. package/src/runtime/guardian-context-resolver.ts +108 -0
  384. package/src/runtime/http-server.ts +289 -745
  385. package/src/runtime/http-types.ts +56 -3
  386. package/src/runtime/middleware/auth.ts +116 -0
  387. package/src/runtime/middleware/error-handler.ts +33 -0
  388. package/src/runtime/middleware/twilio-validation.ts +127 -0
  389. package/src/runtime/routes/app-routes.ts +1 -1
  390. package/src/runtime/routes/call-routes.ts +49 -6
  391. package/src/runtime/routes/channel-delivery-routes.ts +170 -0
  392. package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
  393. package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
  394. package/src/runtime/routes/channel-route-shared.ts +144 -0
  395. package/src/runtime/routes/channel-routes.ts +32 -1634
  396. package/src/runtime/routes/conversation-routes.ts +50 -7
  397. package/src/runtime/routes/events-routes.ts +2 -2
  398. package/src/runtime/routes/identity-routes.ts +126 -0
  399. package/src/runtime/routes/pairing-routes.ts +144 -0
  400. package/src/runtime/routes/run-routes.ts +15 -1
  401. package/src/runtime/run-orchestrator.ts +52 -34
  402. package/src/schedule/schedule-store.ts +36 -32
  403. package/src/schedule/scheduler.ts +3 -3
  404. package/src/security/encrypted-store.ts +5 -7
  405. package/src/security/oauth2.ts +45 -15
  406. package/src/security/parental-control-store.ts +183 -0
  407. package/src/security/secret-allowlist.ts +4 -3
  408. package/src/security/secret-scanner.ts +5 -5
  409. package/src/security/secure-keys.ts +1 -1
  410. package/src/security/token-manager.ts +3 -2
  411. package/src/services/vercel-deploy.ts +6 -2
  412. package/src/skills/tool-manifest.ts +3 -3
  413. package/src/skills/vellum-catalog-remote.ts +75 -16
  414. package/src/slack/slack-webhook.ts +2 -1
  415. package/src/swarm/orchestrator.ts +92 -1
  416. package/src/swarm/router-planner.ts +6 -9
  417. package/src/swarm/worker-prompts.ts +9 -12
  418. package/src/tasks/task-compiler.ts +19 -28
  419. package/src/tasks/task-runner.ts +1 -1
  420. package/src/tools/assets/search.ts +15 -14
  421. package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
  422. package/src/tools/browser/auto-navigate.ts +1 -0
  423. package/src/tools/browser/browser-execution.ts +13 -1
  424. package/src/tools/browser/browser-manager.ts +119 -4
  425. package/src/tools/browser/network-recorder.ts +5 -0
  426. package/src/tools/credentials/broker.ts +11 -2
  427. package/src/tools/credentials/metadata-store.ts +18 -14
  428. package/src/tools/credentials/post-connect-hooks.ts +61 -0
  429. package/src/tools/credentials/vault.ts +49 -23
  430. package/src/tools/executor.ts +80 -18
  431. package/src/tools/host-terminal/cli-discover.ts +1 -1
  432. package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
  433. package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
  434. package/src/tools/network/script-proxy/server.ts +1 -1
  435. package/src/tools/network/script-proxy/session-manager.ts +6 -5
  436. package/src/tools/network/web-fetch.ts +18 -2
  437. package/src/tools/network/web-search.ts +7 -3
  438. package/src/tools/reminder/reminder-store.ts +14 -15
  439. package/src/tools/schedule/create.ts +1 -0
  440. package/src/tools/schedule/list.ts +2 -1
  441. package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
  442. package/src/tools/skills/skill-script-runner.ts +24 -9
  443. package/src/tools/skills/skill-tool-factory.ts +1 -0
  444. package/src/tools/tasks/work-item-enqueue.ts +2 -2
  445. package/src/tools/terminal/evaluate-typescript.ts +21 -12
  446. package/src/tools/terminal/parser.ts +50 -0
  447. package/src/tools/watcher/delete.ts +6 -0
  448. package/src/tools/weather/service.ts +1 -1
  449. package/src/twitter/client.ts +190 -24
  450. package/src/twitter/session.ts +4 -3
  451. package/src/util/clipboard.ts +1 -1
  452. package/src/util/errors.ts +65 -8
  453. package/src/util/fs.ts +40 -0
  454. package/src/util/json.ts +10 -0
  455. package/src/util/log-redact.ts +189 -0
  456. package/src/util/logger.ts +25 -18
  457. package/src/util/object.ts +3 -0
  458. package/src/util/platform.ts +72 -365
  459. package/src/util/pricing.ts +1 -1
  460. package/src/util/promise-guard.ts +1 -1
  461. package/src/util/retry.ts +19 -0
  462. package/src/util/row-mapper.ts +79 -0
  463. package/src/util/silently.ts +21 -0
  464. package/src/watcher/engine.ts +5 -1
  465. package/src/watcher/provider-types.ts +20 -0
  466. package/src/watcher/providers/github.ts +156 -0
  467. package/src/watcher/providers/gmail.ts +1 -0
  468. package/src/watcher/providers/google-calendar.ts +1 -0
  469. package/src/watcher/providers/linear.ts +460 -0
  470. package/src/watcher/providers/slack.ts +1 -0
  471. package/src/work-items/work-item-runner.ts +1 -1
  472. package/src/workspace/git-service.ts +1 -1
  473. package/src/workspace/provider-commit-message-generator.ts +51 -22
  474. package/src/__tests__/call-bridge.test.ts +0 -517
  475. package/src/__tests__/session-process-bridge.test.ts +0 -244
  476. package/src/calls/call-bridge.ts +0 -168
  477. package/src/config/bundled-skills/media-processing/services/capability-registry.ts +0 -137
  478. package/src/config/bundled-skills/media-processing/services/event-detection-service.ts +0 -280
  479. package/src/config/bundled-skills/media-processing/services/feedback-aggregation.ts +0 -144
  480. package/src/config/bundled-skills/media-processing/services/feedback-store.ts +0 -136
  481. package/src/config/bundled-skills/media-processing/services/retrieval-service.ts +0 -95
  482. package/src/config/bundled-skills/media-processing/services/timeline-service.ts +0 -267
  483. package/src/config/bundled-skills/media-processing/tools/detect-events.ts +0 -110
  484. package/src/config/bundled-skills/media-processing/tools/recalibrate.ts +0 -235
  485. package/src/config/bundled-skills/media-processing/tools/select-tracking-profile.ts +0 -142
  486. package/src/config/bundled-skills/media-processing/tools/submit-feedback.ts +0 -150
  487. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
@@ -1,267 +0,0 @@
1
- /**
2
- * Timeline generation service.
3
- *
4
- * Aggregates sequential vision outputs into coherent timeline segments.
5
- * Each segment groups adjacent keyframes that share similar scene characteristics
6
- * into a single time range with merged attributes.
7
- */
8
-
9
- import {
10
- getMediaAssetById,
11
- getKeyframesForAsset,
12
- getVisionOutputsForAsset,
13
- deleteTimelineForAsset,
14
- insertTimelineSegmentsBatch,
15
- createProcessingStage,
16
- updateProcessingStage,
17
- getProcessingStagesForAsset,
18
- type MediaVisionOutput,
19
- type MediaKeyframe,
20
- type MediaTimeline,
21
- } from '../../../../memory/media-store.js';
22
-
23
- export interface TimelineGenerationResult {
24
- assetId: string;
25
- segmentCount: number;
26
- segments: MediaTimeline[];
27
- }
28
-
29
- /**
30
- * Generate a timeline for a media asset from its vision analysis outputs.
31
- *
32
- * Groups consecutive keyframes with similar scene descriptions into segments.
33
- * If a timeline already exists for this asset, it is replaced.
34
- */
35
- export function generateTimeline(
36
- assetId: string,
37
- options?: {
38
- analysisType?: string;
39
- onProgress?: (message: string) => void;
40
- },
41
- ): TimelineGenerationResult {
42
- const analysisType = options?.analysisType ?? 'scene_description';
43
- const onProgress = options?.onProgress;
44
-
45
- const asset = getMediaAssetById(assetId);
46
- if (!asset) {
47
- throw new Error(`Media asset not found: ${assetId}`);
48
- }
49
-
50
- const keyframes = getKeyframesForAsset(assetId);
51
- if (keyframes.length === 0) {
52
- throw new Error('No keyframes found for this asset. Run extract_keyframes first.');
53
- }
54
-
55
- const visionOutputs = getVisionOutputsForAsset(assetId, analysisType);
56
- if (visionOutputs.length === 0) {
57
- throw new Error(`No vision outputs found for analysis type "${analysisType}". Run analyze_keyframes first.`);
58
- }
59
-
60
- // Find or create the timeline_generation processing stage
61
- const existingStages = getProcessingStagesForAsset(assetId);
62
- let stage = existingStages.find((s) => s.stage === 'timeline_generation');
63
- if (!stage) {
64
- stage = createProcessingStage({ assetId, stage: 'timeline_generation' });
65
- }
66
- updateProcessingStage(stage.id, { status: 'running', startedAt: Date.now() });
67
-
68
- try {
69
- // Build a map of keyframeId -> keyframe for timestamp lookup
70
- const keyframeMap = new Map<string, MediaKeyframe>();
71
- for (const kf of keyframes) {
72
- keyframeMap.set(kf.id, kf);
73
- }
74
-
75
- // Build a map of keyframeId -> vision output
76
- const outputByKeyframe = new Map<string, MediaVisionOutput>();
77
- for (const vo of visionOutputs) {
78
- outputByKeyframe.set(vo.keyframeId, vo);
79
- }
80
-
81
- // Sort keyframes by timestamp to ensure sequential processing
82
- const sortedKeyframes = [...keyframes]
83
- .filter((kf) => outputByKeyframe.has(kf.id))
84
- .sort((a, b) => a.timestamp - b.timestamp);
85
-
86
- if (sortedKeyframes.length === 0) {
87
- updateProcessingStage(stage.id, {
88
- status: 'completed',
89
- progress: 100,
90
- completedAt: Date.now(),
91
- });
92
- return { assetId, segmentCount: 0, segments: [] };
93
- }
94
-
95
- onProgress?.('Aggregating vision outputs into timeline segments...');
96
-
97
- // Aggregate consecutive frames into segments based on scene similarity
98
- const segmentRows: Array<{
99
- assetId: string;
100
- startTime: number;
101
- endTime: number;
102
- segmentType: string;
103
- attributes: Record<string, unknown>;
104
- confidence: number;
105
- }> = [];
106
-
107
- let currentSegment = createSegmentFromOutput(
108
- assetId,
109
- sortedKeyframes[0],
110
- outputByKeyframe.get(sortedKeyframes[0].id)!,
111
- );
112
-
113
- for (let i = 1; i < sortedKeyframes.length; i++) {
114
- const kf = sortedKeyframes[i];
115
- const vo = outputByKeyframe.get(kf.id)!;
116
-
117
- if (shouldMergeIntoSegment(currentSegment, vo)) {
118
- // Extend the current segment
119
- currentSegment.endTime = kf.timestamp;
120
- const newConfidence = vo.confidence ?? 0.5;
121
- currentSegment.confidence =
122
- (currentSegment.confidence * currentSegment.frameCount + newConfidence) / (currentSegment.frameCount + 1);
123
- currentSegment.frameCount++;
124
- mergeSubjects(currentSegment.attributes, vo.output);
125
- mergeActions(currentSegment.attributes, vo.output);
126
- } else {
127
- // Finalize current segment and start a new one
128
- segmentRows.push(currentSegment);
129
- currentSegment = createSegmentFromOutput(assetId, kf, vo);
130
- }
131
-
132
- // Update progress
133
- const progress = Math.round((i / sortedKeyframes.length) * 100);
134
- updateProcessingStage(stage.id, { progress });
135
- }
136
-
137
- // Don't forget the last segment
138
- segmentRows.push(currentSegment);
139
-
140
- // Clear existing timeline and insert new segments
141
- deleteTimelineForAsset(assetId);
142
- const segments = insertTimelineSegmentsBatch(segmentRows);
143
-
144
- updateProcessingStage(stage.id, {
145
- status: 'completed',
146
- progress: 100,
147
- completedAt: Date.now(),
148
- });
149
-
150
- onProgress?.(`Generated ${segments.length} timeline segments.`);
151
-
152
- return { assetId, segmentCount: segments.length, segments };
153
- } catch (err) {
154
- updateProcessingStage(stage.id, {
155
- status: 'failed',
156
- lastError: (err as Error).message.slice(0, 500),
157
- });
158
- throw err;
159
- }
160
- }
161
-
162
- // ---------------------------------------------------------------------------
163
- // Internal helpers
164
- // ---------------------------------------------------------------------------
165
-
166
- interface PendingSegment {
167
- assetId: string;
168
- startTime: number;
169
- endTime: number;
170
- segmentType: string;
171
- attributes: Record<string, unknown>;
172
- confidence: number;
173
- frameCount: number;
174
- }
175
-
176
- function createSegmentFromOutput(
177
- assetId: string,
178
- keyframe: MediaKeyframe,
179
- vo: MediaVisionOutput,
180
- ): PendingSegment {
181
- const sceneDescription = (vo.output.sceneDescription as string) ?? '';
182
- const segmentType = deriveSegmentType(vo.output);
183
- return {
184
- assetId,
185
- startTime: keyframe.timestamp,
186
- endTime: keyframe.timestamp,
187
- segmentType,
188
- attributes: {
189
- sceneDescription,
190
- subjects: Array.isArray(vo.output.subjects) ? [...(vo.output.subjects as string[])] : [],
191
- actions: Array.isArray(vo.output.actions) ? [...(vo.output.actions as string[])] : [],
192
- context: (vo.output.context as string) ?? '',
193
- },
194
- confidence: vo.confidence ?? 0.5,
195
- frameCount: 1,
196
- };
197
- }
198
-
199
- /**
200
- * Derive a generic segment type from vision output.
201
- * Uses simple heuristics on the scene description — domain-specific
202
- * interpretation belongs in the VLM prompt, not here.
203
- */
204
- function deriveSegmentType(output: Record<string, unknown>): string {
205
- const actions = output.actions as string[] | undefined;
206
- if (actions && actions.length > 0) {
207
- return 'activity';
208
- }
209
- const subjects = output.subjects as string[] | undefined;
210
- if (subjects && subjects.length > 0) {
211
- return 'scene';
212
- }
213
- return 'static';
214
- }
215
-
216
- /**
217
- * Decide whether a new vision output is similar enough to merge
218
- * into the current segment.
219
- *
220
- * Uses a simple heuristic: same segment type and overlapping subjects.
221
- */
222
- function shouldMergeIntoSegment(
223
- segment: PendingSegment,
224
- vo: MediaVisionOutput,
225
- ): boolean {
226
- const newType = deriveSegmentType(vo.output);
227
- if (newType !== segment.segmentType) return false;
228
-
229
- // Check subject overlap
230
- const existingSubjects = new Set(
231
- (segment.attributes.subjects as string[]) ?? [],
232
- );
233
- const newSubjects = (vo.output.subjects as string[]) ?? [];
234
-
235
- if (existingSubjects.size === 0 && newSubjects.length === 0) return true;
236
- if (existingSubjects.size === 0 || newSubjects.length === 0) return false;
237
-
238
- const overlap = newSubjects.filter((s) => existingSubjects.has(s)).length;
239
- const unionSize = new Set([...existingSubjects, ...newSubjects]).size;
240
-
241
- // Merge if at least 30% overlap (Jaccard similarity)
242
- return unionSize > 0 && overlap / unionSize >= 0.3;
243
- }
244
-
245
- function mergeSubjects(
246
- attributes: Record<string, unknown>,
247
- newOutput: Record<string, unknown>,
248
- ): void {
249
- const existing = new Set((attributes.subjects as string[]) ?? []);
250
- const incoming = (newOutput.subjects as string[]) ?? [];
251
- for (const s of incoming) {
252
- existing.add(s);
253
- }
254
- attributes.subjects = [...existing];
255
- }
256
-
257
- function mergeActions(
258
- attributes: Record<string, unknown>,
259
- newOutput: Record<string, unknown>,
260
- ): void {
261
- const existing = new Set((attributes.actions as string[]) ?? []);
262
- const incoming = (newOutput.actions as string[]) ?? [];
263
- for (const a of incoming) {
264
- existing.add(a);
265
- }
266
- attributes.actions = [...existing];
267
- }
@@ -1,110 +0,0 @@
1
- import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
2
- import { detectEvents, type DetectionConfig, type DetectionRule } from '../services/event-detection-service.js';
3
-
4
- /**
5
- * Sensible default detection rules for common event types.
6
- * These are fallbacks when the caller doesn't provide explicit rules —
7
- * the system is not limited to these event types.
8
- */
9
- const DEFAULT_RULES_BY_EVENT_TYPE: Record<string, DetectionRule[]> = {
10
- turnover: [
11
- { ruleType: 'segment_transition', params: { field: 'subjects' }, weight: 0.5 },
12
- { ruleType: 'short_segment', params: { maxDurationSeconds: 5 }, weight: 0.3 },
13
- { ruleType: 'attribute_match', params: { field: 'actions', pattern: 'steal|turnover|loss|intercept' }, weight: 0.2 },
14
- ],
15
- scene_change: [
16
- { ruleType: 'segment_transition', params: { field: 'segmentType' }, weight: 1.0 },
17
- ],
18
- short_play: [
19
- { ruleType: 'short_segment', params: { maxDurationSeconds: 3 }, weight: 0.6 },
20
- { ruleType: 'segment_transition', params: { field: 'subjects' }, weight: 0.4 },
21
- ],
22
- };
23
-
24
- export async function run(
25
- input: Record<string, unknown>,
26
- context: ToolContext,
27
- ): Promise<ToolExecutionResult> {
28
- const assetId = input.asset_id as string | undefined;
29
- if (!assetId) {
30
- return { content: 'asset_id is required.', isError: true };
31
- }
32
-
33
- const eventType = input.event_type as string | undefined;
34
- if (!eventType) {
35
- return { content: 'event_type is required.', isError: true };
36
- }
37
-
38
- // Parse detection rules: use provided rules or fall back to defaults
39
- let rules: DetectionRule[];
40
- const rawRules = input.detection_rules;
41
-
42
- if (rawRules) {
43
- // Accept rules as a JSON string or as an already-parsed array
44
- if (typeof rawRules === 'string') {
45
- try {
46
- const parsed = JSON.parse(rawRules);
47
- if (!Array.isArray(parsed)) {
48
- return { content: 'detection_rules must be a valid JSON array of rule objects.', isError: true };
49
- }
50
- rules = parsed as DetectionRule[];
51
- } catch {
52
- return { content: 'detection_rules must be a valid JSON array of rule objects.', isError: true };
53
- }
54
- } else if (Array.isArray(rawRules)) {
55
- rules = rawRules as DetectionRule[];
56
- } else {
57
- return { content: 'detection_rules must be an array of rule objects.', isError: true };
58
- }
59
-
60
- // Validate each rule has the required shape
61
- for (const rule of rules) {
62
- if (!rule.ruleType || typeof rule.ruleType !== 'string') {
63
- return { content: 'Each detection rule must have a "ruleType" string.', isError: true };
64
- }
65
- if (rule.weight === undefined || typeof rule.weight !== 'number') {
66
- return { content: 'Each detection rule must have a "weight" number.', isError: true };
67
- }
68
- if (!rule.params || typeof rule.params !== 'object') {
69
- return { content: 'Each detection rule must have a "params" object.', isError: true };
70
- }
71
- }
72
- } else {
73
- // Use defaults for known event types, or a generic transition-based fallback
74
- rules = DEFAULT_RULES_BY_EVENT_TYPE[eventType] ?? [
75
- { ruleType: 'segment_transition', params: { field: 'segmentType' }, weight: 0.6 },
76
- { ruleType: 'short_segment', params: { maxDurationSeconds: 5 }, weight: 0.4 },
77
- ];
78
- }
79
-
80
- const config: DetectionConfig = { eventType, rules };
81
-
82
- try {
83
- const result = detectEvents(assetId, config, {
84
- onProgress: (msg) => context.onOutput?.(`${msg}\n`),
85
- });
86
-
87
- return {
88
- content: JSON.stringify({
89
- message: `Detected ${result.candidateCount} ${result.eventType} events`,
90
- assetId: result.assetId,
91
- eventType: result.eventType,
92
- totalEvents: result.candidateCount,
93
- rulesUsed: rules.map((r) => r.ruleType),
94
- events: result.events.map((e) => ({
95
- id: e.id,
96
- startTime: e.startTime,
97
- endTime: e.endTime,
98
- confidence: e.confidence,
99
- reasons: e.reasons,
100
- })),
101
- }, null, 2),
102
- isError: false,
103
- };
104
- } catch (err) {
105
- return {
106
- content: `Event detection failed: ${(err as Error).message}`,
107
- isError: true,
108
- };
109
- }
110
- }
@@ -1,235 +0,0 @@
1
- /**
2
- * Recalibration tool for media event detection.
3
- *
4
- * Reads all feedback for an asset, analyzes correction patterns, and
5
- * re-ranks existing events using updated heuristics. Updates confidence
6
- * scores in the media_events table.
7
- *
8
- * All interfaces are generic — works for any event type.
9
- */
10
-
11
- import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
12
- import { getFeedbackForAsset, type EventFeedback } from '../services/feedback-store.js';
13
- import { aggregateFeedback } from '../services/feedback-aggregation.js';
14
- import { getEventsForAsset, getMediaAssetById } from '../../../../memory/media-store.js';
15
- import { getDb } from '../../../../memory/db.js';
16
- import { mediaEvents } from '../../../../memory/schema.js';
17
- import { eq } from 'drizzle-orm';
18
-
19
- // ---------------------------------------------------------------------------
20
- // Types
21
- // ---------------------------------------------------------------------------
22
-
23
- interface RecalibrationAdjustment {
24
- eventType: string;
25
- action: string;
26
- detail: string;
27
- }
28
-
29
- interface EventUpdate {
30
- eventId: string;
31
- eventType: string;
32
- oldConfidence: number;
33
- newConfidence: number;
34
- }
35
-
36
- // ---------------------------------------------------------------------------
37
- // Tool entry point
38
- // ---------------------------------------------------------------------------
39
-
40
- export async function run(
41
- input: Record<string, unknown>,
42
- context: ToolContext,
43
- ): Promise<ToolExecutionResult> {
44
- const assetId = input.asset_id as string | undefined;
45
- if (!assetId) {
46
- return { content: 'asset_id is required.', isError: true };
47
- }
48
-
49
- const asset = getMediaAssetById(assetId);
50
- if (!asset) {
51
- return { content: `Asset "${assetId}" not found.`, isError: true };
52
- }
53
-
54
- const allFeedback = getFeedbackForAsset(assetId);
55
- if (allFeedback.length === 0) {
56
- return {
57
- content: JSON.stringify({
58
- message: 'No feedback found for this asset. Submit feedback first, then recalibrate.',
59
- assetId,
60
- }, null, 2),
61
- isError: false,
62
- };
63
- }
64
-
65
- const aggregation = aggregateFeedback(assetId);
66
- const allEvents = getEventsForAsset(assetId);
67
-
68
- // Build a map of event ID to its feedback entries
69
- const feedbackByEventId = new Map<string, EventFeedback[]>();
70
- for (const fb of allFeedback) {
71
- if (!feedbackByEventId.has(fb.eventId)) {
72
- feedbackByEventId.set(fb.eventId, []);
73
- }
74
- feedbackByEventId.get(fb.eventId)!.push(fb);
75
- }
76
-
77
- // Build a map of event ID to event type for filtering feedback by type
78
- const eventTypeById = new Map<string, string>();
79
- for (const ev of allEvents) {
80
- eventTypeById.set(ev.id, ev.eventType);
81
- }
82
-
83
- const adjustments: RecalibrationAdjustment[] = [];
84
- const eventUpdates: EventUpdate[] = [];
85
- const db = getDb();
86
-
87
- // Analyze patterns per event type
88
- for (const stats of aggregation.statsByEventType) {
89
- const { eventType, correct, incorrect, boundaryEdit, missed } = stats;
90
- const totalReviewed = correct + incorrect + boundaryEdit + missed;
91
- if (totalReviewed === 0) continue;
92
-
93
- // Pattern 1: High false positive rate — penalize low-confidence events
94
- const falsePositiveRate = totalReviewed > 0 ? incorrect / totalReviewed : 0;
95
- if (falsePositiveRate > 0.3 && incorrect >= 2) {
96
- adjustments.push({
97
- eventType,
98
- action: 'penalize_low_confidence',
99
- detail: `False positive rate ${(falsePositiveRate * 100).toFixed(1)}% (${incorrect}/${totalReviewed}) — reducing confidence on unreviewed events of this type`,
100
- });
101
- }
102
-
103
- // Pattern 2: Many missed events — note for threshold adjustment
104
- if (missed >= 2) {
105
- adjustments.push({
106
- eventType,
107
- action: 'note_missed_events',
108
- detail: `${missed} missed events reported — consider lowering detection threshold or adding detection rules for this type`,
109
- });
110
- }
111
-
112
- // Pattern 3: Boundary edits — compute average adjustment
113
- if (boundaryEdit >= 1) {
114
- const boundaryFeedback = allFeedback.filter(
115
- (fb) => fb.feedbackType === 'boundary_edit' && eventTypeById.get(fb.eventId) === eventType,
116
- );
117
- let startAdjTotal = 0;
118
- let endAdjTotal = 0;
119
- let startAdjCount = 0;
120
- let endAdjCount = 0;
121
-
122
- for (const fb of boundaryFeedback) {
123
- if (fb.originalStartTime !== null && fb.correctedStartTime !== null) {
124
- startAdjTotal += fb.correctedStartTime - fb.originalStartTime;
125
- startAdjCount++;
126
- }
127
- if (fb.originalEndTime !== null && fb.correctedEndTime !== null) {
128
- endAdjTotal += fb.correctedEndTime - fb.originalEndTime;
129
- endAdjCount++;
130
- }
131
- }
132
-
133
- const avgStartAdj = startAdjCount > 0 ? startAdjTotal / startAdjCount : 0;
134
- const avgEndAdj = endAdjCount > 0 ? endAdjTotal / endAdjCount : 0;
135
-
136
- if (startAdjCount > 0 || endAdjCount > 0) {
137
- adjustments.push({
138
- eventType,
139
- action: 'boundary_correction_pattern',
140
- detail: `Average boundary adjustment: start ${avgStartAdj >= 0 ? '+' : ''}${avgStartAdj.toFixed(2)}s (n=${startAdjCount}), end ${avgEndAdj >= 0 ? '+' : ''}${avgEndAdj.toFixed(2)}s (n=${endAdjCount})`,
141
- });
142
- }
143
- }
144
- }
145
-
146
- // Re-rank events: adjust confidence based on feedback
147
- for (const event of allEvents) {
148
- const eventFeedback = feedbackByEventId.get(event.id);
149
- if (!eventFeedback || eventFeedback.length === 0) {
150
- // For events without direct feedback, apply type-level adjustments
151
- const stats = aggregation.statsByEventType.find((s) => s.eventType === event.eventType);
152
- if (stats) {
153
- const totalReviewed = stats.correct + stats.incorrect + stats.boundaryEdit + stats.missed;
154
- const falsePositiveRate = totalReviewed > 0 ? stats.incorrect / totalReviewed : 0;
155
-
156
- // If high false positive rate for this type, reduce unreviewed event confidence
157
- if (falsePositiveRate > 0.3 && totalReviewed >= 3) {
158
- const penalty = Math.min(falsePositiveRate * 0.3, 0.2);
159
- const newConfidence = Math.max(0.05, event.confidence - penalty);
160
- if (newConfidence !== event.confidence) {
161
- db.update(mediaEvents)
162
- .set({ confidence: newConfidence })
163
- .where(eq(mediaEvents.id, event.id))
164
- .run();
165
- eventUpdates.push({
166
- eventId: event.id,
167
- eventType: event.eventType,
168
- oldConfidence: event.confidence,
169
- newConfidence,
170
- });
171
- }
172
- }
173
- }
174
- continue;
175
- }
176
-
177
- // Direct feedback: adjust confidence based on the latest feedback
178
- const latestFeedback = eventFeedback.sort((a, b) => b.createdAt - a.createdAt)[0];
179
- let newConfidence = event.confidence;
180
-
181
- switch (latestFeedback.feedbackType) {
182
- case 'correct':
183
- // Boost confidence toward 1.0
184
- newConfidence = Math.min(1.0, event.confidence + (1.0 - event.confidence) * 0.3);
185
- break;
186
- case 'incorrect':
187
- // Sharply reduce confidence
188
- newConfidence = Math.max(0.05, event.confidence * 0.3);
189
- break;
190
- case 'boundary_edit':
191
- // Slight confidence boost (event was real but boundaries were off)
192
- newConfidence = Math.min(1.0, event.confidence + (1.0 - event.confidence) * 0.15);
193
- break;
194
- case 'missed':
195
- // User-reported events keep their initial confidence
196
- break;
197
- }
198
-
199
- newConfidence = Math.round(newConfidence * 1000) / 1000;
200
-
201
- if (newConfidence !== event.confidence) {
202
- db.update(mediaEvents)
203
- .set({ confidence: newConfidence })
204
- .where(eq(mediaEvents.id, event.id))
205
- .run();
206
- eventUpdates.push({
207
- eventId: event.id,
208
- eventType: event.eventType,
209
- oldConfidence: event.confidence,
210
- newConfidence,
211
- });
212
- }
213
- }
214
-
215
- context.onOutput?.(`Recalibrated ${eventUpdates.length} events based on ${allFeedback.length} feedback entries.\n`);
216
-
217
- return {
218
- content: JSON.stringify({
219
- message: `Recalibration complete for asset ${assetId}`,
220
- assetId,
221
- totalFeedbackEntries: allFeedback.length,
222
- adjustments,
223
- eventsUpdated: eventUpdates.length,
224
- eventUpdates: eventUpdates.map((u) => ({
225
- eventId: u.eventId,
226
- eventType: u.eventType,
227
- oldConfidence: u.oldConfidence,
228
- newConfidence: u.newConfidence,
229
- delta: Math.round((u.newConfidence - u.oldConfidence) * 1000) / 1000,
230
- })),
231
- aggregation: aggregation.statsByEventType,
232
- }, null, 2),
233
- isError: false,
234
- };
235
- }