@vellumai/assistant 0.8.7 → 0.8.8-dev.202606052332.17fc8ea
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +20 -4
- package/bun.lock +2 -2
- package/docker-entrypoint.sh +4 -2
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/examples/plugins/echo/README.md +61 -66
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +3378 -335
- package/package.json +2 -2
- package/scripts/generate-openapi.ts +68 -41
- package/src/__tests__/agent-loop-exit-reason.test.ts +35 -93
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +37 -87
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -3
- package/src/__tests__/anthropic-provider.test.ts +95 -2
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
- package/src/__tests__/btw-routes.test.ts +62 -3
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/catalog-files.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/clawhub-files.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction.benchmark.test.ts +0 -30
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -5
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -7
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +316 -1143
- package/src/__tests__/conversation-agent-loop.test.ts +638 -1655
- package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-history-web-search.test.ts +11 -1
- package/src/__tests__/conversation-pairing.test.ts +4 -31
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -10
- package/src/__tests__/conversation-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
- package/src/__tests__/conversation-runtime-assembly.test.ts +310 -300
- package/src/__tests__/conversation-runtime-workspace.test.ts +105 -45
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +6 -1
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
- package/src/__tests__/conversation-sync-tags.test.ts +27 -15
- package/src/__tests__/conversation-title-service.test.ts +135 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +17 -16
- package/src/__tests__/conversation-workspace-injection.test.ts +67 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +7 -6
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/cross-provider-web-search.test.ts +214 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
- package/src/__tests__/dm-persistence.test.ts +5 -1
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -0
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/identity-intro-cache.test.ts +12 -100
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
- package/src/__tests__/injector-background-turn.test.ts +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +75 -41
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +31 -37
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/list-messages-page-latest.test.ts +60 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
- package/src/__tests__/llm-usage-store.test.ts +223 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/native-web-search.test.ts +191 -0
- package/src/__tests__/onboarding-template-contract.test.ts +2 -0
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +31 -1
- package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -284
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-api-shim.test.ts +3 -6
- package/src/__tests__/plugin-bootstrap.test.ts +14 -40
- package/src/__tests__/plugin-registry.test.ts +3 -76
- package/src/__tests__/plugin-types.test.ts +0 -193
- package/src/__tests__/process-message-display-content.test.ts +6 -2
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
- package/src/__tests__/schedule-routes.test.ts +603 -2
- package/src/__tests__/schedule-store.test.ts +41 -0
- package/src/__tests__/schedule-tools.test.ts +35 -0
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/skillssh-files.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +20 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +6 -1
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/voice-session-bridge.test.ts +6 -3
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +196 -0
- package/src/acp/auto-install.ts +177 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +83 -29
- package/src/acp/resolve-agent.test.ts +320 -7
- package/src/acp/resolve-agent.ts +182 -18
- package/src/acp/resume-hint.ts +25 -0
- package/src/acp/session-manager.ts +495 -73
- package/src/acp/types.ts +8 -0
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +362 -485
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/index.ts +48 -13
- package/src/api/responses/conversation-message.ts +374 -0
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/avatar/__tests__/avatar-store.test.ts +34 -29
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/notifications.ts +112 -60
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/assistant-feature-flags.ts +22 -11
- package/src/config/bundled-skills/acp/SKILL.md +83 -31
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -398
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +48 -7
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-v2.ts +8 -0
- package/src/config/schemas/memory-v3.ts +8 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +1 -1
- package/src/context/strip-injections.ts +128 -0
- package/src/context/token-estimator.ts +23 -0
- package/src/context/tool-result-truncation.ts +0 -23
- package/src/context/window-manager.ts +5 -7
- package/src/credential-execution/executable-discovery.ts +16 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +2 -2
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +594 -153
- package/src/daemon/conversation-agent-loop.ts +301 -997
- package/src/daemon/conversation-history.ts +5 -4
- package/src/daemon/conversation-lifecycle.ts +3 -4
- package/src/daemon/conversation-messaging.ts +7 -6
- package/src/daemon/conversation-process.ts +11 -16
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +218 -398
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +222 -4
- package/src/daemon/conversation-tool-setup.ts +2 -29
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +32 -20
- package/src/daemon/external-plugins-bootstrap.ts +17 -18
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/shared.ts +156 -84
- package/src/daemon/handlers/skills.ts +42 -10
- package/src/daemon/lifecycle.ts +25 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/messages.ts +9 -57
- package/src/daemon/message-types/skills.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +136 -3
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +1 -3
- package/src/daemon/server.ts +2 -0
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +19 -0
- package/src/daemon/wake-target-adapter.ts +3 -1
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/home/home-greeting-cache.ts +24 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +6 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/conversation-graph-memory.ts +65 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs-store.ts +33 -0
- package/src/memory/jobs-worker.ts +32 -5
- package/src/memory/llm-usage-store.ts +224 -50
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +16 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -4
- package/src/memory/v2/consolidation-job.ts +14 -5
- package/src/notifications/conversation-pairing.ts +8 -15
- package/src/notifications/decision-engine.ts +6 -3
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/permissions/prompter.ts +4 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +7 -5
- package/src/plugin-api/types.ts +151 -1
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +8 -19
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/register.ts +8 -13
- package/src/plugins/defaults/index.ts +2 -18
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +288 -81
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +16 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +48 -12
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +104 -32
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +96 -30
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +34 -16
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +26 -14
- package/src/plugins/defaults/{llm-call → memory-v3-shadow}/package.json +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +3 -3
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +51 -45
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +61 -46
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +69 -99
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +8 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +1 -1
- package/src/plugins/defaults/title-generate/register.ts +18 -18
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +1 -1
- package/src/plugins/defaults/tool-error/register.ts +9 -21
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +6 -305
- package/src/plugins/registry.ts +10 -55
- package/src/plugins/types.ts +62 -797
- package/src/plugins/user-loader.ts +30 -127
- package/src/proactive-artifact/aux-message-injector.ts +4 -4
- package/src/proactive-artifact/job.test.ts +8 -13
- package/src/prompts/__tests__/system-prompt.test.ts +42 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +15 -0
- package/src/providers/anthropic/client.ts +37 -29
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -0
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/runtime/__tests__/agent-wake.test.ts +10 -6
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +2 -5
- package/src/runtime/assistant-event-hub.ts +37 -7
- package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/http-router.ts +16 -21
- package/src/runtime/http-types.ts +16 -70
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/app-management-routes.ts +6 -117
- package/src/runtime/routes/app-routes.ts +13 -15
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/attachment-routes.ts +26 -15
- package/src/runtime/routes/avatar-routes.ts +26 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/btw-routes.ts +29 -23
- package/src/runtime/routes/consolidation-routes.ts +120 -20
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +3 -1
- package/src/runtime/routes/conversation-routes.ts +372 -185
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/documents-routes.ts +4 -0
- package/src/runtime/routes/domain-routes.ts +51 -37
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +28 -34
- package/src/runtime/routes/gateway-log-routes.ts +26 -4
- package/src/runtime/routes/heartbeat-routes.ts +32 -12
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-intro-cache.ts +11 -34
- package/src/runtime/routes/identity-routes.ts +224 -18
- package/src/runtime/routes/image-generation-routes.ts +40 -2
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/a2a.ts +12 -10
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +4 -0
- package/src/runtime/routes/integrations/slack/share.ts +27 -6
- package/src/runtime/routes/integrations/telegram.ts +6 -0
- package/src/runtime/routes/integrations/twilio.ts +42 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/log-export-routes.ts +8 -0
- package/src/runtime/routes/memory-v2-routes.ts +15 -8
- package/src/runtime/routes/memory-v3-routes.ts +66 -34
- package/src/runtime/routes/oauth-apps.ts +66 -12
- package/src/runtime/routes/oauth-providers.ts +44 -5
- package/src/runtime/routes/platform-routes.ts +81 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
- package/src/runtime/routes/playground/force-compact.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/rename-conversation-routes.ts +5 -0
- package/src/runtime/routes/schedule-routes.ts +152 -42
- package/src/runtime/routes/secret-routes.ts +14 -2
- package/src/runtime/routes/skills-routes.ts +43 -14
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trust-rules-routes.ts +26 -2
- package/src/runtime/routes/tts-routes.ts +35 -0
- package/src/runtime/routes/types.ts +66 -8
- package/src/runtime/routes/usage-routes.ts +47 -39
- package/src/runtime/routes/webhook-routes.ts +41 -2
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +4 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
- package/src/runtime/services/analyze-conversation.ts +2 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/schedule/schedule-store.ts +20 -1
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +12 -5
- package/src/signals/cancel.ts +2 -4
- package/src/skills/catalog-files.ts +2 -2
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -2
- package/src/skills/skillssh-files.ts +1 -2
- package/src/subagent/manager.ts +17 -5
- package/src/telemetry/types.ts +29 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
- package/src/telemetry/usage-telemetry-reporter.ts +57 -2
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +158 -55
- package/src/tools/acp/spawn.ts +47 -72
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/executor.ts +1 -53
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +11 -3
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +207 -48
- package/src/tools/schedule/create.ts +2 -0
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/ui-surface/definitions.ts +34 -5
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/util/mutex.ts +47 -0
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/docs/plugins.md +0 -836
- package/examples/plugins/echo/register.ts +0 -184
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/empty-response-pipeline.test.ts +0 -423
- package/src/__tests__/llm-call-pipeline.test.ts +0 -287
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -503
- package/src/__tests__/pipeline-runner.test.ts +0 -564
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/home/feature-gate.ts +0 -22
- package/src/memory/v3/provider-blocks.ts +0 -16
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
- package/src/plugins/defaults/empty-response/terminal.ts +0 -106
- package/src/plugins/defaults/injectors/package.json +0 -15
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
- package/src/plugins/defaults/llm-call/register.ts +0 -45
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
- package/src/plugins/defaults/memory-retrieval/package.json +0 -15
- package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/persistence/middlewares/persistence.ts +0 -19
- package/src/plugins/defaults/persistence/package.json +0 -15
- package/src/plugins/defaults/persistence/register.ts +0 -38
- package/src/plugins/defaults/persistence/terminal.ts +0 -83
- package/src/plugins/defaults/title-generate/terminal.ts +0 -31
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
- package/src/plugins/defaults/token-estimate/package.json +0 -15
- package/src/plugins/defaults/token-estimate/register.ts +0 -34
- package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
- package/src/plugins/defaults/tool-error/terminal.ts +0 -47
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
- package/src/plugins/defaults/tool-execute/package.json +0 -15
- package/src/plugins/defaults/tool-execute/register.ts +0 -49
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
- package/src/skills/category-inference.ts +0 -111
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
|
@@ -85,6 +85,7 @@ const stubConfig: {
|
|
|
85
85
|
activeHoursStart: number | null;
|
|
86
86
|
activeHoursEnd: number | null;
|
|
87
87
|
maxConsecutiveRuns: number | null;
|
|
88
|
+
maxDailyRuns: number | null;
|
|
88
89
|
disposition: string;
|
|
89
90
|
};
|
|
90
91
|
} = {
|
|
@@ -94,6 +95,7 @@ const stubConfig: {
|
|
|
94
95
|
activeHoursStart: null,
|
|
95
96
|
activeHoursEnd: null,
|
|
96
97
|
maxConsecutiveRuns: null,
|
|
98
|
+
maxDailyRuns: null,
|
|
97
99
|
disposition: "Default disposition text.",
|
|
98
100
|
},
|
|
99
101
|
};
|
|
@@ -195,6 +197,7 @@ mock.module("../heartbeat-run-store.js", () => ({
|
|
|
195
197
|
markStaleRunsAsMissed: () => 0,
|
|
196
198
|
markStaleRunningAsError: () => 0,
|
|
197
199
|
countCompletedHeartbeatRuns: () => 10,
|
|
200
|
+
countCompletedRunsToday: () => 0,
|
|
198
201
|
countRecentConsecutiveRuns: () => 0,
|
|
199
202
|
}));
|
|
200
203
|
|
|
@@ -24,7 +24,8 @@ export type HeartbeatSkipReason =
|
|
|
24
24
|
| "outside_active_hours"
|
|
25
25
|
| "overlap"
|
|
26
26
|
| "pre_first_user_message"
|
|
27
|
-
| "max_consecutive_runs"
|
|
27
|
+
| "max_consecutive_runs"
|
|
28
|
+
| "max_daily_runs";
|
|
28
29
|
|
|
29
30
|
export interface HeartbeatRunRecord {
|
|
30
31
|
id: string;
|
|
@@ -217,6 +218,27 @@ export function countCompletedHeartbeatRuns(): number {
|
|
|
217
218
|
return row?.count ?? 0;
|
|
218
219
|
}
|
|
219
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Count heartbeat runs that completed with status `ok` today (local midnight).
|
|
223
|
+
*/
|
|
224
|
+
export function countCompletedRunsToday(): number {
|
|
225
|
+
const db = getDb();
|
|
226
|
+
const now = new Date();
|
|
227
|
+
const startOfDay = new Date(
|
|
228
|
+
now.getFullYear(),
|
|
229
|
+
now.getMonth(),
|
|
230
|
+
now.getDate(),
|
|
231
|
+
).getTime();
|
|
232
|
+
const row = db
|
|
233
|
+
.select({ count: sql<number>`count(*)` })
|
|
234
|
+
.from(heartbeatRuns)
|
|
235
|
+
.where(
|
|
236
|
+
sql`${heartbeatRuns.status} = 'ok' AND ${heartbeatRuns.scheduledFor} >= ${startOfDay}`,
|
|
237
|
+
)
|
|
238
|
+
.get();
|
|
239
|
+
return row?.count ?? 0;
|
|
240
|
+
}
|
|
241
|
+
|
|
220
242
|
/**
|
|
221
243
|
* Count the most recent consecutive heartbeat runs with status `ok`,
|
|
222
244
|
* walking backwards from newest. Stops at the first non-`ok` status
|
|
@@ -25,6 +25,7 @@ import { stripCommentLines } from "../util/strip-comment-lines.js";
|
|
|
25
25
|
import {
|
|
26
26
|
completeHeartbeatRun,
|
|
27
27
|
countCompletedHeartbeatRuns,
|
|
28
|
+
countCompletedRunsToday,
|
|
28
29
|
countRecentConsecutiveRuns,
|
|
29
30
|
insertPendingHeartbeatRun,
|
|
30
31
|
markStaleRunningAsError,
|
|
@@ -187,6 +188,13 @@ export class HeartbeatService {
|
|
|
187
188
|
);
|
|
188
189
|
}
|
|
189
190
|
|
|
191
|
+
/** Whether the daily run cap has been reached. */
|
|
192
|
+
get isDailyCapReached(): boolean {
|
|
193
|
+
const config = getConfig().heartbeat;
|
|
194
|
+
if (config.maxDailyRuns == null) return false;
|
|
195
|
+
return countCompletedRunsToday() >= config.maxDailyRuns;
|
|
196
|
+
}
|
|
197
|
+
|
|
190
198
|
async runManagedWakeIfDue(
|
|
191
199
|
options: ManagedWakeHeartbeatRunOptions = {},
|
|
192
200
|
): Promise<ManagedWakeHeartbeatRunResult> {
|
|
@@ -551,6 +559,24 @@ export class HeartbeatService {
|
|
|
551
559
|
return false;
|
|
552
560
|
}
|
|
553
561
|
|
|
562
|
+
// Daily run cap — stop burning tokens when the daily budget is exhausted.
|
|
563
|
+
// Force runs bypass the cap.
|
|
564
|
+
if (
|
|
565
|
+
!force &&
|
|
566
|
+
config.maxDailyRuns != null &&
|
|
567
|
+
countCompletedRunsToday() >= config.maxDailyRuns
|
|
568
|
+
) {
|
|
569
|
+
log.debug(
|
|
570
|
+
{ maxDailyRuns: config.maxDailyRuns },
|
|
571
|
+
"Daily run cap reached, skipping",
|
|
572
|
+
);
|
|
573
|
+
if (runId) skipHeartbeatRun(runId, "max_daily_runs");
|
|
574
|
+
if (!this.cronMode) {
|
|
575
|
+
this.scheduleNextRun(config.intervalMs);
|
|
576
|
+
}
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
|
|
554
580
|
// Overlap prevention
|
|
555
581
|
if (this.activeRun) {
|
|
556
582
|
log.debug("Previous heartbeat run still active, skipping");
|
|
@@ -10,11 +10,15 @@
|
|
|
10
10
|
* Storage uses the existing `memory_checkpoints` table (simple key-value store).
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
14
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
15
|
+
|
|
13
16
|
import {
|
|
14
17
|
getMemoryCheckpoint,
|
|
15
18
|
setMemoryCheckpoint,
|
|
16
19
|
} from "../memory/checkpoints.js";
|
|
17
|
-
import {
|
|
20
|
+
import { resolveGuardianPersona } from "../prompts/persona-resolver.js";
|
|
21
|
+
import { getWorkspacePromptPath } from "../util/platform.js";
|
|
18
22
|
|
|
19
23
|
// ---------------------------------------------------------------------------
|
|
20
24
|
// Constants
|
|
@@ -26,6 +30,25 @@ const CHECKPOINT_KEY_TEXT = "home:greeting:text";
|
|
|
26
30
|
const CHECKPOINT_KEY_HASH = "home:greeting:content_hash";
|
|
27
31
|
const CHECKPOINT_KEY_TIMESTAMP = "home:greeting:cached_at";
|
|
28
32
|
|
|
33
|
+
const IDENTITY_FILES = ["IDENTITY.md", "SOUL.md"] as const;
|
|
34
|
+
|
|
35
|
+
function readWorkspaceFile(name: string): string {
|
|
36
|
+
try {
|
|
37
|
+
const path = getWorkspacePromptPath(name);
|
|
38
|
+
if (!existsSync(path)) return "";
|
|
39
|
+
return readFileSync(path, "utf-8");
|
|
40
|
+
} catch {
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function computeIdentityContentHash(): string {
|
|
46
|
+
const staticFiles = IDENTITY_FILES.map(readWorkspaceFile).join("\n---\n");
|
|
47
|
+
const guardianPersona = resolveGuardianPersona() ?? "";
|
|
48
|
+
const combined = staticFiles + "\n---\n" + guardianPersona;
|
|
49
|
+
return createHash("sha256").update(combined).digest("hex");
|
|
50
|
+
}
|
|
51
|
+
|
|
29
52
|
// ---------------------------------------------------------------------------
|
|
30
53
|
// Public API
|
|
31
54
|
// ---------------------------------------------------------------------------
|
|
@@ -55,7 +55,7 @@ mock.module("../../browser/operations.js", () => ({
|
|
|
55
55
|
},
|
|
56
56
|
}));
|
|
57
57
|
|
|
58
|
-
mock.module("../../daemon/conversation-
|
|
58
|
+
mock.module("../../daemon/conversation-registry.js", () => ({
|
|
59
59
|
findConversation: (conversationId: string) => {
|
|
60
60
|
mockFindConversationCalls.push(conversationId);
|
|
61
61
|
return mockConversation ?? undefined;
|
|
@@ -32,9 +32,9 @@ let mockSurfaceResult: InteractiveUiResult = {
|
|
|
32
32
|
let mockSurfaceThrows: Error | null = null;
|
|
33
33
|
|
|
34
34
|
// Re-export the real module and override only findConversation.
|
|
35
|
-
const
|
|
36
|
-
mock.module("../../daemon/conversation-
|
|
37
|
-
...
|
|
35
|
+
const realRegistry = await import("../../daemon/conversation-registry.js");
|
|
36
|
+
mock.module("../../daemon/conversation-registry.js", () => ({
|
|
37
|
+
...realRegistry,
|
|
38
38
|
findConversation: (_conversationId: string) => mockConversation ?? undefined,
|
|
39
39
|
}));
|
|
40
40
|
|
|
@@ -91,7 +91,7 @@ describe("ipcGetFeatureFlags", () => {
|
|
|
91
91
|
expect(flags).toEqual({ "flag-a": true, "flag-b": false });
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
test("
|
|
94
|
+
test("accepts boolean and string values, filters other types from response", async () => {
|
|
95
95
|
mockGatewayIpc(null, {
|
|
96
96
|
results: {
|
|
97
97
|
get_feature_flags: {
|
|
@@ -104,7 +104,7 @@ describe("ipcGetFeatureFlags", () => {
|
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
const flags = await ipcGetFeatureFlags();
|
|
107
|
-
expect(flags).toEqual({ valid: true });
|
|
107
|
+
expect(flags).toEqual({ valid: true, string: "yes" });
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
test("returns empty record when IPC returns undefined", async () => {
|
|
@@ -98,12 +98,12 @@ export function resetPersistentClient(): void {
|
|
|
98
98
|
*/
|
|
99
99
|
export async function ipcGetFeatureFlags(
|
|
100
100
|
timeoutMs?: number,
|
|
101
|
-
): Promise<Record<string, boolean>> {
|
|
101
|
+
): Promise<Record<string, boolean | string>> {
|
|
102
102
|
const result = await ipcCall("get_feature_flags", undefined, timeoutMs);
|
|
103
103
|
if (result && typeof result === "object" && !Array.isArray(result)) {
|
|
104
|
-
const filtered: Record<string, boolean> = {};
|
|
104
|
+
const filtered: Record<string, boolean | string> = {};
|
|
105
105
|
for (const [k, v] of Object.entries(result as Record<string, unknown>)) {
|
|
106
|
-
if (typeof v === "boolean") filtered[k] = v;
|
|
106
|
+
if (typeof v === "boolean" || typeof v === "string") filtered[k] = v;
|
|
107
107
|
}
|
|
108
108
|
return filtered;
|
|
109
109
|
}
|
|
@@ -137,6 +137,21 @@ describe("host.memory.addMessage", () => {
|
|
|
137
137
|
}),
|
|
138
138
|
).rejects.toThrow();
|
|
139
139
|
});
|
|
140
|
+
|
|
141
|
+
test("rejects the non-renderable system role", async () => {
|
|
142
|
+
// GIVEN the messages store is UI-facing (ConversationMessage), so only
|
|
143
|
+
// renderable turns may be persisted via this facet
|
|
144
|
+
// WHEN a skill attempts to add a system row
|
|
145
|
+
// THEN the route rejects it instead of persisting agent-context scaffolding
|
|
146
|
+
await expect(
|
|
147
|
+
memoryAddMessageRoute.handler({
|
|
148
|
+
conversationId: "c",
|
|
149
|
+
role: "system",
|
|
150
|
+
content: "agent-context scaffolding",
|
|
151
|
+
}),
|
|
152
|
+
).rejects.toThrow();
|
|
153
|
+
expect(addMessageSpy).not.toHaveBeenCalled();
|
|
154
|
+
});
|
|
140
155
|
});
|
|
141
156
|
|
|
142
157
|
describe("host.memory.wakeAgentForOpportunity", () => {
|
|
@@ -17,7 +17,9 @@ import type { SkillIpcRoute } from "../skill-ipc-types.js";
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* IPC params for `addMessage()`. `role` is constrained to the
|
|
20
|
-
*
|
|
20
|
+
* renderable conversation roles (`user`/`assistant`): the messages store
|
|
21
|
+
* is UI-facing (`ConversationMessage`), so agent-context `system` rows are
|
|
22
|
+
* not accepted here. `metadata` is a free-form record (validated
|
|
21
23
|
* downstream by `messageMetadataSchema` with a warn-and-store fallback).
|
|
22
24
|
* `skipIndexing` and `clientMessageId` mirror `AddMessageOptions`.
|
|
23
25
|
*
|
|
@@ -28,7 +30,7 @@ import type { SkillIpcRoute } from "../skill-ipc-types.js";
|
|
|
28
30
|
*/
|
|
29
31
|
const MemoryAddMessageParams = z.object({
|
|
30
32
|
conversationId: z.string().min(1),
|
|
31
|
-
role: z.enum(["user", "assistant"
|
|
33
|
+
role: z.enum(["user", "assistant"]),
|
|
32
34
|
content: z.string(),
|
|
33
35
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
34
36
|
skipIndexing: z.boolean().optional(),
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type ImageGenCredentials,
|
|
6
6
|
type ImageGenerationRequest,
|
|
7
7
|
type ImageGenerationResult,
|
|
8
|
+
isImageProviderBillingError,
|
|
8
9
|
type ManagedProxyCredentials,
|
|
9
10
|
MAX_VARIANTS,
|
|
10
11
|
} from "./types.js";
|
|
@@ -19,9 +20,18 @@ const ALLOWED_MODELS = new Set([
|
|
|
19
20
|
|
|
20
21
|
// --- Error mapping ---
|
|
21
22
|
|
|
23
|
+
const GEMINI_BILLING_MESSAGE =
|
|
24
|
+
"Image generation is unavailable because the Gemini account or API key is out of credits. " +
|
|
25
|
+
"Add funds with the provider or update the key in Settings — retrying won't help until credits are added.";
|
|
26
|
+
|
|
22
27
|
export function mapGeminiError(error: unknown): string {
|
|
23
28
|
if (error instanceof ApiError) {
|
|
24
29
|
const status = error.status;
|
|
30
|
+
// Billing failures are non-retryable, so check them before the rate-limit
|
|
31
|
+
// branch to avoid telling the user to "wait and try again".
|
|
32
|
+
if (isImageProviderBillingError({ status, message: error.message })) {
|
|
33
|
+
return GEMINI_BILLING_MESSAGE;
|
|
34
|
+
}
|
|
25
35
|
if (status === 400) {
|
|
26
36
|
return "The image request was invalid. Please check your prompt and try again.";
|
|
27
37
|
}
|
|
@@ -37,6 +47,11 @@ export function mapGeminiError(error: unknown): string {
|
|
|
37
47
|
return `Gemini API error (status ${status}). Please try again.`;
|
|
38
48
|
}
|
|
39
49
|
if (error instanceof Error) {
|
|
50
|
+
// The managed proxy surfaces failures as plain Errors whose message embeds
|
|
51
|
+
// the upstream status (e.g. "Managed proxy request failed (402): ...").
|
|
52
|
+
if (isImageProviderBillingError({ message: error.message })) {
|
|
53
|
+
return GEMINI_BILLING_MESSAGE;
|
|
54
|
+
}
|
|
40
55
|
return `Image generation failed: ${error.message}`;
|
|
41
56
|
}
|
|
42
57
|
return "An unexpected error occurred during image generation.";
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type ImageGenCredentials,
|
|
7
7
|
type ImageGenerationRequest,
|
|
8
8
|
type ImageGenerationResult,
|
|
9
|
+
isImageProviderBillingError,
|
|
9
10
|
MAX_VARIANTS,
|
|
10
11
|
} from "./types.js";
|
|
11
12
|
|
|
@@ -16,6 +17,10 @@ const ALLOWED_MODELS = new Set(["gpt-image-2"]);
|
|
|
16
17
|
|
|
17
18
|
// --- Error mapping ---
|
|
18
19
|
|
|
20
|
+
const OPENAI_BILLING_MESSAGE =
|
|
21
|
+
"Image generation is unavailable because the OpenAI account or API key is out of credits. " +
|
|
22
|
+
"Add funds with the provider or update the key in Settings — retrying won't help until credits are added.";
|
|
23
|
+
|
|
19
24
|
/**
|
|
20
25
|
* Map an error raised by the OpenAI Images API to a user-friendly string.
|
|
21
26
|
* Mirrors the status-code branches of `mapGeminiError` in
|
|
@@ -24,6 +29,12 @@ const ALLOWED_MODELS = new Set(["gpt-image-2"]);
|
|
|
24
29
|
export function mapOpenAIError(error: unknown): string {
|
|
25
30
|
if (error instanceof OpenAI.APIError) {
|
|
26
31
|
const status = error.status;
|
|
32
|
+
// Billing failures are non-retryable and can surface as a 402 or as a 429
|
|
33
|
+
// with an `insufficient_quota` body, so check them before the rate-limit
|
|
34
|
+
// branch to avoid telling the user to "wait and try again".
|
|
35
|
+
if (isImageProviderBillingError({ status, message: error.message })) {
|
|
36
|
+
return OPENAI_BILLING_MESSAGE;
|
|
37
|
+
}
|
|
27
38
|
if (status === 400) {
|
|
28
39
|
return "The image request was invalid. Please check your prompt and try again.";
|
|
29
40
|
}
|
|
@@ -39,6 +50,9 @@ export function mapOpenAIError(error: unknown): string {
|
|
|
39
50
|
return `OpenAI API error (status ${status}). Please try again.`;
|
|
40
51
|
}
|
|
41
52
|
if (error instanceof Error) {
|
|
53
|
+
if (isImageProviderBillingError({ message: error.message })) {
|
|
54
|
+
return OPENAI_BILLING_MESSAGE;
|
|
55
|
+
}
|
|
42
56
|
return `Image generation failed: ${error.message}`;
|
|
43
57
|
}
|
|
44
58
|
return "An unexpected error occurred during image generation.";
|
package/src/media/types.ts
CHANGED
|
@@ -44,3 +44,37 @@ export function providerForImageModelPrefix(model: string): ImageGenProvider {
|
|
|
44
44
|
}
|
|
45
45
|
return "gemini";
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Message fragments that indicate a provider billing / insufficient-credits
|
|
50
|
+
* failure. Used by the per-provider error mappers to detect a non-retryable
|
|
51
|
+
* out-of-credits condition that no number of retries will resolve.
|
|
52
|
+
*/
|
|
53
|
+
const BILLING_MESSAGE_PATTERNS: readonly RegExp[] = [
|
|
54
|
+
/credit balance is too low/i,
|
|
55
|
+
/insufficient[\s_-]*credits?/i,
|
|
56
|
+
/insufficient_quota/i,
|
|
57
|
+
/exceeded your current quota/i,
|
|
58
|
+
/out of credits/i,
|
|
59
|
+
/requires more credits/i,
|
|
60
|
+
/billing/i,
|
|
61
|
+
/request failed \(402\)/i,
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Detect a provider billing / insufficient-credits failure from an HTTP status
|
|
66
|
+
* and/or error message. A 402 status is billing by definition; otherwise the
|
|
67
|
+
* message is matched against known billing phrasings (OpenAI's
|
|
68
|
+
* `insufficient_quota` is reported as a 429, so status alone is insufficient).
|
|
69
|
+
*
|
|
70
|
+
* Billing failures are non-retryable: the user must add funds or update the API
|
|
71
|
+
* key. Callers surface a distinct message instead of a generic "try again".
|
|
72
|
+
*/
|
|
73
|
+
export function isImageProviderBillingError(args: {
|
|
74
|
+
status?: number;
|
|
75
|
+
message?: string;
|
|
76
|
+
}): boolean {
|
|
77
|
+
if (args.status === 402) return true;
|
|
78
|
+
const message = args.message ?? "";
|
|
79
|
+
return BILLING_MESSAGE_PATTERNS.some((pattern) => pattern.test(message));
|
|
80
|
+
}
|
|
@@ -72,6 +72,7 @@ const CONSOLIDATE_CHECKPOINT_KEY = "memory_v2_consolidate_last_run";
|
|
|
72
72
|
|
|
73
73
|
function buildConfig(overrides: {
|
|
74
74
|
v2Enabled?: boolean;
|
|
75
|
+
consolidationEnabled?: boolean;
|
|
75
76
|
intervalHours?: number;
|
|
76
77
|
maxBufferLines?: number | null;
|
|
77
78
|
}) {
|
|
@@ -79,6 +80,13 @@ function buildConfig(overrides: {
|
|
|
79
80
|
if (overrides.v2Enabled !== undefined) {
|
|
80
81
|
partial.memory.v2.enabled = overrides.v2Enabled;
|
|
81
82
|
}
|
|
83
|
+
if (overrides.consolidationEnabled !== undefined) {
|
|
84
|
+
(
|
|
85
|
+
partial.memory.v2 as typeof partial.memory.v2 & {
|
|
86
|
+
consolidation_enabled?: boolean;
|
|
87
|
+
}
|
|
88
|
+
).consolidation_enabled = overrides.consolidationEnabled;
|
|
89
|
+
}
|
|
82
90
|
if (overrides.intervalHours !== undefined) {
|
|
83
91
|
partial.memory.v2.consolidation_interval_hours = overrides.intervalHours;
|
|
84
92
|
}
|
|
@@ -110,6 +118,15 @@ function countPendingJobs(type: string): number {
|
|
|
110
118
|
.all().length;
|
|
111
119
|
}
|
|
112
120
|
|
|
121
|
+
function consolidationJobPayloads(): Record<string, unknown>[] {
|
|
122
|
+
return getDb()
|
|
123
|
+
.select({ payload: memoryJobs.payload })
|
|
124
|
+
.from(memoryJobs)
|
|
125
|
+
.where(eq(memoryJobs.type, "memory_v2_consolidate"))
|
|
126
|
+
.all()
|
|
127
|
+
.map((row) => JSON.parse(row.payload) as Record<string, unknown>);
|
|
128
|
+
}
|
|
129
|
+
|
|
113
130
|
// Initialize the DB once for the file; clear per-test tables in beforeEach
|
|
114
131
|
// rather than tearing down the singleton, which is slow because it re-runs
|
|
115
132
|
// every migration on the next access.
|
|
@@ -138,6 +155,7 @@ describe("maybeEnqueueGraphMaintenanceJobs — memory v2 consolidation", () => {
|
|
|
138
155
|
maybeEnqueueGraphMaintenanceJobs(config, Date.now());
|
|
139
156
|
|
|
140
157
|
expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
|
|
158
|
+
expect(consolidationJobPayloads()).toEqual([{ trigger: "automatic" }]);
|
|
141
159
|
// v1 entries are suppressed when v2 is active.
|
|
142
160
|
expect(countPendingJobs("graph_decay")).toBe(0);
|
|
143
161
|
expect(countPendingJobs("graph_consolidate")).toBe(0);
|
|
@@ -170,6 +188,7 @@ describe("maybeEnqueueGraphMaintenanceJobs — memory v2 consolidation", () => {
|
|
|
170
188
|
maybeEnqueueGraphMaintenanceJobs(config, now);
|
|
171
189
|
|
|
172
190
|
expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
|
|
191
|
+
expect(consolidationJobPayloads()).toEqual([{ trigger: "automatic" }]);
|
|
173
192
|
});
|
|
174
193
|
|
|
175
194
|
test("respects a custom consolidation_interval_hours value", () => {
|
|
@@ -231,6 +250,28 @@ describe("maybeEnqueueGraphMaintenanceJobs — memory v2 consolidation", () => {
|
|
|
231
250
|
expect(countPendingJobs("graph_narrative_refine")).toBe(1);
|
|
232
251
|
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
233
252
|
});
|
|
253
|
+
|
|
254
|
+
test("automatic consolidation off suppresses the v2 schedule without re-enabling v1 maintenance", () => {
|
|
255
|
+
const config = buildConfig({
|
|
256
|
+
v2Enabled: true,
|
|
257
|
+
consolidationEnabled: false,
|
|
258
|
+
intervalHours: 1,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
deleteMemoryCheckpoint("graph_maintenance:decay:last_run");
|
|
262
|
+
deleteMemoryCheckpoint("graph_maintenance:consolidate:last_run");
|
|
263
|
+
deleteMemoryCheckpoint("graph_maintenance:pattern_scan:last_run");
|
|
264
|
+
deleteMemoryCheckpoint("graph_maintenance:narrative:last_run");
|
|
265
|
+
deleteMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY);
|
|
266
|
+
|
|
267
|
+
maybeEnqueueGraphMaintenanceJobs(config, Date.now());
|
|
268
|
+
|
|
269
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
270
|
+
expect(countPendingJobs("graph_decay")).toBe(0);
|
|
271
|
+
expect(countPendingJobs("graph_consolidate")).toBe(0);
|
|
272
|
+
expect(countPendingJobs("graph_pattern_scan")).toBe(0);
|
|
273
|
+
expect(countPendingJobs("graph_narrative_refine")).toBe(0);
|
|
274
|
+
});
|
|
234
275
|
});
|
|
235
276
|
|
|
236
277
|
describe("maybeEnqueueGraphMaintenanceJobs — buffer-size trigger", () => {
|
|
@@ -369,4 +410,19 @@ describe("maybeEnqueueGraphMaintenanceJobs — buffer-size trigger", () => {
|
|
|
369
410
|
|
|
370
411
|
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
371
412
|
});
|
|
413
|
+
|
|
414
|
+
test("size trigger inert when automatic consolidation is disabled", () => {
|
|
415
|
+
const config = buildConfig({
|
|
416
|
+
v2Enabled: true,
|
|
417
|
+
consolidationEnabled: false,
|
|
418
|
+
intervalHours: 1,
|
|
419
|
+
maxBufferLines: 1,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
writeBuffer(100);
|
|
423
|
+
|
|
424
|
+
maybeEnqueueGraphMaintenanceJobs(config, Date.now());
|
|
425
|
+
|
|
426
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
427
|
+
});
|
|
372
428
|
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { and, asc, eq, gt, or } from "drizzle-orm";
|
|
2
|
+
import { v4 as uuid } from "uuid";
|
|
3
|
+
|
|
4
|
+
import { getConfig } from "../config/loader.js";
|
|
5
|
+
import { getDb } from "./db-connection.js";
|
|
6
|
+
import { authFallbackEvents } from "./schema.js";
|
|
7
|
+
|
|
8
|
+
/** A single aggregated auth-fallback count for one (guard, path, failure_kind). */
|
|
9
|
+
export interface AuthFallbackCount {
|
|
10
|
+
guard: string;
|
|
11
|
+
path: string;
|
|
12
|
+
failureKind: string;
|
|
13
|
+
count: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** A persisted auth-fallback event row. */
|
|
17
|
+
export interface AuthFallbackEvent {
|
|
18
|
+
id: string;
|
|
19
|
+
createdAt: number;
|
|
20
|
+
guard: string;
|
|
21
|
+
path: string;
|
|
22
|
+
failureKind: string;
|
|
23
|
+
count: number;
|
|
24
|
+
windowStart: number;
|
|
25
|
+
windowEnd: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Record a batch of aggregated auth-fallback counts forwarded by the gateway —
|
|
30
|
+
* one row per count entry, all sharing the same flush window. Returns the
|
|
31
|
+
* number of rows recorded, or 0 when usage data collection is disabled (the
|
|
32
|
+
* counts are dropped to honor the opt-out, matching the rest of telemetry).
|
|
33
|
+
*/
|
|
34
|
+
export function recordAuthFallbackCounts(
|
|
35
|
+
windowStart: number,
|
|
36
|
+
windowEnd: number,
|
|
37
|
+
counts: AuthFallbackCount[],
|
|
38
|
+
): number {
|
|
39
|
+
if (!getConfig().collectUsageData) return 0;
|
|
40
|
+
if (counts.length === 0) return 0;
|
|
41
|
+
const db = getDb();
|
|
42
|
+
const createdAt = Date.now();
|
|
43
|
+
const rows = counts.map((c) => ({
|
|
44
|
+
id: uuid(),
|
|
45
|
+
createdAt,
|
|
46
|
+
guard: c.guard,
|
|
47
|
+
path: c.path,
|
|
48
|
+
failureKind: c.failureKind,
|
|
49
|
+
count: c.count,
|
|
50
|
+
windowStart,
|
|
51
|
+
windowEnd,
|
|
52
|
+
}));
|
|
53
|
+
db.insert(authFallbackEvents).values(rows).run();
|
|
54
|
+
return rows.length;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Query auth-fallback events that haven't been reported to telemetry yet.
|
|
59
|
+
* Uses a compound cursor (createdAt + id) for reliable watermarking.
|
|
60
|
+
*/
|
|
61
|
+
export function queryUnreportedAuthFallbackEvents(
|
|
62
|
+
afterCreatedAt: number,
|
|
63
|
+
afterId: string | undefined,
|
|
64
|
+
limit: number,
|
|
65
|
+
): AuthFallbackEvent[] {
|
|
66
|
+
const db = getDb();
|
|
67
|
+
const rows = db
|
|
68
|
+
.select({
|
|
69
|
+
id: authFallbackEvents.id,
|
|
70
|
+
createdAt: authFallbackEvents.createdAt,
|
|
71
|
+
guard: authFallbackEvents.guard,
|
|
72
|
+
path: authFallbackEvents.path,
|
|
73
|
+
failureKind: authFallbackEvents.failureKind,
|
|
74
|
+
count: authFallbackEvents.count,
|
|
75
|
+
windowStart: authFallbackEvents.windowStart,
|
|
76
|
+
windowEnd: authFallbackEvents.windowEnd,
|
|
77
|
+
})
|
|
78
|
+
.from(authFallbackEvents)
|
|
79
|
+
.where(
|
|
80
|
+
afterId
|
|
81
|
+
? or(
|
|
82
|
+
gt(authFallbackEvents.createdAt, afterCreatedAt),
|
|
83
|
+
and(
|
|
84
|
+
eq(authFallbackEvents.createdAt, afterCreatedAt),
|
|
85
|
+
gt(authFallbackEvents.id, afterId),
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
: gt(authFallbackEvents.createdAt, afterCreatedAt),
|
|
89
|
+
)
|
|
90
|
+
.orderBy(asc(authFallbackEvents.createdAt), asc(authFallbackEvents.id))
|
|
91
|
+
.limit(limit)
|
|
92
|
+
.all();
|
|
93
|
+
return rows;
|
|
94
|
+
}
|
|
@@ -15,6 +15,7 @@ import { memoryCheckpoints } from "./schema.js";
|
|
|
15
15
|
export const CK_ITEM_COUNT = "conversation_starters:item_count_at_last_gen";
|
|
16
16
|
export const CK_BATCH = "conversation_starters:generation_batch";
|
|
17
17
|
export const CK_LAST_GEN_AT = "conversation_starters:last_gen_at";
|
|
18
|
+
export const CK_LAST_ATTEMPT_AT = "conversation_starters:last_attempt_at";
|
|
18
19
|
|
|
19
20
|
export function checkpointKey(base: string, scopeId: string): string {
|
|
20
21
|
return `${base}:${scopeId}`;
|