@byok-sdk/protocol 0.26.1 → 0.27.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.
@@ -1,28 +1,4 @@
1
1
  import { z } from 'zod';
2
- export { INPUT_PREPARATION_WIRE_VERSION } from './input-preparation-version';
3
- /**
4
- * Capability required before a task-free remote input preparation — or a
5
- * prepared Execution — is admitted: `agent-input-preparation-v<N>`, where
6
- * `<N>` is {@link INPUT_PREPARATION_WIRE_VERSION}.
7
- *
8
- * The version is IN the token because the relay wire has none. A device
9
- * declares exactly the one token of the contract it speaks, and a cloud admits
10
- * exactly the one token of the contract it speaks, so a device and a cloud on
11
- * different contract versions never exchange a preparation at all: the cloud
12
- * refuses at enqueue (`agent_capability_missing`, before any receipt or
13
- * mailbox row) instead of relaying a payload the other side would refuse with
14
- * a strict-schema 422 and a device would then redeliver forever. There is no
15
- * dual token and no accepted older one. The retired unversioned token
16
- * `agent-input-preparation` (versions up to 4) is admitted nowhere.
17
- *
18
- * The token gates NEW admissions only. A row enqueued before a version cut is
19
- * still in flight afterwards, and its completion is accepted only by a cloud
20
- * on the same version as the device answering it; across the cut it is a 422
21
- * and a stalled device cursor. Draining in-flight rows and upgrading cloud and
22
- * devices as a pair is the operator precondition for the cut (`docs/spec.md`,
23
- * bounded admission); nothing here parses an older receipt.
24
- */
25
- export declare const AGENT_INPUT_PREPARATION_CAPABILITY: "agent-input-preparation-v9";
26
2
  /** The preparation surface uses the package-wide lowercase `sha256:<hex>` transport form. */
27
3
  export declare const InputPreparationContentHashSchema: z.ZodString;
28
4
  /**
@@ -577,6 +553,13 @@ export declare const InputPreparationArtifactSummarySchema: z.ZodObject<{
577
553
  }, z.core.$strict>;
578
554
  /** The immutable binding a receipt carries and a later consumer must re-present. */
579
555
  export declare const InputPreparationBindingSchema: z.ZodObject<{
556
+ terminalProjection: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
557
+ mode: z.ZodLiteral<"none">;
558
+ }, z.core.$strict>, z.ZodObject<{
559
+ mode: z.ZodLiteral<"result-document">;
560
+ contract: z.ZodString;
561
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
562
+ }, z.core.$strict>], "mode">>;
580
563
  agentMemory: z.ZodEnum<{
581
564
  none: "none";
582
565
  read: "read";
@@ -636,6 +619,13 @@ export declare const InputPreparationReceiptSummarySchema: z.ZodObject<{
636
619
  reserved: "reserved";
637
620
  }>;
638
621
  binding: z.ZodObject<{
622
+ terminalProjection: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
623
+ mode: z.ZodLiteral<"none">;
624
+ }, z.core.$strict>, z.ZodObject<{
625
+ mode: z.ZodLiteral<"result-document">;
626
+ contract: z.ZodString;
627
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
628
+ }, z.core.$strict>], "mode">>;
639
629
  agentMemory: z.ZodEnum<{
640
630
  none: "none";
641
631
  read: "read";
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { type PlainJsonCheck } from './plain-json';
2
3
  export declare const RuntimeIdSchema: z.ZodEnum<{
3
4
  claude: "claude";
4
5
  codex: "codex";
@@ -27,6 +28,7 @@ export declare const RuntimeCapabilitiesSchema: z.ZodObject<{
27
28
  resume: z.ZodOptional<z.ZodBoolean>;
28
29
  approvalInteractive: z.ZodOptional<z.ZodBoolean>;
29
30
  mcpToolsets: z.ZodOptional<z.ZodBoolean>;
31
+ messageDraft: z.ZodOptional<z.ZodBoolean>;
30
32
  }, z.core.$strip>;
31
33
  export type RuntimeCapabilities = z.infer<typeof RuntimeCapabilitiesSchema>;
32
34
  /**
@@ -47,6 +49,7 @@ export declare const RuntimeInfoSchema: z.ZodObject<{
47
49
  resume: z.ZodOptional<z.ZodBoolean>;
48
50
  approvalInteractive: z.ZodOptional<z.ZodBoolean>;
49
51
  mcpToolsets: z.ZodOptional<z.ZodBoolean>;
52
+ messageDraft: z.ZodOptional<z.ZodBoolean>;
50
53
  }, z.core.$strip>>;
51
54
  }, z.core.$strip>;
52
55
  export type RuntimeInfo = z.infer<typeof RuntimeInfoSchema>;
@@ -61,6 +64,7 @@ export declare const HarnessInfoSchema: z.ZodObject<{
61
64
  resume: z.ZodOptional<z.ZodBoolean>;
62
65
  approvalInteractive: z.ZodOptional<z.ZodBoolean>;
63
66
  mcpToolsets: z.ZodOptional<z.ZodBoolean>;
67
+ messageDraft: z.ZodOptional<z.ZodBoolean>;
64
68
  }, z.core.$strip>;
65
69
  }, z.core.$strip>;
66
70
  export type HarnessInfo = z.infer<typeof HarnessInfoSchema>;
@@ -72,6 +76,7 @@ export declare const HarnessInventorySchema: z.ZodArray<z.ZodObject<{
72
76
  resume: z.ZodOptional<z.ZodBoolean>;
73
77
  approvalInteractive: z.ZodOptional<z.ZodBoolean>;
74
78
  mcpToolsets: z.ZodOptional<z.ZodBoolean>;
79
+ messageDraft: z.ZodOptional<z.ZodBoolean>;
75
80
  }, z.core.$strip>;
76
81
  }, z.core.$strip>>;
77
82
  /** Maximum logical toolsets one daemon may advertise as locally configured. */
@@ -126,6 +131,7 @@ export declare const ConnHelloPayloadSchema: z.ZodObject<{
126
131
  resume: z.ZodOptional<z.ZodBoolean>;
127
132
  approvalInteractive: z.ZodOptional<z.ZodBoolean>;
128
133
  mcpToolsets: z.ZodOptional<z.ZodBoolean>;
134
+ messageDraft: z.ZodOptional<z.ZodBoolean>;
129
135
  }, z.core.$strip>>;
130
136
  }, z.core.$strip>>>;
131
137
  harnesses: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -136,6 +142,7 @@ export declare const ConnHelloPayloadSchema: z.ZodObject<{
136
142
  resume: z.ZodOptional<z.ZodBoolean>;
137
143
  approvalInteractive: z.ZodOptional<z.ZodBoolean>;
138
144
  mcpToolsets: z.ZodOptional<z.ZodBoolean>;
145
+ messageDraft: z.ZodOptional<z.ZodBoolean>;
139
146
  }, z.core.$strip>;
140
147
  }, z.core.$strip>>>;
