@sema-agent/client-core 0.102.0 → 0.104.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 +172 -0
- package/README.md +23 -17
- package/dist/adapt/toolCards.d.ts +2 -1
- package/dist/adapt/toolCards.js +3 -1
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +5 -1
- package/dist/adapter/downstream/eventToSdkMessage.js +23 -3
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +0 -1
- package/dist/adapter/downstream/terminalToSdkResult.js +3 -2
- package/dist/adapter/downstream/wiringManifestView.js +4 -1
- package/dist/agentSession/engineAgentRegistryRead.js +3 -0
- package/dist/cloudConfigWireCaps.js +6 -3
- package/dist/coreValuePorts.d.ts +3 -1
- package/dist/coreValuePorts.js +5 -0
- package/dist/credentialPlaneCapability.d.ts +22 -0
- package/dist/credentialPlaneCapability.js +75 -0
- package/dist/deviceExecutorManagementCapability.d.ts +1 -0
- package/dist/deviceExecutorManagementCapability.js +3 -1
- package/dist/deviceRebind.d.ts +17 -4
- package/dist/deviceRebind.js +43 -14
- package/dist/engineAgentAbsence.d.ts +1 -0
- package/dist/engineErrorCodes.d.ts +1 -0
- package/dist/engineErrorCodes.js +3 -1
- package/dist/engineNoticeCodes.d.ts +26 -0
- package/dist/engineNoticeCodes.js +121 -12
- package/dist/engineRowRef.js +1 -0
- package/dist/errorSupplementRoles.js +1 -3
- package/dist/eventLeg.js +2 -1
- package/dist/executionPlacementWords.d.ts +3 -0
- package/dist/executionPlacementWords.js +2 -0
- package/dist/fleet/fleetProjection.js +15 -9
- package/dist/gateOutcome.d.ts +20 -0
- package/dist/gateOutcome.js +89 -0
- package/dist/generated/engineAskFaceTables.js +2 -2
- package/dist/generated/engineFactTables.d.ts +8 -3
- package/dist/generated/engineFactTables.js +58 -2
- package/dist/generated/engineNoticeTables.js +30 -0
- package/dist/generated/settingsSchemaDefaultModel.d.ts +1 -1
- package/dist/generated/settingsSchemaDefaultModel.js +2 -2
- package/dist/generated/settingsSchemaFns.d.ts +15 -0
- package/dist/generated/settingsSchemaFns.js +25 -2
- package/dist/generated/settingsSchemaHooksClassifier.js +109 -29
- package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -1
- package/dist/generated/settingsSchemaMcpRequestEntry.js +213 -93
- package/dist/generated/settingsSchemaMcpServerName.d.ts +1 -0
- package/dist/generated/settingsSchemaMcpServerName.js +8 -0
- package/dist/generated/settingsSchemaOwnKeyRead.d.ts +1 -0
- package/dist/generated/settingsSchemaOwnKeyRead.js +172 -0
- package/dist/generated/settingsSchemaPlainJsonObject.d.ts +1 -0
- package/dist/generated/settingsSchemaPlainJsonObject.js +28 -0
- package/dist/generated/settingsSchemaSafetyMergeSpec.js +10 -7
- package/dist/generated/settingsSchemaTierWords.d.ts +1 -0
- package/dist/generated/settingsSchemaTierWords.js +7 -0
- package/dist/generated/settingsSchemaTypes.d.ts +3 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/automaticAnswerVerdict.js +47 -11
- package/dist/hitl/decisionConflict.js +11 -11
- package/dist/hitl/decisionRefusal.d.ts +1 -0
- package/dist/hitl/decisionRefusal.js +4 -2
- package/dist/hitl/editedRuleTextPrecheck.d.ts +1 -0
- package/dist/hitl/editedRuleTextPrecheck.js +26 -1
- package/dist/hitl/persistedRulesWire.js +1 -0
- package/dist/hitl/planReviewWire.d.ts +2 -1
- package/dist/hitl/planReviewWire.js +8 -12
- package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
- package/dist/hitl/sessionPolicyDeliverable.js +31 -10
- package/dist/hitl/sessionPolicyWire.js +1 -1
- package/dist/hitl/toolApprovalWire.d.ts +20 -7
- package/dist/hitl/toolApprovalWire.js +171 -19
- package/dist/host.d.ts +0 -3
- package/dist/hostTurnSettings.js +3 -1
- package/dist/humanTurn.js +2 -2
- package/dist/i18n/messages.en.d.ts +5 -0
- package/dist/i18n/messages.en.js +6 -1
- package/dist/i18n/messages.zh.js +6 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +3 -1
- package/dist/inheritEnvWire.d.ts +1 -0
- package/dist/inheritEnvWire.js +8 -5
- package/dist/jsonFaithful.js +5 -3
- package/dist/mcpEngineLeg.d.ts +3 -0
- package/dist/mcpEngineLeg.js +4 -1
- package/dist/mcpLiveness.d.ts +18 -0
- package/dist/mcpLiveness.js +48 -1
- package/dist/mcpReconnect.d.ts +3 -0
- package/dist/mcpReconnect.js +6 -0
- package/dist/mcpStatusSupersetKeys.js +24 -1
- package/dist/mcpWireCaps.d.ts +2 -3
- package/dist/mcpWireCaps.js +10 -9
- package/dist/memoryEntriesWire.d.ts +35 -1
- package/dist/memoryEntriesWire.js +110 -14
- package/dist/modsFace.js +7 -3
- package/dist/postureKnob.js +1 -1
- package/dist/prepareRefusal.d.ts +0 -1
- package/dist/prepareRefusal.js +0 -3
- package/dist/printModelStatus.d.ts +1 -0
- package/dist/printModelStatus.js +6 -2
- package/dist/promptProfileWireCaps.d.ts +1 -3
- package/dist/promptProfileWireCaps.js +2 -2
- package/dist/request/taskRequest.d.ts +1 -1
- package/dist/request/taskRequest.js +3 -3
- package/dist/retryStatus.d.ts +20 -1
- package/dist/retryStatus.js +31 -7
- package/dist/ruleCompileVerdict.d.ts +1 -0
- package/dist/ruleCompileVerdict.js +3 -1
- package/dist/seatContract.d.ts +7 -7
- package/dist/seatContract.js +49 -10
- package/dist/sessionMemoryErase.js +24 -2
- package/dist/sessionRowTag.d.ts +24 -0
- package/dist/sessionRowTag.js +77 -0
- package/dist/systemReminderTag.js +14 -4
- package/dist/turnFailurePresentation.js +8 -1
- package/dist/wireFailureShape.d.ts +12 -1
- package/dist/wireFailureShape.js +58 -24
- package/dist/wireRefusalCopy.d.ts +0 -3
- package/dist/wireRefusalCopy.js +0 -17
- package/docs/INTEGRATION-CLIENTS.md +400 -14
- package/package.json +5 -5
|
@@ -21,7 +21,7 @@ export const REQUEST_FIELD_MATRIX = [
|
|
|
21
21
|
{ field: 'selfOrchestration', lanes: ['interactive', 'print'], live: true, why: 'SEMA_SELF_ORCHESTRATION opt-in → core 挂 run_workflow', whyUtilityLane: '无座:它挂的是编排工具,与零工具面直接矛盾' },
|
|
22
22
|
{ field: 'deferTools', lanes: ['interactive', 'print'], live: true, why: '[1052]① Workflow 延迟披露;selfOrchestration 前置门', whyUtilityLane: '无座:工具延迟披露是工具面的位,零工具面上没有对象' },
|
|
23
23
|
{ field: 'retainBackgroundProcesses', lanes: ['interactive', 'print'], live: true, why: '缺省 ON(2026-07-26 起翻转);SEMA_RETAIN_BACKGROUND=0 逃生', whyUtilityLane: '无座:后台进程是工具面的产物,零工具面产不出' },
|
|
24
|
-
{ field: '
|
|
24
|
+
{ field: 'promptLean', lanes: ['interactive', 'print'], live: true, why: '提示词形轴(0.103.0 起布尔,取代退役的两词形轴键;sdk 28 / 服务端 7.137.0):缺省不 stamp = 目录缺省;映射单铸点 promptLeanFromEnv', whyUtilityLane: '无座:提示词形是用户会话的偏好;side-channel 的系统提示由壳整段给出(见 systemPrompt 那一行),不再借形轴调形' },
|
|
25
25
|
{ field: 'enableFork', lanes: ['interactive', 'print'], live: true, why: '显式布尔才 stamp([503]② fail-OPEN 教训:off 必须显式)', whyUtilityLane: '无座:分叉是会话面的动作,而 side-channel 提交是一次性的独立会话' },
|
|
26
26
|
{ field: 'attachments', lanes: ['interactive', 'print'], live: true, why: 'design/133 + G1 缺省开的 turn 边界 attachment', whyUtilityLane: '无座:turn 边界的附件配置属用户会话;side-channel 提交不带附件' },
|
|
27
27
|
{ field: 'skills', lanes: ['interactive', 'print'], live: true, why: '本地技能目录投影(布局取 CC 同款);两条车道都由 launchRepl 载入面注入', whyUtilityLane: '无座:技能挂的是工具,与零工具面矛盾' },
|
|
@@ -152,7 +152,7 @@ const INPUT_KEY_ROUTES = {
|
|
|
152
152
|
selfOrchestration: row('selfOrchestration'),
|
|
153
153
|
deferTools: row('deferTools'),
|
|
154
154
|
retainBackgroundProcesses: row('retainBackgroundProcesses'),
|
|
155
|
-
|
|
155
|
+
promptLean: row('promptLean'),
|
|
156
156
|
enableFork: row('enableFork'),
|
|
157
157
|
attachments: row('attachments'),
|
|
158
158
|
attachmentIds: row('attachmentIds'),
|
|
@@ -1103,7 +1103,7 @@ export function assembleTaskRequest(input, laneOrIdentity) {
|
|
|
1103
1103
|
...(on('selfOrchestration') ? { selfOrchestration: i.selfOrchestration } : {}),
|
|
1104
1104
|
...(on('deferTools') ? { deferTools: i.deferTools } : {}),
|
|
1105
1105
|
...(on('retainBackgroundProcesses') ? { retainBackgroundProcesses: i.retainBackgroundProcesses } : {}),
|
|
1106
|
-
...(on('
|
|
1106
|
+
...(on('promptLean') ? { promptLean: i.promptLean } : {}),
|
|
1107
1107
|
...(on('enableFork') ? { enableFork: i.enableFork } : {}),
|
|
1108
1108
|
...(on('attachments') ? { attachments: attachmentsForWire } : {}),
|
|
1109
1109
|
...(on('repo') ? { repo: i.repo } : {}),
|
package/dist/retryStatus.d.ts
CHANGED
|
@@ -11,6 +11,9 @@ export type RetryStatus = {
|
|
|
11
11
|
providerConditionSource?: string;
|
|
12
12
|
elapsedMs?: number;
|
|
13
13
|
timeoutMs?: number;
|
|
14
|
+
sleptMs?: number;
|
|
15
|
+
waitSegment?: BrainStatusWaitSegment | (string & {});
|
|
16
|
+
seat?: BrainStatusSeat | (string & {});
|
|
14
17
|
detail?: string;
|
|
15
18
|
} | {
|
|
16
19
|
kind: 'error';
|
|
@@ -26,6 +29,9 @@ export type RetryStatus = {
|
|
|
26
29
|
error: RetryStatusErrorPayload;
|
|
27
30
|
elapsedMs?: number;
|
|
28
31
|
timeoutMs?: number;
|
|
32
|
+
sleptMs?: number;
|
|
33
|
+
waitSegment?: BrainStatusWaitSegment | (string & {});
|
|
34
|
+
seat?: BrainStatusSeat | (string & {});
|
|
29
35
|
} | {
|
|
30
36
|
kind: 'waiting';
|
|
31
37
|
deadline: number;
|
|
@@ -38,6 +44,9 @@ export type RetryStatus = {
|
|
|
38
44
|
providerConditionSource?: string;
|
|
39
45
|
elapsedMs?: number;
|
|
40
46
|
timeoutMs?: number;
|
|
47
|
+
sleptMs?: number;
|
|
48
|
+
waitSegment?: BrainStatusWaitSegment | (string & {});
|
|
49
|
+
seat?: BrainStatusSeat | (string & {});
|
|
41
50
|
terminal?: never;
|
|
42
51
|
error: RetryStatusErrorPayload;
|
|
43
52
|
};
|
|
@@ -69,8 +78,15 @@ export interface BrainStatusPayload {
|
|
|
69
78
|
timeoutMs?: number;
|
|
70
79
|
providerCondition?: string;
|
|
71
80
|
providerConditionSource?: string;
|
|
81
|
+
sleptMs?: number;
|
|
82
|
+
waitSegment?: BrainStatusWaitSegment | (string & {});
|
|
83
|
+
seat?: BrainStatusSeat | (string & {});
|
|
72
84
|
}
|
|
73
|
-
export declare const
|
|
85
|
+
export declare const BRAIN_STATUS_WAIT_SEGMENTS: readonly ["response_headers", "first_token"];
|
|
86
|
+
export type BrainStatusWaitSegment = (typeof BRAIN_STATUS_WAIT_SEGMENTS)[number];
|
|
87
|
+
export declare const BRAIN_STATUS_SEATS: readonly ["classifier"];
|
|
88
|
+
type BrainStatusSeat = (typeof BRAIN_STATUS_SEATS)[number];
|
|
89
|
+
export declare const BRAIN_STATUS_PAYLOAD_KEYS: readonly ["phase", "detail", "retryInSec", "retryInMs", "attempt", "maxRetries", "errClass", "retryAtMs", "errorStatus", "elapsedMs", "timeoutMs", "providerCondition", "providerConditionSource", "sleptMs", "waitSegment", "seat"];
|
|
74
90
|
export declare function mapBrainStatusToRetry(p: BrainStatusPayload, nowMs: number): RetryStatus | null;
|
|
75
91
|
export interface RetryStatusArmLike {
|
|
76
92
|
readonly phase?: string;
|
|
@@ -86,6 +102,9 @@ export interface RetryStatusArmLike {
|
|
|
86
102
|
readonly timeoutMs?: number;
|
|
87
103
|
readonly providerCondition?: string;
|
|
88
104
|
readonly providerConditionSource?: string;
|
|
105
|
+
readonly sleptMs?: number;
|
|
106
|
+
readonly waitSegment?: string;
|
|
107
|
+
readonly seat?: string;
|
|
89
108
|
readonly parentToolCallId?: string;
|
|
90
109
|
}
|
|
91
110
|
export declare function retryStatusFromArm(arm: RetryStatusArmLike | null | undefined, nowMs: number): RetryStatus | null | undefined;
|
package/dist/retryStatus.js
CHANGED
|
@@ -11,6 +11,12 @@ export const BRAIN_STATUS_PHASES = [
|
|
|
11
11
|
'gave_up',
|
|
12
12
|
'waiting_first_token',
|
|
13
13
|
];
|
|
14
|
+
export const BRAIN_STATUS_WAIT_SEGMENTS = Object.freeze(['response_headers', 'first_token']);
|
|
15
|
+
void true;
|
|
16
|
+
void true;
|
|
17
|
+
export const BRAIN_STATUS_SEATS = Object.freeze(['classifier']);
|
|
18
|
+
void true;
|
|
19
|
+
void true;
|
|
14
20
|
export const BRAIN_STATUS_PAYLOAD_KEYS = [
|
|
15
21
|
'phase',
|
|
16
22
|
'detail',
|
|
@@ -25,6 +31,9 @@ export const BRAIN_STATUS_PAYLOAD_KEYS = [
|
|
|
25
31
|
'timeoutMs',
|
|
26
32
|
'providerCondition',
|
|
27
33
|
'providerConditionSource',
|
|
34
|
+
'sleptMs',
|
|
35
|
+
'waitSegment',
|
|
36
|
+
'seat',
|
|
28
37
|
];
|
|
29
38
|
const _brainStatusKeyPin = [true, true];
|
|
30
39
|
void _brainStatusKeyPin;
|
|
@@ -41,9 +50,11 @@ export function mapBrainStatusToRetry(p, nowMs) {
|
|
|
41
50
|
const cause = typeof p.errClass === 'string' && p.errClass.length > 0 ? { errClass: p.errClass } : {};
|
|
42
51
|
const producerTiming = typeof p.retryAtMs === 'number' ? { retryAtMs: p.retryAtMs } : {};
|
|
43
52
|
const failureStatus = typeof p.errorStatus === 'number' ? { errorStatus: p.errorStatus } : {};
|
|
53
|
+
const providerCondition = p.providerCondition;
|
|
54
|
+
const providerConditionSource = p.providerConditionSource;
|
|
44
55
|
const providerJudged = {
|
|
45
|
-
...(typeof
|
|
46
|
-
...(typeof
|
|
56
|
+
...(typeof providerCondition === 'string' && providerCondition.length > 0 ? { providerCondition } : {}),
|
|
57
|
+
...(typeof providerConditionSource === 'string' && providerConditionSource.length > 0 ? { providerConditionSource } : {}),
|
|
47
58
|
};
|
|
48
59
|
const saneMs = (v) => typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : undefined;
|
|
49
60
|
const elapsedMs = saneMs(p.elapsedMs);
|
|
@@ -52,10 +63,18 @@ export function mapBrainStatusToRetry(p, nowMs) {
|
|
|
52
63
|
...(elapsedMs !== undefined ? { elapsedMs } : {}),
|
|
53
64
|
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
54
65
|
};
|
|
66
|
+
const sleptMs = saneMs(p.sleptMs);
|
|
67
|
+
const waitSegment = p.waitSegment;
|
|
68
|
+
const seat = p.seat;
|
|
69
|
+
const waitFacts = {
|
|
70
|
+
...(sleptMs !== undefined ? { sleptMs } : {}),
|
|
71
|
+
...(typeof waitSegment === 'string' && waitSegment.length > 0 ? { waitSegment } : {}),
|
|
72
|
+
...(typeof seat === 'string' && seat.length > 0 ? { seat } : {}),
|
|
73
|
+
};
|
|
55
74
|
const stalledShown = typeof p.detail === 'string' && p.detail.length > 0 ? displayUntrusted(p.detail) : '';
|
|
56
75
|
const stalledDetail = stalledShown.length > 0 ? { detail: stalledShown } : {};
|
|
57
76
|
const shown = (absent) => (typeof p.detail === 'string' ? displayUntrusted(p.detail) : absent);
|
|
58
|
-
const extra = { ...counts, ...cause, ...producerTiming, ...failureStatus, ...providerJudged, ...waitProgress };
|
|
77
|
+
const extra = { ...counts, ...cause, ...producerTiming, ...failureStatus, ...providerJudged, ...waitProgress, ...waitFacts };
|
|
59
78
|
switch (p.phase) {
|
|
60
79
|
case 'recovered':
|
|
61
80
|
return null;
|
|
@@ -99,8 +118,8 @@ export function retryStatusFromArm(arm, nowMs) {
|
|
|
99
118
|
const v = str(key);
|
|
100
119
|
return v !== undefined && v.length > 0 ? v : undefined;
|
|
101
120
|
};
|
|
102
|
-
const [detail, retryInSec, retryInMs, attempt, maxRetries, errClass, retryAtMs, errorStatus, elapsedMs, timeoutMs, providerCondition, providerConditionSource] = [
|
|
103
|
-
str('detail'), num('retryInSec'), num('retryInMs'), num('attempt'), num('maxRetries'), str('errClass'), num('retryAtMs'), num('errorStatus'), num('elapsedMs'), num('timeoutMs'), word('providerCondition'), word('providerConditionSource'),
|
|
121
|
+
const [detail, retryInSec, retryInMs, attempt, maxRetries, errClass, retryAtMs, errorStatus, elapsedMs, timeoutMs, providerCondition, providerConditionSource, sleptMs, waitSegment, seat] = [
|
|
122
|
+
str('detail'), num('retryInSec'), num('retryInMs'), num('attempt'), num('maxRetries'), str('errClass'), num('retryAtMs'), num('errorStatus'), num('elapsedMs'), num('timeoutMs'), word('providerCondition'), word('providerConditionSource'), num('sleptMs'), word('waitSegment'), word('seat'),
|
|
104
123
|
];
|
|
105
124
|
const phase = str('phase');
|
|
106
125
|
if (phase === undefined)
|
|
@@ -119,6 +138,9 @@ export function retryStatusFromArm(arm, nowMs) {
|
|
|
119
138
|
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
120
139
|
...(providerCondition !== undefined ? { providerCondition } : {}),
|
|
121
140
|
...(providerConditionSource !== undefined ? { providerConditionSource } : {}),
|
|
141
|
+
...(sleptMs !== undefined ? { sleptMs } : {}),
|
|
142
|
+
...(waitSegment !== undefined ? { waitSegment } : {}),
|
|
143
|
+
...(seat !== undefined ? { seat } : {}),
|
|
122
144
|
}, nowMs);
|
|
123
145
|
}
|
|
124
146
|
const WAIT_SWITCH_FRACTION = 0.5;
|
|
@@ -203,7 +225,8 @@ function sealParts(p) {
|
|
|
203
225
|
}
|
|
204
226
|
export function retryStatusParts(status, ctx) {
|
|
205
227
|
const modelName = washedText(noticeText(ctx, 'modelName'))?.trim();
|
|
206
|
-
const
|
|
228
|
+
const otherSeat = status !== null && noticeText(status, 'seat') !== undefined;
|
|
229
|
+
const model = otherSeat || modelName === undefined || modelName === '' ? undefined : modelName;
|
|
207
230
|
if (status === null)
|
|
208
231
|
return sealParts({ phase: 'cleared' });
|
|
209
232
|
const armWord = noticeText(status, 'kind');
|
|
@@ -228,7 +251,7 @@ export function retryStatusParts(status, ctx) {
|
|
|
228
251
|
const condition = reading === undefined ? undefined : `${reading.clause.charAt(0).toUpperCase()}${reading.clause.slice(1)}`;
|
|
229
252
|
const serviceSide = http !== undefined && isServiceSideStatus(http);
|
|
230
253
|
const knownArm = armWord === 'stalled' || armWord === 'error';
|
|
231
|
-
const
|
|
254
|
+
const recourseOfArm = !knownArm
|
|
232
255
|
? undefined
|
|
233
256
|
: reading !== undefined
|
|
234
257
|
? conditionRecourseOf(conditionWord)
|
|
@@ -237,6 +260,7 @@ export function retryStatusParts(status, ctx) {
|
|
|
237
260
|
: !terminal
|
|
238
261
|
? 'wait'
|
|
239
262
|
: undefined;
|
|
263
|
+
const recourse = otherSeat && recourseOfArm === 'switch_model' ? (terminal ? undefined : 'wait') : recourseOfArm;
|
|
240
264
|
const deadlineRaw = knownArm && !terminal && noticeNumber(status, 'retryAtMs') !== undefined ? noticeNumber(status, 'deadline') : undefined;
|
|
241
265
|
const retryAtMs = deadlineRaw !== undefined && deadlineRaw > 0 ? deadlineRaw : undefined;
|
|
242
266
|
return sealParts({
|
|
@@ -17,6 +17,7 @@ export declare function ruleCompileVerdictUnder(rule: string, behavior: 'deny' |
|
|
|
17
17
|
export type DenyEntryInertReason = 'grammar' | 'content_unsupported' | 'wildcard_all' | 'namespace_wildcard';
|
|
18
18
|
export type DenyEntryReading = {
|
|
19
19
|
readonly kind: 'row';
|
|
20
|
+
readonly covering?: true;
|
|
20
21
|
} | {
|
|
21
22
|
readonly kind: 'inert';
|
|
22
23
|
readonly reason: DenyEntryInertReason;
|
|
@@ -58,7 +58,9 @@ export function denyEntryReading(rule) {
|
|
|
58
58
|
const kind = readOwnDataValue(reading, 'kind');
|
|
59
59
|
if (kind === 'row') {
|
|
60
60
|
const compiled = readOwnDataValue(reading, 'compiled');
|
|
61
|
-
|
|
61
|
+
if (typeof compiled !== 'object' || compiled === null)
|
|
62
|
+
return { kind: 'unknown' };
|
|
63
|
+
return readOwnDataValue(compiled, 'kind') === 'covering' ? { kind: 'row', covering: true } : { kind: 'row' };
|
|
62
64
|
}
|
|
63
65
|
if (kind !== 'inert')
|
|
64
66
|
return { kind: 'unknown' };
|
package/dist/seatContract.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { DeviceEnrollTokenOutcome, DeviceListOutcome, DeviceRebindOutcome,
|
|
|
14
14
|
import type { McpPanelView } from "./mcpPanel.js";
|
|
15
15
|
import type { McpToolToggleKey } from "./mcpToolToggles.js";
|
|
16
16
|
import { type ThinkingLatchEvent, type ThinkingLatchRowWord } from "./thinkingLatchWords.js";
|
|
17
|
+
import type { SessionRowPatchFields } from "./sessionRowTag.js";
|
|
17
18
|
export interface SeatValidationFailure {
|
|
18
19
|
reason: string;
|
|
19
20
|
field?: string;
|
|
@@ -48,6 +49,7 @@ export interface LocalSessionRecord {
|
|
|
48
49
|
}>;
|
|
49
50
|
parked?: boolean;
|
|
50
51
|
pinned?: boolean;
|
|
52
|
+
rowTag?: string;
|
|
51
53
|
thinkingLatch?: ThinkingLatchRowWord;
|
|
52
54
|
}
|
|
53
55
|
export declare const TOOL_PERMISSION_REQUEST_ID_DOMAINS: readonly ["live:", "durable:", "question:", "elicit:", "plan:"];
|
|
@@ -301,12 +303,10 @@ export declare const ATTACHMENT_UPLOAD_REQUEST_KEYS: readonly ["name", "mimeType
|
|
|
301
303
|
export interface SessionScopedRequest {
|
|
302
304
|
sessionId: string;
|
|
303
305
|
}
|
|
304
|
-
export interface SessionRowPatchRequest {
|
|
306
|
+
export interface SessionRowPatchRequest extends SessionRowPatchFields {
|
|
305
307
|
sessionId: string;
|
|
306
|
-
title?: string | null;
|
|
307
|
-
pinned?: boolean;
|
|
308
308
|
}
|
|
309
|
-
export declare const SESSION_ROW_PATCH_REQUEST_KEYS: readonly ["sessionId", "title", "pinned"];
|
|
309
|
+
export declare const SESSION_ROW_PATCH_REQUEST_KEYS: readonly ["sessionId", "title", "pinned", "expectedRowTag"];
|
|
310
310
|
export interface SetThinkingLatchRequest {
|
|
311
311
|
readonly sessionId: string;
|
|
312
312
|
readonly event: ThinkingLatchEvent;
|
|
@@ -688,7 +688,7 @@ export declare const SEAT_STORE_PROPS: readonly ["sessionsStateStore", "focusedS
|
|
|
688
688
|
export declare const SEAT_EVENT_METHOD_NAMES: readonly ["onEvent", "onToolPermissionRequest"];
|
|
689
689
|
export declare const LOCAL_SESSION_EVENT_KEYS: readonly ["type", "sessionId", "message", "error", "errorCategory", "code", "session", "userMessageUuid", "requestId", "outcome", "parked", "chrome", "_sema_turnFailure", "subagentContent"];
|
|
690
690
|
export declare const TOOL_PERMISSION_REQUEST_KEYS: readonly ["requestId", "sessionId", "toolName", "toolCallId", "input", "message", "toctouBinding", "createdAtMs", "governanceForced", "delegation", "mandated", "mandate", "origin", "ruleOffersAbsence", "askClass", "classes", "sessionRow"];
|
|
691
|
-
export declare const LOCAL_SESSION_RECORD_KEYS: readonly ["sessionId", "engineSessionId", "model", "title", "cwd", "isRunning", "createdAt", "lastActivityAt", "queuedMessages", "parked", "pinned", "thinkingLatch"];
|
|
691
|
+
export declare const LOCAL_SESSION_RECORD_KEYS: readonly ["sessionId", "engineSessionId", "model", "title", "cwd", "isRunning", "createdAt", "lastActivityAt", "queuedMessages", "parked", "pinned", "rowTag", "thinkingLatch"];
|
|
692
692
|
export declare const SEND_MESSAGE_REQUEST_KEYS: readonly ["sessionId", "text", "model", "userMessageUuid", "permissionMode", "attachmentIds", "reasoningEffort", "retainBackgroundProcesses", "forwardSubagentEvents", "retainSubagentSessions", "settings", "scenario", "rewind"];
|
|
693
693
|
export declare const SEAT_SEND_MESSAGE_KEY_ORIGINS: {
|
|
694
694
|
readonly sessionId: {
|
|
@@ -738,7 +738,7 @@ export declare const SEAT_VALIDATOR_KEY_COVERAGE: {
|
|
|
738
738
|
readonly LocalSessionRecord: {
|
|
739
739
|
readonly guard: "isLocalSessionRecord";
|
|
740
740
|
readonly check: (v: unknown) => SeatValidation;
|
|
741
|
-
readonly validated: readonly ["sessionId", "engineSessionId", "model", "title", "cwd", "isRunning", "createdAt", "lastActivityAt", "queuedMessages", "parked", "pinned", "thinkingLatch"];
|
|
741
|
+
readonly validated: readonly ["sessionId", "engineSessionId", "model", "title", "cwd", "isRunning", "createdAt", "lastActivityAt", "queuedMessages", "parked", "pinned", "rowTag", "thinkingLatch"];
|
|
742
742
|
readonly unchecked: readonly [];
|
|
743
743
|
};
|
|
744
744
|
readonly ToolPermissionRequest: {
|
|
@@ -815,7 +815,7 @@ export declare const SEAT_VALIDATOR_KEY_COVERAGE: {
|
|
|
815
815
|
readonly SessionRowPatchRequest: {
|
|
816
816
|
readonly guard: "isSessionRowPatchRequest";
|
|
817
817
|
readonly check: (v: unknown) => SeatValidation;
|
|
818
|
-
readonly validated: readonly ["sessionId", "title", "pinned"];
|
|
818
|
+
readonly validated: readonly ["sessionId", "title", "pinned", "expectedRowTag"];
|
|
819
819
|
readonly unchecked: readonly [];
|
|
820
820
|
};
|
|
821
821
|
readonly SetThinkingLatchRequest: {
|
package/dist/seatContract.js
CHANGED
|
@@ -6,6 +6,7 @@ import { PROBE_VERDICTS } from "./modelCapabilityProbe.js";
|
|
|
6
6
|
import { guardedRead, ownDataField, ownDataRefusalKeyOf, ownSendableField, readOwnDataValue } from "./ownKey.js";
|
|
7
7
|
import { MCP_LIVENESS_STATES } from "./mcpLiveness.js";
|
|
8
8
|
import { THINKING_LATCH_EVENTS, THINKING_LATCH_ROW_WORDS } from "./thinkingLatchWords.js";
|
|
9
|
+
import { EXECUTION_PLACEMENT_ROLES } from "./executionPlacementWords.js";
|
|
9
10
|
const bad = (reason, field) => field === undefined ? { reason } : { reason, field };
|
|
10
11
|
const nested = (prefix, verdict) => {
|
|
11
12
|
const path = verdict.field === undefined
|
|
@@ -122,7 +123,22 @@ function shapeVerdict(spec, v, path, disc) {
|
|
|
122
123
|
return true;
|
|
123
124
|
}
|
|
124
125
|
const shapeRule = (label, spec) => ({ label, test: (v, path) => shapeVerdict(spec, v, path) });
|
|
125
|
-
|
|
126
|
+
function keyGroupsVerdict(groups, v, path) {
|
|
127
|
+
let seen;
|
|
128
|
+
for (const g of groups) {
|
|
129
|
+
const present = g.filter((k) => !isAbsent(own(v, k)));
|
|
130
|
+
if (present.length === 0)
|
|
131
|
+
continue;
|
|
132
|
+
const missing = g.find((k) => !present.includes(k));
|
|
133
|
+
if (missing !== undefined)
|
|
134
|
+
return bad("missing key", pathAt(path, missing));
|
|
135
|
+
if (seen !== undefined)
|
|
136
|
+
return bad(`bad value (${seen.join("+")} | ${g.join("+")})`, pathAt(path, g[0]));
|
|
137
|
+
seen = g;
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
const armsRule = (label, disc, arms, groups = {}) => ({
|
|
126
142
|
label,
|
|
127
143
|
test: (v, path) => {
|
|
128
144
|
if (!isPlainRecord(v))
|
|
@@ -130,7 +146,10 @@ const armsRule = (label, disc, arms) => ({
|
|
|
130
146
|
const d = own(v, disc);
|
|
131
147
|
if (typeof d !== "string" || !Object.hasOwn(arms, d))
|
|
132
148
|
return bad("unknown arm", pathAt(path, disc));
|
|
133
|
-
|
|
149
|
+
const verdict = shapeVerdict(arms[d], v, path, disc);
|
|
150
|
+
if (verdict !== true || !Object.hasOwn(groups, d))
|
|
151
|
+
return verdict;
|
|
152
|
+
return keyGroupsVerdict(groups[d], v, path);
|
|
134
153
|
},
|
|
135
154
|
});
|
|
136
155
|
const isArraySlotKey = (k, n) => k === "length" || (/^(0|[1-9][0-9]*)$/.test(k) && Number(k) < n);
|
|
@@ -162,6 +181,7 @@ const R_BOOL = ruleOf("boolean", (v) => typeof v === "boolean");
|
|
|
162
181
|
const R_THINKING_LATCH_ROW = oneOfRule("latch word", THINKING_LATCH_ROW_WORDS);
|
|
163
182
|
const R_TRUE = ruleOf("true", (v) => v === true);
|
|
164
183
|
const R_NUM = ruleOf("finite number", (v) => typeof v === "number" && Number.isFinite(v));
|
|
184
|
+
const R_NUM0 = ruleOf("finite non-negative number", (v) => typeof v === "number" && Number.isFinite(v) && v >= 0);
|
|
165
185
|
const R_INT0 = ruleOf("non-negative integer", (v) => typeof v === "number" && Number.isSafeInteger(v) && v >= 0);
|
|
166
186
|
const R_INT1 = ruleOf("positive integer", (v) => typeof v === "number" && Number.isSafeInteger(v) && v > 0);
|
|
167
187
|
const keyWords = (k) => k
|
|
@@ -558,7 +578,7 @@ export const SEAT_TURN_SETTINGS_ORIGINS = Object.freeze({
|
|
|
558
578
|
});
|
|
559
579
|
export const SEAT_REWIND_INTENT_KEYS = ["mode", "targetMessageUuid"];
|
|
560
580
|
export const ATTACHMENT_UPLOAD_REQUEST_KEYS = ["name", "mimeType", "bytes"];
|
|
561
|
-
export const SESSION_ROW_PATCH_REQUEST_KEYS = Object.freeze(["sessionId", "title", "pinned"]);
|
|
581
|
+
export const SESSION_ROW_PATCH_REQUEST_KEYS = Object.freeze(["sessionId", "title", "pinned", "expectedRowTag"]);
|
|
562
582
|
const SET_THINKING_LATCH_REQUEST_KEYS = Object.freeze(["sessionId", "event"]);
|
|
563
583
|
export const SESSION_SEARCH_RESULT_KEYS = ["sessionId", "title", "matches"];
|
|
564
584
|
export const GET_TRANSCRIPT_RESULT_KEYS = ["sessionId", "messages"];
|
|
@@ -581,7 +601,6 @@ const DEVICE_ROSTER_ROW = shapeRule("device row", {
|
|
|
581
601
|
const DEVICE_BINDING = shapeRule("device binding", {
|
|
582
602
|
deviceId: reqF(R_NONEMPTY),
|
|
583
603
|
rev: reqF(R_INT0),
|
|
584
|
-
boundAt: optF(R_STR),
|
|
585
604
|
});
|
|
586
605
|
const checkDeviceListOutcome = seatShapeCheck(armsRule("listDevices outcome", "kind", {
|
|
587
606
|
ok: { devices: reqF(arrayRule(DEVICE_ROSTER_ROW)), dropped: reqF(R_INT0) },
|
|
@@ -593,23 +612,24 @@ const checkDeviceListOutcome = seatShapeCheck(armsRule("listDevices outcome", "k
|
|
|
593
612
|
}));
|
|
594
613
|
const checkDeviceSessionBindingOutcome = seatShapeCheck(armsRule("readSessionBinding outcome", "kind", {
|
|
595
614
|
ok: { rootSessionId: reqF(R_NONEMPTY), boundDevice: reqF(DEVICE_BINDING) },
|
|
615
|
+
unbound: { role: reqF(oneOfRule("placement role", EXECUTION_PLACEMENT_ROLES)) },
|
|
596
616
|
"not-found": {},
|
|
617
|
+
unsupported: { reason: reqF(oneOfRule("unsupported reason", ["route", "capability"])) },
|
|
597
618
|
unreadable: DEVICE_UNREADABLE_SPEC,
|
|
598
|
-
"lane-absent": DEVICE_LANE_ABSENT_SPEC,
|
|
599
619
|
refused: DEVICE_REFUSED_SPEC,
|
|
600
620
|
transport: DEVICE_TRANSPORT_SPEC,
|
|
601
621
|
unarmed: {},
|
|
602
622
|
}));
|
|
603
623
|
const checkDeviceRebindOutcome = seatShapeCheck(armsRule("rebindSession outcome", "kind", {
|
|
604
624
|
ok: { deviceId: reqF(R_NONEMPTY), rev: reqF(R_INT0), workspaceCarryover: optF(oneOfRule("carryover", ["none"])) },
|
|
605
|
-
"active-run": { activeTaskId: optF(R_STR) },
|
|
625
|
+
"active-run": { activeTaskId: optF(R_STR), children: optF(arrayRule(R_STR)), retirePath: optF(R_NONEMPTY) },
|
|
606
626
|
"rev-conflict": { currentRev: optF(R_INT0) },
|
|
607
627
|
"not-found": {},
|
|
608
628
|
unconfirmed: DEVICE_UNCONFIRMED_SPEC,
|
|
609
629
|
"lane-absent": DEVICE_LANE_ABSENT_SPEC,
|
|
610
630
|
refused: DEVICE_REFUSED_SPEC,
|
|
611
631
|
unarmed: {},
|
|
612
|
-
}));
|
|
632
|
+
}, { "active-run": [["activeTaskId"], ["children", "retirePath"]] }));
|
|
613
633
|
const ENROLL_TOKEN_ALLOW = new Set(["token"]);
|
|
614
634
|
const checkDeviceEnrollTokenOutcome = seatShapeCheck(armsRule("issueEnrollToken outcome", "kind", {
|
|
615
635
|
ok: { token: reqF(R_NONEMPTY), expiresAt: optF(R_STR), ttlSec: optF(R_INT1) },
|
|
@@ -882,6 +902,11 @@ function mcpPanelLivenessArms() {
|
|
|
882
902
|
return arms;
|
|
883
903
|
}
|
|
884
904
|
const MCP_PANEL_LIVENESS_VIEW = armsRule("mcp liveness", "state", mcpPanelLivenessArms());
|
|
905
|
+
const MCP_PANEL_AUTHORIZATION = shapeRule("mcp authorization", {
|
|
906
|
+
reason: reqF(R_NONEMPTY),
|
|
907
|
+
authorizeUrl: optF(R_NONEMPTY),
|
|
908
|
+
resourceMetadataUrl: optF(R_NONEMPTY),
|
|
909
|
+
});
|
|
885
910
|
const MCP_PANEL_LEG_ENTRY = shapeRule("leg entry", {
|
|
886
911
|
name: reqF(R_NONEMPTY),
|
|
887
912
|
status: reqF(R_NONEMPTY),
|
|
@@ -892,6 +917,8 @@ const MCP_PANEL_LEG_ENTRY = shapeRule("leg entry", {
|
|
|
892
917
|
httpStatus: optF(R_NUM),
|
|
893
918
|
liveness: optF(MCP_PANEL_LIVENESS_VIEW),
|
|
894
919
|
livenessUnreadable: optF(R_TRUE),
|
|
920
|
+
authorization: optF(MCP_PANEL_AUTHORIZATION),
|
|
921
|
+
authorizationUnreadable: optF(R_TRUE),
|
|
895
922
|
});
|
|
896
923
|
const MCP_PANEL_LAST_LEG = shapeRule("last leg", {
|
|
897
924
|
runId: reqF(R_NONEMPTY),
|
|
@@ -975,6 +1002,10 @@ const checkLocalSessionRecord = seatCheck((s) => {
|
|
|
975
1002
|
if (!isAbsent(pinned) && typeof pinned !== "boolean") {
|
|
976
1003
|
return bad("pinned must be a boolean when present (absent = not pinned or unknown)", "pinned");
|
|
977
1004
|
}
|
|
1005
|
+
const rowTag = own(s, "rowTag");
|
|
1006
|
+
if (!isAbsent(rowTag) && (typeof rowTag !== "string" || rowTag.length === 0)) {
|
|
1007
|
+
return bad("rowTag must be a non-empty string when present (absent = this row cannot be written conditionally)", "rowTag");
|
|
1008
|
+
}
|
|
978
1009
|
const latch = own(s, "thinkingLatch");
|
|
979
1010
|
if (!isAbsent(latch)) {
|
|
980
1011
|
const verdict = R_THINKING_LATCH_ROW.test(latch, "thinkingLatch");
|
|
@@ -1069,6 +1100,9 @@ const RETRY_COMMON_SPEC = {
|
|
|
1069
1100
|
providerConditionSource: optF(R_STR),
|
|
1070
1101
|
elapsedMs: optF(R_NUM),
|
|
1071
1102
|
timeoutMs: optF(R_NUM),
|
|
1103
|
+
sleptMs: optF(R_NUM0),
|
|
1104
|
+
waitSegment: optF(R_NONEMPTY),
|
|
1105
|
+
seat: optF(R_NONEMPTY),
|
|
1072
1106
|
};
|
|
1073
1107
|
const RETRY_STATUS = armsRule("retry status", "kind", {
|
|
1074
1108
|
stalled: { ...RETRY_COMMON_SPEC, detail: optF(R_STR) },
|
|
@@ -1441,8 +1475,12 @@ export const checkSessionRowPatchRequest = seatCheck((v) => {
|
|
|
1441
1475
|
}
|
|
1442
1476
|
if (!isAbsent(pinned) && typeof pinned !== "boolean")
|
|
1443
1477
|
return bad("pinned must be a boolean when present", "pinned");
|
|
1478
|
+
const expectedRowTag = body.expectedRowTag;
|
|
1479
|
+
if (!isAbsent(expectedRowTag) && (typeof expectedRowTag !== "string" || expectedRowTag.length === 0)) {
|
|
1480
|
+
return bad("expectedRowTag must be the non-empty rowTag read from the same session row when present", "expectedRowTag");
|
|
1481
|
+
}
|
|
1444
1482
|
if (isAbsent(title) && isAbsent(pinned))
|
|
1445
|
-
return bad("nothing to change: carry at least one of title / pinned");
|
|
1483
|
+
return bad("nothing to change: carry at least one of title / pinned (expectedRowTag is a precondition, not a change)");
|
|
1446
1484
|
return true;
|
|
1447
1485
|
});
|
|
1448
1486
|
export function isSessionRowPatchRequest(v) {
|
|
@@ -1734,6 +1772,7 @@ export const LOCAL_SESSION_RECORD_KEYS = [
|
|
|
1734
1772
|
"queuedMessages",
|
|
1735
1773
|
"parked",
|
|
1736
1774
|
"pinned",
|
|
1775
|
+
"rowTag",
|
|
1737
1776
|
"thinkingLatch",
|
|
1738
1777
|
];
|
|
1739
1778
|
export const SEND_MESSAGE_REQUEST_KEYS = [
|
|
@@ -1779,7 +1818,7 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1779
1818
|
LocalSessionRecord: {
|
|
1780
1819
|
guard: "isLocalSessionRecord",
|
|
1781
1820
|
check: checkLocalSessionRecord,
|
|
1782
|
-
validated: ["sessionId", "engineSessionId", "model", "title", "cwd", "isRunning", "createdAt", "lastActivityAt", "queuedMessages", "parked", "pinned", "thinkingLatch"],
|
|
1821
|
+
validated: ["sessionId", "engineSessionId", "model", "title", "cwd", "isRunning", "createdAt", "lastActivityAt", "queuedMessages", "parked", "pinned", "rowTag", "thinkingLatch"],
|
|
1783
1822
|
unchecked: [],
|
|
1784
1823
|
},
|
|
1785
1824
|
ToolPermissionRequest: {
|
|
@@ -1900,7 +1939,7 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1900
1939
|
SessionRowPatchRequest: {
|
|
1901
1940
|
guard: "isSessionRowPatchRequest",
|
|
1902
1941
|
check: checkSessionRowPatchRequest,
|
|
1903
|
-
validated: ["sessionId", "title", "pinned"],
|
|
1942
|
+
validated: ["sessionId", "title", "pinned", "expectedRowTag"],
|
|
1904
1943
|
unchecked: [],
|
|
1905
1944
|
},
|
|
1906
1945
|
SetThinkingLatchRequest: {
|
|
@@ -245,7 +245,29 @@ const UNCONFIRMED_TEXT = {
|
|
|
245
245
|
unreadable: 'Not confirmed: the result of this erase could not be read.',
|
|
246
246
|
};
|
|
247
247
|
const ERASED_TEXT = 'Erased: every memory entry recorded as coming from this session was erased or was already gone.';
|
|
248
|
-
const
|
|
248
|
+
const PARTIAL_ENTRIES_TEXT = 'Partly erased: some memory entries from this session were not erased yet.';
|
|
249
|
+
const PARTIAL_UNKNOWN_TEXT = 'Partly erased: the engine reports this erase as not complete, and its receipt does not show whether memory entries or other stored records of them remain.';
|
|
250
|
+
function partialCarriersText(kinds) {
|
|
251
|
+
return kinds === 1
|
|
252
|
+
? 'Partly erased: every memory entry recorded as coming from this session was erased or was already gone, but 1 kind of stored record that refers to them was not confirmed removed, and trying again may not remove it.'
|
|
253
|
+
: `Partly erased: every memory entry recorded as coming from this session was erased or was already gone, but ${kinds} kinds of stored records that refer to them were not confirmed removed, and trying again may not remove them.`;
|
|
254
|
+
}
|
|
255
|
+
function partialTextOf(cause) {
|
|
256
|
+
if (cause === null)
|
|
257
|
+
return PARTIAL_UNKNOWN_TEXT;
|
|
258
|
+
switch (cause.kind) {
|
|
259
|
+
case 'entries_pending':
|
|
260
|
+
return PARTIAL_ENTRIES_TEXT;
|
|
261
|
+
case 'carriers_residual':
|
|
262
|
+
return partialCarriersText(cause.carriers.length);
|
|
263
|
+
case 'unknown':
|
|
264
|
+
return PARTIAL_UNKNOWN_TEXT;
|
|
265
|
+
default: {
|
|
266
|
+
const unreachable = cause;
|
|
267
|
+
return unreachable;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
249
271
|
const RETRY_TEXT = {
|
|
250
272
|
not_needed: 'Nothing more to do.',
|
|
251
273
|
same_request_id: 'It is safe to try again with the same request id.',
|
|
@@ -414,7 +436,7 @@ export function sessionMemoryEraseOutcome(answer) {
|
|
|
414
436
|
return { kind: 'erased', receipt: reading, text: ERASED_TEXT, retry: 'not_needed', retryText: RETRY_TEXT.not_needed };
|
|
415
437
|
}
|
|
416
438
|
const retry = memoryEraseReplayPosture(reading) === 'idempotent' ? 'same_request_id' : 'human_decision';
|
|
417
|
-
return { kind: 'partial', receipt: reading, text:
|
|
439
|
+
return { kind: 'partial', receipt: reading, text: partialTextOf(reading.partialCause), retry, retryText: RETRY_TEXT[retry] };
|
|
418
440
|
}
|
|
419
441
|
if (status < 400)
|
|
420
442
|
return unconfirmedBy('unclassified', signed, { status });
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface SessionRowPatchFields {
|
|
2
|
+
title?: string | null;
|
|
3
|
+
pinned?: boolean;
|
|
4
|
+
expectedRowTag?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SessionRowCurrentReading {
|
|
7
|
+
readonly rowTag?: string;
|
|
8
|
+
readonly title?: string;
|
|
9
|
+
readonly pinned?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export type SessionRowPatchRefusal = {
|
|
12
|
+
readonly kind: 'already-applied';
|
|
13
|
+
readonly current: SessionRowCurrentReading;
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: 'row-changed';
|
|
16
|
+
readonly current?: SessionRowCurrentReading;
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: 'mirror';
|
|
19
|
+
readonly forkPath?: string;
|
|
20
|
+
} | {
|
|
21
|
+
readonly kind: 'tag-unsupported';
|
|
22
|
+
};
|
|
23
|
+
export declare function sessionRowTagOf(row: object | null | undefined): string | undefined;
|
|
24
|
+
export declare function sessionRowPatchRefusalOf(error: {} | null | undefined, sent: Readonly<SessionRowPatchFields> | null | undefined): SessionRowPatchRefusal | null;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { guardedRead, readOwnDataValue } from './ownKey.js';
|
|
2
|
+
import { isSlotCarrier, readErrorRecord, readErrorString, readThrownSlot, slotReadOf } from './wireFailureShape.js';
|
|
3
|
+
const ROW_CHANGED = 'conflict.session_row_changed';
|
|
4
|
+
const SESSION_MIRROR = 'conflict.session_mirror';
|
|
5
|
+
const BODY_SHAPE = 'request.body_shape';
|
|
6
|
+
function ownData(v, key) {
|
|
7
|
+
if (v === null || typeof v !== 'object')
|
|
8
|
+
return undefined;
|
|
9
|
+
return guardedRead(() => readOwnDataValue(v, key));
|
|
10
|
+
}
|
|
11
|
+
export function sessionRowTagOf(row) {
|
|
12
|
+
const v = ownData(row, 'rowTag');
|
|
13
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
14
|
+
}
|
|
15
|
+
function currentRowOf(e) {
|
|
16
|
+
const row = guardedRead(() => readErrorRecord(e, 'currentRow'));
|
|
17
|
+
if (row === undefined)
|
|
18
|
+
return undefined;
|
|
19
|
+
const rowTag = sessionRowTagOf(row);
|
|
20
|
+
const title = ownData(row, 'title');
|
|
21
|
+
const pinned = ownData(row, 'pinned');
|
|
22
|
+
return Object.freeze({
|
|
23
|
+
...(rowTag !== undefined ? { rowTag } : {}),
|
|
24
|
+
...(typeof title === 'string' ? { title } : {}),
|
|
25
|
+
...(typeof pinned === 'boolean' ? { pinned } : {}),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function pendingSlotOf(sent, key) {
|
|
29
|
+
if (sent === null || typeof sent !== 'object')
|
|
30
|
+
return { state: 'absent' };
|
|
31
|
+
const read = slotReadOf(sent, key);
|
|
32
|
+
if (read.presence === 'absent')
|
|
33
|
+
return { state: 'absent' };
|
|
34
|
+
if (read.presence !== 'present')
|
|
35
|
+
return { state: 'unreadable' };
|
|
36
|
+
return read.value === undefined ? { state: 'absent' } : { state: 'value', value: read.value };
|
|
37
|
+
}
|
|
38
|
+
function alreadyApplied(sent, current) {
|
|
39
|
+
const title = pendingSlotOf(sent, 'title');
|
|
40
|
+
const pinned = pendingSlotOf(sent, 'pinned');
|
|
41
|
+
if (title.state === 'unreadable' || pinned.state === 'unreadable')
|
|
42
|
+
return false;
|
|
43
|
+
let compared = 0;
|
|
44
|
+
if (title.state === 'value') {
|
|
45
|
+
if (typeof title.value !== 'string' || current.title !== title.value)
|
|
46
|
+
return false;
|
|
47
|
+
compared++;
|
|
48
|
+
}
|
|
49
|
+
if (pinned.state === 'value') {
|
|
50
|
+
if (typeof pinned.value !== 'boolean' || current.pinned !== pinned.value)
|
|
51
|
+
return false;
|
|
52
|
+
compared++;
|
|
53
|
+
}
|
|
54
|
+
return compared > 0;
|
|
55
|
+
}
|
|
56
|
+
export function sessionRowPatchRefusalOf(error, sent) {
|
|
57
|
+
if (!isSlotCarrier(error))
|
|
58
|
+
return null;
|
|
59
|
+
const status = readThrownSlot(error, 'status', 'data');
|
|
60
|
+
const code = readThrownSlot(error, 'errorCode', 'data');
|
|
61
|
+
if (status === 409 && code === ROW_CHANGED) {
|
|
62
|
+
const current = currentRowOf(error);
|
|
63
|
+
if (current !== undefined && alreadyApplied(sent, current))
|
|
64
|
+
return { kind: 'already-applied', current };
|
|
65
|
+
return { kind: 'row-changed', ...(current !== undefined ? { current } : {}) };
|
|
66
|
+
}
|
|
67
|
+
if (status === 409 && code === SESSION_MIRROR) {
|
|
68
|
+
const forkPath = guardedRead(() => readErrorString(error, 'forkPath'));
|
|
69
|
+
return { kind: 'mirror', ...(typeof forkPath === 'string' && forkPath.length > 0 ? { forkPath } : {}) };
|
|
70
|
+
}
|
|
71
|
+
if (status === 400 && code === BODY_SHAPE) {
|
|
72
|
+
const tag = ownData(sent, 'expectedRowTag');
|
|
73
|
+
if (typeof tag === 'string' && tag.length > 0)
|
|
74
|
+
return { kind: 'tag-unsupported' };
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
@@ -39,11 +39,21 @@ export function stripSystemReminderBlocks(text) {
|
|
|
39
39
|
}
|
|
40
40
|
return pos === 0 ? text : out + text.slice(pos);
|
|
41
41
|
}
|
|
42
|
-
const
|
|
43
|
-
const
|
|
42
|
+
const ENGINE_DEFUSAL_ENTITY = /&(lt|gt);/g;
|
|
43
|
+
const ENVELOPE_TAG_TOKEN = /<[^A-Za-z0-9>]{0,12}(?:system-reminder|task-notification)(?:[^>]{0,200}>)?/gi;
|
|
44
|
+
const CUT_TAG_HEAD = /<[^A-Za-z0-9>]{0,12}([A-Za-z-]{1,16})…/g;
|
|
45
|
+
const ENVELOPE_TAG_HEAD_BRACKET = /<(?=[^A-Za-z0-9>]{0,12}(?:system-reminder|task-notification|([A-Za-z-]{1,16})…))/gi;
|
|
46
|
+
const ENVELOPE_TAG_NAMES = Object.freeze(['system-reminder', 'task-notification']);
|
|
47
|
+
function isCutTagName(head) {
|
|
48
|
+
if (head === undefined || head === '')
|
|
49
|
+
return false;
|
|
50
|
+
const h = head.toLowerCase();
|
|
51
|
+
return ENVELOPE_TAG_NAMES.some((name) => name.length > h.length && name.startsWith(h));
|
|
52
|
+
}
|
|
44
53
|
export function stripSystemReminderTagTokens(text) {
|
|
45
54
|
if (typeof text !== 'string')
|
|
46
55
|
return text;
|
|
47
|
-
const
|
|
48
|
-
|
|
56
|
+
const restored = text.replace(ENGINE_DEFUSAL_ENTITY, (_entity, name) => (name === 'lt' ? '<' : '>'));
|
|
57
|
+
const once = restored.replace(ENVELOPE_TAG_TOKEN, ' ').replace(CUT_TAG_HEAD, (head, name) => (isCutTagName(name) ? ' …' : head));
|
|
58
|
+
return once.replace(ENVELOPE_TAG_HEAD_BRACKET, (bracket, cutName) => (cutName === undefined || isCutTagName(cutName) ? ' ' : bracket));
|
|
49
59
|
}
|
|
@@ -60,7 +60,14 @@ function isIdleWatchdog(err) {
|
|
|
60
60
|
return false;
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
const DETERMINISTIC_SERVER_CODES = new Set([
|
|
63
|
+
const DETERMINISTIC_SERVER_CODES = new Set([
|
|
64
|
+
CORRUPT_SESSION_ERROR_CODE,
|
|
65
|
+
CORRUPT_ROW_ERROR_CODE,
|
|
66
|
+
SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE,
|
|
67
|
+
MEMORY_CONTROL_PLANE_CORRUPT,
|
|
68
|
+
'approvals.read_corrupt',
|
|
69
|
+
'workflow.journal_incompatible',
|
|
70
|
+
]);
|
|
64
71
|
const BROWSER_FETCH_FAILURE = /\bfailed to fetch\b|\bnetworkerror\b|\bnetwork error\b|\bload failed\b/i;
|
|
65
72
|
function httpShapeOf(verdict, code) {
|
|
66
73
|
const status = verdict.status;
|