@peasant-labs/schema 0.23.0 → 0.25.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/fixtures/session-graph-capability.d.ts +83 -3
- package/dist/fixtures/session-graph.d.ts +14 -0
- package/dist/index.js +75 -0
- package/dist/internal/generated/content-capabilities.gen.d.ts +1 -0
- package/dist/internal/generated/content-capabilities.gen.js +4 -1
- package/dist/internal/generated/contract/zod.gen.d.ts +1240 -214
- package/dist/internal/generated/contract/zod.gen.js +402 -64
- package/dist/internal/generated/enums.gen.d.ts +119 -0
- package/dist/internal/generated/enums.gen.js +132 -0
- package/dist/internal/generated/local-api.d.ts +859 -11
- package/dist/internal/generated/public-contract.gen.d.ts +2 -2
- package/dist/internal/generated/public-contract.gen.js +1 -1
- package/dist/internal/generated/session-graph-capability-fixtures.gen.d.ts +83 -3
- package/dist/internal/generated/session-graph-capability-fixtures.gen.js +116 -3
- package/dist/internal/generated/session-graph-fixtures.gen.d.ts +14 -0
- package/dist/internal/generated/session-graph-fixtures.gen.js +21 -7
- package/dist/internal/generated/versions.gen.d.ts +3 -3
- package/dist/internal/generated/versions.gen.js +3 -3
- package/dist/internal/generated/village-api.d.ts +140 -2
- package/dist/internal/generated/wire-alias-shapes.gen.d.ts +267 -0
- package/dist/internal/generated/wire-alias-shapes.gen.js +268 -0
- package/package.json +1 -1
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
export declare function sessionGraphCapabilityFixtures(): {
|
|
2
2
|
readonly requiredNames: {
|
|
3
|
-
readonly derivation: readonly ["legacy-empty", "root-null", "usage-null", "model-only", "source-ref-only", "count-only-zero", "count-only-positive", "root-only", "purpose-only-interaction", "purpose-only-delegated", "purpose-only-helper", "purpose-only-unknown", "relationship-only", "main-deeper-provenance", "folded-call-provenance", "folded-result-provenance", "earlier-only", "earlier-nested-tool-native-usage-model", "navigation-only-read"];
|
|
4
|
-
readonly reader: readonly ["advertisement-omitted", "advertisement-empty", "advertisement-null", "advertisement-unknown-duplicate-unordered", "advertisement-future-suffix"];
|
|
5
|
-
readonly producer: readonly ["producer-canonical-four", "producer-unsorted-four", "producer-duplicate", "producer-unknown"];
|
|
3
|
+
readonly derivation: readonly ["legacy-empty", "root-null", "usage-null", "model-only", "source-ref-only", "count-only-zero", "count-only-positive", "root-only", "purpose-only-interaction", "purpose-only-delegated", "purpose-only-helper", "purpose-only-unknown", "relationship-only", "main-deeper-provenance", "folded-call-provenance", "folded-result-provenance", "earlier-only", "earlier-nested-tool-native-usage-model", "navigation-only-read", "retained-accumulates-all"];
|
|
4
|
+
readonly reader: readonly ["advertisement-omitted", "advertisement-empty", "advertisement-null", "advertisement-unknown-duplicate-unordered", "advertisement-future-suffix", "advertisement-retained-duplicate"];
|
|
5
|
+
readonly producer: readonly ["producer-canonical-four", "producer-unsorted-four", "producer-duplicate", "producer-unknown", "producer-canonical-retained", "producer-unsorted-retained", "producer-duplicate-retained"];
|
|
6
6
|
};
|
|
7
7
|
readonly derivation: {
|
|
8
8
|
readonly cases: readonly [{
|
|
9
|
+
readonly name: "retained-accumulates-all";
|
|
10
|
+
readonly classification: "must-pass";
|
|
11
|
+
readonly provenance: {
|
|
12
|
+
readonly source: "requirement";
|
|
13
|
+
readonly ref: "content-capability-negotiation";
|
|
14
|
+
};
|
|
15
|
+
readonly mutation: {
|
|
16
|
+
readonly description: "Retained evidence accumulates every existing preservation requirement";
|
|
17
|
+
};
|
|
18
|
+
readonly input: {
|
|
19
|
+
readonly detailJSON: "{\"id\":\"fixture-session\",\"harness\":\"pi\",\"startTime\":\"2020-01-01T00:00:00Z\",\"endTime\":\"2020-01-01T00:00:00Z\",\"durationMins\":0,\"totalTokens\":0,\"tokensIn\":0,\"tokensOut\":0,\"turnCount\":1,\"toolCallCount\":1,\"purpose\":\"interaction\",\"turns\":[{\"index\":0,\"role\":\"assistant\",\"depth\":0,\"content\":\"\",\"timestamp\":\"2020-01-01T00:00:00Z\",\"sourceEntryRef\":\"e1\",\"observedModel\":\"provider/model\",\"usage\":{\"ownerId\":\"u1\",\"sourceEntryRef\":\"e1\",\"scope\":\"assistant\",\"completeness\":\"unknown\"},\"toolCalls\":[{\"id\":\"t1\",\"name\":\"tool\",\"namespace\":\"extension\",\"arguments\":\"\",\"result\":\"\"}]}],\"nativeMetadata\":[{\"id\":\"n1\",\"kind\":\"pi.custom.data\",\"source\":{\"entryRef\":\"custom1\",\"sourceType\":\"pi.custom\"},\"customType\":\"extension\",\"data\":{}}],\"diagnostics\":{\"partial\":true},\"retainedUnknown\":[{\"sourceRef\":\"source-0\",\"recordIndex\":2,\"position\":4,\"pointer\":\"\",\"namespace\":\"record\",\"kind\":\"future\",\"payload\":\"{\\\"type\\\":\\\"future\\\"}\"}]}";
|
|
20
|
+
};
|
|
21
|
+
readonly expected: {
|
|
22
|
+
readonly capabilities: readonly ["detailed_usage_v1", "native_metadata_v1", "observed_model_v1", "retained_unknown_v1", "session_graph_provenance_v1", "tool_namespace_v1"];
|
|
23
|
+
};
|
|
24
|
+
}, {
|
|
9
25
|
readonly name: "legacy-empty";
|
|
10
26
|
readonly classification: "must-pass";
|
|
11
27
|
readonly provenance: {
|
|
@@ -303,6 +319,22 @@ export declare function sessionGraphCapabilityFixtures(): {
|
|
|
303
319
|
};
|
|
304
320
|
readonly reader: {
|
|
305
321
|
readonly cases: readonly [{
|
|
322
|
+
readonly name: "advertisement-retained-duplicate";
|
|
323
|
+
readonly classification: "must-pass";
|
|
324
|
+
readonly provenance: {
|
|
325
|
+
readonly source: "requirement";
|
|
326
|
+
readonly ref: "content-capability-negotiation";
|
|
327
|
+
};
|
|
328
|
+
readonly mutation: {
|
|
329
|
+
readonly description: "Exact retained token survives forward-open discovery";
|
|
330
|
+
};
|
|
331
|
+
readonly input: {
|
|
332
|
+
readonly json: "{\"contentCapabilities\":[\"retained_unknown_v1\",\"retained_unknown_v2\",\"retained_unknown_v1\",\"session_graph_provenance_v1\"]}";
|
|
333
|
+
};
|
|
334
|
+
readonly expected: {
|
|
335
|
+
readonly known: readonly ["retained_unknown_v1", "session_graph_provenance_v1"];
|
|
336
|
+
};
|
|
337
|
+
}, {
|
|
306
338
|
readonly name: "advertisement-omitted";
|
|
307
339
|
readonly classification: "must-pass";
|
|
308
340
|
readonly provenance: {
|
|
@@ -386,6 +418,54 @@ export declare function sessionGraphCapabilityFixtures(): {
|
|
|
386
418
|
};
|
|
387
419
|
readonly producer: {
|
|
388
420
|
readonly cases: readonly [{
|
|
421
|
+
readonly name: "producer-canonical-retained";
|
|
422
|
+
readonly classification: "must-pass";
|
|
423
|
+
readonly provenance: {
|
|
424
|
+
readonly source: "requirement";
|
|
425
|
+
readonly ref: "content-capability-negotiation";
|
|
426
|
+
};
|
|
427
|
+
readonly mutation: {
|
|
428
|
+
readonly description: "Emits sorted accumulated inventory";
|
|
429
|
+
};
|
|
430
|
+
readonly input: {
|
|
431
|
+
readonly tokens: readonly ["detailed_usage_v1", "native_metadata_v1", "observed_model_v1", "retained_unknown_v1", "session_graph_provenance_v1", "tool_namespace_v1"];
|
|
432
|
+
};
|
|
433
|
+
readonly expected: {
|
|
434
|
+
readonly accepted: true;
|
|
435
|
+
};
|
|
436
|
+
}, {
|
|
437
|
+
readonly name: "producer-unsorted-retained";
|
|
438
|
+
readonly classification: "must-fail";
|
|
439
|
+
readonly provenance: {
|
|
440
|
+
readonly source: "boundary";
|
|
441
|
+
readonly ref: "content-capability-negotiation";
|
|
442
|
+
};
|
|
443
|
+
readonly mutation: {
|
|
444
|
+
readonly description: "Retained token out of canonical order refuses";
|
|
445
|
+
};
|
|
446
|
+
readonly input: {
|
|
447
|
+
readonly tokens: readonly ["retained_unknown_v1", "observed_model_v1"];
|
|
448
|
+
};
|
|
449
|
+
readonly expected: {
|
|
450
|
+
readonly errorContains: "canonical lexicographic order";
|
|
451
|
+
};
|
|
452
|
+
}, {
|
|
453
|
+
readonly name: "producer-duplicate-retained";
|
|
454
|
+
readonly classification: "must-fail";
|
|
455
|
+
readonly provenance: {
|
|
456
|
+
readonly source: "boundary";
|
|
457
|
+
readonly ref: "content-capability-negotiation";
|
|
458
|
+
};
|
|
459
|
+
readonly mutation: {
|
|
460
|
+
readonly description: "Duplicate retained token refuses";
|
|
461
|
+
};
|
|
462
|
+
readonly input: {
|
|
463
|
+
readonly tokens: readonly ["retained_unknown_v1", "retained_unknown_v1"];
|
|
464
|
+
};
|
|
465
|
+
readonly expected: {
|
|
466
|
+
readonly errorContains: "duplicated";
|
|
467
|
+
};
|
|
468
|
+
}, {
|
|
389
469
|
readonly name: "producer-canonical-four";
|
|
390
470
|
readonly classification: "must-pass";
|
|
391
471
|
readonly provenance: {
|
|
@@ -5246,6 +5246,7 @@ export declare function sessionGraphFixtures(): {
|
|
|
5246
5246
|
readonly total_turns: 0;
|
|
5247
5247
|
readonly total_duration_ms: 0;
|
|
5248
5248
|
readonly total_tokens: 0;
|
|
5249
|
+
readonly pull_request_count: 0;
|
|
5249
5250
|
};
|
|
5250
5251
|
readonly models: readonly [];
|
|
5251
5252
|
readonly contributors: readonly [];
|
|
@@ -5291,6 +5292,7 @@ export declare function sessionGraphFixtures(): {
|
|
|
5291
5292
|
readonly total_turns: 0;
|
|
5292
5293
|
readonly total_duration_ms: 0;
|
|
5293
5294
|
readonly total_tokens: 0;
|
|
5295
|
+
readonly pull_request_count: 0;
|
|
5294
5296
|
};
|
|
5295
5297
|
readonly models: readonly [];
|
|
5296
5298
|
readonly contributors: readonly [];
|
|
@@ -5345,6 +5347,7 @@ export declare function sessionGraphFixtures(): {
|
|
|
5345
5347
|
readonly total_turns: 0;
|
|
5346
5348
|
readonly total_duration_ms: 0;
|
|
5347
5349
|
readonly total_tokens: 0;
|
|
5350
|
+
readonly pull_request_count: 0;
|
|
5348
5351
|
};
|
|
5349
5352
|
readonly models: readonly [];
|
|
5350
5353
|
readonly contributors: readonly [];
|
|
@@ -5392,6 +5395,7 @@ export declare function sessionGraphFixtures(): {
|
|
|
5392
5395
|
readonly total_turns: 0;
|
|
5393
5396
|
readonly total_duration_ms: 0;
|
|
5394
5397
|
readonly total_tokens: 0;
|
|
5398
|
+
readonly pull_request_count: 0;
|
|
5395
5399
|
};
|
|
5396
5400
|
readonly models: readonly [];
|
|
5397
5401
|
readonly contributors: readonly [];
|
|
@@ -6145,6 +6149,7 @@ export declare function sessionGraphFixtures(): {
|
|
|
6145
6149
|
readonly inputSubmissionCount: 1;
|
|
6146
6150
|
readonly model: "codex";
|
|
6147
6151
|
readonly syncStatus: "synced";
|
|
6152
|
+
readonly previouslyPushed: true;
|
|
6148
6153
|
};
|
|
6149
6154
|
};
|
|
6150
6155
|
readonly helperGroups: readonly [{
|
|
@@ -6203,6 +6208,7 @@ export declare function sessionGraphFixtures(): {
|
|
|
6203
6208
|
readonly inputSubmissionCount: 0;
|
|
6204
6209
|
readonly model: "codex";
|
|
6205
6210
|
readonly syncStatus: "synced";
|
|
6211
|
+
readonly previouslyPushed: true;
|
|
6206
6212
|
};
|
|
6207
6213
|
};
|
|
6208
6214
|
readonly helperGroups: readonly [{
|
|
@@ -6472,6 +6478,10 @@ export declare function sessionGraphFixtures(): {
|
|
|
6472
6478
|
readonly owner_username: "owner";
|
|
6473
6479
|
readonly owner_avatar_url: null;
|
|
6474
6480
|
readonly owner_is_discoverable: true;
|
|
6481
|
+
readonly pull_requests: {
|
|
6482
|
+
readonly count: 0;
|
|
6483
|
+
readonly recent: readonly [];
|
|
6484
|
+
};
|
|
6475
6485
|
};
|
|
6476
6486
|
};
|
|
6477
6487
|
readonly helperGroups: readonly [{
|
|
@@ -6641,6 +6651,10 @@ export declare function sessionGraphFixtures(): {
|
|
|
6641
6651
|
readonly owner_username: "owner";
|
|
6642
6652
|
readonly owner_avatar_url: null;
|
|
6643
6653
|
readonly owner_is_discoverable: true;
|
|
6654
|
+
readonly pull_requests: {
|
|
6655
|
+
readonly count: 0;
|
|
6656
|
+
readonly recent: readonly [];
|
|
6657
|
+
};
|
|
6644
6658
|
readonly input_submission_count: 0;
|
|
6645
6659
|
};
|
|
6646
6660
|
};
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export * from "./internal/generated/versions.gen.js";
|
|
|
5
5
|
import { requiredContentCapabilities, KnownContentCapability } from "./internal/generated/content-capabilities.gen.js";
|
|
6
6
|
import { zNativeMetadataRecord, zTurnDetail, zProjectHash, zServerMessage, zSessionDetailPayload, zSessionDetailReadPayload, zTranscriptContent } from "./internal/generated/contract/zod.gen.js";
|
|
7
7
|
import { maxNativeMetadataStringBytes } from "./internal/generated/metadata-limits.gen.js";
|
|
8
|
+
import { wireAliasShapes } from "./internal/generated/wire-alias-shapes.gen.js";
|
|
8
9
|
function assertProjectHash(value, operation) {
|
|
9
10
|
if (!isProjectHash(value)) {
|
|
10
11
|
const rendered = renderProjectHashInput(value);
|
|
@@ -49,6 +50,7 @@ function scanRawJson(text, policy) {
|
|
|
49
50
|
return scanner;
|
|
50
51
|
}
|
|
51
52
|
export function parseSessionDetailPayloadValue(value) {
|
|
53
|
+
rejectWireAliases(value, "SessionDetailPayload");
|
|
52
54
|
rejectExplicitNullEvidence(value);
|
|
53
55
|
validateRawGraphValue(value);
|
|
54
56
|
const normalized = structuredClone(value);
|
|
@@ -117,6 +119,7 @@ export function parseTranscriptContentText(text) {
|
|
|
117
119
|
const raw = JSON.parse(text);
|
|
118
120
|
if (!isRecord(raw))
|
|
119
121
|
return zTranscriptContent.parse(raw);
|
|
122
|
+
rejectWireAliases(raw, "TranscriptContent");
|
|
120
123
|
const normalizedEnvelope = { ...raw, sessionDetail: parseSessionDetailPayloadValue(raw.sessionDetail) };
|
|
121
124
|
const content = zTranscriptContent.parse(normalizedEnvelope);
|
|
122
125
|
if (content.sessionDetail === undefined || content.sessionDetail === null)
|
|
@@ -297,6 +300,7 @@ class RawJsonScanner {
|
|
|
297
300
|
}
|
|
298
301
|
function pointerMatches(pattern, path) { const expected = pattern.split("/"); const actual = path.split("/"); return expected.length === actual.length && expected.every((part, index) => part === "*" || part === actual[index]); }
|
|
299
302
|
function validateSessionDetail(payload) {
|
|
303
|
+
validateRetainedUnknown(payload);
|
|
300
304
|
validateRelationships(payload);
|
|
301
305
|
const state = newDetailState(payload);
|
|
302
306
|
const turns = validateTurnEvidence(payload.turns ?? [], state);
|
|
@@ -308,6 +312,77 @@ function validateSessionDetail(payload) {
|
|
|
308
312
|
if (state.nativeCount > 0 && String(payload.harness) !== "pi")
|
|
309
313
|
failSemantic("Pi native metadata requires harness pi across every history partition");
|
|
310
314
|
}
|
|
315
|
+
function validateRetainedUnknown(payload) {
|
|
316
|
+
if ((payload.retainedUnknown?.length ?? 0) > 0 && payload.diagnostics?.partial !== true)
|
|
317
|
+
failSemantic("retainedUnknown requires diagnostics.partial=true");
|
|
318
|
+
const sources = new Map();
|
|
319
|
+
for (const [index, record] of (payload.retainedUnknown ?? []).entries()) {
|
|
320
|
+
if (!Number.isSafeInteger(record.recordIndex) || !Number.isSafeInteger(record.position) || record.recordIndex < 0 || record.position < record.recordIndex)
|
|
321
|
+
failSemantic("retainedUnknown has invalid recordIndex or position");
|
|
322
|
+
// Scan strings as JSON as well: typed JS values can contain unpaired surrogates.
|
|
323
|
+
scanRawJsonText(JSON.stringify([record.sourceRef, record.namespace, record.kind, record.pointer]));
|
|
324
|
+
const previous = sources.get(record.sourceRef);
|
|
325
|
+
if (previous !== undefined && (record.position <= previous.position || record.recordIndex < previous.record))
|
|
326
|
+
failSemantic("retainedUnknown repeats or reverses a source position");
|
|
327
|
+
const pointers = previous?.record === record.recordIndex ? previous.pointers : new RetainedPointerNode();
|
|
328
|
+
if (!pointers.insert(record.pointer))
|
|
329
|
+
failSemantic("retainedUnknown duplicates or overlaps a source pointer");
|
|
330
|
+
try {
|
|
331
|
+
scanRawJsonText(record.payload, { maxDocumentBytes: 8 << 20, maxDocumentDepth: 64 });
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
// Native keys/paths are untrusted even when a producer claims redaction.
|
|
335
|
+
// Do not expose the scanner exception, its message, or a cause chain.
|
|
336
|
+
failSemantic(`retainedUnknown[${index}].payload failed JSON syntax or safety validation; provide one complete JSON value with valid Unicode, unique object keys, and the published byte/depth bounds`);
|
|
337
|
+
}
|
|
338
|
+
sources.set(record.sourceRef, { position: record.position, record: record.recordIndex, pointers });
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
class RetainedPointerNode {
|
|
342
|
+
terminal = false;
|
|
343
|
+
children = new Map();
|
|
344
|
+
insert(pointer) {
|
|
345
|
+
let node = this;
|
|
346
|
+
for (const component of pointer === "" ? [] : pointer.slice(1).split("/")) {
|
|
347
|
+
if (node.terminal)
|
|
348
|
+
return false;
|
|
349
|
+
let child = node.children.get(component);
|
|
350
|
+
if (child === undefined) {
|
|
351
|
+
child = new RetainedPointerNode();
|
|
352
|
+
node.children.set(component, child);
|
|
353
|
+
}
|
|
354
|
+
node = child;
|
|
355
|
+
}
|
|
356
|
+
if (node.terminal || node.children.size > 0)
|
|
357
|
+
return false;
|
|
358
|
+
node.terminal = true;
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function rejectWireAliases(value, descriptor) {
|
|
363
|
+
const shape = typeof descriptor === "string" ? wireAliasShapes[descriptor] : descriptor;
|
|
364
|
+
if (shape === undefined)
|
|
365
|
+
return;
|
|
366
|
+
if (shape.items !== undefined && Array.isArray(value)) {
|
|
367
|
+
for (const item of value)
|
|
368
|
+
rejectWireAliases(item, shape.items);
|
|
369
|
+
}
|
|
370
|
+
if (shape.fields === undefined || !isRecord(value))
|
|
371
|
+
return;
|
|
372
|
+
const fields = shape.fields;
|
|
373
|
+
// All canonical contract keys are ASCII. Go's Unicode simple-fold aliases
|
|
374
|
+
// additionally include long s and Kelvin sign; lowercasing handles the latter.
|
|
375
|
+
const fold = (key) => key.replaceAll("ſ", "s").toLowerCase();
|
|
376
|
+
const canonical = new Map(Object.keys(fields).map(key => [fold(key), key]));
|
|
377
|
+
for (const key of Object.keys(value)) {
|
|
378
|
+
const name = canonical.get(fold(key));
|
|
379
|
+
if (name !== undefined && key !== name)
|
|
380
|
+
failSemantic(`key ${key} aliases canonical field ${name}; use only exact published field names`);
|
|
381
|
+
const child = fields[key];
|
|
382
|
+
if (child !== undefined)
|
|
383
|
+
rejectWireAliases(value[key], child);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
311
386
|
function parseSessionDetailReadPayloadValue(value) {
|
|
312
387
|
rejectExplicitNullEvidence(value);
|
|
313
388
|
if (!isRecord(value))
|
|
@@ -12,6 +12,7 @@ export declare const KnownContentCapability: Readonly<{
|
|
|
12
12
|
readonly DetailedUsageV1: "detailed_usage_v1";
|
|
13
13
|
readonly NativeMetadataV1: "native_metadata_v1";
|
|
14
14
|
readonly ObservedModelV1: "observed_model_v1";
|
|
15
|
+
readonly RetainedUnknownV1: "retained_unknown_v1";
|
|
15
16
|
readonly SessionGraphProvenanceV1: "session_graph_provenance_v1";
|
|
16
17
|
readonly ToolNamespaceV1: "tool_namespace_v1";
|
|
17
18
|
}>;
|
|
@@ -11,10 +11,11 @@ export const KnownContentCapability = Object.freeze({
|
|
|
11
11
|
DetailedUsageV1: "detailed_usage_v1",
|
|
12
12
|
NativeMetadataV1: "native_metadata_v1",
|
|
13
13
|
ObservedModelV1: "observed_model_v1",
|
|
14
|
+
RetainedUnknownV1: "retained_unknown_v1",
|
|
14
15
|
SessionGraphProvenanceV1: "session_graph_provenance_v1",
|
|
15
16
|
ToolNamespaceV1: "tool_namespace_v1",
|
|
16
17
|
});
|
|
17
|
-
export const AllContentCapabilities = Object.freeze([KnownContentCapability.DetailedUsageV1, KnownContentCapability.NativeMetadataV1, KnownContentCapability.ObservedModelV1, KnownContentCapability.SessionGraphProvenanceV1, KnownContentCapability.ToolNamespaceV1]);
|
|
18
|
+
export const AllContentCapabilities = Object.freeze([KnownContentCapability.DetailedUsageV1, KnownContentCapability.NativeMetadataV1, KnownContentCapability.ObservedModelV1, KnownContentCapability.RetainedUnknownV1, KnownContentCapability.SessionGraphProvenanceV1, KnownContentCapability.ToolNamespaceV1]);
|
|
18
19
|
export function isContentCapability(value) {
|
|
19
20
|
return typeof value === "string" && AllContentCapabilities.includes(value);
|
|
20
21
|
}
|
|
@@ -55,6 +56,8 @@ export function requiredContentCapabilities(detail) {
|
|
|
55
56
|
found.add(KnownContentCapability.SessionGraphProvenanceV1);
|
|
56
57
|
if ((detail.nativeMetadata?.length ?? 0) > 0)
|
|
57
58
|
found.add(KnownContentCapability.NativeMetadataV1);
|
|
59
|
+
if ((detail.retainedUnknown?.length ?? 0) > 0 || detail.diagnostics !== undefined)
|
|
60
|
+
found.add(KnownContentCapability.RetainedUnknownV1);
|
|
58
61
|
visitTurns(detail.turns, found);
|
|
59
62
|
for (const section of detail.earlierHistory ?? []) {
|
|
60
63
|
if ((section.nativeMetadata?.length ?? 0) > 0)
|