@sema-agent/client-core 0.109.0 → 0.110.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/README.md +46 -22
  3. package/dist/adapt/arms.js +20 -7
  4. package/dist/adapter/downstream/eventToSdkMessage.js +11 -6
  5. package/dist/declared/supportFloorDeclared.js +1 -1
  6. package/dist/displayUntrusted.js +132 -14
  7. package/dist/engineErrorCodes.d.ts +3 -0
  8. package/dist/engineErrorCodes.js +3 -0
  9. package/dist/engineHealthFacts.d.ts +9 -0
  10. package/dist/engineHealthFacts.js +21 -1
  11. package/dist/engineInlineTaskStats.d.ts +4 -3
  12. package/dist/engineInlineTaskStats.js +18 -2
  13. package/dist/engineNoticeCodes.d.ts +10 -0
  14. package/dist/engineNoticeCodes.js +33 -1
  15. package/dist/engineRepoint.d.ts +140 -0
  16. package/dist/engineRepoint.js +285 -0
  17. package/dist/engineRowRef.js +2 -0
  18. package/dist/engineSessionMessages.d.ts +2 -1
  19. package/dist/engineSessionMessages.js +5 -0
  20. package/dist/errorSupplementRoles.js +2 -1
  21. package/dist/fleet/fleetProjection.js +3 -2
  22. package/dist/generated/engineFactTables.d.ts +2 -0
  23. package/dist/generated/engineFactTables.js +12 -0
  24. package/dist/generated/sdkFactTables.d.ts +1 -0
  25. package/dist/generated/sdkFactTables.js +4 -0
  26. package/dist/hitl/approvalAskers.d.ts +6 -0
  27. package/dist/hitl/approvalAskers.js +30 -0
  28. package/dist/hitl/approvalCardReasons.js +6 -3
  29. package/dist/hitl/approvalRequestFrameReading.d.ts +7 -0
  30. package/dist/hitl/approvalRequestFrameReading.js +11 -0
  31. package/dist/hitl/approvalResolution.d.ts +8 -1
  32. package/dist/hitl/approvalResolution.js +4 -0
  33. package/dist/hitl/askGateWire.js +0 -2
  34. package/dist/hitl/automaticAnswerVerdict.js +2 -2
  35. package/dist/hitl/decisionConflict.js +6 -3
  36. package/dist/hitl/decisionRefusal.js +1 -0
  37. package/dist/hitl/decisionSend.d.ts +3 -0
  38. package/dist/hitl/decisionSend.js +29 -11
  39. package/dist/hitl/editedApprovalAcceptance.d.ts +25 -0
  40. package/dist/hitl/editedApprovalAcceptance.js +26 -0
  41. package/dist/hitl/frameRouter.js +4 -18
  42. package/dist/hitl/gateLedger.d.ts +0 -4
  43. package/dist/hitl/gateLedger.js +0 -19
  44. package/dist/hitl/hitlBridge.d.ts +1 -0
  45. package/dist/hitl/hitlBridge.js +4 -4
  46. package/dist/hitl/hitlHostSurface.d.ts +1 -0
  47. package/dist/hitl/hitlHostSurface.js +7 -2
  48. package/dist/hitl/hostWithdrawal.d.ts +15 -0
  49. package/dist/hitl/hostWithdrawal.js +38 -0
  50. package/dist/hitl/parkResolver.js +25 -9
  51. package/dist/hitl/persistedRulesWire.js +2 -2
  52. package/dist/hitl/planReviewWire.js +14 -4
  53. package/dist/hitl/sessionPolicyWire.js +6 -4
  54. package/dist/hitl/standingRows.d.ts +1 -0
  55. package/dist/hitl/standingRows.js +15 -1
  56. package/dist/hitl/toolApprovalWire.d.ts +35 -8
  57. package/dist/hitl/toolApprovalWire.js +235 -33
  58. package/dist/hooksWireCaps.js +31 -1
  59. package/dist/hostTurnSettings.d.ts +10 -4
  60. package/dist/hostTurnSettings.js +112 -5
  61. package/dist/i18n/messages.en.d.ts +83 -0
  62. package/dist/i18n/messages.en.js +86 -2
  63. package/dist/i18n/messages.zh.js +96 -2
  64. package/dist/index.d.ts +21 -7
  65. package/dist/index.js +14 -4
  66. package/dist/inheritEnvCapability.js +2 -0
  67. package/dist/inputAuthor.d.ts +16 -0
  68. package/dist/inputAuthor.js +44 -0
  69. package/dist/interruptRefusalNote.d.ts +2 -0
  70. package/dist/interruptRefusalNote.js +17 -0
  71. package/dist/liveModelCatalog.d.ts +2 -0
  72. package/dist/liveModelCatalog.js +21 -7
  73. package/dist/liveQuestionStore.d.ts +4 -1
  74. package/dist/liveQuestionStore.js +12 -3
  75. package/dist/mcpEngineLeg.d.ts +3 -0
  76. package/dist/mcpEngineLeg.js +38 -1
  77. package/dist/mcpPanel.js +2 -0
  78. package/dist/mcpReconnect.d.ts +9 -1
  79. package/dist/mcpReconnect.js +121 -16
  80. package/dist/modelCapabilityProbe.js +4 -3
  81. package/dist/modsFace.d.ts +8 -1
  82. package/dist/modsFace.js +27 -0
  83. package/dist/notifications.d.ts +17 -6
  84. package/dist/notifications.js +67 -19
  85. package/dist/ownKey.d.ts +0 -5
  86. package/dist/ownKey.js +0 -7
  87. package/dist/peerFrames.d.ts +40 -2
  88. package/dist/peerFrames.js +158 -3
  89. package/dist/pluginHooksWire.d.ts +2 -1
  90. package/dist/pluginHooksWire.js +56 -1
  91. package/dist/replayBody.js +10 -2
  92. package/dist/request/taskRequest.d.ts +5 -0
  93. package/dist/request/taskRequest.js +138 -21
  94. package/dist/resumeRefusalCopy.d.ts +1 -3
  95. package/dist/resumeRefusalCopy.js +2 -1
  96. package/dist/retryStatus.d.ts +2 -2
  97. package/dist/retryStatus.js +2 -0
  98. package/dist/seam.d.ts +12 -1
  99. package/dist/seam.js +7 -1
  100. package/dist/seatContract.d.ts +86 -9
  101. package/dist/seatContract.js +196 -7
  102. package/dist/sessionBackground.js +2 -1
  103. package/dist/sessionBackgroundHandoff.js +2 -1
  104. package/dist/sessionEngine.d.ts +2 -0
  105. package/dist/sessionEngine.js +111 -0
  106. package/dist/sessionMemoryStatus.d.ts +2 -1
  107. package/dist/sessionSyncFileHistory.d.ts +4 -0
  108. package/dist/sessionSyncFileHistory.js +28 -0
  109. package/dist/sseIdleTriage.d.ts +13 -1
  110. package/dist/sseIdleTriage.js +24 -6
  111. package/dist/subagent/engineSubagentTail.js +6 -0
  112. package/dist/terminalStatuses.d.ts +1 -0
  113. package/dist/terminalStatuses.js +4 -1
  114. package/dist/turnFailurePresentation.js +9 -2
  115. package/dist/typePins.d.ts +11 -0
  116. package/dist/usageAnalytics.d.ts +17 -0
  117. package/dist/usageAnalytics.js +44 -2
  118. package/dist/wireFailureShape.d.ts +2 -5
  119. package/dist/wireFailureShape.js +10 -20
  120. package/dist/wireRefusalCopy.d.ts +10 -0
  121. package/dist/wireRefusalCopy.js +76 -0
  122. package/docs/INTEGRATION-CLIENTS.md +2126 -20
  123. package/package.json +3 -3
