@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.
- package/README.md +51 -0
- package/eslint.config.mjs +31 -0
- package/package.json +1 -1
- package/scripts/ipc/check-swift-decoder-drift.ts +4 -1
- package/scripts/ipc/generate-swift.ts +18 -2
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +338 -1
- package/src/__tests__/approval-conversation-turn.test.ts +214 -0
- package/src/__tests__/browser-manager.test.ts +1 -0
- package/src/__tests__/call-conversation-messages.test.ts +130 -0
- package/src/__tests__/call-orchestrator.test.ts +752 -271
- package/src/__tests__/call-pointer-messages.test.ts +148 -0
- package/src/__tests__/call-recovery.test.ts +3 -0
- package/src/__tests__/call-routes-http.test.ts +5 -0
- package/src/__tests__/call-store.test.ts +3 -0
- package/src/__tests__/channel-approval-routes.test.ts +1260 -85
- package/src/__tests__/channel-approval.test.ts +37 -0
- package/src/__tests__/channel-approvals.test.ts +4 -65
- package/src/__tests__/channel-guardian.test.ts +556 -0
- package/src/__tests__/channel-readiness-service.test.ts +74 -7
- package/src/__tests__/checker.test.ts +14 -7
- package/src/__tests__/clarification-resolver.test.ts +44 -24
- package/src/__tests__/commit-message-enrichment-service.test.ts +9 -4
- package/src/__tests__/computer-use-session-working-dir.test.ts +8 -0
- package/src/__tests__/config-schema.test.ts +12 -7
- package/src/__tests__/context-window-manager.test.ts +30 -2
- package/src/__tests__/contradiction-checker.test.ts +20 -5
- package/src/__tests__/credential-security-invariants.test.ts +6 -2
- package/src/__tests__/db-migration-rollback.test.ts +752 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -0
- package/src/__tests__/fuzzy-match-property.test.ts +5 -5
- package/src/__tests__/guardian-action-store.test.ts +123 -0
- package/src/__tests__/guardian-action-sweep.test.ts +277 -0
- package/src/__tests__/guardian-dispatch.test.ts +389 -0
- package/src/__tests__/guardian-question-copy.test.ts +47 -0
- package/src/__tests__/handlers-telegram-config.test.ts +4 -2
- package/src/__tests__/handlers-twilio-config.test.ts +126 -0
- package/src/__tests__/intent-routing.test.ts +2 -0
- package/src/__tests__/ipc-snapshot.test.ts +228 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +828 -0
- package/src/__tests__/model-intents.test.ts +96 -0
- package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +42 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +130 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +89 -13
- package/src/__tests__/provider-error-scenarios.test.ts +621 -0
- package/src/__tests__/provider-fail-open-selection.test.ts +119 -0
- package/src/__tests__/qdrant-manager.test.ts +27 -20
- package/src/__tests__/relay-server.test.ts +779 -40
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +2 -0
- package/src/__tests__/run-orchestrator.test.ts +20 -4
- package/src/__tests__/runtime-runs-http.test.ts +17 -1
- package/src/__tests__/runtime-runs.test.ts +16 -0
- package/src/__tests__/schedule-store.test.ts +18 -4
- package/src/__tests__/scheduler-recurrence.test.ts +13 -4
- package/src/__tests__/session-abort-tool-results.test.ts +6 -0
- package/src/__tests__/session-agent-loop.test.ts +857 -0
- package/src/__tests__/session-conflict-gate.test.ts +6 -0
- package/src/__tests__/session-pre-run-repair.test.ts +6 -0
- package/src/__tests__/session-profile-injection.test.ts +6 -0
- package/src/__tests__/session-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/session-queue.test.ts +6 -0
- package/src/__tests__/session-runtime-assembly.test.ts +237 -13
- package/src/__tests__/session-slash-known.test.ts +6 -0
- package/src/__tests__/session-slash-queue.test.ts +6 -0
- package/src/__tests__/session-slash-unknown.test.ts +6 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +2 -0
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -0
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -0
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -0
- package/src/__tests__/session-workspace-injection.test.ts +6 -0
- package/src/__tests__/session-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/skills.test.ts +2 -0
- package/src/__tests__/sms-messaging-provider.test.ts +2 -1
- package/src/__tests__/starter-task-flow.test.ts +2 -0
- package/src/__tests__/swarm-dag-pathological.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +2 -0
- package/src/__tests__/task-management-tools.test.ts +2 -2
- package/src/__tests__/task-runner.test.ts +14 -4
- package/src/__tests__/terminal-tools.test.ts +25 -19
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +545 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +11 -11
- package/src/__tests__/tool-executor.test.ts +23 -24
- package/src/__tests__/trust-store.test.ts +3 -3
- package/src/__tests__/twilio-rest.test.ts +29 -0
- package/src/__tests__/twilio-routes-elevenlabs.test.ts +3 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +11 -0
- package/src/__tests__/twilio-routes.test.ts +141 -21
- package/src/__tests__/user-reference.test.ts +2 -0
- package/src/__tests__/voice-quality.test.ts +222 -0
- package/src/__tests__/web-search.test.ts +45 -29
- package/src/agent/loop.ts +1 -1
- package/src/agent-heartbeat/agent-heartbeat-service.ts +2 -10
- package/src/amazon/client.ts +1418 -0
- package/src/amazon/request-extractor.ts +135 -0
- package/src/amazon/session.ts +109 -0
- package/src/autonomy/autonomy-store.ts +5 -5
- package/src/browser-extension-relay/client.ts +124 -0
- package/src/browser-extension-relay/protocol.ts +63 -0
- package/src/browser-extension-relay/server.ts +177 -0
- package/src/bundler/app-bundler.ts +3 -3
- package/src/bundler/bundle-signer.ts +1 -1
- package/src/bundler/signature-verifier.ts +1 -1
- package/src/calls/call-conversation-messages.ts +33 -0
- package/src/calls/call-domain.ts +106 -5
- package/src/calls/call-orchestrator.ts +252 -54
- package/src/calls/call-pointer-messages.ts +53 -0
- package/src/calls/call-recovery.ts +3 -8
- package/src/calls/call-store.ts +69 -87
- package/src/calls/elevenlabs-config.ts +3 -2
- package/src/calls/guardian-action-sweep.ts +105 -0
- package/src/calls/guardian-dispatch.ts +203 -0
- package/src/calls/guardian-question-copy.ts +133 -0
- package/src/calls/relay-server.ts +466 -8
- package/src/calls/speaker-identification.ts +1 -1
- package/src/calls/twilio-config.ts +7 -5
- package/src/calls/twilio-provider.ts +6 -4
- package/src/calls/twilio-rest.ts +40 -15
- package/src/calls/twilio-routes.ts +60 -45
- package/src/calls/types.ts +3 -1
- package/src/channels/types.ts +25 -0
- package/src/cli/amazon.ts +815 -0
- package/src/cli/config-commands.ts +2 -2
- package/src/cli/core-commands.ts +4 -3
- package/src/cli/influencer.ts +244 -0
- package/src/cli/map.ts +89 -6
- package/src/cli.ts +1 -1
- package/src/config/agent-schema.ts +171 -0
- package/src/config/bundled-skills/amazon/SKILL.md +127 -0
- package/src/config/bundled-skills/amazon/icon.svg +13 -0
- package/src/config/bundled-skills/api-mapping/SKILL.md +78 -0
- package/src/config/bundled-skills/browser/SKILL.md +1 -0
- package/src/config/bundled-skills/browser/TOOLS.json +17 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +25 -0
- package/src/config/bundled-skills/doordash/SKILL.md +51 -51
- package/src/config/bundled-skills/email-setup/SKILL.md +14 -5
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +183 -0
- package/src/config/bundled-skills/influencer/SKILL.md +144 -0
- package/src/config/bundled-skills/macos-automation/icon.svg +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +72 -95
- package/src/config/bundled-skills/media-processing/TOOLS.json +57 -147
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +77 -0
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +69 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +303 -0
- package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +55 -0
- package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +86 -0
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +339 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +551 -0
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +7 -9
- package/src/config/bundled-skills/media-processing/services/reduce.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +88 -253
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +22 -153
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +28 -51
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +35 -270
- package/src/config/bundled-skills/messaging/SKILL.md +12 -2
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -7
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +2 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +86 -21
- package/src/config/bundled-skills/twitter/icon.svg +14 -0
- package/src/config/bundled-tool-registry.ts +310 -0
- package/src/config/calls-schema.ts +181 -0
- package/src/config/core-schema.ts +309 -0
- package/src/config/defaults.ts +27 -3
- package/src/config/env-registry.ts +169 -0
- package/src/config/env.ts +175 -0
- package/src/config/loader.ts +6 -6
- package/src/config/memory-schema.ts +528 -0
- package/src/config/sandbox-schema.ts +55 -0
- package/src/config/schema.ts +157 -1138
- package/src/config/skill-state.ts +1 -1
- package/src/config/skills-schema.ts +32 -0
- package/src/config/skills.ts +35 -24
- package/src/config/system-prompt.ts +107 -56
- package/src/config/templates/SOUL.md +1 -1
- package/src/config/types.ts +1 -0
- package/src/config/user-reference.ts +4 -9
- package/src/config/vellum-skills/catalog.json +0 -7
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +5 -1
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +1 -0
- package/src/config/vellum-skills/sms-setup/SKILL.md +112 -14
- package/src/context/window-manager.ts +27 -7
- package/src/daemon/approval-generators.ts +186 -0
- package/src/daemon/approved-devices-store.ts +140 -0
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/classifier.ts +35 -32
- package/src/daemon/config-watcher.ts +1 -1
- package/src/daemon/daemon-control.ts +254 -0
- package/src/daemon/handlers/apps.ts +2 -3
- package/src/daemon/handlers/config-channels.ts +158 -0
- package/src/daemon/handlers/config-inbox.ts +540 -0
- package/src/daemon/handlers/config-ingress.ts +231 -0
- package/src/daemon/handlers/config-integrations.ts +258 -0
- package/src/daemon/handlers/config-model.ts +143 -0
- package/src/daemon/handlers/config-parental.ts +163 -0
- package/src/daemon/handlers/config-scheduling.ts +172 -0
- package/src/daemon/handlers/config-slack.ts +92 -0
- package/src/daemon/handlers/config-telegram.ts +301 -0
- package/src/daemon/handlers/config-tools.ts +177 -0
- package/src/daemon/handlers/config-trust.ts +104 -0
- package/src/daemon/handlers/config-twilio.ts +1080 -0
- package/src/daemon/handlers/config.ts +53 -2463
- package/src/daemon/handlers/diagnostics.ts +1 -1
- package/src/daemon/handlers/dictation.ts +4 -6
- package/src/daemon/handlers/documents.ts +18 -32
- package/src/daemon/handlers/index.ts +9 -0
- package/src/daemon/handlers/misc.ts +3 -5
- package/src/daemon/handlers/pairing.ts +98 -0
- package/src/daemon/handlers/sessions.ts +74 -5
- package/src/daemon/handlers/shared.ts +3 -1
- package/src/daemon/handlers/skills.ts +1 -1
- package/src/daemon/handlers/twitter-auth.ts +2 -0
- package/src/daemon/handlers/work-items.ts +2 -2
- package/src/daemon/handlers/workspace-files.ts +4 -3
- package/src/daemon/install-cli-launchers.ts +113 -0
- package/src/daemon/ipc-contract/apps.ts +356 -0
- package/src/daemon/ipc-contract/browser.ts +74 -0
- package/src/daemon/ipc-contract/computer-use.ts +151 -0
- package/src/daemon/ipc-contract/diagnostics.ts +56 -0
- package/src/daemon/ipc-contract/documents.ts +74 -0
- package/src/daemon/ipc-contract/inbox.ts +209 -0
- package/src/daemon/ipc-contract/integrations.ts +284 -0
- package/src/daemon/ipc-contract/memory.ts +48 -0
- package/src/daemon/ipc-contract/messages.ts +211 -0
- package/src/daemon/ipc-contract/pairing.ts +45 -0
- package/src/daemon/ipc-contract/parental-control.ts +95 -0
- package/src/daemon/ipc-contract/schedules.ts +97 -0
- package/src/daemon/ipc-contract/sessions.ts +321 -0
- package/src/daemon/ipc-contract/shared.ts +42 -0
- package/src/daemon/ipc-contract/skills.ts +120 -0
- package/src/daemon/ipc-contract/subagents.ts +58 -0
- package/src/daemon/ipc-contract/surfaces.ts +250 -0
- package/src/daemon/ipc-contract/trust.ts +60 -0
- package/src/daemon/ipc-contract/work-items.ts +225 -0
- package/src/daemon/ipc-contract/workspace.ts +113 -0
- package/src/daemon/ipc-contract-inventory.json +62 -0
- package/src/daemon/ipc-contract-inventory.ts +55 -29
- package/src/daemon/ipc-contract.ts +227 -2527
- package/src/daemon/ipc-protocol.ts +1 -1
- package/src/daemon/ipc-validate.ts +7 -0
- package/src/daemon/lifecycle.ts +97 -379
- package/src/daemon/pairing-store.ts +177 -0
- package/src/daemon/providers-setup.ts +43 -0
- package/src/daemon/ride-shotgun-handler.ts +67 -2
- package/src/daemon/server.ts +60 -44
- package/src/daemon/session-agent-loop-handlers.ts +421 -0
- package/src/daemon/session-agent-loop.ts +113 -275
- package/src/daemon/session-dynamic-profile.ts +1 -1
- package/src/daemon/session-history.ts +1 -1
- package/src/daemon/session-media-retry.ts +1 -1
- package/src/daemon/session-messaging.ts +37 -2
- package/src/daemon/session-notifiers.ts +5 -25
- package/src/daemon/session-process.ts +99 -59
- package/src/daemon/session-queue-manager.ts +98 -4
- package/src/daemon/session-runtime-assembly.ts +149 -15
- package/src/daemon/session-surfaces.ts +26 -4
- package/src/daemon/session-tool-setup.ts +28 -30
- package/src/daemon/session-workspace.ts +1 -1
- package/src/daemon/session.ts +24 -1
- package/src/daemon/shutdown-handlers.ts +122 -0
- package/src/daemon/trace-emitter.ts +1 -1
- package/src/daemon/watch-handler.ts +36 -33
- package/src/doordash/cart-queries.ts +787 -0
- package/src/doordash/client.ts +144 -127
- package/src/doordash/order-queries.ts +85 -0
- package/src/doordash/queries.ts +10 -1308
- package/src/doordash/search-queries.ts +203 -0
- package/src/doordash/session.ts +3 -2
- package/src/doordash/store-queries.ts +246 -0
- package/src/doordash/types.ts +367 -0
- package/src/email/providers/agentmail.ts +2 -1
- package/src/email/providers/index.ts +3 -2
- package/src/email/service.ts +3 -2
- package/src/errors.ts +43 -0
- package/src/home-base/prebuilt/seed.ts +1 -1
- package/src/hooks/cli.ts +6 -5
- package/src/hooks/config.ts +6 -8
- package/src/hooks/discovery.ts +6 -5
- package/src/hooks/manager.ts +4 -3
- package/src/hooks/runner.ts +2 -2
- package/src/hooks/templates.ts +5 -5
- package/src/inbound/public-ingress-urls.ts +3 -1
- package/src/index.ts +4 -2
- package/src/influencer/client.ts +1104 -0
- package/src/instrument.ts +4 -3
- package/src/logfire.ts +4 -3
- package/src/memory/admin.ts +25 -35
- package/src/memory/attachments-store.ts +4 -7
- package/src/memory/channel-delivery-store.ts +30 -1
- package/src/memory/channel-guardian-store.ts +200 -1
- package/src/memory/clarification-resolver.ts +37 -33
- package/src/memory/conflict-store.ts +67 -61
- package/src/memory/contradiction-checker.ts +141 -117
- package/src/memory/conversation-store.ts +335 -51
- package/src/memory/db-connection.ts +27 -4
- package/src/memory/db-init.ts +121 -4
- package/src/memory/db.ts +14 -1
- package/src/memory/embedding-backend.ts +27 -5
- package/src/memory/embedding-ollama.ts +2 -1
- package/src/memory/entity-extractor.ts +38 -35
- package/src/memory/guardian-action-store.ts +430 -0
- package/src/memory/inbox-escalation-projection.ts +59 -0
- package/src/memory/inbox-thread-store.ts +218 -0
- package/src/memory/ingress-invite-store.ts +338 -0
- package/src/memory/ingress-member-store.ts +350 -0
- package/src/memory/items-extractor.ts +91 -97
- package/src/memory/job-handlers/index-maintenance.ts +3 -3
- package/src/memory/job-handlers/media-processing.ts +11 -42
- package/src/memory/job-handlers/summarization.ts +32 -26
- package/src/memory/job-utils.ts +3 -10
- package/src/memory/jobs-store.ts +6 -9
- package/src/memory/jobs-worker.ts +51 -36
- package/src/memory/migrations/001-job-deferrals.ts +45 -0
- package/src/memory/migrations/002-tool-invocations-fk.ts +43 -0
- package/src/memory/migrations/003-memory-fts-backfill.ts +24 -0
- package/src/memory/migrations/004-entity-relation-dedup.ts +87 -0
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +80 -0
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +62 -0
- package/src/memory/migrations/007-assistant-id-to-self.ts +254 -0
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +208 -0
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +83 -0
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +56 -0
- package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +63 -0
- package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +19 -0
- package/src/memory/migrations/013-guardian-action-tables.ts +68 -0
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +76 -0
- package/src/memory/migrations/015-drop-active-search-index.ts +27 -0
- package/src/memory/migrations/016-memory-segments-indexes.ts +11 -0
- package/src/memory/migrations/017-memory-items-indexes.ts +12 -0
- package/src/memory/migrations/018-remaining-table-indexes.ts +13 -0
- package/src/memory/migrations/index.ts +24 -0
- package/src/memory/migrations/registry.ts +79 -0
- package/src/memory/migrations/validate-migration-state.ts +69 -0
- package/src/memory/qdrant-manager.ts +49 -8
- package/src/memory/query-builder.ts +1 -1
- package/src/memory/raw-query.ts +119 -0
- package/src/memory/recall-cache.ts +4 -1
- package/src/memory/retriever.ts +163 -47
- package/src/memory/schema-migration.ts +25 -984
- package/src/memory/schema.ts +130 -7
- package/src/memory/search/entity.ts +10 -19
- package/src/memory/search/lexical.ts +81 -52
- package/src/memory/search/ranking.ts +21 -22
- package/src/memory/search/semantic.ts +157 -19
- package/src/memory/shared-app-links-store.ts +4 -5
- package/src/memory/validation.ts +19 -0
- package/src/messaging/draft-store.ts +5 -6
- package/src/messaging/providers/sms/adapter.ts +3 -6
- package/src/messaging/providers/telegram-bot/adapter.ts +2 -5
- package/src/messaging/providers/whatsapp/adapter.ts +136 -0
- package/src/messaging/providers/whatsapp/client.ts +67 -0
- package/src/messaging/style-analyzer.ts +5 -4
- package/src/messaging/thread-summarizer.ts +61 -69
- package/src/messaging/triage-engine.ts +62 -71
- package/src/migrations/config-merge.ts +53 -0
- package/src/migrations/data-layout.ts +68 -0
- package/src/migrations/data-merge.ts +33 -0
- package/src/migrations/hooks-merge.ts +90 -0
- package/src/migrations/index.ts +6 -0
- package/src/migrations/log.ts +23 -0
- package/src/migrations/skills-merge.ts +33 -0
- package/src/migrations/workspace-layout.ts +79 -0
- package/src/permissions/checker.ts +126 -11
- package/src/permissions/prompter.ts +14 -0
- package/src/permissions/shell-identity.ts +31 -1
- package/src/permissions/trust-store.ts +21 -1
- package/src/providers/anthropic/client.ts +4 -4
- package/src/providers/failover.ts +2 -2
- package/src/providers/model-intents.ts +70 -0
- package/src/providers/ollama/client.ts +2 -1
- package/src/providers/provider-send-message.ts +176 -0
- package/src/providers/registry.ts +71 -30
- package/src/providers/retry.ts +35 -1
- package/src/providers/types.ts +12 -1
- package/src/runtime/approval-conversation-turn.ts +97 -0
- package/src/runtime/approval-message-composer.ts +115 -5
- package/src/runtime/assistant-event-hub.ts +3 -1
- package/src/runtime/channel-approval-parser.ts +36 -2
- package/src/runtime/channel-approvals.ts +0 -21
- package/src/runtime/channel-guardian-service.ts +48 -7
- package/src/runtime/channel-readiness-service.ts +160 -34
- package/src/runtime/channel-readiness-types.ts +10 -4
- package/src/runtime/channel-retry-sweep.ts +184 -0
- package/src/runtime/guardian-context-resolver.ts +108 -0
- package/src/runtime/http-server.ts +289 -745
- package/src/runtime/http-types.ts +56 -3
- package/src/runtime/middleware/auth.ts +116 -0
- package/src/runtime/middleware/error-handler.ts +33 -0
- package/src/runtime/middleware/twilio-validation.ts +127 -0
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/call-routes.ts +49 -6
- package/src/runtime/routes/channel-delivery-routes.ts +170 -0
- package/src/runtime/routes/channel-guardian-routes.ts +1191 -0
- package/src/runtime/routes/channel-inbound-routes.ts +1152 -0
- package/src/runtime/routes/channel-route-shared.ts +144 -0
- package/src/runtime/routes/channel-routes.ts +32 -1634
- package/src/runtime/routes/conversation-routes.ts +50 -7
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/identity-routes.ts +126 -0
- package/src/runtime/routes/pairing-routes.ts +144 -0
- package/src/runtime/routes/run-routes.ts +15 -1
- package/src/runtime/run-orchestrator.ts +52 -34
- package/src/schedule/schedule-store.ts +36 -32
- package/src/schedule/scheduler.ts +3 -3
- package/src/security/encrypted-store.ts +5 -7
- package/src/security/oauth2.ts +45 -15
- package/src/security/parental-control-store.ts +183 -0
- package/src/security/secret-allowlist.ts +4 -3
- package/src/security/secret-scanner.ts +5 -5
- package/src/security/secure-keys.ts +1 -1
- package/src/security/token-manager.ts +3 -2
- package/src/services/vercel-deploy.ts +6 -2
- package/src/skills/tool-manifest.ts +3 -3
- package/src/skills/vellum-catalog-remote.ts +75 -16
- package/src/slack/slack-webhook.ts +2 -1
- package/src/swarm/orchestrator.ts +92 -1
- package/src/swarm/router-planner.ts +6 -9
- package/src/swarm/worker-prompts.ts +9 -12
- package/src/tasks/task-compiler.ts +19 -28
- package/src/tasks/task-runner.ts +1 -1
- package/src/tools/assets/search.ts +15 -14
- package/src/tools/browser/__tests__/auth-detector.test.ts +1 -0
- package/src/tools/browser/auto-navigate.ts +1 -0
- package/src/tools/browser/browser-execution.ts +13 -1
- package/src/tools/browser/browser-manager.ts +119 -4
- package/src/tools/browser/network-recorder.ts +5 -0
- package/src/tools/credentials/broker.ts +11 -2
- package/src/tools/credentials/metadata-store.ts +18 -14
- package/src/tools/credentials/post-connect-hooks.ts +61 -0
- package/src/tools/credentials/vault.ts +49 -23
- package/src/tools/executor.ts +80 -18
- package/src/tools/host-terminal/cli-discover.ts +1 -1
- package/src/tools/network/script-proxy/http-forwarder.ts +1 -1
- package/src/tools/network/script-proxy/mitm-handler.ts +1 -1
- package/src/tools/network/script-proxy/server.ts +1 -1
- package/src/tools/network/script-proxy/session-manager.ts +6 -5
- package/src/tools/network/web-fetch.ts +18 -2
- package/src/tools/network/web-search.ts +7 -3
- package/src/tools/reminder/reminder-store.ts +14 -15
- package/src/tools/schedule/create.ts +1 -0
- package/src/tools/schedule/list.ts +2 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +5 -7
- package/src/tools/skills/skill-script-runner.ts +24 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -0
- package/src/tools/tasks/work-item-enqueue.ts +2 -2
- package/src/tools/terminal/evaluate-typescript.ts +21 -12
- package/src/tools/terminal/parser.ts +50 -0
- package/src/tools/watcher/delete.ts +6 -0
- package/src/tools/weather/service.ts +1 -1
- package/src/twitter/client.ts +190 -24
- package/src/twitter/session.ts +4 -3
- package/src/util/clipboard.ts +1 -1
- package/src/util/errors.ts +65 -8
- package/src/util/fs.ts +40 -0
- package/src/util/json.ts +10 -0
- package/src/util/log-redact.ts +189 -0
- package/src/util/logger.ts +25 -18
- package/src/util/object.ts +3 -0
- package/src/util/platform.ts +72 -365
- package/src/util/pricing.ts +1 -1
- package/src/util/promise-guard.ts +1 -1
- package/src/util/retry.ts +19 -0
- package/src/util/row-mapper.ts +79 -0
- package/src/util/silently.ts +21 -0
- package/src/watcher/engine.ts +5 -1
- package/src/watcher/provider-types.ts +20 -0
- package/src/watcher/providers/github.ts +156 -0
- package/src/watcher/providers/gmail.ts +1 -0
- package/src/watcher/providers/google-calendar.ts +1 -0
- package/src/watcher/providers/linear.ts +460 -0
- package/src/watcher/providers/slack.ts +1 -0
- package/src/work-items/work-item-runner.ts +1 -1
- package/src/workspace/git-service.ts +1 -1
- package/src/workspace/provider-commit-message-generator.ts +51 -22
- package/src/__tests__/call-bridge.test.ts +0 -517
- package/src/__tests__/session-process-bridge.test.ts +0 -244
- package/src/calls/call-bridge.ts +0 -168
- package/src/config/bundled-skills/media-processing/services/capability-registry.ts +0 -137
- package/src/config/bundled-skills/media-processing/services/event-detection-service.ts +0 -280
- package/src/config/bundled-skills/media-processing/services/feedback-aggregation.ts +0 -144
- package/src/config/bundled-skills/media-processing/services/feedback-store.ts +0 -136
- package/src/config/bundled-skills/media-processing/services/retrieval-service.ts +0 -95
- package/src/config/bundled-skills/media-processing/services/timeline-service.ts +0 -267
- package/src/config/bundled-skills/media-processing/tools/detect-events.ts +0 -110
- package/src/config/bundled-skills/media-processing/tools/recalibrate.ts +0 -235
- package/src/config/bundled-skills/media-processing/tools/select-tracking-profile.ts +0 -142
- package/src/config/bundled-skills/media-processing/tools/submit-feedback.ts +0 -150
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +0 -199
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generic event detection service.
|
|
3
|
-
*
|
|
4
|
-
* Evaluates configurable detection rules against timeline segments and produces
|
|
5
|
-
* scored event candidates. The rule system is fully pluggable — callers supply
|
|
6
|
-
* a DetectionConfig that specifies which rules to evaluate and how to weight them.
|
|
7
|
-
*
|
|
8
|
-
* Example configurations (not hardcoded — these are passed in by the caller):
|
|
9
|
-
*
|
|
10
|
-
* Basketball turnovers:
|
|
11
|
-
* eventType: 'turnover'
|
|
12
|
-
* rules: [
|
|
13
|
-
* { ruleType: 'segment_transition', params: { field: 'subjects' }, weight: 0.5 },
|
|
14
|
-
* { ruleType: 'short_segment', params: { maxDurationSeconds: 5 }, weight: 0.3 },
|
|
15
|
-
* { ruleType: 'attribute_match', params: { field: 'actions', pattern: 'steal|turnover' }, weight: 0.2 },
|
|
16
|
-
* ]
|
|
17
|
-
*
|
|
18
|
-
* Scene changes:
|
|
19
|
-
* eventType: 'scene_change'
|
|
20
|
-
* rules: [
|
|
21
|
-
* { ruleType: 'segment_transition', params: { field: 'segmentType' }, weight: 1.0 },
|
|
22
|
-
* ]
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import {
|
|
26
|
-
getMediaAssetById,
|
|
27
|
-
getTimelineForAsset,
|
|
28
|
-
insertEventsBatch,
|
|
29
|
-
deleteEventsForAssetByType,
|
|
30
|
-
type MediaTimeline,
|
|
31
|
-
type MediaEvent,
|
|
32
|
-
} from '../../../../memory/media-store.js';
|
|
33
|
-
|
|
34
|
-
// ---------------------------------------------------------------------------
|
|
35
|
-
// Public types
|
|
36
|
-
// ---------------------------------------------------------------------------
|
|
37
|
-
|
|
38
|
-
export interface DetectionRule {
|
|
39
|
-
ruleType: string;
|
|
40
|
-
params: Record<string, unknown>;
|
|
41
|
-
weight: number;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface DetectionConfig {
|
|
45
|
-
eventType: string;
|
|
46
|
-
rules: DetectionRule[];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface EventCandidate {
|
|
50
|
-
startTime: number;
|
|
51
|
-
endTime: number;
|
|
52
|
-
confidence: number;
|
|
53
|
-
reasons: string[];
|
|
54
|
-
metadata: Record<string, unknown>;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface DetectionResult {
|
|
58
|
-
assetId: string;
|
|
59
|
-
eventType: string;
|
|
60
|
-
candidateCount: number;
|
|
61
|
-
events: MediaEvent[];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
// Rule evaluation
|
|
66
|
-
// ---------------------------------------------------------------------------
|
|
67
|
-
|
|
68
|
-
interface RuleMatch {
|
|
69
|
-
matched: boolean;
|
|
70
|
-
reason: string;
|
|
71
|
-
metadata?: Record<string, unknown>;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
type RuleEvaluator = (
|
|
75
|
-
segment: MediaTimeline,
|
|
76
|
-
prevSegment: MediaTimeline | null,
|
|
77
|
-
nextSegment: MediaTimeline | null,
|
|
78
|
-
params: Record<string, unknown>,
|
|
79
|
-
) => RuleMatch;
|
|
80
|
-
|
|
81
|
-
const RULE_EVALUATORS: Record<string, RuleEvaluator> = {
|
|
82
|
-
/**
|
|
83
|
-
* Fires when a specified field changes between adjacent segments.
|
|
84
|
-
* params.field: which attribute to compare ('subjects', 'segmentType', etc.)
|
|
85
|
-
*/
|
|
86
|
-
segment_transition: (segment, prevSegment, _next, params) => {
|
|
87
|
-
if (!prevSegment) return { matched: false, reason: '' };
|
|
88
|
-
const field = (params.field as string) ?? 'segmentType';
|
|
89
|
-
|
|
90
|
-
if (field === 'segmentType') {
|
|
91
|
-
const changed = segment.segmentType !== prevSegment.segmentType;
|
|
92
|
-
return {
|
|
93
|
-
matched: changed,
|
|
94
|
-
reason: changed
|
|
95
|
-
? `Segment type changed from "${prevSegment.segmentType}" to "${segment.segmentType}"`
|
|
96
|
-
: '',
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Compare attribute arrays (e.g., subjects)
|
|
101
|
-
const prevAttrs = prevSegment.attributes ?? {};
|
|
102
|
-
const currAttrs = segment.attributes ?? {};
|
|
103
|
-
const prevValues = new Set(Array.isArray(prevAttrs[field]) ? (prevAttrs[field] as string[]) : []);
|
|
104
|
-
const currValues = Array.isArray(currAttrs[field]) ? (currAttrs[field] as string[]) : [];
|
|
105
|
-
|
|
106
|
-
if (prevValues.size === 0 && currValues.length === 0) {
|
|
107
|
-
return { matched: false, reason: '' };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const overlap = currValues.filter((v) => prevValues.has(v)).length;
|
|
111
|
-
const unionSize = new Set([...prevValues, ...currValues]).size;
|
|
112
|
-
const similarity = unionSize > 0 ? overlap / unionSize : 0;
|
|
113
|
-
|
|
114
|
-
// A transition is detected when similarity drops below 50%
|
|
115
|
-
const changed = similarity < 0.5;
|
|
116
|
-
return {
|
|
117
|
-
matched: changed,
|
|
118
|
-
reason: changed
|
|
119
|
-
? `${field} changed between segments (similarity: ${(similarity * 100).toFixed(0)}%)`
|
|
120
|
-
: '',
|
|
121
|
-
metadata: changed ? { similarity, prevValues: [...prevValues], currValues } : undefined,
|
|
122
|
-
};
|
|
123
|
-
},
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Fires when a segment's duration is below a threshold.
|
|
127
|
-
* params.maxDurationSeconds: maximum segment duration to trigger (default: 5)
|
|
128
|
-
*/
|
|
129
|
-
short_segment: (segment, _prev, _next, params) => {
|
|
130
|
-
const maxDuration = (params.maxDurationSeconds as number) ?? 5;
|
|
131
|
-
const duration = segment.endTime - segment.startTime;
|
|
132
|
-
const matched = duration > 0 && duration <= maxDuration;
|
|
133
|
-
return {
|
|
134
|
-
matched,
|
|
135
|
-
reason: matched
|
|
136
|
-
? `Short segment (${duration.toFixed(1)}s <= ${maxDuration}s threshold)`
|
|
137
|
-
: '',
|
|
138
|
-
metadata: matched ? { duration } : undefined,
|
|
139
|
-
};
|
|
140
|
-
},
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Fires when a segment's attribute values match a regex pattern.
|
|
144
|
-
* params.field: which attribute array to search (default: 'actions')
|
|
145
|
-
* params.pattern: regex pattern to match against values
|
|
146
|
-
*/
|
|
147
|
-
attribute_match: (segment, _prev, _next, params) => {
|
|
148
|
-
const field = (params.field as string) ?? 'actions';
|
|
149
|
-
const pattern = params.pattern as string;
|
|
150
|
-
if (!pattern) return { matched: false, reason: 'No pattern specified' };
|
|
151
|
-
|
|
152
|
-
const attrs = segment.attributes ?? {};
|
|
153
|
-
const values = Array.isArray(attrs[field]) ? (attrs[field] as string[]) : [];
|
|
154
|
-
const regex = new RegExp(pattern, 'i');
|
|
155
|
-
const matchedValues = values.filter((v) => regex.test(v));
|
|
156
|
-
|
|
157
|
-
return {
|
|
158
|
-
matched: matchedValues.length > 0,
|
|
159
|
-
reason: matchedValues.length > 0
|
|
160
|
-
? `${field} matched pattern /${pattern}/: [${matchedValues.join(', ')}]`
|
|
161
|
-
: '',
|
|
162
|
-
metadata: matchedValues.length > 0 ? { matchedValues } : undefined,
|
|
163
|
-
};
|
|
164
|
-
},
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
// ---------------------------------------------------------------------------
|
|
168
|
-
// Main detection logic
|
|
169
|
-
// ---------------------------------------------------------------------------
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Detect events in a media asset's timeline using the provided configuration.
|
|
173
|
-
*
|
|
174
|
-
* For each timeline segment, evaluates all rules and computes a weighted
|
|
175
|
-
* confidence score. Segments where at least one rule matches are emitted
|
|
176
|
-
* as event candidates. Results are stored in the media_events table (previous
|
|
177
|
-
* events of the same type for this asset are replaced).
|
|
178
|
-
*/
|
|
179
|
-
export function detectEvents(
|
|
180
|
-
assetId: string,
|
|
181
|
-
config: DetectionConfig,
|
|
182
|
-
options?: { onProgress?: (message: string) => void },
|
|
183
|
-
): DetectionResult {
|
|
184
|
-
const onProgress = options?.onProgress;
|
|
185
|
-
|
|
186
|
-
const asset = getMediaAssetById(assetId);
|
|
187
|
-
if (!asset) {
|
|
188
|
-
throw new Error(`Media asset not found: ${assetId}`);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const segments = getTimelineForAsset(assetId);
|
|
192
|
-
if (segments.length === 0) {
|
|
193
|
-
throw new Error('No timeline segments found. Run timeline generation first.');
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Sort segments by start time
|
|
197
|
-
const sorted = [...segments].sort((a, b) => a.startTime - b.startTime);
|
|
198
|
-
|
|
199
|
-
onProgress?.(`Evaluating ${config.rules.length} detection rules against ${sorted.length} segments...`);
|
|
200
|
-
|
|
201
|
-
// Normalize weights so they sum to 1
|
|
202
|
-
const totalWeight = config.rules.reduce((sum, r) => sum + r.weight, 0);
|
|
203
|
-
const normalizedRules = totalWeight > 0
|
|
204
|
-
? config.rules.map((r) => ({ ...r, weight: r.weight / totalWeight }))
|
|
205
|
-
: config.rules;
|
|
206
|
-
|
|
207
|
-
const candidates: EventCandidate[] = [];
|
|
208
|
-
|
|
209
|
-
for (let i = 0; i < sorted.length; i++) {
|
|
210
|
-
const segment = sorted[i];
|
|
211
|
-
const prev = i > 0 ? sorted[i - 1] : null;
|
|
212
|
-
const next = i < sorted.length - 1 ? sorted[i + 1] : null;
|
|
213
|
-
|
|
214
|
-
let weightedScore = 0;
|
|
215
|
-
const reasons: string[] = [];
|
|
216
|
-
const candidateMetadata: Record<string, unknown> = {};
|
|
217
|
-
let anyMatched = false;
|
|
218
|
-
|
|
219
|
-
for (const rule of normalizedRules) {
|
|
220
|
-
const evaluator = RULE_EVALUATORS[rule.ruleType];
|
|
221
|
-
if (!evaluator) {
|
|
222
|
-
reasons.push(`Unknown rule type: ${rule.ruleType}`);
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const result = evaluator(segment, prev, next, rule.params);
|
|
227
|
-
if (result.matched) {
|
|
228
|
-
anyMatched = true;
|
|
229
|
-
weightedScore += rule.weight;
|
|
230
|
-
reasons.push(result.reason);
|
|
231
|
-
if (result.metadata) {
|
|
232
|
-
candidateMetadata[rule.ruleType] = result.metadata;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (anyMatched) {
|
|
238
|
-
candidates.push({
|
|
239
|
-
startTime: segment.startTime,
|
|
240
|
-
endTime: segment.endTime,
|
|
241
|
-
confidence: Math.min(weightedScore, 1),
|
|
242
|
-
reasons,
|
|
243
|
-
metadata: {
|
|
244
|
-
segmentId: segment.id,
|
|
245
|
-
segmentType: segment.segmentType,
|
|
246
|
-
...candidateMetadata,
|
|
247
|
-
},
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Sort by confidence descending
|
|
253
|
-
candidates.sort((a, b) => b.confidence - a.confidence);
|
|
254
|
-
|
|
255
|
-
onProgress?.(`Found ${candidates.length} event candidates. Storing results...`);
|
|
256
|
-
|
|
257
|
-
// Replace existing events of this type for the asset (scoped to eventType)
|
|
258
|
-
deleteEventsForAssetByType(assetId, config.eventType);
|
|
259
|
-
|
|
260
|
-
const eventRows = candidates.map((c) => ({
|
|
261
|
-
assetId,
|
|
262
|
-
eventType: config.eventType,
|
|
263
|
-
startTime: c.startTime,
|
|
264
|
-
endTime: c.endTime,
|
|
265
|
-
confidence: c.confidence,
|
|
266
|
-
reasons: c.reasons,
|
|
267
|
-
metadata: c.metadata,
|
|
268
|
-
}));
|
|
269
|
-
|
|
270
|
-
const events = eventRows.length > 0 ? insertEventsBatch(eventRows) : [];
|
|
271
|
-
|
|
272
|
-
onProgress?.(`Stored ${events.length} events.`);
|
|
273
|
-
|
|
274
|
-
return {
|
|
275
|
-
assetId,
|
|
276
|
-
eventType: config.eventType,
|
|
277
|
-
candidateCount: candidates.length,
|
|
278
|
-
events,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Feedback aggregation service for media events.
|
|
3
|
-
*
|
|
4
|
-
* Computes precision/recall estimates per event type based on user feedback,
|
|
5
|
-
* and provides structured JSON export for offline analysis.
|
|
6
|
-
*
|
|
7
|
-
* All interfaces are generic — works for any event type.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { getFeedbackForAsset, type EventFeedback } from './feedback-store.js';
|
|
11
|
-
import { getEventsForAsset } from '../../../../memory/media-store.js';
|
|
12
|
-
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
// Types
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
|
|
17
|
-
export interface EventTypeStats {
|
|
18
|
-
eventType: string;
|
|
19
|
-
totalEvents: number;
|
|
20
|
-
correct: number;
|
|
21
|
-
incorrect: number;
|
|
22
|
-
boundaryEdit: number;
|
|
23
|
-
missed: number;
|
|
24
|
-
totalFeedback: number;
|
|
25
|
-
precision: number | null;
|
|
26
|
-
recall: number | null;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface AggregationResult {
|
|
30
|
-
assetId: string;
|
|
31
|
-
totalFeedbackEntries: number;
|
|
32
|
-
statsByEventType: EventTypeStats[];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface FeedbackExport {
|
|
36
|
-
assetId: string;
|
|
37
|
-
exportedAt: string;
|
|
38
|
-
totalEntries: number;
|
|
39
|
-
feedback: EventFeedback[];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// ---------------------------------------------------------------------------
|
|
43
|
-
// Aggregation
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Compute precision/recall estimates per event type for a given asset.
|
|
48
|
-
*
|
|
49
|
-
* precision = correct / (correct + incorrect)
|
|
50
|
-
* recall = (correct + boundary_edit) / (correct + boundary_edit + missed)
|
|
51
|
-
*
|
|
52
|
-
* Returns null for precision/recall when the denominator is zero.
|
|
53
|
-
*/
|
|
54
|
-
export function aggregateFeedback(assetId: string): AggregationResult {
|
|
55
|
-
const allFeedback = getFeedbackForAsset(assetId);
|
|
56
|
-
const allEvents = getEventsForAsset(assetId);
|
|
57
|
-
|
|
58
|
-
// Group feedback by event type — we need event type from the events table
|
|
59
|
-
const eventTypeById = new Map<string, string>();
|
|
60
|
-
for (const event of allEvents) {
|
|
61
|
-
eventTypeById.set(event.id, event.eventType);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Collect counts per event type
|
|
65
|
-
const countsMap = new Map<string, {
|
|
66
|
-
correct: number;
|
|
67
|
-
incorrect: number;
|
|
68
|
-
boundaryEdit: number;
|
|
69
|
-
missed: number;
|
|
70
|
-
totalEvents: number;
|
|
71
|
-
}>();
|
|
72
|
-
|
|
73
|
-
// Initialize with known event types from existing events
|
|
74
|
-
for (const event of allEvents) {
|
|
75
|
-
if (!countsMap.has(event.eventType)) {
|
|
76
|
-
countsMap.set(event.eventType, { correct: 0, incorrect: 0, boundaryEdit: 0, missed: 0, totalEvents: 0 });
|
|
77
|
-
}
|
|
78
|
-
countsMap.get(event.eventType)!.totalEvents++;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Tally feedback
|
|
82
|
-
for (const fb of allFeedback) {
|
|
83
|
-
const eventType = eventTypeById.get(fb.eventId);
|
|
84
|
-
if (!eventType) continue;
|
|
85
|
-
|
|
86
|
-
if (!countsMap.has(eventType)) {
|
|
87
|
-
countsMap.set(eventType, { correct: 0, incorrect: 0, boundaryEdit: 0, missed: 0, totalEvents: 0 });
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const counts = countsMap.get(eventType)!;
|
|
91
|
-
switch (fb.feedbackType) {
|
|
92
|
-
case 'correct':
|
|
93
|
-
counts.correct++;
|
|
94
|
-
break;
|
|
95
|
-
case 'incorrect':
|
|
96
|
-
counts.incorrect++;
|
|
97
|
-
break;
|
|
98
|
-
case 'boundary_edit':
|
|
99
|
-
counts.boundaryEdit++;
|
|
100
|
-
break;
|
|
101
|
-
case 'missed':
|
|
102
|
-
counts.missed++;
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const statsByEventType: EventTypeStats[] = [];
|
|
108
|
-
for (const [eventType, counts] of countsMap) {
|
|
109
|
-
const precisionDenom = counts.correct + counts.incorrect;
|
|
110
|
-
const recallDenom = counts.correct + counts.boundaryEdit + counts.missed;
|
|
111
|
-
|
|
112
|
-
statsByEventType.push({
|
|
113
|
-
eventType,
|
|
114
|
-
totalEvents: counts.totalEvents,
|
|
115
|
-
correct: counts.correct,
|
|
116
|
-
incorrect: counts.incorrect,
|
|
117
|
-
boundaryEdit: counts.boundaryEdit,
|
|
118
|
-
missed: counts.missed,
|
|
119
|
-
totalFeedback: counts.correct + counts.incorrect + counts.boundaryEdit + counts.missed,
|
|
120
|
-
precision: precisionDenom > 0 ? counts.correct / precisionDenom : null,
|
|
121
|
-
recall: recallDenom > 0 ? (counts.correct + counts.boundaryEdit) / recallDenom : null,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
assetId,
|
|
127
|
-
totalFeedbackEntries: allFeedback.length,
|
|
128
|
-
statsByEventType,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Export all feedback for an asset as structured JSON for offline analysis.
|
|
134
|
-
*/
|
|
135
|
-
export function exportFeedback(assetId: string): FeedbackExport {
|
|
136
|
-
const allFeedback = getFeedbackForAsset(assetId);
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
assetId,
|
|
140
|
-
exportedAt: new Date().toISOString(),
|
|
141
|
-
totalEntries: allFeedback.length,
|
|
142
|
-
feedback: allFeedback,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Feedback store service for media event corrections.
|
|
3
|
-
*
|
|
4
|
-
* Provides CRUD operations for the media_event_feedback table.
|
|
5
|
-
* All interfaces are generic — works for any event type, not just turnovers.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { and, eq } from 'drizzle-orm';
|
|
9
|
-
import { v4 as uuid } from 'uuid';
|
|
10
|
-
import { getDb } from '../../../../memory/db.js';
|
|
11
|
-
import { mediaEventFeedback } from '../../../../memory/schema.js';
|
|
12
|
-
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
// Types
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
|
|
17
|
-
export type FeedbackType = 'correct' | 'incorrect' | 'boundary_edit' | 'missed';
|
|
18
|
-
|
|
19
|
-
export interface EventFeedback {
|
|
20
|
-
id: string;
|
|
21
|
-
assetId: string;
|
|
22
|
-
eventId: string;
|
|
23
|
-
feedbackType: FeedbackType;
|
|
24
|
-
originalStartTime: number | null;
|
|
25
|
-
originalEndTime: number | null;
|
|
26
|
-
correctedStartTime: number | null;
|
|
27
|
-
correctedEndTime: number | null;
|
|
28
|
-
notes: string | null;
|
|
29
|
-
createdAt: number;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface SubmitFeedbackParams {
|
|
33
|
-
assetId: string;
|
|
34
|
-
eventId: string;
|
|
35
|
-
feedbackType: FeedbackType;
|
|
36
|
-
originalStartTime?: number;
|
|
37
|
-
originalEndTime?: number;
|
|
38
|
-
correctedStartTime?: number;
|
|
39
|
-
correctedEndTime?: number;
|
|
40
|
-
notes?: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
// Validation
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
|
|
47
|
-
const VALID_FEEDBACK_TYPES: FeedbackType[] = ['correct', 'incorrect', 'boundary_edit', 'missed'];
|
|
48
|
-
|
|
49
|
-
function isValidFeedbackType(type: string): type is FeedbackType {
|
|
50
|
-
return VALID_FEEDBACK_TYPES.includes(type as FeedbackType);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
// CRUD
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
|
|
57
|
-
export function submitFeedback(params: SubmitFeedbackParams): EventFeedback {
|
|
58
|
-
if (!isValidFeedbackType(params.feedbackType)) {
|
|
59
|
-
throw new Error(`Invalid feedback type "${params.feedbackType}". Must be one of: ${VALID_FEEDBACK_TYPES.join(', ')}`);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const db = getDb();
|
|
63
|
-
const now = Date.now();
|
|
64
|
-
const record = {
|
|
65
|
-
id: uuid(),
|
|
66
|
-
assetId: params.assetId,
|
|
67
|
-
eventId: params.eventId,
|
|
68
|
-
feedbackType: params.feedbackType,
|
|
69
|
-
originalStartTime: params.originalStartTime ?? null,
|
|
70
|
-
originalEndTime: params.originalEndTime ?? null,
|
|
71
|
-
correctedStartTime: params.correctedStartTime ?? null,
|
|
72
|
-
correctedEndTime: params.correctedEndTime ?? null,
|
|
73
|
-
notes: params.notes ?? null,
|
|
74
|
-
createdAt: now,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
db.insert(mediaEventFeedback).values(record).run();
|
|
78
|
-
|
|
79
|
-
return record;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function getFeedbackForAsset(assetId: string): EventFeedback[] {
|
|
83
|
-
const db = getDb();
|
|
84
|
-
const rows = db
|
|
85
|
-
.select()
|
|
86
|
-
.from(mediaEventFeedback)
|
|
87
|
-
.where(eq(mediaEventFeedback.assetId, assetId))
|
|
88
|
-
.all();
|
|
89
|
-
return rows.map(parseRow);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export function getFeedbackForEvent(eventId: string): EventFeedback[] {
|
|
93
|
-
const db = getDb();
|
|
94
|
-
const rows = db
|
|
95
|
-
.select()
|
|
96
|
-
.from(mediaEventFeedback)
|
|
97
|
-
.where(eq(mediaEventFeedback.eventId, eventId))
|
|
98
|
-
.all();
|
|
99
|
-
return rows.map(parseRow);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function getFeedbackByType(assetId: string, feedbackType: FeedbackType): EventFeedback[] {
|
|
103
|
-
if (!isValidFeedbackType(feedbackType)) {
|
|
104
|
-
throw new Error(`Invalid feedback type "${feedbackType}". Must be one of: ${VALID_FEEDBACK_TYPES.join(', ')}`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const db = getDb();
|
|
108
|
-
const rows = db
|
|
109
|
-
.select()
|
|
110
|
-
.from(mediaEventFeedback)
|
|
111
|
-
.where(and(
|
|
112
|
-
eq(mediaEventFeedback.assetId, assetId),
|
|
113
|
-
eq(mediaEventFeedback.feedbackType, feedbackType),
|
|
114
|
-
))
|
|
115
|
-
.all();
|
|
116
|
-
return rows.map(parseRow);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// ---------------------------------------------------------------------------
|
|
120
|
-
// Row parsing
|
|
121
|
-
// ---------------------------------------------------------------------------
|
|
122
|
-
|
|
123
|
-
function parseRow(row: typeof mediaEventFeedback.$inferSelect): EventFeedback {
|
|
124
|
-
return {
|
|
125
|
-
id: row.id,
|
|
126
|
-
assetId: row.assetId,
|
|
127
|
-
eventId: row.eventId,
|
|
128
|
-
feedbackType: row.feedbackType as FeedbackType,
|
|
129
|
-
originalStartTime: row.originalStartTime,
|
|
130
|
-
originalEndTime: row.originalEndTime,
|
|
131
|
-
correctedStartTime: row.correctedStartTime,
|
|
132
|
-
correctedEndTime: row.correctedEndTime,
|
|
133
|
-
notes: row.notes,
|
|
134
|
-
createdAt: row.createdAt,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generic media event retrieval service.
|
|
3
|
-
*
|
|
4
|
-
* Pure data retrieval with configurable filters and ranking — no
|
|
5
|
-
* domain-specific logic. Callers (e.g. a query tool) are responsible
|
|
6
|
-
* for translating domain concepts into filter parameters.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
getEventsForAsset,
|
|
11
|
-
type MediaEvent,
|
|
12
|
-
} from '../../../../memory/media-store.js';
|
|
13
|
-
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Types
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
export interface RetrievalFilters {
|
|
19
|
-
/** Scope results to a specific media asset. */
|
|
20
|
-
assetId?: string;
|
|
21
|
-
/** Filter by event type label. */
|
|
22
|
-
eventType?: string;
|
|
23
|
-
/** Minimum confidence threshold (0–1). */
|
|
24
|
-
minConfidence?: number;
|
|
25
|
-
/** Maximum number of results to return. */
|
|
26
|
-
limit?: number;
|
|
27
|
-
/** Sort order for results. */
|
|
28
|
-
sortBy?: 'confidence' | 'startTime';
|
|
29
|
-
/** Only return events that start at or after this time (seconds). */
|
|
30
|
-
startTimeMin?: number;
|
|
31
|
-
/** Only return events that start at or before this time (seconds). */
|
|
32
|
-
startTimeMax?: number;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface RetrievalResult {
|
|
36
|
-
events: MediaEvent[];
|
|
37
|
-
totalReturned: number;
|
|
38
|
-
filters: RetrievalFilters;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
|
-
// Retrieval
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Query the media_events table with the given filters and return ranked
|
|
47
|
-
* results with full event metadata.
|
|
48
|
-
*
|
|
49
|
-
* When `assetId` is not provided the function returns an empty result set
|
|
50
|
-
* because the underlying store requires an asset scope. Callers that want
|
|
51
|
-
* cross-asset queries should iterate over asset IDs externally.
|
|
52
|
-
*/
|
|
53
|
-
export function retrieveEvents(filters: RetrievalFilters): RetrievalResult {
|
|
54
|
-
const {
|
|
55
|
-
assetId,
|
|
56
|
-
eventType,
|
|
57
|
-
minConfidence,
|
|
58
|
-
limit = 10,
|
|
59
|
-
sortBy = 'confidence',
|
|
60
|
-
startTimeMin,
|
|
61
|
-
startTimeMax,
|
|
62
|
-
} = filters;
|
|
63
|
-
|
|
64
|
-
if (!assetId) {
|
|
65
|
-
return { events: [], totalReturned: 0, filters };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Fetch from the store with the subset of filters it supports natively
|
|
69
|
-
let events = getEventsForAsset(assetId, {
|
|
70
|
-
eventType,
|
|
71
|
-
minConfidence,
|
|
72
|
-
sortBy,
|
|
73
|
-
// Fetch more than needed so we can apply time-range filtering locally
|
|
74
|
-
limit: startTimeMin !== undefined || startTimeMax !== undefined ? undefined : limit,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Apply time-range filters that the store doesn't support directly
|
|
78
|
-
if (startTimeMin !== undefined) {
|
|
79
|
-
events = events.filter((e) => e.startTime >= startTimeMin);
|
|
80
|
-
}
|
|
81
|
-
if (startTimeMax !== undefined) {
|
|
82
|
-
events = events.filter((e) => e.startTime <= startTimeMax);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Re-apply limit after local filtering
|
|
86
|
-
if (limit && events.length > limit) {
|
|
87
|
-
events = events.slice(0, limit);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
events,
|
|
92
|
-
totalReturned: events.length,
|
|
93
|
-
filters,
|
|
94
|
-
};
|
|
95
|
-
}
|