@canonmsg/backend-contracts 1.8.1 → 2.0.0

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.
Files changed (193) hide show
  1. package/dist/agentBehaviorPolicy.d.ts +45 -86
  2. package/dist/agentBehaviorPolicy.js +0 -53
  3. package/dist/cjs/agentBehaviorPolicy.js +1 -54
  4. package/dist/cjs/contactRequest.js +0 -30
  5. package/dist/cjs/index.js +0 -8
  6. package/dist/cjs/media.js +0 -13
  7. package/dist/cjs/message.js +0 -64
  8. package/dist/cjs/runtimeCardFields.js +1 -58
  9. package/dist/cjs/turnProtocol.js +1 -41
  10. package/dist/contactRequest.d.ts +23 -42
  11. package/dist/contactRequest.js +0 -29
  12. package/dist/index.d.ts +0 -8
  13. package/dist/index.js +0 -8
  14. package/dist/media.d.ts +11 -24
  15. package/dist/media.js +0 -12
  16. package/dist/message.d.ts +50 -133
  17. package/dist/message.js +1 -64
  18. package/dist/runtimeCardFields.d.ts +39 -112
  19. package/dist/runtimeCardFields.js +0 -57
  20. package/dist/turnProtocol.d.ts +24 -91
  21. package/dist/turnProtocol.js +0 -40
  22. package/package.json +5 -8
  23. package/dist/bridgeLocal.d.ts +0 -1729
  24. package/dist/bridgeLocal.js +0 -673
  25. package/dist/cjs/bridgeLocal.js +0 -676
  26. package/dist/cjs/controlSignals.js +0 -44
  27. package/dist/cjs/endpointRegistry.js +0 -264
  28. package/dist/cjs/hitl.js +0 -0
  29. package/dist/cjs/inboundFrame.js +0 -92
  30. package/dist/cjs/restEndpoints.js +0 -237
  31. package/dist/cjs/sendContextual.js +0 -92
  32. package/dist/cjs/sseEvents.js +0 -298
  33. package/dist/controlSignals.d.ts +0 -55
  34. package/dist/controlSignals.js +0 -41
  35. package/dist/endpointRegistry.d.ts +0 -13
  36. package/dist/endpointRegistry.js +0 -261
  37. package/dist/hitl.d.ts +0 -303
  38. package/dist/hitl.js +0 -168
  39. package/dist/inboundFrame.d.ts +0 -229
  40. package/dist/inboundFrame.js +0 -89
  41. package/dist/restEndpoints.d.ts +0 -531
  42. package/dist/restEndpoints.js +0 -234
  43. package/dist/schemas/agent-behavior-settings-record.schema.json +0 -48
  44. package/dist/schemas/bridge-connection-state-notification.schema.json +0 -19
  45. package/dist/schemas/bridge-get-attachment-params.schema.json +0 -24
  46. package/dist/schemas/bridge-get-attachment-result.schema.json +0 -20
  47. package/dist/schemas/bridge-hello-params.schema.json +0 -42
  48. package/dist/schemas/bridge-hello-result.schema.json +0 -105
  49. package/dist/schemas/bridge-hitl-state.schema.json +0 -38
  50. package/dist/schemas/bridge-ok-result.schema.json +0 -15
  51. package/dist/schemas/bridge-ready-notification.schema.json +0 -79
  52. package/dist/schemas/bridge-resync-reason.schema.json +0 -9
  53. package/dist/schemas/bridge-resync.schema.json +0 -18
  54. package/dist/schemas/bridge-rpc-error.schema.json +0 -19
  55. package/dist/schemas/bridge-rpc-id.schema.json +0 -12
  56. package/dist/schemas/bridge-rpc-notification.schema.json +0 -20
  57. package/dist/schemas/bridge-rpc-request.schema.json +0 -31
  58. package/dist/schemas/bridge-rpc-response.schema.json +0 -81
  59. package/dist/schemas/bridge-status-result.schema.json +0 -76
  60. package/dist/schemas/bridge-upload-media-params.schema.json +0 -28
  61. package/dist/schemas/bridge-upstream-state.schema.json +0 -10
  62. package/dist/schemas/contacts-response.schema.json +0 -52
  63. package/dist/schemas/control-channel-key.schema.json +0 -10
  64. package/dist/schemas/control-primitive-event.schema.json +0 -30
  65. package/dist/schemas/control-primitive-map.schema.json +0 -15
  66. package/dist/schemas/control-session-event.schema.json +0 -26
  67. package/dist/schemas/control-session-node.schema.json +0 -11
  68. package/dist/schemas/control-signal-event.schema.json +0 -35
  69. package/dist/schemas/control-signal-node.schema.json +0 -22
  70. package/dist/schemas/control-signal-type.schema.json +0 -10
  71. package/dist/schemas/conversations-response.schema.json +0 -167
  72. package/dist/schemas/create-contact-request-request.schema.json +0 -17
  73. package/dist/schemas/create-contact-request-response.schema.json +0 -51
  74. package/dist/schemas/create-conversation-request.schema.json +0 -82
  75. package/dist/schemas/create-conversation-response.schema.json +0 -29
  76. package/dist/schemas/delete-message-response.schema.json +0 -11
  77. package/dist/schemas/delivery-intent.schema.json +0 -11
  78. package/dist/schemas/forward-message-request.schema.json +0 -25
  79. package/dist/schemas/forward-message-response.schema.json +0 -35
  80. package/dist/schemas/forwarded-from.schema.json +0 -18
  81. package/dist/schemas/get-messages-query.schema.json +0 -17
  82. package/dist/schemas/hitl-approval-category.schema.json +0 -15
  83. package/dist/schemas/hitl-approval-detail.schema.json +0 -21
  84. package/dist/schemas/hitl-approval-outcome-record.schema.json +0 -33
  85. package/dist/schemas/hitl-approval-reply-record.schema.json +0 -57
  86. package/dist/schemas/hitl-approval-request-record.schema.json +0 -105
  87. package/dist/schemas/hitl-approval-risk.schema.json +0 -11
  88. package/dist/schemas/hitl-card-outcome-record.schema.json +0 -48
  89. package/dist/schemas/hitl-card-reply-record.schema.json +0 -46
  90. package/dist/schemas/hitl-card-request-record.schema.json +0 -73
  91. package/dist/schemas/hitl-input-answers.schema.json +0 -23
  92. package/dist/schemas/hitl-input-kind.schema.json +0 -10
  93. package/dist/schemas/hitl-input-outcome-record.schema.json +0 -46
  94. package/dist/schemas/hitl-input-question.schema.json +0 -54
  95. package/dist/schemas/hitl-input-reply-record.schema.json +0 -44
  96. package/dist/schemas/hitl-input-request-record.schema.json +0 -134
  97. package/dist/schemas/hitl-pending.schema.json +0 -31
  98. package/dist/schemas/hitl-request-accepted.schema.json +0 -18
  99. package/dist/schemas/hitl-request-kind.schema.json +0 -10
  100. package/dist/schemas/hitl-resolution-status.schema.json +0 -10
  101. package/dist/schemas/hitl-resolution.schema.json +0 -38
  102. package/dist/schemas/hitl-session-rule.schema.json +0 -32
  103. package/dist/schemas/inbound-disposition.schema.json +0 -13
  104. package/dist/schemas/inbound-frame-attachment-v1.schema.json +0 -94
  105. package/dist/schemas/inbound-frame-contact-card-v1.schema.json +0 -59
  106. package/dist/schemas/inbound-frame-group-context-v1.schema.json +0 -96
  107. package/dist/schemas/inbound-frame-reply-context-v1.schema.json +0 -261
  108. package/dist/schemas/inbound-frame-shape-v1.schema.json +0 -12
  109. package/dist/schemas/inbound-frame-v1.schema.json +0 -506
  110. package/dist/schemas/mark-read-response.schema.json +0 -11
  111. package/dist/schemas/media-attachment-kind.schema.json +0 -11
  112. package/dist/schemas/media-attachment.schema.json +0 -42
  113. package/dist/schemas/messages-page-response.schema.json +0 -290
  114. package/dist/schemas/participation-decision-input.schema.json +0 -44
  115. package/dist/schemas/participation-history-message.schema.json +0 -23
  116. package/dist/schemas/participation-history-snapshot.schema.json +0 -37
  117. package/dist/schemas/participation-style.schema.json +0 -13
  118. package/dist/schemas/react-request.schema.json +0 -22
  119. package/dist/schemas/react-response.schema.json +0 -35
  120. package/dist/schemas/resolve-admission-request.schema.json +0 -30
  121. package/dist/schemas/resolve-admission-response.schema.json +0 -129
  122. package/dist/schemas/resolved-agent-behavior-policy-record.schema.json +0 -81
  123. package/dist/schemas/rest-contact.schema.json +0 -40
  124. package/dist/schemas/rest-conversation-last-message.schema.json +0 -77
  125. package/dist/schemas/rest-conversation.schema.json +0 -155
  126. package/dist/schemas/rest-message.schema.json +0 -252
  127. package/dist/schemas/rest-ok-response.schema.json +0 -11
  128. package/dist/schemas/rest-session-selection.schema.json +0 -40
  129. package/dist/schemas/runtime-card-field-choice.schema.json +0 -23
  130. package/dist/schemas/runtime-card-field-type.schema.json +0 -17
  131. package/dist/schemas/runtime-card-field.schema.json +0 -180
  132. package/dist/schemas/runtime-card-line-item-column-type.schema.json +0 -12
  133. package/dist/schemas/runtime-card-line-item-column.schema.json +0 -74
  134. package/dist/schemas/send-contextual-deferred-response.schema.json +0 -39
  135. package/dist/schemas/send-contextual-messaged-response.schema.json +0 -42
  136. package/dist/schemas/send-contextual-request.schema.json +0 -103
  137. package/dist/schemas/send-contextual-response.schema.json +0 -105
  138. package/dist/schemas/send-contextual-self-context.schema.json +0 -19
  139. package/dist/schemas/send-contextual-state-response.schema.json +0 -24
  140. package/dist/schemas/send-message-request.schema.json +0 -106
  141. package/dist/schemas/send-message-response.schema.json +0 -14
  142. package/dist/schemas/sender-type.schema.json +0 -9
  143. package/dist/schemas/serialize-message-input.schema.json +0 -29
  144. package/dist/schemas/serialized-agent-client-type.schema.json +0 -12
  145. package/dist/schemas/serialized-contact-card.schema.json +0 -65
  146. package/dist/schemas/serialized-contact-request-status.schema.json +0 -11
  147. package/dist/schemas/serialized-contact-request.schema.json +0 -157
  148. package/dist/schemas/serialized-content-type.schema.json +0 -13
  149. package/dist/schemas/serialized-message.schema.json +0 -249
  150. package/dist/schemas/serialized-reactions.schema.json +0 -14
  151. package/dist/schemas/serialized-sender-type.schema.json +0 -9
  152. package/dist/schemas/set-streaming-request.schema.json +0 -67
  153. package/dist/schemas/set-typing-request.schema.json +0 -25
  154. package/dist/schemas/sse-access-policy.schema.json +0 -10
  155. package/dist/schemas/sse-agent-context-payload.schema.json +0 -57
  156. package/dist/schemas/sse-connected-payload.schema.json +0 -18
  157. package/dist/schemas/sse-contact-payload.schema.json +0 -40
  158. package/dist/schemas/sse-contact-removed-payload.schema.json +0 -14
  159. package/dist/schemas/sse-contact-request-payload.schema.json +0 -157
  160. package/dist/schemas/sse-conversation-updated-payload.schema.json +0 -48
  161. package/dist/schemas/sse-error-payload.schema.json +0 -23
  162. package/dist/schemas/sse-event-envelope.schema.json +0 -42
  163. package/dist/schemas/sse-event-family.schema.json +0 -12
  164. package/dist/schemas/sse-event-type.schema.json +0 -28
  165. package/dist/schemas/sse-heartbeat-payload.schema.json +0 -14
  166. package/dist/schemas/sse-membership-change.schema.json +0 -28
  167. package/dist/schemas/sse-message-created-payload.schema.json +0 -414
  168. package/dist/schemas/sse-message-deleted-payload.schema.json +0 -18
  169. package/dist/schemas/sse-message-updated-payload.schema.json +0 -46
  170. package/dist/schemas/sse-presence-payload.schema.json +0 -21
  171. package/dist/schemas/sse-provenance.schema.json +0 -64
  172. package/dist/schemas/sse-replay-expired-payload.schema.json +0 -21
  173. package/dist/schemas/sse-runtime-control-kind.schema.json +0 -13
  174. package/dist/schemas/sse-runtime-control-payload.schema.json +0 -44
  175. package/dist/schemas/sse-runtime-updated-payload.schema.json +0 -78
  176. package/dist/schemas/sse-self-context.schema.json +0 -45
  177. package/dist/schemas/sse-turn-dispatch.schema.json +0 -29
  178. package/dist/schemas/sse-turn-updated-payload.schema.json +0 -33
  179. package/dist/schemas/sse-typing-payload.schema.json +0 -32
  180. package/dist/schemas/sse-voice-session-event-payload.schema.json +0 -170
  181. package/dist/schemas/sse-voice-session.schema.json +0 -157
  182. package/dist/schemas/trigger-decision.schema.json +0 -27
  183. package/dist/schemas/turn-lifecycle-state.schema.json +0 -14
  184. package/dist/schemas/turn-message-semantics.schema.json +0 -10
  185. package/dist/schemas/turn-metadata.schema.json +0 -56
  186. package/dist/schemas/turn-state-like.schema.json +0 -39
  187. package/dist/schemas/update-disposition-request.schema.json +0 -22
  188. package/dist/schemas/upload-media-request.schema.json +0 -25
  189. package/dist/schemas/upload-media-response.schema.json +0 -55
  190. package/dist/sendContextual.d.ts +0 -114
  191. package/dist/sendContextual.js +0 -89
  192. package/dist/sseEvents.d.ts +0 -494
  193. package/dist/sseEvents.js +0 -295
