@opengeni/contracts 0.10.0 → 0.15.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/dist/index.js CHANGED
@@ -1,5 +1,657 @@
1
1
  // src/index.ts
2
2
  import { z } from "zod";
3
+
4
+ // src/event-preview.ts
5
+ var SESSION_EVENT_PAYLOAD_MAX_BYTES = 64 * 1024;
6
+ var TARGET_PAYLOAD_BYTES = 60 * 1024;
7
+ var DEFAULT_STRING_BYTES = 8 * 1024;
8
+ var RETRY_STRING_BYTES = 1024;
9
+ var DEFAULT_ARRAY_ENTRIES = 40;
10
+ var RETRY_ARRAY_ENTRIES = 12;
11
+ var DEFAULT_OBJECT_FIELDS = 80;
12
+ var RETRY_OBJECT_FIELDS = 32;
13
+ var MAX_PREVIEW_DEPTH = 12;
14
+ var MAX_PREVIEW_NODES = 512;
15
+ var MAX_MEASUREMENT_NODES = 2048;
16
+ var MAX_MEASUREMENT_DEPTH = 64;
17
+ var MAX_DETAIL_RECORDS = 24;
18
+ var APPROX_BYTES_PER_TOKEN = 4;
19
+ var encoder = new TextEncoder();
20
+ var IDENTITY_FIELDS = /* @__PURE__ */ new Set([
21
+ "id",
22
+ "callId",
23
+ "call_id",
24
+ "name",
25
+ "toolName",
26
+ "type",
27
+ "status",
28
+ "code",
29
+ "isError",
30
+ "stream",
31
+ "commandId",
32
+ "sequence"
33
+ ]);
34
+ function sessionEventJsonBytes(value) {
35
+ return encoder.encode(stringifyForBoundary(value)).byteLength;
36
+ }
37
+ function measureSessionEventJson(value) {
38
+ return measureJsonBytes(value);
39
+ }
40
+ function approximateSessionEventTokens(bytes) {
41
+ return Math.ceil(Math.max(0, bytes) / APPROX_BYTES_PER_TOKEN);
42
+ }
43
+ function sessionEventMediaPreview(mediaType, inlineBytes) {
44
+ return {
45
+ type: "media_preview",
46
+ mediaType: mediaType || "application/octet-stream",
47
+ inlineBytes: inlineBytes === null ? null : Math.max(0, Math.floor(Number.isFinite(inlineBytes) ? inlineBytes : 0)),
48
+ fullOutputAvailable: false,
49
+ preview: "Inline media omitted from the audit timeline; source bytes were not retained."
50
+ };
51
+ }
52
+ function sessionEventMediaPreviewFromDataUrl(value) {
53
+ const match = /^data:([^;,]+)(?:;[^,]*)?;base64,/i.exec(value);
54
+ if (!match) return null;
55
+ const encodedLength = Math.max(0, value.length - match[0].length);
56
+ const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
57
+ return sessionEventMediaPreview(
58
+ match[1] ?? "application/octet-stream",
59
+ Math.max(0, Math.floor(encodedLength * 3 / 4) - padding)
60
+ );
61
+ }
62
+ function sessionEventPayloadTruncation(payload) {
63
+ if (!isPlainRecord(payload)) return null;
64
+ const value = payload.truncation;
65
+ if (!isPlainRecord(value) || value.truncated !== true) return null;
66
+ return value;
67
+ }
68
+ function boundSessionEventPayload(payload, options = {}) {
69
+ const maxBytes = Math.max(1024, Math.floor(options.maxBytes ?? SESSION_EVENT_PAYLOAD_MAX_BYTES));
70
+ const surface = options.surface ?? "durable_audit";
71
+ const originalMeasurement = measureJsonBytes(payload);
72
+ const originalBytes = originalMeasurement.bytes;
73
+ let state = previewState(DEFAULT_STRING_BYTES, DEFAULT_ARRAY_ENTRIES, DEFAULT_OBJECT_FIELDS);
74
+ let preview = previewValue(payload, state, "$", 0);
75
+ if (!state.changed && originalBytes !== null && originalBytes <= maxBytes) {
76
+ return payload;
77
+ }
78
+ let reason = payloadTruncationReason(originalMeasurement, state);
79
+ let bounded = attachTruncation(preview, boundaryMetadata(surface, reason, originalBytes, state));
80
+ if (sessionEventJsonBytes(bounded) > Math.min(maxBytes, TARGET_PAYLOAD_BYTES)) {
81
+ state = previewState(RETRY_STRING_BYTES, RETRY_ARRAY_ENTRIES, RETRY_OBJECT_FIELDS);
82
+ preview = previewValue(payload, state, "$", 0);
83
+ reason = payloadTruncationReason(originalMeasurement, state);
84
+ bounded = attachTruncation(preview, boundaryMetadata(surface, reason, originalBytes, state));
85
+ }
86
+ if (sessionEventJsonBytes(bounded) > maxBytes) {
87
+ const identity = identityPreview(payload);
88
+ state.changed = true;
89
+ recordDetail(state, {
90
+ path: "$",
91
+ kind: "object",
92
+ ...originalBytes === null ? {} : { originalBytes }
93
+ });
94
+ bounded = attachTruncation(
95
+ {
96
+ ...identity,
97
+ preview: "[event payload omitted: bounded audit preview exceeded the storage envelope]"
98
+ },
99
+ boundaryMetadata(surface, reason, originalBytes, state)
100
+ );
101
+ }
102
+ settleDeliveredSizes(bounded, maxBytes);
103
+ return bounded;
104
+ }
105
+ function previewState(stringBytes, arrayEntries, objectFields) {
106
+ return {
107
+ changed: false,
108
+ sawMedia: false,
109
+ details: [],
110
+ stringBytes,
111
+ arrayEntries,
112
+ objectFields,
113
+ remainingNodes: MAX_PREVIEW_NODES
114
+ };
115
+ }
116
+ function payloadTruncationReason(measurement, state) {
117
+ if (state.sawMedia) return "inline_media_not_retained";
118
+ return measurement.bytes === null ? measurement.reason : "payload_bytes_exceeded";
119
+ }
120
+ function previewValue(value, state, path, depth) {
121
+ if (state.remainingNodes <= 0) {
122
+ state.changed = true;
123
+ recordDetail(state, { path, kind: "budget" });
124
+ return "[nested value omitted at audit preview traversal boundary]";
125
+ }
126
+ state.remainingNodes -= 1;
127
+ if (typeof value === "string") {
128
+ const media = inlineMediaFact(value);
129
+ if (media) {
130
+ state.changed = true;
131
+ state.sawMedia = true;
132
+ recordDetail(state, {
133
+ path,
134
+ kind: "media",
135
+ originalBytes: utf8Bytes(value),
136
+ deliveredBytes: sessionEventJsonBytes(media),
137
+ mediaType: media.mediaType
138
+ });
139
+ return media;
140
+ }
141
+ const originalBytes = utf8Bytes(value);
142
+ if (originalBytes <= state.stringBytes) return value;
143
+ state.changed = true;
144
+ const delivered = truncateUtf8Middle(value, state.stringBytes, originalBytes);
145
+ recordDetail(state, {
146
+ path,
147
+ kind: "string",
148
+ originalBytes,
149
+ deliveredBytes: utf8Bytes(delivered)
150
+ });
151
+ return delivered;
152
+ }
153
+ if (typeof value === "bigint" || typeof value === "function" || typeof value === "symbol") {
154
+ state.changed = true;
155
+ recordDetail(state, { path, kind: "unserializable" });
156
+ return `[${typeof value} value omitted at audit serialization boundary]`;
157
+ }
158
+ if (value === null || typeof value !== "object") return value;
159
+ const binary = binaryFact(value);
160
+ if (binary) {
161
+ state.changed = true;
162
+ recordDetail(state, {
163
+ path,
164
+ kind: "binary",
165
+ originalBytes: binary.originalBytes,
166
+ deliveredBytes: sessionEventJsonBytes(binary.preview)
167
+ });
168
+ return binary.preview;
169
+ }
170
+ if (depth >= MAX_PREVIEW_DEPTH) {
171
+ state.changed = true;
172
+ recordDetail(state, { path, kind: "depth" });
173
+ return "[nested value omitted at audit preview depth boundary]";
174
+ }
175
+ if (Array.isArray(value)) {
176
+ const keep = Math.max(2, state.arrayEntries);
177
+ if (value.length <= keep) {
178
+ return Array.from(
179
+ { length: value.length },
180
+ (_, index) => previewArrayEntry(value, index, state, path, depth)
181
+ );
182
+ }
183
+ state.changed = true;
184
+ const head = Math.ceil(keep / 2);
185
+ const tail = Math.floor(keep / 2);
186
+ const omitted2 = value.length - head - tail;
187
+ recordDetail(state, { path, kind: "array", omittedEntries: omitted2 });
188
+ return [
189
+ ...Array.from(
190
+ { length: head },
191
+ (_, index) => previewArrayEntry(value, index, state, path, depth)
192
+ ),
193
+ { omittedEntries: omitted2, preview: "[middle array entries omitted]" },
194
+ ...Array.from(
195
+ { length: tail },
196
+ (_, index) => previewArrayEntry(value, value.length - tail + index, state, path, depth)
197
+ )
198
+ ];
199
+ }
200
+ if (value instanceof Date) {
201
+ if (!hasCanonicalDateSerialization(value)) {
202
+ state.changed = true;
203
+ recordDetail(state, { path, kind: "unserializable" });
204
+ return "[Date value with custom serialization omitted at audit boundary]";
205
+ }
206
+ try {
207
+ const epoch = Date.prototype.getTime.call(value);
208
+ return Number.isFinite(epoch) ? Date.prototype.toISOString.call(value) : null;
209
+ } catch {
210
+ state.changed = true;
211
+ recordDetail(state, { path, kind: "unserializable" });
212
+ return "[Date value omitted at audit serialization boundary]";
213
+ }
214
+ }
215
+ const record = value;
216
+ const { entries, omitted, accessorKeys } = selectObjectEntries(record, state.objectFields);
217
+ for (const key of accessorKeys) {
218
+ state.changed = true;
219
+ recordDetail(state, {
220
+ path: `${path}.${key}`,
221
+ kind: "unserializable"
222
+ });
223
+ }
224
+ if (omitted) {
225
+ state.changed = true;
226
+ recordDetail(state, {
227
+ path,
228
+ kind: "object",
229
+ // Counting every remaining field would defeat the traversal bound. `null`
230
+ // is deliberate: at least one field was omitted, but its exact count is
231
+ // unknown because the source was not fully enumerated.
232
+ omittedEntries: null
233
+ });
234
+ }
235
+ const out = {};
236
+ for (const [key, entry] of entries) {
237
+ out[key] = previewValue(entry, state, `${path}.${key}`, depth + 1);
238
+ }
239
+ if (omitted) {
240
+ out.omittedFields = "additional fields omitted; exact count not measured";
241
+ }
242
+ return out;
243
+ }
244
+ function previewArrayEntry(value, index, state, path, depth) {
245
+ let descriptor;
246
+ try {
247
+ descriptor = Object.getOwnPropertyDescriptor(value, String(index));
248
+ } catch {
249
+ state.changed = true;
250
+ recordDetail(state, { path: `${path}[${index}]`, kind: "unserializable" });
251
+ return "[array element omitted at audit serialization boundary]";
252
+ }
253
+ if (descriptor && !("value" in descriptor)) {
254
+ state.changed = true;
255
+ recordDetail(state, { path: `${path}[${index}]`, kind: "unserializable" });
256
+ return "[array accessor value omitted at audit serialization boundary]";
257
+ }
258
+ return previewValue(
259
+ descriptor && "value" in descriptor ? descriptor.value : void 0,
260
+ state,
261
+ `${path}[${index}]`,
262
+ depth + 1
263
+ );
264
+ }
265
+ function selectObjectEntries(record, maxFields) {
266
+ const entries = [];
267
+ const selected = /* @__PURE__ */ new Set();
268
+ const accessorKeys = [];
269
+ const select = (key) => {
270
+ const descriptor = Object.getOwnPropertyDescriptor(record, key);
271
+ if (!descriptor?.enumerable) return false;
272
+ selected.add(key);
273
+ if ("value" in descriptor) {
274
+ entries.push([key, descriptor.value]);
275
+ } else {
276
+ entries.push([key, "[accessor value omitted at audit serialization boundary]"]);
277
+ accessorKeys.push(key);
278
+ }
279
+ return true;
280
+ };
281
+ try {
282
+ for (const key of IDENTITY_FIELDS) {
283
+ if (entries.length >= maxFields) break;
284
+ select(key);
285
+ }
286
+ for (const key in record) {
287
+ if (!Object.prototype.hasOwnProperty.call(record, key) || selected.has(key)) continue;
288
+ if (entries.length >= maxFields) {
289
+ return { entries, omitted: true, accessorKeys };
290
+ }
291
+ select(key);
292
+ }
293
+ } catch {
294
+ return { entries, omitted: true, accessorKeys };
295
+ }
296
+ return { entries, omitted: false, accessorKeys };
297
+ }
298
+ function attachTruncation(preview, truncation) {
299
+ if (isPlainRecord(preview)) {
300
+ return { ...preview, truncation };
301
+ }
302
+ return { value: preview, truncation };
303
+ }
304
+ function boundaryMetadata(surface, reason, originalBytes, state) {
305
+ return {
306
+ truncated: true,
307
+ surface,
308
+ reason,
309
+ originalBytes,
310
+ deliveredBytes: 0,
311
+ omittedBytes: originalBytes,
312
+ estimatedOriginalTokens: originalBytes === null ? null : approximateSessionEventTokens(originalBytes),
313
+ estimatedDeliveredTokens: 0,
314
+ fullEvidence: { available: false, reason: "not_retained" },
315
+ details: state.details
316
+ };
317
+ }
318
+ function settleDeliveredSizes(payload, maxBytes) {
319
+ const truncation = payload.truncation;
320
+ convergeDeliveredSizes(payload, truncation);
321
+ if (sessionEventJsonBytes(payload) > maxBytes) {
322
+ payload.preview = "[event payload omitted at audit byte boundary]";
323
+ for (const key of Object.keys(payload)) {
324
+ if (key !== "preview" && key !== "truncation" && IDENTITY_FIELDS.has(key) === false) {
325
+ delete payload[key];
326
+ }
327
+ }
328
+ truncation.details = truncation.details.slice(0, 4);
329
+ convergeDeliveredSizes(payload, truncation);
330
+ }
331
+ }
332
+ function convergeDeliveredSizes(payload, truncation) {
333
+ for (let attempt = 0; attempt < 16; attempt += 1) {
334
+ const deliveredBytes = sessionEventJsonBytes(payload);
335
+ const omittedBytes = truncation.originalBytes === null ? null : Math.max(0, truncation.originalBytes - deliveredBytes);
336
+ const estimatedDeliveredTokens = approximateSessionEventTokens(deliveredBytes);
337
+ if (truncation.deliveredBytes === deliveredBytes && truncation.omittedBytes === omittedBytes && truncation.estimatedDeliveredTokens === estimatedDeliveredTokens) {
338
+ return;
339
+ }
340
+ truncation.deliveredBytes = deliveredBytes;
341
+ truncation.omittedBytes = omittedBytes;
342
+ truncation.estimatedDeliveredTokens = estimatedDeliveredTokens;
343
+ }
344
+ throw new RangeError("Session event byte accounting did not converge");
345
+ }
346
+ function recordDetail(state, detail) {
347
+ if (state.details.length < MAX_DETAIL_RECORDS) state.details.push(detail);
348
+ }
349
+ function identityPreview(value) {
350
+ if (!isPlainRecord(value)) return {};
351
+ const out = {};
352
+ for (const key of IDENTITY_FIELDS) {
353
+ let field;
354
+ try {
355
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
356
+ if (!descriptor?.enumerable || !("value" in descriptor)) continue;
357
+ field = descriptor.value;
358
+ } catch {
359
+ continue;
360
+ }
361
+ if (typeof field === "string") {
362
+ out[key] = truncateUtf8Middle(field, 256, utf8Bytes(field));
363
+ } else if (typeof field === "number" || typeof field === "boolean" || field === null) {
364
+ out[key] = field;
365
+ }
366
+ }
367
+ return out;
368
+ }
369
+ function inlineMediaFact(value) {
370
+ return sessionEventMediaPreviewFromDataUrl(value);
371
+ }
372
+ function binaryFact(value) {
373
+ if (ArrayBuffer.isView(value)) {
374
+ return {
375
+ originalBytes: value.byteLength,
376
+ preview: {
377
+ type: "binary_preview",
378
+ byteLength: value.byteLength,
379
+ fullOutputAvailable: false,
380
+ preview: "Inline binary value omitted from the audit timeline; bytes were not retained."
381
+ }
382
+ };
383
+ }
384
+ if (value instanceof ArrayBuffer) {
385
+ return {
386
+ originalBytes: value.byteLength,
387
+ preview: {
388
+ type: "binary_preview",
389
+ byteLength: value.byteLength,
390
+ fullOutputAvailable: false,
391
+ preview: "Inline binary value omitted from the audit timeline; bytes were not retained."
392
+ }
393
+ };
394
+ }
395
+ return null;
396
+ }
397
+ function truncateUtf8Middle(value, maxBytes, knownBytes = utf8Bytes(value)) {
398
+ if (knownBytes <= maxBytes) return value;
399
+ let omittedBytes = Math.max(0, knownBytes - maxBytes);
400
+ for (let attempt = 0; attempt < 4; attempt += 1) {
401
+ const marker2 = `\u2026[${omittedBytes} bytes omitted]\u2026`;
402
+ const contentBudget2 = Math.max(0, maxBytes - utf8Bytes(marker2));
403
+ if (contentBudget2 === 0) return marker2;
404
+ const left2 = utf8Prefix(value, Math.floor(contentBudget2 / 2));
405
+ const right2 = utf8Suffix(value, contentBudget2 - left2.bytes);
406
+ const exactOmittedBytes = Math.max(0, knownBytes - left2.bytes - right2.bytes);
407
+ if (exactOmittedBytes === omittedBytes) {
408
+ return `${value.slice(0, left2.end)}${marker2}${value.slice(right2.start)}`;
409
+ }
410
+ omittedBytes = exactOmittedBytes;
411
+ }
412
+ const marker = `\u2026[${omittedBytes} bytes omitted]\u2026`;
413
+ const contentBudget = Math.max(0, maxBytes - utf8Bytes(marker));
414
+ const left = utf8Prefix(value, Math.floor(contentBudget / 2));
415
+ const right = utf8Suffix(value, contentBudget - left.bytes);
416
+ return `${value.slice(0, left.end)}${marker}${value.slice(right.start)}`;
417
+ }
418
+ function utf8Prefix(value, maxBytes) {
419
+ let end = 0;
420
+ let bytes = 0;
421
+ while (end < value.length) {
422
+ const unit = utf8UnitAt(value, end);
423
+ if (bytes + unit.bytes > maxBytes) break;
424
+ bytes += unit.bytes;
425
+ end += unit.codeUnits;
426
+ }
427
+ return { end, bytes };
428
+ }
429
+ function utf8Suffix(value, maxBytes) {
430
+ let start = value.length;
431
+ let bytes = 0;
432
+ while (start > 0) {
433
+ const unit = utf8UnitBefore(value, start);
434
+ if (bytes + unit.bytes > maxBytes) break;
435
+ bytes += unit.bytes;
436
+ start -= unit.codeUnits;
437
+ }
438
+ return { start, bytes };
439
+ }
440
+ function utf8UnitAt(value, index) {
441
+ const code = value.charCodeAt(index);
442
+ if (code <= 127) return { codeUnits: 1, bytes: 1 };
443
+ if (code <= 2047) return { codeUnits: 1, bytes: 2 };
444
+ if (code >= 55296 && code <= 56319) {
445
+ const next = index + 1 < value.length ? value.charCodeAt(index + 1) : 0;
446
+ if (next >= 56320 && next <= 57343) {
447
+ return { codeUnits: 2, bytes: 4 };
448
+ }
449
+ }
450
+ return { codeUnits: 1, bytes: 3 };
451
+ }
452
+ function utf8UnitBefore(value, end) {
453
+ const code = value.charCodeAt(end - 1);
454
+ if (code >= 56320 && code <= 57343 && end >= 2) {
455
+ const previous = value.charCodeAt(end - 2);
456
+ if (previous >= 55296 && previous <= 56319) {
457
+ return { codeUnits: 2, bytes: 4 };
458
+ }
459
+ }
460
+ if (code <= 127) return { codeUnits: 1, bytes: 1 };
461
+ if (code <= 2047) return { codeUnits: 1, bytes: 2 };
462
+ return { codeUnits: 1, bytes: 3 };
463
+ }
464
+ function utf8Bytes(value) {
465
+ let bytes = 0;
466
+ for (let index = 0; index < value.length; ) {
467
+ const unit = utf8UnitAt(value, index);
468
+ bytes += unit.bytes;
469
+ index += unit.codeUnits;
470
+ }
471
+ return bytes;
472
+ }
473
+ function measureJsonBytes(value) {
474
+ const state = {
475
+ remainingNodes: MAX_MEASUREMENT_NODES,
476
+ seen: /* @__PURE__ */ new WeakSet(),
477
+ failureReason: null
478
+ };
479
+ try {
480
+ const bytes = measureJsonValue(value, state, "top", 0);
481
+ return bytes === null ? {
482
+ bytes: null,
483
+ reason: state.failureReason ?? "payload_measurement_bounded"
484
+ } : { bytes, reason: null };
485
+ } catch {
486
+ return { bytes: null, reason: "payload_measurement_bounded" };
487
+ }
488
+ }
489
+ function measureJsonValue(value, state, position, depth) {
490
+ if (state.remainingNodes <= 0 || depth > MAX_MEASUREMENT_DEPTH) {
491
+ return failJsonMeasurement(state, "payload_measurement_bounded");
492
+ }
493
+ state.remainingNodes -= 1;
494
+ if (value === null) return 4;
495
+ if (typeof value === "string") return jsonStringBytes(value);
496
+ if (typeof value === "boolean") return value ? 4 : 5;
497
+ if (typeof value === "number") {
498
+ const serialized = JSON.stringify(value);
499
+ return serialized === void 0 ? null : serialized.length;
500
+ }
501
+ if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") {
502
+ return position === "array" ? 4 : failJsonMeasurement(state, "payload_not_serializable");
503
+ }
504
+ if (typeof value === "bigint") {
505
+ return failJsonMeasurement(state, "payload_not_serializable");
506
+ }
507
+ if (typeof value !== "object") {
508
+ return failJsonMeasurement(state, "payload_not_serializable");
509
+ }
510
+ if (value instanceof Date) {
511
+ if (!hasCanonicalDateSerialization(value)) {
512
+ return failJsonMeasurement(state, "payload_measurement_bounded");
513
+ }
514
+ try {
515
+ const epoch = Date.prototype.getTime.call(value);
516
+ return Number.isFinite(epoch) ? jsonStringBytes(Date.prototype.toISOString.call(value)) : 4;
517
+ } catch {
518
+ return failJsonMeasurement(state, "payload_not_serializable");
519
+ }
520
+ }
521
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
522
+ return failJsonMeasurement(state, "payload_measurement_bounded");
523
+ }
524
+ if (state.seen.has(value)) {
525
+ return failJsonMeasurement(state, "payload_not_serializable");
526
+ }
527
+ state.seen.add(value);
528
+ try {
529
+ if (Array.isArray(value)) {
530
+ if (Object.getPrototypeOf(value) !== Array.prototype) {
531
+ return failJsonMeasurement(state, "payload_measurement_bounded");
532
+ }
533
+ const toJson2 = Object.getOwnPropertyDescriptor(value, "toJSON");
534
+ if (toJson2 && ("get" in toJson2 || typeof toJson2.value === "function")) {
535
+ return failJsonMeasurement(state, "payload_measurement_bounded");
536
+ }
537
+ if (value.length > state.remainingNodes) {
538
+ return failJsonMeasurement(state, "payload_measurement_bounded");
539
+ }
540
+ let bytes2 = 2;
541
+ for (let index = 0; index < value.length; index += 1) {
542
+ if (index > 0) bytes2 += 1;
543
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
544
+ if (descriptor && !("value" in descriptor)) {
545
+ return failJsonMeasurement(state, "payload_measurement_bounded");
546
+ }
547
+ const entry = descriptor && "value" in descriptor ? descriptor.value : void 0;
548
+ const measured = measureJsonValue(entry, state, "array", depth + 1);
549
+ if (measured === null) return null;
550
+ bytes2 += measured;
551
+ }
552
+ return bytes2;
553
+ }
554
+ const prototype = Object.getPrototypeOf(value);
555
+ if (prototype !== Object.prototype && prototype !== null) {
556
+ return failJsonMeasurement(state, "payload_measurement_bounded");
557
+ }
558
+ const toJson = Object.getOwnPropertyDescriptor(value, "toJSON");
559
+ if (toJson && ("get" in toJson || typeof toJson.value === "function")) {
560
+ return failJsonMeasurement(state, "payload_measurement_bounded");
561
+ }
562
+ let bytes = 2;
563
+ let fields = 0;
564
+ try {
565
+ for (const key in value) {
566
+ if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
567
+ if (state.remainingNodes <= 0) {
568
+ return failJsonMeasurement(state, "payload_measurement_bounded");
569
+ }
570
+ state.remainingNodes -= 1;
571
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
572
+ if (!descriptor || !("value" in descriptor)) {
573
+ return failJsonMeasurement(state, "payload_measurement_bounded");
574
+ }
575
+ const entry = descriptor.value;
576
+ if (typeof entry === "undefined" || typeof entry === "function" || typeof entry === "symbol") {
577
+ continue;
578
+ }
579
+ const measured = measureJsonValue(entry, state, "object", depth + 1);
580
+ if (measured === null) return null;
581
+ if (fields > 0) bytes += 1;
582
+ bytes += jsonStringBytes(key) + 1 + measured;
583
+ fields += 1;
584
+ }
585
+ } catch {
586
+ return null;
587
+ }
588
+ return bytes;
589
+ } finally {
590
+ state.seen.delete(value);
591
+ }
592
+ }
593
+ function hasCanonicalDateSerialization(value) {
594
+ try {
595
+ if (Object.getPrototypeOf(value) !== Date.prototype) return false;
596
+ return Object.getOwnPropertyDescriptor(value, "toJSON") === void 0;
597
+ } catch {
598
+ return false;
599
+ }
600
+ }
601
+ function failJsonMeasurement(state, reason) {
602
+ state.failureReason ??= reason;
603
+ return null;
604
+ }
605
+ function jsonStringBytes(value) {
606
+ let bytes = 2;
607
+ for (let index = 0; index < value.length; index += 1) {
608
+ const code = value.charCodeAt(index);
609
+ if (code === 34 || code === 92 || code === 8 || code === 9 || code === 10 || code === 12 || code === 13) {
610
+ bytes += 2;
611
+ } else if (code <= 31) {
612
+ bytes += 6;
613
+ } else if (code <= 127) {
614
+ bytes += 1;
615
+ } else if (code <= 2047) {
616
+ bytes += 2;
617
+ } else if (code >= 55296 && code <= 56319) {
618
+ const next = index + 1 < value.length ? value.charCodeAt(index + 1) : 0;
619
+ if (next >= 56320 && next <= 57343) {
620
+ bytes += 4;
621
+ index += 1;
622
+ } else {
623
+ bytes += 6;
624
+ }
625
+ } else if (code >= 56320 && code <= 57343) {
626
+ bytes += 6;
627
+ } else {
628
+ bytes += 3;
629
+ }
630
+ }
631
+ return bytes;
632
+ }
633
+ function serializeForBoundary(value) {
634
+ try {
635
+ const serialized = JSON.stringify(value);
636
+ return {
637
+ value: serialized === void 0 ? "null" : serialized,
638
+ serializable: serialized !== void 0
639
+ };
640
+ } catch {
641
+ return {
642
+ value: JSON.stringify("[unserializable event payload omitted]"),
643
+ serializable: false
644
+ };
645
+ }
646
+ }
647
+ function stringifyForBoundary(value) {
648
+ return serializeForBoundary(value).value;
649
+ }
650
+ function isPlainRecord(value) {
651
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
652
+ }
653
+
654
+ // src/index.ts
3
655
  var SessionStatus = z.enum([
4
656
  "queued",
5
657
  "running",
@@ -7,7 +659,6 @@ var SessionStatus = z.enum([
7
659
  "requires_action",
8
660
  "recovering",
9
661
  "waiting_capacity",
10
- "paused",
11
662
  "failed",
12
663
  "cancelled"
13
664
  ]);
@@ -386,7 +1037,7 @@ var Permission = z.enum([
386
1037
  "sessions:create",
387
1038
  "sessions:read",
388
1039
  "sessions:control",
389
- // Sandbox-surfacing (master-spine §C.3 / crosscut PART 1.2). stream:view is a
1040
+ // sandbox workspace (sandbox contract §C.3 / crosscut PART 1.2). stream:view is a
390
1041
  // REAL, distinct permission — strictly BROADER than sessions:read — because the
391
1042
  // pixel plane (Channel B) is UN-REDACTED: a viewer of raw pixels can see cloud
392
1043
  // creds the agent cat's into a terminal, which the redacted Channel-A event log
@@ -480,25 +1131,255 @@ var Workspace = z.object({
480
1131
  // validated by WorkspaceSettingsSchema; unknown keys are preserved across
481
1132
  // PATCH merges so newer settings survive an older server.
482
1133
  settings: z.record(z.string(), z.unknown()),
483
- inferenceState: z.enum(["active", "paused"]),
484
- inferenceGeneration: z.number().int().nonnegative(),
485
- inferenceReason: z.string().nullable(),
486
- inferenceChangedBy: z.string().nullable(),
487
- inferenceChangedAt: z.string().nullable(),
1134
+ inferenceControl: z.object({
1135
+ state: z.enum(["active", "paused"]),
1136
+ revision: z.number().int().nonnegative(),
1137
+ reason: z.string().nullable(),
1138
+ changedBy: z.string().nullable(),
1139
+ changedAt: z.string().nullable()
1140
+ }),
488
1141
  // Workspace default rig used by session/scheduled-task create fallback.
489
1142
  defaultRigId: z.string().uuid().nullable(),
490
1143
  createdAt: z.string(),
491
1144
  updatedAt: z.string()
492
1145
  });
1146
+ var WorkspaceTranscriptionTarget = z.object({
1147
+ provider: z.string().trim().min(1).max(128),
1148
+ model: z.string().trim().min(1).max(256).nullable(),
1149
+ credentialMode: z.enum(["managed", "byok"]),
1150
+ // A workspace-scoped connection reference, never credential material.
1151
+ credentialConnectionId: z.string().uuid().nullable(),
1152
+ region: z.string().trim().min(1).max(128).nullable()
1153
+ }).strict().superRefine((target, context) => {
1154
+ if (target.provider === "azure-speech" && target.credentialMode !== "byok") {
1155
+ context.addIssue({
1156
+ code: "custom",
1157
+ path: ["credentialMode"],
1158
+ message: "Azure Speech is supported only through workspace BYOK"
1159
+ });
1160
+ }
1161
+ if (target.credentialMode === "byok" && target.credentialConnectionId === null) {
1162
+ context.addIssue({
1163
+ code: "custom",
1164
+ path: ["credentialConnectionId"],
1165
+ message: "BYOK transcription targets require a workspace connection reference"
1166
+ });
1167
+ }
1168
+ if (target.credentialMode === "managed" && target.credentialConnectionId !== null) {
1169
+ context.addIssue({
1170
+ code: "custom",
1171
+ path: ["credentialConnectionId"],
1172
+ message: "managed transcription targets cannot name a BYOK connection"
1173
+ });
1174
+ }
1175
+ });
1176
+ var TranscriptionErrorCode = z.enum([
1177
+ "permission_denied",
1178
+ "not_supported",
1179
+ "network",
1180
+ "provider",
1181
+ "policy_blocked",
1182
+ "timeout",
1183
+ "cancelled",
1184
+ "unknown"
1185
+ ]);
1186
+ var TranscriptionTimeSpan = z.object({
1187
+ startMilliseconds: z.number().finite().nonnegative(),
1188
+ endMilliseconds: z.number().finite().nonnegative()
1189
+ }).strict().superRefine((span, context) => {
1190
+ if (span.endMilliseconds < span.startMilliseconds) {
1191
+ context.addIssue({
1192
+ code: "custom",
1193
+ path: ["endMilliseconds"],
1194
+ message: "transcription spans must not end before they start"
1195
+ });
1196
+ }
1197
+ });
1198
+ var TranscriptionSpeaker = z.object({
1199
+ id: z.string().trim().min(1).max(128),
1200
+ label: z.string().trim().min(1).max(128).optional()
1201
+ }).strict();
1202
+ var TranscriptionWord = z.object({
1203
+ text: z.string().min(1).max(4096),
1204
+ span: TranscriptionTimeSpan,
1205
+ confidence: z.number().finite().min(0).max(1).optional(),
1206
+ speaker: TranscriptionSpeaker.optional()
1207
+ }).strict();
1208
+ var TranscriptionResultMetadata = z.object({
1209
+ detectedLanguage: z.string().trim().min(1).max(64).optional(),
1210
+ span: TranscriptionTimeSpan.optional(),
1211
+ confidence: z.number().finite().min(0).max(1).optional(),
1212
+ speaker: TranscriptionSpeaker.optional(),
1213
+ words: z.array(TranscriptionWord).max(1e4).optional()
1214
+ }).strict().superRefine((metadata, context) => {
1215
+ let previousStart = -1;
1216
+ for (const [index, word] of (metadata.words ?? []).entries()) {
1217
+ if (word.span.startMilliseconds < previousStart) {
1218
+ context.addIssue({
1219
+ code: "custom",
1220
+ path: ["words", index, "span", "startMilliseconds"],
1221
+ message: "transcription words must be ordered by start time"
1222
+ });
1223
+ }
1224
+ previousStart = word.span.startMilliseconds;
1225
+ if (metadata.span && (word.span.startMilliseconds < metadata.span.startMilliseconds || word.span.endMilliseconds > metadata.span.endMilliseconds)) {
1226
+ context.addIssue({
1227
+ code: "custom",
1228
+ path: ["words", index, "span"],
1229
+ message: "transcription word spans must fall within the result span"
1230
+ });
1231
+ }
1232
+ }
1233
+ });
1234
+ var TranscriptionEventBase = z.object({
1235
+ localSessionId: z.string().min(1).max(256),
1236
+ sequence: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
1237
+ occurredAt: z.string().datetime({ offset: true })
1238
+ }).strict();
1239
+ var TranscriptionEvent = z.discriminatedUnion("type", [
1240
+ TranscriptionEventBase.extend({ type: z.literal("permission.requested") }),
1241
+ TranscriptionEventBase.extend({
1242
+ type: z.literal("session.opened"),
1243
+ providerSessionId: z.string().min(1).max(512)
1244
+ }),
1245
+ TranscriptionEventBase.extend({
1246
+ type: z.literal("transcript.partial"),
1247
+ segmentId: z.string().min(1).max(512),
1248
+ text: z.string().max(1e6),
1249
+ metadata: TranscriptionResultMetadata.optional()
1250
+ }),
1251
+ TranscriptionEventBase.extend({
1252
+ type: z.literal("transcript.final"),
1253
+ segmentId: z.string().min(1).max(512),
1254
+ text: z.string().max(1e6),
1255
+ providerAcceptanceId: z.string().min(1).max(512),
1256
+ metadata: TranscriptionResultMetadata.optional()
1257
+ }),
1258
+ TranscriptionEventBase.extend({
1259
+ type: z.literal("usage"),
1260
+ audioMilliseconds: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
1261
+ costUsd: z.number().finite().nonnegative().max(1e9).nullable()
1262
+ }),
1263
+ TranscriptionEventBase.extend({
1264
+ type: z.literal("session.reconnecting"),
1265
+ attempt: z.number().int().nonnegative().max(1e4),
1266
+ reason: z.string().min(1).max(256)
1267
+ }),
1268
+ TranscriptionEventBase.extend({
1269
+ type: z.literal("session.error"),
1270
+ code: TranscriptionErrorCode,
1271
+ recoverable: z.boolean()
1272
+ }),
1273
+ TranscriptionEventBase.extend({
1274
+ type: z.literal("session.closed"),
1275
+ reason: z.enum(["completed", "cancelled", "error", "replaced"])
1276
+ })
1277
+ ]);
1278
+ var WorkspaceTranscriptionPolicy = z.object({
1279
+ enabled: z.boolean(),
1280
+ acceptanceId: z.string().uuid().nullable(),
1281
+ primary: WorkspaceTranscriptionTarget.nullable(),
1282
+ language: z.string().trim().min(1).max(64).nullable(),
1283
+ autoDetectLanguage: z.boolean(),
1284
+ diarization: z.object({
1285
+ enabled: z.boolean(),
1286
+ maxSpeakers: z.number().int().min(2).max(100).nullable()
1287
+ }).strict(),
1288
+ retention: z.object({
1289
+ mode: z.enum(["none", "provider-policy"]),
1290
+ maxDays: z.number().int().nonnegative().max(3650).nullable()
1291
+ }).strict(),
1292
+ privacy: z.object({
1293
+ allowProviderLogging: z.boolean(),
1294
+ allowProviderTraining: z.boolean()
1295
+ }).strict(),
1296
+ fallback: z.object({
1297
+ mode: z.enum(["disabled", "explicit"]),
1298
+ targets: z.array(WorkspaceTranscriptionTarget).max(8)
1299
+ }).strict(),
1300
+ cost: z.object({
1301
+ currency: z.literal("USD"),
1302
+ maxPerHour: z.number().finite().nonnegative().max(1e4).nullable(),
1303
+ maxPerMonth: z.number().finite().nonnegative().max(1e6).nullable()
1304
+ }).strict()
1305
+ }).strict().superRefine((policy, context) => {
1306
+ if (policy.enabled && policy.acceptanceId === null) {
1307
+ context.addIssue({
1308
+ code: "custom",
1309
+ path: ["acceptanceId"],
1310
+ message: "enabled transcription requires an accepted policy identity"
1311
+ });
1312
+ }
1313
+ if (policy.enabled && policy.primary === null) {
1314
+ context.addIssue({
1315
+ code: "custom",
1316
+ path: ["primary"],
1317
+ message: "enabled transcription requires a primary target"
1318
+ });
1319
+ }
1320
+ if (policy.enabled && !policy.autoDetectLanguage && policy.language === null) {
1321
+ context.addIssue({
1322
+ code: "custom",
1323
+ path: ["language"],
1324
+ message: "enabled transcription requires a language or accepted automatic detection"
1325
+ });
1326
+ }
1327
+ if (policy.autoDetectLanguage && policy.language !== null) {
1328
+ context.addIssue({
1329
+ code: "custom",
1330
+ path: ["language"],
1331
+ message: "automatic language detection and a fixed language are mutually exclusive"
1332
+ });
1333
+ }
1334
+ if (!policy.diarization.enabled && policy.diarization.maxSpeakers !== null) {
1335
+ context.addIssue({
1336
+ code: "custom",
1337
+ path: ["diarization", "maxSpeakers"],
1338
+ message: "disabled diarization cannot retain a speaker limit"
1339
+ });
1340
+ }
1341
+ if (policy.fallback.mode === "disabled" && policy.fallback.targets.length > 0) {
1342
+ context.addIssue({
1343
+ code: "custom",
1344
+ path: ["fallback", "targets"],
1345
+ message: "disabled fallback cannot retain accepted targets"
1346
+ });
1347
+ }
1348
+ if (policy.fallback.mode === "explicit" && policy.fallback.targets.length === 0) {
1349
+ context.addIssue({
1350
+ code: "custom",
1351
+ path: ["fallback", "targets"],
1352
+ message: "explicit fallback requires at least one accepted target"
1353
+ });
1354
+ }
1355
+ const targetKeys = [policy.primary, ...policy.fallback.targets].filter((target) => target !== null).map(
1356
+ (target) => [
1357
+ target.provider,
1358
+ target.model ?? "",
1359
+ target.credentialMode,
1360
+ target.credentialConnectionId ?? "",
1361
+ target.region ?? ""
1362
+ ].join("\0")
1363
+ );
1364
+ if (new Set(targetKeys).size !== targetKeys.length) {
1365
+ context.addIssue({
1366
+ code: "custom",
1367
+ path: ["fallback", "targets"],
1368
+ message: "transcription targets must be unique"
1369
+ });
1370
+ }
1371
+ });
493
1372
  var WorkspaceSettingsSchema = z.object({
494
- memoryEnabled: z.boolean().optional()
1373
+ memoryEnabled: z.boolean().optional(),
1374
+ transcription: WorkspaceTranscriptionPolicy.optional()
495
1375
  }).passthrough();
496
1376
  function resolveWorkspaceMemoryEnabled(settings) {
497
1377
  const parsed = WorkspaceSettingsSchema.safeParse(settings ?? {});
498
1378
  return parsed.success ? parsed.data.memoryEnabled === true : false;
499
1379
  }
500
1380
  var UpdateWorkspaceSettingsRequest = z.object({
501
- memoryEnabled: z.boolean().optional()
1381
+ memoryEnabled: z.boolean().optional(),
1382
+ transcription: WorkspaceTranscriptionPolicy.optional()
502
1383
  }).passthrough();
503
1384
  var SetWorkspaceDefaultRigRequest = z.object({
504
1385
  rigId: z.string().uuid().nullable()
@@ -507,6 +1388,52 @@ var UpdateWorkspaceModelPolicyRequest = z.object({
507
1388
  allowedProviders: z.array(z.string().min(1).max(128)).max(64).nullable().optional(),
508
1389
  allowedModels: z.array(z.string().min(1).max(256)).max(256).nullable().optional()
509
1390
  });
1391
+ var turnInitiatorIdentityFields = {
1392
+ subjectId: z.string().min(1),
1393
+ /** Immutable display snapshot; never an authorization input. */
1394
+ label: z.string().min(1).optional()
1395
+ };
1396
+ var UNATTRIBUTED_LEGACY_INITIATOR_SUBJECT_ID = "unattributed-legacy";
1397
+ var ServiceTurnInitiator = z.object({
1398
+ kind: z.literal("service"),
1399
+ subjectId: z.string().min(1).max(1024).refine((value) => value !== UNATTRIBUTED_LEGACY_INITIATOR_SUBJECT_ID, {
1400
+ message: "unattributed-legacy is reserved for migrated rows"
1401
+ }),
1402
+ /** Immutable display snapshot; never an authorization input. */
1403
+ label: z.string().min(1).max(256).optional()
1404
+ });
1405
+ var TurnInitiatorContext = z.record(z.string(), z.unknown());
1406
+ var reservedServiceTurnInitiatorContextKeys = /* @__PURE__ */ new Set([
1407
+ "backfill",
1408
+ "label",
1409
+ "provenanceError",
1410
+ "via",
1411
+ "viaTruncated"
1412
+ ]);
1413
+ var ServiceTurnInitiatorContext = TurnInitiatorContext.superRefine((value, ctx) => {
1414
+ for (const key of reservedServiceTurnInitiatorContextKeys) {
1415
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
1416
+ ctx.addIssue({
1417
+ code: z.ZodIssueCode.custom,
1418
+ path: [key],
1419
+ message: `${key} is reserved OpenGeni initiator context`
1420
+ });
1421
+ }
1422
+ }
1423
+ try {
1424
+ if (new TextEncoder().encode(JSON.stringify(value)).byteLength > 4096) {
1425
+ ctx.addIssue({
1426
+ code: z.ZodIssueCode.custom,
1427
+ message: "service initiator context exceeds 4096 UTF-8 bytes"
1428
+ });
1429
+ }
1430
+ } catch {
1431
+ ctx.addIssue({
1432
+ code: z.ZodIssueCode.custom,
1433
+ message: "service initiator context must be JSON-serializable"
1434
+ });
1435
+ }
1436
+ });
510
1437
  var AccountGrant = z.object({
511
1438
  accountId: z.string().uuid(),
512
1439
  subjectId: z.string().min(1),
@@ -521,7 +1448,11 @@ var AccessGrant = z.object({
521
1448
  subjectId: z.string().min(1),
522
1449
  subjectLabel: z.string().optional(),
523
1450
  permissions: z.array(Permission),
524
- metadata: z.record(z.string(), z.unknown()).optional()
1451
+ metadata: z.record(z.string(), z.unknown()).optional(),
1452
+ // Optional trusted causal principal for a command submitted by an embedding
1453
+ // host. Authorization still uses subjectId + permissions above.
1454
+ serviceInitiator: ServiceTurnInitiator.optional(),
1455
+ serviceInitiatorContext: ServiceTurnInitiatorContext.optional()
525
1456
  });
526
1457
  var AccessContext = z.object({
527
1458
  mode: ProductAccessMode,
@@ -538,6 +1469,11 @@ var DelegatedAccessTokenPayload = z.object({
538
1469
  subjectId: z.string().min(1),
539
1470
  subjectLabel: z.string().optional(),
540
1471
  permissions: z.array(Permission).min(1),
1472
+ // Trusted embedding hosts can sign a causal service principal separately
1473
+ // from the grant subject that authorizes the request. The claim is consumed
1474
+ // only when a command creates a new session/turn.
1475
+ serviceInitiator: ServiceTurnInitiator.optional(),
1476
+ serviceInitiatorContext: ServiceTurnInitiatorContext.optional(),
541
1477
  // Worker-asserted session scope for first-party MCP calls (HMAC-signed, not
542
1478
  // agent-controlled); enables session-scoped tools such as goal management.
543
1479
  sessionId: z.string().uuid().optional(),
@@ -547,36 +1483,71 @@ var DelegatedAccessTokenPayload = z.object({
547
1483
  // sacred-pause guard must know if the CALLER is a machine child-notification
548
1484
  // turn, and the active pointer can flip to another turn mid-check.
549
1485
  turnId: z.string().uuid().optional(),
1486
+ // Exact execution owner. Agent control commands are accepted only while this
1487
+ // attempt still owns the signed turn.
1488
+ attemptId: z.string().uuid().optional(),
1489
+ executionGeneration: z.number().int().positive().optional(),
550
1490
  exp: z.number().int().positive()
1491
+ }).superRefine((payload, ctx) => {
1492
+ if (payload.serviceInitiatorContext && !payload.serviceInitiator) {
1493
+ ctx.addIssue({
1494
+ code: z.ZodIssueCode.custom,
1495
+ path: ["serviceInitiatorContext"],
1496
+ message: "serviceInitiatorContext requires serviceInitiator"
1497
+ });
1498
+ }
1499
+ if (payload.serviceInitiator && (payload.turnId !== void 0 || payload.attemptId !== void 0 || payload.executionGeneration !== void 0)) {
1500
+ ctx.addIssue({
1501
+ code: z.ZodIssueCode.custom,
1502
+ path: ["serviceInitiator"],
1503
+ message: "serviceInitiator cannot replace an exact agent-attempt initiator"
1504
+ });
1505
+ }
551
1506
  });
1507
+ var delegatedAccessTokenPrefix = "ogd_";
1508
+ var delegatedServiceAccessTokenPrefix = "ogd2_";
552
1509
  async function signDelegatedAccessToken(secret, payload) {
553
- const encodedPayload = base64UrlEncode(
554
- JSON.stringify(DelegatedAccessTokenPayload.parse(payload))
1510
+ const parsed = DelegatedAccessTokenPayload.parse(payload);
1511
+ const prefix = parsed.serviceInitiator ? delegatedServiceAccessTokenPrefix : delegatedAccessTokenPrefix;
1512
+ const encodedPayload = base64UrlEncode(JSON.stringify(parsed));
1513
+ const signature = await hmacSha256Base64Url(
1514
+ secret,
1515
+ prefix === delegatedServiceAccessTokenPrefix ? `${prefix}${encodedPayload}` : encodedPayload
555
1516
  );
556
- const signature = await hmacSha256Base64Url(secret, encodedPayload);
557
- return `ogd_${encodedPayload}.${signature}`;
1517
+ return `${prefix}${encodedPayload}.${signature}`;
558
1518
  }
559
1519
  async function verifyDelegatedAccessToken(secret, token, nowSeconds = Math.floor(Date.now() / 1e3)) {
560
- if (!token.startsWith("ogd_")) {
1520
+ const prefix = token.startsWith(delegatedServiceAccessTokenPrefix) ? delegatedServiceAccessTokenPrefix : token.startsWith(delegatedAccessTokenPrefix) ? delegatedAccessTokenPrefix : null;
1521
+ if (!prefix) {
561
1522
  return null;
562
1523
  }
563
- const withoutPrefix = token.slice("ogd_".length);
1524
+ const withoutPrefix = token.slice(prefix.length);
564
1525
  const dot = withoutPrefix.lastIndexOf(".");
565
1526
  if (dot <= 0) {
566
1527
  return null;
567
1528
  }
568
1529
  const encodedPayload = withoutPrefix.slice(0, dot);
569
1530
  const signature = withoutPrefix.slice(dot + 1);
570
- const expected = await hmacSha256Base64Url(secret, encodedPayload);
1531
+ const expected = await hmacSha256Base64Url(
1532
+ secret,
1533
+ prefix === delegatedServiceAccessTokenPrefix ? `${prefix}${encodedPayload}` : encodedPayload
1534
+ );
571
1535
  if (!constantTimeEqual(signature, expected)) {
572
1536
  return null;
573
1537
  }
574
- const payload = DelegatedAccessTokenPayload.safeParse(
575
- JSON.parse(base64UrlDecode(encodedPayload))
576
- );
1538
+ let decoded;
1539
+ try {
1540
+ decoded = JSON.parse(base64UrlDecode(encodedPayload));
1541
+ } catch {
1542
+ return null;
1543
+ }
1544
+ const payload = DelegatedAccessTokenPayload.safeParse(decoded);
577
1545
  if (!payload.success || payload.data.exp < nowSeconds) {
578
1546
  return null;
579
1547
  }
1548
+ if (prefix === delegatedServiceAccessTokenPrefix !== (payload.data.serviceInitiator !== void 0)) {
1549
+ return null;
1550
+ }
580
1551
  return payload.data;
581
1552
  }
582
1553
  var EnrollmentBearerPayload = z.object({
@@ -865,7 +1836,11 @@ var EntitlementValue = z.union([z.boolean(), z.string(), z.number(), z.array(z.s
865
1836
  var Entitlements = z.record(z.string().min(1), EntitlementValue);
866
1837
  var LimitDecision = z.discriminatedUnion("allowed", [
867
1838
  z.object({ allowed: z.literal(true) }),
868
- z.object({ allowed: z.literal(false), code: z.string(), message: z.string() })
1839
+ z.object({
1840
+ allowed: z.literal(false),
1841
+ code: z.string(),
1842
+ message: z.string()
1843
+ })
869
1844
  ]);
870
1845
  var EntitlementDecision = z.discriminatedUnion("allowed", [
871
1846
  z.object({ allowed: z.literal(true), quantity: z.number().optional() }),
@@ -877,9 +1852,13 @@ var EntitlementDecision = z.discriminatedUnion("allowed", [
877
1852
  })
878
1853
  ]);
879
1854
  var GitCredentialProvider = z.enum(["github", "gitlab", "azure_devops"]);
1855
+ var GitCredentialBindingId = z.string().min(1).max(256);
1856
+ var GitRepositoryAccess = z.enum(["read", "write"]);
880
1857
  var GitProviderRepositoryId = z.union([z.number().int().positive(), z.string().min(1)]);
881
1858
  var GitCredentialRepositoryRef = z.object({
882
1859
  provider: GitCredentialProvider.optional(),
1860
+ credentialBindingId: GitCredentialBindingId.optional(),
1861
+ access: GitRepositoryAccess.optional(),
883
1862
  uri: z.string().min(1),
884
1863
  ref: z.string().min(1),
885
1864
  repositoryId: GitProviderRepositoryId.optional(),
@@ -887,6 +1866,56 @@ var GitCredentialRepositoryRef = z.object({
887
1866
  projectId: GitProviderRepositoryId.optional(),
888
1867
  connectionId: z.string().min(1).optional()
889
1868
  });
1869
+ var McpConnectionResourceScope = z.object({
1870
+ /** Provider-stable repository identity, serialized as a string on the wire. */
1871
+ id: z.string().min(1).max(512),
1872
+ kind: z.literal("repository")
1873
+ }).strict();
1874
+ var McpConnectionResourceScopes = z.array(McpConnectionResourceScope).min(1).max(256).superRefine((resources, context) => {
1875
+ const seen = /* @__PURE__ */ new Set();
1876
+ for (const [index, resource] of resources.entries()) {
1877
+ const key = `${resource.kind}\0${resource.id}`;
1878
+ if (seen.has(key)) {
1879
+ context.addIssue({
1880
+ code: "custom",
1881
+ message: "selectedResources must not contain duplicates",
1882
+ path: [index]
1883
+ });
1884
+ }
1885
+ seen.add(key);
1886
+ }
1887
+ });
1888
+ var McpServerConnectionRef = z.object({
1889
+ /** Opaque host or standalone connection identifier. */
1890
+ connectionId: z.string().min(1).optional(),
1891
+ /** Stable provider family (for example github, gitlab, or azure_devops). */
1892
+ provider: z.string().min(1).max(128).optional(),
1893
+ /** Provider host or tenant domain. */
1894
+ providerDomain: z.string().min(1),
1895
+ kind: z.enum(["oauth2", "api_key", "app_install", "delegated"]).optional(),
1896
+ scopes: z.array(z.string().min(1)).optional(),
1897
+ /** OAuth resource indicator. This is distinct from selectedResources. */
1898
+ resource: z.string().min(1).optional(),
1899
+ /** Exact provider resources this MCP binding is allowed to operate on. */
1900
+ selectedResources: McpConnectionResourceScopes.optional(),
1901
+ subjectScope: z.enum(["workspace", "subject"]).optional()
1902
+ }).strict().superRefine((reference, context) => {
1903
+ if (!reference.selectedResources) return;
1904
+ if (!reference.connectionId) {
1905
+ context.addIssue({
1906
+ code: "custom",
1907
+ message: "selectedResources requires connectionId",
1908
+ path: ["connectionId"]
1909
+ });
1910
+ }
1911
+ if (!reference.provider) {
1912
+ context.addIssue({
1913
+ code: "custom",
1914
+ message: "selectedResources requires provider",
1915
+ path: ["provider"]
1916
+ });
1917
+ }
1918
+ });
890
1919
  var BillingBalance = z.object({
891
1920
  accountId: z.string().uuid(),
892
1921
  balanceMicros: z.number().int(),
@@ -913,6 +1942,8 @@ var RepositoryResourceRef = z.object({
913
1942
  mountPath: z.string().min(1).optional(),
914
1943
  subpath: z.string().min(1).optional(),
915
1944
  provider: GitCredentialProvider.optional(),
1945
+ credentialBindingId: GitCredentialBindingId.optional(),
1946
+ access: GitRepositoryAccess.optional(),
916
1947
  repositoryId: GitProviderRepositoryId.optional(),
917
1948
  installationId: GitProviderRepositoryId.optional(),
918
1949
  projectId: GitProviderRepositoryId.optional(),
@@ -920,12 +1951,91 @@ var RepositoryResourceRef = z.object({
920
1951
  githubInstallationId: z.number().int().positive().optional(),
921
1952
  githubRepositoryId: z.number().int().positive().optional()
922
1953
  });
1954
+ function positiveGitProviderInteger(value) {
1955
+ if (typeof value === "number" && Number.isInteger(value) && value > 0) return value;
1956
+ if (typeof value === "string" && /^\d+$/.test(value) && Number(value) > 0) {
1957
+ return Number(value);
1958
+ }
1959
+ return null;
1960
+ }
1961
+ function gitCredentialProviderForRepository(resource) {
1962
+ if (resource.provider) return resource.provider;
1963
+ if (positiveGitProviderInteger(resource.githubInstallationId) && positiveGitProviderInteger(resource.githubRepositoryId)) {
1964
+ return "github";
1965
+ }
1966
+ return null;
1967
+ }
1968
+ function gitCredentialBindingIdForRepository(resource, provider = gitCredentialProviderForRepository(resource)) {
1969
+ if (!provider) return null;
1970
+ const installationId = provider === "github" ? positiveGitProviderInteger(resource.githubInstallationId ?? resource.installationId) : null;
1971
+ return resource.credentialBindingId ?? resource.connectionId ?? (installationId ? `github-installation:${installationId}` : provider);
1972
+ }
923
1973
  var FileResourceRef = z.object({
924
1974
  kind: z.literal("file"),
925
1975
  fileId: z.string().uuid(),
926
1976
  mountPath: z.string().min(1).optional()
927
1977
  });
928
1978
  var ResourceRef = z.discriminatedUnion("kind", [RepositoryResourceRef, FileResourceRef]);
1979
+ var ResourceMountPathError = class extends Error {
1980
+ constructor(message) {
1981
+ super(message);
1982
+ this.name = "ResourceMountPathError";
1983
+ }
1984
+ };
1985
+ function normalizeResourceMountPath(path) {
1986
+ const normalizedSeparators = path.trim().replace(/\\/g, "/");
1987
+ if (!normalizedSeparators || normalizedSeparators.startsWith("/") || /^[A-Za-z]:\//.test(normalizedSeparators) || normalizedSeparators.includes("\0")) {
1988
+ throw new ResourceMountPathError(`invalid resource mount path: ${path}`);
1989
+ }
1990
+ const segments = normalizedSeparators.split("/");
1991
+ if (segments.some(
1992
+ (segment) => !segment || segment === "." || segment === ".." || /[<>:"|?*\u0000-\u001f]/.test(segment) || /[ .]$/.test(segment) || /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(segment)
1993
+ )) {
1994
+ throw new ResourceMountPathError(`invalid resource mount path: ${path}`);
1995
+ }
1996
+ return segments.join("/");
1997
+ }
1998
+ function normalizeRepositorySubpath(path) {
1999
+ const relative = path.trim().replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
2000
+ return normalizeResourceMountPath(relative);
2001
+ }
2002
+ function resourceMountPathCollisionKey(path) {
2003
+ return normalizeResourceMountPath(path).normalize("NFKC").toLowerCase();
2004
+ }
2005
+ function defaultRepositoryMountPath(uri) {
2006
+ let url;
2007
+ try {
2008
+ url = new URL(uri);
2009
+ } catch {
2010
+ throw new ResourceMountPathError(`invalid repository URI for mount path: ${uri}`);
2011
+ }
2012
+ if (url.protocol !== "https:" || !url.host) {
2013
+ throw new ResourceMountPathError(`invalid repository URI for mount path: ${uri}`);
2014
+ }
2015
+ const repositoryPath = url.pathname.replace(/^\/+|\/+$/g, "").replace(/\.git$/, "");
2016
+ const segments = repositoryPath.split("/").filter(Boolean);
2017
+ if (segments.length < 2) {
2018
+ throw new ResourceMountPathError(`repository URI must include owner and repo: ${uri}`);
2019
+ }
2020
+ return normalizeResourceMountPath(
2021
+ `repos/${encodeURIComponent(url.host.toLowerCase())}/${segments.join("/")}`
2022
+ );
2023
+ }
2024
+ function resourceMountPath(resource) {
2025
+ if (resource.mountPath) return normalizeResourceMountPath(resource.mountPath);
2026
+ return resource.kind === "file" ? normalizeResourceMountPath(`files/${resource.fileId}`) : defaultRepositoryMountPath(resource.uri);
2027
+ }
2028
+ function assertUniqueResourceMountPaths(resources) {
2029
+ const mounted = /* @__PURE__ */ new Set();
2030
+ for (const resource of resources) {
2031
+ const path = resourceMountPath(resource);
2032
+ const key = resourceMountPathCollisionKey(path);
2033
+ if (mounted.has(key)) {
2034
+ throw new ResourceRefConflictError(`resource mount path is already attached: ${path}`);
2035
+ }
2036
+ mounted.add(key);
2037
+ }
2038
+ }
929
2039
  var FileStatus = z.enum(["pending_upload", "ready", "failed", "expired", "deleted"]);
930
2040
  var FileUploadStatus = z.enum([
931
2041
  "pending",
@@ -1194,7 +2304,10 @@ var SessionMcpServerInput = z.object({
1194
2304
  requireApproval: z.union([z.boolean(), z.array(z.string().min(1))]).optional(),
1195
2305
  // Write-only credential headers. Values are encrypted at rest and never
1196
2306
  // returned in session responses or events; response metadata exposes names.
1197
- headers: z.record(z.string(), z.string()).optional()
2307
+ headers: z.record(z.string(), z.string()).optional(),
2308
+ // Non-secret opaque pointer resolved at request time by the standalone
2309
+ // connection broker or an embedding host's mcpCredentials port.
2310
+ connectionRef: McpServerConnectionRef.optional()
1198
2311
  });
1199
2312
  var SessionMcpCredentialUpdateInput = z.object({
1200
2313
  id: z.string().min(1).regex(registryId),
@@ -1205,7 +2318,8 @@ var SessionMcpServerMetadata = z.object({
1205
2318
  name: z.string().min(1).nullable(),
1206
2319
  url: httpsUrl,
1207
2320
  headerNames: z.array(z.string()).default([]),
1208
- credentialVersion: z.number().int().positive()
2321
+ credentialVersion: z.number().int().positive(),
2322
+ connectionRef: McpServerConnectionRef.nullable().default(null)
1209
2323
  }).strict();
1210
2324
  var ResourceRefConflictError = class extends Error {
1211
2325
  constructor(message) {
@@ -1232,10 +2346,13 @@ function mergeToolRefs(existing, additions) {
1232
2346
  return order.map((key) => byKey.get(key));
1233
2347
  }
1234
2348
  function mergeResourceRefs(existing, additions, options = {}) {
2349
+ if (options.rejectConflicts) {
2350
+ assertUniqueResourceMountPaths(existing);
2351
+ }
1235
2352
  const out = [...existing];
1236
2353
  const mountPaths = new Map(
1237
- existing.flatMap(
1238
- (resource) => resource.mountPath ? [[resource.mountPath, stableJson(resource)]] : []
2354
+ existing.map(
2355
+ (resource) => [resourceMountPathCollisionKey(resourceMountPath(resource)), stableJson(resource)]
1239
2356
  )
1240
2357
  );
1241
2358
  const identities = new Map(
@@ -1248,11 +2365,10 @@ function mergeResourceRefs(existing, additions, options = {}) {
1248
2365
  continue;
1249
2366
  }
1250
2367
  if (options.rejectConflicts) {
1251
- const existingAtMount = resource.mountPath ? mountPaths.get(resource.mountPath) : void 0;
2368
+ const mountPath = resourceMountPath(resource);
2369
+ const existingAtMount = mountPaths.get(resourceMountPathCollisionKey(mountPath));
1252
2370
  if (existingAtMount && existingAtMount !== serialized) {
1253
- throw new ResourceRefConflictError(
1254
- `resource mount path is already attached: ${resource.mountPath}`
1255
- );
2371
+ throw new ResourceRefConflictError(`resource mount path is already attached: ${mountPath}`);
1256
2372
  }
1257
2373
  const identity = resourceIdentityKey(resource);
1258
2374
  const existingIdentity = identities.get(identity);
@@ -1265,9 +2381,7 @@ function mergeResourceRefs(existing, additions, options = {}) {
1265
2381
  out.push(resource);
1266
2382
  exact.add(serialized);
1267
2383
  identities.set(resourceIdentityKey(resource), serialized);
1268
- if (resource.mountPath) {
1269
- mountPaths.set(resource.mountPath, serialized);
1270
- }
2384
+ mountPaths.set(resourceMountPathCollisionKey(resourceMountPath(resource)), serialized);
1271
2385
  }
1272
2386
  return out;
1273
2387
  }
@@ -1304,7 +2418,8 @@ var SessionTurnStatus = z.enum([
1304
2418
  "completed",
1305
2419
  "failed",
1306
2420
  "cancelled",
1307
- "superseded"
2421
+ "superseded",
2422
+ "withdrawn_for_edit"
1308
2423
  ]);
1309
2424
  var SessionTurnSource = z.enum([
1310
2425
  "user",
@@ -1366,7 +2481,9 @@ var ClearSessionContextRequest = z.object({
1366
2481
  confirm: z.literal(true)
1367
2482
  });
1368
2483
  var CLEARED_RUN_STATE_MARKER = "$opengeniCleared";
1369
- var CLEARED_RUN_STATE_BLOB = JSON.stringify({ [CLEARED_RUN_STATE_MARKER]: true });
2484
+ var CLEARED_RUN_STATE_BLOB = JSON.stringify({
2485
+ [CLEARED_RUN_STATE_MARKER]: true
2486
+ });
1370
2487
  function isClearedRunStateBlob(serialized) {
1371
2488
  if (!serialized) {
1372
2489
  return false;
@@ -1386,6 +2503,104 @@ var CompactSessionContextResult = z.object({
1386
2503
  status: z.enum(["pending", "completed", "noop"]),
1387
2504
  message: z.string()
1388
2505
  });
2506
+ var TurnInitiator = z.object({
2507
+ kind: z.enum(["subject", "service"]),
2508
+ ...turnInitiatorIdentityFields
2509
+ });
2510
+ var SessionAuthorizationSurface = z.enum([
2511
+ "http",
2512
+ "core",
2513
+ "stream",
2514
+ "first_party_mcp",
2515
+ "toolspace"
2516
+ ]);
2517
+ var SessionAuthorizationOperation = z.enum([
2518
+ "session.read",
2519
+ "session.events.read",
2520
+ "session.stream.read",
2521
+ "session.stream.acknowledge",
2522
+ "session.turns.read",
2523
+ "session.append",
2524
+ "session.steer",
2525
+ "session.control",
2526
+ "session.queue.read",
2527
+ "session.queue.control",
2528
+ "session.composer.read",
2529
+ "session.composer.write",
2530
+ "session.lineage.read",
2531
+ "session.capture.read",
2532
+ "session.files.read",
2533
+ "session.files.write",
2534
+ "session.git.read",
2535
+ "session.terminal.read",
2536
+ "session.terminal.control",
2537
+ "session.viewer.read",
2538
+ "session.viewer.control",
2539
+ "session.first_party_mcp.call",
2540
+ "session.toolspace.call",
2541
+ "session.pin.write",
2542
+ "session.codex_account.write",
2543
+ "session.context.write",
2544
+ "session.approval.write",
2545
+ "session.human_input.read",
2546
+ "session.human_input.write",
2547
+ "session.title.write",
2548
+ "session.goal.read",
2549
+ "session.goal.write",
2550
+ "session.child.create"
2551
+ ]);
2552
+ var SessionAuthorizationActor = z.discriminatedUnion("kind", [
2553
+ z.object({
2554
+ kind: z.literal("subject"),
2555
+ subjectId: z.string().min(1),
2556
+ subjectLabel: z.string().min(1).optional()
2557
+ }),
2558
+ z.object({
2559
+ kind: z.literal("agent_attempt"),
2560
+ /** Technical, authenticated first-party caller (not the host authority). */
2561
+ subjectId: z.string().min(1),
2562
+ callerSessionId: z.string().uuid(),
2563
+ callerRootSessionId: z.string().uuid(),
2564
+ turnId: z.string().uuid(),
2565
+ attemptId: z.string().uuid(),
2566
+ executionGeneration: z.number().int().positive(),
2567
+ /** Frozen authority that admitted the calling turn. */
2568
+ initiator: TurnInitiator,
2569
+ initiatorContext: TurnInitiatorContext
2570
+ })
2571
+ ]);
2572
+ var SessionAuthorizationTarget = z.object({
2573
+ sessionId: z.string().uuid(),
2574
+ /** Server-resolved workspace lineage root; never accepted from a caller. */
2575
+ rootSessionId: z.string().uuid()
2576
+ });
2577
+ var SessionAuthorizationDecision = z.discriminatedUnion("allowed", [
2578
+ z.object({
2579
+ allowed: z.literal(true),
2580
+ /**
2581
+ * Whether related-session metadata may be projected with the target.
2582
+ * `target` is the fail-closed default for exact shares; `root` permits the
2583
+ * target's full lineage tree. This does not authorize a separate operation
2584
+ * against another session, which always requires its own decision.
2585
+ */
2586
+ relatedSessionAccess: z.enum(["target", "root"]).optional(),
2587
+ /** A host may request a tighter stream reauthorization bound. */
2588
+ reauthorizeAfterMs: z.number().int().min(1e3).max(6e4).optional()
2589
+ }),
2590
+ z.object({
2591
+ allowed: z.literal(false),
2592
+ reason: z.enum(["not_found", "forbidden", "revoked"])
2593
+ })
2594
+ ]);
2595
+ var SESSION_AUTHORIZATION_LIST_SCOPE_MAX_IDS = 1e4;
2596
+ var SessionAuthorizationListScope = z.discriminatedUnion("kind", [
2597
+ z.object({ kind: z.literal("all") }),
2598
+ z.object({
2599
+ kind: z.literal("scoped"),
2600
+ rootSessionIds: z.array(z.string().uuid()).max(SESSION_AUTHORIZATION_LIST_SCOPE_MAX_IDS),
2601
+ sessionIds: z.array(z.string().uuid()).max(SESSION_AUTHORIZATION_LIST_SCOPE_MAX_IDS)
2602
+ })
2603
+ ]);
1389
2604
  var SessionTurn = z.object({
1390
2605
  id: z.string().uuid(),
1391
2606
  workspaceId: z.string().uuid(),
@@ -1408,6 +2623,8 @@ var SessionTurn = z.object({
1408
2623
  executionGeneration: z.number().int().nonnegative(),
1409
2624
  activeAttemptId: z.string().uuid().nullable(),
1410
2625
  lineage: z.record(z.string(), z.unknown()),
2626
+ initiator: TurnInitiator,
2627
+ initiatorContext: TurnInitiatorContext,
1411
2628
  cancelledBy: z.string().nullable(),
1412
2629
  cancelReason: z.string().nullable(),
1413
2630
  startedAt: z.string().nullable(),
@@ -1415,56 +2632,311 @@ var SessionTurn = z.object({
1415
2632
  createdAt: z.string(),
1416
2633
  updatedAt: z.string()
1417
2634
  });
2635
+ var EffectiveControlBlocker = z.object({
2636
+ kind: z.enum(["session", "workspace"]),
2637
+ sessionId: z.string().uuid().optional(),
2638
+ displayName: z.string().min(1),
2639
+ actor: z.string().nullable(),
2640
+ reason: z.string().nullable(),
2641
+ changedAt: z.string().nullable(),
2642
+ revision: z.number().int().nonnegative()
2643
+ });
2644
+ var EffectiveControlResumeOption = z.object({
2645
+ scope: z.enum(["selected", "session", "workspace"]),
2646
+ targetId: z.string().uuid().optional(),
2647
+ selectedStateAfter: SessionControlState,
2648
+ remainingPrimaryBlocker: EffectiveControlBlocker.optional(),
2649
+ impactCopy: z.string().min(1)
2650
+ });
2651
+ var EffectiveSessionControl = z.object({
2652
+ state: SessionControlState,
2653
+ controlVersion: z.number().int().nonnegative(),
2654
+ controlEtag: z.string().min(1),
2655
+ directState: SessionControlState,
2656
+ primaryBlocker: EffectiveControlBlocker.nullable(),
2657
+ additionalBlockerCount: z.number().int().nonnegative(),
2658
+ blockers: z.array(EffectiveControlBlocker),
2659
+ resumeOptions: z.array(EffectiveControlResumeOption),
2660
+ override: z.object({
2661
+ rootSessionId: z.string().uuid(),
2662
+ revision: z.number().int().nonnegative()
2663
+ }).nullable(),
2664
+ settlement: z.object({
2665
+ state: z.literal("stopping"),
2666
+ attemptCount: z.number().int().positive(),
2667
+ interruptionPendingCount: z.number().int().nonnegative(),
2668
+ quiescencePendingCount: z.number().int().nonnegative()
2669
+ }).nullable()
2670
+ });
2671
+ var SESSION_OPERATION_KEY_MAX_CHARS = 256;
2672
+ var SessionOperationKey = z.string().min(1).max(SESSION_OPERATION_KEY_MAX_CHARS);
2673
+ var SessionCommandReceipt = z.object({
2674
+ id: z.string().uuid(),
2675
+ action: z.string().min(1),
2676
+ operationKey: z.string().min(1).max(SESSION_OPERATION_KEY_MAX_CHARS),
2677
+ targetSessionId: z.string().uuid().nullable(),
2678
+ targetTurnId: z.string().uuid().nullable(),
2679
+ appliedControlRevision: z.number().int().nonnegative().nullable(),
2680
+ appliedQueueVersion: z.number().int().nonnegative().nullable(),
2681
+ appliedTurnVersion: z.number().int().positive().nullable(),
2682
+ appliedDraftRevision: z.number().int().positive().nullable(),
2683
+ createdAt: z.string()
2684
+ });
2685
+ var ComposerDraft = z.object({
2686
+ revision: z.number().int().nonnegative(),
2687
+ text: z.string(),
2688
+ resources: z.array(ResourceRef),
2689
+ tools: z.array(ToolRef),
2690
+ model: z.string().min(1),
2691
+ reasoningEffort: ReasoningEffort,
2692
+ sourceTurnId: z.string().uuid().nullable(),
2693
+ sourceTurnVersion: z.number().int().positive().nullable(),
2694
+ updatedAt: z.string().nullable()
2695
+ });
1418
2696
  var SessionQueueSnapshot = z.object({
1419
2697
  version: z.number().int().nonnegative(),
1420
- controlState: SessionControlState,
1421
- controlGeneration: z.number().int().nonnegative(),
1422
- workspaceInferenceState: WorkspaceInferenceState,
1423
- workspaceInferenceGeneration: z.number().int().nonnegative(),
1424
- workspaceRunExceptionGeneration: z.number().int().nonnegative().nullable(),
2698
+ effectiveControl: EffectiveSessionControl,
2699
+ /**
2700
+ * True while the latest attempt is interrupted but has not durably proved
2701
+ * quiescence: no more inference, user-visible output, or workspace-persistence
2702
+ * authority. Temporal cancellation/terminalization is not that proof. This is
2703
+ * distinct from ordinary capacity queueing, remains accurate with an empty
2704
+ * visible queue, and is independent of Steer-row metadata or withdrawal.
2705
+ */
2706
+ stoppingPreviousAttempt: z.boolean(),
1425
2707
  items: z.array(SessionTurn)
1426
2708
  });
1427
- var CancelSessionQueueItemRequest = z.object({
2709
+ var MoveSessionQueueItemRequest = z.object({
2710
+ clientEventId: SessionOperationKey,
1428
2711
  expectedQueueVersion: z.number().int().nonnegative(),
1429
- expectedItemVersion: z.number().int().positive(),
2712
+ beforeTurnId: z.string().uuid().nullable()
2713
+ });
2714
+ var EditSessionQueueItemRequest = z.object({
2715
+ clientEventId: SessionOperationKey,
2716
+ expectedTurnVersion: z.number().int().positive(),
2717
+ expectedDraftRevision: z.number().int().nonnegative(),
2718
+ replaceDraft: z.boolean()
2719
+ });
2720
+ var SteerSessionQueueItemRequest = z.object({
2721
+ clientEventId: SessionOperationKey,
2722
+ expectedTurnVersion: z.number().int().positive(),
2723
+ controlEtag: z.string().min(1).optional()
2724
+ });
2725
+ var DeleteSessionQueueItemRequest = z.object({
2726
+ clientEventId: SessionOperationKey,
2727
+ expectedTurnVersion: z.number().int().positive(),
1430
2728
  reason: z.string().min(1).optional()
1431
2729
  });
2730
+ var SaveComposerDraftRequest = ComposerDraft.pick({
2731
+ text: true,
2732
+ resources: true,
2733
+ tools: true,
2734
+ model: true,
2735
+ reasoningEffort: true
2736
+ }).extend({ expectedRevision: z.number().int().nonnegative() });
2737
+ var WORKSPACE_CONTROL_REASON_MAX_BYTES = 8 * 1024;
2738
+ var WORKSPACE_CONTROL_ACTOR_MAX_BYTES = 1024;
2739
+ var WORKSPACE_CONTROL_EVENT_MAX_BYTES = 16 * 1024;
2740
+ var WorkspaceControlReason = z.string().min(1).refine((value) => !value.includes("\0"), "reason must not contain NUL bytes").refine(
2741
+ (value) => workspaceControlUtf8Bytes(value) <= WORKSPACE_CONTROL_REASON_MAX_BYTES,
2742
+ `reason must not exceed ${WORKSPACE_CONTROL_REASON_MAX_BYTES} UTF-8 bytes`
2743
+ );
1432
2744
  var SessionControlRequest = z.object({
1433
- mode: z.enum(["pause", "resume"]),
1434
- reason: z.string().min(1).optional(),
1435
- clientEventId: z.string().min(1).optional(),
1436
- expectedControlState: SessionControlState.optional(),
1437
- expectedControlGeneration: z.number().int().nonnegative().optional(),
1438
- expectedWorkspaceInferenceGeneration: z.number().int().nonnegative().optional()
2745
+ action: z.enum(["pause", "resume"]),
2746
+ reason: WorkspaceControlReason.optional(),
2747
+ clientEventId: SessionOperationKey,
2748
+ expectedControlEtag: z.string().min(1).optional()
1439
2749
  });
1440
2750
  var WorkspaceInferenceControlRequest = z.object({
1441
- state: WorkspaceInferenceState,
1442
- reason: z.string().min(1),
1443
- clientEventId: z.string().min(1),
1444
- expectedState: WorkspaceInferenceState,
1445
- expectedGeneration: z.number().int().nonnegative(),
1446
- exceptSessionIds: z.array(z.string().uuid()).default([])
2751
+ action: z.enum(["pause", "resume"]),
2752
+ reason: WorkspaceControlReason.optional(),
2753
+ clientEventId: SessionOperationKey,
2754
+ expectedRevision: z.number().int().nonnegative().optional()
1447
2755
  });
1448
2756
  var WorkspaceInferenceControlResponse = z.object({
1449
- operationId: z.string().uuid(),
1450
- state: WorkspaceInferenceState,
1451
- generation: z.number().int().nonnegative(),
1452
- affectedSessionIds: z.array(z.string().uuid()),
1453
- controlSessionIds: z.array(z.string().uuid()),
1454
- exceptionSessionIds: z.array(z.string().uuid())
2757
+ receipt: SessionCommandReceipt,
2758
+ state: SessionControlState,
2759
+ revision: z.number().int().nonnegative(),
2760
+ interruptionCount: z.number().int().nonnegative(),
2761
+ wakeCount: z.number().int().nonnegative()
2762
+ });
2763
+ var WorkspaceControlEventTruncation = z.object({
2764
+ truncated: z.literal(true),
2765
+ surface: z.enum([
2766
+ "durable_control",
2767
+ "database_guard",
2768
+ "http_projection",
2769
+ "nats_legacy_guard",
2770
+ "sse_legacy_guard"
2771
+ ]),
2772
+ deliveredBytes: z.number().int().nonnegative(),
2773
+ fields: z.array(
2774
+ z.object({
2775
+ field: z.enum(["reason", "actor"]),
2776
+ originalBytes: z.number().int().nonnegative(),
2777
+ deliveredBytes: z.number().int().nonnegative(),
2778
+ omittedBytes: z.number().int().nonnegative()
2779
+ })
2780
+ ),
2781
+ fullEvidence: z.object({
2782
+ available: z.literal(false),
2783
+ reason: z.literal("not_retained")
2784
+ })
2785
+ });
2786
+ var WorkspaceControlEvent = z.object({
2787
+ id: z.string().uuid(),
2788
+ workspaceId: z.string().uuid(),
2789
+ sequence: z.number().int().positive(),
2790
+ revision: z.number().int().positive(),
2791
+ type: z.literal("workspace.control.changed"),
2792
+ scope: z.enum(["workspace", "session"]),
2793
+ rootSessionId: z.string().uuid().nullable(),
2794
+ action: z.enum(["pause", "resume"]),
2795
+ automatic: z.boolean(),
2796
+ reason: z.string().nullable(),
2797
+ actor: z.string().min(1),
2798
+ occurredAt: z.string(),
2799
+ truncation: WorkspaceControlEventTruncation.nullable().optional()
1455
2800
  });
2801
+ function workspaceControlUtf8Bytes(value) {
2802
+ return new TextEncoder().encode(value).byteLength;
2803
+ }
2804
+ function boundWorkspaceControlEvent(event, options = {}) {
2805
+ const existingFields = new Map(
2806
+ (event.truncation?.fields ?? []).map((field) => [field.field, field])
2807
+ );
2808
+ const reason = event.reason === null ? null : boundWorkspaceControlText(event.reason, WORKSPACE_CONTROL_REASON_MAX_BYTES);
2809
+ const actor = boundWorkspaceControlText(event.actor, WORKSPACE_CONTROL_ACTOR_MAX_BYTES);
2810
+ const reasonBytes = reason === null ? 0 : workspaceControlUtf8Bytes(reason);
2811
+ const actorBytes = workspaceControlUtf8Bytes(actor);
2812
+ const reasonOriginalBytes = event.reason === null ? null : Math.max(
2813
+ workspaceControlUtf8Bytes(event.reason),
2814
+ normalizedWorkspaceControlOriginalBytes(options.reasonOriginalBytes),
2815
+ existingFields.get("reason")?.originalBytes ?? 0
2816
+ );
2817
+ const actorOriginalBytes = Math.max(
2818
+ workspaceControlUtf8Bytes(event.actor),
2819
+ normalizedWorkspaceControlOriginalBytes(options.actorOriginalBytes),
2820
+ existingFields.get("actor")?.originalBytes ?? 0
2821
+ );
2822
+ const fields = [];
2823
+ if (reasonOriginalBytes !== null && reasonOriginalBytes > reasonBytes) {
2824
+ fields.push({
2825
+ field: "reason",
2826
+ originalBytes: reasonOriginalBytes,
2827
+ deliveredBytes: reasonBytes,
2828
+ omittedBytes: reasonOriginalBytes - reasonBytes
2829
+ });
2830
+ }
2831
+ if (actorOriginalBytes > actorBytes) {
2832
+ fields.push({
2833
+ field: "actor",
2834
+ originalBytes: actorOriginalBytes,
2835
+ deliveredBytes: actorBytes,
2836
+ omittedBytes: actorOriginalBytes - actorBytes
2837
+ });
2838
+ }
2839
+ if (fields.length === 0 && event.truncation == null) {
2840
+ if (sessionEventJsonBytes(event) > WORKSPACE_CONTROL_EVENT_MAX_BYTES) {
2841
+ throw new RangeError("Workspace control event exceeds its bounded envelope");
2842
+ }
2843
+ return event;
2844
+ }
2845
+ const truncation = {
2846
+ truncated: true,
2847
+ surface: event.truncation?.surface ?? options.surface ?? "durable_control",
2848
+ deliveredBytes: 0,
2849
+ fields,
2850
+ fullEvidence: { available: false, reason: "not_retained" }
2851
+ };
2852
+ const bounded = {
2853
+ ...event,
2854
+ reason,
2855
+ actor,
2856
+ truncation
2857
+ };
2858
+ settleWorkspaceControlDeliveredBytes(bounded, truncation);
2859
+ const deliveredBytes = sessionEventJsonBytes(bounded);
2860
+ if (deliveredBytes > WORKSPACE_CONTROL_EVENT_MAX_BYTES) {
2861
+ throw new RangeError(
2862
+ `Bounded workspace control event exceeds its final envelope (${deliveredBytes} > ${WORKSPACE_CONTROL_EVENT_MAX_BYTES} bytes)`
2863
+ );
2864
+ }
2865
+ return bounded;
2866
+ }
2867
+ function boundWorkspaceControlText(value, maxBytes) {
2868
+ const encoder2 = new TextEncoder();
2869
+ const decoder = new TextDecoder();
2870
+ const bytes = encoder2.encode(value);
2871
+ if (bytes.byteLength <= maxBytes) return value;
2872
+ const marker = "\u2026[truncated]";
2873
+ const prefixBudget = Math.max(0, maxBytes - encoder2.encode(marker).byteLength);
2874
+ let prefixEnd = Math.min(prefixBudget, bytes.byteLength);
2875
+ while (prefixEnd > 0 && prefixEnd < bytes.byteLength && (bytes[prefixEnd] & 192) === 128) {
2876
+ prefixEnd -= 1;
2877
+ }
2878
+ return `${decoder.decode(bytes.subarray(0, prefixEnd))}${marker}`;
2879
+ }
2880
+ function normalizedWorkspaceControlOriginalBytes(value) {
2881
+ return value === null || value === void 0 || !Number.isFinite(value) ? 0 : Math.max(0, Math.floor(value));
2882
+ }
2883
+ function settleWorkspaceControlDeliveredBytes(event, truncation) {
2884
+ for (let attempt = 0; attempt < 16; attempt += 1) {
2885
+ const deliveredBytes2 = sessionEventJsonBytes(event);
2886
+ if (truncation.deliveredBytes === deliveredBytes2) return;
2887
+ truncation.deliveredBytes = deliveredBytes2;
2888
+ }
2889
+ const deliveredBytes = sessionEventJsonBytes(event);
2890
+ if (truncation.deliveredBytes !== deliveredBytes) {
2891
+ throw new RangeError("Workspace control event byte accounting did not converge");
2892
+ }
2893
+ }
1456
2894
  var SystemUpdateClassification = z.enum(["success", "failure", "action_required", "info"]);
1457
2895
  var SessionSystemUpdateKind = z.enum([
1458
- "child_session_update",
1459
- "scheduled_wake",
1460
- "lifecycle_event",
1461
- "runtime_notice"
2896
+ "scheduled_occurrence",
2897
+ "goal_continuation",
2898
+ "agent_message",
2899
+ "agent_steer_instruction",
2900
+ "child_terminal_result"
2901
+ ]);
2902
+ var SessionSystemUpdatePayload = z.discriminatedUnion("type", [
2903
+ z.object({
2904
+ type: z.literal("scheduled_occurrence"),
2905
+ text: z.string().min(1),
2906
+ scheduledTaskId: z.string().uuid(),
2907
+ scheduledTaskRunId: z.string().uuid(),
2908
+ resources: z.array(ResourceRef).optional(),
2909
+ tools: z.array(ToolRef).optional()
2910
+ }).passthrough(),
2911
+ z.object({
2912
+ type: z.literal("goal_continuation"),
2913
+ goalId: z.string().uuid(),
2914
+ goalVersion: z.number().int().positive(),
2915
+ prompt: z.string().min(1),
2916
+ reason: z.string().optional()
2917
+ }).passthrough(),
2918
+ z.object({
2919
+ type: z.literal("agent_message"),
2920
+ text: z.string().min(1),
2921
+ operationId: z.string().uuid()
2922
+ }).passthrough(),
2923
+ z.object({
2924
+ type: z.literal("agent_steer_instruction"),
2925
+ instruction: z.string().min(1),
2926
+ operationId: z.string().uuid()
2927
+ }).passthrough(),
2928
+ z.object({
2929
+ type: z.literal("child_terminal_result"),
2930
+ childSessionId: z.string().uuid(),
2931
+ status: z.enum(["idle", "failed"])
2932
+ }).passthrough()
1462
2933
  ]);
1463
2934
  var SessionSystemUpdateState = z.enum([
1464
2935
  "pending",
1465
2936
  "deferred",
1466
2937
  "delivered",
1467
2938
  "cancelled",
2939
+ "superseded",
1468
2940
  "failed"
1469
2941
  ]);
1470
2942
  var SessionSystemUpdate = z.object({
@@ -1475,7 +2947,7 @@ var SessionSystemUpdate = z.object({
1475
2947
  sourceId: z.string(),
1476
2948
  dedupeKey: z.string(),
1477
2949
  summary: z.string(),
1478
- payload: z.record(z.string(), z.unknown()),
2950
+ payload: SessionSystemUpdatePayload,
1479
2951
  lineage: z.record(z.string(), z.unknown()),
1480
2952
  state: SessionSystemUpdateState,
1481
2953
  deliveredTurnId: z.string().uuid().nullable(),
@@ -1628,7 +3100,10 @@ var RigDefinitionEditPayload = z.object({
1628
3100
  });
1629
3101
  var ProposeRigChangeRequest = z.discriminatedUnion("kind", [
1630
3102
  z.object({ kind: z.literal("setup_append"), payload: RigSetupAppendPayload }),
1631
- z.object({ kind: z.literal("definition_edit"), payload: RigDefinitionEditPayload })
3103
+ z.object({
3104
+ kind: z.literal("definition_edit"),
3105
+ payload: RigDefinitionEditPayload
3106
+ })
1632
3107
  ]);
1633
3108
  var ScheduledTaskStatus = z.enum(["active", "paused"]);
1634
3109
  var ScheduledTaskRunStatus = z.enum(["queued", "dispatched", "failed"]);
@@ -1958,14 +3433,6 @@ var CreateSocialPostRequest = z.object({
1958
3433
  });
1959
3434
  var ConnectionKind = z.enum(["oauth2", "api_key", "app_install", "delegated"]);
1960
3435
  var ConnectionStatus = z.enum(["active", "needs_reauth", "revoked", "error"]);
1961
- var McpServerConnectionRef = z.object({
1962
- connectionId: z.string().uuid().optional(),
1963
- providerDomain: z.string().min(1),
1964
- kind: ConnectionKind.optional(),
1965
- scopes: z.array(z.string().min(1)).optional(),
1966
- resource: z.string().min(1).optional(),
1967
- subjectScope: z.enum(["workspace", "subject"]).optional()
1968
- }).strict();
1969
3436
  var ConnectionMetadata = z.object({
1970
3437
  id: z.string().uuid(),
1971
3438
  accountId: z.string().uuid(),
@@ -2056,6 +3523,7 @@ var MarketingDailyAnalysisTaskRequest = z.object({
2056
3523
  var CapabilityKind = z.enum(["pack", "mcp", "api", "skill", "plugin"]);
2057
3524
  var CapabilitySource = z.enum([
2058
3525
  "built_in",
3526
+ "library",
2059
3527
  "configured",
2060
3528
  "public_registry",
2061
3529
  "registry",
@@ -2183,6 +3651,9 @@ var Session = z.object({
2183
3651
  resources: z.array(ResourceRef),
2184
3652
  tools: z.array(ToolRef),
2185
3653
  metadata: z.record(z.string(), z.unknown()),
3654
+ /** Frozen creator fact used only for creation attribution/idempotent repair. */
3655
+ createdBy: TurnInitiator,
3656
+ createdByContext: TurnInitiatorContext,
2186
3657
  model: z.string(),
2187
3658
  sandboxBackend: SandboxBackend,
2188
3659
  // The OS the session's box runs. Defaults to 'linux' (today's only OS).
@@ -2232,12 +3703,7 @@ var Session = z.object({
2232
3703
  queueVersion: z.number().int().nonnegative(),
2233
3704
  queueHeadPosition: z.number().int(),
2234
3705
  queueTailPosition: z.number().int(),
2235
- controlState: SessionControlState,
2236
- controlGeneration: z.number().int().nonnegative(),
2237
- controlReason: z.string().nullable(),
2238
- controlChangedBy: z.string().nullable(),
2239
- controlChangedAt: z.string().nullable(),
2240
- workspaceRunExceptionGeneration: z.number().int().nonnegative().nullable(),
3706
+ effectiveControl: EffectiveSessionControl,
2241
3707
  lastSequence: z.number().int().nonnegative(),
2242
3708
  // Multi-account Codex (P1). codexPinnedCredentialId: the account this session is
2243
3709
  // manually PINNED to (null ⇒ follow the workspace active pointer).
@@ -2263,13 +3729,20 @@ var Session = z.object({
2263
3729
  queuedDescendants: z.number().int().nonnegative(),
2264
3730
  attentionDescendants: z.number().int().nonnegative(),
2265
3731
  pausedDescendants: z.number().int().nonnegative(),
2266
- failedDescendants: z.number().int().nonnegative()
3732
+ failedDescendants: z.number().int().nonnegative(),
3733
+ /** Counts are lower bounds rather than exact totals when true. */
3734
+ truncated: z.boolean().default(false)
2267
3735
  }).optional(),
2268
3736
  createdAt: z.string(),
2269
3737
  updatedAt: z.string()
2270
3738
  });
3739
+ var CreateSessionResponse = Session.extend({
3740
+ initialTurnId: z.string().uuid().nullable()
3741
+ });
2271
3742
  var SessionListResponse = z.object({
2272
3743
  pinned: z.array(Session),
3744
+ /** True when older matching pins were omitted from this bounded page. */
3745
+ pinnedTruncated: z.boolean().optional(),
2273
3746
  sessions: z.array(Session),
2274
3747
  nextCursor: z.string().nullable()
2275
3748
  });
@@ -2286,8 +3759,14 @@ var SessionLineageResponse = z.object({
2286
3759
  });
2287
3760
  var SessionEventType = z.enum([
2288
3761
  "session.created",
3762
+ // Defensive read/transport projection for a malformed or historically
3763
+ // oversized retained event envelope. The original row stays durable; this
3764
+ // explicit synthetic type prevents unbounded free-form envelope fields from
3765
+ // crossing NATS, SSE, REST, or browser boundaries.
3766
+ "session.event.envelope_omitted",
2289
3767
  "session.status.changed",
2290
3768
  "session.requiresAction",
3769
+ "session.humanInput.requested",
2291
3770
  "session.context.compaction.requested",
2292
3771
  "session.context.compacted",
2293
3772
  "session.context.compaction.skipped",
@@ -2295,6 +3774,7 @@ var SessionEventType = z.enum([
2295
3774
  "user.message",
2296
3775
  "user.pause",
2297
3776
  "user.approvalDecision",
3777
+ "user.humanInputResponse",
2298
3778
  "turn.queued",
2299
3779
  "turn.started",
2300
3780
  "turn.completed",
@@ -2310,6 +3790,7 @@ var SessionEventType = z.enum([
2310
3790
  "agent.toolCall.output",
2311
3791
  "agent.model.usage",
2312
3792
  "tool.auth_needed",
3793
+ "credential.auth_needed",
2313
3794
  "agent.updated",
2314
3795
  "rig.setup.started",
2315
3796
  "rig.setup.completed",
@@ -2334,6 +3815,7 @@ var SessionEventType = z.enum([
2334
3815
  "session.control.steer_requested",
2335
3816
  "workspace.inference.paused",
2336
3817
  "workspace.inference.resumed",
3818
+ "session.queue.changed",
2337
3819
  "session.queue.prompt.cancelled",
2338
3820
  "session.queue.history",
2339
3821
  // A terminal/stale activity callback is retained as an audit wrapper rather
@@ -2352,8 +3834,8 @@ var SessionEventType = z.enum([
2352
3834
  // a viewer detached / was reaped
2353
3835
  "stream.revoked",
2354
3836
  // a grant was revoked → connected clients MUST disconnect now
2355
- // Channel-B recording signals (P4.3 / module 05 §3.4). The "agent films itself
2356
- // proving the fix" loop: ffmpeg x11grab of the SAME :0 humans watch → artifact
3837
+ // Desktop recording signals. The capture loop records the same display humans
3838
+ // watch, then stores the finalized artifact for replay.
2357
3839
  // → storage. The artifact ref rides the AVAILABLE event (storageKey, NOT a
2358
3840
  // long-lived URL — clients mint a short-TTL signed GET via the route).
2359
3841
  "recording.started",
@@ -2362,8 +3844,8 @@ var SessionEventType = z.enum([
2362
3844
  // finalized: bytes PUT to storage, replayable
2363
3845
  "recording.failed",
2364
3846
  // ffmpeg/box-death/rollover/upload error — no artifact
2365
- // Channel-A structured-service notifications (P4.4 / modules/08-channel-a.md
2366
- // §2.2). The A2 reads (fs/git/terminal exec) are SYNCHRONOUS API-direct point
3847
+ // Structured-service notifications. File, Git, and terminal reads are
3848
+ // synchronous API-direct point
2367
3849
  // queries (their result is the HTTP response, NEVER an event). What rides A1
2368
3850
  // here are the side-effect NOTIFICATIONS — a path changed, git state changed,
2369
3851
  // a pty opened/printed/exited — durable, sequenced, gap-filled like every
@@ -2385,10 +3867,10 @@ var SessionEventType = z.enum([
2385
3867
  // (manual switch in P1; failover/rotation in P3 reuse the same event). Drives
2386
3868
  // the in-session "Running on:" indicator's live flip.
2387
3869
  "codex.account.switched",
2388
- // OPE-21 per-turn selection audit. Payload is metadata only: credential row
3870
+ // credential allocator per-turn selection audit. Payload is metadata only: credential row
2389
3871
  // id, bounded strategy/reason, and pool counts — never token material.
2390
3872
  "codex.credential.selected",
2391
- // OPE-21 durable zero-capacity wait lifecycle. Runtime/system events only;
3873
+ // credential allocator durable zero-capacity wait lifecycle. Runtime/system events only;
2392
3874
  // no synthetic user message is created when capacity returns.
2393
3875
  "codex.capacity.waiting",
2394
3876
  "codex.capacity.resumed",
@@ -2418,12 +3900,12 @@ var SessionEventType = z.enum([
2418
3900
  // target id or command content. Announce-only; hits the timeline projection default
2419
3901
  // (no rendered item) like the other sandbox.* diagnostics.
2420
3902
  "session.route.reconciled",
2421
- // Workbench v2 turn-end workspace capture (dossier §10.1). ANNOUNCE-ONLY: a new
3903
+ // Workbench v2 turn-end workspace capture. ANNOUNCE-ONLY: a new
2422
3904
  // capture revision was persisted at turn end; the client refetches the latest
2423
3905
  // capture. It carries metadata only (revision/turnId/capturedAt/leaseEpoch/stats),
2424
3906
  // never file content. Hits the timeline projection default case (ignored) — it
2425
3907
  // must NEVER gain a rendered timeline item without regenerating the golden
2426
- // snapshots (dossier §7.3 golden-grammar gate).
3908
+ // snapshots (golden-grammar gate).
2427
3909
  "workspace.revision.captured",
2428
3910
  // Repository discovery could not prove a complete capture. The worker
2429
3911
  // persisted a failed/degraded revision marker and clients must fall back to
@@ -2463,17 +3945,160 @@ var SessionEventType = z.enum([
2463
3945
  "machine.link.restored",
2464
3946
  "machine.runner.restarted"
2465
3947
  ]);
3948
+ var SessionEventSemanticClass = z.enum([
3949
+ "control",
3950
+ "terminal",
3951
+ "failure",
3952
+ "checkpoint",
3953
+ "tool_receipt",
3954
+ "provider_account"
3955
+ ]);
3956
+ var SessionEventPayloadMode = z.enum(["none", "summary", "full"]);
3957
+ var SessionEventReadMode = z.enum(["monitoring", "forensic"]);
3958
+ var SessionEventReadDirection = z.enum(["after", "before"]);
3959
+ var SESSION_EVENT_RAW_DELTA_TYPES = [
3960
+ "agent.message.delta",
3961
+ "agent.reasoning.delta",
3962
+ "sandbox.command.output.delta",
3963
+ "terminal.pty.output.delta"
3964
+ ];
3965
+ var SESSION_EVENT_SEMANTIC_CLASS_TYPES = {
3966
+ control: [
3967
+ "session.status.changed",
3968
+ "session.requiresAction",
3969
+ "session.humanInput.requested",
3970
+ "user.pause",
3971
+ "user.approvalDecision",
3972
+ "user.humanInputResponse",
3973
+ "goal.set",
3974
+ "goal.updated",
3975
+ "goal.completed",
3976
+ "goal.paused",
3977
+ "goal.resumed",
3978
+ "goal.cleared",
3979
+ "goal.continuation",
3980
+ "system.update.pending",
3981
+ "system.update.delivered",
3982
+ "session.control.paused",
3983
+ "session.control.resumed",
3984
+ "session.control.steer_requested",
3985
+ "workspace.inference.paused",
3986
+ "workspace.inference.resumed",
3987
+ "session.queue.changed",
3988
+ "session.queue.prompt.cancelled"
3989
+ ],
3990
+ terminal: [
3991
+ "turn.completed",
3992
+ "turn.failed",
3993
+ "turn.cancelled",
3994
+ "turn.superseded",
3995
+ "goal.completed",
3996
+ "goal.paused",
3997
+ "rig.setup.completed",
3998
+ "rig.setup.skipped",
3999
+ "rig.setup.failed",
4000
+ "sandbox.operation.completed",
4001
+ "sandbox.operation.failed",
4002
+ "recording.available",
4003
+ "recording.failed",
4004
+ "terminal.pty.exited"
4005
+ ],
4006
+ failure: [
4007
+ "session.event.envelope_omitted",
4008
+ "turn.failed",
4009
+ "tool.auth_needed",
4010
+ "credential.auth_needed",
4011
+ "rig.setup.failed",
4012
+ "sandbox.operation.failed",
4013
+ "recording.failed",
4014
+ "sandbox.box.lost",
4015
+ "workspace.revision.degraded",
4016
+ "machine.op.failed",
4017
+ "machine.link.lost"
4018
+ ],
4019
+ checkpoint: [
4020
+ "session.context.compaction.requested",
4021
+ "session.context.compacted",
4022
+ "session.context.compaction.skipped",
4023
+ "session.context.cleared",
4024
+ "turn.recovery.requested",
4025
+ "session.queue.history",
4026
+ "sandbox.box.snapshot",
4027
+ "workspace.revision.captured"
4028
+ ],
4029
+ tool_receipt: [
4030
+ "agent.toolCall.created",
4031
+ "agent.toolCall.output",
4032
+ "tool.auth_needed",
4033
+ "artifact.created"
4034
+ ],
4035
+ provider_account: [
4036
+ "agent.model.usage",
4037
+ "codex.account.switched",
4038
+ "codex.credential.selected",
4039
+ "codex.capacity.waiting",
4040
+ "codex.capacity.resumed",
4041
+ "codex.capacity.superseded",
4042
+ "sandbox.box.created",
4043
+ "sandbox.box.lost",
4044
+ "sandbox.box.terminated",
4045
+ "sandbox.box.snapshot",
4046
+ "sandbox.env.drift",
4047
+ "session.route.reconciled",
4048
+ "machine.op.failed",
4049
+ "machine.op.recovered",
4050
+ "machine.link.lost",
4051
+ "machine.link.restored",
4052
+ "machine.runner.restarted"
4053
+ ]
4054
+ };
4055
+ function resolveSessionEventTypeFilters(input) {
4056
+ const included = new Set(input.includeTypes ?? []);
4057
+ for (const semanticClass of input.includeClasses ?? []) {
4058
+ for (const type of SESSION_EVENT_SEMANTIC_CLASS_TYPES[semanticClass]) included.add(type);
4059
+ }
4060
+ const excluded = new Set(input.excludeTypes ?? []);
4061
+ for (const semanticClass of input.excludeClasses ?? []) {
4062
+ for (const type of SESSION_EVENT_SEMANTIC_CLASS_TYPES[semanticClass]) excluded.add(type);
4063
+ }
4064
+ for (const type of input.defaultExcludeTypes ?? []) {
4065
+ if (!included.has(type)) excluded.add(type);
4066
+ }
4067
+ for (const type of excluded) included.delete(type);
4068
+ return { includeTypes: [...included], excludeTypes: [...excluded] };
4069
+ }
2466
4070
  var ToolAuthNeededPayload = z.object({
2467
4071
  serverId: z.string().min(1),
2468
4072
  toolName: z.string().min(1).nullable().optional(),
2469
4073
  providerDomain: z.string().min(1),
2470
- connectionId: z.string().uuid().nullable().optional(),
2471
- reason: z.enum(["missing_connection", "expired", "insufficient_scope", "refresh_failed"]),
4074
+ provider: z.string().min(1).max(128).optional(),
4075
+ // Embedded hosts may use an opaque connection identity; never assume an
4076
+ // OpenGeni UUID on the public event wire.
4077
+ connectionId: z.string().min(1).nullable().optional(),
4078
+ reason: z.enum([
4079
+ "missing_connection",
4080
+ "expired",
4081
+ "insufficient_scope",
4082
+ "refresh_failed",
4083
+ "unsupported_auth",
4084
+ "resource_scope_unavailable"
4085
+ ]),
2472
4086
  scopes: z.array(z.string().min(1)).optional(),
2473
4087
  resource: z.string().min(1).optional(),
4088
+ selectedResources: McpConnectionResourceScopes.optional(),
2474
4089
  authorizationUrl: z.string().url().optional(),
2475
4090
  subjectId: z.string().min(1).nullable().optional()
2476
4091
  });
4092
+ var CredentialAuthNeededPayload = z.object({
4093
+ credentialClass: z.literal("run"),
4094
+ providerDomain: z.string().min(1).optional(),
4095
+ connectionId: z.string().min(1).optional(),
4096
+ reason: z.enum(["missing_connection", "expired", "insufficient_scope", "refresh_failed"]),
4097
+ scopes: z.array(z.string().min(1)).optional(),
4098
+ resource: z.string().min(1).optional(),
4099
+ authorizationUrl: z.string().url().optional(),
4100
+ message: z.string().min(1).optional()
4101
+ });
2477
4102
  var StreamUrlRotatedPayload = z.object({
2478
4103
  url: z.string().url(),
2479
4104
  token: z.string().nullable(),
@@ -2671,7 +4296,9 @@ var FsDeleteRequest = z.object({
2671
4296
  recursive: z.boolean().default(false)
2672
4297
  // required true to delete a non-empty dir
2673
4298
  });
2674
- var FsDeleteResponse = z.object({ revision: z.number().int().nonnegative() });
4299
+ var FsDeleteResponse = z.object({
4300
+ revision: z.number().int().nonnegative()
4301
+ });
2675
4302
  var FsMoveRequest = z.object({
2676
4303
  path: z.string(),
2677
4304
  newPath: z.string(),
@@ -2768,6 +4395,9 @@ var GitDiffRequest = z.object({
2768
4395
  // diff selectors, mutually exclusive precedence: refs > staged > worktree
2769
4396
  staged: z.boolean().default(false),
2770
4397
  // --cached (index vs HEAD)
4398
+ // Workspace review includes after-images that ordinary `git diff` omits.
4399
+ // Explicit so commit/staged consumers keep native Git semantics by default.
4400
+ includeUntracked: z.boolean().default(false),
2771
4401
  fromRef: z.string().optional(),
2772
4402
  toRef: z.string().optional(),
2773
4403
  pathspec: z.array(z.string()).default([]),
@@ -2783,7 +4413,7 @@ var WorkspaceCaptureFile = z.object({
2783
4413
  status: GitFileStatusCode,
2784
4414
  // sha256 of the captured after-image bytes; null when deleted / tooLarge.
2785
4415
  hash: z.string().nullable(),
2786
- // git blob sha of the HEAD version — the wake-on-edit flush guard (dossier
4416
+ // git blob sha of the HEAD version — the wake-on-edit flush guard (design
2787
4417
  // §10.1). null when the path is new/untracked (no HEAD blob).
2788
4418
  baseHash: z.string().nullable(),
2789
4419
  // Content-addressed storage key of the after-image; null when deleted /
@@ -2908,14 +4538,25 @@ var GitCommit = z.object({
2908
4538
  sha: z.string(),
2909
4539
  shortSha: z.string(),
2910
4540
  parents: z.array(z.string()),
2911
- author: z.object({ name: z.string(), email: z.string(), timestamp: z.number().int() }),
2912
- committer: z.object({ name: z.string(), email: z.string(), timestamp: z.number().int() }),
4541
+ author: z.object({
4542
+ name: z.string(),
4543
+ email: z.string(),
4544
+ timestamp: z.number().int()
4545
+ }),
4546
+ committer: z.object({
4547
+ name: z.string(),
4548
+ email: z.string(),
4549
+ timestamp: z.number().int()
4550
+ }),
2913
4551
  subject: z.string(),
2914
4552
  body: z.string(),
2915
4553
  refs: z.array(z.string()).default([])
2916
4554
  // decorations: branch/tag pointers
2917
4555
  });
2918
- var GitLogResponse = z.object({ commits: z.array(GitCommit), hasMore: z.boolean() });
4556
+ var GitLogResponse = z.object({
4557
+ commits: z.array(GitCommit),
4558
+ hasMore: z.boolean()
4559
+ });
2919
4560
  var GitShowRequest = z.object({
2920
4561
  path: z.string().default(""),
2921
4562
  ref: z.string(),
@@ -2972,7 +4613,10 @@ var PtyOpenResponse = z.object({
2972
4613
  supportsInput: z.boolean()
2973
4614
  // false on backends without writeStdin
2974
4615
  });
2975
- var PtyWriteRequest = z.object({ ptyId: z.string().uuid(), data: z.string() });
4616
+ var PtyWriteRequest = z.object({
4617
+ ptyId: z.string().uuid(),
4618
+ data: z.string()
4619
+ });
2976
4620
  var PtyResizeRequest = z.object({
2977
4621
  ptyId: z.string().uuid(),
2978
4622
  cols: z.number().int().positive(),
@@ -2980,7 +4624,11 @@ var PtyResizeRequest = z.object({
2980
4624
  });
2981
4625
  var PtyCloseRequest = z.object({ ptyId: z.string().uuid() });
2982
4626
  var SessionStructuredCapabilities = z.object({
2983
- FileSystem: z.object({ available: z.boolean(), readOnly: z.boolean(), root: z.string() }),
4627
+ FileSystem: z.object({
4628
+ available: z.boolean(),
4629
+ readOnly: z.boolean(),
4630
+ root: z.string()
4631
+ }),
2984
4632
  Terminal: z.object({
2985
4633
  events: z.boolean(),
2986
4634
  // command.output firehose (always on if a box exists)
@@ -2999,33 +4647,407 @@ var SessionEvent = z.object({
2999
4647
  type: SessionEventType,
3000
4648
  payload: z.unknown().default({}),
3001
4649
  occurredAt: z.string(),
3002
- clientEventId: z.string().min(1).nullable().optional(),
4650
+ clientEventId: SessionOperationKey.nullable().optional(),
3003
4651
  turnId: z.string().uuid().nullable().optional(),
3004
4652
  turnGeneration: z.number().int().nonnegative().nullable().optional(),
3005
4653
  turnAttemptId: z.string().uuid().nullable().optional(),
3006
4654
  turnAssociation: z.enum(["current", "late_rejected", "duplicate"]).nullable().optional(),
3007
4655
  duplicateOfEventId: z.string().uuid().nullable().optional(),
3008
- duplicateReason: z.string().min(1).nullable().optional()
4656
+ duplicateReason: z.string().min(1).max(1024).nullable().optional()
4657
+ });
4658
+ var OPENGENI_HOST_EXPORT_SCHEMA_REVISION = "2026-07-host-export-v1";
4659
+ var HostExportCursor = z.string().regex(/^(0|[1-9][0-9]*)$/);
4660
+ var HostExportConsumerId = z.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/);
4661
+ var HostExportInitiator = TurnInitiator.extend({
4662
+ subjectId: z.string().min(1).max(1024),
4663
+ label: z.string().min(1).max(256).optional()
4664
+ });
4665
+ var HostExportInitiatorContext = TurnInitiatorContext.refine(
4666
+ (value) => {
4667
+ try {
4668
+ return new TextEncoder().encode(JSON.stringify(value)).byteLength <= 4096;
4669
+ } catch {
4670
+ return false;
4671
+ }
4672
+ },
4673
+ { message: "Host export initiator context exceeds 4096 UTF-8 bytes" }
4674
+ );
4675
+ var HostExportAttribution = {
4676
+ initiator: HostExportInitiator.nullable(),
4677
+ initiatorContext: HostExportInitiatorContext,
4678
+ origin: SessionTurnSource.nullable()
4679
+ };
4680
+ var HostSessionEvent = SessionEvent.extend({
4681
+ type: z.string().min(1).max(256),
4682
+ clientEventId: z.string().max(1024).nullable().optional(),
4683
+ turnAssociation: z.string().min(1).max(64).nullable().optional(),
4684
+ duplicateReason: z.string().max(4096).nullable().optional()
4685
+ });
4686
+ var HostUsageEvent = UsageEvent.extend({
4687
+ subjectId: z.string().max(1024).nullable(),
4688
+ eventType: z.string().min(1).max(256),
4689
+ unit: z.string().min(1).max(128),
4690
+ sourceResourceType: z.string().max(256).nullable(),
4691
+ sourceResourceId: z.string().max(2048).nullable(),
4692
+ idempotencyKey: z.string().min(1).max(2048),
4693
+ billingProviderEventId: z.string().max(2048).nullable()
4694
+ });
4695
+ var HostEventExport = z.object({
4696
+ schemaRevision: z.literal(OPENGENI_HOST_EXPORT_SCHEMA_REVISION),
4697
+ cursor: HostExportCursor,
4698
+ idempotencyKey: z.string().min(1).max(2048),
4699
+ accountId: z.string().uuid(),
4700
+ workspaceId: z.string().uuid(),
4701
+ /**
4702
+ * Immutable root of event.sessionId's session lineage at capture time. Null
4703
+ * only for an unresolved pre-lineage/legacy export row.
4704
+ */
4705
+ rootSessionId: z.string().uuid().nullable(),
4706
+ ...HostExportAttribution,
4707
+ event: HostSessionEvent
3009
4708
  });
4709
+ var HostUsageExport = z.object({
4710
+ schemaRevision: z.literal(OPENGENI_HOST_EXPORT_SCHEMA_REVISION),
4711
+ cursor: HostExportCursor,
4712
+ accountId: z.string().uuid(),
4713
+ workspaceId: z.string().uuid(),
4714
+ sessionId: z.string().uuid().nullable(),
4715
+ /** Null when sessionId is null or an unresolved pre-lineage legacy row. */
4716
+ rootSessionId: z.string().uuid().nullable(),
4717
+ turnId: z.string().uuid().nullable(),
4718
+ turnAttemptId: z.string().uuid().nullable(),
4719
+ ...HostExportAttribution,
4720
+ usage: HostUsageEvent
4721
+ });
4722
+ var HostEventExportBatch = z.object({
4723
+ schemaRevision: z.literal(OPENGENI_HOST_EXPORT_SCHEMA_REVISION),
4724
+ consumerId: HostExportConsumerId,
4725
+ leaseToken: z.string().uuid(),
4726
+ checkpoint: HostExportCursor,
4727
+ throughCursor: HostExportCursor,
4728
+ events: z.array(HostEventExport).min(1).max(256)
4729
+ });
4730
+ var HostUsageExportBatch = z.object({
4731
+ schemaRevision: z.literal(OPENGENI_HOST_EXPORT_SCHEMA_REVISION),
4732
+ consumerId: HostExportConsumerId,
4733
+ leaseToken: z.string().uuid(),
4734
+ checkpoint: HostExportCursor,
4735
+ throughCursor: HostExportCursor,
4736
+ events: z.array(HostUsageExport).min(1).max(256)
4737
+ });
4738
+ var SESSION_EVENT_TYPE_MAX_BYTES = 256;
4739
+ var SESSION_EVENT_CLIENT_EVENT_ID_MAX_BYTES = SESSION_OPERATION_KEY_MAX_CHARS * 4;
4740
+ var SESSION_EVENT_TURN_ASSOCIATION_MAX_BYTES = 64;
4741
+ var SESSION_EVENT_DUPLICATE_REASON_MAX_BYTES = 4 * 1024;
4742
+ var SESSION_EVENT_ENVELOPE_MAX_BYTES = 80 * 1024;
4743
+ function boundSessionEvent(event, options = {}) {
4744
+ const surface = options.surface ?? "durable_audit";
4745
+ const maxBytes = Math.max(8 * 1024, options.maxBytes ?? SESSION_EVENT_ENVELOPE_MAX_BYTES);
4746
+ const originalBytes = measureSessionEventJson(event).bytes;
4747
+ const source = sessionEventOwnDataFields(event);
4748
+ const id = canonicalSessionEventUuid(source.id, SESSION_EVENT_ZERO_UUID);
4749
+ const workspaceId = canonicalSessionEventUuid(source.workspaceId, SESSION_EVENT_ZERO_UUID);
4750
+ const sessionId = canonicalSessionEventUuid(source.sessionId, SESSION_EVENT_ZERO_UUID);
4751
+ const sequence = source.sequence.readable && typeof source.sequence.value === "number" && Number.isSafeInteger(source.sequence.value) && source.sequence.value > 0 ? source.sequence.value : 1;
4752
+ const occurredAt = source.occurredAt.readable && typeof source.occurredAt.value === "string" && sessionEventUtf8Bytes(source.occurredAt.value) <= 256 ? source.occurredAt.value : "1970-01-01T00:00:00.000Z";
4753
+ const rawType = source.type.readable ? source.type.value : void 0;
4754
+ const typeIsSafe = typeof rawType === "string" && sessionEventUtf8Bytes(rawType) <= SESSION_EVENT_TYPE_MAX_BYTES && !rawType.includes("\n") && !rawType.includes("\r");
4755
+ const rawClientEventId = source.clientEventId.readable ? source.clientEventId.value : void 0;
4756
+ const clientEventId = boundOptionalSessionEventText(
4757
+ typeof rawClientEventId === "string" || rawClientEventId === null ? rawClientEventId : void 0,
4758
+ SESSION_EVENT_CLIENT_EVENT_ID_MAX_BYTES
4759
+ );
4760
+ const rawTurnAssociation = source.turnAssociation.readable ? source.turnAssociation.value : void 0;
4761
+ const turnAssociation = rawTurnAssociation === null || rawTurnAssociation === void 0 || rawTurnAssociation === "current" || rawTurnAssociation === "late_rejected" || rawTurnAssociation === "duplicate" ? rawTurnAssociation : null;
4762
+ const rawDuplicateReason = source.duplicateReason.readable ? source.duplicateReason.value : void 0;
4763
+ const duplicateReason = boundOptionalSessionEventText(
4764
+ typeof rawDuplicateReason === "string" || rawDuplicateReason === null ? rawDuplicateReason : void 0,
4765
+ SESSION_EVENT_DUPLICATE_REASON_MAX_BYTES
4766
+ );
4767
+ const turnId = canonicalOptionalSessionEventUuid(source.turnId);
4768
+ const turnGeneration = canonicalSessionEventGeneration(source.turnGeneration);
4769
+ const turnAttemptId = canonicalOptionalSessionEventUuid(source.turnAttemptId);
4770
+ const duplicateOfEventId = canonicalOptionalSessionEventUuid(source.duplicateOfEventId);
4771
+ const envelopeFields = [
4772
+ sessionEventCustomSerializerProjection(event),
4773
+ sessionEventAdditionalTopLevelFieldProjection(event),
4774
+ !typeIsSafe ? sessionEventEnvelopeFieldProjection(
4775
+ "type",
4776
+ rawType,
4777
+ "session.event.envelope_omitted",
4778
+ source.type.readable
4779
+ ) : null,
4780
+ !source.clientEventId.readable || rawClientEventId !== clientEventId ? sessionEventEnvelopeFieldProjection(
4781
+ "clientEventId",
4782
+ rawClientEventId,
4783
+ clientEventId,
4784
+ source.clientEventId.readable
4785
+ ) : null,
4786
+ !source.turnAssociation.readable || rawTurnAssociation !== turnAssociation ? sessionEventEnvelopeFieldProjection(
4787
+ "turnAssociation",
4788
+ rawTurnAssociation,
4789
+ turnAssociation,
4790
+ source.turnAssociation.readable
4791
+ ) : null,
4792
+ !source.duplicateReason.readable || rawDuplicateReason !== duplicateReason ? sessionEventEnvelopeFieldProjection(
4793
+ "duplicateReason",
4794
+ rawDuplicateReason,
4795
+ duplicateReason,
4796
+ source.duplicateReason.readable
4797
+ ) : null,
4798
+ ...sessionEventCanonicalFieldProjections(source, {
4799
+ id,
4800
+ workspaceId,
4801
+ sessionId,
4802
+ sequence,
4803
+ occurredAt
4804
+ }),
4805
+ ...sessionEventOptionalFieldProjections(source, {
4806
+ turnId,
4807
+ turnGeneration,
4808
+ turnAttemptId,
4809
+ duplicateOfEventId
4810
+ }),
4811
+ !source.payload.readable ? sessionEventEnvelopeFieldProjection("payload", void 0, null, false) : null
4812
+ ].filter((field) => field !== null);
4813
+ const rawPayload = source.payload.readable ? source.payload.value : "[event payload accessor omitted at bounded projection boundary]";
4814
+ const payload = envelopeFields.length === 0 ? boundSessionEventPayload(rawPayload, { surface }) : boundSessionEventPayload(
4815
+ {
4816
+ preview: "[legacy event envelope normalized at bounded projection boundary]",
4817
+ originalEventBytes: originalBytes,
4818
+ originalType: typeof rawType === "string" ? boundSessionEventText(rawType, 256) : null,
4819
+ envelopeProjection: {
4820
+ truncated: true,
4821
+ surface,
4822
+ fields: envelopeFields
4823
+ },
4824
+ fullEvidence: { available: false, reason: "not_retained" }
4825
+ },
4826
+ { surface, maxBytes: 8 * 1024 }
4827
+ );
4828
+ const bounded = {
4829
+ id,
4830
+ workspaceId,
4831
+ sessionId,
4832
+ sequence,
4833
+ type: typeIsSafe ? rawType : "session.event.envelope_omitted",
4834
+ payload,
4835
+ occurredAt,
4836
+ ...sessionEventShouldEmitOptionalField(source.clientEventId) ? { clientEventId } : {},
4837
+ ...sessionEventShouldEmitOptionalField(source.turnId) ? { turnId } : {},
4838
+ ...sessionEventShouldEmitOptionalField(source.turnGeneration) ? { turnGeneration } : {},
4839
+ ...sessionEventShouldEmitOptionalField(source.turnAttemptId) ? { turnAttemptId } : {},
4840
+ ...sessionEventShouldEmitOptionalField(source.turnAssociation) ? { turnAssociation } : {},
4841
+ ...sessionEventShouldEmitOptionalField(source.duplicateOfEventId) ? { duplicateOfEventId } : {},
4842
+ ...sessionEventShouldEmitOptionalField(source.duplicateReason) ? { duplicateReason } : {}
4843
+ };
4844
+ if (sessionEventJsonBytes(bounded) <= maxBytes) return bounded;
4845
+ const fallback = {
4846
+ id,
4847
+ workspaceId,
4848
+ sessionId,
4849
+ sequence,
4850
+ type: "session.event.envelope_omitted",
4851
+ payload: boundSessionEventPayload(
4852
+ {
4853
+ preview: "[legacy event envelope omitted at bounded projection boundary]",
4854
+ originalEventBytes: originalBytes,
4855
+ originalType: typeof rawType === "string" ? boundSessionEventText(rawType, 256) : null,
4856
+ fullEvidence: { available: false, reason: "not_retained" }
4857
+ },
4858
+ { surface, maxBytes: 4 * 1024 }
4859
+ ),
4860
+ occurredAt,
4861
+ ...sessionEventShouldEmitOptionalField(source.clientEventId) ? { clientEventId } : {},
4862
+ ...sessionEventShouldEmitOptionalField(source.turnId) ? { turnId } : {},
4863
+ ...sessionEventShouldEmitOptionalField(source.turnGeneration) ? { turnGeneration } : {},
4864
+ ...sessionEventShouldEmitOptionalField(source.turnAttemptId) ? { turnAttemptId } : {},
4865
+ ...sessionEventShouldEmitOptionalField(source.turnAssociation) ? { turnAssociation } : {},
4866
+ ...sessionEventShouldEmitOptionalField(source.duplicateOfEventId) ? { duplicateOfEventId } : {},
4867
+ ...sessionEventShouldEmitOptionalField(source.duplicateReason) ? { duplicateReason } : {}
4868
+ };
4869
+ const deliveredBytes = sessionEventJsonBytes(fallback);
4870
+ if (deliveredBytes > maxBytes) {
4871
+ throw new RangeError(
4872
+ `Bounded session event exceeds its final envelope (${deliveredBytes} > ${maxBytes} bytes)`
4873
+ );
4874
+ }
4875
+ return fallback;
4876
+ }
4877
+ function sessionEventEnvelopeFieldProjection(field, original, delivered, originalReadable = true) {
4878
+ return {
4879
+ field,
4880
+ originalBytes: originalReadable ? typeof original === "string" ? sessionEventUtf8Bytes(original) : typeof original === "number" || typeof original === "boolean" ? sessionEventJsonBytes(original) : original === null || original === void 0 ? 0 : null : null,
4881
+ deliveredBytes: typeof delivered === "string" ? sessionEventUtf8Bytes(delivered) : typeof delivered === "number" || typeof delivered === "boolean" ? sessionEventJsonBytes(delivered) : 0
4882
+ };
4883
+ }
4884
+ function sessionEventCustomSerializerProjection(event) {
4885
+ const projection = {
4886
+ field: "toJSON",
4887
+ originalBytes: null,
4888
+ deliveredBytes: 0
4889
+ };
4890
+ let candidate = event;
4891
+ try {
4892
+ for (let depth = 0; depth <= SESSION_EVENT_PROTOTYPE_MAX_DEPTH; depth += 1) {
4893
+ if (candidate === null) return null;
4894
+ const descriptor = Object.getOwnPropertyDescriptor(candidate, "toJSON");
4895
+ if (descriptor) {
4896
+ return !("value" in descriptor) || typeof descriptor.value === "function" ? projection : null;
4897
+ }
4898
+ candidate = Object.getPrototypeOf(candidate);
4899
+ }
4900
+ return projection;
4901
+ } catch {
4902
+ return projection;
4903
+ }
4904
+ }
4905
+ var SESSION_EVENT_PROTOTYPE_MAX_DEPTH = 32;
4906
+ var SESSION_EVENT_ZERO_UUID = "00000000-0000-4000-8000-000000000000";
4907
+ var SESSION_EVENT_UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
4908
+ var SESSION_EVENT_OWN_DATA_FIELDS = [
4909
+ "id",
4910
+ "workspaceId",
4911
+ "sessionId",
4912
+ "sequence",
4913
+ "type",
4914
+ "payload",
4915
+ "occurredAt",
4916
+ "clientEventId",
4917
+ "turnId",
4918
+ "turnGeneration",
4919
+ "turnAttemptId",
4920
+ "turnAssociation",
4921
+ "duplicateOfEventId",
4922
+ "duplicateReason"
4923
+ ];
4924
+ var SESSION_EVENT_KNOWN_ENUMERABLE_FIELDS = /* @__PURE__ */ new Set([
4925
+ ...SESSION_EVENT_OWN_DATA_FIELDS,
4926
+ "toJSON"
4927
+ ]);
4928
+ function sessionEventAdditionalTopLevelFieldProjection(event) {
4929
+ const projection = {
4930
+ field: "additionalTopLevelFields",
4931
+ originalBytes: null,
4932
+ deliveredBytes: 0
4933
+ };
4934
+ let inspected = 0;
4935
+ try {
4936
+ for (const key in event) {
4937
+ inspected += 1;
4938
+ if (inspected > SESSION_EVENT_KNOWN_ENUMERABLE_FIELDS.size + 1) return projection;
4939
+ const descriptor = Object.getOwnPropertyDescriptor(event, key);
4940
+ if (descriptor?.enumerable && !SESSION_EVENT_KNOWN_ENUMERABLE_FIELDS.has(key)) {
4941
+ return projection;
4942
+ }
4943
+ }
4944
+ return null;
4945
+ } catch {
4946
+ return projection;
4947
+ }
4948
+ }
4949
+ function sessionEventOwnDataFields(event) {
4950
+ return Object.fromEntries(
4951
+ SESSION_EVENT_OWN_DATA_FIELDS.map((key) => {
4952
+ try {
4953
+ const descriptor = Object.getOwnPropertyDescriptor(event, key);
4954
+ if (!descriptor) return [key, { readable: true, value: void 0 }];
4955
+ return [
4956
+ key,
4957
+ "value" in descriptor ? { readable: true, value: descriptor.value } : { readable: false }
4958
+ ];
4959
+ } catch {
4960
+ return [key, { readable: false }];
4961
+ }
4962
+ })
4963
+ );
4964
+ }
4965
+ function canonicalSessionEventUuid(field, fallback) {
4966
+ return field.readable && typeof field.value === "string" && SESSION_EVENT_UUID_PATTERN.test(field.value) ? field.value : fallback;
4967
+ }
4968
+ function canonicalOptionalSessionEventUuid(field) {
4969
+ return field.readable && typeof field.value === "string" && SESSION_EVENT_UUID_PATTERN.test(field.value) ? field.value : null;
4970
+ }
4971
+ function canonicalSessionEventGeneration(field) {
4972
+ return field.readable && typeof field.value === "number" && Number.isSafeInteger(field.value) && field.value >= 0 ? field.value : null;
4973
+ }
4974
+ function sessionEventShouldEmitOptionalField(field) {
4975
+ return !field.readable || field.value !== void 0;
4976
+ }
4977
+ function sessionEventCanonicalFieldProjections(source, delivered) {
4978
+ return ["id", "workspaceId", "sessionId", "sequence", "occurredAt"].flatMap(
4979
+ (field) => {
4980
+ const original = source[field].readable ? source[field].value : void 0;
4981
+ return source[field].readable && original === delivered[field] ? [] : [
4982
+ sessionEventEnvelopeFieldProjection(
4983
+ field,
4984
+ original,
4985
+ delivered[field],
4986
+ source[field].readable
4987
+ )
4988
+ ];
4989
+ }
4990
+ );
4991
+ }
4992
+ function sessionEventOptionalFieldProjections(source, delivered) {
4993
+ return ["turnId", "turnGeneration", "turnAttemptId", "duplicateOfEventId"].flatMap(
4994
+ (field) => {
4995
+ const original = source[field].readable ? source[field].value : void 0;
4996
+ const canonicalOriginal = original ?? null;
4997
+ return source[field].readable && canonicalOriginal === delivered[field] ? [] : [
4998
+ sessionEventEnvelopeFieldProjection(
4999
+ field,
5000
+ original,
5001
+ delivered[field],
5002
+ source[field].readable
5003
+ )
5004
+ ];
5005
+ }
5006
+ );
5007
+ }
5008
+ function boundOptionalSessionEventText(value, maxBytes) {
5009
+ return typeof value === "string" ? boundSessionEventText(value, maxBytes) : value;
5010
+ }
5011
+ function boundSessionEventText(value, maxBytes) {
5012
+ const encoder2 = new TextEncoder();
5013
+ const decoder = new TextDecoder();
5014
+ const bytes = encoder2.encode(value);
5015
+ if (bytes.byteLength <= maxBytes) return value;
5016
+ const marker = "\u2026[truncated]";
5017
+ const markerBytes = encoder2.encode(marker).byteLength;
5018
+ const prefixBudget = Math.max(0, maxBytes - markerBytes);
5019
+ let prefixEnd = Math.min(prefixBudget, bytes.byteLength);
5020
+ while (prefixEnd > 0 && prefixEnd < bytes.byteLength && (bytes[prefixEnd] & 192) === 128) {
5021
+ prefixEnd -= 1;
5022
+ }
5023
+ return `${decoder.decode(bytes.subarray(0, prefixEnd))}${marker}`;
5024
+ }
5025
+ function sessionEventUtf8Bytes(value) {
5026
+ return new TextEncoder().encode(value).byteLength;
5027
+ }
3010
5028
  var SessionQueueMutationResponse = z.object({
5029
+ receipt: SessionCommandReceipt,
3011
5030
  snapshot: SessionQueueSnapshot,
3012
- events: z.array(SessionEvent),
3013
- shouldWake: z.boolean()
5031
+ draft: ComposerDraft.optional()
3014
5032
  });
3015
5033
  var SessionControlResponse = z.object({
3016
- operationId: z.string().uuid(),
3017
- event: SessionEvent,
3018
- controlState: SessionControlState,
3019
- controlGeneration: z.number().int().nonnegative(),
3020
- expectedActiveTurnId: z.string().uuid().nullable(),
3021
- expectedExecutionGeneration: z.number().int().nonnegative().nullable(),
3022
- expectedAttemptId: z.string().uuid().nullable(),
3023
- deliveryEventId: z.string().uuid().nullable(),
3024
- shouldSignalControl: z.boolean(),
3025
- shouldWake: z.boolean()
5034
+ receipt: SessionCommandReceipt,
5035
+ effectiveControl: EffectiveSessionControl,
5036
+ interruptionCount: z.number().int().nonnegative(),
5037
+ wakeCount: z.number().int().nonnegative()
3026
5038
  });
3027
5039
  var CreateSessionRequest = withVariableSetIdAlias({
5040
+ /**
5041
+ * Optional UUID preallocated by an embedding host. This lets the host durably
5042
+ * link its own projection before OpenGeni admits the initial turn. Replays
5043
+ * must pair it with the same idempotency key; OpenGeni never derives host
5044
+ * identity or authorization from the UUID.
5045
+ */
5046
+ requestedSessionId: z.string().uuid().optional(),
3028
5047
  initialMessage: z.string().min(1),
5048
+ // System-level host context for the initial turn only. Unlike `instructions`,
5049
+ // this does not persist into later turns and is never emitted as a user event.
5050
+ turnInstructions: z.string().trim().min(1).max(32768).optional(),
3029
5051
  // Per-session agent persona/system instructions (org-visible metadata, NOT a
3030
5052
  // secret). Rides the SAME system-level instructions channel the per-workspace
3031
5053
  // agentInstructions rides, composed AFTER the workspace persona so it refines
@@ -3035,7 +5057,14 @@ var CreateSessionRequest = withVariableSetIdAlias({
3035
5057
  // matches the codebase's largest free-form string convention (workspace
3036
5058
  // variable set variable values). Absent ⇒ byte-identical to today.
3037
5059
  instructions: z.string().trim().min(1).max(32768).optional(),
5060
+ // For an agent-created child, omission inherits the trusted immediate
5061
+ // parent's repository/file context. An explicit array, including [], is
5062
+ // authoritative. Top-level omission remains []. Presence is resolved from
5063
+ // the raw request because this Zod default erases absent-vs-empty.
3038
5064
  resources: z.array(ResourceRef).default([]),
5065
+ // The same child omission rule applies to selected MCP tool refs. Top-level
5066
+ // omission still applies workspace-default capability MCP tools; explicit []
5067
+ // suppresses those defaults (the first-party OpenGeni server remains added).
3039
5068
  tools: z.array(ToolRef).default([]),
3040
5069
  metadata: z.record(z.string(), z.unknown()).default({}),
3041
5070
  model: z.string().min(1).optional(),
@@ -3062,7 +5091,7 @@ var CreateSessionRequest = withVariableSetIdAlias({
3062
5091
  // behavior). An id that does not name a rig in the workspace is a 422.
3063
5092
  rigId: z.string().uuid().optional(),
3064
5093
  goal: GoalSpec.optional(),
3065
- clientEventId: z.string().min(1).optional(),
5094
+ clientEventId: SessionOperationKey.optional(),
3066
5095
  // Workspace-scoped CREATE idempotency key: collapses concurrent/retried
3067
5096
  // create calls carrying the same key to a single session (partial unique
3068
5097
  // index on (workspace_id, create_idempotency_key)). Distinct from
@@ -3070,13 +5099,19 @@ var CreateSessionRequest = withVariableSetIdAlias({
3070
5099
  // creation of a brand-new session. Absent means no create-dedup (each call
3071
5100
  // is an independent create).
3072
5101
  idempotencyKey: z.string().min(1).max(200).optional(),
3073
- // Permissions the session's first-party MCP token should carry instead of
3074
- // the fixed worker default how an operator hands a manager-style session
3075
- // the orchestration/variableSet/github tools. Capped at creation: every
3076
- // requested permission must be held by the creating grant (no escalation).
5102
+ // Permissions the session's first-party MCP token should carry. A top-level
5103
+ // omission uses the deployment's worker default; a child omission inherits
5104
+ // the creating session's effective grant. An explicit set is capped at
5105
+ // creation: every requested permission must be held by the creating grant.
5106
+ // A goal-bearing session whose explicit/effective set omits goals:manage is
5107
+ // rejected; creation never silently expands a child beyond that set.
3077
5108
  firstPartyMcpPermissions: z.array(Permission).optional(),
3078
- // Third-party MCP servers attached only to this session. Credential headers are
3079
- // write-only: create responses and events expose only SessionMcpServerMetadata.
5109
+ // Third-party MCP servers attached only to this session. For an agent-created
5110
+ // child, omission snapshots its trusted immediate parent's server definitions,
5111
+ // policies, connection refs, and encrypted credentials. Explicit arrays,
5112
+ // including [], are authoritative; non-empty explicit arrays require attach
5113
+ // permission. Credential headers are write-only: create responses and events
5114
+ // expose only SessionMcpServerMetadata.
3080
5115
  mcpServers: z.array(SessionMcpServerInput).default([]),
3081
5116
  // Shared-sandbox placement (addendum 05 §D.1). Three-way union; OMITTED ⇒
3082
5117
  // today's behavior (a context-dependent default resolved server-side: from
@@ -3097,16 +5132,148 @@ var CreateSessionRequest = withVariableSetIdAlias({
3097
5132
  // manifest-env guard).
3098
5133
  sandbox: z.union([z.literal("shared"), z.literal("new"), z.object({ groupId: z.string().uuid() })]).optional()
3099
5134
  });
5135
+ var HumanInputQuestionKind = z.enum(["text", "single_select", "multi_select"]);
5136
+ var HumanInputOption = z.object({
5137
+ id: z.string().min(1).max(64),
5138
+ label: z.string().min(1).max(256),
5139
+ description: z.string().max(2048).nullable().optional()
5140
+ });
5141
+ var HumanInputQuestion = z.object({
5142
+ id: z.string().min(1).max(64),
5143
+ kind: HumanInputQuestionKind,
5144
+ prompt: z.string().min(1).max(4096),
5145
+ label: z.string().min(1).max(128).nullable().optional(),
5146
+ helpText: z.string().max(2048).nullable().optional(),
5147
+ options: z.array(HumanInputOption).max(20).default([]),
5148
+ required: z.boolean().default(true),
5149
+ allowOther: z.boolean().default(false),
5150
+ validation: z.object({
5151
+ minLength: z.number().int().nonnegative().max(8192).nullable().optional(),
5152
+ maxLength: z.number().int().positive().max(8192).nullable().optional(),
5153
+ minSelections: z.number().int().nonnegative().max(20).nullable().optional(),
5154
+ maxSelections: z.number().int().positive().max(20).nullable().optional()
5155
+ }).nullable().optional()
5156
+ }).superRefine((question, ctx) => {
5157
+ const optionIds = new Set(question.options.map((option) => option.id));
5158
+ if (optionIds.size !== question.options.length) {
5159
+ ctx.addIssue({
5160
+ code: "custom",
5161
+ path: ["options"],
5162
+ message: "option ids must be unique"
5163
+ });
5164
+ }
5165
+ if (question.kind === "text") {
5166
+ if (question.options.length > 0) {
5167
+ ctx.addIssue({
5168
+ code: "custom",
5169
+ path: ["options"],
5170
+ message: "text questions cannot have options"
5171
+ });
5172
+ }
5173
+ if (question.allowOther) {
5174
+ ctx.addIssue({
5175
+ code: "custom",
5176
+ path: ["allowOther"],
5177
+ message: "text questions do not use Other"
5178
+ });
5179
+ }
5180
+ } else if (question.options.length === 0) {
5181
+ ctx.addIssue({
5182
+ code: "custom",
5183
+ path: ["options"],
5184
+ message: "select questions require options"
5185
+ });
5186
+ }
5187
+ const validation = question.validation;
5188
+ if (validation?.minLength != null && validation?.maxLength != null && validation.minLength > validation.maxLength) {
5189
+ ctx.addIssue({
5190
+ code: "custom",
5191
+ path: ["validation"],
5192
+ message: "minLength exceeds maxLength"
5193
+ });
5194
+ }
5195
+ if (validation?.minSelections != null && validation?.maxSelections != null && validation.minSelections > validation.maxSelections) {
5196
+ ctx.addIssue({
5197
+ code: "custom",
5198
+ path: ["validation"],
5199
+ message: "minSelections exceeds maxSelections"
5200
+ });
5201
+ }
5202
+ });
5203
+ var HumanInputRequestStatus = z.enum([
5204
+ "pending",
5205
+ "answered",
5206
+ "skipped",
5207
+ "expired",
5208
+ "cancelled"
5209
+ ]);
5210
+ var RequestHumanInputToolInput = z.object({
5211
+ questions: z.array(HumanInputQuestion).min(1).max(20),
5212
+ allowSkip: z.boolean().default(false),
5213
+ expiresInSeconds: z.number().int().positive().max(30 * 24 * 60 * 60).nullable().optional()
5214
+ });
5215
+ var HumanInputAnswer = z.object({
5216
+ questionId: z.string().min(1).max(64),
5217
+ values: z.array(z.string().max(8192)).max(20),
5218
+ other: z.string().max(8192).nullable().optional()
5219
+ });
5220
+ var HumanInputResponse = z.discriminatedUnion("outcome", [
5221
+ z.object({
5222
+ outcome: z.literal("answered"),
5223
+ answers: z.array(HumanInputAnswer).max(20)
5224
+ }),
5225
+ z.object({ outcome: z.literal("skipped") }),
5226
+ z.object({ outcome: z.literal("expired") }),
5227
+ z.object({ outcome: z.literal("cancelled") })
5228
+ ]);
5229
+ var SubmitHumanInputResponseRequest = z.discriminatedUnion("outcome", [
5230
+ z.object({
5231
+ outcome: z.literal("answered"),
5232
+ answers: z.array(HumanInputAnswer).max(20)
5233
+ }),
5234
+ z.object({ outcome: z.literal("skipped") })
5235
+ ]);
5236
+ var SessionHumanInputRequest = z.object({
5237
+ id: z.string().uuid(),
5238
+ workspaceId: z.string().uuid(),
5239
+ sessionId: z.string().uuid(),
5240
+ turnId: z.string().uuid(),
5241
+ turnGeneration: z.number().int().positive(),
5242
+ creationAttemptId: z.string().uuid(),
5243
+ toolCallId: z.string().min(1).max(1024),
5244
+ status: HumanInputRequestStatus,
5245
+ questions: z.array(HumanInputQuestion).min(1).max(20),
5246
+ allowSkip: z.boolean(),
5247
+ response: HumanInputResponse.nullable(),
5248
+ respondedBy: z.string().max(1024).nullable(),
5249
+ respondedAt: z.string().nullable(),
5250
+ expiresAt: z.string().nullable(),
5251
+ createdAt: z.string(),
5252
+ updatedAt: z.string()
5253
+ });
5254
+ function approvalIdentifier(value) {
5255
+ if (!value || typeof value !== "object") return null;
5256
+ const approval = value;
5257
+ const rawItem = approval.rawItem && typeof approval.rawItem === "object" ? approval.rawItem : null;
5258
+ const candidate = rawItem?.callId ?? rawItem?.id ?? approval.id ?? approval.name;
5259
+ if (typeof candidate !== "string" && typeof candidate !== "number") return null;
5260
+ return String(candidate);
5261
+ }
3100
5262
  var ClientSessionEvent = z.discriminatedUnion("type", [
3101
5263
  z.object({
3102
5264
  type: z.literal("user.message"),
3103
- clientEventId: z.string().min(1).optional(),
5265
+ clientEventId: SessionOperationKey.optional(),
3104
5266
  payload: z.object({
3105
5267
  text: z.string().min(1),
5268
+ // System-level host context for this exact turn only. Persisted on the
5269
+ // turn for retry/recovery, never copied into the visible user message.
5270
+ turnInstructions: z.string().trim().min(1).max(32768).optional(),
3106
5271
  resources: z.array(ResourceRef).default([]),
3107
5272
  tools: z.array(ToolRef).default([]),
3108
5273
  model: z.string().min(1).optional(),
3109
5274
  reasoningEffort: ReasoningEffort.optional(),
5275
+ controlEtag: z.string().min(1).optional(),
5276
+ expectedDraftRevision: z.number().int().nonnegative().optional(),
3110
5277
  // Header-value rotation only. URL/name/tool settings are immutable after
3111
5278
  // session create; persisted events expose metadata, never header values.
3112
5279
  mcpCredentialUpdates: z.array(SessionMcpCredentialUpdateInput).optional()
@@ -3114,23 +5281,33 @@ var ClientSessionEvent = z.discriminatedUnion("type", [
3114
5281
  }),
3115
5282
  z.object({
3116
5283
  type: z.literal("user.approvalDecision"),
3117
- clientEventId: z.string().min(1).optional(),
5284
+ clientEventId: SessionOperationKey.optional(),
3118
5285
  payload: z.object({
3119
- approvalId: z.string().min(1),
5286
+ approvalId: z.string().min(1).max(SESSION_OPERATION_KEY_MAX_CHARS),
3120
5287
  decision: z.enum(["approve", "reject"]),
3121
5288
  message: z.string().optional()
3122
5289
  })
5290
+ }),
5291
+ z.object({
5292
+ type: z.literal("user.humanInputResponse"),
5293
+ clientEventId: SessionOperationKey.optional(),
5294
+ payload: z.object({
5295
+ requestId: z.string().uuid(),
5296
+ response: SubmitHumanInputResponseRequest
5297
+ })
3123
5298
  })
3124
5299
  ]);
3125
5300
  var SteerSessionMessageRequest = z.object({
3126
5301
  text: z.string().min(1),
5302
+ // Same per-turn system-level context as a queued user.message.
5303
+ turnInstructions: z.string().trim().min(1).max(32768).optional(),
3127
5304
  resources: z.array(ResourceRef).default([]),
3128
5305
  tools: z.array(ToolRef).default([]),
3129
5306
  model: z.string().min(1).optional(),
3130
5307
  reasoningEffort: ReasoningEffort.optional(),
3131
- clientEventId: z.string().min(1).optional(),
3132
- expectedControlGeneration: z.number().int().nonnegative().optional(),
3133
- expectedWorkspaceInferenceGeneration: z.number().int().nonnegative().optional(),
5308
+ clientEventId: SessionOperationKey.optional(),
5309
+ controlEtag: z.string().min(1).optional(),
5310
+ expectedDraftRevision: z.number().int().nonnegative().optional(),
3134
5311
  mcpCredentialUpdates: z.array(SessionMcpCredentialUpdateInput).optional()
3135
5312
  });
3136
5313
  var SteerSessionMessageResponse = z.object({
@@ -3160,6 +5337,29 @@ var GitHubRepository = z.object({
3160
5337
  accountLogin: z.string(),
3161
5338
  accountType: z.string().nullable()
3162
5339
  });
5340
+ var GitHubRepositoryScope = z.enum(["all", "selected"]);
5341
+ var GitHubInstallationBinding = z.object({
5342
+ installationId: z.number().int().positive(),
5343
+ accountLogin: z.string().nullable(),
5344
+ accountType: z.string().nullable(),
5345
+ repositoryScope: GitHubRepositoryScope,
5346
+ repositoryCount: z.number().int().nonnegative(),
5347
+ createdAt: z.string(),
5348
+ updatedAt: z.string()
5349
+ });
5350
+ var GitHubAppInfo = z.object({
5351
+ configured: z.boolean(),
5352
+ appId: z.string().nullable(),
5353
+ clientId: z.string().nullable(),
5354
+ appSlug: z.string().nullable(),
5355
+ installUrl: z.string().nullable(),
5356
+ linkUrl: z.string().nullable(),
5357
+ installations: z.array(GitHubInstallationBinding),
5358
+ missing: z.array(z.string())
5359
+ });
5360
+ var GitHubRepositoriesResponse = z.object({
5361
+ repositories: z.array(GitHubRepository)
5362
+ });
3163
5363
  var ClientAuthConfig = z.discriminatedUnion("mode", [
3164
5364
  z.object({
3165
5365
  mode: z.literal("none")
@@ -3288,7 +5488,7 @@ var ViewerHolder = z.object({
3288
5488
  leaseEpoch: z.number().int().nonnegative(),
3289
5489
  viewerHeartbeatIntervalMs: z.number().int().positive(),
3290
5490
  // The desktop pixel tunnel URL the viewer connects to directly; null until
3291
- // P4 mints it (gated until then).
5491
+ // a viewer grant is minted (gated until then).
3292
5492
  dataPlaneUrl: z.string().nullable()
3293
5493
  });
3294
5494
  var AcknowledgeStreamRequest = z.object({
@@ -3549,8 +5749,11 @@ var ClientModel = z.object({
3549
5749
  api: z.enum(["responses", "chat"]),
3550
5750
  contextWindowTokens: z.number().int().positive().optional()
3551
5751
  });
5752
+ var OPENGENI_API_CONTRACT_REVISION = "2026-07-turn-instructions-v1";
5753
+ var OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract";
3552
5754
  var ClientConfig = z.object({
3553
5755
  deploymentRevision: z.string(),
5756
+ apiContractRevision: z.literal(OPENGENI_API_CONTRACT_REVISION),
3554
5757
  // Release-train version of the server (absent on dev/source builds). The
3555
5758
  // compatibility policy lives in docs/architecture.md — clients within the
3556
5759
  // same major are supported; evolution is additive within a major.
@@ -3641,7 +5844,6 @@ export {
3641
5844
  CAPABILITY_DESCRIPTORS,
3642
5845
  CLEARED_RUN_STATE_BLOB,
3643
5846
  CLEARED_RUN_STATE_MARKER,
3644
- CancelSessionQueueItemRequest,
3645
5847
  CapabilityCatalogAuthKind,
3646
5848
  CapabilityCatalogItem,
3647
5849
  CapabilityCatalogResponse,
@@ -3667,6 +5869,7 @@ export {
3667
5869
  CompactSessionContextRequest,
3668
5870
  CompactSessionContextResult,
3669
5871
  CompleteFileUploadResponse,
5872
+ ComposerDraft,
3670
5873
  ConnectionCredentialBundle,
3671
5874
  ConnectionKind,
3672
5875
  ConnectionMetadata,
@@ -3685,13 +5888,16 @@ export {
3685
5888
  CreateRigRequest,
3686
5889
  CreateScheduledTaskRequest,
3687
5890
  CreateSessionRequest,
5891
+ CreateSessionResponse,
3688
5892
  CreateSocialConnectionRequest,
3689
5893
  CreateSocialPostRequest,
3690
5894
  CreateVariableSetRequest,
3691
5895
  CreateWorkspaceEnvironmentRequest,
3692
5896
  CreateWorkspaceRequest,
5897
+ CredentialAuthNeededPayload,
3693
5898
  DESKTOP_STREAM_PORT,
3694
5899
  DelegatedAccessTokenPayload,
5900
+ DeleteSessionQueueItemRequest,
3695
5901
  DeviceEnrollmentApproveRequest,
3696
5902
  DeviceEnrollmentApproveResponse,
3697
5903
  DeviceEnrollmentDenyRequest,
@@ -3711,6 +5917,10 @@ export {
3711
5917
  DocumentSearchRequest,
3712
5918
  DocumentSearchResult,
3713
5919
  DocumentStatus,
5920
+ EditSessionQueueItemRequest,
5921
+ EffectiveControlBlocker,
5922
+ EffectiveControlResumeOption,
5923
+ EffectiveSessionControl,
3714
5924
  EnableCapabilityRequest,
3715
5925
  EnablePackRequest,
3716
5926
  EnrollTokenExchangeRequest,
@@ -3753,6 +5963,7 @@ export {
3753
5963
  GetWorkspaceCaptureResponse,
3754
5964
  GitChangedPayload,
3755
5965
  GitCommit,
5966
+ GitCredentialBindingId,
3756
5967
  GitCredentialProvider,
3757
5968
  GitCredentialRepositoryRef,
3758
5969
  GitDiffHunk,
@@ -3763,15 +5974,36 @@ export {
3763
5974
  GitFileDiff,
3764
5975
  GitFileStatus,
3765
5976
  GitFileStatusCode,
5977
+ GitHubAppInfo,
3766
5978
  GitHubAppManifestCreate,
5979
+ GitHubInstallationBinding,
5980
+ GitHubRepositoriesResponse,
3767
5981
  GitHubRepository,
5982
+ GitHubRepositoryScope,
3768
5983
  GitLogRequest,
3769
5984
  GitLogResponse,
5985
+ GitRepositoryAccess,
3770
5986
  GitShowRequest,
3771
5987
  GitShowResponse,
3772
5988
  GitStatusRequest,
3773
5989
  GitStatusResponse,
3774
5990
  GoalSpec,
5991
+ HostEventExport,
5992
+ HostEventExportBatch,
5993
+ HostExportConsumerId,
5994
+ HostExportCursor,
5995
+ HostExportInitiator,
5996
+ HostExportInitiatorContext,
5997
+ HostSessionEvent,
5998
+ HostUsageEvent,
5999
+ HostUsageExport,
6000
+ HostUsageExportBatch,
6001
+ HumanInputAnswer,
6002
+ HumanInputOption,
6003
+ HumanInputQuestion,
6004
+ HumanInputQuestionKind,
6005
+ HumanInputRequestStatus,
6006
+ HumanInputResponse,
3775
6007
  IntegrationClientMetadata,
3776
6008
  KnowledgeMemory,
3777
6009
  KnowledgeMemoryKind,
@@ -3792,12 +6024,17 @@ export {
3792
6024
  MachinesResponse,
3793
6025
  ManagedAccount,
3794
6026
  MarketingDailyAnalysisTaskRequest,
6027
+ McpConnectionResourceScope,
3795
6028
  McpServerConnectionRef,
3796
6029
  MetricSample,
3797
6030
  MintEnrollTokenRequest,
3798
6031
  MintEnrollTokenResponse,
6032
+ MoveSessionQueueItemRequest,
3799
6033
  OAuthStartRequest,
3800
6034
  OAuthStartResponse,
6035
+ OPENGENI_API_CONTRACT_HEADER,
6036
+ OPENGENI_API_CONTRACT_REVISION,
6037
+ OPENGENI_HOST_EXPORT_SCHEMA_REVISION,
3801
6038
  PackInstallation,
3802
6039
  PackInstallationStatus,
3803
6040
  Permission,
@@ -3819,6 +6056,8 @@ export {
3819
6056
  RegisterCapabilityPackRequest,
3820
6057
  RelayTokenPayload,
3821
6058
  RepositoryResourceRef,
6059
+ RequestHumanInputToolInput,
6060
+ ResourceMountPathError,
3822
6061
  ResourceRef,
3823
6062
  ResourceRefConflictError,
3824
6063
  RevokeEnrollmentResponse,
@@ -3833,10 +6072,21 @@ export {
3833
6072
  RigSetupAppendPayload,
3834
6073
  RigVerificationHealth,
3835
6074
  RigVersion,
6075
+ SESSION_AUTHORIZATION_LIST_SCOPE_MAX_IDS,
6076
+ SESSION_EVENT_CLIENT_EVENT_ID_MAX_BYTES,
6077
+ SESSION_EVENT_DUPLICATE_REASON_MAX_BYTES,
6078
+ SESSION_EVENT_ENVELOPE_MAX_BYTES,
6079
+ SESSION_EVENT_PAYLOAD_MAX_BYTES,
6080
+ SESSION_EVENT_RAW_DELTA_TYPES,
6081
+ SESSION_EVENT_SEMANTIC_CLASS_TYPES,
6082
+ SESSION_EVENT_TURN_ASSOCIATION_MAX_BYTES,
6083
+ SESSION_EVENT_TYPE_MAX_BYTES,
6084
+ SESSION_OPERATION_KEY_MAX_CHARS,
3836
6085
  SandboxBackend,
3837
6086
  SandboxCapabilityName,
3838
6087
  SandboxCommandOutputDeltaPayload,
3839
6088
  SandboxOs,
6089
+ SaveComposerDraftRequest,
3840
6090
  ScheduledTask,
3841
6091
  ScheduledTaskAgentConfig,
3842
6092
  ScheduledTaskOverlapPolicy,
@@ -3846,18 +6096,32 @@ export {
3846
6096
  ScheduledTaskScheduleSpec,
3847
6097
  ScheduledTaskStatus,
3848
6098
  ScheduledTaskTriggerType,
6099
+ ServiceTurnInitiator,
6100
+ ServiceTurnInitiatorContext,
3849
6101
  Session,
6102
+ SessionAuthorizationActor,
6103
+ SessionAuthorizationDecision,
6104
+ SessionAuthorizationListScope,
6105
+ SessionAuthorizationOperation,
6106
+ SessionAuthorizationSurface,
6107
+ SessionAuthorizationTarget,
3850
6108
  SessionBusMessage,
3851
6109
  SessionCapabilities,
6110
+ SessionCommandReceipt,
3852
6111
  SessionControlRequest,
3853
6112
  SessionControlResponse,
3854
6113
  SessionControlState,
3855
6114
  SessionEvent,
6115
+ SessionEventPayloadMode,
6116
+ SessionEventReadDirection,
6117
+ SessionEventReadMode,
6118
+ SessionEventSemanticClass,
3856
6119
  SessionEventType,
3857
6120
  SessionGoal,
3858
6121
  SessionGoalCreatedBy,
3859
6122
  SessionGoalPausedReason,
3860
6123
  SessionGoalStatus,
6124
+ SessionHumanInputRequest,
3861
6125
  SessionLineageResponse,
3862
6126
  SessionListResponse,
3863
6127
  SessionMcpCredentialUpdateInput,
@@ -3869,6 +6133,7 @@ export {
3869
6133
  SessionStructuredCapabilities,
3870
6134
  SessionSystemUpdate,
3871
6135
  SessionSystemUpdateKind,
6136
+ SessionSystemUpdatePayload,
3872
6137
  SessionSystemUpdateState,
3873
6138
  SessionTurn,
3874
6139
  SessionTurnSource,
@@ -3883,11 +6148,13 @@ export {
3883
6148
  StaticUsageLimits,
3884
6149
  SteerSessionMessageRequest,
3885
6150
  SteerSessionMessageResponse,
6151
+ SteerSessionQueueItemRequest,
3886
6152
  StreamClosedPayload,
3887
6153
  StreamOpenedPayload,
3888
6154
  StreamRevokedPayload,
3889
6155
  StreamTokenPayload,
3890
6156
  StreamUrlRotatedPayload,
6157
+ SubmitHumanInputResponseRequest,
3891
6158
  SwapActiveSandboxRequest,
3892
6159
  SwapActiveSandboxResponse,
3893
6160
  SystemUpdateClassification,
@@ -3899,7 +6166,16 @@ export {
3899
6166
  TerminalPtyStartedPayload,
3900
6167
  ToolAuthNeededPayload,
3901
6168
  ToolRef,
6169
+ TranscriptionErrorCode,
6170
+ TranscriptionEvent,
6171
+ TranscriptionResultMetadata,
6172
+ TranscriptionSpeaker,
6173
+ TranscriptionTimeSpan,
6174
+ TranscriptionWord,
3902
6175
  TriggerScheduledTaskRequest,
6176
+ TurnInitiator,
6177
+ TurnInitiatorContext,
6178
+ UNATTRIBUTED_LEGACY_INITIATOR_SUBJECT_ID,
3903
6179
  UpdateConnectionRequest,
3904
6180
  UpdateKnowledgeMemoryRequest,
3905
6181
  UpdateRigRequest,
@@ -3922,6 +6198,9 @@ export {
3922
6198
  ViewerHeartbeatRequest,
3923
6199
  ViewerHeartbeatResponse,
3924
6200
  ViewerHolder,
6201
+ WORKSPACE_CONTROL_ACTOR_MAX_BYTES,
6202
+ WORKSPACE_CONTROL_EVENT_MAX_BYTES,
6203
+ WORKSPACE_CONTROL_REASON_MAX_BYTES,
3925
6204
  Workspace,
3926
6205
  WorkspaceCaptureDegradedReason,
3927
6206
  WorkspaceCaptureFile,
@@ -3929,6 +6208,8 @@ export {
3929
6208
  WorkspaceCaptureRepo,
3930
6209
  WorkspaceCaptureSignedUrl,
3931
6210
  WorkspaceCaptureStats,
6211
+ WorkspaceControlEvent,
6212
+ WorkspaceControlEventTruncation,
3932
6213
  WorkspaceEnvironment,
3933
6214
  WorkspaceEnvironmentVariableMetadata,
3934
6215
  WorkspaceInferenceControlRequest,
@@ -3943,14 +6224,35 @@ export {
3943
6224
  WorkspaceRevisionCapturedPayload,
3944
6225
  WorkspaceRevisionDegradedPayload,
3945
6226
  WorkspaceSettingsSchema,
6227
+ WorkspaceTranscriptionPolicy,
6228
+ WorkspaceTranscriptionTarget,
6229
+ approvalIdentifier,
6230
+ approximateSessionEventTokens,
6231
+ assertUniqueResourceMountPaths,
6232
+ boundSessionEvent,
6233
+ boundSessionEventPayload,
6234
+ boundWorkspaceControlEvent,
6235
+ defaultRepositoryMountPath,
3946
6236
  evaluateWorkspaceModelPolicy,
6237
+ gitCredentialBindingIdForRepository,
6238
+ gitCredentialProviderForRepository,
3947
6239
  isClearedRunStateBlob,
6240
+ measureSessionEventJson,
3948
6241
  mergeResourceRefs,
3949
6242
  mergeToolRefs,
6243
+ normalizeRepositorySubpath,
6244
+ normalizeResourceMountPath,
3950
6245
  prefixedMcpToolName,
3951
6246
  reasoningEffortForMetadata,
6247
+ resolveSessionEventTypeFilters,
3952
6248
  resolveWorkspaceMemoryEnabled,
3953
6249
  resourceIdentityKey,
6250
+ resourceMountPath,
6251
+ resourceMountPathCollisionKey,
6252
+ sessionEventJsonBytes,
6253
+ sessionEventMediaPreview,
6254
+ sessionEventMediaPreviewFromDataUrl,
6255
+ sessionEventPayloadTruncation,
3954
6256
  signDelegatedAccessToken,
3955
6257
  signEnrollToken,
3956
6258
  signEnrollmentBearer,
@@ -3961,6 +6263,7 @@ export {
3961
6263
  verifyEnrollToken,
3962
6264
  verifyEnrollmentBearer,
3963
6265
  verifyRelayToken,
3964
- verifyStreamToken
6266
+ verifyStreamToken,
6267
+ workspaceControlUtf8Bytes
3965
6268
  };
3966
6269
  //# sourceMappingURL=index.js.map