@byok-sdk/protocol 0.2.0 → 0.4.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.
- package/README.md +7 -0
- package/dist/codec.d.ts +4 -0
- package/dist/envelope.d.ts +75 -0
- package/dist/http-api.d.ts +208 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +133 -3
- package/dist/index.js.map +1 -1
- package/dist/messages.d.ts +304 -2
- package/dist/version.d.ts +35 -1
- package/package.json +1 -1
package/dist/messages.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ export declare const RuntimeCapabilitiesSchema: z.ZodObject<{
|
|
|
34
34
|
steer: z.ZodOptional<z.ZodBoolean>;
|
|
35
35
|
resume: z.ZodOptional<z.ZodBoolean>;
|
|
36
36
|
approvalInteractive: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
+
mcpToolsets: z.ZodOptional<z.ZodBoolean>;
|
|
37
38
|
permissionModes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
38
39
|
}, z.core.$strip>;
|
|
39
40
|
export type RuntimeCapabilities = z.infer<typeof RuntimeCapabilitiesSchema>;
|
|
@@ -54,10 +55,26 @@ export declare const RuntimeInfoSchema: z.ZodObject<{
|
|
|
54
55
|
steer: z.ZodOptional<z.ZodBoolean>;
|
|
55
56
|
resume: z.ZodOptional<z.ZodBoolean>;
|
|
56
57
|
approvalInteractive: z.ZodOptional<z.ZodBoolean>;
|
|
58
|
+
mcpToolsets: z.ZodOptional<z.ZodBoolean>;
|
|
57
59
|
permissionModes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
58
60
|
}, z.core.$strip>>;
|
|
59
61
|
}, z.core.$strip>;
|
|
60
62
|
export type RuntimeInfo = z.infer<typeof RuntimeInfoSchema>;
|
|
63
|
+
/** Maximum logical toolsets one daemon may advertise as locally configured. */
|
|
64
|
+
export declare const CONFIGURED_TOOLSETS_MAX_ITEMS = 64;
|
|
65
|
+
/**
|
|
66
|
+
* Logical, host-owned MCP toolset identifier. A task may request this name,
|
|
67
|
+
* but the executable/server definition behind it exists only in the daemon's
|
|
68
|
+
* local configuration and never crosses the SaaS wire.
|
|
69
|
+
*/
|
|
70
|
+
export declare const ToolsetIdSchema: z.ZodString;
|
|
71
|
+
export type ToolsetId = z.infer<typeof ToolsetIdSchema>;
|
|
72
|
+
/**
|
|
73
|
+
* Device-local inventory projected for discovery. IDs only: executable MCP
|
|
74
|
+
* definitions, arguments, environment and credentials never enter this shape.
|
|
75
|
+
* Empty means known-none; omission on the containing message means unknown.
|
|
76
|
+
*/
|
|
77
|
+
export declare const ConfiguredToolsetsSchema: z.ZodArray<z.ZodString>;
|
|
61
78
|
/** daemon -> server: opening handshake. */
|
|
62
79
|
export declare const ConnHelloPayloadSchema: z.ZodObject<{
|
|
63
80
|
protocolVersions: z.ZodArray<z.ZodNumber>;
|
|
@@ -76,9 +93,11 @@ export declare const ConnHelloPayloadSchema: z.ZodObject<{
|
|
|
76
93
|
steer: z.ZodOptional<z.ZodBoolean>;
|
|
77
94
|
resume: z.ZodOptional<z.ZodBoolean>;
|
|
78
95
|
approvalInteractive: z.ZodOptional<z.ZodBoolean>;
|
|
96
|
+
mcpToolsets: z.ZodOptional<z.ZodBoolean>;
|
|
79
97
|
permissionModes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
80
98
|
}, z.core.$strip>>;
|
|
81
99
|
}, z.core.$strip>>>;
|
|
100
|
+
configuredToolsets: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
82
101
|
cursor: z.ZodOptional<z.ZodNumber>;
|
|
83
102
|
}, z.core.$strip>;
|
|
84
103
|
export type ConnHelloPayload = z.infer<typeof ConnHelloPayloadSchema>;
|
|
@@ -89,6 +108,28 @@ export declare const ConnAckPayloadSchema: z.ZodObject<{
|
|
|
89
108
|
serverTime: z.ZodISODateTime;
|
|
90
109
|
}, z.core.$strip>;
|
|
91
110
|
export type ConnAckPayload = z.infer<typeof ConnAckPayloadSchema>;
|
|
111
|
+
/**
|
|
112
|
+
* The web-selected runtime/model target carried end to end with a task.
|
|
113
|
+
*
|
|
114
|
+
* This is an additive v1 field. The discriminated union makes lane ownership
|
|
115
|
+
* fail closed at decode time: subscription credentials can only belong to the
|
|
116
|
+
* vendor CLIs, while a BYOK provider can only be executed through Pi.
|
|
117
|
+
*/
|
|
118
|
+
export declare const DispatchSelectionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
119
|
+
lane: z.ZodLiteral<"subscription">;
|
|
120
|
+
runtimeId: z.ZodEnum<{
|
|
121
|
+
claude: "claude";
|
|
122
|
+
codex: "codex";
|
|
123
|
+
}>;
|
|
124
|
+
providerId: z.ZodNull;
|
|
125
|
+
modelId: z.ZodString;
|
|
126
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
127
|
+
lane: z.ZodLiteral<"byok">;
|
|
128
|
+
runtimeId: z.ZodLiteral<"pi">;
|
|
129
|
+
providerId: z.ZodString;
|
|
130
|
+
modelId: z.ZodString;
|
|
131
|
+
}, z.core.$strict>], "lane">;
|
|
132
|
+
export type DispatchSelection = z.infer<typeof DispatchSelectionSchema>;
|
|
92
133
|
/**
|
|
93
134
|
* server -> daemon: offer a task for a device to claim.
|
|
94
135
|
*
|
|
@@ -122,6 +163,20 @@ export declare const TaskOfferPayloadSchema: z.ZodObject<{
|
|
|
122
163
|
codex: "codex";
|
|
123
164
|
pi: "pi";
|
|
124
165
|
}>>;
|
|
166
|
+
dispatchSelection: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
167
|
+
lane: z.ZodLiteral<"subscription">;
|
|
168
|
+
runtimeId: z.ZodEnum<{
|
|
169
|
+
claude: "claude";
|
|
170
|
+
codex: "codex";
|
|
171
|
+
}>;
|
|
172
|
+
providerId: z.ZodNull;
|
|
173
|
+
modelId: z.ZodString;
|
|
174
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
175
|
+
lane: z.ZodLiteral<"byok">;
|
|
176
|
+
runtimeId: z.ZodLiteral<"pi">;
|
|
177
|
+
providerId: z.ZodString;
|
|
178
|
+
modelId: z.ZodString;
|
|
179
|
+
}, z.core.$strict>], "lane">>;
|
|
125
180
|
sessionRef: z.ZodOptional<z.ZodString>;
|
|
126
181
|
workspaceHint: z.ZodOptional<z.ZodString>;
|
|
127
182
|
limits: z.ZodOptional<z.ZodObject<{
|
|
@@ -130,6 +185,66 @@ export declare const TaskOfferPayloadSchema: z.ZodObject<{
|
|
|
130
185
|
}, z.core.$strip>>;
|
|
131
186
|
}, z.core.$strip>;
|
|
132
187
|
export type TaskOfferPayload = z.infer<typeof TaskOfferPayloadSchema>;
|
|
188
|
+
/** Every named toolset is required; duplicates are rejected instead of silently de-duplicated. */
|
|
189
|
+
export declare const RequiredToolsetsSchema: z.ZodArray<z.ZodString>;
|
|
190
|
+
/**
|
|
191
|
+
* Additive v1 offer variant for tasks whose semantics require local MCP
|
|
192
|
+
* tools. This is a distinct message type rather than an optional field on
|
|
193
|
+
* `task.offer`: an older v1 daemon skips an unknown message type, whereas it
|
|
194
|
+
* would legally strip an unknown optional control field and run the task
|
|
195
|
+
* without its required tools. The whole payload is strict because every
|
|
196
|
+
* field here affects execution authority.
|
|
197
|
+
*/
|
|
198
|
+
export declare const TaskOfferWithToolsetsPayloadSchema: z.ZodObject<{
|
|
199
|
+
instruction: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
200
|
+
blobRef: z.ZodObject<{
|
|
201
|
+
blobId: z.ZodString;
|
|
202
|
+
contentHash: z.ZodString;
|
|
203
|
+
size: z.ZodNumber;
|
|
204
|
+
contentType: z.ZodString;
|
|
205
|
+
url: z.ZodOptional<z.ZodString>;
|
|
206
|
+
}, z.core.$strip>;
|
|
207
|
+
}, z.core.$strict>]>;
|
|
208
|
+
policy: z.ZodObject<{
|
|
209
|
+
mode: z.ZodEnum<{
|
|
210
|
+
auto: "auto";
|
|
211
|
+
confirm: "confirm";
|
|
212
|
+
plan: "plan";
|
|
213
|
+
readonly: "readonly";
|
|
214
|
+
}>;
|
|
215
|
+
allowTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
216
|
+
denyTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
217
|
+
workspaceRoot: z.ZodOptional<z.ZodString>;
|
|
218
|
+
network: z.ZodOptional<z.ZodBoolean>;
|
|
219
|
+
}, z.core.$strict>;
|
|
220
|
+
runtime: z.ZodOptional<z.ZodEnum<{
|
|
221
|
+
claude: "claude";
|
|
222
|
+
codex: "codex";
|
|
223
|
+
pi: "pi";
|
|
224
|
+
}>>;
|
|
225
|
+
dispatchSelection: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
226
|
+
lane: z.ZodLiteral<"subscription">;
|
|
227
|
+
runtimeId: z.ZodEnum<{
|
|
228
|
+
claude: "claude";
|
|
229
|
+
codex: "codex";
|
|
230
|
+
}>;
|
|
231
|
+
providerId: z.ZodNull;
|
|
232
|
+
modelId: z.ZodString;
|
|
233
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
234
|
+
lane: z.ZodLiteral<"byok">;
|
|
235
|
+
runtimeId: z.ZodLiteral<"pi">;
|
|
236
|
+
providerId: z.ZodString;
|
|
237
|
+
modelId: z.ZodString;
|
|
238
|
+
}, z.core.$strict>], "lane">>;
|
|
239
|
+
sessionRef: z.ZodOptional<z.ZodString>;
|
|
240
|
+
workspaceHint: z.ZodOptional<z.ZodString>;
|
|
241
|
+
limits: z.ZodOptional<z.ZodObject<{
|
|
242
|
+
maxDurationMs: z.ZodOptional<z.ZodNumber>;
|
|
243
|
+
maxTokens: z.ZodOptional<z.ZodNumber>;
|
|
244
|
+
}, z.core.$strip>>;
|
|
245
|
+
requiredToolsets: z.ZodArray<z.ZodString>;
|
|
246
|
+
}, z.core.$strict>;
|
|
247
|
+
export type TaskOfferWithToolsetsPayload = z.infer<typeof TaskOfferWithToolsetsPayloadSchema>;
|
|
133
248
|
/**
|
|
134
249
|
* server -> daemon: approve a pending `task.await_approval` request.
|
|
135
250
|
*
|
|
@@ -241,6 +356,7 @@ export declare const TaskClaimPayloadSchema: z.ZodObject<{
|
|
|
241
356
|
steer: z.ZodOptional<z.ZodBoolean>;
|
|
242
357
|
resume: z.ZodOptional<z.ZodBoolean>;
|
|
243
358
|
approvalInteractive: z.ZodOptional<z.ZodBoolean>;
|
|
359
|
+
mcpToolsets: z.ZodOptional<z.ZodBoolean>;
|
|
244
360
|
permissionModes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
245
361
|
}, z.core.$strip>>;
|
|
246
362
|
}, z.core.$strip>;
|
|
@@ -356,7 +472,125 @@ export declare const TaskAwaitApprovalPayloadSchema: z.ZodObject<{
|
|
|
356
472
|
approvalId: z.ZodOptional<z.ZodString>;
|
|
357
473
|
}, z.core.$strip>;
|
|
358
474
|
export type TaskAwaitApprovalPayload = z.infer<typeof TaskAwaitApprovalPayloadSchema>;
|
|
359
|
-
/**
|
|
475
|
+
/**
|
|
476
|
+
* Hard cap (1 MiB) on a single `task.complete.document` (see
|
|
477
|
+
* {@link TaskCompletePayloadSchema}), measured as the UTF-8 byte length of
|
|
478
|
+
* its canonical JSON encoding — NOT as a node/key count, since a document is
|
|
479
|
+
* schema-neutral and its object shape is unbounded by design.
|
|
480
|
+
*
|
|
481
|
+
* The cap is a REJECT-AT-BOUNDARY limit on both sides: a daemon that
|
|
482
|
+
* produces an over-cap document reports `task.fail` instead of sending it,
|
|
483
|
+
* and a server rejects an over-cap document at schema validation. It is
|
|
484
|
+
* never truncated — a truncated JSON document is not valid JSON, so
|
|
485
|
+
* "shrinking to fit" can only hand the consumer garbage.
|
|
486
|
+
*
|
|
487
|
+
* 1 MiB is the conservative ceiling declared by the first real consumer
|
|
488
|
+
* (`docs/researches/2026-08-12-salesko-consumption-evidence.md` §1/§2:
|
|
489
|
+
* smallest real frame 8.4 KiB, typical 48-96 KiB, 512 KiB comfortable).
|
|
490
|
+
* Producers should stay at or under ~512 KiB (docs/protocol.md); the extra
|
|
491
|
+
* headroom exists because raising a protocol cap later is additive while
|
|
492
|
+
* lowering one is breaking. A result too big for this channel belongs in
|
|
493
|
+
* `artifactRefs` (the multi-file/binary/oversized channel), not here.
|
|
494
|
+
*/
|
|
495
|
+
export declare const RESULT_DOCUMENT_MAX_BYTES = 1048576;
|
|
496
|
+
/**
|
|
497
|
+
* Outcome of {@link checkResultDocument}.
|
|
498
|
+
*
|
|
499
|
+
* `bytes` is the measured canonical JSON UTF-8 byte length, present on both
|
|
500
|
+
* the accept and the over-cap rejection so a caller can name the actual size
|
|
501
|
+
* in a failure reason. `canonical` is the CANONICAL SNAPSHOT — the value a
|
|
502
|
+
* sender must actually put on the wire; see {@link checkResultDocument}.
|
|
503
|
+
*/
|
|
504
|
+
export type ResultDocumentCheck = {
|
|
505
|
+
readonly ok: true;
|
|
506
|
+
readonly bytes: number;
|
|
507
|
+
readonly canonical: unknown;
|
|
508
|
+
} | {
|
|
509
|
+
readonly ok: false;
|
|
510
|
+
readonly reason: 'not-serializable';
|
|
511
|
+
} | {
|
|
512
|
+
readonly ok: false;
|
|
513
|
+
readonly reason: 'over-cap';
|
|
514
|
+
readonly bytes: number;
|
|
515
|
+
} | {
|
|
516
|
+
readonly ok: false;
|
|
517
|
+
readonly reason: 'not-plain-json';
|
|
518
|
+
};
|
|
519
|
+
/**
|
|
520
|
+
* THE single authority for "is this a legal `task.complete.document`", and
|
|
521
|
+
* the one place its canonical form is produced. `TaskCompletePayloadSchema`'s
|
|
522
|
+
* own refinement calls it, and the daemon-side pre-send gate
|
|
523
|
+
* (`packages/client`'s `task-runner.ts`) imports and calls the exact same
|
|
524
|
+
* function rather than re-deriving any part of it: a daemon that measured or
|
|
525
|
+
* judged a document even slightly differently from the server that validates
|
|
526
|
+
* it would either reject documents the wire would have accepted, or hand the
|
|
527
|
+
* server a payload it is about to reject after the runtime session already
|
|
528
|
+
* ended.
|
|
529
|
+
*
|
|
530
|
+
* **The contract is: a document must be PLAIN JSON DATA.** Not "an object
|
|
531
|
+
* that happens to survive `JSON.stringify`" — that bar is far too low, and
|
|
532
|
+
* two concrete attacks/mistakes live under it:
|
|
533
|
+
*
|
|
534
|
+
* 1. `JSON.stringify` succeeding does not mean the value was preserved. An
|
|
535
|
+
* `undefined`-valued key, a `NaN`, a function-valued property, or a
|
|
536
|
+
* `Date` all serialize "successfully" while silently becoming something
|
|
537
|
+
* else (dropped, `null`, or a string). The result is a well-formed,
|
|
538
|
+
* under-cap document that is not what the producer had — a confidently
|
|
539
|
+
* wrong terminal result, the worst outcome this channel has.
|
|
540
|
+
* 2. `toJSON(key)` receives the property key it is being serialized under,
|
|
541
|
+
* so an object can legally answer one way at the root (`key === ''`,
|
|
542
|
+
* where this function measures it) and a completely different way when
|
|
543
|
+
* nested inside the envelope payload (`key === 'document'`, where the
|
|
544
|
+
* codec actually serializes it). A root-only measurement is therefore
|
|
545
|
+
* not a bound on what goes on the wire at all. The same hole exists for
|
|
546
|
+
* any getter that answers differently on a second read.
|
|
547
|
+
*
|
|
548
|
+
* Both die together via the same mechanism. The steps:
|
|
549
|
+
*
|
|
550
|
+
* 1. `JSON.stringify` must succeed and not return `undefined`.
|
|
551
|
+
* 2. Its UTF-8 byte length must be within {@link RESULT_DOCUMENT_MAX_BYTES}.
|
|
552
|
+
* 3. `JSON.parse` that string — the CANONICAL SNAPSHOT. It is pure data:
|
|
553
|
+
* no `toJSON`, no getters, no prototype, nothing left that can answer
|
|
554
|
+
* differently a second time.
|
|
555
|
+
* 4. The original must be structurally equal to the snapshot
|
|
556
|
+
* ({@link isSameJsonData}). Any mismatch means the value was not plain
|
|
557
|
+
* JSON data, and it is rejected rather than silently transformed.
|
|
558
|
+
*
|
|
559
|
+
* On success the snapshot is returned as `canonical`, and **every sender
|
|
560
|
+
* must put THAT on the wire, never the original reference** — which is what
|
|
561
|
+
* closes the contextual-`toJSON`/unstable-getter hole for good: pure data
|
|
562
|
+
* serializes identically at the root and nested, so what was measured is
|
|
563
|
+
* necessarily what is sent. The check is idempotent on pure data, so the
|
|
564
|
+
* server re-running it on an already-parsed payload is a no-op that always
|
|
565
|
+
* agrees.
|
|
566
|
+
*/
|
|
567
|
+
export declare function checkResultDocument(document: unknown): ResultDocumentCheck;
|
|
568
|
+
/**
|
|
569
|
+
* daemon -> server: task finished successfully.
|
|
570
|
+
*
|
|
571
|
+
* `document` (additive-minor, docs/protocol.md "Freeze rule"): the OPTIONAL
|
|
572
|
+
* structured terminal result of the task — one JSON value the product on the
|
|
573
|
+
* other side consumes as the task's actual output, as opposed to `summary`
|
|
574
|
+
* (human-readable prose) or `artifactRefs` (files). Deliberately
|
|
575
|
+
* `z.unknown()`: this SDK never understands, validates, or transforms the
|
|
576
|
+
* product's own document schema — that validation belongs to the consumer.
|
|
577
|
+
* The only constraints the wire imposes are the ones
|
|
578
|
+
* {@link checkResultDocument} enforces: it must be PLAIN JSON DATA (equal to
|
|
579
|
+
* its own JSON round trip — see that function for why "stringify succeeded"
|
|
580
|
+
* is not enough), and its canonical JSON UTF-8 encoding must be at most
|
|
581
|
+
* {@link RESULT_DOCUMENT_MAX_BYTES}. An over-cap document is REJECTED here,
|
|
582
|
+
* never truncated (see that constant's own doc comment). A sender puts the
|
|
583
|
+
* check's `canonical` snapshot on the wire, never the original object.
|
|
584
|
+
*
|
|
585
|
+
* Unlike `approvalId` on `task.await_approval` above, emitting this field IS
|
|
586
|
+
* gated on a capability flag (`result-document`, `version.ts`): a pre-
|
|
587
|
+
* `result-document` server strips it silently as an unknown key (the
|
|
588
|
+
* tolerant `z.object()` behavior §1 mandates), and silently losing the
|
|
589
|
+
* task's primary structured result is not a tolerable degradation the way
|
|
590
|
+
* losing an observability hint is. So a daemon sends `document` only to a
|
|
591
|
+
* server that advertised the flag, and fails the task loudly otherwise —
|
|
592
|
+
* see `packages/client`'s `task-runner.ts`.
|
|
593
|
+
*/
|
|
360
594
|
export declare const TaskCompletePayloadSchema: z.ZodObject<{
|
|
361
595
|
summary: z.ZodString;
|
|
362
596
|
sessionRef: z.ZodString;
|
|
@@ -367,6 +601,7 @@ export declare const TaskCompletePayloadSchema: z.ZodObject<{
|
|
|
367
601
|
contentType: z.ZodString;
|
|
368
602
|
url: z.ZodOptional<z.ZodString>;
|
|
369
603
|
}, z.core.$strip>>>;
|
|
604
|
+
document: z.ZodOptional<z.ZodUnknown>;
|
|
370
605
|
}, z.core.$strip>;
|
|
371
606
|
export type TaskCompletePayload = z.infer<typeof TaskCompletePayloadSchema>;
|
|
372
607
|
/** daemon -> server: task failed. */
|
|
@@ -464,9 +699,11 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
|
|
|
464
699
|
steer: z.ZodOptional<z.ZodBoolean>;
|
|
465
700
|
resume: z.ZodOptional<z.ZodBoolean>;
|
|
466
701
|
approvalInteractive: z.ZodOptional<z.ZodBoolean>;
|
|
702
|
+
mcpToolsets: z.ZodOptional<z.ZodBoolean>;
|
|
467
703
|
permissionModes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
468
704
|
}, z.core.$strip>>;
|
|
469
705
|
}, z.core.$strip>>>;
|
|
706
|
+
configuredToolsets: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
470
707
|
cursor: z.ZodOptional<z.ZodNumber>;
|
|
471
708
|
}, z.core.$strip>;
|
|
472
709
|
readonly 'conn.ack': z.ZodObject<{
|
|
@@ -501,6 +738,20 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
|
|
|
501
738
|
codex: "codex";
|
|
502
739
|
pi: "pi";
|
|
503
740
|
}>>;
|
|
741
|
+
dispatchSelection: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
742
|
+
lane: z.ZodLiteral<"subscription">;
|
|
743
|
+
runtimeId: z.ZodEnum<{
|
|
744
|
+
claude: "claude";
|
|
745
|
+
codex: "codex";
|
|
746
|
+
}>;
|
|
747
|
+
providerId: z.ZodNull;
|
|
748
|
+
modelId: z.ZodString;
|
|
749
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
750
|
+
lane: z.ZodLiteral<"byok">;
|
|
751
|
+
runtimeId: z.ZodLiteral<"pi">;
|
|
752
|
+
providerId: z.ZodString;
|
|
753
|
+
modelId: z.ZodString;
|
|
754
|
+
}, z.core.$strict>], "lane">>;
|
|
504
755
|
sessionRef: z.ZodOptional<z.ZodString>;
|
|
505
756
|
workspaceHint: z.ZodOptional<z.ZodString>;
|
|
506
757
|
limits: z.ZodOptional<z.ZodObject<{
|
|
@@ -508,6 +759,55 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
|
|
|
508
759
|
maxTokens: z.ZodOptional<z.ZodNumber>;
|
|
509
760
|
}, z.core.$strip>>;
|
|
510
761
|
}, z.core.$strip>;
|
|
762
|
+
readonly 'task.offer_with_toolsets': z.ZodObject<{
|
|
763
|
+
instruction: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
764
|
+
blobRef: z.ZodObject<{
|
|
765
|
+
blobId: z.ZodString;
|
|
766
|
+
contentHash: z.ZodString;
|
|
767
|
+
size: z.ZodNumber;
|
|
768
|
+
contentType: z.ZodString;
|
|
769
|
+
url: z.ZodOptional<z.ZodString>;
|
|
770
|
+
}, z.core.$strip>;
|
|
771
|
+
}, z.core.$strict>]>;
|
|
772
|
+
policy: z.ZodObject<{
|
|
773
|
+
mode: z.ZodEnum<{
|
|
774
|
+
auto: "auto";
|
|
775
|
+
confirm: "confirm";
|
|
776
|
+
plan: "plan";
|
|
777
|
+
readonly: "readonly";
|
|
778
|
+
}>;
|
|
779
|
+
allowTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
780
|
+
denyTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
781
|
+
workspaceRoot: z.ZodOptional<z.ZodString>;
|
|
782
|
+
network: z.ZodOptional<z.ZodBoolean>;
|
|
783
|
+
}, z.core.$strict>;
|
|
784
|
+
runtime: z.ZodOptional<z.ZodEnum<{
|
|
785
|
+
claude: "claude";
|
|
786
|
+
codex: "codex";
|
|
787
|
+
pi: "pi";
|
|
788
|
+
}>>;
|
|
789
|
+
dispatchSelection: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
790
|
+
lane: z.ZodLiteral<"subscription">;
|
|
791
|
+
runtimeId: z.ZodEnum<{
|
|
792
|
+
claude: "claude";
|
|
793
|
+
codex: "codex";
|
|
794
|
+
}>;
|
|
795
|
+
providerId: z.ZodNull;
|
|
796
|
+
modelId: z.ZodString;
|
|
797
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
798
|
+
lane: z.ZodLiteral<"byok">;
|
|
799
|
+
runtimeId: z.ZodLiteral<"pi">;
|
|
800
|
+
providerId: z.ZodString;
|
|
801
|
+
modelId: z.ZodString;
|
|
802
|
+
}, z.core.$strict>], "lane">>;
|
|
803
|
+
sessionRef: z.ZodOptional<z.ZodString>;
|
|
804
|
+
workspaceHint: z.ZodOptional<z.ZodString>;
|
|
805
|
+
limits: z.ZodOptional<z.ZodObject<{
|
|
806
|
+
maxDurationMs: z.ZodOptional<z.ZodNumber>;
|
|
807
|
+
maxTokens: z.ZodOptional<z.ZodNumber>;
|
|
808
|
+
}, z.core.$strip>>;
|
|
809
|
+
requiredToolsets: z.ZodArray<z.ZodString>;
|
|
810
|
+
}, z.core.$strict>;
|
|
511
811
|
readonly 'task.approve': z.ZodObject<{
|
|
512
812
|
approvalId: z.ZodOptional<z.ZodString>;
|
|
513
813
|
}, z.core.$strip>;
|
|
@@ -533,6 +833,7 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
|
|
|
533
833
|
steer: z.ZodOptional<z.ZodBoolean>;
|
|
534
834
|
resume: z.ZodOptional<z.ZodBoolean>;
|
|
535
835
|
approvalInteractive: z.ZodOptional<z.ZodBoolean>;
|
|
836
|
+
mcpToolsets: z.ZodOptional<z.ZodBoolean>;
|
|
536
837
|
permissionModes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
537
838
|
}, z.core.$strip>>;
|
|
538
839
|
}, z.core.$strip>;
|
|
@@ -603,6 +904,7 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
|
|
|
603
904
|
contentType: z.ZodString;
|
|
604
905
|
url: z.ZodOptional<z.ZodString>;
|
|
605
906
|
}, z.core.$strip>>>;
|
|
907
|
+
document: z.ZodOptional<z.ZodUnknown>;
|
|
606
908
|
}, z.core.$strip>;
|
|
607
909
|
readonly 'task.fail': z.ZodObject<{
|
|
608
910
|
reason: z.ZodString;
|
|
@@ -630,7 +932,7 @@ export declare const MESSAGE_TYPES: MessageType[];
|
|
|
630
932
|
* (`envelope.ts`) to decide which branches require envelope `seq` (M1
|
|
631
933
|
* redelivery cursor).
|
|
632
934
|
*/
|
|
633
|
-
export declare const SERVER_TO_DAEMON_TYPES: readonly ["conn.ack", "task.offer", "task.approve", "task.reject", "task.cancel", "task.steer"];
|
|
935
|
+
export declare const SERVER_TO_DAEMON_TYPES: readonly ["conn.ack", "task.offer", "task.offer_with_toolsets", "task.approve", "task.reject", "task.cancel", "task.steer"];
|
|
634
936
|
/**
|
|
635
937
|
* Message types the daemon sends to the server — the flip side of
|
|
636
938
|
* {@link SERVER_TO_DAEMON_TYPES}. `conn.hello` is deliberately excluded: it's
|
package/dist/version.d.ts
CHANGED
|
@@ -66,5 +66,39 @@ export declare const PROTOCOL_VERSION = 1;
|
|
|
66
66
|
* participate in targeting at all -- the same N/N-1-safe shape as every
|
|
67
67
|
* other flag here, just consumed for observability instead of gating.
|
|
68
68
|
*/
|
|
69
|
-
|
|
69
|
+
/**
|
|
70
|
+
* `result-document` (additive-minor): a SERVER-advertised flag meaning "I
|
|
71
|
+
* understand the optional `task.complete.document` field" (`messages.ts`).
|
|
72
|
+
* Functionally gating, like `approval_resolved` and unlike
|
|
73
|
+
* `approval-targeting`.
|
|
74
|
+
*
|
|
75
|
+
* This is the N/N-1 answer for that new daemon -> server FIELD. An old
|
|
76
|
+
* server's `CAPABILITY_FLAGS`/`conn.ack.capabilities` never includes it, and
|
|
77
|
+
* its `TaskCompletePayloadSchema` is a tolerant (non-`.strict()`)
|
|
78
|
+
* `z.object()`, so a `document` sent to it would be silently STRIPPED on
|
|
79
|
+
* parse and vanish without a trace. That is exactly why emission is gated
|
|
80
|
+
* here rather than sent unconditionally the way `approvalId` is: `document`
|
|
81
|
+
* carries the task's primary structured RESULT, so losing it silently is
|
|
82
|
+
* data loss, not a missed observability hint. A new daemon talking to an old
|
|
83
|
+
* server therefore never sends `document` at all, and — if its configured
|
|
84
|
+
* extractor did produce one — reports `task.fail` (retryable: false; the
|
|
85
|
+
* same server will strip it on every retry too) instead of completing the
|
|
86
|
+
* task with its main result quietly deleted (`packages/client`'s
|
|
87
|
+
* `task-runner.ts`). A new server talking to an old daemon is unaffected:
|
|
88
|
+
* the field is optional, and an old daemon simply never sets it.
|
|
89
|
+
*
|
|
90
|
+
* `dispatch-selection` (additive-minor) is a correctness gate for the
|
|
91
|
+
* optional `task.offer.dispatchSelection` control field. An older v1 daemon
|
|
92
|
+
* legally strips unknown optional fields, so a server must never send an
|
|
93
|
+
* authoritative provider/model selection unless the target connection
|
|
94
|
+
* advertises this flag. Absence means reject before task creation, not send
|
|
95
|
+
* a legacy runtime-only offer that could reach a different provider.
|
|
96
|
+
*
|
|
97
|
+
* `toolset-selection` (additive-minor) means the daemon understands
|
|
98
|
+
* `task.offer_with_toolsets` and can resolve its logical ids against local
|
|
99
|
+
* MCP configuration. The distinct message type is also the N/N-1 safety
|
|
100
|
+
* boundary for long-poll: an older daemon skips it as unknown and therefore
|
|
101
|
+
* cannot accidentally execute the instruction without the required tools.
|
|
102
|
+
*/
|
|
103
|
+
export declare const CAPABILITY_FLAGS: readonly ['steer', 'blob-upload', 'interactive-approval', 'approval_resolved', 'approval-targeting', 'result-document', 'dispatch-selection', 'toolset-selection'];
|
|
70
104
|
export type CapabilityFlag = (typeof CAPABILITY_FLAGS)[number];
|