@vellumai/assistant 0.11.4 → 0.11.5-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 +2 -2
- package/ARCHITECTURE.md +29 -4
- package/README.md +1 -1
- package/docs/architecture/memory.md +17 -5
- package/docs/architecture/security.md +96 -152
- package/docs/guardian-request-flow.md +13 -2
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
- package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +7 -14
- package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +29 -31
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/openapi.yaml +193 -3
- package/package.json +1 -1
- package/src/__tests__/anthropic-provider.test.ts +10 -3
- package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +4 -0
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -6
- package/src/__tests__/channel-reply-delivery.test.ts +26 -13
- package/src/__tests__/checker.test.ts +20 -314
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
- package/src/__tests__/client-os-metadata-persistence.test.ts +16 -0
- package/src/__tests__/compactor-retained-image-validation.test.ts +142 -0
- package/src/__tests__/config-loader-backfill.test.ts +19 -10
- package/src/__tests__/container-cpu-sampler.test.ts +153 -0
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-error.test.ts +17 -0
- package/src/__tests__/conversation-lifecycle.test.ts +20 -26
- package/src/__tests__/conversation-pairing.test.ts +186 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +21 -2
- package/src/__tests__/credential-broker-server-use.test.ts +24 -5
- package/src/__tests__/credential-routes.test.ts +22 -3
- package/src/__tests__/credential-security-invariants.test.ts +2 -1
- package/src/__tests__/daemon-credential-client.test.ts +88 -0
- package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
- package/src/__tests__/dm-backfill.test.ts +63 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
- package/src/__tests__/edit-propagation.test.ts +107 -4
- package/src/__tests__/events-client-registration.test.ts +28 -0
- package/src/__tests__/file-write-tool.test.ts +4 -2
- package/src/__tests__/guardian-prompt-notice-privacy.test.ts +133 -0
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +143 -97
- package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
- package/src/__tests__/host-proxy-interface.test.ts +11 -1
- package/src/__tests__/host-shell-tool.test.ts +23 -4
- package/src/__tests__/image-conversion.test.ts +143 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
- package/src/__tests__/input-repairs.test.ts +207 -0
- package/src/__tests__/live-workspace-guard.test.ts +75 -0
- package/src/__tests__/managed-profile-guard.test.ts +4 -2
- package/src/__tests__/mcp-abort-signal.test.ts +1 -1
- package/src/__tests__/mcp-client-auth.test.ts +1 -1
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +1 -1
- package/src/__tests__/media-resolve-image-validation.test.ts +310 -0
- package/src/__tests__/mtime-cache.test.ts +2 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +124 -1
- package/src/__tests__/openai-provider.test.ts +22 -0
- package/src/__tests__/personal-memory-auth-bypass.test.ts +22 -6
- package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
- package/src/__tests__/platform.test.ts +16 -1
- package/src/__tests__/plugin-api-resolve-credential.test.ts +22 -13
- package/src/__tests__/plugin-api-shim.test.ts +5 -0
- package/src/__tests__/plugin-api-store-credential.test.ts +268 -0
- package/src/__tests__/plugin-config-data-migration.test.ts +8 -1
- package/src/__tests__/plugin-disabled-state.test.ts +2 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
- package/src/__tests__/plugin-execution-context.test.ts +73 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -1
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +0 -1
- package/src/__tests__/reaction-persistence.test.ts +200 -7
- package/src/__tests__/require-fresh-approval.test.ts +0 -4
- package/src/__tests__/resource-pressure-guard.test.ts +428 -0
- package/src/__tests__/resource-pressure-routes.test.ts +113 -0
- package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +27 -1
- package/src/__tests__/secret-routes-platform-proxy.test.ts +7 -0
- package/src/__tests__/skill-tool-factory.test.ts +161 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
- package/src/__tests__/tool-executor.test.ts +63 -38
- package/src/__tests__/tool-policy.test.ts +97 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +7 -4
- package/src/__tests__/user-plugin-loader.test.ts +2 -0
- package/src/__tests__/validate-input.test.ts +243 -7
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -0
- package/src/__tests__/voice-session-bridge.test.ts +42 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +97 -29
- package/src/acp/__tests__/prepare-agent-env.test.ts +376 -153
- package/src/acp/acp-claude-oauth.ts +38 -21
- package/src/acp/prepare-agent-env.ts +146 -55
- package/src/agent/loop-tool-dedup.test.ts +161 -0
- package/src/agent/loop.ts +68 -22
- package/src/api/constants/app-tools.ts +34 -0
- package/src/api/events/resource-pressure-status-changed.ts +53 -0
- package/src/api/index.ts +19 -0
- package/src/api/responses/resource-pressure-status.ts +25 -0
- package/src/approvals/guardian-channel-delivery.ts +70 -6
- package/src/approvals/guardian-request-resolvers.ts +32 -66
- package/src/calls/__tests__/voice-session-bridge.test.ts +114 -0
- package/src/calls/voice-session-bridge.ts +60 -6
- package/src/channels/__tests__/message-audience.test.ts +49 -0
- package/src/channels/__tests__/types.test.ts +17 -3
- package/src/channels/message-audience.ts +40 -0
- package/src/channels/types.ts +16 -12
- package/src/cli/__tests__/catalog-search-help.test.ts +50 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +31 -0
- package/src/cli/commands/__tests__/conversations-search.test.ts +289 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
- package/src/cli/commands/__tests__/inference-providers.test.ts +68 -0
- package/src/cli/commands/__tests__/keys.test.ts +89 -8
- package/src/cli/commands/__tests__/plugins.test.ts +57 -1
- package/src/cli/commands/channel-verification-sessions.help.ts +11 -9
- package/src/cli/commands/channel-verification-sessions.ts +11 -21
- package/src/cli/commands/conversations.help.ts +34 -0
- package/src/cli/commands/conversations.ts +125 -0
- package/src/cli/commands/inference-providers.ts +9 -4
- package/src/cli/commands/inference.help.ts +9 -4
- package/src/cli/commands/keys.help.ts +13 -1
- package/src/cli/commands/keys.ts +26 -15
- package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
- package/src/cli/commands/memory/index.help.ts +41 -27
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/memory-v2.ts +58 -54
- package/src/cli/commands/memory/memory-validate.ts +18 -0
- package/src/cli/commands/monitoring.ts +1 -0
- package/src/cli/commands/plugins.help.ts +28 -31
- package/src/cli/commands/plugins.ts +10 -0
- package/src/cli/commands/skills.help.ts +13 -16
- package/src/cli/commands/trust.ts +3 -14
- package/src/cli/lib/__tests__/install-from-github.test.ts +38 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +34 -0
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +32 -1
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +2 -1
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +64 -0
- package/src/cli/lib/bundled-marketplace.json +13 -0
- package/src/cli/lib/daemon-credential-client.ts +25 -3
- package/src/cli/lib/install-from-github.ts +35 -24
- package/src/cli/lib/merge-plugin-tree.ts +22 -4
- package/src/cli/lib/plugin-surfaces.ts +27 -0
- package/src/config/__tests__/balanced-model-experiment.test.ts +7 -7
- package/src/config/__tests__/default-profile-catalog.test.ts +3 -3
- package/src/config/default-profile-catalog.ts +5 -6
- package/src/config/feature-flag-registry.json +32 -32
- package/src/config/webhook-routing.ts +8 -0
- package/src/context/compactor.ts +31 -2
- package/src/daemon/__tests__/provider-rejection-log-fields.test.ts +272 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +4 -1
- package/src/daemon/conversation-error.ts +13 -0
- package/src/daemon/conversation-messaging.ts +22 -2
- package/src/daemon/conversation-process.ts +11 -0
- package/src/daemon/conversation-store.ts +10 -0
- package/src/daemon/conversation-surfaces.ts +21 -8
- package/src/daemon/conversation.ts +12 -10
- package/src/daemon/lifecycle.ts +6 -2
- package/src/daemon/message-types/conversations.ts +5 -7
- package/src/daemon/provider-rejection-log-fields.ts +124 -0
- package/src/daemon/resource-pressure-guard-lifecycle.ts +66 -0
- package/src/daemon/resource-pressure-guard.ts +387 -0
- package/src/daemon/shutdown-handlers.ts +2 -0
- package/src/daemon/startup-error.ts +16 -0
- package/src/daemon/trust-context.ts +14 -10
- package/src/daemon/unsendable-image-notice.ts +76 -0
- package/src/hooks/registry.ts +65 -51
- package/src/ipc/__tests__/socket-path.test.ts +15 -7
- package/src/ipc/gateway-client.test.ts +1 -1
- package/src/ipc/gateway-client.ts +14 -21
- package/src/ipc/socket-cleanup.ts +2 -11
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -1
- package/src/messaging/provider-message-metadata.ts +128 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +116 -68
- package/src/messaging/providers/channel-transport.ts +90 -13
- package/src/messaging/providers/discord/send.ts +16 -0
- package/src/messaging/providers/discord/transport.ts +11 -1
- package/src/messaging/providers/index.ts +109 -16
- package/src/messaging/providers/slack/message-metadata.ts +45 -0
- package/src/messaging/providers/slack/render-transcript.ts +1 -4
- package/src/messaging/providers/slack/send.test.ts +6 -9
- package/src/messaging/providers/slack/send.ts +40 -28
- package/src/messaging/providers/slack/transport.ts +22 -26
- package/src/messaging/providers/telegram-bot/send.test.ts +2 -8
- package/src/messaging/providers/telegram-bot/transport.ts +3 -6
- package/src/messaging/read-provider-metadata.test.ts +157 -0
- package/src/messaging/read-provider-metadata.ts +51 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +94 -0
- package/src/notifications/__tests__/edit-notification.test.ts +174 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +536 -4
- package/src/notifications/adapters/macos.ts +55 -0
- package/src/notifications/adapters/slack.ts +10 -5
- package/src/notifications/assistant-reply-producer.ts +37 -4
- package/src/notifications/conversation-pairing.ts +111 -21
- package/src/notifications/edit-notification.ts +38 -8
- package/src/notifications/emit-signal.ts +12 -14
- package/src/notifications/home-feed-side-effect.ts +218 -15
- package/src/notifications/types.ts +5 -0
- package/src/permissions/AGENTS.md +16 -0
- package/src/permissions/checker.test.ts +75 -122
- package/src/permissions/checker.ts +44 -560
- package/src/permissions/confirmation-guardian-request.test.ts +28 -3
- package/src/permissions/confirmation-guardian-request.ts +5 -1
- package/src/persistence/conversation-crud.ts +23 -20
- package/src/persistence/conversation-queries.ts +14 -1
- package/src/persistence/conversation-types.ts +22 -0
- package/src/persistence/delivery-crud.ts +122 -15
- package/src/plugin-api/__tests__/import-graph-partial-mock.test.ts +67 -0
- package/src/plugin-api/conversation-turn.ts +27 -0
- package/src/plugin-api/credential-scope.test.ts +15 -0
- package/src/plugin-api/credential-scope.ts +14 -0
- package/src/plugin-api/index.ts +19 -1
- package/src/plugin-api/resolve-credential.ts +15 -10
- package/src/plugin-api/store-credential.ts +148 -0
- package/src/plugin-api/system-card.ts +36 -0
- package/src/plugin-api/vision-support.test.ts +82 -0
- package/src/plugin-api/vision-support.ts +14 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +361 -110
- package/src/plugins/defaults/image-fallback/__tests__/vision-recovery.test.ts +4 -0
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +58 -0
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +64 -23
- package/src/plugins/defaults/image-recovery/detect.ts +24 -1
- package/src/plugins/defaults/main.ts +15 -0
- package/src/plugins/defaults/memory/AGENTS.md +11 -3
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +9 -12
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +114 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
- package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
- package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
- package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
- package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
- package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +1 -61
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +68 -6
- package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
- package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
- package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
- package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
- package/src/plugins/defaults/memory/substrate/static-context.ts +0 -29
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +3 -1
- package/src/plugins/defaults/memory/v3/card.ts +9 -9
- package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
- package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
- package/src/plugins/defaults/memory/v3/edge.ts +13 -57
- package/src/plugins/mtime-cache.ts +1 -1
- package/src/plugins/pipeline.ts +14 -7
- package/src/plugins/plugin-execution-context.ts +35 -11
- package/src/plugins/plugin-tree-walk.ts +63 -4
- package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
- package/src/providers/anthropic/client.ts +332 -241
- package/src/providers/connection-resolution.ts +2 -1
- package/src/providers/content-blocks.ts +22 -0
- package/src/providers/gemini/client.ts +5 -2
- package/src/providers/inference/__tests__/adapter-factory-litellm.test.ts +47 -1
- package/src/providers/inference/__tests__/adapter-factory-ollama.test.ts +83 -0
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +98 -1
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +38 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +10 -0
- package/src/providers/inference/__tests__/connections-ollama.test.ts +90 -0
- package/src/providers/inference/__tests__/missing-credential-guard.test.ts +117 -0
- package/src/providers/inference/adapter-factory.ts +33 -2
- package/src/providers/inference/auth.ts +13 -2
- package/src/providers/inference/credential-usage.ts +37 -0
- package/src/providers/inference/missing-credential-guard.ts +110 -0
- package/src/providers/inference/resolve-auth.ts +7 -7
- package/src/providers/media-resolve.ts +176 -15
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +576 -46
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
- package/src/providers/openai/chat-completions-provider.ts +322 -42
- package/src/routes/route-host-protocol.ts +7 -0
- package/src/routes/worker.ts +31 -10
- package/src/runtime/AGENTS.md +35 -0
- package/src/runtime/__tests__/runtime-http-port-collision.test.ts +131 -0
- package/src/runtime/__tests__/web-presence.test.ts +234 -0
- package/src/runtime/assistant-event-hub.ts +38 -0
- package/src/runtime/channel-reply-delivery.ts +54 -31
- package/src/runtime/channel-retry-sweep.ts +6 -4
- package/src/runtime/effective-capabilities.test.ts +19 -0
- package/src/runtime/effective-capabilities.ts +25 -0
- package/src/runtime/guardian-reply-router.ts +6 -2
- package/src/runtime/http-errors.ts +1 -0
- package/src/runtime/http-server.ts +20 -5
- package/src/runtime/routes/__tests__/client-routes.test.ts +150 -0
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +133 -0
- package/src/runtime/routes/__tests__/credential-delete-in-use.test.ts +155 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +52 -1
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/pending-interactions-route.test.ts +175 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +88 -35
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
- package/src/runtime/routes/__tests__/system-card-turn-termination.test.ts +107 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +75 -4
- package/src/runtime/routes/approval-routes.ts +37 -4
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +16 -22
- package/src/runtime/routes/canned-message-complete.ts +68 -29
- package/src/runtime/routes/client-routes.ts +113 -0
- package/src/runtime/routes/conversation-list-routes.ts +22 -7
- package/src/runtime/routes/conversation-management-routes.ts +15 -9
- package/src/runtime/routes/conversation-routes.ts +36 -22
- package/src/runtime/routes/credential-in-use.ts +85 -0
- package/src/runtime/routes/credential-routes.ts +55 -85
- package/src/runtime/routes/guardian-approval-interception.ts +22 -22
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +14 -12
- package/src/runtime/routes/identity-routes.ts +5 -121
- package/src/runtime/routes/inbound-message-handler.ts +71 -27
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +16 -17
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +77 -50
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -97
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -77
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +17 -8
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -7
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -70
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +9 -7
- package/src/runtime/routes/monitoring-routes.ts +9 -1
- package/src/runtime/routes/plugins-routes.ts +17 -5
- package/src/runtime/routes/resource-pressure-routes.ts +22 -0
- package/src/runtime/routes/secret-routes.ts +39 -8
- package/src/runtime/routes/settings-routes.ts +6 -6
- package/src/runtime/routes/surface-action-routes.ts +20 -19
- package/src/runtime/routes/user-route-dispatcher.ts +31 -2
- package/src/runtime/routes/user-route-resolution.ts +18 -1
- package/src/runtime/slack-reply-session.test.ts +23 -13
- package/src/runtime/slack-reply-session.ts +38 -55
- package/src/runtime/web-presence.ts +90 -0
- package/src/skills/validate-input.ts +177 -40
- package/src/subagent/__tests__/consult-context-gating.test.ts +6 -10
- package/src/subagent/consult-context.ts +7 -23
- package/src/tools/credentials/broker.ts +24 -79
- package/src/tools/credentials/ref-parse.ts +35 -0
- package/src/tools/credentials/resolve.ts +4 -10
- package/src/tools/credentials/store.ts +168 -0
- package/src/tools/credentials/tool-policy.ts +67 -0
- package/src/tools/executor.ts +53 -15
- package/src/tools/network/__tests__/web-search.test.ts +41 -1
- package/src/tools/network/url-safety.ts +9 -16
- package/src/tools/network/web-search.ts +21 -3
- package/src/tools/permission-checker.ts +43 -52
- package/src/tools/schema-transforms.ts +40 -5
- package/src/tools/shared/input-repairs.ts +160 -0
- package/src/tools/skills/skill-tool-factory.ts +18 -4
- package/src/tools/subagent/spawn.ts +0 -1
- package/src/tools/tool-approval-handler.ts +16 -10
- package/src/tools/tool-types.ts +26 -13
- package/src/tools/types.ts +6 -6
- package/src/util/__tests__/cgroup-memory.test.ts +3 -0
- package/src/util/cgroup-memory.ts +3 -0
- package/src/util/container-cpu-sampler.ts +250 -0
- package/src/util/image-conversion.ts +178 -14
- package/src/util/platform.ts +93 -10
- package/src/permissions/ipc-risk-types.ts +0 -143
- package/src/permissions/risk-types.ts +0 -76
|
@@ -76,6 +76,7 @@ import type { Conversation } from "../daemon/conversation.js";
|
|
|
76
76
|
import { readSlackMetadata } from "../messaging/providers/slack/message-metadata.js";
|
|
77
77
|
import { getDb } from "../persistence/db-connection.js";
|
|
78
78
|
import { initializeDb } from "../persistence/db-init.js";
|
|
79
|
+
import { linkMessage, recordInbound } from "../persistence/delivery-crud.js";
|
|
79
80
|
import { messages } from "../persistence/schema/conversations.js";
|
|
80
81
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
81
82
|
import {
|
|
@@ -158,6 +159,29 @@ function buildReactionRequest(
|
|
|
158
159
|
});
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Store the message a reaction will be attached to. A reaction resolves its
|
|
164
|
+
* conversation through this row, so without one there is nothing to annotate.
|
|
165
|
+
*/
|
|
166
|
+
function seedStoredMessage(reactedTs: string): string {
|
|
167
|
+
const event = recordInbound(
|
|
168
|
+
"slack",
|
|
169
|
+
SLACK_CHANNEL_ID,
|
|
170
|
+
`${SLACK_CHANNEL_ID}:${reactedTs}:seed`,
|
|
171
|
+
{ sourceMessageId: reactedTs },
|
|
172
|
+
);
|
|
173
|
+
const db = getDb();
|
|
174
|
+
const messageId = `msg-${reactedTs}`;
|
|
175
|
+
db.$client
|
|
176
|
+
.prepare(
|
|
177
|
+
`INSERT INTO messages (id, conversation_id, role, content, created_at)
|
|
178
|
+
VALUES (?, ?, 'user', '"hello"', ?)`,
|
|
179
|
+
)
|
|
180
|
+
.run(messageId, event.conversationId, Date.now());
|
|
181
|
+
linkMessage(event.eventId, messageId);
|
|
182
|
+
return event.conversationId;
|
|
183
|
+
}
|
|
184
|
+
|
|
161
185
|
function readPersistedMessages(): Array<{
|
|
162
186
|
role: string;
|
|
163
187
|
content: string;
|
|
@@ -257,6 +281,7 @@ describe("Slack reaction event persistence", () => {
|
|
|
257
281
|
});
|
|
258
282
|
|
|
259
283
|
test("reaction:thumbsup is persisted with slackMeta.eventKind=reaction", async () => {
|
|
284
|
+
seedStoredMessage("1700000000.111111");
|
|
260
285
|
let agentDispatched = false;
|
|
261
286
|
const processMessage = async (): Promise<{ messageId: string }> => {
|
|
262
287
|
agentDispatched = true;
|
|
@@ -276,7 +301,9 @@ describe("Slack reaction event persistence", () => {
|
|
|
276
301
|
|
|
277
302
|
expect(agentDispatched).toBe(false);
|
|
278
303
|
|
|
279
|
-
const rows = readPersistedMessages()
|
|
304
|
+
const rows = readPersistedMessages().filter(
|
|
305
|
+
(r) => r.content === "[reaction]",
|
|
306
|
+
);
|
|
280
307
|
expect(rows.length).toBe(1);
|
|
281
308
|
|
|
282
309
|
const row = rows[0];
|
|
@@ -293,7 +320,8 @@ describe("Slack reaction event persistence", () => {
|
|
|
293
320
|
expect(slackMeta!.eventKind).toBe("reaction");
|
|
294
321
|
expect(slackMeta!.channelId).toBe(SLACK_CHANNEL_ID);
|
|
295
322
|
expect(slackMeta!.channelTs).toBe("1700000000.111111");
|
|
296
|
-
|
|
323
|
+
// Slack sends no thread on a reaction, so the row claims none.
|
|
324
|
+
expect(slackMeta!.threadTs).toBeUndefined();
|
|
297
325
|
expect(slackMeta!.displayName).toBe(SLACK_DISPLAY_NAME);
|
|
298
326
|
expect(slackMeta!.reaction).toEqual({
|
|
299
327
|
emoji: "thumbsup",
|
|
@@ -304,11 +332,14 @@ describe("Slack reaction event persistence", () => {
|
|
|
304
332
|
});
|
|
305
333
|
|
|
306
334
|
test("reaction_removed:eyes records op === removed", async () => {
|
|
335
|
+
seedStoredMessage("1700000000.111111");
|
|
307
336
|
const req = buildReactionRequest("reaction_removed:eyes");
|
|
308
337
|
const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
|
|
309
338
|
expect(resp.status).toBe(200);
|
|
310
339
|
|
|
311
|
-
const rows = readPersistedMessages()
|
|
340
|
+
const rows = readPersistedMessages().filter(
|
|
341
|
+
(r) => r.content === "[reaction]",
|
|
342
|
+
);
|
|
312
343
|
expect(rows.length).toBe(1);
|
|
313
344
|
|
|
314
345
|
const envelope = JSON.parse(rows[0].metadata!) as Record<string, unknown>;
|
|
@@ -325,12 +356,35 @@ describe("Slack reaction event persistence", () => {
|
|
|
325
356
|
});
|
|
326
357
|
const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
|
|
327
358
|
expect(resp.status).toBe(200);
|
|
359
|
+
expect(((await resp.json()) as Record<string, unknown>).reaction).toBe(
|
|
360
|
+
"dropped_unknown_target",
|
|
361
|
+
);
|
|
328
362
|
|
|
329
363
|
const rows = readPersistedMessages();
|
|
330
364
|
expect(rows.length).toBe(0);
|
|
331
365
|
});
|
|
332
366
|
|
|
367
|
+
test("a reaction never claims a thread, so it is not thread evidence", async () => {
|
|
368
|
+
// Storing the gateway's fabricated thread id here made the row look like
|
|
369
|
+
// proof that a thread belongs to this conversation.
|
|
370
|
+
seedStoredMessage("1700000000.111111");
|
|
371
|
+
await handleChannelInbound(
|
|
372
|
+
buildReactionRequest("reaction:thumbsup"),
|
|
373
|
+
undefined,
|
|
374
|
+
TEST_BEARER_TOKEN,
|
|
375
|
+
);
|
|
376
|
+
const rows = readPersistedMessages().filter(
|
|
377
|
+
(r) => r.content === "[reaction]",
|
|
378
|
+
);
|
|
379
|
+
const meta = readSlackMetadata(
|
|
380
|
+
(JSON.parse(rows[0].metadata!) as Record<string, unknown>)
|
|
381
|
+
.slackMeta as string,
|
|
382
|
+
);
|
|
383
|
+
expect(meta?.threadTs).toBeUndefined();
|
|
384
|
+
});
|
|
385
|
+
|
|
333
386
|
test("reaction without threadId omits threadTs in metadata", async () => {
|
|
387
|
+
seedStoredMessage("1700000000.222222");
|
|
334
388
|
const req = buildReactionRequest("reaction:wave", {
|
|
335
389
|
sourceMetadata: {
|
|
336
390
|
messageId: "1700000000.222222",
|
|
@@ -340,7 +394,9 @@ describe("Slack reaction event persistence", () => {
|
|
|
340
394
|
const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
|
|
341
395
|
expect(resp.status).toBe(200);
|
|
342
396
|
|
|
343
|
-
const rows = readPersistedMessages()
|
|
397
|
+
const rows = readPersistedMessages().filter(
|
|
398
|
+
(r) => r.content === "[reaction]",
|
|
399
|
+
);
|
|
344
400
|
expect(rows.length).toBe(1);
|
|
345
401
|
|
|
346
402
|
const envelope = JSON.parse(rows[0].metadata!) as Record<string, unknown>;
|
|
@@ -352,6 +408,7 @@ describe("Slack reaction event persistence", () => {
|
|
|
352
408
|
});
|
|
353
409
|
|
|
354
410
|
test("agent loop is never dispatched for reaction events", async () => {
|
|
411
|
+
seedStoredMessage("1700000000.111111");
|
|
355
412
|
let dispatchCount = 0;
|
|
356
413
|
const processMessage = async (): Promise<{ messageId: string }> => {
|
|
357
414
|
dispatchCount++;
|
|
@@ -373,6 +430,7 @@ describe("Slack reaction event persistence", () => {
|
|
|
373
430
|
});
|
|
374
431
|
|
|
375
432
|
test("duplicate reaction events do not double-persist", async () => {
|
|
433
|
+
seedStoredMessage("1700000000.111111");
|
|
376
434
|
const sharedExternalMessageId = `${SLACK_CHANNEL_ID}:1700000000.555555:alice`;
|
|
377
435
|
const makeReq = () =>
|
|
378
436
|
buildReactionRequest("reaction:tada", {
|
|
@@ -395,18 +453,150 @@ describe("Slack reaction event persistence", () => {
|
|
|
395
453
|
const j2 = (await r2.json()) as Record<string, unknown>;
|
|
396
454
|
expect(j2.duplicate).toBe(true);
|
|
397
455
|
|
|
398
|
-
const rows = readPersistedMessages()
|
|
456
|
+
const rows = readPersistedMessages().filter(
|
|
457
|
+
(r) => r.content === "[reaction]",
|
|
458
|
+
);
|
|
399
459
|
expect(rows.length).toBe(1);
|
|
400
460
|
});
|
|
401
461
|
|
|
462
|
+
test("reaction on the assistant's own post lands in that conversation", async () => {
|
|
463
|
+
// An outbound post opens no inbound event, so the only record of its ts
|
|
464
|
+
// is the `slackMeta` on the assistant row. Seeded here the way the
|
|
465
|
+
// outbound reconciler writes it.
|
|
466
|
+
const botTs = "1700000000.999999";
|
|
467
|
+
const conversationId = seedStoredMessage("1700000000.111111");
|
|
468
|
+
const db = getDb();
|
|
469
|
+
db.$client
|
|
470
|
+
.prepare(
|
|
471
|
+
`INSERT INTO messages (id, conversation_id, role, content, created_at, metadata)
|
|
472
|
+
VALUES (?, ?, 'assistant', '"posted"', ?, ?)`,
|
|
473
|
+
)
|
|
474
|
+
.run(
|
|
475
|
+
"msg-bot-post",
|
|
476
|
+
conversationId,
|
|
477
|
+
Date.now(),
|
|
478
|
+
JSON.stringify({
|
|
479
|
+
slackMeta: JSON.stringify({
|
|
480
|
+
source: "slack",
|
|
481
|
+
channelId: SLACK_CHANNEL_ID,
|
|
482
|
+
channelTs: botTs,
|
|
483
|
+
eventKind: "message",
|
|
484
|
+
}),
|
|
485
|
+
}),
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
const resp = await handleChannelInbound(
|
|
489
|
+
buildReactionRequest("reaction:tada", {
|
|
490
|
+
externalMessageId: `${SLACK_CHANNEL_ID}:${botTs}:reactor`,
|
|
491
|
+
sourceMetadata: { messageId: botTs, chatType: "channel" },
|
|
492
|
+
}),
|
|
493
|
+
undefined,
|
|
494
|
+
TEST_BEARER_TOKEN,
|
|
495
|
+
);
|
|
496
|
+
expect(resp.status).toBe(200);
|
|
497
|
+
|
|
498
|
+
const reactionRow = db.$client
|
|
499
|
+
.prepare(
|
|
500
|
+
"SELECT conversation_id AS conversationId FROM messages WHERE content = '[reaction]'",
|
|
501
|
+
)
|
|
502
|
+
.get() as { conversationId: string } | null;
|
|
503
|
+
expect(reactionRow?.conversationId).toBe(conversationId);
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
test("a reaction leaves the reacted message resolvable by its own id", async () => {
|
|
507
|
+
// Two linked rows on one provider id would let a later edit or delete of
|
|
508
|
+
// the message resolve to the reaction instead.
|
|
509
|
+
const reactedTs = "1700000000.111111";
|
|
510
|
+
seedStoredMessage(reactedTs);
|
|
511
|
+
await handleChannelInbound(
|
|
512
|
+
buildReactionRequest("reaction:thumbsup"),
|
|
513
|
+
undefined,
|
|
514
|
+
TEST_BEARER_TOKEN,
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
const db = getDb();
|
|
518
|
+
const claimants = (
|
|
519
|
+
db.$client
|
|
520
|
+
.prepare(
|
|
521
|
+
`SELECT COUNT(*) AS n FROM channel_inbound_events
|
|
522
|
+
WHERE source_message_id = ? AND message_id IS NOT NULL`,
|
|
523
|
+
)
|
|
524
|
+
.get(reactedTs) as { n: number }
|
|
525
|
+
).n;
|
|
526
|
+
expect(claimants).toBe(1);
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
test("reaction on a message the assistant never stored creates no conversation", async () => {
|
|
530
|
+
// The reported bug: Slack sends no `thread_ts` on a reaction, so keying a
|
|
531
|
+
// conversation off the reaction's own address minted one per reacted
|
|
532
|
+
// message, each holding a single "[reaction]" row and a permanent
|
|
533
|
+
// "Generating title..." placeholder.
|
|
534
|
+
const db = getDb();
|
|
535
|
+
const countRows = (table: string): number =>
|
|
536
|
+
(
|
|
537
|
+
db.$client.prepare(`SELECT COUNT(*) AS n FROM ${table}`).get() as {
|
|
538
|
+
n: number;
|
|
539
|
+
}
|
|
540
|
+
).n;
|
|
541
|
+
|
|
542
|
+
const resp = await handleChannelInbound(
|
|
543
|
+
buildReactionRequest("reaction:thumbsup"),
|
|
544
|
+
undefined,
|
|
545
|
+
TEST_BEARER_TOKEN,
|
|
546
|
+
);
|
|
547
|
+
const json = (await resp.json()) as Record<string, unknown>;
|
|
548
|
+
|
|
549
|
+
expect(json.accepted).toBe(true);
|
|
550
|
+
expect(json.reaction).toBe("dropped_unknown_target");
|
|
551
|
+
expect(countRows("conversations")).toBe(0);
|
|
552
|
+
expect(countRows("channel_inbound_events")).toBe(0);
|
|
553
|
+
expect(readPersistedMessages().length).toBe(0);
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
test("reaction lands in the conversation of the reacted message, not a new one", async () => {
|
|
557
|
+
const targetConversationId = seedStoredMessage("1700000000.111111");
|
|
558
|
+
const db = getDb();
|
|
559
|
+
const conversationsBefore = (
|
|
560
|
+
db.$client.prepare("SELECT COUNT(*) AS n FROM conversations").get() as {
|
|
561
|
+
n: number;
|
|
562
|
+
}
|
|
563
|
+
).n;
|
|
564
|
+
|
|
565
|
+
const resp = await handleChannelInbound(
|
|
566
|
+
buildReactionRequest("reaction:thumbsup"),
|
|
567
|
+
undefined,
|
|
568
|
+
TEST_BEARER_TOKEN,
|
|
569
|
+
);
|
|
570
|
+
expect(resp.status).toBe(200);
|
|
571
|
+
|
|
572
|
+
const conversationsAfter = (
|
|
573
|
+
db.$client.prepare("SELECT COUNT(*) AS n FROM conversations").get() as {
|
|
574
|
+
n: number;
|
|
575
|
+
}
|
|
576
|
+
).n;
|
|
577
|
+
expect(conversationsAfter).toBe(conversationsBefore);
|
|
578
|
+
|
|
579
|
+
const reactionRow = db.$client
|
|
580
|
+
.prepare(
|
|
581
|
+
"SELECT conversation_id AS conversationId FROM messages WHERE content = '[reaction]'",
|
|
582
|
+
)
|
|
583
|
+
.get() as { conversationId: string } | null;
|
|
584
|
+
expect(reactionRow?.conversationId).toBe(targetConversationId);
|
|
585
|
+
});
|
|
586
|
+
|
|
402
587
|
test("link to channel_inbound_events is created", async () => {
|
|
588
|
+
seedStoredMessage("1700000000.111111");
|
|
403
589
|
const req = buildReactionRequest("reaction:thumbsup");
|
|
404
590
|
const resp = await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
|
|
405
591
|
const json = (await resp.json()) as Record<string, unknown>;
|
|
406
592
|
const eventId = json.eventId as string;
|
|
407
593
|
|
|
408
594
|
const db = getDb();
|
|
409
|
-
const messageRows = db
|
|
595
|
+
const messageRows = db
|
|
596
|
+
.select()
|
|
597
|
+
.from(messages)
|
|
598
|
+
.all()
|
|
599
|
+
.filter((row) => row.content === "[reaction]");
|
|
410
600
|
expect(messageRows.length).toBe(1);
|
|
411
601
|
|
|
412
602
|
const { channelInboundEvents } =
|
|
@@ -707,6 +897,7 @@ describe("reaction access control (no verification handshake)", () => {
|
|
|
707
897
|
displayName: "Pending Contact",
|
|
708
898
|
});
|
|
709
899
|
|
|
900
|
+
seedStoredMessage("1700000000.111111");
|
|
710
901
|
const req = buildReactionRequest("reaction:tada", {
|
|
711
902
|
actorExternalId: CONTACT_USER_ID,
|
|
712
903
|
actorDisplayName: "Pending Contact",
|
|
@@ -718,7 +909,9 @@ describe("reaction access control (no verification handshake)", () => {
|
|
|
718
909
|
expect(json.denied).not.toBe(true);
|
|
719
910
|
expect(json.reason).not.toBe("verification_challenge_sent");
|
|
720
911
|
|
|
721
|
-
const rows = readPersistedMessages()
|
|
912
|
+
const rows = readPersistedMessages().filter(
|
|
913
|
+
(r) => r.content === "[reaction]",
|
|
914
|
+
);
|
|
722
915
|
expect(rows.length).toBe(1);
|
|
723
916
|
const envelope = JSON.parse(rows[0].metadata!) as Record<string, unknown>;
|
|
724
917
|
const slackMeta = readSlackMetadata(envelope.slackMeta as string);
|
|
@@ -94,12 +94,8 @@ mock.module("../permissions/checker.js", () => ({
|
|
|
94
94
|
}
|
|
95
95
|
return { decision: "allow", reason: "allowed" };
|
|
96
96
|
},
|
|
97
|
-
generateAllowlistOptions: () => [
|
|
98
|
-
{ label: "exact", description: "exact", pattern: "exact" },
|
|
99
|
-
],
|
|
100
97
|
generateScopeOptions: () =>
|
|
101
98
|
scopeOptionsOverride ?? [{ label: "/tmp", scope: "/tmp" }],
|
|
102
|
-
getCachedAssessment: () => undefined,
|
|
103
99
|
}));
|
|
104
100
|
|
|
105
101
|
mock.module("../telemetry/tool-usage-store.js", () => ({
|