@vellumai/assistant 0.12.1 → 0.12.2-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -0
- package/ARCHITECTURE.md +20 -21
- package/docs/architecture/turn-actor.md +15 -8
- package/docs/guardian-request-flow.md +16 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +13 -8
- package/node_modules/@vellumai/slack-text/src/label-resolution-entities.test.ts +95 -0
- package/openapi.yaml +360 -51
- package/package.json +3 -1
- package/scripts/smoke-desktop-window-theme.ts +186 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
- package/src/__tests__/anthropic-provider.test.ts +0 -63
- 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__/assistant-event-hub-machine-name.test.ts +6 -7
- package/src/__tests__/assistant-event-hub.test.ts +44 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
- package/src/__tests__/computer-use-tools.test.ts +19 -7
- 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-runtime-assembly.test.ts +28 -0
- 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-point-at-budget.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-point-at-capability.test.ts +1 -0
- 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 +250 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/cu-unified-flow.test.ts +14 -4
- 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__/heartbeat-service.test.ts +56 -40
- 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-cu-proxy.test.ts +596 -0
- 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__/list-messages-camera-frame.test.ts +121 -0
- 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__/oauth-commands-routes.test.ts +168 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +22 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-provider.test.ts +1 -0
- 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 +14 -0
- package/src/__tests__/qdrant-manager.test.ts +132 -0
- package/src/__tests__/resolve-app.test.ts +135 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
- package/src/__tests__/script-proxy-certs.test.ts +35 -0
- package/src/__tests__/secret-routes-acp-guard.test.ts +59 -1
- 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__/skills.test.ts +9 -4
- package/src/__tests__/source-fingerprint.test.ts +184 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +70 -3
- package/src/__tests__/subagent-tools.test.ts +3 -2
- package/src/__tests__/telephony-tts-guard.test.ts +38 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/ui-channel-variants.test.ts +1 -56
- package/src/__tests__/unicode.test.ts +13 -0
- 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__/acp-claude-oauth.test.ts +257 -6
- package/src/acp/__tests__/acp-credentials.test.ts +13 -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__/claude-token-refresh.test.ts +257 -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__/prepare-agent-env.test.ts +60 -1
- 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/acp-claude-oauth.ts +328 -14
- package/src/acp/acp-credentials.ts +19 -0
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +96 -10
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/claude-token-refresh.ts +150 -0
- 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/prepare-agent-env.ts +21 -6
- 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/agent/loop.ts +1 -0
- 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/events/user-message-echo.ts +7 -1
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -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/avatar/identity-avatar.ts +7 -2
- 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 +120 -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 +56 -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 +155 -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 +92 -72
- package/src/calls/voice-triage-escalate.ts +178 -59
- 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/oauth/status.ts +5 -0
- 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/computer-use/SKILL.md +29 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -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/playbooks/tools/playbook-create.ts +2 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -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 +6 -2
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +33 -13
- package/src/config/loader.ts +2 -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 +18 -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/credential-health/credential-health-service.ts +11 -17
- 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-error.ts +3 -2
- package/src/daemon/conversation-media-retry.ts +2 -1
- package/src/daemon/conversation-process.ts +35 -64
- package/src/daemon/conversation-runtime-assembly.ts +20 -7
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +21 -10
- package/src/daemon/conversation-tool-setup.ts +45 -59
- package/src/daemon/conversation.ts +0 -3
- package/src/daemon/dictation-profile-store.ts +2 -1
- package/src/daemon/handlers/shared.ts +2 -1
- package/src/daemon/handlers/skills.ts +6 -3
- package/src/daemon/host-bash-proxy.ts +8 -12
- package/src/daemon/host-browser-proxy.ts +15 -1
- package/src/daemon/host-cu-proxy.ts +224 -19
- package/src/daemon/host-file-proxy.ts +8 -10
- package/src/daemon/host-proxy-preactivation.ts +2 -1
- 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/reaction-history-render.ts +2 -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 +122 -0
- package/src/desktop/desktop-chrome-policy.test.ts +79 -0
- package/src/desktop/desktop-chrome-policy.ts +47 -0
- package/src/desktop/desktop-chrome-session.ts +37 -0
- package/src/desktop/desktop-dependencies.test.ts +102 -0
- package/src/desktop/desktop-dependencies.ts +308 -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 +730 -0
- package/src/desktop/desktop-session-manager.ts +850 -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-drag.ts +177 -0
- package/src/desktop/desktop-window-manager-config.test.ts +230 -0
- package/src/desktop/desktop-window-manager-config.ts +238 -0
- package/src/desktop/desktop-window-theme.ts +170 -0
- package/src/heartbeat/heartbeat-service.ts +21 -3
- 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-agent-turn.test.ts +121 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +8 -7
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +94 -15
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/live-voice/__tests__/protocol.test.ts +39 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/__tests__/session-controls.test.ts +79 -0
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +297 -699
- package/src/live-voice/protocol.ts +60 -2
- package/src/live-voice/session-controls.ts +111 -0
- 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/AGENTS.md +2 -0
- package/src/oauth/__tests__/seed-providers-managed.test.ts +149 -0
- package/src/oauth/byo-connection.test.ts +105 -0
- package/src/oauth/byo-connection.ts +36 -6
- package/src/oauth/connection-resolver.test.ts +100 -0
- package/src/oauth/connection-resolver.ts +120 -3
- package/src/oauth/provider-serializer.ts +9 -0
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +314 -27
- 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-queries.ts +2 -2
- package/src/persistence/conversation-title-placeholders.ts +23 -0
- package/src/persistence/conversation-title-service.ts +9 -26
- package/src/persistence/embeddings/qdrant-manager.ts +163 -18
- 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-prompt.test.ts +5 -0
- 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/context-search/agent-runner.ts +3 -2
- package/src/plugins/defaults/memory/context-search/format.ts +3 -2
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
- 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/host-utils.ts +10 -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-prompt.ts +1 -1
- 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 +28 -2
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
- package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
- package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
- package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
- package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
- package/src/plugins/defaults/memory/v3/card.ts +3 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
- package/src/plugins/defaults/memory/v3/sections.ts +9 -3
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
- 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/__tests__/retry-callsite.test.ts +41 -0
- package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
- package/src/providers/anthropic/client.ts +0 -47
- 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/__tests__/endpoint-probe.test.ts +42 -3
- package/src/providers/inference/auth.ts +2 -3
- package/src/providers/inference/connection-availability.ts +27 -8
- package/src/providers/inference/endpoint-probe.ts +10 -1
- 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-output-token-limit.test.ts +141 -0
- 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 +212 -79
- package/src/providers/openai/codex-models.ts +0 -4
- package/src/providers/openai/google-thought-signature.ts +320 -0
- package/src/providers/opencode/client.test.ts +73 -4
- package/src/providers/opencode/client.ts +60 -3
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/outbound-request-sanitize.ts +96 -0
- package/src/providers/retry.ts +30 -19
- package/src/providers/unparseable-tool-args.ts +5 -1
- package/src/runtime/AGENTS.md +3 -1
- 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__/host-observe.test.ts +40 -1
- 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/agent-wake.ts +2 -1
- package/src/runtime/assistant-event-hub.ts +21 -3
- package/src/runtime/auth/same-actor.ts +38 -3
- package/src/runtime/channel-send.ts +316 -0
- package/src/runtime/host-observe.ts +11 -1
- package/src/runtime/http-server.ts +160 -151
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +16 -5
- package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +275 -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-claude-auth-routes.ts +11 -3
- 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 +90 -2
- 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/conversation-routes.ts +16 -3
- package/src/runtime/routes/credential-routes.ts +20 -14
- 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 +61 -4
- package/src/runtime/routes/events-routes.ts +4 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -0
- 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/oauth-commands-routes.ts +50 -0
- package/src/runtime/routes/oauth-providers.ts +7 -0
- package/src/runtime/routes/platform-routes.ts +18 -15
- package/src/runtime/routes/workspace-routes.test.ts +55 -26
- package/src/runtime/routes/workspace-routes.ts +46 -63
- package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
- package/src/runtime/routes/workspace-tree-walk.ts +240 -0
- package/src/runtime/routes/workspace-utils.ts +17 -0
- 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/run-script.ts +2 -1
- package/src/schedule/schedule-store.ts +9 -2
- 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/security/untrusted-content.ts +3 -1
- 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/__tests__/side-effect-abort-guard.test.ts +1 -0
- 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/browser/browser-execution.ts +1 -1
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
- package/src/tools/browser/network-recorder.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 +121 -2
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
- package/src/tools/credentials/metadata-store.ts +100 -0
- package/src/tools/filesystem/search.ts +2 -1
- 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/network/web-search.ts +6 -1
- package/src/tools/policy-context.ts +6 -7
- package/src/tools/skills/scaffold-managed.ts +61 -3
- package/src/tools/subagent/spawn.ts +5 -8
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
- package/src/tools/terminal/sanitized-bash.ts +105 -0
- package/src/tools/ui-surface/channel-variants.ts +10 -59
- package/src/tools/watch/watch-retro-report.ts +0 -8
- package/src/types/host-capabilities.ts +5 -3
- 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/util/unicode.ts +15 -1
- package/src/watch/watch-retro.ts +6 -8
- package/src/watch/watch-timeline.ts +2 -2
- package/src/workflows/run-manager.ts +2 -1
- package/src/workspace/git-porcelain.ts +66 -0
- package/src/workspace/git-service.ts +6 -55
- 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
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* File watchers and config reload logic extracted from DaemonServer.
|
|
3
|
-
* Watches workspace files (config, prompts
|
|
4
|
-
*
|
|
3
|
+
* Watches workspace files (config, prompts, signals, avatar, sounds).
|
|
4
|
+
* Skill capability cards reseed from SKILL.md mtimes in the memory worker
|
|
5
|
+
* and the assistant process, not from this watcher.
|
|
5
6
|
*/
|
|
6
7
|
import {
|
|
7
8
|
existsSync,
|
|
8
9
|
type FSWatcher,
|
|
9
10
|
mkdirSync,
|
|
10
|
-
readdirSync,
|
|
11
11
|
readFileSync,
|
|
12
12
|
unwatchFile,
|
|
13
13
|
watch,
|
|
14
14
|
watchFile,
|
|
15
15
|
} from "node:fs";
|
|
16
|
-
import {
|
|
16
|
+
import { join } from "node:path";
|
|
17
17
|
|
|
18
18
|
import { AVATAR_IMAGE_FILENAME } from "@vellumai/avatar-manifest";
|
|
19
19
|
|
|
@@ -44,50 +44,14 @@ import {
|
|
|
44
44
|
getSoundsDir,
|
|
45
45
|
getWorkspaceDir,
|
|
46
46
|
getWorkspacePromptPath,
|
|
47
|
-
|
|
47
|
+
WORKSPACE_MCP_FILENAME,
|
|
48
48
|
} from "../util/platform.js";
|
|
49
49
|
import { evictConversationsForReload } from "./conversation-store.js";
|
|
50
50
|
import { parseIdentityFields } from "./handlers/identity.js";
|
|
51
51
|
import { reloadMcpServers } from "./mcp-reload-service.js";
|
|
52
|
-
import { refreshSkillCapabilityMemories } from "./skill-memory-refresh.js";
|
|
53
52
|
|
|
54
53
|
const log = getLogger("config-watcher");
|
|
55
54
|
|
|
56
|
-
const SKILL_WATCH_SKIPPED_DIRS = new Set([
|
|
57
|
-
"node_modules",
|
|
58
|
-
".git",
|
|
59
|
-
"__pycache__",
|
|
60
|
-
".install-staging",
|
|
61
|
-
".cache",
|
|
62
|
-
".next",
|
|
63
|
-
".turbo",
|
|
64
|
-
".venv",
|
|
65
|
-
"coverage",
|
|
66
|
-
]);
|
|
67
|
-
|
|
68
|
-
function isSkippedSkillWatchPath(relativePath: string): boolean {
|
|
69
|
-
if (relativePath === "(unknown)") {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const segments = relativePath.split(/[\\/]+/).filter(Boolean);
|
|
74
|
-
return segments.some((segment) => SKILL_WATCH_SKIPPED_DIRS.has(segment));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Files whose contents feed the skill catalog: `SKILL.md` carries a skill's
|
|
79
|
-
* metadata and body, `TOOLS.json` its tool manifest. Both live at the top
|
|
80
|
-
* level of a skill directory. Every other file (scripts, reference docs, build
|
|
81
|
-
* output) is read fresh on demand or irrelevant to the catalog, so changes to
|
|
82
|
-
* them do not require a catalog reload.
|
|
83
|
-
*/
|
|
84
|
-
const SKILL_CATALOG_FILENAMES = new Set(["SKILL.md", "TOOLS.json"]);
|
|
85
|
-
|
|
86
|
-
/** True when a changed path's basename is a skill-catalog file. */
|
|
87
|
-
function isSkillCatalogFile(filename: string): boolean {
|
|
88
|
-
return SKILL_CATALOG_FILENAMES.has(basename(filename));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
55
|
/**
|
|
92
56
|
* Attach a resilient error handler to an FSWatcher so that async errors
|
|
93
57
|
* (e.g. ENXIO when a Unix socket file like `gateway.sock` appears in a
|
|
@@ -227,19 +191,11 @@ export class ConfigWatcher {
|
|
|
227
191
|
return;
|
|
228
192
|
}
|
|
229
193
|
try {
|
|
230
|
-
const prevMcpFingerprint = JSON.stringify(this.lastConfig?.mcp ?? {});
|
|
231
194
|
const changed = await this.refreshConfigFromSources();
|
|
232
195
|
if (changed) {
|
|
233
196
|
evictConversationsForReload();
|
|
234
197
|
refreshAuthenticatedApiRateLimit();
|
|
235
198
|
publishConfigChanged();
|
|
236
|
-
const newConfig = this.lastConfig ?? getConfig();
|
|
237
|
-
const newMcpFingerprint = JSON.stringify(newConfig.mcp ?? {});
|
|
238
|
-
if (newMcpFingerprint !== prevMcpFingerprint) {
|
|
239
|
-
reloadMcpServers().catch((err: unknown) => {
|
|
240
|
-
log.error({ err }, "MCP reload after config change failed");
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
199
|
}
|
|
244
200
|
} catch (err) {
|
|
245
201
|
log.error(
|
|
@@ -248,6 +204,14 @@ export class ConfigWatcher {
|
|
|
248
204
|
);
|
|
249
205
|
}
|
|
250
206
|
},
|
|
207
|
+
[WORKSPACE_MCP_FILENAME]: () => {
|
|
208
|
+
if (this.suppressReload) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
reloadMcpServers().catch((err: unknown) => {
|
|
212
|
+
log.error({ err }, "MCP reload after mcp.json change failed");
|
|
213
|
+
});
|
|
214
|
+
},
|
|
251
215
|
"SOUL.md": () => {
|
|
252
216
|
evictConversationsForReload();
|
|
253
217
|
},
|
|
@@ -270,7 +234,6 @@ export class ConfigWatcher {
|
|
|
270
234
|
this.startAvatarWatcher();
|
|
271
235
|
this.startSignalsWatcher();
|
|
272
236
|
this.startUsersWatcher();
|
|
273
|
-
this.startSkillsWatchers();
|
|
274
237
|
}
|
|
275
238
|
|
|
276
239
|
stop(): void {
|
|
@@ -485,150 +448,6 @@ export class ConfigWatcher {
|
|
|
485
448
|
);
|
|
486
449
|
}
|
|
487
450
|
}
|
|
488
|
-
|
|
489
|
-
private startSkillsWatchers(): void {
|
|
490
|
-
const skillsDir = getWorkspaceSkillsDir();
|
|
491
|
-
if (!existsSync(skillsDir)) {
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
const scheduleSkillsReload = (file: string): void => {
|
|
496
|
-
if (isSkippedSkillWatchPath(file)) {
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
this.debounceTimers.schedule("skills:catalog", () => {
|
|
501
|
-
log.info({ file }, "Skill catalog changed, reloading");
|
|
502
|
-
evictConversationsForReload();
|
|
503
|
-
refreshSkillCapabilityMemories(getConfig());
|
|
504
|
-
});
|
|
505
|
-
};
|
|
506
|
-
|
|
507
|
-
// Only SKILL.md and TOOLS.json feed the skill catalog, and both live at the
|
|
508
|
-
// top level of a skill directory. Changes to any other file (scripts,
|
|
509
|
-
// reference docs, build output) never alter the catalog, so the watchers
|
|
510
|
-
// react only to those two files — plus skill directories appearing or
|
|
511
|
-
// disappearing, which is an install or removal.
|
|
512
|
-
try {
|
|
513
|
-
const recursiveWatcher = watch(
|
|
514
|
-
skillsDir,
|
|
515
|
-
{ recursive: true },
|
|
516
|
-
(_eventType, filename) => {
|
|
517
|
-
if (!filename || isSkillCatalogFile(String(filename))) {
|
|
518
|
-
scheduleSkillsReload(filename ? String(filename) : "(unknown)");
|
|
519
|
-
}
|
|
520
|
-
},
|
|
521
|
-
);
|
|
522
|
-
attachWatcherErrorHandler(recursiveWatcher, skillsDir);
|
|
523
|
-
this.watchers.push(recursiveWatcher);
|
|
524
|
-
log.info({ dir: skillsDir }, "Watching skills catalog recursively");
|
|
525
|
-
return;
|
|
526
|
-
} catch (err) {
|
|
527
|
-
log.info(
|
|
528
|
-
{ err, dir: skillsDir },
|
|
529
|
-
"Recursive skills watch unavailable; using per-skill-directory watchers",
|
|
530
|
-
);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// Fallback when recursive watches are unavailable: watch the skills root
|
|
534
|
-
// (to detect a skill being installed or removed) plus each immediate skill
|
|
535
|
-
// directory (to detect SKILL.md / TOOLS.json edits). Nested subdirectories
|
|
536
|
-
// are deliberately not watched, bounding the descriptor count to one per
|
|
537
|
-
// skill rather than one per subdirectory.
|
|
538
|
-
const skillDirWatchers = new Map<string, FSWatcher>();
|
|
539
|
-
|
|
540
|
-
const watchDir = (
|
|
541
|
-
dirPath: string,
|
|
542
|
-
onChange: (filename: string | null) => void,
|
|
543
|
-
): FSWatcher | null => {
|
|
544
|
-
try {
|
|
545
|
-
const watcher = watch(dirPath, (_eventType, filename) => {
|
|
546
|
-
onChange(filename ? String(filename) : null);
|
|
547
|
-
});
|
|
548
|
-
attachWatcherErrorHandler(watcher, dirPath);
|
|
549
|
-
this.watchers.push(watcher);
|
|
550
|
-
return watcher;
|
|
551
|
-
} catch (err) {
|
|
552
|
-
log.warn({ err, dirPath }, "Failed to watch skill directory");
|
|
553
|
-
return null;
|
|
554
|
-
}
|
|
555
|
-
};
|
|
556
|
-
|
|
557
|
-
const removeWatcher = (watcher: FSWatcher): void => {
|
|
558
|
-
const idx = this.watchers.indexOf(watcher);
|
|
559
|
-
if (idx !== -1) {
|
|
560
|
-
this.watchers.splice(idx, 1);
|
|
561
|
-
}
|
|
562
|
-
};
|
|
563
|
-
|
|
564
|
-
const listSkillDirs = (): string[] => {
|
|
565
|
-
try {
|
|
566
|
-
return readdirSync(skillsDir, { withFileTypes: true })
|
|
567
|
-
.filter(
|
|
568
|
-
(entry) =>
|
|
569
|
-
entry.isDirectory() && !SKILL_WATCH_SKIPPED_DIRS.has(entry.name),
|
|
570
|
-
)
|
|
571
|
-
.map((entry) => join(skillsDir, entry.name));
|
|
572
|
-
} catch (err) {
|
|
573
|
-
log.warn({ err, skillsDir }, "Failed to enumerate skill directories");
|
|
574
|
-
return [];
|
|
575
|
-
}
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
// Reconcile the per-skill-directory watchers against what is on disk.
|
|
579
|
-
// Returns true when the set of watched directories changed — i.e. a skill
|
|
580
|
-
// was installed or removed — so the caller can reload the catalog.
|
|
581
|
-
const refreshSkillDirWatchers = (): boolean => {
|
|
582
|
-
const nextDirs = new Set(listSkillDirs());
|
|
583
|
-
let changed = false;
|
|
584
|
-
|
|
585
|
-
for (const [dirPath, watcher] of skillDirWatchers.entries()) {
|
|
586
|
-
if (nextDirs.has(dirPath)) {
|
|
587
|
-
continue;
|
|
588
|
-
}
|
|
589
|
-
watcher.close();
|
|
590
|
-
skillDirWatchers.delete(dirPath);
|
|
591
|
-
removeWatcher(watcher);
|
|
592
|
-
changed = true;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
for (const dirPath of nextDirs) {
|
|
596
|
-
if (skillDirWatchers.has(dirPath)) {
|
|
597
|
-
continue;
|
|
598
|
-
}
|
|
599
|
-
const watcher = watchDir(dirPath, (filename) => {
|
|
600
|
-
if (!filename || isSkillCatalogFile(filename)) {
|
|
601
|
-
scheduleSkillsReload(filename ?? "(unknown)");
|
|
602
|
-
}
|
|
603
|
-
});
|
|
604
|
-
if (watcher) {
|
|
605
|
-
skillDirWatchers.set(dirPath, watcher);
|
|
606
|
-
changed = true;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
return changed;
|
|
611
|
-
};
|
|
612
|
-
|
|
613
|
-
const rootWatcher = watchDir(skillsDir, () => {
|
|
614
|
-
// A change directly under the skills root means a skill directory was
|
|
615
|
-
// added, removed, or renamed. Re-sync the per-skill watchers and reload
|
|
616
|
-
// the catalog when the set actually changed.
|
|
617
|
-
if (refreshSkillDirWatchers()) {
|
|
618
|
-
scheduleSkillsReload("(skill installed or removed)");
|
|
619
|
-
}
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
if (!rootWatcher) {
|
|
623
|
-
return;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
refreshSkillDirWatchers();
|
|
627
|
-
log.info(
|
|
628
|
-
{ dir: skillsDir },
|
|
629
|
-
"Watching skills catalog with per-skill-directory fallback",
|
|
630
|
-
);
|
|
631
|
-
}
|
|
632
451
|
}
|
|
633
452
|
|
|
634
453
|
/**
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
isModelNotFoundError,
|
|
31
31
|
isVisionNotSupportedError,
|
|
32
32
|
} from "../util/provider-error-patterns.js";
|
|
33
|
+
import { safeStringSlice } from "../util/unicode.js";
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Classified conversation error ready for client emission.
|
|
@@ -580,7 +581,7 @@ function classifyCore(
|
|
|
580
581
|
const detailMatch = message.match(/API error \(\d+\):\s*(.+)/i);
|
|
581
582
|
const detail = detailMatch?.[1];
|
|
582
583
|
const suffix = detail
|
|
583
|
-
? `: ${detail.length > 200 ? detail
|
|
584
|
+
? `: ${detail.length > 200 ? safeStringSlice(detail, 0, 200) + "…" : detail}`
|
|
584
585
|
: "";
|
|
585
586
|
return {
|
|
586
587
|
code: "PROVIDER_API",
|
|
@@ -612,7 +613,7 @@ function extractProviderDetail(message: string): string | undefined {
|
|
|
612
613
|
if (!detail) {
|
|
613
614
|
return undefined;
|
|
614
615
|
}
|
|
615
|
-
return detail.length > 200 ? `${detail
|
|
616
|
+
return detail.length > 200 ? `${safeStringSlice(detail, 0, 200)}…` : detail;
|
|
616
617
|
}
|
|
617
618
|
|
|
618
619
|
/**
|
|
@@ -16,6 +16,7 @@ import { estimateContentBlockTokens } from "../context/token-estimator.js";
|
|
|
16
16
|
import { getSummaryFromContextMessage } from "../plugins/defaults/compaction/window-manager.js";
|
|
17
17
|
import { mediaSourceDescriptor } from "../providers/media-resolve.js";
|
|
18
18
|
import type { ContentBlock, Message } from "../providers/types.js";
|
|
19
|
+
import { safeStringSlice } from "../util/unicode.js";
|
|
19
20
|
|
|
20
21
|
export interface StripMediaOptions {
|
|
21
22
|
/** Token budget available for media in the latest user message. Keeps as
|
|
@@ -238,7 +239,7 @@ function fileBlockToStub(
|
|
|
238
239
|
const extracted = (block.extracted_text ?? "").trim();
|
|
239
240
|
const preview =
|
|
240
241
|
extracted.length > MAX_MEDIA_STUB_TEXT
|
|
241
|
-
? `${extracted
|
|
242
|
+
? `${safeStringSlice(extracted, 0, MAX_MEDIA_STUB_TEXT)}...`
|
|
242
243
|
: extracted;
|
|
243
244
|
return {
|
|
244
245
|
type: "text",
|
|
@@ -646,52 +646,6 @@ export async function kickQueueDrain(
|
|
|
646
646
|
}
|
|
647
647
|
}
|
|
648
648
|
|
|
649
|
-
/**
|
|
650
|
-
* Commit `actor` as the actor the turn about to start runs for: the resting
|
|
651
|
-
* slot names them, so the history is scoped to them and every reader of the
|
|
652
|
-
* slot (the `<turn_context>` actor section, memory retrieval, the Slack
|
|
653
|
-
* transcript filters) describes them rather than whoever sent last, and the
|
|
654
|
-
* per-turn snapshot then reads back that same actor, which is also returned
|
|
655
|
-
* for callers that must hold it in a local. A caller with no actor of its own
|
|
656
|
-
* (internal dispatch, or a queued message whose enqueue found the slot empty)
|
|
657
|
-
* passes `undefined`, and the resting actor stands.
|
|
658
|
-
*
|
|
659
|
-
* `reloadHistory` is off only for a steered drain, which keeps its resident
|
|
660
|
-
* history: a steer comes from the actor whose turn it cut off, and that
|
|
661
|
-
* history may hold the in-memory repair of the abandoned `tool_use`, which a
|
|
662
|
-
* reload would discard.
|
|
663
|
-
*
|
|
664
|
-
* The committed actor is captured and snapshotted before the reload awaits:
|
|
665
|
-
* the slot is writable out-of-band across that await (a wake's stamp, a
|
|
666
|
-
* pointer elevation), and a read after it would hand the turn that writer's
|
|
667
|
-
* actor. A reload that fails starts no turn, so the slot is put back to what
|
|
668
|
-
* it held before, guarded so a writer that legitimately moved it in between
|
|
669
|
-
* is left alone.
|
|
670
|
-
*/
|
|
671
|
-
async function commitTurnActor(
|
|
672
|
-
conversation: Conversation,
|
|
673
|
-
actor: TrustContext | undefined,
|
|
674
|
-
options: { reloadHistory: boolean },
|
|
675
|
-
): Promise<TrustContext | undefined> {
|
|
676
|
-
const prior = restingTrust(conversation);
|
|
677
|
-
if (actor) {
|
|
678
|
-
conversation.setTrustContext(actor);
|
|
679
|
-
}
|
|
680
|
-
const turnTrustContext = restingTrust(conversation);
|
|
681
|
-
conversation.currentTurnTrustContext = turnTrustContext;
|
|
682
|
-
if (options.reloadHistory) {
|
|
683
|
-
try {
|
|
684
|
-
await conversation.ensureActorScopedHistory();
|
|
685
|
-
} catch (err) {
|
|
686
|
-
if (actor && restingTrust(conversation) === actor) {
|
|
687
|
-
conversation.setTrustContext(prior ?? null);
|
|
688
|
-
}
|
|
689
|
-
throw err;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
return turnTrustContext;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
649
|
async function drainSingleMessage(
|
|
696
650
|
conversation: Conversation,
|
|
697
651
|
next: QueuedMessage,
|
|
@@ -794,12 +748,11 @@ async function drainSingleMessage(
|
|
|
794
748
|
// a different actor's context if a concurrent request mutates the live fields.
|
|
795
749
|
// Trust comes from the queued message, not the live slot: the slot holds
|
|
796
750
|
// whichever actor sent most recently, which is this sender only when nobody
|
|
797
|
-
// else sent while this message waited.
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
);
|
|
751
|
+
// else sent while this message waited. Held in a local as well, because the
|
|
752
|
+
// field is writable out-of-band across the awaits between here and the loop
|
|
753
|
+
// call below.
|
|
754
|
+
const turnTrustContext = next.trustContext ?? restingTrust(conversation);
|
|
755
|
+
conversation.currentTurnTrustContext = turnTrustContext;
|
|
803
756
|
conversation.currentTurnChannelCapabilities =
|
|
804
757
|
conversation.channelCapabilities;
|
|
805
758
|
|
|
@@ -1407,12 +1360,9 @@ async function drainBatch(
|
|
|
1407
1360
|
// The head's trust governs the batch, which is sound only because
|
|
1408
1361
|
// `buildPassthroughBatch` refuses to coalesce messages from different
|
|
1409
1362
|
// actors; without that boundary this would run a tail under the head's
|
|
1410
|
-
// trust.
|
|
1411
|
-
const turnTrustContext =
|
|
1412
|
-
|
|
1413
|
-
head.trustContext,
|
|
1414
|
-
{ reloadHistory: true },
|
|
1415
|
-
);
|
|
1363
|
+
// trust. Held in a local for the same reason as the single-message drain.
|
|
1364
|
+
const turnTrustContext = head.trustContext ?? restingTrust(conversation);
|
|
1365
|
+
conversation.currentTurnTrustContext = turnTrustContext;
|
|
1416
1366
|
conversation.currentTurnChannelCapabilities =
|
|
1417
1367
|
conversation.channelCapabilities;
|
|
1418
1368
|
|
|
@@ -1890,16 +1840,37 @@ export async function processMessage(
|
|
|
1890
1840
|
metadata: callerMetadata,
|
|
1891
1841
|
trustContext: committingTrustContext,
|
|
1892
1842
|
} = options;
|
|
1843
|
+
const priorRestingTrust = restingTrust(conversation);
|
|
1844
|
+
if (committingTrustContext) {
|
|
1845
|
+
conversation.setTrustContext(committingTrustContext);
|
|
1846
|
+
}
|
|
1893
1847
|
// Held in a local as well as on the conversation: the field is writable
|
|
1894
1848
|
// out-of-band while this turn is in flight (`agent-wake` stamps it and
|
|
1895
1849
|
// restores the prior value in a `finally`), so reading it back at the agent
|
|
1896
1850
|
// loop call below would reintroduce the late read this capture exists to
|
|
1897
|
-
// avoid. The local is what the loop runs under.
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1851
|
+
// avoid. The local is what the loop runs under. Captured before the history
|
|
1852
|
+
// reload for the same reason: that await is one of the windows a writer can
|
|
1853
|
+
// land in.
|
|
1854
|
+
const turnTrustContext = restingTrust(conversation);
|
|
1855
|
+
conversation.currentTurnTrustContext = turnTrustContext;
|
|
1856
|
+
try {
|
|
1857
|
+
await conversation.ensureActorScopedHistory();
|
|
1858
|
+
} catch (err) {
|
|
1859
|
+
// This is the commitment point for the turn, so the stamp above is
|
|
1860
|
+
// correct, but a reload that fails starts no turn: the conversation must
|
|
1861
|
+
// not be left attributed to a sender that never ran. Guarded on identity
|
|
1862
|
+
// so a writer that legitimately moved the slot across the await keeps it.
|
|
1863
|
+
// Only the resting slot needs putting back; `runAgentLoopImpl` re-seeds
|
|
1864
|
+
// the per-turn field at the head of every turn, so no later dispatch can
|
|
1865
|
+
// inherit it.
|
|
1866
|
+
if (
|
|
1867
|
+
committingTrustContext &&
|
|
1868
|
+
restingTrust(conversation) === committingTrustContext
|
|
1869
|
+
) {
|
|
1870
|
+
conversation.setTrustContext(priorRestingTrust ?? null);
|
|
1871
|
+
}
|
|
1872
|
+
throw err;
|
|
1873
|
+
}
|
|
1903
1874
|
conversation.currentTurnAuthContext = conversation.authContext;
|
|
1904
1875
|
conversation.currentTurnSourceActorPrincipalId =
|
|
1905
1876
|
sourceActorPrincipalId ?? conversation.authContext?.actorPrincipalId;
|
|
@@ -87,6 +87,7 @@ import { TERMINAL_STATUSES } from "../subagent/types.js";
|
|
|
87
87
|
import { canonicalizeInboundIdentity } from "../util/canonicalize-identity.js";
|
|
88
88
|
import { safeParseRecord } from "../util/json.js";
|
|
89
89
|
import { getLogger } from "../util/logger.js";
|
|
90
|
+
import { safeStringSlice } from "../util/unicode.js";
|
|
90
91
|
import { channelSupportsInlineOptions } from "./channel-ui-capability.js";
|
|
91
92
|
import { findConversationOrSubagent } from "./conversation-registry.js";
|
|
92
93
|
import {
|
|
@@ -575,7 +576,7 @@ function injectActiveSurfaceContext(
|
|
|
575
576
|
if (schema && schema !== '"{}"' && schema !== "{}") {
|
|
576
577
|
const truncatedSchema =
|
|
577
578
|
schema.length > MAX_SCHEMA_LENGTH
|
|
578
|
-
? schema
|
|
579
|
+
? safeStringSlice(schema, 0, MAX_SCHEMA_LENGTH) + "… (truncated)"
|
|
579
580
|
: schema;
|
|
580
581
|
lines.push("", `Data schema: ${truncatedSchema}`);
|
|
581
582
|
}
|
|
@@ -818,10 +819,15 @@ export function applySightFrameRetention(
|
|
|
818
819
|
* `null` on the happy path (desktop, full capabilities, no special context)
|
|
819
820
|
* where no block is injected. Split from {@link injectChannelCapabilityContext}
|
|
820
821
|
* so callers can capture the exact injected text for metadata persistence.
|
|
822
|
+
*
|
|
823
|
+
* Live vs clientless guidance belongs here, not in tool schemas. Tool
|
|
824
|
+
* definitions stay identical so the tools cache prefix can reuse; this block
|
|
825
|
+
* sits later in the system prompt and can describe the current turn.
|
|
821
826
|
*/
|
|
822
827
|
export function buildChannelCapabilityBlock(
|
|
823
828
|
caps: ChannelCapabilities,
|
|
824
829
|
clientOs: string | undefined = caps.clientOS,
|
|
830
|
+
isNonInteractive = false,
|
|
825
831
|
): string | null {
|
|
826
832
|
// Happy path: desktop with full capabilities and no special context — skip injection.
|
|
827
833
|
if (
|
|
@@ -873,18 +879,24 @@ export function buildChannelCapabilityBlock(
|
|
|
873
879
|
"- Do NOT reference the dashboard UI, settings panels, or visual preference pickers.",
|
|
874
880
|
);
|
|
875
881
|
if (!caps.supportsDynamicUi) {
|
|
876
|
-
if (
|
|
882
|
+
if (isNonInteractive) {
|
|
877
883
|
lines.push(
|
|
878
|
-
|
|
884
|
+
"- ui_show, ui_update, and ui_dismiss persist conversation content for the next capable client that opens this conversation. Do not claim a surface is visible now or wait for an action.",
|
|
879
885
|
);
|
|
880
886
|
} else {
|
|
887
|
+
if (caps.channel === "slack") {
|
|
888
|
+
lines.push(
|
|
889
|
+
'- Do NOT use app_create. Only use ui_show/ui_update for card surfaces with template: "task_progress"; present all other information as text.',
|
|
890
|
+
);
|
|
891
|
+
} else {
|
|
892
|
+
lines.push(
|
|
893
|
+
"- Do NOT use ui_show, ui_update, or app_create. This channel cannot render them.",
|
|
894
|
+
);
|
|
895
|
+
}
|
|
881
896
|
lines.push(
|
|
882
|
-
"-
|
|
897
|
+
"- Present information as well-formatted text instead of dynamic UI.",
|
|
883
898
|
);
|
|
884
899
|
}
|
|
885
|
-
lines.push(
|
|
886
|
-
"- Present information as well-formatted text instead of dynamic UI.",
|
|
887
|
-
);
|
|
888
900
|
}
|
|
889
901
|
if (caps.channel === "whatsapp") {
|
|
890
902
|
lines.push(
|
|
@@ -2852,6 +2864,7 @@ export async function applyRuntimeInjections(
|
|
|
2852
2864
|
const channelCapabilityBlock = buildChannelCapabilityBlock(
|
|
2853
2865
|
channelCapabilities,
|
|
2854
2866
|
clientOs,
|
|
2867
|
+
options.isNonInteractive === true,
|
|
2855
2868
|
);
|
|
2856
2869
|
if (channelCapabilityBlock !== null) {
|
|
2857
2870
|
channelCapabilitiesCaptured = channelCapabilityBlock;
|
|
@@ -75,11 +75,13 @@ export interface SkillToolProjection {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
/**
|
|
78
|
-
* Conversation-scoped cache for skill projection. Avoids re-scanning the
|
|
79
|
-
* conversation history
|
|
78
|
+
* Conversation-scoped cache for skill projection. Avoids re-scanning the
|
|
79
|
+
* conversation history on every agent turn. Catalog membership is not stored
|
|
80
|
+
* here: each projection reads a fresh `loadSkillCatalog()` so newly
|
|
81
|
+
* installed or removed skills are visible on the next turn.
|
|
80
82
|
*
|
|
81
|
-
* Each conversation should own its own cache instance to prevent
|
|
82
|
-
* state bleed.
|
|
83
|
+
* Each conversation should own its own cache instance to prevent
|
|
84
|
+
* cross-conversation state bleed.
|
|
83
85
|
*/
|
|
84
86
|
export interface SkillProjectionCache {
|
|
85
87
|
/** Cached deriveActiveSkills result. */
|
|
@@ -95,9 +97,6 @@ export interface SkillProjectionCache {
|
|
|
95
97
|
/** The accumulated active skill entries. */
|
|
96
98
|
entries: ActiveSkillEntry[];
|
|
97
99
|
};
|
|
98
|
-
/** Cached skill catalog. Invalidated when the conversation is marked stale
|
|
99
|
-
* (e.g. skill directories changed on disk while a run is in progress). */
|
|
100
|
-
catalog?: SkillSummary[];
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
export interface ProjectSkillToolsOptions {
|
|
@@ -113,9 +112,9 @@ export interface ProjectSkillToolsOptions {
|
|
|
113
112
|
*/
|
|
114
113
|
previouslyActiveSkillIds?: Map<string, string>;
|
|
115
114
|
/**
|
|
116
|
-
* Conversation-scoped projection cache. When provided, projectSkillTools
|
|
117
|
-
*
|
|
118
|
-
*
|
|
115
|
+
* Conversation-scoped projection cache. When provided, projectSkillTools
|
|
116
|
+
* avoids redundant deriveActiveSkills scans across agent turns. Catalog
|
|
117
|
+
* membership is always a fresh `loadSkillCatalog()` read.
|
|
119
118
|
*/
|
|
120
119
|
cache?: SkillProjectionCache;
|
|
121
120
|
/**
|
|
@@ -310,23 +309,6 @@ function getCachedActiveSkills(
|
|
|
310
309
|
return entries;
|
|
311
310
|
}
|
|
312
311
|
|
|
313
|
-
/**
|
|
314
|
-
* Return the skill catalog, caching it across agent turns.
|
|
315
|
-
*
|
|
316
|
-
* The cache is invalidated when the conversation is marked stale (e.g. skill
|
|
317
|
-
* directories changed on disk while the conversation is still processing).
|
|
318
|
-
*/
|
|
319
|
-
function getCachedCatalog(cache?: SkillProjectionCache): SkillSummary[] {
|
|
320
|
-
if (!cache) {
|
|
321
|
-
return loadSkillCatalog();
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (!cache.catalog) {
|
|
325
|
-
cache.catalog = loadSkillCatalog();
|
|
326
|
-
}
|
|
327
|
-
return cache.catalog;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
312
|
// ---------------------------------------------------------------------------
|
|
331
313
|
// Main export
|
|
332
314
|
// ---------------------------------------------------------------------------
|
|
@@ -363,11 +345,11 @@ export function projectSkillTools(
|
|
|
363
345
|
const contextIds = contextEntries.map((e) => e.id);
|
|
364
346
|
const allCandidateIds = new Set<string>([...contextIds, ...preactivated]);
|
|
365
347
|
|
|
366
|
-
// Load the catalog
|
|
367
|
-
//
|
|
368
|
-
//
|
|
348
|
+
// Load the catalog, then scope it to the conversation's per-chat plugin
|
|
349
|
+
// selection so plugin-contributed skills from unselected plugins are not
|
|
350
|
+
// resolvable for this run (null = no restriction).
|
|
369
351
|
const catalog = filterSkillsByEnabledPlugins(
|
|
370
|
-
|
|
352
|
+
loadSkillCatalog(),
|
|
371
353
|
options?.effectiveEnabledPluginSet ?? null,
|
|
372
354
|
);
|
|
373
355
|
const catalogById = new Map<string, SkillSummary>();
|
|
@@ -548,7 +548,7 @@ export function clearAllActiveConversations(): number {
|
|
|
548
548
|
}
|
|
549
549
|
|
|
550
550
|
/**
|
|
551
|
-
* Evict in-memory conversations after a config/prompt
|
|
551
|
+
* Evict in-memory conversations after a config/prompt reload so the next
|
|
552
552
|
* turn rebuilds them against the new config. Conversations with in-flight work
|
|
553
553
|
* (a live turn, a queued successor, or an active subagent) are marked stale
|
|
554
554
|
* and rebuilt by `getOrCreateConversation` once that work finishes. Idle
|