@vellumai/assistant 0.11.6 → 0.11.7-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/ARCHITECTURE.md +31 -19
- package/Dockerfile +1 -0
- package/docs/architecture/security.md +3 -3
- package/docs/flux-turn-detection-spike.md +8 -7
- package/docs/runbook-trusted-contacts.md +14 -0
- package/docs/stt-provider-onboarding.md +8 -4
- package/knip.json +1 -0
- package/node_modules/@vellumai/avatar-manifest/package.json +18 -0
- package/node_modules/@vellumai/avatar-manifest/src/__tests__/manifest.test.ts +173 -0
- package/node_modules/@vellumai/avatar-manifest/src/__tests__/read.test.ts +114 -0
- package/node_modules/@vellumai/avatar-manifest/src/index.ts +29 -0
- package/node_modules/@vellumai/avatar-manifest/src/layout.ts +18 -0
- package/node_modules/@vellumai/avatar-manifest/src/manifest.ts +156 -0
- package/node_modules/@vellumai/avatar-manifest/src/read.ts +109 -0
- package/node_modules/@vellumai/avatar-manifest/tsconfig.json +20 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/node_modules/@vellumai/ces-client/src/http-credentials.ts +161 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/shell.test.ts +56 -0
- package/node_modules/@vellumai/environments/src/shell.ts +65 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +32 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +82 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/plugin-admission-denied-contract.test.ts +56 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +18 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +5 -11
- package/node_modules/@vellumai/gateway-client/src/channel-permission-contract.ts +3 -1
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +9 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +75 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +17 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +8 -0
- package/node_modules/@vellumai/gateway-client/src/plugin-admission-denied-contract.ts +47 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +11 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +37 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/remote-web-pairing.test.ts +389 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +22 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +508 -18
- package/node_modules/@vellumai/service-contracts/src/rpc.ts +174 -0
- package/openapi.yaml +419 -55
- package/package.json +4 -1
- package/scripts/sync-llm-catalog.ts +6 -0
- package/src/__tests__/approval-card-edit-inbound-handoff.test.ts +199 -0
- package/src/__tests__/approval-card-edit.test.ts +153 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +1 -1
- package/src/__tests__/available-skills.test.ts +54 -0
- package/src/__tests__/avatar-identity-sync.test.ts +5 -1
- package/src/__tests__/catalog-install-normalize.test.ts +9 -1
- package/src/__tests__/channel-policy.test.ts +1 -3
- package/src/__tests__/channel-readiness-discord.test.ts +9 -70
- package/src/__tests__/compactor-call-site-logging.test.ts +61 -0
- package/src/__tests__/config-loader-backfill.test.ts +69 -0
- package/src/__tests__/config-schema.test.ts +2 -3
- package/src/__tests__/conversation-agent-loop.test.ts +238 -0
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-error.test.ts +44 -0
- package/src/__tests__/conversation-evictor.test.ts +19 -0
- package/src/__tests__/conversation-fork-referential.test.ts +73 -63
- package/src/__tests__/conversation-fork-retrospective.test.ts +99 -74
- package/src/__tests__/conversation-runtime-assembly.test.ts +23 -0
- package/src/__tests__/conversation-slash.test.ts +9 -0
- package/src/__tests__/conversation-title-service.test.ts +97 -0
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +16 -0
- package/src/__tests__/credential-broker-server-use.test.ts +0 -218
- package/src/__tests__/credential-broker.test.ts +43 -420
- package/src/__tests__/credential-record-write-through.test.ts +78 -0
- package/src/__tests__/credential-routes.test.ts +17 -1
- package/src/__tests__/credential-security-invariants.test.ts +8 -9
- package/src/__tests__/default-profile-catalog-fallback.test.ts +289 -0
- package/src/__tests__/delete-propagation.test.ts +92 -2
- package/src/__tests__/discord-callback-round-trip.test.ts +93 -0
- package/src/__tests__/discord-channel-config.test.ts +237 -0
- package/src/__tests__/edit-propagation.test.ts +42 -2
- package/src/__tests__/evict-conversations-for-reload.test.ts +51 -1
- package/src/__tests__/fallback-breaker.test.ts +1335 -0
- package/src/__tests__/gateway-threshold-reader-mock.ts +6 -0
- package/src/__tests__/guardian-card-withdrawal.test.ts +30 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -2
- package/src/__tests__/image-conversion.test.ts +38 -4
- package/src/__tests__/install-skill-routing.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +4 -0
- package/src/__tests__/llm-resolver.test.ts +74 -0
- package/src/__tests__/llm-schema-fallback-profile.test.ts +359 -0
- package/src/__tests__/managed-fallback-dispatch.test.ts +430 -0
- package/src/__tests__/managed-profile-guard.test.ts +28 -0
- package/src/__tests__/managed-speech-defaults.test.ts +196 -1
- package/src/__tests__/mcp-cli.test.ts +23 -1
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +43 -34
- package/src/__tests__/media-stream-stt-session.test.ts +2 -0
- package/src/__tests__/notification-decision-fallback.test.ts +106 -0
- package/src/__tests__/notification-discord-adapter.test.ts +162 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +95 -0
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +6 -8
- package/src/__tests__/persist-unsendable-image.test.ts +3 -3
- package/src/__tests__/platform.test.ts +19 -1
- package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
- package/src/__tests__/provider-catalog-visibility.test.ts +17 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +8 -1
- package/src/__tests__/provider-usage-tracking.test.ts +56 -0
- package/src/__tests__/require-fresh-approval.test.ts +5 -2
- package/src/__tests__/retry-fallback-escalation.test.ts +1093 -0
- package/src/__tests__/schedule-retry.test.ts +183 -4
- package/src/__tests__/scheduler-reuse-conversation.test.ts +6 -6
- package/src/__tests__/secret-routes-platform-proxy.test.ts +55 -0
- package/src/__tests__/skill-load-tool.test.ts +34 -0
- package/src/__tests__/skill-tool-factory.test.ts +6 -1
- package/src/__tests__/skill-tool-manifest.test.ts +20 -0
- package/src/__tests__/skills.test.ts +25 -0
- package/src/__tests__/subagent-manager-notify.test.ts +38 -0
- package/src/__tests__/terminal-tools.test.ts +2 -0
- package/src/__tests__/tool-approval-handler.test.ts +146 -2
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +108 -2
- package/src/__tests__/tool-audit.test.ts +111 -40
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +228 -18
- package/src/__tests__/ui-shape-teaching.test.ts +1 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +6 -2
- package/src/__tests__/voice-config-update.test.ts +43 -0
- package/src/__tests__/workspace-migration-147-rename-colliding-backup-profile-names.test.ts +480 -0
- package/src/__tests__/workspace-migration-148-strip-unsupported-fallback-profiles.test.ts +167 -0
- package/src/__tests__/workspace-migration-149-repoint-backup-profile-selections.test.ts +144 -0
- package/src/agent/loop.ts +31 -2
- package/src/approvals/guardian-card-withdrawal.ts +22 -0
- package/src/avatar/__tests__/ensure-raster.test.ts +291 -0
- package/src/avatar/avatar-manifest.ts +48 -100
- package/src/avatar/avatar-store.ts +7 -7
- package/src/avatar/ensure-raster.ts +146 -0
- package/src/avatar/resvg-lazy.test.ts +0 -1
- package/src/avatar/traits-png-sync.ts +9 -10
- package/src/background-wake/wake-intent-hooks.test.ts +0 -1
- package/src/backup/__tests__/paths.test.ts +6 -2
- package/src/backup/paths.ts +6 -4
- package/src/bundler/app-compiler.ts +2 -2
- package/src/bundler/compiler-tools.test.ts +36 -0
- package/src/bundler/compiler-tools.ts +54 -18
- package/src/calls/__tests__/telephony-synthesis-language.test.ts +81 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +57 -0
- package/src/calls/media-stream-stt-session.ts +2 -1
- package/src/calls/telephony-synthesis-language.ts +13 -5
- package/src/calls/voice-session-bridge.ts +19 -4
- package/src/channels/config.ts +23 -12
- package/src/cli/AGENTS.md +3 -1
- package/src/cli/commands/backup.help.ts +10 -13
- package/src/cli/commands/contacts.help.ts +16 -4
- package/src/cli/commands/contacts.ts +5 -1
- package/src/cli/commands/credentials.help.ts +1 -1
- package/src/cli/commands/inference-providers.ts +18 -53
- package/src/cli/commands/mcp.help.ts +6 -5
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/memory/memory-retrospective.ts +1 -0
- package/src/cli/commands/stt.help.ts +2 -2
- package/src/config/__tests__/backup-schema.test.ts +1 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +83 -2
- package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +1 -1
- package/src/config/__tests__/memory-retrospective-schema.test.ts +12 -15
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +9 -6
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +3 -1
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +16 -15
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +2 -1
- package/src/config/bundled-skills/settings/TOOLS.json +11 -5
- package/src/config/bundled-skills/settings/tools/open-system-settings.test.ts +85 -0
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +33 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +54 -3
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +1 -1
- package/src/config/default-profile-catalog.ts +195 -10
- package/src/config/default-profile-names.ts +41 -0
- package/src/config/feature-flag-registry.json +34 -2
- package/src/config/inference-profile-validation.ts +11 -2
- package/src/config/llm-resolver.ts +25 -0
- package/src/config/loader.ts +3 -0
- package/src/config/managed-speech-defaults.ts +160 -10
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/live-voice.test.ts +7 -6
- package/src/config/schemas/__tests__/stt.test.ts +94 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/channels.ts +32 -0
- package/src/config/schemas/live-voice.ts +13 -4
- package/src/config/schemas/llm.ts +263 -15
- package/src/config/schemas/mcp.ts +10 -2
- package/src/config/schemas/memory-retrospective.ts +1 -19
- package/src/config/schemas/services.ts +24 -0
- package/src/config/schemas/stt.ts +128 -5
- package/src/config/seed-inference-profiles.ts +32 -3
- package/src/config/skill-state.ts +5 -0
- package/src/config/skills.ts +21 -0
- package/src/contacts/notify-contacts-changed.ts +5 -2
- package/src/context/compactor.ts +74 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +138 -1
- package/src/daemon/config-watcher.ts +2 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +27 -0
- package/src/daemon/conversation-agent-loop.ts +86 -10
- package/src/daemon/conversation-error.ts +25 -0
- package/src/daemon/conversation-evictor.ts +2 -4
- package/src/daemon/conversation-runtime-assembly.ts +19 -7
- package/src/daemon/conversation-skill-tools.ts +5 -1
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-store.ts +8 -1
- package/src/daemon/conversation-tool-setup.ts +37 -0
- package/src/daemon/conversation.ts +0 -4
- package/src/daemon/handlers/channel-config-result.ts +30 -0
- package/src/daemon/handlers/config-discord-channel.ts +301 -0
- package/src/daemon/handlers/config-ingress.ts +9 -0
- package/src/daemon/handlers/config-slack-channel.ts +13 -15
- package/src/daemon/handlers/config-telegram.ts +2 -5
- package/src/daemon/handlers/conversations.ts +0 -2
- package/src/daemon/handlers/skills.ts +25 -7
- package/src/daemon/lifecycle.ts +3 -1
- package/src/daemon/message-types/messages.ts +0 -2
- package/src/daemon/tool-setup-types.ts +5 -3
- package/src/daemon/trust-context-types.test.ts +33 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +58 -4
- package/src/live-voice/__tests__/live-voice-managed-speech-fallback.test.ts +8 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +73 -11
- package/src/live-voice/__tests__/live-voice-session-preflight.test.ts +148 -2
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +64 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-text-turn.test.ts +391 -0
- package/src/live-voice/__tests__/protocol.test.ts +224 -0
- package/src/live-voice/live-voice-credential-preflight.ts +5 -1
- package/src/live-voice/live-voice-session-manager.ts +39 -2
- package/src/live-voice/live-voice-session.ts +224 -9
- package/src/live-voice/protocol.ts +187 -1
- package/src/messaging/providers/discord/api.ts +2 -1
- package/src/messaging/providers/discord/withdraw.ts +62 -0
- package/src/messaging/read-provider-metadata.ts +32 -0
- package/src/monitoring/__tests__/file-descriptors.test.ts +32 -0
- package/src/monitoring/__tests__/process-memory.test.ts +34 -1
- package/src/monitoring/db-integrity-sample.ts +1 -0
- package/src/monitoring/file-descriptors.ts +39 -6
- package/src/monitoring/process-memory.ts +37 -5
- package/src/monitoring/resource-sampler.ts +25 -8
- package/src/notifications/__tests__/activity-failed-dedupe.test.ts +161 -0
- package/src/notifications/__tests__/background-failure-signal.test.ts +107 -0
- package/src/notifications/__tests__/connected-channels.test.ts +12 -0
- package/src/notifications/__tests__/copy-composer.test.ts +83 -0
- package/src/notifications/__tests__/destination-resolver.test.ts +38 -0
- package/src/notifications/activity-failed-dedupe.ts +95 -0
- package/src/notifications/adapters/discord.ts +132 -0
- package/src/notifications/adapters/shared.ts +16 -0
- package/src/notifications/adapters/slack.ts +6 -1
- package/src/notifications/adapters/telegram.ts +5 -8
- package/src/notifications/approval-card-data.ts +94 -1
- package/src/notifications/background-failure-signal.ts +116 -0
- package/src/notifications/broadcaster.ts +3 -9
- package/src/notifications/copy-composer.ts +41 -8
- package/src/notifications/decision-engine.ts +55 -0
- package/src/notifications/destination-resolver.ts +45 -5
- package/src/notifications/emit-signal.ts +19 -5
- package/src/notifications/guardian-question-mode.ts +57 -0
- package/src/notifications/types.ts +2 -8
- package/src/oauth/__tests__/seed-providers-managed.test.ts +18 -0
- package/src/oauth/connect-orchestrator.ts +16 -0
- package/src/oauth/seed-providers.ts +262 -0
- package/src/permissions/checker.test.ts +21 -0
- package/src/permissions/checker.ts +6 -0
- package/src/permissions/gateway-threshold-reader.test.ts +184 -0
- package/src/permissions/gateway-threshold-reader.ts +144 -10
- package/src/permissions/prompter.ts +0 -6
- package/src/permissions/types.ts +5 -4
- package/src/persistence/__tests__/bulk-write-gate.test.ts +0 -38
- package/src/persistence/bulk-write-gate.ts +9 -10
- package/src/persistence/conversation-crud.ts +88 -134
- package/src/persistence/conversation-title-service.ts +43 -29
- package/src/persistence/embeddings/embedding-local.ts +14 -85
- package/src/persistence/embeddings/embedding-runtime-manager.ts +1 -0
- package/src/persistence/lifecycle-events-store.test.ts +50 -0
- package/src/persistence/lifecycle-events-store.ts +75 -5
- package/src/platform/platform-patch-queue.test.ts +368 -0
- package/src/platform/platform-patch-queue.ts +190 -0
- package/src/platform/sync-avatar.test.ts +527 -0
- package/src/platform/sync-avatar.ts +209 -0
- package/src/platform/sync-identity.test.ts +75 -0
- package/src/platform/sync-identity.ts +17 -110
- package/src/plugin-api/model-profiles.test.ts +2 -2
- package/src/plugin-api/model-profiles.ts +7 -7
- package/src/plugin-api/transcription-session.ts +1 -1
- package/src/plugins/defaults/compaction/window-manager.ts +4 -0
- package/src/plugins/defaults/image-recovery/recover.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +133 -34
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +21 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +13 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +31 -4
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +0 -11
- package/src/plugins/defaults/memory/memory-retrospective-fork-boundary.ts +27 -13
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +183 -113
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +13 -13
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +2 -2
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +1 -1
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +4 -2
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +9 -42
- package/src/plugins/defaults/memory/v2/rerank-local.ts +1 -0
- package/src/plugins/defaults/memory/worker.ts +7 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +55 -0
- package/src/providers/__tests__/vellum-connection-routing.test.ts +21 -3
- package/src/providers/connection-resolution.ts +2 -17
- package/src/providers/fallback-breaker.ts +389 -0
- package/src/providers/inference/__tests__/adapter-factory-opencode.test.ts +92 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +16 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +12 -0
- package/src/providers/inference/adapter-factory.ts +246 -3
- package/src/providers/inference/auth.ts +15 -14
- package/src/providers/inference/chatgpt-subscription-auth.ts +70 -0
- package/src/providers/inference/chatgpt-subscription-credentials.ts +84 -0
- package/src/providers/inference/resolve-auth.ts +1 -1
- package/src/providers/media-resolve.ts +2 -3
- package/src/providers/model-catalog.ts +100 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +22 -0
- package/src/providers/openai/__tests__/chat-template-flatten.test.ts +198 -0
- package/src/providers/openai/api-error-normalization.ts +13 -0
- package/src/providers/openai/chat-completions-provider.ts +84 -0
- package/src/providers/opencode/client.test.ts +150 -0
- package/src/providers/opencode/client.ts +61 -0
- package/src/providers/platform-proxy/constants.ts +5 -0
- package/src/providers/provider-resolvability.ts +20 -0
- package/src/providers/provider-secret-catalog.ts +3 -2
- package/src/providers/retry.ts +956 -68
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +42 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +136 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +120 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +316 -12
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +83 -3
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +132 -4
- package/src/providers/speech-to-text/provider-catalog.ts +191 -3
- package/src/providers/speech-to-text/resolve.ts +132 -24
- package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +296 -0
- package/src/providers/types.ts +39 -0
- package/src/providers/usage-tracking.ts +12 -1
- package/src/providers/vellum/client.ts +29 -0
- package/src/providers/vellum-model-routing.test.ts +2 -0
- package/src/providers/vellum-model-routing.ts +3 -3
- package/src/runtime/AGENTS.md +1 -2
- package/src/runtime/__tests__/agent-wake.test.ts +105 -3
- package/src/runtime/__tests__/background-job-runner.test.ts +89 -3
- package/src/runtime/agent-wake.ts +44 -5
- package/src/runtime/background-job-runner.ts +68 -50
- package/src/runtime/channel-readiness-service.ts +0 -39
- package/src/runtime/http-server.ts +12 -4
- package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +18 -18
- package/src/runtime/routes/__tests__/backup-routes.test.ts +9 -5
- package/src/runtime/routes/__tests__/chatgpt-subscription-auth-routes.test.ts +372 -0
- package/src/runtime/routes/__tests__/contact-routes.test.ts +7 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +96 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +37 -0
- package/src/runtime/routes/__tests__/ingress-status-routes.test.ts +2 -1
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +87 -0
- package/src/runtime/routes/acp-claude-auth-routes.ts +25 -54
- package/src/runtime/routes/approval-routes.ts +0 -12
- package/src/runtime/routes/avatar-routes.ts +17 -30
- package/src/runtime/routes/backup-routes.ts +2 -2
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +296 -113
- package/src/runtime/routes/contact-prompt-routes.ts +65 -6
- package/src/runtime/routes/contact-routes.ts +20 -15
- package/src/runtime/routes/conversation-query-routes.ts +98 -10
- package/src/runtime/routes/conversation-routes.ts +2 -2
- package/src/runtime/routes/credential-routes.ts +2 -1
- package/src/runtime/routes/guardian-approval-interception.ts +12 -9
- package/src/runtime/routes/inbound-message-handler.ts +47 -48
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +18 -13
- package/src/runtime/routes/inbound-stages/admission-policy.ts +2 -2
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +20 -2
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +9 -8
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +2 -2
- package/src/runtime/routes/inference-profiles-routes.ts +12 -7
- package/src/runtime/routes/inference-provider-connection-routes.ts +2 -2
- package/src/runtime/routes/inference-send-routes.ts +2 -2
- package/src/runtime/routes/ingress-status-routes.ts +2 -2
- package/src/runtime/routes/integrations/discord.ts +119 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +2 -2
- package/src/runtime/routes/mcp-auth-routes.ts +12 -6
- package/src/runtime/routes/migration-routes.ts +3 -1
- package/src/runtime/routes/oauth-pending-flows.ts +136 -0
- package/src/runtime/routes/secret-routes.ts +7 -0
- package/src/runtime/routes/stt-routes.ts +38 -6
- package/src/runtime/routes/wake-conversation-routes.ts +8 -1
- package/src/runtime/routes/watch-routes.ts +9 -5
- package/src/runtime/sync/resource-sync-events.ts +2 -0
- package/src/runtime/trust-verdict-consumer.ts +3 -3
- package/src/schedule/__tests__/worker-feature-flags.test.ts +58 -0
- package/src/schedule/retry-policy.ts +8 -8
- package/src/schedule/run-script.ts +14 -23
- package/src/schedule/schedule-recovery.ts +0 -1
- package/src/schedule/scheduler.ts +89 -51
- package/src/schedule/worker.ts +57 -0
- package/src/security/__tests__/openai-device-auth.test.ts +355 -0
- package/src/security/ces-rpc-record-backend.ts +123 -0
- package/src/security/oauth2.ts +7 -0
- package/src/security/openai-device-auth.ts +364 -0
- package/src/security/secure-keys.ts +15 -0
- package/src/skills/available-skills.ts +10 -1
- package/src/skills/catalog-install.ts +19 -1
- package/src/skills/inline-command-runner.ts +6 -2
- package/src/skills/platform-compatibility.test.ts +49 -0
- package/src/skills/platform-compatibility.ts +65 -0
- package/src/skills/tool-manifest.ts +20 -0
- package/src/stt/__tests__/roles.test.ts +152 -0
- package/src/stt/daemon-batch-transcriber.ts +4 -1
- package/src/stt/roles.ts +180 -0
- package/src/stt/stt-stream-session.ts +3 -2
- package/src/stt/types.ts +33 -3
- package/src/subagent/manager.ts +12 -0
- package/src/telemetry/__tests__/live-voice-funnel.test.ts +34 -0
- package/src/telemetry/live-voice-funnel.ts +12 -2
- package/src/telemetry/telemetry-wire.generated.ts +6 -0
- package/src/telemetry/tool-audit.ts +83 -30
- package/src/telemetry/tool-executed-events-store.test.ts +0 -1
- package/src/telemetry/turn-outcome.ts +75 -4
- package/src/tools/client-os.ts +115 -0
- package/src/tools/computer-use/definitions.ts +11 -7
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -2
- package/src/tools/credentials/broker-types.ts +0 -71
- package/src/tools/credentials/broker.ts +6 -201
- package/src/tools/credentials/metadata-store.ts +65 -16
- package/src/tools/credentials/store.ts +2 -0
- package/src/tools/executor.ts +2 -8
- package/src/tools/host-shell.test.ts +75 -0
- package/src/tools/host-shell.ts +24 -0
- package/src/tools/host-terminal/host-shell.ts +15 -44
- package/src/tools/mcp/mcp-tool-factory.ts +44 -9
- package/src/tools/permission-checker.ts +73 -21
- package/src/tools/policy-context.ts +1 -0
- package/src/tools/shared/filesystem/image-read.ts +1 -1
- package/src/tools/skills/find-similar-skills.ts +10 -2
- package/src/tools/skills/load.ts +41 -6
- package/src/tools/skills/sandbox-runner.ts +8 -16
- package/src/tools/skills/skill-tool-factory.ts +1 -0
- package/src/tools/terminal/__tests__/safe-env.test.ts +64 -1
- package/src/tools/terminal/safe-env.ts +39 -9
- package/src/tools/terminal/shell.ts +12 -31
- package/src/tools/tool-approval-handler.ts +64 -10
- package/src/tools/tool-types.ts +10 -0
- package/src/tools/types.ts +19 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +4 -3
- package/src/tools/workflows/manage-workflows.ts +2 -2
- package/src/tools/workflows/run-workflow.test.ts +2 -1
- package/src/util/__tests__/file-use.test.ts +61 -0
- package/src/util/__tests__/process-table.test.ts +66 -0
- package/src/util/__tests__/process-tree.test.ts +46 -0
- package/src/util/errors.ts +1 -0
- package/src/util/file-use.ts +91 -0
- package/src/util/host-process.test.ts +17 -0
- package/src/util/host-process.ts +75 -0
- package/src/util/image-conversion.ts +39 -7
- package/src/util/platform.ts +32 -13
- package/src/util/process-table.ts +249 -0
- package/src/util/process-tree.ts +85 -129
- package/src/util/provider-error-patterns.ts +20 -0
- package/src/util/spawn.ts +9 -2
- package/src/watch/__tests__/watch-retro.test.ts +48 -1
- package/src/watch/watch-retro.ts +46 -4
- package/src/workspace/git-service.ts +4 -14
- package/src/workspace/migrations/147-rename-colliding-backup-profile-names.ts +360 -0
- package/src/workspace/migrations/148-strip-unsupported-fallback-profiles.ts +117 -0
- package/src/workspace/migrations/149-repoint-backup-profile-selections.ts +204 -0
- package/src/workspace/migrations/150-stt-flux-provider-to-model-family.ts +139 -0
- package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +160 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/permission-types.test.ts +0 -17
- package/src/channels/gateway-discord-admission.ts +0 -32
- package/src/persistence/fork-message-copy.ts +0 -239
- package/src/plugins/defaults/memory/__tests__/fork-message-copy.test.ts +0 -221
- package/src/security/__tests__/oauth2-device-code.test.ts +0 -431
- package/src/security/oauth2-device-code.ts +0 -312
|
@@ -733,8 +733,33 @@ export async function runAgentLoopImpl(
|
|
|
733
733
|
// the `finally` (before processing clears, so the reporter's settled-turn
|
|
734
734
|
// barrier guarantees the stamp ships with the turn event). Unset = the turn
|
|
735
735
|
// replied normally and carries no stamp.
|
|
736
|
+
const failedOutcomeFromClassification = (classified: {
|
|
737
|
+
code: string;
|
|
738
|
+
userMessage: string;
|
|
739
|
+
errorCategory: string;
|
|
740
|
+
connectionName?: string;
|
|
741
|
+
profileName?: string;
|
|
742
|
+
}): NonNullable<typeof abnormalOutcome> => ({
|
|
743
|
+
outcome: "failed",
|
|
744
|
+
failureCode: classified.code,
|
|
745
|
+
failureMessage: classified.userMessage,
|
|
746
|
+
failureCategory: classified.errorCategory,
|
|
747
|
+
...(classified.connectionName
|
|
748
|
+
? { failureConnection: classified.connectionName }
|
|
749
|
+
: {}),
|
|
750
|
+
...(classified.profileName
|
|
751
|
+
? { failureProfile: classified.profileName }
|
|
752
|
+
: {}),
|
|
753
|
+
});
|
|
736
754
|
let abnormalOutcome:
|
|
737
|
-
| {
|
|
755
|
+
| {
|
|
756
|
+
outcome: "failed" | "cancelled";
|
|
757
|
+
failureCode?: string;
|
|
758
|
+
failureMessage?: string;
|
|
759
|
+
failureCategory?: string;
|
|
760
|
+
failureConnection?: string;
|
|
761
|
+
failureProfile?: string;
|
|
762
|
+
}
|
|
738
763
|
| undefined;
|
|
739
764
|
// True once a replied terminal SSE (message_complete / generation_handoff)
|
|
740
765
|
// has been emitted. Guards the catch block: an error thrown by the
|
|
@@ -777,6 +802,10 @@ export async function runAgentLoopImpl(
|
|
|
777
802
|
try {
|
|
778
803
|
stampTurnOutcome(userMessageId, abnormalOutcome.outcome, {
|
|
779
804
|
failureCode: abnormalOutcome.failureCode,
|
|
805
|
+
failureMessage: abnormalOutcome.failureMessage,
|
|
806
|
+
failureCategory: abnormalOutcome.failureCategory,
|
|
807
|
+
failureConnection: abnormalOutcome.failureConnection,
|
|
808
|
+
failureProfile: abnormalOutcome.failureProfile,
|
|
780
809
|
});
|
|
781
810
|
} catch (err) {
|
|
782
811
|
rlog.warn(
|
|
@@ -858,6 +887,7 @@ export async function runAgentLoopImpl(
|
|
|
858
887
|
abnormalOutcome = {
|
|
859
888
|
outcome: "failed",
|
|
860
889
|
failureCode: DISK_PRESSURE_ERROR_CODE,
|
|
890
|
+
failureMessage: message,
|
|
861
891
|
};
|
|
862
892
|
rlog.warn(
|
|
863
893
|
{ reason: diskPressureDecision.reason },
|
|
@@ -1382,17 +1412,16 @@ export async function runAgentLoopImpl(
|
|
|
1382
1412
|
);
|
|
1383
1413
|
// Exhausted-overflow exit: the reduction ladder is spent and the turn
|
|
1384
1414
|
// ends without a real reply, so label it failed for telemetry.
|
|
1385
|
-
abnormalOutcome =
|
|
1415
|
+
abnormalOutcome = failedOutcomeFromClassification(classified);
|
|
1386
1416
|
onEvent(buildConversationErrorMessage(ctx.conversationId, classified));
|
|
1387
1417
|
} else if (
|
|
1388
1418
|
overflowTerminalReason === "budget_yield_unrecovered" &&
|
|
1389
1419
|
!abortController.signal.aborted
|
|
1390
1420
|
) {
|
|
1391
1421
|
budgetYieldClassification = budgetYieldUnrecoveredClassification();
|
|
1392
|
-
abnormalOutcome =
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
};
|
|
1422
|
+
abnormalOutcome = failedOutcomeFromClassification(
|
|
1423
|
+
budgetYieldClassification,
|
|
1424
|
+
);
|
|
1396
1425
|
onEvent(
|
|
1397
1426
|
buildConversationErrorMessage(
|
|
1398
1427
|
ctx.conversationId,
|
|
@@ -1548,6 +1577,16 @@ export async function runAgentLoopImpl(
|
|
|
1548
1577
|
...(state.providerErrorCode
|
|
1549
1578
|
? { failureCode: state.providerErrorCode }
|
|
1550
1579
|
: {}),
|
|
1580
|
+
failureMessage: state.providerErrorUserMessage,
|
|
1581
|
+
...(state.providerErrorCategory
|
|
1582
|
+
? { failureCategory: state.providerErrorCategory }
|
|
1583
|
+
: {}),
|
|
1584
|
+
...(state.providerErrorConnection
|
|
1585
|
+
? { failureConnection: state.providerErrorConnection }
|
|
1586
|
+
: {}),
|
|
1587
|
+
...(state.providerErrorProfile
|
|
1588
|
+
? { failureProfile: state.providerErrorProfile }
|
|
1589
|
+
: {}),
|
|
1551
1590
|
};
|
|
1552
1591
|
// Drop any reservation stranded by the failed LLM call. The B3
|
|
1553
1592
|
// pre-allocation path reserves an empty assistant row at
|
|
@@ -1684,9 +1723,23 @@ export async function runAgentLoopImpl(
|
|
|
1684
1723
|
tokens: state.lastCallInputTokens,
|
|
1685
1724
|
maxTokens: resolveCurrentMaxInputTokens(),
|
|
1686
1725
|
},
|
|
1726
|
+
// When the turn's last LLM call was rerouted to a backup profile, that
|
|
1727
|
+
// profile is what served the tokens being recorded, so it outranks the
|
|
1728
|
+
// conversation's own resolution, which knows nothing about the
|
|
1729
|
+
// reroute. `provider` and `model` on this same row already follow the
|
|
1730
|
+
// backup (via `state.exchangeProviderName` / `state.model`), so
|
|
1731
|
+
// attributing the profile from the primary would write a row that
|
|
1732
|
+
// contradicts itself. `forceOverrideProfile` floats it above the
|
|
1733
|
+
// call-site profile exactly as the fallback dispatch did.
|
|
1687
1734
|
{
|
|
1688
1735
|
callSite: turnCallSite,
|
|
1689
|
-
overrideProfile:
|
|
1736
|
+
overrideProfile:
|
|
1737
|
+
state.exchangeInferenceProfile ??
|
|
1738
|
+
resolveCurrentOverrideProfile() ??
|
|
1739
|
+
null,
|
|
1740
|
+
...(state.exchangeInferenceProfile !== undefined
|
|
1741
|
+
? { forceOverrideProfile: true }
|
|
1742
|
+
: {}),
|
|
1690
1743
|
},
|
|
1691
1744
|
turnCronRunId,
|
|
1692
1745
|
);
|
|
@@ -1860,7 +1913,7 @@ export async function runAgentLoopImpl(
|
|
|
1860
1913
|
...turnErrorAttribution(),
|
|
1861
1914
|
});
|
|
1862
1915
|
if (!turnReplied) {
|
|
1863
|
-
abnormalOutcome =
|
|
1916
|
+
abnormalOutcome = failedOutcomeFromClassification(classified);
|
|
1864
1917
|
}
|
|
1865
1918
|
onEvent({
|
|
1866
1919
|
type: "error",
|
|
@@ -1975,6 +2028,13 @@ function emitUsage(
|
|
|
1975
2028
|
attribution?: {
|
|
1976
2029
|
callSite: LLMCallSite | null;
|
|
1977
2030
|
overrideProfile?: string | null;
|
|
2031
|
+
/**
|
|
2032
|
+
* Float `overrideProfile` above the call-site profile, matching how the
|
|
2033
|
+
* dispatch path floated it. Set when the profile being attributed is the
|
|
2034
|
+
* one a reroute actually served under rather than the caller's own
|
|
2035
|
+
* resolution.
|
|
2036
|
+
*/
|
|
2037
|
+
forceOverrideProfile?: boolean;
|
|
1978
2038
|
},
|
|
1979
2039
|
cronRunId: string | null = null,
|
|
1980
2040
|
): void {
|
|
@@ -2051,6 +2111,8 @@ export async function applyCompactionResult(
|
|
|
2051
2111
|
summaryRawResponses?: unknown[];
|
|
2052
2112
|
summaryCallSite?: LLMCallSite;
|
|
2053
2113
|
summaryOverrideProfile?: string | null;
|
|
2114
|
+
summaryActualProvider?: string;
|
|
2115
|
+
summaryActualInferenceProfile?: string;
|
|
2054
2116
|
},
|
|
2055
2117
|
onEvent: (msg: AssistantEvent) => void,
|
|
2056
2118
|
reqId: string | null,
|
|
@@ -2125,12 +2187,26 @@ export async function applyCompactionResult(
|
|
|
2125
2187
|
result.summaryCacheCreationInputTokens ?? 0,
|
|
2126
2188
|
result.summaryCacheReadInputTokens ?? 0,
|
|
2127
2189
|
collapseRawResponses(result.summaryRawResponses),
|
|
2128
|
-
|
|
2190
|
+
// The provider that actually served the summary, which follows a fallback
|
|
2191
|
+
// reroute the way `summaryModel` already did. Undefined only where no call
|
|
2192
|
+
// was made, and `emitUsage` then falls back to `ctx.provider.name` exactly
|
|
2193
|
+
// as before.
|
|
2194
|
+
result.summaryActualProvider /* providerName */,
|
|
2129
2195
|
1 /* llmCallCount */,
|
|
2130
2196
|
undefined /* contextWindow */,
|
|
2197
|
+
// Same rule as the main-agent row above, applied to the compaction row:
|
|
2198
|
+
// a rerouted summary is attributed to the profile that answered, not to
|
|
2199
|
+
// the one the compactor resolved before the call. The two call sites set
|
|
2200
|
+
// this parameter independently off their own state and never share it.
|
|
2131
2201
|
{
|
|
2132
2202
|
callSite: result.summaryCallSite ?? null,
|
|
2133
|
-
overrideProfile:
|
|
2203
|
+
overrideProfile:
|
|
2204
|
+
result.summaryActualInferenceProfile ??
|
|
2205
|
+
result.summaryOverrideProfile ??
|
|
2206
|
+
null,
|
|
2207
|
+
...(result.summaryActualInferenceProfile !== undefined
|
|
2208
|
+
? { forceOverrideProfile: true }
|
|
2209
|
+
: {}),
|
|
2134
2210
|
},
|
|
2135
2211
|
options.cronRunId ?? null,
|
|
2136
2212
|
);
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from "../util/errors.js";
|
|
27
27
|
import {
|
|
28
28
|
INSUFFICIENT_CREDITS_PATTERNS,
|
|
29
|
+
isChatTemplateFailureError,
|
|
29
30
|
isVisionNotSupportedError,
|
|
30
31
|
} from "../util/provider-error-patterns.js";
|
|
31
32
|
|
|
@@ -564,6 +565,9 @@ function classifyCore(
|
|
|
564
565
|
if (isVisionNotSupportedError(message)) {
|
|
565
566
|
return visionNotSupportedClassification();
|
|
566
567
|
}
|
|
568
|
+
if (isChatTemplateFailureError(message)) {
|
|
569
|
+
return requestShapeUnsupportedClassification();
|
|
570
|
+
}
|
|
567
571
|
// Extract the provider detail after "API error (NNN): " prefix
|
|
568
572
|
const detailMatch = message.match(/API error \(\d+\):\s*(.+)/i);
|
|
569
573
|
const detail = detailMatch?.[1];
|
|
@@ -654,6 +658,8 @@ function reasonToClassification(
|
|
|
654
658
|
return contextTooLargeClassification();
|
|
655
659
|
case "vision_unsupported":
|
|
656
660
|
return visionNotSupportedClassification();
|
|
661
|
+
case "request_shape_unsupported":
|
|
662
|
+
return requestShapeUnsupportedClassification();
|
|
657
663
|
// Two producers share this reason: SDK transport failures that never got
|
|
658
664
|
// a response (OpenAI APIConnectionError), and Gemini responses whose empty
|
|
659
665
|
// body reveals a proxy/egress filter intercepting the request. The copy
|
|
@@ -908,6 +914,25 @@ function visionNotSupportedClassification(): Omit<
|
|
|
908
914
|
};
|
|
909
915
|
}
|
|
910
916
|
|
|
917
|
+
/**
|
|
918
|
+
* Classification for a request rejected by the endpoint's server-side
|
|
919
|
+
* chat-template renderer. These endpoints choke on richer request shapes
|
|
920
|
+
* (tool calls, images, structured message content), so the copy points the
|
|
921
|
+
* user at a capability mismatch instead of the raw template error.
|
|
922
|
+
*/
|
|
923
|
+
function requestShapeUnsupportedClassification(): Omit<
|
|
924
|
+
ClassifiedConversationError,
|
|
925
|
+
"debugDetails"
|
|
926
|
+
> {
|
|
927
|
+
return {
|
|
928
|
+
code: "PROVIDER_API",
|
|
929
|
+
userMessage:
|
|
930
|
+
"This model's provider couldn't process the request format (tool calls or images may not be supported). Switch to a different model in Settings → Models & Services and try again.",
|
|
931
|
+
retryable: false,
|
|
932
|
+
errorCategory: "request_shape_unsupported",
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
|
|
911
936
|
/**
|
|
912
937
|
* Build a user-facing message that names the exact profile / connection
|
|
913
938
|
* to fix when one is known, falling back to a generic phrase otherwise.
|
|
@@ -74,11 +74,9 @@ export class ConversationEvictor {
|
|
|
74
74
|
getSubagentManager().abortAllForParent(conversationId);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
/** Protect conversations with
|
|
77
|
+
/** Protect conversations with in-flight subagents from eviction. */
|
|
78
78
|
shouldProtect(conversationId: string): boolean {
|
|
79
|
-
return getSubagentManager()
|
|
80
|
-
.getChildrenOf(conversationId)
|
|
81
|
-
.some((c) => c.status === "running" || c.status === "pending");
|
|
79
|
+
return getSubagentManager().hasActiveChildren(conversationId);
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
/** Record an access for the given conversation (resets its idle clock). */
|
|
@@ -745,6 +745,7 @@ export function stripNowScratchpad(messages: Message[]): Message[] {
|
|
|
745
745
|
*/
|
|
746
746
|
export function buildChannelCapabilityBlock(
|
|
747
747
|
caps: ChannelCapabilities,
|
|
748
|
+
clientOs: string | undefined = caps.clientOS,
|
|
748
749
|
): string | null {
|
|
749
750
|
// Happy path: desktop with full capabilities and no special context — skip injection.
|
|
750
751
|
if (
|
|
@@ -752,7 +753,8 @@ export function buildChannelCapabilityBlock(
|
|
|
752
753
|
caps.supportsDynamicUi &&
|
|
753
754
|
caps.supportsVoiceInput &&
|
|
754
755
|
!isGroupChatType(caps.chatType) &&
|
|
755
|
-
|
|
756
|
+
clientOs !== "macos" &&
|
|
757
|
+
clientOs !== "windows"
|
|
756
758
|
) {
|
|
757
759
|
return null;
|
|
758
760
|
}
|
|
@@ -762,17 +764,24 @@ export function buildChannelCapabilityBlock(
|
|
|
762
764
|
lines.push(`dashboard_capable: ${caps.dashboardCapable}`);
|
|
763
765
|
lines.push(`supports_dynamic_ui: ${caps.supportsDynamicUi}`);
|
|
764
766
|
lines.push(`supports_voice_input: ${caps.supportsVoiceInput}`);
|
|
765
|
-
if (
|
|
766
|
-
lines.push(`client_os: ${
|
|
767
|
+
if (clientOs) {
|
|
768
|
+
lines.push(`client_os: ${clientOs}`);
|
|
767
769
|
}
|
|
768
770
|
|
|
769
|
-
if (
|
|
771
|
+
if (clientOs === "macos") {
|
|
770
772
|
lines.push("");
|
|
771
773
|
lines.push(
|
|
772
774
|
"On macOS, prefer osascript/CLI via `host_bash` over computer use tools, which take over the user's cursor. Use foreground computer use only when no scripting alternative exists or the user explicitly asks.",
|
|
773
775
|
);
|
|
774
776
|
}
|
|
775
777
|
|
|
778
|
+
if (clientOs === "windows") {
|
|
779
|
+
lines.push("");
|
|
780
|
+
lines.push(
|
|
781
|
+
"On Windows, `host_bash` runs PowerShell. Use PowerShell syntax and Windows paths. Prefer PowerShell or CLI automation over foreground computer use when either can complete the task reliably.",
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
|
|
776
785
|
if (!caps.dashboardCapable) {
|
|
777
786
|
lines.push("");
|
|
778
787
|
lines.push("CHANNEL CONSTRAINTS:");
|
|
@@ -834,8 +843,9 @@ export function buildChannelCapabilityBlock(
|
|
|
834
843
|
export function injectChannelCapabilityContext(
|
|
835
844
|
message: Message,
|
|
836
845
|
caps: ChannelCapabilities,
|
|
846
|
+
clientOs?: string,
|
|
837
847
|
): Message {
|
|
838
|
-
const block = buildChannelCapabilityBlock(caps);
|
|
848
|
+
const block = buildChannelCapabilityBlock(caps, clientOs);
|
|
839
849
|
if (block === null) {
|
|
840
850
|
return message;
|
|
841
851
|
}
|
|
@@ -2642,8 +2652,10 @@ export async function applyRuntimeInjections(
|
|
|
2642
2652
|
if (channelCapabilities) {
|
|
2643
2653
|
const userTail = result[result.length - 1];
|
|
2644
2654
|
if (userTail && userTail.role === "user") {
|
|
2645
|
-
const channelCapabilityBlock =
|
|
2646
|
-
|
|
2655
|
+
const channelCapabilityBlock = buildChannelCapabilityBlock(
|
|
2656
|
+
channelCapabilities,
|
|
2657
|
+
clientOs,
|
|
2658
|
+
);
|
|
2647
2659
|
if (channelCapabilityBlock !== null) {
|
|
2648
2660
|
channelCapabilitiesCaptured = channelCapabilityBlock;
|
|
2649
2661
|
result = [
|
|
@@ -24,6 +24,7 @@ import type { ActiveSkillEntry } from "../skills/active-skill-tools.js";
|
|
|
24
24
|
import { deriveActiveSkills } from "../skills/active-skill-tools.js";
|
|
25
25
|
import { getCachedCatalogSync } from "../skills/catalog-cache.js";
|
|
26
26
|
import { readInstallMeta, touchSkillLastUsed } from "../skills/install-meta.js";
|
|
27
|
+
import { isSkillCompatibleWithPlatform } from "../skills/platform-compatibility.js";
|
|
27
28
|
import { parseToolManifestFile } from "../skills/tool-manifest.js";
|
|
28
29
|
import { computeSkillVersionHash } from "../skills/version-hash.js";
|
|
29
30
|
import { recordSkillLoadedEvent } from "../telemetry/skill-loaded-events-store.js";
|
|
@@ -381,7 +382,10 @@ export function projectSkillTools(
|
|
|
381
382
|
for (const id of allCandidateIds) {
|
|
382
383
|
const skill = catalogById.get(id);
|
|
383
384
|
const flagKey = skill ? skillFlagKey(skill) : undefined;
|
|
384
|
-
if (
|
|
385
|
+
if (
|
|
386
|
+
(!skill || isSkillCompatibleWithPlatform(skill)) &&
|
|
387
|
+
(!flagKey || isAssistantFeatureFlagEnabled(flagKey, config))
|
|
388
|
+
) {
|
|
385
389
|
activeIds.add(id);
|
|
386
390
|
}
|
|
387
391
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { InterfaceId } from "../channels/types.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getUserSelectableProfilesForProvider } from "../config/default-profile-catalog.js";
|
|
3
3
|
import { resolveEffectiveContextWindow } from "../config/llm-context-resolution.js";
|
|
4
4
|
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
5
5
|
import {
|
|
@@ -148,7 +148,7 @@ async function resolveModelCommand(
|
|
|
148
148
|
parse: ModelCommandParse,
|
|
149
149
|
): Promise<SlashResolution> {
|
|
150
150
|
const config = getConfig();
|
|
151
|
-
const profiles =
|
|
151
|
+
const profiles = getUserSelectableProfilesForProvider(
|
|
152
152
|
config.llm.profiles,
|
|
153
153
|
config.llm.defaultProvider ?? null,
|
|
154
154
|
);
|
|
@@ -402,7 +402,9 @@ export function clearAllActiveConversations(): number {
|
|
|
402
402
|
* Evict in-memory conversations after a config/prompt/skills reload so the next
|
|
403
403
|
* turn rebuilds them against the new config. Idle conversations are disposed and
|
|
404
404
|
* dropped; busy ones are marked stale so they're rebuilt once their current turn
|
|
405
|
-
* finishes.
|
|
405
|
+
* finishes. Conversations with in-flight subagents are left in place so a
|
|
406
|
+
* reload does not abort those children. Also used when provider credentials
|
|
407
|
+
* change.
|
|
406
408
|
*/
|
|
407
409
|
export function evictConversationsForReload(): void {
|
|
408
410
|
const subagentManager = getSubagentManager();
|
|
@@ -413,6 +415,11 @@ export function evictConversationsForReload(): void {
|
|
|
413
415
|
// would silently drop the queued messages, so mark it stale instead and
|
|
414
416
|
// let it rebuild once the queue has run.
|
|
415
417
|
if (!conversation.isProcessing() && !conversation.hasQueuedMessages()) {
|
|
418
|
+
// Same protection the TTL/LRU evictor applies: an idle parent still
|
|
419
|
+
// owns mid-task children, and aborting them here would kill that work.
|
|
420
|
+
if (subagentManager.hasActiveChildren(id)) {
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
416
423
|
subagentManager.abortAllForParent(id);
|
|
417
424
|
conversation.dispose();
|
|
418
425
|
deleteConversation(id);
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import type { AssistantEvent } from "../api/index.js";
|
|
10
10
|
import {
|
|
11
11
|
type HostProxyCapability,
|
|
12
|
+
parseClientOs,
|
|
12
13
|
supportsHostProxy,
|
|
13
14
|
} from "../channels/types.js";
|
|
14
15
|
import { getIsPlatform } from "../config/env-registry.js";
|
|
@@ -23,6 +24,7 @@ import { isPluginDisabled } from "../plugins/disabled-state.js";
|
|
|
23
24
|
import type { Message, ToolDefinition } from "../providers/types.js";
|
|
24
25
|
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
25
26
|
import { registerConversationSender } from "../tools/browser/browser-screencast.js";
|
|
27
|
+
import { supportsClientOsForSkillTool } from "../tools/client-os.js";
|
|
26
28
|
import type { ToolExecutor } from "../tools/executor.js";
|
|
27
29
|
import {
|
|
28
30
|
getAllPluginToolDefinitions,
|
|
@@ -410,6 +412,7 @@ export function createToolExecutor(
|
|
|
410
412
|
sourceThreadId: turnTrust.sourceThreadId,
|
|
411
413
|
requesterIdentifier: turnTrust.requesterIdentifier,
|
|
412
414
|
requesterDisplayName: turnTrust.requesterDisplayName,
|
|
415
|
+
requesterContactId: turnTrust.requesterContactId,
|
|
413
416
|
channelConversationType: turnTrust.conversationType,
|
|
414
417
|
// The binding's external chat id is the canonical conversation address
|
|
415
418
|
// for every channel adapter (Slack channel, Telegram chat, …); it keys
|
|
@@ -430,6 +433,8 @@ export function createToolExecutor(
|
|
|
430
433
|
toolUseId,
|
|
431
434
|
isPlatformHosted: getIsPlatform(),
|
|
432
435
|
transportInterface: ctx.transportInterface,
|
|
436
|
+
clientOs:
|
|
437
|
+
parseClientOs(ctx.currentTurnClientOs ?? ctx.clientOs) ?? undefined,
|
|
433
438
|
overrideProfile: ctx.currentTurnOverrideProfile,
|
|
434
439
|
cronRunId: ctx.currentTurnCronRunId,
|
|
435
440
|
invokingCallSite: ctx.currentCallSite ?? "mainAgent",
|
|
@@ -707,6 +712,32 @@ export const ALLOWLIST_ONLY_TOOL_NAMES = new Set<string>([
|
|
|
707
712
|
"delete_memory_page",
|
|
708
713
|
]);
|
|
709
714
|
|
|
715
|
+
/**
|
|
716
|
+
* Windows parity gate: skill tools may declare `supported_client_os`; drop
|
|
717
|
+
* them when the turn's client OS (or pinned OS for wakes) is not listed.
|
|
718
|
+
*/
|
|
719
|
+
function isToolSupportedOnClientOs(name: string, ctx: Conversation): boolean {
|
|
720
|
+
const supportedClientOs = getTool(name)?.supportedClientOs;
|
|
721
|
+
if (!supportedClientOs) {
|
|
722
|
+
return true;
|
|
723
|
+
}
|
|
724
|
+
const pin = ctx.toolContextPin;
|
|
725
|
+
const transportInterface = pin
|
|
726
|
+
? pin.transportInterface
|
|
727
|
+
: ctx.transportInterface;
|
|
728
|
+
const clientOs = pin
|
|
729
|
+
? pin.clientOs
|
|
730
|
+
: (parseClientOs(ctx.currentTurnClientOs ?? ctx.clientOs) ??
|
|
731
|
+
(transportInterface === "macos" || transportInterface === "windows"
|
|
732
|
+
? transportInterface
|
|
733
|
+
: undefined));
|
|
734
|
+
return supportsClientOsForSkillTool(supportedClientOs, name, {
|
|
735
|
+
clientOs,
|
|
736
|
+
transportInterface,
|
|
737
|
+
sourceActorPrincipalId: ctx.getTurnActorPrincipalId?.(),
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
|
|
710
741
|
/**
|
|
711
742
|
* Determine whether a tool is part of the final exposed tool set for the
|
|
712
743
|
* current turn. This helper mirrors the filtering applied by
|
|
@@ -729,6 +760,9 @@ export function isToolActiveForContext(
|
|
|
729
760
|
const transportInterface = pin
|
|
730
761
|
? pin.transportInterface
|
|
731
762
|
: ctx.transportInterface;
|
|
763
|
+
if (!isToolSupportedOnClientOs(name, ctx)) {
|
|
764
|
+
return false;
|
|
765
|
+
}
|
|
732
766
|
|
|
733
767
|
// When the conversation is acting as a subagent, the parent orchestrator
|
|
734
768
|
// restricts the tool list. A tool that isn't on the allowlist is not
|
|
@@ -1070,6 +1104,9 @@ export function createResolveToolsCallback(
|
|
|
1070
1104
|
if (excluded.has(name)) {
|
|
1071
1105
|
continue;
|
|
1072
1106
|
}
|
|
1107
|
+
if (!isToolSupportedOnClientOs(name, ctx)) {
|
|
1108
|
+
continue;
|
|
1109
|
+
}
|
|
1073
1110
|
turnAllowed.add(name);
|
|
1074
1111
|
}
|
|
1075
1112
|
// Record the full resolved inventory durably for read-only queries before
|
|
@@ -1917,8 +1917,6 @@ export class Conversation {
|
|
|
1917
1917
|
requestId: string,
|
|
1918
1918
|
decision: UserDecision,
|
|
1919
1919
|
options?: {
|
|
1920
|
-
selectedPattern?: string;
|
|
1921
|
-
selectedScope?: string;
|
|
1922
1920
|
decisionContext?: string;
|
|
1923
1921
|
emissionContext?: {
|
|
1924
1922
|
source?: ConfirmationStateChangedEvent["source"];
|
|
@@ -1937,8 +1935,6 @@ export class Conversation {
|
|
|
1937
1935
|
const toolUseId = this.prompter.getToolUseId(requestId);
|
|
1938
1936
|
|
|
1939
1937
|
this.prompter.resolveConfirmation(requestId, decision, {
|
|
1940
|
-
selectedPattern: options?.selectedPattern,
|
|
1941
|
-
selectedScope: options?.selectedScope,
|
|
1942
1938
|
decisionContext: options?.decisionContext,
|
|
1943
1939
|
});
|
|
1944
1940
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What every channel's connect/disconnect handler answers, whatever the
|
|
5
|
+
* channel.
|
|
6
|
+
*
|
|
7
|
+
* Each channel's own schema extends this with its tail: Slack carries a
|
|
8
|
+
* workspace and a thread mode, Telegram a webhook secret and registered
|
|
9
|
+
* commands, Discord nothing. The shape is the same one the readiness probes
|
|
10
|
+
* have, a declared common part plus a per-channel remainder, and it exists so
|
|
11
|
+
* a caller can ask "is this connected" without knowing which channel it is.
|
|
12
|
+
*
|
|
13
|
+
* `connected` is the field that makes this worth extracting. Holding a
|
|
14
|
+
* credential and having a working connection are different questions, and a
|
|
15
|
+
* channel that answered only the first would read as set up while delivering
|
|
16
|
+
* nothing.
|
|
17
|
+
*/
|
|
18
|
+
export const ChannelConfigResultBaseSchema = z.object({
|
|
19
|
+
/** Whether the operation itself succeeded. */
|
|
20
|
+
success: z.boolean(),
|
|
21
|
+
/** Whether a bot credential is stored, regardless of this call. */
|
|
22
|
+
hasBotToken: z.boolean(),
|
|
23
|
+
/** Whether the channel is actually connected, not merely credentialled. */
|
|
24
|
+
connected: z.boolean(),
|
|
25
|
+
error: z.string().optional(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export type ChannelConfigResultBase = z.infer<
|
|
29
|
+
typeof ChannelConfigResultBaseSchema
|
|
30
|
+
>;
|