141
148
  configuredToolsets: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -372,6 +379,7 @@ export declare const TaskOfferForAgentPayloadSchema: z.ZodObject<{
372
379
  }, z.core.$strict>, z.ZodObject<{
373
380
  mode: z.ZodLiteral<"result-document">;
374
381
  contract: z.ZodString;
382
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
375
383
  }, z.core.$strict>], "mode">>;
376
384
  sessionRef: z.ZodOptional<z.ZodString>;
377
385
  limits: z.ZodOptional<z.ZodObject<{
@@ -438,6 +446,7 @@ export declare const TaskOfferForAgentWithEgressPayloadSchema: z.ZodObject<{
438
446
  }, z.core.$strict>, z.ZodObject<{
439
447
  mode: z.ZodLiteral<"result-document">;
440
448
  contract: z.ZodString;
449
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
441
450
  }, z.core.$strict>], "mode">>;
442
451
  limits: z.ZodOptional<z.ZodObject<{
443
452
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -541,6 +550,7 @@ export declare const TaskOfferForAgentWithEgressFreshPayloadSchema: z.ZodObject<
541
550
  }, z.core.$strict>, z.ZodObject<{
542
551
  mode: z.ZodLiteral<"result-document">;
543
552
  contract: z.ZodString;
553
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
544
554
  }, z.core.$strict>], "mode">>;
545
555
  limits: z.ZodOptional<z.ZodObject<{
546
556
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -648,6 +658,7 @@ export declare const TaskOfferPreparedPayloadSchema: z.ZodObject<{
648
658
  }, z.core.$strict>, z.ZodObject<{
649
659
  mode: z.ZodLiteral<"result-document">;
650
660
  contract: z.ZodString;
661
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
651
662
  }, z.core.$strict>], "mode">>;
652
663
  limits: z.ZodOptional<z.ZodObject<{
653
664
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -730,6 +741,18 @@ export declare const AgentEgressAckPayloadSchema: z.ZodObject<{
730
741
  }, z.core.$strict>;
731
742
  export type AgentEgressAckPayload = z.infer<typeof AgentEgressAckPayloadSchema>;
732
743
  /** Daemon -> server: one Agent-authored message, independent from task activity. */
744
+ /** Display-only text. Offsets count UTF-8 bytes within one revision. */
745
+ export declare const AgentMessageDraftPayloadSchema: z.ZodObject<{
746
+ agentRef: z.ZodObject<{
747
+ agentId: z.ZodString;
748
+ profileRevision: z.ZodString;
749
+ }, z.core.$strict>;
750
+ revision: z.ZodNumber;
751
+ offset: z.ZodNumber;
752
+ text: z.ZodString;
753
+ overflow: z.ZodOptional<z.ZodLiteral<true>>;
754
+ }, z.core.$strict>;
755
+ export type AgentMessageDraftPayload = z.infer<typeof AgentMessageDraftPayloadSchema>;
733
756
  export declare const AgentMessagePublishPayloadSchema: z.ZodObject<{
734
757
  agentRef: z.ZodObject<{
735
758
  agentId: z.ZodString;
@@ -1203,6 +1226,7 @@ export declare const TaskClaimPayloadSchema: z.ZodObject<{
1203
1226
  resume: z.ZodOptional<z.ZodBoolean>;
1204
1227
  approvalInteractive: z.ZodOptional<z.ZodBoolean>;
1205
1228
  mcpToolsets: z.ZodOptional<z.ZodBoolean>;
1229
+ messageDraft: z.ZodOptional<z.ZodBoolean>;
1206
1230
  }, z.core.$strip>>;
1207
1231
  }, z.core.$strip>;
1208
1232
  export type TaskClaimPayload = z.infer<typeof TaskClaimPayloadSchema>;
@@ -1222,7 +1246,7 @@ export type TaskStartedPayload = z.infer<typeof TaskStartedPayloadSchema>;
1222
1246
  * writeup): declining does *not* introduce a new `Declined` terminal state.
1223
1247
  * It maps onto the existing `Failed` state via a new `Offered -> Failed`
1224
1248
  * transition. `reason`/`retryable` intentionally mirror `TaskFailPayload`
1225
- * exactly, because a pre-claim decline and a post-claim failure are the same
1249
+ * semantics, because a pre-claim decline and a post-claim failure are the same
1226
1250
  * outcome from the dispatcher's point of view (this attempt produced no
1227
1251
  * result; here's whether retrying — e.g. offering to a different device —
1228
1252
  * makes sense), and keeping the state machine minimal avoids forking every
