@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
|
@@ -68,6 +68,9 @@ export interface WorkflowJournalEntry {
|
|
|
68
68
|
request: unknown;
|
|
69
69
|
result: unknown;
|
|
70
70
|
status: string;
|
|
71
|
+
/** Per-leaf token usage for a completed agent leaf; undefined otherwise. */
|
|
72
|
+
inputTokens?: number;
|
|
73
|
+
outputTokens?: number;
|
|
71
74
|
createdAt: number | null;
|
|
72
75
|
}
|
|
73
76
|
|
|
@@ -111,6 +114,9 @@ export interface AppendJournalEntryInput {
|
|
|
111
114
|
request?: unknown;
|
|
112
115
|
result?: unknown;
|
|
113
116
|
status: string;
|
|
117
|
+
/** Per-leaf token usage; set for a completed agent leaf, omitted otherwise. */
|
|
118
|
+
inputTokens?: number;
|
|
119
|
+
outputTokens?: number;
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
// ---------------------------------------------------------------------------
|
|
@@ -145,6 +151,8 @@ interface WorkflowJournalRow {
|
|
|
145
151
|
request_json: string | null;
|
|
146
152
|
result_json: string | null;
|
|
147
153
|
status: string;
|
|
154
|
+
input_tokens: number | null;
|
|
155
|
+
output_tokens: number | null;
|
|
148
156
|
created_at: number | null;
|
|
149
157
|
}
|
|
150
158
|
|
|
@@ -194,6 +202,8 @@ function rowToJournalEntry(row: WorkflowJournalRow): WorkflowJournalEntry {
|
|
|
194
202
|
request: parseJsonColumn(row.request_json),
|
|
195
203
|
result: parseJsonColumn(row.result_json),
|
|
196
204
|
status: row.status,
|
|
205
|
+
inputTokens: row.input_tokens ?? undefined,
|
|
206
|
+
outputTokens: row.output_tokens ?? undefined,
|
|
197
207
|
createdAt: row.created_at,
|
|
198
208
|
};
|
|
199
209
|
}
|
|
@@ -318,14 +328,17 @@ export function appendJournalEntry(
|
|
|
318
328
|
rawRun(
|
|
319
329
|
/*sql*/ `
|
|
320
330
|
INSERT INTO workflow_journal (
|
|
321
|
-
run_id, seq, call_hash, kind, request_json, result_json, status,
|
|
322
|
-
|
|
331
|
+
run_id, seq, call_hash, kind, request_json, result_json, status,
|
|
332
|
+
input_tokens, output_tokens, created_at
|
|
333
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
323
334
|
ON CONFLICT(run_id, seq) DO UPDATE SET
|
|
324
335
|
call_hash = excluded.call_hash,
|
|
325
336
|
kind = excluded.kind,
|
|
326
337
|
request_json = excluded.request_json,
|
|
327
338
|
result_json = excluded.result_json,
|
|
328
|
-
status = excluded.status
|
|
339
|
+
status = excluded.status,
|
|
340
|
+
input_tokens = excluded.input_tokens,
|
|
341
|
+
output_tokens = excluded.output_tokens
|
|
329
342
|
`,
|
|
330
343
|
input.runId,
|
|
331
344
|
input.seq,
|
|
@@ -334,6 +347,8 @@ export function appendJournalEntry(
|
|
|
334
347
|
serializeJsonColumn(input.request),
|
|
335
348
|
serializeJsonColumn(input.result),
|
|
336
349
|
input.status,
|
|
350
|
+
input.inputTokens ?? null,
|
|
351
|
+
input.outputTokens ?? null,
|
|
337
352
|
Date.now(),
|
|
338
353
|
);
|
|
339
354
|
return getJournalEntry(input.runId, input.seq)!;
|
|
@@ -292,6 +292,7 @@ describe("WorkflowRunManager.abort", () => {
|
|
|
292
292
|
scriptSource: "export const meta = { name: 'x', description: 'y' }",
|
|
293
293
|
args: {},
|
|
294
294
|
manifest: { tools: [], hostFunctions: [], persona: false },
|
|
295
|
+
conversationId: "conv-1",
|
|
295
296
|
trustContext: TRUST,
|
|
296
297
|
});
|
|
297
298
|
|
|
@@ -318,6 +319,7 @@ describe("WorkflowRunManager — progress events", () => {
|
|
|
318
319
|
scriptSource: "export const meta = { name: 'x', description: 'y' }",
|
|
319
320
|
args: {},
|
|
320
321
|
manifest: { tools: [], hostFunctions: [], persona: false },
|
|
322
|
+
conversationId: "conv-1",
|
|
321
323
|
label: "My Flow",
|
|
322
324
|
trustContext: TRUST,
|
|
323
325
|
});
|
|
@@ -330,14 +332,164 @@ describe("WorkflowRunManager — progress events", () => {
|
|
|
330
332
|
expect(progress).toHaveLength(2);
|
|
331
333
|
expect(progress[0]).toMatchObject({
|
|
332
334
|
type: "workflow_progress",
|
|
335
|
+
conversationId: "conv-1",
|
|
333
336
|
label: "My Flow",
|
|
334
337
|
phase: "Gathering",
|
|
335
338
|
});
|
|
336
339
|
expect(progress[1]).toMatchObject({
|
|
337
340
|
type: "workflow_progress",
|
|
341
|
+
conversationId: "conv-1",
|
|
338
342
|
message: "step done",
|
|
339
343
|
});
|
|
340
344
|
});
|
|
345
|
+
|
|
346
|
+
test("a run with no conversation broadcasts progress unscoped (no conversationId)", () => {
|
|
347
|
+
const h = makeHarness();
|
|
348
|
+
h.manager.start({
|
|
349
|
+
scriptSource: "export const meta = { name: 'x', description: 'y' }",
|
|
350
|
+
args: {},
|
|
351
|
+
manifest: { tools: [], hostFunctions: [], persona: false },
|
|
352
|
+
label: "My Flow",
|
|
353
|
+
trustContext: TRUST,
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const onProgress = h.executeCalls[0]!.onProgress!;
|
|
357
|
+
onProgress({ type: "phase", title: "Gathering" });
|
|
358
|
+
onProgress({ type: "log", message: "step done" });
|
|
359
|
+
|
|
360
|
+
// `workflow_progress` is a pre-existing event; it still broadcasts for a
|
|
361
|
+
// conversationless run, just without a `conversationId` (unscoped).
|
|
362
|
+
const progress = h.broadcasts.filter((b) => b.type === "workflow_progress");
|
|
363
|
+
expect(progress).toHaveLength(2);
|
|
364
|
+
expect(progress[0]).toMatchObject({
|
|
365
|
+
type: "workflow_progress",
|
|
366
|
+
label: "My Flow",
|
|
367
|
+
phase: "Gathering",
|
|
368
|
+
});
|
|
369
|
+
expect(progress[0]).not.toHaveProperty("conversationId");
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
test("onLeaf start/finish are republished as scoped leaf events", () => {
|
|
373
|
+
const fakeEngine: WorkflowRunManagerDeps["executeWorkflow"] = (options) => {
|
|
374
|
+
options.onLeaf?.({
|
|
375
|
+
type: "leaf_started",
|
|
376
|
+
seq: 1,
|
|
377
|
+
label: "Research",
|
|
378
|
+
phase: "Gather",
|
|
379
|
+
promptSummary: "look it up",
|
|
380
|
+
});
|
|
381
|
+
options.onLeaf?.({
|
|
382
|
+
type: "leaf_finished",
|
|
383
|
+
seq: 1,
|
|
384
|
+
status: "completed",
|
|
385
|
+
label: "Research",
|
|
386
|
+
inputTokens: 30,
|
|
387
|
+
outputTokens: 12,
|
|
388
|
+
resultSummary: "found it",
|
|
389
|
+
});
|
|
390
|
+
return new Promise(() => {}) as ReturnType<
|
|
391
|
+
WorkflowRunManagerDeps["executeWorkflow"]
|
|
392
|
+
>;
|
|
393
|
+
};
|
|
394
|
+
const h = makeHarness({ engine: fakeEngine });
|
|
395
|
+
|
|
396
|
+
const { runId } = h.manager.start({
|
|
397
|
+
scriptSource: "export const meta = { name: 'x', description: 'y' }",
|
|
398
|
+
args: {},
|
|
399
|
+
manifest: { tools: [], hostFunctions: [], persona: false },
|
|
400
|
+
conversationId: "conv-1",
|
|
401
|
+
trustContext: TRUST,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const started = h.broadcasts.find(
|
|
405
|
+
(b) => b.type === "workflow_leaf_started",
|
|
406
|
+
);
|
|
407
|
+
expect(started).toMatchObject({
|
|
408
|
+
type: "workflow_leaf_started",
|
|
409
|
+
runId,
|
|
410
|
+
conversationId: "conv-1",
|
|
411
|
+
seq: 1,
|
|
412
|
+
label: "Research",
|
|
413
|
+
phase: "Gather",
|
|
414
|
+
promptSummary: "look it up",
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
const finished = h.broadcasts.find(
|
|
418
|
+
(b) => b.type === "workflow_leaf_finished",
|
|
419
|
+
);
|
|
420
|
+
expect(finished).toMatchObject({
|
|
421
|
+
type: "workflow_leaf_finished",
|
|
422
|
+
runId,
|
|
423
|
+
conversationId: "conv-1",
|
|
424
|
+
seq: 1,
|
|
425
|
+
status: "completed",
|
|
426
|
+
label: "Research",
|
|
427
|
+
inputTokens: 30,
|
|
428
|
+
outputTokens: 12,
|
|
429
|
+
resultSummary: "found it",
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
test("a run with no conversation gets no onLeaf callback", () => {
|
|
434
|
+
const h = makeHarness();
|
|
435
|
+
h.manager.start({
|
|
436
|
+
scriptSource: "export const meta = { name: 'x', description: 'y' }",
|
|
437
|
+
args: {},
|
|
438
|
+
manifest: { tools: [], hostFunctions: [], persona: false },
|
|
439
|
+
trustContext: TRUST,
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
expect(h.executeCalls[0]!.onLeaf).toBeUndefined();
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
describe("WorkflowRunManager.start — workflow_started", () => {
|
|
447
|
+
test("start with a conversation broadcasts workflow_started carrying toolUseId", () => {
|
|
448
|
+
const h = makeHarness();
|
|
449
|
+
const { runId } = h.manager.start({
|
|
450
|
+
scriptSource: "export const meta = { name: 'x', description: 'y' }",
|
|
451
|
+
args: {},
|
|
452
|
+
manifest: { tools: [], hostFunctions: [], persona: false },
|
|
453
|
+
conversationId: "conv-1",
|
|
454
|
+
toolUseId: "toolu-abc",
|
|
455
|
+
label: "My Flow",
|
|
456
|
+
trustContext: TRUST,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
const started = h.broadcasts.find((b) => b.type === "workflow_started");
|
|
460
|
+
expect(started).toMatchObject({
|
|
461
|
+
type: "workflow_started",
|
|
462
|
+
runId,
|
|
463
|
+
conversationId: "conv-1",
|
|
464
|
+
toolUseId: "toolu-abc",
|
|
465
|
+
label: "My Flow",
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
test("start without a conversation broadcasts no workflow_started", () => {
|
|
470
|
+
const h = makeHarness();
|
|
471
|
+
h.manager.start({
|
|
472
|
+
scriptSource: "export const meta = { name: 'x', description: 'y' }",
|
|
473
|
+
args: {},
|
|
474
|
+
manifest: { tools: [], hostFunctions: [], persona: false },
|
|
475
|
+
trustContext: TRUST,
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
expect(h.broadcasts.some((b) => b.type === "workflow_started")).toBe(false);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test("resume never broadcasts workflow_started", () => {
|
|
482
|
+
const h = makeHarness({});
|
|
483
|
+
seedRun(h, {
|
|
484
|
+
id: "run-x",
|
|
485
|
+
status: "interrupted",
|
|
486
|
+
conversationId: "conv-1",
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
h.manager.resume("run-x");
|
|
490
|
+
|
|
491
|
+
expect(h.broadcasts.some((b) => b.type === "workflow_started")).toBe(false);
|
|
492
|
+
});
|
|
341
493
|
});
|
|
342
494
|
|
|
343
495
|
describe("WorkflowRunManager — completion", () => {
|
|
@@ -364,6 +516,7 @@ describe("WorkflowRunManager — completion", () => {
|
|
|
364
516
|
expect(completed).toMatchObject({
|
|
365
517
|
type: "workflow_completed",
|
|
366
518
|
runId,
|
|
519
|
+
conversationId: "conv-1",
|
|
367
520
|
status: "completed",
|
|
368
521
|
agentsSpawned: 4,
|
|
369
522
|
inputTokens: 100,
|
|
@@ -418,7 +571,7 @@ describe("WorkflowRunManager — completion", () => {
|
|
|
418
571
|
expect(h.manager.status(runId)?.result).toBe(big);
|
|
419
572
|
});
|
|
420
573
|
|
|
421
|
-
test("no conversationId →
|
|
574
|
+
test("no conversationId → pre-existing events broadcast unscoped; UI events and wake are gated", async () => {
|
|
422
575
|
const h = makeHarness();
|
|
423
576
|
h.manager.start({
|
|
424
577
|
scriptSource: "export const meta = { name: 'x', description: 'y' }",
|
|
@@ -435,8 +588,23 @@ describe("WorkflowRunManager — completion", () => {
|
|
|
435
588
|
outputTokens: 1,
|
|
436
589
|
});
|
|
437
590
|
|
|
438
|
-
|
|
439
|
-
|
|
591
|
+
// The pre-existing terminal event still broadcasts (unscoped) so raw SSE
|
|
592
|
+
// listeners and conversationless scheduled runs are still surfaced.
|
|
593
|
+
const completed = h.broadcasts.find((b) => b.type === "workflow_completed");
|
|
594
|
+
expect(completed).toMatchObject({
|
|
595
|
+
type: "workflow_completed",
|
|
596
|
+
status: "completed",
|
|
597
|
+
});
|
|
598
|
+
expect(completed).not.toHaveProperty("conversationId");
|
|
599
|
+
|
|
600
|
+
// The conversation-only signals stay gated: no `workflow_started`, no leaf
|
|
601
|
+
// events, and no completion wake without an originating conversation.
|
|
602
|
+
expect(h.broadcasts.some((b) => b.type === "workflow_started")).toBe(false);
|
|
603
|
+
expect(h.broadcasts.some((b) => b.type === "workflow_leaf_started")).toBe(
|
|
604
|
+
false,
|
|
605
|
+
);
|
|
606
|
+
expect(h.broadcasts.some((b) => b.type === "workflow_leaf_finished")).toBe(
|
|
607
|
+
false,
|
|
440
608
|
);
|
|
441
609
|
expect(h.wakes).toHaveLength(0);
|
|
442
610
|
});
|
|
@@ -114,6 +114,11 @@ interface StartWorkflowCommon {
|
|
|
114
114
|
* scheduled run with no chat surface) — the summary is then events-only.
|
|
115
115
|
*/
|
|
116
116
|
conversationId?: string;
|
|
117
|
+
/**
|
|
118
|
+
* The `skill_execute` tool-use block id that launched this run; forwarded on
|
|
119
|
+
* `workflow_started` so the client anchors the inline card to the spawn call.
|
|
120
|
+
*/
|
|
121
|
+
toolUseId?: string;
|
|
117
122
|
/** Human-readable label for display; defaults to the run id. */
|
|
118
123
|
label?: string;
|
|
119
124
|
/** Trust/auth context forwarded to every leaf. */
|
|
@@ -215,6 +220,19 @@ export class WorkflowRunManager {
|
|
|
215
220
|
const controller = new AbortController();
|
|
216
221
|
this.inflight.set(runId, controller);
|
|
217
222
|
|
|
223
|
+
// Announce the launch only when there's a conversation to scope it to (the
|
|
224
|
+
// same gate the in-flight/terminal broadcasts use). `resume` never emits
|
|
225
|
+
// this — the run already announced itself on its original `start`.
|
|
226
|
+
if (opts.conversationId) {
|
|
227
|
+
this.deps.broadcast({
|
|
228
|
+
type: "workflow_started",
|
|
229
|
+
runId,
|
|
230
|
+
conversationId: opts.conversationId,
|
|
231
|
+
...(opts.toolUseId ? { toolUseId: opts.toolUseId } : {}),
|
|
232
|
+
label,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
218
236
|
// Fire-and-forget: the engine owns its own try/catch and always finishes
|
|
219
237
|
// the run row. We never await it — `start` must return synchronously.
|
|
220
238
|
void this.runToCompletion(
|
|
@@ -376,6 +394,14 @@ export class WorkflowRunManager {
|
|
|
376
394
|
ctx: RunContext,
|
|
377
395
|
): Promise<void> {
|
|
378
396
|
const config = this.deps.getConfig();
|
|
397
|
+
// `workflow_progress` / `workflow_completed` always broadcast: a run with no
|
|
398
|
+
// originating conversation emits them unscoped (no `conversationId`) for raw
|
|
399
|
+
// SSE listeners and the DB record, preserving the pre-scoping contract that
|
|
400
|
+
// surfaces conversationless scheduled runs. The conversation-only signals —
|
|
401
|
+
// `workflow_started`, the `onLeaf` leaf events, and the completion wake —
|
|
402
|
+
// stay gated on `conversationId` since they exist solely to drive the inline
|
|
403
|
+
// workflow card in that conversation.
|
|
404
|
+
const conversationId = ctx.conversationId;
|
|
379
405
|
try {
|
|
380
406
|
const result = await this.deps.executeWorkflow({
|
|
381
407
|
runId,
|
|
@@ -393,6 +419,7 @@ export class WorkflowRunManager {
|
|
|
393
419
|
this.deps.broadcast({
|
|
394
420
|
type: "workflow_progress",
|
|
395
421
|
runId,
|
|
422
|
+
...(conversationId ? { conversationId } : {}),
|
|
396
423
|
label,
|
|
397
424
|
agentsSpawned,
|
|
398
425
|
...(event.type === "phase"
|
|
@@ -400,6 +427,41 @@ export class WorkflowRunManager {
|
|
|
400
427
|
: { message: event.message }),
|
|
401
428
|
});
|
|
402
429
|
},
|
|
430
|
+
...(conversationId
|
|
431
|
+
? {
|
|
432
|
+
onLeaf: (event) => {
|
|
433
|
+
if (event.type === "leaf_started") {
|
|
434
|
+
this.deps.broadcast({
|
|
435
|
+
type: "workflow_leaf_started",
|
|
436
|
+
runId,
|
|
437
|
+
conversationId,
|
|
438
|
+
seq: event.seq,
|
|
439
|
+
...(event.label !== undefined
|
|
440
|
+
? { label: event.label }
|
|
441
|
+
: {}),
|
|
442
|
+
...(event.phase !== undefined
|
|
443
|
+
? { phase: event.phase }
|
|
444
|
+
: {}),
|
|
445
|
+
promptSummary: event.promptSummary,
|
|
446
|
+
});
|
|
447
|
+
} else {
|
|
448
|
+
this.deps.broadcast({
|
|
449
|
+
type: "workflow_leaf_finished",
|
|
450
|
+
runId,
|
|
451
|
+
conversationId,
|
|
452
|
+
seq: event.seq,
|
|
453
|
+
status: event.status,
|
|
454
|
+
...(event.label !== undefined
|
|
455
|
+
? { label: event.label }
|
|
456
|
+
: {}),
|
|
457
|
+
inputTokens: event.inputTokens,
|
|
458
|
+
outputTokens: event.outputTokens,
|
|
459
|
+
resultSummary: event.resultSummary,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
}
|
|
464
|
+
: {}),
|
|
403
465
|
});
|
|
404
466
|
|
|
405
467
|
const summary = buildCompletionSummary(
|
|
@@ -412,6 +474,7 @@ export class WorkflowRunManager {
|
|
|
412
474
|
this.deps.broadcast({
|
|
413
475
|
type: "workflow_completed",
|
|
414
476
|
runId,
|
|
477
|
+
...(conversationId ? { conversationId } : {}),
|
|
415
478
|
status: result.status,
|
|
416
479
|
agentsSpawned: result.agentsSpawned,
|
|
417
480
|
inputTokens: result.inputTokens,
|
|
@@ -473,6 +536,7 @@ interface RunContext {
|
|
|
473
536
|
const VALID_TRUST_CLASSES: ReadonlySet<TrustContext["trustClass"]> = new Set([
|
|
474
537
|
"guardian",
|
|
475
538
|
"trusted_contact",
|
|
539
|
+
"unverified_contact",
|
|
476
540
|
"unknown",
|
|
477
541
|
]);
|
|
478
542
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { MigrationRunContext, WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Switch brand-new assistants onto memory-v3 (the live injected memory source)
|
|
8
|
+
* at creation by persisting `memory.v3.live = true`.
|
|
9
|
+
*
|
|
10
|
+
* The schema default is `false`, so existing assistants keep running v2 on
|
|
11
|
+
* upgrade — this migration writes the value only for freshly-created
|
|
12
|
+
* workspaces. The value gates v3 via `isMemoryV3Live`; existing assistants are
|
|
13
|
+
* switched on deliberately, never automatically. Covers every surface (local,
|
|
14
|
+
* Docker, managed) uniformly because all run workspace migrations on first boot.
|
|
15
|
+
*/
|
|
16
|
+
export const enableMemoryV3LiveForNewWorkspacesMigration: WorkspaceMigration = {
|
|
17
|
+
id: "105-enable-memory-v3-live-for-new-workspaces",
|
|
18
|
+
description:
|
|
19
|
+
"Persist memory.v3.live=true for brand-new workspaces so new assistants run memory-v3 from creation",
|
|
20
|
+
|
|
21
|
+
run(workspaceDir: string, ctx?: MigrationRunContext): void {
|
|
22
|
+
// Only switch new assistants on. Existing workspaces fall through to the
|
|
23
|
+
// schema default (false) and keep running v2 until enabled explicitly.
|
|
24
|
+
// Without a context (older callers) treat the workspace as existing.
|
|
25
|
+
if (!ctx?.isNewWorkspace) return;
|
|
26
|
+
|
|
27
|
+
const configPath = join(workspaceDir, "config.json");
|
|
28
|
+
|
|
29
|
+
// A fresh workspace may have no config.json yet (schema defaults are
|
|
30
|
+
// applied in memory at load); create one so the live default persists.
|
|
31
|
+
let config: Record<string, unknown> = {};
|
|
32
|
+
if (existsSync(configPath)) {
|
|
33
|
+
try {
|
|
34
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
35
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
36
|
+
config = raw as Record<string, unknown>;
|
|
37
|
+
} catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (config.memory === undefined) config.memory = {};
|
|
43
|
+
const memory = config.memory;
|
|
44
|
+
if (!memory || typeof memory !== "object" || Array.isArray(memory)) return;
|
|
45
|
+
const memoryConfig = memory as Record<string, unknown>;
|
|
46
|
+
|
|
47
|
+
if (memoryConfig.v3 === undefined) memoryConfig.v3 = {};
|
|
48
|
+
const v3 = memoryConfig.v3;
|
|
49
|
+
if (!v3 || typeof v3 !== "object" || Array.isArray(v3)) return;
|
|
50
|
+
const v3Config = v3 as Record<string, unknown>;
|
|
51
|
+
|
|
52
|
+
// Respect an explicit value already present (idempotent re-runs, or a
|
|
53
|
+
// hatch-time override that set it deliberately).
|
|
54
|
+
if ("live" in v3Config) return;
|
|
55
|
+
|
|
56
|
+
v3Config.live = true;
|
|
57
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
down(_workspaceDir: string): void {
|
|
61
|
+
// Forward-only: cannot distinguish a user's explicit choice from this seed.
|
|
62
|
+
},
|
|
63
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Drops the `collectUsageData` config key (gating is governed by the platform
|
|
8
|
+
* `share_analytics` consent). An explicit local opt-out (`collectUsageData:
|
|
9
|
+
* false`) is preserved as `legacyTelemetryOptOut: true` so telemetry stays off
|
|
10
|
+
* regardless of platform consent, which defaults to opt-in and cannot be
|
|
11
|
+
* written by the daemon. A `true`/non-false value carries no opt-out intent, so
|
|
12
|
+
* the key is removed without setting the marker. The schema strips unknown keys
|
|
13
|
+
* on the next save, so a stale value is otherwise harmless.
|
|
14
|
+
*/
|
|
15
|
+
export const dropCollectUsageDataMigration: WorkspaceMigration = {
|
|
16
|
+
id: "106-drop-collect-usage-data",
|
|
17
|
+
description:
|
|
18
|
+
"Drop collectUsageData; preserve an explicit opt-out as legacyTelemetryOptOut (telemetry is gated by platform share_analytics consent)",
|
|
19
|
+
run(workspaceDir: string): void {
|
|
20
|
+
const configPath = join(workspaceDir, "config.json");
|
|
21
|
+
if (!existsSync(configPath)) return;
|
|
22
|
+
|
|
23
|
+
let config: Record<string, unknown>;
|
|
24
|
+
try {
|
|
25
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
26
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
27
|
+
config = raw as Record<string, unknown>;
|
|
28
|
+
} catch {
|
|
29
|
+
return; // Malformed config — skip
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!("collectUsageData" in config)) return;
|
|
33
|
+
|
|
34
|
+
// An explicit opt-out is preserved as a fail-closed marker; any non-false
|
|
35
|
+
// value carries no opt-out intent.
|
|
36
|
+
if (config.collectUsageData === false) {
|
|
37
|
+
config.legacyTelemetryOptOut = true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
delete config.collectUsageData;
|
|
41
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
42
|
+
},
|
|
43
|
+
down(_workspaceDir: string): void {
|
|
44
|
+
// No-op: the forward migration only removes a key and sets a fail-closed
|
|
45
|
+
// marker, so there is nothing to restore.
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Drops the `sendDiagnostics` config key (crash reporting is governed by the
|
|
8
|
+
* platform `share_diagnostics` consent). An explicit local opt-out
|
|
9
|
+
* (`sendDiagnostics: false`) is preserved as `legacyDiagnosticsOptOut: true` so
|
|
10
|
+
* Sentry stays off regardless of platform consent, which defaults to opt-in and
|
|
11
|
+
* cannot be written by the daemon. A `true`/non-false value carries no opt-out
|
|
12
|
+
* intent, so the key is removed without setting the marker. The schema strips
|
|
13
|
+
* unknown keys on the next save, so a stale value is otherwise harmless.
|
|
14
|
+
*/
|
|
15
|
+
export const dropSendDiagnosticsMigration: WorkspaceMigration = {
|
|
16
|
+
id: "107-drop-send-diagnostics",
|
|
17
|
+
description:
|
|
18
|
+
"Drop sendDiagnostics; preserve an explicit opt-out as legacyDiagnosticsOptOut (crash reporting is gated by platform share_diagnostics consent)",
|
|
19
|
+
run(workspaceDir: string): void {
|
|
20
|
+
const configPath = join(workspaceDir, "config.json");
|
|
21
|
+
if (!existsSync(configPath)) return;
|
|
22
|
+
|
|
23
|
+
let config: Record<string, unknown>;
|
|
24
|
+
try {
|
|
25
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
26
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
27
|
+
config = raw as Record<string, unknown>;
|
|
28
|
+
} catch {
|
|
29
|
+
return; // Malformed config — skip
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!("sendDiagnostics" in config)) return;
|
|
33
|
+
|
|
34
|
+
// An explicit opt-out is preserved as a fail-closed marker; any non-false
|
|
35
|
+
// value carries no opt-out intent.
|
|
36
|
+
if (config.sendDiagnostics === false) {
|
|
37
|
+
config.legacyDiagnosticsOptOut = true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
delete config.sendDiagnostics;
|
|
41
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
42
|
+
},
|
|
43
|
+
down(_workspaceDir: string): void {
|
|
44
|
+
// No-op: the forward migration only removes a key and sets a fail-closed
|
|
45
|
+
// marker, so there is nothing to restore.
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
// Reclaim the managed `balanced-economy` inference profile. Its
|
|
7
|
+
// MiniMax-M3-on-Fireworks config lives on `balanced`, whose content the seeder
|
|
8
|
+
// reconciles from the templates on every boot; the seeder never deletes a
|
|
9
|
+
// profile, so this migration deletes the managed `balanced-economy` object and
|
|
10
|
+
// repoints every reference to it — its `profileOrder` entry, the `activeProfile`
|
|
11
|
+
// and `advisorProfile` selections, call-site `profile` overrides, and mix-profile
|
|
12
|
+
// arms — onto `balanced`, which resolves to the same MiniMax M3 route. A
|
|
13
|
+
// `balanced-economy` profile that the user owns (`source !== "managed"`) is left
|
|
14
|
+
// fully intact, references included.
|
|
15
|
+
|
|
16
|
+
const ECONOMY = "balanced-economy";
|
|
17
|
+
const REPLACEMENT = "balanced";
|
|
18
|
+
|
|
19
|
+
export const dropBalancedEconomyProfileMigration: WorkspaceMigration = {
|
|
20
|
+
id: "108-drop-balanced-economy-profile",
|
|
21
|
+
description:
|
|
22
|
+
"Remove the managed Balanced Economy profile and repoint its references to Balanced",
|
|
23
|
+
run(workspaceDir: string): void {
|
|
24
|
+
const configPath = join(workspaceDir, "config.json");
|
|
25
|
+
if (!existsSync(configPath)) return;
|
|
26
|
+
|
|
27
|
+
let config: Record<string, unknown>;
|
|
28
|
+
try {
|
|
29
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
30
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
31
|
+
config = raw as Record<string, unknown>;
|
|
32
|
+
} catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const llm = readObject(config.llm);
|
|
37
|
+
if (llm === null) return;
|
|
38
|
+
|
|
39
|
+
const profiles = readObject(llm.profiles);
|
|
40
|
+
const economy = profiles !== null ? readObject(profiles[ECONOMY]) : null;
|
|
41
|
+
|
|
42
|
+
// A user-owned profile that happens to use this name keeps everything,
|
|
43
|
+
// references included — only the managed profile is reclaimed.
|
|
44
|
+
if (economy !== null && economy.source !== "managed") return;
|
|
45
|
+
|
|
46
|
+
let changed = false;
|
|
47
|
+
|
|
48
|
+
if (economy !== null && profiles !== null) {
|
|
49
|
+
delete profiles[ECONOMY];
|
|
50
|
+
changed = true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (Array.isArray(llm.profileOrder)) {
|
|
54
|
+
const order = llm.profileOrder as unknown[];
|
|
55
|
+
const pruned = order.filter((name) => name !== ECONOMY);
|
|
56
|
+
if (pruned.length !== order.length) {
|
|
57
|
+
llm.profileOrder = pruned;
|
|
58
|
+
changed = true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Repoint call-site overrides — LLMSchema strips a profile name absent from
|
|
63
|
+
// `llm.profiles` at load, which would drop the equivalent MiniMax route.
|
|
64
|
+
const callSites = readObject(llm.callSites);
|
|
65
|
+
if (callSites !== null) {
|
|
66
|
+
for (const value of Object.values(callSites)) {
|
|
67
|
+
const site = readObject(value);
|
|
68
|
+
if (site !== null && site.profile === ECONOMY) {
|
|
69
|
+
site.profile = REPLACEMENT;
|
|
70
|
+
changed = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Repoint mix-profile arms — LLMSchema.superRefine rejects a mix arm whose
|
|
76
|
+
// referenced profile is absent, failing config validation at load.
|
|
77
|
+
if (profiles !== null) {
|
|
78
|
+
for (const value of Object.values(profiles)) {
|
|
79
|
+
const entry = readObject(value);
|
|
80
|
+
if (entry === null || !Array.isArray(entry.mix)) continue;
|
|
81
|
+
for (const arm of entry.mix) {
|
|
82
|
+
const armObj = readObject(arm);
|
|
83
|
+
if (armObj !== null && armObj.profile === ECONOMY) {
|
|
84
|
+
armObj.profile = REPLACEMENT;
|
|
85
|
+
changed = true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (llm.activeProfile === ECONOMY) {
|
|
92
|
+
llm.activeProfile = REPLACEMENT;
|
|
93
|
+
changed = true;
|
|
94
|
+
|
|
95
|
+
// The replaced selection was an enabled profile, so `balanced` must be
|
|
96
|
+
// usable: a disabled profile is skipped by the resolver and rejected by
|
|
97
|
+
// validation. Clearing the status sticks because the seeder preserves
|
|
98
|
+
// whatever status is on disk.
|
|
99
|
+
const balanced =
|
|
100
|
+
profiles !== null ? readObject(profiles[REPLACEMENT]) : null;
|
|
101
|
+
if (balanced !== null && balanced.status === "disabled") {
|
|
102
|
+
delete balanced.status;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// The advisor selection is the other top-level profile reference
|
|
107
|
+
// `LLMSchema.superRefine` validates against `llm.profiles`; an unresolvable
|
|
108
|
+
// value invalidates the config and is stripped at load.
|
|
109
|
+
if (llm.advisorProfile === ECONOMY) {
|
|
110
|
+
llm.advisorProfile = REPLACEMENT;
|
|
111
|
+
changed = true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!changed) return;
|
|
115
|
+
|
|
116
|
+
config.llm = llm;
|
|
117
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
118
|
+
},
|
|
119
|
+
down(_workspaceDir: string): void {
|
|
120
|
+
// Forward-only.
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
function readObject(value: unknown): Record<string, unknown> | null {
|
|
125
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
return value as Record<string, unknown>;
|
|
129
|
+
}
|