@vellumai/assistant 0.8.12 → 0.9.0-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +105 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +12 -0
- package/openapi.yaml +7197 -5708
- 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-compiler.test.ts +7 -1
- package/src/__tests__/app-dir-path-guard.test.ts +27 -3
- package/src/__tests__/app-executors.test.ts +43 -0
- 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-data-persist.test.ts +97 -0
- 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 +219 -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__/mock-gateway-ipc.ts +23 -0
- 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__/resolve-app-id.test.ts +56 -0
- 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/bundler/package-resolver.ts +0 -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/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +6 -1
- package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +7 -1
- package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +7 -1
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +10 -1
- 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 +167 -3
- 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 +28 -11
- 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/channel-invite-transports/telegram.ts +6 -5
- package/src/runtime/channel-invite-transports/voice.ts +2 -2
- package/src/runtime/channel-invite-types.ts +4 -2
- package/src/runtime/channel-retry-sweep.ts +19 -41
- package/src/runtime/finalize-event-delivery.ts +72 -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-delivery-routes.ts +11 -7
- package/src/runtime/routes/channel-route-definitions.ts +3 -0
- 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-message-handler.ts +13 -12
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +32 -31
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +7 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +7 -21
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +6 -15
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +1 -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 +152 -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/apps/executors.ts +23 -0
- package/src/tools/apps/resolve-app-id.ts +42 -0
- 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 +91 -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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { and, count, desc, eq, inArray, isNull, sql } from "drizzle-orm";
|
|
1
|
+
import { and, count, desc, eq, inArray, isNull, lt, sql } from "drizzle-orm";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
parseExternalContentEnvelope,
|
|
@@ -166,13 +166,17 @@ export function listConversations(
|
|
|
166
166
|
conversationType: ConversationType = "standard",
|
|
167
167
|
offset = 0,
|
|
168
168
|
archiveStatus: ArchiveStatusFilter = "active",
|
|
169
|
+
originChannel?: string,
|
|
169
170
|
): ConversationRow[] {
|
|
170
171
|
ensureDisplayOrderMigration();
|
|
171
172
|
ensureGroupMigration();
|
|
172
173
|
const db = getDb();
|
|
173
174
|
const typeCond = conversationTypeClause(conversationType);
|
|
174
175
|
const archiveCond = archiveStatusClause(archiveStatus);
|
|
175
|
-
const
|
|
176
|
+
const channelCond = originChannel
|
|
177
|
+
? eq(conversations.originChannel, originChannel)
|
|
178
|
+
: undefined;
|
|
179
|
+
const where = and(typeCond, archiveCond ?? undefined, channelCond);
|
|
176
180
|
const query = db
|
|
177
181
|
.select()
|
|
178
182
|
.from(conversations)
|
|
@@ -208,17 +212,24 @@ export function listConversations(
|
|
|
208
212
|
* Defaults to `true` so callers that want a full
|
|
209
213
|
* run history get one; pass `false` for views
|
|
210
214
|
* that hide archived rows.
|
|
215
|
+
* @param opts.beforeCreatedAt Only return rows with `createdAt` strictly
|
|
216
|
+
* older than this epoch-millis cursor (for
|
|
217
|
+
* paginating into history).
|
|
211
218
|
*/
|
|
212
219
|
export function listConversationsBySource(
|
|
213
220
|
source: string,
|
|
214
221
|
limit = 20,
|
|
215
|
-
opts?: { includeArchived?: boolean },
|
|
222
|
+
opts?: { includeArchived?: boolean; beforeCreatedAt?: number },
|
|
216
223
|
): ConversationRow[] {
|
|
217
224
|
const db = getDb();
|
|
218
225
|
const includeArchived = opts?.includeArchived ?? true;
|
|
219
|
-
const where =
|
|
220
|
-
|
|
221
|
-
|
|
226
|
+
const where = and(
|
|
227
|
+
eq(conversations.source, source),
|
|
228
|
+
includeArchived ? undefined : isNull(conversations.archivedAt),
|
|
229
|
+
opts?.beforeCreatedAt != null
|
|
230
|
+
? lt(conversations.createdAt, opts.beforeCreatedAt)
|
|
231
|
+
: undefined,
|
|
232
|
+
);
|
|
222
233
|
const rows = db
|
|
223
234
|
.select()
|
|
224
235
|
.from(conversations)
|
|
@@ -361,12 +372,16 @@ export function listConversationsByTitlePrefix(
|
|
|
361
372
|
export function countConversations(
|
|
362
373
|
conversationType: ConversationType = "standard",
|
|
363
374
|
archiveStatus: ArchiveStatusFilter = "active",
|
|
375
|
+
originChannel?: string,
|
|
364
376
|
): number {
|
|
365
377
|
ensureGroupMigration();
|
|
366
378
|
const db = getDb();
|
|
367
379
|
const typeCond = conversationTypeClause(conversationType);
|
|
368
380
|
const archiveCond = archiveStatusClause(archiveStatus);
|
|
369
|
-
const
|
|
381
|
+
const channelCond = originChannel
|
|
382
|
+
? eq(conversations.originChannel, originChannel)
|
|
383
|
+
: undefined;
|
|
384
|
+
const where = and(typeCond, archiveCond ?? undefined, channelCond);
|
|
370
385
|
const [{ total }] = db
|
|
371
386
|
.select({ total: count() })
|
|
372
387
|
.from(conversations)
|
package/src/memory/db-init.ts
CHANGED
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
migrateBackfillContactInteractionStats,
|
|
56
56
|
migrateBackfillGuardianPrincipalId,
|
|
57
57
|
migrateBackfillInlineAttachmentsToDisk,
|
|
58
|
+
migrateBackfillOriginChannelFromBindings,
|
|
58
59
|
migrateBackfillProviderConnectionLabel,
|
|
59
60
|
migrateBackfillUsageCacheAccounting,
|
|
60
61
|
migrateCallSessionInviteMetadata,
|
|
@@ -68,6 +69,7 @@ import {
|
|
|
68
69
|
migrateChannelInteractionColumns,
|
|
69
70
|
migrateContactChannelsAccessFields,
|
|
70
71
|
migrateContactChannelsTypeChatIdIndex,
|
|
72
|
+
migrateContactChannelsUniqueExtUser,
|
|
71
73
|
migrateContactsAssistantId,
|
|
72
74
|
migrateContactsNotesColumn,
|
|
73
75
|
migrateContactsRolePrincipal,
|
|
@@ -77,6 +79,7 @@ import {
|
|
|
77
79
|
migrateConversationHostAccess,
|
|
78
80
|
migrateConversationInferenceProfileSession,
|
|
79
81
|
migrateConversationLastNotifiedProfile,
|
|
82
|
+
migrateConversationOriginChannelIndex,
|
|
80
83
|
migrateConversationsArchivedAt,
|
|
81
84
|
migrateConversationsLastMessageAt,
|
|
82
85
|
migrateConversationsSurfacedAt,
|
|
@@ -136,11 +139,13 @@ import {
|
|
|
136
139
|
migrateMemoryGraphImageRefs,
|
|
137
140
|
migrateMemoryItemSupersession,
|
|
138
141
|
migrateMemoryRecallLogsQueryContext,
|
|
142
|
+
migrateMemoryRetrospectiveRememberedLog,
|
|
139
143
|
migrateMemoryRetrospectiveState,
|
|
140
144
|
migrateMemoryV2ActivationLogs,
|
|
141
145
|
migrateMemoryV2InjectionEvents,
|
|
142
146
|
migrateMemoryV3AutoEdges,
|
|
143
147
|
migrateMemoryV3Coactivation,
|
|
148
|
+
migrateMemoryV3SelectionsMessageIdAndSections,
|
|
144
149
|
migrateMessageBookmarks,
|
|
145
150
|
migrateMessagesClientMessageId,
|
|
146
151
|
migrateMessagesConversationCreatedAtIndex,
|
|
@@ -189,7 +194,9 @@ import {
|
|
|
189
194
|
migrateRenameVerificationSessionIdColumn,
|
|
190
195
|
migrateRenameVerificationTable,
|
|
191
196
|
migrateRenameVoiceToPhone,
|
|
197
|
+
migrateScheduleCapabilities,
|
|
192
198
|
migrateScheduleDescription,
|
|
199
|
+
migrateScheduleInferenceProfile,
|
|
193
200
|
migrateScheduleOneShotRouting,
|
|
194
201
|
migrateScheduleQuietFlag,
|
|
195
202
|
migrateScheduleRetryPolicy,
|
|
@@ -198,6 +205,7 @@ import {
|
|
|
198
205
|
migrateScheduleScriptTimeout,
|
|
199
206
|
migrateScheduleSourceConversation,
|
|
200
207
|
migrateScheduleWakeConversationId,
|
|
208
|
+
migrateScheduleWorkflowMode,
|
|
201
209
|
migrateSchemaIndexesAndColumns,
|
|
202
210
|
migrateScrubCorruptedImageAttachments,
|
|
203
211
|
migrateSlackCompactionWatermark,
|
|
@@ -214,6 +222,8 @@ import {
|
|
|
214
222
|
migrateUsageLlmCallCount,
|
|
215
223
|
migrateVoiceInviteColumns,
|
|
216
224
|
migrateVoiceInviteDisplayMetadata,
|
|
225
|
+
migrateWorkflowRuns,
|
|
226
|
+
migrateWorkflowRunTrust,
|
|
217
227
|
recoverCrashedMigrations,
|
|
218
228
|
runComplexMigrations,
|
|
219
229
|
runLateMigrations,
|
|
@@ -498,6 +508,16 @@ export function initializeDb(): void {
|
|
|
498
508
|
migrateToolInvocationsTelemetryColumns,
|
|
499
509
|
createSkillLoadedEventsTable,
|
|
500
510
|
migrateConversationsSurfacedAt,
|
|
511
|
+
migrateMemoryRetrospectiveRememberedLog,
|
|
512
|
+
migrateScheduleInferenceProfile,
|
|
513
|
+
migrateMemoryV3SelectionsMessageIdAndSections,
|
|
514
|
+
migrateWorkflowRuns,
|
|
515
|
+
migrateScheduleWorkflowMode,
|
|
516
|
+
migrateWorkflowRunTrust,
|
|
517
|
+
migrateConversationOriginChannelIndex,
|
|
518
|
+
migrateBackfillOriginChannelFromBindings,
|
|
519
|
+
migrateContactChannelsUniqueExtUser,
|
|
520
|
+
migrateScheduleCapabilities,
|
|
501
521
|
];
|
|
502
522
|
|
|
503
523
|
// Run each migration step, catching and logging individual failures so one
|
|
@@ -3,6 +3,7 @@ import { statSync } from "node:fs";
|
|
|
3
3
|
import { getConfig } from "../config/loader.js";
|
|
4
4
|
import { getLogger } from "../util/logger.js";
|
|
5
5
|
import { getDbPath } from "../util/platform.js";
|
|
6
|
+
import { pruneRuns } from "../workflows/journal-store.js";
|
|
6
7
|
import { getMemoryCheckpoint, setMemoryCheckpoint } from "./checkpoints.js";
|
|
7
8
|
import { getLastUserMessageTimestamp } from "./conversation-crud.js";
|
|
8
9
|
import { runAsyncSqlite } from "./db-async-query.js";
|
|
@@ -56,6 +57,21 @@ async function runDbMaintenance(): Promise<void> {
|
|
|
56
57
|
"Starting database maintenance",
|
|
57
58
|
);
|
|
58
59
|
|
|
60
|
+
// Prune finished workflow runs (and their journals) past the retention
|
|
61
|
+
// window BEFORE VACUUM so the freed pages are reclaimed in the same pass.
|
|
62
|
+
// This is a fast bounded DELETE on the small workflow tables, so it runs on
|
|
63
|
+
// the main connection (`rawRun`) — unlike VACUUM/optimize it doesn't need the
|
|
64
|
+
// async/subprocess path. The maintenance scheduler below already defers this
|
|
65
|
+
// whole routine to an idle window.
|
|
66
|
+
try {
|
|
67
|
+
const deletedRuns = pruneRuns(getConfig().workflows.journalRetentionDays);
|
|
68
|
+
if (deletedRuns > 0) {
|
|
69
|
+
log.info({ deletedRuns }, "Pruned expired workflow runs");
|
|
70
|
+
}
|
|
71
|
+
} catch (err) {
|
|
72
|
+
log.warn({ err }, "Workflow run pruning failed (non-fatal)");
|
|
73
|
+
}
|
|
74
|
+
|
|
59
75
|
// VACUUM is the long-running one — minutes on a multi-GB DB. PRAGMA
|
|
60
76
|
// optimize is fast but routed through the same async path for
|
|
61
77
|
// consistency and to keep both off the main thread when the CLI
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* imported files, so we spawn a standalone bun process that runs an embed
|
|
8
8
|
* worker script communicating via JSON-lines over stdin/stdout.
|
|
9
9
|
*
|
|
10
|
-
* The runtime is stored in
|
|
10
|
+
* The runtime is stored in $VELLUM_WORKSPACE_DIR/embedding-models/ and used
|
|
11
11
|
* by embedding-local.ts on demand.
|
|
12
12
|
*
|
|
13
13
|
* Follows the same download/install pattern as qdrant-manager.ts.
|
|
@@ -25,7 +25,11 @@ import {
|
|
|
25
25
|
messageMetadataSchema,
|
|
26
26
|
} from "./conversation-crud.js";
|
|
27
27
|
import type { LlmRequestLogSource } from "./llm-request-log-source.js";
|
|
28
|
-
import type {
|
|
28
|
+
import type {
|
|
29
|
+
CompactionAgentLogRow,
|
|
30
|
+
LogMetaRow,
|
|
31
|
+
LogRow,
|
|
32
|
+
} from "./llm-request-log-store.js";
|
|
29
33
|
|
|
30
34
|
const log = getLogger("clickhouse-llm-request-log-source");
|
|
31
35
|
|
|
@@ -70,6 +74,23 @@ interface ClickHouseRow {
|
|
|
70
74
|
call_site: string;
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
/** Metadata-only wire row — `ClickHouseRow` without the payload columns. */
|
|
78
|
+
type ClickHouseMetaRow = Omit<
|
|
79
|
+
ClickHouseRow,
|
|
80
|
+
"request_payload" | "response_payload"
|
|
81
|
+
>;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Wire row for the compaction-trail query: metadata plus the summarizer
|
|
85
|
+
* response payload and a message count computed server-side. ClickHouse's
|
|
86
|
+
* `JSONLength` returns 0 for missing/invalid paths; `exec` callers map the
|
|
87
|
+
* `nullif(…, 0)` result, so the field arrives as `number | null`.
|
|
88
|
+
*/
|
|
89
|
+
type ClickHouseCompactionRow = ClickHouseMetaRow & {
|
|
90
|
+
response_payload: string;
|
|
91
|
+
request_message_count: number | string | null;
|
|
92
|
+
};
|
|
93
|
+
|
|
73
94
|
/** Injectable fetch override for tests. Defaults to globalThis.fetch. */
|
|
74
95
|
export type ClickHouseFetch = typeof fetch;
|
|
75
96
|
|
|
@@ -143,10 +164,36 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
143
164
|
ORDER BY created_at DESC
|
|
144
165
|
LIMIT 1
|
|
145
166
|
FORMAT JSONEachRow`;
|
|
146
|
-
const rows = await this.exec(sql, {
|
|
167
|
+
const rows = await this.exec<ClickHouseRow>(sql, {
|
|
168
|
+
assistant_id: aid,
|
|
169
|
+
log_id: logId,
|
|
170
|
+
});
|
|
147
171
|
return rows[0] ? this.toLogRow(rows[0]) : null;
|
|
148
172
|
}
|
|
149
173
|
|
|
174
|
+
async getRequestLogMetaById(logId: string): Promise<LogMetaRow | null> {
|
|
175
|
+
const aid = await this.assistantId();
|
|
176
|
+
const sql = `SELECT
|
|
177
|
+
id,
|
|
178
|
+
conversation_id,
|
|
179
|
+
message_id,
|
|
180
|
+
provider,
|
|
181
|
+
toUnixTimestamp64Milli(created_at) AS created_at,
|
|
182
|
+
agent_loop_exit_reason,
|
|
183
|
+
call_site
|
|
184
|
+
FROM ${this.tableRef()}
|
|
185
|
+
WHERE assistant_id = {assistant_id:String}
|
|
186
|
+
AND id = {log_id:String}
|
|
187
|
+
ORDER BY created_at DESC
|
|
188
|
+
LIMIT 1
|
|
189
|
+
FORMAT JSONEachRow`;
|
|
190
|
+
const rows = await this.exec<ClickHouseMetaRow>(sql, {
|
|
191
|
+
assistant_id: aid,
|
|
192
|
+
log_id: logId,
|
|
193
|
+
});
|
|
194
|
+
return rows[0] ? this.toLogMetaRow(rows[0]) : null;
|
|
195
|
+
}
|
|
196
|
+
|
|
150
197
|
async getRequestLogsByMessageId(messageId: string): Promise<LogRow[]> {
|
|
151
198
|
const turnIds = this.resolveTurnMessageIds(messageId);
|
|
152
199
|
let rows = await this.selectByMessageIds(turnIds);
|
|
@@ -202,18 +249,46 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
202
249
|
ORDER BY created_at ASC, id ASC
|
|
203
250
|
LIMIT 1 BY id
|
|
204
251
|
FORMAT JSONEachRow`;
|
|
205
|
-
const rows = await this.exec(sql, {
|
|
252
|
+
const rows = await this.exec<ClickHouseRow>(sql, {
|
|
206
253
|
assistant_id: aid,
|
|
207
254
|
conversation_id: conversationId,
|
|
208
255
|
});
|
|
209
256
|
return rows.map((r) => this.toLogRow(r));
|
|
210
257
|
}
|
|
211
258
|
|
|
259
|
+
async getPreviousNonCompactionCallCreatedAt(
|
|
260
|
+
conversationId: string,
|
|
261
|
+
beforeCreatedAt: number,
|
|
262
|
+
): Promise<number | null> {
|
|
263
|
+
const aid = await this.assistantId();
|
|
264
|
+
// `call_site != 'compactionAgent'` keeps the pre-migration-264 rows
|
|
265
|
+
// (stored as the empty-string default) in scope as real calls and
|
|
266
|
+
// excludes only the summarizer's own logs, matching the local
|
|
267
|
+
// store's `isNull(callSite) OR callSite != 'compactionAgent'`.
|
|
268
|
+
const sql = `SELECT
|
|
269
|
+
toUnixTimestamp64Milli(created_at) AS created_at
|
|
270
|
+
FROM ${this.tableRef()}
|
|
271
|
+
WHERE assistant_id = {assistant_id:String}
|
|
272
|
+
AND conversation_id = {conversation_id:String}
|
|
273
|
+
AND call_site != {call_site:String}
|
|
274
|
+
AND created_at < fromUnixTimestamp64Milli({before_created_at:Int64})
|
|
275
|
+
ORDER BY created_at DESC, id DESC
|
|
276
|
+
LIMIT 1
|
|
277
|
+
FORMAT JSONEachRow`;
|
|
278
|
+
const rows = await this.exec<{ created_at: string }>(sql, {
|
|
279
|
+
assistant_id: aid,
|
|
280
|
+
conversation_id: conversationId,
|
|
281
|
+
call_site: "compactionAgent",
|
|
282
|
+
before_created_at: String(beforeCreatedAt),
|
|
283
|
+
});
|
|
284
|
+
return rows[0] ? Number(rows[0].created_at) : null;
|
|
285
|
+
}
|
|
286
|
+
|
|
212
287
|
async getCompactionLogsBetween(
|
|
213
288
|
conversationId: string,
|
|
214
289
|
afterCreatedAt: number | null,
|
|
215
290
|
beforeCreatedAt: number,
|
|
216
|
-
): Promise<
|
|
291
|
+
): Promise<CompactionAgentLogRow[]> {
|
|
217
292
|
const aid = await this.assistantId();
|
|
218
293
|
// `call_site` is bound as a literal via type-bound parameter (not
|
|
219
294
|
// string interpolation) for parity with the rest of this class —
|
|
@@ -237,13 +312,23 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
237
312
|
afterPredicate =
|
|
238
313
|
" AND created_at > fromUnixTimestamp64Milli({after_created_at:Int64})";
|
|
239
314
|
}
|
|
315
|
+
// The request payload — an entire near-limit context window per
|
|
316
|
+
// compaction — is never transferred: the trail only needs the count
|
|
317
|
+
// of messages it contained, computed server-side across the three
|
|
318
|
+
// provider shapes (`messages`, `contents`, `input`). `JSONLength`
|
|
319
|
+
// returns 0 for missing paths or invalid JSON; `nullif` maps that
|
|
320
|
+
// back to NULL.
|
|
240
321
|
const sql = `SELECT
|
|
241
322
|
id,
|
|
242
323
|
conversation_id,
|
|
243
324
|
message_id,
|
|
244
325
|
provider,
|
|
245
|
-
request_payload,
|
|
246
326
|
response_payload,
|
|
327
|
+
nullif(greatest(
|
|
328
|
+
JSONLength(request_payload, 'messages'),
|
|
329
|
+
JSONLength(request_payload, 'contents'),
|
|
330
|
+
JSONLength(request_payload, 'input')
|
|
331
|
+
), 0) AS request_message_count,
|
|
247
332
|
toUnixTimestamp64Milli(created_at) AS created_at,
|
|
248
333
|
agent_loop_exit_reason,
|
|
249
334
|
call_site
|
|
@@ -255,8 +340,15 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
255
340
|
ORDER BY created_at ASC, id ASC
|
|
256
341
|
LIMIT 1 BY id
|
|
257
342
|
FORMAT JSONEachRow`;
|
|
258
|
-
const rows = await this.exec(sql, params);
|
|
259
|
-
return rows.map((r) =>
|
|
343
|
+
const rows = await this.exec<ClickHouseCompactionRow>(sql, params);
|
|
344
|
+
return rows.map((r) => ({
|
|
345
|
+
...this.toLogMetaRow(r),
|
|
346
|
+
responsePayload: r.response_payload,
|
|
347
|
+
requestMessageCount:
|
|
348
|
+
r.request_message_count === null
|
|
349
|
+
? null
|
|
350
|
+
: Number(r.request_message_count),
|
|
351
|
+
}));
|
|
260
352
|
}
|
|
261
353
|
|
|
262
354
|
private async selectByMessageIds(ids: string[]): Promise<LogRow[]> {
|
|
@@ -293,7 +385,7 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
293
385
|
ORDER BY created_at ASC, id ASC
|
|
294
386
|
LIMIT 1 BY id
|
|
295
387
|
FORMAT JSONEachRow`;
|
|
296
|
-
const rows = await this.exec(sql, params);
|
|
388
|
+
const rows = await this.exec<ClickHouseRow>(sql, params);
|
|
297
389
|
return rows.map((r) => this.toLogRow(r));
|
|
298
390
|
}
|
|
299
391
|
|
|
@@ -304,10 +396,10 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
304
396
|
return `\`${this.config.table.replace(/`/g, "``")}\``;
|
|
305
397
|
}
|
|
306
398
|
|
|
307
|
-
private async exec(
|
|
399
|
+
private async exec<Row>(
|
|
308
400
|
sql: string,
|
|
309
401
|
params: Record<string, string>,
|
|
310
|
-
): Promise<
|
|
402
|
+
): Promise<Row[]> {
|
|
311
403
|
const baseUrl = await this.url();
|
|
312
404
|
const password = await this.password();
|
|
313
405
|
|
|
@@ -352,12 +444,12 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
352
444
|
const text = await res.text();
|
|
353
445
|
if (text.trim().length === 0) return [];
|
|
354
446
|
|
|
355
|
-
const rows:
|
|
447
|
+
const rows: Row[] = [];
|
|
356
448
|
for (const line of text.split("\n")) {
|
|
357
449
|
const trimmed = line.trim();
|
|
358
450
|
if (trimmed.length === 0) continue;
|
|
359
451
|
try {
|
|
360
|
-
rows.push(JSON.parse(trimmed) as
|
|
452
|
+
rows.push(JSON.parse(trimmed) as Row);
|
|
361
453
|
} catch (err) {
|
|
362
454
|
throw new Error(
|
|
363
455
|
`Failed to parse ClickHouse JSONEachRow line: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -368,6 +460,14 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
368
460
|
}
|
|
369
461
|
|
|
370
462
|
private toLogRow(row: ClickHouseRow): LogRow {
|
|
463
|
+
return {
|
|
464
|
+
...this.toLogMetaRow(row),
|
|
465
|
+
requestPayload: row.request_payload,
|
|
466
|
+
responsePayload: row.response_payload,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
private toLogMetaRow(row: ClickHouseMetaRow): LogMetaRow {
|
|
371
471
|
return {
|
|
372
472
|
id: row.id,
|
|
373
473
|
conversationId: row.conversation_id,
|
|
@@ -376,8 +476,6 @@ export class ClickHouseLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
376
476
|
// overhead). Map empty back to null to match the local LogRow shape.
|
|
377
477
|
messageId: row.message_id === "" ? null : row.message_id,
|
|
378
478
|
provider: row.provider === "" ? null : row.provider,
|
|
379
|
-
requestPayload: row.request_payload,
|
|
380
|
-
responsePayload: row.response_payload,
|
|
381
479
|
createdAt: Number(row.created_at),
|
|
382
480
|
agentLoopExitReason:
|
|
383
481
|
row.agent_loop_exit_reason === "" ? null : row.agent_loop_exit_reason,
|
|
@@ -10,10 +10,14 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { LlmRequestLogSource } from "./llm-request-log-source.js";
|
|
12
12
|
import {
|
|
13
|
+
type CompactionAgentLogRow,
|
|
13
14
|
getCompactionLogsBetween,
|
|
15
|
+
getPreviousNonCompactionCallCreatedAt,
|
|
14
16
|
getRequestLogById,
|
|
17
|
+
getRequestLogMetaById,
|
|
15
18
|
getRequestLogsByConversationId,
|
|
16
19
|
getRequestLogsByMessageId,
|
|
20
|
+
type LogMetaRow,
|
|
17
21
|
type LogRow,
|
|
18
22
|
} from "./llm-request-log-store.js";
|
|
19
23
|
|
|
@@ -22,6 +26,10 @@ export class LocalLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
22
26
|
return getRequestLogById(logId);
|
|
23
27
|
}
|
|
24
28
|
|
|
29
|
+
async getRequestLogMetaById(logId: string): Promise<LogMetaRow | null> {
|
|
30
|
+
return getRequestLogMetaById(logId);
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
async getRequestLogsByMessageId(messageId: string): Promise<LogRow[]> {
|
|
26
34
|
return getRequestLogsByMessageId(messageId);
|
|
27
35
|
}
|
|
@@ -32,11 +40,21 @@ export class LocalLlmRequestLogSource implements LlmRequestLogSource {
|
|
|
32
40
|
return getRequestLogsByConversationId(conversationId);
|
|
33
41
|
}
|
|
34
42
|
|
|
43
|
+
async getPreviousNonCompactionCallCreatedAt(
|
|
44
|
+
conversationId: string,
|
|
45
|
+
beforeCreatedAt: number,
|
|
46
|
+
): Promise<number | null> {
|
|
47
|
+
return getPreviousNonCompactionCallCreatedAt(
|
|
48
|
+
conversationId,
|
|
49
|
+
beforeCreatedAt,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
35
53
|
async getCompactionLogsBetween(
|
|
36
54
|
conversationId: string,
|
|
37
55
|
afterCreatedAt: number | null,
|
|
38
56
|
beforeCreatedAt: number,
|
|
39
|
-
): Promise<
|
|
57
|
+
): Promise<CompactionAgentLogRow[]> {
|
|
40
58
|
return getCompactionLogsBetween(
|
|
41
59
|
conversationId,
|
|
42
60
|
afterCreatedAt,
|
|
@@ -17,12 +17,24 @@
|
|
|
17
17
|
* Config edits take effect on the next request without an invalidation hook.
|
|
18
18
|
*/
|
|
19
19
|
import { getConfig } from "../config/loader.js";
|
|
20
|
-
import type {
|
|
20
|
+
import type {
|
|
21
|
+
CompactionAgentLogRow,
|
|
22
|
+
LogMetaRow,
|
|
23
|
+
LogRow,
|
|
24
|
+
} from "./llm-request-log-store.js";
|
|
21
25
|
|
|
22
26
|
export interface LlmRequestLogSource {
|
|
23
27
|
/** Fetch a single log row by its primary key. Returns null if not found. */
|
|
24
28
|
getRequestLogById(logId: string): Promise<LogRow | null>;
|
|
25
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Fetch a single log row's metadata (no payloads) by its primary key.
|
|
32
|
+
* Prefer this when the caller only needs to locate or validate the row
|
|
33
|
+
* — request payloads can be entire context windows, so loading them for
|
|
34
|
+
* a conversation-scope check or a `createdAt` anchor is wasteful.
|
|
35
|
+
*/
|
|
36
|
+
getRequestLogMetaById(logId: string): Promise<LogMetaRow | null>;
|
|
37
|
+
|
|
26
38
|
/**
|
|
27
39
|
* Fetch every LLM request log associated with the given message,
|
|
28
40
|
* including all assistant messages in the same agent turn. Implementations
|
|
@@ -39,22 +51,39 @@ export interface LlmRequestLogSource {
|
|
|
39
51
|
*/
|
|
40
52
|
getRequestLogsByConversationId(conversationId: string): Promise<LogRow[]>;
|
|
41
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Return the `createdAt` of the most recent **non-`compactionAgent`**
|
|
56
|
+
* LLM call in the conversation that ran strictly before
|
|
57
|
+
* `beforeCreatedAt`, or `null` when the selected call is the first real
|
|
58
|
+
* call in the conversation.
|
|
59
|
+
*
|
|
60
|
+
* Drives the call-scoped floor for the Inspector's Compaction tab: a
|
|
61
|
+
* compaction is attributed to the next real call that ran after it, so
|
|
62
|
+
* the compactions for a given call are those that landed strictly
|
|
63
|
+
* between the previous real call and the selected call.
|
|
64
|
+
*/
|
|
65
|
+
getPreviousNonCompactionCallCreatedAt(
|
|
66
|
+
conversationId: string,
|
|
67
|
+
beforeCreatedAt: number,
|
|
68
|
+
): Promise<number | null>;
|
|
69
|
+
|
|
42
70
|
/**
|
|
43
71
|
* Fetch every `callSite = "compactionAgent"` log row in the conversation
|
|
44
72
|
* whose `createdAt` falls in the **open window**
|
|
45
73
|
* `(afterCreatedAt, beforeCreatedAt)`, ordered chronologically.
|
|
46
74
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* `
|
|
50
|
-
*
|
|
75
|
+
* The legacy fallback for the Inspector's Compaction tab, used when the
|
|
76
|
+
* ClickHouse compaction log is unavailable. The route handler resolves
|
|
77
|
+
* the floor from `getPreviousNonCompactionCallCreatedAt` and the ceiling
|
|
78
|
+
* from the selected call's `createdAt`; this source method is
|
|
79
|
+
* bound-agnostic. See `getCompactionLogsBetween` in
|
|
51
80
|
* `llm-request-log-store.ts` for the SQL.
|
|
52
81
|
*/
|
|
53
82
|
getCompactionLogsBetween(
|
|
54
83
|
conversationId: string,
|
|
55
84
|
afterCreatedAt: number | null,
|
|
56
85
|
beforeCreatedAt: number,
|
|
57
|
-
): Promise<
|
|
86
|
+
): Promise<CompactionAgentLogRow[]>;
|
|
58
87
|
}
|
|
59
88
|
|
|
60
89
|
/**
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
isNull,
|
|
10
10
|
lt,
|
|
11
11
|
lte,
|
|
12
|
+
ne,
|
|
13
|
+
or,
|
|
12
14
|
sql,
|
|
13
15
|
} from "drizzle-orm";
|
|
14
16
|
import { v4 as uuid } from "uuid";
|
|
@@ -48,6 +50,20 @@ export type LogRow = {
|
|
|
48
50
|
callSite: string | null;
|
|
49
51
|
};
|
|
50
52
|
|
|
53
|
+
/** `LogRow` without the payload columns — for reads that only need metadata. */
|
|
54
|
+
export type LogMetaRow = Omit<LogRow, "requestPayload" | "responsePayload">;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Compaction-trail row: metadata plus the (small) summarizer response
|
|
58
|
+
* payload and a message count computed in SQL. The request payload — an
|
|
59
|
+
* entire near-limit context window per compaction — is deliberately never
|
|
60
|
+
* loaded; the trail only needs the count of messages it contained.
|
|
61
|
+
*/
|
|
62
|
+
export type CompactionAgentLogRow = LogMetaRow & {
|
|
63
|
+
responsePayload: string;
|
|
64
|
+
requestMessageCount: number | null;
|
|
65
|
+
};
|
|
66
|
+
|
|
51
67
|
/**
|
|
52
68
|
* Build the structured response-payload object recorded in
|
|
53
69
|
* `llm_request_logs.responsePayload` for a provider-rejected LLM call.
|
|
@@ -399,6 +415,43 @@ function selectUnlinkedLogsInRange(
|
|
|
399
415
|
.all();
|
|
400
416
|
}
|
|
401
417
|
|
|
418
|
+
/**
|
|
419
|
+
* Return the `createdAt` of the most recent **non-`compactionAgent`** LLM
|
|
420
|
+
* call in the conversation that ran strictly before `beforeCreatedAt`, or
|
|
421
|
+
* `null` when no such call exists (the selected call is the first real
|
|
422
|
+
* call in the conversation).
|
|
423
|
+
*
|
|
424
|
+
* Drives the call-scoped floor for the Inspector's Compaction tab. A
|
|
425
|
+
* compaction is attributed to the next real call that runs after it, so
|
|
426
|
+
* the trail for a given call is the set of compactions that landed
|
|
427
|
+
* strictly between the previous real call and the selected call. NULL
|
|
428
|
+
* `callSite` rows (pre-migration-264) are treated as real calls — only
|
|
429
|
+
* `compactionAgent` rows are excluded.
|
|
430
|
+
*/
|
|
431
|
+
export function getPreviousNonCompactionCallCreatedAt(
|
|
432
|
+
conversationId: string,
|
|
433
|
+
beforeCreatedAt: number,
|
|
434
|
+
): number | null {
|
|
435
|
+
const db = getDb();
|
|
436
|
+
const row = db
|
|
437
|
+
.select({ createdAt: llmRequestLogs.createdAt })
|
|
438
|
+
.from(llmRequestLogs)
|
|
439
|
+
.where(
|
|
440
|
+
and(
|
|
441
|
+
eq(llmRequestLogs.conversationId, conversationId),
|
|
442
|
+
lt(llmRequestLogs.createdAt, beforeCreatedAt),
|
|
443
|
+
or(
|
|
444
|
+
isNull(llmRequestLogs.callSite),
|
|
445
|
+
ne(llmRequestLogs.callSite, "compactionAgent"),
|
|
446
|
+
),
|
|
447
|
+
),
|
|
448
|
+
)
|
|
449
|
+
.orderBy(desc(llmRequestLogs.createdAt), desc(llmRequestLogs.id))
|
|
450
|
+
.limit(1)
|
|
451
|
+
.get();
|
|
452
|
+
return row?.createdAt ?? null;
|
|
453
|
+
}
|
|
454
|
+
|
|
402
455
|
/**
|
|
403
456
|
* Fetch every `compactionAgent` log row in the conversation whose
|
|
404
457
|
* `createdAt` falls in the **open window** `(afterCreatedAt, beforeCreatedAt)`,
|
|
@@ -426,7 +479,7 @@ export function getCompactionLogsBetween(
|
|
|
426
479
|
conversationId: string,
|
|
427
480
|
afterCreatedAt: number | null,
|
|
428
481
|
beforeCreatedAt: number,
|
|
429
|
-
):
|
|
482
|
+
): CompactionAgentLogRow[] {
|
|
430
483
|
const db = getDb();
|
|
431
484
|
const predicates = [
|
|
432
485
|
eq(llmRequestLogs.conversationId, conversationId),
|
|
@@ -442,8 +495,18 @@ export function getCompactionLogsBetween(
|
|
|
442
495
|
conversationId: llmRequestLogs.conversationId,
|
|
443
496
|
messageId: llmRequestLogs.messageId,
|
|
444
497
|
provider: llmRequestLogs.provider,
|
|
445
|
-
requestPayload: llmRequestLogs.requestPayload,
|
|
446
498
|
responsePayload: llmRequestLogs.responsePayload,
|
|
499
|
+
// Count the request's messages in SQL instead of loading the payload:
|
|
500
|
+
// `messages` (Anthropic / OpenAI chat-completions), `contents`
|
|
501
|
+
// (Gemini), `input` (OpenAI Responses). NULL when the payload is
|
|
502
|
+
// malformed or none of the arrays exist.
|
|
503
|
+
requestMessageCount: sql<
|
|
504
|
+
number | null
|
|
505
|
+
>`CASE WHEN json_valid(${llmRequestLogs.requestPayload}) THEN coalesce(
|
|
506
|
+
json_array_length(${llmRequestLogs.requestPayload}, '$.messages'),
|
|
507
|
+
json_array_length(${llmRequestLogs.requestPayload}, '$.contents'),
|
|
508
|
+
json_array_length(${llmRequestLogs.requestPayload}, '$.input')
|
|
509
|
+
) ELSE NULL END`,
|
|
447
510
|
createdAt: llmRequestLogs.createdAt,
|
|
448
511
|
agentLoopExitReason: llmRequestLogs.agentLoopExitReason,
|
|
449
512
|
callSite: llmRequestLogs.callSite,
|
|
@@ -454,6 +517,31 @@ export function getCompactionLogsBetween(
|
|
|
454
517
|
.all();
|
|
455
518
|
}
|
|
456
519
|
|
|
520
|
+
/**
|
|
521
|
+
* Metadata-only lookup by primary key. Used where the caller needs to
|
|
522
|
+
* locate or validate a log (conversation scoping, `createdAt` anchoring)
|
|
523
|
+
* without paying to load its payloads — a single request payload can be a
|
|
524
|
+
* full context window.
|
|
525
|
+
*/
|
|
526
|
+
export function getRequestLogMetaById(logId: string): LogMetaRow | null {
|
|
527
|
+
const db = getDb();
|
|
528
|
+
return (
|
|
529
|
+
db
|
|
530
|
+
.select({
|
|
531
|
+
id: llmRequestLogs.id,
|
|
532
|
+
conversationId: llmRequestLogs.conversationId,
|
|
533
|
+
messageId: llmRequestLogs.messageId,
|
|
534
|
+
provider: llmRequestLogs.provider,
|
|
535
|
+
createdAt: llmRequestLogs.createdAt,
|
|
536
|
+
agentLoopExitReason: llmRequestLogs.agentLoopExitReason,
|
|
537
|
+
callSite: llmRequestLogs.callSite,
|
|
538
|
+
})
|
|
539
|
+
.from(llmRequestLogs)
|
|
540
|
+
.where(eq(llmRequestLogs.id, logId))
|
|
541
|
+
.get() ?? null
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
|
|
457
545
|
export function getRequestLogById(logId: string): LogRow | null {
|
|
458
546
|
const db = getDb();
|
|
459
547
|
return (
|
|
@@ -24,6 +24,15 @@ export const MEMORY_RETROSPECTIVE_SOURCES: readonly string[] = [
|
|
|
24
24
|
MEMORY_RETROSPECTIVE_FORK_SOURCE,
|
|
25
25
|
];
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Whether a conversation `source` value marks a memory-retrospective
|
|
29
|
+
* background conversation (either kind). Shared predicate for the recursion
|
|
30
|
+
* and auto-analysis guards.
|
|
31
|
+
*/
|
|
32
|
+
export function isMemoryRetrospectiveSource(source: string): boolean {
|
|
33
|
+
return MEMORY_RETROSPECTIVE_SOURCES.includes(source);
|
|
34
|
+
}
|
|
35
|
+
|
|
27
36
|
/**
|
|
28
37
|
* Dedicated `group_id` value for memory-retrospective background
|
|
29
38
|
* conversations. Placed under `system:background` alongside auto-analysis,
|