@vellumai/assistant 0.9.0 → 0.10.0-dev.202606192226.8ed8a6a
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 +19 -35
- 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 +1128 -119
- 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__/agent-loop-pushes-post-hook-prompt.test.ts +306 -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__/approval-cascade.test.ts +6 -0
- package/src/__tests__/approval-routes-http.test.ts +128 -0
- 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__/compaction-events.test.ts +6 -0
- 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-abort-tool-results.test.ts +6 -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-confirmation-signals.test.ts +6 -0
- package/src/__tests__/conversation-lifecycle.test.ts +7 -9
- package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
- package/src/__tests__/conversation-process-callsite.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-queue.test.ts +6 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
- package/src/__tests__/conversation-slash-queue.test.ts +6 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +6 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
- package/src/__tests__/conversation-title-service.test.ts +62 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -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-pressure-tools.test.ts +41 -1
- package/src/__tests__/disk-usage.test.ts +65 -0
- package/src/__tests__/document-tool-security.test.ts +9 -6
- package/src/__tests__/document-update-default-surface.test.ts +202 -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__/gemini-count-tokens.test.ts +70 -0
- 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-disk-pressure.test.ts +10 -5
- 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__/secret-response-routing.test.ts +35 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +16 -2
- package/src/__tests__/skill-execute-input.test.ts +177 -1
- package/src/__tests__/skill-load-tool.test.ts +72 -0
- 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__/system-storage-cleanup-skill.test.ts +56 -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 +75 -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/db/status.ts +37 -3
- 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 +400 -14
- 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__/install-from-github.test.ts +31 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
- package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -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 +128 -19
- package/src/cli/lib/merge-plugin-tree.ts +328 -0
- package/src/cli/lib/plugin-fingerprint.ts +14 -0
- package/src/cli/lib/plugin-marketplace.ts +11 -0
- package/src/cli/lib/plugin-pin-history.ts +257 -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/document-editor/SKILL.md +3 -3
- package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
- 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/system-storage-cleanup/SKILL.md +74 -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/__tests__/conversation-tool-setup.test.ts +44 -0
- 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 +53 -19
- package/src/daemon/conversation.ts +131 -20
- 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/memory-v2-startup.test.ts +131 -0
- package/src/daemon/memory-v2-startup.ts +100 -1
- 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/daemon/wake-conversation-ops.ts +1 -0
- 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__/db-logs-attach.test.ts +122 -0
- 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-async-query.ts +20 -2
- package/src/memory/db-connection.ts +49 -5
- 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/permissions/secret-prompter.ts +15 -1
- 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/compaction/window-manager.ts +18 -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/injectors.ts +4 -4
- 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__/count-tokens-forwarding.test.ts +98 -0
- 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/anthropic/client.ts +230 -175
- package/src/providers/atlascloud/client.ts +85 -0
- package/src/providers/call-site-routing.ts +10 -0
- package/src/providers/fetch-provider-catalog.ts +85 -0
- package/src/providers/gemini/client.ts +43 -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/ratelimit.ts +9 -0
- package/src/providers/retry.ts +62 -12
- package/src/providers/search-provider-catalog.ts +10 -0
- package/src/providers/types.ts +16 -0
- package/src/providers/usage-tracking.ts +7 -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 +227 -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 +71 -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 +126 -0
- package/src/runtime/migrations/vbundle-builder.ts +49 -20
- package/src/runtime/pending-interactions.ts +35 -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 +383 -1
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/approval-routes.ts +40 -9
- 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 +366 -11
- package/src/runtime/routes/schedule-routes.ts +0 -22
- package/src/runtime/routes/secret-routes.ts +15 -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 +30 -6
- 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 +99 -2
- package/src/tools/skills/load.ts +43 -2
- package/src/tools/subagent/spawn.ts +64 -15
- 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 +10 -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/logs-db-path.ts +22 -0
- 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
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
Provider,
|
|
19
19
|
ProviderResponse,
|
|
20
20
|
SendMessageOptions,
|
|
21
|
+
ToolDefinition,
|
|
21
22
|
} from "../types.js";
|
|
22
23
|
import {
|
|
23
24
|
ContextOverflowError,
|
|
@@ -823,181 +824,7 @@ export class AnthropicProvider implements Provider {
|
|
|
823
824
|
// edge LB, NAT idle) — only the latter should be retried.
|
|
824
825
|
let innerTimeoutSignal: AbortSignal | undefined;
|
|
825
826
|
try {
|
|
826
|
-
|
|
827
|
-
.map((m) => {
|
|
828
|
-
// Track whether an unknown block was dropped during filtering
|
|
829
|
-
let droppedUnknownBlock = false;
|
|
830
|
-
|
|
831
|
-
const content = m.content
|
|
832
|
-
.map((block) => {
|
|
833
|
-
const result = this.toAnthropicBlockSafe(block);
|
|
834
|
-
if (result == null) {
|
|
835
|
-
droppedUnknownBlock = true;
|
|
836
|
-
}
|
|
837
|
-
return result;
|
|
838
|
-
})
|
|
839
|
-
.filter(
|
|
840
|
-
(block): block is Anthropic.ContentBlockParam => block != null,
|
|
841
|
-
)
|
|
842
|
-
.filter(
|
|
843
|
-
(block) =>
|
|
844
|
-
!(
|
|
845
|
-
block.type === "text" &&
|
|
846
|
-
!(block as { text?: string }).text?.trim()
|
|
847
|
-
),
|
|
848
|
-
);
|
|
849
|
-
|
|
850
|
-
// Preserve assistant turns that would otherwise become empty after filtering
|
|
851
|
-
// unknown block types (e.g. ui_surface). Dropping these messages can violate
|
|
852
|
-
// Anthropic's role alternation requirement.
|
|
853
|
-
if (
|
|
854
|
-
content.length === 0 &&
|
|
855
|
-
m.role === "assistant" &&
|
|
856
|
-
droppedUnknownBlock
|
|
857
|
-
) {
|
|
858
|
-
return {
|
|
859
|
-
role: m.role as "assistant",
|
|
860
|
-
content: [
|
|
861
|
-
{ type: "text" as const, text: PLACEHOLDER_BLOCKS_OMITTED },
|
|
862
|
-
],
|
|
863
|
-
};
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
return {
|
|
867
|
-
role: m.role,
|
|
868
|
-
content,
|
|
869
|
-
} as Anthropic.MessageParam;
|
|
870
|
-
})
|
|
871
|
-
.reduce<Anthropic.MessageParam[]>((acc, m) => {
|
|
872
|
-
if (m.content.length > 0) {
|
|
873
|
-
acc.push(m);
|
|
874
|
-
return acc;
|
|
875
|
-
}
|
|
876
|
-
// Dropping an empty assistant message between two user messages (or vice
|
|
877
|
-
// versa) would create consecutive same-role messages, violating
|
|
878
|
-
// Anthropic's role alternation requirement. Inject a placeholder instead.
|
|
879
|
-
const prev = acc[acc.length - 1];
|
|
880
|
-
if (m.role === "assistant" && prev && prev.role !== "assistant") {
|
|
881
|
-
acc.push({
|
|
882
|
-
role: "assistant" as const,
|
|
883
|
-
content: [
|
|
884
|
-
{ type: "text" as const, text: PLACEHOLDER_EMPTY_TURN },
|
|
885
|
-
],
|
|
886
|
-
});
|
|
887
|
-
}
|
|
888
|
-
return acc;
|
|
889
|
-
}, []);
|
|
890
|
-
|
|
891
|
-
// Post-processing: merge consecutive same-role messages that violate
|
|
892
|
-
// Anthropic's strict user/assistant alternation requirement. These can
|
|
893
|
-
// arise from:
|
|
894
|
-
// - Dropping empty messages in the reduce above (placeholder-adjacent)
|
|
895
|
-
// - History reconstruction artifacts that bypass repairHistory
|
|
896
|
-
//
|
|
897
|
-
// Walk backwards so splice indices stay valid. After a merge+splice
|
|
898
|
-
// the element that was at i+1 shifts to i, potentially creating a
|
|
899
|
-
// new adjacent pair — bump i back up to recheck that position.
|
|
900
|
-
{
|
|
901
|
-
let i = formatted.length - 1;
|
|
902
|
-
while (i > 0 && i < formatted.length) {
|
|
903
|
-
if (formatted[i].role !== formatted[i - 1].role) {
|
|
904
|
-
i--;
|
|
905
|
-
continue;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
const iContent = (
|
|
909
|
-
Array.isArray(formatted[i].content) ? formatted[i].content : []
|
|
910
|
-
) as Anthropic.ContentBlockParam[];
|
|
911
|
-
const prevContent = (
|
|
912
|
-
Array.isArray(formatted[i - 1].content)
|
|
913
|
-
? formatted[i - 1].content
|
|
914
|
-
: []
|
|
915
|
-
) as Anthropic.ContentBlockParam[];
|
|
916
|
-
const isPlaceholder = (c: Anthropic.ContentBlockParam[]): boolean => {
|
|
917
|
-
if (
|
|
918
|
-
c.length !== 1 ||
|
|
919
|
-
typeof c[0] === "string" ||
|
|
920
|
-
c[0].type !== "text"
|
|
921
|
-
)
|
|
922
|
-
return false;
|
|
923
|
-
const text = (c[0] as { text?: string }).text;
|
|
924
|
-
return typeof text === "string" && isPlaceholderSentinelText(text);
|
|
925
|
-
};
|
|
926
|
-
|
|
927
|
-
if (isPlaceholder(iContent)) {
|
|
928
|
-
formatted.splice(i, 1);
|
|
929
|
-
// Removed the later element. The new formatted[i] (formerly
|
|
930
|
-
// i+1) may now be same-role as i-1, so decrement once to
|
|
931
|
-
// recheck from the correct position.
|
|
932
|
-
i--;
|
|
933
|
-
} else if (isPlaceholder(prevContent)) {
|
|
934
|
-
formatted.splice(i - 1, 1);
|
|
935
|
-
// Removed the earlier element — everything shifted down by 1.
|
|
936
|
-
// The element that was at i is now at i-1. Decrement so the
|
|
937
|
-
// next iteration compares the new i-1 with i-2 (or exits if
|
|
938
|
-
// i-1 is 0).
|
|
939
|
-
i--;
|
|
940
|
-
} else {
|
|
941
|
-
// Neither is a placeholder — merge content blocks into the
|
|
942
|
-
// earlier message and remove the later one. Skip the merge
|
|
943
|
-
// when either message carries tool_use or tool_result blocks;
|
|
944
|
-
// those require structural alternation for ensureToolPairing
|
|
945
|
-
// to inject the correct synthetic results downstream.
|
|
946
|
-
const hasToolBlock = (c: Anthropic.ContentBlockParam[]): boolean =>
|
|
947
|
-
c.some(
|
|
948
|
-
(b) =>
|
|
949
|
-
typeof b !== "string" &&
|
|
950
|
-
(b.type === "tool_use" || b.type === "tool_result"),
|
|
951
|
-
);
|
|
952
|
-
if (!hasToolBlock(prevContent) && !hasToolBlock(iContent)) {
|
|
953
|
-
formatted[i - 1] = {
|
|
954
|
-
...formatted[i - 1],
|
|
955
|
-
content: [...prevContent, ...iContent],
|
|
956
|
-
};
|
|
957
|
-
formatted.splice(i, 1);
|
|
958
|
-
// Clamp i to the new last index — the splice may have put
|
|
959
|
-
// us past the end. If there's a new element at i (formerly
|
|
960
|
-
// i+1), it will be rechecked against the merged i-1.
|
|
961
|
-
if (i >= formatted.length) {
|
|
962
|
-
i = formatted.length - 1;
|
|
963
|
-
}
|
|
964
|
-
} else {
|
|
965
|
-
// Can't merge (tool blocks present) — leave for
|
|
966
|
-
// ensureToolPairing which handles tool_use/tool_result
|
|
967
|
-
// alternation in its own forward walk.
|
|
968
|
-
i--;
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
// Strip thinking/redacted_thinking blocks from completed historical
|
|
975
|
-
// assistant turns. Anthropic only requires these blocks for active
|
|
976
|
-
// tool-use continuation (the tail span where assistant tool_use is
|
|
977
|
-
// followed by user tool_result). Replaying stale thinking blocks from
|
|
978
|
-
// earlier turns causes 400 errors when the signature is no longer
|
|
979
|
-
// valid (e.g. after a provider/model/profile switch).
|
|
980
|
-
const activeToolUseStart = findActiveToolUseContinuationStart(formatted);
|
|
981
|
-
for (let i = 0; i < activeToolUseStart; i++) {
|
|
982
|
-
const msg = formatted[i];
|
|
983
|
-
if (msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
|
|
984
|
-
const stripped = (msg.content as Anthropic.ContentBlockParam[]).filter(
|
|
985
|
-
(b) =>
|
|
986
|
-
typeof b === "string" ||
|
|
987
|
-
(b.type !== "thinking" && b.type !== "redacted_thinking"),
|
|
988
|
-
);
|
|
989
|
-
if (stripped.length === 0) {
|
|
990
|
-
stripped.push({
|
|
991
|
-
type: "text" as const,
|
|
992
|
-
text: PLACEHOLDER_BLOCKS_OMITTED,
|
|
993
|
-
});
|
|
994
|
-
}
|
|
995
|
-
formatted[i] = { ...msg, content: stripped };
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
sentMessages = ensureToolPairing(
|
|
999
|
-
repairOrphanedServerToolBlocks(formatted),
|
|
1000
|
-
);
|
|
827
|
+
sentMessages = this.buildSentMessages(messages);
|
|
1001
828
|
const {
|
|
1002
829
|
effort,
|
|
1003
830
|
speed,
|
|
@@ -1681,6 +1508,234 @@ export class AnthropicProvider implements Provider {
|
|
|
1681
1508
|
}
|
|
1682
1509
|
}
|
|
1683
1510
|
|
|
1511
|
+
/**
|
|
1512
|
+
* Exact prompt-token count via Anthropic's `/v1/messages/count_tokens`
|
|
1513
|
+
* endpoint — the real tokenizer, no inference. Serializes `messages` /
|
|
1514
|
+
* `systemPrompt` / `tools` the same way {@link sendMessage} does (so the
|
|
1515
|
+
* count tracks what the next call would actually send), minus the
|
|
1516
|
+
* `cache_control` breakpoints, which don't affect token counts.
|
|
1517
|
+
*
|
|
1518
|
+
* The serialization here is intentionally simpler than `sendMessage`'s
|
|
1519
|
+
* (no role-alternation merge / placeholder injection): on a pathological
|
|
1520
|
+
* history `count_tokens` may reject the request, which surfaces as a thrown
|
|
1521
|
+
* error the caller turns into a local-estimator fallback. The common path —
|
|
1522
|
+
* a well-formed history — counts exactly.
|
|
1523
|
+
*/
|
|
1524
|
+
async countInputTokens(
|
|
1525
|
+
messages: Message[],
|
|
1526
|
+
systemPrompt: string,
|
|
1527
|
+
tools?: ToolDefinition[],
|
|
1528
|
+
): Promise<number> {
|
|
1529
|
+
const sentMessages = this.buildSentMessages(messages);
|
|
1530
|
+
|
|
1531
|
+
const system = systemPrompt
|
|
1532
|
+
? systemPrompt
|
|
1533
|
+
.split(SYSTEM_PROMPT_CACHE_BOUNDARY)
|
|
1534
|
+
.filter((text) => text.length > 0)
|
|
1535
|
+
.map((text) => ({ type: "text" as const, text }))
|
|
1536
|
+
: [];
|
|
1537
|
+
const toolsParam =
|
|
1538
|
+
tools && tools.length > 0
|
|
1539
|
+
? tools.map((t) => ({
|
|
1540
|
+
name: t.name,
|
|
1541
|
+
description: t.description,
|
|
1542
|
+
input_schema: t.input_schema as Anthropic.Tool["input_schema"],
|
|
1543
|
+
}))
|
|
1544
|
+
: undefined;
|
|
1545
|
+
|
|
1546
|
+
const res = await this.client.messages.countTokens({
|
|
1547
|
+
model: this.model,
|
|
1548
|
+
messages: sentMessages,
|
|
1549
|
+
...(system.length > 0 ? { system } : {}),
|
|
1550
|
+
...(toolsParam ? { tools: toolsParam } : {}),
|
|
1551
|
+
});
|
|
1552
|
+
return res.input_tokens;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
/**
|
|
1556
|
+
* Serialize internal `Message[]` into the Anthropic `MessageParam[]` the
|
|
1557
|
+
* Messages API expects: drop unknown/empty blocks, preserve role
|
|
1558
|
+
* alternation (placeholder injection + same-role merge), strip stale
|
|
1559
|
+
* thinking blocks outside the active tool-use continuation, and repair
|
|
1560
|
+
* tool_use/tool_result pairing. Shared by {@link sendMessage} and
|
|
1561
|
+
* {@link countInputTokens} so both send the identical message payload —
|
|
1562
|
+
* `cache_control` breakpoints (which don't affect token counts) are the
|
|
1563
|
+
* only thing layered on top in `sendMessage`.
|
|
1564
|
+
*/
|
|
1565
|
+
private buildSentMessages(messages: Message[]): Anthropic.MessageParam[] {
|
|
1566
|
+
const formatted = messages
|
|
1567
|
+
.map((m) => {
|
|
1568
|
+
// Track whether an unknown block was dropped during filtering
|
|
1569
|
+
let droppedUnknownBlock = false;
|
|
1570
|
+
|
|
1571
|
+
const content = m.content
|
|
1572
|
+
.map((block) => {
|
|
1573
|
+
const result = this.toAnthropicBlockSafe(block);
|
|
1574
|
+
if (result == null) {
|
|
1575
|
+
droppedUnknownBlock = true;
|
|
1576
|
+
}
|
|
1577
|
+
return result;
|
|
1578
|
+
})
|
|
1579
|
+
.filter(
|
|
1580
|
+
(block): block is Anthropic.ContentBlockParam => block != null,
|
|
1581
|
+
)
|
|
1582
|
+
.filter(
|
|
1583
|
+
(block) =>
|
|
1584
|
+
!(
|
|
1585
|
+
block.type === "text" &&
|
|
1586
|
+
!(block as { text?: string }).text?.trim()
|
|
1587
|
+
),
|
|
1588
|
+
);
|
|
1589
|
+
|
|
1590
|
+
// Preserve assistant turns that would otherwise become empty after filtering
|
|
1591
|
+
// unknown block types (e.g. ui_surface). Dropping these messages can violate
|
|
1592
|
+
// Anthropic's role alternation requirement.
|
|
1593
|
+
if (
|
|
1594
|
+
content.length === 0 &&
|
|
1595
|
+
m.role === "assistant" &&
|
|
1596
|
+
droppedUnknownBlock
|
|
1597
|
+
) {
|
|
1598
|
+
return {
|
|
1599
|
+
role: m.role as "assistant",
|
|
1600
|
+
content: [
|
|
1601
|
+
{ type: "text" as const, text: PLACEHOLDER_BLOCKS_OMITTED },
|
|
1602
|
+
],
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
return {
|
|
1607
|
+
role: m.role,
|
|
1608
|
+
content,
|
|
1609
|
+
} as Anthropic.MessageParam;
|
|
1610
|
+
})
|
|
1611
|
+
.reduce<Anthropic.MessageParam[]>((acc, m) => {
|
|
1612
|
+
if (m.content.length > 0) {
|
|
1613
|
+
acc.push(m);
|
|
1614
|
+
return acc;
|
|
1615
|
+
}
|
|
1616
|
+
// Dropping an empty assistant message between two user messages (or vice
|
|
1617
|
+
// versa) would create consecutive same-role messages, violating
|
|
1618
|
+
// Anthropic's role alternation requirement. Inject a placeholder instead.
|
|
1619
|
+
const prev = acc[acc.length - 1];
|
|
1620
|
+
if (m.role === "assistant" && prev && prev.role !== "assistant") {
|
|
1621
|
+
acc.push({
|
|
1622
|
+
role: "assistant" as const,
|
|
1623
|
+
content: [{ type: "text" as const, text: PLACEHOLDER_EMPTY_TURN }],
|
|
1624
|
+
});
|
|
1625
|
+
}
|
|
1626
|
+
return acc;
|
|
1627
|
+
}, []);
|
|
1628
|
+
|
|
1629
|
+
// Post-processing: merge consecutive same-role messages that violate
|
|
1630
|
+
// Anthropic's strict user/assistant alternation requirement. These can
|
|
1631
|
+
// arise from:
|
|
1632
|
+
// - Dropping empty messages in the reduce above (placeholder-adjacent)
|
|
1633
|
+
// - History reconstruction artifacts that bypass repairHistory
|
|
1634
|
+
//
|
|
1635
|
+
// Walk backwards so splice indices stay valid. After a merge+splice
|
|
1636
|
+
// the element that was at i+1 shifts to i, potentially creating a
|
|
1637
|
+
// new adjacent pair — bump i back up to recheck that position.
|
|
1638
|
+
{
|
|
1639
|
+
let i = formatted.length - 1;
|
|
1640
|
+
while (i > 0 && i < formatted.length) {
|
|
1641
|
+
if (formatted[i].role !== formatted[i - 1].role) {
|
|
1642
|
+
i--;
|
|
1643
|
+
continue;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
const iContent = (
|
|
1647
|
+
Array.isArray(formatted[i].content) ? formatted[i].content : []
|
|
1648
|
+
) as Anthropic.ContentBlockParam[];
|
|
1649
|
+
const prevContent = (
|
|
1650
|
+
Array.isArray(formatted[i - 1].content)
|
|
1651
|
+
? formatted[i - 1].content
|
|
1652
|
+
: []
|
|
1653
|
+
) as Anthropic.ContentBlockParam[];
|
|
1654
|
+
const isPlaceholder = (c: Anthropic.ContentBlockParam[]): boolean => {
|
|
1655
|
+
if (
|
|
1656
|
+
c.length !== 1 ||
|
|
1657
|
+
typeof c[0] === "string" ||
|
|
1658
|
+
c[0].type !== "text"
|
|
1659
|
+
)
|
|
1660
|
+
return false;
|
|
1661
|
+
const text = (c[0] as { text?: string }).text;
|
|
1662
|
+
return typeof text === "string" && isPlaceholderSentinelText(text);
|
|
1663
|
+
};
|
|
1664
|
+
|
|
1665
|
+
if (isPlaceholder(iContent)) {
|
|
1666
|
+
formatted.splice(i, 1);
|
|
1667
|
+
// Removed the later element. The new formatted[i] (formerly
|
|
1668
|
+
// i+1) may now be same-role as i-1, so decrement once to
|
|
1669
|
+
// recheck from the correct position.
|
|
1670
|
+
i--;
|
|
1671
|
+
} else if (isPlaceholder(prevContent)) {
|
|
1672
|
+
formatted.splice(i - 1, 1);
|
|
1673
|
+
// Removed the earlier element — everything shifted down by 1.
|
|
1674
|
+
// The element that was at i is now at i-1. Decrement so the
|
|
1675
|
+
// next iteration compares the new i-1 with i-2 (or exits if
|
|
1676
|
+
// i-1 is 0).
|
|
1677
|
+
i--;
|
|
1678
|
+
} else {
|
|
1679
|
+
// Neither is a placeholder — merge content blocks into the
|
|
1680
|
+
// earlier message and remove the later one. Skip the merge
|
|
1681
|
+
// when either message carries tool_use or tool_result blocks;
|
|
1682
|
+
// those require structural alternation for ensureToolPairing
|
|
1683
|
+
// to inject the correct synthetic results downstream.
|
|
1684
|
+
const hasToolBlock = (c: Anthropic.ContentBlockParam[]): boolean =>
|
|
1685
|
+
c.some(
|
|
1686
|
+
(b) =>
|
|
1687
|
+
typeof b !== "string" &&
|
|
1688
|
+
(b.type === "tool_use" || b.type === "tool_result"),
|
|
1689
|
+
);
|
|
1690
|
+
if (!hasToolBlock(prevContent) && !hasToolBlock(iContent)) {
|
|
1691
|
+
formatted[i - 1] = {
|
|
1692
|
+
...formatted[i - 1],
|
|
1693
|
+
content: [...prevContent, ...iContent],
|
|
1694
|
+
};
|
|
1695
|
+
formatted.splice(i, 1);
|
|
1696
|
+
// Clamp i to the new last index — the splice may have put
|
|
1697
|
+
// us past the end. If there's a new element at i (formerly
|
|
1698
|
+
// i+1), it will be rechecked against the merged i-1.
|
|
1699
|
+
if (i >= formatted.length) {
|
|
1700
|
+
i = formatted.length - 1;
|
|
1701
|
+
}
|
|
1702
|
+
} else {
|
|
1703
|
+
// Can't merge (tool blocks present) — leave for
|
|
1704
|
+
// ensureToolPairing which handles tool_use/tool_result
|
|
1705
|
+
// alternation in its own forward walk.
|
|
1706
|
+
i--;
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
// Strip thinking/redacted_thinking blocks from completed historical
|
|
1713
|
+
// assistant turns. Anthropic only requires these blocks for active
|
|
1714
|
+
// tool-use continuation (the tail span where assistant tool_use is
|
|
1715
|
+
// followed by user tool_result). Replaying stale thinking blocks from
|
|
1716
|
+
// earlier turns causes 400 errors when the signature is no longer
|
|
1717
|
+
// valid (e.g. after a provider/model/profile switch).
|
|
1718
|
+
const activeToolUseStart = findActiveToolUseContinuationStart(formatted);
|
|
1719
|
+
for (let i = 0; i < activeToolUseStart; i++) {
|
|
1720
|
+
const msg = formatted[i];
|
|
1721
|
+
if (msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
|
|
1722
|
+
const stripped = (msg.content as Anthropic.ContentBlockParam[]).filter(
|
|
1723
|
+
(b) =>
|
|
1724
|
+
typeof b === "string" ||
|
|
1725
|
+
(b.type !== "thinking" && b.type !== "redacted_thinking"),
|
|
1726
|
+
);
|
|
1727
|
+
if (stripped.length === 0) {
|
|
1728
|
+
stripped.push({
|
|
1729
|
+
type: "text" as const,
|
|
1730
|
+
text: PLACEHOLDER_BLOCKS_OMITTED,
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
formatted[i] = { ...msg, content: stripped };
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
return ensureToolPairing(repairOrphanedServerToolBlocks(formatted));
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1684
1739
|
/**
|
|
1685
1740
|
* Convert a content block to Anthropic format, returning null for unknown
|
|
1686
1741
|
* block types instead of throwing. Unknown types (e.g. ui_surface stored
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
|
|
3
|
+
import { getLogger } from "../../util/logger.js";
|
|
4
|
+
import { OpenAIChatCompletionsProvider } from "../openai/chat-completions-provider.js";
|
|
5
|
+
|
|
6
|
+
const log = getLogger("atlascloud-client");
|
|
7
|
+
|
|
8
|
+
/** Validation-specific timeout (10s) so a stalled network doesn't block key submission. */
|
|
9
|
+
const VALIDATION_TIMEOUT_MS = 10_000;
|
|
10
|
+
|
|
11
|
+
export interface AtlasCloudProviderOptions {
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
streamTimeoutMs?: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Atlas Cloud exposes a single OpenAI-compatible endpoint. Unlike MiniMax it
|
|
18
|
+
* has no regional fallback host, so validation targets this URL only.
|
|
19
|
+
*/
|
|
20
|
+
const DEFAULT_ATLASCLOUD_BASE_URL = "https://api.atlascloud.ai/v1";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validate an Atlas Cloud API key by listing models against the OpenAI-compatible
|
|
24
|
+
* endpoint. Definitive auth failures (401/403) reject the key; transient errors
|
|
25
|
+
* (429, 5xx, network) allow the key to be stored so a flaky network doesn't
|
|
26
|
+
* block setup.
|
|
27
|
+
*/
|
|
28
|
+
export async function validateAtlasCloudApiKey(
|
|
29
|
+
apiKey: string,
|
|
30
|
+
): Promise<{ valid: true } | { valid: false; reason: string }> {
|
|
31
|
+
try {
|
|
32
|
+
const client = new OpenAI({
|
|
33
|
+
apiKey,
|
|
34
|
+
baseURL: DEFAULT_ATLASCLOUD_BASE_URL,
|
|
35
|
+
timeout: VALIDATION_TIMEOUT_MS,
|
|
36
|
+
maxRetries: 0,
|
|
37
|
+
});
|
|
38
|
+
await client.models.list();
|
|
39
|
+
return { valid: true };
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error instanceof OpenAI.APIError) {
|
|
42
|
+
if (error.status === 401) {
|
|
43
|
+
return { valid: false, reason: "API key is invalid or expired." };
|
|
44
|
+
}
|
|
45
|
+
if (error.status === 403) {
|
|
46
|
+
return {
|
|
47
|
+
valid: false,
|
|
48
|
+
reason: `Atlas Cloud API error (${error.status}): ${error.message}`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// Transient errors (429, 5xx, etc.) — allow the key to be stored.
|
|
52
|
+
log.warn(
|
|
53
|
+
{ status: error.status },
|
|
54
|
+
"Atlas Cloud API returned a transient error during key validation — allowing key",
|
|
55
|
+
);
|
|
56
|
+
return { valid: true };
|
|
57
|
+
}
|
|
58
|
+
// Network errors — allow the key to be stored.
|
|
59
|
+
log.warn(
|
|
60
|
+
{ error: error instanceof Error ? error.message : String(error) },
|
|
61
|
+
"Network error during Atlas Cloud key validation — allowing key",
|
|
62
|
+
);
|
|
63
|
+
return { valid: true };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class AtlasCloudProvider extends OpenAIChatCompletionsProvider {
|
|
68
|
+
constructor(
|
|
69
|
+
apiKey: string,
|
|
70
|
+
model: string,
|
|
71
|
+
options: AtlasCloudProviderOptions = {},
|
|
72
|
+
) {
|
|
73
|
+
super(apiKey, model, {
|
|
74
|
+
baseURL: DEFAULT_ATLASCLOUD_BASE_URL,
|
|
75
|
+
providerName: "atlascloud",
|
|
76
|
+
providerLabel: "Atlas Cloud",
|
|
77
|
+
streamTimeoutMs: options.streamTimeoutMs,
|
|
78
|
+
// Atlas Cloud hosts reasoning models (e.g. DeepSeek) that emit chain of
|
|
79
|
+
// thought via `reasoning_content` rather than inline `<think>` tags. The
|
|
80
|
+
// base provider parses this field into thinking blocks and replays it on
|
|
81
|
+
// multi-turn requests.
|
|
82
|
+
assistantReasoningField: "reasoning_content",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -60,6 +60,12 @@ export class CallSiteRoutingProvider implements Provider {
|
|
|
60
60
|
return this._activeProviderContext.getStore() ?? this.defaultProvider.name;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
// Forward the optional token-counting endpoint from the default provider —
|
|
64
|
+
// the same one whose `tokenEstimationProvider` this wrapper surfaces, and
|
|
65
|
+
// the provider that handles the main agent turn that `/compact` sizes
|
|
66
|
+
// against. Per-call connection routing only affects `sendMessage`.
|
|
67
|
+
public readonly countInputTokens?: NonNullable<Provider["countInputTokens"]>;
|
|
68
|
+
|
|
63
69
|
constructor(
|
|
64
70
|
private readonly defaultProvider: Provider,
|
|
65
71
|
/**
|
|
@@ -88,6 +94,10 @@ export class CallSiteRoutingProvider implements Provider {
|
|
|
88
94
|
) => Promise<Provider | null>,
|
|
89
95
|
) {
|
|
90
96
|
this.tokenEstimationProvider = defaultProvider.tokenEstimationProvider;
|
|
97
|
+
if (defaultProvider.countInputTokens) {
|
|
98
|
+
this.countInputTokens =
|
|
99
|
+
defaultProvider.countInputTokens.bind(defaultProvider);
|
|
100
|
+
}
|
|
91
101
|
}
|
|
92
102
|
|
|
93
103
|
async sendMessage(
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical catalog of built-in web-fetch providers.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth that drives the config-schema enum
|
|
5
|
+
* (`VALID_WEB_FETCH_PROVIDERS` in `assistant/src/config/schemas/services.ts`)
|
|
6
|
+
* and the client picker mirror in
|
|
7
|
+
* `clients/web/src/assistant/generated/web-fetch-provider-catalog.gen.ts`.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors `search-provider-catalog.ts`. Where web-search distinguishes
|
|
10
|
+
* `managed` (platform proxy) from `byok` (user key), web-fetch has no managed
|
|
11
|
+
* proxy yet, so the two kinds are:
|
|
12
|
+
*
|
|
13
|
+
* - `builtin` — the daemon's own HTTP fetch + extract path (`default`). No
|
|
14
|
+
* key, always available, the default.
|
|
15
|
+
* - `byok` — an external provider that needs a user-supplied key (e.g.
|
|
16
|
+
* `firecrawl`, which scrapes via its hosted API and returns clean
|
|
17
|
+
* markdown, including for JavaScript-rendered pages the builtin fetcher
|
|
18
|
+
* can't see).
|
|
19
|
+
*
|
|
20
|
+
* BYOK fetch providers intentionally reuse the SAME bare-name credential as
|
|
21
|
+
* their search counterpart (e.g. `firecrawl` → `FIRECRAWL_API_KEY`), so a
|
|
22
|
+
* single stored key powers both `web_search` and `web_fetch`. The key is
|
|
23
|
+
* already registered in `API_KEY_PROVIDERS` via `SEARCH_PROVIDER_CATALOG`;
|
|
24
|
+
* this catalog deliberately does NOT re-register it.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
export type FetchProviderKind = "builtin" | "byok";
|
|
28
|
+
|
|
29
|
+
export interface FetchProviderCatalogEntry {
|
|
30
|
+
/** Stable provider identifier. Matches config values. */
|
|
31
|
+
readonly id: string;
|
|
32
|
+
/** Short display name used by picker UIs. */
|
|
33
|
+
readonly displayName: string;
|
|
34
|
+
/** Optional long display name for prose contexts. */
|
|
35
|
+
readonly displayNameLong?: string;
|
|
36
|
+
/** `builtin` (no key) or `byok` (user-supplied key). */
|
|
37
|
+
readonly kind: FetchProviderKind;
|
|
38
|
+
/** Placeholder shown in the API-key input. BYOK providers only. */
|
|
39
|
+
readonly apiKeyPrefix?: string;
|
|
40
|
+
/** Environment variable name carrying the API key. BYOK providers only. */
|
|
41
|
+
readonly envVar?: string;
|
|
42
|
+
/** Secret-catalog key (the bare provider name accepted by
|
|
43
|
+
* `getProviderKeyAsync`). BYOK providers only. */
|
|
44
|
+
readonly secretKey?: string;
|
|
45
|
+
/** Privacy-policy URL surfaced in marketing data-sharing docs.
|
|
46
|
+
* BYOK providers only. */
|
|
47
|
+
readonly privacyPolicyUrl?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const FETCH_PROVIDER_CATALOG: readonly FetchProviderCatalogEntry[] = [
|
|
51
|
+
{
|
|
52
|
+
id: "default",
|
|
53
|
+
displayName: "Built-in",
|
|
54
|
+
displayNameLong: "Built-in fetcher",
|
|
55
|
+
kind: "builtin",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "firecrawl",
|
|
59
|
+
displayName: "Firecrawl",
|
|
60
|
+
kind: "byok",
|
|
61
|
+
apiKeyPrefix: "fc-...",
|
|
62
|
+
envVar: "FIRECRAWL_API_KEY",
|
|
63
|
+
secretKey: "firecrawl",
|
|
64
|
+
privacyPolicyUrl: "https://www.firecrawl.dev/privacy-policy",
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
/** Provider ids accepted by the web-fetch config schema. */
|
|
69
|
+
export const FETCH_PROVIDER_IDS: readonly string[] =
|
|
70
|
+
FETCH_PROVIDER_CATALOG.map((p) => p.id);
|
|
71
|
+
|
|
72
|
+
/** Catalog entries that require a user-supplied API key. */
|
|
73
|
+
export const BYOK_FETCH_PROVIDERS: readonly FetchProviderCatalogEntry[] =
|
|
74
|
+
FETCH_PROVIDER_CATALOG.filter((p) => p.kind === "byok");
|
|
75
|
+
|
|
76
|
+
/** BYOK fetch-provider ids. */
|
|
77
|
+
export const BYOK_FETCH_PROVIDER_IDS: readonly string[] =
|
|
78
|
+
BYOK_FETCH_PROVIDERS.map((p) => p.id);
|
|
79
|
+
|
|
80
|
+
/** Look up a single catalog entry by id. Returns `undefined` if unknown. */
|
|
81
|
+
export function getFetchProvider(
|
|
82
|
+
id: string,
|
|
83
|
+
): FetchProviderCatalogEntry | undefined {
|
|
84
|
+
return FETCH_PROVIDER_CATALOG.find((p) => p.id === id);
|
|
85
|
+
}
|
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
Provider,
|
|
18
18
|
ProviderResponse,
|
|
19
19
|
SendMessageOptions,
|
|
20
|
+
ToolDefinition,
|
|
20
21
|
} from "../types.js";
|
|
21
22
|
import {
|
|
22
23
|
ContextOverflowError,
|
|
@@ -518,6 +519,48 @@ export class GeminiProvider implements Provider {
|
|
|
518
519
|
}
|
|
519
520
|
}
|
|
520
521
|
|
|
522
|
+
/**
|
|
523
|
+
* Exact prompt-token count via Gemini's `models.countTokens` — the real
|
|
524
|
+
* tokenizer, no generation. Mirrors {@link sendMessage}'s composition
|
|
525
|
+
* (contents + `systemInstruction` + tool function declarations) so the count
|
|
526
|
+
* tracks what a real call would send. Throws when the endpoint returns no
|
|
527
|
+
* `totalTokens`, so the caller falls back to the local estimate.
|
|
528
|
+
*/
|
|
529
|
+
async countInputTokens(
|
|
530
|
+
messages: Message[],
|
|
531
|
+
systemPrompt: string,
|
|
532
|
+
tools?: ToolDefinition[],
|
|
533
|
+
): Promise<number> {
|
|
534
|
+
const contents = this.toGeminiContents(messages, this.model);
|
|
535
|
+
const config: genai.CountTokensConfig = {};
|
|
536
|
+
if (systemPrompt) {
|
|
537
|
+
config.systemInstruction = systemPrompt.replaceAll(
|
|
538
|
+
SYSTEM_PROMPT_CACHE_BOUNDARY,
|
|
539
|
+
"\n\n",
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
if (tools && tools.length > 0) {
|
|
543
|
+
config.tools = [
|
|
544
|
+
{
|
|
545
|
+
functionDeclarations: tools.map((t) => ({
|
|
546
|
+
name: t.name,
|
|
547
|
+
description: t.description,
|
|
548
|
+
parametersJsonSchema: t.input_schema,
|
|
549
|
+
})),
|
|
550
|
+
},
|
|
551
|
+
];
|
|
552
|
+
}
|
|
553
|
+
const res = await this.client.models.countTokens({
|
|
554
|
+
model: this.model,
|
|
555
|
+
contents,
|
|
556
|
+
...(Object.keys(config).length > 0 ? { config } : {}),
|
|
557
|
+
});
|
|
558
|
+
if (typeof res.totalTokens !== "number") {
|
|
559
|
+
throw new Error("Gemini countTokens returned no totalTokens");
|
|
560
|
+
}
|
|
561
|
+
return res.totalTokens;
|
|
562
|
+
}
|
|
563
|
+
|
|
521
564
|
/** Convert neutral messages to Gemini Content[] format. */
|
|
522
565
|
private toGeminiContents(
|
|
523
566
|
messages: Message[],
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import { AnthropicProvider } from "../anthropic/client.js";
|
|
22
|
+
import { AtlasCloudProvider } from "../atlascloud/client.js";
|
|
22
23
|
import { FireworksProvider } from "../fireworks/client.js";
|
|
23
24
|
import { GeminiProvider } from "../gemini/client.js";
|
|
24
25
|
import { MinimaxProvider } from "../minimax/client.js";
|
|
@@ -114,6 +115,8 @@ const ADAPTER_FACTORIES: Record<string, AdapterFactory> = {
|
|
|
114
115
|
}),
|
|
115
116
|
minimax: ({ apiKey, model, streamTimeoutMs }) =>
|
|
116
117
|
new MinimaxProvider(apiKey, model, { streamTimeoutMs }),
|
|
118
|
+
atlascloud: ({ apiKey, model, streamTimeoutMs }) =>
|
|
119
|
+
new AtlasCloudProvider(apiKey, model, { streamTimeoutMs }),
|
|
117
120
|
};
|
|
118
121
|
|
|
119
122
|
/**
|