@vellumai/assistant 0.9.0 → 0.10.0-dev.202606192226.8ed8a6a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +19 -35
- package/bun.lock +7 -8
- package/docs/activation-funnel-telemetry.md +28 -22
- package/docs/architecture/security.md +29 -28
- package/docs/stt-provider-onboarding.md +3 -5
- package/docs/workflows-testing.md +13 -44
- package/docs/workflows.md +3 -5
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
- package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
- package/openapi.yaml +1128 -119
- package/package.json +2 -1
- package/scripts/sync-llm-catalog.ts +6 -15
- package/scripts/sync-web-search-catalog.ts +3 -11
- package/src/__tests__/access-request-card-view.test.ts +98 -0
- package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
- package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
- package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
- package/src/__tests__/agent-loop-pushes-post-hook-prompt.test.ts +306 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
- package/src/__tests__/app-compiler.test.ts +15 -1
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/approval-cascade.test.ts +6 -0
- package/src/__tests__/approval-routes-http.test.ts +128 -0
- package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
- package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
- package/src/__tests__/avatar-identity-sync.test.ts +2 -27
- package/src/__tests__/btw-routes.test.ts +6 -8
- package/src/__tests__/call-pointer-messages.test.ts +28 -0
- package/src/__tests__/cancel-clears-processing.test.ts +89 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -4
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
- package/src/__tests__/checker.test.ts +0 -3
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
- package/src/__tests__/compaction-events.test.ts +6 -0
- package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
- package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
- package/src/__tests__/config-loader-backfill.test.ts +268 -27
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/config-watcher.test.ts +0 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +0 -6
- package/src/__tests__/contacts-tools.test.ts +29 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +58 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -0
- package/src/__tests__/conversation-lifecycle.test.ts +7 -9
- package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
- package/src/__tests__/conversation-process-callsite.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-queue.test.ts +6 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
- package/src/__tests__/conversation-slash-queue.test.ts +6 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +6 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
- package/src/__tests__/conversation-title-service.test.ts +62 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/credential-broker.test.ts +449 -1
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
- package/src/__tests__/credential-execution-tools.test.ts +0 -1
- package/src/__tests__/credential-prompt-route.test.ts +4 -4
- package/src/__tests__/credential-routes.test.ts +360 -0
- package/src/__tests__/credential-security-invariants.test.ts +4 -13
- package/src/__tests__/disk-pressure-policy.test.ts +12 -0
- package/src/__tests__/disk-pressure-tools.test.ts +41 -1
- package/src/__tests__/disk-usage.test.ts +65 -0
- package/src/__tests__/document-tool-security.test.ts +9 -6
- package/src/__tests__/document-update-default-surface.test.ts +202 -0
- package/src/__tests__/dynamic-page-surface.test.ts +152 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
- package/src/__tests__/gateway-flag-listener.test.ts +110 -1
- package/src/__tests__/gateway-only-guard.test.ts +3 -7
- package/src/__tests__/gemini-count-tokens.test.ts +70 -0
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
- package/src/__tests__/guardian-grant-minting.test.ts +3 -35
- package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/headless-browser-mode.test.ts +10 -0
- package/src/__tests__/headless-browser-navigate.test.ts +8 -3
- package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
- package/src/__tests__/host-browser-proxy.test.ts +87 -0
- package/src/__tests__/identity-routes.test.ts +0 -189
- package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
- package/src/__tests__/injector-disk-pressure.test.ts +10 -5
- package/src/__tests__/injector-v3-suppression.test.ts +27 -20
- package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
- package/src/__tests__/invite-redemption-service.test.ts +4 -7
- package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +30 -23
- package/src/__tests__/llm-resolver.test.ts +70 -24
- package/src/__tests__/llm-schema.test.ts +1 -0
- package/src/__tests__/managed-profile-guard.test.ts +163 -4
- package/src/__tests__/mcp-health-check.test.ts +6 -7
- package/src/__tests__/media-stream-server-integration.test.ts +317 -13
- package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
- package/src/__tests__/onboarding-persona-write.test.ts +1 -1
- package/src/__tests__/path-policy.test.ts +34 -0
- package/src/__tests__/persona-resolver.test.ts +49 -14
- package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
- package/src/__tests__/plugin-api-provider.test.ts +24 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
- package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
- package/src/__tests__/reaction-persistence.test.ts +150 -29
- package/src/__tests__/registry.test.ts +2 -7
- package/src/__tests__/relay-server.test.ts +285 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
- package/src/__tests__/schedule-routes.test.ts +0 -30
- package/src/__tests__/schedule-tools.test.ts +2 -18
- package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
- package/src/__tests__/secret-response-routing.test.ts +35 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +16 -2
- package/src/__tests__/skill-execute-input.test.ts +177 -1
- package/src/__tests__/skill-load-tool.test.ts +72 -0
- package/src/__tests__/skill-runtime-path.test.ts +2 -3
- package/src/__tests__/skills.test.ts +51 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
- package/src/__tests__/subagent-tools.test.ts +266 -0
- package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
- package/src/__tests__/system-storage-cleanup-skill.test.ts +56 -0
- package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +100 -3
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
- package/src/__tests__/token-manager.test.ts +519 -0
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
- package/src/__tests__/tool-audit-listener.test.ts +7 -7
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
- package/src/__tests__/tool-executor.test.ts +0 -79
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
- package/src/__tests__/trusted-contact-verification.test.ts +8 -10
- package/src/__tests__/twilio-routes.test.ts +81 -1
- package/src/__tests__/voice-invite-redemption.test.ts +2 -3
- package/src/__tests__/weak-open-model.test.ts +30 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
- package/src/__tests__/workspace-greetings.test.ts +152 -0
- package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
- package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
- package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
- package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
- package/src/agent/loop.ts +75 -29
- package/src/api/README.md +6 -6
- package/src/api/events/tool-result.ts +6 -0
- package/src/api/events/workflow-completed.ts +53 -0
- package/src/api/events/workflow-leaf-finished.ts +38 -0
- package/src/api/events/workflow-leaf-started.ts +35 -0
- package/src/api/events/workflow-progress.ts +32 -0
- package/src/api/events/workflow-started.ts +31 -0
- package/src/api/index.ts +40 -0
- package/src/api/responses/conversation-message.ts +28 -4
- package/src/api/responses/home.ts +26 -4
- package/src/api/responses/workflow-journal.ts +53 -0
- package/src/approvals/guardian-card-withdrawal.ts +145 -0
- package/src/approvals/guardian-decision-primitive.ts +26 -3
- package/src/approvals/guardian-request-resolvers.ts +183 -80
- package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
- package/src/calls/call-pointer-messages.ts +10 -4
- package/src/calls/channel-admission-reader.ts +104 -0
- package/src/calls/guardian-dispatch.ts +17 -45
- package/src/calls/media-stream-server.ts +84 -2
- package/src/calls/relay-access-wait.ts +1 -1
- package/src/calls/relay-server.ts +66 -0
- package/src/calls/relay-setup-router.ts +82 -1
- package/src/calls/twilio-routes.ts +17 -8
- package/src/calls/voice-session-bridge.ts +2 -2
- package/src/cli/commands/clients.ts +3 -0
- package/src/cli/commands/db/status.ts +37 -3
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
- package/src/cli/commands/memory/index.ts +30 -0
- package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
- package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
- package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
- package/src/cli/commands/oauth/status.test.ts +36 -0
- package/src/cli/commands/oauth/status.ts +23 -3
- package/src/cli/commands/plugins.ts +400 -14
- package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +31 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
- package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -0
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
- package/src/cli/lib/diff-plugin.ts +346 -0
- package/src/cli/lib/inspect-plugin.ts +12 -1
- package/src/cli/lib/install-from-github.ts +128 -19
- package/src/cli/lib/merge-plugin-tree.ts +328 -0
- package/src/cli/lib/plugin-fingerprint.ts +14 -0
- package/src/cli/lib/plugin-marketplace.ts +11 -0
- package/src/cli/lib/plugin-pin-history.ts +257 -0
- package/src/cli/lib/plugin-surfaces.ts +104 -0
- package/src/cli/lib/upgrade-plugin.ts +298 -10
- package/src/cli/program.ts +2 -6
- package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
- package/src/config/assistant-feature-flags.ts +22 -7
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
- package/src/config/bundled-skills/document-editor/SKILL.md +3 -3
- package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
- package/src/config/bundled-skills/messaging/SKILL.md +6 -4
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
- package/src/config/bundled-skills/subagent/SKILL.md +4 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
- package/src/config/bundled-skills/system-storage-cleanup/SKILL.md +74 -0
- package/src/config/bundled-skills/workflows/SKILL.md +14 -8
- package/src/config/bundled-tool-registry.ts +2 -7
- package/src/config/call-site-defaults.ts +15 -2
- package/src/config/feature-flag-registry.json +46 -31
- package/src/config/inference-profile-validation.ts +26 -0
- package/src/config/llm-resolver.ts +3 -0
- package/src/config/loader.ts +4 -0
- package/src/config/memory-v3-gate.ts +11 -0
- package/src/config/profile-order.ts +28 -0
- package/src/config/schema.ts +8 -6
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/channels.ts +11 -0
- package/src/config/schemas/elevenlabs.ts +0 -1
- package/src/config/schemas/llm.ts +31 -0
- package/src/config/schemas/memory-lifecycle.ts +3 -7
- package/src/config/schemas/memory-v3.ts +6 -0
- package/src/config/schemas/platform.ts +0 -8
- package/src/config/schemas/services.ts +18 -0
- package/src/config/seed-inference-profiles.ts +109 -44
- package/src/config/skills.ts +21 -0
- package/src/config/sync-gated-profiles.ts +220 -0
- package/src/contacts/contact-store.ts +89 -106
- package/src/contacts/contacts-write.ts +5 -22
- package/src/contacts/types.ts +0 -1
- package/src/context/compactor.ts +88 -54
- package/src/context/strip-injections.ts +58 -10
- package/src/context/token-estimator.ts +1 -1
- package/src/credential-execution/process-manager.ts +55 -14
- package/src/credential-execution/prompted-credential.ts +2 -3
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +44 -0
- package/src/daemon/config-watcher.ts +0 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
- package/src/daemon/conversation-agent-loop.ts +114 -22
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +3 -5
- package/src/daemon/conversation-process.ts +13 -5
- package/src/daemon/conversation-runtime-assembly.ts +13 -15
- package/src/daemon/conversation-slash.ts +2 -23
- package/src/daemon/conversation-surfaces.ts +26 -0
- package/src/daemon/conversation-tool-setup.ts +53 -19
- package/src/daemon/conversation.ts +131 -20
- package/src/daemon/disk-pressure-policy.ts +5 -3
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
- package/src/daemon/handlers/config-a2a.ts +0 -2
- package/src/daemon/handlers/config-channels.ts +15 -16
- package/src/daemon/handlers/config-slack-channel.ts +22 -3
- package/src/daemon/handlers/conversations.ts +107 -0
- package/src/daemon/host-browser-proxy.ts +41 -0
- package/src/daemon/lifecycle.ts +55 -27
- package/src/daemon/memory-v2-startup.test.ts +131 -0
- package/src/daemon/memory-v2-startup.ts +100 -1
- package/src/daemon/message-provenance.ts +2 -0
- package/src/daemon/message-types/contacts.ts +0 -1
- package/src/daemon/message-types/conversations.ts +3 -3
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/message-types/web-activity.ts +7 -1
- package/src/daemon/message-types/workflows.ts +83 -1
- package/src/daemon/orphan-reaper.test.ts +0 -19
- package/src/daemon/orphan-reaper.ts +2 -24
- package/src/daemon/server.ts +0 -10
- package/src/daemon/tool-setup-types.ts +4 -0
- package/src/daemon/trust-context.ts +1 -1
- package/src/daemon/wake-conversation-ops.ts +1 -0
- package/src/events/tool-audit-listener.ts +2 -2
- package/src/home/feed-source-enrichment.test.ts +151 -0
- package/src/home/feed-source-enrichment.ts +176 -0
- package/src/home/relationship-state.ts +2 -4
- package/src/instrument.ts +18 -6
- package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
- package/src/ipc/assistant-server.ts +37 -4
- package/src/ipc/gateway-flag-listener.ts +18 -2
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
- package/src/memory/__tests__/db-logs-attach.test.ts +122 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
- package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
- package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
- package/src/memory/auth-fallback-events-store.ts +2 -2
- package/src/memory/auto-analysis-enqueue.ts +3 -5
- package/src/memory/bookmark-crud.ts +1 -2
- package/src/memory/canonical-guardian-store.ts +39 -1
- package/src/memory/conversation-crud.ts +9 -4
- package/src/memory/conversation-key-store.ts +17 -2
- package/src/memory/conversation-title-service.ts +64 -7
- package/src/memory/db-async-query.ts +20 -2
- package/src/memory/db-connection.ts +49 -5
- package/src/memory/db-init.ts +17 -17
- package/src/memory/embedding-backend.ts +38 -1
- package/src/memory/embedding-billing-breaker.ts +96 -0
- package/src/memory/jobs-store.ts +25 -13
- package/src/memory/jobs-worker.ts +54 -1
- package/src/memory/lifecycle-events-store.ts +2 -2
- package/src/memory/memory-retrospective-constants.ts +4 -4
- package/src/memory/memory-retrospective-enqueue.ts +31 -6
- package/src/memory/memory-retrospective-job.ts +28 -227
- package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
- package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
- package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
- package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
- package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
- package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
- package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
- package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/run-migrations.ts +41 -0
- package/src/memory/migrations/validate-migration-state.ts +1 -1
- package/src/memory/onboarding-events-store.ts +3 -3
- package/src/memory/schema/contacts.ts +0 -5
- package/src/memory/skill-loaded-events-store.test.ts +7 -15
- package/src/memory/skill-loaded-events-store.ts +2 -2
- package/src/memory/tool-executed-events-store.test.ts +7 -7
- package/src/memory/turn-trace-store.test.ts +736 -0
- package/src/memory/turn-trace-store.ts +364 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
- package/src/memory/v2/consolidation-job.ts +2 -2
- package/src/memory/v2/skill-content.ts +25 -7
- package/src/memory/v2/skill-store.ts +7 -1
- package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
- package/src/memory/v3-eval/eval-packets.ts +546 -0
- package/src/messaging/providers/slack/adapter.ts +1 -1
- package/src/messaging/providers/slack/api.ts +31 -0
- package/src/messaging/providers/slack/send.test.ts +114 -2
- package/src/messaging/providers/slack/send.ts +30 -7
- package/src/messaging/providers/slack/withdraw.test.ts +200 -0
- package/src/messaging/providers/slack/withdraw.ts +161 -0
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/access-request-copy.ts +72 -59
- package/src/notifications/adapters/shared.ts +29 -0
- package/src/notifications/adapters/slack.ts +58 -103
- package/src/notifications/adapters/telegram.ts +2 -20
- package/src/notifications/approval-card-data.ts +333 -0
- package/src/notifications/broadcaster.ts +16 -3
- package/src/notifications/canonical-delivery-recorder.ts +139 -0
- package/src/notifications/copy-composer.ts +3 -3
- package/src/notifications/decision-engine.ts +4 -2
- package/src/notifications/destination-resolver.ts +4 -6
- package/src/notifications/guardian-question-mode.ts +10 -0
- package/src/notifications/home-feed-side-effect.ts +7 -16
- package/src/notifications/notification-utils.ts +19 -20
- package/src/notifications/signal.ts +79 -43
- package/src/notifications/types.ts +98 -121
- package/src/oauth/AGENTS.md +5 -24
- package/src/permissions/checker.test.ts +51 -0
- package/src/permissions/checker.ts +185 -26
- package/src/permissions/ipc-risk-types.ts +24 -0
- package/src/permissions/question-prompter.test.ts +27 -0
- package/src/permissions/question-prompter.ts +4 -0
- package/src/permissions/secret-prompter.ts +15 -1
- package/src/platform/client.test.ts +119 -0
- package/src/platform/client.ts +66 -0
- package/src/platform/consent-cache.test.ts +267 -0
- package/src/platform/consent-cache.ts +174 -0
- package/src/plugin-api/constants.ts +1 -1
- package/src/plugin-api/index.ts +33 -1
- package/src/plugin-api/model-profiles.ts +33 -0
- package/src/plugin-api/types.ts +50 -2
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
- package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
- package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
- package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
- package/src/plugins/defaults/advisor/config.ts +21 -0
- package/src/plugins/defaults/advisor/consult.ts +93 -0
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/advisor/package.json +14 -0
- package/src/plugins/defaults/advisor/steering.ts +67 -0
- package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
- package/src/plugins/defaults/advisor/transcript.ts +76 -0
- package/src/plugins/defaults/compaction/window-manager.ts +18 -0
- package/src/plugins/defaults/index.ts +60 -0
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/injectors.ts +4 -4
- package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
- package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
- package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
- package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
- package/src/prompts/persona-resolver.ts +14 -4
- package/src/prompts/templates/system-sections.ts +7 -2
- package/src/providers/__tests__/count-tokens-forwarding.test.ts +98 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +176 -0
- package/src/providers/anthropic/client.ts +230 -175
- package/src/providers/atlascloud/client.ts +85 -0
- package/src/providers/call-site-routing.ts +10 -0
- package/src/providers/fetch-provider-catalog.ts +85 -0
- package/src/providers/gemini/client.ts +43 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/model-catalog.ts +58 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
- package/src/providers/openai/chat-completions-provider.ts +7 -0
- package/src/providers/openai/responses-provider.ts +10 -0
- package/src/providers/provider-send-message.ts +11 -3
- package/src/providers/ratelimit.ts +9 -0
- package/src/providers/retry.ts +62 -12
- package/src/providers/search-provider-catalog.ts +10 -0
- package/src/providers/types.ts +16 -0
- package/src/providers/usage-tracking.ts +7 -0
- package/src/providers/weak-open-model.ts +22 -0
- package/src/runtime/AGENTS.md +0 -1
- package/src/runtime/__tests__/agent-wake.test.ts +227 -0
- package/src/runtime/__tests__/client-health.test.ts +44 -0
- package/src/runtime/access-request-helper.ts +21 -53
- package/src/runtime/actor-trust-resolver.ts +59 -63
- package/src/runtime/agent-wake.ts +71 -0
- package/src/runtime/assistant-event-hub.ts +18 -4
- package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
- package/src/runtime/auth/require-bound-guardian.ts +1 -4
- package/src/runtime/btw-sidechain.ts +3 -6
- package/src/runtime/capabilities.test.ts +120 -0
- package/src/runtime/capabilities.ts +197 -0
- package/src/runtime/channel-approval-types.ts +22 -45
- package/src/runtime/channel-invite-transports/telegram.ts +4 -4
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/channel-verification-service.ts +3 -3
- package/src/runtime/client-health.ts +26 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
- package/src/runtime/effective-capabilities.test.ts +128 -0
- package/src/runtime/effective-capabilities.ts +84 -0
- package/src/runtime/guardian-reply-router.ts +106 -21
- package/src/runtime/invite-redemption-service.ts +9 -25
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +126 -0
- package/src/runtime/migrations/vbundle-builder.ts +49 -20
- package/src/runtime/pending-interactions.ts +35 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +383 -1
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/approval-routes.ts +40 -9
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
- package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
- package/src/runtime/routes/browser-tabs-routes.ts +9 -0
- package/src/runtime/routes/btw-routes.ts +1 -27
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
- package/src/runtime/routes/client-routes.ts +10 -0
- package/src/runtime/routes/contact-routes.ts +31 -8
- package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
- package/src/runtime/routes/conversation-management-routes.ts +80 -1
- package/src/runtime/routes/conversation-query-routes.ts +68 -22
- package/src/runtime/routes/conversation-routes.ts +39 -14
- package/src/runtime/routes/credential-routes.ts +40 -16
- package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
- package/src/runtime/routes/events-routes.ts +1 -3
- package/src/runtime/routes/guardian-approval-interception.ts +14 -73
- package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
- package/src/runtime/routes/home-feed-routes.ts +8 -3
- package/src/runtime/routes/identity-routes.ts +1 -296
- package/src/runtime/routes/inbound-message-handler.ts +214 -228
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
- package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
- package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
- package/src/runtime/routes/integrations/slack/channel.ts +36 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
- package/src/runtime/routes/mcp-auth-routes.ts +233 -41
- package/src/runtime/routes/memory-eval-routes.ts +87 -0
- package/src/runtime/routes/notification-routes.ts +122 -133
- package/src/runtime/routes/platform-routes.ts +2 -2
- package/src/runtime/routes/plugins-routes.ts +366 -11
- package/src/runtime/routes/schedule-routes.ts +0 -22
- package/src/runtime/routes/secret-routes.ts +15 -0
- package/src/runtime/routes/surface-action-routes.ts +2 -1
- package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
- package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
- package/src/runtime/routes/workflow-routes.test.ts +229 -44
- package/src/runtime/routes/workflow-routes.ts +131 -29
- package/src/runtime/routes/workspace-greetings.ts +55 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -11
- package/src/runtime/tool-grant-request-helper.ts +18 -16
- package/src/runtime/trust-context-resolver.ts +8 -5
- package/src/schedule/inference-profile.ts +2 -14
- package/src/schedule/schedule-store.ts +1 -1
- package/src/schedule/scheduler-types.ts +5 -1
- package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
- package/src/security/secret-patterns.ts +3 -0
- package/src/subagent/manager.ts +17 -4
- package/src/subagent/types.ts +6 -0
- package/src/telemetry/trace-collection-policy.test.ts +28 -0
- package/src/telemetry/trace-collection-policy.ts +30 -0
- package/src/telemetry/types.ts +89 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
- package/src/telemetry/usage-telemetry-reporter.ts +148 -41
- package/src/tools/AGENTS.md +3 -3
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
- package/src/tools/browser/browser-execution.ts +30 -19
- package/src/tools/document/document-tool.ts +30 -6
- package/src/tools/executor.ts +5 -3
- package/src/tools/host-terminal/host-shell.ts +5 -4
- package/src/tools/memory/register.ts +2 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
- package/src/tools/network/__tests__/web-search.test.ts +143 -0
- package/src/tools/network/web-fetch.ts +372 -1
- package/src/tools/network/web-search-error.ts +1 -1
- package/src/tools/network/web-search.ts +213 -10
- package/src/tools/permission-checker.ts +4 -3
- package/src/tools/registry.ts +20 -0
- package/src/tools/schedule/create.ts +7 -12
- package/src/tools/schedule/update.ts +4 -11
- package/src/tools/shared/filesystem/path-policy.ts +39 -13
- package/src/tools/side-effects.ts +2 -17
- package/src/tools/skills/execute.ts +99 -2
- package/src/tools/skills/load.ts +43 -2
- package/src/tools/subagent/spawn.ts +64 -15
- package/src/tools/terminal/shell.ts +10 -4
- package/src/tools/tool-approval-handler.ts +18 -13
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/types.ts +10 -0
- package/src/tools/ui-surface/definitions.ts +64 -3
- package/src/tools/verification-control-plane-policy.ts +3 -1
- package/src/tools/workflows/run-workflow.test.ts +8 -18
- package/src/tools/workflows/run-workflow.ts +1 -0
- package/src/util/disk-usage.ts +78 -23
- package/src/util/logs-db-path.ts +22 -0
- package/src/util/platform.ts +10 -3
- package/src/watcher/telemetry.ts +2 -2
- package/src/workflows/capabilities.ts +2 -3
- package/src/workflows/engine.test.ts +175 -1
- package/src/workflows/engine.ts +82 -0
- package/src/workflows/journal-store.test.ts +70 -0
- package/src/workflows/journal-store.ts +18 -3
- package/src/workflows/run-manager.test.ts +171 -28
- package/src/workflows/run-manager.ts +66 -24
- package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
- package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
- package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
- package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
- package/src/__tests__/credential-security-e2e.test.ts +0 -362
- package/src/__tests__/credential-vault-unit.test.ts +0 -1528
- package/src/__tests__/credential-vault.test.ts +0 -1706
- package/src/__tests__/identity-intro-cache.test.ts +0 -315
- package/src/__tests__/secret-onetime-send.test.ts +0 -182
- package/src/cli/commands/__tests__/task.test.ts +0 -914
- package/src/cli/commands/task.ts +0 -771
- package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
- package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
- package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
- package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
- package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
- package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
- package/src/memory/preloaded-apps.ts +0 -116
- package/src/notifications/tool-approval-copy.ts +0 -142
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
- package/src/runtime/routes/identity-intro-cache.ts +0 -172
- package/src/tools/credentials/vault.ts +0 -712
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RiskLevel } from "../../permissions/types.js";
|
|
2
|
+
import { isUnparseableToolArgs } from "../../providers/unparseable-tool-args.js";
|
|
2
3
|
import { registerTool } from "../registry.js";
|
|
3
4
|
import type {
|
|
4
5
|
ToolContext,
|
|
@@ -9,6 +10,38 @@ import type {
|
|
|
9
10
|
/** Envelope keys consumed by `skill_execute` itself, never inner-tool params. */
|
|
10
11
|
const SKILL_EXECUTE_ENVELOPE_KEYS = new Set(["tool", "input", "activity"]);
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Recover a `skill_execute` envelope that the provider layer wrapped under the
|
|
15
|
+
* `_raw` unparseable marker.
|
|
16
|
+
*
|
|
17
|
+
* MiniMax's object→string argument coercion JSON-decodes the inner `input`
|
|
18
|
+
* value after parsing the outer arguments. When the model passes a bare string
|
|
19
|
+
* as `input` (e.g. Markdown body instead of `{ "content": "..." }`), that inner
|
|
20
|
+
* decode fails and the whole call is marked unparseable — even though the outer
|
|
21
|
+
* envelope is valid JSON. Re-parsing `_raw` recovers `{ tool, input, activity }`
|
|
22
|
+
* so the inner tool can still be dispatched. A genuinely truncated/malformed
|
|
23
|
+
* call's `_raw` won't parse and is returned unchanged, preserving the
|
|
24
|
+
* retryable-error path for real stream corruption.
|
|
25
|
+
*/
|
|
26
|
+
export function recoverSkillExecuteEnvelope(
|
|
27
|
+
envelope: Record<string, unknown>,
|
|
28
|
+
): Record<string, unknown> {
|
|
29
|
+
if (!isUnparseableToolArgs(envelope)) return envelope;
|
|
30
|
+
try {
|
|
31
|
+
const parsed: unknown = JSON.parse(envelope._raw);
|
|
32
|
+
if (
|
|
33
|
+
parsed != null &&
|
|
34
|
+
typeof parsed === "object" &&
|
|
35
|
+
!Array.isArray(parsed)
|
|
36
|
+
) {
|
|
37
|
+
return parsed as Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
// Genuinely malformed/truncated — leave wrapped for the retryable error.
|
|
41
|
+
}
|
|
42
|
+
return envelope;
|
|
43
|
+
}
|
|
44
|
+
|
|
12
45
|
/**
|
|
13
46
|
* Resolve the inner tool's parameters from a `skill_execute` envelope.
|
|
14
47
|
*
|
|
@@ -19,15 +52,20 @@ const SKILL_EXECUTE_ENVELOPE_KEYS = new Set(["tool", "input", "activity"]);
|
|
|
19
52
|
* Weaker models routinely misplace the parameters. Left unhandled, the inner
|
|
20
53
|
* tool receives `{}`, fails schema validation ("<field> is required"), and the
|
|
21
54
|
* model retries the identical malformed call until it gives up — the empty-
|
|
22
|
-
* input retry loop.
|
|
55
|
+
* input retry loop. Three common misplacements are rescued so the call can
|
|
23
56
|
* succeed instead:
|
|
24
57
|
*
|
|
25
58
|
* 1. `input` passed as a JSON-encoded string instead of an object.
|
|
26
59
|
* 2. Parameters spread as top-level siblings of `tool`/`activity`, with `input`
|
|
27
60
|
* absent or an empty object.
|
|
61
|
+
* 3. The sole required field's value passed bare as `input` (a non-JSON string)
|
|
62
|
+
* — e.g. the full Markdown body as `input` instead of `{ "content": "..." }`.
|
|
63
|
+
* Rescued only when `innerSchema` has exactly one required string field, so
|
|
64
|
+
* the mapping is unambiguous.
|
|
28
65
|
*/
|
|
29
66
|
export function resolveSkillExecuteInput(
|
|
30
67
|
envelope: Record<string, unknown>,
|
|
68
|
+
innerSchema?: unknown,
|
|
31
69
|
): Record<string, unknown> {
|
|
32
70
|
const raw = envelope.input;
|
|
33
71
|
|
|
@@ -48,7 +86,14 @@ export function resolveSkillExecuteInput(
|
|
|
48
86
|
return parsed as Record<string, unknown>;
|
|
49
87
|
}
|
|
50
88
|
} catch {
|
|
51
|
-
// Not JSON
|
|
89
|
+
// Not JSON. A weak model may have placed the inner tool's sole required
|
|
90
|
+
// string value directly as `input` (e.g. the full Markdown body as
|
|
91
|
+
// `document_update`'s `content`) instead of a `{ "content": "..." }`
|
|
92
|
+
// object. When the inner tool has exactly one required string field, map
|
|
93
|
+
// the bare string onto it rather than discarding content the model
|
|
94
|
+
// actually produced.
|
|
95
|
+
const field = soleRequiredStringField(innerSchema);
|
|
96
|
+
if (field) return { [field]: raw };
|
|
52
97
|
}
|
|
53
98
|
}
|
|
54
99
|
|
|
@@ -62,6 +107,58 @@ export function resolveSkillExecuteInput(
|
|
|
62
107
|
return {};
|
|
63
108
|
}
|
|
64
109
|
|
|
110
|
+
/**
|
|
111
|
+
* The single required string property of an inner tool's input schema, or
|
|
112
|
+
* `null` when the schema has zero or more than one required field, or its lone
|
|
113
|
+
* required field is not a string. Used to map a bare `input` string onto the
|
|
114
|
+
* one field it can unambiguously belong to.
|
|
115
|
+
*/
|
|
116
|
+
function soleRequiredStringField(innerSchema: unknown): string | null {
|
|
117
|
+
if (innerSchema == null || typeof innerSchema !== "object") return null;
|
|
118
|
+
const schema = innerSchema as {
|
|
119
|
+
required?: unknown;
|
|
120
|
+
properties?: Record<string, { type?: unknown } | undefined>;
|
|
121
|
+
};
|
|
122
|
+
const required = Array.isArray(schema.required) ? schema.required : [];
|
|
123
|
+
if (required.length !== 1) return null;
|
|
124
|
+
const field = required[0];
|
|
125
|
+
if (typeof field !== "string") return null;
|
|
126
|
+
return schema.properties?.[field]?.type === "string" ? field : null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Augment an inner-tool error with `skill_execute` envelope guidance when the
|
|
131
|
+
* call carried no inner parameters.
|
|
132
|
+
*
|
|
133
|
+
* {@link resolveSkillExecuteInput} rescues *misplaced* parameters (siblings, a
|
|
134
|
+
* JSON-encoded string). It cannot rescue a genuinely empty call — there is
|
|
135
|
+
* nothing to relocate — so the inner tool runs with `{}` and rejects it with a
|
|
136
|
+
* field-level message ("<field> is required") that says nothing about the
|
|
137
|
+
* envelope. Weak models then retry the identical empty shape, oscillating over
|
|
138
|
+
* whether parameters belong under `input`, as siblings, or as a JSON string.
|
|
139
|
+
*
|
|
140
|
+
* Appending the canonical envelope shape gives the next attempt a concrete
|
|
141
|
+
* template. Fires only when the resolved inner input was empty AND the tool
|
|
142
|
+
* errored, so well-formed calls and tools that legitimately accept no
|
|
143
|
+
* parameters are untouched.
|
|
144
|
+
*/
|
|
145
|
+
export function augmentSkillExecuteError(
|
|
146
|
+
toolName: string,
|
|
147
|
+
resolvedInput: Record<string, unknown>,
|
|
148
|
+
result: ToolExecutionResult,
|
|
149
|
+
): ToolExecutionResult {
|
|
150
|
+
if (!result.isError || Object.keys(resolvedInput).length > 0) return result;
|
|
151
|
+
|
|
152
|
+
const guidance =
|
|
153
|
+
`\n\nThis skill_execute call carried no parameters for "${toolName}". ` +
|
|
154
|
+
`Put the tool's parameters inside \`input\`. For example: ` +
|
|
155
|
+
`{"tool": "${toolName}", "input": { /* the tool's parameters */ }, ` +
|
|
156
|
+
`"activity": "..."}. The skill's instructions (from skill_load) list ` +
|
|
157
|
+
`"${toolName}"'s required fields.`;
|
|
158
|
+
|
|
159
|
+
return { ...result, content: result.content + guidance };
|
|
160
|
+
}
|
|
161
|
+
|
|
65
162
|
export const skillExecuteTool = {
|
|
66
163
|
name: "skill_execute",
|
|
67
164
|
description:
|
package/src/tools/skills/load.ts
CHANGED
|
@@ -39,6 +39,17 @@ const INLINE_COMMAND_ELIGIBLE_SOURCES = new Set([
|
|
|
39
39
|
"workspace",
|
|
40
40
|
]);
|
|
41
41
|
|
|
42
|
+
/** Matches raw `` !`...` `` inline command tokens in a skill body. */
|
|
43
|
+
const INLINE_COMMAND_TOKEN_PATTERN = /!`[^`]*`/g;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Replacement for inline command tokens when they are not rendered during
|
|
47
|
+
* disk-pressure cleanup mode — keeps the raw tokens out of the prompt without
|
|
48
|
+
* executing any shell.
|
|
49
|
+
*/
|
|
50
|
+
const INLINE_COMMAND_CLEANUP_STUB =
|
|
51
|
+
"[inline command skipped: storage cleanup mode]";
|
|
52
|
+
|
|
42
53
|
const log = getLogger("skill-load");
|
|
43
54
|
|
|
44
55
|
/**
|
|
@@ -159,11 +170,18 @@ export const skillLoadTool = {
|
|
|
159
170
|
};
|
|
160
171
|
}
|
|
161
172
|
|
|
173
|
+
// During disk-pressure cleanup mode, skill_load must not produce side
|
|
174
|
+
// effects: no auto-install (workspace writes / `bun install`) and no inline
|
|
175
|
+
// command execution. Instructions are still returned so the assistant can
|
|
176
|
+
// load the system-storage-cleanup skill (and any already-installed skill).
|
|
177
|
+
const cleanupMode = context.diskPressureCleanupModeActive === true;
|
|
178
|
+
|
|
162
179
|
let loaded = loadSkillBySelector(selector);
|
|
163
180
|
|
|
164
181
|
// Auto-install from catalog if the skill isn't found locally
|
|
165
182
|
if (
|
|
166
183
|
!loaded.skill &&
|
|
184
|
+
!cleanupMode &&
|
|
167
185
|
(loaded.errorCode === "not_found" || loaded.errorCode === "empty_catalog")
|
|
168
186
|
) {
|
|
169
187
|
try {
|
|
@@ -221,6 +239,10 @@ export const skillLoadTool = {
|
|
|
221
239
|
const missing = collectAllMissing(skill.id, catalogIndex);
|
|
222
240
|
if (missing.size === 0) break;
|
|
223
241
|
|
|
242
|
+
// Under the disk-pressure lock, never auto-install missing includes
|
|
243
|
+
// (that writes to the workspace). Leave them advisory ("not loaded").
|
|
244
|
+
if (cleanupMode) break;
|
|
245
|
+
|
|
224
246
|
// Lazily resolve catalog on first round with missing includes
|
|
225
247
|
if (!remoteCatalog) {
|
|
226
248
|
try {
|
|
@@ -289,7 +311,19 @@ export const skillLoadTool = {
|
|
|
289
311
|
const hasInlineCommands =
|
|
290
312
|
skill.inlineCommandExpansions && skill.inlineCommandExpansions.length > 0;
|
|
291
313
|
|
|
292
|
-
if (hasInlineCommands) {
|
|
314
|
+
if (hasInlineCommands && cleanupMode) {
|
|
315
|
+
// Under the disk-pressure lock, loading a skill must not execute shell.
|
|
316
|
+
// Strip inline command tokens instead of rendering them; the rest of the
|
|
317
|
+
// instructions are still returned.
|
|
318
|
+
body = body.replace(
|
|
319
|
+
INLINE_COMMAND_TOKEN_PATTERN,
|
|
320
|
+
INLINE_COMMAND_CLEANUP_STUB,
|
|
321
|
+
);
|
|
322
|
+
log.info(
|
|
323
|
+
{ skillId: skill.id },
|
|
324
|
+
"Skipped inline command expansion during disk pressure cleanup mode",
|
|
325
|
+
);
|
|
326
|
+
} else if (hasInlineCommands) {
|
|
293
327
|
if (skill.source === "extra" || skill.source === "plugin") {
|
|
294
328
|
// Third-party skill roots — `extra` dirs and skills shipped inside
|
|
295
329
|
// installed plugins — are out of scope for inline command expansion.
|
|
@@ -368,7 +402,14 @@ export const skillLoadTool = {
|
|
|
368
402
|
childLoaded.skill.inlineCommandExpansions &&
|
|
369
403
|
childLoaded.skill.inlineCommandExpansions.length > 0;
|
|
370
404
|
|
|
371
|
-
if (childHasInlineCommands) {
|
|
405
|
+
if (childHasInlineCommands && cleanupMode) {
|
|
406
|
+
// No shell execution under the disk-pressure lock — strip the
|
|
407
|
+
// child's inline command tokens rather than rendering them.
|
|
408
|
+
childBody = childBody.replace(
|
|
409
|
+
INLINE_COMMAND_TOKEN_PATTERN,
|
|
410
|
+
INLINE_COMMAND_CLEANUP_STUB,
|
|
411
|
+
);
|
|
412
|
+
} else if (childHasInlineCommands) {
|
|
372
413
|
if (
|
|
373
414
|
childLoaded.skill.source === "extra" ||
|
|
374
415
|
childLoaded.skill.source === "plugin"
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { validateInferenceProfileKey } from "../../config/inference-profile-validation.js";
|
|
2
|
+
import { resolveDefaultProfileKey } from "../../config/llm-resolver.js";
|
|
3
|
+
import { getConfig } from "../../config/loader.js";
|
|
4
|
+
import { AUTO_PROFILE_KEY } from "../../config/seed-inference-profiles.js";
|
|
1
5
|
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
2
6
|
import { getConversationOverrideProfile } from "../../memory/conversation-crud.js";
|
|
3
7
|
import type { Message } from "../../providers/types.js";
|
|
@@ -14,6 +18,7 @@ export async function executeSubagentSpawn(
|
|
|
14
18
|
const extraContext = input.context as string | undefined;
|
|
15
19
|
const fork = input.fork === true;
|
|
16
20
|
const role = (input.role as string | undefined) ?? undefined;
|
|
21
|
+
const inferenceProfile = input.inference_profile;
|
|
17
22
|
|
|
18
23
|
// For fork mode, sendResultToUser defaults to false unless explicitly set to true.
|
|
19
24
|
// For regular mode, sendResultToUser defaults to true (existing behavior).
|
|
@@ -28,6 +33,26 @@ export async function executeSubagentSpawn(
|
|
|
28
33
|
};
|
|
29
34
|
}
|
|
30
35
|
|
|
36
|
+
let requestedOverrideProfile: string | undefined;
|
|
37
|
+
let forceOverrideProfile = false;
|
|
38
|
+
if (inferenceProfile !== undefined) {
|
|
39
|
+
if (typeof inferenceProfile !== "string") {
|
|
40
|
+
return {
|
|
41
|
+
content: "Error: inference_profile must be a string",
|
|
42
|
+
isError: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const profileError = validateInferenceProfileKey(inferenceProfile);
|
|
46
|
+
if (profileError) {
|
|
47
|
+
return {
|
|
48
|
+
content: `Error: ${profileError}`,
|
|
49
|
+
isError: true,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
requestedOverrideProfile = inferenceProfile;
|
|
53
|
+
forceOverrideProfile = true;
|
|
54
|
+
}
|
|
55
|
+
|
|
31
56
|
const manager = getSubagentManager();
|
|
32
57
|
const sendToClient = context.sendToClient as
|
|
33
58
|
| ((msg: { type: string; [key: string]: unknown }) => void)
|
|
@@ -71,22 +96,45 @@ export async function executeSubagentSpawn(
|
|
|
71
96
|
|
|
72
97
|
// The subagent runs as its own background conversation, so the agent
|
|
73
98
|
// loop's background-skip rule would zero out any inherited profile.
|
|
74
|
-
//
|
|
75
|
-
// `SubagentManager.spawn`
|
|
76
|
-
// `
|
|
99
|
+
// Forward the invoker's profile explicitly via `SubagentConfig` so
|
|
100
|
+
// `SubagentManager.spawn` passes it into the subagent's `runAgentLoop` as
|
|
101
|
+
// `options.overrideProfile`.
|
|
77
102
|
//
|
|
78
|
-
//
|
|
79
|
-
// `
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
103
|
+
// Resolution order: an explicit spawn-time profile, then the per-turn
|
|
104
|
+
// `context.overrideProfile` (populated by `runAgentLoopImpl` from its
|
|
105
|
+
// resolved `turnOverrideProfile`, covering per-conversation overrides and
|
|
106
|
+
// tool-routed switches), then a row read, and finally the resolved DEFAULT
|
|
107
|
+
// profile of the call site that invoked us. That last fallback is what makes
|
|
108
|
+
// a subagent match its invoker when the invoking turn ran purely on its
|
|
109
|
+
// call-site default — the workspace `activeProfile` for `mainAgent`, or the
|
|
110
|
+
// call site's own catalog default (e.g. `cost-optimized`) for a
|
|
111
|
+
// heartbeat/background invoker. `resolveDefaultProfileKey` does not reflect a
|
|
112
|
+
// static `llm.callSites.<callSite>` profile override (only the
|
|
113
|
+
// activeProfile-for-mainAgent path plus the catalog default), a narrow gap
|
|
114
|
+
// that only surfaces with no `activeProfile` set and a hand-tuned call-site
|
|
115
|
+
// profile.
|
|
116
|
+
//
|
|
117
|
+
// The fallback is forwarded NON-forced, so an explicit
|
|
118
|
+
// `llm.callSites.subagentSpawn` profile still wins; an explicit
|
|
119
|
+
// `inference_profile` argument keeps `forceOverrideProfile` and wins
|
|
120
|
+
// outright. (The row read short-circuits to `undefined` for the background
|
|
121
|
+
// subagent conversation and for tool calls outside an agent-loop turn.)
|
|
122
|
+
let inheritedOverrideProfile = requestedOverrideProfile;
|
|
123
|
+
if (inheritedOverrideProfile === undefined) {
|
|
124
|
+
const inheritedCandidate =
|
|
125
|
+
context.overrideProfile ??
|
|
126
|
+
getConversationOverrideProfile(context.conversationId) ??
|
|
127
|
+
resolveDefaultProfileKey(
|
|
128
|
+
context.invokingCallSite ?? "mainAgent",
|
|
129
|
+
getConfig().llm,
|
|
130
|
+
);
|
|
131
|
+
// Skip the metadata-only "auto" key: forwarding it collapses the child to
|
|
132
|
+
// `llm.default`, whereas the invoker's own auto base IS the `subagentSpawn`
|
|
133
|
+
// default — so leaving this undefined keeps the child on that default.
|
|
134
|
+
if (inheritedCandidate !== AUTO_PROFILE_KEY) {
|
|
135
|
+
inheritedOverrideProfile = inheritedCandidate;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
90
138
|
|
|
91
139
|
try {
|
|
92
140
|
const subagentId = await manager.spawn(
|
|
@@ -102,6 +150,7 @@ export async function executeSubagentSpawn(
|
|
|
102
150
|
...(inheritedOverrideProfile
|
|
103
151
|
? { overrideProfile: inheritedOverrideProfile }
|
|
104
152
|
: {}),
|
|
153
|
+
...(forceOverrideProfile ? { forceOverrideProfile: true } : {}),
|
|
105
154
|
...(context.toolUseId ? { parentToolUseId: context.toolUseId } : {}),
|
|
106
155
|
...forkFields,
|
|
107
156
|
},
|
|
@@ -4,8 +4,8 @@ import { spawn } from "node:child_process";
|
|
|
4
4
|
import { getConfig } from "../../config/loader.js";
|
|
5
5
|
import { isCesShellLockdownEnabled } from "../../credential-execution/feature-gates.js";
|
|
6
6
|
import { RiskLevel } from "../../permissions/types.js";
|
|
7
|
-
import { isUntrustedTrustClass } from "../../runtime/actor-trust-resolver.js";
|
|
8
7
|
import { wakeAgentForOpportunity } from "../../runtime/agent-wake.js";
|
|
8
|
+
import { isUntrustedShellLockdownActive } from "../../runtime/effective-capabilities.js";
|
|
9
9
|
import { redactSecrets } from "../../security/secret-scanner.js";
|
|
10
10
|
import { getLogger } from "../../util/logger.js";
|
|
11
11
|
import { getDataDir } from "../../util/platform.js";
|
|
@@ -117,9 +117,10 @@ export const shellTool = {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
const config = getConfig();
|
|
120
|
-
const shellLockdownActive =
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
const shellLockdownActive = isUntrustedShellLockdownActive({
|
|
121
|
+
trustClass: context.trustClass,
|
|
122
|
+
lockdownEnabled: isCesShellLockdownEnabled(config),
|
|
123
|
+
});
|
|
123
124
|
|
|
124
125
|
const networkMode: "off" | "proxied" =
|
|
125
126
|
input.network_mode === "proxied" ? "proxied" : "off";
|
|
@@ -307,6 +308,11 @@ export const shellTool = {
|
|
|
307
308
|
|
|
308
309
|
const env = buildSanitizedEnv();
|
|
309
310
|
env.__CONVERSATION_ID = context.conversationId;
|
|
311
|
+
// Surface the resolving model to assistant CLI commands so they can tailor
|
|
312
|
+
// remediation guidance for weak open models (see isWeakOpenModel).
|
|
313
|
+
if (context.attribution?.resolvedModel) {
|
|
314
|
+
env.__RESOLVED_MODEL = context.attribution.resolvedModel;
|
|
315
|
+
}
|
|
310
316
|
if (proxyEnv) {
|
|
311
317
|
Object.assign(env, proxyEnv);
|
|
312
318
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
isUnparseableToolArgs,
|
|
10
10
|
unparseableToolArgsMessage,
|
|
11
11
|
} from "../providers/unparseable-tool-args.js";
|
|
12
|
-
import {
|
|
12
|
+
import { resolveCapabilities } from "../runtime/capabilities.js";
|
|
13
13
|
import { createOrReuseToolGrantRequest } from "../runtime/tool-grant-request-helper.js";
|
|
14
14
|
import { redactSecrets } from "../security/secret-scanner.js";
|
|
15
15
|
import { computeToolApprovalDigest } from "../security/tool-approval-digest.js";
|
|
@@ -157,7 +157,6 @@ const UI_SURFACE_TOOLS = new Set(["ui_show", "ui_update", "ui_dismiss"]);
|
|
|
157
157
|
|
|
158
158
|
function requiresGuardianApprovalForActor(
|
|
159
159
|
toolName: string,
|
|
160
|
-
input: Record<string, unknown>,
|
|
161
160
|
executionTarget: ExecutionTarget,
|
|
162
161
|
): boolean {
|
|
163
162
|
// UI surface tools are passive, user-visible operations (cards, forms,
|
|
@@ -170,14 +169,14 @@ function requiresGuardianApprovalForActor(
|
|
|
170
169
|
// Side-effect tools always require guardian approval for untrusted actors.
|
|
171
170
|
// Read-only host execution is also blocked because it can leak sensitive
|
|
172
171
|
// local information (e.g. shell/file reads).
|
|
173
|
-
return isSideEffectTool(toolName
|
|
172
|
+
return isSideEffectTool(toolName) || executionTarget === "host";
|
|
174
173
|
}
|
|
175
174
|
|
|
176
175
|
function guardianApprovalDeniedMessage(
|
|
177
176
|
trustClass: ToolContext["trustClass"],
|
|
178
177
|
toolName: string,
|
|
179
178
|
): string {
|
|
180
|
-
if (trustClass === "
|
|
179
|
+
if (resolveCapabilities(trustClass).sensitiveToolApproval === "deny") {
|
|
181
180
|
return `Permission denied for "${toolName}": this action requires guardian approval from a verified channel identity.`;
|
|
182
181
|
}
|
|
183
182
|
return `Permission denied for "${toolName}": this action requires guardian approval and the current actor is not the guardian.`;
|
|
@@ -320,11 +319,14 @@ export class ToolApprovalHandler {
|
|
|
320
319
|
|
|
321
320
|
const guardianApprovalRequired = requiresGuardianApprovalForActor(
|
|
322
321
|
name,
|
|
323
|
-
input,
|
|
324
322
|
executionTarget,
|
|
325
323
|
);
|
|
326
324
|
|
|
327
|
-
if (
|
|
325
|
+
if (
|
|
326
|
+
resolveCapabilities(context.trustClass).sensitiveToolApproval !==
|
|
327
|
+
"self" &&
|
|
328
|
+
guardianApprovalRequired
|
|
329
|
+
) {
|
|
328
330
|
const inputDigest = computeToolApprovalDigest(name, input);
|
|
329
331
|
needsGrantConsumption = true;
|
|
330
332
|
deferredConsumeParams = {
|
|
@@ -532,15 +534,18 @@ export class ToolApprovalHandler {
|
|
|
532
534
|
|
|
533
535
|
// No matching grant or race condition - deny or wait inline.
|
|
534
536
|
//
|
|
535
|
-
// For
|
|
536
|
-
// context, escalate to the
|
|
537
|
-
//
|
|
538
|
-
// available - this lets the tool call
|
|
539
|
-
// approval without the requester having
|
|
537
|
+
// For non-guardian actors with established identity (trusted_contact
|
|
538
|
+
// or unverified_contact) and sufficient context, escalate to the
|
|
539
|
+
// guardian by creating a canonical tool_grant_request. Then wait
|
|
540
|
+
// bounded for the grant to become available - this lets the tool call
|
|
541
|
+
// succeed inline after guardian approval without the requester having
|
|
542
|
+
// to retry manually.
|
|
540
543
|
//
|
|
541
|
-
//
|
|
544
|
+
// Actors with no identity (unknown) remain fail-closed with no
|
|
545
|
+
// escalation or wait.
|
|
542
546
|
if (
|
|
543
|
-
context.trustClass ===
|
|
547
|
+
resolveCapabilities(context.trustClass).sensitiveToolApproval ===
|
|
548
|
+
"escalate-and-wait" &&
|
|
544
549
|
context.assistantId &&
|
|
545
550
|
context.executionChannel &&
|
|
546
551
|
context.requesterExternalUserId
|
|
@@ -15,7 +15,6 @@ import { askQuestionTool } from "./ask-question/ask-question-tool.js";
|
|
|
15
15
|
import { makeAuthenticatedRequestTool } from "./credential-execution/make-authenticated-request.js";
|
|
16
16
|
import { manageSecureCommandTool } from "./credential-execution/manage-secure-command-tool.js";
|
|
17
17
|
import { runAuthenticatedCommandTool } from "./credential-execution/run-authenticated-command.js";
|
|
18
|
-
import { credentialStoreTool } from "./credentials/vault.js";
|
|
19
18
|
import { fileEditTool } from "./filesystem/edit.js";
|
|
20
19
|
import { fileListTool } from "./filesystem/list.js";
|
|
21
20
|
import { fileReadTool } from "./filesystem/read.js";
|
|
@@ -90,7 +89,6 @@ export const explicitTools: ToolDefinition[] = [
|
|
|
90
89
|
// Always-explicit tools
|
|
91
90
|
rememberTool,
|
|
92
91
|
recallTool,
|
|
93
|
-
credentialStoreTool,
|
|
94
92
|
notifyParentTool,
|
|
95
93
|
askQuestionTool,
|
|
96
94
|
// NOTE: external skill tools (registered via registerExternalTools in
|
package/src/tools/types.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { RiskLevel } from "@vellumai/skill-host-contracts";
|
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
|
|
15
15
|
import type { InterfaceId } from "../channels/types.js";
|
|
16
|
+
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
16
17
|
import type { ToolActivityMetadata } from "../daemon/message-types/web-activity.js";
|
|
17
18
|
import type { SecretPromptResult } from "../permissions/secret-prompter.js";
|
|
18
19
|
import type { ContentBlock } from "../providers/types.js";
|
|
@@ -25,6 +26,7 @@ export const DISK_PRESSURE_CLEANUP_TOOL_NAMES: ReadonlySet<string> = new Set([
|
|
|
25
26
|
"file_read",
|
|
26
27
|
"file_list",
|
|
27
28
|
"host_file_read",
|
|
29
|
+
"skill_load",
|
|
28
30
|
"background_tool_list",
|
|
29
31
|
"background_tool_cancel",
|
|
30
32
|
]);
|
|
@@ -363,6 +365,14 @@ export interface ToolContext {
|
|
|
363
365
|
* `executeSubagentSpawn` in tools/subagent/spawn.ts.
|
|
364
366
|
*/
|
|
365
367
|
overrideProfile?: string;
|
|
368
|
+
/**
|
|
369
|
+
* The LLM call site of the turn currently executing this tool (`mainAgent`,
|
|
370
|
+
* `heartbeatAgent`, scheduled work, etc.). `subagent_spawn` reads it to
|
|
371
|
+
* default a spawned subagent's inference profile to the profile the invoking
|
|
372
|
+
* turn resolved to, so subagents match whatever agent invoked them rather
|
|
373
|
+
* than always falling back to the static `subagentSpawn` call-site default.
|
|
374
|
+
*/
|
|
375
|
+
invokingCallSite?: LLMCallSite;
|
|
366
376
|
/**
|
|
367
377
|
* Canonical principal ID of the actor on whose behalf this tool invocation
|
|
368
378
|
* is running. Sourced from `conversation.trustContext.guardianPrincipalId`.
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { RiskLevel } from "../../permissions/types.js";
|
|
11
|
+
import { isWeakOpenModel } from "../../providers/weak-open-model.js";
|
|
11
12
|
import { ACTIVATION_MOMENT_PARAMS } from "../../telemetry/activation-funnel.js";
|
|
12
13
|
import type {
|
|
13
14
|
ToolContext,
|
|
@@ -37,8 +38,9 @@ function proxyExecute(toolName: string) {
|
|
|
37
38
|
): Promise<ToolExecutionResult> => {
|
|
38
39
|
if (toolName === "ui_show" && isEmptyDynamicPage(input)) {
|
|
39
40
|
return {
|
|
40
|
-
content:
|
|
41
|
-
|
|
41
|
+
content: isWeakOpenModel(context.attribution?.resolvedModel)
|
|
42
|
+
? EMPTY_DYNAMIC_PAGE_DECLARATIVE_REDIRECT
|
|
43
|
+
: EMPTY_DYNAMIC_PAGE_HTML_HINT,
|
|
42
44
|
isError: true,
|
|
43
45
|
};
|
|
44
46
|
}
|
|
@@ -59,6 +61,14 @@ function proxyExecute(toolName: string) {
|
|
|
59
61
|
};
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
if (toolName === "ui_update" && isEmptyUpdate(input)) {
|
|
65
|
+
return {
|
|
66
|
+
content:
|
|
67
|
+
'Error: ui_update received an empty `data` payload, so the surface was unchanged — the user still sees its previous state. The provided data is merged into the surface\'s current data, and merging nothing is a no-op. To advance a task_progress card, send the full step list: ui_update { surface_id: "<id>", data: { templateData: { steps: [{ label: "<step>", status: "completed" }, { label: "<step>", status: "in_progress" }] } } }. Resend ui_update with the fields you intend to change under `data`.',
|
|
68
|
+
isError: true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
62
72
|
if (!context.proxyToolResolver) {
|
|
63
73
|
return {
|
|
64
74
|
content: `No proxy resolver configured for proxy tool "${toolName}". This tool requires an external resolver (e.g. a connected macOS client).`,
|
|
@@ -81,6 +91,27 @@ function proxyExecute(toolName: string) {
|
|
|
81
91
|
};
|
|
82
92
|
}
|
|
83
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Rejection envelope for an empty `dynamic_page` ui_show from a capable model:
|
|
96
|
+
* the surface carried no `data.html`, so it would render as a blank box. These
|
|
97
|
+
* models reliably author HTML, so the fix is simply to resend it inline.
|
|
98
|
+
*/
|
|
99
|
+
const EMPTY_DYNAMIC_PAGE_HTML_HINT =
|
|
100
|
+
"Error: ui_show dynamic_page requires non-empty HTML in `data.html`. The surface was not displayed because no content was provided — the user would see a blank box. Resend ui_show with the full HTML markup in `data.html`.";
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Rejection envelope for an empty `dynamic_page` ui_show from a weak open model.
|
|
104
|
+
* Authoring full HTML inline is the generation task these models fail at (an
|
|
105
|
+
* empty `data: {}` here, or broken markup otherwise), so steering them to
|
|
106
|
+
* "resend the HTML" just repeats the failure. Most widget requests are really
|
|
107
|
+
* structured data — comparisons, results, metrics — which render reliably via a
|
|
108
|
+
* field-based surface the model populates without writing any HTML, and which
|
|
109
|
+
* cannot render blank. dynamic_page stays available for genuinely custom visual
|
|
110
|
+
* HTML.
|
|
111
|
+
*/
|
|
112
|
+
const EMPTY_DYNAMIC_PAGE_DECLARATIVE_REDIRECT =
|
|
113
|
+
'Error: ui_show dynamic_page was not displayed — `data.html` was empty, so the user would see a blank box. Authoring full HTML inline is error-prone; for data, comparisons, results, or metrics prefer a structured surface, which you fill with fields (no HTML) and which never renders blank. Re-show the content as one of: a `table` (ui_show { surface_type: "table", data: { columns: [{ id, label }], rows: [{ id, cells: { <columnId>: "<value>" } }] } }), a `card` ({ title, body, metadata: [{ label, value }] }), or `work_result` ({ summary, metrics: [{ label, value }] }). Only use dynamic_page when you genuinely need custom visual HTML, in which case include the complete markup in `data.html` now.';
|
|
114
|
+
|
|
84
115
|
/**
|
|
85
116
|
* Worked ui_update example, appended to a successful task_progress `ui_show`
|
|
86
117
|
* result so the model learns the update pattern at the point of use (with the
|
|
@@ -98,6 +129,36 @@ function isTaskProgressCardShow(input: Record<string, unknown>): boolean {
|
|
|
98
129
|
return data?.template === "task_progress";
|
|
99
130
|
}
|
|
100
131
|
|
|
132
|
+
/**
|
|
133
|
+
* A `ui_update` whose `data` merge would change nothing: missing, not an
|
|
134
|
+
* object, or containing only (recursively) empty objects. Merging such a
|
|
135
|
+
* payload is a silent no-op — the surface keeps its prior state while the
|
|
136
|
+
* client still reports "Surface updated" — so the model never learns its
|
|
137
|
+
* update was hollow and a live card (e.g. task_progress) appears frozen.
|
|
138
|
+
* Arrays (e.g. `templateData.steps`) and any non-empty primitive leaf count
|
|
139
|
+
* as content.
|
|
140
|
+
*/
|
|
141
|
+
function isEmptyUpdate(input: Record<string, unknown>): boolean {
|
|
142
|
+
const data = asRecord(input.data);
|
|
143
|
+
return data === null || !hasContent(data);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function hasContent(value: unknown): boolean {
|
|
147
|
+
if (value === null || value === undefined) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
if (Array.isArray(value)) {
|
|
151
|
+
return value.length > 0;
|
|
152
|
+
}
|
|
153
|
+
if (typeof value === "object") {
|
|
154
|
+
return Object.values(value).some(hasContent);
|
|
155
|
+
}
|
|
156
|
+
if (typeof value === "string") {
|
|
157
|
+
return value.trim().length > 0;
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
|
|
101
162
|
function isEmptyDynamicPage(input: Record<string, unknown>): boolean {
|
|
102
163
|
if (input.surface_type !== "dynamic_page") {
|
|
103
164
|
return false;
|
|
@@ -311,7 +372,7 @@ export const uiShowTool = {
|
|
|
311
372
|
// ui_update
|
|
312
373
|
// ---------------------------------------------------------------------------
|
|
313
374
|
|
|
314
|
-
const uiUpdateTool = {
|
|
375
|
+
export const uiUpdateTool = {
|
|
315
376
|
name: "ui_update",
|
|
316
377
|
description:
|
|
317
378
|
"Update an existing surface's data. The provided data object is merged into the surface's current data.\n" +
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* /v1/channel-verification-sessions/revoke
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { resolveCapabilities } from "../runtime/capabilities.js";
|
|
14
|
+
|
|
13
15
|
const VERIFICATION_ENDPOINT_PATHS = [
|
|
14
16
|
"/v1/channel-verification-sessions",
|
|
15
17
|
"/v1/channel-verification-sessions/resend",
|
|
@@ -128,7 +130,7 @@ export function enforceVerificationControlPlanePolicy(
|
|
|
128
130
|
return { denied: false };
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
if (trustClass
|
|
133
|
+
if (resolveCapabilities(trustClass).canUseVerificationControlPlane) {
|
|
132
134
|
return { denied: false };
|
|
133
135
|
}
|
|
134
136
|
|