@vellumai/assistant 0.12.1 → 0.12.2-staging.1
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/openapi.yaml +327 -52
- 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-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-title-service.test.ts +14 -10
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
- package/src/__tests__/credential-record-retire.test.ts +171 -1
- package/src/__tests__/credential-routes.test.ts +212 -3
- package/src/__tests__/credential-security-invariants.test.ts +4 -2
- package/src/__tests__/cu-unified-flow.test.ts +8 -2
- package/src/__tests__/document-sync-tags.test.ts +25 -0
- package/src/__tests__/drain-kick-guard.test.ts +0 -2
- package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/git-porcelain.test.ts +47 -0
- package/src/__tests__/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 +539 -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 +113 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -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__/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 +19 -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__/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__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -0
- package/src/acp/__tests__/client-handler.test.ts +90 -2
- package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
- package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
- package/src/acp/__tests__/session-manager.test.ts +895 -4
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +96 -10
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/client-handler.ts +16 -3
- package/src/acp/model-config.test.ts +166 -0
- package/src/acp/model-config.ts +138 -0
- package/src/acp/resolve-agent.test.ts +220 -6
- package/src/acp/resolve-agent.ts +88 -23
- package/src/acp/session-manager.test.ts +196 -3
- package/src/acp/session-manager.ts +441 -18
- package/src/acp/types.ts +50 -5
- package/src/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 +58 -25
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
- package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
- package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
- package/src/calls/__tests__/voice-session-bridge.test.ts +37 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
- package/src/calls/barge-in-guard.ts +118 -0
- package/src/calls/call-constants.ts +24 -4
- package/src/calls/call-controller.ts +499 -199
- package/src/calls/call-transport.ts +16 -0
- package/src/calls/media-stream-output.ts +32 -0
- package/src/calls/media-stream-server.ts +82 -30
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/{live-voice → calls}/progress-narration.ts +2 -2
- package/src/calls/resolve-call-tts-provider.ts +33 -2
- package/src/calls/tts-call-strategy.ts +9 -5
- package/src/calls/types.ts +2 -0
- package/src/calls/voice-control-protocol.ts +53 -21
- package/src/calls/voice-leg-coordinator.ts +189 -0
- package/src/calls/voice-progress-cadence.ts +423 -0
- package/src/calls/voice-session-bridge.ts +59 -46
- package/src/calls/voice-triage-escalate.ts +175 -56
- package/src/cli/commands/__tests__/apps.test.ts +245 -0
- package/src/cli/commands/__tests__/bash.test.ts +53 -0
- package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
- package/src/cli/commands/apps.help.ts +67 -13
- package/src/cli/commands/apps.ts +183 -0
- package/src/cli/commands/bash.help.ts +8 -13
- package/src/cli/commands/bash.ts +7 -25
- package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
- package/src/cli/commands/channels/index.help.ts +70 -2
- package/src/cli/commands/channels/index.ts +16 -3
- package/src/cli/commands/channels/send.ts +128 -0
- package/src/cli/commands/credentials.help.ts +6 -2
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/roadmap.help.ts +5 -1
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +103 -90
- package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
- package/src/config/__tests__/platform-identity.test.ts +255 -0
- package/src/config/__tests__/platform-rehydration.test.ts +99 -9
- package/src/config/acp-agent-write.ts +43 -0
- package/src/config/acp-defaults.test.ts +13 -3
- package/src/config/acp-defaults.ts +23 -6
- package/src/config/acp-schema.test.ts +81 -0
- package/src/config/acp-schema.ts +30 -2
- package/src/config/bundled-skills/acp/SKILL.md +22 -14
- package/src/config/bundled-skills/acp/TOOLS.json +5 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +20 -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 +24 -12
- package/src/config/loader.ts +1 -0
- package/src/config/memory-v3-gate.test.ts +31 -0
- package/src/config/memory-v3-gate.ts +20 -16
- package/src/config/platform-identity.ts +201 -0
- package/src/config/platform-rehydration.ts +11 -27
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
- package/src/config/schemas/__tests__/voice.test.ts +148 -0
- package/src/config/schemas/calls.ts +1 -28
- package/src/config/schemas/live-voice.ts +1 -173
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +10 -0
- package/src/config/schemas/services.ts +8 -0
- package/src/config/schemas/skills.ts +0 -14
- package/src/config/schemas/voice.ts +150 -0
- package/src/credential-execution/process-manager.test.ts +18 -19
- package/src/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 +2 -1
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +15 -9
- package/src/daemon/conversation-tool-setup.ts +37 -43
- 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 +186 -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-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -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__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +213 -693
- package/src/live-voice/protocol.ts +0 -2
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +29 -45
- package/src/mcp/spec-schema.ts +111 -0
- package/src/mcp/startup.ts +8 -4
- package/src/mcp/workspace-mcp-config.ts +188 -0
- package/src/messaging/provider.ts +10 -3
- package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
- package/src/messaging/providers/callback-routing.ts +18 -0
- package/src/messaging/providers/channel-transport.ts +56 -0
- package/src/messaging/providers/discord/transport.ts +17 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
- package/src/messaging/providers/slack/adapter.ts +7 -44
- package/src/messaging/providers/slack/transport.ts +16 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
- package/src/messaging/providers/telegram-bot/client.ts +0 -26
- package/src/messaging/providers/telegram-bot/transport.ts +20 -0
- package/src/messaging/providers/whatsapp/adapter.ts +1 -48
- package/src/messaging/providers/whatsapp/transport.ts +18 -0
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
- package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/assistant-reply-producer.ts +8 -3
- package/src/notifications/conversation-pairing.ts +36 -16
- package/src/notifications/delivered-post-record.ts +11 -1
- package/src/notifications/guardian-feed-projection.ts +125 -5
- package/src/notifications/home-feed-side-effect.ts +55 -7
- package/src/notifications/schedule-result-producer.ts +66 -22
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/seed-providers-managed.test.ts +54 -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 +73 -0
- package/src/oauth/connection-resolver.ts +95 -2
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +204 -25
- 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-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +205 -0
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
- package/src/runtime/routes/acp-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +73 -0
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/channel-send-routes.ts +85 -0
- package/src/runtime/routes/conversation-list-routes.ts +14 -3
- package/src/runtime/routes/conversation-query-routes.ts +40 -0
- package/src/runtime/routes/conversation-routes.ts +16 -3
- package/src/runtime/routes/credential-routes.ts +19 -10
- package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
- package/src/runtime/routes/desktop-setup-routes.ts +35 -0
- package/src/runtime/routes/diagnostics-routes.ts +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 +36 -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/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-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
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for resolving an app query by name, slug, or id.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
9
|
+
|
|
10
|
+
import { createApp } from "../apps/app-store.js";
|
|
11
|
+
import { resolveAppQuery } from "../apps/resolve-app.js";
|
|
12
|
+
import { getWorkspacePluginsDir } from "../util/platform.js";
|
|
13
|
+
|
|
14
|
+
let workspaceDir: string;
|
|
15
|
+
let previousWorkspaceDir: string | undefined;
|
|
16
|
+
|
|
17
|
+
function freshWorkspace(): string {
|
|
18
|
+
return join(
|
|
19
|
+
tmpdir(),
|
|
20
|
+
`vellum-resolve-app-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function installPlugin(name: string): string {
|
|
25
|
+
const pluginDir = join(getWorkspacePluginsDir(), name);
|
|
26
|
+
mkdirSync(pluginDir, { recursive: true });
|
|
27
|
+
writeFileSync(
|
|
28
|
+
join(pluginDir, "package.json"),
|
|
29
|
+
JSON.stringify({ name, version: "1.0.0" }),
|
|
30
|
+
);
|
|
31
|
+
return pluginDir;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function bundleApp(pluginDir: string, app: string): void {
|
|
35
|
+
const appDir = join(pluginDir, "apps", app);
|
|
36
|
+
mkdirSync(appDir, { recursive: true });
|
|
37
|
+
writeFileSync(join(appDir, "index.html"), "<h1>Plugin app</h1>");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
previousWorkspaceDir = process.env.VELLUM_WORKSPACE_DIR;
|
|
42
|
+
workspaceDir = freshWorkspace();
|
|
43
|
+
process.env.VELLUM_WORKSPACE_DIR = workspaceDir;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
rmSync(workspaceDir, { recursive: true, force: true });
|
|
48
|
+
if (previousWorkspaceDir === undefined) {
|
|
49
|
+
delete process.env.VELLUM_WORKSPACE_DIR;
|
|
50
|
+
} else {
|
|
51
|
+
process.env.VELLUM_WORKSPACE_DIR = previousWorkspaceDir;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe("resolveAppQuery", () => {
|
|
56
|
+
test("resolves a workspace app by display name, slug, and id", () => {
|
|
57
|
+
const created = createApp({
|
|
58
|
+
name: "Budget",
|
|
59
|
+
schemaJson: "{}",
|
|
60
|
+
htmlDefinition: "<h1>Budget</h1>",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const byName = resolveAppQuery("Budget");
|
|
64
|
+
expect(byName.ok).toBe(true);
|
|
65
|
+
if (byName.ok) {
|
|
66
|
+
expect(byName.app.id).toBe(created.id);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const byNameCase = resolveAppQuery("budget");
|
|
70
|
+
expect(byNameCase.ok).toBe(true);
|
|
71
|
+
if (byNameCase.ok) {
|
|
72
|
+
expect(byNameCase.app.id).toBe(created.id);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const slug = created.dirName ?? "";
|
|
76
|
+
expect(slug.length).toBeGreaterThan(0);
|
|
77
|
+
const bySlug = resolveAppQuery(slug);
|
|
78
|
+
expect(bySlug.ok).toBe(true);
|
|
79
|
+
if (bySlug.ok) {
|
|
80
|
+
expect(bySlug.app.id).toBe(created.id);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const byId = resolveAppQuery(created.id);
|
|
84
|
+
expect(byId.ok).toBe(true);
|
|
85
|
+
if (byId.ok) {
|
|
86
|
+
expect(byId.app.id).toBe(created.id);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("returns not_found for an unknown name", () => {
|
|
91
|
+
const result = resolveAppQuery("missing");
|
|
92
|
+
expect(result).toEqual({
|
|
93
|
+
ok: false,
|
|
94
|
+
reason: "not_found",
|
|
95
|
+
query: "missing",
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("returns ambiguous when two apps share a display name", () => {
|
|
100
|
+
const first = createApp({
|
|
101
|
+
name: "Notes",
|
|
102
|
+
schemaJson: "{}",
|
|
103
|
+
htmlDefinition: "<h1>One</h1>",
|
|
104
|
+
});
|
|
105
|
+
const second = createApp({
|
|
106
|
+
name: "Notes",
|
|
107
|
+
schemaJson: "{}",
|
|
108
|
+
htmlDefinition: "<h1>Two</h1>",
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const result = resolveAppQuery("Notes");
|
|
112
|
+
expect(result.ok).toBe(false);
|
|
113
|
+
if (!result.ok && result.reason === "ambiguous") {
|
|
114
|
+
const ids = result.matches.map((m) => m.id).sort();
|
|
115
|
+
expect(ids).toEqual([first.id, second.id].sort());
|
|
116
|
+
} else {
|
|
117
|
+
throw new Error("expected ambiguous resolution");
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("resolves a plugin app by directory name", () => {
|
|
122
|
+
const pluginDir = installPlugin("charts");
|
|
123
|
+
bundleApp(pluginDir, "viewer");
|
|
124
|
+
|
|
125
|
+
const result = resolveAppQuery("viewer");
|
|
126
|
+
expect(result.ok).toBe(true);
|
|
127
|
+
if (result.ok) {
|
|
128
|
+
expect(result.app.origin).toEqual({
|
|
129
|
+
kind: "plugin",
|
|
130
|
+
pluginName: "charts",
|
|
131
|
+
});
|
|
132
|
+
expect(result.app.id).toBe("plugins~charts~viewer");
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
});
|
|
@@ -1103,6 +1103,7 @@ describe("scaffold_managed_skill tool", () => {
|
|
|
1103
1103
|
activation_hints: HINTS,
|
|
1104
1104
|
overwrite: true,
|
|
1105
1105
|
files: [{ path: "references/failure-modes.md", content: "gotchas" }],
|
|
1106
|
+
change_summary: "Added the failure modes reference.",
|
|
1106
1107
|
},
|
|
1107
1108
|
makeRetrospectiveContext(),
|
|
1108
1109
|
);
|
|
@@ -1550,6 +1551,7 @@ describe("scaffold_managed_skill tool", () => {
|
|
|
1550
1551
|
body_markdown: "V2 procedure.",
|
|
1551
1552
|
activation_hints: HINTS,
|
|
1552
1553
|
overwrite: true,
|
|
1554
|
+
change_summary: "Refined the procedure.",
|
|
1553
1555
|
},
|
|
1554
1556
|
makeRetrospectiveContext({ conversationId: "retro-run-conv" }),
|
|
1555
1557
|
lineageSeam(),
|
|
@@ -1702,6 +1704,7 @@ describe("background skill update notification", () => {
|
|
|
1702
1704
|
body_markdown: "1. Refined steps.",
|
|
1703
1705
|
activation_hints: HINTS,
|
|
1704
1706
|
overwrite: true,
|
|
1707
|
+
change_summary: "Refined the steps.",
|
|
1705
1708
|
},
|
|
1706
1709
|
makeRetrospectiveContext({ conversationId: "retro-run-conv" }),
|
|
1707
1710
|
lineage(),
|
|
@@ -1715,9 +1718,7 @@ describe("background skill update notification", () => {
|
|
|
1715
1718
|
// must be the conversation the work came from, not the hidden fork.
|
|
1716
1719
|
expect(signal.sourceContextId).toBe("source-conv");
|
|
1717
1720
|
expect(signal.contextPayload?.skillId).toBe("weekly-export");
|
|
1718
|
-
expect(
|
|
1719
|
-
"Weekly Report Export",
|
|
1720
|
-
);
|
|
1721
|
+
expect(signal.contextPayload?.summary).toBe("Refined the steps.");
|
|
1721
1722
|
// The home feed falls back to `title`/`body` when no channel copy was
|
|
1722
1723
|
// rendered, which is the intended quiet shape for this signal. Without
|
|
1723
1724
|
// them a suppressed delivery would leave the feed item unwritten.
|
|
@@ -1725,15 +1726,236 @@ describe("background skill update notification", () => {
|
|
|
1725
1726
|
expect(signal.contextPayload?.title).toBe(
|
|
1726
1727
|
"Skill updated: Weekly Report Export",
|
|
1727
1728
|
);
|
|
1728
|
-
expect(
|
|
1729
|
-
"Weekly Report Export",
|
|
1730
|
-
);
|
|
1729
|
+
expect(signal.contextPayload?.body).toBe("Refined the steps.");
|
|
1731
1730
|
// Deduped per skill per day so repeated refinements cannot flood the feed.
|
|
1732
1731
|
expect(signal.dedupeKey).toBe(
|
|
1733
1732
|
`skill-updated:weekly-export:${new Date().toISOString().slice(0, 10)}`,
|
|
1734
1733
|
);
|
|
1735
1734
|
});
|
|
1736
1735
|
|
|
1736
|
+
test("the notice body is the pass's change_summary, so the feed says what changed", async () => {
|
|
1737
|
+
await seedAssistantSkill("weekly-export", "Old body.");
|
|
1738
|
+
|
|
1739
|
+
const result = await executeScaffoldManagedSkill(
|
|
1740
|
+
{
|
|
1741
|
+
skill_id: "weekly-export",
|
|
1742
|
+
name: "Weekly Report Export",
|
|
1743
|
+
description: "export the weekly usage report",
|
|
1744
|
+
body_markdown: "1. Refined steps.",
|
|
1745
|
+
activation_hints: HINTS,
|
|
1746
|
+
overwrite: true,
|
|
1747
|
+
change_summary:
|
|
1748
|
+
"Added the retry after an expired session and the export endpoint that held steady.",
|
|
1749
|
+
},
|
|
1750
|
+
makeRetrospectiveContext({ conversationId: "retro-run-conv" }),
|
|
1751
|
+
lineage(),
|
|
1752
|
+
);
|
|
1753
|
+
|
|
1754
|
+
expect(result.isError).toBe(false);
|
|
1755
|
+
expect(emittedSignals).toHaveLength(1);
|
|
1756
|
+
const payload = emittedSignals[0]!.contextPayload;
|
|
1757
|
+
// The title still names the skill; the body is the change itself.
|
|
1758
|
+
expect(payload?.title).toBe("Skill updated: Weekly Report Export");
|
|
1759
|
+
expect(payload?.body).toBe(
|
|
1760
|
+
"Added the retry after an expired session and the export endpoint that held steady.",
|
|
1761
|
+
);
|
|
1762
|
+
expect(payload?.summary).toBe(payload?.body);
|
|
1763
|
+
});
|
|
1764
|
+
|
|
1765
|
+
test("a background overwrite without a change_summary is refused before the write", async () => {
|
|
1766
|
+
await seedAssistantSkill("weekly-export", "Old body.");
|
|
1767
|
+
const skillFile = join(TEST_DIR, "skills", "weekly-export", "SKILL.md");
|
|
1768
|
+
const before = readFileSync(skillFile, "utf-8");
|
|
1769
|
+
|
|
1770
|
+
for (const input of [
|
|
1771
|
+
{},
|
|
1772
|
+
// Whitespace-only reads as missing, not as an empty notice.
|
|
1773
|
+
{ change_summary: " \n " },
|
|
1774
|
+
]) {
|
|
1775
|
+
const result = await executeScaffoldManagedSkill(
|
|
1776
|
+
{
|
|
1777
|
+
skill_id: "weekly-export",
|
|
1778
|
+
name: "Weekly Report Export",
|
|
1779
|
+
description: "export the weekly usage report",
|
|
1780
|
+
body_markdown: "1. Refined steps.",
|
|
1781
|
+
activation_hints: HINTS,
|
|
1782
|
+
overwrite: true,
|
|
1783
|
+
...input,
|
|
1784
|
+
},
|
|
1785
|
+
makeRetrospectiveContext({ conversationId: "retro-run-conv" }),
|
|
1786
|
+
lineage(),
|
|
1787
|
+
);
|
|
1788
|
+
|
|
1789
|
+
// Self-correcting: the error returns to the pass in the same turn, so
|
|
1790
|
+
// the retry carries the field and nothing was lost meanwhile.
|
|
1791
|
+
expect(result.isError).toBe(true);
|
|
1792
|
+
expect(result.content).toBe(
|
|
1793
|
+
'Error: change_summary is required when updating an existing skill: pass one or two short sentences (under 200 characters) for the person who reads the "Skill updated" notice, naming what you changed and what in the trace prompted it (for example "Added the retry after an expired session and the export endpoint that held steady.").',
|
|
1794
|
+
);
|
|
1795
|
+
expect(readFileSync(skillFile, "utf-8")).toBe(before);
|
|
1796
|
+
expect(emittedSignals).toHaveLength(0);
|
|
1797
|
+
}
|
|
1798
|
+
});
|
|
1799
|
+
|
|
1800
|
+
test("a background call on an existing skill without overwrite hears the overwrite error, not the summary requirement", async () => {
|
|
1801
|
+
await seedAssistantSkill("weekly-export", "Old body.");
|
|
1802
|
+
|
|
1803
|
+
const result = await executeScaffoldManagedSkill(
|
|
1804
|
+
{
|
|
1805
|
+
skill_id: "weekly-export",
|
|
1806
|
+
name: "Weekly Report Export",
|
|
1807
|
+
description: "export the weekly usage report",
|
|
1808
|
+
body_markdown: "1. Refined steps.",
|
|
1809
|
+
activation_hints: HINTS,
|
|
1810
|
+
},
|
|
1811
|
+
makeRetrospectiveContext({ conversationId: "retro-run-conv" }),
|
|
1812
|
+
lineage(),
|
|
1813
|
+
);
|
|
1814
|
+
|
|
1815
|
+
// The flag is what actually blocks this call, so that is the error it
|
|
1816
|
+
// gets: a retry that only adds change_summary would still fail.
|
|
1817
|
+
expect(result.isError).toBe(true);
|
|
1818
|
+
expect(result.content).toContain("Set overwrite=true to replace it.");
|
|
1819
|
+
expect(result.content).not.toContain("change_summary");
|
|
1820
|
+
expect(emittedSignals).toHaveLength(0);
|
|
1821
|
+
});
|
|
1822
|
+
|
|
1823
|
+
test("the ownership backstop speaks before the change_summary requirement", async () => {
|
|
1824
|
+
await executeScaffoldManagedSkill(
|
|
1825
|
+
{
|
|
1826
|
+
skill_id: "user-owned",
|
|
1827
|
+
name: "User Owned",
|
|
1828
|
+
description: "a person wrote this",
|
|
1829
|
+
body_markdown: "V1.",
|
|
1830
|
+
activation_hints: HINTS,
|
|
1831
|
+
},
|
|
1832
|
+
makeContext(),
|
|
1833
|
+
);
|
|
1834
|
+
|
|
1835
|
+
const result = await executeScaffoldManagedSkill(
|
|
1836
|
+
{
|
|
1837
|
+
skill_id: "user-owned",
|
|
1838
|
+
name: "User Owned",
|
|
1839
|
+
description: "a person wrote this",
|
|
1840
|
+
body_markdown: "V2.",
|
|
1841
|
+
activation_hints: HINTS,
|
|
1842
|
+
overwrite: true,
|
|
1843
|
+
},
|
|
1844
|
+
makeRetrospectiveContext({ conversationId: "retro-run-conv" }),
|
|
1845
|
+
lineage(),
|
|
1846
|
+
);
|
|
1847
|
+
|
|
1848
|
+
expect(result.isError).toBe(true);
|
|
1849
|
+
expect(result.content).toContain("not verifiably assistant-authored");
|
|
1850
|
+
});
|
|
1851
|
+
|
|
1852
|
+
test("a user-directed overwrite needs no change_summary: it never notifies", async () => {
|
|
1853
|
+
await executeScaffoldManagedSkill(
|
|
1854
|
+
{
|
|
1855
|
+
skill_id: "user-skill",
|
|
1856
|
+
name: "User Skill",
|
|
1857
|
+
description: "asked for",
|
|
1858
|
+
body_markdown: "V1.",
|
|
1859
|
+
activation_hints: HINTS,
|
|
1860
|
+
},
|
|
1861
|
+
makeContext(),
|
|
1862
|
+
);
|
|
1863
|
+
|
|
1864
|
+
const result = await executeScaffoldManagedSkill(
|
|
1865
|
+
{
|
|
1866
|
+
skill_id: "user-skill",
|
|
1867
|
+
name: "User Skill",
|
|
1868
|
+
description: "asked for",
|
|
1869
|
+
body_markdown: "V2.",
|
|
1870
|
+
activation_hints: HINTS,
|
|
1871
|
+
overwrite: true,
|
|
1872
|
+
},
|
|
1873
|
+
makeContext(),
|
|
1874
|
+
);
|
|
1875
|
+
|
|
1876
|
+
expect(result.isError).toBe(false);
|
|
1877
|
+
});
|
|
1878
|
+
|
|
1879
|
+
test("change_summary is sanitized like any other notification body", async () => {
|
|
1880
|
+
await seedAssistantSkill("weekly-export", "Old body.");
|
|
1881
|
+
|
|
1882
|
+
await executeScaffoldManagedSkill(
|
|
1883
|
+
{
|
|
1884
|
+
skill_id: "weekly-export",
|
|
1885
|
+
name: "Weekly Report Export",
|
|
1886
|
+
description: "export the weekly usage report",
|
|
1887
|
+
body_markdown: "1. Refined steps.",
|
|
1888
|
+
activation_hints: HINTS,
|
|
1889
|
+
overwrite: true,
|
|
1890
|
+
change_summary: `Added\u0007 the retry.\r\n\n\n\nDropped the login step. ${"x".repeat(300)}`,
|
|
1891
|
+
},
|
|
1892
|
+
makeRetrospectiveContext({ conversationId: "retro-run-conv" }),
|
|
1893
|
+
lineage(),
|
|
1894
|
+
);
|
|
1895
|
+
|
|
1896
|
+
const body = String(emittedSignals[0]!.contextPayload?.body);
|
|
1897
|
+
// Control characters go, horizontal whitespace collapses, blank-line runs
|
|
1898
|
+
// collapse to one paragraph break, and the whole thing is clamped to the
|
|
1899
|
+
// shared notification preview budget.
|
|
1900
|
+
expect(
|
|
1901
|
+
body.startsWith("Added the retry.\n\nDropped the login step. xxx"),
|
|
1902
|
+
).toBe(true);
|
|
1903
|
+
expect(body).not.toMatch(/[\u0000-\u0008\u000b\u000c\u000e-\u001f]/);
|
|
1904
|
+
expect(body.length).toBe(200);
|
|
1905
|
+
expect(body.endsWith("\u2026")).toBe(true);
|
|
1906
|
+
});
|
|
1907
|
+
|
|
1908
|
+
test("a non-string change_summary is a self-correcting error", async () => {
|
|
1909
|
+
await seedAssistantSkill("weekly-export", "Old body.");
|
|
1910
|
+
|
|
1911
|
+
const result = await executeScaffoldManagedSkill(
|
|
1912
|
+
{
|
|
1913
|
+
skill_id: "weekly-export",
|
|
1914
|
+
name: "Weekly Report Export",
|
|
1915
|
+
description: "export the weekly usage report",
|
|
1916
|
+
body_markdown: "1. Refined steps.",
|
|
1917
|
+
activation_hints: HINTS,
|
|
1918
|
+
overwrite: true,
|
|
1919
|
+
change_summary: ["not", "a", "string"],
|
|
1920
|
+
},
|
|
1921
|
+
makeRetrospectiveContext({ conversationId: "retro-run-conv" }),
|
|
1922
|
+
lineage(),
|
|
1923
|
+
);
|
|
1924
|
+
|
|
1925
|
+
expect(result.isError).toBe(true);
|
|
1926
|
+
expect(result.content).toBe("Error: change_summary must be a string");
|
|
1927
|
+
expect(emittedSignals).toHaveLength(0);
|
|
1928
|
+
});
|
|
1929
|
+
|
|
1930
|
+
test("the registered tool's schema declares change_summary as an optional string", () => {
|
|
1931
|
+
// A call through the registered tool is validated against TOOLS.json
|
|
1932
|
+
// first, and the validator rejects undeclared keys, so the field has to
|
|
1933
|
+
// be in the schema for the executor to ever see it. It stays optional
|
|
1934
|
+
// there: the requirement holds only for a background overwrite of an
|
|
1935
|
+
// existing skill, which the schema cannot express, so the executor
|
|
1936
|
+
// enforces it.
|
|
1937
|
+
const scaffoldTool = readScaffoldToolEntry();
|
|
1938
|
+
expect(scaffoldTool.input_schema.properties.change_summary).toMatchObject({
|
|
1939
|
+
type: "string",
|
|
1940
|
+
});
|
|
1941
|
+
expect(scaffoldTool.input_schema.required).not.toContain("change_summary");
|
|
1942
|
+
|
|
1943
|
+
const result = validateInputAgainstSchema(
|
|
1944
|
+
"scaffold_managed_skill",
|
|
1945
|
+
{
|
|
1946
|
+
skill_id: "s",
|
|
1947
|
+
name: "N",
|
|
1948
|
+
description: "D",
|
|
1949
|
+
body_markdown: "B",
|
|
1950
|
+
activation_hints: HINTS,
|
|
1951
|
+
overwrite: true,
|
|
1952
|
+
change_summary: "Added the retry step.",
|
|
1953
|
+
},
|
|
1954
|
+
scaffoldTool.input_schema,
|
|
1955
|
+
);
|
|
1956
|
+
expect(result.ok).toBe(true);
|
|
1957
|
+
});
|
|
1958
|
+
|
|
1737
1959
|
test("it falls back to the run conversation when fork lineage does not resolve", async () => {
|
|
1738
1960
|
await seedAssistantSkill("weekly-export", "Old body.");
|
|
1739
1961
|
|
|
@@ -1745,6 +1967,7 @@ describe("background skill update notification", () => {
|
|
|
1745
1967
|
body_markdown: "1. Refined steps.",
|
|
1746
1968
|
activation_hints: HINTS,
|
|
1747
1969
|
overwrite: true,
|
|
1970
|
+
change_summary: "Refined the steps.",
|
|
1748
1971
|
},
|
|
1749
1972
|
makeRetrospectiveContext({ conversationId: "retro-run-conv" }),
|
|
1750
1973
|
{ getConversation: () => null },
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
getCAPath,
|
|
9
9
|
issueLeafCert,
|
|
10
10
|
} from "../outbound-proxy/index.js";
|
|
11
|
+
import { writeCombinedCABundle } from "../util/ca-bundle.js";
|
|
11
12
|
|
|
12
13
|
let dataDir: string;
|
|
13
14
|
|
|
@@ -19,6 +20,40 @@ afterAll(async () => {
|
|
|
19
20
|
await rm(dataDir, { recursive: true, force: true });
|
|
20
21
|
});
|
|
21
22
|
|
|
23
|
+
test("combined trust verifies certificates from both CA sources", async () => {
|
|
24
|
+
const roots = [join(dataDir, "system"), join(dataDir, "extra")];
|
|
25
|
+
const leaves: string[] = [];
|
|
26
|
+
for (const root of roots) {
|
|
27
|
+
await ensureLocalCA(root);
|
|
28
|
+
const caDir = join(root, "proxy-ca");
|
|
29
|
+
await issueLeafCert(caDir, "example.com");
|
|
30
|
+
leaves.push(join(caDir, "issued", "example.com.pem"));
|
|
31
|
+
}
|
|
32
|
+
const bundle = join(dataDir, "combined.pem");
|
|
33
|
+
await writeCombinedCABundle(
|
|
34
|
+
getCAPath(roots[0]!),
|
|
35
|
+
getCAPath(roots[1]!),
|
|
36
|
+
bundle,
|
|
37
|
+
);
|
|
38
|
+
const verify = Bun.spawn(
|
|
39
|
+
["openssl", "verify", "-CAfile", bundle, ...leaves],
|
|
40
|
+
{
|
|
41
|
+
stdout: "pipe",
|
|
42
|
+
stderr: "pipe",
|
|
43
|
+
windowsHide: true,
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
const [code, output, error] = await Promise.all([
|
|
47
|
+
verify.exited,
|
|
48
|
+
new Response(verify.stdout).text(),
|
|
49
|
+
new Response(verify.stderr).text(),
|
|
50
|
+
]);
|
|
51
|
+
expect({ code, error }).toEqual({ code: 0, error: "" });
|
|
52
|
+
for (const leaf of leaves) {
|
|
53
|
+
expect(output).toContain(`${leaf}: OK`);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
22
57
|
describe("ensureLocalCA", () => {
|
|
23
58
|
test("creates CA cert and key with correct permissions", async () => {
|
|
24
59
|
await ensureLocalCA(dataDir);
|