@ai-matrx/content-ir 0.1.2 → 0.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0 — 2026-08-23
4
+
5
+ - Added the `wire/` layer — the server→UI contracts every UI reads the same way:
6
+ - `wire/partial-kind` — the streaming partial-kinds channel (`__ir_partial`): `readPartialKindEvent`,
7
+ `sanitizeInboundPartialKindMetadata`, `advancePartialKind`, `makePartialKindStalenessGate`,
8
+ `isProvisionalKind`, `isTerminalKindEvent`, `IR_PARTIAL_KEY` + the event types.
9
+ - `wire/runtime-wrapper` — the `node_outcome` / `run_result` runtime-wrapper reader and THE `output_ref`
10
+ elision gate: `readOutputRef`, `rehydrateNodeOutcome`, `rehydrateRunResult`, `readNodeOutcomeValue`,
11
+ `readRunResultValue`, `kindVerdictOf`, `NODE_OUTCOME_KIND`, `RUN_RESULT_KIND` + the wrapper types.
12
+ - `wire/emit-payload` — the emit/render payload composer: `withRootKind`, `emitPayloadJson`, `emitPayloadFence`.
13
+ - Brought the partial-kind suite pinned to the Python producer's generated fixture
14
+ (`__tests__/partial-kind-events.generated.json`, regenerated by aidream `scripts/generate_partial_kind_fixture.py`
15
+ and drift-gated by `packages/matrx-ai/tests/parity/test_partial_kind_fixture.py`) plus new pure suites for the
16
+ runtime-wrapper reader and the emit composer (196 tests).
17
+ - Existing 0.1.x API unchanged.
18
+
3
19
  ## 0.1.2 — 2026-08-22
4
20
 
5
21
  - Added a CommonJS export condition for Jest and other require-based consumers.
package/README.md CHANGED
@@ -11,6 +11,12 @@ import {
11
11
  createKindStreamParser,
12
12
  envelopeFromCompleteValue,
13
13
  validateStructuralLeg,
14
+ // wire layer (0.2.0): streaming partial kinds + runtime wrappers + emit payload
15
+ readPartialKindEvent,
16
+ makePartialKindStalenessGate,
17
+ rehydrateNodeOutcome,
18
+ rehydrateRunResult,
19
+ withRootKind,
14
20
  } from "@ai-matrx/content-ir";
