@vellumai/assistant 0.5.1 → 0.5.3
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/ARCHITECTURE.md +163 -54
- package/docs/architecture/integrations.md +62 -67
- package/docs/credential-execution-service.md +3 -3
- package/docs/skills.md +100 -0
- package/package.json +1 -1
- package/src/__tests__/agent-loop.test.ts +111 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
- package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
- package/src/__tests__/app-dir-path-guard.test.ts +78 -0
- package/src/__tests__/app-executors.test.ts +1 -291
- package/src/__tests__/app-git-history.test.ts +4 -4
- package/src/__tests__/app-routes-csp.test.ts +1 -0
- package/src/__tests__/app-store-dir-names.test.ts +426 -0
- package/src/__tests__/attachments-store.test.ts +169 -21
- package/src/__tests__/attachments.test.ts +115 -1
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/canonical-guardian-store.test.ts +38 -0
- package/src/__tests__/channel-reply-delivery.test.ts +55 -0
- package/src/__tests__/checker.test.ts +54 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/config-schema-cmd.test.ts +68 -21
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +156 -5
- package/src/__tests__/conversation-agent-loop.test.ts +297 -2
- package/src/__tests__/conversation-attachments.test.ts +17 -19
- package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
- package/src/__tests__/conversation-disk-view.test.ts +810 -0
- package/src/__tests__/conversation-error.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +551 -0
- package/src/__tests__/conversation-fork-route.test.ts +386 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
- package/src/__tests__/conversation-media-retry.test.ts +8 -2
- package/src/__tests__/conversation-memory-dirty-tail.test.ts +150 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +7 -0
- package/src/__tests__/conversation-queue.test.ts +36 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
- package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
- package/src/__tests__/conversation-skill-tools.test.ts +4 -9
- package/src/__tests__/conversation-slash-commands.test.ts +149 -0
- package/src/__tests__/conversation-store.test.ts +24 -21
- package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
- package/src/__tests__/conversation-title-service.test.ts +137 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
- package/src/__tests__/conversation-wipe.test.ts +226 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/credential-vault-unit.test.ts +5 -10
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
- package/src/__tests__/db-memory-archive-migration.test.ts +372 -0
- package/src/__tests__/db-memory-brief-state-migration.test.ts +213 -0
- package/src/__tests__/db-memory-reducer-checkpoints.test.ts +273 -0
- package/src/__tests__/diagnostics-export.test.ts +70 -1
- package/src/__tests__/first-greeting.test.ts +80 -0
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
- package/src/__tests__/history-repair.test.ts +32 -10
- package/src/__tests__/http-conversation-lineage.test.ts +251 -0
- package/src/__tests__/image-source-path-reinject.test.ts +136 -0
- package/src/__tests__/inline-command-runner.test.ts +311 -0
- package/src/__tests__/inline-skill-authoring-guard.test.ts +220 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +435 -0
- package/src/__tests__/list-messages-attachments.test.ts +96 -0
- package/src/__tests__/llm-context-normalization.test.ts +1116 -0
- package/src/__tests__/llm-context-route-provider.test.ts +217 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
- package/src/__tests__/media-generate-image.test.ts +47 -94
- package/src/__tests__/memory-brief-open-loops.test.ts +530 -0
- package/src/__tests__/memory-brief-time.test.ts +285 -0
- package/src/__tests__/memory-brief-wrapper.test.ts +311 -0
- package/src/__tests__/memory-chunk-archive.test.ts +400 -0
- package/src/__tests__/memory-chunk-dual-write.test.ts +453 -0
- package/src/__tests__/memory-episode-archive.test.ts +370 -0
- package/src/__tests__/memory-episode-dual-write.test.ts +626 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
- package/src/__tests__/memory-observation-archive.test.ts +375 -0
- package/src/__tests__/memory-observation-dual-write.test.ts +318 -0
- package/src/__tests__/memory-recall-quality.test.ts +7 -7
- package/src/__tests__/memory-reducer-store.test.ts +728 -0
- package/src/__tests__/memory-reducer-types.test.ts +699 -0
- package/src/__tests__/memory-reducer.test.ts +698 -0
- package/src/__tests__/memory-regressions.test.ts +6 -4
- package/src/__tests__/memory-simplified-config.test.ts +281 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
- package/src/__tests__/migration-export-http.test.ts +3 -1
- package/src/__tests__/migration-import-commit-http.test.ts +18 -4
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
- package/src/__tests__/mime-builder.test.ts +3 -2
- package/src/__tests__/non-member-access-request.test.ts +12 -1
- package/src/__tests__/notification-decision-identity.test.ts +52 -0
- package/src/__tests__/oauth-apps-routes.test.ts +103 -0
- package/src/__tests__/oauth-store.test.ts +115 -0
- package/src/__tests__/parse-identity-fields.test.ts +129 -0
- package/src/__tests__/provider-error-scenarios.test.ts +1 -3
- package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
- package/src/__tests__/recording-handler.test.ts +17 -0
- package/src/__tests__/registry.test.ts +3 -8
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
- package/src/__tests__/schema-transforms.test.ts +165 -5
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/skill-load-inline-command.test.ts +598 -0
- package/src/__tests__/skill-load-inline-includes.test.ts +644 -0
- package/src/__tests__/skills-inline-command-expansions.test.ts +301 -0
- package/src/__tests__/skills-transitive-hash.test.ts +333 -0
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -2
- package/src/__tests__/starter-task-flow.test.ts +1 -0
- package/src/__tests__/suggestion-routes.test.ts +443 -0
- package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
- package/src/__tests__/swarm-recursion.test.ts +1 -0
- package/src/__tests__/swarm-tool.test.ts +1 -0
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
- package/src/__tests__/top-level-renderer.test.ts +22 -0
- package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +320 -0
- package/src/__tests__/web-fetch.test.ts +6 -2
- package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
- package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
- package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
- package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
- package/src/agent/attachments.ts +27 -1
- package/src/agent/loop.ts +29 -1
- package/src/avatar/traits-png-sync.ts +80 -25
- package/src/bundler/app-bundler.ts +4 -4
- package/src/calls/call-domain.ts +1 -0
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/commands/auth.ts +92 -0
- package/src/cli/commands/avatar.ts +7 -6
- package/src/cli/commands/config.ts +2 -0
- package/src/cli/commands/oauth/providers.ts +29 -0
- package/src/cli/program.ts +12 -0
- package/src/cli.ts +15 -48
- package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
- package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
- package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
- package/src/config/bundled-skills/skill-management/SKILL.md +1 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
- package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
- package/src/config/bundled-tool-registry.ts +2 -14
- package/src/config/feature-flag-registry.json +24 -0
- package/src/config/loader.ts +65 -0
- package/src/config/raw-config-utils.ts +58 -0
- package/src/config/schema-utils.ts +28 -7
- package/src/config/schema.ts +20 -0
- package/src/config/schemas/elevenlabs.ts +18 -0
- package/src/config/schemas/memory-lifecycle.ts +4 -2
- package/src/config/schemas/memory-simplified.ts +101 -0
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +8 -6
- package/src/config/skills.ts +50 -4
- package/src/contacts/contact-store.ts +13 -6
- package/src/contacts/contacts-write.ts +0 -1
- package/src/context/window-manager.ts +13 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +54 -8
- package/src/daemon/conversation-agent-loop.ts +127 -20
- package/src/daemon/conversation-attachments.ts +18 -36
- package/src/daemon/conversation-error.ts +2 -1
- package/src/daemon/conversation-history.ts +18 -4
- package/src/daemon/conversation-lifecycle.ts +50 -16
- package/src/daemon/conversation-messaging.ts +70 -26
- package/src/daemon/conversation-process.ts +58 -34
- package/src/daemon/conversation-runtime-assembly.ts +22 -38
- package/src/daemon/conversation-slash.ts +121 -256
- package/src/daemon/conversation-surfaces.ts +170 -24
- package/src/daemon/conversation-tool-setup.ts +0 -6
- package/src/daemon/conversation-workspace.ts +21 -1
- package/src/daemon/conversation.ts +69 -30
- package/src/daemon/first-greeting.ts +35 -0
- package/src/daemon/handlers/config-embeddings.ts +156 -0
- package/src/daemon/handlers/config-model.ts +62 -26
- package/src/daemon/handlers/conversations.ts +0 -23
- package/src/daemon/handlers/identity.ts +12 -1
- package/src/daemon/handlers/recording.ts +26 -21
- package/src/daemon/host-cu-proxy.ts +2 -2
- package/src/daemon/lifecycle.ts +115 -65
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +18 -0
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/shared.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/message-types/upgrades.ts +23 -0
- package/src/daemon/server.ts +83 -12
- package/src/daemon/shutdown-handlers.ts +8 -5
- package/src/daemon/startup-error.ts +9 -0
- package/src/daemon/tool-side-effects.ts +11 -28
- package/src/events/tool-permission-telemetry-listener.ts +1 -3
- package/src/followups/followup-store.ts +47 -1
- package/src/instrument.ts +0 -4
- package/src/media/app-icon-generator.ts +2 -2
- package/src/memory/app-git-service.ts +28 -16
- package/src/memory/app-store.ts +230 -41
- package/src/memory/archive-store.ts +400 -0
- package/src/memory/attachments-store.ts +558 -130
- package/src/memory/brief-formatting.ts +33 -0
- package/src/memory/brief-open-loops.ts +266 -0
- package/src/memory/brief-time.ts +161 -0
- package/src/memory/brief.ts +75 -0
- package/src/memory/conversation-attention-store.ts +70 -0
- package/src/memory/conversation-crud.ts +591 -8
- package/src/memory/conversation-directories.ts +125 -0
- package/src/memory/conversation-disk-view.ts +390 -0
- package/src/memory/conversation-key-store.ts +17 -5
- package/src/memory/conversation-queries.ts +5 -1
- package/src/memory/conversation-title-service.ts +21 -49
- package/src/memory/db-init.ts +40 -0
- package/src/memory/embedding-backend.ts +42 -53
- package/src/memory/embedding-gemini.test.ts +4 -4
- package/src/memory/embedding-local.ts +1 -3
- package/src/memory/embedding-ollama.ts +1 -3
- package/src/memory/embedding-openai.ts +1 -3
- package/src/memory/indexer.ts +114 -21
- package/src/memory/items-extractor.ts +42 -13
- package/src/memory/job-handlers/conversation-starters.ts +6 -1
- package/src/memory/job-handlers/embedding.test.ts +2 -4
- package/src/memory/job-handlers/embedding.ts +83 -0
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +6 -0
- package/src/memory/jobs-worker.ts +12 -0
- package/src/memory/llm-request-log-store.ts +100 -1
- package/src/memory/migrations/102-alter-table-columns.ts +5 -0
- package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
- package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
- package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
- package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
- package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
- package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
- package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
- package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
- package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
- package/src/memory/migrations/185-memory-brief-state.ts +52 -0
- package/src/memory/migrations/186-memory-archive.ts +109 -0
- package/src/memory/migrations/187-memory-reducer-checkpoints.ts +19 -0
- package/src/memory/migrations/index.ts +10 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/qdrant-client.ts +23 -4
- package/src/memory/reducer-store.ts +271 -0
- package/src/memory/reducer-types.ts +99 -0
- package/src/memory/reducer.ts +453 -0
- package/src/memory/retriever.test.ts +601 -2
- package/src/memory/retriever.ts +85 -9
- package/src/memory/schema/conversations.ts +9 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/infrastructure.ts +13 -7
- package/src/memory/schema/memory-archive.ts +121 -0
- package/src/memory/schema/memory-brief.ts +55 -0
- package/src/memory/schema/oauth.ts +6 -0
- package/src/memory/search/semantic.ts +17 -4
- package/src/messaging/providers/gmail/mime-builder.ts +3 -1
- package/src/notifications/copy-composer.ts +26 -0
- package/src/notifications/decision-engine.ts +14 -1
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +36 -0
- package/src/oauth/byo-connection.test.ts +1 -45
- package/src/oauth/byo-connection.ts +2 -8
- package/src/oauth/connect-orchestrator.ts +15 -11
- package/src/oauth/connection-resolver.test.ts +191 -0
- package/src/oauth/connection-resolver.ts +66 -38
- package/src/oauth/connection.ts +0 -1
- package/src/oauth/oauth-store.ts +99 -47
- package/src/oauth/platform-connection.test.ts +0 -1
- package/src/oauth/platform-connection.ts +11 -3
- package/src/oauth/seed-providers.ts +78 -3
- package/src/oauth/token-persistence.ts +16 -10
- package/src/permissions/checker.ts +160 -14
- package/src/permissions/defaults.ts +14 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -0
- package/src/providers/anthropic/client.ts +8 -1
- package/src/providers/failover.ts +4 -1
- package/src/providers/gemini/client.ts +50 -0
- package/src/providers/model-catalog.ts +92 -0
- package/src/providers/model-intents.ts +29 -20
- package/src/providers/openai/client.ts +49 -0
- package/src/providers/types.ts +2 -0
- package/src/runtime/access-request-helper.ts +16 -7
- package/src/runtime/auth/credential-service.ts +3 -1
- package/src/runtime/auth/route-policy.ts +14 -1
- package/src/runtime/btw-sidechain.ts +101 -0
- package/src/runtime/channel-reply-delivery.ts +17 -1
- package/src/runtime/http-router.ts +3 -1
- package/src/runtime/http-server.ts +196 -141
- package/src/runtime/http-types.ts +1 -0
- package/src/runtime/migrations/vbundle-builder.ts +5 -1
- package/src/runtime/routes/access-request-decision.ts +41 -0
- package/src/runtime/routes/app-management-routes.ts +6 -3
- package/src/runtime/routes/app-routes.ts +7 -3
- package/src/runtime/routes/approval-routes.ts +1 -0
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
- package/src/runtime/routes/attachment-routes.ts +45 -15
- package/src/runtime/routes/btw-routes.ts +21 -61
- package/src/runtime/routes/conversation-management-routes.ts +74 -0
- package/src/runtime/routes/conversation-query-routes.ts +187 -10
- package/src/runtime/routes/conversation-routes.ts +269 -28
- package/src/runtime/routes/conversation-starter-routes.ts +9 -11
- package/src/runtime/routes/diagnostics-routes.ts +1 -0
- package/src/runtime/routes/identity-routes.ts +2 -35
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
- package/src/runtime/routes/llm-context-normalization.ts +1212 -0
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/memory-item-routes.test.ts +34 -0
- package/src/runtime/routes/memory-item-routes.ts +94 -5
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/oauth-apps.ts +291 -0
- package/src/runtime/routes/secret-routes.ts +30 -1
- package/src/runtime/routes/settings-routes.ts +14 -0
- package/src/runtime/routes/surface-action-routes.ts +68 -1
- package/src/runtime/routes/trace-event-routes.ts +4 -1
- package/src/schedule/schedule-store.ts +30 -21
- package/src/security/secure-keys.ts +21 -0
- package/src/signals/bash.ts +1 -1
- package/src/skills/inline-command-expansions.ts +204 -0
- package/src/skills/inline-command-render.ts +127 -0
- package/src/skills/inline-command-runner.ts +242 -0
- package/src/skills/transitive-version-hash.ts +88 -0
- package/src/swarm/backend-claude-code.ts +3 -6
- package/src/tasks/task-store.ts +43 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +3 -1
- package/src/tools/AGENTS.md +6 -10
- package/src/tools/apps/executors.ts +17 -232
- package/src/tools/claude-code/claude-code.ts +2 -3
- package/src/tools/credentials/vault.ts +7 -12
- package/src/tools/host-filesystem/read.ts +13 -10
- package/src/tools/network/__tests__/web-search.test.ts +4 -2
- package/src/tools/permission-checker.ts +8 -1
- package/src/tools/schedule/list.ts +2 -7
- package/src/tools/schema-transforms.ts +5 -0
- package/src/tools/shared/filesystem/format-diff.ts +2 -7
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +140 -6
- package/src/tools/tool-manifest.ts +0 -6
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/util/device-id.ts +28 -5
- package/src/util/platform.ts +24 -0
- package/src/util/pricing.ts +1 -0
- package/src/util/retry.ts +1 -3
- package/src/workspace/migrations/003-seed-device-id.ts +3 -4
- package/src/workspace/migrations/006-services-config.ts +5 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
- package/src/workspace/migrations/{002-backfill-installation-id.ts → 011-backfill-installation-id.ts} +24 -13
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
- package/src/workspace/migrations/registry.ts +11 -1
- package/src/workspace/top-level-renderer.ts +12 -0
- package/src/__tests__/asset-materialize-tool.test.ts +0 -523
- package/src/__tests__/asset-search-tool.test.ts +0 -536
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
- package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
- package/src/__tests__/media-visibility-policy.test.ts +0 -190
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
- package/src/daemon/media-visibility-policy.ts +0 -59
- package/src/tools/assets/materialize.ts +0 -248
- package/src/tools/assets/search.ts +0 -400
|
@@ -1,55 +1,22 @@
|
|
|
1
1
|
import { getConfig } from "../../../../config/loader.js";
|
|
2
|
-
import {
|
|
3
|
-
type AttachmentContext,
|
|
4
|
-
isAttachmentVisible,
|
|
5
|
-
} from "../../../../daemon/media-visibility-policy.js";
|
|
6
2
|
import {
|
|
7
3
|
generateImage,
|
|
8
4
|
type ImageGenCredentials,
|
|
9
5
|
mapGeminiError,
|
|
10
6
|
} from "../../../../media/gemini-image-service.js";
|
|
11
|
-
import {
|
|
12
|
-
getAttachmentContent,
|
|
13
|
-
getAttachmentsByIds,
|
|
14
|
-
} from "../../../../memory/attachments-store.js";
|
|
15
|
-
import { getConversationType } from "../../../../memory/conversation-crud.js";
|
|
7
|
+
import { getFilePathBySourcePath } from "../../../../memory/attachments-store.js";
|
|
16
8
|
import {
|
|
17
9
|
buildManagedBaseUrl,
|
|
18
10
|
resolveManagedProxyContext,
|
|
19
11
|
} from "../../../../providers/managed-proxy/context.js";
|
|
20
12
|
import type { ImageContent } from "../../../../providers/types.js";
|
|
21
13
|
import { getProviderKeyAsync } from "../../../../security/secure-keys.js";
|
|
22
|
-
import {
|
|
14
|
+
import { sandboxPolicy } from "../../../../tools/shared/filesystem/path-policy.js";
|
|
23
15
|
import type {
|
|
24
16
|
ToolContext,
|
|
25
17
|
ToolExecutionResult,
|
|
26
18
|
} from "../../../../tools/types.js";
|
|
27
19
|
|
|
28
|
-
/**
|
|
29
|
-
* Check whether an attachment is visible from the given context.
|
|
30
|
-
* Mirrors the logic in tools/assets/search.ts:isAttachmentVisibleFromContext.
|
|
31
|
-
*/
|
|
32
|
-
function isAttachmentAccessible(
|
|
33
|
-
attachmentId: string,
|
|
34
|
-
currentContext: AttachmentContext,
|
|
35
|
-
): boolean {
|
|
36
|
-
const sources = getAttachmentSourceConversations(attachmentId);
|
|
37
|
-
if (sources.length === 0) {
|
|
38
|
-
return true; // orphan attachments are universally visible
|
|
39
|
-
}
|
|
40
|
-
const hasStandard = sources.some((s) => s.conversationType !== "private");
|
|
41
|
-
if (hasStandard) {
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
// All sources are private - visible only if the caller is in one of those conversations
|
|
45
|
-
return sources.some((s) =>
|
|
46
|
-
isAttachmentVisible(
|
|
47
|
-
{ conversationId: s.conversationId, isPrivate: true },
|
|
48
|
-
currentContext,
|
|
49
|
-
),
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
20
|
export async function run(
|
|
54
21
|
input: Record<string, unknown>,
|
|
55
22
|
context: ToolContext,
|
|
@@ -87,54 +54,60 @@ export async function run(
|
|
|
87
54
|
|
|
88
55
|
const prompt = input.prompt as string;
|
|
89
56
|
const mode = (input.mode as "generate" | "edit") ?? "generate";
|
|
90
|
-
const
|
|
57
|
+
const sourcePaths = input.source_paths as string[] | undefined;
|
|
91
58
|
const model =
|
|
92
59
|
(input.model as string | undefined) ??
|
|
93
60
|
config.services["image-generation"].model;
|
|
94
61
|
const variants = input.variants as number | undefined;
|
|
95
62
|
|
|
96
|
-
// Resolve source images from
|
|
63
|
+
// Resolve source images from file paths (sandboxed to workingDir, edit mode only)
|
|
97
64
|
let sourceImages: Array<{ mimeType: string; dataBase64: string }> | undefined;
|
|
98
65
|
|
|
99
|
-
if (
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
66
|
+
if (mode === "edit" && sourcePaths && sourcePaths.length > 0) {
|
|
67
|
+
const errors: string[] = [];
|
|
68
|
+
const validPathImages: Array<{ mimeType: string; dataBase64: string }> = [];
|
|
69
|
+
for (const filePath of sourcePaths) {
|
|
70
|
+
let resolvedPath: string;
|
|
71
|
+
const pathCheck = sandboxPolicy(filePath, context.workingDir);
|
|
72
|
+
if (!pathCheck.ok) {
|
|
73
|
+
// Fallback: if the source path is outside the sandbox (e.g. an image
|
|
74
|
+
// attached from ~/Desktop), check if the attachment store has a
|
|
75
|
+
// workspace-internal copy stored under its original source_path.
|
|
76
|
+
const storedPath = getFilePathBySourcePath(
|
|
77
|
+
filePath,
|
|
78
|
+
context.conversationId,
|
|
79
|
+
);
|
|
80
|
+
if (!storedPath) {
|
|
81
|
+
errors.push(pathCheck.error);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const fallbackCheck = sandboxPolicy(storedPath, context.workingDir);
|
|
85
|
+
if (!fallbackCheck.ok) {
|
|
86
|
+
errors.push(pathCheck.error);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
resolvedPath = fallbackCheck.resolved;
|
|
90
|
+
} else {
|
|
91
|
+
resolvedPath = pathCheck.resolved;
|
|
92
|
+
}
|
|
93
|
+
const file = Bun.file(resolvedPath);
|
|
94
|
+
if (!(await file.exists())) {
|
|
95
|
+
errors.push(`File not found: ${filePath}`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const buffer = Buffer.from(await file.arrayBuffer());
|
|
99
|
+
validPathImages.push({
|
|
100
|
+
mimeType: file.type,
|
|
101
|
+
dataBase64: buffer.toString("base64"),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (validPathImages.length === 0) {
|
|
115
105
|
return {
|
|
116
|
-
content:
|
|
117
|
-
"None of the specified attachments could be found or are accessible.",
|
|
106
|
+
content: `None of the specified file paths could be read.\n${errors.join("\n")}`,
|
|
118
107
|
isError: true,
|
|
119
108
|
};
|
|
120
109
|
}
|
|
121
|
-
|
|
122
|
-
sourceImages = visibleAttachments
|
|
123
|
-
.map((att) => {
|
|
124
|
-
let buffer: Buffer | null | undefined;
|
|
125
|
-
try {
|
|
126
|
-
buffer = getAttachmentContent(att.id);
|
|
127
|
-
} catch {
|
|
128
|
-
// File-backed attachment may point to a missing or unreadable file
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
if (!buffer) return undefined;
|
|
132
|
-
return {
|
|
133
|
-
mimeType: att.mimeType,
|
|
134
|
-
dataBase64: buffer.toString("base64"),
|
|
135
|
-
};
|
|
136
|
-
})
|
|
137
|
-
.filter((img): img is NonNullable<typeof img> => img !== undefined);
|
|
110
|
+
sourceImages = validPathImages;
|
|
138
111
|
}
|
|
139
112
|
|
|
140
113
|
try {
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
getKeyframesForAsset,
|
|
5
5
|
getMediaAssetById,
|
|
6
6
|
} from "../../../../memory/media-store.js";
|
|
7
|
-
import {
|
|
7
|
+
import { getProviderKeyAsync } from "../../../../security/secure-keys.js";
|
|
8
8
|
import type {
|
|
9
9
|
ToolContext,
|
|
10
10
|
ToolExecutionResult,
|
|
@@ -31,7 +31,7 @@ export async function run(
|
|
|
31
31
|
|
|
32
32
|
let openaiApiKey: string | undefined;
|
|
33
33
|
if (includeAudio && (!transcriptionMode || transcriptionMode === "api")) {
|
|
34
|
-
openaiApiKey =
|
|
34
|
+
openaiApiKey = await getProviderKeyAsync("openai");
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const options: PreprocessOptions = {
|
|
@@ -137,5 +137,5 @@ export async function getProviderConnection(
|
|
|
137
137
|
account?: string,
|
|
138
138
|
): Promise<OAuthConnection | string> {
|
|
139
139
|
if (await provider.isConnected?.()) return "";
|
|
140
|
-
return resolveOAuthConnection(provider.credentialService, account);
|
|
140
|
+
return resolveOAuthConnection(provider.credentialService, { account });
|
|
141
141
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
saveRawConfig,
|
|
5
5
|
setNestedValue,
|
|
6
6
|
} from "../../../../config/loader.js";
|
|
7
|
+
import { VALID_CONVERSATION_TIMEOUTS } from "../../../../config/schemas/elevenlabs.js";
|
|
7
8
|
import { normalizeActivationKey } from "../../../../daemon/handlers/config-voice.js";
|
|
8
9
|
import type {
|
|
9
10
|
ToolContext,
|
|
@@ -29,7 +30,7 @@ type VoiceSettingName = keyof typeof VOICE_SETTINGS;
|
|
|
29
30
|
|
|
30
31
|
const VALID_SETTINGS = Object.keys(VOICE_SETTINGS) as VoiceSettingName[];
|
|
31
32
|
|
|
32
|
-
const VALID_TIMEOUTS
|
|
33
|
+
const VALID_TIMEOUTS: readonly number[] = VALID_CONVERSATION_TIMEOUTS;
|
|
33
34
|
|
|
34
35
|
const FRIENDLY_NAMES: Record<VoiceSettingName, string> = {
|
|
35
36
|
activation_key: "PTT activation key",
|
|
@@ -132,12 +133,14 @@ export async function run(
|
|
|
132
133
|
const meta = VOICE_SETTINGS[setting as VoiceSettingName];
|
|
133
134
|
const friendlyName = FRIENDLY_NAMES[setting as VoiceSettingName];
|
|
134
135
|
|
|
135
|
-
// Send client_settings_update message to write to UserDefaults
|
|
136
|
+
// Send client_settings_update message to write to UserDefaults.
|
|
137
|
+
// Always stringify the value — Swift's ClientSettingsUpdate.value is typed
|
|
138
|
+
// as String, so a bare JSON number would fail to decode.
|
|
136
139
|
if (context.sendToClient) {
|
|
137
140
|
context.sendToClient({
|
|
138
141
|
type: "client_settings_update",
|
|
139
142
|
key: meta.userDefaultsKey,
|
|
140
|
-
value: validation.coerced,
|
|
143
|
+
value: String(validation.coerced),
|
|
141
144
|
});
|
|
142
145
|
}
|
|
143
146
|
|
|
@@ -150,6 +153,19 @@ export async function run(
|
|
|
150
153
|
invalidateConfigCache();
|
|
151
154
|
}
|
|
152
155
|
|
|
156
|
+
// For conversation_timeout, persist to the config file
|
|
157
|
+
// (elevenlabs.conversationTimeoutSeconds).
|
|
158
|
+
if (setting === "conversation_timeout") {
|
|
159
|
+
const raw = loadRawConfig();
|
|
160
|
+
setNestedValue(
|
|
161
|
+
raw,
|
|
162
|
+
"elevenlabs.conversationTimeoutSeconds",
|
|
163
|
+
validation.coerced,
|
|
164
|
+
);
|
|
165
|
+
saveRawConfig(raw);
|
|
166
|
+
invalidateConfigCache();
|
|
167
|
+
}
|
|
168
|
+
|
|
153
169
|
return {
|
|
154
170
|
content: `${friendlyName} updated to ${JSON.stringify(
|
|
155
171
|
validation.coerced,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"tools": [
|
|
4
4
|
{
|
|
5
5
|
"name": "scaffold_managed_skill",
|
|
6
|
-
"description": "Create or update a managed skill in
|
|
6
|
+
"description": "Create or update a managed skill in {workspaceDir}/skills. The skill becomes available for skill_load immediately. Never persist a skill without explicit user consent. Before persisting, test the snippet: write to a temp file with bash and run with `bun run /tmp/vellum-eval/snippet.ts`. Iterate up to 3 attempts, then ask the user. Clean up temp files after. Do not use file_write for temp files outside the working directory. After a skill is written, the next turn may run in a recreated conversation due to file-watcher eviction - continue normally.",
|
|
7
7
|
"category": "skills",
|
|
8
8
|
"risk": "high",
|
|
9
9
|
"input_schema": {
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
56
|
"name": "delete_managed_skill",
|
|
57
|
-
"description": "Delete a managed skill from
|
|
57
|
+
"description": "Delete a managed skill from {workspaceDir}/skills and remove it from the SKILLS.md index. Never delete a skill without explicit user confirmation. After deletion, the next turn may run in a recreated conversation due to file-watcher eviction - continue normally.",
|
|
58
58
|
"category": "skills",
|
|
59
59
|
"risk": "high",
|
|
60
60
|
"input_schema": {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Shared utilities for slack skill tools.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
5
|
+
import { credentialKey } from "../../../../security/credential-key.js";
|
|
6
|
+
import { getSecureKeyAsync } from "../../../../security/secure-keys.js";
|
|
7
7
|
import type { ToolExecutionResult } from "../../../../tools/types.js";
|
|
8
8
|
|
|
9
9
|
export function ok(content: string): ToolExecutionResult {
|
|
@@ -14,6 +14,21 @@ export function err(message: string): ToolExecutionResult {
|
|
|
14
14
|
return { content: message, isError: true };
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the Slack bot token from credential storage.
|
|
19
|
+
*
|
|
20
|
+
* Slack uses direct bot/app tokens (Socket Mode), not OAuth connections.
|
|
21
|
+
* The client functions accept `OAuthConnection | string`, so we return the
|
|
22
|
+
* raw token string.
|
|
23
|
+
*/
|
|
24
|
+
export async function getSlackConnection(): Promise<string> {
|
|
25
|
+
const token = await getSecureKeyAsync(
|
|
26
|
+
credentialKey("slack_channel", "bot_token"),
|
|
27
|
+
);
|
|
28
|
+
if (!token) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"No Slack bot token found. Configure Slack with: assistant credentials set --service slack_channel --field bot_token",
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return token;
|
|
19
34
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getConfig } from "../../../../config/loader.js";
|
|
2
2
|
import * as slack from "../../../../messaging/providers/slack/client.js";
|
|
3
3
|
import type { SlackConversation } from "../../../../messaging/providers/slack/types.js";
|
|
4
|
-
import type { OAuthConnection } from "../../../../oauth/connection.js";
|
|
5
4
|
import type {
|
|
6
5
|
ToolContext,
|
|
7
6
|
ToolExecutionResult,
|
|
@@ -28,7 +27,7 @@ interface ChannelDigest {
|
|
|
28
27
|
const userNameCache = new Map<string, string>();
|
|
29
28
|
|
|
30
29
|
async function resolveUserName(
|
|
31
|
-
connection:
|
|
30
|
+
connection: string,
|
|
32
31
|
userId: string,
|
|
33
32
|
): Promise<string> {
|
|
34
33
|
if (!userId) return "unknown";
|
|
@@ -50,7 +49,7 @@ async function resolveUserName(
|
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
async function scanChannel(
|
|
53
|
-
connection:
|
|
52
|
+
connection: string,
|
|
54
53
|
conv: SlackConversation,
|
|
55
54
|
oldestTs: string,
|
|
56
55
|
includeThreads: boolean,
|
|
@@ -22,7 +22,7 @@ If the user says "local", "offline", "private", or "on-device" → use `local`.
|
|
|
22
22
|
|
|
23
23
|
## Usage Notes
|
|
24
24
|
|
|
25
|
-
- The tool accepts
|
|
25
|
+
- The tool accepts a `file_path` (absolute path to a local audio or video file) to transcribe.
|
|
26
26
|
- Supported formats: any video (mp4, mov, etc.) or audio (mp3, wav, m4a, etc.) file.
|
|
27
27
|
- For video files, audio is automatically extracted via ffmpeg before transcription.
|
|
28
28
|
- The API mode has a 25MB per-request limit - large files are automatically split into chunks.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"tools": [
|
|
4
4
|
{
|
|
5
5
|
"name": "transcribe_media",
|
|
6
|
-
"description": "Transcribe an audio or video file using Whisper. Provide
|
|
6
|
+
"description": "Transcribe an audio or video file using Whisper. Provide a file_path to the media file. Set mode to 'api' (OpenAI cloud) or 'local' (whisper.cpp on-device). Ask the user which mode they prefer before calling.",
|
|
7
7
|
"category": "transcribe",
|
|
8
8
|
"risk": "low",
|
|
9
9
|
"input_schema": {
|
|
@@ -13,10 +13,6 @@
|
|
|
13
13
|
"type": "string",
|
|
14
14
|
"description": "Absolute path to a local audio or video file to transcribe"
|
|
15
15
|
},
|
|
16
|
-
"attachment_id": {
|
|
17
|
-
"type": "string",
|
|
18
|
-
"description": "The ID of an attached audio or video file to transcribe"
|
|
19
|
-
},
|
|
20
16
|
"mode": {
|
|
21
17
|
"type": "string",
|
|
22
18
|
"enum": ["api", "local"],
|
|
@@ -27,7 +23,7 @@
|
|
|
27
23
|
"description": "Brief non-technical explanation of why this tool is being called"
|
|
28
24
|
}
|
|
29
25
|
},
|
|
30
|
-
"required": ["mode"]
|
|
26
|
+
"required": ["mode", "file_path"]
|
|
31
27
|
},
|
|
32
28
|
"executor": "tools/transcribe-media.ts",
|
|
33
29
|
"execution_target": "host"
|
|
@@ -10,10 +10,6 @@ import {
|
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import { extname, join } from "node:path";
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
getAttachmentsByIds,
|
|
15
|
-
getFilePathForAttachment,
|
|
16
|
-
} from "../../../../memory/attachments-store.js";
|
|
17
13
|
import { getProviderKeyAsync } from "../../../../security/secure-keys.js";
|
|
18
14
|
import type {
|
|
19
15
|
ToolContext,
|
|
@@ -123,84 +119,31 @@ async function splitAudio(
|
|
|
123
119
|
|
|
124
120
|
async function resolveSource(
|
|
125
121
|
input: Record<string, unknown>,
|
|
126
|
-
): Promise<
|
|
127
|
-
| { inputPath: string; isVideo: boolean; tempFile: string | null }
|
|
128
|
-
| ToolExecutionResult
|
|
129
|
-
> {
|
|
122
|
+
): Promise<{ inputPath: string; isVideo: boolean } | ToolExecutionResult> {
|
|
130
123
|
const filePath = input.file_path as string | undefined;
|
|
131
|
-
const attachmentId = input.attachment_id as string | undefined;
|
|
132
124
|
|
|
133
|
-
if (filePath) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
const ext = extname(filePath).toLowerCase();
|
|
140
|
-
const isVideo = VIDEO_EXTENSIONS.has(ext);
|
|
141
|
-
const isAudio = AUDIO_EXTENSIONS.has(ext);
|
|
142
|
-
if (!isVideo && !isAudio) {
|
|
143
|
-
return {
|
|
144
|
-
content: `Unsupported file type: ${ext}. Only video and audio files can be transcribed.`,
|
|
145
|
-
isError: true,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
return { inputPath: filePath, isVideo, tempFile: null };
|
|
125
|
+
if (!filePath) {
|
|
126
|
+
return {
|
|
127
|
+
content: "Provide a file_path to the audio or video file to transcribe.",
|
|
128
|
+
isError: true,
|
|
129
|
+
};
|
|
149
130
|
}
|
|
150
131
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const mime = attachment.mimeType;
|
|
161
|
-
if (!mime.startsWith("video/") && !mime.startsWith("audio/")) {
|
|
162
|
-
return {
|
|
163
|
-
content: `Unsupported file type: ${mime}. Only video and audio files can be transcribed.`,
|
|
164
|
-
isError: true,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
// Check if this is a file-backed attachment (large files stored on disk)
|
|
168
|
-
const onDiskPath = getFilePathForAttachment(attachment.id);
|
|
169
|
-
if (onDiskPath) {
|
|
170
|
-
// File-backed attachment - use the on-disk file directly
|
|
171
|
-
try {
|
|
172
|
-
await access(onDiskPath);
|
|
173
|
-
} catch {
|
|
174
|
-
return {
|
|
175
|
-
content: `Attachment file not found on disk: ${onDiskPath}`,
|
|
176
|
-
isError: true,
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
return {
|
|
180
|
-
inputPath: onDiskPath,
|
|
181
|
-
isVideo: mime.startsWith("video/"),
|
|
182
|
-
tempFile: null,
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Inline attachment - decode base64 to a temp file
|
|
187
|
-
const ext = mime.startsWith("video/") ? ".mp4" : ".m4a";
|
|
188
|
-
const tempPath = join(
|
|
189
|
-
tmpdir(),
|
|
190
|
-
`vellum-transcribe-in-${randomUUID()}${ext}`,
|
|
191
|
-
);
|
|
192
|
-
await writeFile(tempPath, Buffer.from(attachment.dataBase64, "base64"));
|
|
132
|
+
try {
|
|
133
|
+
await access(filePath);
|
|
134
|
+
} catch {
|
|
135
|
+
return { content: `File not found: ${filePath}`, isError: true };
|
|
136
|
+
}
|
|
137
|
+
const ext = extname(filePath).toLowerCase();
|
|
138
|
+
const isVideo = VIDEO_EXTENSIONS.has(ext);
|
|
139
|
+
const isAudio = AUDIO_EXTENSIONS.has(ext);
|
|
140
|
+
if (!isVideo && !isAudio) {
|
|
193
141
|
return {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
tempFile: tempPath,
|
|
142
|
+
content: `Unsupported file type: ${ext}. Only video and audio files can be transcribed.`,
|
|
143
|
+
isError: true,
|
|
197
144
|
};
|
|
198
145
|
}
|
|
199
|
-
|
|
200
|
-
return {
|
|
201
|
-
content: "Provide either file_path or attachment_id.",
|
|
202
|
-
isError: true,
|
|
203
|
-
};
|
|
146
|
+
return { inputPath: filePath, isVideo };
|
|
204
147
|
}
|
|
205
148
|
|
|
206
149
|
/** Convert source to 16kHz mono WAV for consistent processing. */
|
|
@@ -462,7 +405,7 @@ export async function run(
|
|
|
462
405
|
const source = await resolveSource(input);
|
|
463
406
|
if ("isError" in source) return source;
|
|
464
407
|
|
|
465
|
-
const { inputPath, isVideo
|
|
408
|
+
const { inputPath, isVideo } = source;
|
|
466
409
|
let wavPath: string | null = null;
|
|
467
410
|
|
|
468
411
|
try {
|
|
@@ -487,13 +430,6 @@ export async function run(
|
|
|
487
430
|
isError: true,
|
|
488
431
|
};
|
|
489
432
|
} finally {
|
|
490
|
-
if (tempFile) {
|
|
491
|
-
try {
|
|
492
|
-
await unlink(tempFile);
|
|
493
|
-
} catch {
|
|
494
|
-
/* ignore */
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
433
|
if (wavPath) {
|
|
498
434
|
try {
|
|
499
435
|
await unlink(wavPath);
|
|
@@ -20,14 +20,8 @@ import * as acpStatus from "./bundled-skills/acp/tools/acp-status.js";
|
|
|
20
20
|
// ── app-builder ────────────────────────────────────────────────────────────────
|
|
21
21
|
import * as appCreate from "./bundled-skills/app-builder/tools/app-create.js";
|
|
22
22
|
import * as appDelete from "./bundled-skills/app-builder/tools/app-delete.js";
|
|
23
|
-
import * as appFileEdit from "./bundled-skills/app-builder/tools/app-file-edit.js";
|
|
24
|
-
import * as appFileList from "./bundled-skills/app-builder/tools/app-file-list.js";
|
|
25
|
-
import * as appFileRead from "./bundled-skills/app-builder/tools/app-file-read.js";
|
|
26
|
-
import * as appFileWrite from "./bundled-skills/app-builder/tools/app-file-write.js";
|
|
27
23
|
import * as appGenerateIcon from "./bundled-skills/app-builder/tools/app-generate-icon.js";
|
|
28
|
-
import * as
|
|
29
|
-
import * as appQuery from "./bundled-skills/app-builder/tools/app-query.js";
|
|
30
|
-
import * as appUpdate from "./bundled-skills/app-builder/tools/app-update.js";
|
|
24
|
+
import * as appRefresh from "./bundled-skills/app-builder/tools/app-refresh.js";
|
|
31
25
|
// ── browser ────────────────────────────────────────────────────────────────────
|
|
32
26
|
import * as browserClick from "./bundled-skills/browser/tools/browser-click.js";
|
|
33
27
|
import * as browserClose from "./bundled-skills/browser/tools/browser-close.js";
|
|
@@ -193,14 +187,8 @@ export const bundledToolRegistry = new Map<string, SkillToolScript>([
|
|
|
193
187
|
|
|
194
188
|
// app-builder
|
|
195
189
|
["app-builder:tools/app-create.ts", appCreate],
|
|
196
|
-
["app-builder:tools/app-list.ts", appList],
|
|
197
|
-
["app-builder:tools/app-query.ts", appQuery],
|
|
198
|
-
["app-builder:tools/app-update.ts", appUpdate],
|
|
199
190
|
["app-builder:tools/app-delete.ts", appDelete],
|
|
200
|
-
["app-builder:tools/app-
|
|
201
|
-
["app-builder:tools/app-file-read.ts", appFileRead],
|
|
202
|
-
["app-builder:tools/app-file-edit.ts", appFileEdit],
|
|
203
|
-
["app-builder:tools/app-file-write.ts", appFileWrite],
|
|
191
|
+
["app-builder:tools/app-refresh.ts", appRefresh],
|
|
204
192
|
["app-builder:tools/app-generate-icon.ts", appGenerateIcon],
|
|
205
193
|
|
|
206
194
|
// browser
|
|
@@ -25,6 +25,14 @@
|
|
|
25
25
|
"description": "Show the Contacts tab in Settings for viewing and managing contacts",
|
|
26
26
|
"defaultEnabled": true
|
|
27
27
|
},
|
|
28
|
+
{
|
|
29
|
+
"id": "custom-inference-provider",
|
|
30
|
+
"scope": "macos",
|
|
31
|
+
"key": "custom_inference_provider_enabled",
|
|
32
|
+
"label": "Custom Inference Provider",
|
|
33
|
+
"description": "Allow selecting a specific LLM provider and model for inference in Your Own mode",
|
|
34
|
+
"defaultEnabled": false
|
|
35
|
+
},
|
|
28
36
|
{
|
|
29
37
|
"id": "email-channel",
|
|
30
38
|
"scope": "assistant",
|
|
@@ -249,6 +257,14 @@
|
|
|
249
257
|
"description": "Show the Google OAuth service card in Models & Services settings",
|
|
250
258
|
"defaultEnabled": false
|
|
251
259
|
},
|
|
260
|
+
{
|
|
261
|
+
"id": "settings-embedding-provider",
|
|
262
|
+
"scope": "assistant",
|
|
263
|
+
"key": "feature_flags.settings-embedding-provider.enabled",
|
|
264
|
+
"label": "Embedding Provider Settings",
|
|
265
|
+
"description": "Show the Embedding service card in Models & Services settings",
|
|
266
|
+
"defaultEnabled": false
|
|
267
|
+
},
|
|
252
268
|
{
|
|
253
269
|
"id": "quick-input",
|
|
254
270
|
"scope": "macos",
|
|
@@ -264,6 +280,14 @@
|
|
|
264
280
|
"label": "Expand Completed Steps",
|
|
265
281
|
"description": "Auto-expand completed tool call step groups instead of showing them collapsed",
|
|
266
282
|
"defaultEnabled": false
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"id": "inline-skill-commands",
|
|
286
|
+
"scope": "assistant",
|
|
287
|
+
"key": "feature_flags.inline-skill-commands.enabled",
|
|
288
|
+
"label": "Inline Skill Command Expansion",
|
|
289
|
+
"description": "Enable secure inline skill command expansion via !`command` syntax, with version-pinned approval and sandboxed execution at skill load time",
|
|
290
|
+
"defaultEnabled": true
|
|
267
291
|
}
|
|
268
292
|
]
|
|
269
293
|
}
|
package/src/config/loader.ts
CHANGED
|
@@ -29,6 +29,7 @@ export const API_KEY_PROVIDERS = [
|
|
|
29
29
|
"fireworks",
|
|
30
30
|
"openrouter",
|
|
31
31
|
"brave",
|
|
32
|
+
"elevenlabs",
|
|
32
33
|
"perplexity",
|
|
33
34
|
] as const;
|
|
34
35
|
|
|
@@ -118,6 +119,66 @@ function deleteNestedKey(
|
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Deprecated config fields that have been removed. Each entry maps a
|
|
124
|
+
* dot-separated path to the deprecation message shown to the user.
|
|
125
|
+
*/
|
|
126
|
+
const DEPRECATED_FIELDS: Record<string, string> = {
|
|
127
|
+
"rateLimit.maxTokensPerSession":
|
|
128
|
+
"rateLimit.maxTokensPerSession has been removed and is no longer enforced. " +
|
|
129
|
+
"Per-session token budget tracking is no longer supported. " +
|
|
130
|
+
"The field will be removed from your config file.",
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Check for deprecated config fields, log a warning for each one found,
|
|
135
|
+
* and strip them from both the in-memory object and the on-disk config file
|
|
136
|
+
* so the warning is only emitted once.
|
|
137
|
+
*/
|
|
138
|
+
function warnAndStripDeprecatedFields(
|
|
139
|
+
fileConfig: Record<string, unknown>,
|
|
140
|
+
configPath: string,
|
|
141
|
+
): void {
|
|
142
|
+
const found: string[] = [];
|
|
143
|
+
for (const dotPath of Object.keys(DEPRECATED_FIELDS)) {
|
|
144
|
+
if (getNestedValue(fileConfig, dotPath) !== undefined) {
|
|
145
|
+
log.warn(DEPRECATED_FIELDS[dotPath]);
|
|
146
|
+
found.push(dotPath);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (found.length === 0) return;
|
|
151
|
+
|
|
152
|
+
// Strip from the in-memory object so Zod never sees them
|
|
153
|
+
for (const dotPath of found) {
|
|
154
|
+
deleteNestedKeyByDotPath(fileConfig, dotPath);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Persist the cleaned config to disk so the warning doesn't repeat
|
|
158
|
+
try {
|
|
159
|
+
if (existsSync(configPath)) {
|
|
160
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
161
|
+
if (raw != null && typeof raw === "object" && !Array.isArray(raw)) {
|
|
162
|
+
for (const dotPath of found) {
|
|
163
|
+
deleteNestedKeyByDotPath(raw as Record<string, unknown>, dotPath);
|
|
164
|
+
}
|
|
165
|
+
writeFileSync(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
// Best-effort — if the file can't be rewritten, the warning will repeat
|
|
170
|
+
// on next load, which is acceptable.
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function deleteNestedKeyByDotPath(
|
|
175
|
+
obj: Record<string, unknown>,
|
|
176
|
+
dotPath: string,
|
|
177
|
+
): void {
|
|
178
|
+
const keys = dotPath.split(".");
|
|
179
|
+
deleteNestedKey(obj, keys);
|
|
180
|
+
}
|
|
181
|
+
|
|
121
182
|
/**
|
|
122
183
|
* Deep-merge missing keys from `defaults` into `target`.
|
|
123
184
|
* Only adds keys that do not already exist in `target`; never overwrites.
|
|
@@ -224,6 +285,10 @@ export function loadConfig(): AssistantConfig {
|
|
|
224
285
|
configFileExisted = false;
|
|
225
286
|
}
|
|
226
287
|
|
|
288
|
+
// Warn about and strip deprecated config fields so users know their
|
|
289
|
+
// settings are no longer honored rather than silently dropping them.
|
|
290
|
+
warnAndStripDeprecatedFields(fileConfig, configPath);
|
|
291
|
+
|
|
227
292
|
// Validate and apply defaults via Zod schema
|
|
228
293
|
const config = validateWithSchema(fileConfig);
|
|
229
294
|
|