@@ -1235,6 +1259,10 @@ export declare const TaskDeclinePayloadSchema: z.ZodObject<{
1235
1259
  agentId: z.ZodString;
1236
1260
  profileRevision: z.ZodString;
1237
1261
  }, z.core.$strict>>;
1262
+ code: z.ZodOptional<z.ZodEnum<{
1263
+ agent_home_reader_busy: "agent_home_reader_busy";
1264
+ agent_home_writer_busy: "agent_home_writer_busy";
1265
+ }>>;
1238
1266
  }, z.core.$strip>;
1239
1267
  export type TaskDeclinePayload = z.infer<typeof TaskDeclinePayloadSchema>;
1240
1268
  /**
@@ -1392,21 +1420,7 @@ export declare const RESULT_DOCUMENT_MAX_BYTES = 1048576;
1392
1420
  * in a failure reason. `canonical` is the CANONICAL SNAPSHOT — the value a
1393
1421
  * sender must actually put on the wire; see {@link checkResultDocument}.
1394
1422
  */
1395
- export type ResultDocumentCheck = {
1396
- readonly ok: true;
1397
- readonly bytes: number;
1398
- readonly canonical: unknown;
1399
- } | {
1400
- readonly ok: false;
1401
- readonly reason: 'not-serializable';
1402
- } | {
1403
- readonly ok: false;
1404
- readonly reason: 'over-cap';
1405
- readonly bytes: number;
1406
- } | {
1407
- readonly ok: false;
1408
- readonly reason: 'not-plain-json';
1409
- };
1423
+ export type ResultDocumentCheck = PlainJsonCheck;
1410
1424
  /**
1411
1425
  * THE single authority for "is this a legal `task.complete.document`", and
1412
1426
  * the one place its canonical form is produced. `TaskCompletePayloadSchema`'s
@@ -1444,7 +1458,7 @@ export type ResultDocumentCheck = {
1444
1458
  * no `toJSON`, no getters, no prototype, nothing left that can answer
1445
1459
  * differently a second time.
1446
1460
  * 4. The original must be structurally equal to the snapshot
1447
- * ({@link isSameJsonData}). Any mismatch means the value was not plain
1461
+ * (`isSameJsonData`, `plain-json.ts`). Any mismatch means the value was not plain
1448
1462
  * JSON data, and it is rejected rather than silently transformed.
1449
1463
  *
1450
1464
  * On success the snapshot is returned as `canonical`, and **every sender
@@ -1566,7 +1580,7 @@ export type TerminalAgentHomeMemoryChange = z.infer<typeof TerminalAgentHomeMemo
1566
1580
  /**
1567
1581
  * daemon -> server: task finished successfully.
1568
1582
  *
1569
- * `document` (additive-minor, docs/protocol.md "Freeze rule"): the OPTIONAL
1583
+ * `document` (docs/protocol.md §7.2): the OPTIONAL
1570
1584
  * structured terminal result of the task — one JSON value the product on the
1571
1585
  * other side consumes as the task's actual output, as opposed to `summary`
1572
1586
  * (human-readable prose) or `artifactRefs` (files). Deliberately
@@ -1580,14 +1594,12 @@ export type TerminalAgentHomeMemoryChange = z.infer<typeof TerminalAgentHomeMemo
1580
1594
  * never truncated (see that constant's own doc comment). A sender puts the
1581
1595
  * check's `canonical` snapshot on the wire, never the original object.
1582
1596
  *
1583
- * Unlike `approvalId` on `task.await_approval` above, emitting this field IS
1584
- * gated on a capability flag (`result-document`, `version.ts`): a pre-
1585
- * `result-document` server strips it silently as an unknown key (the
1586
- * tolerant `z.object()` behavior §1 mandates), and silently losing the
1587
- * task's primary structured result is not a tolerable degradation the way
1588
- * losing an observability hint is. So a daemon sends `document` only to a
1589
- * server that advertised the flag, and fails the task loudly otherwise —
1590
- * see `packages/client`'s `task-runner.ts`.
1597
+ * Wire v3: every v3 server keeps this field, so no capability flag gates it
1598
+ * (the v2 `result-document` flag is gone). For a
1599
+ * `terminalProjection.mode: 'result-document'` offer it carries the outcome
1600
+ * the daemon validated against the offer's frozen schema
1601
+ * (`validateResultOutcome`, `result-schema.ts`, at most
1602
+ * `RESULT_OUTCOME_MAX_BYTES`).
1591
1603
  */
