@vellumai/assistant 0.9.0 → 0.10.0-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +18 -34
- package/bun.lock +7 -8
- package/docs/activation-funnel-telemetry.md +28 -22
- package/docs/architecture/security.md +29 -28
- package/docs/stt-provider-onboarding.md +3 -5
- package/docs/workflows-testing.md +13 -44
- package/docs/workflows.md +3 -5
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
- package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
- package/openapi.yaml +976 -63
- package/package.json +2 -1
- package/scripts/sync-llm-catalog.ts +6 -15
- package/scripts/sync-web-search-catalog.ts +3 -11
- package/src/__tests__/access-request-card-view.test.ts +98 -0
- package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
- package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
- package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
- package/src/__tests__/app-compiler.test.ts +15 -1
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
- package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
- package/src/__tests__/avatar-identity-sync.test.ts +2 -27
- package/src/__tests__/btw-routes.test.ts +6 -8
- package/src/__tests__/call-pointer-messages.test.ts +28 -0
- package/src/__tests__/cancel-clears-processing.test.ts +89 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -4
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
- package/src/__tests__/checker.test.ts +0 -3
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
- package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
- package/src/__tests__/config-loader-backfill.test.ts +268 -27
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/config-watcher.test.ts +0 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +0 -6
- package/src/__tests__/contacts-tools.test.ts +29 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +58 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-lifecycle.test.ts +7 -9
- package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
- package/src/__tests__/conversation-title-service.test.ts +62 -0
- package/src/__tests__/credential-broker.test.ts +449 -1
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
- package/src/__tests__/credential-execution-tools.test.ts +0 -1
- package/src/__tests__/credential-prompt-route.test.ts +4 -4
- package/src/__tests__/credential-routes.test.ts +360 -0
- package/src/__tests__/credential-security-invariants.test.ts +4 -13
- package/src/__tests__/disk-pressure-policy.test.ts +12 -0
- package/src/__tests__/disk-usage.test.ts +65 -0
- package/src/__tests__/dynamic-page-surface.test.ts +152 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
- package/src/__tests__/gateway-flag-listener.test.ts +110 -1
- package/src/__tests__/gateway-only-guard.test.ts +3 -7
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
- package/src/__tests__/guardian-grant-minting.test.ts +3 -35
- package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/headless-browser-mode.test.ts +10 -0
- package/src/__tests__/headless-browser-navigate.test.ts +8 -3
- package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
- package/src/__tests__/host-browser-proxy.test.ts +87 -0
- package/src/__tests__/identity-routes.test.ts +0 -189
- package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
- package/src/__tests__/injector-v3-suppression.test.ts +27 -20
- package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
- package/src/__tests__/invite-redemption-service.test.ts +4 -7
- package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +30 -23
- package/src/__tests__/llm-resolver.test.ts +70 -24
- package/src/__tests__/llm-schema.test.ts +1 -0
- package/src/__tests__/managed-profile-guard.test.ts +163 -4
- package/src/__tests__/mcp-health-check.test.ts +6 -7
- package/src/__tests__/media-stream-server-integration.test.ts +317 -13
- package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
- package/src/__tests__/onboarding-persona-write.test.ts +1 -1
- package/src/__tests__/path-policy.test.ts +34 -0
- package/src/__tests__/persona-resolver.test.ts +49 -14
- package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
- package/src/__tests__/plugin-api-provider.test.ts +24 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
- package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
- package/src/__tests__/reaction-persistence.test.ts +150 -29
- package/src/__tests__/registry.test.ts +2 -7
- package/src/__tests__/relay-server.test.ts +285 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
- package/src/__tests__/schedule-routes.test.ts +0 -30
- package/src/__tests__/schedule-tools.test.ts +2 -18
- package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
- package/src/__tests__/skill-execute-input.test.ts +51 -1
- package/src/__tests__/skill-runtime-path.test.ts +2 -3
- package/src/__tests__/skills.test.ts +51 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
- package/src/__tests__/subagent-tools.test.ts +266 -0
- package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
- package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +100 -3
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
- package/src/__tests__/token-manager.test.ts +519 -0
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
- package/src/__tests__/tool-audit-listener.test.ts +7 -7
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
- package/src/__tests__/tool-executor.test.ts +0 -79
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
- package/src/__tests__/trusted-contact-verification.test.ts +8 -10
- package/src/__tests__/twilio-routes.test.ts +81 -1
- package/src/__tests__/voice-invite-redemption.test.ts +2 -3
- package/src/__tests__/weak-open-model.test.ts +30 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
- package/src/__tests__/workspace-greetings.test.ts +152 -0
- package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
- package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
- package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
- package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
- package/src/agent/loop.ts +49 -29
- package/src/api/README.md +6 -6
- package/src/api/events/tool-result.ts +6 -0
- package/src/api/events/workflow-completed.ts +53 -0
- package/src/api/events/workflow-leaf-finished.ts +38 -0
- package/src/api/events/workflow-leaf-started.ts +35 -0
- package/src/api/events/workflow-progress.ts +32 -0
- package/src/api/events/workflow-started.ts +31 -0
- package/src/api/index.ts +40 -0
- package/src/api/responses/conversation-message.ts +28 -4
- package/src/api/responses/home.ts +26 -4
- package/src/api/responses/workflow-journal.ts +53 -0
- package/src/approvals/guardian-card-withdrawal.ts +145 -0
- package/src/approvals/guardian-decision-primitive.ts +26 -3
- package/src/approvals/guardian-request-resolvers.ts +183 -80
- package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
- package/src/calls/call-pointer-messages.ts +10 -4
- package/src/calls/channel-admission-reader.ts +104 -0
- package/src/calls/guardian-dispatch.ts +17 -45
- package/src/calls/media-stream-server.ts +84 -2
- package/src/calls/relay-access-wait.ts +1 -1
- package/src/calls/relay-server.ts +66 -0
- package/src/calls/relay-setup-router.ts +82 -1
- package/src/calls/twilio-routes.ts +17 -8
- package/src/calls/voice-session-bridge.ts +2 -2
- package/src/cli/commands/clients.ts +3 -0
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
- package/src/cli/commands/memory/index.ts +30 -0
- package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
- package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
- package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
- package/src/cli/commands/oauth/status.test.ts +36 -0
- package/src/cli/commands/oauth/status.ts +23 -3
- package/src/cli/commands/plugins.ts +197 -4
- package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
- package/src/cli/lib/diff-plugin.ts +346 -0
- package/src/cli/lib/inspect-plugin.ts +12 -1
- package/src/cli/lib/install-from-github.ts +105 -17
- package/src/cli/lib/merge-plugin-tree.ts +328 -0
- package/src/cli/lib/plugin-fingerprint.ts +14 -0
- package/src/cli/lib/plugin-surfaces.ts +104 -0
- package/src/cli/lib/upgrade-plugin.ts +298 -10
- package/src/cli/program.ts +2 -6
- package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
- package/src/config/assistant-feature-flags.ts +22 -7
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
- package/src/config/bundled-skills/messaging/SKILL.md +6 -4
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
- package/src/config/bundled-skills/subagent/SKILL.md +4 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
- package/src/config/bundled-skills/workflows/SKILL.md +14 -8
- package/src/config/bundled-tool-registry.ts +2 -7
- package/src/config/call-site-defaults.ts +15 -2
- package/src/config/feature-flag-registry.json +46 -31
- package/src/config/inference-profile-validation.ts +26 -0
- package/src/config/llm-resolver.ts +3 -0
- package/src/config/loader.ts +4 -0
- package/src/config/memory-v3-gate.ts +11 -0
- package/src/config/profile-order.ts +28 -0
- package/src/config/schema.ts +8 -6
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/channels.ts +11 -0
- package/src/config/schemas/elevenlabs.ts +0 -1
- package/src/config/schemas/llm.ts +31 -0
- package/src/config/schemas/memory-lifecycle.ts +3 -7
- package/src/config/schemas/memory-v3.ts +6 -0
- package/src/config/schemas/platform.ts +0 -8
- package/src/config/schemas/services.ts +18 -0
- package/src/config/seed-inference-profiles.ts +109 -44
- package/src/config/skills.ts +21 -0
- package/src/config/sync-gated-profiles.ts +220 -0
- package/src/contacts/contact-store.ts +89 -106
- package/src/contacts/contacts-write.ts +5 -22
- package/src/contacts/types.ts +0 -1
- package/src/context/compactor.ts +88 -54
- package/src/context/strip-injections.ts +58 -10
- package/src/context/token-estimator.ts +1 -1
- package/src/credential-execution/process-manager.ts +55 -14
- package/src/credential-execution/prompted-credential.ts +2 -3
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
- package/src/daemon/config-watcher.ts +0 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
- package/src/daemon/conversation-agent-loop.ts +114 -22
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +3 -5
- package/src/daemon/conversation-process.ts +13 -5
- package/src/daemon/conversation-runtime-assembly.ts +13 -15
- package/src/daemon/conversation-slash.ts +2 -23
- package/src/daemon/conversation-surfaces.ts +26 -0
- package/src/daemon/conversation-tool-setup.ts +27 -14
- package/src/daemon/conversation.ts +66 -14
- package/src/daemon/disk-pressure-policy.ts +5 -3
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
- package/src/daemon/handlers/config-a2a.ts +0 -2
- package/src/daemon/handlers/config-channels.ts +15 -16
- package/src/daemon/handlers/config-slack-channel.ts +22 -3
- package/src/daemon/handlers/conversations.ts +107 -0
- package/src/daemon/host-browser-proxy.ts +41 -0
- package/src/daemon/lifecycle.ts +55 -27
- package/src/daemon/message-provenance.ts +2 -0
- package/src/daemon/message-types/contacts.ts +0 -1
- package/src/daemon/message-types/conversations.ts +3 -3
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/message-types/web-activity.ts +7 -1
- package/src/daemon/message-types/workflows.ts +83 -1
- package/src/daemon/orphan-reaper.test.ts +0 -19
- package/src/daemon/orphan-reaper.ts +2 -24
- package/src/daemon/server.ts +0 -10
- package/src/daemon/tool-setup-types.ts +4 -0
- package/src/daemon/trust-context.ts +1 -1
- package/src/events/tool-audit-listener.ts +2 -2
- package/src/home/feed-source-enrichment.test.ts +151 -0
- package/src/home/feed-source-enrichment.ts +176 -0
- package/src/home/relationship-state.ts +2 -4
- package/src/instrument.ts +18 -6
- package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
- package/src/ipc/assistant-server.ts +37 -4
- package/src/ipc/gateway-flag-listener.ts +18 -2
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
- package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
- package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
- package/src/memory/auth-fallback-events-store.ts +2 -2
- package/src/memory/auto-analysis-enqueue.ts +3 -5
- package/src/memory/bookmark-crud.ts +1 -2
- package/src/memory/canonical-guardian-store.ts +39 -1
- package/src/memory/conversation-crud.ts +9 -4
- package/src/memory/conversation-key-store.ts +17 -2
- package/src/memory/conversation-title-service.ts +64 -7
- package/src/memory/db-init.ts +17 -17
- package/src/memory/embedding-backend.ts +38 -1
- package/src/memory/embedding-billing-breaker.ts +96 -0
- package/src/memory/jobs-store.ts +25 -13
- package/src/memory/jobs-worker.ts +54 -1
- package/src/memory/lifecycle-events-store.ts +2 -2
- package/src/memory/memory-retrospective-constants.ts +4 -4
- package/src/memory/memory-retrospective-enqueue.ts +31 -6
- package/src/memory/memory-retrospective-job.ts +28 -227
- package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
- package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
- package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
- package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
- package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
- package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
- package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
- package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/run-migrations.ts +41 -0
- package/src/memory/migrations/validate-migration-state.ts +1 -1
- package/src/memory/onboarding-events-store.ts +3 -3
- package/src/memory/schema/contacts.ts +0 -5
- package/src/memory/skill-loaded-events-store.test.ts +7 -15
- package/src/memory/skill-loaded-events-store.ts +2 -2
- package/src/memory/tool-executed-events-store.test.ts +7 -7
- package/src/memory/turn-trace-store.test.ts +736 -0
- package/src/memory/turn-trace-store.ts +364 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
- package/src/memory/v2/consolidation-job.ts +2 -2
- package/src/memory/v2/skill-content.ts +25 -7
- package/src/memory/v2/skill-store.ts +7 -1
- package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
- package/src/memory/v3-eval/eval-packets.ts +546 -0
- package/src/messaging/providers/slack/adapter.ts +1 -1
- package/src/messaging/providers/slack/api.ts +31 -0
- package/src/messaging/providers/slack/send.test.ts +114 -2
- package/src/messaging/providers/slack/send.ts +30 -7
- package/src/messaging/providers/slack/withdraw.test.ts +200 -0
- package/src/messaging/providers/slack/withdraw.ts +161 -0
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/access-request-copy.ts +72 -59
- package/src/notifications/adapters/shared.ts +29 -0
- package/src/notifications/adapters/slack.ts +58 -103
- package/src/notifications/adapters/telegram.ts +2 -20
- package/src/notifications/approval-card-data.ts +333 -0
- package/src/notifications/broadcaster.ts +16 -3
- package/src/notifications/canonical-delivery-recorder.ts +139 -0
- package/src/notifications/copy-composer.ts +3 -3
- package/src/notifications/decision-engine.ts +4 -2
- package/src/notifications/destination-resolver.ts +4 -6
- package/src/notifications/guardian-question-mode.ts +10 -0
- package/src/notifications/home-feed-side-effect.ts +7 -16
- package/src/notifications/notification-utils.ts +19 -20
- package/src/notifications/signal.ts +79 -43
- package/src/notifications/types.ts +98 -121
- package/src/oauth/AGENTS.md +5 -24
- package/src/permissions/checker.test.ts +51 -0
- package/src/permissions/checker.ts +185 -26
- package/src/permissions/ipc-risk-types.ts +24 -0
- package/src/permissions/question-prompter.test.ts +27 -0
- package/src/permissions/question-prompter.ts +4 -0
- package/src/platform/client.test.ts +119 -0
- package/src/platform/client.ts +66 -0
- package/src/platform/consent-cache.test.ts +267 -0
- package/src/platform/consent-cache.ts +174 -0
- package/src/plugin-api/constants.ts +1 -1
- package/src/plugin-api/index.ts +33 -1
- package/src/plugin-api/model-profiles.ts +33 -0
- package/src/plugin-api/types.ts +50 -2
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
- package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
- package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
- package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
- package/src/plugins/defaults/advisor/config.ts +21 -0
- package/src/plugins/defaults/advisor/consult.ts +93 -0
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/advisor/package.json +14 -0
- package/src/plugins/defaults/advisor/steering.ts +67 -0
- package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
- package/src/plugins/defaults/advisor/transcript.ts +76 -0
- package/src/plugins/defaults/index.ts +60 -0
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
- package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
- package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
- package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
- package/src/prompts/persona-resolver.ts +14 -4
- package/src/prompts/templates/system-sections.ts +7 -2
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +176 -0
- package/src/providers/atlascloud/client.ts +85 -0
- package/src/providers/fetch-provider-catalog.ts +85 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/model-catalog.ts +58 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
- package/src/providers/openai/chat-completions-provider.ts +7 -0
- package/src/providers/openai/responses-provider.ts +10 -0
- package/src/providers/provider-send-message.ts +11 -3
- package/src/providers/retry.ts +53 -12
- package/src/providers/search-provider-catalog.ts +10 -0
- package/src/providers/weak-open-model.ts +22 -0
- package/src/runtime/AGENTS.md +0 -1
- package/src/runtime/__tests__/agent-wake.test.ts +181 -0
- package/src/runtime/__tests__/client-health.test.ts +44 -0
- package/src/runtime/access-request-helper.ts +21 -53
- package/src/runtime/actor-trust-resolver.ts +59 -63
- package/src/runtime/agent-wake.ts +52 -0
- package/src/runtime/assistant-event-hub.ts +18 -4
- package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
- package/src/runtime/auth/require-bound-guardian.ts +1 -4
- package/src/runtime/btw-sidechain.ts +3 -6
- package/src/runtime/capabilities.test.ts +120 -0
- package/src/runtime/capabilities.ts +197 -0
- package/src/runtime/channel-approval-types.ts +22 -45
- package/src/runtime/channel-invite-transports/telegram.ts +4 -4
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/channel-verification-service.ts +3 -3
- package/src/runtime/client-health.ts +26 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
- package/src/runtime/effective-capabilities.test.ts +128 -0
- package/src/runtime/effective-capabilities.ts +84 -0
- package/src/runtime/guardian-reply-router.ts +106 -21
- package/src/runtime/invite-redemption-service.ts +9 -25
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +123 -0
- package/src/runtime/migrations/vbundle-builder.ts +49 -20
- package/src/runtime/pending-interactions.ts +15 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +240 -1
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
- package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
- package/src/runtime/routes/browser-tabs-routes.ts +9 -0
- package/src/runtime/routes/btw-routes.ts +1 -27
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
- package/src/runtime/routes/client-routes.ts +10 -0
- package/src/runtime/routes/contact-routes.ts +31 -8
- package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
- package/src/runtime/routes/conversation-management-routes.ts +80 -1
- package/src/runtime/routes/conversation-query-routes.ts +68 -22
- package/src/runtime/routes/conversation-routes.ts +39 -14
- package/src/runtime/routes/credential-routes.ts +40 -16
- package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
- package/src/runtime/routes/events-routes.ts +1 -3
- package/src/runtime/routes/guardian-approval-interception.ts +14 -73
- package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
- package/src/runtime/routes/home-feed-routes.ts +8 -3
- package/src/runtime/routes/identity-routes.ts +1 -296
- package/src/runtime/routes/inbound-message-handler.ts +214 -228
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
- package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
- package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
- package/src/runtime/routes/integrations/slack/channel.ts +36 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
- package/src/runtime/routes/mcp-auth-routes.ts +233 -41
- package/src/runtime/routes/memory-eval-routes.ts +87 -0
- package/src/runtime/routes/notification-routes.ts +122 -133
- package/src/runtime/routes/platform-routes.ts +2 -2
- package/src/runtime/routes/plugins-routes.ts +202 -3
- package/src/runtime/routes/schedule-routes.ts +0 -22
- package/src/runtime/routes/secret-routes.ts +10 -0
- package/src/runtime/routes/surface-action-routes.ts +2 -1
- package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
- package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
- package/src/runtime/routes/workflow-routes.test.ts +229 -44
- package/src/runtime/routes/workflow-routes.ts +131 -29
- package/src/runtime/routes/workspace-greetings.ts +55 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -11
- package/src/runtime/tool-grant-request-helper.ts +18 -16
- package/src/runtime/trust-context-resolver.ts +8 -5
- package/src/schedule/inference-profile.ts +2 -14
- package/src/schedule/schedule-store.ts +1 -1
- package/src/schedule/scheduler-types.ts +5 -1
- package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
- package/src/security/secret-patterns.ts +3 -0
- package/src/subagent/manager.ts +17 -4
- package/src/subagent/types.ts +6 -0
- package/src/telemetry/trace-collection-policy.test.ts +28 -0
- package/src/telemetry/trace-collection-policy.ts +30 -0
- package/src/telemetry/types.ts +89 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
- package/src/telemetry/usage-telemetry-reporter.ts +148 -41
- package/src/tools/AGENTS.md +3 -3
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
- package/src/tools/browser/browser-execution.ts +30 -19
- package/src/tools/document/document-tool.ts +2 -3
- package/src/tools/executor.ts +5 -3
- package/src/tools/host-terminal/host-shell.ts +5 -4
- package/src/tools/memory/register.ts +2 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
- package/src/tools/network/__tests__/web-search.test.ts +143 -0
- package/src/tools/network/web-fetch.ts +372 -1
- package/src/tools/network/web-search-error.ts +1 -1
- package/src/tools/network/web-search.ts +213 -10
- package/src/tools/permission-checker.ts +4 -3
- package/src/tools/registry.ts +20 -0
- package/src/tools/schedule/create.ts +7 -12
- package/src/tools/schedule/update.ts +4 -11
- package/src/tools/shared/filesystem/path-policy.ts +39 -13
- package/src/tools/side-effects.ts +2 -17
- package/src/tools/skills/execute.ts +33 -0
- package/src/tools/subagent/spawn.ts +61 -12
- package/src/tools/terminal/shell.ts +10 -4
- package/src/tools/tool-approval-handler.ts +18 -13
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/types.ts +9 -0
- package/src/tools/ui-surface/definitions.ts +64 -3
- package/src/tools/verification-control-plane-policy.ts +3 -1
- package/src/tools/workflows/run-workflow.test.ts +8 -18
- package/src/tools/workflows/run-workflow.ts +1 -0
- package/src/util/disk-usage.ts +78 -23
- package/src/util/platform.ts +10 -3
- package/src/watcher/telemetry.ts +2 -2
- package/src/workflows/capabilities.ts +2 -3
- package/src/workflows/engine.test.ts +175 -1
- package/src/workflows/engine.ts +82 -0
- package/src/workflows/journal-store.test.ts +70 -0
- package/src/workflows/journal-store.ts +18 -3
- package/src/workflows/run-manager.test.ts +171 -28
- package/src/workflows/run-manager.ts +66 -24
- package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
- package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
- package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
- package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
- package/src/__tests__/credential-security-e2e.test.ts +0 -362
- package/src/__tests__/credential-vault-unit.test.ts +0 -1528
- package/src/__tests__/credential-vault.test.ts +0 -1706
- package/src/__tests__/identity-intro-cache.test.ts +0 -315
- package/src/__tests__/secret-onetime-send.test.ts +0 -182
- package/src/cli/commands/__tests__/task.test.ts +0 -914
- package/src/cli/commands/task.ts +0 -771
- package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
- package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
- package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
- package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
- package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
- package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
- package/src/memory/preloaded-apps.ts +0 -116
- package/src/notifications/tool-approval-copy.ts +0 -142
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
- package/src/runtime/routes/identity-intro-cache.ts +0 -172
- package/src/tools/credentials/vault.ts +0 -712
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
10
|
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
11
|
+
import { HostBrowserProxy } from "../../daemon/host-browser-proxy.js";
|
|
11
12
|
import { getCdpClient } from "../../tools/browser/cdp-client/factory.js";
|
|
12
13
|
import {
|
|
13
14
|
clearPinnedTab,
|
|
@@ -51,6 +52,14 @@ async function handleBrowserTabs({ body = {} }: RouteHandlerArgs) {
|
|
|
51
52
|
|
|
52
53
|
const cdpOptions = { mode: "extension" as const, targetClientId };
|
|
53
54
|
|
|
55
|
+
// Every tabs command pins extension mode. Absorb a brief extension SSE
|
|
56
|
+
// reconnect blip so a flapping connection doesn't surface as a hard
|
|
57
|
+
// "no Chrome Extension connected" error.
|
|
58
|
+
await HostBrowserProxy.instance.waitForExtensionClient(
|
|
59
|
+
context.sourceActorPrincipalId,
|
|
60
|
+
targetClientId,
|
|
61
|
+
);
|
|
62
|
+
|
|
54
63
|
if (command === "list") {
|
|
55
64
|
const cdp = getCdpClient(context, cdpOptions);
|
|
56
65
|
try {
|
|
@@ -27,18 +27,11 @@ import {
|
|
|
27
27
|
setCachedEmptyStateGreeting,
|
|
28
28
|
} from "./empty-state-greeting-cache.js";
|
|
29
29
|
import { BadRequestError, ServiceUnavailableError } from "./errors.js";
|
|
30
|
-
import {
|
|
31
|
-
getCachedIntro,
|
|
32
|
-
readWorkspaceGreetings,
|
|
33
|
-
setCachedIntro,
|
|
34
|
-
} from "./identity-intro-cache.js";
|
|
35
30
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
31
|
+
import { readWorkspaceGreetings } from "./workspace-greetings.js";
|
|
36
32
|
|
|
37
33
|
const log = getLogger("btw-routes");
|
|
38
34
|
|
|
39
|
-
/** Conversation key used by the client for identity intro generation. */
|
|
40
|
-
const IDENTITY_INTRO_KEY = "identity-intro";
|
|
41
|
-
|
|
42
35
|
/** Conversation key used by the client for empty-state greeting generation. */
|
|
43
36
|
const GREETING_KEY = "greeting";
|
|
44
37
|
|
|
@@ -72,15 +65,6 @@ async function handleBtw({
|
|
|
72
65
|
|
|
73
66
|
const trimmedContent = content.trim();
|
|
74
67
|
|
|
75
|
-
// ----- Cached identity intro fast-path -----
|
|
76
|
-
if (conversationKey === IDENTITY_INTRO_KEY) {
|
|
77
|
-
const fastText = getCachedIntro()?.greetings[0];
|
|
78
|
-
if (fastText) {
|
|
79
|
-
log.debug("Returning identity intro fast-path");
|
|
80
|
-
return streamText(fastText);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
68
|
// ----- Empty-state greeting fast-path -----
|
|
85
69
|
// User-authored `## Greetings` win; otherwise replay a cached greeting when
|
|
86
70
|
// one is fresh within the configurable TTL (`ui.emptyStateGreetingCacheTtlMs`,
|
|
@@ -126,7 +110,6 @@ async function handleBtw({
|
|
|
126
110
|
start(controller) {
|
|
127
111
|
(async () => {
|
|
128
112
|
try {
|
|
129
|
-
const isIntroRequest = conversationKey === IDENTITY_INTRO_KEY;
|
|
130
113
|
const isGreeting = conversationKey === GREETING_KEY;
|
|
131
114
|
const result = await runBtwSidechain({
|
|
132
115
|
content: effectiveContent,
|
|
@@ -153,15 +136,6 @@ async function handleBtw({
|
|
|
153
136
|
);
|
|
154
137
|
}
|
|
155
138
|
|
|
156
|
-
if (isIntroRequest && result.text) {
|
|
157
|
-
try {
|
|
158
|
-
setCachedIntro([result.text]);
|
|
159
|
-
log.debug("Cached identity intro text");
|
|
160
|
-
} catch {
|
|
161
|
-
// Non-fatal — next request will regenerate.
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
139
|
if (isGreeting && result.text) {
|
|
166
140
|
// setCachedEmptyStateGreeting is a no-op when the TTL is 0.
|
|
167
141
|
setCachedEmptyStateGreeting(result.text);
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* clients polling prompts) observe the expired status directly.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
import { withdrawGuardianRequestCards } from "../../approvals/guardian-card-withdrawal.js";
|
|
21
22
|
import {
|
|
22
23
|
listCanonicalGuardianRequests,
|
|
23
24
|
resolveCanonicalGuardianRequest,
|
|
@@ -42,7 +43,7 @@ let sweepInProgress = false;
|
|
|
42
43
|
* concurrent decision that wins the race is never overwritten by the
|
|
43
44
|
* sweep. Returns the count of requests transitioned to expired.
|
|
44
45
|
*/
|
|
45
|
-
function sweepExpiredCanonicalGuardianRequests(): number {
|
|
46
|
+
async function sweepExpiredCanonicalGuardianRequests(): Promise<number> {
|
|
46
47
|
const pending = listCanonicalGuardianRequests({ status: "pending" });
|
|
47
48
|
const now = Date.now();
|
|
48
49
|
let expiredCount = 0;
|
|
@@ -71,6 +72,14 @@ function sweepExpiredCanonicalGuardianRequests(): number {
|
|
|
71
72
|
},
|
|
72
73
|
"Expired canonical guardian request via sweep",
|
|
73
74
|
);
|
|
75
|
+
|
|
76
|
+
// Withdraw the now-stale approval cards on every surface. No origin
|
|
77
|
+
// channel — the expiry is system-driven, so all surfaces (including
|
|
78
|
+
// in-app) are withdrawn. Best-effort and non-throwing.
|
|
79
|
+
await withdrawGuardianRequestCards({
|
|
80
|
+
request: resolved,
|
|
81
|
+
status: "expired",
|
|
82
|
+
});
|
|
74
83
|
}
|
|
75
84
|
}
|
|
76
85
|
|
|
@@ -93,13 +102,13 @@ export function startCanonicalGuardianExpirySweep(): void {
|
|
|
93
102
|
sweepTimer = setInterval(() => {
|
|
94
103
|
if (sweepInProgress) return;
|
|
95
104
|
sweepInProgress = true;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
void sweepExpiredCanonicalGuardianRequests()
|
|
106
|
+
.catch((err) => {
|
|
107
|
+
log.error({ err }, "Canonical guardian expiry sweep failed");
|
|
108
|
+
})
|
|
109
|
+
.finally(() => {
|
|
110
|
+
sweepInProgress = false;
|
|
111
|
+
});
|
|
103
112
|
}, SWEEP_INTERVAL_MS);
|
|
104
113
|
}
|
|
105
114
|
|
|
@@ -12,6 +12,10 @@ import { isHttpAuthDisabled } from "../../config/env.js";
|
|
|
12
12
|
import { datesToISO } from "../../util/json.js";
|
|
13
13
|
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
14
14
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
15
|
+
import {
|
|
16
|
+
DEFAULT_HEARTBEAT_INTERVAL_MS,
|
|
17
|
+
isClientDegraded,
|
|
18
|
+
} from "../client-health.js";
|
|
15
19
|
import { NotFoundError } from "./errors.js";
|
|
16
20
|
import type { RouteDefinition } from "./types.js";
|
|
17
21
|
|
|
@@ -65,6 +69,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
65
69
|
c.actorPrincipalId === callerPrincipalId,
|
|
66
70
|
);
|
|
67
71
|
|
|
72
|
+
const now = new Date();
|
|
68
73
|
return {
|
|
69
74
|
clients: filtered.map((c) =>
|
|
70
75
|
datesToISO({
|
|
@@ -74,6 +79,11 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
74
79
|
machineName: c.machineName,
|
|
75
80
|
connectedAt: c.connectedAt,
|
|
76
81
|
lastActiveAt: c.lastActiveAt,
|
|
82
|
+
degraded: isClientDegraded(
|
|
83
|
+
c.lastActiveAt,
|
|
84
|
+
now,
|
|
85
|
+
DEFAULT_HEARTBEAT_INTERVAL_MS,
|
|
86
|
+
),
|
|
77
87
|
}),
|
|
78
88
|
),
|
|
79
89
|
};
|
|
@@ -50,6 +50,30 @@ function withGuardianNameOverride<
|
|
|
50
50
|
return contact;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/** Adds `externalUserId` (= `address`) to each channel for older macOS clients. */
|
|
54
|
+
function withChannelCompat<T extends { channels: { address: string }[] }>(
|
|
55
|
+
contact: T,
|
|
56
|
+
): T {
|
|
57
|
+
return {
|
|
58
|
+
...contact,
|
|
59
|
+
channels: contact.channels.map((ch) => ({
|
|
60
|
+
...ch,
|
|
61
|
+
externalUserId: ch.address,
|
|
62
|
+
})),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Compose both response transforms (guardian display name + channel compat). */
|
|
67
|
+
function prepareContactResponse<
|
|
68
|
+
T extends {
|
|
69
|
+
role: string;
|
|
70
|
+
displayName: string;
|
|
71
|
+
channels: { address: string }[];
|
|
72
|
+
},
|
|
73
|
+
>(contact: T): T {
|
|
74
|
+
return withChannelCompat(withGuardianNameOverride(contact));
|
|
75
|
+
}
|
|
76
|
+
|
|
53
77
|
const VALID_CONTACT_TYPES: readonly ContactType[] = ["human", "assistant"];
|
|
54
78
|
|
|
55
79
|
const VALID_CHANNEL_STATUSES: readonly ChannelStatus[] = [
|
|
@@ -87,6 +111,7 @@ const contactChannelSchema = z.object({
|
|
|
87
111
|
type: z.string(),
|
|
88
112
|
address: z.string(),
|
|
89
113
|
isPrimary: z.boolean(),
|
|
114
|
+
/** @deprecated Echoes `address` for backwards compatibility with older macOS clients. */
|
|
90
115
|
externalUserId: z.string().nullable(),
|
|
91
116
|
status: z.string(),
|
|
92
117
|
policy: z.string(),
|
|
@@ -143,14 +168,14 @@ function handleListContacts(queryParams: Record<string, string>) {
|
|
|
143
168
|
});
|
|
144
169
|
return {
|
|
145
170
|
ok: true,
|
|
146
|
-
contacts: contacts.map(
|
|
171
|
+
contacts: contacts.map(prepareContactResponse),
|
|
147
172
|
};
|
|
148
173
|
}
|
|
149
174
|
|
|
150
175
|
const contacts = listContacts(limit, role, contactType);
|
|
151
176
|
return {
|
|
152
177
|
ok: true,
|
|
153
|
-
contacts: contacts.map(
|
|
178
|
+
contacts: contacts.map(prepareContactResponse),
|
|
154
179
|
};
|
|
155
180
|
}
|
|
156
181
|
|
|
@@ -165,7 +190,7 @@ function handleGetContact(contactId: string) {
|
|
|
165
190
|
: undefined;
|
|
166
191
|
return {
|
|
167
192
|
ok: true,
|
|
168
|
-
contact:
|
|
193
|
+
contact: prepareContactResponse(contact),
|
|
169
194
|
assistantMetadata: assistantMeta ?? undefined,
|
|
170
195
|
};
|
|
171
196
|
}
|
|
@@ -508,7 +533,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
508
533
|
limit: z.number().optional(),
|
|
509
534
|
})
|
|
510
535
|
.parse(body);
|
|
511
|
-
return searchContacts(parsed);
|
|
536
|
+
return searchContacts(parsed).map(prepareContactResponse);
|
|
512
537
|
},
|
|
513
538
|
},
|
|
514
539
|
|
|
@@ -604,7 +629,7 @@ function handleMergeContactsRoute(args: RouteHandlerArgs) {
|
|
|
604
629
|
|
|
605
630
|
try {
|
|
606
631
|
const contact = mergeContacts(keepId, mergeId);
|
|
607
|
-
return { ok: true, contact:
|
|
632
|
+
return { ok: true, contact: prepareContactResponse(contact) };
|
|
608
633
|
} catch (err) {
|
|
609
634
|
const message = err instanceof Error ? err.message : String(err);
|
|
610
635
|
throw new BadRequestError(message);
|
|
@@ -667,8 +692,6 @@ function handleUpdateContactChannelRoute(args: RouteHandlerArgs) {
|
|
|
667
692
|
const parentContact = getContact(updated.contactId);
|
|
668
693
|
return {
|
|
669
694
|
ok: true,
|
|
670
|
-
contact: parentContact
|
|
671
|
-
? withGuardianNameOverride(parentContact)
|
|
672
|
-
: undefined,
|
|
695
|
+
contact: parentContact ? prepareContactResponse(parentContact) : undefined,
|
|
673
696
|
};
|
|
674
697
|
}
|
|
@@ -72,7 +72,7 @@ const log = getLogger("conversation-compaction-routes");
|
|
|
72
72
|
* `responseBody` (below) is the source-of-truth for the generated
|
|
73
73
|
* OpenAPI client type the frontend imports
|
|
74
74
|
* (`ConversationsByIdCompactionGetResponse` in
|
|
75
|
-
* `
|
|
75
|
+
* `clients/web/src/generated/daemon/types.gen`); regenerate the client with
|
|
76
76
|
* `bun run openapi-ts` after changing the schema.
|
|
77
77
|
*
|
|
78
78
|
* `null` means the value isn't known for the underlying row — either the
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
cancelGeneration,
|
|
27
27
|
clearAllConversations,
|
|
28
28
|
regenerateResponse,
|
|
29
|
+
resolveMetaSlashCommand,
|
|
29
30
|
switchConversation,
|
|
30
31
|
undoLastMessage,
|
|
31
32
|
} from "../../daemon/handlers/conversations.js";
|
|
@@ -93,11 +94,26 @@ function cancelScheduleIfLast(conversationId: string): void {
|
|
|
93
94
|
function handleCreateConversation({ body = {}, headers }: RouteHandlerArgs) {
|
|
94
95
|
const conversationKey =
|
|
95
96
|
(body.conversationKey as string | undefined) ?? crypto.randomUUID();
|
|
97
|
+
// The shared route adapter does not runtime-validate the body against the
|
|
98
|
+
// Zod requestBody (it's codegen-only), so guard the type before trimming —
|
|
99
|
+
// a malformed `{ title: 123 }` would otherwise throw on `.trim()` and 500.
|
|
100
|
+
if (body.title !== undefined && typeof body.title !== "string") {
|
|
101
|
+
throw new BadRequestError("title must be a string");
|
|
102
|
+
}
|
|
103
|
+
const customTitle = body.title?.trim() || undefined;
|
|
96
104
|
const result = getOrCreateConversation(conversationKey, {
|
|
97
105
|
conversationType: "standard",
|
|
98
106
|
});
|
|
99
107
|
if (result.created) {
|
|
100
|
-
|
|
108
|
+
// A caller-supplied title is user-set: persist it with isAutoTitle = 0 so
|
|
109
|
+
// the async LLM titler's safe-overwrite check leaves it untouched. Without
|
|
110
|
+
// one, fall back to the neutral "New Conversation" placeholder, which stays
|
|
111
|
+
// replaceable by the auto-titler once messages arrive.
|
|
112
|
+
if (customTitle) {
|
|
113
|
+
updateConversationTitle(result.conversationId, customTitle, 0);
|
|
114
|
+
} else {
|
|
115
|
+
updateConversationTitle(result.conversationId, "New Conversation");
|
|
116
|
+
}
|
|
101
117
|
publishConversationListAndMetadataChanged(
|
|
102
118
|
"created",
|
|
103
119
|
result.conversationId,
|
|
@@ -452,6 +468,29 @@ async function handleUndoLastMessage({ pathParams = {} }: RouteHandlerArgs) {
|
|
|
452
468
|
};
|
|
453
469
|
}
|
|
454
470
|
|
|
471
|
+
async function handleResolveMetaSlashCommand({
|
|
472
|
+
pathParams = {},
|
|
473
|
+
body = {},
|
|
474
|
+
}: RouteHandlerArgs) {
|
|
475
|
+
const command = body.command as string | undefined;
|
|
476
|
+
if (!command || typeof command !== "string") {
|
|
477
|
+
throw new BadRequestError("Missing command");
|
|
478
|
+
}
|
|
479
|
+
let result: Awaited<ReturnType<typeof resolveMetaSlashCommand>>;
|
|
480
|
+
try {
|
|
481
|
+
result = await resolveMetaSlashCommand(pathParams.id!, command);
|
|
482
|
+
} catch (err) {
|
|
483
|
+
if (err instanceof UserError) {
|
|
484
|
+
throw new BadRequestError(err.message);
|
|
485
|
+
}
|
|
486
|
+
throw err;
|
|
487
|
+
}
|
|
488
|
+
if (!result) {
|
|
489
|
+
throw new NotFoundError(`No conversation for ${pathParams.id}`);
|
|
490
|
+
}
|
|
491
|
+
return result;
|
|
492
|
+
}
|
|
493
|
+
|
|
455
494
|
async function handleRegenerateResponse({ pathParams = {} }: RouteHandlerArgs) {
|
|
456
495
|
const conversationId = pathParams.id!;
|
|
457
496
|
try {
|
|
@@ -526,6 +565,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
526
565
|
.literal("standard")
|
|
527
566
|
.optional()
|
|
528
567
|
.describe("Only standard conversations are created by this endpoint"),
|
|
568
|
+
title: z
|
|
569
|
+
.string()
|
|
570
|
+
.optional()
|
|
571
|
+
.describe(
|
|
572
|
+
"Explicit title for the conversation. When provided on creation, it is persisted as a user-set title (never overwritten by the auto-titler). Used by flows that mint a conversation up-front and don't want an auto-generated title.",
|
|
573
|
+
),
|
|
529
574
|
}),
|
|
530
575
|
responseBody: z.object({
|
|
531
576
|
id: z
|
|
@@ -820,6 +865,40 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
820
865
|
}),
|
|
821
866
|
handler: handleUndoLastMessage,
|
|
822
867
|
},
|
|
868
|
+
{
|
|
869
|
+
operationId: "resolveConversationSlashCommand",
|
|
870
|
+
endpoint: "conversations/:id/slash",
|
|
871
|
+
method: "POST",
|
|
872
|
+
policy: {
|
|
873
|
+
requiredScopes: ["chat.write"],
|
|
874
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
875
|
+
},
|
|
876
|
+
summary: "Resolve a local meta slash command",
|
|
877
|
+
description:
|
|
878
|
+
"Run a local meta slash command (/clean, /status, /commands, /models) " +
|
|
879
|
+
"without starting a turn: no messages are persisted and no turn events " +
|
|
880
|
+
"are emitted. /clean also strips runtime injections from the history. " +
|
|
881
|
+
"Returns the text to render and, for /clean, the post-strip context usage.",
|
|
882
|
+
tags: ["conversations"],
|
|
883
|
+
pathParams: [{ name: "id", type: "uuid" }],
|
|
884
|
+
requestBody: z.object({
|
|
885
|
+
command: z
|
|
886
|
+
.string()
|
|
887
|
+
.describe("The slash command text, e.g. `/clean` or `/status`."),
|
|
888
|
+
}),
|
|
889
|
+
responseBody: z.object({
|
|
890
|
+
kind: z.enum(["clean", "info"]),
|
|
891
|
+
text: z.string(),
|
|
892
|
+
contextUsage: z
|
|
893
|
+
.object({
|
|
894
|
+
tokens: z.number(),
|
|
895
|
+
maxTokens: z.number().nullable(),
|
|
896
|
+
fillRatio: z.number().nullable(),
|
|
897
|
+
})
|
|
898
|
+
.optional(),
|
|
899
|
+
}),
|
|
900
|
+
handler: handleResolveMetaSlashCommand,
|
|
901
|
+
},
|
|
823
902
|
{
|
|
824
903
|
operationId: "regenerateResponse",
|
|
825
904
|
endpoint: "conversations/:id/regenerate",
|
|
@@ -129,9 +129,16 @@ const INFERENCE_PROFILE_UI_KEYS = new Set([
|
|
|
129
129
|
"speed",
|
|
130
130
|
"verbosity",
|
|
131
131
|
"temperature",
|
|
132
|
+
"topP",
|
|
132
133
|
"thinking",
|
|
133
134
|
]);
|
|
134
135
|
|
|
136
|
+
// Fields a MANAGED profile may edit. Beyond `label` (display name) and
|
|
137
|
+
// `status` (enabled/disabled), users can tune `topP` — the seed contract
|
|
138
|
+
// owns provider/model/connection, but top_p is a per-profile sampling knob
|
|
139
|
+
// the UI exposes on the managed Balanced profile.
|
|
140
|
+
const MANAGED_PROFILE_EDITABLE_KEYS = new Set(["label", "status", "topP"]);
|
|
141
|
+
|
|
135
142
|
function asMutablePlainObject(value: unknown): Record<string, unknown> | null {
|
|
136
143
|
if (value == null || typeof value !== "object" || Array.isArray(value)) {
|
|
137
144
|
return null;
|
|
@@ -508,6 +515,8 @@ const ConfigGetResponseSchema = z
|
|
|
508
515
|
profiles: z.record(z.string(), WireProfileEntry).optional(),
|
|
509
516
|
profileOrder: z.array(z.string()).optional(),
|
|
510
517
|
activeProfile: z.string().optional(),
|
|
518
|
+
// The profile the advisor consults; excluded from chat-profile pickers.
|
|
519
|
+
advisorProfile: z.string().optional(),
|
|
511
520
|
callSites: z
|
|
512
521
|
.record(
|
|
513
522
|
z.string(),
|
|
@@ -536,6 +545,13 @@ const ConfigGetResponseSchema = z
|
|
|
536
545
|
})
|
|
537
546
|
.passthrough()
|
|
538
547
|
.optional(),
|
|
548
|
+
"web-fetch": z
|
|
549
|
+
.object({
|
|
550
|
+
mode: ServiceModeSchema.optional(),
|
|
551
|
+
provider: z.string().optional(),
|
|
552
|
+
})
|
|
553
|
+
.passthrough()
|
|
554
|
+
.optional(),
|
|
539
555
|
"image-generation": z
|
|
540
556
|
.object({ mode: ServiceModeSchema.optional() })
|
|
541
557
|
.passthrough()
|
|
@@ -609,6 +625,7 @@ const ConfigPatchRequestSchema = z
|
|
|
609
625
|
.optional(),
|
|
610
626
|
profileOrder: z.array(z.string()).optional(),
|
|
611
627
|
activeProfile: z.string().nullable().optional(),
|
|
628
|
+
advisorProfile: z.string().nullable().optional(),
|
|
612
629
|
callSites: z
|
|
613
630
|
.record(z.string(), CallSiteOverrideDraftSchema.nullable())
|
|
614
631
|
.optional(),
|
|
@@ -633,6 +650,14 @@ const ConfigPatchRequestSchema = z
|
|
|
633
650
|
.passthrough()
|
|
634
651
|
.nullable()
|
|
635
652
|
.optional(),
|
|
653
|
+
"web-fetch": z
|
|
654
|
+
.object({
|
|
655
|
+
mode: ServiceModeSchema.optional(),
|
|
656
|
+
provider: z.string().optional(),
|
|
657
|
+
})
|
|
658
|
+
.passthrough()
|
|
659
|
+
.nullable()
|
|
660
|
+
.optional(),
|
|
636
661
|
"image-generation": z
|
|
637
662
|
.object({ mode: ServiceModeSchema.optional() })
|
|
638
663
|
.passthrough()
|
|
@@ -730,8 +755,14 @@ function rejectManagedProfileDeletion(body: Record<string, unknown>): void {
|
|
|
730
755
|
}
|
|
731
756
|
const profiles = asMutablePlainObject(llm.profiles);
|
|
732
757
|
if (!profiles) return;
|
|
758
|
+
const existingProfiles = asMutablePlainObject(getConfig().llm.profiles) ?? {};
|
|
733
759
|
for (const name of Object.keys(profiles)) {
|
|
734
|
-
if (profiles[name]
|
|
760
|
+
if (profiles[name] !== null || !MANAGED_PROFILE_NAMES.has(name)) continue;
|
|
761
|
+
// Only block deletion when the on-disk entry is Vellum-managed. A
|
|
762
|
+
// user-owned profile sharing a managed name carries a non-managed `source`
|
|
763
|
+
// and is freely deletable.
|
|
764
|
+
const existing = asMutablePlainObject(existingProfiles[name]);
|
|
765
|
+
if (existing?.source === "managed") {
|
|
735
766
|
throw new BadRequestError(`Cannot delete managed profile "${name}".`);
|
|
736
767
|
}
|
|
737
768
|
}
|
|
@@ -904,21 +935,39 @@ async function handleReplaceInferenceProfile({
|
|
|
904
935
|
const detail = parsed.error.issues.map((issue) => issue.message).join("; ");
|
|
905
936
|
throw new BadRequestError(`Invalid profile fragment: ${detail}`);
|
|
906
937
|
}
|
|
907
|
-
|
|
938
|
+
// A managed name with no existing entry stays protected so users can't
|
|
939
|
+
// shadow a seeded managed profile. An existing entry carrying a non-managed
|
|
940
|
+
// `source` is user-owned and remains fully editable.
|
|
941
|
+
const existingProfile = asMutablePlainObject(
|
|
942
|
+
getConfig().llm.profiles?.[name],
|
|
943
|
+
);
|
|
944
|
+
const isManaged =
|
|
945
|
+
MANAGED_PROFILE_NAMES.has(name) &&
|
|
946
|
+
(existingProfile == null || existingProfile.source === "managed");
|
|
947
|
+
// A managed profile name with no materialized entry (e.g. a flag-gated profile
|
|
948
|
+
// whose flag is off) cannot be patched: writing label/status here would persist
|
|
949
|
+
// a source-less stub that later blocks the real managed profile from being
|
|
950
|
+
// seeded. Reject rather than create a placeholder.
|
|
951
|
+
if (MANAGED_PROFILE_NAMES.has(name) && existingProfile == null) {
|
|
952
|
+
throw new BadRequestError(
|
|
953
|
+
`Profile "${name}" is not currently available and cannot be edited.`,
|
|
954
|
+
);
|
|
955
|
+
}
|
|
908
956
|
if (isManaged) {
|
|
909
|
-
// Managed profiles are daemon-seeded — provider, model,
|
|
910
|
-
//
|
|
911
|
-
//
|
|
912
|
-
//
|
|
913
|
-
// managed profile
|
|
957
|
+
// Managed profiles are daemon-seeded — provider, model, and the
|
|
958
|
+
// connection binding all belong to the seed contract and can't be
|
|
959
|
+
// reshaped by the user. The fields that ARE user policy (display label,
|
|
960
|
+
// enabled status, and the topP sampling knob) are allowed through so
|
|
961
|
+
// users can rename a managed profile, temporarily disable it, or tune
|
|
962
|
+
// top_p without duplicating it.
|
|
914
963
|
const requestedKeys = Object.keys(parsed.data);
|
|
915
964
|
const disallowed = requestedKeys.filter(
|
|
916
|
-
(k) => k
|
|
965
|
+
(k) => !MANAGED_PROFILE_EDITABLE_KEYS.has(k),
|
|
917
966
|
);
|
|
918
967
|
if (disallowed.length > 0) {
|
|
919
968
|
throw new BadRequestError(
|
|
920
969
|
`Cannot edit managed profile "${name}" fields [${disallowed.join(", ")}]. ` +
|
|
921
|
-
`Only label and
|
|
970
|
+
`Only label, status, and topP may be edited; duplicate to a custom profile to change other fields.`,
|
|
922
971
|
);
|
|
923
972
|
}
|
|
924
973
|
}
|
|
@@ -1019,7 +1068,7 @@ async function handleReplaceInferenceProfile({
|
|
|
1019
1068
|
}
|
|
1020
1069
|
|
|
1021
1070
|
/**
|
|
1022
|
-
* Apply a `{label?, status?}` patch to a managed profile entry, preserving
|
|
1071
|
+
* Apply a `{label?, status?, topP?}` patch to a managed profile entry, preserving
|
|
1023
1072
|
* every other field already on disk (provider, model, advanced params, etc).
|
|
1024
1073
|
* Caller is responsible for having already restricted the fragment to the
|
|
1025
1074
|
* managed-allowed keys.
|
|
@@ -1039,19 +1088,16 @@ function patchManagedProfileFields(
|
|
|
1039
1088
|
|
|
1040
1089
|
const existingProfile = asMutablePlainObject(profiles[name]) ?? {};
|
|
1041
1090
|
const nextProfile: Record<string, unknown> = { ...existingProfile };
|
|
1042
|
-
//
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
if ("status" in fragment) {
|
|
1051
|
-
if (fragment.status === null) {
|
|
1052
|
-
delete nextProfile.status;
|
|
1091
|
+
// For each managed-editable key: send `null` to clear, a value to set,
|
|
1092
|
+
// omit to leave untouched. Iterating the allowlist keeps persistence in
|
|
1093
|
+
// lock-step with the guard above — a key can't slip through the gate
|
|
1094
|
+
// without also being written.
|
|
1095
|
+
for (const key of MANAGED_PROFILE_EDITABLE_KEYS) {
|
|
1096
|
+
if (!(key in fragment)) continue;
|
|
1097
|
+
if (fragment[key] === null) {
|
|
1098
|
+
delete nextProfile[key];
|
|
1053
1099
|
} else {
|
|
1054
|
-
nextProfile
|
|
1100
|
+
nextProfile[key] = fragment[key];
|
|
1055
1101
|
}
|
|
1056
1102
|
}
|
|
1057
1103
|
profiles[name] = nextProfile;
|
|
@@ -120,7 +120,10 @@ import { assistantEventHub, broadcastMessage } from "../assistant-event-hub.js";
|
|
|
120
120
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
121
121
|
import { getPersistedSeq } from "../assistant-stream-state.js";
|
|
122
122
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
123
|
-
import {
|
|
123
|
+
import {
|
|
124
|
+
type GuardianPendingScope,
|
|
125
|
+
routeGuardianReply,
|
|
126
|
+
} from "../guardian-reply-router.js";
|
|
124
127
|
import { healGuardianBindingDrift } from "../guardian-vellum-migration.js";
|
|
125
128
|
import type {
|
|
126
129
|
ApprovalConversationGenerator,
|
|
@@ -148,6 +151,10 @@ import {
|
|
|
148
151
|
collectPendingConfirmations,
|
|
149
152
|
enrichToolCallsWithConfirmation,
|
|
150
153
|
} from "./tool-call-confirmation-enrichment.js";
|
|
154
|
+
import {
|
|
155
|
+
collectPendingQuestions,
|
|
156
|
+
enrichToolCallsWithQuestion,
|
|
157
|
+
} from "./tool-call-question-enrichment.js";
|
|
151
158
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
152
159
|
import { RouteResponse } from "./types.js";
|
|
153
160
|
|
|
@@ -486,12 +493,14 @@ async function tryConsumeCanonicalGuardianReply(params: {
|
|
|
486
493
|
sourceChannel,
|
|
487
494
|
conversation,
|
|
488
495
|
);
|
|
489
|
-
//
|
|
490
|
-
//
|
|
491
|
-
//
|
|
492
|
-
//
|
|
493
|
-
|
|
494
|
-
|
|
496
|
+
// An empty hint set is `blocked`, not absence: the in-memory staleness
|
|
497
|
+
// filter in collectCanonicalGuardianRequestHintIds found no live requests,
|
|
498
|
+
// so the router must not fall back to identity/DB lookup (which rediscovered
|
|
499
|
+
// stale canonical requests). A non-empty set scopes resolution to it.
|
|
500
|
+
const pendingScope: GuardianPendingScope =
|
|
501
|
+
pendingRequestHintIds.length > 0
|
|
502
|
+
? { mode: "scoped", requestIds: pendingRequestHintIds }
|
|
503
|
+
: { mode: "blocked" };
|
|
495
504
|
|
|
496
505
|
const routerResult = await routeGuardianReply({
|
|
497
506
|
messageText: trimmedContent,
|
|
@@ -503,7 +512,7 @@ async function tryConsumeCanonicalGuardianReply(params: {
|
|
|
503
512
|
guardianPrincipalId: verifiedActorPrincipalId,
|
|
504
513
|
},
|
|
505
514
|
conversationId,
|
|
506
|
-
|
|
515
|
+
pendingScope,
|
|
507
516
|
approvalConversationGenerator,
|
|
508
517
|
emissionContext: {
|
|
509
518
|
source: "inline_nl",
|
|
@@ -817,6 +826,7 @@ export function handleListMessages({
|
|
|
817
826
|
const pendingConfirmations = collectPendingConfirmations(
|
|
818
827
|
resolvedConversationId,
|
|
819
828
|
);
|
|
829
|
+
const pendingQuestions = collectPendingQuestions(resolvedConversationId);
|
|
820
830
|
|
|
821
831
|
const messages: RuntimeMessagePayload[] = parsed.map((m) => {
|
|
822
832
|
const mergedMessageIds = m.id ? (mergedIdMap.get(m.id) ?? []) : [];
|
|
@@ -880,10 +890,13 @@ export function handleListMessages({
|
|
|
880
890
|
m.id ?? undefined,
|
|
881
891
|
);
|
|
882
892
|
|
|
883
|
-
const toolCalls =
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
893
|
+
const toolCalls = enrichToolCallsWithQuestion(
|
|
894
|
+
enrichToolCallsWithConfirmation(rendered.toolCalls, {
|
|
895
|
+
workspaceDir,
|
|
896
|
+
pendingConfirmations,
|
|
897
|
+
}),
|
|
898
|
+
{ pendingQuestions },
|
|
899
|
+
);
|
|
887
900
|
|
|
888
901
|
// Strip <no_response/> markers from assistant messages so web/API clients
|
|
889
902
|
// never see the raw sentinel. Only assistant messages produce it; user
|
|
@@ -944,8 +957,8 @@ export function handleListMessages({
|
|
|
944
957
|
...(mergedMessageIds.length > 0 ? { mergedMessageIds } : {}),
|
|
945
958
|
...(m.clientMessageId ? { clientMessageId: m.clientMessageId } : {}),
|
|
946
959
|
role: m.role,
|
|
947
|
-
// Flat plain-text body the
|
|
948
|
-
//
|
|
960
|
+
// Flat plain-text body; see the `content` field on
|
|
961
|
+
// ConversationMessageSchema for why this must stay.
|
|
949
962
|
content: text,
|
|
950
963
|
timestamp: new Date(displayTimestamp).toISOString(),
|
|
951
964
|
attachments: msgAttachments,
|
|
@@ -1133,6 +1146,7 @@ export async function handleSendMessage(
|
|
|
1133
1146
|
bootstrapTemplate?: string;
|
|
1134
1147
|
initialMessage?: string;
|
|
1135
1148
|
skills?: string[];
|
|
1149
|
+
title?: string;
|
|
1136
1150
|
};
|
|
1137
1151
|
};
|
|
1138
1152
|
|
|
@@ -1310,8 +1324,13 @@ export async function handleSendMessage(
|
|
|
1310
1324
|
: sourceChannel === "vellum"
|
|
1311
1325
|
? crypto.randomUUID()
|
|
1312
1326
|
: `default:${sourceChannel}:${sourceInterface}`;
|
|
1327
|
+
// An onboarding flow may supply an explicit title for the conversation it
|
|
1328
|
+
// mints behind the scenes (e.g. the research pass) so it isn't left with an
|
|
1329
|
+
// auto-generated title. Applied only when this call creates the row.
|
|
1330
|
+
const onboardingTitle = body.onboarding?.title?.trim() || undefined;
|
|
1313
1331
|
mapping = getOrCreateConversation(resolvedConversationKey, {
|
|
1314
1332
|
conversationType: "standard",
|
|
1333
|
+
title: onboardingTitle,
|
|
1315
1334
|
});
|
|
1316
1335
|
}
|
|
1317
1336
|
|
|
@@ -2717,6 +2736,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2717
2736
|
bootstrapTemplate: z.string().optional(),
|
|
2718
2737
|
initialMessage: z.string().optional(),
|
|
2719
2738
|
skills: z.array(z.string()).optional(),
|
|
2739
|
+
title: z
|
|
2740
|
+
.string()
|
|
2741
|
+
.optional()
|
|
2742
|
+
.describe(
|
|
2743
|
+
"Explicit title for the conversation minted on this first message. Persisted as a user-set title (never overwritten by the auto-titler). Used by onboarding flows that mint a conversation behind the scenes.",
|
|
2744
|
+
),
|
|
2720
2745
|
})
|
|
2721
2746
|
.describe("PreChat onboarding context, sent on the first message only")
|
|
2722
2747
|
.optional(),
|