@@ -310,6 +310,7 @@ const CHROME_ARM_SEAT_ROUTE = {
310
310
  compaction_outcome: "seat",
311
311
  engine_notice: "seat",
312
312
  subagent_alias: "seat",
313
+ session_box_notice: "seat",
313
314
  workflow_notification_enqueue: "host",
314
315
  plan_review_park: "host",
315
316
  approval_request: "host",
@@ -398,7 +399,7 @@ export function readSeatStreamDelta(message) {
398
399
  return Object.freeze({ kind: "malformed" });
399
400
  }
400
401
  }
401
- export const SEAT_CAPABILITY_NAMES = Object.freeze(["pickFolder", "rewind", "recents", "patchSession", "devices", "engineTarget", "onboard", "mcpToolToggles", "thinkingLatch", "computerUseSwitch", "engineModeDefaultOnly", "seatActions"]);
402
+ export const SEAT_CAPABILITY_NAMES = Object.freeze(["pickFolder", "rewind", "recents", "patchSession", "devices", "engineTarget", "onboard", "mcpToolToggles", "thinkingLatch", "computerUseSwitch", "engineModeDefaultOnly", "seatActions", "notificationLevels", "modsView"]);
402
403
  const notReported = () => Object.freeze({ kind: "not_reported" });
403
404
  const malformedReading = () => Object.freeze({ kind: "malformed" });
404
405
  const reported = (available) => Object.freeze({ kind: "reported", available });
@@ -478,6 +479,8 @@ const SEAT_CAPABILITY_PHRASES = Object.freeze({
478
479
  computerUseSwitch: Object.freeze({ action: "Computer use", ability: "be switched", support: "switch support" }),
479
480
  engineModeDefaultOnly: Object.freeze({ action: "Default-only engine switching", ability: "keep existing sessions on their engine", support: "default-only engine switching" }),
480
481
  seatActions: Object.freeze({ action: "App menu actions", ability: "send actions to this window", support: "app action support" }),
482
+ notificationLevels: Object.freeze({ action: "Choosing notification levels", ability: "keep notification levels", support: "notification-level support" }),
483
+ modsView: Object.freeze({ action: "Showing mods", ability: "show mods", support: "mods support" }),
481
484
  });
