@vellumai/assistant 0.12.3-staging.1 → 0.12.3-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 +43 -29
- package/Dockerfile +63 -0
- package/docs/architecture/security.md +10 -5
- package/docs/architecture/turn-actor.md +2 -0
- package/docs/desktop-browser-cli.md +45 -4
- package/docs/live-voice-task-outcomes.md +100 -0
- package/docs/mode-sessions.md +183 -0
- package/docs/voice-input-diagnostics.md +58 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
- package/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
- package/openapi.yaml +665 -14
- package/package.json +1 -1
- package/scripts/smoke-desktop-browser-cli.ts +10 -26
- package/scripts/smoke-desktop-window-theme.ts +2 -3
- package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
- package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
- package/src/__tests__/annotate-risk-options.test.ts +2 -0
- package/src/__tests__/answered-question-persistence.test.ts +2 -0
- package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
- package/src/__tests__/approval-message-composer.test.ts +1 -118
- package/src/__tests__/approval-routes-http.test.ts +3 -0
- package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
- package/src/__tests__/assistant-event-targeting.test.ts +186 -0
- package/src/__tests__/assistant-stream-state.test.ts +29 -9
- package/src/__tests__/browser-fill-credential.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +4 -1
- package/src/__tests__/build-persisted-content.test.ts +1 -1
- package/src/__tests__/call-conversation-messages.test.ts +5 -0
- package/src/__tests__/call-recovery.test.ts +7 -2
- package/src/__tests__/call-routes-http.test.ts +12 -0
- package/src/__tests__/call-store.test.ts +7 -2
- package/src/__tests__/channel-retry-sweep.test.ts +9 -0
- package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
- package/src/__tests__/checker.test.ts +11 -3
- package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
- package/src/__tests__/computer-use-tools.test.ts +1 -233
- package/src/__tests__/config-model-image-provider.test.ts +39 -0
- package/src/__tests__/config-schema.test.ts +16 -0
- package/src/__tests__/config-watcher.test.ts +24 -0
- package/src/__tests__/context-search-agent-runner.test.ts +260 -1
- package/src/__tests__/context-search-fanout.test.ts +1 -1
- package/src/__tests__/context-search-types.test.ts +7 -7
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +546 -16
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
- package/src/__tests__/conversation-evictor.test.ts +62 -37
- package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
- package/src/__tests__/conversation-retry-route.test.ts +22 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
- package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
- package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
- package/src/__tests__/conversation-undo.test.ts +61 -0
- package/src/__tests__/credential-execution-client.test.ts +6 -6
- package/src/__tests__/credential-prompt-route.test.ts +35 -3
- package/src/__tests__/cu-unified-flow.test.ts +82 -1
- package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
- package/src/__tests__/dm-backfill.test.ts +91 -1
- package/src/__tests__/document-create-route.test.ts +88 -0
- package/src/__tests__/document-sync-tags.test.ts +27 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
- package/src/__tests__/events-tail-route.test.ts +25 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
- package/src/__tests__/guardian-action-sweep.test.ts +16 -0
- package/src/__tests__/guardian-dispatch.test.ts +13 -0
- package/src/__tests__/headless-browser-interactions.test.ts +64 -20
- package/src/__tests__/heartbeat-service.test.ts +2 -59
- package/src/__tests__/helpers/mock-conversation.ts +21 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
- package/src/__tests__/host-cu-proxy.test.ts +46 -2
- package/src/__tests__/http-user-message-parity.test.ts +2 -0
- package/src/__tests__/image-credentials.test.ts +49 -0
- package/src/__tests__/image-service-dispatcher.test.ts +45 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
- package/src/__tests__/interrupt-on-send.test.ts +57 -43
- package/src/__tests__/interrupt-turn-note.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +49 -1
- package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
- package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
- package/src/__tests__/mode-session-history.test.ts +245 -0
- package/src/__tests__/mode-session-recovery.test.ts +222 -0
- package/src/__tests__/mode-session-wire.test.ts +141 -0
- package/src/__tests__/notification-guardian-path.test.ts +7 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
- package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +12 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/plugin-api-provider.test.ts +5 -0
- package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -0
- package/src/__tests__/process-message-display-content.test.ts +56 -0
- package/src/__tests__/reaction-persistence.test.ts +5 -0
- package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
- package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
- package/src/__tests__/secret-ingress-http.test.ts +2 -0
- package/src/__tests__/secure-keys.test.ts +43 -1
- package/src/__tests__/send-endpoint-busy.test.ts +163 -1
- package/src/__tests__/server-history-render.test.ts +91 -1
- package/src/__tests__/settings-routes.test.ts +50 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
- package/src/__tests__/subagent-manager-notify.test.ts +1 -2
- package/src/__tests__/subagent-notify-parent.test.ts +146 -39
- package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
- package/src/__tests__/thread-backfill.test.ts +53 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +3 -1
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/twilio-routes.test.ts +1 -0
- package/src/__tests__/web-search-backend-failure.test.ts +1 -1
- package/src/activation/progress-store.test.ts +12 -7
- package/src/agent/loop.ts +99 -41
- package/src/api/events/assistant-turn-start.ts +3 -0
- package/src/api/events/generation-handoff.ts +2 -0
- package/src/api/events/message-complete.ts +2 -0
- package/src/api/events/notification-conversation-created.ts +14 -16
- package/src/api/events/notification-intent.ts +4 -2
- package/src/api/events/tool-result.ts +85 -0
- package/src/api/events/tool-use-start.ts +3 -0
- package/src/api/events/user-message-echo.ts +3 -0
- package/src/api/index.ts +31 -6
- package/src/api/mode-session.test.ts +131 -0
- package/src/api/mode-session.ts +148 -0
- package/src/api/remember-tool.ts +15 -0
- package/src/api/responses/conversation-message.ts +6 -0
- package/src/approvals/AGENTS.md +4 -2
- package/src/browser/__tests__/operations.test.ts +29 -0
- package/src/browser/operation-meta.ts +2 -1
- package/src/browser/operations.ts +29 -0
- package/src/browser/virtual-desktop-target.ts +2 -8
- package/src/bundler/bundle-signer.ts +1 -3
- package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
- package/src/calls/__tests__/call-controller.test.ts +94 -0
- package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
- package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
- package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
- package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
- package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
- package/src/calls/barge-in-guard.ts +5 -0
- package/src/calls/call-controller.ts +196 -1
- package/src/calls/call-domain.ts +4 -0
- package/src/calls/call-store.ts +87 -2
- package/src/calls/guardian-action-sweep.ts +22 -8
- package/src/calls/media-stream-audio-transcode.ts +1 -3
- package/src/calls/typesafe-noul.ts +156 -0
- package/src/calls/voice-control-protocol.ts +6 -0
- package/src/calls/voice-escalation-judge.ts +145 -0
- package/src/calls/voice-escalation-target.ts +10 -0
- package/src/calls/voice-leg-coordinator.ts +121 -3
- package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
- package/src/calls/voice-session-bridge.ts +256 -112
- package/src/calls/voice-triage-escalate.ts +7 -0
- package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
- package/src/cli/commands/__tests__/notifications.test.ts +35 -10
- package/src/cli/commands/browser.help.ts +4 -5
- package/src/cli/commands/browser.ts +0 -1
- package/src/cli/commands/clients.help.ts +46 -0
- package/src/cli/commands/clients.ts +116 -0
- package/src/cli/commands/credentials.help.ts +6 -1
- package/src/cli/commands/notifications.help.ts +16 -2
- package/src/cli/commands/notifications.ts +30 -8
- package/src/cli/commands/roadmap.help.ts +18 -21
- package/src/cli/commands/roadmap.ts +4 -21
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
- package/src/cli/lib/bundled-marketplace.json +84 -34
- package/src/cli/lib/plugin-marketplace.ts +8 -0
- package/src/cli/lib/publish-plugin.ts +1 -2
- package/src/config/__tests__/default-provider.test.ts +3 -1
- package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
- package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
- package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
- package/src/config/call-site-defaults.ts +9 -0
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/profile-text-generation.test.ts +2 -2
- package/src/config/schemas/__tests__/tools.test.ts +31 -0
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/channels.ts +0 -18
- package/src/config/schemas/llm.ts +3 -1
- package/src/config/schemas/mcp.ts +2 -1
- package/src/config/schemas/memory-retrospective.ts +11 -2
- package/src/config/schemas/services.ts +15 -6
- package/src/config/schemas/tools.ts +10 -0
- package/src/config/session-groups-gate.ts +21 -0
- package/src/config/skills.ts +2 -6
- package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
- package/src/conversations/message-consolidation.ts +102 -5
- package/src/credential-execution/ces-connect.test.ts +69 -0
- package/src/credential-execution/ces-connect.ts +115 -0
- package/src/credential-execution/ces-runtime.ts +55 -93
- package/src/credential-execution/executable-discovery.ts +1 -11
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
- package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
- package/src/daemon/browser-mode-session.test.ts +402 -0
- package/src/daemon/browser-mode-session.ts +186 -0
- package/src/daemon/computer-use-mode-session.test.ts +210 -0
- package/src/daemon/computer-use-mode-session.ts +105 -0
- package/src/daemon/config-watcher.ts +10 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +58 -10
- package/src/daemon/conversation-agent-loop.ts +219 -25
- package/src/daemon/conversation-evictor.ts +5 -24
- package/src/daemon/conversation-history.ts +10 -0
- package/src/daemon/conversation-interrupt-repair.ts +4 -43
- package/src/daemon/conversation-interrupt.ts +7 -11
- package/src/daemon/conversation-messaging.ts +58 -5
- package/src/daemon/conversation-mode-session.test.ts +1667 -0
- package/src/daemon/conversation-mode-session.ts +1008 -0
- package/src/daemon/conversation-process.ts +5 -0
- package/src/daemon/conversation-runtime-assembly.ts +10 -20
- package/src/daemon/conversation-skill-tools.ts +1 -0
- package/src/daemon/conversation-store.ts +4 -4
- package/src/daemon/conversation-surface-snapshots.ts +135 -0
- package/src/daemon/conversation-surfaces.ts +113 -5
- package/src/daemon/conversation-tool-setup.ts +8 -3
- package/src/daemon/conversation.ts +143 -41
- package/src/daemon/handlers/config-model.ts +7 -5
- package/src/daemon/handlers/shared.ts +55 -16
- package/src/daemon/host-cu-proxy.ts +51 -22
- package/src/daemon/lifecycle.ts +30 -13
- package/src/daemon/message-protocol.ts +0 -1
- package/src/daemon/message-provenance.ts +28 -4
- package/src/daemon/mode-session-startup-recovery.ts +23 -0
- package/src/daemon/mode-session-tracking.ts +54 -0
- package/src/daemon/process-message.ts +13 -4
- package/src/daemon/virtual-desktop-context.ts +21 -0
- package/src/desktop/__tests__/fake-desktop.ts +1 -0
- package/src/desktop/desktop-accessibility-script.ts +88 -0
- package/src/desktop/desktop-accessibility.test.ts +160 -0
- package/src/desktop/desktop-accessibility.ts +169 -0
- package/src/desktop/desktop-automation-lease.test.ts +76 -68
- package/src/desktop/desktop-automation-lease.ts +41 -50
- package/src/desktop/desktop-browser-endpoint.ts +4 -0
- package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
- package/src/desktop/desktop-computer-use.test.ts +449 -0
- package/src/desktop/desktop-computer-use.ts +502 -0
- package/src/desktop/desktop-dependencies.ts +47 -293
- package/src/desktop/desktop-display.ts +2 -2
- package/src/desktop/desktop-panel-config.test.ts +13 -3
- package/src/desktop/desktop-panel-config.ts +109 -15
- package/src/desktop/desktop-session-manager.test.ts +69 -21
- package/src/desktop/desktop-session-manager.ts +76 -22
- package/src/desktop/desktop-stream-bridge.test.ts +11 -122
- package/src/desktop/desktop-stream-bridge.ts +6 -8
- package/src/desktop/desktop-window-theme.ts +5 -25
- package/src/desktop/virtual-desktop-feature.ts +52 -2
- package/src/desktop/virtual-desktop-platform.test.ts +5 -9
- package/src/documents/document-store.ts +23 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
- package/src/heartbeat/heartbeat-service.ts +5 -33
- package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
- package/src/ipc/assistant-server.ts +2 -0
- package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
- package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
- package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
- package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
- package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
- package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
- package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
- package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
- package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
- package/src/live-voice/__tests__/session-controls.test.ts +23 -0
- package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
- package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
- package/src/live-voice/camera-mode-session.test.ts +265 -0
- package/src/live-voice/camera-mode-session.ts +277 -0
- package/src/live-voice/continuation-judge.ts +123 -0
- package/src/live-voice/live-activity-reporter.ts +115 -6
- package/src/live-voice/live-voice-manager.ts +36 -1
- package/src/live-voice/live-voice-photo.ts +88 -7
- package/src/live-voice/live-voice-session-manager.ts +15 -0
- package/src/live-voice/live-voice-session.ts +1443 -747
- package/src/live-voice/live-voice-tts.ts +22 -4
- package/src/live-voice/microphone-idle-gate.ts +56 -0
- package/src/live-voice/protocol.ts +171 -4
- package/src/live-voice/session-controls.ts +11 -3
- package/src/live-voice/task-outcomes.ts +131 -0
- package/src/live-voice/voice-input-diagnostics.ts +117 -0
- package/src/mcp/__tests__/manager-tool-caps.test.ts +63 -18
- package/src/mcp/__tests__/tool-caps.test.ts +28 -1
- package/src/mcp/manager.ts +3 -0
- package/src/mcp/tool-caps.ts +12 -4
- package/src/media/__tests__/image-models.test.ts +58 -0
- package/src/media/image-credentials.ts +5 -0
- package/src/media/image-models.ts +52 -0
- package/src/media/image-service.ts +8 -0
- package/src/media/openrouter-image-service.test.ts +133 -0
- package/src/media/openrouter-image-service.ts +153 -0
- package/src/media/types.ts +1 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
- package/src/messaging/providers/discord/send.ts +4 -17
- package/src/messaging/providers/discord/transport.ts +2 -2
- package/src/messaging/providers/outlook/client.ts +16 -22
- package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
- package/src/messaging/providers/telegram-bot/send.ts +10 -7
- package/src/messaging/providers/telegram-bot/transport.ts +3 -10
- package/src/messaging/providers/whatsapp/send.test.ts +169 -4
- package/src/monitoring/__tests__/control.test.ts +17 -5
- package/src/monitoring/control.ts +15 -5
- package/src/notifications/AGENTS.md +1 -1
- package/src/notifications/README.md +83 -99
- package/src/notifications/__tests__/broadcaster.test.ts +1 -1
- package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
- package/src/notifications/__tests__/copy-composer.test.ts +1 -1
- package/src/notifications/__tests__/decision-engine.test.ts +79 -2
- package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
- package/src/notifications/__tests__/notification-utils.test.ts +18 -0
- package/src/notifications/adapters/macos.ts +37 -46
- package/src/notifications/broadcaster.ts +5 -6
- package/src/notifications/channel-allowlist.ts +44 -0
- package/src/notifications/copy-composer.ts +0 -23
- package/src/notifications/decision-engine.ts +24 -14
- package/src/notifications/deterministic-checks.ts +1 -1
- package/src/notifications/emit-signal.ts +123 -37
- package/src/notifications/home-feed-side-effect.ts +9 -7
- package/src/notifications/notification-utils.ts +19 -0
- package/src/notifications/signal.ts +4 -19
- package/src/notifications/types.ts +15 -0
- package/src/oauth/connection-resolver.ts +1 -2
- package/src/oauth/oauth-store.ts +1 -3
- package/src/oauth/provider-serializer.ts +7 -0
- package/src/oauth/seed-providers.ts +30 -0
- package/src/onboarding/onboarding-events-store.ts +99 -12
- package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
- package/src/persistence/client-connection-events-store.ts +377 -0
- package/src/persistence/conversation-crud.ts +55 -6
- package/src/persistence/conversation-mode-sessions.test.ts +424 -0
- package/src/persistence/conversation-mode-sessions.ts +460 -0
- package/src/persistence/conversation-queries.ts +6 -19
- package/src/persistence/llm-usage-store.ts +3 -9
- package/src/persistence/message-metadata.ts +25 -0
- package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
- package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
- package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
- package/src/persistence/schema/conversations.ts +67 -0
- package/src/persistence/schema/infrastructure.ts +29 -0
- package/src/persistence/steps.ts +17 -0
- package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
- package/src/plugin-api/effective-context-window.ts +33 -0
- package/src/plugin-api/index.ts +24 -5
- package/src/plugin-api/plugin-name-env.ts +125 -0
- package/src/plugin-api/resolve-credential.ts +79 -20
- package/src/plugin-api/vision-support.test.ts +22 -0
- package/src/plugin-api/vision-support.ts +17 -5
- package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
- package/src/plugins/active-plugin-env.ts +51 -0
- package/src/plugins/defaults/index.ts +24 -0
- package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
- package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
- package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +78 -22
- package/src/plugins/defaults/memory/context-search/format.ts +51 -7
- package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
- package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
- package/src/plugins/defaults/memory/context-search/search.ts +8 -14
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
- package/src/plugins/defaults/memory/context-search/types.ts +1 -11
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +12 -21
- package/src/plugins/defaults/memory/graph/tools.ts +35 -64
- package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +5 -0
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +2 -2
- package/src/plugins/defaults/memory/tools.test.ts +124 -9
- package/src/plugins/defaults/memory/tools.ts +38 -11
- package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +165 -27
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +46 -27
- package/src/plugins/defaults/memory/v3/orchestrate.ts +78 -38
- package/src/plugins/defaults/memory/v3/pool-log-store.ts +65 -79
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +14 -5
- package/src/plugins/defaults/memory/v3/pool-select.ts +683 -44
- package/src/plugins/defaults/memory/worker-control.ts +15 -5
- package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
- package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
- package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
- package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
- package/src/plugins/defaults/task-progress/package.json +14 -0
- package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
- package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
- package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
- package/src/providers/anthropic/client.ts +10 -1
- package/src/providers/anthropic-gateway-shared.ts +6 -0
- package/src/providers/fetch-provider-catalog.ts +11 -0
- package/src/providers/gemini/client.ts +25 -8
- package/src/providers/inference/adapter-factory.ts +1 -1
- package/src/providers/jev/client.test.ts +10 -0
- package/src/providers/jev/client.ts +20 -4
- package/src/providers/model-catalog.ts +4 -3
- package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
- package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
- package/src/providers/openai/chat-completions-provider.ts +100 -29
- package/src/providers/openai/google-thought-signature.ts +0 -6
- package/src/providers/openai/responses-provider.ts +23 -1
- package/src/providers/ratelimit.ts +1 -3
- package/src/providers/search-provider-catalog.ts +24 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
- package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
- package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
- package/src/providers/types.ts +5 -0
- package/src/routes/control.ts +7 -5
- package/src/runtime/AGENTS.md +4 -2
- package/src/runtime/actor-trust-resolver.ts +3 -3
- package/src/runtime/agent-wake.ts +1 -1
- package/src/runtime/approval-message-composer.ts +3 -69
- package/src/runtime/assistant-event-hub.ts +73 -75
- package/src/runtime/assistant-event-publish-options.ts +7 -0
- package/src/runtime/assistant-event-targeting.ts +79 -0
- package/src/runtime/assistant-stream-state.ts +13 -100
- package/src/runtime/background-job-runner.ts +5 -5
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/guardian-action-message-composer.ts +8 -161
- package/src/runtime/guardian-reply-router.ts +28 -32
- package/src/runtime/http-types.ts +6 -0
- package/src/runtime/message-composer-types.ts +3 -61
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
- package/src/runtime/migrations/vbundle-builder.ts +24 -1
- package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +10 -0
- package/src/runtime/migrations/vbundle-importer.ts +4 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
- package/src/runtime/migrations/vbundle-validator.ts +1 -0
- package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
- package/src/runtime/pending-interactions.ts +29 -0
- package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
- package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
- package/src/runtime/routes/browser-context.ts +31 -11
- package/src/runtime/routes/browser-routes.ts +43 -4
- package/src/runtime/routes/btw-routes.ts +9 -4
- package/src/runtime/routes/client-routes.ts +108 -0
- package/src/runtime/routes/conversation-management-routes.ts +4 -1
- package/src/runtime/routes/conversation-routes.ts +113 -27
- package/src/runtime/routes/credential-prompt-routes.ts +4 -3
- package/src/runtime/routes/credential-routes.ts +1 -2
- package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
- package/src/runtime/routes/desktop-setup-routes.ts +4 -6
- package/src/runtime/routes/documents-routes.ts +51 -0
- package/src/runtime/routes/email-routes.ts +3 -7
- package/src/runtime/routes/events-routes.ts +75 -54
- package/src/runtime/routes/identity-routes.ts +1 -5
- package/src/runtime/routes/image-generation-routes.ts +8 -14
- package/src/runtime/routes/inbound-message-handler.ts +35 -38
- package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
- package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +38 -9
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +2 -5
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
- package/src/runtime/routes/llm-context-normalization.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +73 -2
- package/src/runtime/routes/notification-routes.ts +10 -0
- package/src/runtime/routes/oauth-providers.ts +7 -0
- package/src/runtime/routes/plugins-routes.ts +6 -0
- package/src/runtime/routes/roadmap-routes.ts +47 -8
- package/src/runtime/routes/secret-routes.ts +1 -1
- package/src/runtime/routes/settings-routes.ts +10 -4
- package/src/runtime/routes/watcher-routes.ts +1 -3
- package/src/runtime/trust-class.test.ts +7 -6
- package/src/runtime/trust-class.ts +9 -17
- package/src/schedule/__tests__/worker-control.test.ts +36 -5
- package/src/schedule/worker-control.ts +15 -5
- package/src/security/secure-keys.ts +53 -103
- package/src/skills/clawhub.ts +3 -8
- package/src/skills/managed-store.ts +1 -5
- package/src/stt/types.ts +4 -0
- package/src/subagent/notify.ts +54 -34
- package/src/subagent/parent-notification.ts +6 -0
- package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
- package/src/telemetry/phone-call-funnel.ts +144 -0
- package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
- package/src/tools/ask-question/ask-question-tool.ts +6 -4
- package/src/tools/browser/browser-execution.ts +22 -59
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
- package/src/tools/client-os.ts +15 -0
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
- package/src/tools/computer-use/target.ts +42 -0
- package/src/tools/document/document-tool.ts +13 -18
- package/src/tools/execution-target.ts +14 -16
- package/src/tools/host-terminal/host-shell.ts +4 -1
- package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
- package/src/tools/network/__tests__/web-search.test.ts +203 -0
- package/src/tools/network/web-fetch.ts +274 -7
- package/src/tools/network/web-search.ts +468 -6
- package/src/tools/permission-checker.ts +3 -3
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/skills/load.ts +2 -1
- package/src/tools/skills/sandbox-runner.ts +11 -2
- package/src/tools/skills/skill-script-runner.ts +7 -0
- package/src/tools/skills/skill-tool-factory.ts +15 -1
- package/src/tools/terminal/__tests__/safe-env.test.ts +11 -0
- package/src/tools/terminal/safe-env.ts +4 -0
- package/src/tools/terminal/shell.ts +2 -0
- package/src/tools/tool-approval-handler.ts +5 -1
- package/src/tools/tool-types.ts +3 -3
- package/src/tools/types.ts +8 -2
- package/src/util/__tests__/worker-process-command.test.ts +5 -4
- package/src/util/abort-reasons.ts +18 -26
- package/src/util/canonicalize-identity.test.ts +21 -0
- package/src/util/canonicalize-identity.ts +16 -0
- package/src/util/errors.ts +13 -3
- package/src/util/provider-error-patterns.ts +3 -0
- package/src/util/worker-process.ts +77 -35
- package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
- package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/computer-use-window-schema.test.ts +0 -24
- package/src/api/events/heartbeat-alert.ts +0 -20
- package/src/daemon/message-types/web-activity.ts +0 -65
- package/src/desktop/desktop-dependencies.test.ts +0 -131
- package/src/tools/computer-use/definitions.ts +0 -607
|
@@ -9,6 +9,7 @@ import { z } from "zod";
|
|
|
9
9
|
|
|
10
10
|
import type { HostProxyCapability } from "../../channels/types.js";
|
|
11
11
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
12
|
+
import { listClientConnectionHistory } from "../../persistence/client-connection-events-store.js";
|
|
12
13
|
import { datesToISO } from "../../util/json.js";
|
|
13
14
|
import { getLogger } from "../../util/logger.js";
|
|
14
15
|
import {
|
|
@@ -112,6 +113,8 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
112
113
|
interfaceId: c.interfaceId,
|
|
113
114
|
capabilities: c.capabilities,
|
|
114
115
|
machineName: c.machineName,
|
|
116
|
+
clientVersion: c.clientVersion,
|
|
117
|
+
sseWatchdog: c.sseWatchdog,
|
|
115
118
|
connectedAt: c.connectedAt,
|
|
116
119
|
lastActiveAt: c.lastActiveAt,
|
|
117
120
|
degraded: isClientDegraded(
|
|
@@ -151,6 +154,79 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
151
154
|
return { disconnected: count };
|
|
152
155
|
},
|
|
153
156
|
},
|
|
157
|
+
{
|
|
158
|
+
operationId: "list_client_history",
|
|
159
|
+
endpoint: "clients/history",
|
|
160
|
+
method: "GET",
|
|
161
|
+
policy: {
|
|
162
|
+
requiredScopes: ["settings.read"],
|
|
163
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
164
|
+
},
|
|
165
|
+
summary: "List client connection history",
|
|
166
|
+
description:
|
|
167
|
+
"Return persisted client subscribe/dispose events and coalesced sessions. Reconnects shorter than 60 seconds are flaps, not outages.",
|
|
168
|
+
tags: ["clients"],
|
|
169
|
+
queryParams: [
|
|
170
|
+
{
|
|
171
|
+
name: "clientId",
|
|
172
|
+
type: "string",
|
|
173
|
+
required: false,
|
|
174
|
+
description: "Restrict history to one client UUID.",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: "interfaceId",
|
|
178
|
+
type: "string",
|
|
179
|
+
required: false,
|
|
180
|
+
description: "Restrict history to one interface (e.g. chrome-extension).",
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: "since",
|
|
184
|
+
type: "string",
|
|
185
|
+
required: false,
|
|
186
|
+
description:
|
|
187
|
+
"ISO-8601 or epoch-ms lower bound. Sessions already open at this time are included.",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: "limit",
|
|
191
|
+
type: "string",
|
|
192
|
+
required: false,
|
|
193
|
+
description: "Max coalesced sessions to return (1-500, default 50).",
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
responseBody: z.object({
|
|
197
|
+
sessions: z.array(z.object({}).passthrough()),
|
|
198
|
+
events: z.array(z.object({}).passthrough()),
|
|
199
|
+
}),
|
|
200
|
+
handler: ({ queryParams, headers }) => {
|
|
201
|
+
const since = parseHistorySince(queryParams?.since);
|
|
202
|
+
const limit = parseHistoryLimit(queryParams?.limit);
|
|
203
|
+
const callerPrincipalId = headers?.["x-vellum-actor-principal-id"];
|
|
204
|
+
const history = listClientConnectionHistory({
|
|
205
|
+
clientId: queryParams?.clientId?.trim() || undefined,
|
|
206
|
+
interfaceId: queryParams?.interfaceId?.trim() || undefined,
|
|
207
|
+
actorPrincipalId: isHttpAuthDisabled()
|
|
208
|
+
? undefined
|
|
209
|
+
: callerPrincipalId || "__none__",
|
|
210
|
+
since,
|
|
211
|
+
limit,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
sessions: history.sessions.map((session) => ({
|
|
216
|
+
...session,
|
|
217
|
+
startedAt: new Date(session.startedAt).toISOString(),
|
|
218
|
+
endedAt:
|
|
219
|
+
session.endedAt == null
|
|
220
|
+
? null
|
|
221
|
+
: new Date(session.endedAt).toISOString(),
|
|
222
|
+
})),
|
|
223
|
+
events: history.events.map((event) => ({
|
|
224
|
+
...event,
|
|
225
|
+
occurredAt: new Date(event.occurredAt).toISOString(),
|
|
226
|
+
})),
|
|
227
|
+
};
|
|
228
|
+
},
|
|
229
|
+
},
|
|
154
230
|
{
|
|
155
231
|
operationId: "report_client_presence",
|
|
156
232
|
endpoint: "clients/presence",
|
|
@@ -342,3 +418,35 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
342
418
|
},
|
|
343
419
|
},
|
|
344
420
|
];
|
|
421
|
+
|
|
422
|
+
function parseHistorySince(raw: string | undefined): number | undefined {
|
|
423
|
+
if (!raw?.trim()) {
|
|
424
|
+
return undefined;
|
|
425
|
+
}
|
|
426
|
+
const trimmed = raw.trim();
|
|
427
|
+
if (/^\d+$/.test(trimmed)) {
|
|
428
|
+
const epoch = Number(trimmed);
|
|
429
|
+
if (!Number.isFinite(epoch) || epoch < 0) {
|
|
430
|
+
throw new BadRequestError("since must be a non-negative epoch-ms value");
|
|
431
|
+
}
|
|
432
|
+
return epoch;
|
|
433
|
+
}
|
|
434
|
+
const parsed = Date.parse(trimmed);
|
|
435
|
+
if (Number.isNaN(parsed)) {
|
|
436
|
+
throw new BadRequestError(
|
|
437
|
+
"since must be an ISO-8601 timestamp or epoch milliseconds",
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
return parsed;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function parseHistoryLimit(raw: string | undefined): number | undefined {
|
|
444
|
+
if (!raw?.trim()) {
|
|
445
|
+
return undefined;
|
|
446
|
+
}
|
|
447
|
+
const parsed = Number(raw.trim());
|
|
448
|
+
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
449
|
+
throw new BadRequestError("limit must be a positive integer");
|
|
450
|
+
}
|
|
451
|
+
return parsed;
|
|
452
|
+
}
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
* POST /v1/conversations/:id/retry — retry the last assistant turn
|
|
20
20
|
* POST /v1/conversations/reorder — reorder / pin conversations
|
|
21
21
|
*/
|
|
22
|
-
|
|
23
22
|
import { v7 as uuidv7 } from "uuid";
|
|
24
23
|
import { z } from "zod";
|
|
25
24
|
|
|
@@ -43,6 +42,7 @@ import {
|
|
|
43
42
|
undoLastMessage,
|
|
44
43
|
} from "../../daemon/handlers/conversations.js";
|
|
45
44
|
import { normalizeConversationType } from "../../daemon/message-types/shared.js";
|
|
45
|
+
import { bestEffortModeSessionTracking } from "../../daemon/mode-session-tracking.js";
|
|
46
46
|
import { stripConversationIds } from "../../home/feed-writer.js";
|
|
47
47
|
import {
|
|
48
48
|
archiveConversation,
|
|
@@ -732,6 +732,9 @@ async function handleRetryLastAssistantTurn({
|
|
|
732
732
|
if (!discarded) {
|
|
733
733
|
throw new UnprocessableEntityError("No user message to retry from");
|
|
734
734
|
}
|
|
735
|
+
bestEffortModeSessionTracking("conversation wait invalidation", () =>
|
|
736
|
+
conversation.modeSessions.invalidateAllStructuralWaits(),
|
|
737
|
+
);
|
|
735
738
|
} catch (err) {
|
|
736
739
|
if (conversation.abortController === abortController) {
|
|
737
740
|
conversation.abortController = null;
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
createUserMessage,
|
|
19
19
|
} from "../../agent/message-types.js";
|
|
20
20
|
import type { AssistantEvent } from "../../api/index.js";
|
|
21
|
+
import { ModeSessionDescriptorSchema } from "../../api/mode-session.js";
|
|
21
22
|
import {
|
|
22
23
|
BackgroundToolCompletionSchema,
|
|
23
24
|
type ConversationContentBlock,
|
|
@@ -44,10 +45,8 @@ import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-fl
|
|
|
44
45
|
import { getUserSelectableProfilesForProvider } from "../../config/default-profile-catalog.js";
|
|
45
46
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
46
47
|
import { getConfig } from "../../config/loader.js";
|
|
47
|
-
import {
|
|
48
|
-
|
|
49
|
-
mergeToolResultsIntoAssistantMessages,
|
|
50
|
-
} from "../../conversations/message-consolidation.js";
|
|
48
|
+
import { isModeSessionRecoveryHealthy } from "../../config/session-groups-gate.js";
|
|
49
|
+
import { consolidateMessageRows } from "../../conversations/message-consolidation.js";
|
|
51
50
|
import { resolveTurnCommitWaitMs } from "../../daemon/abort-watchdog.js";
|
|
52
51
|
import { createApprovalConversationGenerator } from "../../daemon/approval-generators.js";
|
|
53
52
|
import type { Conversation } from "../../daemon/conversation.js";
|
|
@@ -140,6 +139,7 @@ import {
|
|
|
140
139
|
getConversationByKey,
|
|
141
140
|
getOrCreateConversation,
|
|
142
141
|
} from "../../persistence/conversation-key-store.js";
|
|
142
|
+
import { listConversationModeSessionsByIds } from "../../persistence/conversation-mode-sessions.js";
|
|
143
143
|
import { searchConversations } from "../../persistence/conversation-queries.js";
|
|
144
144
|
import {
|
|
145
145
|
computerUseScreenshotAttachmentIdsFromMetadata,
|
|
@@ -147,6 +147,10 @@ import {
|
|
|
147
147
|
messageMetadataIsAmbientSightKeep,
|
|
148
148
|
} from "../../persistence/conversation-types.js";
|
|
149
149
|
import { linkRequestLogsToMessage } from "../../persistence/llm-request-log-store.js";
|
|
150
|
+
import {
|
|
151
|
+
mergeMessageMetadata,
|
|
152
|
+
readModeSessionMetadata,
|
|
153
|
+
} from "../../persistence/message-metadata.js";
|
|
150
154
|
import { assistantTextVisibilityOf } from "../../persistence/user-facing-content.js";
|
|
151
155
|
import { MEMORY_RETROSPECTIVE_FORK_SOURCE } from "../../plugins/defaults/memory/memory-retrospective-constants.js";
|
|
152
156
|
import { normalizeOnboardingContext } from "../../prompts/normalize-onboarding.js";
|
|
@@ -881,10 +885,31 @@ function displayRowFilter(conversationId: string): (m: MessageRow) => boolean {
|
|
|
881
885
|
function consolidateDisplayTurns(rows: MessageRow[]): {
|
|
882
886
|
messages: MessageRow[];
|
|
883
887
|
mergedIdMap: Map<string, string[]>;
|
|
888
|
+
modeSessionActivityMap: Map<string, { firstAt: number; lastAt: number }>;
|
|
884
889
|
} {
|
|
885
|
-
return
|
|
886
|
-
|
|
887
|
-
|
|
890
|
+
return consolidateMessageRows(rows);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
const MAX_REQUESTED_MODE_SESSION_IDS = 100;
|
|
894
|
+
const MAX_MODE_SESSION_ID_LENGTH = 200;
|
|
895
|
+
|
|
896
|
+
function parseRequestedModeSessionIds(raw: unknown): string[] {
|
|
897
|
+
if (raw === undefined) {
|
|
898
|
+
return [];
|
|
899
|
+
}
|
|
900
|
+
if (typeof raw !== "string") {
|
|
901
|
+
throw new BadRequestError(
|
|
902
|
+
"modeSessionIds must be a comma-separated string",
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
const ids = [...new Set(raw.split(",").map((id) => id.trim()))];
|
|
906
|
+
if (
|
|
907
|
+
ids.length > MAX_REQUESTED_MODE_SESSION_IDS ||
|
|
908
|
+
ids.some((id) => id.length === 0 || id.length > MAX_MODE_SESSION_ID_LENGTH)
|
|
909
|
+
) {
|
|
910
|
+
throw new BadRequestError("modeSessionIds contains an invalid session ID");
|
|
911
|
+
}
|
|
912
|
+
return ids;
|
|
888
913
|
}
|
|
889
914
|
|
|
890
915
|
export async function handleListMessages({
|
|
@@ -920,6 +945,9 @@ export async function handleListMessages({
|
|
|
920
945
|
const beforeTimestampRaw = queryParams?.beforeTimestamp;
|
|
921
946
|
const limitRaw = queryParams?.limit;
|
|
922
947
|
const pageRaw = queryParams?.page;
|
|
948
|
+
const requestedModeSessionIds = parseRequestedModeSessionIds(
|
|
949
|
+
queryParams?.modeSessionIds,
|
|
950
|
+
);
|
|
923
951
|
|
|
924
952
|
// Validate: reject NaN values with 400
|
|
925
953
|
if (beforeTimestampRaw != null && isNaN(Number(beforeTimestampRaw))) {
|
|
@@ -1023,8 +1051,47 @@ export async function handleListMessages({
|
|
|
1023
1051
|
// consolidation is deferred to compaction for prefix-cache stability.
|
|
1024
1052
|
// Merge here at query time so renderHistoryContent produces the same
|
|
1025
1053
|
// contentOrder shape as streaming (consecutive tool refs grouped together).
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1054
|
+
const pageModeSessionIds = rawMessages.flatMap((message) => {
|
|
1055
|
+
const owner = readModeSessionMetadata(message.metadata);
|
|
1056
|
+
return owner ? [owner.id] : [];
|
|
1057
|
+
});
|
|
1058
|
+
const summaries = listConversationModeSessionsByIds(resolvedConversationId, [
|
|
1059
|
+
...new Set([...pageModeSessionIds, ...requestedModeSessionIds]),
|
|
1060
|
+
]);
|
|
1061
|
+
const validOwners = new Map(
|
|
1062
|
+
summaries.map((summary) => [summary.id, summary.mode]),
|
|
1063
|
+
);
|
|
1064
|
+
const projectionMessages = rawMessages.map((message) => {
|
|
1065
|
+
const owner = readModeSessionMetadata(message.metadata);
|
|
1066
|
+
if (!owner || validOwners.get(owner.id) === owner.mode) {
|
|
1067
|
+
return message;
|
|
1068
|
+
}
|
|
1069
|
+
return {
|
|
1070
|
+
...message,
|
|
1071
|
+
metadata: mergeMessageMetadata(message.metadata, {
|
|
1072
|
+
modeSession: undefined,
|
|
1073
|
+
}),
|
|
1074
|
+
};
|
|
1075
|
+
});
|
|
1076
|
+
const {
|
|
1077
|
+
messages: consolidatedMessages,
|
|
1078
|
+
mergedIdMap,
|
|
1079
|
+
modeSessionActivityMap,
|
|
1080
|
+
} = consolidateDisplayTurns(projectionMessages);
|
|
1081
|
+
const liveConversation = findConversation(resolvedConversationId);
|
|
1082
|
+
const modeSessions = summaries
|
|
1083
|
+
.filter(
|
|
1084
|
+
(summary) =>
|
|
1085
|
+
isModeSessionRecoveryHealthy() || summary.status !== "active",
|
|
1086
|
+
)
|
|
1087
|
+
.flatMap((summary) => {
|
|
1088
|
+
const descriptor = liveConversation?.modeSessions
|
|
1089
|
+
? liveConversation.modeSessions.describeSummary(summary)
|
|
1090
|
+
: summary.status !== "active"
|
|
1091
|
+
? { summary }
|
|
1092
|
+
: undefined;
|
|
1093
|
+
return descriptor ? [descriptor] : [];
|
|
1094
|
+
});
|
|
1028
1095
|
const assistantSlackDisplayName = getAssistantName()?.trim() || undefined;
|
|
1029
1096
|
|
|
1030
1097
|
// Parse each row's stored content and per-message metadata. Rendering is
|
|
@@ -1152,6 +1219,7 @@ export async function handleListMessages({
|
|
|
1152
1219
|
deletedAt,
|
|
1153
1220
|
clientMessageId: msg.clientMessageId ?? undefined,
|
|
1154
1221
|
assistantTextVisibility: assistantTextVisibilityOf(msg.metadata),
|
|
1222
|
+
modeSession: readModeSessionMetadata(msg.metadata),
|
|
1155
1223
|
// The row's raw stored envelope, carried to the render pass below so it
|
|
1156
1224
|
// can read the row's own `assistantTextVisibility` marker. Never part of
|
|
1157
1225
|
// the wire payload, which the serializer builds field by field.
|
|
@@ -1172,6 +1240,9 @@ export async function handleListMessages({
|
|
|
1172
1240
|
const messages: RuntimeMessagePayload[] = await Promise.all(
|
|
1173
1241
|
parsed.map(async (m) => {
|
|
1174
1242
|
const mergedMessageIds = m.id ? (mergedIdMap.get(m.id) ?? []) : [];
|
|
1243
|
+
const modeSessionActivity = m.id
|
|
1244
|
+
? modeSessionActivityMap.get(m.id)
|
|
1245
|
+
: undefined;
|
|
1175
1246
|
|
|
1176
1247
|
// Hydrate the row's attachments from the DB. A metadata-only query avoids
|
|
1177
1248
|
// loading large base64 blobs for non-image attachments (documents, audio);
|
|
@@ -1183,26 +1254,18 @@ export async function handleListMessages({
|
|
|
1183
1254
|
if (m.id) {
|
|
1184
1255
|
const idsToQuery = [m.id, ...mergedMessageIds];
|
|
1185
1256
|
const linkedRows = getAttachmentMetadataForMessages(idsToQuery);
|
|
1186
|
-
const
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1257
|
+
const computerUseScreenshotIds = new Set(
|
|
1258
|
+
linkedRows.flatMap((row) =>
|
|
1259
|
+
computerUseScreenshotAttachmentIdsFromMetadata(
|
|
1260
|
+
parseMessageMetadata(row.messageMetadata),
|
|
1261
|
+
),
|
|
1262
|
+
),
|
|
1263
|
+
);
|
|
1190
1264
|
const linked = linkedRows.map((row) => {
|
|
1191
|
-
let screenshotIds = computerUseScreenshotIdsByMessage.get(
|
|
1192
|
-
row.messageId,
|
|
1193
|
-
);
|
|
1194
|
-
if (!screenshotIds) {
|
|
1195
|
-
screenshotIds = new Set(
|
|
1196
|
-
computerUseScreenshotAttachmentIdsFromMetadata(
|
|
1197
|
-
parseMessageMetadata(row.messageMetadata),
|
|
1198
|
-
),
|
|
1199
|
-
);
|
|
1200
|
-
computerUseScreenshotIdsByMessage.set(row.messageId, screenshotIds);
|
|
1201
|
-
}
|
|
1202
1265
|
return {
|
|
1203
1266
|
...row.attachment,
|
|
1204
1267
|
computerUseScreenshot:
|
|
1205
|
-
|
|
1268
|
+
computerUseScreenshotIds.has(row.attachment.id) || undefined,
|
|
1206
1269
|
};
|
|
1207
1270
|
});
|
|
1208
1271
|
if (linked.length > 0) {
|
|
@@ -1358,6 +1421,8 @@ export async function handleListMessages({
|
|
|
1358
1421
|
return {
|
|
1359
1422
|
id: m.id ?? "",
|
|
1360
1423
|
...(mergedMessageIds.length > 0 ? { mergedMessageIds } : {}),
|
|
1424
|
+
...(m.modeSession ? { modeSession: m.modeSession } : {}),
|
|
1425
|
+
...(modeSessionActivity ? { modeSessionActivity } : {}),
|
|
1361
1426
|
...(m.clientMessageId ? { clientMessageId: m.clientMessageId } : {}),
|
|
1362
1427
|
role: m.role,
|
|
1363
1428
|
timestamp: new Date(displayTimestamp).toISOString(),
|
|
@@ -1447,6 +1512,7 @@ export async function handleListMessages({
|
|
|
1447
1512
|
oldestMessageId: oldestMessageId ?? null,
|
|
1448
1513
|
seq: persistedSeq,
|
|
1449
1514
|
processing,
|
|
1515
|
+
...(modeSessions.length > 0 ? { modeSessions } : {}),
|
|
1450
1516
|
};
|
|
1451
1517
|
}
|
|
1452
1518
|
|
|
@@ -1457,10 +1523,16 @@ export async function handleListMessages({
|
|
|
1457
1523
|
...(oldestMessageId != null ? { oldestMessageId } : {}),
|
|
1458
1524
|
seq: persistedSeq,
|
|
1459
1525
|
processing,
|
|
1526
|
+
...(modeSessions.length > 0 ? { modeSessions } : {}),
|
|
1460
1527
|
};
|
|
1461
1528
|
}
|
|
1462
1529
|
|
|
1463
|
-
return {
|
|
1530
|
+
return {
|
|
1531
|
+
messages,
|
|
1532
|
+
seq: persistedSeq,
|
|
1533
|
+
processing,
|
|
1534
|
+
...(modeSessions.length > 0 ? { modeSessions } : {}),
|
|
1535
|
+
};
|
|
1464
1536
|
}
|
|
1465
1537
|
|
|
1466
1538
|
/**
|
|
@@ -2192,7 +2264,7 @@ export async function handleSendMessage(
|
|
|
2192
2264
|
publishConversationMessagesChanged(conversationId, originClientId);
|
|
2193
2265
|
},
|
|
2194
2266
|
afterRelease: () => {
|
|
2195
|
-
conversation.warmPromptCache();
|
|
2267
|
+
void conversation.warmPromptCache();
|
|
2196
2268
|
},
|
|
2197
2269
|
});
|
|
2198
2270
|
|
|
@@ -3052,6 +3124,7 @@ export async function handleSendMessage(
|
|
|
3052
3124
|
messageId,
|
|
3053
3125
|
requestId,
|
|
3054
3126
|
clientMessageId,
|
|
3127
|
+
modeSession: conversation.modeSessions.getTurnOwner(requestId),
|
|
3055
3128
|
});
|
|
3056
3129
|
// The row this echo announces was durably persisted above, so advance
|
|
3057
3130
|
// the snapshot↔stream anchor to the echo's seq (stamped inline by
|
|
@@ -3676,6 +3749,13 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
3676
3749
|
required: false,
|
|
3677
3750
|
description: "Maximum number of messages to return.",
|
|
3678
3751
|
},
|
|
3752
|
+
{
|
|
3753
|
+
name: "modeSessionIds",
|
|
3754
|
+
type: "string",
|
|
3755
|
+
required: false,
|
|
3756
|
+
description:
|
|
3757
|
+
"Comma-separated mode-session IDs to include with summaries for loaded active groups outside this page.",
|
|
3758
|
+
},
|
|
3679
3759
|
],
|
|
3680
3760
|
responseBody: z.object({
|
|
3681
3761
|
messages: z
|
|
@@ -3710,6 +3790,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
3710
3790
|
.describe(
|
|
3711
3791
|
"Whether the agent is currently mid-turn for this conversation, sourced authoritatively from the persisted `processing_started_at` column. `true` means a turn is in flight; `false` means the conversation is idle. Clients use this to recover from a dropped SSE stream: if a turn appears to be running locally but the server reports `processing: false`, the turn has ended (or died) and the UI should stop waiting rather than spin indefinitely. Absent on older daemons that predate this field.",
|
|
3712
3792
|
),
|
|
3793
|
+
modeSessions: z
|
|
3794
|
+
.array(ModeSessionDescriptorSchema)
|
|
3795
|
+
.optional()
|
|
3796
|
+
.describe(
|
|
3797
|
+
"Conversation-owned mode-session summaries referenced by this page or explicitly requested by ID.",
|
|
3798
|
+
),
|
|
3713
3799
|
}),
|
|
3714
3800
|
handler: (args) => handleListMessages(args),
|
|
3715
3801
|
},
|
|
@@ -177,13 +177,14 @@ async function handleCredentialPrompt({ body = {} }: RouteHandlerArgs) {
|
|
|
177
177
|
expiresAt: result.collectionExpiresAt,
|
|
178
178
|
service: validated.service,
|
|
179
179
|
field: validated.field,
|
|
180
|
-
message:
|
|
180
|
+
message: `${validated.conversationId ? "This channel does not support secure input." : "No conversation is attached to this invocation, so no secure prompt can be shown."} The credential has NOT been stored yet. Share this one-time link with the user to collect it securely (single-use${expiresInMinutes ? `, expires in ${expiresInMinutes} minutes` : ""}): ${result.collectionUrl}`,
|
|
181
181
|
};
|
|
182
182
|
}
|
|
183
183
|
return {
|
|
184
184
|
ok: false,
|
|
185
|
-
error:
|
|
186
|
-
"This conversation's channel does not support secure credential entry"
|
|
185
|
+
error: validated.conversationId
|
|
186
|
+
? "This conversation's channel does not support secure credential entry"
|
|
187
|
+
: "No conversation is attached to this invocation, so no secure prompt can be shown, and a one-time collection link could not be created. Ask the user to add the credential in the app under Settings > Credentials. Never ask them to paste it into chat.",
|
|
187
188
|
};
|
|
188
189
|
}
|
|
189
190
|
// An explicit user cancel is a valid flow, not a failure. Keep it distinct
|
|
@@ -607,8 +607,7 @@ async function handleCredentialsDelete({ body }: RouteHandlerArgs) {
|
|
|
607
607
|
}
|
|
608
608
|
|
|
609
609
|
async function handleCredentialsStatus() {
|
|
610
|
-
|
|
611
|
-
return info;
|
|
610
|
+
return getActiveBackendInfoAsync();
|
|
612
611
|
}
|
|
613
612
|
|
|
614
613
|
// ---------------------------------------------------------------------------
|
|
@@ -9,25 +9,22 @@ import {
|
|
|
9
9
|
} from "bun:test";
|
|
10
10
|
|
|
11
11
|
import { setOverridesForTesting } from "../../__tests__/feature-flag-test-helpers.js";
|
|
12
|
-
import {
|
|
12
|
+
import { desktopDependencies } from "../../desktop/desktop-dependencies.js";
|
|
13
13
|
import { ROUTES } from "./desktop-setup-routes.js";
|
|
14
14
|
import { NotFoundError } from "./errors.js";
|
|
15
15
|
|
|
16
16
|
const originalContainerized = process.env.IS_CONTAINERIZED;
|
|
17
17
|
const originalPlatform = process.env.IS_PLATFORM;
|
|
18
|
-
const status = spyOn(
|
|
19
|
-
const start = spyOn(desktopDependencyInstaller, "start");
|
|
18
|
+
const status = spyOn(desktopDependencies, "getStatus");
|
|
20
19
|
|
|
21
20
|
afterAll(() => {
|
|
22
21
|
status.mockRestore();
|
|
23
|
-
start.mockRestore();
|
|
24
22
|
});
|
|
25
23
|
|
|
26
24
|
beforeEach(() => {
|
|
27
25
|
process.env.IS_CONTAINERIZED = "true";
|
|
28
26
|
process.env.IS_PLATFORM = "true";
|
|
29
|
-
status.mockReturnValue({ state: "
|
|
30
|
-
start.mockReturnValue({ state: "installing", stage: "packages" });
|
|
27
|
+
status.mockReturnValue({ state: "ready" });
|
|
31
28
|
});
|
|
32
29
|
|
|
33
30
|
afterEach(() => {
|
|
@@ -43,7 +40,6 @@ afterEach(() => {
|
|
|
43
40
|
}
|
|
44
41
|
setOverridesForTesting({});
|
|
45
42
|
status.mockClear();
|
|
46
|
-
start.mockClear();
|
|
47
43
|
});
|
|
48
44
|
|
|
49
45
|
describe("desktop setup route feature gate", () => {
|
|
@@ -55,7 +51,6 @@ describe("desktop setup route feature gate", () => {
|
|
|
55
51
|
);
|
|
56
52
|
expect(() => route.handler({})).toThrow(NotFoundError);
|
|
57
53
|
expect(status).not.toHaveBeenCalled();
|
|
58
|
-
expect(start).not.toHaveBeenCalled();
|
|
59
54
|
});
|
|
60
55
|
}
|
|
61
56
|
|
|
@@ -64,26 +59,22 @@ describe("desktop setup route feature gate", () => {
|
|
|
64
59
|
setOverridesForTesting({ "assistant-desktop": true });
|
|
65
60
|
expect(() => route.handler({})).toThrow(NotFoundError);
|
|
66
61
|
expect(status).not.toHaveBeenCalled();
|
|
67
|
-
expect(start).not.toHaveBeenCalled();
|
|
68
62
|
});
|
|
69
63
|
|
|
70
|
-
test(`${route.method} rejects self-hosted Docker assistants without inspecting
|
|
64
|
+
test(`${route.method} rejects self-hosted Docker assistants without inspecting dependencies`, () => {
|
|
71
65
|
process.env.IS_PLATFORM = "false";
|
|
72
66
|
setOverridesForTesting({ "assistant-desktop": true });
|
|
73
67
|
expect(() => route.handler({})).toThrow(NotFoundError);
|
|
74
68
|
expect(status).not.toHaveBeenCalled();
|
|
75
|
-
expect(start).not.toHaveBeenCalled();
|
|
76
69
|
});
|
|
77
70
|
|
|
78
71
|
test(`${route.method} serves setup only for enabled platform containers`, () => {
|
|
79
72
|
setOverridesForTesting({ "assistant-desktop": true });
|
|
80
|
-
expect(route.handler({})).toEqual(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
);
|
|
85
|
-
expect(route.method === "GET" ? status : start).toHaveBeenCalledTimes(1);
|
|
86
|
-
expect(route.method === "GET" ? start : status).not.toHaveBeenCalled();
|
|
73
|
+
expect(route.handler({})).toEqual({
|
|
74
|
+
state: "ready",
|
|
75
|
+
automationActive: false,
|
|
76
|
+
});
|
|
77
|
+
expect(status).toHaveBeenCalledTimes(1);
|
|
87
78
|
});
|
|
88
79
|
}
|
|
89
80
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
3
|
import { desktopAutomationLease } from "../../desktop/desktop-automation-lease.js";
|
|
4
|
-
import {
|
|
4
|
+
import { desktopDependencies } from "../../desktop/desktop-dependencies.js";
|
|
5
5
|
import { isVirtualDesktopEnabled } from "../../desktop/virtual-desktop-feature.js";
|
|
6
6
|
import { GATEWAY_PRINCIPALS } from "../auth/route-policy.js";
|
|
7
7
|
import { NotFoundError } from "./errors.js";
|
|
@@ -13,6 +13,7 @@ const statusSchema = z.object({
|
|
|
13
13
|
stage: z.enum(["packages", "chrome", "checking"]).optional(),
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
+
// POST and its wire schema support released clients; both methods only read readiness.
|
|
16
17
|
export const ROUTES: RouteDefinition[] = ["GET", "POST"].map((method) => ({
|
|
17
18
|
operationId:
|
|
18
19
|
method === "GET" ? "desktop_setup_status" : "desktop_setup_install",
|
|
@@ -25,16 +26,13 @@ export const ROUTES: RouteDefinition[] = ["GET", "POST"].map((method) => ({
|
|
|
25
26
|
"Virtual desktop is available only on enabled platform-hosted assistants",
|
|
26
27
|
);
|
|
27
28
|
}
|
|
28
|
-
const status =
|
|
29
|
-
method === "GET"
|
|
30
|
-
? desktopDependencyInstaller.getStatus()
|
|
31
|
-
: desktopDependencyInstaller.start();
|
|
29
|
+
const status = desktopDependencies.getStatus();
|
|
32
30
|
return { ...status, automationActive: desktopAutomationLease.isActive };
|
|
33
31
|
},
|
|
34
32
|
summary:
|
|
35
33
|
method === "GET"
|
|
36
34
|
? "Get virtual desktop setup status"
|
|
37
|
-
: "
|
|
35
|
+
: "Check virtual desktop readiness (legacy POST)",
|
|
38
36
|
tags: ["desktop"],
|
|
39
37
|
responseBody: statusSchema,
|
|
40
38
|
}));
|
|
@@ -8,10 +8,13 @@ import { z } from "zod";
|
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
addDocumentConversation,
|
|
11
|
+
createDocument,
|
|
12
|
+
DEFAULT_DOCUMENT_TITLE,
|
|
11
13
|
getDocumentById,
|
|
12
14
|
getDocumentsForConversation,
|
|
13
15
|
saveDocument,
|
|
14
16
|
} from "../../documents/document-store.js";
|
|
17
|
+
import { getConversation } from "../../persistence/conversation-crud.js";
|
|
15
18
|
import { rawAll } from "../../persistence/raw-query.js";
|
|
16
19
|
import { getLogger } from "../../util/logger.js";
|
|
17
20
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
@@ -214,6 +217,54 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
214
217
|
},
|
|
215
218
|
},
|
|
216
219
|
|
|
220
|
+
{
|
|
221
|
+
operationId: "createDocument",
|
|
222
|
+
endpoint: "documents/create",
|
|
223
|
+
method: "POST",
|
|
224
|
+
policy: {
|
|
225
|
+
requiredScopes: ["settings.write"],
|
|
226
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
227
|
+
},
|
|
228
|
+
summary: "Create a document",
|
|
229
|
+
description:
|
|
230
|
+
"Create an empty document owned by a conversation and return it with its new surface ID.",
|
|
231
|
+
tags: ["documents"],
|
|
232
|
+
requestBody: z.object({
|
|
233
|
+
conversationId: z.string().describe("Owning conversation"),
|
|
234
|
+
title: z
|
|
235
|
+
.string()
|
|
236
|
+
.optional()
|
|
237
|
+
.describe(`Document title. Defaults to "${DEFAULT_DOCUMENT_TITLE}".`),
|
|
238
|
+
}),
|
|
239
|
+
responseBody: documentPayloadSchema,
|
|
240
|
+
handler: ({ body, headers }) => {
|
|
241
|
+
const { conversationId, title } = (body ?? {}) as {
|
|
242
|
+
conversationId?: string;
|
|
243
|
+
title?: string;
|
|
244
|
+
};
|
|
245
|
+
if (!conversationId || typeof conversationId !== "string") {
|
|
246
|
+
throw new BadRequestError("conversationId is required");
|
|
247
|
+
}
|
|
248
|
+
if (title !== undefined && typeof title !== "string") {
|
|
249
|
+
throw new BadRequestError("title must be a string");
|
|
250
|
+
}
|
|
251
|
+
if (!getConversation(conversationId)) {
|
|
252
|
+
throw new NotFoundError("Conversation not found");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const result = createDocument({ conversationId, title: title?.trim() });
|
|
256
|
+
if (!result.success) {
|
|
257
|
+
throw new InternalError(result.error);
|
|
258
|
+
}
|
|
259
|
+
const doc = getDocumentById(result.surfaceId);
|
|
260
|
+
if (!doc) {
|
|
261
|
+
throw new InternalError("Created document could not be read back");
|
|
262
|
+
}
|
|
263
|
+
publishDocumentsChanged(getOriginClientId(headers));
|
|
264
|
+
return { success: true, ...doc };
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
|
|
217
268
|
{
|
|
218
269
|
operationId: "linkDocumentConversation",
|
|
219
270
|
endpoint: "documents/:id/conversations",
|
|
@@ -169,7 +169,7 @@ async function handleEmailStatus(_args: RouteHandlerArgs) {
|
|
|
169
169
|
);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
return (await statusResponse.json()) as {
|
|
173
173
|
address: string;
|
|
174
174
|
status: string;
|
|
175
175
|
created_at: string;
|
|
@@ -181,8 +181,6 @@ async function handleEmailStatus(_args: RouteHandlerArgs) {
|
|
|
181
181
|
received_this_month: number;
|
|
182
182
|
};
|
|
183
183
|
};
|
|
184
|
-
|
|
185
|
-
return statusData;
|
|
186
184
|
}
|
|
187
185
|
|
|
188
186
|
async function handleEmailList({ queryParams = {} }: RouteHandlerArgs) {
|
|
@@ -239,8 +237,7 @@ async function handleEmailDownload({ queryParams = {} }: RouteHandlerArgs) {
|
|
|
239
237
|
throw new RouteError(String(detail), "DOWNLOAD_FAILED", response.status);
|
|
240
238
|
}
|
|
241
239
|
|
|
242
|
-
|
|
243
|
-
return msg;
|
|
240
|
+
return response.json();
|
|
244
241
|
}
|
|
245
242
|
|
|
246
243
|
async function handleEmailSend({ body = {} }: RouteHandlerArgs) {
|
|
@@ -323,11 +320,10 @@ async function handleEmailSend({ body = {} }: RouteHandlerArgs) {
|
|
|
323
320
|
throw new BadRequestError(String(detail));
|
|
324
321
|
}
|
|
325
322
|
|
|
326
|
-
|
|
323
|
+
return (await response.json()) as {
|
|
327
324
|
delivery_id: string;
|
|
328
325
|
status: string;
|
|
329
326
|
};
|
|
330
|
-
return data;
|
|
331
327
|
}
|
|
332
328
|
|
|
333
329
|
// ── Attachment handlers ───────────────────────────────────────────────
|