@vellumai/assistant 0.11.8 → 0.11.9-staging.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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__/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__/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 +12 -0
- package/src/cli/commands/channels/__tests__/channels.test.ts +26 -0
- package/src/cli/commands/channels/index.help.ts +15 -1
- 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/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/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/injector.ts +14 -15
- 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 +12 -7
- package/src/providers/inference/auth.ts +6 -6
- package/src/providers/media-resolve.ts +14 -0
- package/src/providers/model-catalog.ts +31 -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
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical vocabulary for a guardian request's lifecycle status, shared by
|
|
3
|
+
* the gateway that owns the request rows, the daemon that decides and
|
|
4
|
+
* projects them, and the web that renders the projection.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
export const GUARDIAN_REQUEST_STATUS_VALUES = [
|
|
9
|
+
"pending",
|
|
10
|
+
"approved",
|
|
11
|
+
"denied",
|
|
12
|
+
"expired",
|
|
13
|
+
"cancelled",
|
|
14
|
+
] as const;
|
|
15
|
+
export const GuardianRequestStatusSchema = z.enum(
|
|
16
|
+
GUARDIAN_REQUEST_STATUS_VALUES,
|
|
17
|
+
);
|
|
18
|
+
export type GuardianRequestStatus = z.infer<typeof GuardianRequestStatusSchema>;
|
package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ export * from "./rpc.js";
|
|
|
28
28
|
export * from "./trust-rules.js";
|
|
29
29
|
export * from "./ingress.js";
|
|
30
30
|
export * from "./no-response.js";
|
|
31
|
+
export * from "./platform-credential.js";
|
|
31
32
|
export * from "./remote-web-pairing.js";
|
|
32
33
|
export * from "./twilio-ingress.js";
|
|
33
34
|
export * from "./url-normalization.js";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract for asking an assistant whether its stored platform-managed
|
|
3
|
+
* credential still authenticates.
|
|
4
|
+
*
|
|
5
|
+
* The daemon route is the authoritative serving side:
|
|
6
|
+
* - `POST /v1/platform/verify-credential`
|
|
7
|
+
* (`assistant/src/runtime/routes/platform-routes.ts`)
|
|
8
|
+
*
|
|
9
|
+
* The daemon's platform client produces the verdict, the route reports it,
|
|
10
|
+
* and the `vellum` CLI reads it before deciding whether a stored key can be
|
|
11
|
+
* re-injected (`cli/src/lib/assistant-api-key-resolution.ts`), so all three
|
|
12
|
+
* share one definition and cannot silently drift. The web app reads the same
|
|
13
|
+
* shape through its generated daemon client.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* What the platform said about the stored credential, right now.
|
|
19
|
+
*
|
|
20
|
+
* - `valid`: the platform accepted it.
|
|
21
|
+
* - `rejected`: the platform refused it (unauthorized or forbidden); the
|
|
22
|
+
* credential needs replacing.
|
|
23
|
+
* - `unknown`: the check itself could not run (no credential stored, the
|
|
24
|
+
* platform unreachable, a server error). Not evidence either way.
|
|
25
|
+
*/
|
|
26
|
+
export const PlatformCredentialVerificationStatusSchema = z.enum([
|
|
27
|
+
"valid",
|
|
28
|
+
"rejected",
|
|
29
|
+
"unknown",
|
|
30
|
+
]);
|
|
31
|
+
export type PlatformCredentialVerificationStatus = z.infer<
|
|
32
|
+
typeof PlatformCredentialVerificationStatusSchema
|
|
33
|
+
>;
|
|
34
|
+
|
|
35
|
+
/** `POST /v1/platform/verify-credential` response body. */
|
|
36
|
+
export const PlatformVerifyCredentialResponseSchema = z.object({
|
|
37
|
+
status: PlatformCredentialVerificationStatusSchema,
|
|
38
|
+
});
|
|
39
|
+
export type PlatformVerifyCredentialResponse = z.infer<
|
|
40
|
+
typeof PlatformVerifyCredentialResponseSchema
|
|
41
|
+
>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical vocabulary for a reaction's emoji, shared by every service that
|
|
3
|
+
* handles one: the gateway that normalizes it, the daemon that stores and
|
|
4
|
+
* projects it, and the web that renders it.
|
|
5
|
+
*
|
|
6
|
+
* The kind is said by the channel rather than inferred from how the emoji
|
|
7
|
+
* is spelled. Modelled on Zulip's `reaction_type`, the one surveyed system
|
|
8
|
+
* that separates the namespace from the name.
|
|
9
|
+
*
|
|
10
|
+
* `shortcode` is a name in a channel's own namespace whose kind the channel
|
|
11
|
+
* does not disclose: Slack sends `+1` for the standard emoji and `blob_wave`
|
|
12
|
+
* for a workspace upload with nothing to tell them apart, and only the
|
|
13
|
+
* workspace token can resolve the second. It is a distinct kind from
|
|
14
|
+
* `unicode`, not a stand-in for an unknown one.
|
|
15
|
+
*/
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
|
|
18
|
+
export const REACTION_EMOJI_KINDS = ["unicode", "shortcode", "custom"] as const;
|
|
19
|
+
export type ReactionEmojiKind = (typeof REACTION_EMOJI_KINDS)[number];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The typed emoji fields every schema that carries a reaction spreads in,
|
|
23
|
+
* so the wire contract, the stored envelopes, and the response projection
|
|
24
|
+
* describe one shape. Optional throughout: a persisted row or a replayed
|
|
25
|
+
* payload may carry only the spelling.
|
|
26
|
+
*/
|
|
27
|
+
export const ReactionEmojiFieldsSchema = z.object({
|
|
28
|
+
/** Which namespace the emoji was drawn from. */
|
|
29
|
+
emojiKind: z.enum(REACTION_EMOJI_KINDS).optional(),
|
|
30
|
+
/**
|
|
31
|
+
* The emoji's name in that namespace: the character itself for `unicode`,
|
|
32
|
+
* the bare name for `shortcode` and `custom`. Never a mention form.
|
|
33
|
+
*/
|
|
34
|
+
emojiName: z.string().optional(),
|
|
35
|
+
/** The channel's id for a `custom` emoji, absent for every other kind. */
|
|
36
|
+
emojiId: z.string().optional(),
|
|
37
|
+
/** Whether a `custom` emoji animates. Absent for every other kind. */
|
|
38
|
+
emojiAnimated: z.boolean().optional(),
|
|
39
|
+
});
|
|
40
|
+
export type ReactionEmojiFields = z.infer<typeof ReactionEmojiFieldsSchema>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The typed emoji fields a source actually carries, with undefined ones
|
|
44
|
+
* omitted: an absent key and a present-but-undefined one serialize alike, but the
|
|
45
|
+
* stored envelope and the response should carry only what was declared. Every writer of a reaction shape (the wire
|
|
46
|
+
* payload, both stored envelopes, the response projection) copies the
|
|
47
|
+
* fields through this rather than restating the four-way pick.
|
|
48
|
+
*/
|
|
49
|
+
export function pickReactionEmojiFields(
|
|
50
|
+
source: ReactionEmojiFields,
|
|
51
|
+
): ReactionEmojiFields {
|
|
52
|
+
return {
|
|
53
|
+
...(source.emojiKind !== undefined ? { emojiKind: source.emojiKind } : {}),
|
|
54
|
+
...(source.emojiName !== undefined ? { emojiName: source.emojiName } : {}),
|
|
55
|
+
...(source.emojiId !== undefined ? { emojiId: source.emojiId } : {}),
|
|
56
|
+
...(source.emojiAnimated !== undefined
|
|
57
|
+
? { emojiAnimated: source.emojiAnimated }
|
|
58
|
+
: {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-request-contract.test.ts
CHANGED
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
ExpireGuardianRequestIpcParamsSchema,
|
|
17
17
|
ExpireInteractionBoundIpcResponseSchema,
|
|
18
18
|
GetGuardianRequestByCallSessionIpcParamsSchema,
|
|
19
|
-
GetGuardianRequestByDestinationMessageIpcParamsSchema,
|
|
20
19
|
GetGuardianRequestByPendingQuestionIpcParamsSchema,
|
|
21
20
|
GUARDIAN_REQUESTS_IPC_METHODS,
|
|
22
21
|
GuardianRequestAclOutcomeSchema,
|
|
@@ -482,23 +481,6 @@ describe("delivery + destination IPC schemas", () => {
|
|
|
482
481
|
);
|
|
483
482
|
});
|
|
484
483
|
|
|
485
|
-
test("get_by_destination_message requires all three keys", () => {
|
|
486
|
-
const params = {
|
|
487
|
-
channel: "telegram",
|
|
488
|
-
chatId: "tg-chat-guardian",
|
|
489
|
-
messageId: "msg-42",
|
|
490
|
-
};
|
|
491
|
-
expect(
|
|
492
|
-
GetGuardianRequestByDestinationMessageIpcParamsSchema.parse(params),
|
|
493
|
-
).toEqual(params);
|
|
494
|
-
expect(() =>
|
|
495
|
-
GetGuardianRequestByDestinationMessageIpcParamsSchema.parse({
|
|
496
|
-
channel: "telegram",
|
|
497
|
-
chatId: "tg-chat-guardian",
|
|
498
|
-
}),
|
|
499
|
-
).toThrow();
|
|
500
|
-
});
|
|
501
|
-
|
|
502
484
|
test("list_pending_by_destination accepts either addressing form", () => {
|
|
503
485
|
const byConversation = { conversationId: "conv-1", channel: "telegram" };
|
|
504
486
|
expect(
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
resolveInboundEventKind,
|
|
12
12
|
resolveInboundReactionPayload,
|
|
13
13
|
} from "../inbound-event-kind.js";
|
|
14
|
+
import { RuntimeInboundPayloadSchema } from "../inbound-contract.js";
|
|
14
15
|
|
|
15
16
|
describe("resolveInboundEventKind", () => {
|
|
16
17
|
test("a stamped kind wins over every legacy field", () => {
|
|
@@ -83,14 +84,58 @@ describe("inboundEventRefersToAnotherMessage", () => {
|
|
|
83
84
|
});
|
|
84
85
|
|
|
85
86
|
describe("resolveInboundReactionPayload", () => {
|
|
86
|
-
test("a structured payload wins outright", () => {
|
|
87
|
+
test("a structured payload wins outright, typed fields included", () => {
|
|
87
88
|
expect(
|
|
88
89
|
resolveInboundReactionPayload({
|
|
89
90
|
eventKind: "reaction",
|
|
90
|
-
reaction: {
|
|
91
|
+
reaction: {
|
|
92
|
+
op: "removed",
|
|
93
|
+
emoji: "+1",
|
|
94
|
+
emojiKind: "shortcode",
|
|
95
|
+
emojiName: "+1",
|
|
96
|
+
targetMessageId: "11.22",
|
|
97
|
+
},
|
|
91
98
|
callbackData: "reaction:eyes",
|
|
92
99
|
}),
|
|
93
|
-
).toEqual({
|
|
100
|
+
).toEqual({
|
|
101
|
+
op: "removed",
|
|
102
|
+
emoji: "+1",
|
|
103
|
+
emojiKind: "shortcode",
|
|
104
|
+
emojiName: "+1",
|
|
105
|
+
targetMessageId: "11.22",
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("a stored payload without typed fields recovers its kind", () => {
|
|
110
|
+
// Rows predating the typed fields carry the spelling only. This is the
|
|
111
|
+
// one place the kind is inferred, and each spelling has one answer.
|
|
112
|
+
const at = (emoji: string) =>
|
|
113
|
+
resolveInboundReactionPayload({
|
|
114
|
+
eventKind: "reaction",
|
|
115
|
+
reaction: { op: "added", emoji, targetMessageId: "11.22" },
|
|
116
|
+
});
|
|
117
|
+
expect(at("<:blob_wave:987>")).toMatchObject({
|
|
118
|
+
emojiKind: "custom",
|
|
119
|
+
emojiName: "blob_wave",
|
|
120
|
+
emojiId: "987",
|
|
121
|
+
});
|
|
122
|
+
// The plain form records nothing about animation, so the field is
|
|
123
|
+
// absent rather than a fabricated false; a resolver must not read
|
|
124
|
+
// "not animated" off a row that never knew.
|
|
125
|
+
expect(at("<:blob_wave:987>")).not.toHaveProperty("emojiAnimated");
|
|
126
|
+
expect(at("<a:party:5>")).toMatchObject({
|
|
127
|
+
emojiKind: "custom",
|
|
128
|
+
emojiName: "party",
|
|
129
|
+
emojiId: "5",
|
|
130
|
+
emojiAnimated: true,
|
|
131
|
+
});
|
|
132
|
+
expect(at("thumbsup")).toMatchObject({
|
|
133
|
+
emojiKind: "shortcode",
|
|
134
|
+
emojiName: "thumbsup",
|
|
135
|
+
});
|
|
136
|
+
expect(at("🎉")).toMatchObject({ emojiKind: "unicode", emojiName: "🎉" });
|
|
137
|
+
// The spelling itself is never rewritten: the write path parses it back.
|
|
138
|
+
expect(at("<:blob_wave:987>")?.emoji).toBe("<:blob_wave:987>");
|
|
94
139
|
});
|
|
95
140
|
|
|
96
141
|
test("a replayed payload parses its sentinel and wire target", () => {
|
|
@@ -99,13 +144,25 @@ describe("resolveInboundReactionPayload", () => {
|
|
|
99
144
|
callbackData: "reaction:thumbsup",
|
|
100
145
|
sourceMetadata: { messageId: "33.44" },
|
|
101
146
|
}),
|
|
102
|
-
).toEqual({
|
|
147
|
+
).toEqual({
|
|
148
|
+
op: "added",
|
|
149
|
+
emoji: "thumbsup",
|
|
150
|
+
emojiKind: "shortcode",
|
|
151
|
+
emojiName: "thumbsup",
|
|
152
|
+
targetMessageId: "33.44",
|
|
153
|
+
});
|
|
103
154
|
expect(
|
|
104
155
|
resolveInboundReactionPayload({
|
|
105
156
|
callbackData: "reaction_removed:thumbsup",
|
|
106
157
|
sourceMetadata: { messageId: "33.44" },
|
|
107
158
|
}),
|
|
108
|
-
).toEqual({
|
|
159
|
+
).toEqual({
|
|
160
|
+
op: "removed",
|
|
161
|
+
emoji: "thumbsup",
|
|
162
|
+
emojiKind: "shortcode",
|
|
163
|
+
emojiName: "thumbsup",
|
|
164
|
+
targetMessageId: "33.44",
|
|
165
|
+
});
|
|
109
166
|
});
|
|
110
167
|
|
|
111
168
|
test("no emoji or no target is not a reaction payload", () => {
|
|
@@ -126,3 +183,51 @@ describe("resolveInboundReactionPayload", () => {
|
|
|
126
183
|
).toBeNull();
|
|
127
184
|
});
|
|
128
185
|
});
|
|
186
|
+
|
|
187
|
+
describe("RuntimeInboundPayloadSchema carries a reaction's typed emoji", () => {
|
|
188
|
+
const base = {
|
|
189
|
+
sourceChannel: "discord",
|
|
190
|
+
interface: "discord",
|
|
191
|
+
conversationExternalId: "chan-1",
|
|
192
|
+
externalMessageId: "msg-1:reaction:<:party_blob:111>:user-1:ingest-1",
|
|
193
|
+
content: "",
|
|
194
|
+
eventKind: "reaction",
|
|
195
|
+
actorExternalId: "user-1",
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
test("a custom emoji keeps all four typed fields through the wire schema", () => {
|
|
199
|
+
const parsed = RuntimeInboundPayloadSchema.parse({
|
|
200
|
+
...base,
|
|
201
|
+
reaction: {
|
|
202
|
+
op: "added",
|
|
203
|
+
emoji: "<:party_blob:111>",
|
|
204
|
+
emojiKind: "custom",
|
|
205
|
+
emojiName: "party_blob",
|
|
206
|
+
emojiId: "111",
|
|
207
|
+
emojiAnimated: true,
|
|
208
|
+
targetMessageId: "msg-1",
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
expect(parsed.reaction).toEqual({
|
|
212
|
+
op: "added",
|
|
213
|
+
emoji: "<:party_blob:111>",
|
|
214
|
+
emojiKind: "custom",
|
|
215
|
+
emojiName: "party_blob",
|
|
216
|
+
emojiId: "111",
|
|
217
|
+
emojiAnimated: true,
|
|
218
|
+
targetMessageId: "msg-1",
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("a reaction carrying only the spelling still parses", () => {
|
|
223
|
+
const parsed = RuntimeInboundPayloadSchema.parse({
|
|
224
|
+
...base,
|
|
225
|
+
reaction: { op: "removed", emoji: "+1", targetMessageId: "msg-1" },
|
|
226
|
+
});
|
|
227
|
+
expect(parsed.reaction).toEqual({
|
|
228
|
+
op: "removed",
|
|
229
|
+
emoji: "+1",
|
|
230
|
+
targetMessageId: "msg-1",
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
@@ -15,13 +15,9 @@
|
|
|
15
15
|
* daemon's client-facing HTTP surface owns the distinct `guardian_actions_*`
|
|
16
16
|
* operationIds (`guardian_actions_pending` / `guardian_actions_decision`),
|
|
17
17
|
* which do not change.
|
|
18
|
-
*
|
|
19
|
-
* Destination lookups are deliberately split into a single-message lookup
|
|
20
|
-
* (`get_by_destination_message`) and a pending-list read
|
|
21
|
-
* (`list_pending_by_destination`) so each response schema has exactly one
|
|
22
|
-
* shape instead of a params-dependent polymorphic result.
|
|
23
18
|
*/
|
|
24
19
|
|
|
20
|
+
import { GuardianRequestStatusSchema } from "@vellumai/service-contracts/guardian-requests";
|
|
25
21
|
import { z } from "zod";
|
|
26
22
|
|
|
27
23
|
import {
|
|
@@ -33,19 +29,11 @@ import {
|
|
|
33
29
|
// Enums
|
|
34
30
|
// ---------------------------------------------------------------------------
|
|
35
31
|
|
|
36
|
-
|
|
37
|
-
"pending",
|
|
38
|
-
"approved",
|
|
39
|
-
"denied",
|
|
40
|
-
"expired",
|
|
41
|
-
"cancelled",
|
|
42
|
-
] as const;
|
|
43
|
-
|
|
44
|
-
export const GuardianRequestStatusSchema = z.enum(
|
|
32
|
+
export {
|
|
45
33
|
GUARDIAN_REQUEST_STATUS_VALUES,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
type GuardianRequestStatus,
|
|
35
|
+
GuardianRequestStatusSchema,
|
|
36
|
+
} from "@vellumai/service-contracts/guardian-requests";
|
|
49
37
|
|
|
50
38
|
const GUARDIAN_REQUEST_KIND_VALUES = [
|
|
51
39
|
"access_request",
|
|
@@ -194,7 +182,6 @@ export const GUARDIAN_REQUESTS_IPC_METHODS = {
|
|
|
194
182
|
updateDelivery: "guardian_requests_update_delivery",
|
|
195
183
|
listDeliveries: "guardian_requests_list_deliveries",
|
|
196
184
|
listDeliveriesByChat: "guardian_requests_list_deliveries_by_chat",
|
|
197
|
-
getByDestinationMessage: "guardian_requests_get_by_destination_message",
|
|
198
185
|
listPendingByDestination: "guardian_requests_list_pending_by_destination",
|
|
199
186
|
listPendingByScope: "guardian_requests_list_pending_by_scope",
|
|
200
187
|
inScope: "guardian_requests_in_scope",
|
|
@@ -627,21 +614,6 @@ export type GuardianRequestDeliveryListIpcResponse = z.infer<
|
|
|
627
614
|
// Destination + scope lookups
|
|
628
615
|
// ---------------------------------------------------------------------------
|
|
629
616
|
|
|
630
|
-
/**
|
|
631
|
-
* Request for `guardian_requests_get_by_destination_message` — reaction
|
|
632
|
-
* routing: recover the pending request whose delivered card is the reacted-to
|
|
633
|
-
* message.
|
|
634
|
-
*/
|
|
635
|
-
export const GetGuardianRequestByDestinationMessageIpcParamsSchema = z.object({
|
|
636
|
-
channel: z.string().min(1),
|
|
637
|
-
chatId: z.string().min(1),
|
|
638
|
-
messageId: z.string().min(1),
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
export type GetGuardianRequestByDestinationMessageIpcParams = z.infer<
|
|
642
|
-
typeof GetGuardianRequestByDestinationMessageIpcParamsSchema
|
|
643
|
-
>;
|
|
644
|
-
|
|
645
617
|
/**
|
|
646
618
|
* Request for `guardian_requests_list_pending_by_destination`. Two forms:
|
|
647
619
|
* by destination conversation (`conversationId`, optionally narrowed by
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { INBOUND_EVENT_KINDS } from "./inbound-event-kind.js";
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
|
|
16
|
+
import { ReactionEmojiFieldsSchema } from "@vellumai/service-contracts/reactions";
|
|
17
|
+
|
|
16
18
|
import { ChannelConversationTypeSchema } from "./channel-permission-contract.js";
|
|
17
19
|
|
|
18
20
|
import { AdmissionPolicySchema } from "./admission-policy-contract.js";
|
|
@@ -183,6 +185,7 @@ export const RuntimeInboundPayloadSchema = z.object({
|
|
|
183
185
|
.object({
|
|
184
186
|
op: z.enum(["added", "removed"]),
|
|
185
187
|
emoji: z.string(),
|
|
188
|
+
...ReactionEmojiFieldsSchema.shape,
|
|
186
189
|
targetMessageId: z.string(),
|
|
187
190
|
})
|
|
188
191
|
.optional(),
|
|
@@ -74,16 +74,34 @@ export function inboundEventRefersToAnotherMessage(
|
|
|
74
74
|
return kind !== "message";
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
import {
|
|
78
|
+
pickReactionEmojiFields,
|
|
79
|
+
type ReactionEmojiKind,
|
|
80
|
+
} from "@vellumai/service-contracts/reactions";
|
|
81
|
+
|
|
77
82
|
/** The structured payload of a reaction event. */
|
|
78
83
|
export interface InboundReactionPayload {
|
|
79
84
|
op: "added" | "removed";
|
|
80
85
|
/**
|
|
81
|
-
* The emoji
|
|
82
|
-
* and
|
|
83
|
-
*
|
|
84
|
-
*
|
|
86
|
+
* The emoji in the channel's own spelling, which is what the channel's
|
|
87
|
+
* write path and the model both consume: Discord's outbound route parses
|
|
88
|
+
* a custom emoji back out of its `<:name:id>` mention form. Kept as the
|
|
89
|
+
* wire's token rather than replaced by the typed fields below, because
|
|
90
|
+
* the dedup id embeds it and the model hands it back to `react_to_message`
|
|
91
|
+
* verbatim.
|
|
85
92
|
*/
|
|
86
93
|
emoji: string;
|
|
94
|
+
/** Which namespace {@link emoji} was drawn from. */
|
|
95
|
+
emojiKind: ReactionEmojiKind;
|
|
96
|
+
/**
|
|
97
|
+
* The emoji's name in that namespace: the character itself for `unicode`,
|
|
98
|
+
* the bare name for `shortcode` and `custom`. Never the mention form.
|
|
99
|
+
*/
|
|
100
|
+
emojiName: string;
|
|
101
|
+
/** The channel's id for a `custom` emoji, absent for every other kind. */
|
|
102
|
+
emojiId?: string;
|
|
103
|
+
/** Whether a `custom` emoji animates. Absent for every other kind. */
|
|
104
|
+
emojiAnimated?: boolean;
|
|
87
105
|
/**
|
|
88
106
|
* Provider id of the message reacted to, in the same namespace as
|
|
89
107
|
* `source.messageId`.
|
|
@@ -101,15 +119,28 @@ export interface InboundReactionPayload {
|
|
|
101
119
|
*/
|
|
102
120
|
export function resolveInboundReactionPayload(fields: {
|
|
103
121
|
eventKind?: string;
|
|
104
|
-
reaction?: InboundReactionPayload
|
|
122
|
+
reaction?: Omit<InboundReactionPayload, "emojiKind" | "emojiName"> &
|
|
123
|
+
Partial<Pick<InboundReactionPayload, "emojiKind" | "emojiName">>;
|
|
105
124
|
callbackData?: string;
|
|
106
125
|
sourceMetadata?: { messageId?: string };
|
|
107
126
|
}): InboundReactionPayload | null {
|
|
108
127
|
if (fields.reaction) {
|
|
109
128
|
const { op, emoji, targetMessageId } = fields.reaction;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
129
|
+
if (emoji.length === 0 || targetMessageId.length === 0) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
// A payload carrying only the spelling has its kind recovered from
|
|
133
|
+
// the string, the one source left.
|
|
134
|
+
const typed =
|
|
135
|
+
fields.reaction.emojiKind !== undefined &&
|
|
136
|
+
fields.reaction.emojiName !== undefined
|
|
137
|
+
? {
|
|
138
|
+
...pickReactionEmojiFields(fields.reaction),
|
|
139
|
+
emojiKind: fields.reaction.emojiKind,
|
|
140
|
+
emojiName: fields.reaction.emojiName,
|
|
141
|
+
}
|
|
142
|
+
: classifyLegacyReactionEmoji(emoji);
|
|
143
|
+
return { op, emoji, targetMessageId, ...typed };
|
|
113
144
|
}
|
|
114
145
|
const cb = fields.callbackData;
|
|
115
146
|
const target = fields.sourceMetadata?.messageId;
|
|
@@ -123,6 +154,66 @@ export function resolveInboundReactionPayload(fields: {
|
|
|
123
154
|
}
|
|
124
155
|
const emoji = cb.slice(cb.indexOf(":") + 1);
|
|
125
156
|
return emoji.length > 0
|
|
126
|
-
? {
|
|
157
|
+
? {
|
|
158
|
+
op: removed ? "removed" : "added",
|
|
159
|
+
emoji,
|
|
160
|
+
targetMessageId: target,
|
|
161
|
+
...classifyLegacyReactionEmoji(emoji),
|
|
162
|
+
}
|
|
163
|
+
: null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Parse Discord's custom-emoji mention form. The form travels the wire as a
|
|
168
|
+
* reaction's spelling, so more than one package reads it: the daemon rebuilds
|
|
169
|
+
* a REST path from it when the assistant reacts, and a row carrying only the
|
|
170
|
+
* spelling recovers its kind from it. One parser, so the two cannot disagree
|
|
171
|
+
* about what counts as one.
|
|
172
|
+
*
|
|
173
|
+
* `animated` reports whether the spelling carries the `a` marker. This
|
|
174
|
+
* normalizer never writes that marker, so it is read only from spellings that
|
|
175
|
+
* arrive from elsewhere: a row written by another producer, or a value the
|
|
176
|
+
* model hands back as it received it.
|
|
177
|
+
*/
|
|
178
|
+
export function parseDiscordEmojiMention(
|
|
179
|
+
emoji: string,
|
|
180
|
+
): { name: string; id: string; animated: boolean } | null {
|
|
181
|
+
const match = /^<(a?):([^:>]+):(\d+)>$/.exec(emoji);
|
|
182
|
+
return match
|
|
183
|
+
? { name: match[2]!, id: match[3]!, animated: match[1] === "a" }
|
|
127
184
|
: null;
|
|
128
185
|
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Recover an emoji's kind from its spelling alone. This is the one inference
|
|
189
|
+
* the design permits, reserved for a payload that carries the string and no
|
|
190
|
+
* typed fields: a persisted row or a replayed retry payload. A payload that
|
|
191
|
+
* declares its kind never reaches this.
|
|
192
|
+
*
|
|
193
|
+
* A mention form is unambiguous. Past that the two remaining kinds are told
|
|
194
|
+
* apart by whether the string is a name at all: a channel's shortcode is
|
|
195
|
+
* ASCII word characters, and anything else is the character itself.
|
|
196
|
+
*/
|
|
197
|
+
function classifyLegacyReactionEmoji(
|
|
198
|
+
emoji: string,
|
|
199
|
+
): Pick<
|
|
200
|
+
InboundReactionPayload,
|
|
201
|
+
"emojiKind" | "emojiName" | "emojiId" | "emojiAnimated"
|
|
202
|
+
> {
|
|
203
|
+
const custom = parseDiscordEmojiMention(emoji);
|
|
204
|
+
if (custom) {
|
|
205
|
+
// The plain `<:name:id>` form says nothing about animation: the
|
|
206
|
+
// normalizer spells every custom emoji that way and reports animation
|
|
207
|
+
// in the typed field instead, so a spelling without the `a` marker is
|
|
208
|
+
// "unrecorded", not "not animated". Only the `<a:` form asserts it.
|
|
209
|
+
return {
|
|
210
|
+
emojiKind: "custom",
|
|
211
|
+
emojiName: custom.name,
|
|
212
|
+
emojiId: custom.id,
|
|
213
|
+
...(custom.animated ? { emojiAnimated: true } : {}),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return /^[\w+-]+$/.test(emoji)
|
|
217
|
+
? { emojiKind: "shortcode", emojiName: emoji }
|
|
218
|
+
: { emojiKind: "unicode", emojiName: emoji };
|
|
219
|
+
}
|
|
@@ -88,6 +88,7 @@ export {
|
|
|
88
88
|
inboundEventRefersToAnotherMessage,
|
|
89
89
|
isInboundEventKind,
|
|
90
90
|
resolveInboundEventKind,
|
|
91
|
+
parseDiscordEmojiMention,
|
|
91
92
|
resolveInboundReactionPayload,
|
|
92
93
|
} from "./inbound-event-kind.js";
|
|
93
94
|
export type {
|
|
@@ -245,7 +246,6 @@ export {
|
|
|
245
246
|
ExpireInteractionBoundIpcResponseSchema,
|
|
246
247
|
GetGuardianRequestByCallSessionIpcParamsSchema,
|
|
247
248
|
GetGuardianRequestByCodeIpcParamsSchema,
|
|
248
|
-
GetGuardianRequestByDestinationMessageIpcParamsSchema,
|
|
249
249
|
GetGuardianRequestByPendingQuestionIpcParamsSchema,
|
|
250
250
|
GetGuardianRequestIpcParamsSchema,
|
|
251
251
|
GUARDIAN_REQUESTS_IPC_METHODS,
|
|
@@ -286,7 +286,6 @@ export type {
|
|
|
286
286
|
ExpireInteractionBoundIpcResponse,
|
|
287
287
|
GetGuardianRequestByCallSessionIpcParams,
|
|
288
288
|
GetGuardianRequestByCodeIpcParams,
|
|
289
|
-
GetGuardianRequestByDestinationMessageIpcParams,
|
|
290
289
|
GetGuardianRequestByPendingQuestionIpcParams,
|
|
291
290
|
GetGuardianRequestIpcParams,
|
|
292
291
|
GuardianRequestAclOutcome,
|
|
@@ -59,6 +59,15 @@ export type PermissionRequestDetails = z.infer<
|
|
|
59
59
|
export const ApprovalUIMetadataSchema = z.object({
|
|
60
60
|
requestId: z.string(),
|
|
61
61
|
actions: z.array(ApprovalActionOptionSchema),
|
|
62
|
+
/**
|
|
63
|
+
* Typed-reply instructions for a transport that sends text without
|
|
64
|
+
* buttons. Two producers, two shapes: the notification pipeline sends the
|
|
65
|
+
* instructions alone and always beside a message text, so a transport
|
|
66
|
+
* appends them; the legacy in-turn approval rail sends prompt plus
|
|
67
|
+
* instructions and a transport may use them as the whole message when no
|
|
68
|
+
* text is given. An empty `actions` list means there is nothing to draw
|
|
69
|
+
* and the instructions are the message's only affordance.
|
|
70
|
+
*/
|
|
62
71
|
plainTextFallback: z.string(),
|
|
63
72
|
permissionDetails: PermissionRequestDetailsSchema.optional(),
|
|
64
73
|
/**
|
|
@@ -22,7 +22,10 @@
|
|
|
22
22
|
"./redacted-credential": "./src/redacted-credential.ts",
|
|
23
23
|
"./secret-detection": "./src/secret-detection.ts",
|
|
24
24
|
"./stripe-currency": "./src/stripe-currency.ts",
|
|
25
|
-
"./error": "./src/error.ts"
|
|
25
|
+
"./error": "./src/error.ts",
|
|
26
|
+
"./reactions": "./src/reactions.ts",
|
|
27
|
+
"./guardian-requests": "./src/guardian-requests.ts",
|
|
28
|
+
"./platform-credential": "./src/platform-credential.ts"
|
|
26
29
|
},
|
|
27
30
|
"scripts": {
|
|
28
31
|
"typecheck": "bunx tsc --noEmit",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical vocabulary for a guardian request's lifecycle status, shared by
|
|
3
|
+
* the gateway that owns the request rows, the daemon that decides and
|
|
4
|
+
* projects them, and the web that renders the projection.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
export const GUARDIAN_REQUEST_STATUS_VALUES = [
|
|
9
|
+
"pending",
|
|
10
|
+
"approved",
|
|
11
|
+
"denied",
|
|
12
|
+
"expired",
|
|
13
|
+
"cancelled",
|
|
14
|
+
] as const;
|
|
15
|
+
export const GuardianRequestStatusSchema = z.enum(
|
|
16
|
+
GUARDIAN_REQUEST_STATUS_VALUES,
|
|
17
|
+
);
|
|
18
|
+
export type GuardianRequestStatus = z.infer<typeof GuardianRequestStatusSchema>;
|
|
@@ -28,6 +28,7 @@ export * from "./rpc.js";
|
|
|
28
28
|
export * from "./trust-rules.js";
|
|
29
29
|
export * from "./ingress.js";
|
|
30
30
|
export * from "./no-response.js";
|
|
31
|
+
export * from "./platform-credential.js";
|
|
31
32
|
export * from "./remote-web-pairing.js";
|
|
32
33
|
export * from "./twilio-ingress.js";
|
|
33
34
|
export * from "./url-normalization.js";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract for asking an assistant whether its stored platform-managed
|
|
3
|
+
* credential still authenticates.
|
|
4
|
+
*
|
|
5
|
+
* The daemon route is the authoritative serving side:
|
|
6
|
+
* - `POST /v1/platform/verify-credential`
|
|
7
|
+
* (`assistant/src/runtime/routes/platform-routes.ts`)
|
|
8
|
+
*
|
|
9
|
+
* The daemon's platform client produces the verdict, the route reports it,
|
|
10
|
+
* and the `vellum` CLI reads it before deciding whether a stored key can be
|
|
11
|
+
* re-injected (`cli/src/lib/assistant-api-key-resolution.ts`), so all three
|
|
12
|
+
* share one definition and cannot silently drift. The web app reads the same
|
|
13
|
+
* shape through its generated daemon client.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* What the platform said about the stored credential, right now.
|
|
19
|
+
*
|
|
20
|
+
* - `valid`: the platform accepted it.
|
|
21
|
+
* - `rejected`: the platform refused it (unauthorized or forbidden); the
|
|
22
|
+
* credential needs replacing.
|
|
23
|
+
* - `unknown`: the check itself could not run (no credential stored, the
|
|
24
|
+
* platform unreachable, a server error). Not evidence either way.
|
|
25
|
+
*/
|
|
26
|
+
export const PlatformCredentialVerificationStatusSchema = z.enum([
|
|
27
|
+
"valid",
|
|
28
|
+
"rejected",
|
|
29
|
+
"unknown",
|
|
30
|
+
]);
|
|
31
|
+
export type PlatformCredentialVerificationStatus = z.infer<
|
|
32
|
+
typeof PlatformCredentialVerificationStatusSchema
|
|
33
|
+
>;
|
|
34
|
+
|
|
35
|
+
/** `POST /v1/platform/verify-credential` response body. */
|
|
36
|
+
export const PlatformVerifyCredentialResponseSchema = z.object({
|
|
37
|
+
status: PlatformCredentialVerificationStatusSchema,
|
|
38
|
+
});
|
|
39
|
+
export type PlatformVerifyCredentialResponse = z.infer<
|
|
40
|
+
typeof PlatformVerifyCredentialResponseSchema
|
|
41
|
+
>;
|