482
485
  export function seatCapabilityUnavailableDetail(name, reading) {
483
486
  const phrase = Object.hasOwn(SEAT_CAPABILITY_PHRASES, name)
@@ -600,6 +603,7 @@ export const SEAT_TURN_SETTINGS_ORIGINS = Object.freeze({
600
603
  hooks: Object.freeze({ hostSupplied: "settings.hooks" }),
601
604
  resolved: Object.freeze({ hostSupplied: "settings.resolved" }),
602
605
  outputStyle: Object.freeze({ hostSupplied: "settings.outputStyle" }),
606
+ env: Object.freeze({ hostSupplied: "settings.env" }),
603
607
  });
604
608
  export const SEAT_REWIND_INTENT_KEYS = ["mode", "targetMessageUuid"];
605
609
  export const ATTACHMENT_UPLOAD_REQUEST_KEYS = ["name", "mimeType", "bytes"];
@@ -845,7 +849,7 @@ const R_UNANSWERED_ONLY = ruleOf("unanswered-only", () => false);
845
849
  const ENGINE_TARGET_LOCAL_SPEC = {
846
850
  lastBootError: optF(R_STR),
847
851
  mcp: optF(SEAT_LOCAL_MCP_READING),
848
- lifecycle: optF(LOCAL_ENGINE_SEAT_READING),
852
+ lifecycle: reqF(LOCAL_ENGINE_SEAT_READING),
849
853
  };
850
854
  const ENGINE_TARGET_LOCAL = {
851
855
  label: "local",
@@ -855,8 +859,6 @@ const ENGINE_TARGET_LOCAL = {
855
859
  return verdict;
856
860
  const rec = v;
857
861
  const lifecycle = own(rec, "lifecycle");
858
- if (isAbsent(lifecycle))
859
- return true;
860
862
  const phase = own(lifecycle, "phase");
861
863
  const bootError = !isAbsent(own(rec, "lastBootError"));
862
864
  if (bootError !== (phase === "down"))
@@ -1074,6 +1076,46 @@ const checkSessionMcpPanelResult = seatCheck((v) => {
1074
1076
  return checkSessionMcpPanelFailure(v);
1075
1077
  return Object.hasOwn(v, "scenarioRefusal") ? checkSessionMcpPanelRefusalView(v) : checkSessionMcpPanelServersView(v);
1076
1078
  });
1079
+ const MOD_ROW_SKIP = shapeRule("mod skip", {
1080
+ registration: reqF(R_NONEMPTY),
1081
+ cause: reqF(R_NONEMPTY),
1082
+ reason: reqF(R_NONEMPTY),
1083
+ });
1084
+ const MOD_ROW_MOUNTED_SPEC = {
1085
+ name: reqF(R_NONEMPTY),
1086
+ seat: reqF(R_NONEMPTY),
1087
+ tier: reqF(R_NONEMPTY),
1088
+ provenance: optF(R_NONEMPTY),
1089
+ events: reqF(arrayRule(R_STR)),
1090
+ observe: optF(arrayRule(R_STR)),
1091
+ skipped: optF(arrayRule(MOD_ROW_SKIP, true)),
1092
+ };
1093
+ const MOD_ROW_REFUSED_SPEC = {
1094
+ name: reqF(R_NONEMPTY),
1095
+ seat: reqF(R_NONEMPTY),
1096
+ tier: reqF(R_NONEMPTY),
1097
+ provenance: optF(R_NONEMPTY),
1098
+ refusedBy: reqF(R_NONEMPTY),
1099
+ reason: reqF(R_NONEMPTY),
1100
+ };
1101
+ const MOD_ROW = {
1102
+ label: "mod row",
1103
+ test: (v, path) => {
1104
+ if (!isPlainRecord(v))
1105
+ return bad("not object", path);
1106
+ return Object.hasOwn(v, "refusedBy") || Object.hasOwn(v, "reason") ? shapeVerdict(MOD_ROW_REFUSED_SPEC, v, path) : shapeVerdict(MOD_ROW_MOUNTED_SPEC, v, path);
1107
+ },
1108
+ };
1109
+ const checkSessionModsFailure = seatShapeCheck(armsRule("readSessionMods failure", "kind", {
1110
+ unreadable: DEVICE_UNREADABLE_SPEC,
1111
+ unarmed: {},
1112
+ }));
1113
+ const checkSessionModsView = seatShapeCheck(shapeRule("mods view", { rows: reqF(arrayRule(MOD_ROW)) }));
1114
+ const checkSessionModsResult = seatCheck((v) => {
1115
+ if (!isPlainRecord(v))
1116
+ return bad("not object");
1117
+ return Object.hasOwn(v, "kind") ? checkSessionModsFailure(v) : checkSessionModsView(v);
1118
+ });
1077
1119
  const MCP_TOOL_TOGGLE_KEY = shapeRule("toggle key", {
1078
1120
  server: reqF(R_NONEMPTY),
1079
1121
  tool: reqF(R_NONEMPTY),
@@ -1169,6 +1211,75 @@ export function planSetComputerUse(request, lockedByEnv) {
1169
1211
  return Object.freeze({ kind: "refused", reason: "confirmation-required" });
1170
1212
  return Object.freeze({ kind: "apply", enabled: intent.kind === "enable" });
1171
1213
  }
1214
+ export const NOTIFICATION_LEVEL_TYPES = Object.freeze(["permission", "question", "idle"]);
1215
+ export const NOTIFICATION_LEVELS = Object.freeze(["off", "badge", "banner"]);
1216
+ export const NOTIFICATION_LEVEL_REFUSAL_REASONS = Object.freeze(["invalid-request", "unsupported-level", "write-failed"]);
1217
+ const R_NOTIFICATION_LEVEL = oneOfRule("notification level", NOTIFICATION_LEVELS);
1218
+ const NOTIFICATION_SUPPORTED_ITEMS = arrayRule(R_NOTIFICATION_LEVEL, true);
1219
+ const NOTIFICATION_SUPPORTED_ORDER = "bad value (supported levels: off first, closed-set order, no repeats)";
1220
+ const R_NOTIFICATION_SUPPORTED = {
1221
+ label: "supported levels",
1222
+ test: (v, path) => {
1223
+ const verdict = NOTIFICATION_SUPPORTED_ITEMS.test(v, path);
1224
+ if (verdict !== true)
1225
+ return verdict;
1226
+ const rank = (x) => NOTIFICATION_LEVELS.indexOf(x);
1227
+ const rows = ownItems(v);
1228
+ if (rows[0] !== "off")
1229
+ return bad(NOTIFICATION_SUPPORTED_ORDER, path);
1230
+ for (let i = 1; i < rows.length; i += 1)
1231
+ if (rank(rows[i]) <= rank(rows[i - 1]))
1232
+ return bad(NOTIFICATION_SUPPORTED_ORDER, `${path}[${i}]`);
1233
+ return true;
1234
+ },
1235
+ };
1236
+ const NOTIFICATION_LEVELS_STATE_SHAPE = shapeRule("notification levels state", {
1237
+ levels: reqF(shapeRule("notification levels", {
1238
+ permission: reqF(R_NOTIFICATION_LEVEL),
1239
+ question: reqF(R_NOTIFICATION_LEVEL),
1240
+ idle: reqF(R_NOTIFICATION_LEVEL),
1241
+ })),
1242
+ supported: reqF(R_NOTIFICATION_SUPPORTED),
1243
+ });
1244
+ const NOTIFICATION_LEVELS_STATE = {
1245
+ label: NOTIFICATION_LEVELS_STATE_SHAPE.label,
1246
+ test: (v, path) => {
1247
+ const verdict = NOTIFICATION_LEVELS_STATE_SHAPE.test(v, path);
1248
+ if (verdict !== true)
1249
+ return verdict;
1250
+ const rec = v;
1251
+ const levels = own(rec, "levels");
1252
+ const supported = ownItems(own(rec, "supported"));
1253
+ for (const t of NOTIFICATION_LEVEL_TYPES)
1254
+ if (!supported.includes(own(levels, t)))
1255
+ return bad("unsupported level", pathAt(path, `levels.${t}`));
1256
+ return true;
1257
+ },
1258
+ };
1259
+ const checkNotificationLevelsState = seatShapeCheck(NOTIFICATION_LEVELS_STATE);
1260
+ const checkSetNotificationLevelResult = seatShapeCheck(okArmsRule("setNotificationLevel result", { state: reqF(NOTIFICATION_LEVELS_STATE) }, {
1261
+ reason: reqF(oneOfRule("notification level refusal", NOTIFICATION_LEVEL_REFUSAL_REASONS)),
1262
+ state: reqF(NOTIFICATION_LEVELS_STATE),
1263
+ }));
1264
+ export function planSetNotificationLevel(type, level, supported) {
1265
+ if (typeof type !== "string" || !inTuple(NOTIFICATION_LEVEL_TYPES, type) || typeof level !== "string" || !inTuple(NOTIFICATION_LEVELS, level)) {
1266
+ return Object.freeze({ kind: "refused", reason: "invalid-request" });
1267
+ }
1268
+ let delivers = false;
1269
+ try {
1270
+ const n = Array.isArray(supported) ? ownDataField(supported, "length") : undefined;
1271
+ if (typeof n === "number" && Number.isSafeInteger(n) && n <= NOTIFICATION_LEVELS.length) {
1272
+ for (let i = 0; i < n && !delivers; i += 1)
1273
+ delivers = own(supported, String(i)) === level;
1274
+ }
1275
+ }
1276
+ catch {
1277
+ delivers = false;
1278
+ }
1279
+ if (!delivers)
1280
+ return Object.freeze({ kind: "refused", reason: "unsupported-level" });
1281
+ return Object.freeze({ kind: "apply", type, level });
1282
+ }
1172
1283
  export const SEAT_ACTION_NAMES = Object.freeze(["new-project", "prefill-composer"]);
1173
1284
  const SEAT_PREFILL_TEXT_MAX = 14336;
1174
1285
  const SEAT_PREFILL_CWD_MAX = 4096;
@@ -1919,7 +2030,37 @@ export function isSendMessageAck(v) {
1919
2030
  }
1920
2031
  const checkInterruptAck = seatCheck((v) => isPlainRecord(v) && typeof own(v, "interrupted") === "boolean" ? true : bad("interrupt ack needs a plain object with boolean `interrupted`", "interrupted"));
1921
2032
  const checkStopAck = seatCheck((v) => isPlainRecord(v) && typeof own(v, "stopped") === "boolean" ? true : bad("stop ack needs a plain object with boolean `stopped`", "stopped"));
1922
- const checkOkAck = seatCheck((v) => isPlainRecord(v) && typeof own(v, "ok") === "boolean" ? true : bad("ack needs a plain object with boolean `ok`", "ok"));
2033
+ const okAckVerdict = (v) => isPlainRecord(v) && typeof own(v, "ok") === "boolean" ? true : bad("ack needs a plain object with boolean `ok`", "ok");
2034
+ const checkOkAck = seatCheck(okAckVerdict);
2035
+ const TOOL_PERMISSION_SETTLED_WORDS = Object.freeze(["allow", "deny"]);
2036
+ const R_SETTLED_ELSEWHERE = shapeRule("settled elsewhere", {
2037
+ firstDecision: reqF(oneOfRule("decision word", TOOL_PERMISSION_SETTLED_WORDS)),
2038
+ contrary: reqF(R_BOOL),
2039
+ });
2040
+ const checkToolPermissionAck = seatCheck((v) => {
2041
+ const base = okAckVerdict(v);
2042
+ if (base !== true)
2043
+ return base;
2044
+ const slot = own(v, "settledElsewhere");
2045
+ return isAbsent(slot) ? true : R_SETTLED_ELSEWHERE.test(slot, "settledElsewhere");
2046
+ });
2047
+ const checkSettledElsewhereSlot = seatCheck((v) => R_SETTLED_ELSEWHERE.test(v, "settledElsewhere"));
2048
+ export function readToolPermissionSettledElsewhere(ack) {
2049
+ try {
2050
+ if (typeof ack !== "object" || ack === null)
2051
+ return undefined;
2052
+ const slot = own(ack, "settledElsewhere");
2053
+ if (isAbsent(slot))
2054
+ return undefined;
2055
+ if (checkSettledElsewhereSlot(slot) !== true)
2056
+ return undefined;
2057
+ const first = own(slot, "firstDecision");
2058
+ return Object.freeze({ firstDecision: first === "allow" ? "allow" : "deny", contrary: own(slot, "contrary") === true });
2059
+ }
2060
+ catch {
2061
+ return undefined;
2062
+ }
2063
+ }
1923
2064
  const checkBooleanAck = (v) => typeof v === "boolean" ? true : bad("expected a bare boolean result");
1924
2065
  const checkGetTranscriptResult = seatCheck((v) => {
1925
2066
  if (!isPlainRecord(v))
@@ -2042,7 +2183,7 @@ export const LOCAL_SESSIONS_SPEC = {
2042
2183
  sendMessage: { kind: "invoke", check: checkSendMessageAck },
2043
2184
  interrupt: { kind: "invoke", check: checkInterruptAck },
2044
2185
  stop: { kind: "invoke", check: checkStopAck },
2045
- respondToToolPermission: { kind: "invoke", check: checkOkAck },
2186
+ respondToToolPermission: { kind: "invoke", check: checkToolPermissionAck },
2046
2187
  cancelQueuedMessage: { kind: "invoke", check: checkBooleanAck },
2047
2188
  reorderQueuedMessage: { kind: "invoke", check: checkBooleanAck },
2048
2189
  promoteQueuedMessage: { kind: "invoke", check: checkBooleanAck },
@@ -2078,7 +2219,10 @@ export const LOCAL_SESSIONS_SPEC = {
2078
2219
  setThinkingLatch: { kind: "invoke", check: checkOkAck },
2079
2220
  getComputerUse: { kind: "invoke", check: checkComputerUseState },
2080
2221
  setComputerUse: { kind: "invoke", check: checkSetComputerUseResult },
2222
+ getNotificationLevels: { kind: "invoke", check: checkNotificationLevelsState },
2223
+ setNotificationLevel: { kind: "invoke", check: checkSetNotificationLevelResult },
2081
2224
  claimSeatActions: { kind: "invoke", check: checkOkAck },
2225
+ readSessionMods: { kind: "invoke", check: checkSessionModsResult },
2082
2226
  onEvent: { kind: "event", check: checkLocalSessionEvent },
2083
2227
  onToolPermissionRequest: { kind: "event", check: checkToolPermissionRequest },
2084
2228
  onSeatAction: { kind: "event", check: checkSeatAction },
@@ -2132,7 +2276,10 @@ export const SEAT_METHOD_NAMES = [
2132
2276
  "setThinkingLatch",
2133
2277
  "getComputerUse",
2134
2278
  "setComputerUse",
2279
+ "getNotificationLevels",
2280
+ "setNotificationLevel",
2135
2281
  "claimSeatActions",
2282
+ "readSessionMods",
2136
2283
  "onEvent",
2137
2284
  "onToolPermissionRequest",
2138
2285
  "onSeatAction",
@@ -2179,6 +2326,12 @@ export const TOOL_PERMISSION_REQUEST_KEYS = [
2179
2326
  "askClass",
2180
2327
  "classes",
2181
2328
  "sessionRow",
2329
+ "probeReason",
2330
+ "probeCause",
2331
+ "feedbackCapable",
2332
+ "requestedBy",
2333
+ "frameReading",
2334
+ "inputSource",
2182
2335
  ];
2183
2336
  export const LOCAL_SESSION_RECORD_KEYS = [
2184
2337
  "sessionId",
@@ -2236,6 +2389,7 @@ export const TOOL_PERMISSION_DECISION_KEYS = [
2236
2389
  "answer",
2237
2390
  "updatedInput",
2238
2391
  "remember",
2392
+ "feedback",
2239
2393
  ];
2240
2394
  export const START_SESSION_OPTION_KEYS = ["model", "title", "cwd", "excludeTools", "engine"];
2241
2395
  export const SEAT_VALIDATOR_KEY_COVERAGE = {
@@ -2286,10 +2440,34 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
2286
2440
  key: "sessionRow",
2287
2441
  why: "放宽方向的展示位(CC-699),判官在过境口 toolPermissionRequestAskBits(card, requestId):卡上「本会话放行」判官 standingRowsOf 的会话行同一前提 ∧ 本请求 requestId 的域带得走(live: / durable:),严格 true 才上座、永不铸 false;座位门不设第二判官,理由同 mandated(为一个展示位拒掉整条 request = 把安全 ask 丢给引擎 TTL deny)。消费端 `=== true` 才渲「本会话放行」,其余(缺席 / 坏形)一律不渲 —— 缺席是闭合失败,不是「没说就照渲」。不经过境口自铸座位请求的宿主拿不到这一位,座位卡就不给那一档。",
2288
2442
  },
2443
+ {
2444
+ key: "feedbackCapable",
2445
+ why: "放宽方向的展示位(CC-585),判官在过境口 toolPermissionRequestAskBits(card, requestId):卡判官 answerCarriage(card) 答 model(卡带耐久待决行腿的正向事实 parkRow)∧ 本请求 requestId 的域恰是 durable:(只有 /decide 收放行反馈位),严格 true 才上座、永不铸 false;座位门不设第二判官,理由同 sessionRow(为一个展示位拒掉整条 request = 把安全 ask 丢给引擎 TTL deny)。消费端 `=== true` 才渲「Yes + 告诉 agent 下一步」那一格输入,其余(缺席 / 坏形)一律不渲 —— 缺席是闭合失败。不经过境口自铸座位请求的宿主拿不到这一位,座位卡就不给那一格。",
2446
+ },
2289
2447
  {
2290
2448
  key: "ruleOffersAbsence",
2291
2449
  why: "喂强制判据口 approvalIsMandated 的位(CC-203;寄存行那条腿的强制只以缺席词 mandated 表达),按开集读(非空串原文字节、词表不校);权威窄读在卡口与过境口,座位门不设第二判官,理由同 mandated。坏形读成缺席 ⇒ 这一路不判强制(放宽方向:寄存行上的强制就丢了;另两路 mandated / mandate 照判);表外串只是不等于 mandated。不经过境口自铸座位请求的宿主要自己按同一把窄读。",
2292
2450
  },
2451
+ {
2452
+ key: "probeReason",
2453
+ why: "展示位(CC-1316),权威窄读在过境口 toolPermissionRequestAskBits,与「为什么问」那一句的读口 askProbeReasonDetail 同一个读点(自有数据属性、取值器不执行;串且去两端空白后非空才在场,原文字节);座位门不设第二判官,理由同 mandated(为一个展示位拒掉整条 request = 把安全 ask 丢给引擎 TTL deny)。坏形读成缺席 ⇒ 卡上不显示这一句,不改决断;缺席不是「没有原因」。不经过境口自铸座位请求的宿主要自己按同一把窄读。",
2454
+ },
2455
+ {
2456
+ key: "probeCause",
2457
+ why: "展示位(CC-1316),与 probeReason 同一对、同一个读点;载体层判(自有数据属性、非 null 非数组对象)才在场,同一引用原样搬运,内部成员不校(成员的窄读归 askProbeReasonDetail / probeCauseRowsOf);座位门不设第二判官,理由同 probeReason。坏形读成缺席 ⇒ 不显示因由行,不改决断。两位按键隔离:一位读不出不连坐另一位。",
2458
+ },
2459
+ {
2460
+ key: "requestedBy",
2461
+ why: "展示位(CC-1341),权威窄读在过境口 toolPermissionRequestAskBits,读点是卡口的唯一载体级读口 approvalRequestedByOf(载体顶层的自有数据属性、取值器不执行;kind 恰 extension 且 name 非空串才在场,出冻结的新铸副本);原始耐久待决行不读(上游不在行上铸这一位);座位门不设第二判官,理由同 mandated(为一个展示位拒掉整条 request = 把安全 ask 丢给引擎 TTL deny)。坏形读成缺席 ⇒ 卡上不显示发起者行,不改决断;缺席不是「模型发起」。不经过境口自铸座位请求的宿主要自己按同一把窄读。",
2462
+ },
2463
+ {
2464
+ key: "frameReading",
2465
+ why: "展示位(CC-1345),权威窄读在过境口 toolPermissionRequestAskBits,读点是包内唯一读口 cardPayloadReadingOf(卡上 cardPayloadUnreadable 严格 true ∧ cardPayloadUnreadableWhy 是判因闭集三词之一才在场;卡面通用卡第一行按因选句同读它);座位门不设第二判官,理由同 mandated(为一个展示位拒掉整条 request = 把安全 ask 丢给引擎 TTL deny)。表外词 / 游离判因词 / 判因未知读成缺席 ⇒ 卡上回落不分因的原句,不改决断;缺席不是「帧读得出」。不经过境口自铸座位请求的宿主要自己按同一把窄读。",
2466
+ },
2467
+ {
2468
+ key: "inputSource",
2469
+ why: "展示位(CC-1366),权威窄读在过境口 toolPermissionRequestAskBits,读点是包内唯一窄读 approvalInputSourceOf(载体顶层的自有数据属性、取值器不执行;闭集 record / stream 两词精确字节才在场);来源位本身只有一个铸点(卡入参读法的读数 → 位),过境口只抄卡上已铸的位、不拿 input 重判来源,原始帧 / 原始耐久待决行直交恒缺席;座位门不设第二判官,理由同 mandated(为一个展示位拒掉整条 request = 把安全 ask 丢给引擎 TTL deny)。表外词 / 近义词 / 非串读成缺席 ⇒ 壳按来源不明处置,不改决断;缺席不是 record。不经过境口自铸座位请求的宿主要自己按同一把窄读。",
2470
+ },
2293
2471
  ],
2294
2472
  },
2295
2473
  LocalSessionEvent: {
@@ -2421,6 +2599,11 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
2421
2599
  validated: ["ok"],
2422
2600
  unchecked: [],
2423
2601
  },
2602
+ ToolPermissionAck: {
2603
+ check: checkToolPermissionAck,
2604
+ validated: ["ok", "settledElsewhere"],
2605
+ unchecked: [],
2606
+ },
2424
2607
  GetTranscriptResult: {
2425
2608
  check: checkGetTranscriptResult,
2426
2609
  validated: ["sessionId", "messages"],
@@ -2448,7 +2631,7 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
2448
2631
  },
2449
2632
  SeatCapabilitiesState: {
2450
2633
  check: checkSeatCapabilitiesState,
2451
- validated: ["pickFolder", "rewind", "recents", "patchSession", "devices", "engineTarget", "onboard", "mcpToolToggles", "thinkingLatch", "computerUseSwitch", "engineModeDefaultOnly", "seatActions"],
2634
+ validated: ["pickFolder", "rewind", "recents", "patchSession", "devices", "engineTarget", "onboard", "mcpToolToggles", "thinkingLatch", "computerUseSwitch", "engineModeDefaultOnly", "seatActions", "notificationLevels", "modsView"],
2452
2635
  unchecked: [],
2453
2636
  },
2454
2637
  RecentFoldersResult: {
@@ -2514,9 +2697,12 @@ export const SEAT_VALIDATOR_COVERAGE_EXEMPT = [
2514
2697
  ["ComputerUseState", checkComputerUseState],
2515
2698
  ["SetComputerUseResult", checkSetComputerUseResult],
2516
2699
  ["SetComputerUseRequest", checkSetComputerUseRequest],
2700
+ ["NotificationLevelsState", checkNotificationLevelsState],
2701
+ ["SetNotificationLevelResult", checkSetNotificationLevelResult],
2517
2702
  ["SeatAction", checkSeatAction],
2518
2703
  ["EngineSwapAnswerOutcome", checkEngineSwapAnswerOutcome],
2519
2704
  ["SelfUpgradeOutcome", checkSelfUpgradeOutcome],
2705
+ ["SessionModsResult", checkSessionModsResult],
2520
2706
  ].map(([label, check]) => ({
2521
2707
  label,
2522
2708
  check,
@@ -2581,5 +2767,8 @@ const _seatContractPins = [
2581
2767
  true, true,
2582
2768
  true, true, true, true, true, true, true,
2583
2769
  true, true, true, true, true, true, true, true,
2770
+ true, true, true, true, true,
2771
+ true, true, true,
2772
+ true, true, true, true,
2584
2773
  ];
2585
2774
  void _seatContractPins;
@@ -6,6 +6,7 @@ import { isLoopbackWireUrl } from './engineWireSdk.js';
6
6
  import { hostEnv } from './hostEnv.js';
7
7
  import { approvalDecisionHolds } from './hitl/approvalHolds.js';
8
8
  import { readRunTerminal } from './runTerminal.js';
9
+ import { isReplayedTerminal } from './replayBody.js';
9
10
  import { appendOwnElement, ownDataField, putOwnKey, readOwnDataFiniteNumber, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
10
11
  import { msg, renderMessage } from './i18n/translate.js';
11
12
  export function projectSessionBackgroundable(caps) {
@@ -418,7 +419,7 @@ function observeFrame(rec, ev) {
418
419
  }
419
420
  else {
420
421
  rec.phase = 'ended-unstarted';
421
- rec.replay = type === 'done' && frameSlot(ev, 'replay') === true;
422
+ rec.replay = type === 'done' && isReplayedTerminal(ev);
422
423
  }
423
424
  return;
424
425
  }
@@ -4,6 +4,7 @@ import { REATTACH_WINDOW_MS, reattachBackoffMs } from './reattachWindow.js';
4
4
  import { terminalEventFromRunRow } from './headlessReconnectWire.js';
5
5
  import { RUN_CANCELLED_CODE } from './runCancelContext.js';
6
6
  import { readRunTerminal } from './runTerminal.js';
7
+ import { isReplayedTerminal } from './replayBody.js';
7
8
  import { readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
8
9
  import { backgroundHandoffSentence, judgeHandoff, ownSlotOf, wireStateOf, } from './sessionBackground.js';
9
10
  export const BACKGROUND_HANDOFF_ABORT_REASON = 'background';
@@ -34,7 +35,7 @@ function executionSettlementOf(ev) {
34
35
  return { runEnded: true, kind: 'cancelled', status: 'failed' };
35
36
  return { runEnded: true, kind: 'failed', status: 'failed', ...(code !== undefined ? { errorCode: code } : {}) };
36
37
  }
37
- if (type !== 'done' || slot(ev, 'replay') === true)
38
+ if (type !== 'done' || isReplayedTerminal(ev))
38
39
  return undefined;
39
40
  const read = readRunTerminal(slot(ev, 'result'));
40
41
  if (read === null)
@@ -153,5 +153,7 @@ export declare function sessionEngineBindingFor(input: SessionEngineBindingInput
153
153
  export declare function isSessionEngineView(v: {} | null | undefined): boolean;
154
154
  export declare function readSessionEngine(record: SessionMapRecord | undefined): SessionEngineReading;
155
155
  export declare function commitSessionEngine(store: SessionMapStorePort, session: SessionEngineSessionRef, request: SessionEngineCommitRequest): SessionEngineCommitResult;
156
+ export type SessionEngineRepointResult = 'moved' | 'unaffected' | 'conflict' | 'unreadable' | 'store-failed' | 'request-invalid';
157
+ export declare function repointSessionEngine(store: SessionMapStorePort, from: string, to: string): SessionEngineRepointResult;
156
158
  export declare function sessionDispatchRefusedFor(refusal: SessionDispatchRefusal): SessionDispatchRefused;
157
159
  export declare function sessionDispatchTarget(reading: SessionEngineReading, ctx: SessionEngineWiring): SessionDispatchDecision;
@@ -377,6 +377,117 @@ function methodOf(o, key) {
377
377
  return undefined;
378
378
  }
379
379
  }
380
+ function addressBindingOf(raw) {
381
+ if (typeof raw !== 'string')
382
+ return undefined;
383
+ const b = addressBinding(raw);
384
+ return b.ok && b.identityKind === 'address' ? b : undefined;
385
+ }
386
+ function enginesTableOf(record) {
387
+ const slot = slotReadOf(record, 'engines');
388
+ if (slot.presence === 'absent' || (slot.presence === 'present' && slot.value === undefined))
389
+ return 'absent';
390
+ return slot.presence === 'present' && isObj(slot.value) ? slot.value : 'unreadable';
391
+ }
392
+ function movedEngines(table, dropKey, putKey, entry) {
393
+ const out = {};
394
+ for (const k of Object.keys(table)) {
395
+ if (k === dropKey)
396
+ continue;
397
+ const slot = slotReadOf(table, k);
398
+ if (slot.presence !== 'present')
399
+ return undefined;
400
+ Object.defineProperty(out, k, { value: slot.value, writable: true, enumerable: true, configurable: true });
401
+ }
402
+ Object.defineProperty(out, putKey, { value: entry, writable: true, enumerable: true, configurable: true });
403
+ return out;
404
+ }
405
+ function repointStep(prior, from, to, fromNs, toNs, now) {
406
+ try {
407
+ const reading = readSessionEngine(prior);
408
+ if (reading.kind === 'none')
409
+ return { result: 'unaffected' };
410
+ if (reading.kind === 'unresolved' || prior === undefined)
411
+ return { result: 'unreadable' };
412
+ const table = enginesTableOf(prior);
413
+ if (reading.kind === 'bound') {
414
+ const id = reading.binding.identity;
415
+ if (id.identityKind !== 'address' || id.key !== from.key)
416
+ return { result: 'unaffected' };
417
+ if (table === 'absent' || table === 'unreadable')
418
+ return { result: 'unreadable' };
419
+ if (Object.hasOwn(table, to.key))
420
+ return { result: 'conflict' };
421
+ const entry = slotReadOf(table, from.key);
422
+ if (entry.presence !== 'present' || !isObj(entry.value))
423
+ return { result: 'unreadable' };
424
+ const engines = movedEngines(table, from.key, to.key, entry.value);
425
+ if (engines === undefined)
426
+ return { result: 'unreadable' };
427
+ return {
428
+ result: 'moved',
429
+ next: { ...prior, boundEngine: snapshotOf({ kind: reading.binding.kind, identity: to }), engines, updatedAt: now },
430
+ };
431
+ }
432
+ if (table === 'absent')
433
+ return { result: 'unaffected' };
434
+ if (table === 'unreadable')
435
+ return { result: 'unreadable' };
436
+ if (!Object.hasOwn(table, fromNs))
437
+ return { result: 'unaffected' };
438
+ if (Object.hasOwn(table, toNs))
439
+ return { result: 'conflict' };
440
+ const entry = slotReadOf(table, fromNs);
441
+ if (entry.presence !== 'present' || !isObj(entry.value))
442
+ return { result: 'unreadable' };
443
+ const engines = movedEngines(table, fromNs, toNs, entry.value);
444
+ if (engines === undefined)
445
+ return { result: 'unreadable' };
446
+ return { result: 'moved', next: { ...prior, engines, updatedAt: now } };
447
+ }
448
+ catch {
449
+ return { result: 'unreadable' };
450
+ }
451
+ }
452
+ export function repointSessionEngine(store, from, to) {
453
+ let readMergeWrite;
454
+ let fromB;
455
+ let toB;
456
+ try {
457
+ if (!isObj(store))
458
+ return 'request-invalid';
459
+ const rmw = methodOf(store, 'readMergeWrite');
460
+ if (rmw === undefined)
461
+ return 'request-invalid';
462
+ readMergeWrite = (build) => rmw.call(store, build);
463
+ const f = addressBindingOf(from);
464
+ const t = addressBindingOf(to);
465
+ if (f === undefined || t === undefined || f.key === t.key)
466
+ return 'request-invalid';
467
+ fromB = f;
468
+ toB = t;
469
+ }
470
+ catch {
471
+ return 'request-invalid';
472
+ }
473
+ const fromNs = engineNamespaceKeyFor(from);
474
+ const toNs = engineNamespaceKeyFor(to);
475
+ let step;
476
+ try {
477
+ const returned = readMergeWrite((prior) => {
478
+ step = repointStep(prior, fromB, toB, fromNs, toNs, new Date().toISOString());
479
+ return Object.hasOwn(step, 'next') ? step.next : undefined;
480
+ });
481
+ if (step === undefined)
482
+ return 'store-failed';
483
+ if (Object.hasOwn(step, 'next') && !isObj(returned))
484
+ return 'store-failed';
485
+ return step.result;
486
+ }
487
+ catch {
488
+ return 'store-failed';
489
+ }
490
+ }
380
491
  const REFUSAL_KEYS = {
381
492
  'not-wired': 'session.engine.dispatch.notWired',
382
493
  'scope-mismatch': 'session.engine.dispatch.scopeMismatch',
@@ -9,7 +9,8 @@ export interface MemoryStatusClientLike {
9
9
  } & SessionMemoryStatus>;
10
10
  };
11
11
  }
12
- export type MemoryStatusFacts = Omit<SessionMemoryStatusResponse, 'sessionId' | 'memorySync'> & {
12
+ export type MemoryStatusFacts = SessionMemoryStatus & {
13
+ autoConsolidationArmed?: SessionMemoryStatusResponse['autoConsolidationArmed'];
13
14
  readonly memorySync?: MemorySyncFacts;
14
15
  };
15
16
  export interface MemorySyncFacts {
@@ -1,4 +1,8 @@
1
+ import type { RowBitsOutcome } from '@sema-agent/sdk';
2
+ import { type UiLanguage } from './env/uiLanguage.js';
1
3
  export declare const FILE_HISTORY_SKIPPED_NOTICE: string;
2
4
  export declare function fileHistorySyncNotice(result: unknown): string | undefined;
3
5
  export declare function fileHistorySyncNoticeIdentity(result: unknown): string | undefined;
4
6
  export declare function isFileHistoryBlobMissing(err: unknown): boolean;
7
+ export type PushRowBitsWord = RowBitsOutcome | 'writer_side';
8
+ export declare function sessionPushRowBitsNotice(result: {} | null | undefined, lang?: UiLanguage | (string & {})): string | undefined;
@@ -1,6 +1,8 @@
1
1
  import { NOT_FOUND_BLOB } from './engineErrorCodes.js';
2
2
  import { effectiveWireErrorCode } from './wireErrorTriage.js';
3
3
  import { readThrownSlot } from './wireFailureShape.js';
4
+ import { isUiLanguage } from './env/uiLanguage.js';
5
+ import { msg, renderMessage } from './i18n/translate.js';
4
6
  export const FILE_HISTORY_SKIPPED_NOTICE = 'File history was not copied: only the conversation was synced, because one of the two engines does not confirm that it can ' +
5
7
  'transfer file history (the record /rewind uses to restore files). Syncing this session again will not add it until ' +
6
8
  'the conversation has new turns and both engines can transfer file history.';
@@ -64,3 +66,29 @@ export function isFileHistoryBlobMissing(err) {
64
66
  return false;
65
67
  }
66
68
  }
69
+ function pushRowBitsSpeaks(word) {
70
+ switch (word) {
71
+ case 'writer_side':
72
+ return true;
73
+ case 'mirrored':
74
+ case 'unsupported':
75
+ case 'absent':
76
+ return false;
77
+ }
78
+ }
79
+ function isPushRowBitsWord(v) {
80
+ return v === 'mirrored' || v === 'unsupported' || v === 'absent' || v === 'writer_side';
81
+ }
82
+ export function sessionPushRowBitsNotice(result, lang) {
83
+ if (result === null || typeof result !== 'object')
84
+ return undefined;
85
+ try {
86
+ const word = getOwn(result, 'rowBits');
87
+ if (typeof word !== 'string' || !isPushRowBitsWord(word) || !pushRowBitsSpeaks(word))
88
+ return undefined;
89
+ return renderMessage(msg('session.sync.pushRowBitsWriterSide'), isUiLanguage(lang) ? lang : undefined);
90
+ }
91
+ catch {
92
+ return undefined;
93
+ }
94
+ }
@@ -1,4 +1,5 @@
1
1
  import { type EnvLike } from './hostEnv.js';
2
+ import { SDK_STREAM_ENDED_REASONS } from './generated/sdkFactTables.js';
2
3
  import { type RunNotFollowed } from './runFollow.js';
3
4
  export declare const SSE_HEARTBEAT_GRACE_ENV = "SEMA_SSE_HEARTBEAT_GRACE_MS";
4
5
  export declare const SSE_GRACE_MIN_MS = 5000;
@@ -8,8 +9,19 @@ export declare function resolveSseHeartbeatGraceMs(env?: EnvLike): number | unde
8
9
  export declare function markEngineAliveIdle<E extends Error>(err: E): E;
9
10
  export declare function engineAliveIdleElapsedMs(err: unknown): number | undefined;
10
11
  export declare function isSseIdleError(err: unknown): boolean;
12
+ export type StreamEndedReasonWord = (typeof SDK_STREAM_ENDED_REASONS)[number];
13
+ export type StreamEndedUnknownWhy = 'not_this_class' | 'reason_unreadable' | 'reason_unrecognized';
14
+ export type StreamEndedReading = {
15
+ readonly kind: 'read';
16
+ readonly reason: StreamEndedReasonWord;
17
+ readonly cause?: {} | null;
18
+ } | {
19
+ readonly kind: 'unknown';
20
+ readonly why: StreamEndedUnknownWhy;
21
+ };
22
+ export declare function streamEndedReasonOf(err: {} | null | undefined): StreamEndedReading;
11
23
  export declare function isStreamEndedWithoutTerminalError(err: {} | null | undefined): boolean;
12
- export declare function probeEngineAlive(baseUrl: string, timeoutMs?: number): Promise<boolean>;
24
+ export declare function probeEngineAlive(baseUrl: string): Promise<boolean>;
13
25
  export declare function diagnoseSseIdleTear<T>(inner: AsyncGenerator<T>, baseUrl: string, signal?: AbortSignal): AsyncGenerator<T>;
14
26
  export declare function engineAliveIdleContent(elapsedMs: number, detach?: {
15
27
  detached: true;
@@ -1,6 +1,7 @@
1
1
  import { hostEnv } from './hostEnv.js';
2
2
  import { SseIdleError, StreamEndedWithoutTerminalError, probeHealth as sdkProbeHealth } from '@sema-agent/sdk';
3
- import { readThrownSlot, thrownIsInstanceOf } from './wireFailureShape.js';
3
+ import { THROWN_SLOT_UNREADABLE, readThrownSlot, thrownIsInstanceOf } from './wireFailureShape.js';
4
+ import { SDK_STREAM_ENDED_REASONS } from './generated/sdkFactTables.js';
4
5
  import { msg, renderMessage } from './i18n/translate.js';
5
6
  import { runNotFollowedNoticeRef } from './runFollow.js';
6
7
  export const SSE_HEARTBEAT_GRACE_ENV = 'SEMA_SSE_HEARTBEAT_GRACE_MS';
@@ -38,13 +39,30 @@ export function isSseIdleError(err) {
38
39
  return true;
39
40
  return readThrownSlot(err, 'name', 'data') === 'SseIdleError';
40
41
  }
42
+ function streamEndedUnknown(why) {
43
+ return Object.freeze({ kind: 'unknown', why });
44
+ }
45
+ function isStreamEndedClass(err) {
46
+ return thrownIsInstanceOf(err, StreamEndedWithoutTerminalError) || readThrownSlot(err, 'name', 'data') === 'StreamEndedWithoutTerminalError';
47
+ }
48
+ export function streamEndedReasonOf(err) {
49
+ if (!isStreamEndedClass(err))
50
+ return streamEndedUnknown('not_this_class');
51
+ const raw = readThrownSlot(err, 'reason', 'data');
52
+ if (raw === THROWN_SLOT_UNREADABLE || raw === undefined)
53
+ return streamEndedUnknown('reason_unreadable');
54
+ const reason = SDK_STREAM_ENDED_REASONS.find((w) => w === raw);
55
+ if (reason === undefined)
56
+ return streamEndedUnknown('reason_unrecognized');
57
+ const cause = readThrownSlot(err, 'cause', 'data');
58
+ return Object.freeze(cause === THROWN_SLOT_UNREADABLE || cause === undefined ? { kind: 'read', reason } : { kind: 'read', reason, cause: cause });
59
+ }
41
60
  export function isStreamEndedWithoutTerminalError(err) {
42
- if (thrownIsInstanceOf(err, StreamEndedWithoutTerminalError))
43
- return true;
44
- return readThrownSlot(err, 'name', 'data') === 'StreamEndedWithoutTerminalError';
61
+ const reading = streamEndedReasonOf(err);
62
+ return reading.kind !== 'unknown' || reading.why !== 'not_this_class';
45
63
  }
46
- export async function probeEngineAlive(baseUrl, timeoutMs = 2_000) {
47
- return (await sdkProbeHealth(baseUrl, timeoutMs)).alive;
64
+ export async function probeEngineAlive(baseUrl) {
65
+ return (await sdkProbeHealth(baseUrl)).alive;
48
66
  }
49
67
  export async function* diagnoseSseIdleTear(inner, baseUrl, signal) {
50
68
  try {