@vellumai/assistant 0.8.12 → 0.9.0-staging.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/AGENTS.md +0 -14
- package/ARCHITECTURE.md +45 -45
- package/README.md +1 -1
- package/bun.lock +200 -154
- package/docs/architecture/integrations.md +3 -3
- package/docs/architecture/memory.md +2 -2
- package/docs/architecture/security.md +10 -10
- package/docs/runbook-trusted-contacts.md +12 -12
- package/docs/skills.md +6 -6
- package/docs/workflows-testing.md +221 -0
- package/docs/workflows.md +510 -0
- package/examples/plugins/echo/README.md +5 -5
- package/knip.json +2 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +105 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +12 -0
- package/openapi.yaml +7197 -5708
- package/package.json +8 -4
- package/scripts/generate-openapi.ts +66 -114
- package/src/__tests__/access-request-seed-content-blocks.test.ts +213 -0
- package/src/__tests__/adaptive-thinking-repair.test.ts +32 -3
- package/src/__tests__/agent-loop-output-hooks.test.ts +183 -0
- package/src/__tests__/agent-loop-regrowth-guard.test.ts +506 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +77 -0
- package/src/__tests__/app-compiler.test.ts +7 -1
- package/src/__tests__/app-dir-path-guard.test.ts +27 -3
- package/src/__tests__/app-executors.test.ts +43 -0
- package/src/__tests__/approval-cascade.test.ts +0 -5
- package/src/__tests__/approval-routes-http.test.ts +91 -0
- package/src/__tests__/assistant-stream-state.test.ts +107 -0
- package/src/__tests__/browser-fill-credential.test.ts +3 -3
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +1 -1
- package/src/__tests__/compaction-events.test.ts +63 -7
- package/src/__tests__/compaction-trail-store.test.ts +74 -1
- package/src/__tests__/compaction.benchmark.test.ts +63 -41
- package/src/__tests__/compactor-low-watermark-cut.test.ts +349 -0
- package/src/__tests__/context-window-manager-compact-retry.test.ts +64 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -5
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -5
- package/src/__tests__/conversation-history-web-search.test.ts +7 -0
- package/src/__tests__/conversation-process-callsite.test.ts +0 -5
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -5
- package/src/__tests__/conversation-queue.test.ts +0 -5
- package/src/__tests__/conversation-slash-queue.test.ts +0 -5
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -5
- package/src/__tests__/conversation-speed-override.test.ts +0 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +97 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-usage.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -5
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -5
- package/src/__tests__/credential-broker-browser-fill.test.ts +2 -2
- package/src/__tests__/credential-broker-server-use.test.ts +2 -2
- package/src/__tests__/credential-broker.test.ts +1 -1
- package/src/__tests__/credential-prompt-route.test.ts +417 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault.test.ts +37 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +24 -0
- package/src/__tests__/dynamic-page-surface.test.ts +219 -0
- package/src/__tests__/empty-state-greeting-cache.test.ts +94 -0
- package/src/__tests__/gateway-flag-listener.test.ts +24 -7
- package/src/__tests__/guardian-action-sweep.test.ts +56 -219
- package/src/__tests__/guardian-routing-invariants.test.ts +138 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +99 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +87 -1
- package/src/__tests__/llm-resolver.test.ts +115 -0
- package/src/__tests__/managed-profile-guard.test.ts +6 -5
- package/src/__tests__/max-tokens-continue-hook.test.ts +184 -0
- package/src/__tests__/media-generate-image.test.ts +20 -9
- package/src/__tests__/mock-gateway-ipc.ts +23 -0
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/normalize-onboarding.test.ts +26 -0
- package/src/__tests__/notification-decision-strategy.test.ts +4 -2
- package/src/__tests__/notification-telegram-adapter.test.ts +21 -3
- package/src/__tests__/pending-interactions-resolved-event.test.ts +62 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +72 -18
- package/src/__tests__/require-fresh-approval.test.ts +425 -1
- package/src/__tests__/resolve-app-id.test.ts +56 -0
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -0
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +408 -0
- package/src/__tests__/schedule-routes.test.ts +257 -4
- package/src/__tests__/schedule-store.test.ts +60 -0
- package/src/__tests__/schedule-tools.test.ts +247 -2
- package/src/__tests__/skill-execute-input.test.ts +85 -0
- package/src/__tests__/skill-secret-handling-guard.test.ts +21 -20
- package/src/__tests__/skills.test.ts +3 -3
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +1 -1
- package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +547 -0
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/task-progress-nudge-hook.test.ts +372 -0
- package/src/__tests__/task-scheduler.test.ts +299 -0
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +209 -0
- package/src/__tests__/tool-result-spool.test.ts +3 -1
- package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +181 -0
- package/src/__tests__/workspace-migration-103-upgrade-quality-profile-to-opus-4-8.test.ts +174 -0
- package/src/agent/compaction-circuit.ts +11 -0
- package/src/agent/loop.ts +181 -12
- package/src/api/constants/call-sites.ts +12 -0
- package/src/api/events/assistant-thinking-delta.ts +10 -0
- package/src/api/events/usage-update.ts +7 -0
- package/src/api/index.ts +4 -1
- package/src/api/responses/memory-v3-selection-log.ts +18 -11
- package/src/approvals/approval-primitive.ts +2 -2
- package/src/background-wake/background-wake-routes.test.ts +5 -2
- package/src/bundler/compiler-tools.ts +1 -1
- package/src/bundler/package-resolver.ts +0 -1
- package/src/calls/call-domain.ts +1 -1
- package/src/calls/guardian-action-sweep.ts +16 -93
- package/src/cli/AGENTS.md +4 -0
- package/src/cli/commands/__tests__/schedules.test.ts +430 -1
- package/src/cli/commands/credentials.ts +28 -24
- package/src/cli/commands/image-generation.ts +23 -9
- package/src/cli/commands/notifications.ts +1 -1
- package/src/cli/commands/plugins.ts +89 -46
- package/src/cli/commands/schedules.ts +384 -11
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +69 -5
- package/src/cli/lib/__tests__/install-from-github.test.ts +15 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +81 -4
- package/src/cli/lib/inspect-plugin.ts +62 -1
- package/src/cli/lib/install-from-github.ts +52 -5
- package/src/cli/lib/upgrade-plugin.ts +18 -0
- package/src/config/__tests__/workflows-schema.test.ts +60 -0
- package/src/config/bundled-skills/acp/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +6 -1
- package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +7 -1
- package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +7 -1
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +10 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +66 -19
- package/src/config/bundled-skills/image-studio/TOOLS.json +1 -6
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +22 -3
- package/src/config/bundled-skills/personal-page/SKILL.md +57 -0
- package/src/config/bundled-skills/personal-page/TOOLS.json +27 -0
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +17 -0
- package/src/config/bundled-skills/schedule/SKILL.md +7 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +48 -4
- package/src/config/bundled-skills/workflows/SKILL.md +214 -0
- package/src/config/bundled-skills/workflows/TOOLS.json +84 -0
- package/src/config/bundled-skills/workflows/tools/manage-workflows.ts +12 -0
- package/src/config/bundled-skills/workflows/tools/run-workflow.ts +12 -0
- package/src/config/bundled-tool-registry.ts +14 -2
- package/src/config/call-site-defaults.ts +5 -0
- package/src/config/feature-flag-registry.json +12 -4
- package/src/config/llm-context-resolution.ts +8 -0
- package/src/config/llm-resolver.ts +30 -0
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +22 -0
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +16 -0
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +77 -0
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +57 -0
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +28 -0
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +234 -0
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +48 -0
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +16 -0
- package/src/config/preloaded-apps/personal-page/src/index.html +20 -0
- package/src/config/preloaded-apps/personal-page/src/main.tsx +7 -0
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +82 -0
- package/src/config/preloaded-apps/personal-page/src/styles.css +759 -0
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/heartbeat.ts +4 -1
- package/src/config/schemas/llm.ts +33 -26
- package/src/config/schemas/memory-retrospective.ts +19 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/services.ts +5 -2
- package/src/config/schemas/workflows.ts +42 -0
- package/src/config/skills.ts +3 -3
- package/src/context/compactor.ts +273 -39
- package/src/context/post-turn-tool-result-truncation.ts +23 -6
- package/src/context/tool-result-spool.ts +12 -17
- package/src/credential-execution/executable-discovery.ts +1 -1
- package/src/credential-execution/process-manager.ts +37 -3
- package/src/credential-execution/prompted-credential.ts +205 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +14 -0
- package/src/daemon/conversation-process.ts +11 -2
- package/src/daemon/conversation-surfaces.ts +167 -3
- package/src/daemon/conversation-tool-setup.ts +103 -26
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +115 -11
- package/src/daemon/handlers/shared.ts +26 -14
- package/src/daemon/host-cu-proxy.ts +15 -12
- package/src/daemon/host-file-proxy.ts +15 -12
- package/src/daemon/host-transfer-proxy.ts +30 -24
- package/src/daemon/lifecycle.ts +40 -3
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/messages.ts +2 -10
- package/src/daemon/message-types/workflows.ts +49 -0
- package/src/daemon/parse-actual-tokens-from-error.test.ts +62 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +43 -4
- package/src/daemon/process-message.ts +6 -0
- package/src/daemon/tool-setup-types.ts +57 -0
- package/src/daemon/wake-conversation-ops.ts +18 -0
- package/src/heartbeat/heartbeat-run-store.ts +8 -2
- package/src/home/feed-types.ts +1 -1
- package/src/ipc/gateway-flag-listener.ts +28 -6
- package/src/mcp/mcp-auth-state.ts +8 -20
- package/src/media/__tests__/image-models.test.ts +57 -0
- package/src/media/image-models.ts +66 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +38 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +12 -2
- package/src/memory/__tests__/memory-retrospective-job.test.ts +911 -34
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +227 -5
- package/src/memory/__tests__/memory-retrospective-state.test.ts +195 -0
- package/src/memory/__tests__/preloaded-apps.test.ts +85 -0
- package/src/memory/auto-analysis-enqueue.ts +14 -1
- package/src/memory/compaction-log-store-clickhouse.ts +6 -4
- package/src/memory/conversation-crud.ts +9 -2
- package/src/memory/conversation-disk-view.ts +1 -1
- package/src/memory/conversation-queries.ts +22 -7
- package/src/memory/db-init.ts +20 -0
- package/src/memory/db-maintenance.ts +16 -0
- package/src/memory/embedding-runtime-manager.ts +1 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +112 -14
- package/src/memory/llm-request-log-source-local.ts +19 -1
- package/src/memory/llm-request-log-source.ts +35 -6
- package/src/memory/llm-request-log-store.ts +90 -2
- package/src/memory/memory-retrospective-constants.ts +9 -0
- package/src/memory/memory-retrospective-enqueue.ts +3 -6
- package/src/memory/memory-retrospective-fork-boundary.ts +94 -0
- package/src/memory/memory-retrospective-job.ts +500 -208
- package/src/memory/memory-retrospective-startup-cleanup.ts +97 -19
- package/src/memory/memory-retrospective-state.ts +85 -2
- package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +40 -0
- package/src/memory/migrations/282-schedule-inference-profile.test.ts +77 -0
- package/src/memory/migrations/282-schedule-inference-profile.ts +26 -0
- package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.test.ts +102 -0
- package/src/memory/migrations/283-memory-v3-selections-message-id-and-sections.ts +53 -0
- package/src/memory/migrations/284-workflow-runs.ts +51 -0
- package/src/memory/migrations/285-schedule-workflow-mode.ts +26 -0
- package/src/memory/migrations/286-workflow-run-trust.ts +27 -0
- package/src/memory/migrations/287-conversation-origin-channel-index.ts +15 -0
- package/src/memory/migrations/288-backfill-origin-channel-from-bindings.ts +43 -0
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +115 -0
- package/src/memory/migrations/290-schedule-capabilities.test.ts +77 -0
- package/src/memory/migrations/290-schedule-capabilities.ts +25 -0
- package/src/memory/migrations/__tests__/281-memory-retrospective-remembered-log.test.ts +96 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +571 -0
- package/src/memory/migrations/index.ts +10 -0
- package/src/memory/preloaded-apps.ts +116 -0
- package/src/memory/schema/infrastructure.ts +4 -0
- package/src/memory/schema/memory-core.ts +4 -0
- package/src/memory/v2/__tests__/concept-page-frontmatter-schema.test.ts +45 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +11 -7
- package/src/memory/v2/__tests__/page-store.test.ts +13 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +24 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -6
- package/src/memory/v2/page-store.ts +4 -3
- package/src/memory/v2/qdrant.ts +42 -3
- package/src/memory/v2/types.ts +16 -10
- package/src/messaging/draft-store.ts +1 -1
- package/src/notifications/access-request-copy.ts +200 -113
- package/src/notifications/adapters/slack.ts +250 -111
- package/src/notifications/adapters/telegram.ts +7 -44
- package/src/notifications/approval-card-builder.ts +93 -0
- package/src/notifications/broadcaster.ts +74 -0
- package/src/notifications/conversation-pairing.ts +8 -6
- package/src/notifications/copy-composer.ts +32 -26
- package/src/notifications/decision-engine.ts +59 -7
- package/src/notifications/guardian-question-mode.ts +145 -155
- package/src/notifications/home-feed-side-effect.ts +28 -11
- package/src/notifications/notification-utils.ts +66 -0
- package/src/notifications/signal.ts +6 -0
- package/src/notifications/tool-approval-copy.ts +142 -0
- package/src/notifications/types.ts +19 -0
- package/src/permissions/threshold.ts +11 -0
- package/src/plugin-api/types.ts +16 -4
- package/src/plugins/defaults/compaction/window-manager.ts +44 -0
- package/src/plugins/defaults/index.ts +46 -0
- package/src/plugins/defaults/max-tokens-continue/continue-state-store.ts +53 -0
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +80 -0
- package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +20 -0
- package/src/plugins/defaults/max-tokens-continue/package.json +14 -0
- package/src/plugins/defaults/memory-retrieval/hooks/__tests__/user-prompt-submit.test.ts +37 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +29 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +8 -3
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +4 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +28 -18
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +67 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +122 -22
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +2 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +63 -1
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +61 -18
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +1 -1
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +39 -10
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +34 -1
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +112 -47
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +78 -15
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +206 -0
- package/src/plugins/defaults/task-progress-nudge/package.json +15 -0
- package/src/prompts/__tests__/system-prompt.test.ts +100 -1
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +5 -7
- package/src/prompts/normalize-onboarding.ts +2 -0
- package/src/prompts/persona-resolver.ts +3 -0
- package/src/prompts/system-prompt.ts +51 -2
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +3 -1
- package/src/prompts/templates/system-sections.ts +8 -3
- package/src/providers/call-site-routing.ts +6 -3
- package/src/providers/fireworks/client.ts +3 -0
- package/src/providers/inference/auth.ts +52 -46
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/__tests__/coerce-object-args.test.ts +105 -0
- package/src/providers/openai/chat-completions-provider.ts +47 -9
- package/src/providers/openai/coerce-object-args.ts +104 -0
- package/src/providers/retry.ts +8 -5
- package/src/providers/types.ts +10 -0
- package/src/runtime/__tests__/agent-wake.test.ts +629 -7
- package/src/runtime/access-request-helper.ts +16 -9
- package/src/runtime/agent-wake.ts +302 -51
- package/src/runtime/assistant-stream-state.ts +141 -8
- package/src/runtime/background-job-runner.ts +9 -0
- package/src/runtime/channel-approval-types.ts +1 -0
- package/src/runtime/channel-invite-transports/telegram.ts +6 -5
- package/src/runtime/channel-invite-transports/voice.ts +2 -2
- package/src/runtime/channel-invite-types.ts +4 -2
- package/src/runtime/channel-retry-sweep.ts +19 -41
- package/src/runtime/finalize-event-delivery.ts +72 -0
- package/src/runtime/guardian-action-message-composer.ts +0 -54
- package/src/runtime/http-server.ts +6 -14
- package/src/runtime/http-types.ts +0 -1
- package/src/runtime/message-composer-types.ts +0 -9
- package/src/runtime/middleware/__tests__/rate-limiter.test.ts +63 -0
- package/src/runtime/middleware/auth.ts +27 -3
- package/src/runtime/middleware/rate-limiter.ts +28 -1
- package/src/runtime/migrations/vbundle-builder.ts +6 -5
- package/src/runtime/pending-interactions.ts +20 -1
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +232 -173
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +18 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +436 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +11 -0
- package/src/runtime/routes/approval-routes.ts +35 -8
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -1
- package/src/runtime/routes/btw-routes.ts +37 -1
- package/src/runtime/routes/channel-delivery-routes.ts +11 -7
- package/src/runtime/routes/channel-route-definitions.ts +3 -0
- package/src/runtime/routes/channel-route-shared.ts +3 -1
- package/src/runtime/routes/consolidation-routes.ts +17 -13
- package/src/runtime/routes/conversation-compaction-routes.ts +159 -119
- package/src/runtime/routes/conversation-list-routes.ts +41 -4
- package/src/runtime/routes/conversation-query-routes.ts +196 -11
- package/src/runtime/routes/conversation-routes.ts +15 -1
- package/src/runtime/routes/credential-prompt-routes.ts +39 -17
- package/src/runtime/routes/empty-state-greeting-cache.ts +65 -0
- package/src/runtime/routes/heartbeat-routes.ts +18 -13
- package/src/runtime/routes/image-generation-routes.ts +20 -2
- package/src/runtime/routes/inbound-message-handler.ts +13 -12
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +32 -31
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +7 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +7 -21
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +6 -15
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +1 -1
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/log-export/AGENTS.md +1 -1
- package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
- package/src/runtime/routes/migration-routes.ts +5 -9
- package/src/runtime/routes/plugins-routes.ts +26 -0
- package/src/runtime/routes/ps-routes.ts +10 -8
- package/src/runtime/routes/retrospective-routes.ts +235 -0
- package/src/runtime/routes/runs-pagination.ts +75 -0
- package/src/runtime/routes/schedule-routes.ts +367 -59
- package/src/runtime/routes/sounds-config-routes.ts +239 -0
- package/src/runtime/routes/surface-action-routes.ts +84 -4
- package/src/runtime/routes/workflow-routes.test.ts +372 -0
- package/src/runtime/routes/workflow-routes.ts +363 -0
- package/src/runtime/routes/workspace-routes.test.ts +61 -1
- package/src/runtime/routes/workspace-routes.ts +26 -1
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +38 -0
- package/src/runtime/services/analyze-conversation.ts +26 -13
- package/src/schedule/inference-profile.ts +28 -0
- package/src/schedule/schedule-store.ts +152 -4
- package/src/schedule/scheduler-types.ts +6 -0
- package/src/schedule/scheduler.ts +96 -0
- package/src/security/secret-allowlist.ts +1 -1
- package/src/skills/path-classifier.ts +1 -1
- package/src/tools/apps/executors.ts +23 -0
- package/src/tools/apps/resolve-app-id.ts +42 -0
- package/src/tools/browser/browser-execution.ts +9 -11
- package/src/tools/credentials/broker.ts +4 -4
- package/src/tools/credentials/vault.ts +26 -137
- package/src/tools/executor.ts +69 -0
- package/src/tools/flag-gated-tools.test.ts +76 -0
- package/src/tools/permission-checker.ts +8 -1
- package/src/tools/registry.ts +51 -0
- package/src/tools/schedule/create.ts +77 -1
- package/src/tools/schedule/list.ts +1 -0
- package/src/tools/schedule/update.ts +73 -1
- package/src/tools/skills/execute.ts +56 -0
- package/src/tools/terminal/shell.ts +1 -1
- package/src/tools/ui-surface/definitions.ts +91 -2
- package/src/tools/workflows/manage-workflows.ts +183 -0
- package/src/tools/workflows/run-workflow.test.ts +442 -0
- package/src/tools/workflows/run-workflow.ts +88 -0
- package/src/types/onboarding-context.ts +2 -0
- package/src/usage/attribution.ts +24 -0
- package/src/util/canonicalize-identity.ts +12 -3
- package/src/util/platform.ts +17 -17
- package/src/watcher/__tests__/engine.test.ts +24 -0
- package/src/watcher/__tests__/telemetry.test.ts +135 -0
- package/src/watcher/engine.ts +7 -0
- package/src/watcher/telemetry.ts +74 -0
- package/src/workflows/capabilities.test.ts +365 -0
- package/src/workflows/capabilities.ts +359 -0
- package/src/workflows/deterministic-stringify.ts +27 -0
- package/src/workflows/engine-integration.test.ts +656 -0
- package/src/workflows/engine.test.ts +1144 -0
- package/src/workflows/engine.ts +1078 -0
- package/src/workflows/fanout-load.test.ts +168 -0
- package/src/workflows/journal-store.test.ts +369 -0
- package/src/workflows/journal-store.ts +470 -0
- package/src/workflows/leaf-runner.test.ts +704 -0
- package/src/workflows/leaf-runner.ts +589 -0
- package/src/workflows/library.test.ts +134 -0
- package/src/workflows/library.ts +124 -0
- package/src/workflows/run-manager.test.ts +711 -0
- package/src/workflows/run-manager.ts +593 -0
- package/src/workflows/sandbox-escape.test.ts +339 -0
- package/src/workflows/sandbox.test.ts +251 -0
- package/src/workflows/sandbox.ts +447 -0
- package/src/workspace/adaptive-thinking-repair.ts +33 -11
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +1 -1
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +1 -1
- package/src/workspace/migrations/026-backfill-install-meta.ts +1 -1
- package/src/workspace/migrations/030-seed-pkb-autoinject.ts +2 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -4
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +1 -1
- package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +5 -2
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +1 -1
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +8 -2
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +41 -14
- package/src/workspace/migrations/102-preserve-heartbeat-enabled-for-existing-workspaces.ts +69 -0
- package/src/workspace/migrations/103-upgrade-quality-profile-to-opus-4-8.ts +83 -0
- package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +133 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/migrations/runner.ts +1 -1
- package/tsconfig.json +1 -1
- package/src/__tests__/guardian-action-copy-generator.test.ts +0 -200
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -579
- package/src/__tests__/guardian-action-store.test.ts +0 -106
- package/src/daemon/guardian-action-generators.ts +0 -71
- package/src/memory/guardian-action-store.ts +0 -484
- package/src/runtime/guardian-action-grant-minter.ts +0 -150
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { loadConfig } from "../config/loader.js";
|
|
2
|
-
import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
|
|
3
|
-
import { getConfiguredProvider } from "../providers/provider-send-message.js";
|
|
4
|
-
import {
|
|
5
|
-
buildGuardianActionGenerationPrompt,
|
|
6
|
-
getGuardianActionFallbackMessage,
|
|
7
|
-
GUARDIAN_ACTION_COPY_MAX_TOKENS,
|
|
8
|
-
GUARDIAN_ACTION_COPY_SYSTEM_PROMPT,
|
|
9
|
-
GUARDIAN_ACTION_COPY_TIMEOUT_MS,
|
|
10
|
-
includesRequiredKeywords,
|
|
11
|
-
} from "../runtime/guardian-action-message-composer.js";
|
|
12
|
-
import type { GuardianActionCopyGenerator } from "../runtime/http-types.js";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Create the daemon-owned guardian action copy generator that resolves
|
|
16
|
-
* providers and calls `provider.sendMessage` to generate guardian action
|
|
17
|
-
* copy text. Uses the `guardianQuestionCopy` call site so model selection
|
|
18
|
-
* tracks the unified `llm.callSites` configuration.
|
|
19
|
-
*
|
|
20
|
-
* This keeps all provider awareness in the daemon lifecycle, away from
|
|
21
|
-
* the runtime composer.
|
|
22
|
-
*/
|
|
23
|
-
export function createGuardianActionCopyGenerator(): GuardianActionCopyGenerator {
|
|
24
|
-
return async (context, options = {}) => {
|
|
25
|
-
const baseProvider = await getConfiguredProvider("guardianQuestionCopy");
|
|
26
|
-
if (!baseProvider) return null;
|
|
27
|
-
// Wrap so the per-call `callSite` can route to a different provider
|
|
28
|
-
// transport when `llm.callSites.guardianQuestionCopy.provider` overrides
|
|
29
|
-
// the default. Connection-aware: when the resolved profile names a
|
|
30
|
-
// `provider_connection`, that connection's auth wins over the legacy
|
|
31
|
-
// registry lookup. See `wrapWithCallSiteRouting`.
|
|
32
|
-
const provider = wrapWithCallSiteRouting(baseProvider, loadConfig());
|
|
33
|
-
|
|
34
|
-
const fallbackText =
|
|
35
|
-
options.fallbackText?.trim() || getGuardianActionFallbackMessage(context);
|
|
36
|
-
const requiredKeywords = options.requiredKeywords
|
|
37
|
-
?.map((kw) => kw.trim())
|
|
38
|
-
.filter((kw) => kw.length > 0);
|
|
39
|
-
const prompt = buildGuardianActionGenerationPrompt(
|
|
40
|
-
context,
|
|
41
|
-
fallbackText,
|
|
42
|
-
requiredKeywords,
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
const response = await provider.sendMessage(
|
|
46
|
-
[{ role: "user", content: [{ type: "text", text: prompt }] }],
|
|
47
|
-
{
|
|
48
|
-
tools: [],
|
|
49
|
-
systemPrompt: GUARDIAN_ACTION_COPY_SYSTEM_PROMPT,
|
|
50
|
-
config: {
|
|
51
|
-
max_tokens: options.maxTokens ?? GUARDIAN_ACTION_COPY_MAX_TOKENS,
|
|
52
|
-
callSite: "guardianQuestionCopy",
|
|
53
|
-
},
|
|
54
|
-
signal: AbortSignal.timeout(
|
|
55
|
-
options.timeoutMs ?? GUARDIAN_ACTION_COPY_TIMEOUT_MS,
|
|
56
|
-
),
|
|
57
|
-
},
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
const block = response.content.find((entry) => entry.type === "text");
|
|
61
|
-
const text = block && "text" in block ? block.text.trim() : "";
|
|
62
|
-
if (!text) return null;
|
|
63
|
-
const cleaned = text
|
|
64
|
-
.replace(/^["'`]+/, "")
|
|
65
|
-
.replace(/["'`]+$/, "")
|
|
66
|
-
.trim();
|
|
67
|
-
if (!cleaned) return null;
|
|
68
|
-
if (!includesRequiredKeywords(cleaned, requiredKeywords)) return null;
|
|
69
|
-
return cleaned;
|
|
70
|
-
};
|
|
71
|
-
}
|
|
@@ -1,484 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Store for cross-channel guardian action requests and deliveries.
|
|
3
|
-
*
|
|
4
|
-
* Guardian action requests are created when a voice call's ASK_GUARDIAN
|
|
5
|
-
* marker fires, and deliveries track per-channel dispatch (telegram, mac).
|
|
6
|
-
* Resolution uses first-response-wins semantics: the first channel to
|
|
7
|
-
* answer resolves the request and all other deliveries are marked answered.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { and, desc, eq, inArray, lt } from "drizzle-orm";
|
|
11
|
-
import { v4 as uuid } from "uuid";
|
|
12
|
-
|
|
13
|
-
import { getDb } from "./db-connection.js";
|
|
14
|
-
import { rawChanges } from "./raw-query.js";
|
|
15
|
-
import { guardianActionDeliveries, guardianActionRequests } from "./schema.js";
|
|
16
|
-
|
|
17
|
-
// ---------------------------------------------------------------------------
|
|
18
|
-
// Types
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
|
-
|
|
21
|
-
export type GuardianActionRequestStatus =
|
|
22
|
-
| "pending"
|
|
23
|
-
| "answered"
|
|
24
|
-
| "expired"
|
|
25
|
-
| "cancelled";
|
|
26
|
-
export type GuardianActionDeliveryStatus =
|
|
27
|
-
| "pending"
|
|
28
|
-
| "sent"
|
|
29
|
-
| "failed"
|
|
30
|
-
| "answered"
|
|
31
|
-
| "expired"
|
|
32
|
-
| "cancelled";
|
|
33
|
-
export type ExpiredReason =
|
|
34
|
-
| "call_timeout"
|
|
35
|
-
| "sweep_timeout"
|
|
36
|
-
| "cancelled"
|
|
37
|
-
| "superseded";
|
|
38
|
-
export type FollowupState =
|
|
39
|
-
| "none"
|
|
40
|
-
| "awaiting_guardian_choice"
|
|
41
|
-
| "dispatching"
|
|
42
|
-
| "completed"
|
|
43
|
-
| "declined"
|
|
44
|
-
| "failed";
|
|
45
|
-
/** Follow-up action recorded on a request row (column retained). */
|
|
46
|
-
export type FollowupAction = "call_back" | "decline";
|
|
47
|
-
|
|
48
|
-
export interface GuardianActionRequest {
|
|
49
|
-
id: string;
|
|
50
|
-
kind: string;
|
|
51
|
-
sourceChannel: string;
|
|
52
|
-
sourceConversationId: string;
|
|
53
|
-
callSessionId: string;
|
|
54
|
-
pendingQuestionId: string;
|
|
55
|
-
questionText: string;
|
|
56
|
-
requestCode: string;
|
|
57
|
-
status: GuardianActionRequestStatus;
|
|
58
|
-
answerText: string | null;
|
|
59
|
-
answeredByChannel: string | null;
|
|
60
|
-
answeredByExternalUserId: string | null;
|
|
61
|
-
answeredAt: number | null;
|
|
62
|
-
expiresAt: number;
|
|
63
|
-
expiredReason: ExpiredReason | null;
|
|
64
|
-
followupState: FollowupState;
|
|
65
|
-
lateAnswerText: string | null;
|
|
66
|
-
lateAnsweredAt: number | null;
|
|
67
|
-
followupAction: FollowupAction | null;
|
|
68
|
-
followupCompletedAt: number | null;
|
|
69
|
-
toolName: string | null;
|
|
70
|
-
inputDigest: string | null;
|
|
71
|
-
supersededByRequestId: string | null;
|
|
72
|
-
supersededAt: number | null;
|
|
73
|
-
createdAt: number;
|
|
74
|
-
updatedAt: number;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface GuardianActionDelivery {
|
|
78
|
-
id: string;
|
|
79
|
-
requestId: string;
|
|
80
|
-
destinationChannel: string;
|
|
81
|
-
destinationConversationId: string | null;
|
|
82
|
-
destinationChatId: string | null;
|
|
83
|
-
destinationExternalUserId: string | null;
|
|
84
|
-
status: GuardianActionDeliveryStatus;
|
|
85
|
-
sentAt: number | null;
|
|
86
|
-
respondedAt: number | null;
|
|
87
|
-
lastError: string | null;
|
|
88
|
-
createdAt: number;
|
|
89
|
-
updatedAt: number;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ---------------------------------------------------------------------------
|
|
93
|
-
// Helpers
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
|
-
|
|
96
|
-
function rowToRequest(
|
|
97
|
-
row: typeof guardianActionRequests.$inferSelect,
|
|
98
|
-
): GuardianActionRequest {
|
|
99
|
-
return {
|
|
100
|
-
id: row.id,
|
|
101
|
-
kind: row.kind,
|
|
102
|
-
sourceChannel: row.sourceChannel,
|
|
103
|
-
sourceConversationId: row.sourceConversationId,
|
|
104
|
-
callSessionId: row.callSessionId,
|
|
105
|
-
pendingQuestionId: row.pendingQuestionId,
|
|
106
|
-
questionText: row.questionText,
|
|
107
|
-
requestCode: row.requestCode,
|
|
108
|
-
status: row.status as GuardianActionRequestStatus,
|
|
109
|
-
answerText: row.answerText,
|
|
110
|
-
answeredByChannel: row.answeredByChannel,
|
|
111
|
-
answeredByExternalUserId: row.answeredByExternalUserId,
|
|
112
|
-
answeredAt: row.answeredAt,
|
|
113
|
-
expiresAt: row.expiresAt,
|
|
114
|
-
expiredReason: (row.expiredReason as ExpiredReason) ?? null,
|
|
115
|
-
followupState: (row.followupState as FollowupState) ?? "none",
|
|
116
|
-
lateAnswerText: row.lateAnswerText ?? null,
|
|
117
|
-
lateAnsweredAt: row.lateAnsweredAt ?? null,
|
|
118
|
-
followupAction: (row.followupAction as FollowupAction) ?? null,
|
|
119
|
-
followupCompletedAt: row.followupCompletedAt ?? null,
|
|
120
|
-
toolName: row.toolName ?? null,
|
|
121
|
-
inputDigest: row.inputDigest ?? null,
|
|
122
|
-
supersededByRequestId: row.supersededByRequestId ?? null,
|
|
123
|
-
supersededAt: row.supersededAt ?? null,
|
|
124
|
-
createdAt: row.createdAt,
|
|
125
|
-
updatedAt: row.updatedAt,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function rowToDelivery(
|
|
130
|
-
row: typeof guardianActionDeliveries.$inferSelect,
|
|
131
|
-
): GuardianActionDelivery {
|
|
132
|
-
return {
|
|
133
|
-
id: row.id,
|
|
134
|
-
requestId: row.requestId,
|
|
135
|
-
destinationChannel: row.destinationChannel,
|
|
136
|
-
destinationConversationId: row.destinationConversationId,
|
|
137
|
-
destinationChatId: row.destinationChatId,
|
|
138
|
-
destinationExternalUserId: row.destinationExternalUserId,
|
|
139
|
-
status: row.status as GuardianActionDeliveryStatus,
|
|
140
|
-
sentAt: row.sentAt,
|
|
141
|
-
respondedAt: row.respondedAt,
|
|
142
|
-
lastError: row.lastError,
|
|
143
|
-
createdAt: row.createdAt,
|
|
144
|
-
updatedAt: row.updatedAt,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/** Generate a short human-readable request code (6 hex chars). */
|
|
149
|
-
function generateRequestCode(): string {
|
|
150
|
-
return uuid().replace(/-/g, "").slice(0, 6).toUpperCase();
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// ---------------------------------------------------------------------------
|
|
154
|
-
// Guardian Action Requests
|
|
155
|
-
// ---------------------------------------------------------------------------
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* @internal Test-only helper. Production code should create guardian requests
|
|
159
|
-
* via `createCanonicalGuardianRequest` in canonical-guardian-store.ts.
|
|
160
|
-
* This function is retained solely so that existing test fixtures that seed
|
|
161
|
-
* legacy guardian action rows continue to compile.
|
|
162
|
-
*/
|
|
163
|
-
export function createGuardianActionRequest(params: {
|
|
164
|
-
kind: string;
|
|
165
|
-
sourceChannel: string;
|
|
166
|
-
sourceConversationId: string;
|
|
167
|
-
callSessionId: string;
|
|
168
|
-
pendingQuestionId: string;
|
|
169
|
-
questionText: string;
|
|
170
|
-
expiresAt: number;
|
|
171
|
-
toolName?: string;
|
|
172
|
-
inputDigest?: string;
|
|
173
|
-
}): GuardianActionRequest {
|
|
174
|
-
const db = getDb();
|
|
175
|
-
const now = Date.now();
|
|
176
|
-
const id = uuid();
|
|
177
|
-
|
|
178
|
-
const row = {
|
|
179
|
-
id,
|
|
180
|
-
kind: params.kind,
|
|
181
|
-
sourceChannel: params.sourceChannel,
|
|
182
|
-
sourceConversationId: params.sourceConversationId,
|
|
183
|
-
callSessionId: params.callSessionId,
|
|
184
|
-
pendingQuestionId: params.pendingQuestionId,
|
|
185
|
-
questionText: params.questionText,
|
|
186
|
-
requestCode: generateRequestCode(),
|
|
187
|
-
status: "pending" as const,
|
|
188
|
-
answerText: null,
|
|
189
|
-
answeredByChannel: null,
|
|
190
|
-
answeredByExternalUserId: null,
|
|
191
|
-
answeredAt: null,
|
|
192
|
-
expiresAt: params.expiresAt,
|
|
193
|
-
expiredReason: null,
|
|
194
|
-
followupState: "none" as const,
|
|
195
|
-
lateAnswerText: null,
|
|
196
|
-
lateAnsweredAt: null,
|
|
197
|
-
followupAction: null,
|
|
198
|
-
followupCompletedAt: null,
|
|
199
|
-
toolName: params.toolName ?? null,
|
|
200
|
-
inputDigest: params.inputDigest ?? null,
|
|
201
|
-
supersededByRequestId: null,
|
|
202
|
-
supersededAt: null,
|
|
203
|
-
createdAt: now,
|
|
204
|
-
updatedAt: now,
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
db.insert(guardianActionRequests).values(row).run();
|
|
208
|
-
return rowToRequest(row);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export function getGuardianActionRequest(
|
|
212
|
-
id: string,
|
|
213
|
-
): GuardianActionRequest | null {
|
|
214
|
-
const db = getDb();
|
|
215
|
-
const row = db
|
|
216
|
-
.select()
|
|
217
|
-
.from(guardianActionRequests)
|
|
218
|
-
.where(eq(guardianActionRequests.id, id))
|
|
219
|
-
.get();
|
|
220
|
-
return row ? rowToRequest(row) : null;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Find the most recent pending guardian action request for a given call session.
|
|
225
|
-
* Used by the consultation timeout handler to mark the linked request as timed out.
|
|
226
|
-
*/
|
|
227
|
-
export function getPendingRequestByCallSessionId(
|
|
228
|
-
callSessionId: string,
|
|
229
|
-
): GuardianActionRequest | null {
|
|
230
|
-
const db = getDb();
|
|
231
|
-
const row = db
|
|
232
|
-
.select()
|
|
233
|
-
.from(guardianActionRequests)
|
|
234
|
-
.where(
|
|
235
|
-
and(
|
|
236
|
-
eq(guardianActionRequests.callSessionId, callSessionId),
|
|
237
|
-
eq(guardianActionRequests.status, "pending"),
|
|
238
|
-
),
|
|
239
|
-
)
|
|
240
|
-
.orderBy(desc(guardianActionRequests.createdAt))
|
|
241
|
-
.get();
|
|
242
|
-
return row ? rowToRequest(row) : null;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* First-response-wins resolution. Checks that the request is still
|
|
247
|
-
* 'pending' before updating; returns the updated request on success
|
|
248
|
-
* or null if the request was already resolved.
|
|
249
|
-
*/
|
|
250
|
-
export function resolveGuardianActionRequest(
|
|
251
|
-
id: string,
|
|
252
|
-
answerText: string,
|
|
253
|
-
answeredByChannel: string,
|
|
254
|
-
answeredByExternalUserId?: string,
|
|
255
|
-
): GuardianActionRequest | null {
|
|
256
|
-
const db = getDb();
|
|
257
|
-
const now = Date.now();
|
|
258
|
-
|
|
259
|
-
// Atomically check-and-update: only update if status is still 'pending'
|
|
260
|
-
db.update(guardianActionRequests)
|
|
261
|
-
.set({
|
|
262
|
-
status: "answered",
|
|
263
|
-
answerText,
|
|
264
|
-
answeredByChannel,
|
|
265
|
-
answeredByExternalUserId: answeredByExternalUserId ?? null,
|
|
266
|
-
answeredAt: now,
|
|
267
|
-
updatedAt: now,
|
|
268
|
-
})
|
|
269
|
-
.where(
|
|
270
|
-
and(
|
|
271
|
-
eq(guardianActionRequests.id, id),
|
|
272
|
-
eq(guardianActionRequests.status, "pending"),
|
|
273
|
-
),
|
|
274
|
-
)
|
|
275
|
-
.run();
|
|
276
|
-
|
|
277
|
-
// Check if the update took effect
|
|
278
|
-
if (rawChanges() === 0) return null;
|
|
279
|
-
|
|
280
|
-
// Mark all deliveries as 'answered'
|
|
281
|
-
db.update(guardianActionDeliveries)
|
|
282
|
-
.set({ status: "answered", respondedAt: now, updatedAt: now })
|
|
283
|
-
.where(eq(guardianActionDeliveries.requestId, id))
|
|
284
|
-
.run();
|
|
285
|
-
|
|
286
|
-
return getGuardianActionRequest(id);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Expire a guardian action request and all its deliveries.
|
|
291
|
-
*/
|
|
292
|
-
export function expireGuardianActionRequest(
|
|
293
|
-
id: string,
|
|
294
|
-
reason: ExpiredReason,
|
|
295
|
-
): void {
|
|
296
|
-
const db = getDb();
|
|
297
|
-
const now = Date.now();
|
|
298
|
-
|
|
299
|
-
db.update(guardianActionRequests)
|
|
300
|
-
.set({
|
|
301
|
-
status: "expired",
|
|
302
|
-
expiredReason: reason,
|
|
303
|
-
updatedAt: now,
|
|
304
|
-
})
|
|
305
|
-
.where(
|
|
306
|
-
and(
|
|
307
|
-
eq(guardianActionRequests.id, id),
|
|
308
|
-
eq(guardianActionRequests.status, "pending"),
|
|
309
|
-
),
|
|
310
|
-
)
|
|
311
|
-
.run();
|
|
312
|
-
|
|
313
|
-
db.update(guardianActionDeliveries)
|
|
314
|
-
.set({ status: "expired", updatedAt: now })
|
|
315
|
-
.where(
|
|
316
|
-
and(
|
|
317
|
-
eq(guardianActionDeliveries.requestId, id),
|
|
318
|
-
inArray(guardianActionDeliveries.status, ["pending", "sent"]),
|
|
319
|
-
),
|
|
320
|
-
)
|
|
321
|
-
.run();
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Supersede a pending guardian action request: mark it expired with
|
|
326
|
-
* reason='superseded', record the replacement request ID and timestamp,
|
|
327
|
-
* and expire its active deliveries.
|
|
328
|
-
*
|
|
329
|
-
* Returns the updated request on success, or null if the request was
|
|
330
|
-
* not in 'pending' status (first-writer-wins).
|
|
331
|
-
*/
|
|
332
|
-
export function supersedeGuardianActionRequest(
|
|
333
|
-
id: string,
|
|
334
|
-
supersededByRequestId: string,
|
|
335
|
-
): GuardianActionRequest | null {
|
|
336
|
-
const db = getDb();
|
|
337
|
-
const now = Date.now();
|
|
338
|
-
|
|
339
|
-
db.update(guardianActionRequests)
|
|
340
|
-
.set({
|
|
341
|
-
status: "expired",
|
|
342
|
-
expiredReason: "superseded",
|
|
343
|
-
supersededByRequestId,
|
|
344
|
-
supersededAt: now,
|
|
345
|
-
updatedAt: now,
|
|
346
|
-
})
|
|
347
|
-
.where(
|
|
348
|
-
and(
|
|
349
|
-
eq(guardianActionRequests.id, id),
|
|
350
|
-
eq(guardianActionRequests.status, "pending"),
|
|
351
|
-
),
|
|
352
|
-
)
|
|
353
|
-
.run();
|
|
354
|
-
|
|
355
|
-
if (rawChanges() === 0) return null;
|
|
356
|
-
|
|
357
|
-
// Also expire active deliveries
|
|
358
|
-
db.update(guardianActionDeliveries)
|
|
359
|
-
.set({ status: "expired", updatedAt: now })
|
|
360
|
-
.where(
|
|
361
|
-
and(
|
|
362
|
-
eq(guardianActionDeliveries.requestId, id),
|
|
363
|
-
inArray(guardianActionDeliveries.status, ["pending", "sent"]),
|
|
364
|
-
),
|
|
365
|
-
)
|
|
366
|
-
.run();
|
|
367
|
-
|
|
368
|
-
return getGuardianActionRequest(id);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Get all pending guardian action requests that have expired.
|
|
373
|
-
*/
|
|
374
|
-
export function getExpiredGuardianActionRequests(): GuardianActionRequest[] {
|
|
375
|
-
const db = getDb();
|
|
376
|
-
const now = Date.now();
|
|
377
|
-
return db
|
|
378
|
-
.select()
|
|
379
|
-
.from(guardianActionRequests)
|
|
380
|
-
.where(
|
|
381
|
-
and(
|
|
382
|
-
eq(guardianActionRequests.status, "pending"),
|
|
383
|
-
lt(guardianActionRequests.expiresAt, now),
|
|
384
|
-
),
|
|
385
|
-
)
|
|
386
|
-
.all()
|
|
387
|
-
.map(rowToRequest);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Get all deliveries for a specific request.
|
|
392
|
-
*/
|
|
393
|
-
export function getDeliveriesByRequestId(
|
|
394
|
-
requestId: string,
|
|
395
|
-
): GuardianActionDelivery[] {
|
|
396
|
-
const db = getDb();
|
|
397
|
-
return db
|
|
398
|
-
.select()
|
|
399
|
-
.from(guardianActionDeliveries)
|
|
400
|
-
.where(eq(guardianActionDeliveries.requestId, requestId))
|
|
401
|
-
.all()
|
|
402
|
-
.map(rowToDelivery);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Cancel a guardian action request and all its deliveries.
|
|
407
|
-
*/
|
|
408
|
-
export function cancelGuardianActionRequest(id: string): void {
|
|
409
|
-
const db = getDb();
|
|
410
|
-
const now = Date.now();
|
|
411
|
-
|
|
412
|
-
db.update(guardianActionRequests)
|
|
413
|
-
.set({ status: "cancelled", updatedAt: now })
|
|
414
|
-
.where(
|
|
415
|
-
and(
|
|
416
|
-
eq(guardianActionRequests.id, id),
|
|
417
|
-
eq(guardianActionRequests.status, "pending"),
|
|
418
|
-
),
|
|
419
|
-
)
|
|
420
|
-
.run();
|
|
421
|
-
|
|
422
|
-
db.update(guardianActionDeliveries)
|
|
423
|
-
.set({ status: "cancelled", updatedAt: now })
|
|
424
|
-
.where(
|
|
425
|
-
and(
|
|
426
|
-
eq(guardianActionDeliveries.requestId, id),
|
|
427
|
-
inArray(guardianActionDeliveries.status, ["pending", "sent"]),
|
|
428
|
-
),
|
|
429
|
-
)
|
|
430
|
-
.run();
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// ---------------------------------------------------------------------------
|
|
434
|
-
// Guardian Action Deliveries
|
|
435
|
-
// ---------------------------------------------------------------------------
|
|
436
|
-
|
|
437
|
-
export function createGuardianActionDelivery(params: {
|
|
438
|
-
requestId: string;
|
|
439
|
-
destinationChannel: string;
|
|
440
|
-
destinationConversationId?: string;
|
|
441
|
-
destinationChatId?: string;
|
|
442
|
-
destinationExternalUserId?: string;
|
|
443
|
-
}): GuardianActionDelivery {
|
|
444
|
-
const db = getDb();
|
|
445
|
-
const now = Date.now();
|
|
446
|
-
const id = uuid();
|
|
447
|
-
|
|
448
|
-
const row = {
|
|
449
|
-
id,
|
|
450
|
-
requestId: params.requestId,
|
|
451
|
-
destinationChannel: params.destinationChannel,
|
|
452
|
-
destinationConversationId: params.destinationConversationId ?? null,
|
|
453
|
-
destinationChatId: params.destinationChatId ?? null,
|
|
454
|
-
destinationExternalUserId: params.destinationExternalUserId ?? null,
|
|
455
|
-
status: "pending" as const,
|
|
456
|
-
sentAt: null,
|
|
457
|
-
respondedAt: null,
|
|
458
|
-
lastError: null,
|
|
459
|
-
createdAt: now,
|
|
460
|
-
updatedAt: now,
|
|
461
|
-
};
|
|
462
|
-
|
|
463
|
-
db.insert(guardianActionDeliveries).values(row).run();
|
|
464
|
-
return rowToDelivery(row);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
export function updateDeliveryStatus(
|
|
468
|
-
deliveryId: string,
|
|
469
|
-
status: GuardianActionDeliveryStatus,
|
|
470
|
-
error?: string,
|
|
471
|
-
): void {
|
|
472
|
-
const db = getDb();
|
|
473
|
-
const now = Date.now();
|
|
474
|
-
|
|
475
|
-
const updates: Record<string, unknown> = { status, updatedAt: now };
|
|
476
|
-
if (status === "sent") updates.sentAt = now;
|
|
477
|
-
if (status === "answered") updates.respondedAt = now;
|
|
478
|
-
if (error !== undefined) updates.lastError = error;
|
|
479
|
-
|
|
480
|
-
db.update(guardianActionDeliveries)
|
|
481
|
-
.set(updates)
|
|
482
|
-
.where(eq(guardianActionDeliveries.id, deliveryId))
|
|
483
|
-
.run();
|
|
484
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared helper for minting scoped approval grants when a guardian-action
|
|
3
|
-
* request is resolved with tool metadata.
|
|
4
|
-
*
|
|
5
|
-
* Used by both the channel inbound path (inbound-message-handler.ts) and
|
|
6
|
-
* the desktop path (conversation-process.ts) to ensure grants are minted
|
|
7
|
-
* consistently regardless of which channel the guardian answers on.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { mintGrantFromDecision } from "../approvals/approval-primitive.js";
|
|
11
|
-
import type { GuardianActionRequest } from "../memory/guardian-action-store.js";
|
|
12
|
-
import { getLogger } from "../util/logger.js";
|
|
13
|
-
import { runApprovalConversationTurn } from "./approval-conversation-turn.js";
|
|
14
|
-
import type { ApprovalConversationGenerator } from "./http-types.js";
|
|
15
|
-
|
|
16
|
-
const log = getLogger("guardian-action-grant-minter");
|
|
17
|
-
|
|
18
|
-
/** TTL for scoped approval grants minted on guardian-action answer resolution. */
|
|
19
|
-
const GUARDIAN_ACTION_GRANT_TTL_MS = 5 * 60 * 1000;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Mint a `tool_signature` scoped grant when a guardian-action request is
|
|
23
|
-
* resolved and the request carries tool metadata (toolName + inputDigest).
|
|
24
|
-
*
|
|
25
|
-
* Classifies the guardian's answer via the conversational approval engine
|
|
26
|
-
* (`runApprovalConversationTurn`). Only `approve_once` produces a grant —
|
|
27
|
-
* guardian-action grants are always single-use `tool_signature` scoped.
|
|
28
|
-
*
|
|
29
|
-
* Skips silently when:
|
|
30
|
-
* - The resolved request has no toolName/inputDigest (informational consult).
|
|
31
|
-
* - The guardian's answer is not classified as approval (fail-closed).
|
|
32
|
-
*
|
|
33
|
-
* Fails silently on error -- grant minting is best-effort and must never
|
|
34
|
-
* block the guardian-action answer flow.
|
|
35
|
-
*/
|
|
36
|
-
export async function tryMintGuardianActionGrant(params: {
|
|
37
|
-
request: GuardianActionRequest;
|
|
38
|
-
answerText: string;
|
|
39
|
-
decisionChannel: string;
|
|
40
|
-
guardianExternalUserId?: string;
|
|
41
|
-
approvalConversationGenerator: ApprovalConversationGenerator;
|
|
42
|
-
}): Promise<void> {
|
|
43
|
-
const {
|
|
44
|
-
request,
|
|
45
|
-
answerText,
|
|
46
|
-
decisionChannel,
|
|
47
|
-
guardianExternalUserId,
|
|
48
|
-
approvalConversationGenerator,
|
|
49
|
-
} = params;
|
|
50
|
-
|
|
51
|
-
// Only mint for requests that carry tool metadata -- informational
|
|
52
|
-
// ASK_GUARDIAN consults without tool context do not produce grants.
|
|
53
|
-
if (!request.toolName || !request.inputDigest) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Classify the guardian's answer via the conversational approval engine.
|
|
58
|
-
// Guardian-action grants are always single-use (approve_once only).
|
|
59
|
-
let isApproval = false;
|
|
60
|
-
try {
|
|
61
|
-
const llmResult = await runApprovalConversationTurn(
|
|
62
|
-
{
|
|
63
|
-
toolName: request.toolName,
|
|
64
|
-
allowedActions: ["approve_once", "reject"],
|
|
65
|
-
role: "guardian",
|
|
66
|
-
pendingApprovals: [
|
|
67
|
-
{ requestId: request.id, toolName: request.toolName },
|
|
68
|
-
],
|
|
69
|
-
userMessage: answerText,
|
|
70
|
-
},
|
|
71
|
-
approvalConversationGenerator,
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
isApproval = llmResult.disposition === "approve_once";
|
|
75
|
-
|
|
76
|
-
log.info(
|
|
77
|
-
{
|
|
78
|
-
event: "guardian_action_grant_classification",
|
|
79
|
-
toolName: request.toolName,
|
|
80
|
-
requestId: request.id,
|
|
81
|
-
answerText,
|
|
82
|
-
llmDisposition: llmResult.disposition,
|
|
83
|
-
matched: isApproval,
|
|
84
|
-
decisionChannel,
|
|
85
|
-
},
|
|
86
|
-
`Approval classifier returned disposition: ${llmResult.disposition}`,
|
|
87
|
-
);
|
|
88
|
-
} catch (err) {
|
|
89
|
-
// Fail-closed: generator errors must not produce grants.
|
|
90
|
-
log.warn(
|
|
91
|
-
{
|
|
92
|
-
event: "guardian_action_grant_classification_error",
|
|
93
|
-
toolName: request.toolName,
|
|
94
|
-
requestId: request.id,
|
|
95
|
-
err,
|
|
96
|
-
decisionChannel,
|
|
97
|
-
},
|
|
98
|
-
"Approval classifier threw an error; treating as non-approval (fail-closed)",
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (!isApproval) {
|
|
103
|
-
log.info(
|
|
104
|
-
{
|
|
105
|
-
event: "guardian_action_grant_skipped_no_approval",
|
|
106
|
-
toolName: request.toolName,
|
|
107
|
-
requestId: request.id,
|
|
108
|
-
answerText,
|
|
109
|
-
decisionChannel,
|
|
110
|
-
},
|
|
111
|
-
"Skipped grant minting: guardian answer not classified as approval",
|
|
112
|
-
);
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const result = mintGrantFromDecision({
|
|
117
|
-
scopeMode: "tool_signature",
|
|
118
|
-
toolName: request.toolName,
|
|
119
|
-
inputDigest: request.inputDigest,
|
|
120
|
-
requestChannel: request.sourceChannel,
|
|
121
|
-
decisionChannel,
|
|
122
|
-
executionChannel: null,
|
|
123
|
-
conversationId: request.sourceConversationId,
|
|
124
|
-
callSessionId: request.callSessionId,
|
|
125
|
-
guardianExternalUserId: guardianExternalUserId ?? null,
|
|
126
|
-
expiresAt: Date.now() + GUARDIAN_ACTION_GRANT_TTL_MS,
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
if (result.ok) {
|
|
130
|
-
log.info(
|
|
131
|
-
{
|
|
132
|
-
event: "guardian_action_grant_minted",
|
|
133
|
-
toolName: request.toolName,
|
|
134
|
-
requestId: request.id,
|
|
135
|
-
callSessionId: request.callSessionId,
|
|
136
|
-
decisionChannel,
|
|
137
|
-
},
|
|
138
|
-
"Minted scoped approval grant for guardian-action answer resolution",
|
|
139
|
-
);
|
|
140
|
-
} else {
|
|
141
|
-
log.error(
|
|
142
|
-
{
|
|
143
|
-
reason: result.reason,
|
|
144
|
-
toolName: request.toolName,
|
|
145
|
-
requestId: request.id,
|
|
146
|
-
},
|
|
147
|
-
"Failed to mint scoped approval grant for guardian-action (non-fatal)",
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
}
|