@arbiterforge/ca-pi 0.6.0 → 0.6.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arbiterforge/ca-pi",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "license": "AGPL-3.0-only",
5
5
  "repository": {
6
6
  "type": "git",
@@ -4,6 +4,29 @@ All notable changes to `ca-pi` are documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.6.2] - 2026-08-10
8
+
9
+ ### Fixed
10
+
11
+ - Child dispatch protocol accepts the three optional message fields Pi 0.84.x
12
+ added: assistant `rawStopReason` (observed on the live RPC wire, where it
13
+ degraded every 0.84 child dispatch after the first provider turn), assistant
14
+ `deferred` (provider deferred-response handle), and toolResult `usage`. Each
15
+ validates strictly when present; unknown keys still fail closed (ADR-0014).
16
+ Proven by the live isolated-child contract against real Pi 0.84.1 and
17
+ 0.80.10.
18
+
19
+ ## [0.6.1] - 2026-08-10
20
+
21
+ ### Fixed
22
+
23
+ - Child dispatch protocol accepts Pi ≥0.84.0's delta-only RPC `message_update`
24
+ events (pi#7290): the wire event dropped the full `message` record and the
25
+ `partial` field inside assistant events, which the strict validator rejected,
26
+ degrading every live child dispatch on Pi 0.84.x. Both window shapes now
27
+ validate with exact key sets — the fail-closed boundary (ADR-0014) is
28
+ unchanged, only the newly-documented shape is recognized.
29
+
7
30
  ## [0.6.0] - 2026-08-09
8
31
 
9
32
  ### Added
@@ -7593,6 +7593,13 @@ function validDiagnostic(value) {
7593
7593
  }
7594
7594
  return value.details === void 0 || validOpaqueJson(value.details);
7595
7595
  }
7596
+ function validDeferredHandle(value) {
7597
+ return isRecord(value) && exactKeys4(
7598
+ value,
7599
+ ["provider", "modelId", "api", "id", "expiresAt", "pollAfterMs", "data"],
7600
+ ["provider", "modelId", "api", "id"]
7601
+ ) && ["provider", "modelId", "api", "id"].every((key) => boundedString2(value[key])) && (value.expiresAt === void 0 || typeof value.expiresAt === "number" && Number.isFinite(value.expiresAt)) && (value.pollAfterMs === void 0 || typeof value.pollAfterMs === "number" && Number.isFinite(value.pollAfterMs)) && (value.data === void 0 || validOpaqueJson(value.data));
7602
+ }
7596
7603
  function validMessage(value) {
7597
7604
  if (!isRecord(value) || typeof value.role !== "string") return false;
7598
7605
  if (value.role === "user") {
@@ -7601,16 +7608,16 @@ function validMessage(value) {
7601
7608
  if (value.role === "assistant") {
7602
7609
  return exactKeys4(
7603
7610
  value,
7604
- ["role", "content", "api", "provider", "model", "responseModel", "responseId", "diagnostics", "usage", "stopReason", "errorMessage", "timestamp"],
7611
+ ["role", "content", "api", "provider", "model", "responseModel", "responseId", "diagnostics", "usage", "stopReason", "errorMessage", "rawStopReason", "deferred", "timestamp"],
7605
7612
  ["role", "content", "api", "provider", "model", "usage", "stopReason", "timestamp"]
7606
- ) && validContent(value.content, "assistant") && ["api", "provider", "model", "stopReason"].every((key) => typeof value[key] === "string") && (value.responseModel === void 0 || boundedString2(value.responseModel)) && (value.responseId === void 0 || boundedString2(value.responseId)) && (value.errorMessage === void 0 || boundedString2(value.errorMessage)) && (value.diagnostics === void 0 || Array.isArray(value.diagnostics) && value.diagnostics.length <= MAX_JSON_ARRAY && value.diagnostics.every(validDiagnostic)) && validUsage(value.usage) && typeof value.timestamp === "number" && Number.isFinite(value.timestamp);
7613
+ ) && validContent(value.content, "assistant") && ["api", "provider", "model", "stopReason"].every((key) => typeof value[key] === "string") && (value.responseModel === void 0 || boundedString2(value.responseModel)) && (value.responseId === void 0 || boundedString2(value.responseId)) && (value.errorMessage === void 0 || boundedString2(value.errorMessage)) && (value.rawStopReason === void 0 || boundedString2(value.rawStopReason)) && (value.deferred === void 0 || validDeferredHandle(value.deferred)) && (value.diagnostics === void 0 || Array.isArray(value.diagnostics) && value.diagnostics.length <= MAX_JSON_ARRAY && value.diagnostics.every(validDiagnostic)) && validUsage(value.usage) && typeof value.timestamp === "number" && Number.isFinite(value.timestamp);
7607
7614
  }
7608
7615
  if (value.role === "toolResult") {
7609
7616
  return exactKeys4(
7610
7617
  value,
7611
- ["role", "toolCallId", "toolName", "content", "details", "isError", "timestamp"],
7618
+ ["role", "toolCallId", "toolName", "content", "details", "isError", "usage", "timestamp"],
7612
7619
  ["role", "toolCallId", "toolName", "content", "isError", "timestamp"]
7613
- ) && typeof value.toolCallId === "string" && typeof value.toolName === "string" && validContent(value.content, "toolResult") && (value.details === void 0 || validOpaqueJson(value.details)) && typeof value.isError === "boolean" && typeof value.timestamp === "number" && Number.isFinite(value.timestamp);
7620
+ ) && typeof value.toolCallId === "string" && typeof value.toolName === "string" && validContent(value.content, "toolResult") && (value.details === void 0 || validOpaqueJson(value.details)) && (value.usage === void 0 || validUsage(value.usage)) && typeof value.isError === "boolean" && typeof value.timestamp === "number" && Number.isFinite(value.timestamp);
7614
7621
  }
7615
7622
  return false;
7616
7623
  }