15
21
  ```
16
22
 
package/dist/index.cjs CHANGED
@@ -4117,8 +4117,291 @@ function kindSchemaToJsonSchema(kind, resolve, options = {}) {
4117
4117
  return { name: kind, schema: { ...rootNode, $defs: defs }, strict, unresolved };
4118
4118
  }
4119
4119
 
4120
+ // wire/partial-kind.ts
4121
+ var IR_PARTIAL_KEY = "__ir_partial";
4122
+ var PARTIAL_STATES = [
4123
+ "partial",
4124
+ "superseded",
4125
+ "retracted"
4126
+ ];
4127
+ function isRecord5(value) {
4128
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4129
+ }
4130
+ function readPath(value) {
4131
+ if (!Array.isArray(value)) return null;
4132
+ return value.every(
4133
+ (segment) => typeof segment === "string" || typeof segment === "number"
4134
+ ) ? value : null;
4135
+ }
4136
+ function readDiscriminator(value) {
4137
+ if (!isRecord5(value)) return null;
4138
+ if (value.format === "json" && value.key === "__kind") {
4139
+ return { format: "json", key: "__kind" };
4140
+ }
4141
+ if (value.format === "xml" && typeof value.tag === "string") {
4142
+ return { format: "xml", tag: value.tag };
4143
+ }
4144
+ if (value.format === "fence" && typeof value.language === "string") {
4145
+ return { format: "fence", language: value.language };
4146
+ }
4147
+ return null;
4148
+ }
4149
+ function readResidue(value) {
4150
+ if (value === null) return null;
4151
+ if (!isRecord5(value)) return void 0;
4152
+ const extra = value.extra;
4153
+ const optionalMissing = value.optionalMissing;
4154
+ const notices = value.notices;
4155
+ if (extra !== null && !isRecord5(extra)) return void 0;
4156
+ if (optionalMissing !== null && (!Array.isArray(optionalMissing) || !optionalMissing.every((item) => typeof item === "string"))) {
4157
+ return void 0;
4158
+ }
4159
+ if (notices !== null && (!Array.isArray(notices) || !notices.every(
4160
+ (notice) => isRecord5(notice) && typeof notice.code === "string" && typeof notice.message === "string" && (notice.at === void 0 || typeof notice.at === "number")
4161
+ ))) {
4162
+ return void 0;
4163
+ }
4164
+ return { extra, optionalMissing, notices };
4165
+ }
4166
+ function readPartialKindEvent(metadata) {
4167
+ if (!isRecord5(metadata)) return null;
4168
+ const candidate = metadata[IR_PARTIAL_KEY];
4169
+ if (!isRecord5(candidate)) return null;
4170
+ if (candidate.v !== IR_VERSION) return null;
4171
+ if (typeof candidate.engine !== "string") return null;
4172
+ if (typeof candidate.seq !== "number" || !Number.isFinite(candidate.seq)) {
4173
+ return null;
4174
+ }
4175
+ const state = candidate.state;
4176
+ if (typeof state !== "string") return null;
4177
+ if (!PARTIAL_STATES.includes(state)) return null;
4178
+ if (state === "partial") {
4179
+ const root = candidate.root;
4180
+ if (!isRecord5(root)) return null;
4181
+ if (root.role !== "structured") return null;
4182
+ if (root.status !== "streaming") return null;
4183
+ if (root.kindState !== "speculative") return null;
4184
+ if (typeof root.kind !== "string" || !root.kind) return null;
4185
+ if (!isRecord5(root.value)) return null;
4186
+ const discriminator = readDiscriminator(root.discriminator);
4187
+ const path = readPath(root.path);
4188
+ const residue = readResidue(root.residue);
4189
+ if (discriminator === null || path === null || residue === void 0) {
4190
+ return null;
4191
+ }
4192
+ return {
4193
+ v: IR_VERSION,
4194
+ engine: candidate.engine,
4195
+ state: "partial",
4196
+ seq: candidate.seq,
4197
+ fingerprint: typeof candidate.fingerprint === "string" ? candidate.fingerprint : "",
4198
+ root: {
4199
+ role: "structured",
4200
+ kind: root.kind,
4201
+ kindState: "speculative",
4202
+ discriminator,
4203
+ path,
4204
+ status: "streaming",
4205
+ value: root.value,
4206
+ residue
4207
+ }
4208
+ };
4209
+ }
4210
+ if (typeof candidate.kind !== "string" || !candidate.kind) return null;
4211
+ if (state === "superseded") {
4212
+ return {
4213
+ v: IR_VERSION,
4214
+ engine: candidate.engine,
4215
+ state: "superseded",
4216
+ seq: candidate.seq,
4217
+ kind: candidate.kind
4218
+ };
4219
+ }
4220
+ if (typeof candidate.reason !== "string" || !candidate.reason) return null;
4221
+ if (candidate.becameKind !== null && typeof candidate.becameKind !== "string") {
4222
+ return null;
4223
+ }
4224
+ if (candidate.becameBlockType !== null && typeof candidate.becameBlockType !== "string") {
4225
+ return null;
4226
+ }
4227
+ return {
4228
+ v: IR_VERSION,
4229
+ engine: candidate.engine,
4230
+ state: "retracted",
4231
+ seq: candidate.seq,
4232
+ kind: candidate.kind,
4233
+ reason: candidate.reason,
4234
+ becameKind: candidate.becameKind,
4235
+ becameBlockType: candidate.becameBlockType
4236
+ };
4237
+ }
4238
+ function sanitizeInboundPartialKindMetadata(metadata, context, hooks = {}) {
4239
+ if (!isRecord5(metadata) || !(IR_PARTIAL_KEY in metadata)) {
4240
+ return metadata ?? void 0;
4241
+ }
4242
+ if (readPartialKindEvent(metadata) !== null) return metadata;
4243
+ const { [IR_PARTIAL_KEY]: raw, ...rest } = metadata;
4244
+ hooks.reportMalformed?.({ blockId: context.blockId, raw });
4245
+ return rest;
4246
+ }
4247
+ function isProvisionalKind(event) {
4248
+ return event !== null && event.state === "partial";
4249
+ }
4250
+ function isTerminalKindEvent(event) {
4251
+ return event !== null && (event.state === "superseded" || event.state === "retracted");
4252
+ }
4253
+ function advancePartialKind(seen, blockId, event) {
4254
+ if (event === null) return null;
4255
+ const last = seen[blockId];
4256
+ if (last !== void 0 && event.seq <= last) return null;
4257
+ return event;
4258
+ }
4259
+ function makePartialKindStalenessGate() {
4260
+ const seen = {};
4261
+ const lastAccepted = {};
4262
+ const terminated = {};
4263
+ return (blockId, metadata) => {
4264
+ if (!isRecord5(metadata)) return metadata;
4265
+ if (!(IR_PARTIAL_KEY in metadata)) {
4266
+ const open = lastAccepted[blockId];
4267
+ if (terminated[blockId] || open === void 0) return metadata;
4268
+ return { ...metadata, [IR_PARTIAL_KEY]: open };
4269
+ }
4270
+ const parsed = readPartialKindEvent(metadata);
4271
+ if (parsed === null) return metadata;
4272
+ if (advancePartialKind(seen, blockId, parsed) !== null) {
4273
+ seen[blockId] = parsed.seq;
4274
+ lastAccepted[blockId] = metadata[IR_PARTIAL_KEY];
4275
+ if (isTerminalKindEvent(parsed)) terminated[blockId] = true;
4276
+ return metadata;
4277
+ }
4278
+ const carried = lastAccepted[blockId];
4279
+ if (carried === void 0 || carried === metadata[IR_PARTIAL_KEY]) {
4280
+ return metadata;
4281
+ }
4282
+ return { ...metadata, [IR_PARTIAL_KEY]: carried };
4283
+ };
4284
+ }
4285
+
4286
+ // wire/runtime-wrapper.ts
4287
+ var NODE_OUTCOME_KIND = "node_outcome";
4288
+ var RUN_RESULT_KIND = "run_result";
4289
+ function isRecord6(value) {
4290
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4291
+ }
4292
+ function str(source, key) {
4293
+ const value = source[key];
4294
+ return typeof value === "string" && value.length > 0 ? value : null;
4295
+ }
4296
+ function num(source, key) {
4297
+ const value = source[key];
4298
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
4299
+ }
4300
+ function bool(source, key) {
4301
+ const value = source[key];
4302
+ return typeof value === "boolean" ? value : null;
4303
+ }
4304
+ function strings(source, key) {
4305
+ const value = source[key];
4306
+ if (!Array.isArray(value)) return null;
4307
+ const out = value.filter((item) => typeof item === "string");
4308
+ return out.length > 0 ? out : null;
4309
+ }
4310
+ function readOutputRef(frame, ref) {
4311
+ let cursor = frame;
4312
+ for (const segment of ref.split(".")) {
4313
+ if (!isRecord6(cursor)) return void 0;
4314
+ if (!(segment in cursor)) return void 0;
4315
+ cursor = cursor[segment];
4316
+ }
4317
+ return cursor;
4318
+ }
4319
+ function rehydrateNodeOutcome(raw, frame) {
4320
+ if (!isRecord6(raw)) return null;
4321
+ if (raw[KIND_KEY] !== NODE_OUTCOME_KIND) return null;
4322
+ const ref = str(raw, "output_ref");
4323
+ const resolved = ref === null ? void 0 : readOutputRef(frame, ref);
4324
+ return readNodeOutcomeValue(
4325
+ resolved === void 0 ? raw : { ...raw, output: resolved }
4326
+ );
4327
+ }
4328
+ function readNodeOutcomeValue(raw) {
4329
+ if (!isRecord6(raw)) return null;
4330
+ const runId = str(raw, "run_id");
4331
+ const nodeId = str(raw, "node_id");
4332
+ if (!runId || !nodeId) return null;
4333
+ const output = raw.output ?? null;
4334
+ return {
4335
+ __kind: NODE_OUTCOME_KIND,
4336
+ run_id: runId,
4337
+ node_id: nodeId,
4338
+ workflow_id: str(raw, "workflow_id"),
4339
+ step: num(raw, "step"),
4340
+ attempt: num(raw, "attempt") ?? 1,
4341
+ status: str(raw, "status") ?? "completed",
4342
+ started_at: str(raw, "started_at"),
4343
+ ended_at: str(raw, "ended_at"),
4344
+ duration_ms: num(raw, "duration_ms"),
4345
+ output_kind: str(raw, "output_kind"),
4346
+ output_kind_ok: bool(raw, "output_kind_ok"),
4347
+ output_kind_errors: strings(raw, "output_kind_errors"),
4348
+ output
4349
+ };
4350
+ }
4351
+ function rehydrateRunResult(raw, frame) {
4352
+ if (!isRecord6(raw)) return null;
4353
+ if (raw[KIND_KEY] !== RUN_RESULT_KIND) return null;
4354
+ const ref = str(raw, "output_ref");
4355
+ const resolved = ref === null ? void 0 : readOutputRef(frame, ref);
4356
+ const outputs = Array.isArray(raw.outputs) ? raw.outputs.map((child) => rehydrateNodeOutcome(child, frame) ?? child) : [];
4357
+ return readRunResultValue({
4358
+ ...raw,
4359
+ ...resolved === void 0 ? {} : { output: resolved },
4360
+ outputs
4361
+ });
4362
+ }
4363
+ function readRunResultValue(raw) {
4364
+ if (!isRecord6(raw)) return null;
4365
+ const runId = str(raw, "run_id");
4366
+ if (!runId) return null;
4367
+ const output = raw.output ?? null;
4368
+ const outputs = Array.isArray(raw.outputs) ? raw.outputs.map((child) => readNodeOutcomeValue(child)).filter((child) => child !== null) : [];
4369
+ return {
4370
+ __kind: RUN_RESULT_KIND,
4371
+ run_id: runId,
4372
+ workflow_id: str(raw, "workflow_id"),
4373
+ status: str(raw, "status") ?? "completed",
4374
+ started_at: str(raw, "started_at"),
4375
+ ended_at: str(raw, "ended_at"),
4376
+ duration_ms: num(raw, "duration_ms"),
4377
+ output_kind: str(raw, "output_kind"),
4378
+ output,
4379
+ outputs
4380
+ };
4381
+ }
4382
+ function kindVerdictOf(wrapper) {
4383
+ if (wrapper.output_kind_ok === true) return "passed";
4384
+ if (wrapper.output_kind_ok === false) return "failed";
4385
+ return "unchecked";
4386
+ }
4387
+
4388
+ // wire/emit-payload.ts
4389
+ function withRootKind(kind, value) {
4390
+ if (value && typeof value === "object" && !Array.isArray(value)) {
4391
+ return { [KIND_KEY]: kind, ...value };
4392
+ }
4393
+ return value;
4394
+ }
4395
+ function emitPayloadJson(kind, value) {
4396
+ return JSON.stringify(withRootKind(kind, value), null, 2);
4397
+ }
4398
+ function emitPayloadFence(kind, value) {
4399
+ return "```json\n" + emitPayloadJson(kind, value) + "\n```";
4400
+ }
4401
+
4120
4402
  exports.IR_ENVELOPE_CACHE_VERSION = IR_ENVELOPE_CACHE_VERSION;
4121
4403
  exports.IR_ENVELOPE_KEY = IR_ENVELOPE_KEY;
4404
+ exports.IR_PARTIAL_KEY = IR_PARTIAL_KEY;
4122
4405
  exports.IR_VERSION = IR_VERSION;
4123
4406
  exports.IrTree = IrTree;
4124
4407
  exports.JSON_DISCRIMINATOR = JSON_DISCRIMINATOR;
@@ -4126,8 +4409,11 @@ exports.JsonStreamTokenizer = JsonStreamTokenizer;
4126
4409
  exports.KIND_KEY = KIND_KEY;
4127
4410
  exports.KindStorageError = KindStorageError;
4128
4411
  exports.KindStreamParser = KindStreamParser;
4412
+ exports.NODE_OUTCOME_KIND = NODE_OUTCOME_KIND;
4129
4413
  exports.ParseSession = ParseSession;
4130
4414
  exports.ROOT_STORAGE_NAME = ROOT_STORAGE_NAME;
4415
+ exports.RUN_RESULT_KIND = RUN_RESULT_KIND;
4416
+ exports.advancePartialKind = advancePartialKind;
4131
4417
  exports.buildAgentSchemaWithRenderBlockSupport = buildAgentSchemaWithRenderBlockSupport;
4132
4418
  exports.buildCompliantKindSnapshot = buildCompliantKindSnapshot;
4133
4419
  exports.classifyInboundEnvelopeMetadata = classifyInboundEnvelopeMetadata;
@@ -4139,6 +4425,8 @@ exports.createFingerprinter = createFingerprinter;
4139
4425
  exports.createKindStreamParser = createKindStreamParser;
4140
4426
  exports.describeDualGateFailure = describeDualGateFailure;
4141
4427
  exports.disposeParseSession = disposeParseSession;
4428
+ exports.emitPayloadFence = emitPayloadFence;
4429
+ exports.emitPayloadJson = emitPayloadJson;
4142
4430
  exports.emptyValueForFieldSchema = emptyValueForFieldSchema;
4143
4431
  exports.envelopeCacheFromEnvelopes = envelopeCacheFromEnvelopes;
4144
4432
  exports.envelopeFromCompleteValue = envelopeFromCompleteValue;
@@ -4157,20 +4445,31 @@ exports.isDuplicateBlockSlug = isDuplicateBlockSlug;
4157
4445
  exports.isEmptyResidue = isEmptyResidue;
4158
4446
  exports.isIrEnvelopeCache = isIrEnvelopeCache;
4159
4447
  exports.isJsonAnyField = isJsonAnyField;
4448
+ exports.isProvisionalKind = isProvisionalKind;
4160
4449
  exports.isScalarArrayType = isScalarArrayType;
4450
+ exports.isTerminalKindEvent = isTerminalKindEvent;
4161
4451
  exports.kindSchemaToJsonSchema = kindSchemaToJsonSchema;
4162
4452
  exports.kindSchemaToStorage = kindSchemaToStorage;
4453
+ exports.kindVerdictOf = kindVerdictOf;
4454
+ exports.makePartialKindStalenessGate = makePartialKindStalenessGate;
4163
4455
  exports.mergeResidueIntoValue = mergeResidueIntoValue;
4164
4456
  exports.normalizeAiSchemaInput = normalizeAiSchemaInput;
4165
4457
  exports.normalizeJsonRegion = normalizeJsonRegion;
4166
4458
  exports.openParseSession = openParseSession;
4167
4459
  exports.readEnvelope = readEnvelope;
4460
+ exports.readNodeOutcomeValue = readNodeOutcomeValue;
4168
4461
  exports.readObjectKind = readObjectKind;
4462
+ exports.readOutputRef = readOutputRef;
4463
+ exports.readPartialKindEvent = readPartialKindEvent;
4464
+ exports.readRunResultValue = readRunResultValue;
4169
4465
  exports.reconstructRegionValue = reconstructRegionValue;
4466
+ exports.rehydrateNodeOutcome = rehydrateNodeOutcome;
4467
+ exports.rehydrateRunResult = rehydrateRunResult;
4170
4468
  exports.reuseEnvelopeIfCurrent = reuseEnvelopeIfCurrent;
4171
4469
  exports.runKindDualGate = runKindDualGate;
4172
4470
  exports.runSchemaConversion = runSchemaConversion;
4173
4471
  exports.sanitizeInboundEnvelopeMetadata = sanitizeInboundEnvelopeMetadata;
4472
+ exports.sanitizeInboundPartialKindMetadata = sanitizeInboundPartialKindMetadata;
4174
4473
  exports.scalarArrayItemType = scalarArrayItemType;
4175
4474
  exports.schemaLayoutMode = schemaLayoutMode;
4176
4475
  exports.schemaStructureDepth = schemaStructureDepth;
@@ -4179,6 +4478,7 @@ exports.storageToKindSchema = storageToKindSchema;
4179
4478
  exports.stripKindDeep = stripKindDeep;
4180
4479
  exports.validateBlockSchemaSavePlan = validateBlockSchemaSavePlan;
4181
4480
  exports.validateStructuralLeg = validateStructuralLeg;
4481
+ exports.withRootKind = withRootKind;
4182
4482
  exports.xmlDiscriminator = xmlDiscriminator;
4183
4483
  //# sourceMappingURL=index.cjs.map
4184
4484
  //# sourceMappingURL=index.cjs.map