@vellumai/assistant 0.9.1-staging.1 → 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/docs/activation-funnel-telemetry.md +24 -18
- 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 +15 -0
- package/openapi.yaml +852 -15
- package/package.json +1 -1
- 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 +59 -7
- package/src/__tests__/agent-loop-compaction-strip.test.ts +17 -16
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
- package/src/__tests__/app-compiler.test.ts +15 -1
- package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
- 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__/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 +174 -30
- package/src/__tests__/config-schema.test.ts +35 -0
- 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-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-execution-shell-lockdown.test.ts +18 -11
- package/src/__tests__/credential-prompt-route.test.ts +1 -0
- package/src/__tests__/credential-security-invariants.test.ts +2 -0
- 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 +51 -0
- package/src/__tests__/gateway-flag-listener.test.ts +110 -1
- 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__/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 +0 -3
- package/src/__tests__/llm-catalog-parity.test.ts +30 -1
- package/src/__tests__/llm-resolver.test.ts +21 -0
- 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__/path-policy.test.ts +34 -0
- package/src/__tests__/persona-resolver.test.ts +38 -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__/relay-server.test.ts +285 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
- package/src/__tests__/skill-execute-input.test.ts +5 -0
- 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 +150 -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__/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__/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-verification.test.ts +2 -4
- package/src/__tests__/twilio-routes.test.ts +81 -1
- package/src/__tests__/voice-invite-redemption.test.ts +0 -1
- package/src/__tests__/weak-open-model.test.ts +30 -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 +33 -33
- 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 +26 -0
- package/src/api/responses/home.ts +26 -0
- 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 +181 -78
- 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-server.ts +66 -0
- package/src/calls/relay-setup-router.ts +82 -1
- package/src/calls/twilio-routes.ts +17 -8
- 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 +57 -5
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +134 -4
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +53 -11
- package/src/cli/lib/inspect-plugin.ts +12 -1
- package/src/cli/lib/merge-plugin-tree.ts +149 -49
- package/src/cli/lib/plugin-surfaces.ts +104 -0
- package/src/cli/lib/upgrade-plugin.ts +64 -36
- package/src/cli/program.ts +2 -4
- 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/workflows/SKILL.md +14 -7
- package/src/config/call-site-defaults.ts +3 -0
- package/src/config/feature-flag-registry.json +49 -18
- package/src/config/llm-resolver.ts +3 -0
- package/src/config/memory-v3-gate.ts +11 -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/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/services.ts +18 -0
- package/src/config/seed-inference-profiles.ts +94 -34
- package/src/config/skills.ts +21 -0
- package/src/config/sync-gated-profiles.ts +220 -0
- package/src/contacts/contact-store.ts +2 -10
- package/src/contacts/contacts-write.ts +1 -2
- package/src/contacts/types.ts +0 -1
- package/src/context/compactor.ts +86 -52
- package/src/context/strip-injections.ts +58 -10
- package/src/context/token-estimator.ts +1 -1
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
- package/src/daemon/conversation-agent-loop.ts +100 -19
- 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-surfaces.ts +26 -0
- package/src/daemon/conversation-tool-setup.ts +16 -11
- package/src/daemon/conversation.ts +64 -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 +5 -10
- package/src/daemon/handlers/config-slack-channel.ts +20 -0
- package/src/daemon/handlers/conversations.ts +107 -0
- package/src/daemon/host-browser-proxy.ts +41 -0
- package/src/daemon/lifecycle.ts +55 -20
- package/src/daemon/message-provenance.ts +2 -0
- package/src/daemon/message-types/contacts.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/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/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 +34 -0
- 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/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 +10 -0
- package/src/memory/embedding-backend.ts +15 -1
- package/src/memory/jobs-worker.ts +2 -1
- package/src/memory/lifecycle-events-store.ts +2 -2
- package/src/memory/memory-retrospective-enqueue.ts +31 -6
- package/src/memory/memory-retrospective-job.ts +9 -0
- 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 +10 -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 +30 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/onboarding-events-store.ts +3 -3
- package/src/memory/schema/contacts.ts +0 -1
- 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/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/slack.ts +55 -73
- package/src/notifications/approval-card-data.ts +333 -0
- package/src/notifications/broadcaster.ts +6 -2
- 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 +3 -13
- package/src/notifications/notification-utils.ts +2 -1
- package/src/notifications/signal.ts +79 -43
- package/src/notifications/types.ts +98 -128
- 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/index.ts +27 -0
- 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 +35 -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 +75 -7
- 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 +37 -4
- 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/task-progress-nudge/hooks/post-tool-use.ts +2 -12
- package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
- package/src/prompts/persona-resolver.ts +12 -2
- 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/__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 +49 -21
- 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/capabilities.test.ts +120 -0
- package/src/runtime/capabilities.ts +197 -0
- package/src/runtime/channel-approval-types.ts +5 -1
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/channel-verification-service.ts +1 -2
- 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 +6 -22
- 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 +35 -13
- package/src/runtime/routes/browser-tabs-routes.ts +9 -0
- 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-management-routes.ts +80 -1
- package/src/runtime/routes/conversation-query-routes.ts +68 -22
- package/src/runtime/routes/conversation-routes.ts +37 -12
- 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/inbound-message-handler.ts +214 -228
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +88 -6
- 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 +40 -7
- 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 +225 -1
- package/src/runtime/routes/workflow-routes.ts +131 -1
- package/src/runtime/tool-grant-request-helper.ts +18 -16
- package/src/runtime/trust-context-resolver.ts +8 -5
- 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 +11 -4
- 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/browser/__tests__/browser-execution-acquire.test.ts +31 -0
- package/src/tools/browser/browser-execution.ts +29 -18
- 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.ts +213 -10
- package/src/tools/permission-checker.ts +3 -2
- package/src/tools/registry.ts +20 -0
- package/src/tools/schedule/create.ts +4 -3
- package/src/tools/schedule/update.ts +2 -1
- package/src/tools/shared/filesystem/path-policy.ts +39 -13
- package/src/tools/skills/execute.ts +1 -2
- package/src/tools/subagent/spawn.ts +37 -13
- package/src/tools/terminal/shell.ts +10 -4
- package/src/tools/tool-approval-handler.ts +17 -10
- package/src/tools/types.ts +9 -0
- package/src/tools/ui-surface/definitions.ts +25 -2
- package/src/tools/verification-control-plane-policy.ts +3 -1
- package/src/tools/workflows/run-workflow.ts +1 -0
- package/src/util/disk-usage.ts +78 -23
- package/src/util/platform.ts +8 -1
- package/src/watcher/telemetry.ts +2 -2
- 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 -3
- package/src/workflows/run-manager.ts +64 -0
- 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/notifications/tool-approval-copy.ts +0 -142
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
|
@@ -41,7 +41,11 @@ function resetTables(): void {
|
|
|
41
41
|
|
|
42
42
|
async function addImageMessage(
|
|
43
43
|
conversationId: string,
|
|
44
|
-
provenanceTrustClass:
|
|
44
|
+
provenanceTrustClass:
|
|
45
|
+
| "guardian"
|
|
46
|
+
| "trusted_contact"
|
|
47
|
+
| "unverified_contact"
|
|
48
|
+
| "unknown",
|
|
45
49
|
filename: string,
|
|
46
50
|
): Promise<void> {
|
|
47
51
|
const inserted = await addMessage(
|
|
@@ -109,4 +113,20 @@ describe("collectImageManifest trust filtering", () => {
|
|
|
109
113
|
expect(filenames).toContain("contact.png");
|
|
110
114
|
expect(filenames).not.toContain("guardian-secret.png");
|
|
111
115
|
});
|
|
116
|
+
|
|
117
|
+
test("unverified_contact actor manifest excludes guardian images but keeps unverified-provenance images", async () => {
|
|
118
|
+
// GIVEN a conversation with a guardian image and an unverified-contact image
|
|
119
|
+
const conv = createConversation();
|
|
120
|
+
await addImageMessage(conv.id, "guardian", "guardian-secret.png");
|
|
121
|
+
await addImageMessage(conv.id, "unverified_contact", "unverified.png");
|
|
122
|
+
|
|
123
|
+
// WHEN the manifest is built for an unverified_contact actor
|
|
124
|
+
const manifest = collectImageManifest(conv.id, "unverified_contact");
|
|
125
|
+
|
|
126
|
+
// THEN the unverified-provenance image is listed and the guardian image
|
|
127
|
+
// is excluded — unverified_contact is treated as untrusted downstream.
|
|
128
|
+
const filenames = manifest.map((e) => e.filename);
|
|
129
|
+
expect(filenames).toContain("unverified.png");
|
|
130
|
+
expect(filenames).not.toContain("guardian-secret.png");
|
|
131
|
+
});
|
|
112
132
|
});
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The compaction summary call bounds its own input to the context window.
|
|
3
|
+
*
|
|
4
|
+
* With no tool pair to anchor an emergency split, an overflow recovery routes
|
|
5
|
+
* the full conversation straight into `runAssistantDrivenCompaction`. If that
|
|
6
|
+
* history exceeds the window, the summary call must front-truncate its own
|
|
7
|
+
* request or it overflows in turn and recovery stalls. Below the window the
|
|
8
|
+
* request is sent untouched so its prefix stays byte-aligned with the agent's
|
|
9
|
+
* warm cache (the budget-path cache reuse must not regress).
|
|
10
|
+
*/
|
|
11
|
+
import { describe, expect, mock, test } from "bun:test";
|
|
12
|
+
|
|
13
|
+
function makeLoggerStub(): Record<string, unknown> {
|
|
14
|
+
const stub: Record<string, unknown> = {};
|
|
15
|
+
for (const m of [
|
|
16
|
+
"info",
|
|
17
|
+
"warn",
|
|
18
|
+
"error",
|
|
19
|
+
"debug",
|
|
20
|
+
"trace",
|
|
21
|
+
"fatal",
|
|
22
|
+
"silent",
|
|
23
|
+
"child",
|
|
24
|
+
]) {
|
|
25
|
+
stub[m] = m === "child" ? () => makeLoggerStub() : () => {};
|
|
26
|
+
}
|
|
27
|
+
return stub;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
mock.module("../util/logger.js", () => ({
|
|
31
|
+
getLogger: () => makeLoggerStub(),
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
mock.module("../memory/conversation-crud.js", () => ({
|
|
35
|
+
getMessages: () => [],
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
mock.module("../memory/attachments-store.js", () => ({
|
|
39
|
+
getAttachmentMetadataForMessage: () => [],
|
|
40
|
+
getAttachmentContent: () => null,
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
mock.module("../memory/llm-request-log-store.js", () => ({
|
|
44
|
+
recordRequestLog: () => {},
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
import { runAssistantDrivenCompaction } from "../context/compactor.js";
|
|
48
|
+
import { estimatePromptTokens } from "../context/token-estimator.js";
|
|
49
|
+
import type { Message, Provider } from "../providers/types.js";
|
|
50
|
+
|
|
51
|
+
const TRUNCATION_MARKER = "summary covers only the visible portion";
|
|
52
|
+
|
|
53
|
+
function turnTimestamp(turn: number): string {
|
|
54
|
+
const hour = String(10 + Math.floor(turn / 60)).padStart(2, "0");
|
|
55
|
+
const minute = String(turn % 60).padStart(2, "0");
|
|
56
|
+
return `2026-05-21 (Thursday) ${hour}:${minute}:00 -05:00 (America/Chicago)`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function userTurn(turn: number, body: string): Message {
|
|
60
|
+
return {
|
|
61
|
+
role: "user",
|
|
62
|
+
content: [
|
|
63
|
+
{
|
|
64
|
+
type: "text",
|
|
65
|
+
text: `<turn_context>\ncurrent_time: ${turnTimestamp(
|
|
66
|
+
turn,
|
|
67
|
+
)}\n</turn_context>\n[U${turn}] ${body}`,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function assistantTurn(turn: number, body: string): Message {
|
|
74
|
+
return {
|
|
75
|
+
role: "assistant",
|
|
76
|
+
content: [{ type: "text", text: `[A${turn}] ${body}` }],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const SUMMARY = "Earlier turns summarized in the assistant's own voice.";
|
|
81
|
+
|
|
82
|
+
function compactionResponse(tailTurn: number, preview: string): string {
|
|
83
|
+
return `<compaction_result>
|
|
84
|
+
<summary>
|
|
85
|
+
${SUMMARY}
|
|
86
|
+
</summary>
|
|
87
|
+
<key_state>
|
|
88
|
+
- Nothing critical pending.
|
|
89
|
+
</key_state>
|
|
90
|
+
<tail_start timestamp="${turnTimestamp(tailTurn)}" preview="${preview}" />
|
|
91
|
+
</compaction_result>`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function makeCapturingProvider(response: string): {
|
|
95
|
+
provider: Provider;
|
|
96
|
+
lastRequest: () => Message[] | null;
|
|
97
|
+
} {
|
|
98
|
+
let captured: Message[] | null = null;
|
|
99
|
+
const provider: Provider = {
|
|
100
|
+
name: "mock-provider",
|
|
101
|
+
sendMessage: async (messages: Message[]) => {
|
|
102
|
+
captured = messages;
|
|
103
|
+
return {
|
|
104
|
+
content: [{ type: "text", text: response }],
|
|
105
|
+
model: "mock-model",
|
|
106
|
+
usage: { inputTokens: 100, outputTokens: 50 },
|
|
107
|
+
stopReason: "end_turn",
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
return { provider, lastRequest: () => captured };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function estimate(messages: Message[]): number {
|
|
115
|
+
return estimatePromptTokens(messages, "system", {
|
|
116
|
+
providerName: "mock-provider",
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
describe("runAssistantDrivenCompaction — summary call self-truncation", () => {
|
|
121
|
+
test("front-truncates the outbound request when the full history exceeds the context window", async () => {
|
|
122
|
+
// GIVEN a tool-pair-free history whose estimate exceeds the window, so an
|
|
123
|
+
// overflow recovery would route it straight into the summary call.
|
|
124
|
+
const messages: Message[] = [];
|
|
125
|
+
for (let i = 0; i < 40; i++) {
|
|
126
|
+
messages.push(
|
|
127
|
+
userTurn(
|
|
128
|
+
i,
|
|
129
|
+
"Heavy user turn body that carries real weight. ".repeat(8),
|
|
130
|
+
),
|
|
131
|
+
);
|
|
132
|
+
messages.push(
|
|
133
|
+
assistantTurn(
|
|
134
|
+
i,
|
|
135
|
+
"Heavy assistant reply that also carries weight. ".repeat(8),
|
|
136
|
+
),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const maxInputTokens = 10_000;
|
|
141
|
+
// Budget mirrors compactor.compactionPrefixBudget: window minus the
|
|
142
|
+
// instruction reserve (800) and the 15% output reserve.
|
|
143
|
+
const prefixBudget =
|
|
144
|
+
maxInputTokens - 800 - Math.floor(maxInputTokens * 0.15);
|
|
145
|
+
expect(estimate(messages)).toBeGreaterThan(prefixBudget);
|
|
146
|
+
|
|
147
|
+
const { provider, lastRequest } = makeCapturingProvider(
|
|
148
|
+
compactionResponse(38, "Heavy user turn body"),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// WHEN the summary call runs against that oversized history.
|
|
152
|
+
const result = await runAssistantDrivenCompaction({
|
|
153
|
+
conversationId: "conv-test",
|
|
154
|
+
messages,
|
|
155
|
+
provider,
|
|
156
|
+
systemPrompt: "system",
|
|
157
|
+
compaction: { enabled: true, autoThreshold: 0.7 },
|
|
158
|
+
maxInputTokens,
|
|
159
|
+
force: true,
|
|
160
|
+
previousEstimatedInputTokens: 90_000,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
expect(result.compacted).toBe(true);
|
|
164
|
+
|
|
165
|
+
// THEN the request actually sent fits within the context window.
|
|
166
|
+
const sent = lastRequest();
|
|
167
|
+
expect(sent).not.toBeNull();
|
|
168
|
+
expect(estimate(sent ?? [])).toBeLessThan(maxInputTokens);
|
|
169
|
+
|
|
170
|
+
// AND it opens with a marker noting the dropped leading messages so the
|
|
171
|
+
// model knows the summary covers only the visible portion.
|
|
172
|
+
const firstBlock = sent?.[0]?.content[0];
|
|
173
|
+
const firstText = firstBlock && "text" in firstBlock ? firstBlock.text : "";
|
|
174
|
+
expect(firstText).toContain(TRUNCATION_MARKER);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("sends the full history untouched when it already fits below the budget", async () => {
|
|
178
|
+
// GIVEN a small history whose estimate is well under the window — the
|
|
179
|
+
// common budget-triggered compaction.
|
|
180
|
+
const messages: Message[] = [];
|
|
181
|
+
for (let i = 0; i < 8; i++) {
|
|
182
|
+
messages.push(userTurn(i, "short user turn body"));
|
|
183
|
+
messages.push(assistantTurn(i, "short assistant reply body"));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const maxInputTokens = 200_000;
|
|
187
|
+
const prefixBudget =
|
|
188
|
+
maxInputTokens - 800 - Math.floor(maxInputTokens * 0.15);
|
|
189
|
+
expect(estimate(messages)).toBeLessThan(prefixBudget);
|
|
190
|
+
|
|
191
|
+
const { provider, lastRequest } = makeCapturingProvider(
|
|
192
|
+
compactionResponse(6, "short user turn body"),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
// WHEN the summary call runs against the below-budget history.
|
|
196
|
+
const result = await runAssistantDrivenCompaction({
|
|
197
|
+
conversationId: "conv-test",
|
|
198
|
+
messages,
|
|
199
|
+
provider,
|
|
200
|
+
systemPrompt: "system",
|
|
201
|
+
compaction: { enabled: true, autoThreshold: 0.7 },
|
|
202
|
+
maxInputTokens,
|
|
203
|
+
force: true,
|
|
204
|
+
previousEstimatedInputTokens: 90_000,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
expect(result.compacted).toBe(true);
|
|
208
|
+
|
|
209
|
+
// THEN no truncation marker is prepended and the request carries every
|
|
210
|
+
// history message plus the single instruction, with the leading message
|
|
211
|
+
// byte-identical to the original — keeping the prefix cache warm.
|
|
212
|
+
const sent = lastRequest();
|
|
213
|
+
expect(sent).not.toBeNull();
|
|
214
|
+
expect(sent?.length).toBe(messages.length + 1);
|
|
215
|
+
const firstBlock = sent?.[0]?.content[0];
|
|
216
|
+
const firstText = firstBlock && "text" in firstBlock ? firstBlock.text : "";
|
|
217
|
+
expect(firstText).not.toContain(TRUNCATION_MARKER);
|
|
218
|
+
const originalFirst = messages[0]?.content[0];
|
|
219
|
+
expect(firstText).toBe(
|
|
220
|
+
originalFirst && "text" in originalFirst ? originalFirst.text : "",
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
@@ -75,7 +75,12 @@ import {
|
|
|
75
75
|
loadConfig,
|
|
76
76
|
mergeDefaultWorkspaceConfig,
|
|
77
77
|
} from "../config/loader.js";
|
|
78
|
-
import {
|
|
78
|
+
import {
|
|
79
|
+
MANAGED_PROFILE_NAMES,
|
|
80
|
+
materializeProfile,
|
|
81
|
+
OS_BETA_PROFILE_TEMPLATE,
|
|
82
|
+
seedInferenceProfiles,
|
|
83
|
+
} from "../config/seed-inference-profiles.js";
|
|
79
84
|
import type { DrizzleDb } from "../memory/db-connection.js";
|
|
80
85
|
import { migrateCreateProviderConnections } from "../memory/migrations/243-provider-connections.js";
|
|
81
86
|
import { migrateProviderConnectionStatusLabel } from "../memory/migrations/244-provider-connection-status-label.js";
|
|
@@ -480,9 +485,11 @@ describe("loadConfig startup behavior", () => {
|
|
|
480
485
|
"anthropic-personal",
|
|
481
486
|
);
|
|
482
487
|
// Managed profiles exist as well.
|
|
483
|
-
expect(config.llm.profiles.balanced?.model).toBe(
|
|
488
|
+
expect(config.llm.profiles.balanced?.model).toBe(
|
|
489
|
+
"accounts/fireworks/models/minimax-m3",
|
|
490
|
+
);
|
|
484
491
|
expect(config.llm.profiles.balanced?.provider_connection).toBe(
|
|
485
|
-
"
|
|
492
|
+
"fireworks-managed",
|
|
486
493
|
);
|
|
487
494
|
|
|
488
495
|
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
@@ -491,7 +498,9 @@ describe("loadConfig startup behavior", () => {
|
|
|
491
498
|
model: "claude-opus-4-7",
|
|
492
499
|
});
|
|
493
500
|
expect(raw.llm.activeProfile).toBe("custom-balanced");
|
|
494
|
-
expect(raw.llm.profiles.balanced.model).toBe(
|
|
501
|
+
expect(raw.llm.profiles.balanced.model).toBe(
|
|
502
|
+
"accounts/fireworks/models/minimax-m3",
|
|
503
|
+
);
|
|
495
504
|
});
|
|
496
505
|
|
|
497
506
|
test("on-platform hatch seeds only managed profiles", () => {
|
|
@@ -519,9 +528,11 @@ describe("loadConfig startup behavior", () => {
|
|
|
519
528
|
const config = loadConfig();
|
|
520
529
|
|
|
521
530
|
expect(config.llm.activeProfile).toBe("balanced");
|
|
522
|
-
expect(config.llm.profiles.balanced?.model).toBe(
|
|
531
|
+
expect(config.llm.profiles.balanced?.model).toBe(
|
|
532
|
+
"accounts/fireworks/models/minimax-m3",
|
|
533
|
+
);
|
|
523
534
|
expect(config.llm.profiles.balanced?.provider_connection).toBe(
|
|
524
|
-
"
|
|
535
|
+
"fireworks-managed",
|
|
525
536
|
);
|
|
526
537
|
// No user profiles created on platform.
|
|
527
538
|
expect(config.llm.profiles["custom-balanced"]).toBeUndefined();
|
|
@@ -563,10 +574,10 @@ describe("loadConfig startup behavior", () => {
|
|
|
563
574
|
expect(raw.llm.profiles["custom-balanced"].provider_connection).toBe(
|
|
564
575
|
"anthropic-personal",
|
|
565
576
|
);
|
|
566
|
-
// Managed balanced profile is seeded for
|
|
567
|
-
expect(raw.llm.profiles.balanced.provider).toBe("
|
|
577
|
+
// Managed balanced profile is seeded for fireworks-managed (MiniMax M3).
|
|
578
|
+
expect(raw.llm.profiles.balanced.provider).toBe("fireworks");
|
|
568
579
|
expect(raw.llm.profiles.balanced.provider_connection).toBe(
|
|
569
|
-
"
|
|
580
|
+
"fireworks-managed",
|
|
570
581
|
);
|
|
571
582
|
});
|
|
572
583
|
|
|
@@ -600,9 +611,9 @@ describe("loadConfig startup behavior", () => {
|
|
|
600
611
|
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
601
612
|
// On-platform: no user profiles created, active resets to managed balanced.
|
|
602
613
|
expect(raw.llm.activeProfile).toBe("balanced");
|
|
603
|
-
expect(raw.llm.profiles.balanced.provider).toBe("
|
|
614
|
+
expect(raw.llm.profiles.balanced.provider).toBe("fireworks");
|
|
604
615
|
expect(raw.llm.profiles.balanced.provider_connection).toBe(
|
|
605
|
-
"
|
|
616
|
+
"fireworks-managed",
|
|
606
617
|
);
|
|
607
618
|
// The old custom-balanced is preserved on disk but no longer active.
|
|
608
619
|
expect(raw.llm.profiles["custom-balanced"].provider).toBe("openai");
|
|
@@ -654,10 +665,10 @@ describe("loadConfig startup behavior", () => {
|
|
|
654
665
|
"gpt-5.4-nano",
|
|
655
666
|
);
|
|
656
667
|
|
|
657
|
-
// Managed profiles are also seeded (balanced uses
|
|
658
|
-
expect(raw.llm.profiles.balanced.provider).toBe("
|
|
668
|
+
// Managed profiles are also seeded (balanced uses Fireworks/MiniMax M3).
|
|
669
|
+
expect(raw.llm.profiles.balanced.provider).toBe("fireworks");
|
|
659
670
|
expect(raw.llm.profiles.balanced.provider_connection).toBe(
|
|
660
|
-
"
|
|
671
|
+
"fireworks-managed",
|
|
661
672
|
);
|
|
662
673
|
expect(raw.llm.profiles.balanced.source).toBe("managed");
|
|
663
674
|
expect(raw.llm.profiles["quality-optimized"].provider).toBe("anthropic");
|
|
@@ -685,9 +696,11 @@ describe("loadConfig startup behavior", () => {
|
|
|
685
696
|
mergeDefaultConfigAndSeedInferenceProfiles();
|
|
686
697
|
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
687
698
|
|
|
688
|
-
expect(raw.llm.profiles.balanced.model).toBe(
|
|
699
|
+
expect(raw.llm.profiles.balanced.model).toBe(
|
|
700
|
+
"accounts/fireworks/models/minimax-m3",
|
|
701
|
+
);
|
|
689
702
|
expect(raw.llm.profiles.balanced.provider_connection).toBe(
|
|
690
|
-
"
|
|
703
|
+
"fireworks-managed",
|
|
691
704
|
);
|
|
692
705
|
expect(raw.llm.activeProfile).toBe("balanced");
|
|
693
706
|
});
|
|
@@ -717,10 +730,13 @@ describe("loadConfig startup behavior", () => {
|
|
|
717
730
|
mergeDefaultConfigAndSeedInferenceProfiles();
|
|
718
731
|
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
719
732
|
|
|
720
|
-
expect(raw.llm.profiles.balanced.model).toBe(
|
|
721
|
-
|
|
733
|
+
expect(raw.llm.profiles.balanced.model).toBe(
|
|
734
|
+
"accounts/fireworks/models/minimax-m3",
|
|
735
|
+
);
|
|
736
|
+
expect(raw.llm.profiles.balanced.maxTokens).toBe(32000);
|
|
737
|
+
expect(raw.llm.profiles.balanced.topP).toBe(0.95);
|
|
722
738
|
expect(raw.llm.profiles.balanced.provider_connection).toBe(
|
|
723
|
-
"
|
|
739
|
+
"fireworks-managed",
|
|
724
740
|
);
|
|
725
741
|
expect(raw.llm.activeProfile).toBe("balanced");
|
|
726
742
|
});
|
|
@@ -750,7 +766,9 @@ describe("loadConfig startup behavior", () => {
|
|
|
750
766
|
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
751
767
|
|
|
752
768
|
// Content refreshes from the template...
|
|
753
|
-
expect(raw.llm.profiles.balanced.model).toBe(
|
|
769
|
+
expect(raw.llm.profiles.balanced.model).toBe(
|
|
770
|
+
"accounts/fireworks/models/minimax-m3",
|
|
771
|
+
);
|
|
754
772
|
// ...but the user's label and status overrides are preserved.
|
|
755
773
|
expect(raw.llm.profiles.balanced.label).toBe("My Default");
|
|
756
774
|
expect(raw.llm.profiles.balanced.status).toBe("disabled");
|
|
@@ -778,7 +796,9 @@ describe("loadConfig startup behavior", () => {
|
|
|
778
796
|
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
779
797
|
|
|
780
798
|
// Model still gets the new template value (provider-controlled).
|
|
781
|
-
expect(raw.llm.profiles.balanced.model).toBe(
|
|
799
|
+
expect(raw.llm.profiles.balanced.model).toBe(
|
|
800
|
+
"accounts/fireworks/models/minimax-m3",
|
|
801
|
+
);
|
|
782
802
|
// But the user's label override is preserved across the reseed.
|
|
783
803
|
expect(raw.llm.profiles.balanced.label).toBe("My Default");
|
|
784
804
|
});
|
|
@@ -806,7 +826,51 @@ describe("loadConfig startup behavior", () => {
|
|
|
806
826
|
|
|
807
827
|
expect(raw.llm.profiles.balanced.status).toBe("disabled");
|
|
808
828
|
// Model still refreshes — only label/status are user-owned.
|
|
809
|
-
expect(raw.llm.profiles.balanced.model).toBe(
|
|
829
|
+
expect(raw.llm.profiles.balanced.model).toBe(
|
|
830
|
+
"accounts/fireworks/models/minimax-m3",
|
|
831
|
+
);
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
test("reseed preserves user-edited topP on managed profiles", () => {
|
|
835
|
+
// Simulate a user who overrode topP on the managed "balanced" profile via
|
|
836
|
+
// PUT /v1/config/llm/profiles/balanced { topP: 0.5 }. The override must
|
|
837
|
+
// survive the reconcile instead of reverting to the template's 0.95.
|
|
838
|
+
writeConfig({
|
|
839
|
+
llm: {
|
|
840
|
+
profiles: {
|
|
841
|
+
balanced: {
|
|
842
|
+
source: "managed",
|
|
843
|
+
provider: "anthropic",
|
|
844
|
+
model: "old-model-from-previous-release",
|
|
845
|
+
provider_connection: "anthropic-managed",
|
|
846
|
+
topP: 0.5,
|
|
847
|
+
},
|
|
848
|
+
},
|
|
849
|
+
activeProfile: "balanced",
|
|
850
|
+
},
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
mergeDefaultConfigAndSeedInferenceProfiles();
|
|
854
|
+
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
855
|
+
|
|
856
|
+
// The user's topP override is preserved across the reseed (not reverted to
|
|
857
|
+
// the template default of 0.95).
|
|
858
|
+
expect(raw.llm.profiles.balanced.topP).toBe(0.5);
|
|
859
|
+
// Model still refreshes — topP is user-owned, the rest is template-owned.
|
|
860
|
+
expect(raw.llm.profiles.balanced.model).toBe(
|
|
861
|
+
"accounts/fireworks/models/minimax-m3",
|
|
862
|
+
);
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
test("reseed seeds the template topP on a fresh managed balanced profile", () => {
|
|
866
|
+
// No previous on-disk entry → the balanced profile materializes with the
|
|
867
|
+
// template's topP default of 0.95.
|
|
868
|
+
writeConfig({ llm: {} });
|
|
869
|
+
|
|
870
|
+
mergeDefaultConfigAndSeedInferenceProfiles();
|
|
871
|
+
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
872
|
+
|
|
873
|
+
expect(raw.llm.profiles.balanced.topP).toBe(0.95);
|
|
810
874
|
});
|
|
811
875
|
|
|
812
876
|
test("off-platform reseed preserves an explicit null label (user cleared it)", () => {
|
|
@@ -847,7 +911,9 @@ describe("loadConfig startup behavior", () => {
|
|
|
847
911
|
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
848
912
|
|
|
849
913
|
expect(raw.llm.profiles.balanced.label).toBe("Balanced (Managed)");
|
|
850
|
-
expect(raw.llm.profiles.balanced.model).toBe(
|
|
914
|
+
expect(raw.llm.profiles.balanced.model).toBe(
|
|
915
|
+
"accounts/fireworks/models/minimax-m3",
|
|
916
|
+
);
|
|
851
917
|
// Status is unset by default — must not appear as `undefined`.
|
|
852
918
|
expect("status" in raw.llm.profiles.balanced).toBe(false);
|
|
853
919
|
});
|
|
@@ -933,18 +999,20 @@ describe("loadConfig startup behavior", () => {
|
|
|
933
999
|
expect(raw.llm.profiles.balanced.maxTokens).toBeUndefined();
|
|
934
1000
|
expect(raw.llm.profiles.balanced.thinking).toBeUndefined();
|
|
935
1001
|
|
|
936
|
-
// Next boot, no overlay: content reconciles to the
|
|
1002
|
+
// Next boot, no overlay: content reconciles to the fireworks-managed code
|
|
937
1003
|
// template; only the overlay-set label is carried across.
|
|
938
1004
|
mergeDefaultConfigAndSeedInferenceProfiles();
|
|
939
1005
|
|
|
940
1006
|
const afterRestart = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
941
1007
|
expect(afterRestart.llm.activeProfile).toBe("balanced");
|
|
942
|
-
expect(afterRestart.llm.profiles.balanced.provider).toBe("
|
|
1008
|
+
expect(afterRestart.llm.profiles.balanced.provider).toBe("fireworks");
|
|
943
1009
|
expect(afterRestart.llm.profiles.balanced.provider_connection).toBe(
|
|
944
|
-
"
|
|
1010
|
+
"fireworks-managed",
|
|
1011
|
+
);
|
|
1012
|
+
expect(afterRestart.llm.profiles.balanced.model).toBe(
|
|
1013
|
+
"accounts/fireworks/models/minimax-m3",
|
|
945
1014
|
);
|
|
946
|
-
expect(afterRestart.llm.profiles.balanced.
|
|
947
|
-
expect(afterRestart.llm.profiles.balanced.maxTokens).toBe(16000);
|
|
1015
|
+
expect(afterRestart.llm.profiles.balanced.maxTokens).toBe(32000);
|
|
948
1016
|
expect(afterRestart.llm.profiles.balanced.thinking).toEqual({
|
|
949
1017
|
enabled: true,
|
|
950
1018
|
streamThinking: true,
|
|
@@ -989,7 +1057,9 @@ describe("loadConfig startup behavior", () => {
|
|
|
989
1057
|
// Off-platform hatch: user profiles are active.
|
|
990
1058
|
expect(raw.llm.activeProfile).toBe("custom-balanced");
|
|
991
1059
|
expect(raw.llm.profiles["custom-balanced"].provider).toBe("anthropic");
|
|
992
|
-
expect(raw.llm.profiles.balanced.model).toBe(
|
|
1060
|
+
expect(raw.llm.profiles.balanced.model).toBe(
|
|
1061
|
+
"accounts/fireworks/models/minimax-m3",
|
|
1062
|
+
);
|
|
993
1063
|
});
|
|
994
1064
|
|
|
995
1065
|
test("still quarantines corrupt JSON", () => {
|
|
@@ -1086,6 +1156,11 @@ describe("seedInferenceProfiles BYOK-mode managed profile labels", () => {
|
|
|
1086
1156
|
|
|
1087
1157
|
// Personal profiles keep their bare labels — they're the daily driver.
|
|
1088
1158
|
expect(config.llm.profiles["custom-balanced"]?.label).toBe("Balanced");
|
|
1159
|
+
|
|
1160
|
+
// top_p is scoped to the managed Balanced profile only; the BYOK
|
|
1161
|
+
// custom-balanced profile must not pick it up.
|
|
1162
|
+
expect(config.llm.profiles.balanced?.topP).toBe(0.95);
|
|
1163
|
+
expect(config.llm.profiles["custom-balanced"]?.topP).toBeUndefined();
|
|
1089
1164
|
});
|
|
1090
1165
|
|
|
1091
1166
|
test("off-platform hatch initializes managed profile status to 'disabled'", () => {
|
|
@@ -1133,7 +1208,7 @@ describe("seedInferenceProfiles BYOK-mode managed profile labels", () => {
|
|
|
1133
1208
|
|
|
1134
1209
|
expect(raw.llm.activeProfile).toBe("balanced");
|
|
1135
1210
|
expect(raw.llm.profiles.balanced.provider_connection).toBe(
|
|
1136
|
-
"
|
|
1211
|
+
"fireworks-managed",
|
|
1137
1212
|
);
|
|
1138
1213
|
expect("status" in raw.llm.profiles.balanced).toBe(false);
|
|
1139
1214
|
// Connections exist (status is no longer a connection-level concept).
|
|
@@ -1380,3 +1455,72 @@ describe("seedInferenceProfiles BYOK-mode managed profile labels", () => {
|
|
|
1380
1455
|
expect(config.llm.profiles.balanced?.label).toBe("Balanced (Managed)");
|
|
1381
1456
|
});
|
|
1382
1457
|
});
|
|
1458
|
+
|
|
1459
|
+
// ---------------------------------------------------------------------------
|
|
1460
|
+
// Tests: OS Beta flag-gated managed profile. The template is defined but
|
|
1461
|
+
// intentionally NOT part of MANAGED_PROFILE_TEMPLATES, so seedInferenceProfiles
|
|
1462
|
+
// must never create it. A later PR reconciles it in/out based on the `os-beta`
|
|
1463
|
+
// feature flag.
|
|
1464
|
+
// ---------------------------------------------------------------------------
|
|
1465
|
+
|
|
1466
|
+
describe("OS Beta managed profile template", () => {
|
|
1467
|
+
beforeEach(() => {
|
|
1468
|
+
ensureTestDir();
|
|
1469
|
+
const resetPaths = [
|
|
1470
|
+
CONFIG_PATH,
|
|
1471
|
+
join(WORKSPACE_DIR, "default-config.json"),
|
|
1472
|
+
join(WORKSPACE_DIR, "hatch-overlay.json"),
|
|
1473
|
+
join(WORKSPACE_DIR, "keys.enc"),
|
|
1474
|
+
join(WORKSPACE_DIR, "data"),
|
|
1475
|
+
join(WORKSPACE_DIR, "data", "memory"),
|
|
1476
|
+
];
|
|
1477
|
+
for (const path of resetPaths) {
|
|
1478
|
+
if (existsSync(path)) {
|
|
1479
|
+
rmSync(path, { recursive: true, force: true });
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
ensureTestDir();
|
|
1483
|
+
setStorePathForTesting(join(WORKSPACE_DIR, "keys.enc"));
|
|
1484
|
+
delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
|
|
1485
|
+
delete process.env.IS_PLATFORM;
|
|
1486
|
+
invalidateConfigCache();
|
|
1487
|
+
});
|
|
1488
|
+
|
|
1489
|
+
afterEach(() => {
|
|
1490
|
+
setStorePathForTesting(null);
|
|
1491
|
+
delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
|
|
1492
|
+
delete process.env.IS_PLATFORM;
|
|
1493
|
+
invalidateConfigCache();
|
|
1494
|
+
});
|
|
1495
|
+
|
|
1496
|
+
test("seedInferenceProfiles does not create an os-beta profile", () => {
|
|
1497
|
+
writeConfig({ llm: { default: { provider: "anthropic" } } });
|
|
1498
|
+
|
|
1499
|
+
mergeDefaultConfigAndSeedInferenceProfiles();
|
|
1500
|
+
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
1501
|
+
|
|
1502
|
+
expect(raw.llm.profiles["os-beta"]).toBeUndefined();
|
|
1503
|
+
expect((raw.llm.profileOrder as string[]).includes("os-beta")).toBe(false);
|
|
1504
|
+
});
|
|
1505
|
+
|
|
1506
|
+
test("MANAGED_PROFILE_NAMES contains os-beta", () => {
|
|
1507
|
+
expect(MANAGED_PROFILE_NAMES.has("os-beta")).toBe(true);
|
|
1508
|
+
});
|
|
1509
|
+
|
|
1510
|
+
test("materializeProfile honors the explicit OS Beta model", () => {
|
|
1511
|
+
const entry = materializeProfile(
|
|
1512
|
+
OS_BETA_PROFILE_TEMPLATE,
|
|
1513
|
+
"fireworks",
|
|
1514
|
+
"fireworks-managed",
|
|
1515
|
+
);
|
|
1516
|
+
|
|
1517
|
+
expect(entry.model).toBe("accounts/fireworks/models/glm-5p2");
|
|
1518
|
+
expect(entry.provider_connection).toBe("fireworks-managed");
|
|
1519
|
+
expect(entry.provider).toBe("fireworks");
|
|
1520
|
+
expect(entry.label).toBe("OS Beta");
|
|
1521
|
+
expect(entry.source).toBe("managed");
|
|
1522
|
+
expect(entry.maxTokens).toBe(32000);
|
|
1523
|
+
expect(entry.effort).toBe("high");
|
|
1524
|
+
expect(entry.thinking?.enabled).toBe(true);
|
|
1525
|
+
});
|
|
1526
|
+
});
|
|
@@ -145,6 +145,40 @@ describe("AssistantConfigSchema", () => {
|
|
|
145
145
|
expect(result.services["web-search"].mode).toBe("your-own");
|
|
146
146
|
});
|
|
147
147
|
|
|
148
|
+
test("accepts Firecrawl as a web search provider", () => {
|
|
149
|
+
const result = AssistantConfigSchema.parse({
|
|
150
|
+
services: {
|
|
151
|
+
"web-search": { mode: "your-own", provider: "firecrawl" },
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(result.services["web-search"].provider).toBe("firecrawl");
|
|
156
|
+
expect(result.services["web-search"].mode).toBe("your-own");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("defaults the web-fetch provider to the built-in fetcher", () => {
|
|
160
|
+
const result = AssistantConfigSchema.parse({});
|
|
161
|
+
expect(result.services["web-fetch"].provider).toBe("default");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("accepts Firecrawl as a web fetch provider", () => {
|
|
165
|
+
const result = AssistantConfigSchema.parse({
|
|
166
|
+
services: {
|
|
167
|
+
"web-fetch": { mode: "your-own", provider: "firecrawl" },
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(result.services["web-fetch"].provider).toBe("firecrawl");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("rejects an unknown web-fetch provider", () => {
|
|
175
|
+
expect(() =>
|
|
176
|
+
AssistantConfigSchema.parse({
|
|
177
|
+
services: { "web-fetch": { provider: "nope" } },
|
|
178
|
+
}),
|
|
179
|
+
).toThrow();
|
|
180
|
+
});
|
|
181
|
+
|
|
148
182
|
test("accepts valid complete config", () => {
|
|
149
183
|
const input = {
|
|
150
184
|
llm: {
|
|
@@ -185,6 +219,7 @@ describe("AssistantConfigSchema", () => {
|
|
|
185
219
|
speed: "standard",
|
|
186
220
|
verbosity: "medium",
|
|
187
221
|
temperature: null,
|
|
222
|
+
topP: null,
|
|
188
223
|
thinking: { enabled: true, streamThinking: true },
|
|
189
224
|
contextWindow: {
|
|
190
225
|
enabled: true,
|
|
@@ -178,7 +178,7 @@ describe("bridgeConfirmationRequestToGuardian", () => {
|
|
|
178
178
|
|
|
179
179
|
expect("skipped" in result && result.skipped).toBe(true);
|
|
180
180
|
if ("skipped" in result) {
|
|
181
|
-
expect(result.reason).toBe("
|
|
181
|
+
expect(result.reason).toBe("not_bridgeable_trust_class");
|
|
182
182
|
}
|
|
183
183
|
expect(emittedSignals).toHaveLength(0);
|
|
184
184
|
});
|
|
@@ -199,7 +199,7 @@ describe("bridgeConfirmationRequestToGuardian", () => {
|
|
|
199
199
|
|
|
200
200
|
expect("skipped" in result && result.skipped).toBe(true);
|
|
201
201
|
if ("skipped" in result) {
|
|
202
|
-
expect(result.reason).toBe("
|
|
202
|
+
expect(result.reason).toBe("not_bridgeable_trust_class");
|
|
203
203
|
}
|
|
204
204
|
expect(emittedSignals).toHaveLength(0);
|
|
205
205
|
});
|