@vellumai/assistant 0.8.7 → 0.8.8-dev.202606052332.17fc8ea
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/Dockerfile +20 -4
- package/bun.lock +2 -2
- package/docker-entrypoint.sh +4 -2
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/examples/plugins/echo/README.md +61 -66
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +3378 -335
- package/package.json +2 -2
- package/scripts/generate-openapi.ts +68 -41
- package/src/__tests__/agent-loop-exit-reason.test.ts +35 -93
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +37 -87
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -3
- package/src/__tests__/anthropic-provider.test.ts +95 -2
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
- package/src/__tests__/btw-routes.test.ts +62 -3
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/catalog-files.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/clawhub-files.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction.benchmark.test.ts +0 -30
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -5
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -7
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +316 -1143
- package/src/__tests__/conversation-agent-loop.test.ts +638 -1655
- package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-history-web-search.test.ts +11 -1
- package/src/__tests__/conversation-pairing.test.ts +4 -31
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -10
- package/src/__tests__/conversation-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
- package/src/__tests__/conversation-runtime-assembly.test.ts +310 -300
- package/src/__tests__/conversation-runtime-workspace.test.ts +105 -45
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +6 -1
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
- package/src/__tests__/conversation-sync-tags.test.ts +27 -15
- package/src/__tests__/conversation-title-service.test.ts +135 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +17 -16
- package/src/__tests__/conversation-workspace-injection.test.ts +67 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +7 -6
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/cross-provider-web-search.test.ts +214 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
- package/src/__tests__/dm-persistence.test.ts +5 -1
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -0
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/identity-intro-cache.test.ts +12 -100
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
- package/src/__tests__/injector-background-turn.test.ts +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +75 -41
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +31 -37
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/list-messages-page-latest.test.ts +60 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
- package/src/__tests__/llm-usage-store.test.ts +223 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/native-web-search.test.ts +191 -0
- package/src/__tests__/onboarding-template-contract.test.ts +2 -0
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +31 -1
- package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -284
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-api-shim.test.ts +3 -6
- package/src/__tests__/plugin-bootstrap.test.ts +14 -40
- package/src/__tests__/plugin-registry.test.ts +3 -76
- package/src/__tests__/plugin-types.test.ts +0 -193
- package/src/__tests__/process-message-display-content.test.ts +6 -2
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
- package/src/__tests__/schedule-routes.test.ts +603 -2
- package/src/__tests__/schedule-store.test.ts +41 -0
- package/src/__tests__/schedule-tools.test.ts +35 -0
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/skillssh-files.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +20 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +6 -1
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/voice-session-bridge.test.ts +6 -3
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +196 -0
- package/src/acp/auto-install.ts +177 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +83 -29
- package/src/acp/resolve-agent.test.ts +320 -7
- package/src/acp/resolve-agent.ts +182 -18
- package/src/acp/resume-hint.ts +25 -0
- package/src/acp/session-manager.ts +495 -73
- package/src/acp/types.ts +8 -0
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +362 -485
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/index.ts +48 -13
- package/src/api/responses/conversation-message.ts +374 -0
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/avatar/__tests__/avatar-store.test.ts +34 -29
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/notifications.ts +112 -60
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/assistant-feature-flags.ts +22 -11
- package/src/config/bundled-skills/acp/SKILL.md +83 -31
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -398
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +48 -7
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-v2.ts +8 -0
- package/src/config/schemas/memory-v3.ts +8 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +1 -1
- package/src/context/strip-injections.ts +128 -0
- package/src/context/token-estimator.ts +23 -0
- package/src/context/tool-result-truncation.ts +0 -23
- package/src/context/window-manager.ts +5 -7
- package/src/credential-execution/executable-discovery.ts +16 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +2 -2
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +594 -153
- package/src/daemon/conversation-agent-loop.ts +301 -997
- package/src/daemon/conversation-history.ts +5 -4
- package/src/daemon/conversation-lifecycle.ts +3 -4
- package/src/daemon/conversation-messaging.ts +7 -6
- package/src/daemon/conversation-process.ts +11 -16
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +218 -398
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +222 -4
- package/src/daemon/conversation-tool-setup.ts +2 -29
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +32 -20
- package/src/daemon/external-plugins-bootstrap.ts +17 -18
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/shared.ts +156 -84
- package/src/daemon/handlers/skills.ts +42 -10
- package/src/daemon/lifecycle.ts +25 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/messages.ts +9 -57
- package/src/daemon/message-types/skills.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +136 -3
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +1 -3
- package/src/daemon/server.ts +2 -0
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +19 -0
- package/src/daemon/wake-target-adapter.ts +3 -1
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/home/home-greeting-cache.ts +24 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +6 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/conversation-graph-memory.ts +65 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs-store.ts +33 -0
- package/src/memory/jobs-worker.ts +32 -5
- package/src/memory/llm-usage-store.ts +224 -50
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +16 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -4
- package/src/memory/v2/consolidation-job.ts +14 -5
- package/src/notifications/conversation-pairing.ts +8 -15
- package/src/notifications/decision-engine.ts +6 -3
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/permissions/prompter.ts +4 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +7 -5
- package/src/plugin-api/types.ts +151 -1
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +8 -19
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/register.ts +8 -13
- package/src/plugins/defaults/index.ts +2 -18
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +288 -81
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +16 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +48 -12
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +104 -32
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +96 -30
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +34 -16
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +26 -14
- package/src/plugins/defaults/{llm-call → memory-v3-shadow}/package.json +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +3 -3
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +51 -45
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +61 -46
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +69 -99
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +8 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +1 -1
- package/src/plugins/defaults/title-generate/register.ts +18 -18
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +1 -1
- package/src/plugins/defaults/tool-error/register.ts +9 -21
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +6 -305
- package/src/plugins/registry.ts +10 -55
- package/src/plugins/types.ts +62 -797
- package/src/plugins/user-loader.ts +30 -127
- package/src/proactive-artifact/aux-message-injector.ts +4 -4
- package/src/proactive-artifact/job.test.ts +8 -13
- package/src/prompts/__tests__/system-prompt.test.ts +42 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +15 -0
- package/src/providers/anthropic/client.ts +37 -29
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -0
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/runtime/__tests__/agent-wake.test.ts +10 -6
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +2 -5
- package/src/runtime/assistant-event-hub.ts +37 -7
- package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/http-router.ts +16 -21
- package/src/runtime/http-types.ts +16 -70
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/app-management-routes.ts +6 -117
- package/src/runtime/routes/app-routes.ts +13 -15
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/attachment-routes.ts +26 -15
- package/src/runtime/routes/avatar-routes.ts +26 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/btw-routes.ts +29 -23
- package/src/runtime/routes/consolidation-routes.ts +120 -20
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +3 -1
- package/src/runtime/routes/conversation-routes.ts +372 -185
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/documents-routes.ts +4 -0
- package/src/runtime/routes/domain-routes.ts +51 -37
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +28 -34
- package/src/runtime/routes/gateway-log-routes.ts +26 -4
- package/src/runtime/routes/heartbeat-routes.ts +32 -12
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-intro-cache.ts +11 -34
- package/src/runtime/routes/identity-routes.ts +224 -18
- package/src/runtime/routes/image-generation-routes.ts +40 -2
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/a2a.ts +12 -10
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +4 -0
- package/src/runtime/routes/integrations/slack/share.ts +27 -6
- package/src/runtime/routes/integrations/telegram.ts +6 -0
- package/src/runtime/routes/integrations/twilio.ts +42 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/log-export-routes.ts +8 -0
- package/src/runtime/routes/memory-v2-routes.ts +15 -8
- package/src/runtime/routes/memory-v3-routes.ts +66 -34
- package/src/runtime/routes/oauth-apps.ts +66 -12
- package/src/runtime/routes/oauth-providers.ts +44 -5
- package/src/runtime/routes/platform-routes.ts +81 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
- package/src/runtime/routes/playground/force-compact.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/rename-conversation-routes.ts +5 -0
- package/src/runtime/routes/schedule-routes.ts +152 -42
- package/src/runtime/routes/secret-routes.ts +14 -2
- package/src/runtime/routes/skills-routes.ts +43 -14
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trust-rules-routes.ts +26 -2
- package/src/runtime/routes/tts-routes.ts +35 -0
- package/src/runtime/routes/types.ts +66 -8
- package/src/runtime/routes/usage-routes.ts +47 -39
- package/src/runtime/routes/webhook-routes.ts +41 -2
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +4 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
- package/src/runtime/services/analyze-conversation.ts +2 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/schedule/schedule-store.ts +20 -1
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +12 -5
- package/src/signals/cancel.ts +2 -4
- package/src/skills/catalog-files.ts +2 -2
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -2
- package/src/skills/skillssh-files.ts +1 -2
- package/src/subagent/manager.ts +17 -5
- package/src/telemetry/types.ts +29 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
- package/src/telemetry/usage-telemetry-reporter.ts +57 -2
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +158 -55
- package/src/tools/acp/spawn.ts +47 -72
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/executor.ts +1 -53
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +11 -3
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +207 -48
- package/src/tools/schedule/create.ts +2 -0
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/ui-surface/definitions.ts +34 -5
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/util/mutex.ts +47 -0
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/docs/plugins.md +0 -836
- package/examples/plugins/echo/register.ts +0 -184
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/empty-response-pipeline.test.ts +0 -423
- package/src/__tests__/llm-call-pipeline.test.ts +0 -287
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -503
- package/src/__tests__/pipeline-runner.test.ts +0 -564
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/home/feature-gate.ts +0 -22
- package/src/memory/v3/provider-blocks.ts +0 -16
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
- package/src/plugins/defaults/empty-response/terminal.ts +0 -106
- package/src/plugins/defaults/injectors/package.json +0 -15
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
- package/src/plugins/defaults/llm-call/register.ts +0 -45
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
- package/src/plugins/defaults/memory-retrieval/package.json +0 -15
- package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/persistence/middlewares/persistence.ts +0 -19
- package/src/plugins/defaults/persistence/package.json +0 -15
- package/src/plugins/defaults/persistence/register.ts +0 -38
- package/src/plugins/defaults/persistence/terminal.ts +0 -83
- package/src/plugins/defaults/title-generate/terminal.ts +0 -31
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
- package/src/plugins/defaults/token-estimate/package.json +0 -15
- package/src/plugins/defaults/token-estimate/register.ts +0 -34
- package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
- package/src/plugins/defaults/tool-error/terminal.ts +0 -47
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
- package/src/plugins/defaults/tool-execute/package.json +0 -15
- package/src/plugins/defaults/tool-execute/register.ts +0 -49
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
- package/src/skills/category-inference.ts +0 -111
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
|
@@ -11,6 +11,7 @@ import { z } from "zod";
|
|
|
11
11
|
import {
|
|
12
12
|
checkpointKey,
|
|
13
13
|
CK_ITEM_COUNT,
|
|
14
|
+
CK_LAST_ATTEMPT_AT,
|
|
14
15
|
CK_LAST_GEN_AT,
|
|
15
16
|
countActiveMemoryNodes,
|
|
16
17
|
getCheckpointValue,
|
|
@@ -42,10 +43,11 @@ const starterItemSchema = z.object({
|
|
|
42
43
|
|
|
43
44
|
type StarterItem = z.infer<typeof starterItemSchema>;
|
|
44
45
|
|
|
45
|
-
export const CONVERSATION_STARTERS_STALE_TTL_MS =
|
|
46
|
+
export const CONVERSATION_STARTERS_STALE_TTL_MS = 4 * 60 * 60 * 1000;
|
|
46
47
|
|
|
47
|
-
/** Minimum interval between re-enqueue attempts
|
|
48
|
-
|
|
48
|
+
/** Minimum interval between re-enqueue attempts (prevents tight retry loops
|
|
49
|
+
* when generation repeatedly fails or produces 0 valid starters). */
|
|
50
|
+
const REFRESH_COOLDOWN_MS = 5 * 60 * 1000;
|
|
49
51
|
|
|
50
52
|
function hasActiveConversationStarterJob(
|
|
51
53
|
db: ReturnType<typeof getDb>,
|
|
@@ -199,12 +201,16 @@ function handleListConversationStarters({
|
|
|
199
201
|
Date.now() - lastGenAt >= CONVERSATION_STARTERS_STALE_TTL_MS;
|
|
200
202
|
const checkpointAhead = lastCount != null && totalActive < lastCount;
|
|
201
203
|
let hasActiveJob = hasActiveConversationStarterJob(db, scopeId);
|
|
204
|
+
const lastAttemptAt = parseCheckpointInt(
|
|
205
|
+
getCheckpointValue(checkpointKey(CK_LAST_ATTEMPT_AT, scopeId)),
|
|
206
|
+
);
|
|
202
207
|
const withinCooldown =
|
|
203
|
-
|
|
208
|
+
lastAttemptAt != null && Date.now() - lastAttemptAt < REFRESH_COOLDOWN_MS;
|
|
204
209
|
const shouldRefresh =
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
210
|
+
!withinCooldown &&
|
|
211
|
+
(staleByAge ||
|
|
212
|
+
checkpointAhead ||
|
|
213
|
+
(invalidItemCount > 0 && totalActive > 0));
|
|
208
214
|
|
|
209
215
|
if (shouldRefresh && !hasActiveJob && isMemoryEnabled()) {
|
|
210
216
|
enqueueMemoryJob("generate_conversation_starters", { scopeId });
|
|
@@ -46,7 +46,10 @@ interface ImportPayload {
|
|
|
46
46
|
|
|
47
47
|
// -- Helpers (ported from CLI) --
|
|
48
48
|
|
|
49
|
-
function resolveTimestamps(
|
|
49
|
+
function resolveTimestamps(
|
|
50
|
+
conv: ImportConversation,
|
|
51
|
+
messages: ImportMessage[],
|
|
52
|
+
): {
|
|
50
53
|
convCreatedAt: number;
|
|
51
54
|
convUpdatedAt: number;
|
|
52
55
|
messageTimestamps: number[];
|
|
@@ -54,13 +57,23 @@ function resolveTimestamps(conv: ImportConversation): {
|
|
|
54
57
|
const now = Date.now();
|
|
55
58
|
const convCreatedAt = conv.createdAt ?? now;
|
|
56
59
|
const convUpdatedAt = conv.updatedAt ?? conv.createdAt ?? now;
|
|
57
|
-
const messageTimestamps =
|
|
60
|
+
const messageTimestamps = messages.map((msg, i) => {
|
|
58
61
|
if (msg.createdAt != null) return msg.createdAt;
|
|
59
62
|
return convCreatedAt + i;
|
|
60
63
|
});
|
|
61
64
|
return { convCreatedAt, convUpdatedAt, messageTimestamps };
|
|
62
65
|
}
|
|
63
66
|
|
|
67
|
+
/**
|
|
68
|
+
* The messages store is UI-facing (`ConversationMessage`), so only renderable
|
|
69
|
+
* turns are persisted. Non-renderable roles (e.g. agent-context `system`
|
|
70
|
+
* rows an export might carry) are dropped here rather than imported — the
|
|
71
|
+
* import still succeeds with the displayable turns.
|
|
72
|
+
*/
|
|
73
|
+
function isRenderableRole(role: string): role is "user" | "assistant" {
|
|
74
|
+
return role === "user" || role === "assistant";
|
|
75
|
+
}
|
|
76
|
+
|
|
64
77
|
// -- Handler --
|
|
65
78
|
|
|
66
79
|
async function handleConversationsImport({ body }: RouteHandlerArgs) {
|
|
@@ -99,12 +112,16 @@ async function handleConversationsImport({ body }: RouteHandlerArgs) {
|
|
|
99
112
|
}
|
|
100
113
|
}
|
|
101
114
|
|
|
115
|
+
const messages = conv.messages.filter((msg) =>
|
|
116
|
+
isRenderableRole(msg.role),
|
|
117
|
+
);
|
|
118
|
+
|
|
102
119
|
const { convCreatedAt, convUpdatedAt, messageTimestamps } =
|
|
103
|
-
resolveTimestamps(conv);
|
|
120
|
+
resolveTimestamps(conv, messages);
|
|
104
121
|
|
|
105
122
|
const conversation = createConversation(conv.title);
|
|
106
123
|
|
|
107
|
-
for (const msg of
|
|
124
|
+
for (const msg of messages) {
|
|
108
125
|
const contentStr =
|
|
109
126
|
typeof msg.content === "string"
|
|
110
127
|
? msg.content
|
|
@@ -144,8 +161,8 @@ async function handleConversationsImport({ body }: RouteHandlerArgs) {
|
|
|
144
161
|
}
|
|
145
162
|
|
|
146
163
|
// Index messages
|
|
147
|
-
for (let i = 0; i < dbMessages.length && i <
|
|
148
|
-
const msg =
|
|
164
|
+
for (let i = 0; i < dbMessages.length && i < messages.length; i++) {
|
|
165
|
+
const msg = messages[i];
|
|
149
166
|
const contentStr =
|
|
150
167
|
typeof msg.content === "string"
|
|
151
168
|
? msg.content
|
|
@@ -176,7 +193,7 @@ async function handleConversationsImport({ body }: RouteHandlerArgs) {
|
|
|
176
193
|
}
|
|
177
194
|
|
|
178
195
|
imported++;
|
|
179
|
-
totalMessages +=
|
|
196
|
+
totalMessages += messages.length;
|
|
180
197
|
} catch (err) {
|
|
181
198
|
errors.push({
|
|
182
199
|
index: idx,
|
|
@@ -243,6 +243,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
243
243
|
summary: "Export a document as PDF",
|
|
244
244
|
description: "Render a document to PDF and return the binary content.",
|
|
245
245
|
tags: ["documents"],
|
|
246
|
+
responseBody: {
|
|
247
|
+
contentType: "application/pdf",
|
|
248
|
+
schema: { type: "string", format: "binary" },
|
|
249
|
+
},
|
|
246
250
|
handler: async ({ pathParams }) => {
|
|
247
251
|
const doc = getDocumentById(pathParams!.id);
|
|
248
252
|
if (!doc) {
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* the subdomain to local config so getAssistantDomain() can use it.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
|
|
8
10
|
import { getApexDomain } from "../../config/env.js";
|
|
9
11
|
import {
|
|
10
12
|
loadRawConfig,
|
|
@@ -19,18 +21,36 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
|
19
21
|
|
|
20
22
|
const log = getLogger("domain-routes");
|
|
21
23
|
|
|
22
|
-
// ──
|
|
24
|
+
// ── Schemas ───────────────────────────────────────────────────────────
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
const DomainEntrySchema = z.object({
|
|
27
|
+
id: z.string(),
|
|
28
|
+
subdomain: z.string().optional(),
|
|
29
|
+
domain: z.string().optional(),
|
|
30
|
+
created_at: z.string().optional(),
|
|
31
|
+
created: z.string().optional(),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const DomainListResponseSchema = z.object({
|
|
35
|
+
count: z.number(),
|
|
36
|
+
next: z.string().nullable().optional(),
|
|
37
|
+
previous: z.string().nullable().optional(),
|
|
38
|
+
results: z.array(DomainEntrySchema),
|
|
39
|
+
});
|
|
40
|
+
type DomainListResponse = z.infer<typeof DomainListResponseSchema>;
|
|
41
|
+
|
|
42
|
+
const DomainRegisterResponseSchema = DomainEntrySchema.extend({
|
|
43
|
+
email_error: z.object({ detail: z.string(), code: z.string() }).optional(),
|
|
44
|
+
});
|
|
45
|
+
type DomainRegisterResponse = z.infer<typeof DomainRegisterResponseSchema>;
|
|
46
|
+
|
|
47
|
+
const DomainVerificationStatusResponseSchema = z.object({
|
|
48
|
+
domain: z.string(),
|
|
49
|
+
status: z.string(),
|
|
50
|
+
message: z.string(),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// ── Helpers ───────────────────────────────────────────────────────────
|
|
34
54
|
|
|
35
55
|
async function requireClient(): Promise<VellumPlatformClient> {
|
|
36
56
|
const client = await VellumPlatformClient.create();
|
|
@@ -113,20 +133,11 @@ async function handleDomainRegister({ body = {} }: RouteHandlerArgs) {
|
|
|
113
133
|
throw new BadRequestError(String(detail));
|
|
114
134
|
}
|
|
115
135
|
|
|
116
|
-
const data = (await response.json()) as
|
|
117
|
-
id: string;
|
|
118
|
-
subdomain?: string;
|
|
119
|
-
domain?: string;
|
|
120
|
-
created_at?: string;
|
|
121
|
-
created?: string;
|
|
122
|
-
email_error?: { detail: string; code: string };
|
|
123
|
-
};
|
|
136
|
+
const data = (await response.json()) as DomainRegisterResponse;
|
|
124
137
|
|
|
125
138
|
// Persist the subdomain to config so getAssistantDomain() can use it
|
|
126
139
|
const registeredSubdomain =
|
|
127
|
-
data.subdomain ??
|
|
128
|
-
data.domain?.replace(`.${apexDomain}`, "") ??
|
|
129
|
-
subdomain;
|
|
140
|
+
data.subdomain ?? data.domain?.replace(`.${apexDomain}`, "") ?? subdomain;
|
|
130
141
|
if (registeredSubdomain) {
|
|
131
142
|
const raw = loadRawConfig();
|
|
132
143
|
setNestedValue(raw, "platform.subdomain", registeredSubdomain);
|
|
@@ -146,12 +157,11 @@ async function handleDomainStatus(_args: RouteHandlerArgs) {
|
|
|
146
157
|
// Sync subdomain to config if not already cached
|
|
147
158
|
if (domains.length > 0) {
|
|
148
159
|
const first = domains[0];
|
|
149
|
-
const sub =
|
|
150
|
-
first.subdomain ?? first.domain?.replace(`.${apexDomain}`, "");
|
|
160
|
+
const sub = first.subdomain ?? first.domain?.replace(`.${apexDomain}`, "");
|
|
151
161
|
if (sub) {
|
|
152
162
|
const raw = loadRawConfig();
|
|
153
|
-
const existing = (raw as Record<string, Record<string, unknown>>)
|
|
154
|
-
|
|
163
|
+
const existing = (raw as Record<string, Record<string, unknown>>).platform
|
|
164
|
+
?.subdomain;
|
|
155
165
|
if (existing !== sub) {
|
|
156
166
|
setNestedValue(raw, "platform.subdomain", sub);
|
|
157
167
|
saveRawConfig(raw);
|
|
@@ -162,9 +172,7 @@ async function handleDomainStatus(_args: RouteHandlerArgs) {
|
|
|
162
172
|
return data;
|
|
163
173
|
}
|
|
164
174
|
|
|
165
|
-
async function handleDomainVerificationStatus({
|
|
166
|
-
body = {},
|
|
167
|
-
}: RouteHandlerArgs) {
|
|
175
|
+
async function handleDomainVerificationStatus({ body = {} }: RouteHandlerArgs) {
|
|
168
176
|
const { domain_id } = body as { domain_id?: string };
|
|
169
177
|
if (!domain_id) {
|
|
170
178
|
throw new BadRequestError("domain_id is required");
|
|
@@ -179,9 +187,7 @@ async function handleDomainVerificationStatus({
|
|
|
179
187
|
);
|
|
180
188
|
}
|
|
181
189
|
if (!results?.some((d) => d.id === domain_id)) {
|
|
182
|
-
throw new BadRequestError(
|
|
183
|
-
"domain_id is not registered for this assistant",
|
|
184
|
-
);
|
|
190
|
+
throw new BadRequestError("domain_id is not registered for this assistant");
|
|
185
191
|
}
|
|
186
192
|
|
|
187
193
|
const response = await client.fetch(
|
|
@@ -201,11 +207,9 @@ async function handleDomainVerificationStatus({
|
|
|
201
207
|
);
|
|
202
208
|
}
|
|
203
209
|
|
|
204
|
-
return (await response.json()) as
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
message: string;
|
|
208
|
-
};
|
|
210
|
+
return (await response.json()) as z.infer<
|
|
211
|
+
typeof DomainVerificationStatusResponseSchema
|
|
212
|
+
>;
|
|
209
213
|
}
|
|
210
214
|
|
|
211
215
|
// ── Route definitions ─────────────────────────────────────────────────
|
|
@@ -222,6 +226,11 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
222
226
|
handler: handleDomainRegister,
|
|
223
227
|
summary: "Register a subdomain for this assistant",
|
|
224
228
|
tags: ["domain"],
|
|
229
|
+
requestBody: z.object({
|
|
230
|
+
subdomain: z.string().optional(),
|
|
231
|
+
email_username: z.string().optional(),
|
|
232
|
+
}),
|
|
233
|
+
responseBody: DomainRegisterResponseSchema,
|
|
225
234
|
},
|
|
226
235
|
{
|
|
227
236
|
operationId: "domain_status",
|
|
@@ -234,6 +243,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
234
243
|
handler: handleDomainStatus,
|
|
235
244
|
summary: "Show domain registration and health",
|
|
236
245
|
tags: ["domain"],
|
|
246
|
+
responseBody: DomainListResponseSchema,
|
|
237
247
|
},
|
|
238
248
|
{
|
|
239
249
|
operationId: "domain_verification_status",
|
|
@@ -246,5 +256,9 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
246
256
|
handler: handleDomainVerificationStatus,
|
|
247
257
|
summary: "Get live DNS verification status for a domain",
|
|
248
258
|
tags: ["domain"],
|
|
259
|
+
requestBody: z.object({
|
|
260
|
+
domain_id: z.string(),
|
|
261
|
+
}),
|
|
262
|
+
responseBody: DomainVerificationStatusResponseSchema,
|
|
249
263
|
},
|
|
250
264
|
];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { BadRequestError } from "./errors.js";
|
|
2
|
+
|
|
3
|
+
export interface EpochMillisRange {
|
|
4
|
+
from: number;
|
|
5
|
+
to: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function parseEpochMillisRange(
|
|
9
|
+
queryParams: Record<string, string>,
|
|
10
|
+
): EpochMillisRange {
|
|
11
|
+
const fromRaw = queryParams.from;
|
|
12
|
+
const toRaw = queryParams.to;
|
|
13
|
+
|
|
14
|
+
if (!fromRaw || !toRaw) {
|
|
15
|
+
throw new BadRequestError(
|
|
16
|
+
'Missing required query parameters: "from" and "to" (epoch milliseconds)',
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const from = Number(fromRaw);
|
|
21
|
+
const to = Number(toRaw);
|
|
22
|
+
|
|
23
|
+
if (!Number.isFinite(from) || !Number.isFinite(to)) {
|
|
24
|
+
throw new BadRequestError(
|
|
25
|
+
'"from" and "to" must be valid numbers (epoch milliseconds)',
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (from > to) {
|
|
30
|
+
throw new BadRequestError('"from" must be less than or equal to "to"');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return { from, to };
|
|
34
|
+
}
|
|
@@ -39,9 +39,9 @@ import {
|
|
|
39
39
|
AssistantEventHub,
|
|
40
40
|
assistantEventHub,
|
|
41
41
|
} from "../assistant-event-hub.js";
|
|
42
|
+
import type { ReplaySubscriber } from "../assistant-stream-state.js";
|
|
43
|
+
import { getReplayWindow } from "../assistant-stream-state.js";
|
|
42
44
|
import { ACTOR_PRINCIPALS, GATEWAY_PRINCIPALS } from "../auth/route-policy.js";
|
|
43
|
-
import type { ReplaySubscriber } from "../conversation-stream-state.js";
|
|
44
|
-
import { getReplayWindow } from "../conversation-stream-state.js";
|
|
45
45
|
import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
|
|
46
46
|
import {
|
|
47
47
|
BadRequestError,
|
|
@@ -143,6 +143,12 @@ export interface SseSubscriberInstrumentation {
|
|
|
143
143
|
clientId: string | null;
|
|
144
144
|
interfaceId: string | null;
|
|
145
145
|
conversationKey: string | null;
|
|
146
|
+
/**
|
|
147
|
+
* Per-connection id assigned by the hub. Distinguishes connections
|
|
148
|
+
* sharing a `clientId` (old vs reconnected) so a shed can be attributed
|
|
149
|
+
* to a specific connection. `null` until the hub subscription is created.
|
|
150
|
+
*/
|
|
151
|
+
connectionId: string | null;
|
|
146
152
|
}
|
|
147
153
|
|
|
148
154
|
export type SseShedReason = "callback_backpressure" | "heartbeat_backpressure";
|
|
@@ -177,6 +183,7 @@ export function buildSseShedSentryContext(
|
|
|
177
183
|
heartbeats_sent: inst.heartbeatsSent,
|
|
178
184
|
client_id: inst.clientId,
|
|
179
185
|
interface_id: inst.interfaceId,
|
|
186
|
+
connection_id: inst.connectionId,
|
|
180
187
|
event_loop_delay_mean_ms: elDelay.mean_ms,
|
|
181
188
|
event_loop_delay_p99_ms: elDelay.p99_ms,
|
|
182
189
|
event_loop_delay_max_ms: elDelay.max_ms,
|
|
@@ -216,6 +223,7 @@ const defaultSseShedReporter: SseShedReporter = (reason, inst) => {
|
|
|
216
223
|
scope.setTag("sse_shed_reason", reason);
|
|
217
224
|
if (inst.clientId) scope.setTag("client_id", inst.clientId);
|
|
218
225
|
if (inst.interfaceId) scope.setTag("interface_id", inst.interfaceId);
|
|
226
|
+
if (inst.connectionId) scope.setTag("connection_id", inst.connectionId);
|
|
219
227
|
scope.setContext("sse_shed", sentryContext);
|
|
220
228
|
Sentry.captureMessage(`sse_subscriber_shed:${reason}`);
|
|
221
229
|
});
|
|
@@ -371,6 +379,7 @@ export function handleSubscribeAssistantEvents(
|
|
|
371
379
|
clientId,
|
|
372
380
|
interfaceId,
|
|
373
381
|
conversationKey: scopeConversationKey,
|
|
382
|
+
connectionId: null,
|
|
374
383
|
};
|
|
375
384
|
|
|
376
385
|
ensureEventLoopDelayMonitorStarted();
|
|
@@ -394,19 +403,6 @@ export function handleSubscribeAssistantEvents(
|
|
|
394
403
|
// replay window we just drained.
|
|
395
404
|
let highWaterReplaySeq = -1;
|
|
396
405
|
|
|
397
|
-
// Per-conversation subscriber-filtered sequence counters. Incremented
|
|
398
|
-
// for each conversation-scoped event this specific subscriber receives
|
|
399
|
-
// (after capability/client/interface targeting), producing a gap-free
|
|
400
|
-
// sequence from the subscriber's perspective. Clients use `clientSeq`
|
|
401
|
-
// for gap detection instead of the global `seq` to avoid false
|
|
402
|
-
// positives from targeted events they never receive.
|
|
403
|
-
const clientSeqCounters = new Map<string, number>();
|
|
404
|
-
function nextClientSeqFor(conversationId: string): number {
|
|
405
|
-
const next = (clientSeqCounters.get(conversationId) ?? 0) + 1;
|
|
406
|
-
clientSeqCounters.set(conversationId, next);
|
|
407
|
-
return next;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
406
|
const callback: AssistantEventCallback = (event) => {
|
|
411
407
|
const controller = controllerRef;
|
|
412
408
|
if (!controller) return;
|
|
@@ -425,11 +421,7 @@ export function handleSubscribeAssistantEvents(
|
|
|
425
421
|
cleanup();
|
|
426
422
|
return;
|
|
427
423
|
}
|
|
428
|
-
|
|
429
|
-
event.conversationId != null && event.seq != null
|
|
430
|
-
? { ...event, clientSeq: nextClientSeqFor(event.conversationId) }
|
|
431
|
-
: event;
|
|
432
|
-
controller.enqueue(encoder.encode(formatSseFrame(frame)));
|
|
424
|
+
controller.enqueue(encoder.encode(formatSseFrame(event)));
|
|
433
425
|
instrumentation.eventsDelivered += 1;
|
|
434
426
|
} catch {
|
|
435
427
|
sub.dispose();
|
|
@@ -461,6 +453,9 @@ export function handleSubscribeAssistantEvents(
|
|
|
461
453
|
...subscriberBase,
|
|
462
454
|
type: "process" as const,
|
|
463
455
|
});
|
|
456
|
+
// Stamp the hub-assigned connection id so a later backpressure shed can be
|
|
457
|
+
// tied back to this specific connection in logs and Sentry.
|
|
458
|
+
instrumentation.connectionId = sub.connectionId;
|
|
464
459
|
} catch (err) {
|
|
465
460
|
if (err instanceof RangeError) {
|
|
466
461
|
throw new ServiceUnavailableError("Too many concurrent connections");
|
|
@@ -479,16 +474,22 @@ export function handleSubscribeAssistantEvents(
|
|
|
479
474
|
return;
|
|
480
475
|
}
|
|
481
476
|
|
|
482
|
-
// Reconnect replay: when the caller passed lastSeenSeq
|
|
483
|
-
//
|
|
484
|
-
//
|
|
477
|
+
// Reconnect replay: when the caller passed lastSeenSeq, deliver
|
|
478
|
+
// any buffered events the client missed before the first
|
|
479
|
+
// heartbeat. `seq` is a single global per-assistant counter, so
|
|
480
|
+
// one cursor resumes the stream regardless of how many
|
|
481
|
+
// conversations are multiplexed on an unfiltered connection.
|
|
482
|
+
// Replay re-applies the subscriber's targeting filter; a
|
|
483
|
+
// conversation-scoped subscription additionally scopes replay to
|
|
484
|
+
// its own conversation (other conversations are never delivered
|
|
485
|
+
// live on that connection, so replaying them would be wrong).
|
|
485
486
|
//
|
|
486
487
|
// If the cursor is older than the ring's oldest entry,
|
|
487
488
|
// `getReplayWindow` returns `null`. We do not surface that to
|
|
488
489
|
// the client over the wire -- the connection just goes live.
|
|
489
490
|
// The client detects the gap from the seq jump on its first
|
|
490
491
|
// live event and refetches via the existing messages API.
|
|
491
|
-
if (lastSeenSeq != null
|
|
492
|
+
if (lastSeenSeq != null) {
|
|
492
493
|
const replaySubscriber: ReplaySubscriber =
|
|
493
494
|
clientId && interfaceId
|
|
494
495
|
? {
|
|
@@ -501,20 +502,13 @@ export function handleSubscribeAssistantEvents(
|
|
|
501
502
|
}
|
|
502
503
|
: { type: "process" };
|
|
503
504
|
const window = getReplayWindow(
|
|
504
|
-
filter.conversationId,
|
|
505
505
|
lastSeenSeq,
|
|
506
506
|
replaySubscriber,
|
|
507
|
+
filter.conversationId,
|
|
507
508
|
);
|
|
508
509
|
if (window !== null) {
|
|
509
510
|
for (const replayed of window) {
|
|
510
|
-
|
|
511
|
-
replayed.conversationId != null && replayed.seq != null
|
|
512
|
-
? {
|
|
513
|
-
...replayed,
|
|
514
|
-
clientSeq: nextClientSeqFor(replayed.conversationId),
|
|
515
|
-
}
|
|
516
|
-
: replayed;
|
|
517
|
-
controller.enqueue(encoder.encode(formatSseFrame(frame)));
|
|
511
|
+
controller.enqueue(encoder.encode(formatSseFrame(replayed)));
|
|
518
512
|
instrumentation.eventsDelivered += 1;
|
|
519
513
|
if (replayed.seq != null && replayed.seq > highWaterReplaySeq) {
|
|
520
514
|
highWaterReplaySeq = replayed.seq;
|
|
@@ -621,7 +615,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
621
615
|
{
|
|
622
616
|
name: "lastSeenSeq",
|
|
623
617
|
description:
|
|
624
|
-
"Optional reconnect cursor: the highest
|
|
618
|
+
"Optional reconnect cursor: the highest global event seq the client has already applied. `seq` is a single per-assistant counter shared across all conversations, so one cursor resumes the stream regardless of how many conversations are multiplexed on the connection. When set, the daemon replays any buffered events with seq > lastSeenSeq (re-applying the subscriber's targeting/scope filter) before going live. If the cursor is older than the ring buffer's oldest entry the connection simply goes live; the client is expected to detect the gap from the next event's seq and refetch via the messages API. Must be a non-negative integer.",
|
|
625
619
|
},
|
|
626
620
|
],
|
|
627
621
|
responseHeaders: {
|
|
@@ -35,7 +35,14 @@ async function gatewayFetch(
|
|
|
35
35
|
|
|
36
36
|
// ── Schemas ─────────────────────────────────────────────────────────────
|
|
37
37
|
|
|
38
|
-
const LEVEL_NAMES = [
|
|
38
|
+
const LEVEL_NAMES = [
|
|
39
|
+
"trace",
|
|
40
|
+
"debug",
|
|
41
|
+
"info",
|
|
42
|
+
"warn",
|
|
43
|
+
"error",
|
|
44
|
+
"fatal",
|
|
45
|
+
] as const;
|
|
39
46
|
|
|
40
47
|
const GatewayLogsTailParams = z
|
|
41
48
|
.object({
|
|
@@ -45,9 +52,18 @@ const GatewayLogsTailParams = z
|
|
|
45
52
|
})
|
|
46
53
|
.strict();
|
|
47
54
|
|
|
55
|
+
const GatewayLogsTailResponseSchema = z.object({
|
|
56
|
+
lines: z.array(z.record(z.string(), z.unknown())),
|
|
57
|
+
truncated: z.boolean(),
|
|
58
|
+
});
|
|
59
|
+
type GatewayLogsTailResponse = z.infer<typeof GatewayLogsTailResponseSchema>;
|
|
60
|
+
|
|
48
61
|
// ── Handlers ────────────────────────────────────────────────────────────
|
|
49
62
|
|
|
50
|
-
async function handleGatewayLogsTail({
|
|
63
|
+
async function handleGatewayLogsTail({
|
|
64
|
+
queryParams = {},
|
|
65
|
+
body = {},
|
|
66
|
+
}: RouteHandlerArgs): Promise<GatewayLogsTailResponse> {
|
|
51
67
|
// HTTP GET delivers filters via queryParams; CLI IPC puts them in body.
|
|
52
68
|
const source = Object.keys(queryParams).length > 0 ? queryParams : body;
|
|
53
69
|
const p = GatewayLogsTailParams.parse(source);
|
|
@@ -56,7 +72,9 @@ async function handleGatewayLogsTail({ queryParams = {}, body = {} }: RouteHandl
|
|
|
56
72
|
if (p.level !== undefined) qs.set("level", p.level);
|
|
57
73
|
if (p.module !== undefined) qs.set("module", p.module);
|
|
58
74
|
const query = qs.toString();
|
|
59
|
-
return gatewayFetch(
|
|
75
|
+
return gatewayFetch(
|
|
76
|
+
`/v1/logs/tail${query ? `?${query}` : ""}`,
|
|
77
|
+
) as Promise<GatewayLogsTailResponse>;
|
|
60
78
|
}
|
|
61
79
|
|
|
62
80
|
// ── Route definitions ───────────────────────────────────────────────────
|
|
@@ -75,8 +93,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
75
93
|
description:
|
|
76
94
|
"Return the last N structured log entries from the gateway log files.",
|
|
77
95
|
tags: ["gateway-logs"],
|
|
96
|
+
responseBody: GatewayLogsTailResponseSchema,
|
|
78
97
|
queryParams: [
|
|
79
|
-
{
|
|
98
|
+
{
|
|
99
|
+
name: "n",
|
|
100
|
+
description: "Number of lines to return (1–1000, default: 10)",
|
|
101
|
+
},
|
|
80
102
|
{ name: "level", description: "Minimum pino level name (default: info)" },
|
|
81
103
|
{ name: "module", description: "Filter to exact pino module name" },
|
|
82
104
|
],
|
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
} from "../../config/loader.js";
|
|
19
19
|
import { listHeartbeatRuns } from "../../heartbeat/heartbeat-run-store.js";
|
|
20
20
|
import { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
|
|
21
|
+
import { getConversation } from "../../memory/conversation-crud.js";
|
|
22
|
+
import { getUsageCostForConversationWindow } from "../../memory/llm-usage-store.js";
|
|
21
23
|
import { readTextFileSync } from "../../util/fs.js";
|
|
22
24
|
import { getLogger } from "../../util/logger.js";
|
|
23
25
|
import { getWorkspacePromptPath } from "../../util/platform.js";
|
|
@@ -38,19 +40,34 @@ function handleListRuns(queryParams: Record<string, string>) {
|
|
|
38
40
|
: 20;
|
|
39
41
|
|
|
40
42
|
const runs = listHeartbeatRuns(limit);
|
|
43
|
+
const now = Date.now();
|
|
41
44
|
return {
|
|
42
|
-
runs: runs.map((r) =>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
runs: runs.map((r) => {
|
|
46
|
+
const conversation = r.conversationId
|
|
47
|
+
? getConversation(r.conversationId)
|
|
48
|
+
: null;
|
|
49
|
+
return {
|
|
50
|
+
id: r.id,
|
|
51
|
+
scheduledFor: r.scheduledFor,
|
|
52
|
+
startedAt: r.startedAt,
|
|
53
|
+
finishedAt: r.finishedAt,
|
|
54
|
+
durationMs: r.durationMs,
|
|
55
|
+
status: r.status,
|
|
56
|
+
skipReason: r.skipReason,
|
|
57
|
+
error: r.error,
|
|
58
|
+
conversationId: r.conversationId,
|
|
59
|
+
conversationExists: conversation != null,
|
|
60
|
+
conversationArchivedAt: conversation?.archivedAt ?? null,
|
|
61
|
+
estimatedCostUsd: r.conversationId
|
|
62
|
+
? getUsageCostForConversationWindow({
|
|
63
|
+
conversationId: r.conversationId,
|
|
64
|
+
from: r.startedAt ?? r.scheduledFor,
|
|
65
|
+
to: r.finishedAt ?? now,
|
|
66
|
+
})
|
|
67
|
+
: 0,
|
|
68
|
+
createdAt: r.createdAt,
|
|
69
|
+
};
|
|
70
|
+
}),
|
|
54
71
|
};
|
|
55
72
|
}
|
|
56
73
|
|
|
@@ -116,6 +133,9 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
116
133
|
skipReason: z.string().nullable(),
|
|
117
134
|
error: z.string().nullable(),
|
|
118
135
|
conversationId: z.string().nullable(),
|
|
136
|
+
conversationExists: z.boolean(),
|
|
137
|
+
conversationArchivedAt: z.number().nullable(),
|
|
138
|
+
estimatedCostUsd: z.number(),
|
|
119
139
|
createdAt: z.number(),
|
|
120
140
|
}),
|
|
121
141
|
)
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { z } from "zod";
|
|
16
16
|
|
|
17
|
-
import { findConversation } from "../../daemon/conversation-
|
|
17
|
+
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
18
18
|
import type {
|
|
19
19
|
HostAppControlResultPayload,
|
|
20
20
|
HostAppControlState,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
|
-
import { findConversation } from "../../daemon/conversation-
|
|
9
|
+
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
10
10
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
11
11
|
import {
|
|
12
12
|
enforceSameActorOrThrow,
|