@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
|
@@ -51,7 +51,12 @@ mock.module("../../../persistence/embeddings/embedding-backend.js", () => ({
|
|
|
51
51
|
}));
|
|
52
52
|
|
|
53
53
|
import { BACKUP_PROFILE_KEYS } from "../../../config/default-profile-names.js";
|
|
54
|
-
import {
|
|
54
|
+
import {
|
|
55
|
+
getConfig,
|
|
56
|
+
loadConfig,
|
|
57
|
+
loadRawConfig,
|
|
58
|
+
} from "../../../config/loader.js";
|
|
59
|
+
import { AssistantConfigSchema } from "../../../config/schema.js";
|
|
55
60
|
import { LLMConfigBase } from "../../../config/schemas/llm.js";
|
|
56
61
|
import type { ConversationCreateType } from "../../../persistence/conversation-types.js";
|
|
57
62
|
import {
|
|
@@ -1940,3 +1945,105 @@ describe("ingress URL writes through the generic config routes", () => {
|
|
|
1940
1945
|
expect(ingress.lastTunnel).toEqual(LAST_TUNNEL);
|
|
1941
1946
|
});
|
|
1942
1947
|
});
|
|
1948
|
+
|
|
1949
|
+
describe("config writes to a per-agent acp entry", () => {
|
|
1950
|
+
const patchRoute = ROUTES.find((r) => r.operationId === "config_patch")!;
|
|
1951
|
+
const setRoute = ROUTES.find((r) => r.operationId === "config_set")!;
|
|
1952
|
+
|
|
1953
|
+
beforeEach(() => {
|
|
1954
|
+
rawConfigFixture = {
|
|
1955
|
+
acp: {
|
|
1956
|
+
agents: {
|
|
1957
|
+
claude: { command: "claude-agent-acp", args: [], model: "opus" },
|
|
1958
|
+
},
|
|
1959
|
+
},
|
|
1960
|
+
};
|
|
1961
|
+
seedRawConfig();
|
|
1962
|
+
});
|
|
1963
|
+
|
|
1964
|
+
function agentEntry(
|
|
1965
|
+
raw: Record<string, unknown>,
|
|
1966
|
+
id = "claude",
|
|
1967
|
+
): Record<string, unknown> {
|
|
1968
|
+
const acp = raw.acp as Record<string, unknown>;
|
|
1969
|
+
const agents = acp.agents as Record<string, Record<string, unknown>>;
|
|
1970
|
+
return agents[id]!;
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
test("a nulled per-agent model is dropped on both write paths", async () => {
|
|
1974
|
+
await patchRoute.handler({
|
|
1975
|
+
body: { acp: { agents: { claude: { model: null } } } },
|
|
1976
|
+
});
|
|
1977
|
+
|
|
1978
|
+
const patched = agentEntry(loadRawConfig());
|
|
1979
|
+
expect("model" in patched).toBe(false);
|
|
1980
|
+
expect(patched.command).toBe("claude-agent-acp");
|
|
1981
|
+
expect(AssistantConfigSchema.safeParse(loadRawConfig()).success).toBe(true);
|
|
1982
|
+
|
|
1983
|
+
seedRawConfig();
|
|
1984
|
+
await setRoute.handler({
|
|
1985
|
+
body: { path: "acp.agents.claude.model", value: null },
|
|
1986
|
+
});
|
|
1987
|
+
|
|
1988
|
+
expect("model" in agentEntry(loadRawConfig())).toBe(false);
|
|
1989
|
+
expect(AssistantConfigSchema.safeParse(loadRawConfig()).success).toBe(true);
|
|
1990
|
+
expect(loadConfig().acp.agents.claude?.model).toBeUndefined();
|
|
1991
|
+
});
|
|
1992
|
+
|
|
1993
|
+
test("a nulled per-agent command is dropped on both write paths", async () => {
|
|
1994
|
+
await setRoute.handler({
|
|
1995
|
+
body: { path: "acp.agents.claude.command", value: null },
|
|
1996
|
+
});
|
|
1997
|
+
|
|
1998
|
+
expect("command" in agentEntry(loadRawConfig())).toBe(false);
|
|
1999
|
+
expect(AssistantConfigSchema.safeParse(loadRawConfig()).success).toBe(true);
|
|
2000
|
+
expect(loadConfig().acp.agents.claude?.command).toBeUndefined();
|
|
2001
|
+
|
|
2002
|
+
seedRawConfig();
|
|
2003
|
+
await patchRoute.handler({
|
|
2004
|
+
body: { acp: { agents: { claude: { command: null } } } },
|
|
2005
|
+
});
|
|
2006
|
+
|
|
2007
|
+
const patched = agentEntry(loadRawConfig());
|
|
2008
|
+
expect("command" in patched).toBe(false);
|
|
2009
|
+
expect(patched.model).toBe("opus");
|
|
2010
|
+
expect(AssistantConfigSchema.safeParse(loadRawConfig()).success).toBe(true);
|
|
2011
|
+
expect(loadConfig().acp.agents.claude?.command).toBeUndefined();
|
|
2012
|
+
});
|
|
2013
|
+
|
|
2014
|
+
test("a nulled command on an id with no bundled profile is dropped too", async () => {
|
|
2015
|
+
rawConfigFixture = {
|
|
2016
|
+
acp: { agents: { mine: { command: "my-acp", args: [] } } },
|
|
2017
|
+
};
|
|
2018
|
+
seedRawConfig();
|
|
2019
|
+
|
|
2020
|
+
await setRoute.handler({
|
|
2021
|
+
body: { path: "acp.agents.mine.command", value: null },
|
|
2022
|
+
});
|
|
2023
|
+
|
|
2024
|
+
expect("command" in agentEntry(loadRawConfig(), "mine")).toBe(false);
|
|
2025
|
+
const result = AssistantConfigSchema.safeParse(loadRawConfig());
|
|
2026
|
+
expect(result.success).toBe(false);
|
|
2027
|
+
if (result.success) {
|
|
2028
|
+
return;
|
|
2029
|
+
}
|
|
2030
|
+
expect(result.error.issues.map((issue) => issue.path)).toEqual([
|
|
2031
|
+
["acp", "agents", "mine", "command"],
|
|
2032
|
+
]);
|
|
2033
|
+
expect(result.error.issues[0]?.message).toContain("acp.agents.mine");
|
|
2034
|
+
});
|
|
2035
|
+
|
|
2036
|
+
test("a model set on a bare bundled entry survives the next load", async () => {
|
|
2037
|
+
rawConfigFixture = {};
|
|
2038
|
+
seedRawConfig();
|
|
2039
|
+
|
|
2040
|
+
await setRoute.handler({
|
|
2041
|
+
body: { path: "acp.agents.claude.model", value: "sonnet" },
|
|
2042
|
+
});
|
|
2043
|
+
|
|
2044
|
+
const entry = agentEntry(loadRawConfig());
|
|
2045
|
+
expect("command" in entry).toBe(false);
|
|
2046
|
+
expect(AssistantConfigSchema.safeParse(loadRawConfig()).success).toBe(true);
|
|
2047
|
+
expect(loadConfig().acp.agents.claude?.model).toBe("sonnet");
|
|
2048
|
+
});
|
|
2049
|
+
});
|
|
@@ -377,7 +377,7 @@ describe("GET config/llm/default-provider", () => {
|
|
|
377
377
|
expect(availability(result).message).toContain("Vellum-managed");
|
|
378
378
|
});
|
|
379
379
|
|
|
380
|
-
test("service_account connection
|
|
380
|
+
test("service_account connection with invalid credential → missing_credential", async () => {
|
|
381
381
|
seedConnection({
|
|
382
382
|
name: "gemini-personal",
|
|
383
383
|
provider: "gemini",
|
|
@@ -390,7 +390,7 @@ describe("GET config/llm/default-provider", () => {
|
|
|
390
390
|
setConfig("llm", { defaultProvider: { provider: "gemini" } });
|
|
391
391
|
|
|
392
392
|
const result = await get();
|
|
393
|
-
expect(availability(result).status).toBe("
|
|
393
|
+
expect(availability(result).status).toBe("missing_credential");
|
|
394
394
|
expect(availability(result).message).toContain("service-account");
|
|
395
395
|
});
|
|
396
396
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The dictation cleanup pass rewrites what the user actually said, so a
|
|
3
|
+
* rewrite the provider cut off at the token cap must never become the
|
|
4
|
+
* payload: the raw transcript is sent instead.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, expect, test } from "bun:test";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
computeMaxTokens,
|
|
11
|
+
resolveCleanedDictation,
|
|
12
|
+
} from "../diagnostics-routes.js";
|
|
13
|
+
|
|
14
|
+
const SPOKEN =
|
|
15
|
+
"Hello Quill can you generate a list of 20 open HR coordinator or HR " +
|
|
16
|
+
"related roles that are remote and pay about 50 to 60 K per year";
|
|
17
|
+
|
|
18
|
+
describe("resolveCleanedDictation", () => {
|
|
19
|
+
test("accepts an ordinary cleanup", () => {
|
|
20
|
+
const cleaned =
|
|
21
|
+
"Hello Quill, can you generate a list of 20 open HR coordinator or HR " +
|
|
22
|
+
"related roles that are remote and pay about 50 to 60K per year?";
|
|
23
|
+
expect(resolveCleanedDictation(SPOKEN, cleaned, "end_turn")).toEqual({
|
|
24
|
+
text: cleaned,
|
|
25
|
+
rejected: null,
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("trims surrounding whitespace off an accepted cleanup", () => {
|
|
30
|
+
const { text } = resolveCleanedDictation(
|
|
31
|
+
"so um I think we should ship the thing on Tuesday you know",
|
|
32
|
+
" I think we should ship the thing on Tuesday. ",
|
|
33
|
+
"end_turn",
|
|
34
|
+
);
|
|
35
|
+
expect(text).toBe("I think we should ship the thing on Tuesday.");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("rejects a rewrite cut off by max_tokens and keeps the raw words", () => {
|
|
39
|
+
expect(
|
|
40
|
+
resolveCleanedDictation(
|
|
41
|
+
SPOKEN,
|
|
42
|
+
"Hello Quill, can you create a list",
|
|
43
|
+
"max_tokens",
|
|
44
|
+
),
|
|
45
|
+
).toEqual({ text: SPOKEN, rejected: "truncated" });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("rejects a max_tokens rewrite even when it kept most of the words", () => {
|
|
49
|
+
const nearlyComplete = SPOKEN.slice(0, SPOKEN.length - 4);
|
|
50
|
+
const { rejected } = resolveCleanedDictation(
|
|
51
|
+
SPOKEN,
|
|
52
|
+
nearlyComplete,
|
|
53
|
+
"max_tokens",
|
|
54
|
+
);
|
|
55
|
+
expect(rejected).toBe("truncated");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("rejects the token-cap stop under every provider's name for it", () => {
|
|
59
|
+
for (const stopReason of ["length", "max_output_tokens", "MAX_TOKENS "]) {
|
|
60
|
+
expect(
|
|
61
|
+
resolveCleanedDictation(SPOKEN, "Hello Quill, can you", stopReason)
|
|
62
|
+
.rejected,
|
|
63
|
+
).toBe("truncated");
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("a missing stop reason is not treated as a truncation", () => {
|
|
68
|
+
const cleaned = "Hello Quill, can you generate a list?";
|
|
69
|
+
expect(resolveCleanedDictation(SPOKEN, cleaned, undefined)).toEqual({
|
|
70
|
+
text: cleaned,
|
|
71
|
+
rejected: null,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("a much shorter rewrite is the model's call, not a rejection", () => {
|
|
76
|
+
// The prompt asks for fillers and vague phrasing to go, so a concise
|
|
77
|
+
// rewrite of a rambling utterance is a correct cleanup.
|
|
78
|
+
const spoken =
|
|
79
|
+
"um you know I just kind of wanted to say like thank you so much you know";
|
|
80
|
+
expect(
|
|
81
|
+
resolveCleanedDictation(spoken, "Thank you so much.", "end_turn"),
|
|
82
|
+
).toEqual({ text: "Thank you so much.", rejected: null });
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("an empty rewrite falls back to raw without flagging a rejection", () => {
|
|
86
|
+
// The model returned nothing usable; there is no rewrite to distrust.
|
|
87
|
+
expect(resolveCleanedDictation(SPOKEN, " ", "end_turn")).toEqual({
|
|
88
|
+
text: SPOKEN,
|
|
89
|
+
rejected: null,
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("computeMaxTokens", () => {
|
|
95
|
+
test("budgets room for the transcript, reasoning, and JSON scaffolding", () => {
|
|
96
|
+
// The tool call carries the whole transcript back in `text`, so the
|
|
97
|
+
// budget has to clear the input's own token count with room to spare.
|
|
98
|
+
const estimatedInputTokens = Math.ceil(SPOKEN.length / 3);
|
|
99
|
+
expect(computeMaxTokens(SPOKEN.length)).toBeGreaterThan(
|
|
100
|
+
estimatedInputTokens * 2,
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("holds a floor for very short transcripts", () => {
|
|
105
|
+
expect(computeMaxTokens(5)).toBe(512);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `internal_mcp_add` writes only the transport
|
|
3
|
-
* risk, tool caps, allow/block lists) are not
|
|
2
|
+
* `internal_mcp_add` writes only the transport into workspace mcp.json.
|
|
3
|
+
* Policy fields (enabled, risk, tool caps, allow/block lists) are not
|
|
4
|
+
* persisted.
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
7
8
|
|
|
8
|
-
let
|
|
9
|
-
|
|
9
|
+
let stored: { servers: Record<string, { transport: Record<string, unknown> }> } =
|
|
10
|
+
{ servers: {} };
|
|
11
|
+
let saved:
|
|
12
|
+
| { servers: Record<string, { transport: Record<string, unknown> }> }
|
|
13
|
+
| undefined;
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
mock.module("../../../mcp/workspace-mcp-config.js", () => ({
|
|
16
|
+
loadWorkspaceMcpConfig: () => stored,
|
|
17
|
+
saveWorkspaceMcpConfig: (next: {
|
|
18
|
+
servers: Record<string, { transport: Record<string, unknown> }>;
|
|
19
|
+
}) => {
|
|
16
20
|
saved = next;
|
|
21
|
+
stored = next;
|
|
17
22
|
},
|
|
18
23
|
}));
|
|
19
24
|
|
|
@@ -26,13 +31,12 @@ const { ROUTES } = await import("../mcp-auth-routes.js");
|
|
|
26
31
|
const addRoute = ROUTES.find((r) => r.operationId === "internal_mcp_add")!;
|
|
27
32
|
|
|
28
33
|
function addedEntry(): Record<string, unknown> {
|
|
29
|
-
|
|
30
|
-
return mcp.servers["srv"] as Record<string, unknown>;
|
|
34
|
+
return saved!.servers["srv"] as Record<string, unknown>;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
describe("internal_mcp_add persisted shape", () => {
|
|
34
38
|
beforeEach(() => {
|
|
35
|
-
|
|
39
|
+
stored = { servers: {} };
|
|
36
40
|
saved = undefined;
|
|
37
41
|
});
|
|
38
42
|
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* has landed.
|
|
19
19
|
* POST /v1/acp/claude/auth/exchange — complete a manual/cloud flow: accept the
|
|
20
20
|
* pasted `code#state` (or a raw code + state), exchange it, and store the
|
|
21
|
-
* Claude OAuth token.
|
|
21
|
+
* Claude OAuth token set (access token plus any refresh token and expiry).
|
|
22
22
|
*
|
|
23
23
|
* `handleStartAuth` picks loopback vs. manual: a containerized host, or a client
|
|
24
24
|
* that sets `preferManual` because its browser can't reach the daemon's
|
|
@@ -126,7 +126,11 @@ async function handleStartLocalAuth(): Promise<StartResponse> {
|
|
|
126
126
|
// can react. Runs in the background — the web client opens `authorize_url`.
|
|
127
127
|
void flow.completion
|
|
128
128
|
.then(async (result) => {
|
|
129
|
-
await storeAcpClaudeToken(
|
|
129
|
+
await storeAcpClaudeToken({
|
|
130
|
+
accessToken: result.tokens.accessToken,
|
|
131
|
+
refreshToken: result.tokens.refreshToken,
|
|
132
|
+
expiresIn: result.tokens.expiresIn,
|
|
133
|
+
});
|
|
130
134
|
pendingFlows.mark(flow.state, "connected");
|
|
131
135
|
log.info("ACP Claude local OAuth flow connected");
|
|
132
136
|
})
|
|
@@ -216,7 +220,11 @@ async function handleExchange(args: RouteHandlerArgs): Promise<{ ok: true }> {
|
|
|
216
220
|
pending.codeVerifier,
|
|
217
221
|
state,
|
|
218
222
|
);
|
|
219
|
-
await storeAcpClaudeToken(
|
|
223
|
+
await storeAcpClaudeToken({
|
|
224
|
+
accessToken: result.tokens.accessToken,
|
|
225
|
+
refreshToken: result.tokens.refreshToken,
|
|
226
|
+
expiresIn: result.tokens.expiresIn,
|
|
227
|
+
});
|
|
220
228
|
} catch (err) {
|
|
221
229
|
const message = err instanceof Error ? err.message : String(err);
|
|
222
230
|
pendingFlows.mark(state, "error", { error: message });
|
|
@@ -262,6 +262,21 @@ describe("POST /v1/acp/spawn", () => {
|
|
|
262
262
|
// Guard runs before the approval gate — no prompt is surfaced.
|
|
263
263
|
expect(confirmationRequests).toHaveLength(0);
|
|
264
264
|
});
|
|
265
|
+
|
|
266
|
+
test("rejects a non-string model before the approval gate", async () => {
|
|
267
|
+
const handler = getSpawnHandler();
|
|
268
|
+
await expect(
|
|
269
|
+
handler({
|
|
270
|
+
body: {
|
|
271
|
+
agent: "claude",
|
|
272
|
+
task: "do a thing",
|
|
273
|
+
conversationId: "conv-1",
|
|
274
|
+
model: 42,
|
|
275
|
+
},
|
|
276
|
+
}),
|
|
277
|
+
).rejects.toThrow("model must be a string when provided");
|
|
278
|
+
expect(confirmationRequests).toHaveLength(0);
|
|
279
|
+
});
|
|
265
280
|
});
|
|
266
281
|
|
|
267
282
|
// ---------------------------------------------------------------------------
|
|
@@ -24,8 +24,11 @@ import {
|
|
|
24
24
|
AcpResumeError,
|
|
25
25
|
AcpSessionNotFoundError,
|
|
26
26
|
} from "../../acp/session-manager.js";
|
|
27
|
-
import type
|
|
28
|
-
import
|
|
27
|
+
import { type AcpSessionState, isLiveAcpStatus } from "../../acp/types.js";
|
|
28
|
+
import {
|
|
29
|
+
AcpSessionModelUpdateEventSchema,
|
|
30
|
+
type AssistantEvent,
|
|
31
|
+
} from "../../api/index.js";
|
|
29
32
|
import { getConfig } from "../../config/loader.js";
|
|
30
33
|
import { createGuardianRequestForConfirmation } from "../../permissions/confirmation-guardian-request.js";
|
|
31
34
|
import type { UserDecision } from "../../permissions/types.js";
|
|
@@ -53,6 +56,10 @@ const log = getLogger("acp-routes");
|
|
|
53
56
|
const DEFAULT_SESSION_LIMIT = 50;
|
|
54
57
|
const MAX_SESSION_LIMIT = 500;
|
|
55
58
|
|
|
59
|
+
/** The option shape the `acp_session_model_update` event already publishes. */
|
|
60
|
+
const acpModelOptionsSchema =
|
|
61
|
+
AcpSessionModelUpdateEventSchema.shape.availableModels;
|
|
62
|
+
|
|
56
63
|
const sessionEntrySchema = z.object({
|
|
57
64
|
id: z.string(),
|
|
58
65
|
agentId: z.string(),
|
|
@@ -68,6 +75,15 @@ const sessionEntrySchema = z.object({
|
|
|
68
75
|
/** Credential failure that ended the run, when one did. Drives the inline
|
|
69
76
|
* Connect card on reopen; cleared when a replacement token is stored. */
|
|
70
77
|
authErrorCode: z.string().optional(),
|
|
78
|
+
/** Model a live session is running on. Absent for history rows, which have
|
|
79
|
+
* no live process to ask. */
|
|
80
|
+
model: z.string().optional(),
|
|
81
|
+
/** Models a live session could run on. Absent for history rows. */
|
|
82
|
+
availableModels: acpModelOptionsSchema.optional(),
|
|
83
|
+
/** Scopes live model revisions to one assistant process. */
|
|
84
|
+
modelRevisionEpoch: z.string().uuid().optional(),
|
|
85
|
+
/** Orders live model state within `modelRevisionEpoch`. */
|
|
86
|
+
modelRevision: z.number().int().nonnegative().optional(),
|
|
71
87
|
usedTokens: z.number().optional(),
|
|
72
88
|
contextSize: z.number().optional(),
|
|
73
89
|
costAmount: z.number().optional(),
|
|
@@ -214,17 +230,26 @@ async function spawnSession({ body, abortSignal }: RouteHandlerArgs) {
|
|
|
214
230
|
const task = body?.task as string | undefined;
|
|
215
231
|
const conversationId = body?.conversationId as string | undefined;
|
|
216
232
|
const cwd = (body?.cwd as string | undefined) ?? process.cwd();
|
|
233
|
+
const model = body?.model ?? undefined;
|
|
217
234
|
|
|
218
235
|
if (!agent || !task || !conversationId) {
|
|
219
236
|
throw new BadRequestError("agent, task, and conversationId are required");
|
|
220
237
|
}
|
|
238
|
+
if (model !== undefined && typeof model !== "string") {
|
|
239
|
+
throw new BadRequestError("model must be a string when provided");
|
|
240
|
+
}
|
|
221
241
|
|
|
222
242
|
// High-risk approval gate. Block BEFORE any side effects — resolution can
|
|
223
243
|
// trigger a `bun` global install (auto-install.ts) and `manager.spawn`
|
|
224
244
|
// launches the host subprocess — so an unapproved request mutates nothing.
|
|
225
245
|
const decision = await awaitRouteApproval({
|
|
226
246
|
toolName: "acp_spawn",
|
|
227
|
-
input: {
|
|
247
|
+
input: {
|
|
248
|
+
agent,
|
|
249
|
+
task,
|
|
250
|
+
cwd,
|
|
251
|
+
...(model !== undefined ? { model } : {}),
|
|
252
|
+
},
|
|
228
253
|
conversationId,
|
|
229
254
|
signal: abortSignal,
|
|
230
255
|
});
|
|
@@ -262,17 +287,33 @@ async function spawnSession({ body, abortSignal }: RouteHandlerArgs) {
|
|
|
262
287
|
);
|
|
263
288
|
|
|
264
289
|
const manager = getAcpSessionManager();
|
|
265
|
-
const {
|
|
290
|
+
const {
|
|
291
|
+
acpSessionId,
|
|
292
|
+
protocolSessionId,
|
|
293
|
+
requestedModel,
|
|
294
|
+
effectiveModel,
|
|
295
|
+
modelWarning,
|
|
296
|
+
} = await manager.spawn(
|
|
266
297
|
agent,
|
|
267
298
|
agentConfig,
|
|
268
299
|
task,
|
|
269
300
|
cwd,
|
|
270
301
|
conversationId,
|
|
271
302
|
broadcastMessage,
|
|
303
|
+
{ model },
|
|
272
304
|
);
|
|
273
305
|
|
|
274
306
|
log.info({ acpSessionId, protocolSessionId, agent }, "ACP spawn succeeded");
|
|
275
|
-
|
|
307
|
+
// A refused model is a warning, not a failed spawn: the session is live on
|
|
308
|
+
// the agent's own model.
|
|
309
|
+
return {
|
|
310
|
+
acpSessionId,
|
|
311
|
+
protocolSessionId,
|
|
312
|
+
agent,
|
|
313
|
+
requestedModel: requestedModel ?? null,
|
|
314
|
+
effectiveModel: effectiveModel ?? null,
|
|
315
|
+
...(modelWarning ? { modelWarning } : {}),
|
|
316
|
+
};
|
|
276
317
|
}
|
|
277
318
|
|
|
278
319
|
async function steerSession({ pathParams, body }: RouteHandlerArgs) {
|
|
@@ -588,10 +629,7 @@ function deleteSession({ pathParams }: RouteHandlerArgs) {
|
|
|
588
629
|
|
|
589
630
|
try {
|
|
590
631
|
const state = manager.getStatus(id);
|
|
591
|
-
if (
|
|
592
|
-
!Array.isArray(state) &&
|
|
593
|
-
(state.status === "running" || state.status === "initializing")
|
|
594
|
-
) {
|
|
632
|
+
if (!Array.isArray(state) && isLiveAcpStatus(state.status)) {
|
|
595
633
|
throw new ConflictError(
|
|
596
634
|
`ACP session "${id}" is still ${state.status}. Cancel or close it before deleting.`,
|
|
597
635
|
);
|
|
@@ -640,11 +678,32 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
640
678
|
task: z.string().describe("Task description"),
|
|
641
679
|
conversationId: z.string(),
|
|
642
680
|
cwd: z.string().describe("Working directory").optional(),
|
|
681
|
+
model: z
|
|
682
|
+
.string()
|
|
683
|
+
.optional()
|
|
684
|
+
.describe("Optional model id or alias to request for the session."),
|
|
643
685
|
}),
|
|
644
686
|
responseBody: z.object({
|
|
645
687
|
acpSessionId: z.string(),
|
|
646
688
|
protocolSessionId: z.string(),
|
|
647
689
|
agent: z.string(),
|
|
690
|
+
requestedModel: z
|
|
691
|
+
.string()
|
|
692
|
+
.nullable()
|
|
693
|
+
.describe("The model explicitly requested for this spawn, if any."),
|
|
694
|
+
effectiveModel: z
|
|
695
|
+
.string()
|
|
696
|
+
.nullable()
|
|
697
|
+
.describe(
|
|
698
|
+
"The top-level session model reported by the ACP adapter, if any.",
|
|
699
|
+
),
|
|
700
|
+
modelWarning: z
|
|
701
|
+
.string()
|
|
702
|
+
.optional()
|
|
703
|
+
.describe(
|
|
704
|
+
"Why the requested model was not applied. The session is running " +
|
|
705
|
+
"on the agent's own model.",
|
|
706
|
+
),
|
|
648
707
|
}),
|
|
649
708
|
},
|
|
650
709
|
{
|
|
@@ -852,6 +911,10 @@ function listMergedSessions(opts: { limit: number; conversationId?: string }): {
|
|
|
852
911
|
parentToolUseId: s.parentToolUseId,
|
|
853
912
|
authErrorCode: s.authErrorCode,
|
|
854
913
|
authErrorCredential: s.authErrorCredential,
|
|
914
|
+
model: s.model,
|
|
915
|
+
availableModels: s.availableModels,
|
|
916
|
+
modelRevisionEpoch: s.modelRevisionEpoch,
|
|
917
|
+
modelRevision: s.modelRevision,
|
|
855
918
|
usedTokens: s.latestUsage?.usedTokens,
|
|
856
919
|
contextSize: s.latestUsage?.contextSize,
|
|
857
920
|
costAmount: s.latestUsage?.costAmount,
|
|
@@ -51,6 +51,7 @@ import { compileApp, runCompile } from "../../bundler/app-compiler.js";
|
|
|
51
51
|
import { scanBundle } from "../../bundler/bundle-scanner.js";
|
|
52
52
|
import type { SignatureJson } from "../../bundler/bundle-signer.js";
|
|
53
53
|
import { verifyBundleSignature } from "../../bundler/signature-verifier.js";
|
|
54
|
+
import { notifyAppSurfacesChanged } from "../../daemon/app-change-notify.js";
|
|
54
55
|
import { compareSemver } from "../../daemon/handlers/shared.js";
|
|
55
56
|
import { computeContentId } from "../../util/content-id.js";
|
|
56
57
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -128,6 +129,17 @@ const appListItemSchema = z.object({
|
|
|
128
129
|
|
|
129
130
|
type AppListItem = z.infer<typeof appListItemSchema>;
|
|
130
131
|
|
|
132
|
+
const compileDiagnosticSchema = z.object({
|
|
133
|
+
text: z.string(),
|
|
134
|
+
location: z
|
|
135
|
+
.object({
|
|
136
|
+
file: z.string(),
|
|
137
|
+
line: z.number(),
|
|
138
|
+
column: z.number(),
|
|
139
|
+
})
|
|
140
|
+
.optional(),
|
|
141
|
+
});
|
|
142
|
+
|
|
131
143
|
/**
|
|
132
144
|
* The pin route's body. `RouteDefinition.requestBody` is a codegen signal and
|
|
133
145
|
* does not validate, so the handler parses against this too; declaring it once
|
|
@@ -169,7 +181,7 @@ function workspaceAppItem(a: AppDefinition): AppListItem {
|
|
|
169
181
|
description: a.description,
|
|
170
182
|
icon: a.icon,
|
|
171
183
|
createdAt: a.createdAt,
|
|
172
|
-
updatedAt: a.updatedAt,
|
|
184
|
+
updatedAt: appContentUpdatedAt(getAppDirPath(a.id), a.updatedAt),
|
|
173
185
|
version: a.version ?? "1.0.0",
|
|
174
186
|
contentId: computeContentId(a.name),
|
|
175
187
|
origin: "workspace",
|
|
@@ -191,13 +203,28 @@ function pluginAppItem(app: EnumeratedApp): AppListItem {
|
|
|
191
203
|
id: app.id,
|
|
192
204
|
name: app.name,
|
|
193
205
|
createdAt: mtime,
|
|
194
|
-
updatedAt: mtime,
|
|
206
|
+
updatedAt: appContentUpdatedAt(app.sourcePath, mtime),
|
|
195
207
|
version: "1.0.0",
|
|
196
208
|
contentId: computeContentId(app.name),
|
|
197
209
|
origin: `plugin:${pluginName}`,
|
|
198
210
|
};
|
|
199
211
|
}
|
|
200
212
|
|
|
213
|
+
/** The newest persisted metadata or compiled-output revision for an app. */
|
|
214
|
+
function appContentUpdatedAt(
|
|
215
|
+
sourcePath: string,
|
|
216
|
+
metadataUpdatedAt: number,
|
|
217
|
+
): number {
|
|
218
|
+
try {
|
|
219
|
+
return Math.max(
|
|
220
|
+
metadataUpdatedAt,
|
|
221
|
+
statSync(join(sourcePath, "dist")).mtimeMs,
|
|
222
|
+
);
|
|
223
|
+
} catch {
|
|
224
|
+
return metadataUpdatedAt;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
201
228
|
function getAppDataResult(
|
|
202
229
|
method: string,
|
|
203
230
|
appId: string,
|
|
@@ -896,6 +923,44 @@ async function handleOpenApp({ pathParams }: RouteHandlerArgs) {
|
|
|
896
923
|
return { ...result, html };
|
|
897
924
|
}
|
|
898
925
|
|
|
926
|
+
/**
|
|
927
|
+
* Compile an app's source into dist/ and refresh open surfaces.
|
|
928
|
+
* Runs in the assistant process so open surfaces, client broadcasts, and
|
|
929
|
+
* published-app redeploy see the new build. Workspace and plugin apps both
|
|
930
|
+
* compile in place so local plugin edits can be rebuilt without waiting for
|
|
931
|
+
* the plugin source watcher.
|
|
932
|
+
*/
|
|
933
|
+
async function handleRefreshApp({ pathParams }: RouteHandlerArgs) {
|
|
934
|
+
const appId = pathParams?.id;
|
|
935
|
+
if (!appId) {
|
|
936
|
+
throw new BadRequestError("App id is required.");
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
const source = resolveAppSource(appId);
|
|
940
|
+
if (!source) {
|
|
941
|
+
throw new NotFoundError(
|
|
942
|
+
`App "${appId}" not found. Run 'assistant apps list' to see available apps.`,
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
const compileResult = await compileApp(source.sourceDir);
|
|
947
|
+
notifyAppSurfacesChanged(source.id, { fileChange: true });
|
|
948
|
+
|
|
949
|
+
return {
|
|
950
|
+
ok: true as const,
|
|
951
|
+
appId: source.id,
|
|
952
|
+
name: source.name,
|
|
953
|
+
compiled: compileResult.ok,
|
|
954
|
+
compile_duration_ms: compileResult.durationMs,
|
|
955
|
+
...(compileResult.ok
|
|
956
|
+
? {}
|
|
957
|
+
: {
|
|
958
|
+
compile_errors: compileResult.errors,
|
|
959
|
+
compile_warnings: compileResult.warnings,
|
|
960
|
+
}),
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
|
|
899
964
|
/**
|
|
900
965
|
* Reject a mutation targeting a plugin-bundled app. Plugin apps are owned by
|
|
901
966
|
* their plugin and are read-only over this surface — their source is not
|
|
@@ -1253,6 +1318,29 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
1253
1318
|
origin: z.string(),
|
|
1254
1319
|
}),
|
|
1255
1320
|
},
|
|
1321
|
+
{
|
|
1322
|
+
operationId: "apps_refresh",
|
|
1323
|
+
endpoint: "apps/:id/refresh",
|
|
1324
|
+
method: "POST",
|
|
1325
|
+
policy: {
|
|
1326
|
+
requiredScopes: ["settings.write"],
|
|
1327
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
1328
|
+
},
|
|
1329
|
+
handler: handleRefreshApp,
|
|
1330
|
+
summary: "Compile an app",
|
|
1331
|
+
description:
|
|
1332
|
+
"Compile workspace or plugin app source into dist/ and refresh open surfaces.",
|
|
1333
|
+
tags: ["apps"],
|
|
1334
|
+
responseBody: z.object({
|
|
1335
|
+
ok: z.literal(true),
|
|
1336
|
+
appId: z.string(),
|
|
1337
|
+
name: z.string(),
|
|
1338
|
+
compiled: z.boolean(),
|
|
1339
|
+
compile_duration_ms: z.number(),
|
|
1340
|
+
compile_errors: z.array(compileDiagnosticSchema).optional(),
|
|
1341
|
+
compile_warnings: z.array(compileDiagnosticSchema).optional(),
|
|
1342
|
+
}),
|
|
1343
|
+
},
|
|
1256
1344
|
{
|
|
1257
1345
|
operationId: "apps_delete",
|
|
1258
1346
|
endpoint: "apps/:id/delete",
|
|
@@ -92,7 +92,7 @@ function serveCompiledApp(
|
|
|
92
92
|
);
|
|
93
93
|
const body = isLegacySingleFileDir(appDir)
|
|
94
94
|
? UNSUPPORTED_LEGACY_APP_HTML
|
|
95
|
-
: `<p>App has not been compiled yet.
|
|
95
|
+
: `<p>App has not been compiled yet. Run <code>assistant apps refresh</code> to build.</p>`;
|
|
96
96
|
return (
|
|
97
97
|
`<!DOCTYPE html><html><head><title>${escapedName}</title></head>` +
|
|
98
98
|
`<body>${body}</body></html>`
|