@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
|
@@ -159,3 +159,31 @@ describe("serializeConversationSummary · enabledPlugins", () => {
|
|
|
159
159
|
expect("enabledPlugins" in summary).toBe(false);
|
|
160
160
|
});
|
|
161
161
|
});
|
|
162
|
+
|
|
163
|
+
describe("serializeConversationSummary · title keys", () => {
|
|
164
|
+
test("resolves a stored title key for the locale", () => {
|
|
165
|
+
const summary = serializeConversationSummary({
|
|
166
|
+
conversation: makeConversationRow({
|
|
167
|
+
title: "conversation.title.generating",
|
|
168
|
+
}),
|
|
169
|
+
displayMeta: { displayOrder: null, isPinned: false, groupId: null },
|
|
170
|
+
parentCache: new Map(),
|
|
171
|
+
isProcessing: false,
|
|
172
|
+
locale: "es",
|
|
173
|
+
});
|
|
174
|
+
expect(summary.title).toBe("Generando título...");
|
|
175
|
+
expect("titleState" in summary).toBe(false);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("passes a stored display string through", () => {
|
|
179
|
+
const summary = serialize(
|
|
180
|
+
makeConversationRow({ title: "Untitled Conversation" }),
|
|
181
|
+
);
|
|
182
|
+
expect(summary.title).toBe("Untitled Conversation");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("passes a custom title through", () => {
|
|
186
|
+
const summary = serialize(makeConversationRow({ title: "Weekly planning" }));
|
|
187
|
+
expect(summary.title).toBe("Weekly planning");
|
|
188
|
+
});
|
|
189
|
+
});
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
|
|
9
9
|
import { parseChannelId } from "../../channels/types.js";
|
|
10
10
|
import { normalizeConversationType } from "../../daemon/message-types/shared.js";
|
|
11
|
+
import {
|
|
12
|
+
resolveConversationTitle,
|
|
13
|
+
type SupportedLocale,
|
|
14
|
+
} from "../../i18n/index.js";
|
|
11
15
|
import { buildChannelBindingMetadata } from "../../messaging/channel-binding-metadata.js";
|
|
12
16
|
import {
|
|
13
17
|
type AttentionState,
|
|
@@ -78,6 +82,7 @@ interface ForkLineage {
|
|
|
78
82
|
function buildForkLineage(
|
|
79
83
|
conversation: ConversationRow,
|
|
80
84
|
parentCache: Map<string, ConversationRow | null>,
|
|
85
|
+
locale?: SupportedLocale,
|
|
81
86
|
): ForkLineage {
|
|
82
87
|
const parentConversationId = conversation.forkParentConversationId;
|
|
83
88
|
const parentMessageId = conversation.forkParentMessageId;
|
|
@@ -101,7 +106,7 @@ function buildForkLineage(
|
|
|
101
106
|
forkParent: {
|
|
102
107
|
conversationId: parentConversationId,
|
|
103
108
|
messageId: parentMessageId,
|
|
104
|
-
title: parentConversation.title
|
|
109
|
+
title: resolveConversationTitle(parentConversation.title, locale),
|
|
105
110
|
},
|
|
106
111
|
};
|
|
107
112
|
}
|
|
@@ -178,6 +183,11 @@ export function serializeConversationSummary(params: {
|
|
|
178
183
|
* with no daemon-store coupling.
|
|
179
184
|
*/
|
|
180
185
|
isProcessing: boolean;
|
|
186
|
+
/**
|
|
187
|
+
* Locale used to resolve stored title keys. Omitted locale is English
|
|
188
|
+
* inside {@link resolveConversationTitle}.
|
|
189
|
+
*/
|
|
190
|
+
locale?: SupportedLocale;
|
|
181
191
|
}) {
|
|
182
192
|
const {
|
|
183
193
|
conversation,
|
|
@@ -186,14 +196,15 @@ export function serializeConversationSummary(params: {
|
|
|
186
196
|
displayMeta,
|
|
187
197
|
parentCache,
|
|
188
198
|
isProcessing,
|
|
199
|
+
locale,
|
|
189
200
|
} = params;
|
|
190
201
|
const originChannel = parseChannelId(conversation.originChannel);
|
|
191
202
|
const assistantAttention = buildAssistantAttention(attentionState);
|
|
192
|
-
const forkLineage = buildForkLineage(conversation, parentCache);
|
|
203
|
+
const forkLineage = buildForkLineage(conversation, parentCache, locale);
|
|
193
204
|
|
|
194
205
|
return {
|
|
195
206
|
id: conversation.id,
|
|
196
|
-
title: conversation.title
|
|
207
|
+
title: resolveConversationTitle(conversation.title, locale),
|
|
197
208
|
createdAt: conversation.createdAt,
|
|
198
209
|
updatedAt: conversation.updatedAt,
|
|
199
210
|
lastMessageAt: conversation.lastMessageAt,
|
|
@@ -253,6 +264,7 @@ export function serializeConversationSummary(params: {
|
|
|
253
264
|
*/
|
|
254
265
|
export function buildConversationDetailResponse(
|
|
255
266
|
conversationId: string,
|
|
267
|
+
locale?: SupportedLocale,
|
|
256
268
|
): { conversation: ReturnType<typeof serializeConversationSummary> } | null {
|
|
257
269
|
const conversation = getConversation(conversationId);
|
|
258
270
|
if (!conversation || conversation.conversationType === "private") {
|
|
@@ -274,6 +286,7 @@ export function buildConversationDetailResponse(
|
|
|
274
286
|
// Checks in-memory flag first (hot path), falls back to the
|
|
275
287
|
// persisted `processing_started_at` column for cold conversations.
|
|
276
288
|
isProcessing: isConversationProcessing(conversation.id),
|
|
289
|
+
locale,
|
|
277
290
|
}),
|
|
278
291
|
};
|
|
279
292
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
conversationMetadataSyncTag,
|
|
5
5
|
SYNC_TAGS,
|
|
6
6
|
} from "../../daemon/message-types/sync.js";
|
|
7
|
+
import { resolveConversationTitle } from "../../i18n/index.js";
|
|
7
8
|
import { syncAvatarToPlatform } from "../../platform/sync-avatar.js";
|
|
8
9
|
import { getAvatarImagePath } from "../../util/platform.js";
|
|
9
10
|
import { broadcastMessage } from "../assistant-event-hub.js";
|
|
@@ -257,7 +258,7 @@ export function publishConversationTitleChanged(
|
|
|
257
258
|
{
|
|
258
259
|
type: "conversation_title_updated",
|
|
259
260
|
conversationId,
|
|
260
|
-
title,
|
|
261
|
+
title: resolveConversationTitle(title),
|
|
261
262
|
},
|
|
262
263
|
conversationId,
|
|
263
264
|
);
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
} from "../util/host-process.js";
|
|
6
6
|
import { getLogger } from "../util/logger.js";
|
|
7
7
|
import { getWorkspaceDir } from "../util/platform.js";
|
|
8
|
+
import { safeStringSlice } from "../util/unicode.js";
|
|
8
9
|
|
|
9
10
|
const log = getLogger("run-script");
|
|
10
11
|
|
|
@@ -200,7 +201,7 @@ function truncate(text: string): string {
|
|
|
200
201
|
if (text.length <= MAX_OUTPUT_BYTES) {
|
|
201
202
|
return text;
|
|
202
203
|
}
|
|
203
|
-
return text
|
|
204
|
+
return safeStringSlice(text, 0, MAX_OUTPUT_BYTES) + "\n... (truncated)";
|
|
204
205
|
}
|
|
205
206
|
|
|
206
207
|
/**
|
|
@@ -23,6 +23,7 @@ import { publishSchedulesChanged } from "../runtime/sync/resource-sync-events.js
|
|
|
23
23
|
import { UserError } from "../util/errors.js";
|
|
24
24
|
import { getLogger } from "../util/logger.js";
|
|
25
25
|
import { withSqliteRetry } from "../util/sqlite-retry.js";
|
|
26
|
+
import { safeStringSlice } from "../util/unicode.js";
|
|
26
27
|
import {
|
|
27
28
|
hasOwnerDeferProvenance,
|
|
28
29
|
isDeferSchedule,
|
|
@@ -1511,8 +1512,14 @@ async function finishScheduleRunRow(
|
|
|
1511
1512
|
status: result.status,
|
|
1512
1513
|
finishedAt: now,
|
|
1513
1514
|
durationMs,
|
|
1514
|
-
output:
|
|
1515
|
-
|
|
1515
|
+
output:
|
|
1516
|
+
result.output === undefined
|
|
1517
|
+
? null
|
|
1518
|
+
: safeStringSlice(result.output, 0, 10_000),
|
|
1519
|
+
error:
|
|
1520
|
+
result.error === undefined
|
|
1521
|
+
? null
|
|
1522
|
+
: safeStringSlice(result.error, 0, 2000),
|
|
1516
1523
|
})
|
|
1517
1524
|
.where(eq(scheduleRuns.id, runId))
|
|
1518
1525
|
.run(),
|
package/src/schedule/worker.ts
CHANGED
|
@@ -195,7 +195,7 @@ async function main(): Promise<void> {
|
|
|
195
195
|
//
|
|
196
196
|
// Bounded by MCP_STARTUP_GRACE_MS: unreachable servers must not hold the
|
|
197
197
|
// schedules that do not use them. The connect runs on past the deadline.
|
|
198
|
-
const mcpStartup = startConfiguredMcpServers(
|
|
198
|
+
const mcpStartup = startConfiguredMcpServers();
|
|
199
199
|
await Promise.race([
|
|
200
200
|
mcpStartup,
|
|
201
201
|
// Unref'd so a connect that beats the deadline leaves nothing pending.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { afterEach, describe, expect, spyOn, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import type { CredentialRecord } from "@vellumai/service-contracts/credential-rpc";
|
|
4
|
+
|
|
5
|
+
import * as envRegistry from "../../config/env-registry.js";
|
|
6
|
+
import {
|
|
7
|
+
CesHttpRecordBackend,
|
|
8
|
+
createCesHttpRecordBackendIfConfigured,
|
|
9
|
+
} from "../ces-http-record-backend.js";
|
|
10
|
+
|
|
11
|
+
const ORIGINAL_URL = process.env.CES_CREDENTIAL_URL;
|
|
12
|
+
const ORIGINAL_TOKEN = process.env.CES_SERVICE_TOKEN;
|
|
13
|
+
|
|
14
|
+
function restoreCesHttpEnv(): void {
|
|
15
|
+
if (ORIGINAL_URL === undefined) {
|
|
16
|
+
delete process.env.CES_CREDENTIAL_URL;
|
|
17
|
+
} else {
|
|
18
|
+
process.env.CES_CREDENTIAL_URL = ORIGINAL_URL;
|
|
19
|
+
}
|
|
20
|
+
if (ORIGINAL_TOKEN === undefined) {
|
|
21
|
+
delete process.env.CES_SERVICE_TOKEN;
|
|
22
|
+
} else {
|
|
23
|
+
process.env.CES_SERVICE_TOKEN = ORIGINAL_TOKEN;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function fakeHttpClient(options: {
|
|
28
|
+
listRecords: () => Promise<{
|
|
29
|
+
records: Array<{ account: string; record: CredentialRecord }>;
|
|
30
|
+
unreachable: boolean;
|
|
31
|
+
}>;
|
|
32
|
+
}) {
|
|
33
|
+
return {
|
|
34
|
+
getRecord: async () => ({ record: undefined, unreachable: false }),
|
|
35
|
+
setRecord: async () => false,
|
|
36
|
+
deleteRecord: async () => "error" as const,
|
|
37
|
+
listRecords: options.listRecords,
|
|
38
|
+
bulkSetRecords: async (records: Array<{ account: string }>) =>
|
|
39
|
+
records.map((entry) => ({ account: entry.account, ok: false })),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe("CES HTTP credential record backend", () => {
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
restoreCesHttpEnv();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("factory returns null when the assistant is not containerized", () => {
|
|
49
|
+
const spy = spyOn(envRegistry, "getIsContainerized").mockReturnValue(false);
|
|
50
|
+
process.env.CES_CREDENTIAL_URL = "http://ces-container:8090";
|
|
51
|
+
process.env.CES_SERVICE_TOKEN = "token-123";
|
|
52
|
+
try {
|
|
53
|
+
expect(createCesHttpRecordBackendIfConfigured()).toBeNull();
|
|
54
|
+
} finally {
|
|
55
|
+
spy.mockRestore();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("factory returns null when CES_CREDENTIAL_URL is unset", () => {
|
|
60
|
+
const spy = spyOn(envRegistry, "getIsContainerized").mockReturnValue(true);
|
|
61
|
+
delete process.env.CES_CREDENTIAL_URL;
|
|
62
|
+
process.env.CES_SERVICE_TOKEN = "token-123";
|
|
63
|
+
try {
|
|
64
|
+
expect(createCesHttpRecordBackendIfConfigured()).toBeNull();
|
|
65
|
+
} finally {
|
|
66
|
+
spy.mockRestore();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("factory returns null when CES_SERVICE_TOKEN is unset", () => {
|
|
71
|
+
const spy = spyOn(envRegistry, "getIsContainerized").mockReturnValue(true);
|
|
72
|
+
process.env.CES_CREDENTIAL_URL = "http://ces-container:8090";
|
|
73
|
+
delete process.env.CES_SERVICE_TOKEN;
|
|
74
|
+
try {
|
|
75
|
+
expect(createCesHttpRecordBackendIfConfigured()).toBeNull();
|
|
76
|
+
} finally {
|
|
77
|
+
spy.mockRestore();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("factory returns a backend when containerized with CES HTTP env", () => {
|
|
82
|
+
const spy = spyOn(envRegistry, "getIsContainerized").mockReturnValue(true);
|
|
83
|
+
process.env.CES_CREDENTIAL_URL = "http://ces-container:8090";
|
|
84
|
+
process.env.CES_SERVICE_TOKEN = "token-123";
|
|
85
|
+
try {
|
|
86
|
+
const backend = createCesHttpRecordBackendIfConfigured();
|
|
87
|
+
expect(backend?.name).toBe("ces-http");
|
|
88
|
+
expect(backend?.isAvailable()).toBe(true);
|
|
89
|
+
} finally {
|
|
90
|
+
spy.mockRestore();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("list returns records when HTTP reports a reachable catalog", async () => {
|
|
95
|
+
const record: CredentialRecord = {
|
|
96
|
+
credentialId: "cred-http",
|
|
97
|
+
service: "github",
|
|
98
|
+
field: "token",
|
|
99
|
+
allowedTools: ["bash"],
|
|
100
|
+
allowedDomains: [],
|
|
101
|
+
createdAt: 1,
|
|
102
|
+
updatedAt: 2,
|
|
103
|
+
};
|
|
104
|
+
const backend = new CesHttpRecordBackend(
|
|
105
|
+
fakeHttpClient({
|
|
106
|
+
listRecords: async () => ({
|
|
107
|
+
records: [{ account: "github:token", record }],
|
|
108
|
+
unreachable: false,
|
|
109
|
+
}),
|
|
110
|
+
}),
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const listed = await backend.list();
|
|
114
|
+
expect(listed).toEqual([{ account: "github:token", record }]);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("list returns an empty catalog when HTTP is reachable and empty", async () => {
|
|
118
|
+
const backend = new CesHttpRecordBackend(
|
|
119
|
+
fakeHttpClient({
|
|
120
|
+
listRecords: async () => ({ records: [], unreachable: false }),
|
|
121
|
+
}),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const listed = await backend.list();
|
|
125
|
+
expect(listed).toEqual([]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("list returns null when HTTP reports the vault unreachable", async () => {
|
|
129
|
+
const backend = new CesHttpRecordBackend(
|
|
130
|
+
fakeHttpClient({
|
|
131
|
+
listRecords: async () => ({ records: [], unreachable: true }),
|
|
132
|
+
}),
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect(await backend.list()).toBeNull();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CES HTTP backend for non-secret credential records (identity + policy).
|
|
3
|
+
*
|
|
4
|
+
* Used when the CES RPC socket is down but the CES HTTP sidecar is
|
|
5
|
+
* reachable (containerized deployments with CES_CREDENTIAL_URL).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
type CesHttpCredentialClient,
|
|
10
|
+
createCesHttpCredentialClient,
|
|
11
|
+
} from "@vellumai/ces-client/http-credentials";
|
|
12
|
+
import type { CredentialRecord } from "@vellumai/service-contracts/credential-rpc";
|
|
13
|
+
|
|
14
|
+
import { getIsContainerized } from "../config/env-registry.js";
|
|
15
|
+
import { getLogger } from "../util/logger.js";
|
|
16
|
+
import type { CredentialRecordBackend } from "./ces-rpc-record-backend.js";
|
|
17
|
+
|
|
18
|
+
const log = getLogger("ces-http-record-backend");
|
|
19
|
+
|
|
20
|
+
type RecordHttpClient = Pick<
|
|
21
|
+
CesHttpCredentialClient,
|
|
22
|
+
| "getRecord"
|
|
23
|
+
| "setRecord"
|
|
24
|
+
| "deleteRecord"
|
|
25
|
+
| "listRecords"
|
|
26
|
+
| "bulkSetRecords"
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
function resolveEnvHttpClient(): RecordHttpClient | undefined {
|
|
30
|
+
const baseUrl = process.env.CES_CREDENTIAL_URL?.trim();
|
|
31
|
+
const serviceToken = process.env.CES_SERVICE_TOKEN?.trim();
|
|
32
|
+
if (!baseUrl || !serviceToken) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
return createCesHttpCredentialClient({ baseUrl, serviceToken }, log);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class CesHttpRecordBackend implements CredentialRecordBackend {
|
|
39
|
+
readonly name = "ces-http";
|
|
40
|
+
|
|
41
|
+
constructor(private readonly client?: RecordHttpClient) {}
|
|
42
|
+
|
|
43
|
+
private resolveClient(): RecordHttpClient | undefined {
|
|
44
|
+
return this.client ?? resolveEnvHttpClient();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
isAvailable(): boolean {
|
|
48
|
+
return this.resolveClient() !== undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async get(account: string): Promise<CredentialRecord | undefined> {
|
|
52
|
+
const client = this.resolveClient();
|
|
53
|
+
if (!client) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const result = await client.getRecord(account);
|
|
57
|
+
return result.record;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async set(account: string, record: CredentialRecord): Promise<boolean> {
|
|
61
|
+
const client = this.resolveClient();
|
|
62
|
+
if (!client) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return client.setRecord(account, record);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async delete(
|
|
69
|
+
account: string,
|
|
70
|
+
): Promise<"deleted" | "not-found" | "error"> {
|
|
71
|
+
const client = this.resolveClient();
|
|
72
|
+
if (!client) {
|
|
73
|
+
return "error";
|
|
74
|
+
}
|
|
75
|
+
return client.deleteRecord(account);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async list(): Promise<Array<{
|
|
79
|
+
account: string;
|
|
80
|
+
record: CredentialRecord;
|
|
81
|
+
}> | null> {
|
|
82
|
+
const client = this.resolveClient();
|
|
83
|
+
if (!client) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const result = await client.listRecords();
|
|
87
|
+
if (result.unreachable) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
return result.records ?? [];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async bulkSet(
|
|
94
|
+
records: Array<{ account: string; record: CredentialRecord }>,
|
|
95
|
+
): Promise<Array<{ account: string; ok: boolean }>> {
|
|
96
|
+
const client = this.resolveClient();
|
|
97
|
+
if (!client) {
|
|
98
|
+
return records.map((entry) => ({ account: entry.account, ok: false }));
|
|
99
|
+
}
|
|
100
|
+
return client.bulkSetRecords(records);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* CES HTTP record backend when the assistant is containerized and the
|
|
106
|
+
* CES HTTP sidecar URL is configured. Returns null otherwise.
|
|
107
|
+
*/
|
|
108
|
+
export function createCesHttpRecordBackendIfConfigured(): CredentialRecordBackend | null {
|
|
109
|
+
if (!getIsContainerized()) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
if (!process.env.CES_CREDENTIAL_URL?.trim()) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const backend = new CesHttpRecordBackend();
|
|
116
|
+
if (!backend.isAvailable()) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
return backend;
|
|
120
|
+
}
|
|
@@ -11,6 +11,11 @@ import { getLogger } from "../util/logger.js";
|
|
|
11
11
|
const log = getLogger("ces-rpc-record-backend");
|
|
12
12
|
|
|
13
13
|
export interface CredentialRecordBackend {
|
|
14
|
+
/**
|
|
15
|
+
* Transport id. `"ces-rpc"` is the attached CES socket backend; live
|
|
16
|
+
* catalog listing fails over to CES HTTP when that transport is down.
|
|
17
|
+
*/
|
|
18
|
+
readonly name?: string;
|
|
14
19
|
isAvailable(): boolean;
|
|
15
20
|
get(account: string): Promise<CredentialRecord | undefined>;
|
|
16
21
|
set(account: string, record: CredentialRecord): Promise<boolean>;
|
|
@@ -29,6 +34,8 @@ export interface CredentialRecordBackend {
|
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
export class CesRpcRecordBackend implements CredentialRecordBackend {
|
|
37
|
+
readonly name = "ces-rpc";
|
|
38
|
+
|
|
32
39
|
constructor(private readonly client: CesClient) {}
|
|
33
40
|
|
|
34
41
|
isAvailable(): boolean {
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* 3. Enforces per-source character budgets to prevent context flooding.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import { safeStringSlice } from "../util/unicode.js";
|
|
15
|
+
|
|
14
16
|
// ---------------------------------------------------------------------------
|
|
15
17
|
// Types
|
|
16
18
|
// ---------------------------------------------------------------------------
|
|
@@ -156,7 +158,7 @@ export function escapeContentBoundaries(content: string): string {
|
|
|
156
158
|
|
|
157
159
|
/** Sanitize a value for use as an XML attribute (no quotes, angle brackets, newlines). */
|
|
158
160
|
function sanitizeAttr(value: string): string {
|
|
159
|
-
return value.replace(/[<>"&\r\n]/g, "")
|
|
161
|
+
return safeStringSlice(value.replace(/[<>"&\r\n]/g, ""), 0, 200);
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
function parseExternalContentAttributes(
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync, utimesSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
5
|
+
|
|
6
|
+
import { readWorkspaceSkillMdSignature } from "../workspace-skill-md-signature.js";
|
|
7
|
+
|
|
8
|
+
const ROOT = mkdtempSync(join(tmpdir(), "skill-md-signature-"));
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
rmSync(ROOT, { recursive: true, force: true });
|
|
12
|
+
mkdirSync(ROOT, { recursive: true });
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
function writeSkill(id: string, body = "body"): string {
|
|
16
|
+
const dir = join(ROOT, id);
|
|
17
|
+
mkdirSync(dir, { recursive: true });
|
|
18
|
+
const skillMd = join(dir, "SKILL.md");
|
|
19
|
+
writeFileSync(skillMd, `---\nname: ${id}\ndescription: ${id}\n---\n${body}\n`);
|
|
20
|
+
return skillMd;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("readWorkspaceSkillMdSignature", () => {
|
|
24
|
+
test("empty or missing skills dir is the empty signature", () => {
|
|
25
|
+
expect(readWorkspaceSkillMdSignature(join(ROOT, "missing"))).toBe("");
|
|
26
|
+
mkdirSync(ROOT, { recursive: true });
|
|
27
|
+
expect(readWorkspaceSkillMdSignature(ROOT)).toBe("");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("includes SKILL.md mtimes and ignores TOOLS.json", () => {
|
|
31
|
+
const skillMd = writeSkill("alpha");
|
|
32
|
+
const first = readWorkspaceSkillMdSignature(ROOT);
|
|
33
|
+
expect(first).toMatch(/^alpha:\d+$/);
|
|
34
|
+
|
|
35
|
+
writeFileSync(join(ROOT, "alpha", "TOOLS.json"), '{"version":1,"tools":[]}');
|
|
36
|
+
expect(readWorkspaceSkillMdSignature(ROOT)).toBe(first);
|
|
37
|
+
|
|
38
|
+
const later = new Date(Date.now() + 5_000);
|
|
39
|
+
utimesSync(skillMd, later, later);
|
|
40
|
+
expect(readWorkspaceSkillMdSignature(ROOT)).not.toBe(first);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("add and remove skill directories change the signature", () => {
|
|
44
|
+
writeSkill("alpha");
|
|
45
|
+
const one = readWorkspaceSkillMdSignature(ROOT);
|
|
46
|
+
writeSkill("bravo");
|
|
47
|
+
const two = readWorkspaceSkillMdSignature(ROOT);
|
|
48
|
+
expect(two).not.toBe(one);
|
|
49
|
+
expect(two.split("\n")).toHaveLength(2);
|
|
50
|
+
|
|
51
|
+
rmSync(join(ROOT, "bravo"), { recursive: true, force: true });
|
|
52
|
+
expect(readWorkspaceSkillMdSignature(ROOT)).toBe(one);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("directories without SKILL.md are omitted", () => {
|
|
56
|
+
mkdirSync(join(ROOT, "not-a-skill"), { recursive: true });
|
|
57
|
+
writeFileSync(join(ROOT, "README.md"), "nope");
|
|
58
|
+
expect(readWorkspaceSkillMdSignature(ROOT)).toBe("");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { getWorkspaceSkillsDir } from "../util/platform.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Cheap change detector for workspace skill capability cards: the sorted set
|
|
8
|
+
* of immediate skill directories that contain a top-level `SKILL.md`, each
|
|
9
|
+
* paired with that file's mtime. Capability cards are frontmatter fields from
|
|
10
|
+
* `SKILL.md`. Body files, `TOOLS.json`, scripts, and `references/` are not part
|
|
11
|
+
* of this signature.
|
|
12
|
+
*
|
|
13
|
+
* Listing the skills directory (not only statting known paths) is what makes
|
|
14
|
+
* install and delete visible: a new or removed skill directory changes the
|
|
15
|
+
* signature even when no previously known `SKILL.md` mtime moved.
|
|
16
|
+
*/
|
|
17
|
+
export function readWorkspaceSkillMdSignature(
|
|
18
|
+
skillsDir: string = getWorkspaceSkillsDir(),
|
|
19
|
+
): string {
|
|
20
|
+
if (!existsSync(skillsDir)) {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let entries;
|
|
25
|
+
try {
|
|
26
|
+
entries = readdirSync(skillsDir, { withFileTypes: true });
|
|
27
|
+
} catch {
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const parts: string[] = [];
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
if (!entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const skillMdPath = join(skillsDir, entry.name, "SKILL.md");
|
|
37
|
+
try {
|
|
38
|
+
const st = statSync(skillMdPath);
|
|
39
|
+
if (!st.isFile()) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
parts.push(`${entry.name}:${Math.trunc(st.mtimeMs)}`);
|
|
43
|
+
} catch {
|
|
44
|
+
// No readable SKILL.md: not a catalog skill.
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
parts.sort();
|
|
49
|
+
return parts.join("\n");
|
|
50
|
+
}
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
import { readdir } from "node:fs/promises";
|
|
34
34
|
import { join } from "node:path";
|
|
35
35
|
|
|
36
|
-
import type { SkillSummary } from "../config/skills.js";
|
|
37
36
|
import type { TrustContext } from "../daemon/trust-context-types.js";
|
|
38
37
|
import type { TrustClass } from "../runtime/actor-trust-resolver.js";
|
|
39
38
|
import { truncate as truncateText } from "../util/truncate.js";
|
|
@@ -56,15 +55,6 @@ export interface AdvisorContextSources {
|
|
|
56
55
|
* from the catalog section, mirroring the `skill_load` gate.
|
|
57
56
|
*/
|
|
58
57
|
enabledPluginSet?: ReadonlySet<string> | null;
|
|
59
|
-
/**
|
|
60
|
-
* Pre-resolved skill catalog, typically the parent conversation's warm
|
|
61
|
-
* `skillProjectionCache.catalog`. Passing it keeps the synchronous on-disk
|
|
62
|
-
* catalog scan out of the consult path (and matches the catalog view the
|
|
63
|
-
* parent turn's tool projection used). When absent, the section falls back
|
|
64
|
-
* to a fresh `loadSkillCatalog()` scan, the same call every agent turn's
|
|
65
|
-
* projection already makes.
|
|
66
|
-
*/
|
|
67
|
-
skillCatalog?: readonly SkillSummary[];
|
|
68
58
|
}
|
|
69
59
|
|
|
70
60
|
/** Cap a block so the assembled context never balloons the consult prompt. */
|
|
@@ -114,7 +104,6 @@ async function buildToolsSection(
|
|
|
114
104
|
*/
|
|
115
105
|
async function buildSkillsSection(
|
|
116
106
|
enabledPluginSet: ReadonlySet<string> | null | undefined,
|
|
117
|
-
preResolvedCatalog: readonly SkillSummary[] | undefined,
|
|
118
107
|
): Promise<string | null> {
|
|
119
108
|
try {
|
|
120
109
|
const [
|
|
@@ -130,19 +119,17 @@ async function buildSkillsSection(
|
|
|
130
119
|
]);
|
|
131
120
|
const config = getConfig();
|
|
132
121
|
const pluginScope = enabledPluginSet ?? null;
|
|
133
|
-
const catalog =
|
|
134
|
-
(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
},
|
|
145
|
-
);
|
|
122
|
+
const catalog = loadSkillCatalog().filter((skill) => {
|
|
123
|
+
if (
|
|
124
|
+
pluginScope !== null &&
|
|
125
|
+
skill.owner?.kind === "plugin" &&
|
|
126
|
+
!pluginScope.has(skill.owner.id)
|
|
127
|
+
) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
const flagKey = skillFlagKey(skill);
|
|
131
|
+
return !flagKey || isAssistantFeatureFlagEnabled(flagKey, config);
|
|
132
|
+
});
|
|
146
133
|
if (catalog.length === 0) {
|
|
147
134
|
return null;
|
|
148
135
|
}
|
|
@@ -384,7 +371,7 @@ export async function buildAdvisorContext(
|
|
|
384
371
|
const sections = await Promise.all(
|
|
385
372
|
[
|
|
386
373
|
buildToolsSection(sources.allowedToolNames),
|
|
387
|
-
buildSkillsSection(sources.enabledPluginSet
|
|
374
|
+
buildSkillsSection(sources.enabledPluginSet),
|
|
388
375
|
buildWorkspaceSection(sources),
|
|
389
376
|
].map((section) => withSectionTimeout(section, sectionTimeoutMs)),
|
|
390
377
|
);
|
|
@@ -158,6 +158,7 @@ const SKILL_TOOLS: GuardedTool[] = [
|
|
|
158
158
|
proxied("computer_use_drag"),
|
|
159
159
|
proxied("computer_use_open_app"),
|
|
160
160
|
proxied("computer_use_run_applescript"),
|
|
161
|
+
proxied("computer_use_sequence"),
|
|
161
162
|
proxied("computer_use_respond"),
|
|
162
163
|
|
|
163
164
|
{ name: "contact_merge", input: { keep_id: "c-1", merge_id: "c-2" } },
|
|
@@ -90,7 +90,9 @@ describe("executeAcpListAgents", () => {
|
|
|
90
90
|
const codex = parsed.agents.find((a: { id: string }) => a.id === "codex");
|
|
91
91
|
expect(codex.available).toBe(false);
|
|
92
92
|
expect(codex.unavailableReason).toBe("'codex-acp' is not on PATH");
|
|
93
|
-
expect(codex.setupHint).toBe(
|
|
93
|
+
expect(codex.setupHint).toBe(
|
|
94
|
+
"bun add -g @agentclientprotocol/codex-acp@1.10.0",
|
|
95
|
+
);
|
|
94
96
|
|
|
95
97
|
const claude = parsed.agents.find((a: { id: string }) => a.id === "claude");
|
|
96
98
|
expect(claude.available).toBe(true);
|