@@ -7652,24 +7659,24 @@ function validPartialAssistantMessage(value) {
7652
7659
  }
7653
7660
  function validAssistantEvent(value) {
7654
7661
  if (!isRecord(value) || typeof value.type !== "string") return false;
7655
- const partial = () => validPartialAssistantMessage(value.partial);
7662
+ const exactWithOptionalPartial = (base) => "partial" in value ? exactKeys4(value, [...base, "partial"]) && validPartialAssistantMessage(value.partial) : exactKeys4(value, base);
7656
7663
  const contentIndex = () => Number.isSafeInteger(value.contentIndex) && value.contentIndex >= 0;
7657
7664
  switch (value.type) {
7658
7665
  case "start":
7659
- return exactKeys4(value, ["type", "partial"]) && partial();
7666
+ return exactWithOptionalPartial(["type"]);
7660
7667
  case "text_start":
7661
7668
  case "thinking_start":
7662
7669
  case "toolcall_start":
7663
- return exactKeys4(value, ["type", "contentIndex", "partial"]) && contentIndex() && partial();
7670
+ return exactWithOptionalPartial(["type", "contentIndex"]) && contentIndex();
7664
7671
  case "text_delta":
7665
7672
  case "thinking_delta":
7666
7673
  case "toolcall_delta":
7667
- return exactKeys4(value, ["type", "contentIndex", "delta", "partial"]) && contentIndex() && boundedString2(value.delta) && partial();
7674
+ return exactWithOptionalPartial(["type", "contentIndex", "delta"]) && contentIndex() && boundedString2(value.delta);
7668
7675
  case "text_end":
7669
7676
  case "thinking_end":
7670
- return exactKeys4(value, ["type", "contentIndex", "content", "partial"]) && contentIndex() && boundedString2(value.content) && partial();
7677
+ return exactWithOptionalPartial(["type", "contentIndex", "content"]) && contentIndex() && boundedString2(value.content);
7671
7678
  case "toolcall_end":
7672
- return exactKeys4(value, ["type", "contentIndex", "toolCall", "partial"]) && contentIndex() && validContentBlock(value.toolCall, "assistant") && partial();
7679
+ return exactWithOptionalPartial(["type", "contentIndex", "toolCall"]) && contentIndex() && validContentBlock(value.toolCall, "assistant");
7673
7680
  case "done":
7674
7681
  return exactKeys4(value, ["type", "reason", "message"]) && ["stop", "length", "toolUse"].includes(value.reason) && validMessage(value.message) && value.message.role === "assistant";
7675
7682
  case "error":
@@ -7712,7 +7719,7 @@ function parseChildJsonLine(line) {
7712
7719
  if (!exactKeys4(record2, ["type", "message"]) || !validMessage(record2.message) && !validPartialAssistantMessage(record2.message)) invalidProtocol();
7713
7720
  break;
7714
7721
  case "message_update":
7715
- if (!exactKeys4(record2, ["type", "message", "assistantMessageEvent"]) || !validPartialAssistantMessage(record2.message) || !validAssistantEvent(record2.assistantMessageEvent)) invalidProtocol();
7722
+ if ("message" in record2 ? !exactKeys4(record2, ["type", "message", "assistantMessageEvent"]) || !validPartialAssistantMessage(record2.message) || !validAssistantEvent(record2.assistantMessageEvent) : !exactKeys4(record2, ["type", "assistantMessageEvent"]) || !validAssistantEvent(record2.assistantMessageEvent)) invalidProtocol();
7716
7723
  break;
7717
7724
  case "tool_execution_start":
7718
7725
  if (!exactKeys4(record2, ["type", "toolCallId", "toolName", "args"]) || typeof record2.toolCallId !== "string" || typeof record2.toolName !== "string" || !validOpaqueJson(record2.args)) invalidProtocol();