1592
1604
  export declare const TaskCompletePayloadSchema: z.ZodObject<{
1593
1605
  harnessId: z.ZodOptional<z.ZodString>;
@@ -1950,6 +1962,7 @@ declare const TASK_OFFER_PAYLOAD_SCHEMAS: {
1950
1962
  }, z.core.$strict>, z.ZodObject<{
1951
1963
  mode: z.ZodLiteral<"result-document">;
1952
1964
  contract: z.ZodString;
1965
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
1953
1966
  }, z.core.$strict>], "mode">>;
1954
1967
  sessionRef: z.ZodOptional<z.ZodString>;
1955
1968
  limits: z.ZodOptional<z.ZodObject<{
@@ -2010,6 +2023,7 @@ declare const TASK_OFFER_PAYLOAD_SCHEMAS: {
2010
2023
  }, z.core.$strict>, z.ZodObject<{
2011
2024
  mode: z.ZodLiteral<"result-document">;
2012
2025
  contract: z.ZodString;
2026
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
2013
2027
  }, z.core.$strict>], "mode">>;
2014
2028
  limits: z.ZodOptional<z.ZodObject<{
2015
2029
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -2106,6 +2120,7 @@ declare const TASK_OFFER_PAYLOAD_SCHEMAS: {
2106
2120
  }, z.core.$strict>, z.ZodObject<{
2107
2121
  mode: z.ZodLiteral<"result-document">;
2108
2122
  contract: z.ZodString;
2123
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
2109
2124
  }, z.core.$strict>], "mode">>;
2110
2125
  limits: z.ZodOptional<z.ZodObject<{
2111
2126
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -2192,6 +2207,7 @@ declare const TASK_OFFER_PAYLOAD_SCHEMAS: {
2192
2207
  }, z.core.$strict>, z.ZodObject<{
2193
2208
  mode: z.ZodLiteral<"result-document">;
2194
2209
  contract: z.ZodString;
2210
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
2195
2211
  }, z.core.$strict>], "mode">>;
2196
2212
  limits: z.ZodOptional<z.ZodObject<{
2197
2213
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -2402,6 +2418,7 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
2402
2418
  }, z.core.$strict>, z.ZodObject<{
2403
2419
  mode: z.ZodLiteral<"result-document">;
2404
2420
  contract: z.ZodString;
2421
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
2405
2422
  }, z.core.$strict>], "mode">>;
2406
2423
  sessionRef: z.ZodOptional<z.ZodString>;
2407
2424
  limits: z.ZodOptional<z.ZodObject<{
@@ -2462,6 +2479,7 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
2462
2479
  }, z.core.$strict>, z.ZodObject<{
2463
2480
  mode: z.ZodLiteral<"result-document">;
2464
2481
  contract: z.ZodString;
2482
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
2465
2483
  }, z.core.$strict>], "mode">>;
2466
2484
  limits: z.ZodOptional<z.ZodObject<{
2467
2485
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -2558,6 +2576,7 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
2558
2576
  }, z.core.$strict>, z.ZodObject<{
2559
2577
  mode: z.ZodLiteral<"result-document">;
2560
2578
  contract: z.ZodString;
2579
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
2561
2580
  }, z.core.$strict>], "mode">>;
2562
2581
  limits: z.ZodOptional<z.ZodObject<{
2563
2582
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -2644,6 +2663,7 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
2644
2663
  }, z.core.$strict>, z.ZodObject<{
2645
2664
  mode: z.ZodLiteral<"result-document">;
2646
2665
  contract: z.ZodString;
2666
+ schema: z.ZodCustom<import("./result-schema").ResultSchema, import("./result-schema").ResultSchema>;
2647
2667
  }, z.core.$strict>], "mode">>;
2648
2668
  limits: z.ZodOptional<z.ZodObject<{
2649
2669
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -2715,6 +2735,7 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
2715
2735
  resume: z.ZodOptional<z.ZodBoolean>;
2716
2736
  approvalInteractive: z.ZodOptional<z.ZodBoolean>;
2717
2737
  mcpToolsets: z.ZodOptional<z.ZodBoolean>;
2738
+ messageDraft: z.ZodOptional<z.ZodBoolean>;
2718
2739
  }, z.core.$strip>>;
2719
2740
  }, z.core.$strip>>>;
2720
2741
  harnesses: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -2725,6 +2746,7 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
2725
2746
  resume: z.ZodOptional<z.ZodBoolean>;
2726
2747
  approvalInteractive: z.ZodOptional<z.ZodBoolean>;
2727
2748
  mcpToolsets: z.ZodOptional<z.ZodBoolean>;
2749
+ messageDraft: z.ZodOptional<z.ZodBoolean>;
2728
2750
  }, z.core.$strip>;
2729
2751
  }, z.core.$strip>>>;
2730
2752
  configuredToolsets: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -2759,6 +2781,16 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
2759
2781
  cursor: z.ZodNumber;
2760
2782
  receiptId: z.ZodUUID;
2761
2783
  }, z.core.$strict>;
