@vellumai/assistant 0.11.8 → 0.11.9-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/ARCHITECTURE.md +2 -2
- package/Dockerfile +8 -48
- package/docker-entrypoint.sh +5 -1
- package/docker-kata-apt-env.sh +3 -0
- package/docker-kata-apt-shims.sh +127 -0
- package/docker-kata-apt-wrapper.sh +45 -0
- package/docker-kata-chroot-exec.sh +35 -0
- package/docker-kata-pip.sh +8 -2
- package/docs/architecture/memory.md +8 -4
- package/docs/guardian-request-flow.md +18 -14
- package/docs/trusted-contact-access.md +1 -7
- package/node_modules/@vellumai/avatar-catalog/src/catalog.ts +7 -1
- package/node_modules/@vellumai/avatar-catalog/src/index.ts +1 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +4 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +4 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-request-contract.test.ts +0 -18
- package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +110 -5
- package/node_modules/@vellumai/gateway-client/src/guardian-request-contract.ts +5 -33
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +3 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +100 -9
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -2
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +9 -0
- package/node_modules/@vellumai/service-contracts/package.json +4 -1
- package/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
- package/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
- package/openapi.yaml +193 -4
- package/package.json +2 -2
- package/src/__tests__/access-request-card-view.test.ts +6 -5
- package/src/__tests__/access-request-seed-content-blocks.test.ts +5 -2
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +43 -82
- package/src/__tests__/always-loaded-tools-guard.test.ts +8 -2
- package/src/__tests__/attachment-stored-path-annotation.test.ts +80 -0
- package/src/__tests__/attachments-store.test.ts +27 -0
- package/src/__tests__/attachments.test.ts +43 -0
- package/src/__tests__/canned-reply-release.test.ts +48 -5
- package/src/__tests__/channel-delivery-store.test.ts +129 -18
- package/src/__tests__/channel-reply-delivery.test.ts +553 -93
- package/src/__tests__/channel-retry-sweep.test.ts +199 -0
- package/src/__tests__/client-os-metadata-persistence.test.ts +32 -3
- package/src/__tests__/conversation-error.test.ts +15 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +118 -0
- package/src/__tests__/conversation-pairing.test.ts +141 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +28 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +125 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +79 -0
- package/src/__tests__/conversation-store-ephemeral.test.ts +323 -10
- package/src/__tests__/conversation-sync-tags.test.ts +2 -37
- package/src/__tests__/credential-health-service.test.ts +98 -10
- package/src/__tests__/delete-propagation.test.ts +469 -0
- package/src/__tests__/dm-persistence.test.ts +16 -0
- package/src/__tests__/docker-kata-apt-shims.test.ts +135 -0
- package/src/__tests__/forbidden-legacy-symbols.test.ts +12 -0
- package/src/__tests__/gemini-provider.test.ts +46 -0
- package/src/__tests__/guardian-card-withdrawal.test.ts +0 -22
- package/src/__tests__/guardian-gateway-sim.ts +0 -23
- package/src/__tests__/guardian-question-mode.test.ts +108 -0
- package/src/__tests__/guardian-reply-router-answer-mode.test.ts +0 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +26 -12
- package/src/__tests__/host-proxy-interface.test.ts +10 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +16 -0
- package/src/__tests__/injector-v3-suppression.test.ts +43 -9
- package/src/__tests__/list-messages-page-latest.test.ts +127 -0
- package/src/__tests__/list-messages-system-card.test.ts +103 -0
- package/src/__tests__/media-resolve-image-validation.test.ts +77 -0
- package/src/__tests__/notification-decision-fallback.test.ts +199 -77
- package/src/__tests__/notification-decision-strategy.test.ts +198 -213
- package/src/__tests__/notification-discord-adapter.test.ts +25 -0
- package/src/__tests__/notification-slack-adapter.test.ts +133 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +36 -0
- package/src/__tests__/openai-provider.test.ts +5 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +85 -72
- package/src/__tests__/persist-user-message-set-processing-failure.test.ts +83 -65
- package/src/__tests__/platform-client-verify-credential.test.ts +100 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +1 -1
- package/src/__tests__/pricing.test.ts +11 -0
- package/src/__tests__/process-message-display-content.test.ts +20 -9
- package/src/__tests__/processing-acquire-fenced-guard.test.ts +56 -0
- package/src/__tests__/provider-meta-persistence.test.ts +67 -0
- package/src/__tests__/reaction-persistence.test.ts +22 -198
- package/src/__tests__/run-conversation-turn-persistence.test.ts +5 -2
- package/src/__tests__/scripted-turn-metadata-persistence.test.ts +16 -0
- package/src/__tests__/skill-load-tool.test.ts +27 -0
- package/src/__tests__/skills.test.ts +34 -1
- package/src/__tests__/strip-memory-injections.test.ts +3 -4
- package/src/__tests__/terminal-tools.test.ts +9 -0
- package/src/__tests__/thread-backfill.test.ts +5 -3
- package/src/__tests__/unified-turn-context-location.test.ts +76 -0
- package/src/__tests__/voice-session-bridge.test.ts +18 -0
- package/src/__tests__/watch-retro-report-payload.test.ts +185 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +82 -0
- package/src/__tests__/workspace-migration-151-repair-renamed-fireworks-deepseek-pro-model-id.test.ts +235 -0
- package/src/__tests__/workspace-migration-152-repair-retired-fireworks-minimax-m2p7-model-id.test.ts +233 -0
- package/src/agent/attachments.ts +13 -2
- package/src/agent/loop.ts +3 -19
- package/src/api/README.md +9 -5
- package/src/api/index.ts +9 -8
- package/src/api/package.json +1 -0
- package/src/api/responses/conversation-message.ts +8 -0
- package/src/api/responses/home.ts +7 -18
- package/src/api/surfaces.ts +114 -7
- package/src/approvals/AGENTS.md +1 -1
- package/src/channels/__tests__/gateway-guardian-requests.test.ts +1 -23
- package/src/channels/__tests__/types.test.ts +22 -1
- package/src/channels/gateway-guardian-requests.ts +0 -22
- package/src/channels/types.ts +8 -6
- package/src/cli/__tests__/catalog-search-help.test.ts +18 -0
- package/src/cli/commands/channels/__tests__/channels.test.ts +26 -0
- package/src/cli/commands/channels/index.help.ts +19 -6
- package/src/cli/commands/channels/index.ts +6 -2
- package/src/cli/commands/db/__tests__/status.test.ts +22 -0
- package/src/cli/commands/db/index.help.ts +1 -1
- package/src/cli/commands/db/status.ts +172 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +29 -0
- package/src/cli/commands/platform/connect.ts +14 -5
- package/src/cli/commands/plugins.help.ts +6 -5
- package/src/cli/lib/__tests__/install-from-github.test.ts +0 -8
- package/src/cli/lib/__tests__/install-from-platform.test.ts +72 -0
- package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +33 -0
- package/src/cli/lib/bundled-marketplace.json +14 -0
- package/src/cli/lib/install-from-github.ts +9 -5
- package/src/cli/lib/install-from-platform.ts +12 -1
- package/src/config/__tests__/assistant-initiated-threads-gate.test.ts +61 -0
- package/src/config/assistant-initiated-threads-gate.ts +50 -0
- package/src/config/bundled-skills/acp/SKILL.md +10 -3
- package/src/config/bundled-skills/schedule/SKILL.md +25 -11
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +3 -1
- package/src/config/call-site-defaults.ts +4 -1
- package/src/config/feature-flag-registry.json +21 -4
- package/src/config/schemas/memory-v3.ts +4 -3
- package/src/context/strip-injections.ts +17 -56
- package/src/conversations/__tests__/message-consolidation.test.ts +39 -0
- package/src/conversations/message-consolidation.ts +4 -3
- package/src/credential-health/credential-health-service.ts +130 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +31 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +55 -59
- package/src/daemon/conversation-error.ts +2 -0
- package/src/daemon/conversation-messaging.ts +195 -47
- package/src/daemon/conversation-process.ts +20 -5
- package/src/daemon/conversation-runtime-assembly.ts +48 -39
- package/src/daemon/conversation-store.ts +159 -11
- package/src/daemon/conversation-tool-setup.ts +9 -2
- package/src/daemon/conversation.ts +290 -19
- package/src/daemon/dictation-text-processing.ts +2 -7
- package/src/daemon/handlers/config-channels.ts +33 -3
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/shared.ts +9 -0
- package/src/daemon/port-oversized-content.test.ts +117 -0
- package/src/daemon/port-oversized-content.ts +110 -0
- package/src/daemon/process-message.ts +87 -16
- package/src/daemon/reaction-record.test.ts +23 -11
- package/src/daemon/reaction-record.ts +6 -9
- package/src/documents/document-store.ts +1 -5
- package/src/home/conversation-starter-validation.ts +1 -5
- package/src/live-voice/__tests__/live-voice-photo.test.ts +910 -50
- package/src/live-voice/__tests__/live-voice-sight-frame-inline.test.ts +31 -25
- package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +70 -1
- package/src/live-voice/live-voice-photo.ts +544 -61
- package/src/live-voice/live-voice-session.ts +6 -2
- package/src/live-voice/protocol.ts +20 -1
- package/src/messaging/provider-message-metadata.ts +40 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +10 -2
- package/src/messaging/providers/channel-transport.ts +28 -0
- package/src/messaging/providers/discord/send.ts +3 -2
- package/src/messaging/providers/slack/api.ts +11 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +133 -0
- package/src/messaging/providers/slack/message-metadata.ts +141 -1
- package/src/messaging/providers/slack/send.test.ts +58 -0
- package/src/messaging/providers/slack/send.ts +4 -4
- package/src/messaging/providers/slack/transport.ts +28 -2
- package/src/messaging/providers/telegram-bot/send.test.ts +159 -0
- package/src/messaging/providers/telegram-bot/send.ts +93 -0
- package/src/messaging/providers/telegram-bot/transport.ts +71 -0
- package/src/messaging/reaction-envelopes.test.ts +73 -0
- package/src/messaging/reaction-envelopes.ts +33 -5
- package/src/messaging/read-provider-metadata.ts +4 -3
- package/src/monitoring/recovery/__tests__/stranded-delivery-events.test.ts +208 -0
- package/src/monitoring/recovery/db.ts +35 -0
- package/src/monitoring/recovery/orphaned-channel-events.ts +3 -22
- package/src/monitoring/recovery/run-recovery.ts +6 -2
- package/src/monitoring/recovery/stale-processing.ts +3 -20
- package/src/monitoring/recovery/stranded-delivery-events.ts +68 -0
- package/src/notifications/AGENTS.md +2 -2
- package/src/notifications/README.md +2 -2
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +11 -9
- package/src/notifications/__tests__/broadcaster.test.ts +35 -4
- package/src/notifications/__tests__/notification-utils.test.ts +31 -0
- package/src/notifications/access-request-copy.ts +126 -114
- package/src/notifications/adapters/discord.ts +9 -5
- package/src/notifications/adapters/shared.ts +17 -4
- package/src/notifications/adapters/slack.ts +14 -4
- package/src/notifications/adapters/telegram.ts +8 -4
- package/src/notifications/approval-card-data.ts +5 -2
- package/src/notifications/assistant-reply-producer.ts +7 -7
- package/src/notifications/broadcaster.ts +57 -25
- package/src/notifications/conversation-pairing.ts +68 -2
- package/src/notifications/copy-composer.ts +13 -32
- package/src/notifications/decision-engine.ts +56 -237
- package/src/notifications/guardian-delivery-recorder.ts +5 -9
- package/src/notifications/guardian-feed-projection.ts +0 -15
- package/src/notifications/guardian-question-mode.ts +147 -6
- package/src/notifications/notification-utils.ts +117 -1
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/prompter.ts +1 -1
- package/src/persistence/conversation-crud.ts +93 -14
- package/src/persistence/conversation-queries.ts +144 -17
- package/src/persistence/conversation-types.ts +39 -5
- package/src/persistence/delivery-crud.ts +224 -28
- package/src/persistence/delivery-status.ts +21 -2
- package/src/persistence/migrations/374-channel-inbound-message-id-index.ts +26 -0
- package/src/persistence/migrations/375-create-channel-outbound-posts.ts +52 -0
- package/src/persistence/migrations/__tests__/375-create-channel-outbound-posts.test.ts +84 -0
- package/src/persistence/schema/conversations.ts +71 -2
- package/src/persistence/schema-contract.test.ts +78 -0
- package/src/persistence/schema-contract.ts +96 -0
- package/src/persistence/steps.ts +4 -0
- package/src/platform/client.ts +55 -0
- package/src/plugins/__tests__/mcp-servers.test.ts +46 -0
- package/src/plugins/defaults/injector-order.ts +2 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +2 -2
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +13 -15
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +10 -0
- package/src/plugins/defaults/memory/injectors.ts +1 -1
- package/src/plugins/defaults/memory/memory-marker.ts +17 -7
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +1 -5
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +17 -0
- package/src/plugins/defaults/memory/substrate/skill-content.ts +7 -0
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +54 -41
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +3 -3
- package/src/plugins/defaults/memory/v3/__tests__/render-injection.test.ts +22 -0
- package/src/plugins/defaults/memory/v3/injector.ts +14 -15
- package/src/plugins/defaults/memory/v3/prune.test.ts +20 -2
- package/src/plugins/defaults/memory/v3/render-injection.ts +10 -1
- package/src/plugins/defaults/memory/v3/types.ts +15 -4
- package/src/plugins/defaults/turn-context/injectors.ts +3 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +24 -0
- package/src/plugins/mcp-servers.ts +14 -2
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +50 -0
- package/src/providers/__tests__/registry-native-web-search.test.ts +49 -2
- package/src/providers/anthropic/client.ts +21 -24
- package/src/providers/call-site-routing.ts +5 -4
- package/src/providers/connection-resolution.ts +29 -1
- package/src/providers/content-block-size.test.ts +82 -0
- package/src/providers/content-block-size.ts +99 -0
- package/src/providers/file-block-text.test.ts +64 -0
- package/src/providers/file-block-text.ts +28 -0
- package/src/providers/gemini/client.ts +15 -9
- package/src/providers/inference/auth.ts +6 -6
- package/src/providers/media-resolve.ts +14 -0
- package/src/providers/model-catalog.ts +47 -34
- package/src/providers/openai/chat-completions-provider.ts +9 -25
- package/src/providers/openai/responses-provider.ts +11 -18
- package/src/providers/registry.ts +10 -7
- package/src/providers/routing-identity.ts +2 -1
- package/src/providers/types.ts +1 -4
- package/src/providers/vellum-model-routing.ts +3 -2
- package/src/runtime/AGENTS.md +40 -15
- package/src/runtime/approval-message-composer.ts +1 -6
- package/src/runtime/assistant-event-hub.ts +2 -39
- package/src/runtime/channel-approval-types.ts +1 -5
- package/src/runtime/channel-reply-delivery.ts +182 -115
- package/src/runtime/{slack-reply-session.test.ts → channel-reply-session.test.ts} +294 -156
- package/src/runtime/{slack-reply-session.ts → channel-reply-session.ts} +107 -86
- package/src/runtime/channel-retry-sweep.ts +102 -1
- package/src/runtime/finalize-event-delivery.ts +4 -4
- package/src/runtime/guardian-action-message-composer.ts +1 -4
- package/src/runtime/guardian-reply-router.ts +4 -75
- package/src/runtime/http-router.ts +1 -5
- package/src/runtime/question-request-guardian-bridge.ts +2 -3
- package/src/runtime/routes/__tests__/conversation-list-assistant-section.test.ts +359 -0
- package/src/runtime/routes/__tests__/dictation-command-mode.test.ts +120 -0
- package/src/runtime/routes/__tests__/sight-frame-routes.test.ts +487 -0
- package/src/runtime/routes/acp-routes.ts +1 -1
- package/src/runtime/routes/canned-reply-release.ts +19 -9
- package/src/runtime/routes/channel-route-shared.ts +0 -39
- package/src/runtime/routes/channel-verification-routes.ts +4 -1
- package/src/runtime/routes/conversation-list-routes.ts +44 -3
- package/src/runtime/routes/conversation-management-routes.ts +2 -1
- package/src/runtime/routes/conversation-routes.ts +138 -59
- package/src/runtime/routes/diagnostics-routes.ts +111 -60
- package/src/runtime/routes/guardian-action-routes.ts +10 -14
- package/src/runtime/routes/guardian-approval-interception.ts +0 -5
- package/src/runtime/routes/inbound-message-handler.ts +170 -48
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +4 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +169 -8
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +82 -14
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +23 -48
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +454 -94
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +309 -102
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/platform-routes.ts +99 -10
- package/src/runtime/routes/sight-frame-routes.ts +136 -0
- package/src/runtime/sync/resource-sync-events.ts +14 -37
- package/src/runtime/sync/sync-publisher.test.ts +5 -4
- package/src/tools/__tests__/tool-input-schemas.test.ts +2 -0
- package/src/tools/client-os.ts +11 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/terminal/safe-env.ts +4 -0
- package/src/tools/tool-input-schemas.ts +2 -0
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/ui-surface/definitions.ts +4 -3
- package/src/tools/watch/watch-retro-report.ts +205 -0
- package/src/watch/__tests__/watch-retro.test.ts +268 -40
- package/src/watch/watch-retro.ts +190 -77
- package/src/workspace/migrations/151-repair-renamed-fireworks-deepseek-pro-model-id.ts +195 -0
- package/src/workspace/migrations/152-repair-retired-fireworks-minimax-m2p7-model-id.ts +198 -0
- package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +0 -10
- package/src/workspace/migrations/registry.ts +4 -0
- package/docker-kata-pip-chroot.sh +0 -22
- package/src/__tests__/slack-reaction-approvals.test.ts +0 -97
- package/src/__tests__/slack-reaction-guardian-approval.test.ts +0 -307
- package/src/api/events/conversation-list-invalidated.ts +0 -38
|
@@ -33,7 +33,13 @@ const log = getLogger("diagnostics-routes");
|
|
|
33
33
|
// Dictation
|
|
34
34
|
// ---------------------------------------------------------------------------
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* `command` is a selection changed by the words, `question` a selection the
|
|
38
|
+
* words asked about. Both need selected text; which one comes back is the
|
|
39
|
+
* model's reading of the words, so a client that holds a key over a passage
|
|
40
|
+
* and says "what does this mean" is not handed a rewrite of it.
|
|
41
|
+
*/
|
|
42
|
+
type DictationMode = "dictation" | "command" | "action" | "question";
|
|
37
43
|
|
|
38
44
|
const DICTATION_CLASSIFICATION_TIMEOUT_MS = 5000;
|
|
39
45
|
const MAX_WINDOW_TITLE_LENGTH = 100;
|
|
@@ -65,61 +71,47 @@ function buildCombinedDictationPrompt(
|
|
|
65
71
|
body: DictationBody,
|
|
66
72
|
stylePrompt?: string,
|
|
67
73
|
): string {
|
|
74
|
+
// Every line here is read on every hold, so the prompt says each thing
|
|
75
|
+
// once and leaves the model no reasoning to write.
|
|
68
76
|
const sections = [
|
|
69
|
-
"You are a voice input assistant.
|
|
70
|
-
'1. Classify it as "dictation" (text to insert) or "action" (task for an assistant to execute)',
|
|
71
|
-
"2. If dictation, clean up the text. If action, return the raw transcription.",
|
|
77
|
+
"You are a voice input assistant. Given a speech transcription, classify it and, if it is dictation, clean it up.",
|
|
72
78
|
"",
|
|
73
79
|
"## Classification",
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"",
|
|
77
|
-
"Key signals for ACTION: the user is addressing an assistant and asking it to DO something (send, message, open, search, create, schedule, etc.)",
|
|
78
|
-
"Key signals for DICTATION: the user is composing text content that should be typed out as-is",
|
|
79
|
-
`Cursor in text field: ${body.context.cursorInTextField ? "yes" : "no"} -- if yes, lean toward dictation unless the intent to command is clear.`,
|
|
80
|
+
"dictation: the user is composing text to be typed as-is.",
|
|
81
|
+
"action: the user is asking an assistant to do something (send, message, open, search, create, schedule). Return the transcription unchanged.",
|
|
82
|
+
`Cursor in text field: ${body.context.cursorInTextField ? "yes" : "no"}. If yes, lean toward dictation unless the intent to command is clear.`,
|
|
80
83
|
"",
|
|
81
|
-
"## Cleanup
|
|
82
|
-
"- Fix grammar, punctuation
|
|
83
|
-
"-
|
|
84
|
-
|
|
85
|
-
"-
|
|
84
|
+
"## Cleanup",
|
|
85
|
+
"- Fix grammar, punctuation and capitalization; remove filler words",
|
|
86
|
+
"- Rewrite hedging into clear statements, keeping the speaker's meaning",
|
|
87
|
+
"- When the speaker enumerates items, lay them out as a list, one per line",
|
|
88
|
+
"- Keep the user's natural voice; do not over-formalize casual speech",
|
|
86
89
|
];
|
|
87
90
|
|
|
88
91
|
if (stylePrompt) {
|
|
89
92
|
sections.push(
|
|
90
93
|
"",
|
|
91
|
-
"## User Style (
|
|
92
|
-
"The user
|
|
93
|
-
"Follow these instructions precisely -- they reflect the user's personal writing voice and preferences.",
|
|
94
|
+
"## User Style (highest priority)",
|
|
95
|
+
"The user's own writing preferences. They override the tone guidance below.",
|
|
94
96
|
"",
|
|
95
97
|
stylePrompt,
|
|
96
98
|
);
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
sections.push("", "## Tone Adaptation");
|
|
100
|
-
|
|
101
|
-
if (stylePrompt) {
|
|
102
|
-
sections.push(
|
|
103
|
-
"Use these as fallback guidance only when the User Style above does not cover a specific aspect:",
|
|
104
|
-
);
|
|
105
|
-
} else {
|
|
106
|
-
sections.push("Adapt your output tone based on the active application:");
|
|
107
|
-
}
|
|
108
|
-
|
|
109
101
|
sections.push(
|
|
110
|
-
"- Email apps (Gmail, Mail): Professional but warm. Use proper greetings and sign-offs if appropriate.",
|
|
111
|
-
"- Slack: Casual and conversational. Match typical chat style.",
|
|
112
|
-
"- Code editors (VS Code, Xcode): Technical and concise. Code comments style.",
|
|
113
|
-
"- Terminal: Command-like, terse.",
|
|
114
|
-
"- Messages/iMessage: Very casual, texting style. Short sentences.",
|
|
115
|
-
"- Notes/Docs: Neutral, clear writing.",
|
|
116
|
-
"- Default: Match the user's natural voice.",
|
|
117
102
|
"",
|
|
118
|
-
"##
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
"-
|
|
103
|
+
"## Tone",
|
|
104
|
+
stylePrompt
|
|
105
|
+
? "Fallback guidance where the User Style above is silent:"
|
|
106
|
+
: "Adapt tone to the active application:",
|
|
107
|
+
"- Email: professional but warm, greetings and sign-offs where they fit",
|
|
108
|
+
"- Slack: casual and conversational",
|
|
109
|
+
"- Code editors: technical and concise",
|
|
110
|
+
"- Terminal: terse, command-like",
|
|
111
|
+
"- Messages: very casual, short sentences",
|
|
112
|
+
"- Notes and docs: neutral, clear writing",
|
|
113
|
+
"- Otherwise: the user's natural voice",
|
|
114
|
+
"The window title may name the recipient; adapt formality to the apparent relationship.",
|
|
123
115
|
"",
|
|
124
116
|
buildAppMetadataBlock(body.context),
|
|
125
117
|
);
|
|
@@ -129,12 +121,12 @@ function buildCombinedDictationPrompt(
|
|
|
129
121
|
|
|
130
122
|
function buildCommandPrompt(body: DictationBody, stylePrompt?: string): string {
|
|
131
123
|
const sections = [
|
|
132
|
-
"You are a text transformation assistant. The user has selected text and
|
|
124
|
+
"You are a text transformation assistant. The user has selected text and spoken. The words are either an instruction to change the selected text or a question about it.",
|
|
133
125
|
"",
|
|
134
126
|
"## Rules",
|
|
135
|
-
"-
|
|
136
|
-
"-
|
|
137
|
-
"- Do NOT add explanations or commentary",
|
|
127
|
+
"- If the words ask for a changed version of the selected text (rewrite, shorten, translate, fix, make it lighter, turn it into a list), kind is edit and text is ONLY the transformed text, nothing else",
|
|
128
|
+
"- If the words ask about the selected text rather than for a changed version of it (what does this mean, is this right, who said this, summarize it for me), kind is answer and text is empty",
|
|
129
|
+
"- Do NOT add explanations or commentary to an edit",
|
|
138
130
|
];
|
|
139
131
|
|
|
140
132
|
if (stylePrompt) {
|
|
@@ -233,6 +225,9 @@ async function handleDictation(body: DictationBody): Promise<DictationResult> {
|
|
|
233
225
|
// Non-command: single LLM call that classifies AND cleans in one shot
|
|
234
226
|
const transcription = expandSnippets(body.transcription, profile.snippets);
|
|
235
227
|
|
|
228
|
+
// Covers provider resolution as well as the call, which is what the caller
|
|
229
|
+
// waits for.
|
|
230
|
+
const modelStartedAt = Date.now();
|
|
236
231
|
try {
|
|
237
232
|
const provider = await getConfiguredProvider("interactionClassifier");
|
|
238
233
|
if (!provider) {
|
|
@@ -289,12 +284,8 @@ async function handleDictation(body: DictationBody): Promise<DictationResult> {
|
|
|
289
284
|
description:
|
|
290
285
|
"If dictation: the cleaned/formatted text ready for insertion. If action: the raw transcription unchanged.",
|
|
291
286
|
},
|
|
292
|
-
reasoning: {
|
|
293
|
-
type: "string",
|
|
294
|
-
description: "Brief reasoning for the classification",
|
|
295
|
-
},
|
|
296
287
|
},
|
|
297
|
-
required: ["mode", "text"
|
|
288
|
+
required: ["mode", "text"],
|
|
298
289
|
},
|
|
299
290
|
},
|
|
300
291
|
],
|
|
@@ -317,12 +308,16 @@ async function handleDictation(body: DictationBody): Promise<DictationResult> {
|
|
|
317
308
|
const input = toolBlock.input as {
|
|
318
309
|
mode?: string;
|
|
319
310
|
text?: string;
|
|
320
|
-
reasoning?: string;
|
|
321
311
|
};
|
|
322
312
|
const mode: DictationMode =
|
|
323
313
|
input.mode === "action" ? "action" : "dictation";
|
|
324
314
|
log.info(
|
|
325
|
-
{
|
|
315
|
+
{
|
|
316
|
+
mode,
|
|
317
|
+
modelMs: Date.now() - modelStartedAt,
|
|
318
|
+
inChars: transcription.length,
|
|
319
|
+
outChars: input.text?.length ?? 0,
|
|
320
|
+
},
|
|
326
321
|
"LLM dictation classify+clean",
|
|
327
322
|
);
|
|
328
323
|
|
|
@@ -343,14 +338,17 @@ async function handleDictation(body: DictationBody): Promise<DictationResult> {
|
|
|
343
338
|
};
|
|
344
339
|
}
|
|
345
340
|
|
|
346
|
-
log.warn(
|
|
341
|
+
log.warn(
|
|
342
|
+
{ modelMs: Date.now() - modelStartedAt },
|
|
343
|
+
"No tool_use block in combined dictation call, using heuristic",
|
|
344
|
+
);
|
|
347
345
|
} finally {
|
|
348
346
|
cleanup();
|
|
349
347
|
}
|
|
350
348
|
} catch (err) {
|
|
351
349
|
const message = err instanceof Error ? err.message : String(err);
|
|
352
350
|
log.warn(
|
|
353
|
-
{ err: message },
|
|
351
|
+
{ err: message, modelMs: Date.now() - modelStartedAt },
|
|
354
352
|
"Combined dictation LLM call failed, using heuristic",
|
|
355
353
|
);
|
|
356
354
|
}
|
|
@@ -407,20 +405,69 @@ async function handleCommandMode(
|
|
|
407
405
|
};
|
|
408
406
|
}
|
|
409
407
|
|
|
408
|
+
const modelStartedAt = Date.now();
|
|
410
409
|
const response = await provider.sendMessage(
|
|
411
410
|
[userMessage(body.transcription)],
|
|
412
411
|
{
|
|
413
|
-
tools: [
|
|
412
|
+
tools: [
|
|
413
|
+
{
|
|
414
|
+
name: "transform_selection",
|
|
415
|
+
description:
|
|
416
|
+
"Return the selected text changed as instructed, or say the words were a question about it",
|
|
417
|
+
input_schema: {
|
|
418
|
+
type: "object" as const,
|
|
419
|
+
properties: {
|
|
420
|
+
kind: {
|
|
421
|
+
type: "string",
|
|
422
|
+
enum: ["edit", "answer"],
|
|
423
|
+
description:
|
|
424
|
+
"edit = the words ask for a changed version of the selected text. answer = the words ask about the selected text and no changed version is wanted.",
|
|
425
|
+
},
|
|
426
|
+
text: {
|
|
427
|
+
type: "string",
|
|
428
|
+
description:
|
|
429
|
+
"If edit: the transformed text only, ready to replace the selection. If answer: empty.",
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
required: ["kind", "text"],
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
],
|
|
414
436
|
systemPrompt,
|
|
415
|
-
config: {
|
|
437
|
+
config: {
|
|
438
|
+
callSite: "interactionClassifier",
|
|
439
|
+
max_tokens: maxTokens,
|
|
440
|
+
tool_choice: { type: "tool" as const, name: "transform_selection" },
|
|
441
|
+
},
|
|
416
442
|
},
|
|
417
443
|
);
|
|
418
444
|
|
|
419
|
-
const
|
|
445
|
+
const toolBlock = extractToolUse(response);
|
|
446
|
+
const input = (toolBlock?.input ?? {}) as { kind?: string; text?: string };
|
|
447
|
+
const edited = input.text?.trim() ?? "";
|
|
448
|
+
const isQuestion =
|
|
449
|
+
input.kind === "answer" || (toolBlock !== undefined && !edited);
|
|
450
|
+
log.info(
|
|
451
|
+
{
|
|
452
|
+
mode: isQuestion ? "question" : "command",
|
|
453
|
+
modelMs: Date.now() - modelStartedAt,
|
|
454
|
+
inChars: inputLength,
|
|
455
|
+
outChars: edited.length,
|
|
456
|
+
},
|
|
457
|
+
"LLM selection transform",
|
|
458
|
+
);
|
|
459
|
+
if (isQuestion) {
|
|
460
|
+
return {
|
|
461
|
+
text: body.transcription,
|
|
462
|
+
mode: "question",
|
|
463
|
+
...profileMeta,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
// No tool block at all is a model that did not answer the question
|
|
467
|
+
// asked; the selection goes back unchanged, which a client reads as
|
|
468
|
+
// nothing to put in its place.
|
|
420
469
|
const cleanedText =
|
|
421
|
-
|
|
422
|
-
? textBlock.text.trim()
|
|
423
|
-
: (body.context.selectedText ?? body.transcription);
|
|
470
|
+
edited || (body.context.selectedText ?? body.transcription);
|
|
424
471
|
const normalizedText = applyDictionary(cleanedText, profile.dictionary);
|
|
425
472
|
return {
|
|
426
473
|
text: normalizedText,
|
|
@@ -461,7 +508,11 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
461
508
|
requestBody: DictationRequestSchema,
|
|
462
509
|
responseBody: z.object({
|
|
463
510
|
text: z.string().describe("Processed text output"),
|
|
464
|
-
mode: z
|
|
511
|
+
mode: z
|
|
512
|
+
.string()
|
|
513
|
+
.describe(
|
|
514
|
+
"Detected mode: dictation, command, action, or question (selected text the words asked about rather than changed; text is the transcription)",
|
|
515
|
+
),
|
|
465
516
|
actionPlan: z
|
|
466
517
|
.string()
|
|
467
518
|
.optional()
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
listPendingRequestsByScope,
|
|
19
19
|
} from "../../channels/gateway-guardian-requests.js";
|
|
20
20
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
21
|
+
import { buildAccessRequestInviteDirective } from "../../notifications/access-request-copy.js";
|
|
21
22
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
22
23
|
import { processGuardianDecision } from "../guardian-action-service.js";
|
|
23
24
|
import type { GuardianDecisionPrompt } from "../guardian-decision-types.js";
|
|
@@ -196,6 +197,12 @@ function mapRequestToPrompt(
|
|
|
196
197
|
};
|
|
197
198
|
}
|
|
198
199
|
|
|
200
|
+
/**
|
|
201
|
+
* The prompt's text is the ask. Its `actions` carry the decision, so a
|
|
202
|
+
* typed decision directive here would duplicate them on every client. An
|
|
203
|
+
* access request also carries the invite-flow sentence, because no action
|
|
204
|
+
* anywhere offers that flow and the sentence is the only way to start it.
|
|
205
|
+
*/
|
|
199
206
|
function buildKindAwareQuestionText(req: GuardianRequestWire): string {
|
|
200
207
|
const baseText =
|
|
201
208
|
req.questionText ??
|
|
@@ -204,20 +211,9 @@ function buildKindAwareQuestionText(req: GuardianRequestWire): string {
|
|
|
204
211
|
? `Approve tool: ${req.toolName} — ${req.activityText}`
|
|
205
212
|
: `Approve tool: ${req.toolName}`
|
|
206
213
|
: `Guardian request: ${req.kind}`);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const lines = [baseText];
|
|
211
|
-
lines.push(
|
|
212
|
-
`\nReply "${code} approve" to grant access or "${code} reject" to deny.`,
|
|
213
|
-
);
|
|
214
|
-
lines.push(
|
|
215
|
-
'Reply "open invite flow" to start Trusted Contacts invite flow.',
|
|
216
|
-
);
|
|
217
|
-
return lines.join("\n");
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return baseText;
|
|
214
|
+
return req.kind === "access_request"
|
|
215
|
+
? `${baseText}\n${buildAccessRequestInviteDirective()}`
|
|
216
|
+
: baseText;
|
|
221
217
|
}
|
|
222
218
|
|
|
223
219
|
// ---------------------------------------------------------------------------
|
|
@@ -81,11 +81,6 @@ export async function handleApprovalInterception(
|
|
|
81
81
|
approvalMessageId,
|
|
82
82
|
} = params;
|
|
83
83
|
|
|
84
|
-
// Slack emoji reactions are handled by the guardian decision
|
|
85
|
-
// pipeline (`routeGuardianReply`), invoked from the inbound reaction stage:
|
|
86
|
-
// it resolves the target request from the reacted card's delivery record.
|
|
87
|
-
// See `guardian-reply-router.ts`.
|
|
88
|
-
|
|
89
84
|
// ── Standard approval interception (existing flow) ──
|
|
90
85
|
const pendingPrompt = getChannelApprovalPrompt(conversationId);
|
|
91
86
|
if (!pendingPrompt) {
|