@vellumai/assistant 0.4.56 → 0.4.57
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/ARCHITECTURE.md +10 -10
- package/Dockerfile +3 -0
- package/README.md +11 -11
- package/docs/architecture/integrations.md +2 -2
- package/docs/architecture/memory.md +3 -4
- package/docs/credential-execution-service.md +13 -20
- package/node_modules/@vellumai/ces-contracts/src/error.ts +5 -4
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +7 -7
- package/src/__tests__/anthropic-provider.test.ts +172 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +15 -1
- package/src/__tests__/approval-cascade.test.ts +2 -2
- package/src/__tests__/approval-routes-http.test.ts +3 -4
- package/src/__tests__/asset-materialize-tool.test.ts +5 -5
- package/src/__tests__/asset-search-tool.test.ts +1 -1
- package/src/__tests__/assistant-attachments.test.ts +5 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
- package/src/__tests__/assistant-feature-flags-integration.test.ts +50 -38
- package/src/__tests__/attachments-store.test.ts +2 -2
- package/src/__tests__/avatar-e2e.test.ts +5 -3
- package/src/__tests__/browser-skill-endstate.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +2 -2
- package/src/__tests__/callback-handoff-copy.test.ts +1 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +158 -0
- package/src/__tests__/channel-readiness-routes.test.ts +0 -1
- package/src/__tests__/channel-readiness-service.test.ts +0 -1
- package/src/__tests__/checker.test.ts +31 -32
- package/src/__tests__/chrome-cdp.test.ts +47 -18
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -2
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +9 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -2
- package/src/__tests__/conversation-agent-loop.test.ts +11 -4
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +33 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -1
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +1 -1
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -4
- package/src/__tests__/conversation-provider-retry-repair.test.ts +4 -4
- package/src/__tests__/conversation-queue.test.ts +23 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +3 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +185 -173
- package/src/__tests__/conversation-seed-composer.test.ts +1 -1
- package/src/__tests__/conversation-slash-queue.test.ts +4 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -4
- package/src/__tests__/conversation-starter-routes.test.ts +291 -0
- package/src/__tests__/conversation-wipe.test.ts +438 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -3
- package/src/__tests__/conversation-workspace-injection.test.ts +4 -5
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -5
- package/src/__tests__/credential-security-e2e.test.ts +20 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +227 -0
- package/src/__tests__/credentials-cli.test.ts +3 -0
- package/src/__tests__/date-context.test.ts +59 -377
- package/src/__tests__/drop-capability-card-state-migration.test.ts +169 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +11 -45
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
- package/src/__tests__/encrypted-store.test.ts +237 -15
- package/src/__tests__/ephemeral-permissions.test.ts +4 -5
- package/src/__tests__/event-bus.test.ts +3 -3
- package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/gemini-image-service.test.ts +4 -4
- package/src/__tests__/gemini-provider.test.ts +6 -9
- package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/host-shell-tool.test.ts +6 -6
- package/src/__tests__/http-user-message-parity.test.ts +2 -2
- package/src/__tests__/intent-routing.test.ts +51 -99
- package/src/__tests__/invite-routes-http.test.ts +5 -0
- package/src/__tests__/list-messages-attachments.test.ts +1 -1
- package/src/__tests__/managed-proxy-context.test.ts +2 -5
- package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
- package/src/__tests__/media-generate-image.test.ts +32 -15
- package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
- package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
- package/src/__tests__/memory-recall-quality.test.ts +4 -3
- package/src/__tests__/memory-regressions.test.ts +86 -90
- package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
- package/src/__tests__/migration-export-http.test.ts +26 -27
- package/src/__tests__/migration-import-commit-http.test.ts +165 -37
- package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
- package/src/__tests__/migration-validate-http.test.ts +16 -16
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
- package/src/__tests__/notification-broadcaster.test.ts +1 -1
- package/src/__tests__/notification-decision-fallback.test.ts +2 -2
- package/src/__tests__/notification-decision-identity.test.ts +8 -9
- package/src/__tests__/notification-decision-strategy.test.ts +1 -1
- package/src/__tests__/notification-deep-link.test.ts +1 -1
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
- package/src/__tests__/oauth-store.test.ts +1 -3
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
- package/src/__tests__/onboarding-template-contract.test.ts +23 -59
- package/src/__tests__/provider-error-scenarios.test.ts +154 -0
- package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
- package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
- package/src/__tests__/provider-registry-ollama.test.ts +5 -2
- package/src/__tests__/qdrant-manager.test.ts +7 -7
- package/src/__tests__/ratelimit.test.ts +0 -74
- package/src/__tests__/recording-handler.test.ts +0 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/scheduler-recurrence.test.ts +46 -2
- package/src/__tests__/schema-transforms.test.ts +114 -54
- package/src/__tests__/secret-onetime-send.test.ts +20 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
- package/src/__tests__/secret-scanner-executor.test.ts +1 -2
- package/src/__tests__/send-endpoint-busy.test.ts +63 -4
- package/src/__tests__/send-notification-tool.test.ts +2 -2
- package/src/__tests__/shell-credential-ref.test.ts +0 -1
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
- package/src/__tests__/skill-memory.test.ts +547 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
- package/src/__tests__/slack-channel-config.test.ts +109 -94
- package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
- package/src/__tests__/swarm-recursion.test.ts +2 -2
- package/src/__tests__/swarm-tool.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +19 -66
- package/src/__tests__/telegram-config.test.ts +121 -0
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +1 -1
- package/src/__tests__/trace-emitter.test.ts +8 -1
- package/src/__tests__/trust-store.test.ts +7 -8
- package/src/__tests__/twilio-routes.test.ts +1 -18
- package/src/__tests__/user-reference.test.ts +82 -2
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
- package/src/approvals/guardian-request-resolvers.ts +3 -3
- package/src/avatar/ascii-renderer.ts +2 -2
- package/src/avatar/png-renderer.ts +2 -2
- package/src/avatar/resvg-lazy.ts +21 -0
- package/src/calls/guardian-dispatch.ts +1 -1
- package/src/calls/relay-access-wait.ts +2 -2
- package/src/calls/twilio-rest.ts +0 -248
- package/src/cli/AGENTS.md +5 -8
- package/src/cli/__tests__/notifications.test.ts +5 -5
- package/src/cli/commands/avatar.ts +64 -2
- package/src/cli/commands/conversations.ts +131 -1
- package/src/cli/commands/credentials.ts +2 -0
- package/src/cli/commands/notifications.ts +3 -3
- package/src/cli.ts +10 -0
- package/src/config/bundled-skills/acp/SKILL.md +5 -5
- package/src/config/bundled-skills/acp/TOOLS.json +6 -6
- package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
- package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
- package/src/config/bundled-skills/browser/SKILL.md +15 -15
- package/src/config/bundled-skills/browser/TOOLS.json +14 -14
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
- package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
- package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
- package/src/config/bundled-skills/contacts/SKILL.md +3 -3
- package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
- package/src/config/bundled-skills/document/SKILL.md +4 -4
- package/src/config/bundled-skills/document/TOOLS.json +2 -2
- package/src/config/bundled-skills/followups/TOOLS.json +3 -3
- package/src/config/bundled-skills/gmail/SKILL.md +32 -32
- package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
- package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
- package/src/config/bundled-skills/google-calendar/types.ts +1 -1
- package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
- package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
- package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
- package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +29 -25
- package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/notifications/SKILL.md +3 -3
- package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
- package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
- package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
- package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
- package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
- package/src/config/bundled-skills/schedule/SKILL.md +26 -26
- package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
- package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
- package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
- package/src/config/bundled-skills/sequences/SKILL.md +2 -2
- package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
- package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
- package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
- package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
- package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
- package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
- package/src/config/bundled-skills/slack/SKILL.md +2 -2
- package/src/config/bundled-skills/slack/TOOLS.json +8 -8
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
- package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
- package/src/config/bundled-skills/tasks/SKILL.md +1 -1
- package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
- package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
- package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
- package/src/config/bundled-skills/watcher/SKILL.md +4 -4
- package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
- package/src/config/feature-flag-registry.json +33 -17
- package/src/config/schemas/sandbox.ts +1 -1
- package/src/config/schemas/services.ts +13 -3
- package/src/config/schemas/timeouts.ts +0 -10
- package/src/contacts/contact-store.ts +63 -0
- package/src/contacts/contacts-write.ts +1 -1
- package/src/daemon/assistant-attachments.ts +2 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
- package/src/daemon/conversation-agent-loop.ts +7 -30
- package/src/daemon/conversation-error.ts +24 -0
- package/src/daemon/conversation-memory.ts +8 -7
- package/src/daemon/conversation-runtime-assembly.ts +139 -274
- package/src/daemon/conversation-slash.ts +7 -26
- package/src/daemon/conversation-surfaces.ts +14 -0
- package/src/daemon/conversation-tool-setup.ts +9 -8
- package/src/daemon/conversation.ts +2 -0
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +10 -83
- package/src/daemon/handlers/config-channels.ts +12 -2
- package/src/daemon/handlers/config-slack-channel.ts +7 -1
- package/src/daemon/handlers/config-telegram.ts +6 -1
- package/src/daemon/handlers/conversations.ts +2 -2
- package/src/daemon/handlers/skills.ts +4 -0
- package/src/daemon/lifecycle.ts +28 -4
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +1 -5
- package/src/daemon/shutdown-handlers.ts +9 -3
- package/src/daemon/tool-side-effects.ts +40 -0
- package/src/daemon/trace-emitter.ts +25 -2
- package/src/events/domain-events.ts +1 -1
- package/src/events/tool-permission-telemetry-listener.ts +46 -0
- package/src/inbound/platform-callback-registration.ts +0 -18
- package/src/media/app-icon-generator.ts +15 -8
- package/src/media/avatar-router.ts +15 -8
- package/src/media/gemini-image-service.ts +125 -21
- package/src/memory/attachments-store.ts +3 -3
- package/src/memory/channel-verification-sessions.ts +6 -6
- package/src/memory/conversation-crud.ts +196 -1
- package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
- package/src/memory/conversation-title-service.ts +2 -3
- package/src/memory/db-init.ts +25 -1
- package/src/memory/invite-store.ts +4 -4
- package/src/memory/items-extractor.ts +4 -4
- package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/jobs-worker.ts +7 -5
- package/src/memory/lifecycle-events-store.ts +63 -0
- package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
- package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
- package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
- package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
- package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
- package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/retriever.test.ts +223 -96
- package/src/memory/retriever.ts +115 -138
- package/src/memory/schema/calls.ts +1 -1
- package/src/memory/schema/contacts.ts +1 -1
- package/src/memory/schema/infrastructure.ts +29 -0
- package/src/memory/schema/memory-core.ts +7 -17
- package/src/memory/schema/notifications.ts +1 -1
- package/src/memory/search/formatting.ts +23 -6
- package/src/memory/search/lexical.ts +2 -0
- package/src/memory/search/semantic.ts +2 -0
- package/src/memory/search/staleness.ts +1 -0
- package/src/memory/search/types.ts +4 -0
- package/src/memory/task-memory-cleanup.ts +96 -6
- package/src/memory/trace-event-store.ts +148 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/decision-engine.ts +2 -2
- package/src/notifications/emit-signal.ts +4 -4
- package/src/notifications/events-store.ts +4 -4
- package/src/notifications/signal.ts +1 -1
- package/src/oauth/manual-token-connection.ts +49 -25
- package/src/permissions/checker.ts +6 -5
- package/src/permissions/defaults.ts +4 -4
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
- package/src/prompts/cache-boundary.ts +8 -0
- package/src/prompts/system-prompt.ts +105 -634
- package/src/prompts/templates/BOOTSTRAP.md +166 -33
- package/src/prompts/templates/IDENTITY.md +8 -23
- package/src/prompts/templates/SOUL.md +20 -41
- package/src/prompts/templates/USER.md +3 -19
- package/src/prompts/user-reference.ts +14 -16
- package/src/providers/anthropic/client.ts +46 -2
- package/src/providers/gemini/client.ts +6 -9
- package/src/providers/managed-proxy/constants.ts +1 -7
- package/src/providers/managed-proxy/context.ts +0 -1
- package/src/providers/model-intents.ts +5 -5
- package/src/providers/openai/client.ts +10 -1
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/ratelimit.ts +0 -35
- package/src/providers/registry.ts +3 -5
- package/src/providers/retry.ts +18 -1
- package/src/runtime/access-request-helper.ts +1 -1
- package/src/runtime/auth/route-policy.ts +7 -0
- package/src/runtime/channel-verification-service.ts +1 -1
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/guardian-vellum-migration.ts +63 -1
- package/src/runtime/http-server.ts +8 -4
- package/src/runtime/migrations/vbundle-builder.ts +212 -32
- package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
- package/src/runtime/migrations/vbundle-importer.ts +66 -1
- package/src/runtime/migrations/vbundle-validator.ts +17 -3
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
- package/src/runtime/routes/attachment-routes.ts +2 -2
- package/src/runtime/routes/btw-routes.ts +9 -0
- package/src/runtime/routes/channel-verification-routes.ts +19 -2
- package/src/runtime/routes/conversation-management-routes.ts +55 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +49 -5
- package/src/runtime/routes/conversation-starter-routes.ts +207 -0
- package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
- package/src/runtime/routes/migration-routes.ts +25 -13
- package/src/runtime/routes/secret-routes.ts +18 -0
- package/src/runtime/routes/settings-routes.ts +8 -8
- package/src/runtime/routes/telemetry-routes.ts +53 -0
- package/src/runtime/routes/trace-event-routes.ts +62 -0
- package/src/runtime/tool-grant-request-helper.ts +1 -1
- package/src/runtime/verification-outbound-actions.ts +47 -31
- package/src/security/encrypted-store.ts +263 -78
- package/src/skills/catalog-install.ts +10 -0
- package/src/skills/managed-store.ts +2 -0
- package/src/skills/skill-memory.ts +220 -0
- package/src/subagent/manager.ts +1 -4
- package/src/telemetry/types.ts +10 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
- package/src/telemetry/usage-telemetry-reporter.ts +51 -4
- package/src/tools/AGENTS.md +11 -11
- package/src/tools/acp/spawn.ts +1 -1
- package/src/tools/apps/executors.ts +8 -8
- package/src/tools/apps/registry.ts +1 -1
- package/src/tools/assets/materialize.ts +6 -6
- package/src/tools/assets/search.ts +10 -10
- package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
- package/src/tools/browser/auth-detector.ts +6 -6
- package/src/tools/browser/browser-execution.ts +13 -13
- package/src/tools/browser/browser-manager.ts +3 -3
- package/src/tools/browser/chrome-cdp.ts +5 -5
- package/src/tools/browser/jit-auth.ts +2 -2
- package/src/tools/browser/network-recorder.test.ts +2 -2
- package/src/tools/browser/network-recorder.ts +3 -3
- package/src/tools/browser/runtime-check.ts +3 -3
- package/src/tools/claude-code/claude-code.ts +2 -2
- package/src/tools/computer-use/definitions.ts +18 -18
- package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
- package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
- package/src/tools/credentials/broker-types.ts +5 -5
- package/src/tools/credentials/broker.ts +15 -15
- package/src/tools/credentials/metadata-store.ts +2 -2
- package/src/tools/credentials/resolve.ts +1 -1
- package/src/tools/credentials/selection.ts +1 -1
- package/src/tools/credentials/tool-policy.ts +1 -1
- package/src/tools/credentials/vault.ts +115 -25
- package/src/tools/execution-target.ts +2 -2
- package/src/tools/executor.ts +7 -7
- package/src/tools/filesystem/edit.ts +2 -2
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +1 -1
- package/src/tools/host-filesystem/edit.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -1
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +9 -8
- package/src/tools/mcp/mcp-tool-factory.ts +7 -6
- package/src/tools/memory/definitions.ts +6 -5
- package/src/tools/memory/handlers.test.ts +1 -1
- package/src/tools/network/__tests__/web-search.test.ts +3 -3
- package/src/tools/network/domain-normalize.ts +2 -2
- package/src/tools/network/script-proxy/session-manager.ts +10 -10
- package/src/tools/network/web-fetch.ts +1 -1
- package/src/tools/network/web-search.ts +3 -3
- package/src/tools/permission-checker.ts +8 -8
- package/src/tools/registry.ts +7 -7
- package/src/tools/schedule/list.ts +2 -2
- package/src/tools/schema-transforms.ts +31 -21
- package/src/tools/secret-detection-handler.ts +1 -1
- package/src/tools/sensitive-output-placeholders.ts +1 -1
- package/src/tools/shared/filesystem/edit-engine.ts +1 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
- package/src/tools/shared/filesystem/image-read.ts +25 -5
- package/src/tools/shared/filesystem/path-policy.ts +2 -2
- package/src/tools/shared/shell-output.ts +1 -1
- package/src/tools/side-effects.ts +1 -1
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +3 -3
- package/src/tools/skills/sandbox-runner.ts +3 -3
- package/src/tools/subagent/read.ts +1 -1
- package/src/tools/subagent/spawn.ts +2 -2
- package/src/tools/swarm/delegate.ts +3 -3
- package/src/tools/system/request-permission.ts +5 -4
- package/src/tools/terminal/backends/native.ts +4 -4
- package/src/tools/terminal/parser.ts +6 -6
- package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
- package/src/tools/terminal/shell.ts +16 -16
- package/src/tools/tool-approval-handler.ts +21 -12
- package/src/tools/tool-manifest.ts +4 -4
- package/src/tools/types.ts +3 -3
- package/src/tools/ui-surface/definitions.ts +9 -37
- package/src/tools/watcher/list.ts +1 -1
- package/src/util/logger.ts +7 -2
- package/src/util/retry.ts +29 -1
- package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
- package/src/cli/reference.ts +0 -38
- package/src/memory/job-handlers/capability-cards.ts +0 -420
- package/src/runtime/routes/thread-starter-routes.ts +0 -294
|
@@ -1,420 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Job handler for generating capability cards.
|
|
3
|
-
*
|
|
4
|
-
* Each job generates cards for a single capability category, running in
|
|
5
|
-
* parallel with jobs for other categories. Cards are personalized to the
|
|
6
|
-
* user's memory items and available skills.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { and, eq } from "drizzle-orm";
|
|
10
|
-
import { v4 as uuid } from "uuid";
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
createTimeout,
|
|
14
|
-
extractToolUse,
|
|
15
|
-
getConfiguredProvider,
|
|
16
|
-
userMessage,
|
|
17
|
-
} from "../../providers/provider-send-message.js";
|
|
18
|
-
import { getLogger } from "../../util/logger.js";
|
|
19
|
-
import { truncate } from "../../util/truncate.js";
|
|
20
|
-
import { getDb } from "../db.js";
|
|
21
|
-
import { asString } from "../job-utils.js";
|
|
22
|
-
import type { MemoryJob } from "../jobs-store.js";
|
|
23
|
-
import {
|
|
24
|
-
capabilityCardCategories,
|
|
25
|
-
memoryCheckpoints,
|
|
26
|
-
threadStarters,
|
|
27
|
-
} from "../schema.js";
|
|
28
|
-
import { buildMemoryRollup, buildSkillsSummary } from "./thread-starters.js";
|
|
29
|
-
|
|
30
|
-
const log = getLogger("capability-cards-gen");
|
|
31
|
-
|
|
32
|
-
/** Capability categories for the feed (knowledge dropped — not actionable). */
|
|
33
|
-
export const CAPABILITY_CARD_CATEGORIES = [
|
|
34
|
-
"communication",
|
|
35
|
-
"productivity",
|
|
36
|
-
"development",
|
|
37
|
-
"media",
|
|
38
|
-
"automation",
|
|
39
|
-
"web_social",
|
|
40
|
-
"integration",
|
|
41
|
-
] as const;
|
|
42
|
-
|
|
43
|
-
export type CapabilityCardCategory =
|
|
44
|
-
(typeof CAPABILITY_CARD_CATEGORIES)[number];
|
|
45
|
-
|
|
46
|
-
/** Human-readable descriptions for each category, used in the LLM prompt. */
|
|
47
|
-
const CATEGORY_DESCRIPTIONS: Record<CapabilityCardCategory, string> = {
|
|
48
|
-
communication: "Email, Slack, messaging, drafting messages, replying",
|
|
49
|
-
productivity:
|
|
50
|
-
"Calendar, tasks, planning, scheduling, meeting prep, time management",
|
|
51
|
-
development:
|
|
52
|
-
"Code, debugging, architecture, PR reviews, build systems, documentation",
|
|
53
|
-
media: "Images, video, audio, 3D, creative assets, media editing",
|
|
54
|
-
automation:
|
|
55
|
-
"Workflows, scheduling, scripts, recurring tasks, integrations orchestration",
|
|
56
|
-
web_social:
|
|
57
|
-
"Web browsing, social media, research, competitive analysis, news",
|
|
58
|
-
integration:
|
|
59
|
-
"Third-party services, APIs, syncing data across tools, connecting services",
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Curated subset of VIcon names the LLM can choose from, organized by
|
|
64
|
-
* category relevance. Kept small (~30) to avoid bloating the prompt.
|
|
65
|
-
*/
|
|
66
|
-
const ICON_PALETTE: Record<string, string[]> = {
|
|
67
|
-
communication: [
|
|
68
|
-
"lucide-mail",
|
|
69
|
-
"lucide-message-circle",
|
|
70
|
-
"lucide-message-square",
|
|
71
|
-
"lucide-phone",
|
|
72
|
-
"lucide-send",
|
|
73
|
-
],
|
|
74
|
-
productivity: [
|
|
75
|
-
"lucide-calendar",
|
|
76
|
-
"lucide-clock",
|
|
77
|
-
"lucide-clipboard-list",
|
|
78
|
-
"lucide-list-checks",
|
|
79
|
-
"lucide-flag",
|
|
80
|
-
],
|
|
81
|
-
development: [
|
|
82
|
-
"lucide-terminal",
|
|
83
|
-
"lucide-git-branch",
|
|
84
|
-
"lucide-file-code",
|
|
85
|
-
"lucide-bug",
|
|
86
|
-
"lucide-cpu",
|
|
87
|
-
],
|
|
88
|
-
media: [
|
|
89
|
-
"lucide-image",
|
|
90
|
-
"lucide-video",
|
|
91
|
-
"lucide-music-2",
|
|
92
|
-
"lucide-camera",
|
|
93
|
-
"lucide-palette",
|
|
94
|
-
],
|
|
95
|
-
automation: [
|
|
96
|
-
"lucide-zap",
|
|
97
|
-
"lucide-refresh-cw",
|
|
98
|
-
"lucide-settings",
|
|
99
|
-
"lucide-layers",
|
|
100
|
-
"lucide-rocket",
|
|
101
|
-
],
|
|
102
|
-
web_social: [
|
|
103
|
-
"lucide-globe",
|
|
104
|
-
"lucide-search",
|
|
105
|
-
"lucide-trending-up",
|
|
106
|
-
"lucide-chart-bar",
|
|
107
|
-
"lucide-binoculars",
|
|
108
|
-
],
|
|
109
|
-
integration: [
|
|
110
|
-
"lucide-puzzle",
|
|
111
|
-
"lucide-link",
|
|
112
|
-
"lucide-network",
|
|
113
|
-
"lucide-package",
|
|
114
|
-
"lucide-share-2",
|
|
115
|
-
],
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const CK_BATCH = "capability_cards:generation_batch";
|
|
119
|
-
|
|
120
|
-
function checkpointKey(base: string, scopeId: string): string {
|
|
121
|
-
return `${base}:${scopeId}`;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
interface GeneratedCard {
|
|
125
|
-
icon: string;
|
|
126
|
-
title: string;
|
|
127
|
-
description: string;
|
|
128
|
-
prompt: string;
|
|
129
|
-
tags: string[];
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
interface GenerationResult {
|
|
133
|
-
relevance: number;
|
|
134
|
-
cards: GeneratedCard[];
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async function generateCardsForCategory(
|
|
138
|
-
scopeId: string,
|
|
139
|
-
category: CapabilityCardCategory,
|
|
140
|
-
): Promise<GenerationResult> {
|
|
141
|
-
const provider = await getConfiguredProvider();
|
|
142
|
-
if (!provider) {
|
|
143
|
-
log.info("No configured provider for capability card generation");
|
|
144
|
-
return { relevance: 0, cards: [] };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const rollup = buildMemoryRollup(scopeId);
|
|
148
|
-
if (!rollup) {
|
|
149
|
-
log.info("No memory items to generate capability cards from");
|
|
150
|
-
return { relevance: 0, cards: [] };
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const skills = buildSkillsSummary();
|
|
154
|
-
const icons = ICON_PALETTE[category] ?? [];
|
|
155
|
-
const allIcons = [
|
|
156
|
-
...icons,
|
|
157
|
-
// A few general-purpose icons always available
|
|
158
|
-
"lucide-sparkles",
|
|
159
|
-
"lucide-wand",
|
|
160
|
-
"lucide-lightbulb",
|
|
161
|
-
"lucide-star",
|
|
162
|
-
"lucide-briefcase",
|
|
163
|
-
];
|
|
164
|
-
|
|
165
|
-
const systemPrompt = `You are generating capability cards for a personal AI assistant's new thread page. These cards showcase what the assistant can do, personalized to the user's context.
|
|
166
|
-
|
|
167
|
-
You are generating cards for the "${category}" category: ${CATEGORY_DESCRIPTIONS[category]}.
|
|
168
|
-
|
|
169
|
-
Given the user's memories below, do two things:
|
|
170
|
-
1. Assess how relevant this category is to this user (0.0–1.0). A score of 0.7+ means the user has clear context that makes this category actionable. Score lower if the user's memories have little relation to this category.
|
|
171
|
-
2. If relevant (0.7+), generate 2–3 capability cards that cross the user's context with what the assistant can do in this area.
|
|
172
|
-
|
|
173
|
-
For each card, provide:
|
|
174
|
-
- icon: One of these Lucide icon names: ${allIcons.join(", ")}
|
|
175
|
-
- title: Action-oriented, verb-first, max 50 chars (e.g., "Triage your inbox", "Debug the auth middleware")
|
|
176
|
-
- description: One line explaining the outcome, personalized to the user's context, max 120 chars
|
|
177
|
-
- prompt: The full message that will be sent when clicked (1-2 natural sentences, as if the user typed it)
|
|
178
|
-
- tags: 1-3 short labels for integrations/tools involved (e.g., "Gmail", "Calendar", "Linear")
|
|
179
|
-
|
|
180
|
-
Rules:
|
|
181
|
-
- Be specific to THIS user — generic suggestions are not useful.
|
|
182
|
-
- Titles should be concise and scannable, starting with a verb.
|
|
183
|
-
- Prompts should be natural, as if the user typed them.
|
|
184
|
-
- Tags should reference actual tools/services relevant to the suggestion.
|
|
185
|
-
- If relevance is below 0.7, you may return an empty cards array.
|
|
186
|
-
|
|
187
|
-
${rollup}
|
|
188
|
-
${skills}`;
|
|
189
|
-
|
|
190
|
-
const { signal, cleanup } = createTimeout(25000);
|
|
191
|
-
try {
|
|
192
|
-
const response = await provider.sendMessage(
|
|
193
|
-
[
|
|
194
|
-
userMessage(
|
|
195
|
-
`Generate capability cards for the "${category}" category based on my context.`,
|
|
196
|
-
),
|
|
197
|
-
],
|
|
198
|
-
[
|
|
199
|
-
{
|
|
200
|
-
name: "store_capability_cards",
|
|
201
|
-
description:
|
|
202
|
-
"Store the relevance assessment and generated capability cards",
|
|
203
|
-
input_schema: {
|
|
204
|
-
type: "object" as const,
|
|
205
|
-
properties: {
|
|
206
|
-
relevance: {
|
|
207
|
-
type: "number",
|
|
208
|
-
description:
|
|
209
|
-
"How relevant this category is to the user (0.0–1.0)",
|
|
210
|
-
},
|
|
211
|
-
cards: {
|
|
212
|
-
type: "array",
|
|
213
|
-
items: {
|
|
214
|
-
type: "object",
|
|
215
|
-
properties: {
|
|
216
|
-
icon: {
|
|
217
|
-
type: "string",
|
|
218
|
-
description: "Lucide icon name from the provided list",
|
|
219
|
-
},
|
|
220
|
-
title: {
|
|
221
|
-
type: "string",
|
|
222
|
-
description:
|
|
223
|
-
"Action-oriented title, verb-first, max 50 chars",
|
|
224
|
-
},
|
|
225
|
-
description: {
|
|
226
|
-
type: "string",
|
|
227
|
-
description:
|
|
228
|
-
"One-line outcome description, max 120 chars",
|
|
229
|
-
},
|
|
230
|
-
prompt: {
|
|
231
|
-
type: "string",
|
|
232
|
-
description: "Full message sent on click (1-2 sentences)",
|
|
233
|
-
},
|
|
234
|
-
tags: {
|
|
235
|
-
type: "array",
|
|
236
|
-
items: { type: "string" },
|
|
237
|
-
description: "1-3 integration/tool tags",
|
|
238
|
-
},
|
|
239
|
-
},
|
|
240
|
-
required: ["icon", "title", "description", "prompt", "tags"],
|
|
241
|
-
},
|
|
242
|
-
},
|
|
243
|
-
},
|
|
244
|
-
required: ["relevance", "cards"],
|
|
245
|
-
},
|
|
246
|
-
},
|
|
247
|
-
],
|
|
248
|
-
systemPrompt,
|
|
249
|
-
{
|
|
250
|
-
config: {
|
|
251
|
-
modelIntent: "quality-optimized",
|
|
252
|
-
max_tokens: 1024,
|
|
253
|
-
tool_choice: {
|
|
254
|
-
type: "tool" as const,
|
|
255
|
-
name: "store_capability_cards",
|
|
256
|
-
},
|
|
257
|
-
},
|
|
258
|
-
signal,
|
|
259
|
-
},
|
|
260
|
-
);
|
|
261
|
-
cleanup();
|
|
262
|
-
|
|
263
|
-
const toolBlock = extractToolUse(response);
|
|
264
|
-
if (!toolBlock) {
|
|
265
|
-
log.warn("No tool_use block in capability card generation response");
|
|
266
|
-
return { relevance: 0, cards: [] };
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const input = toolBlock.input as {
|
|
270
|
-
relevance?: number;
|
|
271
|
-
cards?: GeneratedCard[];
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
const relevance =
|
|
275
|
-
typeof input.relevance === "number"
|
|
276
|
-
? Math.max(0, Math.min(1, input.relevance))
|
|
277
|
-
: 0;
|
|
278
|
-
|
|
279
|
-
if (!Array.isArray(input.cards)) {
|
|
280
|
-
return { relevance, cards: [] };
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const cards = input.cards
|
|
284
|
-
.filter(
|
|
285
|
-
(c) =>
|
|
286
|
-
typeof c.title === "string" &&
|
|
287
|
-
c.title.length > 0 &&
|
|
288
|
-
typeof c.prompt === "string" &&
|
|
289
|
-
c.prompt.length > 0,
|
|
290
|
-
)
|
|
291
|
-
.map((c) => ({
|
|
292
|
-
icon:
|
|
293
|
-
typeof c.icon === "string" && c.icon.length > 0
|
|
294
|
-
? c.icon
|
|
295
|
-
: "lucide-sparkles",
|
|
296
|
-
title: truncate(c.title, 50, ""),
|
|
297
|
-
description: truncate(c.description ?? "", 120, ""),
|
|
298
|
-
prompt: truncate(c.prompt, 500, ""),
|
|
299
|
-
tags: Array.isArray(c.tags)
|
|
300
|
-
? c.tags.filter((t): t is string => typeof t === "string").slice(0, 3)
|
|
301
|
-
: [],
|
|
302
|
-
}));
|
|
303
|
-
|
|
304
|
-
return { relevance, cards };
|
|
305
|
-
} catch (err) {
|
|
306
|
-
cleanup();
|
|
307
|
-
throw err;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// ── Job handler ───────────────────────────────────────────────────
|
|
312
|
-
|
|
313
|
-
export async function generateCapabilityCardsJob(
|
|
314
|
-
job: MemoryJob,
|
|
315
|
-
): Promise<void> {
|
|
316
|
-
const scopeId = asString(job.payload.scopeId) ?? "default";
|
|
317
|
-
const category = asString(job.payload.category) as
|
|
318
|
-
| CapabilityCardCategory
|
|
319
|
-
| undefined;
|
|
320
|
-
|
|
321
|
-
if (
|
|
322
|
-
!category ||
|
|
323
|
-
!(CAPABILITY_CARD_CATEGORIES as readonly string[]).includes(category)
|
|
324
|
-
) {
|
|
325
|
-
log.warn({ category }, "Invalid or missing category for capability cards");
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const result = await generateCardsForCategory(scopeId, category);
|
|
330
|
-
|
|
331
|
-
const db = getDb();
|
|
332
|
-
const now = Date.now();
|
|
333
|
-
|
|
334
|
-
// Determine next batch number
|
|
335
|
-
const batchCheckpoint = db
|
|
336
|
-
.select({ value: memoryCheckpoints.value })
|
|
337
|
-
.from(memoryCheckpoints)
|
|
338
|
-
.where(eq(memoryCheckpoints.key, checkpointKey(CK_BATCH, scopeId)))
|
|
339
|
-
.get();
|
|
340
|
-
const nextBatch = batchCheckpoint
|
|
341
|
-
? parseInt(batchCheckpoint.value, 10) + 1
|
|
342
|
-
: 1;
|
|
343
|
-
|
|
344
|
-
// Upsert category relevance
|
|
345
|
-
db.insert(capabilityCardCategories)
|
|
346
|
-
.values({
|
|
347
|
-
scopeId,
|
|
348
|
-
category,
|
|
349
|
-
relevance: result.relevance,
|
|
350
|
-
generationBatch: nextBatch,
|
|
351
|
-
createdAt: now,
|
|
352
|
-
})
|
|
353
|
-
.onConflictDoUpdate({
|
|
354
|
-
target: [
|
|
355
|
-
capabilityCardCategories.scopeId,
|
|
356
|
-
capabilityCardCategories.category,
|
|
357
|
-
],
|
|
358
|
-
set: {
|
|
359
|
-
relevance: result.relevance,
|
|
360
|
-
generationBatch: nextBatch,
|
|
361
|
-
createdAt: now,
|
|
362
|
-
},
|
|
363
|
-
})
|
|
364
|
-
.run();
|
|
365
|
-
|
|
366
|
-
// Delete old cards for this category+scope, then insert new ones
|
|
367
|
-
db.delete(threadStarters)
|
|
368
|
-
.where(
|
|
369
|
-
and(
|
|
370
|
-
eq(threadStarters.scopeId, scopeId),
|
|
371
|
-
eq(threadStarters.category, category),
|
|
372
|
-
eq(threadStarters.cardType, "card"),
|
|
373
|
-
),
|
|
374
|
-
)
|
|
375
|
-
.run();
|
|
376
|
-
|
|
377
|
-
// Insert new cards
|
|
378
|
-
for (const card of result.cards) {
|
|
379
|
-
db.insert(threadStarters)
|
|
380
|
-
.values({
|
|
381
|
-
id: uuid(),
|
|
382
|
-
label: card.title,
|
|
383
|
-
prompt: card.prompt,
|
|
384
|
-
icon: card.icon,
|
|
385
|
-
description: card.description,
|
|
386
|
-
tags: card.tags.join(","),
|
|
387
|
-
category,
|
|
388
|
-
cardType: "card",
|
|
389
|
-
generationBatch: nextBatch,
|
|
390
|
-
scopeId,
|
|
391
|
-
sourceMemoryKinds: null,
|
|
392
|
-
createdAt: now,
|
|
393
|
-
})
|
|
394
|
-
.run();
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Update batch checkpoint
|
|
398
|
-
db.insert(memoryCheckpoints)
|
|
399
|
-
.values({
|
|
400
|
-
key: checkpointKey(CK_BATCH, scopeId),
|
|
401
|
-
value: String(nextBatch),
|
|
402
|
-
updatedAt: now,
|
|
403
|
-
})
|
|
404
|
-
.onConflictDoUpdate({
|
|
405
|
-
target: memoryCheckpoints.key,
|
|
406
|
-
set: { value: String(nextBatch), updatedAt: now },
|
|
407
|
-
})
|
|
408
|
-
.run();
|
|
409
|
-
|
|
410
|
-
log.info(
|
|
411
|
-
{
|
|
412
|
-
scopeId,
|
|
413
|
-
category,
|
|
414
|
-
relevance: result.relevance,
|
|
415
|
-
cardCount: result.cards.length,
|
|
416
|
-
batch: nextBatch,
|
|
417
|
-
},
|
|
418
|
-
"Generated capability cards",
|
|
419
|
-
);
|
|
420
|
-
}
|
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route handlers for thread starter endpoints.
|
|
3
|
-
*
|
|
4
|
-
* GET /v1/thread-starters — list thread starters (chips) or capability cards
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { and, desc, eq, inArray, like } from "drizzle-orm";
|
|
8
|
-
|
|
9
|
-
import { getDb } from "../../memory/db.js";
|
|
10
|
-
import { CAPABILITY_CARD_CATEGORIES } from "../../memory/job-handlers/capability-cards.js";
|
|
11
|
-
import { enqueueMemoryJob } from "../../memory/jobs-store.js";
|
|
12
|
-
import { rawAll, rawGet } from "../../memory/raw-query.js";
|
|
13
|
-
import {
|
|
14
|
-
capabilityCardCategories,
|
|
15
|
-
memoryJobs,
|
|
16
|
-
threadStarters,
|
|
17
|
-
} from "../../memory/schema.js";
|
|
18
|
-
import type { RouteDefinition } from "../http-router.js";
|
|
19
|
-
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
// GET /v1/thread-starters?card_type=chip (default, backwards-compat)
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
|
|
24
|
-
function handleListThreadStarters(url: URL): Response {
|
|
25
|
-
const cardType = url.searchParams.get("card_type") ?? "chip";
|
|
26
|
-
|
|
27
|
-
if (cardType === "card") {
|
|
28
|
-
return handleListCapabilityCards(url);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const limitParam = Math.min(
|
|
32
|
-
Math.max(1, Number(url.searchParams.get("limit") ?? 4)),
|
|
33
|
-
20,
|
|
34
|
-
);
|
|
35
|
-
const offsetParam = Math.max(0, Number(url.searchParams.get("offset") ?? 0));
|
|
36
|
-
const scopeId = url.searchParams.get("scope_id") ?? "default";
|
|
37
|
-
|
|
38
|
-
const db = getDb();
|
|
39
|
-
|
|
40
|
-
const items = db
|
|
41
|
-
.select({
|
|
42
|
-
id: threadStarters.id,
|
|
43
|
-
label: threadStarters.label,
|
|
44
|
-
prompt: threadStarters.prompt,
|
|
45
|
-
category: threadStarters.category,
|
|
46
|
-
batch: threadStarters.generationBatch,
|
|
47
|
-
})
|
|
48
|
-
.from(threadStarters)
|
|
49
|
-
.where(
|
|
50
|
-
and(
|
|
51
|
-
eq(threadStarters.scopeId, scopeId),
|
|
52
|
-
eq(threadStarters.cardType, "chip"),
|
|
53
|
-
),
|
|
54
|
-
)
|
|
55
|
-
.orderBy(
|
|
56
|
-
desc(threadStarters.generationBatch),
|
|
57
|
-
desc(threadStarters.createdAt),
|
|
58
|
-
)
|
|
59
|
-
.limit(limitParam)
|
|
60
|
-
.offset(offsetParam)
|
|
61
|
-
.all();
|
|
62
|
-
|
|
63
|
-
const countRow = rawGet<{ c: number }>(
|
|
64
|
-
`SELECT COUNT(*) AS c FROM thread_starters WHERE scope_id = ? AND card_type = 'chip'`,
|
|
65
|
-
scopeId,
|
|
66
|
-
);
|
|
67
|
-
const total = countRow?.c ?? 0;
|
|
68
|
-
|
|
69
|
-
// If starters exist, return them immediately.
|
|
70
|
-
if (total > 0) {
|
|
71
|
-
return Response.json({ starters: items, total, status: "ready" });
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// No starters — check whether we have memory items to generate from.
|
|
75
|
-
const memoryCount = rawGet<{ c: number }>(
|
|
76
|
-
`SELECT COUNT(*) AS c FROM memory_items WHERE status = 'active' AND scope_id = ?`,
|
|
77
|
-
scopeId,
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
if (!memoryCount || memoryCount.c === 0) {
|
|
81
|
-
return Response.json({ starters: [], total: 0, status: "empty" });
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Memory items exist but no starters yet — ensure a generation job is queued.
|
|
85
|
-
const existing = db
|
|
86
|
-
.select({ id: memoryJobs.id })
|
|
87
|
-
.from(memoryJobs)
|
|
88
|
-
.where(
|
|
89
|
-
and(
|
|
90
|
-
eq(memoryJobs.type, "generate_thread_starters"),
|
|
91
|
-
inArray(memoryJobs.status, ["pending", "running"]),
|
|
92
|
-
like(memoryJobs.payload, `%"scopeId":"${scopeId}"%`),
|
|
93
|
-
),
|
|
94
|
-
)
|
|
95
|
-
.get();
|
|
96
|
-
|
|
97
|
-
if (!existing) {
|
|
98
|
-
enqueueMemoryJob("generate_thread_starters", { scopeId });
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return Response.json({ starters: [], total: 0, status: "generating" });
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// ---------------------------------------------------------------------------
|
|
105
|
-
// GET /v1/thread-starters?card_type=card — capability cards feed
|
|
106
|
-
// ---------------------------------------------------------------------------
|
|
107
|
-
|
|
108
|
-
function handleListCapabilityCards(url: URL): Response {
|
|
109
|
-
const limitParam = Math.min(
|
|
110
|
-
Math.max(1, Number(url.searchParams.get("limit") ?? 24)),
|
|
111
|
-
50,
|
|
112
|
-
);
|
|
113
|
-
const scopeId = url.searchParams.get("scope_id") ?? "default";
|
|
114
|
-
const categoryFilter = url.searchParams.get("category");
|
|
115
|
-
|
|
116
|
-
const db = getDb();
|
|
117
|
-
|
|
118
|
-
// Build WHERE conditions for cards
|
|
119
|
-
const conditions = [
|
|
120
|
-
eq(threadStarters.scopeId, scopeId),
|
|
121
|
-
eq(threadStarters.cardType, "card"),
|
|
122
|
-
];
|
|
123
|
-
if (categoryFilter) {
|
|
124
|
-
conditions.push(eq(threadStarters.category, categoryFilter));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const cards = db
|
|
128
|
-
.select({
|
|
129
|
-
id: threadStarters.id,
|
|
130
|
-
icon: threadStarters.icon,
|
|
131
|
-
label: threadStarters.label,
|
|
132
|
-
description: threadStarters.description,
|
|
133
|
-
prompt: threadStarters.prompt,
|
|
134
|
-
category: threadStarters.category,
|
|
135
|
-
tags: threadStarters.tags,
|
|
136
|
-
batch: threadStarters.generationBatch,
|
|
137
|
-
})
|
|
138
|
-
.from(threadStarters)
|
|
139
|
-
.where(and(...conditions))
|
|
140
|
-
.orderBy(
|
|
141
|
-
desc(threadStarters.generationBatch),
|
|
142
|
-
desc(threadStarters.createdAt),
|
|
143
|
-
)
|
|
144
|
-
.limit(limitParam)
|
|
145
|
-
.all();
|
|
146
|
-
|
|
147
|
-
// Transform tags from comma-separated string to array
|
|
148
|
-
const transformedCards = cards.map((c) => ({
|
|
149
|
-
...c,
|
|
150
|
-
tags: c.tags ? c.tags.split(",").filter(Boolean) : [],
|
|
151
|
-
}));
|
|
152
|
-
|
|
153
|
-
// Build per-category status map
|
|
154
|
-
const categoryStatuses = buildCategoryStatuses(scopeId);
|
|
155
|
-
|
|
156
|
-
// Proper COUNT query — transformedCards.length would be LIMIT-capped
|
|
157
|
-
const countCondition = categoryFilter ? `AND category = ?` : ``;
|
|
158
|
-
const countParams = categoryFilter ? [scopeId, categoryFilter] : [scopeId];
|
|
159
|
-
const countRow = rawGet<{ c: number }>(
|
|
160
|
-
`SELECT COUNT(*) AS c FROM thread_starters WHERE scope_id = ? AND card_type = 'card' ${countCondition}`,
|
|
161
|
-
...countParams,
|
|
162
|
-
);
|
|
163
|
-
const total = countRow?.c ?? 0;
|
|
164
|
-
|
|
165
|
-
// If we have cards, return them
|
|
166
|
-
if (total > 0) {
|
|
167
|
-
const overallStatus = Object.values(categoryStatuses).some(
|
|
168
|
-
(s) => s.status === "generating",
|
|
169
|
-
)
|
|
170
|
-
? "generating"
|
|
171
|
-
: "ready";
|
|
172
|
-
|
|
173
|
-
return Response.json({
|
|
174
|
-
cards: transformedCards,
|
|
175
|
-
total,
|
|
176
|
-
status: overallStatus,
|
|
177
|
-
categories: categoryStatuses,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// No cards — check whether we have memory items to generate from
|
|
182
|
-
const memoryCount = rawGet<{ c: number }>(
|
|
183
|
-
`SELECT COUNT(*) AS c FROM memory_items WHERE status = 'active' AND scope_id = ?`,
|
|
184
|
-
scopeId,
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
if (!memoryCount || memoryCount.c === 0) {
|
|
188
|
-
return Response.json({
|
|
189
|
-
cards: [],
|
|
190
|
-
total: 0,
|
|
191
|
-
status: "empty",
|
|
192
|
-
categories: {},
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Memory items exist but no cards — enqueue generation for all categories
|
|
197
|
-
enqueueCapabilityCardJobs(scopeId);
|
|
198
|
-
|
|
199
|
-
return Response.json({
|
|
200
|
-
cards: [],
|
|
201
|
-
total: 0,
|
|
202
|
-
status: "generating",
|
|
203
|
-
categories: Object.fromEntries(
|
|
204
|
-
CAPABILITY_CARD_CATEGORIES.map((cat) => [
|
|
205
|
-
cat,
|
|
206
|
-
{ status: "generating" as const },
|
|
207
|
-
]),
|
|
208
|
-
),
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/** Build a status map for each category: ready (with relevance) or generating. */
|
|
213
|
-
function buildCategoryStatuses(
|
|
214
|
-
scopeId: string,
|
|
215
|
-
): Record<string, { status: string; relevance?: number }> {
|
|
216
|
-
const db = getDb();
|
|
217
|
-
const statuses: Record<string, { status: string; relevance?: number }> = {};
|
|
218
|
-
|
|
219
|
-
// Get completed categories with relevance scores
|
|
220
|
-
const completed = db
|
|
221
|
-
.select({
|
|
222
|
-
category: capabilityCardCategories.category,
|
|
223
|
-
relevance: capabilityCardCategories.relevance,
|
|
224
|
-
})
|
|
225
|
-
.from(capabilityCardCategories)
|
|
226
|
-
.where(eq(capabilityCardCategories.scopeId, scopeId))
|
|
227
|
-
.all();
|
|
228
|
-
|
|
229
|
-
const completedSet = new Set(completed.map((c) => c.category));
|
|
230
|
-
for (const row of completed) {
|
|
231
|
-
statuses[row.category] = { status: "ready", relevance: row.relevance };
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Check for in-flight generation jobs
|
|
235
|
-
const pendingJobs = rawAll<{ payload: string }>(
|
|
236
|
-
`SELECT payload FROM memory_jobs
|
|
237
|
-
WHERE type = 'generate_capability_cards'
|
|
238
|
-
AND status IN ('pending', 'running')
|
|
239
|
-
AND payload LIKE ?`,
|
|
240
|
-
`%"scopeId":"${scopeId}"%`,
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
for (const job of pendingJobs) {
|
|
244
|
-
try {
|
|
245
|
-
const parsed = JSON.parse(job.payload) as { category?: string };
|
|
246
|
-
if (parsed.category && !completedSet.has(parsed.category)) {
|
|
247
|
-
statuses[parsed.category] = { status: "generating" };
|
|
248
|
-
}
|
|
249
|
-
} catch {
|
|
250
|
-
// Skip malformed payloads
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return statuses;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/** Enqueue one generation job per category, skipping those already in-flight. */
|
|
258
|
-
function enqueueCapabilityCardJobs(scopeId: string): void {
|
|
259
|
-
const db = getDb();
|
|
260
|
-
|
|
261
|
-
for (const category of CAPABILITY_CARD_CATEGORIES) {
|
|
262
|
-
// Check if already pending/running for this scope+category
|
|
263
|
-
const existing = db
|
|
264
|
-
.select({ id: memoryJobs.id })
|
|
265
|
-
.from(memoryJobs)
|
|
266
|
-
.where(
|
|
267
|
-
and(
|
|
268
|
-
eq(memoryJobs.type, "generate_capability_cards"),
|
|
269
|
-
inArray(memoryJobs.status, ["pending", "running"]),
|
|
270
|
-
like(memoryJobs.payload, `%"scopeId":"${scopeId}"%`),
|
|
271
|
-
like(memoryJobs.payload, `%"category":"${category}"%`),
|
|
272
|
-
),
|
|
273
|
-
)
|
|
274
|
-
.get();
|
|
275
|
-
|
|
276
|
-
if (!existing) {
|
|
277
|
-
enqueueMemoryJob("generate_capability_cards", { scopeId, category });
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// ---------------------------------------------------------------------------
|
|
283
|
-
// Route definitions
|
|
284
|
-
// ---------------------------------------------------------------------------
|
|
285
|
-
|
|
286
|
-
export function threadStarterRouteDefinitions(): RouteDefinition[] {
|
|
287
|
-
return [
|
|
288
|
-
{
|
|
289
|
-
endpoint: "thread-starters",
|
|
290
|
-
method: "GET",
|
|
291
|
-
handler: (ctx) => handleListThreadStarters(ctx.url),
|
|
292
|
-
},
|
|
293
|
-
];
|
|
294
|
-
}
|