@vellumai/assistant 0.12.1 → 0.12.2-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -0
- package/ARCHITECTURE.md +20 -21
- package/docs/architecture/turn-actor.md +15 -8
- package/docs/guardian-request-flow.md +16 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +13 -8
- package/node_modules/@vellumai/slack-text/src/label-resolution-entities.test.ts +95 -0
- package/openapi.yaml +360 -51
- package/package.json +3 -1
- package/scripts/smoke-desktop-window-theme.ts +186 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
- package/src/__tests__/anthropic-provider.test.ts +0 -63
- package/src/__tests__/app-compiler.test.ts +6 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
- package/src/__tests__/app-dir-path-guard.test.ts +1 -3
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
- package/src/__tests__/assistant-event-hub.test.ts +44 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
- package/src/__tests__/computer-use-tools.test.ts +19 -7
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +28 -29
- package/src/__tests__/config-watcher.test.ts +23 -8
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +26 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
- package/src/__tests__/conversation-queue.test.ts +48 -207
- package/src/__tests__/conversation-retry-discard.test.ts +54 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +28 -0
- package/src/__tests__/conversation-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-point-at-capability.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-title-service.test.ts +14 -10
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
- package/src/__tests__/credential-record-retire.test.ts +171 -1
- package/src/__tests__/credential-routes.test.ts +250 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/cu-unified-flow.test.ts +14 -4
- package/src/__tests__/document-sync-tags.test.ts +25 -0
- package/src/__tests__/drain-kick-guard.test.ts +0 -2
- package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/git-porcelain.test.ts +47 -0
- package/src/__tests__/heartbeat-service.test.ts +56 -40
- package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
- package/src/__tests__/host-bash-proxy.test.ts +26 -45
- package/src/__tests__/host-browser-proxy.test.ts +6 -17
- package/src/__tests__/host-cu-proxy.test.ts +596 -0
- package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
- package/src/__tests__/host-file-proxy.test.ts +11 -23
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
- package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
- package/src/__tests__/llm-catalog-parity.test.ts +25 -0
- package/src/__tests__/mcp-auth-routes.test.ts +6 -9
- package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
- package/src/__tests__/mcp-health-check.test.ts +8 -11
- package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +355 -548
- package/src/__tests__/model-intents.test.ts +3 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
- package/src/__tests__/oauth-commands-routes.test.ts +168 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +22 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-provider.test.ts +1 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +8 -16
- package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +14 -0
- package/src/__tests__/qdrant-manager.test.ts +132 -0
- package/src/__tests__/resolve-app.test.ts +135 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
- package/src/__tests__/script-proxy-certs.test.ts +35 -0
- package/src/__tests__/secret-routes-acp-guard.test.ts +59 -1
- package/src/__tests__/service-account-token.test.ts +247 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/source-fingerprint.test.ts +184 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +70 -3
- package/src/__tests__/subagent-tools.test.ts +3 -2
- package/src/__tests__/telephony-tts-guard.test.ts +38 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/ui-channel-variants.test.ts +1 -56
- package/src/__tests__/unicode.test.ts +13 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
- package/src/__tests__/workspace-git-service.test.ts +26 -0
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +257 -6
- package/src/acp/__tests__/acp-credentials.test.ts +13 -0
- package/src/acp/__tests__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -0
- package/src/acp/__tests__/claude-token-refresh.test.ts +257 -0
- package/src/acp/__tests__/client-handler.test.ts +90 -2
- package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +60 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
- package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
- package/src/acp/__tests__/session-manager.test.ts +895 -4
- package/src/acp/acp-claude-oauth.ts +328 -14
- package/src/acp/acp-credentials.ts +19 -0
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +96 -10
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/claude-token-refresh.ts +150 -0
- package/src/acp/client-handler.ts +16 -3
- package/src/acp/model-config.test.ts +166 -0
- package/src/acp/model-config.ts +138 -0
- package/src/acp/prepare-agent-env.ts +21 -6
- package/src/acp/resolve-agent.test.ts +220 -6
- package/src/acp/resolve-agent.ts +88 -23
- package/src/acp/session-manager.test.ts +196 -3
- package/src/acp/session-manager.ts +441 -18
- package/src/acp/types.ts +50 -5
- package/src/agent/loop.ts +1 -0
- package/src/api/events/acp-session-model-update.test.ts +88 -0
- package/src/api/events/acp-session-model-update.ts +46 -0
- package/src/api/events/app-files-changed.ts +4 -3
- package/src/api/events/notification-intent.ts +2 -0
- package/src/api/events/user-message-echo.ts +7 -1
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +1 -1
- package/src/apps/resolve-app.ts +81 -0
- package/src/apps/source-fingerprint.ts +266 -0
- package/src/avatar/identity-avatar.ts +7 -2
- package/src/bundler/app-compiler.ts +15 -0
- package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
- package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
- package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
- package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
- package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
- package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
- package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
- package/src/calls/__tests__/voice-control-protocol.test.ts +120 -25
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
- package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
- package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
- package/src/calls/__tests__/voice-session-bridge.test.ts +56 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
- package/src/calls/barge-in-guard.ts +118 -0
- package/src/calls/call-constants.ts +24 -4
- package/src/calls/call-controller.ts +499 -199
- package/src/calls/call-transport.ts +16 -0
- package/src/calls/media-stream-output.ts +32 -0
- package/src/calls/media-stream-server.ts +82 -30
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/{live-voice → calls}/progress-narration.ts +2 -2
- package/src/calls/resolve-call-tts-provider.ts +33 -2
- package/src/calls/tts-call-strategy.ts +9 -5
- package/src/calls/types.ts +2 -0
- package/src/calls/voice-control-protocol.ts +155 -21
- package/src/calls/voice-leg-coordinator.ts +189 -0
- package/src/calls/voice-progress-cadence.ts +423 -0
- package/src/calls/voice-session-bridge.ts +92 -72
- package/src/calls/voice-triage-escalate.ts +178 -59
- package/src/cli/commands/__tests__/apps.test.ts +245 -0
- package/src/cli/commands/__tests__/bash.test.ts +53 -0
- package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
- package/src/cli/commands/apps.help.ts +67 -13
- package/src/cli/commands/apps.ts +183 -0
- package/src/cli/commands/bash.help.ts +8 -13
- package/src/cli/commands/bash.ts +7 -25
- package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
- package/src/cli/commands/channels/index.help.ts +70 -2
- package/src/cli/commands/channels/index.ts +16 -3
- package/src/cli/commands/channels/send.ts +128 -0
- package/src/cli/commands/credentials.help.ts +6 -2
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/oauth/status.ts +5 -0
- package/src/cli/commands/roadmap.help.ts +5 -1
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +103 -90
- package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
- package/src/config/__tests__/platform-identity.test.ts +255 -0
- package/src/config/__tests__/platform-rehydration.test.ts +99 -9
- package/src/config/acp-agent-write.ts +43 -0
- package/src/config/acp-defaults.test.ts +13 -3
- package/src/config/acp-defaults.ts +23 -6
- package/src/config/acp-schema.test.ts +81 -0
- package/src/config/acp-schema.ts +30 -2
- package/src/config/bundled-skills/acp/SKILL.md +22 -14
- package/src/config/bundled-skills/acp/TOOLS.json +5 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +29 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -1
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
- package/src/config/bundled-skills/schedule/SKILL.md +3 -4
- package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +6 -2
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +33 -13
- package/src/config/loader.ts +2 -0
- package/src/config/memory-v3-gate.test.ts +31 -0
- package/src/config/memory-v3-gate.ts +20 -16
- package/src/config/platform-identity.ts +201 -0
- package/src/config/platform-rehydration.ts +11 -27
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
- package/src/config/schemas/__tests__/voice.test.ts +148 -0
- package/src/config/schemas/calls.ts +1 -28
- package/src/config/schemas/live-voice.ts +1 -173
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +10 -0
- package/src/config/schemas/services.ts +18 -0
- package/src/config/schemas/skills.ts +0 -14
- package/src/config/schemas/voice.ts +150 -0
- package/src/credential-execution/process-manager.test.ts +18 -19
- package/src/credential-health/credential-health-service.ts +11 -17
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
- package/src/daemon/app-change-notify.ts +45 -0
- package/src/daemon/config-watcher.ts +13 -194
- package/src/daemon/conversation-error.ts +3 -2
- package/src/daemon/conversation-media-retry.ts +2 -1
- package/src/daemon/conversation-process.ts +35 -64
- package/src/daemon/conversation-runtime-assembly.ts +20 -7
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +21 -10
- package/src/daemon/conversation-tool-setup.ts +45 -59
- package/src/daemon/conversation.ts +0 -3
- package/src/daemon/dictation-profile-store.ts +2 -1
- package/src/daemon/handlers/shared.ts +2 -1
- package/src/daemon/handlers/skills.ts +6 -3
- package/src/daemon/host-bash-proxy.ts +8 -12
- package/src/daemon/host-browser-proxy.ts +15 -1
- package/src/daemon/host-cu-proxy.ts +224 -19
- package/src/daemon/host-file-proxy.ts +8 -10
- package/src/daemon/host-proxy-preactivation.ts +2 -1
- package/src/daemon/host-transfer-proxy.ts +14 -18
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/reaction-history-render.ts +2 -1
- package/src/daemon/shutdown-handlers.ts +1 -9
- package/src/daemon/skill-memory-refresh.ts +64 -0
- package/src/daemon/tool-side-effects.ts +7 -18
- package/src/desktop/__tests__/fake-desktop.ts +122 -0
- package/src/desktop/desktop-chrome-policy.test.ts +79 -0
- package/src/desktop/desktop-chrome-policy.ts +47 -0
- package/src/desktop/desktop-chrome-session.ts +37 -0
- package/src/desktop/desktop-dependencies.test.ts +102 -0
- package/src/desktop/desktop-dependencies.ts +308 -0
- package/src/desktop/desktop-feature.test.ts +18 -0
- package/src/desktop/desktop-feature.ts +19 -0
- package/src/desktop/desktop-panel-config.test.ts +135 -0
- package/src/desktop/desktop-panel-config.ts +149 -0
- package/src/desktop/desktop-session-manager.test.ts +730 -0
- package/src/desktop/desktop-session-manager.ts +850 -0
- package/src/desktop/desktop-stream-bridge.test.ts +395 -0
- package/src/desktop/desktop-stream-bridge.ts +214 -0
- package/src/desktop/desktop-wallpaper.test.ts +191 -0
- package/src/desktop/desktop-wallpaper.ts +113 -0
- package/src/desktop/desktop-window-drag.ts +177 -0
- package/src/desktop/desktop-window-manager-config.test.ts +230 -0
- package/src/desktop/desktop-window-manager-config.ts +238 -0
- package/src/desktop/desktop-window-theme.ts +170 -0
- package/src/heartbeat/heartbeat-service.ts +21 -3
- package/src/home/__tests__/feed-writer.test.ts +22 -0
- package/src/home/feed-writer.ts +11 -2
- package/src/hooks/types.ts +33 -0
- package/src/i18n/AGENTS.md +22 -0
- package/src/i18n/__tests__/i18n.test.ts +108 -0
- package/src/i18n/index.ts +16 -0
- package/src/i18n/locales.ts +93 -0
- package/src/i18n/messages.ts +61 -0
- package/src/i18n/title.ts +25 -0
- package/src/inbound/platform-callback-registration.ts +4 -5
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +121 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +8 -7
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +94 -15
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/live-voice/__tests__/protocol.test.ts +39 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/__tests__/session-controls.test.ts +79 -0
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +297 -699
- package/src/live-voice/protocol.ts +60 -2
- package/src/live-voice/session-controls.ts +111 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +29 -45
- package/src/mcp/spec-schema.ts +111 -0
- package/src/mcp/startup.ts +8 -4
- package/src/mcp/workspace-mcp-config.ts +188 -0
- package/src/messaging/provider.ts +10 -3
- package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
- package/src/messaging/providers/callback-routing.ts +18 -0
- package/src/messaging/providers/channel-transport.ts +56 -0
- package/src/messaging/providers/discord/transport.ts +17 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
- package/src/messaging/providers/slack/adapter.ts +7 -44
- package/src/messaging/providers/slack/transport.ts +16 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
- package/src/messaging/providers/telegram-bot/client.ts +0 -26
- package/src/messaging/providers/telegram-bot/transport.ts +20 -0
- package/src/messaging/providers/whatsapp/adapter.ts +1 -48
- package/src/messaging/providers/whatsapp/transport.ts +18 -0
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
- package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/assistant-reply-producer.ts +8 -3
- package/src/notifications/conversation-pairing.ts +36 -16
- package/src/notifications/delivered-post-record.ts +11 -1
- package/src/notifications/guardian-feed-projection.ts +125 -5
- package/src/notifications/home-feed-side-effect.ts +55 -7
- package/src/notifications/schedule-result-producer.ts +66 -22
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/seed-providers-managed.test.ts +149 -0
- package/src/oauth/byo-connection.test.ts +105 -0
- package/src/oauth/byo-connection.ts +36 -6
- package/src/oauth/connection-resolver.test.ts +100 -0
- package/src/oauth/connection-resolver.ts +120 -3
- package/src/oauth/provider-serializer.ts +9 -0
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +314 -27
- package/src/outbound-proxy/certs.ts +3 -5
- package/src/permissions/checker.test.ts +11 -6
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +71 -63
- package/src/persistence/conversation-lineage.ts +12 -4
- package/src/persistence/conversation-queries.ts +2 -2
- package/src/persistence/conversation-title-placeholders.ts +23 -0
- package/src/persistence/conversation-title-service.ts +9 -26
- package/src/persistence/embeddings/qdrant-manager.ts +163 -18
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-cursor.ts +78 -0
- package/src/persistence/message-reads.ts +30 -0
- package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
- package/src/persistence/schema/memory-core.ts +5 -0
- package/src/platform/client.test.ts +4 -2
- package/src/platform/client.ts +2 -10
- package/src/plugin-api/constants.ts +2 -0
- package/src/plugin-api/index.ts +1 -0
- package/src/plugin-api/types.ts +2 -0
- package/src/plugins/defaults/index.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +5 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -2
- package/src/plugins/defaults/memory/context-search/format.ts +3 -2
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
- package/src/plugins/defaults/memory/hooks/init.ts +10 -0
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
- package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
- package/src/plugins/defaults/memory/host-utils.ts +10 -0
- package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
- package/src/plugins/defaults/memory/startup.ts +28 -2
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
- package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
- package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
- package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
- package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
- package/src/plugins/defaults/memory/v3/card.ts +3 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
- package/src/plugins/defaults/memory/v3/sections.ts +9 -3
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
- package/src/plugins/defaults/memory/worker.ts +6 -0
- package/src/plugins/mcp-servers.ts +15 -75
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/__tests__/retry-callsite.test.ts +41 -0
- package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
- package/src/providers/anthropic/client.ts +0 -47
- package/src/providers/gemini/client.ts +9 -23
- package/src/providers/gemini-thought-signature.test.ts +63 -0
- package/src/providers/gemini-thought-signature.ts +44 -0
- package/src/providers/inference/__tests__/endpoint-probe.test.ts +42 -3
- package/src/providers/inference/auth.ts +2 -3
- package/src/providers/inference/connection-availability.ts +27 -8
- package/src/providers/inference/endpoint-probe.ts +10 -1
- package/src/providers/inference/resolve-auth.ts +22 -4
- package/src/providers/inference/service-account-token.ts +248 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/model-intents.ts +10 -5
- package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
- package/src/providers/openai/chat-completions-provider.ts +212 -79
- package/src/providers/openai/codex-models.ts +0 -4
- package/src/providers/openai/google-thought-signature.ts +320 -0
- package/src/providers/opencode/client.test.ts +73 -4
- package/src/providers/opencode/client.ts +60 -3
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/outbound-request-sanitize.ts +96 -0
- package/src/providers/retry.ts +30 -19
- package/src/providers/unparseable-tool-args.ts +5 -1
- package/src/runtime/AGENTS.md +3 -1
- package/src/runtime/__tests__/channel-send.test.ts +443 -0
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
- package/src/runtime/__tests__/host-observe.test.ts +40 -1
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
- package/src/runtime/agent-wake.ts +2 -1
- package/src/runtime/assistant-event-hub.ts +21 -3
- package/src/runtime/auth/same-actor.ts +38 -3
- package/src/runtime/channel-send.ts +316 -0
- package/src/runtime/host-observe.ts +11 -1
- package/src/runtime/http-server.ts +160 -151
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +16 -5
- package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +275 -0
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
- package/src/runtime/routes/acp-claude-auth-routes.ts +11 -3
- package/src/runtime/routes/acp-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +90 -2
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/channel-send-routes.ts +85 -0
- package/src/runtime/routes/conversation-list-routes.ts +14 -3
- package/src/runtime/routes/conversation-query-routes.ts +40 -0
- package/src/runtime/routes/conversation-routes.ts +16 -3
- package/src/runtime/routes/credential-routes.ts +20 -14
- package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
- package/src/runtime/routes/desktop-setup-routes.ts +35 -0
- package/src/runtime/routes/diagnostics-routes.ts +61 -4
- package/src/runtime/routes/events-routes.ts +4 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -0
- package/src/runtime/routes/index.ts +4 -2
- package/src/runtime/routes/log-export-routes.ts +2 -0
- package/src/runtime/routes/mcp-auth-routes.ts +39 -47
- package/src/runtime/routes/migration-routes.ts +6 -20
- package/src/runtime/routes/oauth-commands-routes.ts +50 -0
- package/src/runtime/routes/oauth-providers.ts +7 -0
- package/src/runtime/routes/platform-routes.ts +18 -15
- package/src/runtime/routes/workspace-routes.test.ts +55 -26
- package/src/runtime/routes/workspace-routes.ts +46 -63
- package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
- package/src/runtime/routes/workspace-tree-walk.ts +240 -0
- package/src/runtime/routes/workspace-utils.ts +17 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +16 -3
- package/src/runtime/sync/resource-sync-events.ts +2 -1
- package/src/schedule/run-script.ts +2 -1
- package/src/schedule/schedule-store.ts +9 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
- package/src/security/ces-http-record-backend.ts +120 -0
- package/src/security/ces-rpc-record-backend.ts +7 -0
- package/src/security/untrusted-content.ts +3 -1
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
- package/src/skills/workspace-skill-md-signature.ts +50 -0
- package/src/subagent/consult-context.ts +12 -25
- package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
- package/src/tools/acp/list-agents.test.ts +3 -1
- package/src/tools/acp/spawn.test.ts +146 -11
- package/src/tools/acp/spawn.ts +21 -3
- package/src/tools/acp/status.test.ts +94 -0
- package/src/tools/acp/status.ts +40 -3
- package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
- package/src/tools/browser/network-recorder.ts +2 -1
- package/src/tools/capability-offer.test.ts +22 -2
- package/src/tools/capability-offer.ts +16 -1
- package/src/tools/computer-use/definitions.ts +121 -2
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
- package/src/tools/credentials/metadata-store.ts +100 -0
- package/src/tools/filesystem/search.ts +2 -1
- package/src/tools/host-filesystem/edit.test.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +2 -1
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +2 -1
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +16 -0
- package/src/tools/host-terminal/host-shell.ts +4 -20
- package/src/tools/network/web-search.ts +6 -1
- package/src/tools/policy-context.ts +6 -7
- package/src/tools/skills/scaffold-managed.ts +61 -3
- package/src/tools/subagent/spawn.ts +5 -8
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
- package/src/tools/terminal/sanitized-bash.ts +105 -0
- package/src/tools/ui-surface/channel-variants.ts +10 -59
- package/src/tools/watch/watch-retro-report.ts +0 -8
- package/src/types/host-capabilities.ts +5 -3
- package/src/util/__tests__/language-subtag.test.ts +23 -1
- package/src/util/ca-bundle.ts +13 -0
- package/src/util/language-subtag.ts +16 -0
- package/src/util/platform.ts +8 -0
- package/src/util/unicode.ts +15 -1
- package/src/watch/watch-retro.ts +6 -8
- package/src/watch/watch-timeline.ts +2 -2
- package/src/workflows/run-manager.ts +2 -1
- package/src/workspace/git-porcelain.ts +66 -0
- package/src/workspace/git-service.ts +6 -55
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/app-source-watcher.test.ts +0 -218
- package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
- package/src/__tests__/speaker-identification.test.ts +0 -56
- package/src/calls/speaker-identification.ts +0 -233
- package/src/daemon/app-source-watcher.ts +0 -218
- package/src/messaging/providers/whatsapp/client.ts +0 -29
- package/src/runtime/routes/debug-bash-routes.ts +0 -173
- package/src/util/fs-watcher-error.ts +0 -36
- /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { basename } from "node:path";
|
|
3
3
|
|
|
4
|
-
import { isChannelId } from "../../../../channels/types.js";
|
|
5
4
|
import type { OutboundAttachment } from "../../../../messaging/provider-types.js";
|
|
6
5
|
import {
|
|
7
6
|
createDraft,
|
|
@@ -16,11 +15,10 @@ import {
|
|
|
16
15
|
toOutlookFileAttachments,
|
|
17
16
|
} from "../../../../messaging/providers/outlook/client.js";
|
|
18
17
|
import type { OutlookDraftMessage } from "../../../../messaging/providers/outlook/types.js";
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import { normalizeExternalThreadId } from "../../../../persistence/external-conversation-store.js";
|
|
18
|
+
import {
|
|
19
|
+
isProactivelyAddressable,
|
|
20
|
+
sendChannelText,
|
|
21
|
+
} from "../../../../runtime/channel-send.js";
|
|
24
22
|
import {
|
|
25
23
|
isAbortLikeError,
|
|
26
24
|
throwIfCancelled,
|
|
@@ -29,7 +27,6 @@ import type {
|
|
|
29
27
|
ToolContext,
|
|
30
28
|
ToolExecutionResult,
|
|
31
29
|
} from "../../../../tools/types.js";
|
|
32
|
-
import { getLogger } from "../../../../util/logger.js";
|
|
33
30
|
import { guessMimeType } from "../../../../util/mime-type.js";
|
|
34
31
|
import {
|
|
35
32
|
err,
|
|
@@ -42,8 +39,6 @@ import {
|
|
|
42
39
|
resolveProvider,
|
|
43
40
|
} from "./shared.js";
|
|
44
41
|
|
|
45
|
-
const log = getLogger("messaging-send");
|
|
46
|
-
|
|
47
42
|
/** Read attachment files from disk into in-memory parts for outbound sending. */
|
|
48
43
|
async function readAttachments(paths: string[]): Promise<OutboundAttachment[]> {
|
|
49
44
|
return Promise.all(
|
|
@@ -58,123 +53,6 @@ async function readAttachments(paths: string[]): Promise<OutboundAttachment[]> {
|
|
|
58
53
|
/** Email providers that accept file attachments on outbound sends. */
|
|
59
54
|
const ATTACHMENT_CAPABLE_PLATFORMS = new Set(["gmail", "outlook"]);
|
|
60
55
|
|
|
61
|
-
/**
|
|
62
|
-
* Record a message the provider just accepted where the chat's proactive
|
|
63
|
-
* posts live, so the chat's own conversation and `recall` can see what was
|
|
64
|
-
* sent from elsewhere (a scheduled run, another conversation).
|
|
65
|
-
*
|
|
66
|
-
* Only channel providers have such a home; an email send is tool-mediated
|
|
67
|
-
* and has no chat conversation. The row is written after the provider
|
|
68
|
-
* returned the message id, never before, and carries that id on its
|
|
69
|
-
* envelope and in `channel_outbound_posts` like every other post the daemon
|
|
70
|
-
* makes.
|
|
71
|
-
*
|
|
72
|
-
* A send into the sending turn's own chat writes no row: its tool call and
|
|
73
|
-
* result already sit in that conversation's history, and a second assistant
|
|
74
|
-
* row beside the tool pair would break history repair. Whether the send is
|
|
75
|
-
* "its own" is decided by the delivered target against the turn, not by the
|
|
76
|
-
* home: the turn arrived on a channel, in a chat, in a thread (the turn-local
|
|
77
|
-
* snapshot on the tool context), and a post the provider delivered to exactly
|
|
78
|
-
* that place is a same-conversation send even when the chat's home resolves
|
|
79
|
-
* elsewhere. The delivered thread is the one the provider reports, not the
|
|
80
|
-
* one requested: a provider that ignores the request lands the post in the
|
|
81
|
-
* thread-less chat, and the record must say so; a post into a thread is
|
|
82
|
-
* recorded in the thread's own conversation, where its replies arrive. The home
|
|
83
|
-
* comparison stays as the second test, for a sender that arrived through no
|
|
84
|
-
* channel but is the home. The post is then in the outbound index only
|
|
85
|
-
* through no path, which is the same class as a raw API send and is deferred
|
|
86
|
-
* with it.
|
|
87
|
-
*
|
|
88
|
-
* Failures here never fail the send: the message is already out.
|
|
89
|
-
*/
|
|
90
|
-
async function recordSentChannelPost(params: {
|
|
91
|
-
providerId: string;
|
|
92
|
-
externalChatId: string;
|
|
93
|
-
/** The thread the provider delivered into, as it reported it. */
|
|
94
|
-
deliveredThreadId: string | undefined;
|
|
95
|
-
text: string;
|
|
96
|
-
providerMessageId: string;
|
|
97
|
-
sender: ToolContext;
|
|
98
|
-
}): Promise<void> {
|
|
99
|
-
const { providerId, externalChatId, sender } = params;
|
|
100
|
-
if (!isChannelId(providerId) || !params.providerMessageId) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
try {
|
|
104
|
-
if (
|
|
105
|
-
isSendIntoOwnChat(
|
|
106
|
-
sender,
|
|
107
|
-
providerId,
|
|
108
|
-
externalChatId,
|
|
109
|
-
params.deliveredThreadId,
|
|
110
|
-
)
|
|
111
|
-
) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
const home = await resolveProactiveHomeConversation({
|
|
115
|
-
sourceChannel: providerId,
|
|
116
|
-
externalChatId,
|
|
117
|
-
threadId: params.deliveredThreadId,
|
|
118
|
-
source: "notification",
|
|
119
|
-
conversationType: "background",
|
|
120
|
-
title: `Messages to ${externalChatId}`,
|
|
121
|
-
});
|
|
122
|
-
if (home.conversationId === sender.conversationId) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
const recorded = await recordDeliveredChannelPost({
|
|
126
|
-
conversationId: home.conversationId,
|
|
127
|
-
channel: providerId,
|
|
128
|
-
externalChatId,
|
|
129
|
-
...(params.deliveredThreadId
|
|
130
|
-
? { threadId: params.deliveredThreadId }
|
|
131
|
-
: {}),
|
|
132
|
-
text: params.text,
|
|
133
|
-
providerMessageId: params.providerMessageId,
|
|
134
|
-
crossPostedFrom: sender.conversationId,
|
|
135
|
-
});
|
|
136
|
-
const homeConversation = getConversation(home.conversationId);
|
|
137
|
-
if (homeConversation) {
|
|
138
|
-
syncMessageToDisk(
|
|
139
|
-
home.conversationId,
|
|
140
|
-
recorded.messageId,
|
|
141
|
-
homeConversation.createdAt,
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
} catch (e) {
|
|
145
|
-
log.warn(
|
|
146
|
-
{ err: e, provider: providerId, externalChatId },
|
|
147
|
-
"Failed to record the sent message in the chat's conversation",
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* True when the delivered chat and thread are the ones the sending turn
|
|
154
|
-
* arrived in. Reads the turn-local snapshot the tool context carries
|
|
155
|
-
* (`executionChannel`, `requesterChatId`, `sourceThreadId`), never the live
|
|
156
|
-
* binding, which a concurrent inbound can rewrite while this call runs.
|
|
157
|
-
* Thread ids compare in the binding store's normalized form, so an absent
|
|
158
|
-
* thread on both sides matches and a thread-less delivery never matches a
|
|
159
|
-
* turn that arrived in a thread.
|
|
160
|
-
*/
|
|
161
|
-
function isSendIntoOwnChat(
|
|
162
|
-
sender: ToolContext,
|
|
163
|
-
channel: string,
|
|
164
|
-
externalChatId: string,
|
|
165
|
-
deliveredThreadId: string | undefined,
|
|
166
|
-
): boolean {
|
|
167
|
-
if (!sender.executionChannel || !sender.requesterChatId) {
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
return (
|
|
171
|
-
sender.executionChannel === channel &&
|
|
172
|
-
sender.requesterChatId === externalChatId &&
|
|
173
|
-
normalizeExternalThreadId(sender.sourceThreadId) ===
|
|
174
|
-
normalizeExternalThreadId(deliveredThreadId)
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
56
|
export async function run(
|
|
179
57
|
input: Record<string, unknown>,
|
|
180
58
|
context: ToolContext,
|
|
@@ -197,9 +75,62 @@ export async function run(
|
|
|
197
75
|
throwIfCancelled(context);
|
|
198
76
|
|
|
199
77
|
try {
|
|
200
|
-
|
|
78
|
+
// A channel whose transport can be addressed from a named chat is sent
|
|
79
|
+
// through the transport, which is the one send implementation for that
|
|
80
|
+
// channel, records what it sent, and reaches channels with no messaging
|
|
81
|
+
// provider at all. A platform named outright is checked first; one
|
|
82
|
+
// auto-detected from the connected providers is checked the same way.
|
|
83
|
+
const namedChannel =
|
|
84
|
+
platform && isProactivelyAddressable(platform) ? platform : undefined;
|
|
85
|
+
const provider = namedChannel ? undefined : await resolveProvider(platform);
|
|
86
|
+
const channel =
|
|
87
|
+
namedChannel ??
|
|
88
|
+
(provider && isProactivelyAddressable(provider.id)
|
|
89
|
+
? provider.id
|
|
90
|
+
: undefined);
|
|
91
|
+
|
|
92
|
+
if (channel) {
|
|
93
|
+
if (attachmentPaths?.length) {
|
|
94
|
+
return err("Attachments are only supported on Gmail and Outlook.");
|
|
95
|
+
}
|
|
96
|
+
// A channel's transport sends as the channel's one bot identity, so an
|
|
97
|
+
// account cannot select where the send goes out from. Refusing is
|
|
98
|
+
// safer than silently sending from the default account.
|
|
99
|
+
if (input.account) {
|
|
100
|
+
return err(
|
|
101
|
+
`account does not apply to ${channel}: a channel send goes out as the channel's own bot.`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
// Recheck: provider resolution above is an await, and this posts to
|
|
105
|
+
// the channel.
|
|
106
|
+
throwIfCancelled(context);
|
|
107
|
+
const sent = await sendChannelText({
|
|
108
|
+
channel,
|
|
109
|
+
target: {
|
|
110
|
+
kind: "chat",
|
|
111
|
+
chatId: conversationId,
|
|
112
|
+
...(threadId ? { threadId } : {}),
|
|
113
|
+
},
|
|
114
|
+
text,
|
|
115
|
+
renderRichly: true,
|
|
116
|
+
assistantId: context.assistantId,
|
|
117
|
+
sender: {
|
|
118
|
+
conversationId: context.conversationId,
|
|
119
|
+
executionChannel: context.executionChannel,
|
|
120
|
+
requesterChatId: context.requesterChatId,
|
|
121
|
+
sourceThreadId: context.sourceThreadId,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
const threadSuffix = sent.threadId
|
|
125
|
+
? `, "thread_id": "${sent.threadId}"`
|
|
126
|
+
: "";
|
|
127
|
+
return ok(`Message sent (ID: ${sent.lastMessageId}${threadSuffix}).`);
|
|
128
|
+
}
|
|
129
|
+
if (!provider) {
|
|
130
|
+
throw new Error(`Messaging provider "${platform}" not found.`);
|
|
131
|
+
}
|
|
201
132
|
|
|
202
|
-
// Reject attachments on platforms that can't carry them
|
|
133
|
+
// Reject attachments on platforms that can't carry them.
|
|
203
134
|
if (
|
|
204
135
|
attachmentPaths?.length &&
|
|
205
136
|
!ATTACHMENT_CAPABLE_PLATFORMS.has(provider.id)
|
|
@@ -426,7 +357,14 @@ export async function run(
|
|
|
426
357
|
);
|
|
427
358
|
}
|
|
428
359
|
|
|
429
|
-
//
|
|
360
|
+
// A provider with a send of its own and no direct transport (a plugin's,
|
|
361
|
+
// for instance). Its send is tool-mediated and has no chat conversation
|
|
362
|
+
// to record in.
|
|
363
|
+
if (!provider.sendMessage) {
|
|
364
|
+
return err(
|
|
365
|
+
`${provider.displayName} cannot send from here: it has no send of its own and no channel transport to address.`,
|
|
366
|
+
);
|
|
367
|
+
}
|
|
430
368
|
const attachments = attachmentPaths?.length
|
|
431
369
|
? await readAttachments(attachmentPaths)
|
|
432
370
|
: undefined;
|
|
@@ -442,16 +380,6 @@ export async function run(
|
|
|
442
380
|
const threadSuffix = result.threadId
|
|
443
381
|
? `, "thread_id": "${result.threadId}"`
|
|
444
382
|
: "";
|
|
445
|
-
|
|
446
|
-
await recordSentChannelPost({
|
|
447
|
-
providerId: provider.id,
|
|
448
|
-
externalChatId: conversationId,
|
|
449
|
-
deliveredThreadId: result.threadId,
|
|
450
|
-
text,
|
|
451
|
-
providerMessageId: result.id,
|
|
452
|
-
sender: context,
|
|
453
|
-
});
|
|
454
|
-
|
|
455
383
|
return ok(`Message sent (ID: ${result.id}${threadSuffix}).`);
|
|
456
384
|
} catch (e) {
|
|
457
385
|
// A cancelled turn is not a send failure: let it reach the executor's
|
|
@@ -23,7 +23,7 @@ sqlite3 "$VELLUM_WORKSPACE_DIR/data/db/assistant.db" \
|
|
|
23
23
|
|
|
24
24
|
This returns all messages in chronological order with:
|
|
25
25
|
|
|
26
|
-
- `role: "user"` - caller speech
|
|
26
|
+
- `role: "user"` - caller speech and system events
|
|
27
27
|
- `role: "assistant"` - assistant responses, including `text` content and any `tool_use`/`tool_result` blocks
|
|
28
28
|
|
|
29
29
|
## Quick one-liner for the most recent call
|
|
@@ -23,6 +23,7 @@ import type {
|
|
|
23
23
|
ToolContext,
|
|
24
24
|
ToolExecutionResult,
|
|
25
25
|
} from "../../../../tools/types.js";
|
|
26
|
+
import { safeStringSlice } from "../../../../util/unicode.js";
|
|
26
27
|
|
|
27
28
|
const VALID_AUTONOMY_LEVELS = new Set<string>(["auto", "draft", "notify"]);
|
|
28
29
|
|
|
@@ -68,7 +69,7 @@ export async function executePlaybookCreate(
|
|
|
68
69
|
};
|
|
69
70
|
const statement = JSON.stringify(playbook);
|
|
70
71
|
const sanitizedTrigger = trigger.replace(/[\r\n]+/g, " ");
|
|
71
|
-
const subject = `Playbook: ${sanitizedTrigger}
|
|
72
|
+
const subject = safeStringSlice(`Playbook: ${sanitizedTrigger}`, 0, 80);
|
|
72
73
|
const content = `${subject}\n${statement}`;
|
|
73
74
|
|
|
74
75
|
try {
|
|
@@ -23,6 +23,7 @@ import type {
|
|
|
23
23
|
ToolContext,
|
|
24
24
|
ToolExecutionResult,
|
|
25
25
|
} from "../../../../tools/types.js";
|
|
26
|
+
import { safeStringSlice } from "../../../../util/unicode.js";
|
|
26
27
|
|
|
27
28
|
const VALID_AUTONOMY_LEVELS = new Set<string>(["auto", "draft", "notify"]);
|
|
28
29
|
|
|
@@ -100,7 +101,7 @@ export async function executePlaybookUpdate(
|
|
|
100
101
|
|
|
101
102
|
const statement = JSON.stringify(updated);
|
|
102
103
|
const sanitizedTrigger = updated.trigger.replace(/[\r\n]+/g, " ");
|
|
103
|
-
const subject = `Playbook: ${sanitizedTrigger}
|
|
104
|
+
const subject = safeStringSlice(`Playbook: ${sanitizedTrigger}`, 0, 80);
|
|
104
105
|
const content = `${subject}\n${statement}`;
|
|
105
106
|
|
|
106
107
|
// Check for duplicate content among other playbook nodes
|
|
@@ -209,7 +209,6 @@ When you mention a schedule or a conversation it owns in Vellum chat, write a ma
|
|
|
209
209
|
|
|
210
210
|
Use these paths only in Vellum chat. Do not use them in Slack, Telegram, Discord, email, or notifications. Those surfaces cannot navigate `/assistant/...` routes.
|
|
211
211
|
|
|
212
|
-
|
|
213
212
|
### Anchored & Ambiguous Relative Time
|
|
214
213
|
|
|
215
214
|
Phrases like "at the 45 minute mark", "at the top of the hour", "at noon", or "20 minutes in" are **clock-position or anchored relative time** expressions. Do NOT treat them as offsets from now.
|
|
@@ -256,13 +255,13 @@ Write the delivery step into the `message` when you create the schedule — not
|
|
|
256
255
|
|
|
257
256
|
A schedule whose message has no delivery step is not finished. Before calling `schedule_create` in `execute` mode, read your own message back and check that it says where the output goes.
|
|
258
257
|
|
|
259
|
-
There is a safety net, and it is not a substitute for the above. When an execute-mode run finishes with user-facing output and delivered
|
|
258
|
+
There is a safety net, and it is not a substitute for the above. When an execute-mode run finishes with user-facing output and nothing delivered it, the assistant sends a notification carrying the run's final reply, so a schedule can no longer run and leave no trace. `messaging_send` counts as a delivery only when the call reported success, and `assistant notifications send` once the notification pipeline has taken it: a send the channel refused, or one that never reported at all, leaves the run eligible for the net, so the failure reaches you instead of vanishing into a conversation nobody has open. A Slack `chat.postMessage` never counts, because Slack refuses a call with a successful HTTP status and `ok: false` in the body, so the command succeeding proves nothing; a run that posts Block Kit that way also gets the net's notification. It fires on the raw reply, whatever the run happened to end on, at whatever length. An authored delivery step gets a title and body you chose, sent at the moment you chose. Rely on the net and you get the machine's guess instead.
|
|
260
259
|
|
|
261
260
|
Choose the right delivery tool based on the content:
|
|
262
261
|
|
|
263
|
-
- **Rich content** (digests, summaries, reports):
|
|
262
|
+
- **Rich content** (digests, summaries, reports): Use `messaging_send` with the target platform and conversation ID. It reaches Gmail or Outlook as a draft, and posts to a Slack, Telegram, or Discord chat through that channel's own transport, where the post is recorded and can be found again afterwards. Reach for `chat.postMessage` through `assistant oauth request` only for a Block Kit shape `messaging_send` cannot carry, with the provider the **slack** skill says to pass for posting on this workspace (`slack_channel` when the bot is set up; where only the `slack` integration exists, the skill says to tell the user before posting as them), never through `curl` or a revealed token. Either way the full content posts directly.
|
|
264
263
|
- **Short alerts** (status updates, completion notices): Use `assistant notifications send` via `bash` to let the notification router pick the best channel. Note: the router's decision engine rewrites content into short alerts, so it is not suitable for rich content.
|
|
265
264
|
|
|
266
265
|
Example schedule message for a Slack digest:
|
|
267
266
|
|
|
268
|
-
> "Scan my Slack channels for the last 24 hours using `assistant oauth request` for every Slack Web API
|
|
267
|
+
> "Scan my Slack channels for the last 24 hours using `assistant oauth request` for every Slack Web API read, with the provider the slack skill names for this workspace, then post the summary to the channel the user named with `messaging_send`, passing `platform: \"slack\"` and that channel's ID."
|
|
@@ -124,7 +124,14 @@ their ear. Silence is the cue that it is their turn.
|
|
|
124
124
|
|
|
125
125
|
**Advance on evidence, not on time.** Move to the next step when a fresh
|
|
126
126
|
picture shows this one done, or when they tell you it is. Do not move on
|
|
127
|
-
because a plausible amount of time has passed.
|
|
127
|
+
because a plausible amount of time has passed.
|
|
128
|
+
|
|
129
|
+
The most direct telling is automatic. When the user clicks the control an
|
|
130
|
+
arrow is pointing at, a message arrives as their turn saying they clicked it,
|
|
131
|
+
by name, and that mark comes down on its own. Treat it as the step done: say
|
|
132
|
+
what comes next and point at it. Nothing arrives for a click anywhere else,
|
|
133
|
+
and nothing arrives for a ring, so for those the picture and their words are
|
|
134
|
+
still the evidence. If the next picture shows the
|
|
128
135
|
step not done, or done to the wrong thing, point at the same place again with
|
|
129
136
|
a shorter caption and say what you saw. Pointing at the next step while the
|
|
130
137
|
previous one is still open is how someone ends up two steps behind a mark.
|
|
@@ -53,7 +53,10 @@ describe("screen_point_at", () => {
|
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
expect(result.isError).toBe(true);
|
|
56
|
-
expect(result.content).toContain(
|
|
56
|
+
expect(result.content).toContain(
|
|
57
|
+
"The Vellum desktop app is needed to view or control your screen",
|
|
58
|
+
);
|
|
59
|
+
expect(result.content).toContain("https://www.vellum.ai/downloads");
|
|
57
60
|
});
|
|
58
61
|
|
|
59
62
|
/** Drawing on the user's screen is a side effect a stopped turn must not have. */
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"tools": [
|
|
4
4
|
{
|
|
5
5
|
"name": "scaffold_managed_skill",
|
|
6
|
-
"description": "Create or update a managed skill in {workspaceDir}/skills. The skill becomes available for skill_load when a valid top-level SKILL.md is written under the skill directory. Never persist a skill without explicit user consent. Before persisting, test the snippet: write to a temp file with bash and run with `bun run /tmp/vellum-eval/snippet.ts`. Iterate up to 3 attempts, then ask the user. Clean up temp files after. Do not use file_write for temp files outside the working directory.
|
|
6
|
+
"description": "Create or update a managed skill in {workspaceDir}/skills. The skill becomes available for skill_load when a valid top-level SKILL.md is written under the skill directory. Never persist a skill without explicit user consent. Before persisting, test the snippet: write to a temp file with bash and run with `bun run /tmp/vellum-eval/snippet.ts`. Iterate up to 3 attempts, then ask the user. Clean up temp files after. Do not use file_write for temp files outside the working directory.",
|
|
7
7
|
"category": "skills",
|
|
8
8
|
"risk": "high",
|
|
9
9
|
"input_schema": {
|
|
@@ -37,6 +37,10 @@
|
|
|
37
37
|
"type": "boolean",
|
|
38
38
|
"description": "Whether to overwrite an existing skill with the same ID (default: false)."
|
|
39
39
|
},
|
|
40
|
+
"change_summary": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "What changed and why, in one or two short sentences (at most 200 characters) written for the person who reads the \"Skill updated\" notice, e.g. \"Added the retry after an expired session and the export endpoint that held steady.\" Required when a background pass overwrites an existing skill (the update is rejected without it) and becomes that notice's body. Ignored on a create and on a user-directed edit."
|
|
43
|
+
},
|
|
40
44
|
"includes": {
|
|
41
45
|
"type": "array",
|
|
42
46
|
"items": { "type": "string" },
|
|
@@ -92,7 +96,7 @@
|
|
|
92
96
|
},
|
|
93
97
|
{
|
|
94
98
|
"name": "delete_managed_skill",
|
|
95
|
-
"description": "Delete a managed skill directory from {workspaceDir}/skills. Never delete a skill without explicit user confirmation.
|
|
99
|
+
"description": "Delete a managed skill directory from {workspaceDir}/skills. Never delete a skill without explicit user confirmation.",
|
|
96
100
|
"category": "skills",
|
|
97
101
|
"risk": "high",
|
|
98
102
|
"input_schema": {
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
FFPROBE_TIMEOUT_MS,
|
|
20
20
|
spawnWithTimeout,
|
|
21
21
|
} from "../../../../util/spawn.js";
|
|
22
|
+
import { safeStringSlice } from "../../../../util/unicode.js";
|
|
22
23
|
|
|
23
24
|
const VIDEO_EXTENSIONS = new Set([
|
|
24
25
|
".mp4",
|
|
@@ -107,7 +108,9 @@ async function splitAudio(
|
|
|
107
108
|
signal,
|
|
108
109
|
);
|
|
109
110
|
if (result.exitCode !== 0) {
|
|
110
|
-
throw new Error(
|
|
111
|
+
throw new Error(
|
|
112
|
+
`Failed to split audio: ${safeStringSlice(result.stderr, 0, 300)}`,
|
|
113
|
+
);
|
|
111
114
|
}
|
|
112
115
|
const files = await readdir(chunkDir);
|
|
113
116
|
return files
|
|
@@ -167,7 +170,7 @@ async function toWav(
|
|
|
167
170
|
signal,
|
|
168
171
|
);
|
|
169
172
|
if (result.exitCode !== 0) {
|
|
170
|
-
throw new Error(`ffmpeg failed: ${result.stderr
|
|
173
|
+
throw new Error(`ffmpeg failed: ${safeStringSlice(result.stderr, 0, 500)}`);
|
|
171
174
|
}
|
|
172
175
|
return wavPath;
|
|
173
176
|
}
|
|
@@ -137,7 +137,7 @@ const VELLUM_PROFILE_IMPLS: ProfileImpls = {
|
|
|
137
137
|
// The managed latency class, also what the live-voice front model runs on.
|
|
138
138
|
// Its leading tokens are the turn-taking verdict, so what this profile
|
|
139
139
|
// optimizes is the tail of time-to-first-token rather than the median: a
|
|
140
|
-
// verdict slower than `
|
|
140
|
+
// verdict slower than `voice.frontModel.endpointDecisionTimeoutMs`
|
|
141
141
|
// trips the speculative fail-open commit in live-voice-session.ts, which
|
|
142
142
|
// is audible dead air.
|
|
143
143
|
//
|
package/src/config/env.ts
CHANGED
|
@@ -229,8 +229,8 @@ export function setPlatformAssistantId(value: string | undefined): void {
|
|
|
229
229
|
* Platform assistant ID — UUID of this assistant on the platform.
|
|
230
230
|
*
|
|
231
231
|
* Resolved from the in-memory override (populated by providers-setup
|
|
232
|
-
* rehydration
|
|
233
|
-
*
|
|
232
|
+
* rehydration via platform validate, or by secret-routes when the
|
|
233
|
+
* platform pushes the value).
|
|
234
234
|
*/
|
|
235
235
|
export function getPlatformAssistantId(): string {
|
|
236
236
|
return _platformAssistantIdOverride ?? "";
|
|
@@ -29,18 +29,6 @@
|
|
|
29
29
|
"description": "Enable user-hosted onboarding flow",
|
|
30
30
|
"defaultEnabled": false
|
|
31
31
|
},
|
|
32
|
-
{
|
|
33
|
-
"id": "proactive-tips",
|
|
34
|
-
"scope": "client",
|
|
35
|
-
"key": "proactive-tips",
|
|
36
|
-
"label": "Proactive Tips",
|
|
37
|
-
"description": "Gates the dismissible proactive tip card in the web sidebar. String-valued so future A/B arms can be added as new values.",
|
|
38
|
-
"defaultEnabled": "off",
|
|
39
|
-
"values": [
|
|
40
|
-
"off",
|
|
41
|
-
"on"
|
|
42
|
-
]
|
|
43
|
-
},
|
|
44
32
|
{
|
|
45
33
|
"id": "vision-mode",
|
|
46
34
|
"scope": "client",
|
|
@@ -187,7 +175,7 @@
|
|
|
187
175
|
"scope": "client",
|
|
188
176
|
"key": "teleport",
|
|
189
177
|
"label": "Teleport",
|
|
190
|
-
"description": "Enable teleport UI in General settings
|
|
178
|
+
"description": "Enable the local-to-platform teleport UI in General settings. Platform-to-local teleport is GA and not gated by this flag",
|
|
191
179
|
"defaultEnabled": false
|
|
192
180
|
},
|
|
193
181
|
{
|
|
@@ -454,6 +442,14 @@
|
|
|
454
442
|
"description": "Native notifications show the assistant's avatar as the icon with the assistant's name on line one. Same key the platform reads for APNs/FCM sender blocks.",
|
|
455
443
|
"defaultEnabled": false
|
|
456
444
|
},
|
|
445
|
+
{
|
|
446
|
+
"id": "local-notification-avatar",
|
|
447
|
+
"scope": "client",
|
|
448
|
+
"key": "local-notification-avatar",
|
|
449
|
+
"label": "Local Notification Avatar",
|
|
450
|
+
"description": "Shows the assistant name and avatar in notifications posted locally by native clients and supported browsers. Independent of remote push avatar presentation.",
|
|
451
|
+
"defaultEnabled": false
|
|
452
|
+
},
|
|
457
453
|
{
|
|
458
454
|
"id": "channel-conversation-sidecar",
|
|
459
455
|
"scope": "client",
|
|
@@ -478,6 +474,22 @@
|
|
|
478
474
|
"description": "Gates the seeded Figma OAuth provider. When off, the provider is hidden from GET /v1/oauth/providers, its get-by-id route, and the connect/update routes, so it cannot be listed or connected from the CLI, gateway, or web integrations list. The row is still seeded into oauth_providers on startup, and existing connections keep injecting credentials; only its visibility changes.",
|
|
479
475
|
"defaultEnabled": false
|
|
480
476
|
},
|
|
477
|
+
{
|
|
478
|
+
"id": "quickbooks-oauth",
|
|
479
|
+
"scope": "assistant",
|
|
480
|
+
"key": "quickbooks-oauth",
|
|
481
|
+
"label": "QuickBooks Integration",
|
|
482
|
+
"description": "Gates the seeded QuickBooks OAuth provider. When off, the provider is hidden from GET /v1/oauth/providers, its get-by-id route, and the connect/update routes, so it cannot be listed or connected from the CLI, gateway, or web integrations list. The row is still seeded into oauth_providers on startup, and existing connections keep injecting credentials; only its visibility changes.",
|
|
483
|
+
"defaultEnabled": false
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
"id": "shopify-oauth",
|
|
487
|
+
"scope": "assistant",
|
|
488
|
+
"key": "shopify-oauth",
|
|
489
|
+
"label": "Shopify Integration",
|
|
490
|
+
"description": "Gates the seeded Shopify OAuth provider. When off, the provider is hidden from GET /v1/oauth/providers, its get-by-id route, and the connect/update routes, so it cannot be listed or connected from the CLI, gateway, or web integrations list. The row is still seeded into oauth_providers on startup, and existing connections keep injecting credentials; only its visibility changes. Off by default because Shopify is the first per-tenant provider: connecting needs the merchant's myshopify.com domain, and the shop-domain input in the clients ships separately from the seed.",
|
|
491
|
+
"defaultEnabled": false
|
|
492
|
+
},
|
|
481
493
|
{
|
|
482
494
|
"id": "chatgpt-device-code-login",
|
|
483
495
|
"scope": "client",
|
|
@@ -523,6 +535,14 @@
|
|
|
523
535
|
"label": "Send User Message Tool",
|
|
524
536
|
"description": "Route all user-facing assistant text through the send_user_message tool instead of streamed assistant text",
|
|
525
537
|
"defaultEnabled": false
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
"id": "assistant-desktop",
|
|
541
|
+
"scope": "assistant",
|
|
542
|
+
"key": "assistant-desktop",
|
|
543
|
+
"label": "Assistant Desktop",
|
|
544
|
+
"description": "Streams an interactive desktop from a containerized assistant pod to the web client over /v1/desktop/stream. Off: no desktop affordance is rendered. On: the chat header offers a desktop panel that views and controls the pod's display.",
|
|
545
|
+
"defaultEnabled": false
|
|
526
546
|
}
|
|
527
547
|
]
|
|
528
548
|
}
|
package/src/config/loader.ts
CHANGED
|
@@ -180,8 +180,10 @@ export function getDeploymentContextDefaults(): Record<string, unknown> {
|
|
|
180
180
|
"discord-oauth": managed,
|
|
181
181
|
"hubspot-oauth": managed,
|
|
182
182
|
"monday-oauth": managed,
|
|
183
|
+
"shopify-oauth": managed,
|
|
183
184
|
"stripe-link-oauth": managed,
|
|
184
185
|
"figma-oauth": managed,
|
|
186
|
+
"quickbooks-oauth": managed,
|
|
185
187
|
"eventbrite-oauth": managed,
|
|
186
188
|
"calendly-oauth": managed,
|
|
187
189
|
},
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
isMemoryV1Active,
|
|
7
7
|
isMemoryV2ExplicitlyDisabled,
|
|
8
8
|
isMemoryV3Live,
|
|
9
|
+
isSkillImprovementActive,
|
|
9
10
|
isV2InjectionEngineActive,
|
|
10
11
|
isV3TierActive,
|
|
11
12
|
usesConceptPageMemory,
|
|
@@ -55,12 +56,16 @@ function makeConfig(
|
|
|
55
56
|
enabled: TriState,
|
|
56
57
|
v2Enabled: TriState,
|
|
57
58
|
v3Live: TriState,
|
|
59
|
+
skillImprovement?: boolean,
|
|
58
60
|
): AssistantConfig {
|
|
59
61
|
return {
|
|
60
62
|
memory: {
|
|
61
63
|
...(enabled === undefined ? {} : { enabled }),
|
|
62
64
|
...(v2Enabled === undefined ? {} : { v2: { enabled: v2Enabled } }),
|
|
63
65
|
...(v3Live === undefined ? {} : { v3: { live: v3Live } }),
|
|
66
|
+
...(skillImprovement === undefined
|
|
67
|
+
? {}
|
|
68
|
+
: { retrospective: { skillImprovement } }),
|
|
64
69
|
},
|
|
65
70
|
} as AssistantConfig;
|
|
66
71
|
}
|
|
@@ -296,6 +301,32 @@ describe("v1-staleness guard is one condition", () => {
|
|
|
296
301
|
* proc-to-skills alias of `isMemoryV3Live` (which did not). One predicate now
|
|
297
302
|
* answers for both features.
|
|
298
303
|
*/
|
|
304
|
+
describe("skill improvement gate", () => {
|
|
305
|
+
test("defaults on for a live v3 tier", () => {
|
|
306
|
+
expect(isSkillImprovementActive(makeConfig(true, undefined, true))).toBe(
|
|
307
|
+
true,
|
|
308
|
+
);
|
|
309
|
+
expect(isSkillImprovementActive(makeConfig(undefined, undefined, true))).toBe(
|
|
310
|
+
true,
|
|
311
|
+
);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test("explicit opt-out disables skill improvement without disabling v3", () => {
|
|
315
|
+
const config = makeConfig(true, undefined, true, false);
|
|
316
|
+
|
|
317
|
+
expect(isV3TierActive(config)).toBe(true);
|
|
318
|
+
expect(isSkillImprovementActive(config)).toBe(false);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test("requires the live v3 tier even when explicitly enabled", () => {
|
|
322
|
+
const v2Config = makeConfig(true, true, false, true);
|
|
323
|
+
const memoryOffConfig = makeConfig(false, undefined, true, true);
|
|
324
|
+
|
|
325
|
+
expect(isSkillImprovementActive(v2Config)).toBe(false);
|
|
326
|
+
expect(isSkillImprovementActive(memoryOffConfig)).toBe(false);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
|
|
299
330
|
describe("v3 tier is one condition", () => {
|
|
300
331
|
test("memory off suppresses the v3 tier even with memory.v3.live set", () => {
|
|
301
332
|
const config = makeConfig(false, undefined, true);
|
|
@@ -81,28 +81,32 @@ export function isMemoryV3Live(config: AssistantConfig): boolean {
|
|
|
81
81
|
* FEATURE asks this predicate; only the injection-suppression checks that must
|
|
82
82
|
* mirror the raw `memory.v3.live` key ask {@link isMemoryV3Live} directly.
|
|
83
83
|
*
|
|
84
|
-
* The
|
|
84
|
+
* The memory concept graph is gated on it: both `GET /memory-graph`
|
|
85
|
+
* (`supported`) and the cheap `graph_supported` bit on `GET /memory/stats`
|
|
86
|
+
* must agree with whether the graph can build from the v3 concept-page
|
|
87
|
+
* substrate.
|
|
85
88
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* never drift. The graph builds off the v3 concept-page substrate.
|
|
90
|
-
* - Procedural-memory-as-skills — the retrospective's skill-authoring step and
|
|
91
|
-
* its permission grant. Scoped to the v3 tier because skill retrieval rides
|
|
92
|
-
* the v3 lanes and the usage-prune stage lives in the v3 maintain job. That
|
|
93
|
-
* prune ships observe-first: with `memory.maintenance.skillPruneDays` at its
|
|
94
|
-
* default (`null`) it reports stale assistant-authored skills
|
|
95
|
-
* (`prunableSkills`) but deletes none — so a v3-tier assistant authors skills
|
|
96
|
-
* without an automatic retirement bound until a positive `skillPruneDays` is
|
|
97
|
-
* configured.
|
|
98
|
-
*
|
|
99
|
-
* Both write into memory on the user's behalf, so both honor the Memory
|
|
100
|
-
* opt-out identically: one predicate, one answer.
|
|
89
|
+
* Retrospective skill improvement is a separate optional v3-tier feature.
|
|
90
|
+
* Ask {@link isSkillImprovementActive} for it so an operator can stop managed
|
|
91
|
+
* skill authoring without turning off ordinary retrospective memory capture.
|
|
101
92
|
*/
|
|
102
93
|
export function isV3TierActive(config: AssistantConfig): boolean {
|
|
103
94
|
return isMemoryEnabled(config) && isMemoryV3Live(config);
|
|
104
95
|
}
|
|
105
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Whether a retrospective may turn observed procedures into managed skills.
|
|
99
|
+
* This requires the v3 tier because skills are retrieved through its memory
|
|
100
|
+
* substrate, and it honors the retrospective-specific opt-out without
|
|
101
|
+
* disabling ordinary retrospective fact retention.
|
|
102
|
+
*/
|
|
103
|
+
export function isSkillImprovementActive(config: AssistantConfig): boolean {
|
|
104
|
+
return (
|
|
105
|
+
isV3TierActive(config) &&
|
|
106
|
+
config.memory?.retrospective?.skillImprovement !== false
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
106
110
|
/**
|
|
107
111
|
* Minimal structural view of the memory config the concept-page gate reads.
|
|
108
112
|
* Accepting the shape (rather than the full `MemoryConfig`) lets call sites
|