@vellumai/assistant 0.4.56 → 0.5.0
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 +204 -185
- 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 +249 -15
- package/src/__tests__/ephemeral-permissions.test.ts +4 -5
- package/src/__tests__/event-bus.test.ts +3 -3
- package/src/__tests__/file-read-tool.test.ts +40 -0
- 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-file-read-tool.test.ts +87 -0
- package/src/__tests__/host-shell-tool.test.ts +6 -6
- package/src/__tests__/http-user-message-parity.test.ts +2 -2
- package/src/__tests__/identity-intro-cache.test.ts +209 -0
- 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 +2 -2
- package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
- package/src/__tests__/non-member-access-request.test.ts +3 -3
- 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 +549 -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 +141 -275
- 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 +26 -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 +5 -1
- 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 +45 -4
- package/src/notifications/emit-signal.ts +5 -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 +172 -33
- package/src/prompts/templates/IDENTITY.md +8 -24
- 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 +51 -19
- 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 +16 -2
- 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 +61 -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 +93 -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/identity-intro-cache.ts +105 -0
- package/src/runtime/routes/identity-routes.ts +51 -0
- 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 +9 -9
- 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 +262 -78
- package/src/skills/catalog-install.ts +10 -0
- package/src/skills/managed-store.ts +2 -0
- package/src/skills/skill-memory.ts +222 -0
- package/src/subagent/manager.ts +1 -4
- package/src/telemetry/types.ts +10 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +7 -2
- package/src/telemetry/usage-telemetry-reporter.ts +53 -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 +15 -4
- package/src/tools/filesystem/write.ts +1 -1
- package/src/tools/host-filesystem/edit.ts +2 -1
- package/src/tools/host-filesystem/read.ts +18 -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/pricing.ts +4 -0
- 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
|
@@ -146,7 +146,6 @@ export async function generateAndPersistConversationTitle(
|
|
|
146
146
|
signal: combinedSignal,
|
|
147
147
|
},
|
|
148
148
|
);
|
|
149
|
-
|
|
150
149
|
const textBlock = response.content.find((b) => b.type === "text");
|
|
151
150
|
if (textBlock && textBlock.type === "text") {
|
|
152
151
|
let title = normalizeTitle(textBlock.text);
|
|
@@ -312,7 +311,7 @@ function buildTitlePrompt(
|
|
|
312
311
|
assistantResponse?: string,
|
|
313
312
|
): string {
|
|
314
313
|
const parts: string[] = [
|
|
315
|
-
"Generate a very short title
|
|
314
|
+
"Generate a very short title summarizing the TOPIC of this conversation. Rules: at most 5 words, at most 40 characters, no quotes, no markdown formatting. IMPORTANT: Summarize what the user is asking about — do NOT respond to the message, do NOT assess feasibility, and do NOT comment on your own capabilities.",
|
|
316
315
|
];
|
|
317
316
|
|
|
318
317
|
if (context) {
|
|
@@ -369,7 +368,7 @@ function deriveFallbackTitle(context?: TitleContext): string | null {
|
|
|
369
368
|
|
|
370
369
|
function buildRegenerationPrompt(recentMessages: MessageRow[]): string {
|
|
371
370
|
const parts: string[] = [
|
|
372
|
-
"Generate a very short title
|
|
371
|
+
"Generate a very short title summarizing the TOPIC of this conversation based on the recent messages below. Rules: at most 5 words, at most 40 characters, no quotes, no markdown formatting. IMPORTANT: Summarize what the user is asking about — do NOT respond to the messages, do NOT assess feasibility, and do NOT comment on your own capabilities.",
|
|
373
372
|
"",
|
|
374
373
|
"Recent messages:",
|
|
375
374
|
];
|
package/src/memory/db-init.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
createCoreTables,
|
|
26
26
|
createExternalConversationBindingsTables,
|
|
27
27
|
createFollowupsTables,
|
|
28
|
+
createLifecycleEventsTable,
|
|
28
29
|
createMediaAssetsTables,
|
|
29
30
|
createMessagesFts,
|
|
30
31
|
createNotificationTables,
|
|
@@ -51,8 +52,10 @@ import {
|
|
|
51
52
|
migrateContactsRolePrincipal,
|
|
52
53
|
migrateConversationsThreadTypeIndex,
|
|
53
54
|
migrateCreateThreadStartersTable,
|
|
55
|
+
migrateCreateTraceEventsTable,
|
|
54
56
|
migrateDropAccountsTable,
|
|
55
57
|
migrateDropAssistantIdColumns,
|
|
58
|
+
migrateDropCapabilityCardState,
|
|
56
59
|
migrateDropConflicts,
|
|
57
60
|
migrateDropContactInteractionColumns,
|
|
58
61
|
migrateDropEntityTables,
|
|
@@ -84,6 +87,7 @@ import {
|
|
|
84
87
|
migrateReminderRoutingIntent,
|
|
85
88
|
migrateRemindersToSchedules,
|
|
86
89
|
migrateRenameConversationTypeColumn,
|
|
90
|
+
migrateRenameCreatedBySessionIdColumns,
|
|
87
91
|
migrateRenameFollowupsThreadIdColumn,
|
|
88
92
|
migrateRenameGmailProviderKeyToGoogle,
|
|
89
93
|
migrateRenameGuardianVerificationValues,
|
|
@@ -91,6 +95,8 @@ import {
|
|
|
91
95
|
migrateRenameNotificationThreadColumns,
|
|
92
96
|
migrateRenameSequenceEnrollmentsThreadIdColumn,
|
|
93
97
|
migrateRenameSequenceStepsReplyKey,
|
|
98
|
+
migrateRenameSourceSessionIdColumn,
|
|
99
|
+
migrateRenameThreadStartersTable,
|
|
94
100
|
migrateRenameVerificationSessionIdColumn,
|
|
95
101
|
migrateRenameVerificationTable,
|
|
96
102
|
migrateRenameVoiceToPhone,
|
|
@@ -426,12 +432,30 @@ export function initializeDb(): void {
|
|
|
426
432
|
// 72. Rename integration:gmail → integration:google across OAuth tables
|
|
427
433
|
migrateRenameGmailProviderKeyToGoogle(database);
|
|
428
434
|
|
|
429
|
-
// 73. Create thread_starters table for personalized empty-thread suggestions
|
|
435
|
+
// 73. Create thread_starters table for personalized empty-thread suggestions (renamed in migration 77)
|
|
430
436
|
migrateCreateThreadStartersTable(database);
|
|
431
437
|
|
|
432
438
|
// 74. Add capability card columns to thread_starters + category relevance table
|
|
433
439
|
migrateCapabilityCardColumns(database);
|
|
434
440
|
|
|
441
|
+
// 75. Rename created_by_session_id → source_conversation_id in verification sessions and invites
|
|
442
|
+
migrateRenameCreatedBySessionIdColumns(database);
|
|
443
|
+
|
|
444
|
+
// 76. Rename source_session_id → source_context_id in notification_events
|
|
445
|
+
migrateRenameSourceSessionIdColumn(database);
|
|
446
|
+
|
|
447
|
+
// 77. Rename thread_starters → conversation_starters table and indexes
|
|
448
|
+
migrateRenameThreadStartersTable(database);
|
|
449
|
+
|
|
450
|
+
// 78. Lifecycle events table for app_open / hatch telemetry
|
|
451
|
+
createLifecycleEventsTable(database);
|
|
452
|
+
|
|
453
|
+
// 79. Remove deleted capability-card state while keeping conversation starter chips
|
|
454
|
+
migrateDropCapabilityCardState(database);
|
|
455
|
+
|
|
456
|
+
// 80. Trace events table for persistent trace/activity storage across sessions
|
|
457
|
+
migrateCreateTraceEventsTable(database);
|
|
458
|
+
|
|
435
459
|
validateMigrationState(database);
|
|
436
460
|
|
|
437
461
|
if (process.env.BUN_TEST === "1") {
|
|
@@ -23,7 +23,7 @@ export interface IngressInvite {
|
|
|
23
23
|
id: string;
|
|
24
24
|
sourceChannel: string;
|
|
25
25
|
tokenHash: string;
|
|
26
|
-
|
|
26
|
+
sourceConversationId: string | null;
|
|
27
27
|
note: string | null;
|
|
28
28
|
maxUses: number;
|
|
29
29
|
useCount: number;
|
|
@@ -73,7 +73,7 @@ function rowToInvite(
|
|
|
73
73
|
id: row.id,
|
|
74
74
|
sourceChannel: row.sourceChannel,
|
|
75
75
|
tokenHash: row.tokenHash,
|
|
76
|
-
|
|
76
|
+
sourceConversationId: row.sourceConversationId,
|
|
77
77
|
note: row.note,
|
|
78
78
|
maxUses: row.maxUses,
|
|
79
79
|
useCount: row.useCount,
|
|
@@ -101,7 +101,7 @@ function rowToInvite(
|
|
|
101
101
|
export function createInvite(params: {
|
|
102
102
|
sourceChannel: string;
|
|
103
103
|
contactId: string;
|
|
104
|
-
|
|
104
|
+
sourceConversationId?: string;
|
|
105
105
|
note?: string;
|
|
106
106
|
maxUses?: number;
|
|
107
107
|
expiresInMs?: number;
|
|
@@ -124,7 +124,7 @@ export function createInvite(params: {
|
|
|
124
124
|
id,
|
|
125
125
|
sourceChannel: params.sourceChannel,
|
|
126
126
|
tokenHash: tokenH,
|
|
127
|
-
|
|
127
|
+
sourceConversationId: params.sourceConversationId ?? null,
|
|
128
128
|
note: params.note ?? null,
|
|
129
129
|
maxUses: params.maxUses ?? 1,
|
|
130
130
|
useCount: 0,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "../providers/provider-send-message.js";
|
|
13
13
|
import { getLogger } from "../util/logger.js";
|
|
14
14
|
import { truncate } from "../util/truncate.js";
|
|
15
|
+
import { maybeEnqueueConversationStartersJob } from "./conversation-starters-cadence.js";
|
|
15
16
|
import { getDb } from "./db.js";
|
|
16
17
|
import { computeMemoryFingerprint } from "./fingerprint.js";
|
|
17
18
|
import { enqueueMemoryJob } from "./jobs-store.js";
|
|
@@ -20,7 +21,6 @@ import { withQdrantBreaker } from "./qdrant-circuit-breaker.js";
|
|
|
20
21
|
import { getQdrantClient } from "./qdrant-client.js";
|
|
21
22
|
import { memoryItems, memoryItemSources, messages } from "./schema.js";
|
|
22
23
|
import { isConversationFailed } from "./task-memory-cleanup.js";
|
|
23
|
-
import { maybeEnqueueThreadStartersJob } from "./thread-starters-cadence.js";
|
|
24
24
|
import { clampUnitInterval } from "./validation.js";
|
|
25
25
|
|
|
26
26
|
const log = getLogger("memory-items-extractor");
|
|
@@ -715,14 +715,14 @@ export async function extractAndUpsertMemoryItemsForMessage(
|
|
|
715
715
|
"Extracted memory items from message",
|
|
716
716
|
);
|
|
717
717
|
|
|
718
|
-
// Trigger
|
|
718
|
+
// Trigger conversation starters generation when new items are upserted
|
|
719
719
|
if (upserted > 0) {
|
|
720
720
|
try {
|
|
721
|
-
|
|
721
|
+
maybeEnqueueConversationStartersJob(effectiveScopeId);
|
|
722
722
|
} catch (err) {
|
|
723
723
|
log.warn(
|
|
724
724
|
{ err: err instanceof Error ? err.message : String(err) },
|
|
725
|
-
"Failed to check
|
|
725
|
+
"Failed to check conversation starters cadence",
|
|
726
726
|
);
|
|
727
727
|
}
|
|
728
728
|
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Job handler for generating
|
|
2
|
+
* Job handler for generating conversation starters.
|
|
3
3
|
*
|
|
4
4
|
* Crosses user memory items with the skill catalog to produce personalized
|
|
5
|
-
* suggestion chips shown on the empty
|
|
5
|
+
* suggestion chips shown on the empty conversation page.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { and, desc, eq } from "drizzle-orm";
|
|
9
9
|
import { v4 as uuid } from "uuid";
|
|
10
10
|
|
|
11
11
|
import { loadSkillCatalog } from "../../config/skills.js";
|
|
12
|
+
import { buildCoreIdentityContext } from "../../prompts/system-prompt.js";
|
|
12
13
|
import {
|
|
13
14
|
createTimeout,
|
|
14
15
|
extractToolUse,
|
|
@@ -21,17 +22,21 @@ import { getDb } from "../db.js";
|
|
|
21
22
|
import { asString } from "../job-utils.js";
|
|
22
23
|
import type { MemoryJob } from "../jobs-store.js";
|
|
23
24
|
import { rawAll, rawGet } from "../raw-query.js";
|
|
24
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
conversationStarters,
|
|
27
|
+
memoryCheckpoints,
|
|
28
|
+
memoryItems,
|
|
29
|
+
} from "../schema.js";
|
|
25
30
|
|
|
26
|
-
const log = getLogger("
|
|
31
|
+
const log = getLogger("conversation-starters-gen");
|
|
27
32
|
|
|
28
33
|
function checkpointKey(base: string, scopeId: string): string {
|
|
29
34
|
return `${base}:${scopeId}`;
|
|
30
35
|
}
|
|
31
36
|
|
|
32
|
-
const CK_ITEM_COUNT = "
|
|
33
|
-
const CK_BATCH = "
|
|
34
|
-
const CK_LAST_GEN_AT = "
|
|
37
|
+
const CK_ITEM_COUNT = "conversation_starters:item_count_at_last_gen";
|
|
38
|
+
const CK_BATCH = "conversation_starters:generation_batch";
|
|
39
|
+
const CK_LAST_GEN_AT = "conversation_starters:last_gen_at";
|
|
35
40
|
|
|
36
41
|
// ── Rollup construction ───────────────────────────────────────────
|
|
37
42
|
|
|
@@ -126,7 +131,7 @@ export function buildSkillsSummary(): string {
|
|
|
126
131
|
// ── LLM generation ────────────────────────────────────────────────
|
|
127
132
|
|
|
128
133
|
/** Capability categories matching the Intelligence page taxonomy. */
|
|
129
|
-
export const
|
|
134
|
+
export const CONVERSATION_STARTER_CATEGORIES = [
|
|
130
135
|
"communication",
|
|
131
136
|
"productivity",
|
|
132
137
|
"development",
|
|
@@ -137,7 +142,8 @@ export const THREAD_STARTER_CATEGORIES = [
|
|
|
137
142
|
"integration",
|
|
138
143
|
] as const;
|
|
139
144
|
|
|
140
|
-
export type
|
|
145
|
+
export type ConversationStarterCategory =
|
|
146
|
+
(typeof CONVERSATION_STARTER_CATEGORIES)[number];
|
|
141
147
|
|
|
142
148
|
interface GeneratedStarter {
|
|
143
149
|
label: string;
|
|
@@ -148,48 +154,110 @@ interface GeneratedStarter {
|
|
|
148
154
|
async function generateStarters(scopeId: string): Promise<GeneratedStarter[]> {
|
|
149
155
|
const provider = await getConfiguredProvider();
|
|
150
156
|
if (!provider) {
|
|
151
|
-
log.info("No configured provider for
|
|
157
|
+
log.info("No configured provider for conversation starters generation");
|
|
152
158
|
return [];
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
const rollup = buildMemoryRollup(scopeId);
|
|
156
162
|
if (!rollup) {
|
|
157
|
-
log.info("No memory items to generate
|
|
163
|
+
log.info("No memory items to generate conversation starters from");
|
|
158
164
|
return [];
|
|
159
165
|
}
|
|
160
166
|
const diff = buildNewItemsDiff(scopeId);
|
|
161
167
|
const skills = buildSkillsSummary();
|
|
162
168
|
|
|
163
|
-
const
|
|
169
|
+
const now = new Date();
|
|
170
|
+
const timeContext = `Current time: ${now.toLocaleString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "2-digit", hour12: true })}`;
|
|
171
|
+
|
|
172
|
+
const identityContext = buildCoreIdentityContext();
|
|
173
|
+
|
|
174
|
+
const systemPrompt = `You are generating 4 conversation starters for a personal assistant app. These appear as clickable chips on the empty conversation page — the first thing the user sees when they open the app.
|
|
175
|
+
|
|
176
|
+
${timeContext}
|
|
164
177
|
|
|
165
|
-
|
|
166
|
-
- label: Short chip text (max 50 chars). Start with a verb. Be specific and actionable.
|
|
167
|
-
- prompt: The full message that will be sent when clicked (1-2 natural sentences).
|
|
168
|
-
- category: One of: ${THREAD_STARTER_CATEGORIES.join(", ")}. Pick the best-fit capability category.
|
|
178
|
+
Your goal: look at what's going on in this person's life right now and suggest the 4 most useful things they could ask you to do. Think about what a thoughtful chief of staff would proactively bring up in a 30-second check-in.
|
|
169
179
|
|
|
170
|
-
|
|
171
|
-
- Cross user context (who they are, what they work on) with assistant capabilities (skills).
|
|
172
|
-
- Be specific to THIS user — generic suggestions like "Tell me a joke" are not useful.
|
|
173
|
-
- Vary across different skills and memory categories.
|
|
174
|
-
- Labels should be concise and scannable.
|
|
175
|
-
- Prompts should be natural, as if the user typed them.
|
|
180
|
+
${identityContext ? `## Assistant identity & user profile\n\n${identityContext}\n\n` : ""}## What you know
|
|
176
181
|
|
|
177
182
|
${rollup}
|
|
178
183
|
${diff}
|
|
179
|
-
${skills}
|
|
184
|
+
${skills}
|
|
185
|
+
|
|
186
|
+
## How to think about this
|
|
187
|
+
|
|
188
|
+
Start from the user's situation, not from the skill list. Ask yourself:
|
|
189
|
+
- What is this person likely dealing with right now (given the day/time and their context)?
|
|
190
|
+
- What's active, stuck, or coming up soon?
|
|
191
|
+
- Where could I save them real time or effort right now?
|
|
192
|
+
|
|
193
|
+
The skills list tells you what the assistant CAN do — use it to filter out suggestions the assistant can't actually help with, not as a menu to generate suggestions from.
|
|
194
|
+
|
|
195
|
+
## Selection
|
|
196
|
+
|
|
197
|
+
Generate exactly 4 starters, ranked #1 (best) to #4.
|
|
198
|
+
|
|
199
|
+
For each, you must be able to clearly answer:
|
|
200
|
+
- Why now? (timing — day of week, recent activity, upcoming deadline)
|
|
201
|
+
- Why this user? (grounded in their specific context, not generic)
|
|
202
|
+
- Why would they be glad I suggested this? (genuine usefulness, not just relevance)
|
|
203
|
+
|
|
204
|
+
If you can't answer all three strongly, replace it with something better.
|
|
205
|
+
|
|
206
|
+
Prioritize:
|
|
207
|
+
- Relief: unblock something stuck, reduce drag
|
|
208
|
+
- Momentum: advance work already in motion
|
|
209
|
+
- Confidence: surface what they need to decide or act on
|
|
210
|
+
- Curiosity: something timely they'd want to know about
|
|
211
|
+
|
|
212
|
+
Favor what is live over what is merely true. Recent changes matter more than old memories. Active work matters more than dormant topics. This week matters more than "someday."
|
|
213
|
+
|
|
214
|
+
## Output format
|
|
215
|
+
|
|
216
|
+
Return exactly 4 starters in rank order (best first).
|
|
217
|
+
|
|
218
|
+
Each starter has:
|
|
219
|
+
- label: 3-6 words, max 40 chars, starts with a verb. Should sound like a smart offer of help, not a feature name or task description. Must sound natural when read aloud.
|
|
220
|
+
- prompt: 1-2 natural sentences, written as the user would actually say them — not templated.
|
|
221
|
+
- category: one of ${CONVERSATION_STARTER_CATEGORIES.join(", ")}
|
|
222
|
+
|
|
223
|
+
The 4 starters should feel like one coherent set of recommendations for this moment — similar abstraction level, no jarring mix of mundane chores and life strategy. Don't lift raw memory phrases, project names, or jargon into labels unless they already sound natural in conversation.
|
|
224
|
+
|
|
225
|
+
Never include a chip whose primary meaning is configuration, setup, workflow creation, or "set up X for Y" unless it solves an urgent pain the user is actively feeling right now. Prefer the outcome over the mechanism — "Catch the emails that matter" beats "Set up a playbook for inbox."
|
|
226
|
+
|
|
227
|
+
## Topic diversity
|
|
228
|
+
|
|
229
|
+
Each chip should cover a distinct topic or concern. Never have two chips about the same tool, project, or theme — even if there are multiple related issues. Pick the single most impactful angle and give the other slot to something different. Four chips about three topics is too narrow; four chips about four topics is right.
|
|
230
|
+
|
|
231
|
+
## User-facingness check
|
|
232
|
+
|
|
233
|
+
If a label sounds like an issue title, project ticket, or implementation task, rewrite it. Prefer the user-visible payoff over the internal object name. The chip should feel inviting and useful, not merely accurate.
|
|
234
|
+
|
|
235
|
+
Prefer natural, flowing language over mechanical or operational phrasing. "Get Slack messages flowing" is better than "Restore outgoing Slack messages." The label should sound like something a helpful person would say, not a support ticket.
|
|
236
|
+
|
|
237
|
+
Before finalizing each label, ask yourself: would this feel good to click? Or does it sound like a backlog item? If it sounds like a backlog item, rewrite it.
|
|
238
|
+
|
|
239
|
+
Examples of bad vs good:
|
|
240
|
+
- BAD: "Fix Slack Socket Mode blocker" → GOOD: "Fix Slack so it just works"
|
|
241
|
+
- BAD: "Rewire messaging for Socket Mode" → GOOD: "Get Socket Mode stable"
|
|
242
|
+
- BAD: "Review this week's calendar" → GOOD: "Protect this week's focus"
|
|
243
|
+
- BAD: "Model the coaching transition" → GOOD: "Plan the coaching transition"
|
|
244
|
+
- BAD: "Restore outgoing Slack messages" → GOOD: "Get Slack messages flowing"
|
|
245
|
+
- BAD: "Set up a playbook for inbox" → GOOD: "Catch the emails that matter"
|
|
246
|
+
|
|
247
|
+
The good versions emphasize the user's payoff, not the internal mechanism.`;
|
|
180
248
|
|
|
181
249
|
const { signal, cleanup } = createTimeout(20000);
|
|
182
250
|
try {
|
|
183
251
|
const response = await provider.sendMessage(
|
|
184
252
|
[
|
|
185
253
|
userMessage(
|
|
186
|
-
"Generate personalized
|
|
254
|
+
"Generate personalized conversation starters based on my context.",
|
|
187
255
|
),
|
|
188
256
|
],
|
|
189
257
|
[
|
|
190
258
|
{
|
|
191
|
-
name: "
|
|
192
|
-
description: "Store generated
|
|
259
|
+
name: "store_conversation_starters",
|
|
260
|
+
description: "Store generated conversation starter suggestions",
|
|
193
261
|
input_schema: {
|
|
194
262
|
type: "object" as const,
|
|
195
263
|
properties: {
|
|
@@ -201,15 +269,16 @@ ${skills}`;
|
|
|
201
269
|
label: {
|
|
202
270
|
type: "string",
|
|
203
271
|
description:
|
|
204
|
-
"
|
|
272
|
+
"Concierge-quality chip text (2-7 words, max 40 chars, starts with a verb)",
|
|
205
273
|
},
|
|
206
274
|
prompt: {
|
|
207
275
|
type: "string",
|
|
208
|
-
description:
|
|
276
|
+
description:
|
|
277
|
+
"Full message sent on click (1-2 natural sentences, as the user would say it)",
|
|
209
278
|
},
|
|
210
279
|
category: {
|
|
211
280
|
type: "string",
|
|
212
|
-
enum: [...
|
|
281
|
+
enum: [...CONVERSATION_STARTER_CATEGORIES],
|
|
213
282
|
description: "Capability category for grouping",
|
|
214
283
|
},
|
|
215
284
|
},
|
|
@@ -226,7 +295,10 @@ ${skills}`;
|
|
|
226
295
|
config: {
|
|
227
296
|
modelIntent: "quality-optimized",
|
|
228
297
|
max_tokens: 1024,
|
|
229
|
-
tool_choice: {
|
|
298
|
+
tool_choice: {
|
|
299
|
+
type: "tool" as const,
|
|
300
|
+
name: "store_conversation_starters",
|
|
301
|
+
},
|
|
230
302
|
},
|
|
231
303
|
signal,
|
|
232
304
|
},
|
|
@@ -235,7 +307,9 @@ ${skills}`;
|
|
|
235
307
|
|
|
236
308
|
const toolBlock = extractToolUse(response);
|
|
237
309
|
if (!toolBlock) {
|
|
238
|
-
log.warn(
|
|
310
|
+
log.warn(
|
|
311
|
+
"No tool_use block in conversation starters generation response",
|
|
312
|
+
);
|
|
239
313
|
return [];
|
|
240
314
|
}
|
|
241
315
|
|
|
@@ -253,12 +327,15 @@ ${skills}`;
|
|
|
253
327
|
typeof s.prompt === "string" &&
|
|
254
328
|
s.prompt.length > 0,
|
|
255
329
|
)
|
|
330
|
+
.slice(0, 4)
|
|
256
331
|
.map((s) => ({
|
|
257
|
-
label: truncate(s.label,
|
|
332
|
+
label: truncate(s.label, 40, ""),
|
|
258
333
|
prompt: truncate(s.prompt, 500, ""),
|
|
259
334
|
category:
|
|
260
335
|
typeof s.category === "string" &&
|
|
261
|
-
(
|
|
336
|
+
(CONVERSATION_STARTER_CATEGORIES as readonly string[]).includes(
|
|
337
|
+
s.category,
|
|
338
|
+
)
|
|
262
339
|
? s.category
|
|
263
340
|
: "productivity",
|
|
264
341
|
}));
|
|
@@ -270,12 +347,14 @@ ${skills}`;
|
|
|
270
347
|
|
|
271
348
|
// ── Job handler ───────────────────────────────────────────────────
|
|
272
349
|
|
|
273
|
-
export async function
|
|
350
|
+
export async function generateConversationStartersJob(
|
|
351
|
+
job: MemoryJob,
|
|
352
|
+
): Promise<void> {
|
|
274
353
|
const scopeId = asString(job.payload.scopeId) ?? "default";
|
|
275
354
|
|
|
276
355
|
const starters = await generateStarters(scopeId);
|
|
277
356
|
if (starters.length === 0) {
|
|
278
|
-
log.info({ scopeId }, "No
|
|
357
|
+
log.info({ scopeId }, "No conversation starters generated");
|
|
279
358
|
return;
|
|
280
359
|
}
|
|
281
360
|
|
|
@@ -303,14 +382,20 @@ export async function generateThreadStartersJob(job: MemoryJob): Promise<void> {
|
|
|
303
382
|
.all();
|
|
304
383
|
const sourceKinds = kindRows.map((r) => r.kind).join(",");
|
|
305
384
|
|
|
306
|
-
//
|
|
385
|
+
// Remove previous starters for this scope before inserting the new batch
|
|
386
|
+
db.delete(conversationStarters)
|
|
387
|
+
.where(eq(conversationStarters.scopeId, scopeId))
|
|
388
|
+
.run();
|
|
389
|
+
|
|
390
|
+
// Insert starters — all are chips
|
|
307
391
|
for (const starter of starters) {
|
|
308
|
-
db.insert(
|
|
392
|
+
db.insert(conversationStarters)
|
|
309
393
|
.values({
|
|
310
394
|
id: uuid(),
|
|
311
395
|
label: starter.label,
|
|
312
396
|
prompt: starter.prompt,
|
|
313
397
|
category: starter.category,
|
|
398
|
+
cardType: "chip",
|
|
314
399
|
generationBatch: nextBatch,
|
|
315
400
|
scopeId,
|
|
316
401
|
sourceMemoryKinds: sourceKinds,
|
|
@@ -343,6 +428,6 @@ export async function generateThreadStartersJob(job: MemoryJob): Promise<void> {
|
|
|
343
428
|
|
|
344
429
|
log.info(
|
|
345
430
|
{ scopeId, batch: nextBatch, count: starters.length },
|
|
346
|
-
"Generated
|
|
431
|
+
"Generated conversation starters",
|
|
347
432
|
);
|
|
348
433
|
}
|
package/src/memory/jobs-store.ts
CHANGED
|
@@ -26,8 +26,9 @@ export type MemoryJobType =
|
|
|
26
26
|
| "media_processing"
|
|
27
27
|
| "embed_media"
|
|
28
28
|
| "embed_attachment"
|
|
29
|
-
| "
|
|
30
|
-
| "generate_capability_cards"
|
|
29
|
+
| "generate_conversation_starters"
|
|
30
|
+
| "generate_capability_cards" // legacy compat — silently dropped by worker (capability cards removed)
|
|
31
|
+
| "generate_thread_starters"; // legacy compat — silently dropped by worker (renamed to generate_conversation_starters)
|
|
31
32
|
|
|
32
33
|
const EMBED_JOB_TYPES: MemoryJobType[] = [
|
|
33
34
|
"embed_segment",
|
|
@@ -3,11 +3,11 @@ import type { AssistantConfig } from "../config/types.js";
|
|
|
3
3
|
import { getLogger } from "../util/logger.js";
|
|
4
4
|
import { rawRun } from "./db.js";
|
|
5
5
|
import { backfillJob } from "./job-handlers/backfill.js";
|
|
6
|
-
import { generateCapabilityCardsJob } from "./job-handlers/capability-cards.js";
|
|
7
6
|
import {
|
|
8
7
|
cleanupStaleSupersededItemsJob,
|
|
9
8
|
pruneOldConversationsJob,
|
|
10
9
|
} from "./job-handlers/cleanup.js";
|
|
10
|
+
import { generateConversationStartersJob } from "./job-handlers/conversation-starters.js";
|
|
11
11
|
// ── Per-job-type handlers ──────────────────────────────────────────
|
|
12
12
|
import {
|
|
13
13
|
embedAttachmentJob,
|
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
} from "./job-handlers/index-maintenance.js";
|
|
24
24
|
import { mediaProcessingJob } from "./job-handlers/media-processing.js";
|
|
25
25
|
import { buildConversationSummaryJob } from "./job-handlers/summarization.js";
|
|
26
|
-
import { generateThreadStartersJob } from "./job-handlers/thread-starters.js";
|
|
27
26
|
import {
|
|
28
27
|
BackendUnavailableError,
|
|
29
28
|
classifyError,
|
|
@@ -308,11 +307,14 @@ async function processJob(
|
|
|
308
307
|
case "embed_attachment":
|
|
309
308
|
await embedAttachmentJob(job, config);
|
|
310
309
|
return;
|
|
311
|
-
case "
|
|
312
|
-
await
|
|
310
|
+
case "generate_conversation_starters":
|
|
311
|
+
await generateConversationStartersJob(job);
|
|
313
312
|
return;
|
|
314
313
|
case "generate_capability_cards":
|
|
315
|
-
|
|
314
|
+
// Capability cards were removed — silently drop legacy jobs.
|
|
315
|
+
return;
|
|
316
|
+
case "generate_thread_starters":
|
|
317
|
+
// Thread starters renamed to conversation starters — silently drop legacy jobs
|
|
316
318
|
return;
|
|
317
319
|
default:
|
|
318
320
|
throw new Error(
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { and, asc, eq, gt, or } from "drizzle-orm";
|
|
2
|
+
import { v4 as uuid } from "uuid";
|
|
3
|
+
|
|
4
|
+
import { getDb } from "./db.js";
|
|
5
|
+
import { lifecycleEvents } from "./schema.js";
|
|
6
|
+
|
|
7
|
+
export interface LifecycleEvent {
|
|
8
|
+
id: string;
|
|
9
|
+
eventName: string;
|
|
10
|
+
createdAt: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Record a lifecycle event (e.g. app_open, hatch). */
|
|
14
|
+
export function recordLifecycleEvent(eventName: string): LifecycleEvent {
|
|
15
|
+
const db = getDb();
|
|
16
|
+
const event: LifecycleEvent = {
|
|
17
|
+
id: uuid(),
|
|
18
|
+
eventName,
|
|
19
|
+
createdAt: Date.now(),
|
|
20
|
+
};
|
|
21
|
+
db.insert(lifecycleEvents)
|
|
22
|
+
.values({
|
|
23
|
+
id: event.id,
|
|
24
|
+
eventName: event.eventName,
|
|
25
|
+
createdAt: event.createdAt,
|
|
26
|
+
})
|
|
27
|
+
.run();
|
|
28
|
+
return event;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Query lifecycle events that haven't been reported to telemetry yet.
|
|
33
|
+
* Uses a compound cursor (createdAt + id) for reliable watermarking.
|
|
34
|
+
*/
|
|
35
|
+
export function queryUnreportedLifecycleEvents(
|
|
36
|
+
afterCreatedAt: number,
|
|
37
|
+
afterId: string | undefined,
|
|
38
|
+
limit: number,
|
|
39
|
+
): LifecycleEvent[] {
|
|
40
|
+
const db = getDb();
|
|
41
|
+
const rows = db
|
|
42
|
+
.select({
|
|
43
|
+
id: lifecycleEvents.id,
|
|
44
|
+
eventName: lifecycleEvents.eventName,
|
|
45
|
+
createdAt: lifecycleEvents.createdAt,
|
|
46
|
+
})
|
|
47
|
+
.from(lifecycleEvents)
|
|
48
|
+
.where(
|
|
49
|
+
afterId
|
|
50
|
+
? or(
|
|
51
|
+
gt(lifecycleEvents.createdAt, afterCreatedAt),
|
|
52
|
+
and(
|
|
53
|
+
eq(lifecycleEvents.createdAt, afterCreatedAt),
|
|
54
|
+
gt(lifecycleEvents.id, afterId),
|
|
55
|
+
),
|
|
56
|
+
)
|
|
57
|
+
: gt(lifecycleEvents.createdAt, afterCreatedAt),
|
|
58
|
+
)
|
|
59
|
+
.orderBy(asc(lifecycleEvents.createdAt), asc(lifecycleEvents.id))
|
|
60
|
+
.limit(limit)
|
|
61
|
+
.all();
|
|
62
|
+
return rows;
|
|
63
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type DrizzleDb } from "../db-connection.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Rename `created_by_session_id` to `source_conversation_id` in two tables,
|
|
5
|
+
* aligning with the broader session → conversation terminology unification.
|
|
6
|
+
*
|
|
7
|
+
* Each rename is wrapped in try/catch so re-running the migration is
|
|
8
|
+
* idempotent (SQLite throws if the source column does not exist).
|
|
9
|
+
*/
|
|
10
|
+
export function migrateRenameCreatedBySessionIdColumns(
|
|
11
|
+
database: DrizzleDb,
|
|
12
|
+
): void {
|
|
13
|
+
try {
|
|
14
|
+
database.run(
|
|
15
|
+
`ALTER TABLE channel_verification_sessions RENAME COLUMN created_by_session_id TO source_conversation_id`,
|
|
16
|
+
);
|
|
17
|
+
} catch {
|
|
18
|
+
/* already renamed */
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
database.run(
|
|
22
|
+
`ALTER TABLE assistant_ingress_invites RENAME COLUMN created_by_session_id TO source_conversation_id`,
|
|
23
|
+
);
|
|
24
|
+
} catch {
|
|
25
|
+
/* already renamed */
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type DrizzleDb } from "../db-connection.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Rename `source_session_id` to `source_context_id` in the `notification_events`
|
|
5
|
+
* table, aligning with the field's actual polymorphic usage (it holds conversation
|
|
6
|
+
* IDs, call session IDs, schedule IDs, etc.).
|
|
7
|
+
*/
|
|
8
|
+
export function migrateRenameSourceSessionIdColumn(database: DrizzleDb): void {
|
|
9
|
+
try {
|
|
10
|
+
database.run(
|
|
11
|
+
`ALTER TABLE notification_events RENAME COLUMN source_session_id TO source_context_id`,
|
|
12
|
+
);
|
|
13
|
+
} catch {
|
|
14
|
+
/* already renamed */
|
|
15
|
+
}
|
|
16
|
+
}
|