@vellumai/assistant 0.8.12 → 0.9.0-staging.1
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/AGENTS.md +0 -14
- package/ARCHITECTURE.md +45 -45
- package/README.md +1 -1
- package/bun.lock +200 -154
- package/docs/architecture/integrations.md +3 -3
- package/docs/architecture/memory.md +2 -2
- package/docs/architecture/security.md +10 -10
- package/docs/runbook-trusted-contacts.md +12 -12
- package/docs/skills.md +6 -6
- package/docs/workflows-testing.md +221 -0
- package/docs/workflows.md +510 -0
- package/examples/plugins/echo/README.md +5 -5
- package/knip.json +2 -0
- package/openapi.yaml +6935 -5545
- package/package.json +8 -4
- package/scripts/generate-openapi.ts +66 -114
- package/src/__tests__/access-request-seed-content-blocks.test.ts +213 -0
- package/src/__tests__/adaptive-thinking-repair.test.ts +32 -3
- package/src/__tests__/agent-loop-output-hooks.test.ts +183 -0
- package/src/__tests__/agent-loop-regrowth-guard.test.ts +506 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +77 -0
- package/src/__tests__/app-dir-path-guard.test.ts +27 -3
- package/src/__tests__/approval-cascade.test.ts +0 -5
- package/src/__tests__/approval-routes-http.test.ts +91 -0
- package/src/__tests__/assistant-stream-state.test.ts +107 -0
- package/src/__tests__/browser-fill-credential.test.ts +3 -3
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +1 -1
- package/src/__tests__/compaction-events.test.ts +63 -7
- package/src/__tests__/compaction-trail-store.test.ts +74 -1
- package/src/__tests__/compaction.benchmark.test.ts +63 -41
- package/src/__tests__/compactor-low-watermark-cut.test.ts +349 -0
- package/src/__tests__/context-window-manager-compact-retry.test.ts +64 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -5
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -5
- package/src/__tests__/conversation-history-web-search.test.ts +7 -0
- package/src/__tests__/conversation-process-callsite.test.ts +0 -5
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -5
- package/src/__tests__/conversation-queue.test.ts +0 -5
- package/src/__tests__/conversation-slash-queue.test.ts +0 -5
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -5
- package/src/__tests__/conversation-speed-override.test.ts +0 -5
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-usage.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -5
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -5
- package/src/__tests__/credential-broker-browser-fill.test.ts +2 -2
- package/src/__tests__/credential-broker-server-use.test.ts +2 -2
- package/src/__tests__/credential-broker.test.ts +1 -1
- package/src/__tests__/credential-prompt-route.test.ts +417 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault.test.ts +37 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +24 -0
- package/src/__tests__/dynamic-page-surface.test.ts +125 -0
- package/src/__tests__/empty-state-greeting-cache.test.ts +94 -0
- package/src/__tests__/gateway-flag-listener.test.ts +24 -7
- package/src/__tests__/guardian-action-sweep.test.ts +56 -219
- package/src/__tests__/guardian-routing-invariants.test.ts +138 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +99 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +87 -1
- package/src/__tests__/llm-resolver.test.ts +115 -0
- package/src/__tests__/managed-profile-guard.test.ts +6 -5
- package/src/__tests__/max-tokens-continue-hook.test.ts +184 -0
- package/src/__tests__/media-generate-image.test.ts +20 -9
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/normalize-onboarding.test.ts +26 -0
- package/src/__tests__/notification-decision-strategy.test.ts +4 -2
- package/src/__tests__/notification-telegram-adapter.test.ts +21 -3
- package/src/__tests__/pending-interactions-resolved-event.test.ts +62 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +72 -18
- package/src/__tests__/require-fresh-approval.test.ts +425 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -0
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +408 -0
- package/src/__tests__/schedule-routes.test.ts +257 -4
- package/src/__tests__/schedule-store.test.ts +60 -0
- package/src/__tests__/schedule-tools.test.ts +247 -2
- package/src/__tests__/skill-execute-input.test.ts +85 -0
- package/src/__tests__/skill-secret-handling-guard.test.ts +21 -20
- package/src/__tests__/skills.test.ts +3 -3
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +1 -1
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +547 -0
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/task-progress-nudge-hook.test.ts +372 -0
- package/src/__tests__/task-scheduler.test.ts +299 -0
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +209 -0
- package/src/__tests__/tool-result-spool.test.ts +3 -1
- package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +181 -0
- package/src/__tests__/workspace-migration-103-upgrade-quality-profile-to-opus-4-8.test.ts +174 -0
- package/src/agent/compaction-circuit.ts +11 -0
- package/src/agent/loop.ts +181 -12
- package/src/api/constants/call-sites.ts +12 -0
- package/src/api/events/assistant-thinking-delta.ts +10 -0
- package/src/api/events/usage-update.ts +7 -0
- package/src/api/index.ts +4 -1
- package/src/api/responses/memory-v3-selection-log.ts +18 -11
- package/src/approvals/approval-primitive.ts +2 -2
- package/src/background-wake/background-wake-routes.test.ts +5 -2
- package/src/bundler/compiler-tools.ts +1 -1
- package/src/calls/call-domain.ts +1 -1
- package/src/calls/guardian-action-sweep.ts +16 -93
- package/src/cli/AGENTS.md +4 -0
- package/src/cli/commands/__tests__/schedules.test.ts +430 -1
- package/src/cli/commands/credentials.ts +28 -24
- package/src/cli/commands/image-generation.ts +23 -9
- package/src/cli/commands/notifications.ts +1 -1
- package/src/cli/commands/plugins.ts +89 -46
- package/src/cli/commands/schedules.ts +384 -11
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +69 -5
- package/src/cli/lib/__tests__/install-from-github.test.ts +15 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +81 -4
- package/src/cli/lib/inspect-plugin.ts +62 -1
- package/src/cli/lib/install-from-github.ts +52 -5
- package/src/cli/lib/upgrade-plugin.ts +18 -0
- package/src/config/__tests__/workflows-schema.test.ts +60 -0
- package/src/config/bundled-skills/acp/SKILL.md +2 -2
- package/src/config/bundled-skills/image-studio/SKILL.md +66 -19
- package/src/config/bundled-skills/image-studio/TOOLS.json +1 -6
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +22 -3
- package/src/config/bundled-skills/personal-page/SKILL.md +57 -0
- package/src/config/bundled-skills/personal-page/TOOLS.json +27 -0
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +17 -0
- package/src/config/bundled-skills/schedule/SKILL.md +7 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +48 -4
- package/src/config/bundled-skills/workflows/SKILL.md +214 -0
- package/src/config/bundled-skills/workflows/TOOLS.json +84 -0
- package/src/config/bundled-skills/workflows/tools/manage-workflows.ts +12 -0
- package/src/config/bundled-skills/workflows/tools/run-workflow.ts +12 -0
- package/src/config/bundled-tool-registry.ts +14 -2
- package/src/config/call-site-defaults.ts +5 -0
- package/src/config/feature-flag-registry.json +12 -4
- package/src/config/llm-context-resolution.ts +8 -0
- package/src/config/llm-resolver.ts +30 -0
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +22 -0
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +16 -0
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +77 -0
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +57 -0
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +28 -0
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +234 -0
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +48 -0
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +16 -0
- package/src/config/preloaded-apps/personal-page/src/index.html +20 -0
- package/src/config/preloaded-apps/personal-page/src/main.tsx +7 -0
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +82 -0
- package/src/config/preloaded-apps/personal-page/src/styles.css +759 -0
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/heartbeat.ts +4 -1
- package/src/config/schemas/llm.ts +33 -26
- package/src/config/schemas/memory-retrospective.ts +19 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/services.ts +5 -2
- package/src/config/schemas/workflows.ts +42 -0
- package/src/config/skills.ts +3 -3
- package/src/context/compactor.ts +273 -39
- package/src/context/post-turn-tool-result-truncation.ts +23 -6
- package/src/context/tool-result-spool.ts +12 -17
- package/src/credential-execution/executable-discovery.ts +1 -1
- package/src/credential-execution/process-manager.ts +37 -3
- package/src/credential-execution/prompted-credential.ts +205 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +14 -0
- package/src/daemon/conversation-process.ts +11 -2
- package/src/daemon/conversation-surfaces.ts +75 -0
- package/src/daemon/conversation-tool-setup.ts +103 -26
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +115 -11
- package/src/daemon/handlers/shared.ts +26 -14
- package/src/daemon/host-cu-proxy.ts +15 -12
- package/src/daemon/host-file-proxy.ts +15 -12
- package/src/daemon/host-transfer-proxy.ts +30 -24
- package/src/daemon/lifecycle.ts +40 -3
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/messages.ts +2 -10
- package/src/daemon/message-types/workflows.ts +49 -0
- package/src/daemon/parse-actual-tokens-from-error.test.ts +62 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +43 -4
- package/src/daemon/process-message.ts +6 -0
- package/src/daemon/tool-setup-types.ts +57 -0
- package/src/daemon/wake-conversation-ops.ts +18 -0
- package/src/heartbeat/heartbeat-run-store.ts +8 -2
- package/src/home/feed-types.ts +1 -1
- package/src/ipc/gateway-flag-listener.ts +28 -6
- package/src/mcp/mcp-auth-state.ts +8 -20
- package/src/media/__tests__/image-models.test.ts +57 -0
- package/src/media/image-models.ts +66 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +38 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +12 -2
- package/src/memory/__tests__/memory-retrospective-job.test.ts +911 -34
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +227 -5
- package/src/memory/__tests__/memory-retrospective-state.test.ts +195 -0
- package/src/memory/__tests__/preloaded-apps.test.ts +85 -0
- package/src/memory/auto-analysis-enqueue.ts +14 -1
- package/src/memory/compaction-log-store-clickhouse.ts +6 -4
- package/src/memory/conversation-crud.ts +9 -2
- package/src/memory/conversation-disk-view.ts +1 -1
- package/src/memory/conversation-queries.ts +22 -7
- package/src/memory/db-init.ts +20 -0
- package/src/memory/db-maintenance.ts +16 -0
- package/src/memory/embedding-runtime-manager.ts +1 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +112 -14
- package/src/memory/llm-request-log-source-local.ts +19 -1
- package/src/memory/llm-request-log-source.ts +35 -6
- package/src/memory/llm-request-log-store.ts +90 -2
- package/src/memory/memory-retrospective-constants.ts +9 -0
- package/src/memory/memory-retrospective-enqueue.ts +3 -6
- package/src/memory/memory-retrospective-fork-boundary.ts +94 -0
- package/src/memory/memory-retrospective-job.ts +500 -208
- package/src/memory/memory-retrospective-startup-cleanup.ts +97 -19
- package/src/memory/memory-retrospective-state.ts +85 -2
- package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +40 -0
- package/src/memory/migrations/282-schedule-inference-profile.test.ts +77 -0
- package/src/memory/migrations/282-schedule-inference-profile.ts +26 -0
- package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.test.ts +102 -0
- package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.ts +53 -0
- package/src/memory/migrations/284-workflow-runs.ts +51 -0
- package/src/memory/migrations/285-schedule-workflow-mode.ts +26 -0
- package/src/memory/migrations/286-workflow-run-trust.ts +27 -0
- package/src/memory/migrations/287-conversation-origin-channel-index.ts +15 -0
- package/src/memory/migrations/288-backfill-origin-channel-from-bindings.ts +43 -0
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +115 -0
- package/src/memory/migrations/290-schedule-capabilities.test.ts +77 -0
- package/src/memory/migrations/290-schedule-capabilities.ts +25 -0
- package/src/memory/migrations/__tests__/281-memory-retrospective-remembered-log.test.ts +96 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +571 -0
- package/src/memory/migrations/index.ts +10 -0
- package/src/memory/preloaded-apps.ts +116 -0
- package/src/memory/schema/infrastructure.ts +4 -0
- package/src/memory/schema/memory-core.ts +4 -0
- package/src/memory/v2/__tests__/concept-page-frontmatter-schema.test.ts +45 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +11 -7
- package/src/memory/v2/__tests__/page-store.test.ts +13 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +24 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -6
- package/src/memory/v2/page-store.ts +4 -3
- package/src/memory/v2/qdrant.ts +42 -3
- package/src/memory/v2/types.ts +16 -10
- package/src/messaging/draft-store.ts +1 -1
- package/src/notifications/access-request-copy.ts +200 -113
- package/src/notifications/adapters/slack.ts +250 -111
- package/src/notifications/adapters/telegram.ts +7 -44
- package/src/notifications/approval-card-builder.ts +93 -0
- package/src/notifications/broadcaster.ts +74 -0
- package/src/notifications/conversation-pairing.ts +8 -6
- package/src/notifications/copy-composer.ts +32 -26
- package/src/notifications/decision-engine.ts +59 -7
- package/src/notifications/guardian-question-mode.ts +145 -155
- package/src/notifications/home-feed-side-effect.ts +1 -1
- package/src/notifications/notification-utils.ts +66 -0
- package/src/notifications/signal.ts +6 -0
- package/src/notifications/tool-approval-copy.ts +142 -0
- package/src/notifications/types.ts +19 -0
- package/src/permissions/threshold.ts +11 -0
- package/src/plugin-api/types.ts +16 -4
- package/src/plugins/defaults/compaction/window-manager.ts +44 -0
- package/src/plugins/defaults/index.ts +46 -0
- package/src/plugins/defaults/max-tokens-continue/continue-state-store.ts +53 -0
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +80 -0
- package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +20 -0
- package/src/plugins/defaults/max-tokens-continue/package.json +14 -0
- package/src/plugins/defaults/memory-retrieval/hooks/__tests__/user-prompt-submit.test.ts +37 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +29 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +8 -3
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +4 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +28 -18
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +67 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +122 -22
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +2 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +63 -1
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +61 -18
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +1 -1
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +39 -10
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +34 -1
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +112 -47
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +78 -15
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +206 -0
- package/src/plugins/defaults/task-progress-nudge/package.json +15 -0
- package/src/prompts/__tests__/system-prompt.test.ts +100 -1
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +5 -7
- package/src/prompts/normalize-onboarding.ts +2 -0
- package/src/prompts/persona-resolver.ts +3 -0
- package/src/prompts/system-prompt.ts +51 -2
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +3 -1
- package/src/prompts/templates/system-sections.ts +8 -3
- package/src/providers/call-site-routing.ts +6 -3
- package/src/providers/fireworks/client.ts +3 -0
- package/src/providers/inference/auth.ts +52 -46
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/__tests__/coerce-object-args.test.ts +105 -0
- package/src/providers/openai/chat-completions-provider.ts +47 -9
- package/src/providers/openai/coerce-object-args.ts +104 -0
- package/src/providers/retry.ts +8 -5
- package/src/providers/types.ts +10 -0
- package/src/runtime/__tests__/agent-wake.test.ts +629 -7
- package/src/runtime/access-request-helper.ts +16 -9
- package/src/runtime/agent-wake.ts +302 -51
- package/src/runtime/assistant-stream-state.ts +141 -8
- package/src/runtime/background-job-runner.ts +9 -0
- package/src/runtime/channel-approval-types.ts +1 -0
- package/src/runtime/guardian-action-message-composer.ts +0 -54
- package/src/runtime/http-server.ts +6 -14
- package/src/runtime/http-types.ts +0 -1
- package/src/runtime/message-composer-types.ts +0 -9
- package/src/runtime/middleware/__tests__/rate-limiter.test.ts +63 -0
- package/src/runtime/middleware/auth.ts +27 -3
- package/src/runtime/middleware/rate-limiter.ts +28 -1
- package/src/runtime/migrations/vbundle-builder.ts +6 -5
- package/src/runtime/pending-interactions.ts +20 -1
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +232 -173
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +18 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +436 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +11 -0
- package/src/runtime/routes/approval-routes.ts +35 -8
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -1
- package/src/runtime/routes/btw-routes.ts +37 -1
- package/src/runtime/routes/channel-route-shared.ts +3 -1
- package/src/runtime/routes/consolidation-routes.ts +17 -13
- package/src/runtime/routes/conversation-compaction-routes.ts +159 -119
- package/src/runtime/routes/conversation-list-routes.ts +41 -4
- package/src/runtime/routes/conversation-query-routes.ts +196 -11
- package/src/runtime/routes/conversation-routes.ts +15 -1
- package/src/runtime/routes/credential-prompt-routes.ts +39 -17
- package/src/runtime/routes/empty-state-greeting-cache.ts +65 -0
- package/src/runtime/routes/heartbeat-routes.ts +18 -13
- package/src/runtime/routes/image-generation-routes.ts +20 -2
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +26 -1
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/log-export/AGENTS.md +1 -1
- package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
- package/src/runtime/routes/migration-routes.ts +5 -9
- package/src/runtime/routes/plugins-routes.ts +26 -0
- package/src/runtime/routes/ps-routes.ts +10 -8
- package/src/runtime/routes/retrospective-routes.ts +235 -0
- package/src/runtime/routes/runs-pagination.ts +75 -0
- package/src/runtime/routes/schedule-routes.ts +367 -59
- package/src/runtime/routes/sounds-config-routes.ts +239 -0
- package/src/runtime/routes/surface-action-routes.ts +84 -4
- package/src/runtime/routes/workflow-routes.test.ts +372 -0
- package/src/runtime/routes/workflow-routes.ts +363 -0
- package/src/runtime/routes/workspace-routes.test.ts +61 -1
- package/src/runtime/routes/workspace-routes.ts +26 -1
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +38 -0
- package/src/runtime/services/analyze-conversation.ts +26 -13
- package/src/schedule/inference-profile.ts +28 -0
- package/src/schedule/schedule-store.ts +122 -4
- package/src/schedule/scheduler-types.ts +6 -0
- package/src/schedule/scheduler.ts +96 -0
- package/src/security/secret-allowlist.ts +1 -1
- package/src/skills/path-classifier.ts +1 -1
- package/src/tools/browser/browser-execution.ts +9 -11
- package/src/tools/credentials/broker.ts +4 -4
- package/src/tools/credentials/vault.ts +26 -137
- package/src/tools/executor.ts +69 -0
- package/src/tools/flag-gated-tools.test.ts +76 -0
- package/src/tools/permission-checker.ts +8 -1
- package/src/tools/registry.ts +51 -0
- package/src/tools/schedule/create.ts +77 -1
- package/src/tools/schedule/list.ts +1 -0
- package/src/tools/schedule/update.ts +73 -1
- package/src/tools/skills/execute.ts +56 -0
- package/src/tools/terminal/shell.ts +1 -1
- package/src/tools/ui-surface/definitions.ts +48 -2
- package/src/tools/workflows/manage-workflows.ts +183 -0
- package/src/tools/workflows/run-workflow.test.ts +442 -0
- package/src/tools/workflows/run-workflow.ts +88 -0
- package/src/types/onboarding-context.ts +2 -0
- package/src/usage/attribution.ts +24 -0
- package/src/util/canonicalize-identity.ts +12 -3
- package/src/util/platform.ts +17 -17
- package/src/watcher/__tests__/engine.test.ts +24 -0
- package/src/watcher/__tests__/telemetry.test.ts +135 -0
- package/src/watcher/engine.ts +7 -0
- package/src/watcher/telemetry.ts +74 -0
- package/src/workflows/capabilities.test.ts +365 -0
- package/src/workflows/capabilities.ts +359 -0
- package/src/workflows/deterministic-stringify.ts +27 -0
- package/src/workflows/engine-integration.test.ts +656 -0
- package/src/workflows/engine.test.ts +1144 -0
- package/src/workflows/engine.ts +1078 -0
- package/src/workflows/fanout-load.test.ts +168 -0
- package/src/workflows/journal-store.test.ts +369 -0
- package/src/workflows/journal-store.ts +470 -0
- package/src/workflows/leaf-runner.test.ts +704 -0
- package/src/workflows/leaf-runner.ts +589 -0
- package/src/workflows/library.test.ts +134 -0
- package/src/workflows/library.ts +124 -0
- package/src/workflows/run-manager.test.ts +711 -0
- package/src/workflows/run-manager.ts +593 -0
- package/src/workflows/sandbox-escape.test.ts +339 -0
- package/src/workflows/sandbox.test.ts +251 -0
- package/src/workflows/sandbox.ts +447 -0
- package/src/workspace/adaptive-thinking-repair.ts +33 -11
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +1 -1
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +1 -1
- package/src/workspace/migrations/026-backfill-install-meta.ts +1 -1
- package/src/workspace/migrations/030-seed-pkb-autoinject.ts +2 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -4
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +1 -1
- package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +5 -2
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +1 -1
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +8 -2
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +41 -14
- package/src/workspace/migrations/102-preserve-heartbeat-enabled-for-existing-workspaces.ts +69 -0
- package/src/workspace/migrations/103-upgrade-quality-profile-to-opus-4-8.ts +83 -0
- package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +133 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/migrations/runner.ts +1 -1
- package/tsconfig.json +1 -1
- package/src/__tests__/guardian-action-copy-generator.test.ts +0 -200
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -579
- package/src/__tests__/guardian-action-store.test.ts +0 -106
- package/src/daemon/guardian-action-generators.ts +0 -71
- package/src/memory/guardian-action-store.ts +0 -484
- package/src/runtime/guardian-action-grant-minter.ts +0 -150
|
@@ -110,6 +110,7 @@ import { ROUTES as PUBLISH_ROUTES } from "./publish-routes.js";
|
|
|
110
110
|
import { ROUTES as QUESTION_ROUTES } from "./question-routes.js";
|
|
111
111
|
import { ROUTES as RECORDING_ROUTES } from "./recording-routes.js";
|
|
112
112
|
import { ROUTES as RENAME_CONVERSATION_ROUTES } from "./rename-conversation-routes.js";
|
|
113
|
+
import { ROUTES as RETROSPECTIVE_ROUTES } from "./retrospective-routes.js";
|
|
113
114
|
import { ROUTES as SANITY_ROUTES } from "./sanity-routes.js";
|
|
114
115
|
import { ROUTES as SCHEDULE_ROUTES } from "./schedule-routes.js";
|
|
115
116
|
import { ROUTES as SECRET_ROUTES } from "./secret-routes.js";
|
|
@@ -117,6 +118,7 @@ import { ROUTES as SEQUENCE_ROUTES } from "./sequence-routes.js";
|
|
|
117
118
|
import { ROUTES as SETTINGS_ROUTES } from "./settings-routes.js";
|
|
118
119
|
import { ROUTES as SKILL_ROUTES } from "./skills-routes.js";
|
|
119
120
|
import { ROUTES as SLACK_CHANNEL_RESOLVE_ROUTES } from "./slack-channel-routes.js";
|
|
121
|
+
import { ROUTES as SOUNDS_CONFIG_ROUTES } from "./sounds-config-routes.js";
|
|
120
122
|
import { ROUTES as STT_ROUTES } from "./stt-routes.js";
|
|
121
123
|
import { ROUTES as SUBAGENT_ROUTES } from "./subagents-routes.js";
|
|
122
124
|
import { ROUTES as SUGGEST_TRUST_RULE_ROUTES } from "./suggest-trust-rule-routes.js";
|
|
@@ -138,6 +140,7 @@ import { ROUTES as WATCHER_ROUTES } from "./watcher-routes.js";
|
|
|
138
140
|
import { ROUTES as WEBHOOK_ROUTES } from "./webhook-routes.js";
|
|
139
141
|
import { ROUTES as WIPE_CONVERSATION_ROUTES } from "./wipe-conversation-routes.js";
|
|
140
142
|
import { ROUTES as WORK_ITEM_ROUTES } from "./work-items-routes.js";
|
|
143
|
+
import { ROUTES as WORKFLOW_ROUTES } from "./workflow-routes.js";
|
|
141
144
|
import { ROUTES as WORKSPACE_COMMIT_ROUTES } from "./workspace-commit-routes.js";
|
|
142
145
|
import { ROUTES as WORKSPACE_ROUTES } from "./workspace-routes.js";
|
|
143
146
|
|
|
@@ -238,10 +241,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
238
241
|
...QUESTION_ROUTES,
|
|
239
242
|
...RECORDING_ROUTES,
|
|
240
243
|
...RENAME_CONVERSATION_ROUTES,
|
|
244
|
+
...RETROSPECTIVE_ROUTES,
|
|
241
245
|
...SCHEDULE_ROUTES,
|
|
242
246
|
...SANITY_ROUTES,
|
|
243
247
|
...SECRET_ROUTES,
|
|
244
248
|
...SETTINGS_ROUTES,
|
|
249
|
+
...SOUNDS_CONFIG_ROUTES,
|
|
245
250
|
...SKILL_ROUTES,
|
|
246
251
|
...A2A_ROUTES,
|
|
247
252
|
...SLACK_CHANNEL_CONFIG_ROUTES,
|
|
@@ -264,6 +269,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
264
269
|
...USAGE_ROUTES,
|
|
265
270
|
...VERCEL_ROUTES,
|
|
266
271
|
...WORK_ITEM_ROUTES,
|
|
272
|
+
...WORKFLOW_ROUTES,
|
|
267
273
|
...WATCHER_ROUTES,
|
|
268
274
|
...WEBHOOK_ROUTES,
|
|
269
275
|
...WIPE_CONVERSATION_ROUTES,
|
|
@@ -5,7 +5,7 @@ from audit DB rows, daemon logs under `<workspace>/data/logs/`, and a
|
|
|
5
5
|
sanitized `config.json` snapshot. This directory
|
|
6
6
|
(`assistant/src/runtime/routes/log-export/`) houses the allowlist module
|
|
7
7
|
that governs which subpaths of the user's workspace directory
|
|
8
|
-
(
|
|
8
|
+
(`$VELLUM_WORKSPACE_DIR/`) are permitted to flow into that archive.
|
|
9
9
|
|
|
10
10
|
Workspace contents are **opt-in (allowlist), not opt-out**. The workspace
|
|
11
11
|
contains arbitrary user files — skills, hooks, routes, conversations,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `POST /v1/export` collects audit DB rows, daemon logs, and a sanitized
|
|
5
5
|
* `config.json` snapshot. This module governs which subpaths of the user's
|
|
6
|
-
* workspace directory (
|
|
6
|
+
* workspace directory (`$VELLUM_WORKSPACE_DIR/`) are *opted in* to the export
|
|
7
7
|
* archive. The default is "nothing from the workspace ships" — every entry
|
|
8
8
|
* here must be justified against the rules in `./AGENTS.md`.
|
|
9
9
|
*
|
|
@@ -359,15 +359,11 @@ export async function handleMigrationExport(
|
|
|
359
359
|
// flush on a multi-GB WAL file can otherwise stall the daemon's
|
|
360
360
|
// event loop for the full duration of the flush.
|
|
361
361
|
//
|
|
362
|
-
// FULL (not TRUNCATE):
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
// connections create a fresh WAL on disk — split-brain. FULL
|
|
368
|
-
// gives us the same flush-completion guarantee without the
|
|
369
|
-
// unlink side effect. See assistant/AGENTS.md "SQLite WAL
|
|
370
|
-
// checkpointing".
|
|
362
|
+
// FULL (not TRUNCATE): FULL blocks until every committed frame is
|
|
363
|
+
// written back to the main `.db` file, which is all the export
|
|
364
|
+
// needs since it copies that file. TRUNCATE additionally restarts
|
|
365
|
+
// the WAL and truncates it to zero bytes — extra work and blocking
|
|
366
|
+
// this path does not need.
|
|
371
367
|
const result = await runAsyncSqlite("PRAGMA wal_checkpoint(FULL)");
|
|
372
368
|
if (!result.ok) {
|
|
373
369
|
// Best-effort: if the DB can't be checkpointed (e.g. not a valid
|
|
@@ -295,6 +295,12 @@ const pluginLocalInfoSchema = z
|
|
|
295
295
|
.describe(
|
|
296
296
|
"Resolved commit the copy was installed at; null when no provenance was recorded.",
|
|
297
297
|
),
|
|
298
|
+
committedAt: z
|
|
299
|
+
.string()
|
|
300
|
+
.nullable()
|
|
301
|
+
.describe(
|
|
302
|
+
"ISO-8601 committer timestamp (UTC) of the installed commit — the human-readable version; null for installs predating commit-timestamp capture. Distinct from `installedAt`.",
|
|
303
|
+
),
|
|
298
304
|
version: z
|
|
299
305
|
.string()
|
|
300
306
|
.nullable()
|
|
@@ -342,6 +348,12 @@ const pluginRemoteInfoSchema = z
|
|
|
342
348
|
.describe(
|
|
343
349
|
"Pinned commit SHA the marketplace currently resolves installs to.",
|
|
344
350
|
),
|
|
351
|
+
committedAt: z
|
|
352
|
+
.string()
|
|
353
|
+
.nullable()
|
|
354
|
+
.describe(
|
|
355
|
+
"ISO-8601 committer timestamp (UTC) of the pinned commit, resolved from GitHub; null when the commit metadata could not be fetched.",
|
|
356
|
+
),
|
|
345
357
|
description: z.string().nullable(),
|
|
346
358
|
homepage: z.string().nullable(),
|
|
347
359
|
license: z.string().nullable(),
|
|
@@ -413,11 +425,23 @@ const pluginUpgradeResponseSchema = z.object({
|
|
|
413
425
|
.describe(
|
|
414
426
|
"Installed commit before the upgrade; null when no provenance was recorded.",
|
|
415
427
|
),
|
|
428
|
+
fromTimestamp: z
|
|
429
|
+
.string()
|
|
430
|
+
.nullable()
|
|
431
|
+
.describe(
|
|
432
|
+
"ISO-8601 committer timestamp (UTC) of `fromCommit` — the version moved from; null when not recorded.",
|
|
433
|
+
),
|
|
416
434
|
toCommit: z
|
|
417
435
|
.string()
|
|
418
436
|
.describe(
|
|
419
437
|
"Marketplace-pinned commit the install was (or would be) moved to.",
|
|
420
438
|
),
|
|
439
|
+
toTimestamp: z
|
|
440
|
+
.string()
|
|
441
|
+
.nullable()
|
|
442
|
+
.describe(
|
|
443
|
+
"ISO-8601 committer timestamp (UTC) of `toCommit` — the version moved to; null when it could not be resolved.",
|
|
444
|
+
),
|
|
421
445
|
target: z
|
|
422
446
|
.string()
|
|
423
447
|
.describe("Absolute path to the installed plugin directory on the host."),
|
|
@@ -740,7 +764,9 @@ async function handleUpgradePlugin({
|
|
|
740
764
|
name: result.name,
|
|
741
765
|
outcome: result.outcome,
|
|
742
766
|
fromCommit: result.fromCommit,
|
|
767
|
+
fromTimestamp: result.fromTimestamp,
|
|
743
768
|
toCommit: result.toCommit,
|
|
769
|
+
toTimestamp: result.toTimestamp,
|
|
744
770
|
target: result.target,
|
|
745
771
|
fileCount: result.fileCount,
|
|
746
772
|
dryRun: result.dryRun,
|
|
@@ -29,14 +29,16 @@ interface ProcessEntry {
|
|
|
29
29
|
info?: string;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const processEntrySchema: z.ZodType<ProcessEntry> = z
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
)
|
|
32
|
+
const processEntrySchema: z.ZodType<ProcessEntry> = z
|
|
33
|
+
.lazy(() =>
|
|
34
|
+
z.object({
|
|
35
|
+
name: z.string(),
|
|
36
|
+
status: z.enum(["running", "not_running", "unreachable"]),
|
|
37
|
+
children: z.array(processEntrySchema).optional(),
|
|
38
|
+
info: z.string().optional(),
|
|
39
|
+
}),
|
|
40
|
+
)
|
|
41
|
+
.meta({ id: "ProcessEntry" });
|
|
40
42
|
|
|
41
43
|
const psResponseSchema = z.object({
|
|
42
44
|
processes: z.array(processEntrySchema),
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route handlers for memory retrospective background runs.
|
|
3
|
+
*
|
|
4
|
+
* Retrospectives are per-conversation background passes that review recent
|
|
5
|
+
* activity in a source conversation and persist durable memories. They are
|
|
6
|
+
* event-driven — enqueued by per-conversation triggers (time/message-count
|
|
7
|
+
* thresholds after activity, pre-compaction) via
|
|
8
|
+
* `maybeEnqueueMemoryRetrospective` in `memory/memory-retrospective-enqueue.ts`
|
|
9
|
+
* — never globally scheduled, so there is no run-now endpoint and `nextRunAt`
|
|
10
|
+
* is always null. These routes only surface config and run history for the
|
|
11
|
+
* Settings UI.
|
|
12
|
+
*
|
|
13
|
+
* `available` gates on `memory.enabled` alone (matching `isMemoryEnabled` in
|
|
14
|
+
* the enqueue path). Retrospectives do NOT depend on `memory.v2.enabled`.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
|
|
19
|
+
import { getConfig } from "../../config/loader.js";
|
|
20
|
+
import type { ConversationRow } from "../../memory/conversation-crud.js";
|
|
21
|
+
import {
|
|
22
|
+
getMessageRoleStatsByConversation,
|
|
23
|
+
listConversationsBySource,
|
|
24
|
+
} from "../../memory/conversation-queries.js";
|
|
25
|
+
import { isMemoryEnabled } from "../../memory/jobs-store.js";
|
|
26
|
+
import { getUsageCostForConversationWindow } from "../../memory/llm-usage-store.js";
|
|
27
|
+
import {
|
|
28
|
+
MEMORY_RETROSPECTIVE_FORK_SOURCE,
|
|
29
|
+
MEMORY_RETROSPECTIVE_SOURCE,
|
|
30
|
+
} from "../../memory/memory-retrospective-constants.js";
|
|
31
|
+
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
32
|
+
import {
|
|
33
|
+
paginateRuns,
|
|
34
|
+
parseRunsBeforeCursor,
|
|
35
|
+
parseRunsLimit,
|
|
36
|
+
RUNS_NEXT_CURSOR_SCHEMA,
|
|
37
|
+
RUNS_PAGINATION_QUERY_PARAMS,
|
|
38
|
+
} from "./runs-pagination.js";
|
|
39
|
+
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
40
|
+
|
|
41
|
+
type RetrospectiveKind = "legacy" | "fork";
|
|
42
|
+
|
|
43
|
+
const SOURCE_KINDS: ReadonlyArray<{
|
|
44
|
+
source: string;
|
|
45
|
+
kind: RetrospectiveKind;
|
|
46
|
+
}> = [
|
|
47
|
+
{ source: MEMORY_RETROSPECTIVE_SOURCE, kind: "legacy" },
|
|
48
|
+
{ source: MEMORY_RETROSPECTIVE_FORK_SOURCE, kind: "fork" },
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Fetch the most recent retrospective conversations across BOTH source
|
|
53
|
+
* sentinels (legacy + fork), newest first. Fetches `limit` rows from each
|
|
54
|
+
* source before merging so the merged top-N is correct regardless of how
|
|
55
|
+
* runs are distributed across kinds. The same `before` cursor applies to
|
|
56
|
+
* each source query, so paging never skips rows from either kind.
|
|
57
|
+
*/
|
|
58
|
+
function listRetrospectiveConversations(
|
|
59
|
+
limit: number,
|
|
60
|
+
before?: number,
|
|
61
|
+
): Array<{ row: ConversationRow; kind: RetrospectiveKind }> {
|
|
62
|
+
const merged = SOURCE_KINDS.flatMap(({ source, kind }) =>
|
|
63
|
+
listConversationsBySource(source, limit, {
|
|
64
|
+
beforeCreatedAt: before,
|
|
65
|
+
}).map((row) => ({ row, kind })),
|
|
66
|
+
);
|
|
67
|
+
merged.sort((a, b) => b.row.createdAt - a.row.createdAt);
|
|
68
|
+
return merged.slice(0, limit);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function readRetrospectiveConfigResponse() {
|
|
72
|
+
const config = getConfig();
|
|
73
|
+
const available = isMemoryEnabled();
|
|
74
|
+
const enabled = available;
|
|
75
|
+
const intervalMs = config.memory.retrospective.timeThresholdMs;
|
|
76
|
+
// Retrospectives have no global schedule — runs are triggered per
|
|
77
|
+
// conversation after activity, so a future run time is never known.
|
|
78
|
+
const nextRunAt = null;
|
|
79
|
+
const lastRunAt = listRetrospectiveConversations(1)[0]?.row.createdAt ?? null;
|
|
80
|
+
return {
|
|
81
|
+
available,
|
|
82
|
+
enabled,
|
|
83
|
+
intervalMs,
|
|
84
|
+
nextRunAt,
|
|
85
|
+
lastRunAt,
|
|
86
|
+
success: true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
// Shared ROUTES
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
export const ROUTES: RouteDefinition[] = [
|
|
95
|
+
{
|
|
96
|
+
operationId: "getRetrospectiveConfig",
|
|
97
|
+
endpoint: "retrospective/config",
|
|
98
|
+
method: "GET",
|
|
99
|
+
policy: {
|
|
100
|
+
requiredScopes: ["settings.read"],
|
|
101
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
102
|
+
},
|
|
103
|
+
summary: "Get memory retrospective config",
|
|
104
|
+
description:
|
|
105
|
+
"Return the memory retrospective configuration. Retrospectives are " +
|
|
106
|
+
"event-driven background passes triggered per conversation after " +
|
|
107
|
+
"activity (time/message thresholds, pre-compaction) — there is no " +
|
|
108
|
+
"global schedule, so `nextRunAt` is always null and no run-now " +
|
|
109
|
+
"endpoint exists. `intervalMs` is the per-conversation time threshold " +
|
|
110
|
+
"(`memory.retrospective.timeThresholdMs`), `lastRunAt` is the " +
|
|
111
|
+
"`createdAt` of the most recent retrospective conversation across " +
|
|
112
|
+
"both legacy and fork sources, and `available` gates on " +
|
|
113
|
+
"`memory.enabled` (not `memory.v2.enabled`).",
|
|
114
|
+
tags: ["retrospective"],
|
|
115
|
+
responseBody: z.object({
|
|
116
|
+
available: z.boolean(),
|
|
117
|
+
enabled: z.boolean(),
|
|
118
|
+
intervalMs: z.number(),
|
|
119
|
+
nextRunAt: z.number().nullable(),
|
|
120
|
+
lastRunAt: z.number().nullable(),
|
|
121
|
+
success: z.boolean(),
|
|
122
|
+
}),
|
|
123
|
+
handler: async (_args: RouteHandlerArgs) => {
|
|
124
|
+
return readRetrospectiveConfigResponse();
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
operationId: "listRetrospectiveRuns",
|
|
129
|
+
endpoint: "retrospective/runs",
|
|
130
|
+
method: "GET",
|
|
131
|
+
policy: {
|
|
132
|
+
requiredScopes: ["settings.read"],
|
|
133
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
134
|
+
},
|
|
135
|
+
summary: "List memory retrospective runs",
|
|
136
|
+
description:
|
|
137
|
+
"Return recent memory retrospective conversations as run records, " +
|
|
138
|
+
"merged across both sources (`memory-retrospective` → kind `legacy`, " +
|
|
139
|
+
"`memory-retrospective-fork` → kind `fork`) and sorted newest first. " +
|
|
140
|
+
"Each retrospective dispatch creates exactly one background " +
|
|
141
|
+
"conversation; that conversation IS the run. Shape mirrors " +
|
|
142
|
+
"`consolidation/runs` (synthetic `id`/`scheduledFor`/`startedAt` from " +
|
|
143
|
+
"the conversation row, `finishedAt`/`status` from assistant-message " +
|
|
144
|
+
"presence, `skipReason`/`error` always null) plus `kind` and `title` " +
|
|
145
|
+
"(fork runs are titled '<source title> (Retrospective)', which " +
|
|
146
|
+
"identifies what was reviewed). For fork runs, copied source messages " +
|
|
147
|
+
"keep their original timestamps, so only assistant messages at or " +
|
|
148
|
+
"after the fork's creation count as agent output. NOTE: superseded " +
|
|
149
|
+
"runs are garbage-collected by default " +
|
|
150
|
+
"(`memory.retrospective.keepSupersededRuns: false` deletes the prior " +
|
|
151
|
+
"run when a newer one succeeds), so this lists what currently exists " +
|
|
152
|
+
"— typically the most recent run per source conversation unless the " +
|
|
153
|
+
"operator retains history.",
|
|
154
|
+
tags: ["retrospective"],
|
|
155
|
+
queryParams: RUNS_PAGINATION_QUERY_PARAMS(20),
|
|
156
|
+
responseBody: z.object({
|
|
157
|
+
runs: z
|
|
158
|
+
.array(
|
|
159
|
+
z.object({
|
|
160
|
+
id: z.string(),
|
|
161
|
+
scheduledFor: z.number(),
|
|
162
|
+
startedAt: z.number().nullable(),
|
|
163
|
+
finishedAt: z.number().nullable(),
|
|
164
|
+
durationMs: z.number().nullable(),
|
|
165
|
+
status: z.enum(["ok", "running"]),
|
|
166
|
+
skipReason: z.string().nullable(),
|
|
167
|
+
error: z.string().nullable(),
|
|
168
|
+
conversationId: z.string().nullable(),
|
|
169
|
+
conversationExists: z.boolean(),
|
|
170
|
+
conversationArchivedAt: z.number().nullable(),
|
|
171
|
+
estimatedCostUsd: z.number(),
|
|
172
|
+
createdAt: z.number(),
|
|
173
|
+
kind: z.enum(["legacy", "fork"]),
|
|
174
|
+
title: z.string().nullable(),
|
|
175
|
+
}),
|
|
176
|
+
)
|
|
177
|
+
.describe("Retrospective run records"),
|
|
178
|
+
nextCursor: RUNS_NEXT_CURSOR_SCHEMA,
|
|
179
|
+
}),
|
|
180
|
+
handler: async ({ queryParams }: RouteHandlerArgs) => {
|
|
181
|
+
const params = queryParams ?? {};
|
|
182
|
+
const limit = parseRunsLimit(params, 20);
|
|
183
|
+
const before = parseRunsBeforeCursor(params);
|
|
184
|
+
const { rows, nextCursor } = paginateRuns(
|
|
185
|
+
listRetrospectiveConversations(limit + 1, before),
|
|
186
|
+
limit,
|
|
187
|
+
(r) => r.row.createdAt,
|
|
188
|
+
);
|
|
189
|
+
const assistantStats = getMessageRoleStatsByConversation(
|
|
190
|
+
rows.map((r) => r.row.id),
|
|
191
|
+
"assistant",
|
|
192
|
+
);
|
|
193
|
+
const now = Date.now();
|
|
194
|
+
return {
|
|
195
|
+
nextCursor,
|
|
196
|
+
runs: rows.map(({ row: c, kind }) => {
|
|
197
|
+
const stat = assistantStats.get(c.id);
|
|
198
|
+
// Fork-based retrospectives copy the source conversation's
|
|
199
|
+
// messages with their ORIGINAL timestamps, so assistant messages
|
|
200
|
+
// can predate the fork row's createdAt. Only an assistant message
|
|
201
|
+
// at-or-after the conversation's creation is evidence the
|
|
202
|
+
// retrospective agent itself emitted output — without this guard
|
|
203
|
+
// an in-flight fork run would read "ok" with a negative duration.
|
|
204
|
+
const hasAssistantOutput = stat != null && stat.lastAt >= c.createdAt;
|
|
205
|
+
const finishedAt = hasAssistantOutput ? stat.lastAt : null;
|
|
206
|
+
const estimatedCostUsd =
|
|
207
|
+
c.totalEstimatedCost > 0
|
|
208
|
+
? c.totalEstimatedCost
|
|
209
|
+
: getUsageCostForConversationWindow({
|
|
210
|
+
conversationId: c.id,
|
|
211
|
+
from: c.createdAt,
|
|
212
|
+
to: finishedAt ?? now,
|
|
213
|
+
});
|
|
214
|
+
return {
|
|
215
|
+
id: c.id,
|
|
216
|
+
scheduledFor: c.createdAt,
|
|
217
|
+
startedAt: c.createdAt,
|
|
218
|
+
finishedAt,
|
|
219
|
+
durationMs: finishedAt != null ? finishedAt - c.createdAt : null,
|
|
220
|
+
status: (hasAssistantOutput ? "ok" : "running") as "ok" | "running",
|
|
221
|
+
skipReason: null,
|
|
222
|
+
error: null,
|
|
223
|
+
conversationId: c.id,
|
|
224
|
+
conversationExists: true,
|
|
225
|
+
conversationArchivedAt: c.archivedAt,
|
|
226
|
+
estimatedCostUsd,
|
|
227
|
+
createdAt: c.createdAt,
|
|
228
|
+
kind,
|
|
229
|
+
title: c.title ?? null,
|
|
230
|
+
};
|
|
231
|
+
}),
|
|
232
|
+
};
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
];
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared cursor-pagination helpers for run-history routes
|
|
3
|
+
* (`heartbeat/runs`, `consolidation/runs`, `schedules/:id/runs`).
|
|
4
|
+
*
|
|
5
|
+
* Pages are keyed by each route's epoch-millis sort column. Clients pass the
|
|
6
|
+
* previous page's `nextCursor` back as `before` to fetch strictly older rows;
|
|
7
|
+
* a null `nextCursor` means the history is exhausted.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
12
|
+
import type { RouteQueryParam } from "./types.js";
|
|
13
|
+
|
|
14
|
+
/** Parse the optional `before` cursor query param (epoch millis). */
|
|
15
|
+
export function parseRunsBeforeCursor(
|
|
16
|
+
queryParams: Record<string, string>,
|
|
17
|
+
): number | undefined {
|
|
18
|
+
const raw = Number(queryParams.before);
|
|
19
|
+
return Number.isFinite(raw) ? raw : undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Parse and clamp the `limit` query param to 1..100. */
|
|
23
|
+
export function parseRunsLimit(
|
|
24
|
+
queryParams: Record<string, string>,
|
|
25
|
+
defaultLimit: number,
|
|
26
|
+
): number {
|
|
27
|
+
const raw = Number(queryParams.limit ?? defaultLimit);
|
|
28
|
+
return Number.isFinite(raw)
|
|
29
|
+
? Math.min(Math.max(Math.floor(raw), 1), 100)
|
|
30
|
+
: defaultLimit;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Slice a `limit + 1`-sized fetch down to the page and derive `nextCursor`
|
|
35
|
+
* from the last returned row's sort key (null when no older rows remain).
|
|
36
|
+
*/
|
|
37
|
+
export function paginateRuns<T>(
|
|
38
|
+
rows: T[],
|
|
39
|
+
limit: number,
|
|
40
|
+
cursorOf: (row: T) => number,
|
|
41
|
+
): { rows: T[]; nextCursor: number | null } {
|
|
42
|
+
const hasMore = rows.length > limit;
|
|
43
|
+
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
44
|
+
return {
|
|
45
|
+
rows: page,
|
|
46
|
+
nextCursor: hasMore ? cursorOf(page[page.length - 1]) : null,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Shared `nextCursor` response field for the paginated run-list routes. */
|
|
51
|
+
export const RUNS_NEXT_CURSOR_SCHEMA = z
|
|
52
|
+
.number()
|
|
53
|
+
.nullable()
|
|
54
|
+
.describe(
|
|
55
|
+
"Cursor for fetching older runs (pass as `before`); null when no " +
|
|
56
|
+
"older runs exist",
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
/** OpenAPI query-param entries shared by the paginated run-list routes. */
|
|
60
|
+
export const RUNS_PAGINATION_QUERY_PARAMS = (
|
|
61
|
+
defaultLimit: number,
|
|
62
|
+
): RouteQueryParam[] => [
|
|
63
|
+
{
|
|
64
|
+
name: "limit",
|
|
65
|
+
schema: { type: "integer" },
|
|
66
|
+
description: `Max runs to return (default ${defaultLimit}, max 100)`,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "before",
|
|
70
|
+
schema: { type: "integer" },
|
|
71
|
+
description:
|
|
72
|
+
"Cursor for older runs: pass the previous page's `nextCursor` to " +
|
|
73
|
+
"return runs strictly older than it.",
|
|
74
|
+
},
|
|
75
|
+
];
|