@@ -1,673 +0,0 @@
1
- // Bridge ⇄ runtime-adapter LOCAL JSON-RPC contract v1 (types + schemas ONLY —
2
- // no runtime, no transport; Phase 4 builds the bridge against these).
3
- //
4
- // Source spec: docs/design/bridge-local-api.md §A–§C. Where that draft
5
- // conflicts with code-grounded wire shapes (event names, REST payloads), the
6
- // code-grounded schemas in this package win — payload slots below COMPOSE
7
- // restEndpoints.ts / hitl.ts / sseEvents.ts / controlSignals.ts so every
8
- // shape is defined once.
9
- //
10
- // Protocol: JSON-RPC 2.0 over one duplex channel (stdio pipe or unix
11
- // socket / named pipe), NDJSON framing. Requests adapter→bridge (replied),
12
- // notifications bridge→adapter (never awaited). `hello` carries
13
- // protocolVersion — the local contract is version-guarded from v1.
14
- import { z } from 'zod';
15
- import { SerializedContactRequestSchema } from './contactRequest.js';
16
- import { DeliveryIntentSchema, TurnLifecycleStateSchema } from './turnProtocol.js';
17
- import { ControlPrimitiveEventSchema, ControlSessionEventSchema, ControlSignalEventSchema, } from './controlSignals.js';
18
- import { HitlApprovalCategorySchema, HitlApprovalDetailSchema, HitlApprovalRiskSchema, HitlInputKindSchema, HitlInputQuestionSchema, HitlPendingSchema, HitlRequestAcceptedSchema, HitlResolutionSchema, HitlResolutionStatusSchema, } from './hitl.js';
19
- import { ContactsResponseSchema, ConversationsResponseSchema, CreateContactRequestRequestSchema, CreateContactRequestResponseSchema, CreateConversationRequestSchema, CreateConversationResponseSchema, ForwardMessageRequestSchema, ForwardMessageResponseSchema, MessagesPageResponseSchema, ReactRequestSchema, ReactResponseSchema, ResolveAdmissionRequestSchema, ResolveAdmissionResponseSchema, RestContactSchema, RestSessionSelectionSchema, SendMessageRequestSchema, SendMessageResponseSchema, UpdateDispositionRequestSchema, UploadMediaResponseSchema, } from './restEndpoints.js';
20
- import { SendContextualRequestSchema, SendContextualResponseSchema, } from './sendContextual.js';
21
- import { SseAgentContextPayloadSchema, SseConversationUpdatedPayloadSchema, SseEventFamilySchema, SseMessageCreatedPayloadSchema, SseMessageDeletedPayloadSchema, SseMessageUpdatedPayloadSchema, SsePresencePayloadSchema, SseTypingPayloadSchema, SseVoiceSessionEventPayloadSchema, } from './sseEvents.js';
22
- export const BRIDGE_LOCAL_PROTOCOL_VERSION = 1;
23
- const OkResultSchema = z.object({ ok: z.literal(true) });
24
- export { OkResultSchema as BridgeOkResultSchema };
25
- // ── §A Session lifecycle ───────────────────────────────────────────────
26
- export const BridgeHelloParamsSchema = z.object({
27
- protocolVersion: z.number(),
28
- /** Adapter self-identification (claude-code | codex | openclaw | hermes | …). */
29
- clientType: z.string(),
30
- /** Event families to deliver; [] = pure-request adapter, no C-notifications. */
31
- wantFamilies: z.array(SseEventFamilySchema),
32
- /** Replay C-notifications missed while disconnected. */
33
- resumeCursor: z.string().optional(),
34
- /** Publish the runtime descriptor in the same round trip. */
35
- runtimeDescriptor: z.record(z.string(), z.unknown()).optional(),
36
- });
37
- // ── §G resume cursor / resync ───────────────────────────────────────────
38
- //
39
- // The bridge keeps a bounded, locally-sequenced event log. Every replayable
40
- // §C event notification carries the OPAQUE `cursor` token that produced it;
41
- // adapters persist the last cursor they fully processed and present it as
42
- // `hello.resumeCursor` on reconnect to replay exactly the gap. When the
43
- // cursor cannot be honored the hello result answers `sinceCursor: null`
44
- // PLUS a `resync` field — the adapter must treat the gap as lost locally and
45
- // recover out-of-band (REST backfill / state refresh). Never silent loss.
46
- export const BridgeResyncReasonSchema = z.enum([
47
- /** Cursor was valid but its events were evicted from the bounded log. */
48
- 'cursor-expired',
49
- /** Cursor was never issued by this bridge run (restart or corruption). */
50
- 'unknown-cursor',
51
- ]);
52
- export const BridgeResyncSchema = z.object({
53
- reason: BridgeResyncReasonSchema,
54
- });
55
- /**
56
- * Shape mixin for replayable §C notification params (`.extend(...)` onto the
57
- * payload schema). `cursor` is optional in the schema for compatibility, but
58
- * the bridge always sends it on log-delivered notifications. `ready` and
59
- * `connectionState` are connection-scoped (never replayed) and carry none.
60
- */
61
- export const BRIDGE_EVENT_CURSOR_SHAPE = {
62
- cursor: z.string().optional(),
63
- };
64
- export const BridgeHelloResultSchema = z.object({
65
- protocolVersion: z.number(),
66
- agentId: z.string(),
67
- agentName: z.string(),
68
- agentContext: SseAgentContextPayloadSchema,
69
- /** Cursor the delivered replay starts from; null = no replay. */
70
- sinceCursor: z.string().nullable(),
71
- /**
72
- * Present when resumeCursor could not be honored (§G): delivery starts at
73
- * the live head and the adapter must recover the gap out-of-band.
74
- */
75
- resync: BridgeResyncSchema.optional(),
76
- });
77
- export const BridgeUpstreamStateSchema = z.enum(['connected', 'reconnecting', 'down']);
78
- export const BridgeReadyNotificationSchema = z.object({
79
- agentId: z.string(),
80
- agentContext: SseAgentContextPayloadSchema,
81
- upstreamState: BridgeUpstreamStateSchema,
82
- });
83
- export const BridgeConnectionStateNotificationSchema = z.object({
84
- upstream: BridgeUpstreamStateSchema,
85
- });
86
- /**
87
- * `status` result (B4.6 observability): a live snapshot of the daemon
88
- * process, its upstream health, and the B4.2 hub counters. Additive to
89
- * contract v1 — served by the daemon and rendered by `canon-bridge status`.
90
- */
91
- export const BridgeStatusResultSchema = z.object({
92
- /** Daemon process id. */
93
- pid: z.number(),
94
- /** canon-bridge binary (package) version. */
95
- version: z.string(),
96
- /** bridgeLocal contract version the daemon speaks. */
97
- protocolVersion: z.number(),
98
- /** ISO timestamp of daemon start. */
99
- startedAt: z.string(),
100
- uptimeMs: z.number(),
101
- /** Lifecycle profile served (one identity per daemon). */
102
- profile: z.string(),
103
- /** Socket / named-pipe path; null in stdio (spawned-child) mode. */
104
- socketPath: z.string().nullable(),
105
- agentId: z.string(),
106
- agentName: z.string(),
107
- upstream: BridgeUpstreamStateSchema,
108
- /** Adapter connections currently subscribed to the fan-out. */
109
- connectedClients: z.number(),
110
- /** Non-zero B4.2 hub counters (upstream.* / fanout.*). */
111
- counters: z.record(z.string(), z.number()),
112
- });
113
- // ── §B7 HITL state (durable; resolution arrives via onHitlResolved) ────
114
- export const BridgeHitlStateSchema = z.object({
115
- status: z.union([z.literal('pending'), HitlResolutionStatusSchema]),
116
- answer: z.record(z.string(), z.unknown()).optional(),
117
- expiresAt: z.string(),
118
- });
119
- // ── §B8 media (named schemas so the bridge + Framework share the types) ──
120
- //
121
- // Byte transfer is bridge-owned (adapter-interface §1): adapters hand the
122
- // bridge a {path} (streamed from disk — preferred for anything big) or
123
- // inline {bytes} (base64, size-capped so a frame never breaches the NDJSON
124
- // line limit). getAttachment returns the bridge-cached materialization.
125
- export const BridgeUploadMediaParamsSchema = z.object({
126
- /** Absolute file path — the bridge streams it (exactly one of path | bytes). */
127
- path: z.string().optional(),
128
- /** Base64 bytes — size-capped by the bridge; prefer `path` for large files. */
129
- bytes: z.string().optional(),
130
- mime: z.string(),
131
- fileName: z.string(),
132
- conversationId: z.string(),
133
- });
134
- export const BridgeGetAttachmentParamsSchema = z.object({
135
- /** Storage download URL from a MediaAttachment (exactly one of url | attachmentId). */
136
- url: z.string().optional(),
137
- attachmentId: z.string().optional(),
138
- as: z.enum(['path', 'bytes']),
139
- });
140
- export const BridgeGetAttachmentResultSchema = z.object({
141
- /** Stable bridge-cache path — present when as:'path'. */
142
- path: z.string().optional(),
143
- /** Base64 — present when as:'bytes'; capped by the bridge's bytes ceiling. */
144
- bytes: z.string().optional(),
145
- mime: z.string(),
146
- });
147
- const conversationScoped = z.object({ conversationId: z.string() });
148
- const messageScoped = z.object({ conversationId: z.string(), messageId: z.string() });
149
- /**
150
- * RTDB server-timestamp sentinel — code-grounded pass-through (hosts write
151
- * `{'.sv':'timestamp'}` for openedAt/completedAt today; the bridge forwards
152
- * it to the RTDB REST API untouched).
153
- */
154
- const ServerTimestampSentinelSchema = z.object({ '.sv': z.literal('timestamp') });
155
- const EpochOrServerTimestampSchema = z.union([z.number(), ServerTimestampSentinelSchema]);
156
- export const BRIDGE_LOCAL_METHODS = {
157
- // §A lifecycle
158
- hello: { params: BridgeHelloParamsSchema, result: BridgeHelloResultSchema },
159
- /** Liveness probe — the bridge answers without touching upstream. */
160
- ping: { params: z.object({}), result: OkResultSchema },
161
- shutdown: { params: z.object({}), result: OkResultSchema },
162
- /** Daemon snapshot (B4.6): process, upstream health, hub counters. */
163
- status: { params: z.object({}), result: BridgeStatusResultSchema },
164
- // §B1 messaging (outbound)
165
- sendMessage: {
166
- params: SendMessageRequestSchema,
167
- // B4.3 additive: the bridge chunks oversized text (core retry/chunking);
168
- // messageId is the FINAL chunk (carries the caller's metadata/turn
169
- // semantics), messageIds lists every part in send order.
170
- result: SendMessageResponseSchema.extend({
171
- messageIds: z.array(z.string()).optional(),
172
- }),
173
- },
174
- sendContextualMessage: {
175
- params: SendContextualRequestSchema,
176
- result: SendContextualResponseSchema,
177
- },
178
- reactToMessage: { params: ReactRequestSchema, result: ReactResponseSchema },
179
- forwardMessage: { params: ForwardMessageRequestSchema, result: ForwardMessageResponseSchema },
180
- deleteMessage: { params: messageScoped, result: OkResultSchema },
181
- markRead: { params: conversationScoped, result: OkResultSchema },
182
- setDisposition: {
183
- params: messageScoped.extend(UpdateDispositionRequestSchema.shape),
184
- result: OkResultSchema,
185
- },
186
- // §B2 reading / history
187
- getMessages: {
188
- params: z.object({
189
- conversationId: z.string(),
190
- limit: z.number().optional(),
191
- before: z.string().optional(),
192
- includeBehavior: z.boolean().optional(),
193
- }),
194
- // B4.3 additive: nextCursor is the bridge-derived `before` token for the
195
- // next page (oldest returned message id), present when the page filled
196
- // the requested limit. The REST surface itself emits no cursor.
197
- result: MessagesPageResponseSchema.extend({
198
- nextCursor: z.string().optional(),
199
- }),
200
- },
201
- getConversations: { params: z.object({}), result: ConversationsResponseSchema },
202
- // §B3 conversation / group management
203
- createConversation: {
204
- params: CreateConversationRequestSchema,
205
- result: CreateConversationResponseSchema,
206
- },
207
- updateTopic: {
208
- params: conversationScoped.extend({ topic: z.string() }),
209
- result: OkResultSchema,
210
- },
211
- updateName: {
212
- params: conversationScoped.extend({ name: z.string() }),
213
- result: OkResultSchema,
214
- },
215
- updateAvatar: {
216
- params: conversationScoped.extend({ avatarUrl: z.string().nullable().optional() }),
217
- result: OkResultSchema,
218
- },
219
- addMember: {
220
- params: conversationScoped.extend({ userId: z.string() }),
221
- result: z.union([
222
- z.object({ status: z.literal('added') }),
223
- z.object({ status: z.literal('pending'), requestId: z.string() }),
224
- ]),
225
- },
226
- removeMember: {
227
- params: conversationScoped.extend({ userId: z.string() }),
228
- result: OkResultSchema,
229
- },
230
- leaveConversation: { params: conversationScoped, result: OkResultSchema },
231
- muteConversation: {
232
- params: conversationScoped.extend({ until: z.number().optional() }),
233
- result: OkResultSchema,
234
- },
235
- unmuteConversation: { params: conversationScoped, result: OkResultSchema },
236
- hideConversation: { params: conversationScoped, result: OkResultSchema },
237
- // §B4 contacts / admission / blocking
238
- createContactRequest: {
239
- params: CreateContactRequestRequestSchema,
240
- result: CreateContactRequestResponseSchema,
241
- },
242
- listContacts: { params: z.object({}), result: ContactsResponseSchema },
243
- getContact: {
244
- params: z.object({ contactId: z.string() }),
245
- result: RestContactSchema.nullable(),
246
- },
247
- removeContact: { params: z.object({ contactId: z.string() }), result: OkResultSchema },
248
- listContactRequests: {
249
- params: z.object({}),
250
- result: z.object({ requests: z.array(SerializedContactRequestSchema) }),
251
- },
252
- resolveAdmission: {
253
- params: ResolveAdmissionRequestSchema,
254
- result: ResolveAdmissionResponseSchema,
255
- },
256
- reachOut: {
257
- // B6.1 additive (P6 openclaw): the optional fields mirror core
258
- // reachOutToCanonContact options — contact-request message, agent
259
- // session config/selection, and SendMessageOptions passthrough — so
260
- // channel adapters keep today's reach-out fidelity through the bridge.
261
- params: z.object({
262
- targetId: z.string(),
263
- /**
264
- * Optional (B6.1): core reach-out treats a missing text as
265
- * "resolve/open the conversation only" — the openclaw media path
266
- * reaches out first and sends the uploaded attachment separately.
267
- */
268
- text: z.string().optional(),
269
- selfContext: z.string().optional(),
270
- /** Contact-request message when admission requires approval. */
271
- requestMessage: z.string().optional(),
272
- /** Initial agent session config — opaque pass-through. */
273
- sessionConfig: z.record(z.string(), z.unknown()).nullable().optional(),
274
- /** Same union as the REST send surfaces (incl. mode: 'specific'). */
275
- sessionSelection: RestSessionSelectionSchema.optional(),
276
- /** SendMessageOptions passthrough (replyTo, selfContextId, metadata, …). */
277
- sendMessageOptions: z.record(z.string(), z.unknown()).optional(),
278
- }),
279
- result: z.record(z.string(), z.unknown()),
280
- },
281
- blockUser: { params: z.object({ userId: z.string() }), result: OkResultSchema },
282
- unblockUser: { params: z.object({ userId: z.string() }), result: OkResultSchema },
283
- // §B5 live presence / streaming (bridge throttles internally)
284
- setTyping: {
285
- params: conversationScoped.extend({ state: z.enum(['typing', 'thinking', 'clear']) }),
286
- result: OkResultSchema,
287
- },
288
- publishStreaming: {
289
- params: conversationScoped.extend({
290
- turnId: z.string().nullable().optional(),
291
- messageId: z.string().optional(),
292
- text: z.string().optional(),
293
- delta: z.string().optional(),
294
- /** TurnOutputBlock[] — opaque pass-through. */
295
- blocks: z.array(z.record(z.string(), z.unknown())).optional(),
296
- /**
297
- * Explicit bubble/presentation status override (union of B6.1 openclaw
298
- * + P6 host surface): 'tool' / 'waiting_input' cannot be derived from
299
- * text/blocks. Omitted: the bridge derives thinking/streaming from
300
- * content as before.
301
- */
302
- status: z.enum(['thinking', 'streaming', 'tool', 'waiting_input']).optional(),
303
- done: z.boolean().optional(),
304
- }),
305
- result: OkResultSchema,
306
- },
307
- clearStreaming: { params: conversationScoped, result: OkResultSchema },
308
- // §B6 runtime presentation (adapter owns content, bridge publishes)
309
- publishRuntimeDescriptor: {
310
- params: z.object({
311
- descriptor: z.record(z.string(), z.unknown()),
312
- /**
313
- * B6.1 additive (P6 openclaw): rides into the published /agent-runtime
314
- * payload — hosts and host-mode channel plugins publish hostMode: true
315
- * today and the field is app-visible. Latched for subsequent publishes;
316
- * defaults to false (bridge-adapter split is not a host process).
317
- */
318
- hostMode: z.boolean().optional(),
319
- }),
320
- result: OkResultSchema,
321
- },
322
- publishRuntimeStatus: {
323
- // Code-grounded correction (B4.3): RTDB runtime-info lives per
324
- // conversation (/runtime-info/{convoId}/{agentId}), so the publish is
325
- // conversation-scoped. `presentation` carries the remaining
326
- // RuntimeInfoPayload fields (surfaceMode, facts, inventories, notes, …)
327
- // as an opaque pass-through.
328
- params: conversationScoped.extend({
329
- statusItems: z.array(z.record(z.string(), z.unknown())).optional(),
330
- presentation: z.record(z.string(), z.unknown()).optional(),
331
- }),
332
- result: OkResultSchema,
333
- },
334
- publishTurnState: {
335
- // B6.1 additive (P6 openclaw): the remaining CanonTurnStatePayload
336
- // fields hosts publish today. `completedAt: true` asks the bridge to
337
- // stamp the server timestamp (the RTDB sentinel is bridge-owned).
338
- params: conversationScoped.extend({
339
- turnId: z.string().nullable().optional(),
340
- state: TurnLifecycleStateSchema,
341
- queueDepth: z.number().optional(),
342
- capabilities: z.record(z.string(), z.unknown()).optional(),
343
- // Union of B6.1 (openclaw) + P6 host surface — the remaining
344
- // code-grounded TurnStatePayload fields (rtdb-rest.ts).
345
- currentSpeakerId: z.string().nullable().optional(),
346
- lastAcceptedIntent: DeliveryIntentSchema.nullable().optional(),
347
- activeMessageIds: z.array(z.string()).optional(),
348
- openedAt: EpochOrServerTimestampSchema.optional(),
349
- turnUpdatedAt: EpochOrServerTimestampSchema.nullable().optional(),
350
- // `true` (B6.1 openclaw) asks the bridge to stamp the server-timestamp
351
- // sentinel; hosts (P6) pass an epoch or the sentinel through directly.
352
- completedAt: z
353
- .union([z.boolean(), EpochOrServerTimestampSchema])
354
- .nullable()
355
- .optional(),
356
- }),
357
- result: OkResultSchema,
358
- },
359
- clearTurnState: { params: conversationScoped, result: OkResultSchema },
360
- publishActivity: {
361
- params: conversationScoped.extend({
362
- activityItems: z.array(z.record(z.string(), z.unknown())),
363
- }),
364
- result: OkResultSchema,
365
- },
366
- clearActivity: {
367
- // B6.1 additive (P6 openclaw): remove activity blocks. `all` wipes the
368
- // conversation's node; `itemIds` removes specific blocks; neither falls
369
- // back to the publisher's terminal-only sweep semantics.
370
- params: conversationScoped.extend({
371
- all: z.boolean().optional(),
372
- itemIds: z.array(z.string()).optional(),
373
- }),
374
- result: OkResultSchema,
375
- },
376
- /** B6.1 additive: clear the per-conversation runtime-info node. */
377
- clearRuntimeStatus: { params: conversationScoped, result: OkResultSchema },
378
- /**
379
- * B6.1 additive: clear /agent-runtime for this identity (preserves
380
- * descriptor-bearing payloads with updatedAt: 0, like hosts do today).
381
- */
382
- clearRuntimeDescriptor: { params: z.object({}), result: OkResultSchema },
383
- // §B7 HITL (durable; returns requestId, resolves via onHitlResolved).
384
- //
385
- // P6 host surface (additive): process-executing hosts publish the SAME
386
- // rich records channel runtimes create today (approval cards with
387
- // diff/details/native handles, titled input cards, card ids the runtime
388
- // correlates on). All new fields are optional — the narrow Phase-4 shape
389
- // still parses. `requestId`/`inputId`/`cardId`-style explicit ids become
390
- // the bridge record's requestId so adapters keep their own correlation.
391
- // `responseUserId: null` means "let the server pick a reachable responder"
392
- // (codex cards today); absent keeps the Phase-4 default (agent owner).
393
- requestApproval: {
394
- // B6.1 additive (P6 openclaw): optional approval-card fidelity fields
395
- // (core createRuntimeApprovalRequest passthrough) so native runtime
396
- // approvals keep their tool name, detail rows, correlation handles and
397
- // allow-always affordance through the bridge.
398
- params: conversationScoped.extend({
399
- detail: z.string(),
400
- risk: HitlApprovalRiskSchema,
401
- category: HitlApprovalCategorySchema,
402
- expiresAt: z.string().optional(),
403
- approvalId: z.string().optional(),
404
- /** Card header tool name; defaults to the category. */
405
- toolName: z.string().optional(),
406
- riskLevel: z.enum(['normal', 'destructive']).optional(),
407
- details: z.array(HitlApprovalDetailSchema).optional(),
408
- /** File-change preview (CanonUnifiedDiff) — opaque pass-through. */
409
- diff: z.record(z.string(), z.unknown()).optional(),
410
- /** Native runtime correlation handles — opaque pass-through. */
411
- native: z.record(z.string(), z.unknown()).optional(),
412
- turnId: z.string().optional(),
413
- runtimeId: z.string().optional(),
414
- /** Offer the "always allow" session-rule affordance on the card. */
415
- allowSessionRule: z.boolean().optional(),
416
- responseUserId: z.string().nullable().optional(),
417
- }),
418
- result: HitlRequestAcceptedSchema,
419
- },
420
- requestInput: {
421
- params: conversationScoped.extend({
422
- questions: z.array(HitlInputQuestionSchema),
423
- expiresAt: z.string().optional(),
424
- inputId: z.string().optional(),
425
- title: z.string().optional(),
426
- prompt: z.string().optional(),
427
- kind: HitlInputKindSchema.optional(),
428
- sensitive: z.boolean().optional(),
429
- native: z.record(z.string(), z.unknown()).optional(),
430
- turnId: z.string().optional(),
431
- responseUserId: z.string().nullable().optional(),
432
- }),
433
- result: HitlRequestAcceptedSchema,
434
- },
435
- requestCard: {
436
- params: conversationScoped.extend({
437
- /** canon.card.v1 content — opaque pass-through. */
438
- card: z.record(z.string(), z.unknown()),
439
- expiresAt: z.string().optional(),
440
- cardId: z.string().optional(),
441
- native: z.record(z.string(), z.unknown()).optional(),
442
- turnId: z.string().optional(),
443
- responseUserId: z.string().nullable().optional(),
444
- }),
445
- result: HitlRequestAcceptedSchema,
446
- },
447
- getHitlState: {
448
- params: z.object({ requestId: z.string() }),
449
- result: BridgeHitlStateSchema,
450
- },
451
- cancelHitl: { params: z.object({ requestId: z.string() }), result: OkResultSchema },
452
- // §B8 media (named schemas above — the bridge + Framework share them)
453
- uploadMedia: {
454
- params: BridgeUploadMediaParamsSchema,
455
- result: UploadMediaResponseSchema,
456
- },
457
- getAttachment: {
458
- params: BridgeGetAttachmentParamsSchema,
459
- result: BridgeGetAttachmentResultSchema,
460
- },
461
- // §B9 voice (media stays client↔LiveKit; bridge brokers the token).
462
- // Code-grounded correction (B4.3): every /voice/sessions/:id REST op
463
- // requires the conversationId (body or query) — the session doc lives
464
- // under the conversation — so the session-scoped methods carry it too.
465
- createVoiceSession: {
466
- params: conversationScoped.extend({ targetAgentId: z.string().optional() }),
467
- result: z.looseObject({ sessionId: z.string() }),
468
- },
469
- joinVoiceSession: {
470
- params: z.object({ sessionId: z.string(), conversationId: z.string() }),
471
- result: z.looseObject({ url: z.string(), token: z.string() }),
472
- },
473
- endVoiceSession: {
474
- params: z.object({ sessionId: z.string(), conversationId: z.string() }),
475
- result: OkResultSchema,
476
- },
477
- getVoiceSession: {
478
- params: z.object({ sessionId: z.string(), conversationId: z.string() }),
479
- result: SseVoiceSessionEventPayloadSchema,
480
- },
481
- // §B10 registration / identity
482
- getAgent: {
483
- params: z.object({}),
484
- result: z.object({
485
- agentId: z.string(),
486
- agentName: z.string(),
487
- context: SseAgentContextPayloadSchema,
488
- }),
489
- },
490
- register: {
491
- params: z.record(z.string(), z.unknown()),
492
- // pollToken (when issued) authorizes subsequent status polls.
493
- result: z.object({ requestId: z.string(), pollToken: z.string().optional() }),
494
- },
495
- getRegistrationStatus: {
496
- // `baseUrl` (B6.1 additive) supports the pre-identity bootstrap: the
497
- // registration statics are unauthenticated, so a stub-identity bridge
498
- // can serve them with an explicit endpoint.
499
- params: z.object({
500
- requestId: z.string(),
501
- pollToken: z.string().optional(),
502
- baseUrl: z.string().optional(),
503
- }),
504
- result: z.looseObject({ status: z.string() }),
505
- },
506
- /**
507
- * Acknowledge one-time API-key delivery after an approved registration
508
- * (POST /agents/status/:id/ack). Best-effort on the wire; failures surface
509
- * as upstream-band errors. Additive union of Phase 5 + P6 openclaw: the
510
- * Hermes port consumed it through the GENERIC Python escape hatch first
511
- * (a bridge-side method addition with zero framework-py release), and
512
- * `baseUrl` (B6.1) supports the wizard's per-call pre-identity bootstrap.
513
- */
514
- ackRegistrationStatus: {
515
- params: z.object({
516
- requestId: z.string(),
517
- pollToken: z.string().optional(),
518
- baseUrl: z.string().optional(),
519
- }),
520
- result: OkResultSchema,
521
- },
522
- // §5b host-profile surface (bridge-execution-plan Phase 4 step 5b) —
523
- // additive methods for process-executing (host-mode) adapters, beyond §B.
524
- // Shapes mirror @canonmsg/core host-runtime-wire.ts; runtime payloads are
525
- // opaque pass-through (AgentRuntime).
526
- publishHostAgentRuntime: {
527
- params: z.object({
528
- /** Defaults to the hello clientType. */
529
- clientType: z.string().optional(),
530
- /** AgentRuntime — opaque pass-through. */
531
- runtime: z.record(z.string(), z.unknown()),
532
- }),
533
- result: OkResultSchema,
534
- },
535
- publishHostSessionSnapshots: {
536
- params: z.object({
537
- conversationIds: z.array(z.string()),
538
- /** Defaults to the hello clientType. */
539
- clientType: z.string().optional(),
540
- /** AgentRuntime — opaque pass-through. */
541
- runtime: z.record(z.string(), z.unknown()),
542
- workspaceOptions: z.array(z.object({ id: z.string(), cwd: z.string() })).optional(),
543
- defaultCwd: z.string().optional(),
544
- extraSessionConfigFields: z.array(z.string()).optional(),
545
- /** conversationId → live session-config overrides (JSON'd Map). */
546
- liveSessionConfigByConversation: z
547
- .record(z.string(), z.record(z.string(), z.unknown()))
548
- .optional(),
549
- }),
550
- result: OkResultSchema,
551
- },
552
- // §5b host-profile surface, P6 additions (bridge-execution-plan Phase 6) —
553
- // the remaining RTDB planes the process-executing hosts touched directly
554
- // until now: the per-conversation session-state node, its config read, and
555
- // the terminal clears. Payloads mirror @canonmsg/core rtdb-rest.ts shapes
556
- // as opaque pass-through; the bridge executes them through the core
557
- // runtime-state publisher (hostMode) over its single RTDB handle.
558
- getSessionConfig: {
559
- params: conversationScoped,
560
- /** Raw `/session-config/{convoId}/{agentId}` node; adapters parse locally. */
561
- result: z.record(z.string(), z.unknown()).nullable(),
562
- },
563
- publishSessionState: {
564
- params: conversationScoped.extend({
565
- /** SessionStatePayload minus updatedAt — opaque pass-through. */
566
- state: z.record(z.string(), z.unknown()),
567
- }),
568
- result: OkResultSchema,
569
- },
570
- clearSessionState: { params: conversationScoped, result: OkResultSchema },
571
- // clearTurnState is defined once under §B6 above (both legs added it; the
572
- // clear is publisher-agnostic so channel adapters and hosts share it).
573
- /**
574
- * Terminal /agent-runtime clear through the HOST publisher. Same RTDB
575
- * effect as §B6.1 clearRuntimeDescriptor (preserve descriptor-bearing
576
- * payloads with updatedAt: 0) — kept as a distinct §5b name because host
577
- * consumers correlate it with the publishHostAgentRuntime plane.
578
- */
579
- clearAgentRuntime: { params: z.object({}), result: OkResultSchema },
580
- };
581
- export const BRIDGE_LOCAL_METHOD_NAMES = Object.keys(BRIDGE_LOCAL_METHODS);
582
- // ── §C Notification registry (bridge → adapter, one-way) ───────────────
583
- export const BRIDGE_LOCAL_NOTIFICATIONS = {
584
- // §A — connection-scoped, never replayed, no cursor
585
- ready: BridgeReadyNotificationSchema,
586
- connectionState: BridgeConnectionStateNotificationSchema,
587
- // §C1 inbound messages (pre-filtered: deduped, self/control stripped)
588
- onMessage: SseMessageCreatedPayloadSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
589
- onMessageUpdated: SseMessageUpdatedPayloadSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
590
- onMessageDeleted: SseMessageDeletedPayloadSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
591
- onConversationUpdated: SseConversationUpdatedPayloadSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
592
- // §C2 control (bridge consumed from RTDB — adapters never poll)
593
- onControlSignal: ControlSignalEventSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
594
- onSessionControl: ControlSessionEventSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
595
- // §C2 addition (P6, both legs): `/control/.../primitive` runtime command
596
- // dispatch (/status, /compact, …) consumed by the bridge poller — adapters
597
- // (openclaw handlers, codex compact) never poll RTDB themselves.
598
- onControlPrimitive: ControlPrimitiveEventSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
599
- // §C6 HITL resolution (durable; matches a §B7 requestId)
600
- onHitlResolved: HitlResolutionSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
601
- onHitlPending: HitlPendingSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
602
- /**
603
- * §C6 addition (P6 host surface): a stripped HITL control-reply message
604
- * (metadata.type approval_reply / plan_approval_reply) that matched NO
605
- * bridge-owned HITL record fans out here instead of being dropped —
606
- * process-executing hosts run reply flows the bridge did not raise
607
- * (claude plan approval is a plain sendMessage + metadata-reply waiter).
608
- * `message` is the serialized Canon message, opaque pass-through.
609
- */
610
- onControlReply: z.object({
611
- conversationId: z.string(),
612
- message: z.record(z.string(), z.unknown()),
613
- }).extend(BRIDGE_EVENT_CURSOR_SHAPE),
614
- // §C3 contacts
615
- onContactChanged: z.object({
616
- kind: z.enum(['request', 'approved', 'added', 'updated', 'removed']),
617
- contact: z.record(z.string(), z.unknown()),
618
- }).extend(BRIDGE_EVENT_CURSOR_SHAPE),
619
- // §C4 typing / presence
620
- onTyping: SseTypingPayloadSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
621
- onPresence: SsePresencePayloadSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
622
- // §C5 voice
623
- onVoiceSessionStarted: SseVoiceSessionEventPayloadSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
624
- onVoiceSessionEnded: SseVoiceSessionEventPayloadSchema.extend(BRIDGE_EVENT_CURSOR_SHAPE),
625
- };
626
- export const BRIDGE_LOCAL_NOTIFICATION_NAMES = Object.keys(BRIDGE_LOCAL_NOTIFICATIONS);
627
- /**
628
- * Event family per §C notification, mirroring SSE_EVENT_FAMILY_BY_TYPE.
629
- * `lifecycle` notifications are connection-scoped and delivered to every
630
- * client; family notifications are filtered by `hello.wantFamilies`
631
- * (`wantFamilies: []` = pure-request adapter, no §C events at all).
632
- */
633
- export const BRIDGE_LOCAL_NOTIFICATION_FAMILIES = {
634
- ready: 'lifecycle',
635
- connectionState: 'lifecycle',
636
- onMessage: 'messages',
637
- onMessageUpdated: 'messages',
638
- onMessageDeleted: 'messages',
639
- onConversationUpdated: 'messages',
640
- onControlSignal: 'runtime_turn',
641
- onSessionControl: 'runtime_turn',
642
- onControlPrimitive: 'runtime_turn',
643
- onHitlResolved: 'runtime_turn',
644
- onHitlPending: 'runtime_turn',
645
- onControlReply: 'runtime_turn',
646
- onContactChanged: 'contacts',
647
- onTyping: 'typing_presence',
648
- onPresence: 'typing_presence',
649
- onVoiceSessionStarted: 'voice',
650
- onVoiceSessionEnded: 'voice',
651
- };
652
- // ── JSON-RPC 2.0 framing ───────────────────────────────────────────────
653
- export const BridgeRpcIdSchema = z.union([z.string(), z.number()]);
654
- export const BridgeRpcRequestSchema = z.object({
655
- jsonrpc: z.literal('2.0'),
656
- id: BridgeRpcIdSchema,
657
- method: z.string(),
658
- params: z.unknown().optional(),
659
- });
660
- export const BridgeRpcNotificationSchema = z.object({
661
- jsonrpc: z.literal('2.0'),
662
- method: z.string(),
663
- params: z.unknown().optional(),
664
- });
665
- export const BridgeRpcErrorSchema = z.object({
666
- code: z.number(),
667
- message: z.string(),
668
- data: z.unknown().optional(),
669
- });
670
- export const BridgeRpcResponseSchema = z.union([
671
- z.object({ jsonrpc: z.literal('2.0'), id: BridgeRpcIdSchema, result: z.unknown() }),
672
- z.object({ jsonrpc: z.literal('2.0'), id: BridgeRpcIdSchema.nullable(), error: BridgeRpcErrorSchema }),
673
- ]);