2784
+ readonly 'agent.message.draft': z.ZodObject<{
2785
+ agentRef: z.ZodObject<{
2786
+ agentId: z.ZodString;
2787
+ profileRevision: z.ZodString;
2788
+ }, z.core.$strict>;
2789
+ revision: z.ZodNumber;
2790
+ offset: z.ZodNumber;
2791
+ text: z.ZodString;
2792
+ overflow: z.ZodOptional<z.ZodLiteral<true>>;
2793
+ }, z.core.$strict>;
2762
2794
  readonly 'agent.message.publish': z.ZodObject<{
2763
2795
  agentRef: z.ZodObject<{
2764
2796
  agentId: z.ZodString;
@@ -3103,6 +3135,7 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
3103
3135
  resume: z.ZodOptional<z.ZodBoolean>;
3104
3136
  approvalInteractive: z.ZodOptional<z.ZodBoolean>;
3105
3137
  mcpToolsets: z.ZodOptional<z.ZodBoolean>;
3138
+ messageDraft: z.ZodOptional<z.ZodBoolean>;
3106
3139
  }, z.core.$strip>>;
3107
3140
  }, z.core.$strip>;
3108
3141
  readonly 'task.started': z.ZodObject<{}, z.core.$strip>;
@@ -3113,6 +3146,10 @@ export declare const MESSAGE_PAYLOAD_SCHEMAS: {
3113
3146
  agentId: z.ZodString;
3114
3147
  profileRevision: z.ZodString;
3115
3148
  }, z.core.$strict>>;
3149
+ code: z.ZodOptional<z.ZodEnum<{
3150
+ agent_home_reader_busy: "agent_home_reader_busy";
3151
+ agent_home_writer_busy: "agent_home_writer_busy";
3152
+ }>>;
3116
3153
  }, z.core.$strip>;
