@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
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* - platform_status (GET platform/status): aggregates platform context,
|
|
6
6
|
* credentials, assistant ID, and webhook secret. (Velay tunnel status
|
|
7
7
|
* lives on the gateway — see gateway_status.)
|
|
8
|
-
* - platform_connect (POST platform/connect):
|
|
9
|
-
* and
|
|
8
|
+
* - platform_connect (POST platform/connect): reports whether the stored
|
|
9
|
+
* credentials still connect, and when the stored key has been rejected,
|
|
10
|
+
* says so, so the caller can tell the user what replaces it.
|
|
10
11
|
* - platform_disconnect (POST platform/disconnect): deletes stored platform
|
|
11
12
|
* credentials and emits platform_disconnected signal.
|
|
12
13
|
* - platform_callback_routes_register (POST platform/callback-routes/register):
|
|
@@ -24,6 +25,11 @@
|
|
|
24
25
|
* invoice list and returns a single invoice by Stripe invoice ID.
|
|
25
26
|
*/
|
|
26
27
|
|
|
28
|
+
import {
|
|
29
|
+
type PlatformCredentialVerificationStatus,
|
|
30
|
+
type PlatformVerifyCredentialResponse,
|
|
31
|
+
PlatformVerifyCredentialResponseSchema,
|
|
32
|
+
} from "@vellumai/service-contracts/platform-credential";
|
|
27
33
|
import { z } from "zod";
|
|
28
34
|
|
|
29
35
|
import { isPlatformRemote } from "../../config/env-registry.js";
|
|
@@ -80,8 +86,16 @@ const PlatformConnectResponseSchema = z.object({
|
|
|
80
86
|
alreadyConnected: z.boolean().optional(),
|
|
81
87
|
baseUrl: z.string().optional(),
|
|
82
88
|
showPlatformLogin: z.boolean().optional(),
|
|
89
|
+
/**
|
|
90
|
+
* The stored managed credential exists but the platform rejects it. Distinct
|
|
91
|
+
* from "nothing stored": the user is not setting up, they are recovering,
|
|
92
|
+
* and what replaces the key is a fresh sign-in, not a first one.
|
|
93
|
+
*/
|
|
94
|
+
credentialRejected: z.boolean().optional(),
|
|
83
95
|
});
|
|
84
|
-
type PlatformConnectResponse = z.infer<
|
|
96
|
+
export type PlatformConnectResponse = z.infer<
|
|
97
|
+
typeof PlatformConnectResponseSchema
|
|
98
|
+
>;
|
|
85
99
|
|
|
86
100
|
const PlatformDisconnectResponseSchema = z.object({
|
|
87
101
|
disconnected: z.literal(true),
|
|
@@ -249,17 +263,72 @@ async function handlePlatformConnect(
|
|
|
249
263
|
),
|
|
250
264
|
]);
|
|
251
265
|
|
|
266
|
+
// Stored credentials only count as a connection while they still
|
|
267
|
+
// authenticate. Answering "already connected" for a key the platform has
|
|
268
|
+
// rejected would report nothing to do about the one thing that needs doing,
|
|
269
|
+
// and no client would get the signal to rotate it.
|
|
270
|
+
//
|
|
271
|
+
// Checked here rather than read from a cache: connect is a deliberate user
|
|
272
|
+
// action, so one request is affordable, and an answer computed now cannot go
|
|
273
|
+
// stale between the check and the answer. An unreachable platform leaves the
|
|
274
|
+
// stored credentials counting as a connection, so a network problem never
|
|
275
|
+
// strands a working install by reporting it disconnected.
|
|
276
|
+
let credentialRejected = false;
|
|
252
277
|
if (existingUrl && existingApiKey) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
278
|
+
const verified = await verifyStoredCredential();
|
|
279
|
+
if (verified !== "rejected") {
|
|
280
|
+
return {
|
|
281
|
+
alreadyConnected: true,
|
|
282
|
+
baseUrl: existingUrl,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
credentialRejected = true;
|
|
257
286
|
}
|
|
258
287
|
|
|
259
|
-
//
|
|
288
|
+
// The outcome travels in the response, where the CLI reads it and tells the
|
|
289
|
+
// user what to do. Nothing shipped consumes the signal below, so the
|
|
290
|
+
// response is the only path the answer reaches anyone by.
|
|
260
291
|
broadcastMessage({ type: "show_platform_login" });
|
|
261
292
|
|
|
262
|
-
return
|
|
293
|
+
return credentialRejected
|
|
294
|
+
? { showPlatformLogin: true, credentialRejected: true }
|
|
295
|
+
: { showPlatformLogin: true };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Ask the platform whether the stored managed credential authenticates.
|
|
300
|
+
* Nothing is stored: each caller that needs the answer asks, so there is no
|
|
301
|
+
* verdict to go stale.
|
|
302
|
+
*
|
|
303
|
+
* Shared by the verification route and by connect, so the two cannot disagree
|
|
304
|
+
* about what "connected" means. Never throws: an unsettled answer is
|
|
305
|
+
* `"unknown"`, which no caller treats as evidence of a dead credential.
|
|
306
|
+
*/
|
|
307
|
+
async function verifyStoredCredential(): Promise<PlatformCredentialVerificationStatus> {
|
|
308
|
+
try {
|
|
309
|
+
const { checkAssistantApiKey } =
|
|
310
|
+
await import("../../credential-health/credential-health-service.js");
|
|
311
|
+
const result = await checkAssistantApiKey();
|
|
312
|
+
if (result === null) {
|
|
313
|
+
// No platform identity at all, so there is nothing to verify.
|
|
314
|
+
return "unknown";
|
|
315
|
+
}
|
|
316
|
+
if (result.status === "healthy") {
|
|
317
|
+
return "valid";
|
|
318
|
+
}
|
|
319
|
+
if (result.status === "revoked" || result.status === "missing_token") {
|
|
320
|
+
return "rejected";
|
|
321
|
+
}
|
|
322
|
+
return "unknown";
|
|
323
|
+
} catch {
|
|
324
|
+
return "unknown";
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function handlePlatformVerifyCredential(
|
|
329
|
+
_args: RouteHandlerArgs,
|
|
330
|
+
): Promise<PlatformVerifyCredentialResponse> {
|
|
331
|
+
return { status: await verifyStoredCredential() };
|
|
263
332
|
}
|
|
264
333
|
|
|
265
334
|
async function handlePlatformDisconnect(
|
|
@@ -711,11 +780,31 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
711
780
|
},
|
|
712
781
|
summary: "Connect to the Vellum Platform",
|
|
713
782
|
description:
|
|
714
|
-
"Checks
|
|
783
|
+
"Checks whether the stored platform credentials still connect. Reports a stored key the platform rejects as credentialRejected, so the caller can direct the user to sign in again and replace it.",
|
|
715
784
|
tags: ["platform"],
|
|
716
785
|
handler: handlePlatformConnect,
|
|
717
786
|
responseBody: PlatformConnectResponseSchema,
|
|
718
787
|
},
|
|
788
|
+
{
|
|
789
|
+
operationId: "platform_verify_credential",
|
|
790
|
+
endpoint: "platform/verify-credential",
|
|
791
|
+
method: "POST",
|
|
792
|
+
// The in-app repair calls this through the gateway with an actor token,
|
|
793
|
+
// the same caller shape as platform_status, so it takes that route's
|
|
794
|
+
// principal bundle. A local-only policy would 403 every browser repair
|
|
795
|
+
// after it had already rotated and stored the replacement. Read scope:
|
|
796
|
+
// the route performs a check and mutates nothing.
|
|
797
|
+
policy: {
|
|
798
|
+
requiredScopes: ["settings.read"],
|
|
799
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
800
|
+
},
|
|
801
|
+
summary: "Verify the Vellum-managed credential against the platform",
|
|
802
|
+
description:
|
|
803
|
+
"Asks the platform whether the stored assistant API key authenticates. POST because it performs a check; the result is returned, not stored.",
|
|
804
|
+
tags: ["platform"],
|
|
805
|
+
handler: handlePlatformVerifyCredential,
|
|
806
|
+
responseBody: PlatformVerifyCredentialResponseSchema,
|
|
807
|
+
},
|
|
719
808
|
{
|
|
720
809
|
operationId: "platform_disconnect",
|
|
721
810
|
endpoint: "platform/disconnect",
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport-agnostic route definition for ambient camera keeps.
|
|
3
|
+
*
|
|
4
|
+
* POST /v1/conversations/:id/sight-frame persists one already-uploaded camera
|
|
5
|
+
* frame into a conversation as its own sight-tagged user message. It runs no
|
|
6
|
+
* turn and starts no agent loop: it is the same standalone-image persist the
|
|
7
|
+
* live-voice `sight_frame` socket frame performs, reached over HTTP by the
|
|
8
|
+
* clients that have a camera tile but no voice socket. The rationale for
|
|
9
|
+
* persisting a kept frame on its own rather than attaching it to a turn is at
|
|
10
|
+
* the top of `live-voice/live-voice-photo.ts`.
|
|
11
|
+
*
|
|
12
|
+
* The response is the client's per-frame acknowledgement, which is why the
|
|
13
|
+
* handler waits on the persist rather than accepting and reporting later.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
|
|
18
|
+
import { persistAmbientSightFrame } from "../../live-voice/live-voice-photo.js";
|
|
19
|
+
import { getConversation } from "../../persistence/conversation-crud.js";
|
|
20
|
+
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
21
|
+
import { resolveOrThrow } from "./conversation-management-routes.js";
|
|
22
|
+
import { BadRequestError, NotFoundError } from "./errors.js";
|
|
23
|
+
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
24
|
+
import { resolveVellumActorTrustContext } from "./vellum-actor-trust.js";
|
|
25
|
+
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Handlers
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Persist a kept camera frame into an existing conversation.
|
|
32
|
+
*
|
|
33
|
+
* The DB existence check comes before the persist because the persist calls
|
|
34
|
+
* `getOrCreateConversation`, which mints a conversation for an id it has never
|
|
35
|
+
* seen. Without the gate a stale client id would silently create a phantom
|
|
36
|
+
* conversation holding nothing but camera frames.
|
|
37
|
+
*
|
|
38
|
+
* That read is also where the frame is accepted, so the row's `created_at` is
|
|
39
|
+
* taken from it and handed to the persist. Resolving the request's actor is
|
|
40
|
+
* awaited below, and a conversation deleted and recreated under this id inside
|
|
41
|
+
* that await leaves a row the gate never saw: the persist reading the id for
|
|
42
|
+
* itself afterwards would take the replacement for the conversation the client
|
|
43
|
+
* addressed. Nothing awaits between the check and the capture, so the two are
|
|
44
|
+
* one moment.
|
|
45
|
+
*
|
|
46
|
+
* The body is hand-validated because the HTTP adapter does not run a route's
|
|
47
|
+
* zod schema against the request and swallows a JSON parse failure, so a
|
|
48
|
+
* malformed send arrives here as an empty bag.
|
|
49
|
+
*/
|
|
50
|
+
async function handleConversationSightFrame({
|
|
51
|
+
pathParams = {},
|
|
52
|
+
body = {},
|
|
53
|
+
headers,
|
|
54
|
+
}: RouteHandlerArgs) {
|
|
55
|
+
const rawId = pathParams.id!;
|
|
56
|
+
const conversationId = resolveOrThrow(rawId);
|
|
57
|
+
const accepted = getConversation(conversationId);
|
|
58
|
+
if (!accepted) {
|
|
59
|
+
throw new NotFoundError(`Conversation ${rawId} not found`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const attachmentId = body.attachmentId;
|
|
63
|
+
if (typeof attachmentId !== "string" || attachmentId.length === 0) {
|
|
64
|
+
throw new BadRequestError("Missing attachmentId");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// The row is attributed to the actor this request was verified as, resolved
|
|
68
|
+
// the way every other vellum-channel route resolves it. Left to the
|
|
69
|
+
// conversation's resting trust, a frame would be stamped for whoever used
|
|
70
|
+
// the conversation last.
|
|
71
|
+
const trustContext = await resolveVellumActorTrustContext(
|
|
72
|
+
headers?.["x-vellum-actor-principal-id"],
|
|
73
|
+
{ healResetDrift: true },
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// Every non-fatal outcome the persist folds into `ok` is reported as a
|
|
77
|
+
// refusal rather than an error status: the frame is gone either way, the
|
|
78
|
+
// client's only move is to keep sampling, and the upload behind each one is
|
|
79
|
+
// the persist's to settle. It gives the bytes up as it refuses, or, where
|
|
80
|
+
// the store would not say whether a row landed, holds them until it answers
|
|
81
|
+
// and gives them up then. Either way the client is done with the frame,
|
|
82
|
+
// which is what the two-state response means.
|
|
83
|
+
const result = await persistAmbientSightFrame(
|
|
84
|
+
conversationId,
|
|
85
|
+
attachmentId,
|
|
86
|
+
"chat",
|
|
87
|
+
trustContext,
|
|
88
|
+
accepted.createdAt,
|
|
89
|
+
);
|
|
90
|
+
return {
|
|
91
|
+
persisted: result.ok,
|
|
92
|
+
...(result.messageId === undefined ? {} : { messageId: result.messageId }),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Route definitions
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
export const ROUTES: RouteDefinition[] = [
|
|
101
|
+
{
|
|
102
|
+
operationId: "conversationSightFrame",
|
|
103
|
+
endpoint: "conversations/:id/sight-frame",
|
|
104
|
+
method: "POST",
|
|
105
|
+
policy: {
|
|
106
|
+
requiredScopes: ["chat.write"],
|
|
107
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
108
|
+
},
|
|
109
|
+
summary: "Persist an ambient camera frame",
|
|
110
|
+
description:
|
|
111
|
+
"Add an already-uploaded camera frame to a conversation as its own " +
|
|
112
|
+
"message, tagged so retention can age the image out of the model's " +
|
|
113
|
+
"context while the transcript keeps it. No reply is generated. " +
|
|
114
|
+
"Returns persisted=false when the frame was dropped, in which case the " +
|
|
115
|
+
"assistant owns the upload and there is nothing to clean up.",
|
|
116
|
+
tags: ["conversations"],
|
|
117
|
+
pathParams: [{ name: "id", type: "uuid" }],
|
|
118
|
+
requestBody: z.object({
|
|
119
|
+
attachmentId: z
|
|
120
|
+
.string()
|
|
121
|
+
.describe("Id of the uploaded attachment holding the frame."),
|
|
122
|
+
}),
|
|
123
|
+
responseBody: z.object({
|
|
124
|
+
persisted: z.boolean(),
|
|
125
|
+
messageId: z
|
|
126
|
+
.string()
|
|
127
|
+
.optional()
|
|
128
|
+
.describe("The message the frame landed on, when one was written."),
|
|
129
|
+
}),
|
|
130
|
+
additionalResponses: {
|
|
131
|
+
"400": { description: "Missing or empty attachmentId" },
|
|
132
|
+
"404": { description: "Conversation not found" },
|
|
133
|
+
},
|
|
134
|
+
handler: handleConversationSightFrame,
|
|
135
|
+
},
|
|
136
|
+
];
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ConversationListInvalidatedReason } from "../../api/events/conversation-list-invalidated.js";
|
|
2
1
|
import type { IdentityFields } from "../../daemon/handlers/identity.js";
|
|
3
2
|
import {
|
|
4
3
|
conversationMessagesSyncTag,
|
|
@@ -160,42 +159,23 @@ export function publishPluginsChanged(originClientId?: string): void {
|
|
|
160
159
|
* delivered exclusively via the per-conversation `sync_changed` tag, which
|
|
161
160
|
* web consumes by GET-and-patching the single row.
|
|
162
161
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
type ConversationListReason =
|
|
163
|
+
| "created"
|
|
164
|
+
| "renamed"
|
|
165
|
+
| "deleted"
|
|
166
|
+
| "reordered"
|
|
167
|
+
| "seen_changed";
|
|
165
168
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
* `conversation:<id>:metadata` for content changes) directly and patches
|
|
172
|
-
* the cached list in place — see `useConversationSync` for the consumer
|
|
173
|
-
* side. macOS (`ConversationRestorer.swift`) still listens for the typed
|
|
174
|
-
* broadcast.
|
|
175
|
-
*
|
|
176
|
-
* TODO(electron-cutover): remove this helper and all callers once macOS
|
|
177
|
-
* migrates to the Electron client and consumes `sync_changed` directly.
|
|
178
|
-
* At that point the `conversation_list_invalidated` message type can be
|
|
179
|
-
* retired entirely.
|
|
180
|
-
*/
|
|
181
|
-
function broadcastConversationListInvalidatedToMacos(
|
|
182
|
-
reason: ConversationListInvalidatedReason,
|
|
183
|
-
): void {
|
|
184
|
-
broadcastMessage(
|
|
185
|
-
{
|
|
186
|
-
type: "conversation_list_invalidated",
|
|
187
|
-
reason,
|
|
188
|
-
},
|
|
189
|
-
undefined,
|
|
190
|
-
{ targetInterfaceId: "macos" },
|
|
191
|
-
);
|
|
192
|
-
}
|
|
169
|
+
const SHAPE_CHANGING_REASONS: ReadonlySet<ConversationListReason> = new Set([
|
|
170
|
+
"created",
|
|
171
|
+
"deleted",
|
|
172
|
+
"reordered",
|
|
173
|
+
]);
|
|
193
174
|
|
|
194
175
|
export function publishConversationListChanged(
|
|
195
|
-
reason:
|
|
176
|
+
reason: ConversationListReason,
|
|
196
177
|
originClientId?: string,
|
|
197
178
|
): void {
|
|
198
|
-
broadcastConversationListInvalidatedToMacos(reason);
|
|
199
179
|
void publishSyncInvalidation([SYNC_TAGS.conversationsList], originClientId);
|
|
200
180
|
}
|
|
201
181
|
|
|
@@ -220,14 +200,13 @@ export function publishConversationMessagesChanged(
|
|
|
220
200
|
}
|
|
221
201
|
|
|
222
202
|
export function publishConversationListAndMetadataChanged(
|
|
223
|
-
reason:
|
|
203
|
+
reason: ConversationListReason,
|
|
224
204
|
conversationIds: string | string[],
|
|
225
205
|
originClientId?: string,
|
|
226
206
|
): void {
|
|
227
207
|
const ids = Array.isArray(conversationIds)
|
|
228
208
|
? conversationIds
|
|
229
209
|
: [conversationIds];
|
|
230
|
-
broadcastConversationListInvalidatedToMacos(reason);
|
|
231
210
|
|
|
232
211
|
// Shape-changing reasons (`created`, `deleted`, `reordered`) add or
|
|
233
212
|
// remove rows or change the order of the paginated window — web must
|
|
@@ -260,9 +239,7 @@ export function publishConversationTitleChanged(
|
|
|
260
239
|
conversationId,
|
|
261
240
|
);
|
|
262
241
|
// Renames are content-only — the paired typed `conversation_title_updated`
|
|
263
|
-
// event already carries the new title and patches the row in place
|
|
264
|
-
// web; macOS receives the per-interface `conversation_list_invalidated`
|
|
265
|
-
// emitted from `broadcastMessage` (see `assistant-event-hub.ts`). The
|
|
242
|
+
// event already carries the new title and patches the row in place; the
|
|
266
243
|
// `sync_changed` metadata tag is included as a belt-and-suspenders signal
|
|
267
244
|
// for any sibling-tab consumer that missed the typed event.
|
|
268
245
|
void publishSyncInvalidation(
|
|
@@ -78,7 +78,7 @@ describe("sync publisher", () => {
|
|
|
78
78
|
const subscription = assistantEventHub.subscribe({
|
|
79
79
|
type: "process",
|
|
80
80
|
callback: async (event) => {
|
|
81
|
-
if (event.message.type === "
|
|
81
|
+
if (event.message.type === "conversation_title_updated") {
|
|
82
82
|
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
83
83
|
}
|
|
84
84
|
receivedTypes.push(event.message.type);
|
|
@@ -87,15 +87,16 @@ describe("sync publisher", () => {
|
|
|
87
87
|
|
|
88
88
|
try {
|
|
89
89
|
broadcastMessage({
|
|
90
|
-
type: "
|
|
91
|
-
|
|
90
|
+
type: "conversation_title_updated",
|
|
91
|
+
conversationId: "conv-1",
|
|
92
|
+
title: "Test",
|
|
92
93
|
});
|
|
93
94
|
await publishSyncInvalidation([SYNC_TAGS.conversationsList]);
|
|
94
95
|
|
|
95
96
|
await waitFor(() => receivedTypes.length === 2);
|
|
96
97
|
|
|
97
98
|
expect(receivedTypes).toEqual([
|
|
98
|
-
"
|
|
99
|
+
"conversation_title_updated",
|
|
99
100
|
"sync_changed",
|
|
100
101
|
]);
|
|
101
102
|
} finally {
|
|
@@ -14,6 +14,7 @@ import { notifyParentTool } from "../subagent/notify-parent.js";
|
|
|
14
14
|
import { requestSystemPermissionTool } from "../system/request-permission.js";
|
|
15
15
|
import { shellTool } from "../terminal/shell.js";
|
|
16
16
|
import { parseToolInput, TOOL_INPUT_SCHEMAS } from "../tool-input-schemas.js";
|
|
17
|
+
import { watchRetroReportTool } from "../watch/watch-retro-report.js";
|
|
17
18
|
|
|
18
19
|
describe("parseToolInput", () => {
|
|
19
20
|
test("passes input through unchanged for a tool with no registered schema", () => {
|
|
@@ -142,6 +143,7 @@ describe("derived input_schema", () => {
|
|
|
142
143
|
requestSystemPermissionTool,
|
|
143
144
|
notifyParentTool,
|
|
144
145
|
reactToMessageTool,
|
|
146
|
+
watchRetroReportTool,
|
|
145
147
|
];
|
|
146
148
|
|
|
147
149
|
test("every registered schema belongs to a tool whose input_schema is derived from it", () => {
|
package/src/tools/client-os.ts
CHANGED
|
@@ -13,6 +13,15 @@ interface HostClientContext {
|
|
|
13
13
|
sourceActorPrincipalId?: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export function desktopClientName(
|
|
17
|
+
context: HostClientContext,
|
|
18
|
+
): "Windows" | "macOS" {
|
|
19
|
+
return context.clientOs === "windows" ||
|
|
20
|
+
context.transportInterface === "windows"
|
|
21
|
+
? "Windows"
|
|
22
|
+
: "macOS";
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
export function supportsClientOs(
|
|
17
26
|
supportedClientOs: readonly ClientOs[] | undefined,
|
|
18
27
|
clientOs: ClientOs | undefined,
|
|
@@ -43,7 +52,8 @@ export function getEligibleHostClientOs(
|
|
|
43
52
|
const eligible = new Set<ClientOs>();
|
|
44
53
|
const sourceClientOs =
|
|
45
54
|
context.transportInterface === "macos" ||
|
|
46
|
-
context.transportInterface === "windows"
|
|
55
|
+
context.transportInterface === "windows" ||
|
|
56
|
+
context.transportInterface === "linux"
|
|
47
57
|
? context.transportInterface
|
|
48
58
|
: context.clientOs;
|
|
49
59
|
if (
|
|
@@ -4,6 +4,7 @@ import { supportsHostProxy } from "../../channels/types.js";
|
|
|
4
4
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
5
5
|
import { RiskLevel } from "../../permissions/types.js";
|
|
6
6
|
import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
|
|
7
|
+
import { desktopClientName } from "../client-os.js";
|
|
7
8
|
import { FileSystemOps } from "../shared/filesystem/file-ops-service.js";
|
|
8
9
|
import { formatEditDiff } from "../shared/filesystem/format-diff.js";
|
|
9
10
|
import { hostPolicy } from "../shared/filesystem/path-policy.js";
|
|
@@ -114,8 +115,7 @@ export const hostFileEditTool = {
|
|
|
114
115
|
!HostFileProxy.instance.isAvailable()
|
|
115
116
|
) {
|
|
116
117
|
return {
|
|
117
|
-
content:
|
|
118
|
-
"Error: no client with host_file capability is connected. Connect a macOS client to use host_file from a non-desktop interface.",
|
|
118
|
+
content: `Error: no client with host_file capability is connected. Connect a ${desktopClientName(context)} client to use host_file from a non-desktop interface.`,
|
|
119
119
|
isError: true,
|
|
120
120
|
};
|
|
121
121
|
}
|
|
@@ -6,6 +6,7 @@ import { supportsHostProxy } from "../../channels/types.js";
|
|
|
6
6
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
7
7
|
import { RiskLevel } from "../../permissions/types.js";
|
|
8
8
|
import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
|
|
9
|
+
import { desktopClientName } from "../client-os.js";
|
|
9
10
|
import {
|
|
10
11
|
AUDIO_EXTENSIONS,
|
|
11
12
|
readAudioFile,
|
|
@@ -120,8 +121,7 @@ export const hostFileReadTool = {
|
|
|
120
121
|
!HostFileProxy.instance.isAvailable()
|
|
121
122
|
) {
|
|
122
123
|
return {
|
|
123
|
-
content:
|
|
124
|
-
"Error: no client with host_file capability is connected. Connect a macOS client to use host_file from a non-desktop interface.",
|
|
124
|
+
content: `Error: no client with host_file capability is connected. Connect a ${desktopClientName(context)} client to use host_file from a non-desktop interface.`,
|
|
125
125
|
isError: true,
|
|
126
126
|
};
|
|
127
127
|
}
|
|
@@ -6,6 +6,7 @@ import { supportsHostProxy } from "../../channels/types.js";
|
|
|
6
6
|
import { HostTransferProxy } from "../../daemon/host-transfer-proxy.js";
|
|
7
7
|
import { RiskLevel } from "../../permissions/types.js";
|
|
8
8
|
import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
|
|
9
|
+
import { desktopClientName } from "../client-os.js";
|
|
9
10
|
import { sandboxPolicy } from "../shared/filesystem/path-policy.js";
|
|
10
11
|
import type {
|
|
11
12
|
ToolContext,
|
|
@@ -124,8 +125,7 @@ export const hostFileTransferTool = {
|
|
|
124
125
|
!HostTransferProxy.instance.isAvailable()
|
|
125
126
|
) {
|
|
126
127
|
return {
|
|
127
|
-
content:
|
|
128
|
-
"Error: no client with host_file capability is connected. Connect a macOS client to use host_file from a non-desktop interface.",
|
|
128
|
+
content: `Error: no client with host_file capability is connected. Connect a ${desktopClientName(context)} client to use host_file from a non-desktop interface.`,
|
|
129
129
|
isError: true,
|
|
130
130
|
};
|
|
131
131
|
}
|
|
@@ -4,6 +4,7 @@ import { supportsHostProxy } from "../../channels/types.js";
|
|
|
4
4
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
5
5
|
import { RiskLevel } from "../../permissions/types.js";
|
|
6
6
|
import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
|
|
7
|
+
import { desktopClientName } from "../client-os.js";
|
|
7
8
|
import { FileSystemOps } from "../shared/filesystem/file-ops-service.js";
|
|
8
9
|
import { formatWriteSummary } from "../shared/filesystem/format-diff.js";
|
|
9
10
|
import { hostPolicy } from "../shared/filesystem/path-policy.js";
|
|
@@ -89,8 +90,7 @@ export const hostFileWriteTool = {
|
|
|
89
90
|
!HostFileProxy.instance.isAvailable()
|
|
90
91
|
) {
|
|
91
92
|
return {
|
|
92
|
-
content:
|
|
93
|
-
"Error: no client with host_file capability is connected. Connect a macOS client to use host_file from a non-desktop interface.",
|
|
93
|
+
content: `Error: no client with host_file capability is connected. Connect a ${desktopClientName(context)} client to use host_file from a non-desktop interface.`,
|
|
94
94
|
isError: true,
|
|
95
95
|
};
|
|
96
96
|
}
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
registerBackgroundTool,
|
|
40
40
|
removeBackgroundTool,
|
|
41
41
|
} from "../background-tool-registry.js";
|
|
42
|
+
import { desktopClientName } from "../client-os.js";
|
|
42
43
|
import {
|
|
43
44
|
attachBoundedStdio,
|
|
44
45
|
MAX_OUTPUT_LENGTH,
|
|
@@ -225,8 +226,7 @@ export const hostShellTool = {
|
|
|
225
226
|
!HostBashProxy.instance.isAvailable()
|
|
226
227
|
) {
|
|
227
228
|
return {
|
|
228
|
-
content:
|
|
229
|
-
"Error: no client with host_bash capability is connected. Connect a macOS client to use host_bash from a non-desktop interface.",
|
|
229
|
+
content: `Error: no client with host_bash capability is connected. Connect a ${desktopClientName(context)} client to use host_bash from a non-desktop interface.`,
|
|
230
230
|
isError: true,
|
|
231
231
|
};
|
|
232
232
|
}
|
package/src/tools/skills/load.ts
CHANGED
|
@@ -158,7 +158,7 @@ export const skillLoadTool = {
|
|
|
158
158
|
name: "skill_load",
|
|
159
159
|
|
|
160
160
|
description:
|
|
161
|
-
'Load full instructions for a skill. Works for both bundled skills (listed in the catalog) and custom workspace skills. Bundled/first-party skills (like `app-builder`) are already installed
|
|
161
|
+
'Load full instructions for a skill. Works for both bundled skills (listed in the catalog) and custom workspace skills. Bundled/first-party skills (like `app-builder`) are already installed: loading only activates their instructions for the current conversation, since skills unload between turns. Treat "load" as activation, not installation, and don\'t tell users a bundled skill needs installing. Loading can still fail (e.g. a feature-gated skill returns "currently unavailable", or the load errors). If it does, relay that specific error rather than claiming the skill is not installed or offering to install it. For app, website, dashboard, game, calculator, tracker, visualization, or interactive tool requests, load `app-builder` with `skill: "app-builder"`. For recurring monitoring of a page, dashboard, or status (check it later and notify), or for reminders and timed checks, load `schedule` with `skill: "schedule"`. When the user names Claude Code or Codex (including as a tool they will use elsewhere), load `acp` with `skill: "acp"`.',
|
|
162
162
|
|
|
163
163
|
category: "skills",
|
|
164
164
|
|
|
@@ -116,6 +116,10 @@ function isKataFamilyRuntime(runtime: string | undefined): boolean {
|
|
|
116
116
|
|
|
117
117
|
function kataAptPaths(dataRoot: string): string[] {
|
|
118
118
|
return [
|
|
119
|
+
// Shims for chroot wrapper scripts with hardcoded absolute paths must
|
|
120
|
+
// shadow the broken originals in the chroot bin dirs below (see
|
|
121
|
+
// docker-kata-apt-shims.sh).
|
|
122
|
+
`${dataRoot}/.host-shims`,
|
|
119
123
|
`${dataRoot}/bin`,
|
|
120
124
|
`${dataRoot}/usr/local/sbin`,
|
|
121
125
|
`${dataRoot}/usr/local/bin`,
|
|
@@ -14,6 +14,7 @@ import { formatToolInputError } from "./shared/zod-tool-schema.js";
|
|
|
14
14
|
import { notifyParentInputSchema } from "./subagent/notify-parent.js";
|
|
15
15
|
import { requestSystemPermissionInputSchema } from "./system/request-permission.js";
|
|
16
16
|
import { shellInputSchema } from "./terminal/shell.js";
|
|
17
|
+
import { watchRetroReportInputSchema } from "./watch/watch-retro-report.js";
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Per-tool Zod input schemas, keyed by tool name. Tool calls are a
|
|
@@ -57,6 +58,7 @@ export const TOOL_INPUT_SCHEMAS: Readonly<Record<string, z.ZodType>> = {
|
|
|
57
58
|
host_file_read: hostFileReadInputSchema,
|
|
58
59
|
host_file_write: hostFileWriteInputSchema,
|
|
59
60
|
notify_parent: notifyParentInputSchema,
|
|
61
|
+
watch_retro_report: watchRetroReportInputSchema,
|
|
60
62
|
react_to_message: reactToMessageInputSchema,
|
|
61
63
|
request_system_permission: requestSystemPermissionInputSchema,
|
|
62
64
|
};
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
uiShowTool,
|
|
37
37
|
uiUpdateTool,
|
|
38
38
|
} from "./ui-surface/definitions.js";
|
|
39
|
+
import { watchRetroReportTool } from "./watch/watch-retro-report.js";
|
|
39
40
|
|
|
40
41
|
// ── Explicit tool instances ─────────────────────────────────────────
|
|
41
42
|
// Core tools registered by initializeTools(). Tool modules only export
|
|
@@ -75,4 +76,5 @@ export const explicitTools: ToolDefinition[] = [
|
|
|
75
76
|
uiShowTool,
|
|
76
77
|
uiUpdateTool,
|
|
77
78
|
uiDismissTool,
|
|
79
|
+
watchRetroReportTool,
|
|
78
80
|
];
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* UI surface tool definitions.
|
|
3
3
|
*
|
|
4
4
|
* These tools allow the model to show, update, and dismiss just-in-time UI
|
|
5
|
-
* surfaces (cards, tables, forms, confirmations) on a connected
|
|
5
|
+
* surfaces (cards, tables, forms, confirmations) on a connected desktop client.
|
|
6
6
|
* They are proxy tools -- execution is forwarded to the client and never
|
|
7
7
|
* handled locally by the daemon.
|
|
8
8
|
*/
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from "../../api/surfaces.js";
|
|
14
14
|
import { RiskLevel } from "../../permissions/types.js";
|
|
15
15
|
import { isWeakOpenModel } from "../../providers/weak-open-model.js";
|
|
16
|
+
import { desktopClientName } from "../client-os.js";
|
|
16
17
|
import type {
|
|
17
18
|
ToolContext,
|
|
18
19
|
ToolDefinition,
|
|
@@ -37,7 +38,7 @@ const APP_BUILDER_BUILD_RE =
|
|
|
37
38
|
/\b(build|building|built|create|creating|created|make|making|made|generate|generating|generated)\b/i;
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
|
-
* Forward execution to the connected
|
|
41
|
+
* Forward execution to the connected desktop client via the request-bound
|
|
41
42
|
* `proxyToolResolver`. Returns a structured error when no resolver is
|
|
42
43
|
* configured (e.g. no client connected) so callers see a normal tool
|
|
43
44
|
* failure rather than an unhandled throw.
|
|
@@ -88,7 +89,7 @@ function proxyExecute(toolName: string) {
|
|
|
88
89
|
|
|
89
90
|
if (!context.proxyToolResolver) {
|
|
90
91
|
return {
|
|
91
|
-
content: `No proxy resolver configured for proxy tool "${toolName}". This tool requires an external resolver (e.g. a connected
|
|
92
|
+
content: `No proxy resolver configured for proxy tool "${toolName}". This tool requires an external resolver (e.g. a connected ${desktopClientName(context)} client).`,
|
|
92
93
|
isError: true,
|
|
93
94
|
};
|
|
94
95
|
}
|