@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
|
@@ -42,9 +42,13 @@ export function isConversationFailed(conversationId: string): boolean {
|
|
|
42
42
|
export function invalidateAssistantInferredItemsForConversation(
|
|
43
43
|
conversationId: string,
|
|
44
44
|
): number {
|
|
45
|
-
// Cancel pending
|
|
45
|
+
// Cancel pending extraction jobs for this conversation's messages
|
|
46
46
|
// so the worker never processes them. Jobs already running will be
|
|
47
47
|
// caught by the isConversationFailed check in the extraction handler.
|
|
48
|
+
// NOTE: Only extract_items jobs are cancelled here — not embed_item or
|
|
49
|
+
// other job types. Multi-sourced items may still be valid (corroborated
|
|
50
|
+
// by other conversations), and their embedding jobs must not be killed.
|
|
51
|
+
// The broader cancelPendingJobsForConversation is used by the wipe path.
|
|
48
52
|
cancelPendingExtractionJobsForConversation(conversationId);
|
|
49
53
|
|
|
50
54
|
const affected = rawRun(
|
|
@@ -94,9 +98,95 @@ export function invalidateAssistantInferredItemsForConversation(
|
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
/**
|
|
97
|
-
* Cancel pending
|
|
98
|
-
*
|
|
99
|
-
*
|
|
101
|
+
* Cancel all pending/running memory jobs referencing the given conversation.
|
|
102
|
+
* Covers every job type: `extract_items`, `embed_attachment` (keyed by messageId),
|
|
103
|
+
* `embed_segment` (keyed by segmentId via memory_segments),
|
|
104
|
+
* `build_conversation_summary` (keyed by conversationId),
|
|
105
|
+
* and `embed_item` (keyed by itemId sourced from the conversation's messages).
|
|
106
|
+
*/
|
|
107
|
+
export function cancelPendingJobsForConversation(
|
|
108
|
+
conversationId: string,
|
|
109
|
+
reason: string = "conversation_wiped",
|
|
110
|
+
): number {
|
|
111
|
+
const now = Date.now();
|
|
112
|
+
let total = 0;
|
|
113
|
+
|
|
114
|
+
// Jobs keyed by messageId: extract_items, embed_attachment
|
|
115
|
+
total += rawRun(
|
|
116
|
+
`UPDATE memory_jobs
|
|
117
|
+
SET status = 'failed',
|
|
118
|
+
last_error = ?,
|
|
119
|
+
updated_at = ?
|
|
120
|
+
WHERE status IN ('pending', 'running')
|
|
121
|
+
AND json_extract(payload, '$.messageId') IN (
|
|
122
|
+
SELECT id FROM messages WHERE conversation_id = ?
|
|
123
|
+
)`,
|
|
124
|
+
reason,
|
|
125
|
+
now,
|
|
126
|
+
conversationId,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// Jobs keyed by conversationId: build_conversation_summary
|
|
130
|
+
total += rawRun(
|
|
131
|
+
`UPDATE memory_jobs
|
|
132
|
+
SET status = 'failed',
|
|
133
|
+
last_error = ?,
|
|
134
|
+
updated_at = ?
|
|
135
|
+
WHERE status IN ('pending', 'running')
|
|
136
|
+
AND json_extract(payload, '$.conversationId') = ?`,
|
|
137
|
+
reason,
|
|
138
|
+
now,
|
|
139
|
+
conversationId,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// Jobs keyed by segmentId: embed_segment (segments belong to the conversation)
|
|
143
|
+
total += rawRun(
|
|
144
|
+
`UPDATE memory_jobs
|
|
145
|
+
SET status = 'failed',
|
|
146
|
+
last_error = ?,
|
|
147
|
+
updated_at = ?
|
|
148
|
+
WHERE status IN ('pending', 'running')
|
|
149
|
+
AND json_extract(payload, '$.segmentId') IN (
|
|
150
|
+
SELECT id FROM memory_segments WHERE conversation_id = ?
|
|
151
|
+
)`,
|
|
152
|
+
reason,
|
|
153
|
+
now,
|
|
154
|
+
conversationId,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Jobs keyed by itemId: embed_item (items sourced from this conversation)
|
|
158
|
+
total += rawRun(
|
|
159
|
+
`UPDATE memory_jobs
|
|
160
|
+
SET status = 'failed',
|
|
161
|
+
last_error = ?,
|
|
162
|
+
updated_at = ?
|
|
163
|
+
WHERE status IN ('pending', 'running')
|
|
164
|
+
AND json_extract(payload, '$.itemId') IN (
|
|
165
|
+
SELECT mis.memory_item_id
|
|
166
|
+
FROM memory_item_sources mis
|
|
167
|
+
JOIN messages m ON m.id = mis.message_id
|
|
168
|
+
WHERE m.conversation_id = ?
|
|
169
|
+
)`,
|
|
170
|
+
reason,
|
|
171
|
+
now,
|
|
172
|
+
conversationId,
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
if (total > 0) {
|
|
176
|
+
log.info(
|
|
177
|
+
{ conversationId, cancelled: total },
|
|
178
|
+
"Cancelled pending memory jobs for conversation",
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return total;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Cancel only pending/running `extract_items` jobs for messages in the
|
|
187
|
+
* given conversation. Used by the task-failure path where we want to
|
|
188
|
+
* stop new extractions but must NOT cancel `embed_item` jobs — those
|
|
189
|
+
* items may be multi-sourced and still valid.
|
|
100
190
|
*/
|
|
101
191
|
function cancelPendingExtractionJobsForConversation(
|
|
102
192
|
conversationId: string,
|
|
@@ -107,8 +197,8 @@ function cancelPendingExtractionJobsForConversation(
|
|
|
107
197
|
SET status = 'failed',
|
|
108
198
|
last_error = 'conversation_failed',
|
|
109
199
|
updated_at = ?
|
|
110
|
-
WHERE
|
|
111
|
-
AND
|
|
200
|
+
WHERE status IN ('pending', 'running')
|
|
201
|
+
AND type = 'extract_items'
|
|
112
202
|
AND json_extract(payload, '$.messageId') IN (
|
|
113
203
|
SELECT id FROM messages WHERE conversation_id = ?
|
|
114
204
|
)`,
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { and, asc, eq, gt, lt, sql } from "drizzle-orm";
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
TraceEvent,
|
|
5
|
+
TraceEventKind,
|
|
6
|
+
} from "../daemon/message-types/messages.js";
|
|
7
|
+
import { getDb, rawChanges } from "./db.js";
|
|
8
|
+
import { traceEvents } from "./schema.js";
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Types
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
export interface TraceEventRow {
|
|
15
|
+
eventId: string;
|
|
16
|
+
conversationId: string;
|
|
17
|
+
requestId?: string;
|
|
18
|
+
timestampMs: number;
|
|
19
|
+
sequence: number;
|
|
20
|
+
kind: TraceEventKind;
|
|
21
|
+
status?: "info" | "success" | "warning" | "error";
|
|
22
|
+
summary: string;
|
|
23
|
+
attributes?: Record<string, string | number | boolean | null>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Write
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
/** Insert a single trace event row. Duplicate eventIds are silently ignored. */
|
|
31
|
+
export function persistTraceEvent(event: TraceEvent): void {
|
|
32
|
+
const db = getDb();
|
|
33
|
+
db.insert(traceEvents)
|
|
34
|
+
.values({
|
|
35
|
+
eventId: event.eventId,
|
|
36
|
+
conversationId: event.conversationId,
|
|
37
|
+
requestId: event.requestId ?? null,
|
|
38
|
+
timestampMs: event.timestampMs,
|
|
39
|
+
sequence: event.sequence,
|
|
40
|
+
kind: event.kind,
|
|
41
|
+
status: event.status ?? null,
|
|
42
|
+
summary: event.summary,
|
|
43
|
+
attributesJson: event.attributes
|
|
44
|
+
? JSON.stringify(event.attributes)
|
|
45
|
+
: null,
|
|
46
|
+
createdAt: Date.now(),
|
|
47
|
+
})
|
|
48
|
+
.onConflictDoNothing()
|
|
49
|
+
.run();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Read
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
/** Parse a raw DB row into a TraceEventRow with deserialized attributes. */
|
|
57
|
+
function rowToTraceEventRow(row: {
|
|
58
|
+
eventId: string;
|
|
59
|
+
conversationId: string;
|
|
60
|
+
requestId: string | null;
|
|
61
|
+
timestampMs: number;
|
|
62
|
+
sequence: number;
|
|
63
|
+
kind: string;
|
|
64
|
+
status: string | null;
|
|
65
|
+
summary: string;
|
|
66
|
+
attributesJson: string | null;
|
|
67
|
+
}): TraceEventRow {
|
|
68
|
+
return {
|
|
69
|
+
eventId: row.eventId,
|
|
70
|
+
conversationId: row.conversationId,
|
|
71
|
+
requestId: row.requestId ?? undefined,
|
|
72
|
+
timestampMs: row.timestampMs,
|
|
73
|
+
sequence: row.sequence,
|
|
74
|
+
kind: row.kind as TraceEventKind,
|
|
75
|
+
status: (row.status as TraceEventRow["status"]) ?? undefined,
|
|
76
|
+
summary: row.summary,
|
|
77
|
+
attributes: row.attributesJson
|
|
78
|
+
? (JSON.parse(row.attributesJson) as Record<
|
|
79
|
+
string,
|
|
80
|
+
string | number | boolean | null
|
|
81
|
+
>)
|
|
82
|
+
: undefined,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Query trace events for a conversation, ordered by sequence ASC, timestamp_ms ASC.
|
|
88
|
+
* Default limit of 5000 (matching the client's retention cap).
|
|
89
|
+
* Supports `afterSequence` for incremental fetching.
|
|
90
|
+
*/
|
|
91
|
+
export function getTraceEvents(
|
|
92
|
+
conversationId: string,
|
|
93
|
+
opts?: { limit?: number; afterSequence?: number },
|
|
94
|
+
): TraceEventRow[] {
|
|
95
|
+
const db = getDb();
|
|
96
|
+
const limit = opts?.limit ?? 5000;
|
|
97
|
+
|
|
98
|
+
const where =
|
|
99
|
+
opts?.afterSequence != null
|
|
100
|
+
? and(
|
|
101
|
+
eq(traceEvents.conversationId, conversationId),
|
|
102
|
+
gt(traceEvents.sequence, opts.afterSequence),
|
|
103
|
+
)
|
|
104
|
+
: eq(traceEvents.conversationId, conversationId);
|
|
105
|
+
|
|
106
|
+
const rows = db
|
|
107
|
+
.select()
|
|
108
|
+
.from(traceEvents)
|
|
109
|
+
.where(where)
|
|
110
|
+
.orderBy(asc(traceEvents.sequence), asc(traceEvents.timestampMs))
|
|
111
|
+
.limit(limit)
|
|
112
|
+
.all();
|
|
113
|
+
|
|
114
|
+
return rows.map(rowToTraceEventRow);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
// Cleanup
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Delete trace events older than `maxAgeDays` based on `created_at`.
|
|
123
|
+
* Returns the count of deleted rows.
|
|
124
|
+
*/
|
|
125
|
+
export function deleteOldTraceEvents(maxAgeDays: number): number {
|
|
126
|
+
const db = getDb();
|
|
127
|
+
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;
|
|
128
|
+
db.delete(traceEvents).where(lt(traceEvents.createdAt, cutoff)).run();
|
|
129
|
+
return rawChanges();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// Sequence
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Return the highest sequence number persisted for a conversation,
|
|
138
|
+
* or -1 if no events exist yet.
|
|
139
|
+
*/
|
|
140
|
+
export function getMaxSequence(conversationId: string): number {
|
|
141
|
+
const db = getDb();
|
|
142
|
+
const row = db
|
|
143
|
+
.select({ maxSeq: sql<number>`MAX(${traceEvents.sequence})` })
|
|
144
|
+
.from(traceEvents)
|
|
145
|
+
.where(eq(traceEvents.conversationId, conversationId))
|
|
146
|
+
.get();
|
|
147
|
+
return row?.maxSeq ?? -1;
|
|
148
|
+
}
|
|
@@ -441,7 +441,7 @@ import { emitNotificationSignal } from "../notifications/emit-signal.js";
|
|
|
441
441
|
await emitNotificationSignal({
|
|
442
442
|
sourceEventName: "your_event_name",
|
|
443
443
|
sourceChannel: "scheduler", // where the event originated
|
|
444
|
-
|
|
444
|
+
sourceContextId: conversationId,
|
|
445
445
|
attentionHints: {
|
|
446
446
|
requiresAction: true,
|
|
447
447
|
urgency: "high",
|
|
@@ -319,7 +319,7 @@ function buildFallbackDecision(
|
|
|
319
319
|
selectedChannels: [],
|
|
320
320
|
reasoningSummary: "Fallback: suppressed (vellum channel not available)",
|
|
321
321
|
renderedCopy: {},
|
|
322
|
-
dedupeKey: `fallback:${signal.sourceEventName}:${signal.
|
|
322
|
+
dedupeKey: `fallback:${signal.sourceEventName}:${signal.sourceContextId}:${signal.createdAt}`,
|
|
323
323
|
confidence: 0.3,
|
|
324
324
|
fallbackUsed: true,
|
|
325
325
|
};
|
|
@@ -334,7 +334,7 @@ function buildFallbackDecision(
|
|
|
334
334
|
? "Fallback: high urgency + requires action — all channels"
|
|
335
335
|
: "Fallback: vellum-only (local, always delivered)",
|
|
336
336
|
renderedCopy: copy,
|
|
337
|
-
dedupeKey: `fallback:${signal.sourceEventName}:${signal.
|
|
337
|
+
dedupeKey: `fallback:${signal.sourceEventName}:${signal.sourceContextId}:${signal.createdAt}`,
|
|
338
338
|
confidence: 0.3,
|
|
339
339
|
fallbackUsed: true,
|
|
340
340
|
};
|
|
@@ -852,17 +852,58 @@ async function classifyWithLLM(
|
|
|
852
852
|
*
|
|
853
853
|
* - `all_channels`: force selected channels to all connected channels.
|
|
854
854
|
* - `multi_channel`: ensure at least 2 channels when 2+ are connected.
|
|
855
|
-
* - `single_channel`:
|
|
855
|
+
* - `single_channel`: cap to a single channel. When explicitly set, reduces
|
|
856
|
+
* selected channels to one — preferring the source channel if present.
|
|
856
857
|
*/
|
|
857
858
|
export function enforceRoutingIntent(
|
|
858
859
|
decision: NotificationDecision,
|
|
859
860
|
routingIntent: RoutingIntent | undefined,
|
|
860
861
|
connectedChannels: NotificationChannel[],
|
|
862
|
+
sourceChannel?: string,
|
|
861
863
|
): NotificationDecision {
|
|
862
|
-
if (!routingIntent
|
|
864
|
+
if (!routingIntent) {
|
|
863
865
|
return decision;
|
|
864
866
|
}
|
|
865
867
|
|
|
868
|
+
if (routingIntent === "single_channel") {
|
|
869
|
+
if (!decision.shouldNotify) {
|
|
870
|
+
return decision;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// Force delivery to the source channel only. If the source channel
|
|
874
|
+
// is among the connected channels, use it regardless of what the LLM
|
|
875
|
+
// picked (even if the LLM picked exactly one wrong channel).
|
|
876
|
+
// Otherwise fall back to capping at the first selected channel.
|
|
877
|
+
const sourceIsConnected =
|
|
878
|
+
sourceChannel &&
|
|
879
|
+
connectedChannels.includes(sourceChannel as NotificationChannel);
|
|
880
|
+
const preferred = sourceIsConnected
|
|
881
|
+
? (sourceChannel as NotificationChannel)
|
|
882
|
+
: decision.selectedChannels[0];
|
|
883
|
+
|
|
884
|
+
// No change needed if the decision already matches.
|
|
885
|
+
if (
|
|
886
|
+
decision.selectedChannels.length === 1 &&
|
|
887
|
+
decision.selectedChannels[0] === preferred
|
|
888
|
+
) {
|
|
889
|
+
return decision;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
const enforced = { ...decision };
|
|
893
|
+
enforced.selectedChannels = [preferred];
|
|
894
|
+
enforced.reasoningSummary = `${decision.reasoningSummary} [routing_intent=single_channel enforced: capped to ${preferred}]`;
|
|
895
|
+
log.info(
|
|
896
|
+
{
|
|
897
|
+
routingIntent,
|
|
898
|
+
sourceChannel,
|
|
899
|
+
originalChannels: decision.selectedChannels,
|
|
900
|
+
enforcedChannel: preferred,
|
|
901
|
+
},
|
|
902
|
+
"Routing intent enforcement: single_channel → capped to one channel",
|
|
903
|
+
);
|
|
904
|
+
return enforced;
|
|
905
|
+
}
|
|
906
|
+
|
|
866
907
|
if (!decision.shouldNotify) {
|
|
867
908
|
return decision;
|
|
868
909
|
}
|
|
@@ -148,8 +148,8 @@ export interface EmitSignalParams<TEventName extends string = string> {
|
|
|
148
148
|
sourceEventName: TEventName;
|
|
149
149
|
/** Source channel that produced the event — must be a registered channel. */
|
|
150
150
|
sourceChannel: NotificationSourceChannel;
|
|
151
|
-
/**
|
|
152
|
-
|
|
151
|
+
/** Opaque identifier for the source context (conversation ID, schedule ID, call session ID, etc.). */
|
|
152
|
+
sourceContextId: string;
|
|
153
153
|
/** Attention hints for the decision engine. */
|
|
154
154
|
attentionHints: AttentionHints;
|
|
155
155
|
/** Arbitrary context payload passed to the decision engine. */
|
|
@@ -202,7 +202,7 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
202
202
|
signalId,
|
|
203
203
|
createdAt: Date.now(),
|
|
204
204
|
sourceChannel: params.sourceChannel,
|
|
205
|
-
|
|
205
|
+
sourceContextId: params.sourceContextId,
|
|
206
206
|
sourceEventName: params.sourceEventName,
|
|
207
207
|
contextPayload: (params.contextPayload ??
|
|
208
208
|
{}) as NotificationContextPayload<TEventName>,
|
|
@@ -218,7 +218,7 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
218
218
|
id: signalId,
|
|
219
219
|
sourceEventName: params.sourceEventName,
|
|
220
220
|
sourceChannel: params.sourceChannel,
|
|
221
|
-
|
|
221
|
+
sourceContextId: params.sourceContextId,
|
|
222
222
|
attentionHints: params.attentionHints,
|
|
223
223
|
payload: params.contextPayload ?? {},
|
|
224
224
|
dedupeKey: params.dedupeKey,
|
|
@@ -256,6 +256,7 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
256
256
|
decision,
|
|
257
257
|
signal.routingIntent,
|
|
258
258
|
connectedChannels,
|
|
259
|
+
signal.sourceChannel,
|
|
259
260
|
);
|
|
260
261
|
|
|
261
262
|
// Re-persist the decision if routing intent enforcement changed it,
|
|
@@ -16,7 +16,7 @@ export interface NotificationEventRow {
|
|
|
16
16
|
id: string;
|
|
17
17
|
sourceEventName: string;
|
|
18
18
|
sourceChannel: string;
|
|
19
|
-
|
|
19
|
+
sourceContextId: string;
|
|
20
20
|
attentionHintsJson: string;
|
|
21
21
|
payloadJson: string;
|
|
22
22
|
dedupeKey: string | null;
|
|
@@ -31,7 +31,7 @@ function rowToEvent(
|
|
|
31
31
|
id: row.id,
|
|
32
32
|
sourceEventName: row.sourceEventName,
|
|
33
33
|
sourceChannel: row.sourceChannel,
|
|
34
|
-
|
|
34
|
+
sourceContextId: row.sourceContextId,
|
|
35
35
|
attentionHintsJson: row.attentionHintsJson,
|
|
36
36
|
payloadJson: row.payloadJson,
|
|
37
37
|
dedupeKey: row.dedupeKey,
|
|
@@ -44,7 +44,7 @@ export interface CreateEventParams {
|
|
|
44
44
|
id: string;
|
|
45
45
|
sourceEventName: string;
|
|
46
46
|
sourceChannel: string;
|
|
47
|
-
|
|
47
|
+
sourceContextId: string;
|
|
48
48
|
attentionHints: AttentionHints;
|
|
49
49
|
payload: Record<string, unknown>;
|
|
50
50
|
dedupeKey?: string;
|
|
@@ -76,7 +76,7 @@ export function createEvent(
|
|
|
76
76
|
id: params.id,
|
|
77
77
|
sourceEventName: params.sourceEventName,
|
|
78
78
|
sourceChannel: params.sourceChannel,
|
|
79
|
-
|
|
79
|
+
sourceContextId: params.sourceContextId,
|
|
80
80
|
attentionHintsJson: JSON.stringify(params.attentionHints),
|
|
81
81
|
payloadJson: JSON.stringify(params.payload),
|
|
82
82
|
dedupeKey: normalizedDedupeKey,
|
|
@@ -131,7 +131,7 @@ export interface NotificationSignal<TEventName extends string = string> {
|
|
|
131
131
|
signalId: string;
|
|
132
132
|
createdAt: number; // epoch ms
|
|
133
133
|
sourceChannel: NotificationSourceChannel; // see NOTIFICATION_SOURCE_CHANNELS registry
|
|
134
|
-
|
|
134
|
+
sourceContextId: string;
|
|
135
135
|
sourceEventName: TEventName; // free-form: 'reminder_fired', 'schedule_complete', 'guardian_question', etc.
|
|
136
136
|
contextPayload: NotificationContextPayload<TEventName>;
|
|
137
137
|
attentionHints: AttentionHints;
|
|
@@ -65,6 +65,53 @@ export function removeManualTokenConnection(providerKey: string): void {
|
|
|
65
65
|
deleteConnection(conn.id);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Reconcile the synthetic oauth_connection row for a manual-token provider
|
|
70
|
+
* with whatever credentials are currently present in secure storage.
|
|
71
|
+
*
|
|
72
|
+
* This lets generic credential entry paths (chat setup, CLI, secure prompt)
|
|
73
|
+
* keep connection status in sync without duplicating per-provider rules.
|
|
74
|
+
*/
|
|
75
|
+
export async function syncManualTokenConnection(
|
|
76
|
+
providerKey: string,
|
|
77
|
+
accountInfo?: string,
|
|
78
|
+
): Promise<void> {
|
|
79
|
+
switch (providerKey) {
|
|
80
|
+
case "telegram": {
|
|
81
|
+
const hasBotToken = !!(await getSecureKeyAsync(
|
|
82
|
+
credentialKey("telegram", "bot_token"),
|
|
83
|
+
));
|
|
84
|
+
const hasWebhookSecret = !!(await getSecureKeyAsync(
|
|
85
|
+
credentialKey("telegram", "webhook_secret"),
|
|
86
|
+
));
|
|
87
|
+
if (hasBotToken && hasWebhookSecret) {
|
|
88
|
+
await ensureManualTokenConnection(providerKey, accountInfo);
|
|
89
|
+
} else {
|
|
90
|
+
removeManualTokenConnection(providerKey);
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
case "slack_channel": {
|
|
96
|
+
const hasBotToken = !!(await getSecureKeyAsync(
|
|
97
|
+
credentialKey("slack_channel", "bot_token"),
|
|
98
|
+
));
|
|
99
|
+
const hasAppToken = !!(await getSecureKeyAsync(
|
|
100
|
+
credentialKey("slack_channel", "app_token"),
|
|
101
|
+
));
|
|
102
|
+
if (hasBotToken && hasAppToken) {
|
|
103
|
+
await ensureManualTokenConnection(providerKey, accountInfo);
|
|
104
|
+
} else {
|
|
105
|
+
removeManualTokenConnection(providerKey);
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
default:
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
68
115
|
/**
|
|
69
116
|
* Backfill oauth_connection rows for manual-token providers that already
|
|
70
117
|
* have valid keychain credentials but are missing connection records.
|
|
@@ -78,29 +125,6 @@ export function removeManualTokenConnection(providerKey: string): void {
|
|
|
78
125
|
* connection row.
|
|
79
126
|
*/
|
|
80
127
|
export async function backfillManualTokenConnections(): Promise<void> {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const hasBotToken = !!(await getSecureKeyAsync(
|
|
84
|
-
credentialKey("telegram", "bot_token"),
|
|
85
|
-
));
|
|
86
|
-
const hasWebhookSecret = !!(await getSecureKeyAsync(
|
|
87
|
-
credentialKey("telegram", "webhook_secret"),
|
|
88
|
-
));
|
|
89
|
-
if (hasBotToken && hasWebhookSecret) {
|
|
90
|
-
await ensureManualTokenConnection("telegram");
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Slack channel: requires both bot_token and app_token
|
|
95
|
-
if (!getConnectionByProvider("slack_channel")) {
|
|
96
|
-
const hasBotToken = !!(await getSecureKeyAsync(
|
|
97
|
-
credentialKey("slack_channel", "bot_token"),
|
|
98
|
-
));
|
|
99
|
-
const hasAppToken = !!(await getSecureKeyAsync(
|
|
100
|
-
credentialKey("slack_channel", "app_token"),
|
|
101
|
-
));
|
|
102
|
-
if (hasBotToken && hasAppToken) {
|
|
103
|
-
await ensureManualTokenConnection("slack_channel");
|
|
104
|
-
}
|
|
105
|
-
}
|
|
128
|
+
await syncManualTokenConnection("telegram");
|
|
129
|
+
await syncManualTokenConnection("slack_channel");
|
|
106
130
|
}
|
|
@@ -48,10 +48,10 @@ function riskCacheKey(
|
|
|
48
48
|
workingDir?: string,
|
|
49
49
|
manifestOverride?: ManifestOverride,
|
|
50
50
|
): string {
|
|
51
|
-
// Strip `reason` before computing the cache key —
|
|
52
|
-
// per invocation even for identical tool
|
|
53
|
-
// cache misses.
|
|
54
|
-
const { reason: _reason, ...cacheableInput } = input;
|
|
51
|
+
// Strip `reason` and `activity` before computing the cache key — they are
|
|
52
|
+
// cosmetic status text that varies per invocation even for identical tool
|
|
53
|
+
// operations, causing unnecessary cache misses.
|
|
54
|
+
const { reason: _reason, activity: _activity, ...cacheableInput } = input;
|
|
55
55
|
const inputJson = JSON.stringify(cacheableInput);
|
|
56
56
|
const hash = createHash("sha256")
|
|
57
57
|
.update(inputJson)
|
|
@@ -143,6 +143,7 @@ const LOW_RISK_PROGRAMS = new Set([
|
|
|
143
143
|
"tree",
|
|
144
144
|
"du",
|
|
145
145
|
"df",
|
|
146
|
+
"assistant",
|
|
146
147
|
]);
|
|
147
148
|
|
|
148
149
|
// High-risk shell programs / patterns
|
|
@@ -544,7 +545,7 @@ async function classifyRiskUncached(
|
|
|
544
545
|
) {
|
|
545
546
|
return RiskLevel.High;
|
|
546
547
|
}
|
|
547
|
-
return RiskLevel.
|
|
548
|
+
return RiskLevel.Low;
|
|
548
549
|
}
|
|
549
550
|
if (toolName === "web_search") return RiskLevel.Low;
|
|
550
551
|
if (toolName === "web_fetch") {
|
|
@@ -259,10 +259,10 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
|
|
|
259
259
|
}),
|
|
260
260
|
);
|
|
261
261
|
|
|
262
|
-
//
|
|
263
|
-
// surfaces
|
|
264
|
-
//
|
|
265
|
-
const UI_SURFACE_TOOLS = ["ui_update", "ui_dismiss"] as const;
|
|
262
|
+
// All three UI surface tools are passive, user-visible operations. ui_show
|
|
263
|
+
// creates surfaces (cards, forms, tables) but user input is voluntary and
|
|
264
|
+
// user-controlled — safe to auto-approve like ui_update and ui_dismiss.
|
|
265
|
+
const UI_SURFACE_TOOLS = ["ui_show", "ui_update", "ui_dismiss"] as const;
|
|
266
266
|
const uiSurfaceRules: DefaultRuleTemplate[] = UI_SURFACE_TOOLS.map(
|
|
267
267
|
(tool) => ({
|
|
268
268
|
id: `default:allow-${tool}-global`,
|