3117
3154
  readonly 'task.progress': z.ZodObject<{
3118
3155
  seq: z.ZodNumber;
@@ -3377,5 +3414,5 @@ export declare const SERVER_TO_DAEMON_TYPES: readonly ["conn.ack", "task.offer",
3377
3414
  * or anything unrecognized — is rejected before it's dispatched to any
3378
3415
  * handler or counted `accepted` on the `/byok/messages` wire.
3379
3416
  */
3380
- export declare const DAEMON_TO_SERVER_TYPES: readonly ["task.claim", "task.started", "task.decline", "task.progress", "task.artifact", "task.await_approval", "task.complete", "task.fail", "task.cancelled", "task.approval_resolved", "agent.egress.reliable", "agent.message.publish", "agent.content.receipt"];
3417
+ export declare const DAEMON_TO_SERVER_TYPES: readonly ["task.claim", "task.started", "task.decline", "task.progress", "task.artifact", "task.await_approval", "task.complete", "task.fail", "task.cancelled", "task.approval_resolved", "agent.egress.reliable", "agent.message.draft", "agent.message.publish", "agent.content.receipt"];
3381
3418
  export {};
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Plain-JSON-data canonicalization shared by every bounded JSON channel of
3
+ * the wire: `task.complete.document` (`checkResultDocument`, messages.ts) and
4
+ * the result-document schema and outcome (`result-schema.ts`). One rule, one
5
+ * implementation, so the channels cannot disagree about what "plain JSON
6
+ * data" means or how its canonical UTF-8 size is measured.
7
+ *
8
+ * Zod-free and free of node builtins.
9
+ */
10
+ /** Outcome of {@link canonicalizePlainJson} without a depth bound. */
11
+ export type PlainJsonCheck = {
12
+ readonly ok: true;
13
+ readonly bytes: number;
14
+ readonly canonical: unknown;
15
+ } | {
16
+ readonly ok: false;
17
+ readonly reason: 'not-serializable';
18
+ } | {
19
+ readonly ok: false;
20
+ readonly reason: 'over-cap';
21
+ readonly bytes: number;
22
+ } | {
23
+ readonly ok: false;
24
+ readonly reason: 'not-plain-json';
25
+ };
26
+ /** Outcome of {@link canonicalizePlainJson} with a container-nesting bound. */
27
+ export type BoundedPlainJsonCheck = PlainJsonCheck | {
28
+ readonly ok: false;
29
+ readonly reason: 'too-deep';
30
+ readonly bytes: number;
31
+ };
32
+ /**
33
+ * Container nesting depth of pure JSON data (a `JSON.parse` output), computed
34
+ * iteratively so no input can exhaust the call stack. A scalar is depth 0,
35
+ * `{}` and `[]` are depth 1. Stops as soon as `limit` is exceeded.
36
+ */
37
+ export declare function jsonDepthExceeds(value: unknown, limit: number): boolean;
38
+ /**
39
+ * Canonicalize `value` as plain JSON data within `maxBytes` canonical UTF-8
40
+ * bytes:
41
+ *
42
+ * 1. `JSON.stringify` must succeed and not return `undefined`.
43
+ * 2. Its UTF-8 byte length must be at most `maxBytes`.
44
+ * 3. `JSON.parse` that string: the CANONICAL SNAPSHOT (pure data).
45
+ * 4. With `maxDepth`, the snapshot's container nesting must be at most
46
+ * `maxDepth`. This runs before step 5, so the recursive comparison
47
+ * below is bounded by it.
48
+ * 5. The original must be structurally equal to the snapshot
49
+ * (`isSameJsonData`).
50
+ *
51
+ * On success a sender uses `canonical`, never the original reference.
52
+ */
53
+ export declare function canonicalizePlainJson(value: unknown, maxBytes: number): PlainJsonCheck;
54
+ export declare function canonicalizePlainJson(value: unknown, maxBytes: number, maxDepth: number): BoundedPlainJsonCheck;
@@ -1,6 +1,4 @@
1
1
  import { z } from 'zod';
2
- /** Daemon capability required before an exact local provider profile may be offered. */
3
- export declare const PROVIDER_PROFILE_BINDING_CAPABILITY: 'provider-profile-binding';
4
2
  /** Opaque, portable local profile identity. It is one logical id, never a path. */
5
3
  export declare const ProviderProfileRefSchema: z.ZodString;
6
4
  export type ProviderProfileRef = z.infer<typeof ProviderProfileRefSchema>;
@@ -23,8 +23,6 @@ import { z } from 'zod';
23
23
  * Audiences, route paths and product names are Host vocabulary and stay out of
24
24
  * this package.
25
25
  */
26
- /** Device capability required before a Host may enqueue `provider.provisioning.available`. */
27
- export declare const PROVIDER_PROVISIONING_CAPABILITY: 'provider-provisioning.v1';
28
26
  /**
29
27
  * Device-proof `operation` for the signed claim that registers the device's
30
28
  * provider-secret sealing public key (`{ keyId, epoch, publicJwk }`).
@@ -0,0 +1,95 @@
1
+ /** Maximum canonical JSON UTF-8 size of a result-document schema. */
2
+ export declare const RESULT_SCHEMA_MAX_BYTES = 16384;
3
+ /** Maximum canonical JSON UTF-8 size of a submitted outcome document. */
4
+ export declare const RESULT_OUTCOME_MAX_BYTES = 65536;
5
+ /**
6
+ * Maximum subschema nesting below the root (each `properties` member, `items`
7
+ * and `oneOf` branch is one level). With the 16 KiB cap this bounds how much
8
+ * schema structure one validation walks.
9
+ */
10
+ export declare const RESULT_SCHEMA_MAX_DEPTH = 32;
11
+ /**
12
+ * Maximum JSON container nesting of a schema or outcome document, checked
13
+ * iteratively before any recursive routine runs on it.
14
+ */
15
+ export declare const RESULT_JSON_MAX_DEPTH = 128;
16
+ /** Maximum number of issues one failed check reports. */
17
+ export declare const RESULT_ISSUES_MAX_COUNT = 20;
18
+ /** Maximum UTF-8 size of the reported issue list, as JSON. */
19
+ export declare const RESULT_ISSUES_MAX_BYTES = 4096;
20
+ export declare const RESULT_SCHEMA_KEYWORDS: readonly ["type", "properties", "required", "additionalProperties", "items", "enum", "const", "oneOf", "minLength", "maxLength", "minItems", "maxItems", "minimum", "maximum", "description"];
21
+ export type ResultSchemaKeyword = (typeof RESULT_SCHEMA_KEYWORDS)[number];
22
+ export declare const RESULT_SCHEMA_INSTANCE_TYPES: readonly ["object", "array", "string", "number", "integer", "boolean", "null"];
23
+ export type ResultSchemaInstanceType = (typeof RESULT_SCHEMA_INSTANCE_TYPES)[number];
24
+ /** A schema inside the admitted subset. Only {@link checkResultSchema} proves a value is one. */
25
+ export interface ResultSchema {
26
+ readonly type?: ResultSchemaInstanceType | readonly ResultSchemaInstanceType[];
27
+ readonly properties?: {
28
+ readonly [name: string]: ResultSchema;
29
+ };
30
+ readonly required?: readonly string[];
31
+ readonly additionalProperties?: false;
32
+ readonly items?: ResultSchema;
33
+ readonly enum?: readonly unknown[];
34
+ readonly const?: unknown;
35
+ readonly oneOf?: readonly ResultSchema[];
36
+ readonly minLength?: number;
37
+ readonly maxLength?: number;
38
+ readonly minItems?: number;
39
+ readonly maxItems?: number;
40
+ readonly minimum?: number;
41
+ readonly maximum?: number;
42
+ readonly description?: string;
43
+ }
44
+ /**
45
+ * One bounded failure detail. `pointer` is an RFC 6901 JSON Pointer into the
46
+ * checked document: the schema for admission issues, the outcome for
47
+ * validation issues (`''` is the document root). `keyword` is the JSON Schema
48
+ * keyword at fault, or a document-level code: `not-serializable`,
49
+ * `not-plain-json`, `over-cap`, `too-deep` (JSON nesting), `schema` (a
50
+ * subschema that is not an object) or `depth` (subschema nesting).
51
+ */
52
+ export interface ResultIssue {
53
+ readonly pointer: string;
54
+ readonly keyword: string;
55
+ readonly message: string;
56
+ }
57
+ /** Document-level failure shared by the schema and outcome checks. */
58
+ export type ResultDocumentFailureReason = 'not-serializable' | 'not-plain-json' | 'over-cap' | 'too-deep';
59
+ interface ResultFailure<Reason extends string> {
60
+ readonly ok: false;
61
+ readonly reason: Reason;
62
+ /** Canonical UTF-8 size, when it was measured. */
63
+ readonly bytes?: number;
64
+ /** At least one issue; at most {@link RESULT_ISSUES_MAX_COUNT} and {@link RESULT_ISSUES_MAX_BYTES}. */
65
+ readonly issues: readonly ResultIssue[];
66
+ /** True when issues were dropped to respect the caps. */
67
+ readonly truncated: boolean;
68
+ }
69
+ export type ResultSchemaCheck = {
70
+ readonly ok: true;
71
+ readonly bytes: number;
72
+ readonly canonical: ResultSchema;
73
+ } | ResultFailure<ResultDocumentFailureReason | 'not-subset'>;
74
+ export type ResultOutcomeCheck = {
75
+ readonly ok: true;
76
+ readonly bytes: number;
77
+ readonly canonical: unknown;
78
+ } | ResultFailure<'schema-not-admitted' | ResultDocumentFailureReason | 'schema-mismatch'>;
79
+ /**
80
+ * The admission guard for a result-document schema. Accepts only plain JSON
81
+ * data of at most {@link RESULT_SCHEMA_MAX_BYTES} canonical UTF-8 bytes that
82
+ * lies inside the subset (module comment). On success, `canonical` is the
83
+ * snapshot every party freezes and validates against.
84
+ */
85
+ export declare function checkResultSchema(schema: unknown): ResultSchemaCheck;
86
+ /**
87
+ * Validate one outcome document against a result schema. The guard
88
+ * ({@link checkResultSchema}) always runs first; a schema it refuses is
89
+ * `schema-not-admitted` and never reaches the library. The outcome must be
90
+ * plain JSON data of at most {@link RESULT_OUTCOME_MAX_BYTES} canonical UTF-8
91
+ * bytes, checked before validation. On success, `canonical` is the snapshot
92
+ * a sender stages and puts on the wire.
93
+ */
94
+ export declare function validateResultOutcome(schema: unknown, outcome: unknown): ResultOutcomeCheck;
95
+ export {};
@@ -26,5 +26,3 @@
26
26
  * carries this exact literal, so a name legal in only one of the two channels
27
27
  * would leave them naming different things.
28
28
  */
29
- /** Contract §8.1's capability gate for `byok-task-assertion-v1` tool authority. */
30
- export declare const HOST_MCP_TASK_CONTEXT_CAPABILITY: 'host-mcp-task-context';
@@ -1,12 +1,19 @@
1
1
  import { z } from 'zod';
2
- /** Capability required before an offer may select terminal projection behavior. */
3
- export declare const TERMINAL_PROJECTION_SELECTION_CAPABILITY: 'terminal-projection-selection';
2
+ import { type ResultSchema } from './result-schema';
4
3
  export declare const TerminalProjectionContractSchema: z.ZodString;
5
- /** Offer-scoped authority: explicit bypass or one required structured result. */
4
+ /**
5
+ * The frozen outcome schema of a result-document offer (wire v3). The value
6
+ * is kept exactly as sent; {@link checkResultSchema} decides admission, so
7
+ * every decode (Host submit, server/cloud parse, daemon admission) applies
8
+ * the one subset guard and reports its capped issues.
9
+ */
10
+ export declare const ResultDocumentSchemaSchema: z.ZodCustom<ResultSchema, ResultSchema>;
11
+ /** Offer-scoped authority: explicit bypass or one required structured result with its frozen schema. */
6
12
  export declare const TerminalProjectionSelectionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
7
13
  mode: z.ZodLiteral<"none">;
8
14
  }, z.core.$strict>, z.ZodObject<{
9
15
  mode: z.ZodLiteral<"result-document">;
10
16
  contract: z.ZodString;
17
+ schema: z.ZodCustom<ResultSchema, ResultSchema>;
11
18
  }, z.core.$strict>], "mode">;
