@vellumai/assistant 0.3.5 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +26 -2
- package/src/config/env-registry.ts +162 -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 +156 -1137
- 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 +217 -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 +54 -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 +315 -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 +60 -0
- package/src/daemon/ipc-contract-inventory.ts +55 -29
- package/src/daemon/ipc-contract.ts +226 -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 +96 -4
- package/src/daemon/session-runtime-assembly.ts +149 -15
- package/src/daemon/session-surfaces.ts +19 -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 +10 -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 +160 -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 +119 -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/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 +275 -743
- 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 +143 -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 +10 -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 +68 -9
- 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 +19 -17
- 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
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reduce service — sends Map output to Claude as text-only for analysis.
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* - One-shot merge: assembles all Map results into a single document,
|
|
6
|
+
* sends to Claude with the provided system prompt for analysis.
|
|
7
|
+
* - Interactive Q&A: loads existing map output + user query, sends to
|
|
8
|
+
* Claude, returns the answer.
|
|
9
|
+
*
|
|
10
|
+
* Uses the existing provider infrastructure (getConfiguredProvider) so
|
|
11
|
+
* it works with whatever LLM provider is configured.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { readFile } from 'node:fs/promises';
|
|
15
|
+
import { join, dirname } from 'node:path';
|
|
16
|
+
import { getMediaAssetById } from '../../../../memory/media-store.js';
|
|
17
|
+
import {
|
|
18
|
+
getConfiguredProvider,
|
|
19
|
+
createTimeout,
|
|
20
|
+
extractAllText,
|
|
21
|
+
userMessage,
|
|
22
|
+
} from '../../../../providers/provider-send-message.js';
|
|
23
|
+
import type { MapOutput } from './gemini-map.js';
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Types
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
export interface ReduceOptions {
|
|
30
|
+
/** Natural language query about the video data. Optional for one-shot merge mode. */
|
|
31
|
+
query?: string;
|
|
32
|
+
/** Optional system prompt for Claude. */
|
|
33
|
+
systemPrompt?: string;
|
|
34
|
+
/** Model override. When omitted, the configured provider's default is used. */
|
|
35
|
+
model?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ReduceResult {
|
|
39
|
+
answer: string;
|
|
40
|
+
model: string;
|
|
41
|
+
inputTokens: number;
|
|
42
|
+
outputTokens: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Helpers
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
const REDUCE_TIMEOUT_MS = 120_000;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Load map-output.json for an asset from its pipeline directory.
|
|
53
|
+
*/
|
|
54
|
+
async function loadMapOutput(assetId: string): Promise<MapOutput> {
|
|
55
|
+
const asset = getMediaAssetById(assetId);
|
|
56
|
+
if (!asset) {
|
|
57
|
+
throw new Error(`Media asset not found: ${assetId}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const pipelineDir = join(dirname(asset.filePath), 'pipeline', assetId);
|
|
61
|
+
const mapOutputPath = join(pipelineDir, 'map-output.json');
|
|
62
|
+
|
|
63
|
+
let raw: string;
|
|
64
|
+
try {
|
|
65
|
+
raw = await readFile(mapOutputPath, 'utf-8');
|
|
66
|
+
} catch {
|
|
67
|
+
throw new Error(
|
|
68
|
+
'No map output found. Run analyze_keyframes first to generate map-output.json.',
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return JSON.parse(raw) as MapOutput;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Format map output segments into a text document for Claude.
|
|
77
|
+
* Strips image data — text only.
|
|
78
|
+
*/
|
|
79
|
+
function formatMapOutputAsText(mapOutput: MapOutput): string {
|
|
80
|
+
const lines: string[] = [];
|
|
81
|
+
|
|
82
|
+
lines.push(`Video Analysis Data (asset: ${mapOutput.assetId})`);
|
|
83
|
+
lines.push(`Model: ${mapOutput.model}`);
|
|
84
|
+
lines.push(`Segments analyzed: ${mapOutput.successCount}/${mapOutput.segmentCount}`);
|
|
85
|
+
if (mapOutput.failedCount > 0) {
|
|
86
|
+
lines.push(`Failed segments: ${mapOutput.failedCount}`);
|
|
87
|
+
}
|
|
88
|
+
if (mapOutput.skippedCount > 0) {
|
|
89
|
+
lines.push(`Skipped segments: ${mapOutput.skippedCount}`);
|
|
90
|
+
}
|
|
91
|
+
lines.push('');
|
|
92
|
+
lines.push('--- Segment Results ---');
|
|
93
|
+
lines.push('');
|
|
94
|
+
|
|
95
|
+
for (const segment of mapOutput.segments) {
|
|
96
|
+
const startMin = Math.floor(segment.startSeconds / 60);
|
|
97
|
+
const startSec = Math.floor(segment.startSeconds % 60);
|
|
98
|
+
const endMin = Math.floor(segment.endSeconds / 60);
|
|
99
|
+
const endSec = Math.floor(segment.endSeconds % 60);
|
|
100
|
+
const timeRange = `${startMin}:${String(startSec).padStart(2, '0')} - ${endMin}:${String(endSec).padStart(2, '0')}`;
|
|
101
|
+
|
|
102
|
+
lines.push(`[Segment ${segment.segmentId}] ${timeRange}`);
|
|
103
|
+
lines.push(JSON.stringify(segment.result, null, 2));
|
|
104
|
+
lines.push('');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return lines.join('\n');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// Core: send to Claude via provider infrastructure
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
async function sendToClaude(
|
|
115
|
+
mapText: string,
|
|
116
|
+
query: string,
|
|
117
|
+
systemPrompt?: string,
|
|
118
|
+
model?: string,
|
|
119
|
+
onProgress?: (msg: string) => void,
|
|
120
|
+
): Promise<ReduceResult> {
|
|
121
|
+
const provider = getConfiguredProvider();
|
|
122
|
+
if (!provider) {
|
|
123
|
+
throw new Error('No LLM provider available. Please configure an API key.');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const effectiveSystemPrompt = systemPrompt
|
|
127
|
+
?? 'You are an expert video analyst. You have been given structured analysis data extracted from a video. Answer the user\'s question based on this data. Be specific, reference timestamps when relevant, and provide clear, actionable insights.';
|
|
128
|
+
|
|
129
|
+
const userContent = `Here is the video analysis data:\n\n${mapText}\n\n---\n\nUser query: ${query}`;
|
|
130
|
+
|
|
131
|
+
onProgress?.('Sending map output to Claude for analysis...\n');
|
|
132
|
+
|
|
133
|
+
const { signal, cleanup } = createTimeout(REDUCE_TIMEOUT_MS);
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const response = await provider.sendMessage(
|
|
137
|
+
[userMessage(userContent)],
|
|
138
|
+
[],
|
|
139
|
+
effectiveSystemPrompt,
|
|
140
|
+
{
|
|
141
|
+
config: model ? { model } : {},
|
|
142
|
+
signal,
|
|
143
|
+
},
|
|
144
|
+
);
|
|
145
|
+
cleanup();
|
|
146
|
+
|
|
147
|
+
const answer = extractAllText(response);
|
|
148
|
+
|
|
149
|
+
onProgress?.(`Reduce complete (${response.usage.inputTokens} input + ${response.usage.outputTokens} output tokens).\n`);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
answer,
|
|
153
|
+
model: response.model,
|
|
154
|
+
inputTokens: response.usage.inputTokens,
|
|
155
|
+
outputTokens: response.usage.outputTokens,
|
|
156
|
+
};
|
|
157
|
+
} finally {
|
|
158
|
+
cleanup();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// Public API
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* One-shot merge mode: load map output for an asset, send all data to
|
|
168
|
+
* Claude with a system prompt, and return the analysis.
|
|
169
|
+
*/
|
|
170
|
+
export async function reduceForAsset(
|
|
171
|
+
assetId: string,
|
|
172
|
+
options: ReduceOptions,
|
|
173
|
+
onProgress?: (msg: string) => void,
|
|
174
|
+
): Promise<ReduceResult> {
|
|
175
|
+
const mapOutput = await loadMapOutput(assetId);
|
|
176
|
+
|
|
177
|
+
if (mapOutput.segments.length === 0) {
|
|
178
|
+
throw new Error('Map output contains no segments. Run analyze_keyframes first.');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const mapText = formatMapOutputAsText(mapOutput);
|
|
182
|
+
const effectiveQuery = options.query ?? 'Summarize the video content.';
|
|
183
|
+
return sendToClaude(mapText, effectiveQuery, options.systemPrompt, options.model, onProgress);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Interactive Q&A mode: load existing map output + user query, send to
|
|
188
|
+
* Claude, return the answer. Functionally identical to reduceForAsset
|
|
189
|
+
* but named distinctly for clarity in call sites.
|
|
190
|
+
*/
|
|
191
|
+
export async function queryMapOutput(
|
|
192
|
+
assetId: string,
|
|
193
|
+
options: ReduceOptions,
|
|
194
|
+
onProgress?: (msg: string) => void,
|
|
195
|
+
): Promise<ReduceResult> {
|
|
196
|
+
return reduceForAsset(assetId, options, onProgress);
|
|
197
|
+
}
|
|
@@ -1,42 +1,36 @@
|
|
|
1
|
+
import { join, dirname } from 'node:path';
|
|
1
2
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import Anthropic from '@anthropic-ai/sdk';
|
|
3
|
-
import { getConfig } from '../../../../config/loader.js';
|
|
4
3
|
import type { ToolContext, ToolExecutionResult } from '../../../../tools/types.js';
|
|
4
|
+
import { getConfig } from '../../../../config/loader.js';
|
|
5
5
|
import {
|
|
6
6
|
getMediaAssetById,
|
|
7
|
-
getKeyframesForAsset,
|
|
8
|
-
getVisionOutputsForAsset,
|
|
9
|
-
insertVisionOutputsBatch,
|
|
10
|
-
createProcessingStage,
|
|
11
|
-
updateProcessingStage,
|
|
12
|
-
getProcessingStagesForAsset,
|
|
13
|
-
type MediaKeyframe,
|
|
14
|
-
type ProcessingStage,
|
|
15
7
|
} from '../../../../memory/media-store.js';
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
8
|
+
import { mapSegments, type MapOutput } from '../services/gemini-map.js';
|
|
9
|
+
import type { PreprocessManifest } from '../services/preprocess.js';
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Exported function for job handler use
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
export interface MapSegmentsOptions {
|
|
16
|
+
systemPrompt: string;
|
|
17
|
+
outputSchema: Record<string, unknown>;
|
|
18
|
+
context?: Record<string, unknown>;
|
|
19
|
+
model?: string;
|
|
20
|
+
concurrency?: number;
|
|
21
|
+
maxRetries?: number;
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export async function analyzeKeyframesForAsset(
|
|
24
|
+
export async function mapSegmentsForAsset(
|
|
29
25
|
assetId: string,
|
|
30
|
-
|
|
31
|
-
batchSize?: number,
|
|
26
|
+
options: MapSegmentsOptions,
|
|
32
27
|
onProgress?: (msg: string) => void,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
const batch = batchSize ?? 10;
|
|
28
|
+
): Promise<MapOutput> {
|
|
29
|
+
const config = getConfig();
|
|
30
|
+
const apiKey = config.apiKeys.gemini;
|
|
37
31
|
|
|
38
|
-
if (
|
|
39
|
-
throw new Error('
|
|
32
|
+
if (!apiKey) {
|
|
33
|
+
throw new Error('No Gemini API key configured. Please set your Gemini API key to use keyframe analysis.');
|
|
40
34
|
}
|
|
41
35
|
|
|
42
36
|
const asset = getMediaAssetById(assetId);
|
|
@@ -44,123 +38,37 @@ export async function analyzeKeyframesForAsset(
|
|
|
44
38
|
throw new Error(`Media asset not found: ${assetId}`);
|
|
45
39
|
}
|
|
46
40
|
|
|
47
|
-
//
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
throw new Error('No keyframes found for this asset. Run extract_keyframes first.');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Resumability: find already-analyzed keyframe IDs for this analysis type
|
|
54
|
-
const existingOutputs = getVisionOutputsForAsset(assetId, type);
|
|
55
|
-
const analyzedKeyframeIds = new Set(existingOutputs.map((o) => o.keyframeId));
|
|
56
|
-
const pendingKeyframes = keyframes.filter((kf) => !analyzedKeyframeIds.has(kf.id));
|
|
41
|
+
// Load preprocess manifest
|
|
42
|
+
const pipelineDir = join(dirname(asset.filePath), 'pipeline', assetId);
|
|
43
|
+
const manifestPath = join(pipelineDir, 'manifest.json');
|
|
57
44
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
45
|
+
let manifest: PreprocessManifest;
|
|
46
|
+
try {
|
|
47
|
+
const raw = await readFile(manifestPath, 'utf-8');
|
|
48
|
+
manifest = JSON.parse(raw) as PreprocessManifest;
|
|
49
|
+
} catch {
|
|
50
|
+
throw new Error('No preprocess manifest found. Run extract_keyframes first.');
|
|
61
51
|
}
|
|
62
52
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const existingStages = getProcessingStagesForAsset(assetId);
|
|
66
|
-
stage = existingStages.find((s) => s.stage === 'vision_analysis');
|
|
67
|
-
if (!stage) {
|
|
68
|
-
stage = createProcessingStage({ assetId, stage: 'vision_analysis' });
|
|
53
|
+
if (manifest.segments.length === 0) {
|
|
54
|
+
throw new Error('No segments found in preprocess manifest. Run extract_keyframes first.');
|
|
69
55
|
}
|
|
70
56
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
throw new Error('No Anthropic API key available. Configure it in settings or set ANTHROPIC_API_KEY.');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const client = new Anthropic({ apiKey });
|
|
84
|
-
let analyzedCount = analyzedKeyframeIds.size;
|
|
85
|
-
const totalKeyframes = keyframes.length;
|
|
86
|
-
|
|
87
|
-
onProgress?.(`Analyzing ${pendingKeyframes.length} keyframes (${analyzedKeyframeIds.size} already done)...\n`);
|
|
88
|
-
|
|
89
|
-
let aborted = false;
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
// Process in batches
|
|
93
|
-
for (let i = 0; i < pendingKeyframes.length; i += batch) {
|
|
94
|
-
if (signal?.aborted) {
|
|
95
|
-
onProgress?.('Aborted.\n');
|
|
96
|
-
aborted = true;
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const currentBatch = pendingKeyframes.slice(i, i + batch);
|
|
101
|
-
const batchResults: Array<{
|
|
102
|
-
assetId: string;
|
|
103
|
-
keyframeId: string;
|
|
104
|
-
analysisType: string;
|
|
105
|
-
output: Record<string, unknown>;
|
|
106
|
-
confidence?: number;
|
|
107
|
-
}> = [];
|
|
108
|
-
|
|
109
|
-
for (const keyframe of currentBatch) {
|
|
110
|
-
if (signal?.aborted) {
|
|
111
|
-
onProgress?.('Aborted.\n');
|
|
112
|
-
aborted = true;
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
try {
|
|
117
|
-
const result = await analyzeKeyframe(client, keyframe);
|
|
118
|
-
batchResults.push({
|
|
119
|
-
assetId,
|
|
120
|
-
keyframeId: keyframe.id,
|
|
121
|
-
analysisType: type,
|
|
122
|
-
output: result.output,
|
|
123
|
-
confidence: result.confidence,
|
|
124
|
-
});
|
|
125
|
-
analyzedCount++;
|
|
126
|
-
} catch (err) {
|
|
127
|
-
onProgress?.(` Warning: failed to analyze frame at ${keyframe.timestamp}s: ${(err as Error).message}\n`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Batch insert results
|
|
132
|
-
if (batchResults.length > 0) {
|
|
133
|
-
insertVisionOutputsBatch(batchResults);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Update progress
|
|
137
|
-
const progress = Math.round((analyzedCount / totalKeyframes) * 100);
|
|
138
|
-
updateProcessingStage(stage.id, { progress });
|
|
139
|
-
|
|
140
|
-
onProgress?.(` Batch ${Math.floor(i / batch) + 1}: analyzed ${batchResults.length}/${currentBatch.length} frames (${progress}% total)\n`);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (aborted) {
|
|
144
|
-
throw new Error('Analysis aborted');
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const finalProgress = Math.round((analyzedCount / totalKeyframes) * 100);
|
|
148
|
-
const isComplete = analyzedCount >= totalKeyframes;
|
|
149
|
-
|
|
150
|
-
updateProcessingStage(stage.id, {
|
|
151
|
-
status: isComplete ? 'completed' : 'running',
|
|
152
|
-
progress: finalProgress,
|
|
153
|
-
...(isComplete ? { completedAt: Date.now() } : {}),
|
|
154
|
-
});
|
|
155
|
-
} catch (err) {
|
|
156
|
-
updateProcessingStage(stage.id, {
|
|
157
|
-
status: 'failed',
|
|
158
|
-
lastError: (err as Error).message.slice(0, 500),
|
|
159
|
-
});
|
|
160
|
-
throw err;
|
|
161
|
-
}
|
|
57
|
+
return mapSegments(assetId, pipelineDir, manifest.segments, {
|
|
58
|
+
apiKey,
|
|
59
|
+
systemPrompt: options.systemPrompt,
|
|
60
|
+
outputSchema: options.outputSchema,
|
|
61
|
+
context: options.context,
|
|
62
|
+
model: options.model,
|
|
63
|
+
concurrency: options.concurrency,
|
|
64
|
+
maxRetries: options.maxRetries,
|
|
65
|
+
}, onProgress);
|
|
162
66
|
}
|
|
163
67
|
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Tool entry point
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
164
72
|
export async function run(
|
|
165
73
|
input: Record<string, unknown>,
|
|
166
74
|
context: ToolContext,
|
|
@@ -170,132 +78,59 @@ export async function run(
|
|
|
170
78
|
return { content: 'asset_id is required.', isError: true };
|
|
171
79
|
}
|
|
172
80
|
|
|
173
|
-
const
|
|
174
|
-
|
|
81
|
+
const systemPrompt = input.system_prompt as string | undefined;
|
|
82
|
+
if (!systemPrompt) {
|
|
83
|
+
return { content: 'system_prompt is required.', isError: true };
|
|
84
|
+
}
|
|
175
85
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const analyzedKeyframeIds = new Set(existingOutputs.map((o) => o.keyframeId));
|
|
181
|
-
const pendingKeyframes = keyframes.filter((kf) => !analyzedKeyframeIds.has(kf.id));
|
|
86
|
+
const outputSchema = input.output_schema as Record<string, unknown> | undefined;
|
|
87
|
+
if (!outputSchema) {
|
|
88
|
+
return { content: 'output_schema is required.', isError: true };
|
|
89
|
+
}
|
|
182
90
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
assetId,
|
|
188
|
-
analysisType,
|
|
189
|
-
totalKeyframes: keyframes.length,
|
|
190
|
-
alreadyAnalyzed: existingOutputs.length,
|
|
191
|
-
}, null, 2),
|
|
192
|
-
isError: false,
|
|
193
|
-
};
|
|
194
|
-
}
|
|
91
|
+
const contextObj = input.context as Record<string, unknown> | undefined;
|
|
92
|
+
const model = input.model as string | undefined;
|
|
93
|
+
const concurrency = input.concurrency as number | undefined;
|
|
94
|
+
const maxRetries = input.max_retries as number | undefined;
|
|
195
95
|
|
|
196
|
-
|
|
96
|
+
if (concurrency !== undefined && concurrency < 1) {
|
|
97
|
+
return { content: 'concurrency must be at least 1.', isError: true };
|
|
98
|
+
}
|
|
99
|
+
if (maxRetries !== undefined && maxRetries < 0) {
|
|
100
|
+
return { content: 'max_retries must be non-negative.', isError: true };
|
|
101
|
+
}
|
|
197
102
|
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
103
|
+
try {
|
|
104
|
+
const output = await mapSegmentsForAsset(
|
|
105
|
+
assetId,
|
|
106
|
+
{
|
|
107
|
+
systemPrompt,
|
|
108
|
+
outputSchema,
|
|
109
|
+
context: contextObj,
|
|
110
|
+
model,
|
|
111
|
+
concurrency,
|
|
112
|
+
maxRetries,
|
|
113
|
+
},
|
|
114
|
+
context.onOutput,
|
|
115
|
+
);
|
|
205
116
|
|
|
206
117
|
return {
|
|
207
118
|
content: JSON.stringify({
|
|
208
|
-
message: `
|
|
119
|
+
message: `Map ${output.failedCount === 0 ? 'completed' : 'completed with errors'}`,
|
|
209
120
|
assetId,
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
121
|
+
model: output.model,
|
|
122
|
+
segmentCount: output.segmentCount,
|
|
123
|
+
successCount: output.successCount,
|
|
124
|
+
failedCount: output.failedCount,
|
|
125
|
+
skippedCount: output.skippedCount,
|
|
126
|
+
totalInputTokens: output.costSummary.totalInputTokens,
|
|
127
|
+
totalOutputTokens: output.costSummary.totalOutputTokens,
|
|
128
|
+
estimatedCostUSD: output.costSummary.totalEstimatedUSD,
|
|
216
129
|
}, null, 2),
|
|
217
130
|
isError: false,
|
|
218
131
|
};
|
|
219
132
|
} catch (err) {
|
|
220
133
|
const msg = (err as Error).message;
|
|
221
|
-
|
|
222
|
-
if (
|
|
223
|
-
msg === 'batch_size must be greater than 0.' ||
|
|
224
|
-
msg.startsWith('Media asset not found:') ||
|
|
225
|
-
msg === 'No keyframes found for this asset. Run extract_keyframes first.' ||
|
|
226
|
-
msg === 'No Anthropic API key available. Configure it in settings or set ANTHROPIC_API_KEY.'
|
|
227
|
-
) {
|
|
228
|
-
return { content: msg, isError: true };
|
|
229
|
-
}
|
|
230
|
-
return { content: `Vision analysis failed: ${(err as Error).message}`, isError: true };
|
|
134
|
+
return { content: msg, isError: true };
|
|
231
135
|
}
|
|
232
136
|
}
|
|
233
|
-
|
|
234
|
-
async function analyzeKeyframe(
|
|
235
|
-
client: Anthropic,
|
|
236
|
-
keyframe: MediaKeyframe,
|
|
237
|
-
): Promise<{ output: Record<string, unknown>; confidence: number }> {
|
|
238
|
-
// Read the image file and encode as base64
|
|
239
|
-
const imageData = await readFile(keyframe.filePath);
|
|
240
|
-
const base64 = imageData.toString('base64');
|
|
241
|
-
|
|
242
|
-
// Determine media type from file extension
|
|
243
|
-
const ext = keyframe.filePath.split('.').pop()?.toLowerCase() ?? 'jpg';
|
|
244
|
-
const mediaTypeMap: Record<string, string> = {
|
|
245
|
-
jpg: 'image/jpeg',
|
|
246
|
-
jpeg: 'image/jpeg',
|
|
247
|
-
png: 'image/png',
|
|
248
|
-
gif: 'image/gif',
|
|
249
|
-
webp: 'image/webp',
|
|
250
|
-
};
|
|
251
|
-
const mediaType = mediaTypeMap[ext] ?? 'image/jpeg';
|
|
252
|
-
|
|
253
|
-
const response = await client.messages.create({
|
|
254
|
-
model: 'claude-sonnet-4-6-20250514',
|
|
255
|
-
max_tokens: 1024,
|
|
256
|
-
messages: [
|
|
257
|
-
{
|
|
258
|
-
role: 'user',
|
|
259
|
-
content: [
|
|
260
|
-
{
|
|
261
|
-
type: 'image',
|
|
262
|
-
source: {
|
|
263
|
-
type: 'base64',
|
|
264
|
-
media_type: mediaType as 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp',
|
|
265
|
-
data: base64,
|
|
266
|
-
},
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
type: 'text',
|
|
270
|
-
text: VLM_PROMPT,
|
|
271
|
-
},
|
|
272
|
-
],
|
|
273
|
-
},
|
|
274
|
-
],
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
// Extract text from response
|
|
278
|
-
const textBlock = response.content.find((block) => block.type === 'text');
|
|
279
|
-
const responseText = textBlock && 'text' in textBlock ? textBlock.text : '';
|
|
280
|
-
|
|
281
|
-
// Parse JSON from response
|
|
282
|
-
let output: Record<string, unknown>;
|
|
283
|
-
try {
|
|
284
|
-
// Try to extract JSON from the response (handle markdown code fences)
|
|
285
|
-
const jsonMatch = responseText.match(/```(?:json)?\s*([\s\S]*?)```/) ?? [null, responseText];
|
|
286
|
-
output = JSON.parse(jsonMatch[1]!.trim()) as Record<string, unknown>;
|
|
287
|
-
} catch {
|
|
288
|
-
// If JSON parsing fails, wrap raw text as output
|
|
289
|
-
output = {
|
|
290
|
-
sceneDescription: responseText,
|
|
291
|
-
subjects: [],
|
|
292
|
-
actions: [],
|
|
293
|
-
context: '',
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Add timestamp context to the output
|
|
298
|
-
output.timestamp = keyframe.timestamp;
|
|
299
|
-
|
|
300
|
-
return { output, confidence: 0.8 };
|
|
301
|
-
}
|