@vellumai/assistant 0.7.1 → 0.7.2
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 +32 -49
- package/Dockerfile +1 -0
- package/README.md +1 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
- package/bun.lock +26 -26
- package/docs/architecture/security.md +20 -0
- package/docs/plugins.md +7 -9
- package/knip.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
- package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -0
- package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
- package/node_modules/@vellumai/twilio-client/package.json +18 -0
- package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
- package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
- package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
- package/openapi.yaml +565 -12
- package/package.json +6 -3
- package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
- package/src/__tests__/app-bundler.test.ts +170 -1
- package/src/__tests__/app-control-flow.test.ts +374 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
- package/src/__tests__/app-executors.test.ts +30 -43
- package/src/__tests__/approval-routes-http.test.ts +23 -6
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
- package/src/__tests__/assistant-event-hub.test.ts +109 -2
- package/src/__tests__/assistant-event.test.ts +10 -0
- package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
- package/src/__tests__/btw-routes.test.ts +13 -4
- package/src/__tests__/call-controller.test.ts +49 -1
- package/src/__tests__/call-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-readiness-service.test.ts +59 -1
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +90 -155
- package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-lifecycle.test.ts +36 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
- package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
- package/src/__tests__/credentials-cli.test.ts +5 -12
- package/src/__tests__/cu-unified-flow.test.ts +185 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
- package/src/__tests__/heartbeat-service.test.ts +718 -1
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +602 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +246 -47
- package/src/__tests__/host-bash-routes.test.ts +294 -0
- package/src/__tests__/host-browser-proxy.test.ts +24 -22
- package/src/__tests__/host-browser-routes.test.ts +39 -13
- package/src/__tests__/host-cu-proxy.test.ts +41 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
- package/src/__tests__/host-file-proxy.test.ts +37 -43
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
- package/src/__tests__/host-file-write-tool.test.ts +42 -1
- package/src/__tests__/host-proxy-base.test.ts +312 -0
- package/src/__tests__/host-shell-tool.test.ts +22 -4
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/identity-intro-cache.test.ts +29 -0
- package/src/__tests__/identity-routes.test.ts +103 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
- package/src/__tests__/inline-command-runner.test.ts +0 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
- package/src/__tests__/integration-status.test.ts +85 -5
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +97 -0
- package/src/__tests__/require-fresh-approval.test.ts +0 -1
- package/src/__tests__/retry-backoff.test.ts +87 -0
- package/src/__tests__/runtime-events-sse.test.ts +10 -6
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
- package/src/__tests__/skill-feature-flags.test.ts +43 -41
- package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
- package/src/__tests__/skill-load-inline-command.test.ts +0 -51
- package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
- package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +9 -14
- package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/test-preload.ts +8 -0
- package/src/__tests__/tool-approval-handler.test.ts +3 -4
- package/src/__tests__/tool-audit-listener.test.ts +48 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +3 -16
- package/src/__tests__/twilio-routes.test.ts +3 -5
- package/src/__tests__/twilio-validation.test.ts +93 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
- package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
- package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- package/src/backup/__tests__/paths.test.ts +0 -22
- package/src/backup/__tests__/restore.test.ts +51 -151
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +107 -231
- package/src/bundler/app-bundler.ts +51 -3
- package/src/calls/relay-server.ts +4 -44
- package/src/calls/twilio-config.ts +2 -17
- package/src/calls/twilio-rest.ts +33 -105
- package/src/calls/twilio-routes.ts +11 -12
- package/src/channels/types.ts +8 -7
- package/src/cli/commands/__tests__/backup.test.ts +6 -277
- package/src/cli/commands/__tests__/gateway.test.ts +288 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +73 -0
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +15 -7
- package/src/cli/commands/domain.ts +66 -15
- package/src/cli/commands/gateway.ts +183 -0
- package/src/cli/commands/keys.ts +9 -6
- package/src/cli/commands/mcp.ts +116 -156
- package/src/cli/commands/memory-v2.ts +296 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +0 -18
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +67 -10
- package/src/config/bundled-skills/acp/SKILL.md +6 -0
- package/src/config/bundled-skills/acp/TOOLS.json +1 -22
- package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
- package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
- package/src/config/bundled-skills/app-control/SKILL.md +75 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
- package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
- package/src/config/bundled-skills/document/TOOLS.json +0 -8
- package/src/config/bundled-skills/followups/TOOLS.json +0 -12
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
- package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
- package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
- package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
- package/src/config/bundled-skills/settings/SKILL.md +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +0 -12
- package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
- package/src/config/bundled-skills/subagent/SKILL.md +6 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
- package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
- package/src/config/bundled-tool-registry.ts +21 -0
- package/src/config/env-registry.ts +0 -2
- package/src/config/env.ts +19 -12
- package/src/config/feature-flag-registry.json +21 -133
- package/src/config/loader.ts +73 -99
- package/src/config/sanitize-for-transfer.ts +2 -0
- package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +7 -4
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/heartbeat.ts +63 -0
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +5 -10
- package/src/config/schemas/memory-lifecycle.ts +77 -24
- package/src/config/schemas/memory-v2.ts +48 -4
- package/src/config/schemas/platform.ts +6 -0
- package/src/config/schemas/services.ts +1 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +1 -1
- package/src/contacts/contact-store.ts +0 -30
- package/src/contacts/contacts-write.ts +0 -27
- package/src/context/window-manager.ts +1 -2
- package/src/credential-execution/feature-gates.ts +10 -10
- package/src/credential-execution/process-manager.ts +12 -41
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +4 -3
- package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
- package/src/daemon/conversation-agent-loop.ts +32 -28
- package/src/daemon/conversation-lifecycle.ts +8 -1
- package/src/daemon/conversation-process.ts +16 -11
- package/src/daemon/conversation-runtime-assembly.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +125 -4
- package/src/daemon/conversation-tool-setup.ts +16 -55
- package/src/daemon/conversation.ts +21 -2
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -1
- package/src/daemon/host-app-control-proxy.ts +293 -0
- package/src/daemon/host-bash-proxy.ts +84 -74
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +81 -86
- package/src/daemon/host-file-proxy.ts +93 -69
- package/src/daemon/host-proxy-base.ts +294 -0
- package/src/daemon/host-proxy-preactivation.ts +82 -0
- package/src/daemon/host-transfer-proxy.ts +247 -129
- package/src/daemon/lifecycle.ts +115 -117
- package/src/daemon/message-protocol.ts +3 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +11 -8
- package/src/daemon/message-types/host-app-control.ts +150 -0
- package/src/daemon/message-types/host-bash.ts +4 -0
- package/src/daemon/message-types/host-cu.ts +2 -0
- package/src/daemon/message-types/host-file.ts +4 -0
- package/src/daemon/message-types/host-transfer.ts +3 -0
- package/src/daemon/message-types/schedules.ts +8 -3
- package/src/daemon/message-types/skills.ts +2 -2
- package/src/daemon/process-message.ts +18 -1
- package/src/daemon/shutdown-handlers.ts +0 -3
- package/src/daemon/tool-setup-types.ts +51 -0
- package/src/daemon/tool-side-effects.ts +1 -1
- package/src/events/tool-audit-listener.ts +2 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
- package/src/heartbeat/heartbeat-run-store.ts +236 -0
- package/src/heartbeat/heartbeat-service.ts +280 -49
- package/src/home/__tests__/post-connect-feed.test.ts +99 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
- package/src/home/__tests__/suggested-prompts.test.ts +89 -0
- package/src/home/post-connect-feed.ts +68 -0
- package/src/home/relationship-state-writer.ts +17 -92
- package/src/home/suggested-prompts.ts +46 -10
- package/src/inbound/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +14 -1
- package/src/ipc/cli-client.ts +32 -1
- package/src/live-voice/live-voice-metrics.ts +10 -10
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
- package/src/mcp/mcp-auth-orchestrator.ts +213 -0
- package/src/mcp/mcp-auth-state.ts +133 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
- package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
- package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
- package/src/memory/anisotropy.test.ts +247 -0
- package/src/memory/anisotropy.ts +443 -0
- package/src/memory/auto-analysis-constants.ts +17 -0
- package/src/memory/auto-analysis-guard.ts +5 -15
- package/src/memory/canonical-guardian-store.ts +7 -7
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
- package/src/memory/context-search/agent-protocol.ts +6 -6
- package/src/memory/context-search/agent-runner.ts +32 -7
- package/src/memory/context-search/sources/memory-v2.ts +17 -5
- package/src/memory/conversation-crud.ts +1 -1
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +4 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
- package/src/memory/graph/conversation-graph-memory.ts +1 -24
- package/src/memory/graph/graph-search.ts +8 -0
- package/src/memory/graph/retriever.ts +28 -0
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
- package/src/memory/jobs/embed-concept-page.ts +28 -2
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
- package/src/memory/jobs-store.ts +66 -22
- package/src/memory/jobs-worker.ts +112 -63
- package/src/memory/memory-v2-activation-log-store.ts +1 -1
- package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
- package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +50 -20
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +7 -0
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/v2/__tests__/activation.test.ts +77 -95
- package/src/memory/v2/__tests__/injection.test.ts +43 -21
- package/src/memory/v2/__tests__/sim.test.ts +166 -6
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +0 -1
- package/src/memory/v2/activation.ts +69 -88
- package/src/memory/v2/consolidation-job.ts +3 -5
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +86 -53
- package/src/memory/v2/prompts/consolidation.ts +312 -91
- package/src/memory/v2/qdrant.ts +99 -1
- package/src/memory/v2/sim.ts +126 -16
- package/src/memory/v2/skill-qdrant.ts +12 -3
- package/src/memory/v2/skill-store.ts +16 -1
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +6 -5
- package/src/messaging/providers/gmail/types.ts +0 -49
- package/src/messaging/providers/slack/adapter.ts +1 -31
- package/src/messaging/providers/slack/types.ts +0 -32
- package/src/notifications/README.md +10 -10
- package/src/notifications/broadcaster.ts +1 -1
- package/src/notifications/guardian-question-mode.ts +5 -5
- package/src/oauth/connect-orchestrator.ts +4 -0
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- package/src/outbound-proxy/index.ts +1 -37
- package/src/outbound-proxy/logging.ts +1 -1
- package/src/outbound-proxy/policy.ts +6 -5
- package/src/outbound-proxy/router.ts +2 -1
- package/src/permissions/approval-policy.test.ts +6 -275
- package/src/permissions/approval-policy.ts +0 -51
- package/src/permissions/checker.test.ts +0 -1
- package/src/permissions/checker.ts +3 -17
- package/src/permissions/gateway-threshold-reader.ts +2 -0
- package/src/permissions/prompter.ts +34 -1
- package/src/permissions/secret-prompter.ts +6 -2
- package/src/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/system-prompt.ts +3 -18
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/providers/speech-to-text/provider-catalog.ts +7 -8
- package/src/runtime/assistant-event-hub.ts +118 -96
- package/src/runtime/assistant-event.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +19 -0
- package/src/runtime/btw-sidechain.ts +2 -3
- package/src/runtime/channel-invite-transport.ts +2 -48
- package/src/runtime/channel-invite-transports/email.ts +1 -1
- package/src/runtime/channel-invite-transports/slack.ts +1 -1
- package/src/runtime/channel-invite-transports/telegram.ts +1 -1
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
- package/src/runtime/channel-invite-types.ts +54 -0
- package/src/runtime/channel-readiness-service.ts +32 -13
- package/src/runtime/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
- package/src/runtime/migrations/migration-transport.ts +7 -7
- package/src/runtime/migrations/vbundle-builder.ts +327 -60
- package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
- package/src/runtime/migrations/vbundle-importer.ts +245 -68
- package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
- package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
- package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
- package/src/runtime/migrations/vbundle-validator.ts +114 -0
- package/src/runtime/pending-interactions.ts +35 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
- package/src/runtime/routes/approval-interception-types.ts +13 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
- package/src/runtime/routes/backup-routes.ts +15 -38
- package/src/runtime/routes/btw-routes.ts +14 -37
- package/src/runtime/routes/client-routes.ts +1 -0
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +30 -13
- package/src/runtime/routes/document-pdf-renderer.ts +165 -0
- package/src/runtime/routes/documents-routes.ts +30 -0
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +12 -6
- package/src/runtime/routes/gateway-log-routes.ts +79 -0
- package/src/runtime/routes/guardian-approval-interception.ts +2 -8
- package/src/runtime/routes/heartbeat-routes.ts +103 -38
- package/src/runtime/routes/host-app-control-routes.ts +134 -0
- package/src/runtime/routes/host-bash-routes.ts +36 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +44 -14
- package/src/runtime/routes/host-file-routes.ts +33 -10
- package/src/runtime/routes/host-transfer-routes.ts +64 -24
- package/src/runtime/routes/http-adapter.ts +1 -0
- package/src/runtime/routes/identity-intro-cache.ts +30 -0
- package/src/runtime/routes/identity-routes.ts +15 -43
- package/src/runtime/routes/inbound-message-handler.ts +1 -9
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +441 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- package/src/runtime/verification-templates.ts +4 -7
- package/src/schedule/integration-status.ts +66 -2
- package/src/schedule/recurrence-engine.ts +4 -1
- package/src/schedule/retry-backoff.ts +18 -0
- package/src/schedule/retry-policy.ts +82 -0
- package/src/schedule/schedule-recovery.ts +64 -0
- package/src/schedule/schedule-store.ts +106 -2
- package/src/schedule/scheduler-types.ts +25 -0
- package/src/schedule/scheduler.ts +63 -38
- package/src/security/oauth-callback-registry.ts +8 -0
- package/src/sequence/analytics.ts +5 -5
- package/src/sequence/engine.ts +1 -1
- package/src/skills/catalog-files.ts +2 -8
- package/src/skills/include-graph.ts +5 -5
- package/src/skills/remote-skill-policy.ts +5 -5
- package/src/skills/skill-file-provider.ts +1 -1
- package/src/skills/skill-file-types.ts +13 -0
- package/src/skills/skillssh-audit-types.ts +28 -0
- package/src/skills/skillssh-registry.ts +8 -21
- package/src/telemetry/types.ts +2 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
- package/src/tools/apps/executors.ts +56 -69
- package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
- package/src/tools/browser/cdp-client/factory.ts +23 -24
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/computer-use/definitions.ts +42 -20
- package/src/tools/executor.ts +2 -0
- package/src/tools/host-filesystem/edit.ts +26 -0
- package/src/tools/host-filesystem/read.ts +26 -0
- package/src/tools/host-filesystem/transfer.ts +31 -1
- package/src/tools/host-filesystem/write.ts +26 -0
- package/src/tools/host-terminal/host-shell.ts +58 -0
- package/src/tools/schedule/create.ts +6 -0
- package/src/tools/schedule/list.ts +2 -0
- package/src/tools/schedule/update.ts +10 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
- package/src/tools/shared/filesystem/path-policy.ts +25 -1
- package/src/tools/skills/load.ts +0 -32
- package/src/tools/tool-approval-handler.ts +1 -5
- package/src/tools/types.ts +4 -0
- package/src/usage/pricing.ts +1 -1
- package/src/workspace/hatched-date.ts +86 -0
- package/src/workspace/migrations/003-seed-device-id.ts +1 -1
- package/src/workspace/migrations/006-services-config.ts +8 -5
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/utils.ts +21 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
- package/src/__tests__/twilio-rest.test.ts +0 -34
- package/src/backup/__tests__/backup-key.test.ts +0 -152
- package/src/backup/__tests__/backup-worker.test.ts +0 -782
- package/src/backup/__tests__/offsite-writer.test.ts +0 -641
- package/src/backup/__tests__/stream-crypt.test.ts +0 -228
- package/src/backup/backup-key.ts +0 -137
- package/src/backup/backup-worker.ts +0 -472
- package/src/backup/offsite-writer.ts +0 -222
- package/src/backup/stream-crypt.ts +0 -263
- package/src/daemon/message-types/pairing.ts +0 -58
- package/src/outbound-proxy/config.ts +0 -20
- package/src/outbound-proxy/health.ts +0 -18
- package/src/outbound-proxy/types.ts +0 -150
- package/src/runtime/capability-tokens.ts +0 -190
- package/src/signals/mcp-reload.ts +0 -18
|
@@ -42,9 +42,6 @@ export const GUARDIAN_VERIFY_TEMPLATE_KEYS = {
|
|
|
42
42
|
CHANNEL_BOOTSTRAP_BOUND: "guardian_verify.channel.bootstrap_bound",
|
|
43
43
|
} as const;
|
|
44
44
|
|
|
45
|
-
export type GuardianVerifyTemplateKey =
|
|
46
|
-
(typeof GUARDIAN_VERIFY_TEMPLATE_KEYS)[keyof typeof GUARDIAN_VERIFY_TEMPLATE_KEYS];
|
|
47
|
-
|
|
48
45
|
/** Template keys for Telegram/Slack text-based verification messages. */
|
|
49
46
|
type TextVerifyTemplateKey =
|
|
50
47
|
| typeof GUARDIAN_VERIFY_TEMPLATE_KEYS.ALREADY_VERIFIED
|
|
@@ -56,7 +53,7 @@ type TextVerifyTemplateKey =
|
|
|
56
53
|
| typeof GUARDIAN_VERIFY_TEMPLATE_KEYS.SLACK_TRUSTED_CONTACT_RESEND;
|
|
57
54
|
|
|
58
55
|
/** Template keys for deterministic channel verification reply messages. */
|
|
59
|
-
|
|
56
|
+
type ChannelVerifyReplyTemplateKey =
|
|
60
57
|
| typeof GUARDIAN_VERIFY_TEMPLATE_KEYS.CHANNEL_VERIFY_SUCCESS
|
|
61
58
|
| typeof GUARDIAN_VERIFY_TEMPLATE_KEYS.CHANNEL_VERIFY_FAILED
|
|
62
59
|
| typeof GUARDIAN_VERIFY_TEMPLATE_KEYS.CHANNEL_BOOTSTRAP_BOUND;
|
|
@@ -65,18 +62,18 @@ export type ChannelVerifyReplyTemplateKey =
|
|
|
65
62
|
// Template Variables
|
|
66
63
|
// ---------------------------------------------------------------------------
|
|
67
64
|
|
|
68
|
-
|
|
65
|
+
interface GuardianVerifyTemplateVars {
|
|
69
66
|
code: string;
|
|
70
67
|
expiresInMinutes: number;
|
|
71
68
|
assistantName?: string;
|
|
72
69
|
}
|
|
73
70
|
|
|
74
|
-
|
|
71
|
+
interface GuardianVerifyVoiceTemplateVars {
|
|
75
72
|
/** Number of digits in the verification code. */
|
|
76
73
|
codeDigits: number;
|
|
77
74
|
}
|
|
78
75
|
|
|
79
|
-
|
|
76
|
+
interface ChannelVerifyReplyVars {
|
|
80
77
|
/** Failure reason (anti-oracle: generic message). Only used for failed template. */
|
|
81
78
|
failureReason?: string;
|
|
82
79
|
/** Drives different success copy for guardian vs trusted contact verification. */
|
|
@@ -1,9 +1,73 @@
|
|
|
1
1
|
import { hasTwilioCredentials } from "../calls/twilio-rest.js";
|
|
2
|
+
import type { Services } from "../config/schemas/services.js";
|
|
2
3
|
import {
|
|
3
4
|
getConnectionByProvider,
|
|
5
|
+
getProvider,
|
|
4
6
|
isProviderConnected,
|
|
5
7
|
} from "../oauth/oauth-store.js";
|
|
6
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Check whether a provider has an active connection, handling both BYO
|
|
11
|
+
* (local SQLite) and managed (platform) modes.
|
|
12
|
+
*/
|
|
13
|
+
async function isOAuthProviderConnected(provider: string): Promise<boolean> {
|
|
14
|
+
const providerRow = getProvider(provider);
|
|
15
|
+
const managedKey = providerRow?.managedServiceConfigKey;
|
|
16
|
+
|
|
17
|
+
if (managedKey) {
|
|
18
|
+
try {
|
|
19
|
+
const { ServicesSchema, getServiceMode } =
|
|
20
|
+
await import("../config/schemas/services.js");
|
|
21
|
+
|
|
22
|
+
if (managedKey in ServicesSchema.shape) {
|
|
23
|
+
const { getConfig } = await import("../config/loader.js");
|
|
24
|
+
const services: Services = getConfig().services;
|
|
25
|
+
if (
|
|
26
|
+
getServiceMode(services, managedKey as keyof Services) === "managed"
|
|
27
|
+
) {
|
|
28
|
+
return isProviderConnectedOnPlatform(provider);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
// Config unavailable — fall through to BYO check
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return isProviderConnected(provider);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check the platform for active connections for a managed provider.
|
|
41
|
+
* Returns false on any error (network, auth, etc.) rather than throwing.
|
|
42
|
+
*/
|
|
43
|
+
async function isProviderConnectedOnPlatform(
|
|
44
|
+
provider: string,
|
|
45
|
+
): Promise<boolean> {
|
|
46
|
+
try {
|
|
47
|
+
const { VellumPlatformClient } = await import("../platform/client.js");
|
|
48
|
+
const client = await VellumPlatformClient.create();
|
|
49
|
+
if (!client?.platformAssistantId) return false;
|
|
50
|
+
|
|
51
|
+
const params = new URLSearchParams();
|
|
52
|
+
params.set("provider", provider);
|
|
53
|
+
params.set("status", "ACTIVE");
|
|
54
|
+
|
|
55
|
+
const path = `/v1/assistants/${encodeURIComponent(client.platformAssistantId)}/oauth/connections/?${params.toString()}`;
|
|
56
|
+
const response = await client.fetch(path);
|
|
57
|
+
|
|
58
|
+
if (!response.ok) return false;
|
|
59
|
+
|
|
60
|
+
const body = (await response.json()) as unknown;
|
|
61
|
+
const connections = Array.isArray(body)
|
|
62
|
+
? body
|
|
63
|
+
: ((body as Record<string, unknown>).results ?? []);
|
|
64
|
+
|
|
65
|
+
return (connections as unknown[]).length > 0;
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
7
71
|
interface IntegrationProbe {
|
|
8
72
|
name: string;
|
|
9
73
|
category: string;
|
|
@@ -15,12 +79,12 @@ const INTEGRATION_PROBES: IntegrationProbe[] = [
|
|
|
15
79
|
{
|
|
16
80
|
name: "Gmail",
|
|
17
81
|
category: "email",
|
|
18
|
-
isConnected: () =>
|
|
82
|
+
isConnected: () => isOAuthProviderConnected("google"),
|
|
19
83
|
},
|
|
20
84
|
{
|
|
21
85
|
name: "Slack",
|
|
22
86
|
category: "messaging",
|
|
23
|
-
isConnected: () =>
|
|
87
|
+
isConnected: () => isOAuthProviderConnected("slack"),
|
|
24
88
|
},
|
|
25
89
|
{
|
|
26
90
|
name: "Twilio",
|
|
@@ -107,7 +107,10 @@ export function validateRruleSetLines(expression: string): string | null {
|
|
|
107
107
|
export function isValidScheduleExpression(spec: ScheduleSpec): boolean {
|
|
108
108
|
try {
|
|
109
109
|
if (spec.syntax === "cron") {
|
|
110
|
-
new Cron(spec.expression, {
|
|
110
|
+
new Cron(spec.expression, {
|
|
111
|
+
maxRuns: 0,
|
|
112
|
+
timezone: spec.timezone ?? undefined,
|
|
113
|
+
});
|
|
111
114
|
return true;
|
|
112
115
|
}
|
|
113
116
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const DEFAULT_MAX_BACKOFF_MS = 30 * 60 * 1000; // 30 minutes
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Compute retry delay with exponential backoff and jitter.
|
|
5
|
+
* The exponential term is clamped to maxMs BEFORE jitter to prevent
|
|
6
|
+
* Infinity/NaN for large attempt values, and capped again after jitter
|
|
7
|
+
* so the result never exceeds maxMs.
|
|
8
|
+
*/
|
|
9
|
+
export function computeRetryDelay(
|
|
10
|
+
attempt: number,
|
|
11
|
+
baseMs: number,
|
|
12
|
+
maxMs: number = DEFAULT_MAX_BACKOFF_MS,
|
|
13
|
+
random: () => number = Math.random,
|
|
14
|
+
): number {
|
|
15
|
+
const exponential = Math.min(baseMs * Math.pow(2, attempt), maxMs);
|
|
16
|
+
const jitter = exponential * 0.2 * (2 * random() - 1);
|
|
17
|
+
return Math.max(0, Math.min(Math.round(exponential + jitter), maxMs));
|
|
18
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Logger } from "pino";
|
|
2
|
+
|
|
3
|
+
import { computeRetryDelay } from "./retry-backoff.js";
|
|
4
|
+
|
|
5
|
+
export interface RetryPolicyJob {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
retryCount: number;
|
|
9
|
+
maxRetries: number;
|
|
10
|
+
retryBackoffMs: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type RetryDecision =
|
|
14
|
+
| { action: "retry"; delayMs: number; nextRetryAt: number }
|
|
15
|
+
| { action: "exhaust" };
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Pure decision function: given a job's retry state, decide whether
|
|
19
|
+
* to retry with backoff or give up.
|
|
20
|
+
*
|
|
21
|
+
* `retryCount` is the PRE-increment value (before completeScheduleRun
|
|
22
|
+
* bumped it). So `retryCount < maxRetries` allows exactly maxRetries
|
|
23
|
+
* retries: retryCount 0, 1, …, maxRetries−1 all pass the check.
|
|
24
|
+
*/
|
|
25
|
+
export function decideRetry(
|
|
26
|
+
job: RetryPolicyJob,
|
|
27
|
+
now: number = Date.now(),
|
|
28
|
+
): RetryDecision {
|
|
29
|
+
if (job.retryCount < job.maxRetries) {
|
|
30
|
+
const delayMs = computeRetryDelay(job.retryCount, job.retryBackoffMs);
|
|
31
|
+
return { action: "retry", delayMs, nextRetryAt: now + delayMs };
|
|
32
|
+
}
|
|
33
|
+
return { action: "exhaust" };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Apply the retry decision to a schedule: schedule a retry or exhaust.
|
|
38
|
+
* Calls the provided store operations so this module stays decoupled
|
|
39
|
+
* from direct DB imports.
|
|
40
|
+
*/
|
|
41
|
+
export function applyRetryDecision(params: {
|
|
42
|
+
job: RetryPolicyJob;
|
|
43
|
+
isOneShot: boolean;
|
|
44
|
+
errorMsg: string;
|
|
45
|
+
decision: RetryDecision;
|
|
46
|
+
scheduleRetry: (id: string, nextRetryAt: number) => void;
|
|
47
|
+
failOneShotPermanently: (id: string) => void;
|
|
48
|
+
resetRetryCount: (id: string) => void;
|
|
49
|
+
emitAlert: (title: string, summary: string, dedupKey: string) => void;
|
|
50
|
+
log: Logger;
|
|
51
|
+
}): void {
|
|
52
|
+
const { job, isOneShot, errorMsg, decision } = params;
|
|
53
|
+
|
|
54
|
+
if (decision.action === "retry") {
|
|
55
|
+
params.scheduleRetry(job.id, decision.nextRetryAt);
|
|
56
|
+
params.log.info(
|
|
57
|
+
{
|
|
58
|
+
jobId: job.id,
|
|
59
|
+
name: job.name,
|
|
60
|
+
attempt: job.retryCount + 1,
|
|
61
|
+
maxRetries: job.maxRetries,
|
|
62
|
+
delayMs: decision.delayMs,
|
|
63
|
+
},
|
|
64
|
+
"Scheduling retry with backoff",
|
|
65
|
+
);
|
|
66
|
+
} else {
|
|
67
|
+
if (isOneShot) {
|
|
68
|
+
params.failOneShotPermanently(job.id);
|
|
69
|
+
} else {
|
|
70
|
+
params.resetRetryCount(job.id);
|
|
71
|
+
}
|
|
72
|
+
params.emitAlert(
|
|
73
|
+
`${job.name}: Retries exhausted`,
|
|
74
|
+
`Failed after ${job.retryCount + 1} attempt(s): ${errorMsg}`,
|
|
75
|
+
`schedule-retries-exhausted:${job.id}:${Date.now()}`,
|
|
76
|
+
);
|
|
77
|
+
params.log.warn(
|
|
78
|
+
{ jobId: job.id, name: job.name, attempts: job.retryCount + 1 },
|
|
79
|
+
"Schedule retries exhausted",
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { getLogger } from "../util/logger.js";
|
|
2
|
+
import { applyRetryDecision, decideRetry } from "./retry-policy.js";
|
|
3
|
+
import {
|
|
4
|
+
completeScheduleRun,
|
|
5
|
+
createScheduleRun,
|
|
6
|
+
failOneShotPermanently,
|
|
7
|
+
findStaleInFlightJobs,
|
|
8
|
+
getSchedule,
|
|
9
|
+
resetRetryCount,
|
|
10
|
+
scheduleRetry,
|
|
11
|
+
} from "./schedule-store.js";
|
|
12
|
+
|
|
13
|
+
const log = getLogger("schedule-recovery");
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Recover schedules left in an inconsistent state by a prior process crash.
|
|
17
|
+
* Called once at daemon startup, before the scheduler tick loop starts,
|
|
18
|
+
* so all "firing" / "running" rows are definitively stale.
|
|
19
|
+
*/
|
|
20
|
+
export function recoverStaleSchedules(): number {
|
|
21
|
+
const stale = findStaleInFlightJobs(0);
|
|
22
|
+
if (stale.length === 0) return 0;
|
|
23
|
+
|
|
24
|
+
log.info({ count: stale.length }, "Recovering stale in-flight schedules");
|
|
25
|
+
|
|
26
|
+
let recovered = 0;
|
|
27
|
+
for (const { jobId, staleRunId } of stale) {
|
|
28
|
+
try {
|
|
29
|
+
const job = getSchedule(jobId);
|
|
30
|
+
if (!job) continue;
|
|
31
|
+
|
|
32
|
+
const errorMsg =
|
|
33
|
+
"Process terminated during execution (recovered on restart)";
|
|
34
|
+
|
|
35
|
+
if (staleRunId) {
|
|
36
|
+
completeScheduleRun(staleRunId, { status: "error", error: errorMsg });
|
|
37
|
+
} else {
|
|
38
|
+
const runId = createScheduleRun(jobId, `recovery:${jobId}`);
|
|
39
|
+
completeScheduleRun(runId, { status: "error", error: errorMsg });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Use the same retry-or-exhaust path as the scheduler
|
|
43
|
+
const isOneShot = job.expression == null;
|
|
44
|
+
const decision = decideRetry(job);
|
|
45
|
+
applyRetryDecision({
|
|
46
|
+
job,
|
|
47
|
+
isOneShot,
|
|
48
|
+
errorMsg,
|
|
49
|
+
decision,
|
|
50
|
+
scheduleRetry,
|
|
51
|
+
failOneShotPermanently,
|
|
52
|
+
resetRetryCount,
|
|
53
|
+
emitAlert: () => {}, // no feed event on startup recovery
|
|
54
|
+
log,
|
|
55
|
+
});
|
|
56
|
+
recovered++;
|
|
57
|
+
} catch (err) {
|
|
58
|
+
log.error({ err, jobId }, "Failed to recover stale schedule");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
log.info({ recovered }, "Stale schedule recovery complete");
|
|
63
|
+
return recovered;
|
|
64
|
+
}
|
|
@@ -33,6 +33,8 @@ export interface ScheduleJob {
|
|
|
33
33
|
lastRunAt: number | null;
|
|
34
34
|
lastStatus: string | null;
|
|
35
35
|
retryCount: number;
|
|
36
|
+
maxRetries: number;
|
|
37
|
+
retryBackoffMs: number;
|
|
36
38
|
createdBy: string;
|
|
37
39
|
mode: ScheduleMode;
|
|
38
40
|
routingIntent: RoutingIntent;
|
|
@@ -83,6 +85,8 @@ export function createSchedule(params: {
|
|
|
83
85
|
routingHints?: Record<string, unknown>;
|
|
84
86
|
quiet?: boolean;
|
|
85
87
|
reuseConversation?: boolean;
|
|
88
|
+
maxRetries?: number;
|
|
89
|
+
retryBackoffMs?: number;
|
|
86
90
|
}): ScheduleJob {
|
|
87
91
|
const expression = params.expression ?? params.cronExpression ?? null;
|
|
88
92
|
const isOneShot = expression == null;
|
|
@@ -116,6 +120,8 @@ export function createSchedule(params: {
|
|
|
116
120
|
const routingHints = params.routingHints ?? {};
|
|
117
121
|
const quiet = params.quiet ?? false;
|
|
118
122
|
const reuseConversation = params.reuseConversation ?? false;
|
|
123
|
+
const maxRetries = params.maxRetries ?? 3;
|
|
124
|
+
const retryBackoffMs = params.retryBackoffMs ?? 60000;
|
|
119
125
|
|
|
120
126
|
let nextRunAt: number;
|
|
121
127
|
if (isOneShot) {
|
|
@@ -140,6 +146,8 @@ export function createSchedule(params: {
|
|
|
140
146
|
lastRunAt: null as number | null,
|
|
141
147
|
lastStatus: null as string | null,
|
|
142
148
|
retryCount: 0,
|
|
149
|
+
maxRetries,
|
|
150
|
+
retryBackoffMs,
|
|
143
151
|
createdBy: params.createdBy ?? "agent",
|
|
144
152
|
mode,
|
|
145
153
|
routingIntent,
|
|
@@ -235,6 +243,8 @@ export function updateSchedule(
|
|
|
235
243
|
quiet?: boolean;
|
|
236
244
|
reuseConversation?: boolean;
|
|
237
245
|
wakeConversationId?: string | null;
|
|
246
|
+
maxRetries?: number;
|
|
247
|
+
retryBackoffMs?: number;
|
|
238
248
|
},
|
|
239
249
|
): ScheduleJob | null {
|
|
240
250
|
const db = getDb();
|
|
@@ -257,12 +267,13 @@ export function updateSchedule(
|
|
|
257
267
|
|
|
258
268
|
const isOneShot = newExpr == null;
|
|
259
269
|
|
|
260
|
-
// Validate if expression or
|
|
270
|
+
// Validate if expression, syntax, or timezone changed (only for recurring schedules)
|
|
261
271
|
if (
|
|
262
272
|
!isOneShot &&
|
|
263
273
|
(updates.expression !== undefined ||
|
|
264
274
|
updates.cronExpression !== undefined ||
|
|
265
|
-
updates.syntax !== undefined
|
|
275
|
+
updates.syntax !== undefined ||
|
|
276
|
+
updates.timezone !== undefined)
|
|
266
277
|
) {
|
|
267
278
|
const spec = {
|
|
268
279
|
syntax: newSyntax,
|
|
@@ -295,6 +306,9 @@ export function updateSchedule(
|
|
|
295
306
|
set.reuseConversation = updates.reuseConversation;
|
|
296
307
|
if (updates.wakeConversationId !== undefined)
|
|
297
308
|
set.wakeConversationId = updates.wakeConversationId;
|
|
309
|
+
if (updates.maxRetries !== undefined) set.maxRetries = updates.maxRetries;
|
|
310
|
+
if (updates.retryBackoffMs !== undefined)
|
|
311
|
+
set.retryBackoffMs = updates.retryBackoffMs;
|
|
298
312
|
|
|
299
313
|
// Recompute nextRunAt if schedule timing may have changed (only for recurring)
|
|
300
314
|
if (
|
|
@@ -817,6 +831,94 @@ export function describeCronExpression(expr: string | null): string {
|
|
|
817
831
|
}
|
|
818
832
|
}
|
|
819
833
|
|
|
834
|
+
/**
|
|
835
|
+
* Set the next retry time for a schedule and revert one-shot status from
|
|
836
|
+
* "firing" to "active" so the scheduler will claim it again when nextRetryAt
|
|
837
|
+
* arrives. No-op for recurring schedules (they stay in their current status).
|
|
838
|
+
*/
|
|
839
|
+
export function scheduleRetry(id: string, nextRetryAt: number): void {
|
|
840
|
+
const db = getDb();
|
|
841
|
+
const now = Date.now();
|
|
842
|
+
db.update(scheduleJobs)
|
|
843
|
+
.set({ nextRunAt: nextRetryAt, updatedAt: now })
|
|
844
|
+
.where(eq(scheduleJobs.id, id))
|
|
845
|
+
.run();
|
|
846
|
+
// Revert one-shot status from "firing" to "active" so the scheduler
|
|
847
|
+
// will claim it again when nextRetryAt arrives. No-op for recurring.
|
|
848
|
+
db.update(scheduleJobs)
|
|
849
|
+
.set({ status: "active", updatedAt: now })
|
|
850
|
+
.where(and(eq(scheduleJobs.id, id), eq(scheduleJobs.status, "firing")))
|
|
851
|
+
.run();
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* Reset the retry count for a schedule back to zero (e.g. after a successful run).
|
|
856
|
+
*/
|
|
857
|
+
export function resetRetryCount(id: string): void {
|
|
858
|
+
const db = getDb();
|
|
859
|
+
db.update(scheduleJobs)
|
|
860
|
+
.set({ retryCount: 0, updatedAt: Date.now() })
|
|
861
|
+
.where(eq(scheduleJobs.id, id))
|
|
862
|
+
.run();
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Find schedules stuck in an in-flight state (one-shots in "firing",
|
|
867
|
+
* cron runs in "running"). Used at daemon startup to recover from
|
|
868
|
+
* a prior process crash.
|
|
869
|
+
*
|
|
870
|
+
* @param staleThresholdMs If >0, only consider rows whose lastRunAt
|
|
871
|
+
* (for one-shots) or startedAt (for runs) is older than `now - staleThresholdMs`.
|
|
872
|
+
* Pass 0 at startup (the previous process is definitely dead).
|
|
873
|
+
*/
|
|
874
|
+
export function findStaleInFlightJobs(staleThresholdMs: number = 0): Array<{
|
|
875
|
+
jobId: string;
|
|
876
|
+
staleRunId: string | null;
|
|
877
|
+
}> {
|
|
878
|
+
const db = getDb();
|
|
879
|
+
const cutoff = Date.now() - staleThresholdMs;
|
|
880
|
+
|
|
881
|
+
// One-shots stuck in "firing" where lastRunAt is older than cutoff
|
|
882
|
+
const staleOneShots = db
|
|
883
|
+
.select({ id: scheduleJobs.id })
|
|
884
|
+
.from(scheduleJobs)
|
|
885
|
+
.where(
|
|
886
|
+
and(
|
|
887
|
+
isNull(scheduleJobs.cronExpression),
|
|
888
|
+
eq(scheduleJobs.status, "firing"),
|
|
889
|
+
eq(scheduleJobs.enabled, true),
|
|
890
|
+
staleThresholdMs > 0 ? lte(scheduleJobs.lastRunAt, cutoff) : undefined,
|
|
891
|
+
),
|
|
892
|
+
)
|
|
893
|
+
.all();
|
|
894
|
+
|
|
895
|
+
// Cron runs stuck in "running" where startedAt is older than cutoff
|
|
896
|
+
const staleRuns = db
|
|
897
|
+
.select({ id: scheduleRuns.id, jobId: scheduleRuns.jobId })
|
|
898
|
+
.from(scheduleRuns)
|
|
899
|
+
.where(
|
|
900
|
+
and(
|
|
901
|
+
eq(scheduleRuns.status, "running"),
|
|
902
|
+
staleThresholdMs > 0 ? lte(scheduleRuns.startedAt, cutoff) : undefined,
|
|
903
|
+
),
|
|
904
|
+
)
|
|
905
|
+
.all();
|
|
906
|
+
|
|
907
|
+
const result: Array<{ jobId: string; staleRunId: string | null }> = [];
|
|
908
|
+
const seenJobIds = new Set<string>();
|
|
909
|
+
|
|
910
|
+
for (const run of staleRuns) {
|
|
911
|
+
result.push({ jobId: run.jobId, staleRunId: run.id });
|
|
912
|
+
seenJobIds.add(run.jobId);
|
|
913
|
+
}
|
|
914
|
+
for (const job of staleOneShots) {
|
|
915
|
+
if (!seenJobIds.has(job.id)) {
|
|
916
|
+
result.push({ jobId: job.id, staleRunId: null });
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return result;
|
|
920
|
+
}
|
|
921
|
+
|
|
820
922
|
function parseJobRow(row: typeof scheduleJobs.$inferSelect): ScheduleJob {
|
|
821
923
|
return {
|
|
822
924
|
id: row.id,
|
|
@@ -833,6 +935,8 @@ function parseJobRow(row: typeof scheduleJobs.$inferSelect): ScheduleJob {
|
|
|
833
935
|
lastRunAt: row.lastRunAt,
|
|
834
936
|
lastStatus: row.lastStatus,
|
|
835
937
|
retryCount: row.retryCount,
|
|
938
|
+
maxRetries: row.maxRetries ?? 3,
|
|
939
|
+
retryBackoffMs: row.retryBackoffMs ?? 60000,
|
|
836
940
|
createdBy: row.createdBy,
|
|
837
941
|
mode: (row.mode ?? "execute") as ScheduleMode,
|
|
838
942
|
routingIntent: (row.routingIntent ?? "all_channels") as RoutingIntent,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types extracted from scheduler.ts to break the scheduler ↔ engine cycle.
|
|
3
|
+
* `sequence/engine.ts` needs `ScheduleMessageProcessor` but scheduler.ts
|
|
4
|
+
* imports from engine — extracting the type here breaks the back-edge.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
8
|
+
|
|
9
|
+
export interface ScheduleMessageOptions {
|
|
10
|
+
trustClass?: "guardian" | "trusted_contact" | "unknown";
|
|
11
|
+
taskRunId?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Optional LLM call-site identifier propagated to the per-call provider
|
|
14
|
+
* config. Schedule and sequence callers will start passing their own call-site
|
|
15
|
+
* (e.g. for a future scheduled-agent profile) once PRs 7-11 migrate them off
|
|
16
|
+
* the default `mainAgent` route.
|
|
17
|
+
*/
|
|
18
|
+
callSite?: LLMCallSite;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type ScheduleMessageProcessor = (
|
|
22
|
+
conversationId: string,
|
|
23
|
+
message: string,
|
|
24
|
+
options?: ScheduleMessageOptions,
|
|
25
|
+
) => Promise<unknown>;
|