12
19
  export type TerminalProjectionSelection = z.infer<typeof TerminalProjectionSelectionSchema>;
package/dist/version.d.ts CHANGED
@@ -2,15 +2,22 @@
2
2
  export declare const MAILBOX_READ_AHEAD_MAX_SEQS = 4096;
3
3
  export declare const MAILBOX_READ_AHEAD_CAPABILITY = "mailbox-read-ahead";
4
4
  /**
5
- * Wire protocol version. Bump on breaking (non-additive) changes to the envelope
6
- * or message shapes. Additive changes (new optional fields, new message types)
7
- * do not require a bump — servers negotiate the highest common version and
8
- * daemons/servers must ignore unknown fields and unknown message types.
5
+ * Wire protocol version. Every v3 change is a version bump, a gated addition
6
+ * or a strip-safe addition: see docs/protocol.md "Freeze rule", which is the
7
+ * one statement of the rule, and `src/wire-additions.ts`, which declares the
8
+ * receiver-capability gates and additions. No v3 release has been published
9
+ * yet, so `src/__tests__/compat.test.ts` has no published v3 decoder to prove
10
+ * additions against; cross-release gates stay unproven until one exists.
9
11
  *
10
- * FROZEN (see docs/protocol.md "Freeze rule"): `PROTOCOL_VERSION` does not
11
- * bump for additive changes (new optional fields, new message types, new
12
- * `AgentEvent` variants, new capability flags) — only for a breaking one
13
- * (changing, removing, or retyping anything that already exists).
12
+ * v3 makes `schema` required on the `terminalProjection.mode:
13
+ * 'result-document'` arm (`terminal-projection.ts`, `result-schema.ts`): the
14
+ * offer freezes the outcome schema, and the outcome reaches the Host only as
15
+ * `task.complete.document`. That narrows a strict shape, so it is a wire
16
+ * major. A v2 envelope is rejected; there is no v2 reader and no capability
17
+ * negotiation between the two result-document shapes. Drain, then upgrade
18
+ * server and client together. Every addition v2 declared is part of the v3
19
+ * baseline, and the v2 `result-document` capability flag is gone: every v3
20
+ * server keeps `task.complete.document`.
14
21
  *
15
22
  * v2 removed the task offer's `policy` (`PermissionPolicy`), the runtime
16
23
  * capability `permissionModes` and the input-preparation `permissionMode`.
@@ -23,18 +30,8 @@ export declare const MAILBOX_READ_AHEAD_CAPABILITY = "mailbox-read-ahead";
23
30
  * and the readiness reason `executor_identity_unproven`. The SDK does not
24
31
  * attest tool executables. The artifact names its counted tools in
25
32
  * `toolNames`.
26
- *
27
- * IMPORTANT: changing this constant, or changing/removing/retyping any
28
- * already-frozen schema in this package, requires a DELIBERATE update to the
29
- * committed golden fixtures in `src/__tests__/golden/` (`v<N>.frozen.json`,
30
- * `v<N>.envelopes.ndjson`) — see `src/__tests__/freeze-guard.test.ts`, which
31
- * fails loudly on exactly that kind of drift. A passing freeze-guard run
32
- * after such a change means either (a) the change was genuinely additive and
33
- * the golden was regenerated with justification, or (b) this constant was
34
- * bumped alongside a new golden generation for the new version — never a
35
- * silent edit to either file to make the test pass.
36
33
  */
