@vellumai/assistant 0.9.0 → 0.10.0-staging.2
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 +18 -34
- package/bun.lock +7 -8
- package/docs/activation-funnel-telemetry.md +28 -22
- package/docs/architecture/security.md +29 -28
- package/docs/stt-provider-onboarding.md +3 -5
- package/docs/workflows-testing.md +13 -44
- package/docs/workflows.md +3 -5
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
- package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
- package/openapi.yaml +976 -63
- package/package.json +2 -1
- package/scripts/sync-llm-catalog.ts +6 -15
- package/scripts/sync-web-search-catalog.ts +3 -11
- package/src/__tests__/access-request-card-view.test.ts +98 -0
- package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
- package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
- package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
- package/src/__tests__/app-compiler.test.ts +15 -1
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
- package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
- package/src/__tests__/avatar-identity-sync.test.ts +2 -27
- package/src/__tests__/btw-routes.test.ts +6 -8
- package/src/__tests__/call-pointer-messages.test.ts +28 -0
- package/src/__tests__/cancel-clears-processing.test.ts +89 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -4
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
- package/src/__tests__/checker.test.ts +0 -3
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
- package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
- package/src/__tests__/config-loader-backfill.test.ts +268 -27
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/config-watcher.test.ts +0 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +0 -6
- package/src/__tests__/contacts-tools.test.ts +29 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +58 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-lifecycle.test.ts +7 -9
- package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
- package/src/__tests__/conversation-title-service.test.ts +62 -0
- package/src/__tests__/credential-broker.test.ts +449 -1
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
- package/src/__tests__/credential-execution-tools.test.ts +0 -1
- package/src/__tests__/credential-prompt-route.test.ts +4 -4
- package/src/__tests__/credential-routes.test.ts +360 -0
- package/src/__tests__/credential-security-invariants.test.ts +4 -13
- package/src/__tests__/disk-pressure-policy.test.ts +12 -0
- package/src/__tests__/disk-usage.test.ts +65 -0
- package/src/__tests__/dynamic-page-surface.test.ts +152 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
- package/src/__tests__/gateway-flag-listener.test.ts +110 -1
- package/src/__tests__/gateway-only-guard.test.ts +3 -7
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
- package/src/__tests__/guardian-grant-minting.test.ts +3 -35
- package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/headless-browser-mode.test.ts +10 -0
- package/src/__tests__/headless-browser-navigate.test.ts +8 -3
- package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
- package/src/__tests__/host-browser-proxy.test.ts +87 -0
- package/src/__tests__/identity-routes.test.ts +0 -189
- package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
- package/src/__tests__/injector-v3-suppression.test.ts +27 -20
- package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
- package/src/__tests__/invite-redemption-service.test.ts +4 -7
- package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +30 -23
- package/src/__tests__/llm-resolver.test.ts +70 -24
- package/src/__tests__/llm-schema.test.ts +1 -0
- package/src/__tests__/managed-profile-guard.test.ts +163 -4
- package/src/__tests__/mcp-health-check.test.ts +6 -7
- package/src/__tests__/media-stream-server-integration.test.ts +317 -13
- package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
- package/src/__tests__/onboarding-persona-write.test.ts +1 -1
- package/src/__tests__/path-policy.test.ts +34 -0
- package/src/__tests__/persona-resolver.test.ts +49 -14
- package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
- package/src/__tests__/plugin-api-provider.test.ts +24 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
- package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
- package/src/__tests__/reaction-persistence.test.ts +150 -29
- package/src/__tests__/registry.test.ts +2 -7
- package/src/__tests__/relay-server.test.ts +285 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
- package/src/__tests__/schedule-routes.test.ts +0 -30
- package/src/__tests__/schedule-tools.test.ts +2 -18
- package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
- package/src/__tests__/skill-execute-input.test.ts +51 -1
- package/src/__tests__/skill-runtime-path.test.ts +2 -3
- package/src/__tests__/skills.test.ts +51 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
- package/src/__tests__/subagent-tools.test.ts +266 -0
- package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
- package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +100 -3
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
- package/src/__tests__/token-manager.test.ts +519 -0
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
- package/src/__tests__/tool-audit-listener.test.ts +7 -7
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
- package/src/__tests__/tool-executor.test.ts +0 -79
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
- package/src/__tests__/trusted-contact-verification.test.ts +8 -10
- package/src/__tests__/twilio-routes.test.ts +81 -1
- package/src/__tests__/voice-invite-redemption.test.ts +2 -3
- package/src/__tests__/weak-open-model.test.ts +30 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
- package/src/__tests__/workspace-greetings.test.ts +152 -0
- package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
- package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
- package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
- package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
- package/src/agent/loop.ts +49 -29
- package/src/api/README.md +6 -6
- package/src/api/events/tool-result.ts +6 -0
- package/src/api/events/workflow-completed.ts +53 -0
- package/src/api/events/workflow-leaf-finished.ts +38 -0
- package/src/api/events/workflow-leaf-started.ts +35 -0
- package/src/api/events/workflow-progress.ts +32 -0
- package/src/api/events/workflow-started.ts +31 -0
- package/src/api/index.ts +40 -0
- package/src/api/responses/conversation-message.ts +28 -4
- package/src/api/responses/home.ts +26 -4
- package/src/api/responses/workflow-journal.ts +53 -0
- package/src/approvals/guardian-card-withdrawal.ts +145 -0
- package/src/approvals/guardian-decision-primitive.ts +26 -3
- package/src/approvals/guardian-request-resolvers.ts +183 -80
- package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
- package/src/calls/call-pointer-messages.ts +10 -4
- package/src/calls/channel-admission-reader.ts +104 -0
- package/src/calls/guardian-dispatch.ts +17 -45
- package/src/calls/media-stream-server.ts +84 -2
- package/src/calls/relay-access-wait.ts +1 -1
- package/src/calls/relay-server.ts +66 -0
- package/src/calls/relay-setup-router.ts +82 -1
- package/src/calls/twilio-routes.ts +17 -8
- package/src/calls/voice-session-bridge.ts +2 -2
- package/src/cli/commands/clients.ts +3 -0
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
- package/src/cli/commands/memory/index.ts +30 -0
- package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
- package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
- package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
- package/src/cli/commands/oauth/status.test.ts +36 -0
- package/src/cli/commands/oauth/status.ts +23 -3
- package/src/cli/commands/plugins.ts +197 -4
- package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
- package/src/cli/lib/diff-plugin.ts +346 -0
- package/src/cli/lib/inspect-plugin.ts +12 -1
- package/src/cli/lib/install-from-github.ts +105 -17
- package/src/cli/lib/merge-plugin-tree.ts +328 -0
- package/src/cli/lib/plugin-fingerprint.ts +14 -0
- package/src/cli/lib/plugin-surfaces.ts +104 -0
- package/src/cli/lib/upgrade-plugin.ts +298 -10
- package/src/cli/program.ts +2 -6
- package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
- package/src/config/assistant-feature-flags.ts +22 -7
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
- package/src/config/bundled-skills/messaging/SKILL.md +6 -4
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
- package/src/config/bundled-skills/subagent/SKILL.md +4 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
- package/src/config/bundled-skills/workflows/SKILL.md +14 -8
- package/src/config/bundled-tool-registry.ts +2 -7
- package/src/config/call-site-defaults.ts +15 -2
- package/src/config/feature-flag-registry.json +46 -31
- package/src/config/inference-profile-validation.ts +26 -0
- package/src/config/llm-resolver.ts +3 -0
- package/src/config/loader.ts +4 -0
- package/src/config/memory-v3-gate.ts +11 -0
- package/src/config/profile-order.ts +28 -0
- package/src/config/schema.ts +8 -6
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/channels.ts +11 -0
- package/src/config/schemas/elevenlabs.ts +0 -1
- package/src/config/schemas/llm.ts +31 -0
- package/src/config/schemas/memory-lifecycle.ts +3 -7
- package/src/config/schemas/memory-v3.ts +6 -0
- package/src/config/schemas/platform.ts +0 -8
- package/src/config/schemas/services.ts +18 -0
- package/src/config/seed-inference-profiles.ts +109 -44
- package/src/config/skills.ts +21 -0
- package/src/config/sync-gated-profiles.ts +220 -0
- package/src/contacts/contact-store.ts +89 -106
- package/src/contacts/contacts-write.ts +5 -22
- package/src/contacts/types.ts +0 -1
- package/src/context/compactor.ts +88 -54
- package/src/context/strip-injections.ts +58 -10
- package/src/context/token-estimator.ts +1 -1
- package/src/credential-execution/process-manager.ts +55 -14
- package/src/credential-execution/prompted-credential.ts +2 -3
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
- package/src/daemon/config-watcher.ts +0 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
- package/src/daemon/conversation-agent-loop.ts +114 -22
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +3 -5
- package/src/daemon/conversation-process.ts +13 -5
- package/src/daemon/conversation-runtime-assembly.ts +13 -15
- package/src/daemon/conversation-slash.ts +2 -23
- package/src/daemon/conversation-surfaces.ts +26 -0
- package/src/daemon/conversation-tool-setup.ts +27 -14
- package/src/daemon/conversation.ts +66 -14
- package/src/daemon/disk-pressure-policy.ts +5 -3
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
- package/src/daemon/handlers/config-a2a.ts +0 -2
- package/src/daemon/handlers/config-channels.ts +15 -16
- package/src/daemon/handlers/config-slack-channel.ts +22 -3
- package/src/daemon/handlers/conversations.ts +107 -0
- package/src/daemon/host-browser-proxy.ts +41 -0
- package/src/daemon/lifecycle.ts +55 -27
- package/src/daemon/message-provenance.ts +2 -0
- package/src/daemon/message-types/contacts.ts +0 -1
- package/src/daemon/message-types/conversations.ts +3 -3
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/message-types/web-activity.ts +7 -1
- package/src/daemon/message-types/workflows.ts +83 -1
- package/src/daemon/orphan-reaper.test.ts +0 -19
- package/src/daemon/orphan-reaper.ts +2 -24
- package/src/daemon/server.ts +0 -10
- package/src/daemon/tool-setup-types.ts +4 -0
- package/src/daemon/trust-context.ts +1 -1
- package/src/events/tool-audit-listener.ts +2 -2
- package/src/home/feed-source-enrichment.test.ts +151 -0
- package/src/home/feed-source-enrichment.ts +176 -0
- package/src/home/relationship-state.ts +2 -4
- package/src/instrument.ts +18 -6
- package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
- package/src/ipc/assistant-server.ts +37 -4
- package/src/ipc/gateway-flag-listener.ts +18 -2
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
- package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
- package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
- package/src/memory/auth-fallback-events-store.ts +2 -2
- package/src/memory/auto-analysis-enqueue.ts +3 -5
- package/src/memory/bookmark-crud.ts +1 -2
- package/src/memory/canonical-guardian-store.ts +39 -1
- package/src/memory/conversation-crud.ts +9 -4
- package/src/memory/conversation-key-store.ts +17 -2
- package/src/memory/conversation-title-service.ts +64 -7
- package/src/memory/db-init.ts +17 -17
- package/src/memory/embedding-backend.ts +38 -1
- package/src/memory/embedding-billing-breaker.ts +96 -0
- package/src/memory/jobs-store.ts +25 -13
- package/src/memory/jobs-worker.ts +54 -1
- package/src/memory/lifecycle-events-store.ts +2 -2
- package/src/memory/memory-retrospective-constants.ts +4 -4
- package/src/memory/memory-retrospective-enqueue.ts +31 -6
- package/src/memory/memory-retrospective-job.ts +28 -227
- package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
- package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
- package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
- package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
- package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
- package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
- package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
- package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/run-migrations.ts +41 -0
- package/src/memory/migrations/validate-migration-state.ts +1 -1
- package/src/memory/onboarding-events-store.ts +3 -3
- package/src/memory/schema/contacts.ts +0 -5
- package/src/memory/skill-loaded-events-store.test.ts +7 -15
- package/src/memory/skill-loaded-events-store.ts +2 -2
- package/src/memory/tool-executed-events-store.test.ts +7 -7
- package/src/memory/turn-trace-store.test.ts +736 -0
- package/src/memory/turn-trace-store.ts +364 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
- package/src/memory/v2/consolidation-job.ts +2 -2
- package/src/memory/v2/skill-content.ts +25 -7
- package/src/memory/v2/skill-store.ts +7 -1
- package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
- package/src/memory/v3-eval/eval-packets.ts +546 -0
- package/src/messaging/providers/slack/adapter.ts +1 -1
- package/src/messaging/providers/slack/api.ts +31 -0
- package/src/messaging/providers/slack/send.test.ts +114 -2
- package/src/messaging/providers/slack/send.ts +30 -7
- package/src/messaging/providers/slack/withdraw.test.ts +200 -0
- package/src/messaging/providers/slack/withdraw.ts +161 -0
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/access-request-copy.ts +72 -59
- package/src/notifications/adapters/shared.ts +29 -0
- package/src/notifications/adapters/slack.ts +58 -103
- package/src/notifications/adapters/telegram.ts +2 -20
- package/src/notifications/approval-card-data.ts +333 -0
- package/src/notifications/broadcaster.ts +16 -3
- package/src/notifications/canonical-delivery-recorder.ts +139 -0
- package/src/notifications/copy-composer.ts +3 -3
- package/src/notifications/decision-engine.ts +4 -2
- package/src/notifications/destination-resolver.ts +4 -6
- package/src/notifications/guardian-question-mode.ts +10 -0
- package/src/notifications/home-feed-side-effect.ts +7 -16
- package/src/notifications/notification-utils.ts +19 -20
- package/src/notifications/signal.ts +79 -43
- package/src/notifications/types.ts +98 -121
- package/src/oauth/AGENTS.md +5 -24
- package/src/permissions/checker.test.ts +51 -0
- package/src/permissions/checker.ts +185 -26
- package/src/permissions/ipc-risk-types.ts +24 -0
- package/src/permissions/question-prompter.test.ts +27 -0
- package/src/permissions/question-prompter.ts +4 -0
- package/src/platform/client.test.ts +119 -0
- package/src/platform/client.ts +66 -0
- package/src/platform/consent-cache.test.ts +267 -0
- package/src/platform/consent-cache.ts +174 -0
- package/src/plugin-api/constants.ts +1 -1
- package/src/plugin-api/index.ts +33 -1
- package/src/plugin-api/model-profiles.ts +33 -0
- package/src/plugin-api/types.ts +50 -2
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
- package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
- package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
- package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
- package/src/plugins/defaults/advisor/config.ts +21 -0
- package/src/plugins/defaults/advisor/consult.ts +93 -0
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/advisor/package.json +14 -0
- package/src/plugins/defaults/advisor/steering.ts +67 -0
- package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
- package/src/plugins/defaults/advisor/transcript.ts +76 -0
- package/src/plugins/defaults/index.ts +60 -0
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
- package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
- package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
- package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
- package/src/prompts/persona-resolver.ts +14 -4
- package/src/prompts/templates/system-sections.ts +7 -2
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +176 -0
- package/src/providers/atlascloud/client.ts +85 -0
- package/src/providers/fetch-provider-catalog.ts +85 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/model-catalog.ts +58 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
- package/src/providers/openai/chat-completions-provider.ts +7 -0
- package/src/providers/openai/responses-provider.ts +10 -0
- package/src/providers/provider-send-message.ts +11 -3
- package/src/providers/retry.ts +53 -12
- package/src/providers/search-provider-catalog.ts +10 -0
- package/src/providers/weak-open-model.ts +22 -0
- package/src/runtime/AGENTS.md +0 -1
- package/src/runtime/__tests__/agent-wake.test.ts +181 -0
- package/src/runtime/__tests__/client-health.test.ts +44 -0
- package/src/runtime/access-request-helper.ts +21 -53
- package/src/runtime/actor-trust-resolver.ts +59 -63
- package/src/runtime/agent-wake.ts +52 -0
- package/src/runtime/assistant-event-hub.ts +18 -4
- package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
- package/src/runtime/auth/require-bound-guardian.ts +1 -4
- package/src/runtime/btw-sidechain.ts +3 -6
- package/src/runtime/capabilities.test.ts +120 -0
- package/src/runtime/capabilities.ts +197 -0
- package/src/runtime/channel-approval-types.ts +22 -45
- package/src/runtime/channel-invite-transports/telegram.ts +4 -4
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/channel-verification-service.ts +3 -3
- package/src/runtime/client-health.ts +26 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
- package/src/runtime/effective-capabilities.test.ts +128 -0
- package/src/runtime/effective-capabilities.ts +84 -0
- package/src/runtime/guardian-reply-router.ts +106 -21
- package/src/runtime/invite-redemption-service.ts +9 -25
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +123 -0
- package/src/runtime/migrations/vbundle-builder.ts +49 -20
- package/src/runtime/pending-interactions.ts +15 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +240 -1
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
- package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
- package/src/runtime/routes/browser-tabs-routes.ts +9 -0
- package/src/runtime/routes/btw-routes.ts +1 -27
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
- package/src/runtime/routes/client-routes.ts +10 -0
- package/src/runtime/routes/contact-routes.ts +31 -8
- package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
- package/src/runtime/routes/conversation-management-routes.ts +80 -1
- package/src/runtime/routes/conversation-query-routes.ts +68 -22
- package/src/runtime/routes/conversation-routes.ts +39 -14
- package/src/runtime/routes/credential-routes.ts +40 -16
- package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
- package/src/runtime/routes/events-routes.ts +1 -3
- package/src/runtime/routes/guardian-approval-interception.ts +14 -73
- package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
- package/src/runtime/routes/home-feed-routes.ts +8 -3
- package/src/runtime/routes/identity-routes.ts +1 -296
- package/src/runtime/routes/inbound-message-handler.ts +214 -228
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
- package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
- package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
- package/src/runtime/routes/integrations/slack/channel.ts +36 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
- package/src/runtime/routes/mcp-auth-routes.ts +233 -41
- package/src/runtime/routes/memory-eval-routes.ts +87 -0
- package/src/runtime/routes/notification-routes.ts +122 -133
- package/src/runtime/routes/platform-routes.ts +2 -2
- package/src/runtime/routes/plugins-routes.ts +202 -3
- package/src/runtime/routes/schedule-routes.ts +0 -22
- package/src/runtime/routes/secret-routes.ts +10 -0
- package/src/runtime/routes/surface-action-routes.ts +2 -1
- package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
- package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
- package/src/runtime/routes/workflow-routes.test.ts +229 -44
- package/src/runtime/routes/workflow-routes.ts +131 -29
- package/src/runtime/routes/workspace-greetings.ts +55 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -11
- package/src/runtime/tool-grant-request-helper.ts +18 -16
- package/src/runtime/trust-context-resolver.ts +8 -5
- package/src/schedule/inference-profile.ts +2 -14
- package/src/schedule/schedule-store.ts +1 -1
- package/src/schedule/scheduler-types.ts +5 -1
- package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
- package/src/security/secret-patterns.ts +3 -0
- package/src/subagent/manager.ts +17 -4
- package/src/subagent/types.ts +6 -0
- package/src/telemetry/trace-collection-policy.test.ts +28 -0
- package/src/telemetry/trace-collection-policy.ts +30 -0
- package/src/telemetry/types.ts +89 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
- package/src/telemetry/usage-telemetry-reporter.ts +148 -41
- package/src/tools/AGENTS.md +3 -3
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
- package/src/tools/browser/browser-execution.ts +30 -19
- package/src/tools/document/document-tool.ts +2 -3
- package/src/tools/executor.ts +5 -3
- package/src/tools/host-terminal/host-shell.ts +5 -4
- package/src/tools/memory/register.ts +2 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
- package/src/tools/network/__tests__/web-search.test.ts +143 -0
- package/src/tools/network/web-fetch.ts +372 -1
- package/src/tools/network/web-search-error.ts +1 -1
- package/src/tools/network/web-search.ts +213 -10
- package/src/tools/permission-checker.ts +4 -3
- package/src/tools/registry.ts +20 -0
- package/src/tools/schedule/create.ts +7 -12
- package/src/tools/schedule/update.ts +4 -11
- package/src/tools/shared/filesystem/path-policy.ts +39 -13
- package/src/tools/side-effects.ts +2 -17
- package/src/tools/skills/execute.ts +33 -0
- package/src/tools/subagent/spawn.ts +61 -12
- package/src/tools/terminal/shell.ts +10 -4
- package/src/tools/tool-approval-handler.ts +18 -13
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/types.ts +9 -0
- package/src/tools/ui-surface/definitions.ts +64 -3
- package/src/tools/verification-control-plane-policy.ts +3 -1
- package/src/tools/workflows/run-workflow.test.ts +8 -18
- package/src/tools/workflows/run-workflow.ts +1 -0
- package/src/util/disk-usage.ts +78 -23
- package/src/util/platform.ts +10 -3
- package/src/watcher/telemetry.ts +2 -2
- package/src/workflows/capabilities.ts +2 -3
- package/src/workflows/engine.test.ts +175 -1
- package/src/workflows/engine.ts +82 -0
- package/src/workflows/journal-store.test.ts +70 -0
- package/src/workflows/journal-store.ts +18 -3
- package/src/workflows/run-manager.test.ts +171 -28
- package/src/workflows/run-manager.ts +66 -24
- package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
- package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
- package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
- package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
- package/src/__tests__/credential-security-e2e.test.ts +0 -362
- package/src/__tests__/credential-vault-unit.test.ts +0 -1528
- package/src/__tests__/credential-vault.test.ts +0 -1706
- package/src/__tests__/identity-intro-cache.test.ts +0 -315
- package/src/__tests__/secret-onetime-send.test.ts +0 -182
- package/src/cli/commands/__tests__/task.test.ts +0 -914
- package/src/cli/commands/task.ts +0 -771
- package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
- package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
- package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
- package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
- package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
- package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
- package/src/memory/preloaded-apps.ts +0 -116
- package/src/notifications/tool-approval-copy.ts +0 -142
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
- package/src/runtime/routes/identity-intro-cache.ts +0 -172
- package/src/tools/credentials/vault.ts +0 -712
|
@@ -35,8 +35,9 @@ const BRAVE_SEARCH_PATH = "/res/v1/web/search";
|
|
|
35
35
|
const BRAVE_API_URL = `https://api.search.brave.com${BRAVE_SEARCH_PATH}`;
|
|
36
36
|
const PERPLEXITY_API_URL = "https://api.perplexity.ai/chat/completions";
|
|
37
37
|
const TAVILY_API_URL = "https://api.tavily.com/search";
|
|
38
|
+
const FIRECRAWL_API_URL = "https://api.firecrawl.dev/v2/search";
|
|
38
39
|
|
|
39
|
-
type WebSearchProvider = "perplexity" | "brave" | "tavily";
|
|
40
|
+
type WebSearchProvider = "perplexity" | "brave" | "tavily" | "firecrawl";
|
|
40
41
|
type WebSearchMode = "managed" | "your-own";
|
|
41
42
|
|
|
42
43
|
/**
|
|
@@ -108,6 +109,28 @@ interface TavilySearchResponse {
|
|
|
108
109
|
results?: TavilySearchResult[];
|
|
109
110
|
}
|
|
110
111
|
|
|
112
|
+
interface FirecrawlSearchResult {
|
|
113
|
+
title?: string;
|
|
114
|
+
description?: string;
|
|
115
|
+
url?: string;
|
|
116
|
+
category?: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Firecrawl `/v2/search` returns one array per requested source under `data`
|
|
121
|
+
* (defaults to `web`). We request only `web`, so that is the array we read;
|
|
122
|
+
* `news`/`images` are typed loosely since we never request them here.
|
|
123
|
+
*/
|
|
124
|
+
interface FirecrawlSearchResponse {
|
|
125
|
+
success?: boolean;
|
|
126
|
+
data?: {
|
|
127
|
+
web?: FirecrawlSearchResult[];
|
|
128
|
+
news?: FirecrawlSearchResult[];
|
|
129
|
+
images?: unknown[];
|
|
130
|
+
};
|
|
131
|
+
warning?: string | null;
|
|
132
|
+
}
|
|
133
|
+
|
|
111
134
|
function getWebSearchProvider(): WebSearchProvider {
|
|
112
135
|
const config = getConfig();
|
|
113
136
|
const configured = config.services["web-search"].provider ?? "perplexity";
|
|
@@ -229,6 +252,34 @@ function formatTavilyResults(
|
|
|
229
252
|
return lines.join("\n");
|
|
230
253
|
}
|
|
231
254
|
|
|
255
|
+
function formatFirecrawlResults(
|
|
256
|
+
data: FirecrawlSearchResponse,
|
|
257
|
+
query: string,
|
|
258
|
+
): string {
|
|
259
|
+
const results = data.data?.web ?? [];
|
|
260
|
+
|
|
261
|
+
if (results.length === 0) {
|
|
262
|
+
return `No results found for "${query}".`;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const lines: string[] = [`Web search results for "${query}":\n`];
|
|
266
|
+
|
|
267
|
+
for (let i = 0; i < results.length; i++) {
|
|
268
|
+
const r = results[i];
|
|
269
|
+
const title = r.title?.trim() || r.url?.trim() || "Untitled result";
|
|
270
|
+
lines.push(`${i + 1}. ${title}`);
|
|
271
|
+
if (r.url) {
|
|
272
|
+
lines.push(` URL: ${r.url}`);
|
|
273
|
+
}
|
|
274
|
+
if (r.description) {
|
|
275
|
+
lines.push(` ${r.description}`);
|
|
276
|
+
}
|
|
277
|
+
lines.push("");
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return lines.join("\n");
|
|
281
|
+
}
|
|
282
|
+
|
|
232
283
|
function buildBraveMetadata(
|
|
233
284
|
results: BraveSearchResult[],
|
|
234
285
|
query: string,
|
|
@@ -365,6 +416,55 @@ function tavilyTimeRangeForFreshness(
|
|
|
365
416
|
}
|
|
366
417
|
}
|
|
367
418
|
|
|
419
|
+
function buildFirecrawlMetadata(
|
|
420
|
+
data: FirecrawlSearchResponse,
|
|
421
|
+
query: string,
|
|
422
|
+
durationMs: number,
|
|
423
|
+
): WebSearchMetadata {
|
|
424
|
+
const results = data.data?.web ?? [];
|
|
425
|
+
const items: WebSearchResultItem[] = results.map((r, i) => {
|
|
426
|
+
const url = r.url ?? "";
|
|
427
|
+
const domain = extractDomain(url);
|
|
428
|
+
return {
|
|
429
|
+
rank: i + 1,
|
|
430
|
+
title: r.title?.trim() || url.trim() || "Untitled result",
|
|
431
|
+
url,
|
|
432
|
+
domain,
|
|
433
|
+
faviconUrl: faviconUrlForDomain(domain),
|
|
434
|
+
snippet: r.description,
|
|
435
|
+
};
|
|
436
|
+
});
|
|
437
|
+
return {
|
|
438
|
+
query,
|
|
439
|
+
provider: "firecrawl",
|
|
440
|
+
resultCount: items.length,
|
|
441
|
+
durationMs,
|
|
442
|
+
results: items,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Map the tool's `freshness` window onto Firecrawl's `tbs` time filter
|
|
448
|
+
* (`qdr:d` / `qdr:w` / `qdr:m` / `qdr:y`). Returns `undefined` for an
|
|
449
|
+
* unrecognized value so the request omits `tbs` entirely.
|
|
450
|
+
*/
|
|
451
|
+
function firecrawlTbsForFreshness(
|
|
452
|
+
freshness: string | undefined,
|
|
453
|
+
): "qdr:d" | "qdr:w" | "qdr:m" | "qdr:y" | undefined {
|
|
454
|
+
switch (freshness) {
|
|
455
|
+
case "pd":
|
|
456
|
+
return "qdr:d";
|
|
457
|
+
case "pw":
|
|
458
|
+
return "qdr:w";
|
|
459
|
+
case "pm":
|
|
460
|
+
return "qdr:m";
|
|
461
|
+
case "py":
|
|
462
|
+
return "qdr:y";
|
|
463
|
+
default:
|
|
464
|
+
return undefined;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
368
468
|
function errorResult(
|
|
369
469
|
query: string,
|
|
370
470
|
provider: WebSearchProvider,
|
|
@@ -396,8 +496,7 @@ function errorResult(
|
|
|
396
496
|
*/
|
|
397
497
|
function rawBodyDetail(body: unknown): { message: string } | undefined {
|
|
398
498
|
if (body == null) return undefined;
|
|
399
|
-
const text =
|
|
400
|
-
typeof body === "string" ? body : safeStringifyBody(body);
|
|
499
|
+
const text = typeof body === "string" ? body : safeStringifyBody(body);
|
|
401
500
|
const trimmed = text.trim();
|
|
402
501
|
return trimmed ? { message: trimmed } : undefined;
|
|
403
502
|
}
|
|
@@ -602,10 +701,7 @@ async function executeManagedBraveSearch(
|
|
|
602
701
|
if (!proxyResult.ok) {
|
|
603
702
|
// Keep billing/auth/unavailable mapping as specific copy; route genuine
|
|
604
703
|
// platform 5xx (transport-level failures) to the friendly backend helper.
|
|
605
|
-
if (
|
|
606
|
-
proxyResult.kind === "platform-error" &&
|
|
607
|
-
proxyResult.status >= 500
|
|
608
|
-
) {
|
|
704
|
+
if (proxyResult.kind === "platform-error" && proxyResult.status >= 500) {
|
|
609
705
|
return backendFailureResult(
|
|
610
706
|
query,
|
|
611
707
|
"brave",
|
|
@@ -868,6 +964,104 @@ async function executeTavilySearch(
|
|
|
868
964
|
);
|
|
869
965
|
}
|
|
870
966
|
|
|
967
|
+
async function executeFirecrawlSearch(
|
|
968
|
+
query: string,
|
|
969
|
+
count: number,
|
|
970
|
+
freshness: string | undefined,
|
|
971
|
+
apiKey: string,
|
|
972
|
+
signal?: AbortSignal,
|
|
973
|
+
): Promise<ToolExecutionResult> {
|
|
974
|
+
const tbs = firecrawlTbsForFreshness(freshness);
|
|
975
|
+
const body: Record<string, unknown> = {
|
|
976
|
+
query,
|
|
977
|
+
limit: count,
|
|
978
|
+
sources: ["web"],
|
|
979
|
+
};
|
|
980
|
+
if (tbs) {
|
|
981
|
+
body.tbs = tbs;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
const startedAt = Date.now();
|
|
985
|
+
|
|
986
|
+
for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
|
|
987
|
+
let response: Response;
|
|
988
|
+
try {
|
|
989
|
+
response = await fetch(FIRECRAWL_API_URL, {
|
|
990
|
+
method: "POST",
|
|
991
|
+
headers: {
|
|
992
|
+
"Content-Type": "application/json",
|
|
993
|
+
Authorization: `Bearer ${apiKey}`,
|
|
994
|
+
"X-Client-Source": "vellum-assistant",
|
|
995
|
+
},
|
|
996
|
+
body: JSON.stringify(body),
|
|
997
|
+
signal,
|
|
998
|
+
});
|
|
999
|
+
} catch (err) {
|
|
1000
|
+
return networkFailureResult(query, "firecrawl", startedAt, err, signal);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
if (response.ok) {
|
|
1004
|
+
const data = (await response.json()) as FirecrawlSearchResponse;
|
|
1005
|
+
const durationMs = Date.now() - startedAt;
|
|
1006
|
+
return {
|
|
1007
|
+
content:
|
|
1008
|
+
wrapUntrustedContent(formatFirecrawlResults(data, query), {
|
|
1009
|
+
source: "search",
|
|
1010
|
+
sourceDetail: "firecrawl",
|
|
1011
|
+
}) + CITATION_INSTRUCTION,
|
|
1012
|
+
isError: false,
|
|
1013
|
+
activityMetadata: {
|
|
1014
|
+
webSearch: buildFirecrawlMetadata(data, query, durationMs),
|
|
1015
|
+
},
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
const bodyText = await response.text();
|
|
1020
|
+
|
|
1021
|
+
if (response.status === 401 || response.status === 403) {
|
|
1022
|
+
return errorResult(
|
|
1023
|
+
query,
|
|
1024
|
+
"firecrawl",
|
|
1025
|
+
startedAt,
|
|
1026
|
+
"Invalid or expired Firecrawl API key",
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
if (response.status === 429 && attempt < DEFAULT_MAX_RETRIES) {
|
|
1031
|
+
const delayMs = getHttpRetryDelay(
|
|
1032
|
+
response,
|
|
1033
|
+
attempt,
|
|
1034
|
+
DEFAULT_BASE_DELAY_MS,
|
|
1035
|
+
);
|
|
1036
|
+
log.warn(
|
|
1037
|
+
{ attempt: attempt + 1, delayMs },
|
|
1038
|
+
"Firecrawl Search rate limited, retrying",
|
|
1039
|
+
);
|
|
1040
|
+
await sleep(delayMs);
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
log.warn({ status: response.status }, "Firecrawl Search API error");
|
|
1045
|
+
return backendFailureResult(
|
|
1046
|
+
query,
|
|
1047
|
+
"firecrawl",
|
|
1048
|
+
startedAt,
|
|
1049
|
+
{ statusCode: response.status, error: rawBodyDetail(bodyText) },
|
|
1050
|
+
response.status === 429
|
|
1051
|
+
? "Firecrawl Search rate limit exceeded after retries. Try again shortly."
|
|
1052
|
+
: `Firecrawl Search API returned status ${response.status}`,
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
return backendFailureResult(
|
|
1057
|
+
query,
|
|
1058
|
+
"firecrawl",
|
|
1059
|
+
startedAt,
|
|
1060
|
+
{ statusCode: 429 },
|
|
1061
|
+
"Firecrawl Search rate limit exceeded after retries. Try again shortly.",
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
871
1065
|
// ----------------------------------------------------------------------------
|
|
872
1066
|
// Adapter registry
|
|
873
1067
|
//
|
|
@@ -909,6 +1103,14 @@ const tavilySearchAdapter: WebSearchAdapter = {
|
|
|
909
1103
|
executeTavilySearch(query, count, freshness, apiKey, signal),
|
|
910
1104
|
};
|
|
911
1105
|
|
|
1106
|
+
const firecrawlSearchAdapter: WebSearchAdapter = {
|
|
1107
|
+
id: "firecrawl",
|
|
1108
|
+
providerKeyName: "firecrawl",
|
|
1109
|
+
fallbackOrder: 4,
|
|
1110
|
+
execute: ({ query, count, freshness, apiKey, signal }) =>
|
|
1111
|
+
executeFirecrawlSearch(query, count, freshness, apiKey, signal),
|
|
1112
|
+
};
|
|
1113
|
+
|
|
912
1114
|
/**
|
|
913
1115
|
* All built-in web-search adapters keyed by provider id. The
|
|
914
1116
|
* `Record<WebSearchProvider, ...>` shape forces TypeScript to flag any
|
|
@@ -918,6 +1120,7 @@ const WEB_SEARCH_ADAPTERS: Record<WebSearchProvider, WebSearchAdapter> = {
|
|
|
918
1120
|
perplexity: perplexitySearchAdapter,
|
|
919
1121
|
brave: braveSearchAdapter,
|
|
920
1122
|
tavily: tavilySearchAdapter,
|
|
1123
|
+
firecrawl: firecrawlSearchAdapter,
|
|
921
1124
|
};
|
|
922
1125
|
|
|
923
1126
|
/**
|
|
@@ -949,7 +1152,7 @@ export const webSearchTool = {
|
|
|
949
1152
|
count: {
|
|
950
1153
|
type: "number",
|
|
951
1154
|
description:
|
|
952
|
-
"Number of results to return (1-20, default 10). Used with Brave and
|
|
1155
|
+
"Number of results to return (1-20, default 10). Used with Brave, Tavily, and Firecrawl providers.",
|
|
953
1156
|
},
|
|
954
1157
|
offset: {
|
|
955
1158
|
type: "number",
|
|
@@ -959,7 +1162,7 @@ export const webSearchTool = {
|
|
|
959
1162
|
freshness: {
|
|
960
1163
|
type: "string",
|
|
961
1164
|
description:
|
|
962
|
-
'Filter by recency: "pd" (past day), "pw" (past week), "pm" (past month), "py" (past year). Used with Brave and
|
|
1165
|
+
'Filter by recency: "pd" (past day), "pw" (past week), "pm" (past month), "py" (past year). Used with Brave, Tavily, and Firecrawl providers.',
|
|
963
1166
|
},
|
|
964
1167
|
},
|
|
965
1168
|
required: ["query"],
|
|
@@ -1039,7 +1242,7 @@ export const webSearchTool = {
|
|
|
1039
1242
|
query,
|
|
1040
1243
|
provider,
|
|
1041
1244
|
startedAt,
|
|
1042
|
-
"No web search API key configured. Set it via `keys set perplexity <key>`, `keys set brave <key>`, or `keys set
|
|
1245
|
+
"No web search API key configured. Set it via `keys set perplexity <key>`, `keys set brave <key>`, `keys set tavily <key>`, or `keys set firecrawl <key>`, or configure it from the Settings page under API Keys.",
|
|
1043
1246
|
);
|
|
1044
1247
|
}
|
|
1045
1248
|
}
|
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
RiskThreshold,
|
|
17
17
|
} from "../permissions/types.js";
|
|
18
18
|
import { RiskLevel } from "../permissions/types.js";
|
|
19
|
+
import { resolveCapabilities } from "../runtime/capabilities.js";
|
|
19
20
|
import { getLogger } from "../util/logger.js";
|
|
20
21
|
import { buildPolicyContext } from "./policy-context.js";
|
|
21
22
|
import { isSideEffectTool } from "./side-effects.js";
|
|
@@ -173,7 +174,7 @@ export class PermissionChecker {
|
|
|
173
174
|
if (
|
|
174
175
|
context.forcePromptSideEffects &&
|
|
175
176
|
result.decision === "allow" &&
|
|
176
|
-
isSideEffectTool(name
|
|
177
|
+
isSideEffectTool(name)
|
|
177
178
|
) {
|
|
178
179
|
result.decision = "prompt";
|
|
179
180
|
result.reason = "Side-effect tool requires explicit approval";
|
|
@@ -238,7 +239,7 @@ export class PermissionChecker {
|
|
|
238
239
|
result.decision === "prompt" &&
|
|
239
240
|
context.isPlatformHosted &&
|
|
240
241
|
name === "bash" &&
|
|
241
|
-
context.trustClass
|
|
242
|
+
resolveCapabilities(context.trustClass).canSelfApproveTools &&
|
|
242
243
|
!context.requireFreshApproval
|
|
243
244
|
) {
|
|
244
245
|
log.info(
|
|
@@ -274,7 +275,7 @@ export class PermissionChecker {
|
|
|
274
275
|
true;
|
|
275
276
|
if (
|
|
276
277
|
context.isInteractive === false &&
|
|
277
|
-
context.trustClass
|
|
278
|
+
resolveCapabilities(context.trustClass).canSelfApproveTools &&
|
|
278
279
|
!context.requireFreshApproval &&
|
|
279
280
|
!isDynamicSkillLoad
|
|
280
281
|
) {
|
package/src/tools/registry.ts
CHANGED
|
@@ -548,6 +548,26 @@ export function getMcpToolDefinitions(): Tool[] {
|
|
|
548
548
|
);
|
|
549
549
|
}
|
|
550
550
|
|
|
551
|
+
/**
|
|
552
|
+
* Return MCP tools grouped by their owning server ID. Each entry contains
|
|
553
|
+
* the server ID and the tool definitions registered by that server.
|
|
554
|
+
*/
|
|
555
|
+
export function getMcpToolsByServer(): Map<string, Tool[]> {
|
|
556
|
+
const byServer = new Map<string, Tool[]>();
|
|
557
|
+
for (const [name, owner] of ownersByName) {
|
|
558
|
+
if (owner.kind !== "mcp") continue;
|
|
559
|
+
const tool = tools.get(name);
|
|
560
|
+
if (!tool) continue;
|
|
561
|
+
let list = byServer.get(owner.id);
|
|
562
|
+
if (!list) {
|
|
563
|
+
list = [];
|
|
564
|
+
byServer.set(owner.id, list);
|
|
565
|
+
}
|
|
566
|
+
list.push(tool);
|
|
567
|
+
}
|
|
568
|
+
return byServer;
|
|
569
|
+
}
|
|
570
|
+
|
|
551
571
|
/**
|
|
552
572
|
* Return the names of all currently registered skill-origin tools.
|
|
553
573
|
*/
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getConfig } from "../../config/loader.js";
|
|
1
|
+
import { resolveCapabilities } from "../../runtime/capabilities.js";
|
|
3
2
|
import { validateScheduleInferenceProfile } from "../../schedule/inference-profile.js";
|
|
4
3
|
import { formatIntegrationSummary } from "../../schedule/integration-status.js";
|
|
5
4
|
import { validateRruleSetLines } from "../../schedule/recurrence-engine.js";
|
|
@@ -17,7 +16,7 @@ import {
|
|
|
17
16
|
} from "../../schedule/schedule-store.js";
|
|
18
17
|
import {
|
|
19
18
|
CapabilityManifestSchema,
|
|
20
|
-
resolveCapabilities,
|
|
19
|
+
resolveCapabilities as resolveWorkflowCapabilities,
|
|
21
20
|
} from "../../workflows/capabilities.js";
|
|
22
21
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
23
22
|
|
|
@@ -32,7 +31,7 @@ export async function executeScheduleCreate(
|
|
|
32
31
|
input: Record<string, unknown>,
|
|
33
32
|
context: ToolContext,
|
|
34
33
|
): Promise<ToolExecutionResult> {
|
|
35
|
-
if (context.trustClass
|
|
34
|
+
if (!resolveCapabilities(context.trustClass).canManageSchedules) {
|
|
36
35
|
return {
|
|
37
36
|
content:
|
|
38
37
|
"Error: schedule_create is restricted to guardian actors because schedules execute with elevated privileges.",
|
|
@@ -121,13 +120,9 @@ export async function executeScheduleCreate(
|
|
|
121
120
|
};
|
|
122
121
|
}
|
|
123
122
|
} else if (mode === "workflow") {
|
|
124
|
-
// Workflow mode
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
// path and the settings route enforce the same shape.
|
|
128
|
-
if (!isAssistantFeatureFlagEnabled("workflows", getConfig())) {
|
|
129
|
-
return { content: "Error: workflows are not enabled.", isError: true };
|
|
130
|
-
}
|
|
123
|
+
// Workflow mode requires a saved workflow name — mirrors the HTTP route's
|
|
124
|
+
// create-side validation so the assistant-facing path and the settings route
|
|
125
|
+
// enforce the same shape.
|
|
131
126
|
if (!workflowName) {
|
|
132
127
|
return {
|
|
133
128
|
content:
|
|
@@ -144,7 +139,7 @@ export async function executeScheduleCreate(
|
|
|
144
139
|
if (input.capabilities !== undefined) {
|
|
145
140
|
try {
|
|
146
141
|
const manifest = CapabilityManifestSchema.parse(input.capabilities);
|
|
147
|
-
|
|
142
|
+
resolveWorkflowCapabilities(manifest);
|
|
148
143
|
capabilities = manifest;
|
|
149
144
|
} catch (err) {
|
|
150
145
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getConfig } from "../../config/loader.js";
|
|
1
|
+
import { resolveCapabilities } from "../../runtime/capabilities.js";
|
|
3
2
|
import { validateScheduleInferenceProfile } from "../../schedule/inference-profile.js";
|
|
4
3
|
import { validateRruleSetLines } from "../../schedule/recurrence-engine.js";
|
|
5
4
|
import {
|
|
@@ -31,7 +30,7 @@ export async function executeScheduleUpdate(
|
|
|
31
30
|
input: Record<string, unknown>,
|
|
32
31
|
context: ToolContext,
|
|
33
32
|
): Promise<ToolExecutionResult> {
|
|
34
|
-
if (context.trustClass
|
|
33
|
+
if (!resolveCapabilities(context.trustClass).canManageSchedules) {
|
|
35
34
|
return {
|
|
36
35
|
content:
|
|
37
36
|
"Error: schedule_update is restricted to guardian actors because schedules execute with elevated privileges.",
|
|
@@ -205,8 +204,8 @@ export async function executeScheduleUpdate(
|
|
|
205
204
|
};
|
|
206
205
|
}
|
|
207
206
|
|
|
208
|
-
// Mirror the HTTP route: a schedule whose RESULTING mode is `workflow` must
|
|
209
|
-
//
|
|
207
|
+
// Mirror the HTTP route: a schedule whose RESULTING mode is `workflow` must
|
|
208
|
+
// carry a non-empty workflowName. Compute the post-update
|
|
210
209
|
// state (the update's value if present, else the persisted one) so both
|
|
211
210
|
// "switch to workflow without a name" and "clear the name on a workflow
|
|
212
211
|
// schedule" are rejected — otherwise the scheduler hits the `!job.workflowName`
|
|
@@ -217,12 +216,6 @@ export async function executeScheduleUpdate(
|
|
|
217
216
|
const resultingMode =
|
|
218
217
|
updates.mode !== undefined ? (updates.mode as string) : existing.mode;
|
|
219
218
|
if (resultingMode === "workflow") {
|
|
220
|
-
if (!isAssistantFeatureFlagEnabled("workflows", getConfig())) {
|
|
221
|
-
return {
|
|
222
|
-
content: "Error: workflows are not enabled.",
|
|
223
|
-
isError: true,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
219
|
const resultingWorkflowName =
|
|
227
220
|
updates.workflowName !== undefined
|
|
228
221
|
? ((updates.workflowName as string | null) ?? "")
|
|
@@ -31,6 +31,40 @@ export type PathResult =
|
|
|
31
31
|
const CONTAINER_WORKSPACE_PREFIX = "/workspace/";
|
|
32
32
|
const CONTAINER_WORKSPACE_EXACT = "/workspace";
|
|
33
33
|
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Symlink resolution
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Resolve symlinks in an absolute path.
|
|
40
|
+
*
|
|
41
|
+
* For an existing path, returns its `realpathSync`. For a path that does not
|
|
42
|
+
* exist yet (e.g. a `file_write` target), walks up to the nearest existing
|
|
43
|
+
* ancestor, resolves that ancestor via `realpathSync`, then re-appends the
|
|
44
|
+
* trailing (non-existent) components — so a symlink anywhere in the existing
|
|
45
|
+
* prefix is still followed. Falls back to the lexical input when nothing on
|
|
46
|
+
* the path resolves (e.g. the path lives on a filesystem this process cannot
|
|
47
|
+
* see, as with host_file paths proxied to a remote client).
|
|
48
|
+
*
|
|
49
|
+
* Used both for sandbox-boundary enforcement and to canonicalize paths before
|
|
50
|
+
* security risk classification, so a symlink cannot mask the true target of a
|
|
51
|
+
* file operation.
|
|
52
|
+
*/
|
|
53
|
+
export function resolveRealPath(absolutePath: string): string {
|
|
54
|
+
let current = absolutePath;
|
|
55
|
+
const trailing: string[] = [];
|
|
56
|
+
while (current !== dirname(current)) {
|
|
57
|
+
try {
|
|
58
|
+
const real = realpathSync(current);
|
|
59
|
+
return trailing.length > 0 ? join(real, ...trailing) : real;
|
|
60
|
+
} catch {
|
|
61
|
+
trailing.unshift(basename(current));
|
|
62
|
+
current = dirname(current);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return absolutePath;
|
|
66
|
+
}
|
|
67
|
+
|
|
34
68
|
// ---------------------------------------------------------------------------
|
|
35
69
|
// Sandbox policy
|
|
36
70
|
// ---------------------------------------------------------------------------
|
|
@@ -82,18 +116,7 @@ export function sandboxPolicy(
|
|
|
82
116
|
realResolved = resolved;
|
|
83
117
|
}
|
|
84
118
|
} else {
|
|
85
|
-
|
|
86
|
-
const trailing: string[] = [];
|
|
87
|
-
while (current !== dirname(current)) {
|
|
88
|
-
try {
|
|
89
|
-
const real = realpathSync(current);
|
|
90
|
-
realResolved = trailing.length > 0 ? join(real, ...trailing) : real;
|
|
91
|
-
break;
|
|
92
|
-
} catch {
|
|
93
|
-
trailing.unshift(basename(current));
|
|
94
|
-
current = dirname(current);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
119
|
+
realResolved = resolveRealPath(resolved);
|
|
97
120
|
}
|
|
98
121
|
|
|
99
122
|
// Resolve the boundary directory's real path too (in case it's a symlink)
|
|
@@ -115,7 +138,10 @@ export function sandboxPolicy(
|
|
|
115
138
|
|
|
116
139
|
// Check both the logical path and the symlink-resolved path so a symlink
|
|
117
140
|
// with a non-denied name pointing at a denied file is still caught.
|
|
118
|
-
if (
|
|
141
|
+
if (
|
|
142
|
+
DENIED_BASENAMES.has(basename(resolved)) ||
|
|
143
|
+
DENIED_BASENAMES.has(basename(realResolved))
|
|
144
|
+
) {
|
|
119
145
|
return {
|
|
120
146
|
ok: false,
|
|
121
147
|
reason: "denied",
|
|
@@ -25,22 +25,7 @@ const SIDE_EFFECT_TOOLS: ReadonlySet<string> = new Set([
|
|
|
25
25
|
* Returns `true` if the given tool name is classified as having side effects
|
|
26
26
|
* (i.e. it can modify the filesystem, execute arbitrary commands, or trigger
|
|
27
27
|
* external actions). Read-only and informational tools return `false`.
|
|
28
|
-
*
|
|
29
|
-
* For mixed-action tools (e.g. credential_store), the optional
|
|
30
|
-
* `input` parameter is inspected to distinguish mutating actions (create,
|
|
31
|
-
* update, cancel) from read-only ones (list, get).
|
|
32
28
|
*/
|
|
33
|
-
export function isSideEffectTool(
|
|
34
|
-
toolName
|
|
35
|
-
input?: Record<string, unknown>,
|
|
36
|
-
): boolean {
|
|
37
|
-
if (SIDE_EFFECT_TOOLS.has(toolName)) return true;
|
|
38
|
-
|
|
39
|
-
// Action-aware checks for mixed-action tools
|
|
40
|
-
if (toolName === "credential_store") {
|
|
41
|
-
const action = input?.action;
|
|
42
|
-
return action === "store" || action === "delete" || action === "prompt";
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return false;
|
|
29
|
+
export function isSideEffectTool(toolName: string): boolean {
|
|
30
|
+
return SIDE_EFFECT_TOOLS.has(toolName);
|
|
46
31
|
}
|
|
@@ -62,6 +62,39 @@ export function resolveSkillExecuteInput(
|
|
|
62
62
|
return {};
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Augment an inner-tool error with `skill_execute` envelope guidance when the
|
|
67
|
+
* call carried no inner parameters.
|
|
68
|
+
*
|
|
69
|
+
* {@link resolveSkillExecuteInput} rescues *misplaced* parameters (siblings, a
|
|
70
|
+
* JSON-encoded string). It cannot rescue a genuinely empty call — there is
|
|
71
|
+
* nothing to relocate — so the inner tool runs with `{}` and rejects it with a
|
|
72
|
+
* field-level message ("<field> is required") that says nothing about the
|
|
73
|
+
* envelope. Weak models then retry the identical empty shape, oscillating over
|
|
74
|
+
* whether parameters belong under `input`, as siblings, or as a JSON string.
|
|
75
|
+
*
|
|
76
|
+
* Appending the canonical envelope shape gives the next attempt a concrete
|
|
77
|
+
* template. Fires only when the resolved inner input was empty AND the tool
|
|
78
|
+
* errored, so well-formed calls and tools that legitimately accept no
|
|
79
|
+
* parameters are untouched.
|
|
80
|
+
*/
|
|
81
|
+
export function augmentSkillExecuteError(
|
|
82
|
+
toolName: string,
|
|
83
|
+
resolvedInput: Record<string, unknown>,
|
|
84
|
+
result: ToolExecutionResult,
|
|
85
|
+
): ToolExecutionResult {
|
|
86
|
+
if (!result.isError || Object.keys(resolvedInput).length > 0) return result;
|
|
87
|
+
|
|
88
|
+
const guidance =
|
|
89
|
+
`\n\nThis skill_execute call carried no parameters for "${toolName}". ` +
|
|
90
|
+
`Put the tool's parameters inside \`input\`. For example: ` +
|
|
91
|
+
`{"tool": "${toolName}", "input": { /* the tool's parameters */ }, ` +
|
|
92
|
+
`"activity": "..."}. The skill's instructions (from skill_load) list ` +
|
|
93
|
+
`"${toolName}"'s required fields.`;
|
|
94
|
+
|
|
95
|
+
return { ...result, content: result.content + guidance };
|
|
96
|
+
}
|
|
97
|
+
|
|
65
98
|
export const skillExecuteTool = {
|
|
66
99
|
name: "skill_execute",
|
|
67
100
|
description:
|