@vellumai/assistant 0.12.0 → 0.12.1-dev.202609141913.5e16607
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -1
- package/ARCHITECTURE.md +11 -12
- package/docs/architecture/turn-actor.md +15 -8
- package/docs/guardian-request-flow.md +16 -0
- package/openapi.yaml +292 -50
- package/package.json +1 -1
- package/scripts/smoke-desktop-window-theme.ts +186 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
- package/src/__tests__/app-compiler.test.ts +6 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
- package/src/__tests__/app-dir-path-guard.test.ts +1 -3
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
- package/src/__tests__/computer-use-tools.test.ts +17 -5
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +28 -29
- package/src/__tests__/config-watcher.test.ts +23 -8
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +26 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
- package/src/__tests__/conversation-queue.test.ts +48 -207
- package/src/__tests__/conversation-retry-discard.test.ts +54 -1
- package/src/__tests__/conversation-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-title-service.test.ts +14 -10
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
- package/src/__tests__/credential-record-retire.test.ts +171 -1
- package/src/__tests__/credential-routes.test.ts +212 -3
- package/src/__tests__/credential-security-invariants.test.ts +4 -2
- package/src/__tests__/cu-unified-flow.test.ts +8 -2
- package/src/__tests__/document-sync-tags.test.ts +25 -0
- package/src/__tests__/drain-kick-guard.test.ts +0 -2
- package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/git-porcelain.test.ts +47 -0
- package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
- package/src/__tests__/host-bash-proxy.test.ts +26 -45
- package/src/__tests__/host-browser-proxy.test.ts +6 -17
- package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
- package/src/__tests__/host-file-proxy.test.ts +11 -23
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
- package/src/__tests__/llm-catalog-parity.test.ts +25 -0
- package/src/__tests__/mcp-auth-routes.test.ts +6 -9
- package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
- package/src/__tests__/mcp-health-check.test.ts +8 -11
- package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +355 -548
- package/src/__tests__/model-intents.test.ts +3 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +8 -16
- package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +13 -0
- package/src/__tests__/resolve-app.test.ts +135 -0
- package/src/__tests__/script-proxy-certs.test.ts +35 -0
- package/src/__tests__/service-account-token.test.ts +247 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/source-fingerprint.test.ts +184 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +19 -3
- package/src/__tests__/subagent-tools.test.ts +3 -2
- package/src/__tests__/telephony-tts-guard.test.ts +38 -3
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
- package/src/__tests__/workspace-git-service.test.ts +26 -0
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
- package/src/acp/__tests__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -0
- package/src/acp/__tests__/client-handler.test.ts +90 -2
- package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
- package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
- package/src/acp/__tests__/session-manager.test.ts +895 -4
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +94 -9
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/client-handler.ts +16 -3
- package/src/acp/model-config.test.ts +166 -0
- package/src/acp/model-config.ts +138 -0
- package/src/acp/resolve-agent.test.ts +220 -6
- package/src/acp/resolve-agent.ts +88 -23
- package/src/acp/session-manager.test.ts +196 -3
- package/src/acp/session-manager.ts +441 -18
- package/src/acp/types.ts +50 -5
- package/src/api/events/acp-session-model-update.test.ts +88 -0
- package/src/api/events/acp-session-model-update.ts +46 -0
- package/src/api/events/app-files-changed.ts +4 -3
- package/src/api/events/notification-intent.ts +2 -0
- package/src/api/index.ts +6 -0
- package/src/apps/app-store.ts +1 -1
- package/src/apps/resolve-app.ts +81 -0
- package/src/apps/source-fingerprint.ts +266 -0
- package/src/bundler/app-compiler.ts +15 -0
- package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
- package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
- package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
- package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
- package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
- package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
- package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
- package/src/calls/__tests__/voice-control-protocol.test.ts +58 -25
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
- package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
- package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
- package/src/calls/__tests__/voice-session-bridge.test.ts +37 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
- package/src/calls/barge-in-guard.ts +118 -0
- package/src/calls/call-constants.ts +24 -4
- package/src/calls/call-controller.ts +499 -199
- package/src/calls/call-transport.ts +16 -0
- package/src/calls/media-stream-output.ts +32 -0
- package/src/calls/media-stream-server.ts +82 -30
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/{live-voice → calls}/progress-narration.ts +2 -2
- package/src/calls/resolve-call-tts-provider.ts +33 -2
- package/src/calls/tts-call-strategy.ts +9 -5
- package/src/calls/types.ts +2 -0
- package/src/calls/voice-control-protocol.ts +53 -21
- package/src/calls/voice-leg-coordinator.ts +189 -0
- package/src/calls/voice-progress-cadence.ts +423 -0
- package/src/calls/voice-session-bridge.ts +59 -46
- package/src/calls/voice-triage-escalate.ts +175 -56
- package/src/cli/commands/__tests__/apps.test.ts +245 -0
- package/src/cli/commands/__tests__/bash.test.ts +53 -0
- package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
- package/src/cli/commands/apps.help.ts +67 -13
- package/src/cli/commands/apps.ts +183 -0
- package/src/cli/commands/bash.help.ts +8 -13
- package/src/cli/commands/bash.ts +7 -25
- package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
- package/src/cli/commands/channels/index.help.ts +70 -2
- package/src/cli/commands/channels/index.ts +16 -3
- package/src/cli/commands/channels/send.ts +128 -0
- package/src/cli/commands/credentials.help.ts +6 -2
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/roadmap.help.ts +5 -1
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +103 -90
- package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
- package/src/config/__tests__/platform-identity.test.ts +255 -0
- package/src/config/__tests__/platform-rehydration.test.ts +99 -9
- package/src/config/acp-agent-write.ts +43 -0
- package/src/config/acp-defaults.test.ts +13 -3
- package/src/config/acp-defaults.ts +23 -6
- package/src/config/acp-schema.test.ts +81 -0
- package/src/config/acp-schema.ts +30 -2
- package/src/config/bundled-skills/acp/SKILL.md +22 -14
- package/src/config/bundled-skills/acp/TOOLS.json +5 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +3 -4
- package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +24 -12
- package/src/config/loader.ts +1 -0
- package/src/config/memory-v3-gate.test.ts +31 -0
- package/src/config/memory-v3-gate.ts +20 -16
- package/src/config/platform-identity.ts +201 -0
- package/src/config/platform-rehydration.ts +11 -27
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
- package/src/config/schemas/__tests__/voice.test.ts +148 -0
- package/src/config/schemas/calls.ts +1 -28
- package/src/config/schemas/live-voice.ts +1 -173
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +10 -0
- package/src/config/schemas/services.ts +8 -0
- package/src/config/schemas/skills.ts +0 -14
- package/src/config/schemas/voice.ts +150 -0
- package/src/credential-execution/process-manager.test.ts +18 -19
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
- package/src/daemon/app-change-notify.ts +45 -0
- package/src/daemon/config-watcher.ts +13 -194
- package/src/daemon/conversation-process.ts +35 -64
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +10 -8
- package/src/daemon/conversation-tool-setup.ts +37 -43
- package/src/daemon/conversation.ts +0 -3
- package/src/daemon/host-bash-proxy.ts +8 -12
- package/src/daemon/host-browser-proxy.ts +15 -1
- package/src/daemon/host-file-proxy.ts +8 -10
- package/src/daemon/host-transfer-proxy.ts +14 -18
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/shutdown-handlers.ts +1 -9
- package/src/daemon/skill-memory-refresh.ts +64 -0
- package/src/daemon/tool-side-effects.ts +7 -18
- package/src/desktop/__tests__/fake-desktop.ts +119 -0
- package/src/desktop/desktop-chrome-policy.test.ts +71 -0
- package/src/desktop/desktop-chrome-policy.ts +42 -0
- package/src/desktop/desktop-dependencies.test.ts +102 -0
- package/src/desktop/desktop-dependencies.ts +306 -0
- package/src/desktop/desktop-feature.test.ts +18 -0
- package/src/desktop/desktop-feature.ts +19 -0
- package/src/desktop/desktop-panel-config.test.ts +135 -0
- package/src/desktop/desktop-panel-config.ts +149 -0
- package/src/desktop/desktop-session-manager.test.ts +627 -0
- package/src/desktop/desktop-session-manager.ts +814 -0
- package/src/desktop/desktop-stream-bridge.test.ts +395 -0
- package/src/desktop/desktop-stream-bridge.ts +214 -0
- package/src/desktop/desktop-wallpaper.test.ts +191 -0
- package/src/desktop/desktop-wallpaper.ts +113 -0
- package/src/desktop/desktop-window-theme.ts +170 -0
- package/src/home/__tests__/feed-writer.test.ts +22 -0
- package/src/home/feed-writer.ts +11 -2
- package/src/hooks/types.ts +33 -0
- package/src/i18n/AGENTS.md +22 -0
- package/src/i18n/__tests__/i18n.test.ts +108 -0
- package/src/i18n/index.ts +16 -0
- package/src/i18n/locales.ts +93 -0
- package/src/i18n/messages.ts +61 -0
- package/src/i18n/title.ts +25 -0
- package/src/inbound/platform-callback-registration.ts +4 -5
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/live-voice-session.ts +213 -693
- package/src/live-voice/protocol.ts +0 -2
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +29 -45
- package/src/mcp/spec-schema.ts +111 -0
- package/src/mcp/startup.ts +8 -4
- package/src/mcp/workspace-mcp-config.ts +188 -0
- package/src/messaging/provider.ts +10 -3
- package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
- package/src/messaging/providers/callback-routing.ts +18 -0
- package/src/messaging/providers/channel-transport.ts +56 -0
- package/src/messaging/providers/discord/transport.ts +17 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
- package/src/messaging/providers/slack/adapter.ts +7 -44
- package/src/messaging/providers/slack/transport.ts +16 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
- package/src/messaging/providers/telegram-bot/client.ts +0 -26
- package/src/messaging/providers/telegram-bot/transport.ts +20 -0
- package/src/messaging/providers/whatsapp/adapter.ts +1 -48
- package/src/messaging/providers/whatsapp/transport.ts +18 -0
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
- package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/assistant-reply-producer.ts +8 -3
- package/src/notifications/conversation-pairing.ts +36 -16
- package/src/notifications/delivered-post-record.ts +11 -1
- package/src/notifications/guardian-feed-projection.ts +125 -5
- package/src/notifications/home-feed-side-effect.ts +55 -7
- package/src/notifications/schedule-result-producer.ts +66 -22
- package/src/oauth/__tests__/seed-providers-managed.test.ts +54 -0
- package/src/oauth/byo-connection.test.ts +45 -0
- package/src/oauth/byo-connection.ts +36 -6
- package/src/oauth/connection-resolver.test.ts +73 -0
- package/src/oauth/connection-resolver.ts +95 -2
- package/src/oauth/seed-providers.ts +165 -0
- package/src/outbound-proxy/certs.ts +3 -5
- package/src/permissions/checker.test.ts +11 -6
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +71 -63
- package/src/persistence/conversation-lineage.ts +12 -4
- package/src/persistence/conversation-title-placeholders.ts +23 -0
- package/src/persistence/conversation-title-service.ts +9 -26
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-cursor.ts +78 -0
- package/src/persistence/message-reads.ts +30 -0
- package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
- package/src/persistence/schema/memory-core.ts +5 -0
- package/src/platform/client.test.ts +4 -2
- package/src/platform/client.ts +2 -10
- package/src/plugin-api/constants.ts +2 -0
- package/src/plugin-api/index.ts +1 -0
- package/src/plugin-api/types.ts +2 -0
- package/src/plugins/defaults/index.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
- package/src/plugins/defaults/memory/graph/capability-seed.ts +4 -6
- package/src/plugins/defaults/memory/hooks/init.ts +10 -0
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
- package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
- package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
- package/src/plugins/defaults/memory/startup.ts +6 -1
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +89 -0
- package/src/plugins/defaults/memory/worker.ts +6 -0
- package/src/plugins/mcp-servers.ts +15 -75
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/gemini/client.ts +9 -23
- package/src/providers/gemini-thought-signature.test.ts +63 -0
- package/src/providers/gemini-thought-signature.ts +44 -0
- package/src/providers/inference/auth.ts +2 -3
- package/src/providers/inference/connection-availability.ts +27 -8
- package/src/providers/inference/resolve-auth.ts +22 -4
- package/src/providers/inference/service-account-token.ts +248 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/model-intents.ts +10 -5
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
- package/src/providers/openai/chat-completions-provider.ts +192 -78
- package/src/providers/openai/codex-models.ts +0 -4
- package/src/providers/openai/google-thought-signature.ts +320 -0
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/channel-send.test.ts +443 -0
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
- package/src/runtime/auth/same-actor.ts +38 -3
- package/src/runtime/channel-send.ts +316 -0
- package/src/runtime/http-server.ts +160 -151
- package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +205 -0
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
- package/src/runtime/routes/acp-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +73 -0
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/channel-send-routes.ts +85 -0
- package/src/runtime/routes/conversation-list-routes.ts +14 -3
- package/src/runtime/routes/conversation-query-routes.ts +40 -0
- package/src/runtime/routes/credential-routes.ts +19 -10
- package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
- package/src/runtime/routes/desktop-setup-routes.ts +35 -0
- package/src/runtime/routes/diagnostics-routes.ts +55 -3
- package/src/runtime/routes/index.ts +4 -2
- package/src/runtime/routes/log-export-routes.ts +2 -0
- package/src/runtime/routes/mcp-auth-routes.ts +39 -47
- package/src/runtime/routes/migration-routes.ts +6 -20
- package/src/runtime/routes/platform-routes.ts +18 -15
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +16 -3
- package/src/runtime/sync/resource-sync-events.ts +2 -1
- package/src/schedule/worker.ts +1 -1
- package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
- package/src/security/ces-http-record-backend.ts +120 -0
- package/src/security/ces-rpc-record-backend.ts +7 -0
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
- package/src/skills/workspace-skill-md-signature.ts +50 -0
- package/src/subagent/consult-context.ts +12 -25
- package/src/tools/acp/list-agents.test.ts +3 -1
- package/src/tools/acp/spawn.test.ts +146 -11
- package/src/tools/acp/spawn.ts +21 -3
- package/src/tools/acp/status.test.ts +94 -0
- package/src/tools/acp/status.ts +40 -3
- package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
- package/src/tools/capability-offer.test.ts +22 -2
- package/src/tools/capability-offer.ts +16 -1
- package/src/tools/computer-use/definitions.ts +4 -2
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
- package/src/tools/credentials/metadata-store.ts +100 -0
- package/src/tools/host-filesystem/edit.test.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +2 -1
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +2 -1
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +16 -0
- package/src/tools/host-terminal/host-shell.ts +4 -20
- package/src/tools/policy-context.ts +6 -7
- package/src/tools/subagent/spawn.ts +5 -8
- package/src/tools/terminal/__tests__/safe-env.test.ts +6 -6
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
- package/src/tools/terminal/safe-env.ts +23 -3
- package/src/tools/terminal/sanitized-bash.ts +105 -0
- package/src/tools/watch/watch-retro-report.ts +0 -8
- package/src/util/__tests__/language-subtag.test.ts +23 -1
- package/src/util/ca-bundle.ts +13 -0
- package/src/util/language-subtag.ts +16 -0
- package/src/util/platform.ts +8 -0
- package/src/workspace/git-porcelain.ts +66 -0
- package/src/workspace/git-service.ts +5 -54
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/app-source-watcher.test.ts +0 -218
- package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
- package/src/__tests__/speaker-identification.test.ts +0 -56
- package/src/calls/speaker-identification.ts +0 -233
- package/src/daemon/app-source-watcher.ts +0 -218
- package/src/messaging/providers/whatsapp/client.ts +0 -29
- package/src/runtime/routes/debug-bash-routes.ts +0 -173
- package/src/util/fs-watcher-error.ts +0 -36
- /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
isActivationMomentParam,
|
|
56
56
|
} from "../telemetry/activation-funnel.js";
|
|
57
57
|
import { resolveAppId } from "../tools/apps/resolve-app-id.js";
|
|
58
|
+
import { formatDesktopAppRequired } from "../tools/capability-offer.js";
|
|
58
59
|
import { POINT_AT_PROXY_TOOL } from "../tools/computer-use/skill-proxy-bridge.js";
|
|
59
60
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
60
61
|
import { getLogger } from "../util/logger.js";
|
|
@@ -2936,7 +2937,7 @@ export function buildAppOpenPreview(
|
|
|
2936
2937
|
function describeComputerUseUnavailable(ctx: Conversation): string {
|
|
2937
2938
|
const capable = assistantEventHub.listClientsByCapability("host_cu");
|
|
2938
2939
|
if (capable.length === 0) {
|
|
2939
|
-
return "
|
|
2940
|
+
return formatDesktopAppRequired("screen");
|
|
2940
2941
|
}
|
|
2941
2942
|
return `Computer use is not available for this conversation — ${capable.length} desktop client(s) advertise host_cu, but none of them can be driven from this conversation's interface (${ctx.transportInterface ?? "unknown"}) as its current user.`;
|
|
2942
2943
|
}
|
|
@@ -3251,8 +3252,7 @@ export async function surfaceProxyResolver(
|
|
|
3251
3252
|
|
|
3252
3253
|
if (!ctx.hostAppControlProxy || !ctx.hostAppControlProxy.isAvailable()) {
|
|
3253
3254
|
return {
|
|
3254
|
-
content:
|
|
3255
|
-
"App control is not available — enable the `app-control` feature flag and connect a macOS client.",
|
|
3255
|
+
content: formatDesktopAppRequired("apps"),
|
|
3256
3256
|
isError: true,
|
|
3257
3257
|
};
|
|
3258
3258
|
}
|
|
@@ -3344,6 +3344,7 @@ export async function surfaceProxyResolver(
|
|
|
3344
3344
|
const caps = ctx.channelCapabilities;
|
|
3345
3345
|
if (
|
|
3346
3346
|
caps &&
|
|
3347
|
+
!ctx.hasNoClient &&
|
|
3347
3348
|
!caps.supportsDynamicUi &&
|
|
3348
3349
|
!isSlackTaskProgressUiException(ctx, toolName, input)
|
|
3349
3350
|
) {
|
|
@@ -3552,11 +3553,12 @@ export async function surfaceProxyResolver(
|
|
|
3552
3553
|
: surfaceType === "table"
|
|
3553
3554
|
? hasActions
|
|
3554
3555
|
: INTERACTIVE_SURFACE_TYPES.includes(surfaceType);
|
|
3555
|
-
//
|
|
3556
|
-
// actionless surface has nothing to await
|
|
3557
|
-
const awaitAction =
|
|
3558
|
-
|
|
3559
|
-
|
|
3556
|
+
// Background turns persist surfaces for a later conversation open and
|
|
3557
|
+
// return immediately. An actionless surface also has nothing to await.
|
|
3558
|
+
const awaitAction =
|
|
3559
|
+
!ctx.hasNoClient &&
|
|
3560
|
+
!isActionless &&
|
|
3561
|
+
((input.await_action as boolean) ?? isInteractive);
|
|
3560
3562
|
|
|
3561
3563
|
// Only one non-persistent interactive surface at a time. If another
|
|
3562
3564
|
// surface is already awaiting user input, reject this one so the LLM
|
|
@@ -28,7 +28,6 @@ import { getAllDefaultPluginNames } from "../plugins/defaults/main.js";
|
|
|
28
28
|
import { isActivationSession } from "../plugins/defaults/memory/activation-session-store.js";
|
|
29
29
|
import { isPluginDisabled } from "../plugins/disabled-state.js";
|
|
30
30
|
import type { Message, ToolDefinition } from "../providers/types.js";
|
|
31
|
-
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
32
31
|
import { registerConversationSender } from "../tools/browser/browser-screencast.js";
|
|
33
32
|
import { supportsClientOsForSkillTool } from "../tools/client-os.js";
|
|
34
33
|
import type { ToolExecutor } from "../tools/executor.js";
|
|
@@ -260,6 +259,24 @@ export function createToolExecutor(
|
|
|
260
259
|
// see {@link SubagentToolGateMode}): rejects non-allowlisted calls BEFORE
|
|
261
260
|
// any executor dispatch, so a non-allowlisted tool's executor never runs.
|
|
262
261
|
// The error tool_result lets the model continue or finish.
|
|
262
|
+
const rejectUnattendedHostTool = (
|
|
263
|
+
toolName: string,
|
|
264
|
+
): ToolExecutionResult | null => {
|
|
265
|
+
const { transportInterface } = resolveTurnClientOs(ctx);
|
|
266
|
+
const isUnattended = ctx.currentTurnIsNonInteractive ?? ctx.hasNoClient;
|
|
267
|
+
if (
|
|
268
|
+
HOST_TOOL_NAMES.has(toolName) &&
|
|
269
|
+
isUnattended &&
|
|
270
|
+
transportInterface !== "chrome-extension"
|
|
271
|
+
) {
|
|
272
|
+
return {
|
|
273
|
+
content: `The "${toolName}" tool requires an interactive user turn and cannot run in the background.`,
|
|
274
|
+
isError: true,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
return null;
|
|
278
|
+
};
|
|
279
|
+
|
|
263
280
|
const rejectNonAllowlistedTool = (
|
|
264
281
|
toolName: string,
|
|
265
282
|
): ToolExecutionResult | null => {
|
|
@@ -387,6 +404,10 @@ export function createToolExecutor(
|
|
|
387
404
|
if (rejection) {
|
|
388
405
|
return rejection;
|
|
389
406
|
}
|
|
407
|
+
const unattendedRejection = rejectUnattendedHostTool(executionName);
|
|
408
|
+
if (unattendedRejection) {
|
|
409
|
+
return unattendedRejection;
|
|
410
|
+
}
|
|
390
411
|
}
|
|
391
412
|
|
|
392
413
|
if (isDoordashCommand(executionName, executionInput)) {
|
|
@@ -550,6 +571,10 @@ export function createToolExecutor(
|
|
|
550
571
|
if (innerRejection) {
|
|
551
572
|
return innerRejection;
|
|
552
573
|
}
|
|
574
|
+
const unattendedRejection = rejectUnattendedHostTool(toolName);
|
|
575
|
+
if (unattendedRejection) {
|
|
576
|
+
return unattendedRejection;
|
|
577
|
+
}
|
|
553
578
|
|
|
554
579
|
// Per-chat plugin scope: reject the resolved inner tool when it belongs
|
|
555
580
|
// to a plugin outside the conversation's effective set.
|
|
@@ -628,7 +653,6 @@ export const DEFAULT_PREACTIVATED_SKILL_IDS = ["notifications", "subagent"];
|
|
|
628
653
|
// ── Conditional tool sets ────────────────────────────────────────────
|
|
629
654
|
|
|
630
655
|
const UI_SURFACE_TOOL_NAMES = new Set(["ui_show", "ui_update", "ui_dismiss"]);
|
|
631
|
-
const SLACK_TASK_PROGRESS_UI_TOOL_NAMES = new Set(["ui_show", "ui_update"]);
|
|
632
656
|
/**
|
|
633
657
|
* Single source of truth for which tools are host tools and the capability
|
|
634
658
|
* each one requires from the connected client interface. Adding a tool here
|
|
@@ -856,56 +880,26 @@ export function isToolActiveForContext(
|
|
|
856
880
|
return supportsChannelReaction(turnChannel);
|
|
857
881
|
}
|
|
858
882
|
if (UI_SURFACE_TOOL_NAMES.has(name)) {
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
return !hasNoClient;
|
|
864
|
-
}
|
|
865
|
-
return channelCapabilities?.supportsDynamicUi ?? !hasNoClient;
|
|
883
|
+
// Surface calls write conversation content. Background turns persist that
|
|
884
|
+
// content for the next client that opens the conversation, so presence
|
|
885
|
+
// cannot change whether the model receives these definitions.
|
|
886
|
+
return true;
|
|
866
887
|
}
|
|
867
888
|
if (HOST_TOOL_NAMES.has(name)) {
|
|
868
889
|
const capability = HOST_TOOL_TO_CAPABILITY.get(name);
|
|
869
890
|
const transport = transportInterface;
|
|
870
891
|
|
|
871
|
-
//
|
|
872
|
-
//
|
|
892
|
+
// A transport that does not implement a capability can invoke it through
|
|
893
|
+
// an eligible same-user client. Client selection happens when the call
|
|
894
|
+
// runs, so the wire schema stays stable across live and background turns.
|
|
873
895
|
if (transport && capability && !supportsHostProxy(transport, capability)) {
|
|
874
|
-
|
|
875
|
-
// cross-client routing infrastructure (Phases 1–3 plus host_browser
|
|
876
|
-
// via PR #27489) to be exposed for non-host-proxy transports (e.g.
|
|
877
|
-
// "web", "ios") when at least one capable client is connected via
|
|
878
|
-
// the event hub. Members of CROSS_CLIENT_EXPOSED_CAPABILITIES
|
|
879
|
-
// (host_bash, host_file, host_browser) qualify.
|
|
880
|
-
// chrome-extension transport is excluded as a security boundary
|
|
881
|
-
// (extension only gets host_browser via its own executor path);
|
|
882
|
-
// hasNoClient turns are excluded (no interactive approval UI
|
|
883
|
-
// available).
|
|
884
|
-
if (
|
|
885
|
-
capability &&
|
|
896
|
+
return (
|
|
886
897
|
CROSS_CLIENT_EXPOSED_CAPABILITIES.has(capability) &&
|
|
887
|
-
transport !== "chrome-extension"
|
|
888
|
-
|
|
889
|
-
assistantEventHub.listClientsByCapability(capability).length > 0
|
|
890
|
-
) {
|
|
891
|
-
return true;
|
|
892
|
-
}
|
|
893
|
-
return false;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
// chrome-extension is its own executor — the extension's popup gates
|
|
897
|
-
// commands via its own UI, and the transport does not use an SSE-level
|
|
898
|
-
// interactive approval channel. hasNoClient is intentionally `true` for
|
|
899
|
-
// chrome-extension turns (chrome-extension is not in INTERACTIVE_INTERFACES)
|
|
900
|
-
// and must not gate host_browser. Trust the per-capability check.
|
|
901
|
-
if (transport === "chrome-extension") {
|
|
902
|
-
return true;
|
|
898
|
+
transport !== "chrome-extension"
|
|
899
|
+
);
|
|
903
900
|
}
|
|
904
901
|
|
|
905
|
-
|
|
906
|
-
// fallback), deny when no client is present so the guardian auto-approve
|
|
907
|
-
// path cannot execute host commands unattended.
|
|
908
|
-
return !hasNoClient;
|
|
902
|
+
return true;
|
|
909
903
|
}
|
|
910
904
|
if (CLIENT_CAPABILITY_TOOL_NAMES.has(name)) {
|
|
911
905
|
if (name === "ask_question" && channelCapabilities?.clientOS === "macos") {
|
|
@@ -2366,9 +2366,6 @@ export class Conversation {
|
|
|
2366
2366
|
|
|
2367
2367
|
markStale(): void {
|
|
2368
2368
|
this.stale = true;
|
|
2369
|
-
// Invalidate the cached skill catalog so the next projection picks up
|
|
2370
|
-
// filesystem changes (e.g. a skill created during this run).
|
|
2371
|
-
this.skillProjectionCache.catalog = undefined;
|
|
2372
2369
|
}
|
|
2373
2370
|
|
|
2374
2371
|
isStale(): boolean {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { getConfig } from "../config/loader.js";
|
|
2
2
|
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
3
3
|
import {
|
|
4
|
-
ambiguousSameUserError,
|
|
5
4
|
enforceSameActorOrErrorResult,
|
|
6
|
-
|
|
5
|
+
pickMostRecentSameUserClient,
|
|
6
|
+
unavailableSameUserClientError,
|
|
7
7
|
} from "../runtime/auth/same-actor.js";
|
|
8
8
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
9
9
|
import { formatShellOutput } from "../tools/shared/shell-output.js";
|
|
@@ -93,21 +93,17 @@ export class HostBashProxy extends HostProxyBase<
|
|
|
93
93
|
}
|
|
94
94
|
resolvedTargetClientId = input.targetClientId;
|
|
95
95
|
} else {
|
|
96
|
-
|
|
97
|
-
// broadcast) when multiple same-user clients are connected so that
|
|
98
|
-
// a single targeted-style request cannot fan out across every one
|
|
99
|
-
// of the user's machines. Zero same-user matches falls through to
|
|
100
|
-
// the existing untargeted code path.
|
|
101
|
-
const resolved = pickSameUserAutoResolve({
|
|
96
|
+
resolvedTargetClientId = pickMostRecentSameUserClient({
|
|
102
97
|
hub: assistantEventHub,
|
|
103
98
|
capability: "host_bash",
|
|
104
99
|
sourceActorPrincipalId,
|
|
105
100
|
});
|
|
106
|
-
if (
|
|
107
|
-
|
|
101
|
+
if (
|
|
102
|
+
resolvedTargetClientId === undefined &&
|
|
103
|
+
sourceActorPrincipalId !== undefined
|
|
104
|
+
) {
|
|
105
|
+
return unavailableSameUserClientError("host_bash");
|
|
108
106
|
}
|
|
109
|
-
resolvedTargetClientId =
|
|
110
|
-
resolved.kind === "match" ? resolved.clientId : undefined;
|
|
111
107
|
}
|
|
112
108
|
|
|
113
109
|
// Targeted requests must be bound to the same authenticated user as the
|
|
@@ -5,7 +5,10 @@ import {
|
|
|
5
5
|
assistantEventHub,
|
|
6
6
|
broadcastMessage,
|
|
7
7
|
} from "../runtime/assistant-event-hub.js";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
enforceSameActorOrErrorResult,
|
|
10
|
+
unavailableSameUserClientError,
|
|
11
|
+
} from "../runtime/auth/same-actor.js";
|
|
9
12
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
10
13
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
11
14
|
import { AssistantError, ErrorCode } from "../util/errors.js";
|
|
@@ -284,6 +287,17 @@ export class HostBrowserProxy {
|
|
|
284
287
|
targetClientId,
|
|
285
288
|
);
|
|
286
289
|
|
|
290
|
+
if (
|
|
291
|
+
preferredClient === undefined &&
|
|
292
|
+
sourceActorPrincipalId !== undefined &&
|
|
293
|
+
targetClientId === undefined
|
|
294
|
+
) {
|
|
295
|
+
if (isExtensionOnlyMethod(input.cdpMethod)) {
|
|
296
|
+
return Promise.resolve(extensionRequiredResult(input.cdpMethod));
|
|
297
|
+
}
|
|
298
|
+
return Promise.resolve(unavailableSameUserClientError("host_browser"));
|
|
299
|
+
}
|
|
300
|
+
|
|
287
301
|
// Same-user enforcement: when the caller's actor is known, refuse to
|
|
288
302
|
// dispatch to a client owned by a different actor. This covers the
|
|
289
303
|
// cross-client exposure case where a web/iOS turn for actor A would
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
broadcastMessage,
|
|
7
7
|
} from "../runtime/assistant-event-hub.js";
|
|
8
8
|
import {
|
|
9
|
-
ambiguousSameUserError,
|
|
10
9
|
enforceSameActorOrErrorResult,
|
|
11
|
-
|
|
10
|
+
pickMostRecentSameUserClient,
|
|
12
11
|
snapshotHostProxyActorPrincipalId,
|
|
12
|
+
unavailableSameUserClientError,
|
|
13
13
|
} from "../runtime/auth/same-actor.js";
|
|
14
14
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
15
15
|
import { readAudioBase64 } from "../tools/shared/filesystem/audio-read.js";
|
|
@@ -102,19 +102,17 @@ export class HostFileProxy {
|
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
104
|
} else {
|
|
105
|
-
|
|
106
|
-
// (multi-machine) cases so a single targeted-style request cannot
|
|
107
|
-
// fan out across the user's machines.
|
|
108
|
-
const resolved = pickSameUserAutoResolve({
|
|
105
|
+
resolvedTargetClientId = pickMostRecentSameUserClient({
|
|
109
106
|
hub: assistantEventHub,
|
|
110
107
|
capability: "host_file",
|
|
111
108
|
sourceActorPrincipalId,
|
|
112
109
|
});
|
|
113
|
-
if (
|
|
114
|
-
|
|
110
|
+
if (
|
|
111
|
+
resolvedTargetClientId === undefined &&
|
|
112
|
+
sourceActorPrincipalId !== undefined
|
|
113
|
+
) {
|
|
114
|
+
return Promise.resolve(unavailableSameUserClientError("host_file"));
|
|
115
115
|
}
|
|
116
|
-
resolvedTargetClientId =
|
|
117
|
-
resolved.kind === "match" ? resolved.clientId : undefined;
|
|
118
116
|
}
|
|
119
117
|
|
|
120
118
|
// Same-user check: targeted host_file requests must be bound to the same
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
broadcastMessage,
|
|
11
11
|
} from "../runtime/assistant-event-hub.js";
|
|
12
12
|
import {
|
|
13
|
-
ambiguousSameUserError,
|
|
14
13
|
enforceSameActorOrErrorResult,
|
|
15
|
-
|
|
14
|
+
pickMostRecentSameUserClient,
|
|
16
15
|
snapshotHostProxyActorPrincipalId,
|
|
16
|
+
unavailableSameUserClientError,
|
|
17
17
|
} from "../runtime/auth/same-actor.js";
|
|
18
18
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
19
19
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
@@ -162,19 +162,17 @@ export class HostTransferProxy {
|
|
|
162
162
|
});
|
|
163
163
|
}
|
|
164
164
|
} else {
|
|
165
|
-
|
|
166
|
-
// (multi-machine) cases so a single targeted-style transfer cannot
|
|
167
|
-
// fan out across the user's machines.
|
|
168
|
-
const resolved = pickSameUserAutoResolve({
|
|
165
|
+
resolvedTargetClientId = pickMostRecentSameUserClient({
|
|
169
166
|
hub: assistantEventHub,
|
|
170
167
|
capability: "host_file",
|
|
171
168
|
sourceActorPrincipalId,
|
|
172
169
|
});
|
|
173
|
-
if (
|
|
174
|
-
|
|
170
|
+
if (
|
|
171
|
+
resolvedTargetClientId === undefined &&
|
|
172
|
+
sourceActorPrincipalId !== undefined
|
|
173
|
+
) {
|
|
174
|
+
return Promise.resolve(unavailableSameUserClientError("host_file"));
|
|
175
175
|
}
|
|
176
|
-
resolvedTargetClientId =
|
|
177
|
-
resolved.kind === "match" ? resolved.clientId : undefined;
|
|
178
176
|
}
|
|
179
177
|
|
|
180
178
|
if (resolvedTargetClientId != null) {
|
|
@@ -364,19 +362,17 @@ export class HostTransferProxy {
|
|
|
364
362
|
});
|
|
365
363
|
}
|
|
366
364
|
} else {
|
|
367
|
-
|
|
368
|
-
// (multi-machine) cases so a single targeted-style transfer cannot
|
|
369
|
-
// fan out across the user's machines.
|
|
370
|
-
const resolved = pickSameUserAutoResolve({
|
|
365
|
+
resolvedTargetClientId = pickMostRecentSameUserClient({
|
|
371
366
|
hub: assistantEventHub,
|
|
372
367
|
capability: "host_file",
|
|
373
368
|
sourceActorPrincipalId,
|
|
374
369
|
});
|
|
375
|
-
if (
|
|
376
|
-
|
|
370
|
+
if (
|
|
371
|
+
resolvedTargetClientId === undefined &&
|
|
372
|
+
sourceActorPrincipalId !== undefined
|
|
373
|
+
) {
|
|
374
|
+
return Promise.resolve(unavailableSameUserClientError("host_file"));
|
|
377
375
|
}
|
|
378
|
-
resolvedTargetClientId =
|
|
379
|
-
resolved.kind === "match" ? resolved.clientId : undefined;
|
|
380
376
|
}
|
|
381
377
|
|
|
382
378
|
if (resolvedTargetClientId != null) {
|
package/src/daemon/lifecycle.ts
CHANGED
|
@@ -71,7 +71,6 @@ import { ensureCompleteCustomProfiles } from "../workspace/custom-profile-ensure
|
|
|
71
71
|
import { ensureDefaultProvider } from "../workspace/default-provider-ensure.js";
|
|
72
72
|
import { WORKSPACE_MIGRATIONS } from "../workspace/migrations/registry.js";
|
|
73
73
|
import { runWorkspaceMigrations } from "../workspace/migrations/runner.js";
|
|
74
|
-
import { startAppSourceWatcher } from "./app-source-watcher.js";
|
|
75
74
|
import { startConfigWatcher } from "./config-watcher.js";
|
|
76
75
|
import { startConversationEvictor } from "./conversation-evictor.js";
|
|
77
76
|
import { writePid } from "./daemon-control.js";
|
|
@@ -706,10 +705,6 @@ export async function runDaemon(): Promise<void> {
|
|
|
706
705
|
// config, and broadcast the relevant resource-changed events to clients.
|
|
707
706
|
startConfigWatcher();
|
|
708
707
|
|
|
709
|
-
// Watch app source directories so edits recompile + refresh surfaces across
|
|
710
|
-
// all conversations.
|
|
711
|
-
startAppSourceWatcher();
|
|
712
|
-
|
|
713
708
|
// Start the CLI IPC server. Throws on EADDRINUSE to abort startup when another
|
|
714
709
|
// daemon already holds the socket, so this process never runs background jobs
|
|
715
710
|
// against the shared database as an unmanageable duplicate.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared MCP reload business logic.
|
|
3
3
|
*
|
|
4
|
-
* Called by the ConfigWatcher when
|
|
4
|
+
* Called by the ConfigWatcher when mcp.json changes or a reload signal
|
|
5
5
|
* file is detected, so the daemon automatically reconnects MCP servers.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { invalidateConfigCache } from "../config/loader.js";
|
|
9
9
|
import {
|
|
10
10
|
buildEffectiveMcpConfig,
|
|
11
11
|
pluginMcpServersChangedSinceLastBuild,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { getMcpServerManager } from "../mcp/manager.js";
|
|
14
14
|
import { migrateLegacyMcpHeaders } from "../mcp/mcp-header-store.js";
|
|
15
15
|
import { signalMcpReloaded } from "../mcp/reload-signal.js";
|
|
16
|
+
import { loadWorkspaceMcpConfig } from "../mcp/workspace-mcp-config.js";
|
|
16
17
|
import { createMcpToolsFromServer } from "../tools/mcp/mcp-tool-factory.js";
|
|
17
18
|
import { registerMcpTools, unregisterAllMcpTools } from "../tools/registry.js";
|
|
18
19
|
import { getLogger } from "../util/logger.js";
|
|
@@ -95,16 +96,15 @@ async function doReload(): Promise<McpReloadResult> {
|
|
|
95
96
|
// If the config is broken we abort early, preserving the current
|
|
96
97
|
// working MCP setup instead of leaving zero servers.
|
|
97
98
|
invalidateConfigCache();
|
|
98
|
-
const config = getConfig();
|
|
99
99
|
|
|
100
100
|
// 2. Stop existing MCP servers + unregister their tools
|
|
101
101
|
await manager.stop();
|
|
102
102
|
unregisterAllMcpTools();
|
|
103
103
|
|
|
104
104
|
// Plugins are re-read here too: installing or removing one changes the
|
|
105
|
-
// server set exactly like editing
|
|
105
|
+
// server set exactly like editing mcp.json does, and both arrive
|
|
106
106
|
// through this same reload.
|
|
107
|
-
const mcpConfig = buildEffectiveMcpConfig(
|
|
107
|
+
const mcpConfig = buildEffectiveMcpConfig(loadWorkspaceMcpConfig());
|
|
108
108
|
const serverIds = Object.keys(mcpConfig.servers);
|
|
109
109
|
|
|
110
110
|
// 3. Restart MCP servers
|
|
@@ -13,6 +13,7 @@ export const SYNC_TAGS = {
|
|
|
13
13
|
assistantConfig: "assistant:self:config",
|
|
14
14
|
assistantSounds: "assistant:self:sounds",
|
|
15
15
|
assistantSchedules: "assistant:self:schedules",
|
|
16
|
+
assistantDesktop: "assistant:self:desktop",
|
|
16
17
|
assistantTheme: "assistant:self:theme",
|
|
17
18
|
appsList: "apps:list",
|
|
18
19
|
documentsList: "documents:list",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Tools run commands in their own process group (`detached: true`) and, on
|
|
5
5
|
* timeout/abort, group-kill with `process.kill(-pgid, SIGKILL)` (the bash and
|
|
6
|
-
* host_bash tools, the skill sandbox runner
|
|
6
|
+
* host_bash tools, and the skill sandbox runner). The
|
|
7
7
|
* immediate child is reaped by Bun/libuv, but its descendants — e.g. git's
|
|
8
8
|
* transport helpers or a skill runner's `bun` process — were never spawned by
|
|
9
9
|
* the daemon, so when the group dies they reparent to PID 1. When the daemon
|
|
@@ -63,7 +63,7 @@ export async function initializeProvidersAndTools(
|
|
|
63
63
|
// Start MCP servers — workspace-configured and plugin-declared alike —
|
|
64
64
|
// and register their tools. Shared with the schedule worker, which hosts
|
|
65
65
|
// agent turns in its own process and so needs its own connections.
|
|
66
|
-
await startConfiguredMcpServers(
|
|
66
|
+
await startConfiguredMcpServers();
|
|
67
67
|
|
|
68
68
|
log.info("Daemon startup: providers and tools initialized");
|
|
69
69
|
}
|
|
@@ -24,11 +24,7 @@ import { browserManager } from "../tools/browser/browser-manager.js";
|
|
|
24
24
|
import { getLogger } from "../util/logger.js";
|
|
25
25
|
import { APP_VERSION } from "../version.js";
|
|
26
26
|
import { getEnrichmentService } from "../workspace/commit-message-enrichment-service.js";
|
|
27
|
-
import {
|
|
28
|
-
commitAllPendingWorkspaceChanges,
|
|
29
|
-
stopWorkspaceHeartbeatService,
|
|
30
|
-
} from "../workspace/heartbeat-service.js";
|
|
31
|
-
import { stopAppSourceWatcher } from "./app-source-watcher.js";
|
|
27
|
+
import { commitAllPendingWorkspaceChanges } from "../workspace/heartbeat-service.js";
|
|
32
28
|
import { stopConfigWatcher } from "./config-watcher.js";
|
|
33
29
|
import { stopConversationEvictor } from "./conversation-evictor.js";
|
|
34
30
|
import { stopConversations } from "./conversation-store.js";
|
|
@@ -98,9 +94,6 @@ async function shutdown(): Promise<void> {
|
|
|
98
94
|
}, 30_000);
|
|
99
95
|
forceTimer.unref();
|
|
100
96
|
|
|
101
|
-
// Workspace git heartbeat timer lives in the monitor process. This
|
|
102
|
-
// in-process stop is a no-op unless the singleton was started here.
|
|
103
|
-
await stopWorkspaceHeartbeatService();
|
|
104
97
|
await stopHeartbeatService();
|
|
105
98
|
|
|
106
99
|
// Stop the periodic consent-cache refresh (a daemon-owned interval).
|
|
@@ -134,7 +127,6 @@ async function shutdown(): Promise<void> {
|
|
|
134
127
|
disposeAcpSessionManager();
|
|
135
128
|
stopConversationEvictor();
|
|
136
129
|
stopConfigWatcher();
|
|
137
|
-
stopAppSourceWatcher();
|
|
138
130
|
stopCliIpcServer();
|
|
139
131
|
stopConversations();
|
|
140
132
|
await stopCes();
|
|
@@ -8,16 +8,24 @@ import {
|
|
|
8
8
|
maybeSeedCapabilitySkills,
|
|
9
9
|
maybeSeedCliCommandCards,
|
|
10
10
|
} from "../plugins/defaults/memory/substrate/boot-maintenance.js";
|
|
11
|
+
import { readWorkspaceSkillMdSignature } from "../skills/workspace-skill-md-signature.js";
|
|
11
12
|
import { getLogger } from "../util/logger.js";
|
|
12
13
|
|
|
13
14
|
const log = getLogger("skill-memory-refresh");
|
|
14
15
|
|
|
16
|
+
/** Poll interval for workspace `SKILL.md` mtimes. Stats only, no tree walk. */
|
|
17
|
+
export const SKILL_MD_MTIME_POLL_MS = 1_500;
|
|
18
|
+
|
|
19
|
+
let lastSignature: string | undefined;
|
|
20
|
+
let pollTimer: ReturnType<typeof setInterval> | undefined;
|
|
21
|
+
|
|
15
22
|
export function refreshSkillCapabilityMemories(
|
|
16
23
|
config: AssistantConfig = getConfig(),
|
|
17
24
|
): void {
|
|
18
25
|
seedSkillGraphNodes();
|
|
19
26
|
maybeSeedCapabilitySkills(config);
|
|
20
27
|
maybeSeedCliCommandCards(config);
|
|
28
|
+
lastSignature = readWorkspaceSkillMdSignature();
|
|
21
29
|
void seedUninstalledCatalogSkillMemories()
|
|
22
30
|
.then(() => {
|
|
23
31
|
// Re-run after the async catalog fetch populates the cache so stale
|
|
@@ -31,3 +39,59 @@ export function refreshSkillCapabilityMemories(
|
|
|
31
39
|
),
|
|
32
40
|
);
|
|
33
41
|
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Reseed skill capability memories when the workspace `SKILL.md` set or
|
|
45
|
+
* mtimes have changed since the last refresh in this process. No-op when the
|
|
46
|
+
* signature is unchanged. First call in a process always reseeds so the
|
|
47
|
+
* memory worker, whose in-process skill cache starts empty, picks up the
|
|
48
|
+
* catalog without waiting for an install path.
|
|
49
|
+
*/
|
|
50
|
+
export function maybeRefreshSkillCapabilityMemoriesFromMtime(): boolean {
|
|
51
|
+
const signature = readWorkspaceSkillMdSignature();
|
|
52
|
+
if (lastSignature !== undefined && signature === lastSignature) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (lastSignature !== undefined) {
|
|
56
|
+
log.info("Workspace SKILL.md set changed, reseeding capability memories");
|
|
57
|
+
}
|
|
58
|
+
refreshSkillCapabilityMemories();
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function pollOnce(): void {
|
|
63
|
+
try {
|
|
64
|
+
maybeRefreshSkillCapabilityMemoriesFromMtime();
|
|
65
|
+
} catch (err) {
|
|
66
|
+
log.warn({ err }, "SKILL.md mtime poll failed");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Start a per-process poll of workspace `SKILL.md` mtimes. Idempotent.
|
|
72
|
+
* The memory worker and the assistant each run this against their own
|
|
73
|
+
* in-process skill caches. Runs once immediately so a worker that has never
|
|
74
|
+
* seeded picks up the catalog without waiting a tick.
|
|
75
|
+
*/
|
|
76
|
+
export function startWorkspaceSkillMdMtimePoll(): void {
|
|
77
|
+
if (pollTimer !== undefined) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
pollOnce();
|
|
81
|
+
pollTimer = setInterval(pollOnce, SKILL_MD_MTIME_POLL_MS);
|
|
82
|
+
pollTimer.unref?.();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function stopWorkspaceSkillMdMtimePoll(): void {
|
|
86
|
+
if (pollTimer === undefined) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
clearInterval(pollTimer);
|
|
90
|
+
pollTimer = undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** @internal Test-only: clear the in-process signature and poll timer. */
|
|
94
|
+
export function _resetSkillMdMtimeStateForTests(): void {
|
|
95
|
+
lastSignature = undefined;
|
|
96
|
+
stopWorkspaceSkillMdMtimePoll();
|
|
97
|
+
}
|
|
@@ -18,17 +18,15 @@ import { invalidateEdgeIndex } from "../plugins/defaults/memory/substrate/edge-i
|
|
|
18
18
|
import { invalidatePageIndex } from "../plugins/defaults/memory/substrate/page-index.js";
|
|
19
19
|
import { getConceptsDir } from "../plugins/defaults/memory/substrate/page-store.js";
|
|
20
20
|
import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
21
|
-
import {
|
|
22
|
-
publishAppsChanged,
|
|
23
|
-
publishDocumentsChanged,
|
|
24
|
-
} from "../runtime/sync/resource-sync-events.js";
|
|
25
|
-
import { updatePublishedAppDeployment } from "../services/published-app-updater.js";
|
|
21
|
+
import { publishDocumentsChanged } from "../runtime/sync/resource-sync-events.js";
|
|
26
22
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
27
23
|
import { getLogger } from "../util/logger.js";
|
|
28
24
|
import { getWorkspaceDir } from "../util/platform.js";
|
|
29
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
broadcastAppFilesChanged,
|
|
27
|
+
notifyAppSurfacesChanged,
|
|
28
|
+
} from "./app-change-notify.js";
|
|
30
29
|
import type { Conversation } from "./conversation.js";
|
|
31
|
-
import { refreshSurfacesForApp } from "./conversation-surfaces.js";
|
|
32
30
|
import { isDoordashCommand, updateDoordashProgress } from "./doordash-steps.js";
|
|
33
31
|
|
|
34
32
|
const log = getLogger("tool-side-effects");
|
|
@@ -54,7 +52,7 @@ export type PostExecutionHook = (
|
|
|
54
52
|
* Compilation is the responsibility of the tool executor (see
|
|
55
53
|
* `executeAppCreate`, `executeAppRefresh`): executors own the source→dist
|
|
56
54
|
* transform and surface `compile_errors` in their result when it fails.
|
|
57
|
-
* Post-execution hooks only observe the outcome and notify
|
|
55
|
+
* Post-execution hooks only observe the outcome and notify. They must
|
|
58
56
|
* not re-run a compile because `compileApp()` begins with `rm -rf dist/`
|
|
59
57
|
* and would race with the executor's own output (LUM-1153).
|
|
60
58
|
*/
|
|
@@ -63,14 +61,7 @@ function notifyAppChanged(
|
|
|
63
61
|
appId: string,
|
|
64
62
|
opts?: { fileChange?: boolean; status?: string },
|
|
65
63
|
): void {
|
|
66
|
-
|
|
67
|
-
broadcastAppFilesChanged(appId);
|
|
68
|
-
void updatePublishedAppDeployment(appId);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function broadcastAppFilesChanged(appId: string): void {
|
|
72
|
-
broadcastMessage({ type: "app_files_changed", appId });
|
|
73
|
-
publishAppsChanged();
|
|
64
|
+
notifyAppSurfacesChanged(appId, opts, ctx);
|
|
74
65
|
}
|
|
75
66
|
|
|
76
67
|
/**
|
|
@@ -128,8 +119,6 @@ registerHook("app_create", (_name, _input, result, { ctx }) => {
|
|
|
128
119
|
log.warn({ err, appId }, "Failed to track conversation ID on app_create");
|
|
129
120
|
}
|
|
130
121
|
|
|
131
|
-
ensureAppSourceWatcher();
|
|
132
|
-
|
|
133
122
|
notifyAppChanged(ctx, appId);
|
|
134
123
|
|
|
135
124
|
// Seed background icon generation from the created app's canonical record
|