@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
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ChildProcess } from "node:child_process";
|
|
2
1
|
import { spawn } from "node:child_process";
|
|
3
2
|
|
|
4
3
|
import { z } from "zod";
|
|
@@ -10,6 +9,10 @@ import { wakeAgentForOpportunity } from "../../runtime/agent-wake.js";
|
|
|
10
9
|
import { broadcastMessage } from "../../runtime/assistant-event-hub.js";
|
|
11
10
|
import { conversationRevealNonce } from "../../runtime/reveal-nonce.js";
|
|
12
11
|
import { redactSecrets } from "../../security/secret-scanner.js";
|
|
12
|
+
import {
|
|
13
|
+
buildShellInvocation,
|
|
14
|
+
terminateProcessTree,
|
|
15
|
+
} from "../../util/host-process.js";
|
|
13
16
|
import { getLogger } from "../../util/logger.js";
|
|
14
17
|
import { getDataDir } from "../../util/platform.js";
|
|
15
18
|
import type { CompletedBackgroundTool } from "../background-tool-registry.js";
|
|
@@ -296,7 +299,7 @@ export const shellTool = {
|
|
|
296
299
|
Object.assign(env, proxyEnv);
|
|
297
300
|
}
|
|
298
301
|
|
|
299
|
-
const wrapped =
|
|
302
|
+
const wrapped = buildShellInvocation(command);
|
|
300
303
|
|
|
301
304
|
// -----------------------------------------------------------------------
|
|
302
305
|
// Background mode: spawn and return immediately. The process output is
|
|
@@ -644,12 +647,11 @@ export const shellTool = {
|
|
|
644
647
|
|
|
645
648
|
/**
|
|
646
649
|
* Structured teardown log. Pairs with the `"Executing shell command"`
|
|
647
|
-
* start log: every shell invocation
|
|
650
|
+
* start log: every shell invocation produces a start/exit pair so
|
|
648
651
|
* orphan-leak post-mortems can correlate command + exitCode + signal +
|
|
649
652
|
* timedOut + duration without spelunking through prose hints. The
|
|
650
|
-
* `signal === "SIGKILL"` + `timedOut === true` combination
|
|
651
|
-
*
|
|
652
|
-
* — i.e. the moment that creates the orphans.
|
|
653
|
+
* `signal === "SIGKILL"` + `timedOut === true` combination identifies a
|
|
654
|
+
* timeout-driven process termination.
|
|
653
655
|
*/
|
|
654
656
|
function logShellExit(args: {
|
|
655
657
|
toolName: string;
|
|
@@ -681,19 +683,10 @@ function logShellExit(args: {
|
|
|
681
683
|
}
|
|
682
684
|
|
|
683
685
|
/**
|
|
684
|
-
*
|
|
685
|
-
* first (negative PID), then falls back to killing the direct child if the
|
|
686
|
-
* PID is unavailable or the group kill fails.
|
|
687
|
-
*
|
|
688
|
-
* Emits a structured `warn` log on every invocation: this is the
|
|
689
|
-
* ground-truth event that creates orphaned subprocesses (the SIGKILL hits
|
|
690
|
-
* the entire group, so the immediate bash child has no chance to reap its
|
|
691
|
-
* grandchildren; under bun-as-PID-1 they accumulate as `<defunct>`).
|
|
692
|
-
* `reason` lets the next zombie report point at a specific call site (the
|
|
693
|
-
* timeout watcher in the foreground/background branches, or an abort).
|
|
686
|
+
* Terminate the process tree and record the call site for timeout diagnostics.
|
|
694
687
|
*/
|
|
695
688
|
function buildKillTree(
|
|
696
|
-
child:
|
|
689
|
+
child: ReturnType<typeof spawn>,
|
|
697
690
|
context: {
|
|
698
691
|
toolName: string;
|
|
699
692
|
conversationId: string;
|
|
@@ -715,20 +708,8 @@ function buildKillTree(
|
|
|
715
708
|
groupPid,
|
|
716
709
|
invocationId: context.invocationId,
|
|
717
710
|
},
|
|
718
|
-
"Shell process group SIGKILL'd
|
|
711
|
+
"Shell process group SIGKILL'd",
|
|
719
712
|
);
|
|
720
|
-
|
|
721
|
-
try {
|
|
722
|
-
process.kill(-groupPid, "SIGKILL");
|
|
723
|
-
return;
|
|
724
|
-
} catch {
|
|
725
|
-
// Process group may have already exited — fall through.
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
try {
|
|
729
|
-
child.kill("SIGKILL");
|
|
730
|
-
} catch {
|
|
731
|
-
// Child may have already exited.
|
|
732
|
-
}
|
|
713
|
+
terminateProcessTree(child);
|
|
733
714
|
};
|
|
734
715
|
}
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from "../permissions/checker.js";
|
|
19
19
|
import {
|
|
20
20
|
channelNoCellDefault,
|
|
21
|
+
getContactAutoApproveThreshold,
|
|
21
22
|
resolveChannelPermissionCell,
|
|
22
23
|
} from "../permissions/gateway-threshold-reader.js";
|
|
23
24
|
import {
|
|
@@ -525,6 +526,11 @@ function reachesPrivateNetwork(
|
|
|
525
526
|
* Each stays on the capability floor, so a channel actor escalates to the
|
|
526
527
|
* guardian for them at every level. None of this touches the guardian's own
|
|
527
528
|
* lane — it decides what a *cell* may delegate, not how risk is classified.
|
|
529
|
+
*
|
|
530
|
+
* A contact-level ceiling is a different grant: the owner named this person,
|
|
531
|
+
* not a room. That ceiling may lift sandbox `bash`. It still cannot lift
|
|
532
|
+
* host reach, control-plane writes, unvetted tools, or private-network
|
|
533
|
+
* fetches; those stay on the floor regardless of the contact's threshold.
|
|
528
534
|
*/
|
|
529
535
|
function isChannelLiftable(
|
|
530
536
|
reach: SensitiveToolReach,
|
|
@@ -558,16 +564,54 @@ function isChannelLiftable(
|
|
|
558
564
|
}
|
|
559
565
|
|
|
560
566
|
/**
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
567
|
+
* Whether a contact-level ceiling may lift the floor for this invocation.
|
|
568
|
+
*
|
|
569
|
+
* Same sandbox-only rule as {@link isChannelLiftable}, except sandbox `bash`
|
|
570
|
+
* is included: the owner set a per-person ceiling, and that ceiling is what
|
|
571
|
+
* authorizes code execution in the workspace. Host reach, control-plane
|
|
572
|
+
* writes, unvetted tools, and private-network fetches stay unliftable.
|
|
573
|
+
*/
|
|
574
|
+
function isContactCeilingLiftable(
|
|
575
|
+
reach: SensitiveToolReach,
|
|
576
|
+
toolName: string,
|
|
577
|
+
input: Record<string, unknown>,
|
|
578
|
+
workingDir: string | undefined,
|
|
579
|
+
): boolean {
|
|
580
|
+
if (reach !== "sandbox") {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
if (
|
|
584
|
+
isWorkspaceWriteTool(toolName) &&
|
|
585
|
+
(!workingDir || isControlPlaneWorkspaceWrite(toolName, input, workingDir))
|
|
586
|
+
) {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
if (isUnvettedExtensionTool(toolName)) {
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
if (reachesPrivateNetwork(toolName, input)) {
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Threshold governing this invocation's floor lift, read only when it can
|
|
600
|
+
* change the outcome: an escalate-floor actor whose invocation a cell or a
|
|
601
|
+
* contact ceiling may lift. Guardians, non-sensitive tools, host reach,
|
|
602
|
+
* everything those lift paths exclude, and identity-less actors return
|
|
603
|
+
* early, so the gateway lookup never lands on the paths where it could
|
|
566
604
|
* only add latency — grant consumption for an already-approved call, and voice
|
|
567
605
|
* abort handling.
|
|
568
606
|
*
|
|
569
|
-
*
|
|
570
|
-
*
|
|
607
|
+
* A non-null contact ceiling wins over the matrix cell. It is the owner's
|
|
608
|
+
* override for that person and is not collapsed to the channel's two
|
|
609
|
+
* levels, so `medium` / `high` can lift sandbox `bash`. Cells still cannot
|
|
610
|
+
* lift bash.
|
|
611
|
+
*
|
|
612
|
+
* The permission checker reads this same contact ceiling / cell later in
|
|
613
|
+
* the turn, within the reader's cache window, so the lift costs at most
|
|
614
|
+
* one lookup per turn.
|
|
571
615
|
*
|
|
572
616
|
* Returns `undefined` when the turn has no channel coordinates or a lookup
|
|
573
617
|
* fails — nothing lifts the floor then. A successful walk that finds no cell
|
|
@@ -583,10 +627,21 @@ async function resolveApprovalCellThreshold(
|
|
|
583
627
|
sensitiveToolApproval: SensitiveToolApproval,
|
|
584
628
|
context: ToolContext,
|
|
585
629
|
): Promise<ApprovalCellThreshold | undefined> {
|
|
630
|
+
if (sensitiveToolApproval !== "escalate-and-wait") {
|
|
631
|
+
return undefined;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const contactCeiling = await getContactAutoApproveThreshold(
|
|
635
|
+
context.requesterContactId,
|
|
636
|
+
);
|
|
586
637
|
if (
|
|
587
|
-
|
|
588
|
-
|
|
638
|
+
contactCeiling !== null &&
|
|
639
|
+
isContactCeilingLiftable(reach, toolName, input, context.workingDir)
|
|
589
640
|
) {
|
|
641
|
+
return contactCeiling;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (!isChannelLiftable(reach, toolName, input, context.workingDir)) {
|
|
590
645
|
return undefined;
|
|
591
646
|
}
|
|
592
647
|
const query = buildChannelPermissionCellQuery(
|
|
@@ -708,7 +763,6 @@ export class ToolApprovalHandler {
|
|
|
708
763
|
reason,
|
|
709
764
|
riskLevel,
|
|
710
765
|
durationMs: Date.now() - startTime,
|
|
711
|
-
wasPrompted: false,
|
|
712
766
|
});
|
|
713
767
|
}
|
|
714
768
|
|
package/src/tools/tool-types.ts
CHANGED
|
@@ -348,6 +348,8 @@ export interface ToolContext {
|
|
|
348
348
|
* `InterfaceId` union.
|
|
349
349
|
*/
|
|
350
350
|
transportInterface?: string;
|
|
351
|
+
/** Operating system reported by the client for the current turn. */
|
|
352
|
+
clientOs?: "web" | "ios" | "macos" | "windows" | "android";
|
|
351
353
|
/**
|
|
352
354
|
* True when the host browser proxy's sender was overridden by an
|
|
353
355
|
* extension connection (WebSocket browser-relay).
|
|
@@ -374,6 +376,14 @@ export interface Tool {
|
|
|
374
376
|
/** Declared execution target from the skill manifest. Used by resolveExecutionTarget
|
|
375
377
|
* to accurately label lifecycle events for skill-provided tools. */
|
|
376
378
|
executionTarget?: ExecutionTarget;
|
|
379
|
+
/** Client operating systems that may expose this tool. Unset means all. */
|
|
380
|
+
supportedClientOs?: readonly (
|
|
381
|
+
| "web"
|
|
382
|
+
| "ios"
|
|
383
|
+
| "macos"
|
|
384
|
+
| "windows"
|
|
385
|
+
| "android"
|
|
386
|
+
)[];
|
|
377
387
|
getDefinition(): ToolDefinition;
|
|
378
388
|
execute(
|
|
379
389
|
input: Record<string, unknown>,
|
package/src/tools/types.ts
CHANGED
|
@@ -6,7 +6,11 @@ import type {
|
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
8
|
import type { AnsweredQuestion } from "../api/events/question-answered.js";
|
|
9
|
-
import
|
|
9
|
+
import {
|
|
10
|
+
CLIENT_OS_VALUES,
|
|
11
|
+
type ClientOs,
|
|
12
|
+
type InterfaceId,
|
|
13
|
+
} from "../channels/types.js";
|
|
10
14
|
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
11
15
|
import type { ToolActivityMetadata } from "../daemon/message-types/web-activity.js";
|
|
12
16
|
import type { SecretPromptResult } from "../permissions/secret-prompt-types.js";
|
|
@@ -367,6 +371,12 @@ export interface ToolContext {
|
|
|
367
371
|
* @legacy
|
|
368
372
|
*/
|
|
369
373
|
requesterIdentifier?: string;
|
|
374
|
+
/**
|
|
375
|
+
* Contact ID of the requester's member record. Approval resolution looks
|
|
376
|
+
* up this contact's auto-approve ceiling from the gateway at use time.
|
|
377
|
+
* @legacy
|
|
378
|
+
*/
|
|
379
|
+
requesterContactId?: string;
|
|
370
380
|
/**
|
|
371
381
|
* Preferred display name for the requester.
|
|
372
382
|
* @legacy
|
|
@@ -406,6 +416,8 @@ export interface ToolContext {
|
|
|
406
416
|
* @legacy
|
|
407
417
|
*/
|
|
408
418
|
transportInterface?: InterfaceId;
|
|
419
|
+
/** Operating system reported by the client for the current turn. */
|
|
420
|
+
clientOs?: ClientOs;
|
|
409
421
|
/**
|
|
410
422
|
* The per-turn inference-profile override the agent loop is currently
|
|
411
423
|
* running under, propagated through tool context so subagent-spawn tools
|
|
@@ -504,6 +516,8 @@ export const ToolDefinitionSchema = z.object({
|
|
|
504
516
|
category: z.string().min(1).optional(),
|
|
505
517
|
/** Where the tool runs — sandbox (assistant container) or host (guardian device via proxy). Resolved by `resolveExecutionTarget` if omitted. */
|
|
506
518
|
executionTarget: z.enum(["sandbox", "host"]).optional(),
|
|
519
|
+
/** Client operating systems that may expose this tool. Unset means all. */
|
|
520
|
+
supportedClientOs: z.array(z.enum(CLIENT_OS_VALUES)).optional(),
|
|
507
521
|
/**
|
|
508
522
|
* Implementation invoked when the model calls the tool. Optional
|
|
509
523
|
* because some `ToolDefinition` instances are schema-only (e.g.
|
|
@@ -551,8 +565,10 @@ export type ToolDefinition = z.infer<typeof ToolDefinitionSchema>;
|
|
|
551
565
|
* it, and the agent loop reads it as `?.exclusive === true`, so forcing every
|
|
552
566
|
* hand-built `Tool` (MCP/meet/test fixtures) to carry it would be noise.
|
|
553
567
|
*/
|
|
554
|
-
export type Tool = Required<
|
|
555
|
-
|
|
568
|
+
export type Tool = Required<
|
|
569
|
+
Omit<ToolDefinition, "exclusive" | "supportedClientOs">
|
|
570
|
+
> &
|
|
571
|
+
Pick<ToolDefinition, "exclusive" | "supportedClientOs">;
|
|
556
572
|
|
|
557
573
|
/**
|
|
558
574
|
* The kind of entity that owns a tool. `"default"` is the built-in tool set
|
|
@@ -202,14 +202,15 @@ export const SURFACE_SHAPE_DOCS: Record<string, SurfaceShapeDoc> = {
|
|
|
202
202
|
"{ html, height? } — one self-contained HTML/SVG fragment (no DOCTYPE/html/head/body, no external resources); every colour comes from the injected design-token CSS variables, so hex/rgb literals and invented `var()` names are rejected. Load the `visualize` skill with `skill_load` for the full contract and the token vocabulary",
|
|
203
203
|
},
|
|
204
204
|
channel_setup: {
|
|
205
|
-
purpose: "open the Slack/Telegram/Phone setup panel",
|
|
206
|
-
shape: '{ channel: "slack" | "telegram" | "phone" }',
|
|
205
|
+
purpose: "open the Slack/Telegram/Discord/Phone setup panel",
|
|
206
|
+
shape: '{ channel: "slack" | "telegram" | "discord" | "phone" }',
|
|
207
207
|
missingContent: (data) =>
|
|
208
208
|
data.channel === "slack" ||
|
|
209
209
|
data.channel === "telegram" ||
|
|
210
|
+
data.channel === "discord" ||
|
|
210
211
|
data.channel === "phone"
|
|
211
212
|
? null
|
|
212
|
-
: '`data.channel` must be one of "slack", "telegram", "phone"',
|
|
213
|
+
: '`data.channel` must be one of "slack", "telegram", "discord", "phone"',
|
|
213
214
|
},
|
|
214
215
|
voice_picker: {
|
|
215
216
|
// The steering lives in `purpose` because that is the only part of a cold
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import { z } from "zod";
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import { getUserSelectableProfilesForProvider } from "../../config/default-profile-catalog.js";
|
|
19
19
|
import { loadConfig } from "../../config/loader.js";
|
|
20
20
|
import { callerOwnsWorkflowRun } from "../../workflows/capabilities.js";
|
|
21
21
|
import type { WorkflowRun } from "../../workflows/journal-store.js";
|
|
@@ -192,7 +192,7 @@ export async function executeManageWorkflows(
|
|
|
192
192
|
// workspace-wide active profile. Read-only — leaves use this to pick a
|
|
193
193
|
// valid `profile` for `run_workflow` (an unknown profile throws).
|
|
194
194
|
const { llm } = loadConfig();
|
|
195
|
-
const profiles =
|
|
195
|
+
const profiles = getUserSelectableProfilesForProvider(
|
|
196
196
|
llm?.profiles,
|
|
197
197
|
llm?.defaultProvider ?? null,
|
|
198
198
|
);
|
|
@@ -338,7 +338,8 @@ describe("manage_workflows", () => {
|
|
|
338
338
|
);
|
|
339
339
|
expect(res.isError).toBe(false);
|
|
340
340
|
const parsed = JSON.parse(res.content);
|
|
341
|
-
// The
|
|
341
|
+
// The user-selectable view includes the code-catalog defaults and omits
|
|
342
|
+
// managed backup routes.
|
|
342
343
|
expect(parsed.profiles).toEqual([
|
|
343
344
|
"balanced",
|
|
344
345
|
"cost-optimized",
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { isFileUnheld } from "../file-use.js";
|
|
4
|
+
|
|
5
|
+
describe("isFileUnheld", () => {
|
|
6
|
+
test("returns false when a process holds the file", async () => {
|
|
7
|
+
expect(
|
|
8
|
+
await isFileUnheld("lock", "linux", async () => ({ stdout: "123\n" })),
|
|
9
|
+
).toBe(false);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("uses an exclusive-open probe on Windows", async () => {
|
|
13
|
+
let invocation: { command: string; args: string[] } | undefined;
|
|
14
|
+
expect(
|
|
15
|
+
await isFileUnheld(
|
|
16
|
+
"C:\\Example Workspace\\.git\\index.lock",
|
|
17
|
+
"win32",
|
|
18
|
+
async (command, args) => {
|
|
19
|
+
invocation = { command, args };
|
|
20
|
+
return { stdout: "" };
|
|
21
|
+
},
|
|
22
|
+
),
|
|
23
|
+
).toBe(true);
|
|
24
|
+
expect(invocation?.command).toBe("powershell.exe");
|
|
25
|
+
expect(invocation?.args.at(-1)).toBe(
|
|
26
|
+
"C:\\Example Workspace\\.git\\index.lock",
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("returns false when Windows reports a sharing violation", async () => {
|
|
31
|
+
expect(
|
|
32
|
+
await isFileUnheld("lock", "win32", async () => {
|
|
33
|
+
throw Object.assign(new Error("held"), { code: 1 });
|
|
34
|
+
}),
|
|
35
|
+
).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("fails closed when the Windows probe errors", async () => {
|
|
39
|
+
expect(
|
|
40
|
+
await isFileUnheld("lock", "win32", async () => {
|
|
41
|
+
throw Object.assign(new Error("probe failed"), { code: 2 });
|
|
42
|
+
}),
|
|
43
|
+
).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("returns true when lsof reports no holder", async () => {
|
|
47
|
+
expect(
|
|
48
|
+
await isFileUnheld("lock", "linux", async () => {
|
|
49
|
+
throw Object.assign(new Error("no matches"), { code: 1 });
|
|
50
|
+
}),
|
|
51
|
+
).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("treats lsof errors as unheld to match prior behavior", async () => {
|
|
55
|
+
expect(
|
|
56
|
+
await isFileUnheld("lock", "linux", async () => {
|
|
57
|
+
throw Object.assign(new Error("missing"), { code: "ENOENT" });
|
|
58
|
+
}),
|
|
59
|
+
).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
parsePsProcessTable,
|
|
5
|
+
parseWindowsProcessTable,
|
|
6
|
+
} from "../process-table.js";
|
|
7
|
+
|
|
8
|
+
describe("parsePsProcessTable", () => {
|
|
9
|
+
test("preserves command lines while parsing process relationships", () => {
|
|
10
|
+
expect(
|
|
11
|
+
parsePsProcessTable(
|
|
12
|
+
" 10 1 /usr/bin/bun run worker.ts arg\n 11 10 helper\n",
|
|
13
|
+
),
|
|
14
|
+
).toEqual([
|
|
15
|
+
{ pid: 10, ppid: 1, command: "/usr/bin/bun run worker.ts arg" },
|
|
16
|
+
{ pid: 11, ppid: 10, command: "helper" },
|
|
17
|
+
]);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("parseWindowsProcessTable", () => {
|
|
22
|
+
test("parses PowerShell JSON and falls back to the image name", () => {
|
|
23
|
+
expect(
|
|
24
|
+
parseWindowsProcessTable(
|
|
25
|
+
JSON.stringify([
|
|
26
|
+
{
|
|
27
|
+
ProcessId: 100,
|
|
28
|
+
ParentProcessId: 4,
|
|
29
|
+
CommandLine: "C:\\Program Files\\Bun\\bun.exe worker.ts",
|
|
30
|
+
Name: "bun.exe",
|
|
31
|
+
WorkingSetSize: 4096,
|
|
32
|
+
HandleCount: 42,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
ProcessId: 101,
|
|
36
|
+
ParentProcessId: 100,
|
|
37
|
+
CommandLine: null,
|
|
38
|
+
Name: "helper.exe",
|
|
39
|
+
},
|
|
40
|
+
]),
|
|
41
|
+
),
|
|
42
|
+
).toEqual([
|
|
43
|
+
{
|
|
44
|
+
pid: 100,
|
|
45
|
+
ppid: 4,
|
|
46
|
+
command: "C:\\Program Files\\Bun\\bun.exe worker.ts",
|
|
47
|
+
rssBytes: 4096,
|
|
48
|
+
handleCount: 42,
|
|
49
|
+
},
|
|
50
|
+
{ pid: 101, ppid: 100, command: "helper.exe" },
|
|
51
|
+
]);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("handles the single-object shape emitted for one process", () => {
|
|
55
|
+
expect(
|
|
56
|
+
parseWindowsProcessTable(
|
|
57
|
+
JSON.stringify({
|
|
58
|
+
ProcessId: 100,
|
|
59
|
+
ParentProcessId: 4,
|
|
60
|
+
CommandLine: "worker.exe",
|
|
61
|
+
Name: "worker.exe",
|
|
62
|
+
}),
|
|
63
|
+
),
|
|
64
|
+
).toEqual([{ pid: 100, ppid: 4, command: "worker.exe" }]);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -9,6 +9,7 @@ import { describe, expect, test } from "bun:test";
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
buildProcessTree,
|
|
12
|
+
buildSystemProcessTree,
|
|
12
13
|
deriveName,
|
|
13
14
|
deriveOrigin,
|
|
14
15
|
type ProcInfo,
|
|
@@ -20,6 +21,14 @@ describe("deriveName", () => {
|
|
|
20
21
|
expect(deriveName("qdrant")).toBe("qdrant");
|
|
21
22
|
});
|
|
22
23
|
|
|
24
|
+
test("handles quoted Windows executable and script paths", () => {
|
|
25
|
+
expect(
|
|
26
|
+
deriveName(
|
|
27
|
+
'"C:\\Program Files\\Bun\\bun.exe" run "C:\\Example App\\jobs\\worker.ts"',
|
|
28
|
+
),
|
|
29
|
+
).toBe("jobs-worker");
|
|
30
|
+
});
|
|
31
|
+
|
|
23
32
|
test("summarizes the script path as <parent>-<file> for interpreter invocations", () => {
|
|
24
33
|
expect(deriveName("bun run /home/u/app/jobs/worker.ts")).toBe(
|
|
25
34
|
"jobs-worker",
|
|
@@ -67,6 +76,12 @@ describe("deriveOrigin", () => {
|
|
|
67
76
|
).toBe("plugin:cognee");
|
|
68
77
|
});
|
|
69
78
|
|
|
79
|
+
test("tags a plugin from a Windows command path", () => {
|
|
80
|
+
expect(
|
|
81
|
+
deriveOrigin("bun run C:\\Vellum\\workspace\\plugins\\cognee\\server.ts"),
|
|
82
|
+
).toBe("plugin:cognee");
|
|
83
|
+
});
|
|
84
|
+
|
|
70
85
|
test("tags a bundled default plugin as default-<name>", () => {
|
|
71
86
|
expect(
|
|
72
87
|
deriveOrigin("bun --smol run /app/src/plugins/defaults/memory/worker.ts"),
|
|
@@ -195,3 +210,34 @@ describe("buildProcessTree", () => {
|
|
|
195
210
|
expect(tree.children[0].children).toEqual([]);
|
|
196
211
|
});
|
|
197
212
|
});
|
|
213
|
+
|
|
214
|
+
describe("buildSystemProcessTree", () => {
|
|
215
|
+
test("includes every process under a synthetic system root", () => {
|
|
216
|
+
const procs: ProcInfo[] = [
|
|
217
|
+
{ pid: 4, ppid: 0, command: "System", origin: "workspace" },
|
|
218
|
+
{ pid: 100, ppid: 4, command: "assistant.exe", origin: "workspace" },
|
|
219
|
+
{ pid: 200, ppid: 100, command: "worker.exe", origin: "workspace" },
|
|
220
|
+
{ pid: 300, ppid: 999, command: "orphan.exe", origin: "workspace" },
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
const tree = buildSystemProcessTree(procs);
|
|
224
|
+
const allPids = (node: typeof tree): number[] => [
|
|
225
|
+
node.pid,
|
|
226
|
+
...node.children.flatMap(allPids),
|
|
227
|
+
];
|
|
228
|
+
|
|
229
|
+
expect(tree.name).toBe("system");
|
|
230
|
+
expect(allPids(tree)).toEqual([0, 4, 100, 200, 300]);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("includes processes trapped in a parent cycle", () => {
|
|
234
|
+
const procs: ProcInfo[] = [
|
|
235
|
+
{ pid: 10, ppid: 20, command: "a", origin: "workspace" },
|
|
236
|
+
{ pid: 20, ppid: 10, command: "b", origin: "workspace" },
|
|
237
|
+
];
|
|
238
|
+
|
|
239
|
+
const tree = buildSystemProcessTree(procs);
|
|
240
|
+
expect(tree.children.map((child) => child.pid)).toEqual([10]);
|
|
241
|
+
expect(tree.children[0].children.map((child) => child.pid)).toEqual([20]);
|
|
242
|
+
});
|
|
243
|
+
});
|
package/src/util/errors.ts
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
|
|
6
|
+
const WINDOWS_EXCLUSIVE_OPEN_SCRIPT = String.raw`
|
|
7
|
+
Add-Type -TypeDefinition @'
|
|
8
|
+
using System;
|
|
9
|
+
using System.Runtime.InteropServices;
|
|
10
|
+
using Microsoft.Win32.SafeHandles;
|
|
11
|
+
|
|
12
|
+
public static class FileUseProbe {
|
|
13
|
+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
14
|
+
public static extern SafeFileHandle CreateFile(
|
|
15
|
+
string fileName,
|
|
16
|
+
uint desiredAccess,
|
|
17
|
+
uint shareMode,
|
|
18
|
+
IntPtr securityAttributes,
|
|
19
|
+
uint creationDisposition,
|
|
20
|
+
uint flagsAndAttributes,
|
|
21
|
+
IntPtr templateFile);
|
|
22
|
+
}
|
|
23
|
+
'@
|
|
24
|
+
|
|
25
|
+
$handle = [FileUseProbe]::CreateFile($args[0], 0, 0, [IntPtr]::Zero, 3, 128, [IntPtr]::Zero)
|
|
26
|
+
if (-not $handle.IsInvalid) {
|
|
27
|
+
$handle.Dispose()
|
|
28
|
+
exit 0
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
$errorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
|
|
32
|
+
if ($errorCode -eq 2) {
|
|
33
|
+
exit 0
|
|
34
|
+
}
|
|
35
|
+
if ($errorCode -eq 32 -or $errorCode -eq 33) {
|
|
36
|
+
exit 1
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[Console]::Error.WriteLine($errorCode)
|
|
40
|
+
exit 2
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
type ExecFileResult = { stdout: string };
|
|
44
|
+
type ExecFileRunner = (
|
|
45
|
+
command: string,
|
|
46
|
+
args: string[],
|
|
47
|
+
options: { encoding: "utf8"; timeout: number },
|
|
48
|
+
) => Promise<ExecFileResult>;
|
|
49
|
+
|
|
50
|
+
const runExecFile: ExecFileRunner = async (command, args, options) => {
|
|
51
|
+
const { stdout } = await execFileAsync(command, args, options);
|
|
52
|
+
return { stdout };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** Whether no process holds `path` open. Windows fails closed on probe errors. */
|
|
56
|
+
export async function isFileUnheld(
|
|
57
|
+
path: string,
|
|
58
|
+
platform: NodeJS.Platform = process.platform,
|
|
59
|
+
run: ExecFileRunner = runExecFile,
|
|
60
|
+
): Promise<boolean> {
|
|
61
|
+
if (platform === "win32") {
|
|
62
|
+
try {
|
|
63
|
+
await run(
|
|
64
|
+
"powershell.exe",
|
|
65
|
+
[
|
|
66
|
+
"-NoProfile",
|
|
67
|
+
"-NonInteractive",
|
|
68
|
+
"-Command",
|
|
69
|
+
WINDOWS_EXCLUSIVE_OPEN_SCRIPT,
|
|
70
|
+
path,
|
|
71
|
+
],
|
|
72
|
+
{ encoding: "utf8", timeout: 3000 },
|
|
73
|
+
);
|
|
74
|
+
return true;
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const { stdout } = await run("lsof", ["-t", path], {
|
|
82
|
+
encoding: "utf8",
|
|
83
|
+
timeout: 3000,
|
|
84
|
+
});
|
|
85
|
+
return stdout.length === 0;
|
|
86
|
+
} catch {
|
|
87
|
+
// lsof exits non-zero when no process holds the file. On hosts without
|
|
88
|
+
// lsof this degrades to unconditional removal, matching prior behavior.
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { terminateProcessTree } from "./host-process.js";
|
|
4
|
+
|
|
5
|
+
test("Windows process trees use taskkill and fall back to the direct child", () => {
|
|
6
|
+
const kill = mock(() => true);
|
|
7
|
+
let taskkillPid: number | undefined;
|
|
8
|
+
|
|
9
|
+
terminateProcessTree({ pid: 1234, kill }, "win32", (pid, onFailure) => {
|
|
10
|
+
taskkillPid = pid;
|
|
11
|
+
onFailure();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
expect(taskkillPid).toBe(1234);
|
|
15
|
+
expect(kill).toHaveBeenCalledTimes(1);
|
|
16
|
+
expect(kill).toHaveBeenCalledWith();
|
|
17
|
+
});
|