@vellumai/assistant 0.6.5 → 0.6.6
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 +9 -1
- package/ARCHITECTURE.md +15 -17
- package/Dockerfile +6 -4
- package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
- package/docs/architecture/integrations.md +32 -39
- package/docs/architecture/memory.md +25 -30
- package/docs/architecture/security.md +7 -6
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/plugins.md +761 -0
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/openapi.yaml +212 -68
- package/package.json +1 -1
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/approval-cascade.test.ts +7 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/catalog-cache.test.ts +69 -0
- package/src/__tests__/checker.test.ts +459 -171
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/compaction-events.test.ts +501 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/config-model-image-provider.test.ts +110 -0
- package/src/__tests__/config-schema.test.ts +22 -9
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/contacts-tools.test.ts +26 -0
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-window-manager.test.ts +355 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +26 -30
- package/src/__tests__/conversation-agent-loop.test.ts +30 -141
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -1
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +2 -16
- package/src/__tests__/conversation-pairing.test.ts +174 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -1
- package/src/__tests__/conversation-process-callsite.test.ts +3 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +16 -7
- package/src/__tests__/conversation-queue.test.ts +29 -14
- package/src/__tests__/conversation-routes-disk-view.test.ts +7 -6
- package/src/__tests__/conversation-runtime-assembly.test.ts +155 -110
- package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-slash-queue.test.ts +7 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +25 -2
- package/src/__tests__/conversation-speed-override.test.ts +6 -1
- package/src/__tests__/conversation-title-service.test.ts +116 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
- package/src/__tests__/conversation-usage.test.ts +1 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +3 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -1
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +2 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +3 -3
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
- package/src/__tests__/host-proxy-interface.test.ts +36 -2
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/injector-chain.test.ts +526 -0
- package/src/__tests__/intent-routing.test.ts +0 -26
- package/src/__tests__/llm-call-pipeline.test.ts +285 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +5 -68
- package/src/__tests__/model-intents.test.ts +4 -2
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
- package/src/__tests__/oauth-apps-routes.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +14 -12
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
- package/src/__tests__/oauth-providers-routes.test.ts +3 -2
- package/src/__tests__/oauth-store.test.ts +41 -76
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +0 -24
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +377 -0
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/platform.test.ts +5 -2
- package/src/__tests__/plugin-bootstrap.test.ts +483 -0
- package/src/__tests__/plugin-registry.test.ts +273 -0
- package/src/__tests__/plugin-route-contribution.test.ts +288 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +44 -12
- package/src/__tests__/proxy-approval-callback.test.ts +69 -8
- package/src/__tests__/reaction-persistence.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +0 -2
- package/src/__tests__/schedule-routes.test.ts +131 -1
- package/src/__tests__/scheduler-recurrence.test.ts +14 -70
- package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
- package/src/__tests__/secret-detection-handler.test.ts +0 -10
- package/src/__tests__/shell-identity.test.ts +0 -134
- package/src/__tests__/suggestion-routes.test.ts +103 -4
- package/src/__tests__/task-memory-cleanup.test.ts +1 -0
- package/src/__tests__/task-scheduler.test.ts +3 -15
- package/src/__tests__/test-preload.ts +11 -0
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -6
- package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
- package/src/__tests__/tool-executor.test.ts +141 -0
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/user-plugin-loader.test.ts +191 -0
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-policy.test.ts +21 -3
- package/src/agent/loop.ts +340 -102
- package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
- package/src/approvals/guardian-request-resolvers.ts +80 -0
- package/src/backup/__tests__/backup-worker.test.ts +2 -13
- package/src/backup/backup-worker.ts +3 -15
- package/src/bundler/app-compiler.ts +84 -1
- package/src/calls/call-state.ts +2 -2
- package/src/channels/__tests__/types.test.ts +3 -3
- package/src/channels/types.ts +6 -4
- package/src/cli/__tests__/notifications.test.ts +87 -211
- package/src/cli/commands/__tests__/backup.test.ts +1 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
- package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
- package/src/cli/commands/backup.ts +2 -2
- package/src/cli/commands/clients.ts +138 -0
- package/src/cli/commands/completions.ts +2 -9
- package/src/cli/commands/conversations.ts +55 -7
- package/src/cli/commands/image-generation.ts +33 -34
- package/src/cli/commands/notifications.ts +68 -103
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +2 -2
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/skills.ts +3 -4
- package/src/cli/program.ts +25 -29
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-tool-registry.ts +0 -15
- package/src/config/feature-flag-registry.json +17 -1
- package/src/config/schema.ts +19 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/llm.ts +2 -3
- package/src/config/schemas/security.ts +6 -6
- package/src/config/schemas/tts.ts +11 -0
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +94 -5
- package/src/context/__tests__/compact-prompt.test.ts +27 -9
- package/src/context/prompts/compact.md +26 -12
- package/src/context/tool-result-truncation.ts +3 -63
- package/src/context/window-manager.ts +190 -16
- package/src/credential-health/credential-health-service.ts +19 -6
- package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/config-watcher.ts +0 -2
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +83 -22
- package/src/daemon/conversation-agent-loop.ts +984 -683
- package/src/daemon/conversation-history.ts +10 -19
- package/src/daemon/conversation-lifecycle.ts +37 -19
- package/src/daemon/conversation-notifiers.ts +2 -110
- package/src/daemon/conversation-process.ts +14 -7
- package/src/daemon/conversation-runtime-assembly.ts +532 -411
- package/src/daemon/conversation-tool-setup.ts +41 -4
- package/src/daemon/conversation.ts +80 -35
- package/src/daemon/external-plugins-bootstrap.ts +478 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/handlers/config-model.ts +11 -0
- package/src/daemon/handlers/skills.ts +5 -1
- package/src/daemon/lifecycle.ts +33 -68
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +49 -0
- package/src/daemon/message-types/messages.ts +12 -0
- package/src/daemon/server.ts +5 -3
- package/src/daemon/shutdown-handlers.ts +2 -12
- package/src/daemon/tool-side-effects.ts +14 -56
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
- package/src/heartbeat/heartbeat-service.ts +24 -1
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/emit-feed-event.ts +7 -0
- package/src/home/feed-types.ts +41 -2
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/ipc/__tests__/socket-path.test.ts +11 -50
- package/src/ipc/cli-client.ts +1 -1
- package/src/ipc/cli-server.ts +3 -3
- package/src/ipc/gateway-client.ts +4 -1
- package/src/ipc/routes/browser-context.ts +2 -0
- package/src/ipc/routes/browser.ts +1 -0
- package/src/ipc/routes/get-contact.ts +16 -0
- package/src/ipc/routes/index.ts +14 -0
- package/src/ipc/routes/list-clients.ts +31 -0
- package/src/ipc/routes/merge-contacts.ts +17 -0
- package/src/ipc/routes/notification.ts +133 -0
- package/src/ipc/routes/rename-conversation.ts +59 -0
- package/src/ipc/routes/search-contacts.ts +19 -0
- package/src/ipc/routes/upsert-contact.ts +25 -0
- package/src/ipc/socket-path.ts +14 -38
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/conversation-crud.ts +48 -18
- package/src/memory/conversation-queries.ts +57 -4
- package/src/memory/conversation-title-service.ts +25 -0
- package/src/memory/db-init.ts +8 -0
- package/src/memory/embedding-gemini.test.ts +41 -2
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/graph/bootstrap.test.ts +282 -0
- package/src/memory/graph/bootstrap.ts +8 -5
- package/src/memory/graph/extraction.ts +10 -2
- package/src/memory/graph/graph-search.test.ts +1 -0
- package/src/memory/graph/inspect.ts +2 -2
- package/src/memory/graph/retriever.ts +10 -3
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/pkb/pkb-index.test.ts +1 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +65 -4
- package/src/memory/pkb/pkb-search.ts +40 -18
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +25 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/schema/oauth.ts +4 -1
- package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
- package/src/messaging/providers/slack/render-transcript.ts +58 -0
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +1 -2
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +30 -14
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -108
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/permissions/approval-policy.test.ts +293 -18
- package/src/permissions/approval-policy.ts +110 -58
- package/src/permissions/arg-parser.test.ts +161 -0
- package/src/permissions/arg-parser.ts +141 -0
- package/src/permissions/bash-risk-classifier.test.ts +414 -2
- package/src/permissions/bash-risk-classifier.ts +303 -60
- package/src/permissions/checker.ts +157 -29
- package/src/permissions/command-registry.test.ts +239 -0
- package/src/permissions/command-registry.ts +234 -54
- package/src/permissions/defaults.ts +5 -4
- package/src/permissions/gateway-threshold-reader.ts +196 -0
- package/src/permissions/prompter.ts +4 -0
- package/src/permissions/risk-types.ts +61 -4
- package/src/permissions/schedule-risk-classifier.test.ts +129 -0
- package/src/permissions/schedule-risk-classifier.ts +85 -0
- package/src/permissions/shell-identity.ts +2 -42
- package/src/permissions/types.ts +2 -0
- package/src/permissions/workspace-policy.ts +8 -3
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +491 -0
- package/src/plugins/defaults/llm-call.ts +82 -0
- package/src/plugins/defaults/memory-retrieval.ts +226 -0
- package/src/plugins/defaults/overflow-reduce.ts +181 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +104 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +241 -0
- package/src/plugins/types.ts +1134 -0
- package/src/plugins/user-loader.ts +177 -0
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/providers/model-catalog.ts +52 -29
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
- package/src/providers/speech-to-text/xai-realtime.ts +39 -14
- package/src/runtime/AGENTS.md +25 -16
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
- package/src/runtime/__tests__/client-registry.test.ts +293 -0
- package/src/runtime/client-registry.ts +261 -0
- package/src/runtime/http-server.ts +77 -8
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +1 -22
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
- package/src/runtime/routes/approval-routes.ts +17 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
- package/src/runtime/routes/conversation-routes.ts +223 -116
- package/src/runtime/routes/inbound-message-handler.ts +88 -13
- package/src/runtime/routes/memory-item-routes.test.ts +1 -0
- package/src/runtime/routes/migration-routes.ts +0 -3
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
- package/src/runtime/routes/playground/deps.ts +56 -0
- package/src/runtime/routes/playground/force-compact.ts +73 -0
- package/src/runtime/routes/playground/guard.ts +37 -0
- package/src/runtime/routes/playground/index.ts +28 -0
- package/src/runtime/routes/playground/inject-failures.ts +159 -0
- package/src/runtime/routes/playground/reset-circuit.ts +115 -0
- package/src/runtime/routes/playground/seed-conversation.ts +139 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
- package/src/runtime/routes/playground/state.ts +78 -0
- package/src/runtime/routes/schedule-routes.ts +89 -8
- package/src/runtime/skill-route-registry.ts +75 -15
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +7 -1
- package/src/schedule/scheduler.ts +48 -8
- package/src/skills/catalog-cache.ts +12 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
- package/src/tools/browser/browser-execution.ts +88 -19
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/executor.ts +126 -74
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/permission-checker.ts +98 -49
- package/src/tools/policy-context.ts +4 -0
- package/src/tools/registry.ts +140 -3
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +0 -51
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/types.ts +28 -2
- package/src/util/platform.ts +7 -2
- package/src/util/pricing.ts +26 -3
- package/src/workspace/migrations/006-services-config.ts +2 -4
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/oauth/scope-policy.ts +0 -89
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/signals/shotgun.ts +0 -203
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
|
@@ -107,6 +107,9 @@ export const messageMetadataSchema = z
|
|
|
107
107
|
memoryInjectedBlock: z.string().optional(),
|
|
108
108
|
turnContextBlock: z.string().optional(),
|
|
109
109
|
pkbSystemReminderBlock: z.string().optional(),
|
|
110
|
+
workspaceBlock: z.string().optional(),
|
|
111
|
+
nowScratchpadBlock: z.string().optional(),
|
|
112
|
+
pkbContextBlock: z.string().optional(),
|
|
110
113
|
})
|
|
111
114
|
.passthrough();
|
|
112
115
|
|
|
@@ -1048,20 +1051,26 @@ export function getMessages(conversationId: string): MessageRow[] {
|
|
|
1048
1051
|
}
|
|
1049
1052
|
|
|
1050
1053
|
/**
|
|
1051
|
-
*
|
|
1052
|
-
*
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
1055
|
-
*
|
|
1056
|
-
*
|
|
1054
|
+
* Return raw `metadata` strings for messages whose metadata contains the
|
|
1055
|
+
* literal substring `"slackMeta"`, capped at `limit` and skipping the first
|
|
1056
|
+
* `offset` matches. Pushes `LIKE` + `LIMIT`/`OFFSET` into SQL so warm Slack
|
|
1057
|
+
* DM conversations don't require a full-table scan on the webhook critical
|
|
1058
|
+
* path. The substring match is an indexable prefilter only — callers must
|
|
1059
|
+
* parse and validate each returned string against the Slack metadata schema,
|
|
1060
|
+
* because a malformed row (partial write, legacy format, unrelated key
|
|
1061
|
+
* accidentally containing the literal) can still slip through the substring
|
|
1062
|
+
* match. Callers that need a fixed number of *valid* rows should iterate
|
|
1063
|
+
* with increasing offsets until the target is reached (capped at a
|
|
1064
|
+
* reasonable maximum to bound scan cost).
|
|
1057
1065
|
*/
|
|
1058
|
-
export function
|
|
1066
|
+
export function selectSlackMetaCandidateMetadata(
|
|
1059
1067
|
conversationId: string,
|
|
1060
1068
|
limit: number,
|
|
1061
|
-
|
|
1069
|
+
offset = 0,
|
|
1070
|
+
): string[] {
|
|
1062
1071
|
const db = getDb();
|
|
1063
1072
|
const rows = db
|
|
1064
|
-
.select({
|
|
1073
|
+
.select({ metadata: messages.metadata })
|
|
1065
1074
|
.from(messages)
|
|
1066
1075
|
.where(
|
|
1067
1076
|
and(
|
|
@@ -1069,9 +1078,17 @@ export function countMessagesWithSlackMeta(
|
|
|
1069
1078
|
like(messages.metadata, '%"slackMeta"%'),
|
|
1070
1079
|
),
|
|
1071
1080
|
)
|
|
1081
|
+
.orderBy(asc(messages.createdAt))
|
|
1072
1082
|
.limit(limit)
|
|
1083
|
+
.offset(offset)
|
|
1073
1084
|
.all();
|
|
1074
|
-
|
|
1085
|
+
const out: string[] = [];
|
|
1086
|
+
for (const r of rows) {
|
|
1087
|
+
if (typeof r.metadata === "string" && r.metadata.length > 0) {
|
|
1088
|
+
out.push(r.metadata);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
return out;
|
|
1075
1092
|
}
|
|
1076
1093
|
|
|
1077
1094
|
/**
|
|
@@ -1503,22 +1520,35 @@ export function updateMessageMetadata(
|
|
|
1503
1520
|
}
|
|
1504
1521
|
|
|
1505
1522
|
/**
|
|
1506
|
-
* Bulk-remove the
|
|
1507
|
-
*
|
|
1508
|
-
*
|
|
1509
|
-
*
|
|
1510
|
-
*
|
|
1523
|
+
* Bulk-remove the metadata fields that back the blocks stripped by
|
|
1524
|
+
* `stripInjectionsForCompaction` — currently `pkbSystemReminderBlock`
|
|
1525
|
+
* (`<system_reminder>`), `nowScratchpadBlock` (`<NOW.md …>`), and
|
|
1526
|
+
* `pkbContextBlock` (`<knowledge_base>`). Called from compaction-strip
|
|
1527
|
+
* sites so post-restart rehydration stays consistent with the in-memory
|
|
1528
|
+
* state produced by `stripInjectionsForCompaction` (which removes those
|
|
1529
|
+
* tags from live messages but cannot touch the DB). Fields backing
|
|
1530
|
+
* blocks that are intentionally NOT stripped (`turnContextBlock`,
|
|
1531
|
+
* `workspaceBlock`, `memoryInjectedBlock`) are preserved.
|
|
1511
1532
|
*/
|
|
1512
|
-
export function
|
|
1533
|
+
export function clearStrippedInjectionMetadataForConversation(
|
|
1513
1534
|
conversationId: string,
|
|
1514
1535
|
): void {
|
|
1515
1536
|
rawRun(
|
|
1516
1537
|
`UPDATE messages
|
|
1517
|
-
SET metadata = json_remove(
|
|
1538
|
+
SET metadata = json_remove(
|
|
1539
|
+
metadata,
|
|
1540
|
+
'$.pkbSystemReminderBlock',
|
|
1541
|
+
'$.nowScratchpadBlock',
|
|
1542
|
+
'$.pkbContextBlock'
|
|
1543
|
+
)
|
|
1518
1544
|
WHERE conversation_id = ?
|
|
1519
1545
|
AND role = 'user'
|
|
1520
1546
|
AND metadata IS NOT NULL
|
|
1521
|
-
AND
|
|
1547
|
+
AND (
|
|
1548
|
+
json_extract(metadata, '$.pkbSystemReminderBlock') IS NOT NULL
|
|
1549
|
+
OR json_extract(metadata, '$.nowScratchpadBlock') IS NOT NULL
|
|
1550
|
+
OR json_extract(metadata, '$.pkbContextBlock') IS NOT NULL
|
|
1551
|
+
)`,
|
|
1522
1552
|
conversationId,
|
|
1523
1553
|
);
|
|
1524
1554
|
}
|
|
@@ -88,6 +88,59 @@ export function listPinnedConversations(): ConversationRow[] {
|
|
|
88
88
|
return query.all().map(parseConversation);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Row shape returned by {@link listConversationsByTitlePrefix}.
|
|
93
|
+
*
|
|
94
|
+
* Kept deliberately narrow (no full `ConversationRow`) since the only caller
|
|
95
|
+
* today is the playground's seeded-conversation listing endpoint, which only
|
|
96
|
+
* needs display metadata plus a message count to show in a list.
|
|
97
|
+
*/
|
|
98
|
+
export interface ConversationTitlePrefixRow {
|
|
99
|
+
id: string;
|
|
100
|
+
title: string;
|
|
101
|
+
messageCount: number;
|
|
102
|
+
createdAt: number;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* List non-archived conversations whose `title` begins with `prefix`.
|
|
107
|
+
*
|
|
108
|
+
* Uses raw SQL with a subquery for `messageCount` so a single round-trip
|
|
109
|
+
* returns everything the caller needs. The `LIKE ? || '%'` pattern does a
|
|
110
|
+
* prefix match; SQLite optimizes this with an index when one exists on
|
|
111
|
+
* `title`, otherwise it degrades to a table scan — acceptable for the
|
|
112
|
+
* playground-seeded set, which is small by construction.
|
|
113
|
+
*
|
|
114
|
+
* Escaping is unnecessary here because the prefix is a build-time constant
|
|
115
|
+
* (`PLAYGROUND_TITLE_PREFIX`) rather than user input. If callers ever pass
|
|
116
|
+
* dynamic prefixes, switch to `ESCAPE '\\'` and pre-escape `%` / `_` / `\`.
|
|
117
|
+
*/
|
|
118
|
+
export function listConversationsByTitlePrefix(
|
|
119
|
+
prefix: string,
|
|
120
|
+
): ConversationTitlePrefixRow[] {
|
|
121
|
+
interface Row {
|
|
122
|
+
id: string;
|
|
123
|
+
title: string;
|
|
124
|
+
message_count: number;
|
|
125
|
+
created_at: number;
|
|
126
|
+
}
|
|
127
|
+
const rows = rawAll<Row>(
|
|
128
|
+
`SELECT c.id, c.title,
|
|
129
|
+
(SELECT COUNT(*) FROM messages WHERE conversation_id = c.id) AS message_count,
|
|
130
|
+
c.created_at
|
|
131
|
+
FROM conversations c
|
|
132
|
+
WHERE c.title LIKE ? || '%' AND c.archived_at IS NULL
|
|
133
|
+
ORDER BY c.created_at DESC`,
|
|
134
|
+
prefix,
|
|
135
|
+
);
|
|
136
|
+
return rows.map((r) => ({
|
|
137
|
+
id: r.id,
|
|
138
|
+
title: r.title,
|
|
139
|
+
messageCount: r.message_count,
|
|
140
|
+
createdAt: r.created_at,
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
|
|
91
144
|
export function countConversations(backgroundOnly = false): number {
|
|
92
145
|
const db = getDb();
|
|
93
146
|
const where = backgroundOnly
|
|
@@ -257,10 +310,10 @@ export function searchConversations(
|
|
|
257
310
|
.from(conversations)
|
|
258
311
|
.where(
|
|
259
312
|
and(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
313
|
+
sql`${conversations.conversationType} NOT IN ('background', 'private', 'scheduled')`,
|
|
314
|
+
sql`${conversations.title} LIKE ${titlePattern} ESCAPE '\\'`,
|
|
315
|
+
sql`${conversations.archivedAt} IS NULL`,
|
|
316
|
+
),
|
|
264
317
|
)
|
|
265
318
|
.all();
|
|
266
319
|
for (const row of titleMatchConvs) ftsConvIds.add(row.id);
|
|
@@ -234,6 +234,12 @@ export async function regenerateConversationTitle(
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
const prompt = buildRegenerationPrompt(recentMessages);
|
|
237
|
+
// Skip the LLM call if no messages yielded extractable text — the prompt
|
|
238
|
+
// would be just the "Recent messages:" header, and the model tends to
|
|
239
|
+
// fabricate a meta-title about the emptiness rather than decline.
|
|
240
|
+
if (!/\n(?:User|Assistant): /.test(prompt)) {
|
|
241
|
+
return { title: conversation.title ?? UNTITLED_FALLBACK, updated: false };
|
|
242
|
+
}
|
|
237
243
|
const result = await runBtwSidechain({
|
|
238
244
|
content: prompt,
|
|
239
245
|
provider,
|
|
@@ -296,6 +302,7 @@ function buildTitleSystemPrompt(): string {
|
|
|
296
302
|
"- Do NOT echo back what the user asked you to do",
|
|
297
303
|
"- Do NOT respond to the conversation content",
|
|
298
304
|
"- Do NOT assess feasibility or comment on capabilities",
|
|
305
|
+
"- If input is sparse or references external context, extract a topic from the words that ARE present (e.g. 'so about that t-shirt...' → 'T-Shirt Discussion'). Never describe the absence, emptiness, or insufficiency of context — titles like 'Missing Context', 'Unclear Request', 'No Topic' are forbidden",
|
|
299
306
|
].join("\n");
|
|
300
307
|
}
|
|
301
308
|
|
|
@@ -329,9 +336,27 @@ function buildTitlePrompt(
|
|
|
329
336
|
return parts.join("\n");
|
|
330
337
|
}
|
|
331
338
|
|
|
339
|
+
const META_FAILURE_TITLES = new Set([
|
|
340
|
+
"missing context",
|
|
341
|
+
"no context",
|
|
342
|
+
"insufficient context",
|
|
343
|
+
"unclear context",
|
|
344
|
+
"empty context",
|
|
345
|
+
"no topic",
|
|
346
|
+
"unclear topic",
|
|
347
|
+
"unclear request",
|
|
348
|
+
"unclear message",
|
|
349
|
+
"empty conversation",
|
|
350
|
+
"empty message",
|
|
351
|
+
"no content",
|
|
352
|
+
]);
|
|
353
|
+
|
|
332
354
|
function normalizeTitle(raw: string): string {
|
|
333
355
|
let title = raw.trim().replace(/^["']|["']$/g, "");
|
|
334
356
|
title = stripMarkdown(title);
|
|
357
|
+
if (META_FAILURE_TITLES.has(title.toLowerCase())) {
|
|
358
|
+
return "";
|
|
359
|
+
}
|
|
335
360
|
return title;
|
|
336
361
|
}
|
|
337
362
|
|
package/src/memory/db-init.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
addCoreColumns,
|
|
18
18
|
createActorRefreshTokenRecordsTable,
|
|
19
19
|
createActorTokenRecordsTable,
|
|
20
|
+
createApprovalPromptTsTrackerTable,
|
|
20
21
|
createAssistantInboxTables,
|
|
21
22
|
createCallSessionsTables,
|
|
22
23
|
createCanonicalGuardianTables,
|
|
@@ -110,11 +111,13 @@ import {
|
|
|
110
111
|
migrateNormalizeUserFileByPrincipal,
|
|
111
112
|
migrateNotificationDeliveryThreadDecision,
|
|
112
113
|
migrateOAuthAppsClientSecretPath,
|
|
114
|
+
migrateOAuthProvidersAvailableScopes,
|
|
113
115
|
migrateOAuthProvidersBehaviorColumns,
|
|
114
116
|
migrateOAuthProvidersDisplayMetadata,
|
|
115
117
|
migrateOAuthProvidersFeatureFlag,
|
|
116
118
|
migrateOAuthProvidersLogoUrl,
|
|
117
119
|
migrateOAuthProvidersManagedServiceConfigKey,
|
|
120
|
+
migrateOAuthProvidersManagedServiceIsPaid,
|
|
118
121
|
migrateOAuthProvidersPingConfig,
|
|
119
122
|
migrateOAuthProvidersPingUrl,
|
|
120
123
|
migrateOAuthProvidersRefreshUrl,
|
|
@@ -143,6 +146,7 @@ import {
|
|
|
143
146
|
migrateScheduleOneShotRouting,
|
|
144
147
|
migrateScheduleQuietFlag,
|
|
145
148
|
migrateScheduleReuseConversation,
|
|
149
|
+
migrateScheduleScriptColumn,
|
|
146
150
|
migrateSchemaIndexesAndColumns,
|
|
147
151
|
migrateScrubCorruptedImageAttachments,
|
|
148
152
|
migrateStripIntegrationPrefixFromProviderKeys,
|
|
@@ -267,6 +271,7 @@ export function initializeDb(): void {
|
|
|
267
271
|
migrateInviteCodeHashColumn,
|
|
268
272
|
createActorTokenRecordsTable,
|
|
269
273
|
createActorRefreshTokenRecordsTable,
|
|
274
|
+
createApprovalPromptTsTrackerTable,
|
|
270
275
|
migrateGuardianPrincipalIdColumns,
|
|
271
276
|
migrateBackfillGuardianPrincipalId,
|
|
272
277
|
migrateGuardianPrincipalIdNotNull,
|
|
@@ -360,6 +365,7 @@ export function initializeDb(): void {
|
|
|
360
365
|
migrateConversationsLastMessageAt,
|
|
361
366
|
migrateStripThinkingFromConsolidated,
|
|
362
367
|
migrateScheduleReuseConversation,
|
|
368
|
+
migrateScheduleScriptColumn,
|
|
363
369
|
migrateMemoryRecallLogsQueryContext,
|
|
364
370
|
migrateLlmRequestLogsCreatedAtIndex,
|
|
365
371
|
migrateOAuthProvidersScopeSeparator,
|
|
@@ -372,6 +378,8 @@ export function initializeDb(): void {
|
|
|
372
378
|
migrateNormalizeUserFileByPrincipal,
|
|
373
379
|
migrateConversationsArchivedAt,
|
|
374
380
|
migrateStripPlaceholderSentinelsFromMessages,
|
|
381
|
+
migrateOAuthProvidersManagedServiceIsPaid,
|
|
382
|
+
migrateOAuthProvidersAvailableScopes,
|
|
375
383
|
];
|
|
376
384
|
|
|
377
385
|
// Run each migration step, catching and logging individual failures so one
|
|
@@ -35,7 +35,7 @@ describe("GeminiEmbeddingBackend", () => {
|
|
|
35
35
|
expect(url).toContain("key=test-key");
|
|
36
36
|
|
|
37
37
|
const body = JSON.parse(init.body as string);
|
|
38
|
-
expect(body.model).
|
|
38
|
+
expect(body.model).toBeUndefined();
|
|
39
39
|
expect(body.content).toEqual({ parts: [{ text: "hello world" }] });
|
|
40
40
|
});
|
|
41
41
|
|
|
@@ -181,7 +181,7 @@ describe("GeminiEmbeddingBackend", () => {
|
|
|
181
181
|
const body = JSON.parse(init.body as string);
|
|
182
182
|
expect(body.taskType).toBeUndefined();
|
|
183
183
|
expect(body.outputDimensionality).toBeUndefined();
|
|
184
|
-
expect(Object.keys(body)).toEqual(["
|
|
184
|
+
expect(Object.keys(body)).toEqual(["content"]);
|
|
185
185
|
});
|
|
186
186
|
});
|
|
187
187
|
|
|
@@ -276,6 +276,45 @@ describe("GeminiEmbeddingBackend", () => {
|
|
|
276
276
|
// Should have Bearer auth header
|
|
277
277
|
const headers = init.headers as Record<string, string>;
|
|
278
278
|
expect(headers["Authorization"]).toBe("Bearer ast-managed-key");
|
|
279
|
+
// Managed path must NOT include `model` in the body — Gemini models it
|
|
280
|
+
// as a protobuf oneof populated from the URL path (internally `_model`)
|
|
281
|
+
// and rejects the duplicate with "oneof field '_model' is already set".
|
|
282
|
+
// See the comment in embedSingle() for the full invariant.
|
|
283
|
+
const body = JSON.parse(init.body as string);
|
|
284
|
+
expect(body.model).toBeUndefined();
|
|
285
|
+
expect(body._model).toBeUndefined();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test("never sets `model` or `_model` in the request body (oneof invariant)", async () => {
|
|
289
|
+
// Regression for JARVIS-587: every embed_segment job was failing with
|
|
290
|
+
// `Invalid value (oneof), oneof field '_model' is already set. Cannot
|
|
291
|
+
// set 'model'`. Ensure neither field is ever present on the wire,
|
|
292
|
+
// regardless of transport.
|
|
293
|
+
const managedBackend = new GeminiEmbeddingBackend(
|
|
294
|
+
"ast-managed-key",
|
|
295
|
+
"gemini-embedding-2-preview",
|
|
296
|
+
{
|
|
297
|
+
managedBaseUrl:
|
|
298
|
+
"https://platform.example.com/v1/runtime-proxy/gemini",
|
|
299
|
+
taskType: "RETRIEVAL_DOCUMENT",
|
|
300
|
+
dimensions: 3072,
|
|
301
|
+
},
|
|
302
|
+
);
|
|
303
|
+
await managedBackend.embed(["hello"]);
|
|
304
|
+
|
|
305
|
+
const directBackend = new GeminiEmbeddingBackend(
|
|
306
|
+
"direct-key",
|
|
307
|
+
"test-model",
|
|
308
|
+
);
|
|
309
|
+
await directBackend.embed(["hello"]);
|
|
310
|
+
|
|
311
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
312
|
+
for (const call of mockFetch.mock.calls) {
|
|
313
|
+
const [, init] = call as [string, RequestInit];
|
|
314
|
+
const body = JSON.parse(init.body as string);
|
|
315
|
+
expect(body.model).toBeUndefined();
|
|
316
|
+
expect(body._model).toBeUndefined();
|
|
317
|
+
}
|
|
279
318
|
});
|
|
280
319
|
|
|
281
320
|
test("uses direct Google API URL when managedBaseUrl is not set", async () => {
|
|
@@ -58,9 +58,14 @@ export class GeminiEmbeddingBackend implements EmbeddingBackend {
|
|
|
58
58
|
const parts = this.buildParts(normalized);
|
|
59
59
|
|
|
60
60
|
const body: Record<string, unknown> = {
|
|
61
|
-
model: `models/${this.model}`,
|
|
62
61
|
content: { parts },
|
|
63
62
|
};
|
|
63
|
+
// Do NOT set `model` in the body. Gemini's embedContent API models `model`
|
|
64
|
+
// as a protobuf oneof populated from the URL path (internally `_model`),
|
|
65
|
+
// so adding it to the body triggers a 400: "oneof field '_model' is
|
|
66
|
+
// already set. Cannot set 'model'". This holds for both the direct API
|
|
67
|
+
// and the managed proxy, which forwards the body unchanged; the platform
|
|
68
|
+
// billing layer parses the model from the URL path instead.
|
|
64
69
|
if (this.taskType) body.taskType = this.taskType;
|
|
65
70
|
if (this.dimensions) body.outputDimensionality = this.dimensions;
|
|
66
71
|
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { setMemoryCheckpoint } from "../checkpoints.js";
|
|
4
|
+
import {
|
|
5
|
+
initializeDb,
|
|
6
|
+
rawAll,
|
|
7
|
+
rawGet,
|
|
8
|
+
rawRun,
|
|
9
|
+
resetTestTables,
|
|
10
|
+
} from "../db.js";
|
|
11
|
+
import { migrateToolCreatedItems } from "./bootstrap.js";
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// The checkpoint key used by migrateToolCreatedItems (not exported, so we
|
|
15
|
+
// inline the literal value).
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
const MIGRATE_ITEMS_CHECKPOINT = "graph_bootstrap:migrated_tool_items";
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Setup
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
beforeAll(() => {
|
|
24
|
+
initializeDb();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
// Clear graph nodes and checkpoints between tests so each test starts clean.
|
|
29
|
+
resetTestTables("memory_graph_nodes", "memory_checkpoints", "memory_jobs");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// migrateToolCreatedItems
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
describe("migrateToolCreatedItems", () => {
|
|
37
|
+
test("migrates legacy memory_items to graph nodes", () => {
|
|
38
|
+
// The memory_items table has been dropped by migration 203, so we need to
|
|
39
|
+
// recreate it for this test. We create a minimal version with just the
|
|
40
|
+
// columns the migration reads.
|
|
41
|
+
rawRun(
|
|
42
|
+
`CREATE TABLE IF NOT EXISTS memory_items (
|
|
43
|
+
id TEXT PRIMARY KEY,
|
|
44
|
+
kind TEXT NOT NULL,
|
|
45
|
+
subject TEXT NOT NULL,
|
|
46
|
+
statement TEXT NOT NULL,
|
|
47
|
+
status TEXT NOT NULL,
|
|
48
|
+
confidence REAL NOT NULL,
|
|
49
|
+
importance REAL,
|
|
50
|
+
scope_id TEXT NOT NULL DEFAULT 'default',
|
|
51
|
+
first_seen_at INTEGER NOT NULL,
|
|
52
|
+
fingerprint TEXT NOT NULL DEFAULT ''
|
|
53
|
+
)`,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
// Insert a legacy playbook item
|
|
58
|
+
rawRun(
|
|
59
|
+
`INSERT INTO memory_items (id, kind, subject, statement, status, confidence, importance, scope_id, first_seen_at)
|
|
60
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
61
|
+
"legacy-item-1",
|
|
62
|
+
"playbook",
|
|
63
|
+
"Test Playbook",
|
|
64
|
+
"Do the thing correctly",
|
|
65
|
+
"active",
|
|
66
|
+
0.9,
|
|
67
|
+
0.8,
|
|
68
|
+
"default",
|
|
69
|
+
1700000000000,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Clear the checkpoint so the migration re-runs
|
|
73
|
+
rawRun(
|
|
74
|
+
"DELETE FROM memory_checkpoints WHERE key = ?",
|
|
75
|
+
MIGRATE_ITEMS_CHECKPOINT,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Run migration
|
|
79
|
+
migrateToolCreatedItems();
|
|
80
|
+
|
|
81
|
+
// Assert a corresponding graph node was created
|
|
82
|
+
const node = rawGet<{
|
|
83
|
+
id: string;
|
|
84
|
+
content: string;
|
|
85
|
+
type: string;
|
|
86
|
+
source_conversations: string;
|
|
87
|
+
image_refs: string | null;
|
|
88
|
+
}>(
|
|
89
|
+
`SELECT id, content, type, source_conversations, image_refs
|
|
90
|
+
FROM memory_graph_nodes
|
|
91
|
+
WHERE source_conversations LIKE ?`,
|
|
92
|
+
"%playbook:legacy-item-1%",
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
expect(node).not.toBeNull();
|
|
96
|
+
expect(node!.content).toBe("Test Playbook\nDo the thing correctly");
|
|
97
|
+
expect(node!.type).toBe("semantic");
|
|
98
|
+
expect(JSON.parse(node!.source_conversations)).toContain(
|
|
99
|
+
"playbook:legacy-item-1",
|
|
100
|
+
);
|
|
101
|
+
expect(node!.image_refs).toBeNull();
|
|
102
|
+
} finally {
|
|
103
|
+
// Clean up the recreated table so it does not interfere with other tests
|
|
104
|
+
rawRun("DROP TABLE IF EXISTS memory_items");
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("succeeds when image_refs column does not exist", () => {
|
|
109
|
+
// This is the regression test for the v0.6.0 bug: when upgrading from
|
|
110
|
+
// v0.5.x, migrateToolCreatedItems ran before the image_refs column was
|
|
111
|
+
// added by migration 205, causing a crash.
|
|
112
|
+
|
|
113
|
+
// Recreate memory_items for legacy data
|
|
114
|
+
rawRun(
|
|
115
|
+
`CREATE TABLE IF NOT EXISTS memory_items (
|
|
116
|
+
id TEXT PRIMARY KEY,
|
|
117
|
+
kind TEXT NOT NULL,
|
|
118
|
+
subject TEXT NOT NULL,
|
|
119
|
+
statement TEXT NOT NULL,
|
|
120
|
+
status TEXT NOT NULL,
|
|
121
|
+
confidence REAL NOT NULL,
|
|
122
|
+
importance REAL,
|
|
123
|
+
scope_id TEXT NOT NULL DEFAULT 'default',
|
|
124
|
+
first_seen_at INTEGER NOT NULL,
|
|
125
|
+
fingerprint TEXT NOT NULL DEFAULT ''
|
|
126
|
+
)`,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
// Rebuild memory_graph_nodes WITHOUT the image_refs column to simulate
|
|
131
|
+
// the pre-205 schema. SQLite doesn't support DROP COLUMN on all
|
|
132
|
+
// versions, so we use the standard CREATE-new/INSERT-SELECT/DROP-old/
|
|
133
|
+
// RENAME pattern.
|
|
134
|
+
rawRun(`CREATE TABLE memory_graph_nodes_backup AS
|
|
135
|
+
SELECT
|
|
136
|
+
id, content, type, created, last_accessed, last_consolidated,
|
|
137
|
+
event_date, emotional_charge, fidelity, confidence, significance,
|
|
138
|
+
stability, reinforcement_count, last_reinforced,
|
|
139
|
+
source_conversations, source_type, narrative_role, part_of_story,
|
|
140
|
+
scope_id
|
|
141
|
+
FROM memory_graph_nodes`);
|
|
142
|
+
rawRun("DROP TABLE memory_graph_nodes");
|
|
143
|
+
rawRun(
|
|
144
|
+
`CREATE TABLE memory_graph_nodes (
|
|
145
|
+
id TEXT PRIMARY KEY,
|
|
146
|
+
content TEXT NOT NULL,
|
|
147
|
+
type TEXT NOT NULL,
|
|
148
|
+
created INTEGER NOT NULL,
|
|
149
|
+
last_accessed INTEGER NOT NULL,
|
|
150
|
+
last_consolidated INTEGER NOT NULL,
|
|
151
|
+
event_date INTEGER,
|
|
152
|
+
emotional_charge TEXT NOT NULL,
|
|
153
|
+
fidelity TEXT NOT NULL DEFAULT 'vivid',
|
|
154
|
+
confidence REAL NOT NULL,
|
|
155
|
+
significance REAL NOT NULL,
|
|
156
|
+
stability REAL NOT NULL DEFAULT 14,
|
|
157
|
+
reinforcement_count INTEGER NOT NULL DEFAULT 0,
|
|
158
|
+
last_reinforced INTEGER NOT NULL,
|
|
159
|
+
source_conversations TEXT NOT NULL DEFAULT '[]',
|
|
160
|
+
source_type TEXT NOT NULL DEFAULT 'inferred',
|
|
161
|
+
narrative_role TEXT,
|
|
162
|
+
part_of_story TEXT,
|
|
163
|
+
scope_id TEXT NOT NULL DEFAULT 'default'
|
|
164
|
+
)`,
|
|
165
|
+
);
|
|
166
|
+
rawRun(
|
|
167
|
+
`INSERT INTO memory_graph_nodes
|
|
168
|
+
SELECT * FROM memory_graph_nodes_backup`,
|
|
169
|
+
);
|
|
170
|
+
rawRun("DROP TABLE memory_graph_nodes_backup");
|
|
171
|
+
|
|
172
|
+
// Clear checkpoint
|
|
173
|
+
rawRun(
|
|
174
|
+
"DELETE FROM memory_checkpoints WHERE key = ?",
|
|
175
|
+
MIGRATE_ITEMS_CHECKPOINT,
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
// Insert a legacy item
|
|
179
|
+
rawRun(
|
|
180
|
+
`INSERT INTO memory_items (id, kind, subject, statement, status, confidence, importance, scope_id, first_seen_at)
|
|
181
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
182
|
+
"legacy-item-2",
|
|
183
|
+
"style",
|
|
184
|
+
"Formal tone",
|
|
185
|
+
"Always use formal language",
|
|
186
|
+
"active",
|
|
187
|
+
0.85,
|
|
188
|
+
0.7,
|
|
189
|
+
"default",
|
|
190
|
+
1700000000000,
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// This should NOT throw — the migration should succeed without image_refs
|
|
194
|
+
expect(() => migrateToolCreatedItems()).not.toThrow();
|
|
195
|
+
|
|
196
|
+
// Verify the row was migrated
|
|
197
|
+
const node = rawGet<{ id: string; content: string }>(
|
|
198
|
+
`SELECT id, content FROM memory_graph_nodes
|
|
199
|
+
WHERE source_conversations LIKE ?`,
|
|
200
|
+
"%style:legacy-item-2%",
|
|
201
|
+
);
|
|
202
|
+
expect(node).not.toBeNull();
|
|
203
|
+
expect(node!.content).toBe("Formal tone\nAlways use formal language");
|
|
204
|
+
} finally {
|
|
205
|
+
rawRun("DROP TABLE IF EXISTS memory_items");
|
|
206
|
+
// Restore the full schema for subsequent tests by re-adding image_refs
|
|
207
|
+
try {
|
|
208
|
+
rawRun("ALTER TABLE memory_graph_nodes ADD COLUMN image_refs TEXT");
|
|
209
|
+
} catch {
|
|
210
|
+
// Column may already exist
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("skips migration when checkpoint is already set", () => {
|
|
216
|
+
// Recreate memory_items for legacy data
|
|
217
|
+
rawRun(
|
|
218
|
+
`CREATE TABLE IF NOT EXISTS memory_items (
|
|
219
|
+
id TEXT PRIMARY KEY,
|
|
220
|
+
kind TEXT NOT NULL,
|
|
221
|
+
subject TEXT NOT NULL,
|
|
222
|
+
statement TEXT NOT NULL,
|
|
223
|
+
status TEXT NOT NULL,
|
|
224
|
+
confidence REAL NOT NULL,
|
|
225
|
+
importance REAL,
|
|
226
|
+
scope_id TEXT NOT NULL DEFAULT 'default',
|
|
227
|
+
first_seen_at INTEGER NOT NULL,
|
|
228
|
+
fingerprint TEXT NOT NULL DEFAULT ''
|
|
229
|
+
)`,
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
// Set the checkpoint BEFORE inserting data — the migration should skip
|
|
234
|
+
setMemoryCheckpoint(MIGRATE_ITEMS_CHECKPOINT, "done");
|
|
235
|
+
|
|
236
|
+
rawRun(
|
|
237
|
+
`INSERT INTO memory_items (id, kind, subject, statement, status, confidence, importance, scope_id, first_seen_at)
|
|
238
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
239
|
+
"legacy-item-3",
|
|
240
|
+
"relationship",
|
|
241
|
+
"Colleague",
|
|
242
|
+
"Works with user on project X",
|
|
243
|
+
"active",
|
|
244
|
+
0.75,
|
|
245
|
+
0.6,
|
|
246
|
+
"default",
|
|
247
|
+
1700000000000,
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
// Run migration — should be a no-op because checkpoint is set
|
|
251
|
+
migrateToolCreatedItems();
|
|
252
|
+
|
|
253
|
+
// Assert no rows were inserted into memory_graph_nodes
|
|
254
|
+
const rows = rawAll<{ id: string }>("SELECT id FROM memory_graph_nodes");
|
|
255
|
+
expect(rows).toHaveLength(0);
|
|
256
|
+
} finally {
|
|
257
|
+
rawRun("DROP TABLE IF EXISTS memory_items");
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("handles missing memory_items table gracefully", () => {
|
|
262
|
+
// Ensure memory_items table does not exist
|
|
263
|
+
rawRun("DROP TABLE IF EXISTS memory_items");
|
|
264
|
+
|
|
265
|
+
// Clear the checkpoint so migration attempts to run
|
|
266
|
+
rawRun(
|
|
267
|
+
"DELETE FROM memory_checkpoints WHERE key = ?",
|
|
268
|
+
MIGRATE_ITEMS_CHECKPOINT,
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
// Should not throw even though the table doesn't exist
|
|
272
|
+
expect(() => migrateToolCreatedItems()).not.toThrow();
|
|
273
|
+
|
|
274
|
+
// The checkpoint should be set to "done" (migration handled the missing table)
|
|
275
|
+
const checkpoint = rawGet<{ value: string }>(
|
|
276
|
+
"SELECT value FROM memory_checkpoints WHERE key = ?",
|
|
277
|
+
MIGRATE_ITEMS_CHECKPOINT,
|
|
278
|
+
);
|
|
279
|
+
expect(checkpoint).not.toBeNull();
|
|
280
|
+
expect(checkpoint!.value).toBe("done");
|
|
281
|
+
});
|
|
282
|
+
});
|