37
- export declare const PROTOCOL_VERSION = 2;
34
+ export declare const PROTOCOL_VERSION = 3;
38
35
  /** Host declares that this device accepts only Agent-bound offer variants. */
39
36
  export declare const STRICT_AGENT_ONLY_CAPABILITY: 'strict-agent-only';
40
37
  /**
@@ -89,27 +86,6 @@ export declare const AGENT_HOME_READERS_CAPABILITY: 'agent-home-readers';
89
86
  * other flag here, just consumed for observability instead of gating.
90
87
  */
91
88
  /**
92
- * `result-document` (additive-minor): a SERVER-advertised flag meaning "I
93
- * understand the optional `task.complete.document` field" (`messages.ts`).
94
- * Functionally gating, like `approval_resolved` and unlike
95
- * `approval-targeting`.
96
- *
97
- * This is the N/N-1 answer for that new daemon -> server FIELD. An old
98
- * server's transport advertisement (`conn.ack.capabilities` on WS or
99
- * `EventsPollResponse.capabilities` on long-poll) never includes it, and
100
- * its `TaskCompletePayloadSchema` is a tolerant (non-`.strict()`)
101
- * `z.object()`, so a `document` sent to it would be silently STRIPPED on
102
- * parse and vanish without a trace. That is exactly why emission is gated
103
- * here rather than sent unconditionally the way `approvalId` is: `document`
104
- * carries the task's primary structured RESULT, so losing it silently is
105
- * data loss, not a missed observability hint. A new daemon talking to an old
106
- * server therefore never sends `document` at all, and — if its configured
107
- * extractor did produce one — reports `task.fail` (retryable: false; the
108
- * same server will strip it on every retry too) instead of completing the
109
- * task with its main result quietly deleted (`packages/client`'s
110
- * `task-runner.ts`). A new server talking to an old daemon is unaffected:
111
- * the field is optional, and an old daemon simply never sets it.
112
- *
113
89
  * `dispatch-selection` (additive-minor) is a correctness gate for the
114
90
  * optional `task.offer.dispatchSelection` control field. An older v1 daemon
115
91
  * legally strips unknown optional fields, so a server must never send an
@@ -124,5 +100,5 @@ export declare const AGENT_HOME_READERS_CAPABILITY: 'agent-home-readers';
124
100
  * cannot accidentally execute the instruction without the required tools.
125
101
  */
126
102
  export declare const CUSTOM_HARNESS_CAPABILITY: 'custom-harness';
127
- export declare const CAPABILITY_FLAGS: readonly ['steer', 'blob-upload', 'interactive-approval', 'approval_resolved', 'approval-targeting', 'result-document', 'dispatch-selection', "provider-profile-binding", 'toolset-selection', 'agent-home-contract', "agent-home-readers", "strict-agent-only", "agent-egress-policy", "agent-egress-reliable-ack", "agent-message-egress", "agent-egress-fresh-session", "agent-content-workspace-read", "agent-content-transcript-read", "agent-content-artifact-read", "agent-home-projection", "agent-input-preparation-v9", "terminal-projection-selection", "host-mcp-task-context", "custom-harness", "mailbox-read-ahead", "provider-provisioning.v1", "agent-memory-intent.v1"];
103
+ export declare const CAPABILITY_FLAGS: readonly ['steer', 'blob-upload', 'interactive-approval', 'approval_resolved', 'approval-targeting', 'dispatch-selection', "provider-profile-binding", 'toolset-selection', 'agent-home-contract', "agent-home-readers", "strict-agent-only", "agent-egress-policy", "agent-egress-reliable-ack", "agent-message-egress", "agent-egress-fresh-session", "agent-content-workspace-read", "agent-content-transcript-read", "agent-content-artifact-read", "agent-home-projection", "agent-input-preparation-v9", "terminal-projection-selection", "host-mcp-task-context", "custom-harness", "mailbox-read-ahead", "provider-provisioning.v1", "agent-memory-intent.v1", 'agent-message-draft'];
128
104
  export type CapabilityFlag = (typeof CAPABILITY_FLAGS)[number];