@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.
- package/CHANGELOG.md +173 -0
- package/README.md +46 -22
- package/dist/adapt/arms.js +20 -7
- package/dist/adapter/downstream/eventToSdkMessage.js +11 -6
- package/dist/declared/supportFloorDeclared.js +1 -1
- package/dist/displayUntrusted.js +132 -14
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +3 -0
- package/dist/engineHealthFacts.d.ts +9 -0
- package/dist/engineHealthFacts.js +21 -1
- package/dist/engineInlineTaskStats.d.ts +4 -3
- package/dist/engineInlineTaskStats.js +18 -2
- package/dist/engineNoticeCodes.d.ts +10 -0
- package/dist/engineNoticeCodes.js +33 -1
- package/dist/engineRepoint.d.ts +140 -0
- package/dist/engineRepoint.js +285 -0
- package/dist/engineRowRef.js +2 -0
- package/dist/engineSessionMessages.d.ts +2 -1
- package/dist/engineSessionMessages.js +5 -0
- package/dist/errorSupplementRoles.js +2 -1
- package/dist/fleet/fleetProjection.js +3 -2
- package/dist/generated/engineFactTables.d.ts +2 -0
- package/dist/generated/engineFactTables.js +12 -0
- package/dist/generated/sdkFactTables.d.ts +1 -0
- package/dist/generated/sdkFactTables.js +4 -0
- package/dist/hitl/approvalAskers.d.ts +6 -0
- package/dist/hitl/approvalAskers.js +30 -0
- package/dist/hitl/approvalCardReasons.js +6 -3
- package/dist/hitl/approvalRequestFrameReading.d.ts +7 -0
- package/dist/hitl/approvalRequestFrameReading.js +11 -0
- package/dist/hitl/approvalResolution.d.ts +8 -1
- package/dist/hitl/approvalResolution.js +4 -0
- package/dist/hitl/askGateWire.js +0 -2
- package/dist/hitl/automaticAnswerVerdict.js +2 -2
- package/dist/hitl/decisionConflict.js +6 -3
- package/dist/hitl/decisionRefusal.js +1 -0
- package/dist/hitl/decisionSend.d.ts +3 -0
- package/dist/hitl/decisionSend.js +29 -11
- package/dist/hitl/editedApprovalAcceptance.d.ts +25 -0
- package/dist/hitl/editedApprovalAcceptance.js +26 -0
- package/dist/hitl/frameRouter.js +4 -18
- package/dist/hitl/gateLedger.d.ts +0 -4
- package/dist/hitl/gateLedger.js +0 -19
- package/dist/hitl/hitlBridge.d.ts +1 -0
- package/dist/hitl/hitlBridge.js +4 -4
- package/dist/hitl/hitlHostSurface.d.ts +1 -0
- package/dist/hitl/hitlHostSurface.js +7 -2
- package/dist/hitl/hostWithdrawal.d.ts +15 -0
- package/dist/hitl/hostWithdrawal.js +38 -0
- package/dist/hitl/parkResolver.js +25 -9
- package/dist/hitl/persistedRulesWire.js +2 -2
- package/dist/hitl/planReviewWire.js +14 -4
- package/dist/hitl/sessionPolicyWire.js +6 -4
- package/dist/hitl/standingRows.d.ts +1 -0
- package/dist/hitl/standingRows.js +15 -1
- package/dist/hitl/toolApprovalWire.d.ts +35 -8
- package/dist/hitl/toolApprovalWire.js +235 -33
- package/dist/hooksWireCaps.js +31 -1
- package/dist/hostTurnSettings.d.ts +10 -4
- package/dist/hostTurnSettings.js +112 -5
- package/dist/i18n/messages.en.d.ts +83 -0
- package/dist/i18n/messages.en.js +86 -2
- package/dist/i18n/messages.zh.js +96 -2
- package/dist/index.d.ts +21 -7
- package/dist/index.js +14 -4
- package/dist/inheritEnvCapability.js +2 -0
- package/dist/inputAuthor.d.ts +16 -0
- package/dist/inputAuthor.js +44 -0
- package/dist/interruptRefusalNote.d.ts +2 -0
- package/dist/interruptRefusalNote.js +17 -0
- package/dist/liveModelCatalog.d.ts +2 -0
- package/dist/liveModelCatalog.js +21 -7
- package/dist/liveQuestionStore.d.ts +4 -1
- package/dist/liveQuestionStore.js +12 -3
- package/dist/mcpEngineLeg.d.ts +3 -0
- package/dist/mcpEngineLeg.js +38 -1
- package/dist/mcpPanel.js +2 -0
- package/dist/mcpReconnect.d.ts +9 -1
- package/dist/mcpReconnect.js +121 -16
- package/dist/modelCapabilityProbe.js +4 -3
- package/dist/modsFace.d.ts +8 -1
- package/dist/modsFace.js +27 -0
- package/dist/notifications.d.ts +17 -6
- package/dist/notifications.js +67 -19
- package/dist/ownKey.d.ts +0 -5
- package/dist/ownKey.js +0 -7
- package/dist/peerFrames.d.ts +40 -2
- package/dist/peerFrames.js +158 -3
- package/dist/pluginHooksWire.d.ts +2 -1
- package/dist/pluginHooksWire.js +56 -1
- package/dist/replayBody.js +10 -2
- package/dist/request/taskRequest.d.ts +5 -0
- package/dist/request/taskRequest.js +138 -21
- package/dist/resumeRefusalCopy.d.ts +1 -3
- package/dist/resumeRefusalCopy.js +2 -1
- package/dist/retryStatus.d.ts +2 -2
- package/dist/retryStatus.js +2 -0
- package/dist/seam.d.ts +12 -1
- package/dist/seam.js +7 -1
- package/dist/seatContract.d.ts +86 -9
- package/dist/seatContract.js +196 -7
- package/dist/sessionBackground.js +2 -1
- package/dist/sessionBackgroundHandoff.js +2 -1
- package/dist/sessionEngine.d.ts +2 -0
- package/dist/sessionEngine.js +111 -0
- package/dist/sessionMemoryStatus.d.ts +2 -1
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +28 -0
- package/dist/sseIdleTriage.d.ts +13 -1
- package/dist/sseIdleTriage.js +24 -6
- package/dist/subagent/engineSubagentTail.js +6 -0
- package/dist/terminalStatuses.d.ts +1 -0
- package/dist/terminalStatuses.js +4 -1
- package/dist/turnFailurePresentation.js +9 -2
- package/dist/typePins.d.ts +11 -0
- package/dist/usageAnalytics.d.ts +17 -0
- package/dist/usageAnalytics.js +44 -2
- package/dist/wireFailureShape.d.ts +2 -5
- package/dist/wireFailureShape.js +10 -20
- package/dist/wireRefusalCopy.d.ts +10 -0
- package/dist/wireRefusalCopy.js +76 -0
- package/docs/INTEGRATION-CLIENTS.md +2126 -20
- package/package.json +3 -3
package/dist/seatContract.js
CHANGED
|
@@ -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:
|
|
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
|
|
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:
|
|
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' &&
|
|
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' ||
|
|
38
|
+
if (type !== 'done' || isReplayedTerminal(ev))
|
|
38
39
|
return undefined;
|
|
39
40
|
const read = readRunTerminal(slot(ev, 'result'));
|
|
40
41
|
if (read === null)
|
package/dist/sessionEngine.d.ts
CHANGED
|
@@ -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;
|
package/dist/sessionEngine.js
CHANGED
|
@@ -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 =
|
|
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
|
+
}
|
package/dist/sseIdleTriage.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/sseIdleTriage.js
CHANGED
|
@@ -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
|
-
|
|
43
|
-
|
|
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
|
|
47
|
-
return (await sdkProbeHealth(baseUrl
|
|
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 {
|