@sema-agent/client-core 0.96.0 → 0.97.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 +89 -0
- package/README.md +28 -22
- package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
- package/dist/adapter/activeRunSelfHeal.js +7 -7
- package/dist/adapter/downstream/terminalToSdkResult.js +6 -2
- package/dist/agentSession/backgroundView.js +2 -15
- package/dist/agentsWireCaps.d.ts +1 -1
- package/dist/agentsWireCaps.js +16 -10
- package/dist/approvalDecidedByCapability.d.ts +2 -0
- package/dist/approvalDecidedByCapability.js +0 -1
- package/dist/approvalsStreamLiveCapability.d.ts +2 -0
- package/dist/approvalsStreamLiveCapability.js +3 -2
- package/dist/attachmentSeatCapability.d.ts +2 -0
- package/dist/attachmentSeatCapability.js +0 -1
- package/dist/callerCwdCapability.d.ts +2 -0
- package/dist/callerCwdCapability.js +0 -1
- package/dist/centerWiringCapability.d.ts +2 -0
- package/dist/centerWiringCapability.js +4 -3
- package/dist/cloudConfigWireCaps.d.ts +2 -2
- package/dist/cloudConfigWireCaps.js +192 -56
- package/dist/declared/supportFloorDeclared.js +3 -3
- package/dist/deviceExecutorManagementCapability.d.ts +2 -0
- package/dist/deviceExecutorManagementCapability.js +3 -2
- package/dist/displayUntrusted.d.ts +3 -0
- package/dist/displayUntrusted.js +15 -0
- package/dist/engineCapReader.d.ts +8 -2
- package/dist/engineCapReader.js +15 -7
- package/dist/engineCapsCache.d.ts +11 -3
- package/dist/engineCapsCache.js +54 -23
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +9 -1
- package/dist/engineNoticeCodes.js +2 -3
- package/dist/executionLaneCapability.d.ts +2 -0
- package/dist/executionLaneCapability.js +3 -2
- package/dist/fileHistoryCaptureCapability.d.ts +2 -0
- package/dist/fileHistoryCaptureCapability.js +34 -8
- package/dist/fileHistoryLegNotice.js +4 -0
- package/dist/fleet/fleetLedger.js +129 -105
- package/dist/gateOutcome.js +2 -4
- package/dist/gateVocabulary.d.ts +1 -6
- package/dist/gateVocabulary.js +2 -5
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +7 -0
- package/dist/generated/toolNameTables.d.ts +0 -1
- package/dist/generated/toolNameTables.js +0 -42
- package/dist/hitl/approvalDecisionNoteAudit.js +2 -2
- package/dist/hitl/approvalEndingCause.js +2 -7
- package/dist/hitl/approvalHolds.d.ts +16 -1
- package/dist/hitl/approvalHolds.js +52 -12
- package/dist/hitl/askGateWire.js +1 -0
- package/dist/hitl/automaticAnswerVerdict.js +5 -7
- package/dist/hitl/decisionConflict.js +4 -3
- package/dist/hitl/decisionRefusal.js +19 -12
- package/dist/hitl/frameRouter.d.ts +3 -0
- package/dist/hitl/frameRouter.js +52 -25
- package/dist/hitl/gateLedger.d.ts +0 -5
- package/dist/hitl/gateLedger.js +0 -21
- package/dist/hitl/hitlBridge.js +18 -4
- package/dist/hitl/parkResolver.js +7 -3
- package/dist/hitl/replayedApproval.d.ts +2 -3
- package/dist/hitl/replayedApproval.js +7 -16
- package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
- package/dist/hitl/sessionPolicyDeliverable.js +15 -17
- package/dist/hitl/sessionPolicyWire.d.ts +2 -0
- package/dist/hitl/sessionPolicyWire.js +15 -3
- package/dist/hitl/standingRows.d.ts +1 -0
- package/dist/hitl/standingRows.js +38 -17
- package/dist/hitl/suspendedReopen.js +2 -1
- package/dist/hitl/toolApprovalWire.d.ts +8 -8
- package/dist/hitl/toolApprovalWire.js +50 -24
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -3
- package/dist/liveModelCatalog.d.ts +13 -0
- package/dist/liveModelCatalog.js +56 -0
- package/dist/mcpProbeCapability.d.ts +2 -0
- package/dist/mcpProbeCapability.js +3 -2
- package/dist/mcpWireCaps.d.ts +1 -0
- package/dist/mcpWireCaps.js +4 -1
- package/dist/memoryComplianceCapability.d.ts +2 -0
- package/dist/memoryComplianceCapability.js +3 -2
- package/dist/memoryOriginCapability.d.ts +2 -0
- package/dist/memoryOriginCapability.js +3 -2
- package/dist/modelIdentityResolvability.js +2 -2
- package/dist/noticePresentation.js +2 -2
- package/dist/outputStyleSeatCapability.d.ts +2 -0
- package/dist/outputStyleSeatCapability.js +0 -1
- package/dist/peerLaneCapability.d.ts +2 -0
- package/dist/peerLaneCapability.js +3 -2
- package/dist/permissionModesCapability.d.ts +2 -0
- package/dist/permissionModesCapability.js +0 -1
- package/dist/permissionRulesWriteCapability.d.ts +2 -0
- package/dist/permissionRulesWriteCapability.js +3 -2
- package/dist/permissionsAllowGrantCapability.d.ts +2 -0
- package/dist/permissionsAllowGrantCapability.js +4 -2
- package/dist/permissionsDeclaration.js +19 -21
- package/dist/request/taskRequest.d.ts +1 -4
- package/dist/request/taskRequest.js +74 -19
- package/dist/resumeRefusalCopy.js +4 -4
- package/dist/rewindArchiveCapability.js +5 -0
- package/dist/rewindArchiveReading.d.ts +2 -0
- package/dist/rewindArchiveReading.js +0 -1
- package/dist/runTerminal.d.ts +33 -4
- package/dist/runTerminal.js +170 -15
- package/dist/sdkWireTransit.d.ts +2 -1
- package/dist/sdkWireTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +2 -0
- package/dist/sealedKeyCapability.js +0 -1
- package/dist/seatContract.d.ts +7 -4
- package/dist/seatContract.js +34 -20
- package/dist/sessionPolicyCapability.d.ts +2 -0
- package/dist/sessionPolicyCapability.js +3 -2
- package/dist/sessionReadRedactionCapability.d.ts +2 -0
- package/dist/sessionReadRedactionCapability.js +0 -1
- package/dist/sessionSyncFileHistoryCapability.d.ts +2 -0
- package/dist/sessionSyncFileHistoryCapability.js +3 -2
- package/dist/skillToolListsCapability.d.ts +2 -0
- package/dist/skillToolListsCapability.js +3 -2
- package/dist/sqlEngineCapability.d.ts +2 -0
- package/dist/sqlEngineCapability.js +4 -3
- package/dist/steerPriorityCapability.d.ts +2 -0
- package/dist/steerPriorityCapability.js +3 -2
- package/dist/storePostureCapability.d.ts +2 -0
- package/dist/storePostureCapability.js +4 -3
- package/dist/toolHistoryBadTurn.js +3 -2
- package/dist/toolResult.d.ts +11 -0
- package/dist/toolResult.js +53 -0
- package/dist/userInvokedSkillsCapability.d.ts +2 -0
- package/dist/userInvokedSkillsCapability.js +3 -2
- package/dist/webSearchBackendCapability.d.ts +2 -0
- package/dist/webSearchBackendCapability.js +3 -2
- package/dist/wireErrorTriage.js +58 -34
- package/dist/wireFailureShape.d.ts +1 -1
- package/dist/wireFailureShape.js +76 -25
- package/dist/workflowsJournalCapability.d.ts +2 -0
- package/dist/workflowsJournalCapability.js +3 -2
- package/dist/writeProtectionCapability.d.ts +2 -0
- package/dist/writeProtectionCapability.js +3 -2
- package/docs/INTEGRATION-CLIENTS.md +533 -14
- package/package.json +4 -4
- package/dist/engineRefusedToolName.d.ts +0 -1
- package/dist/engineRefusedToolName.js +0 -8
- package/dist/engineWordRenames.d.ts +0 -8
- package/dist/engineWordRenames.js +0 -13
package/dist/runTerminal.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CheckpointGate } from '@sema-agent/sdk';
|
|
1
|
+
import type { CheckpointGate, TerminalModelOutputInvalidDetail } from '@sema-agent/sdk';
|
|
2
2
|
export type RunTerminalPlane = 'cause' | 'flat';
|
|
3
3
|
export interface RunTerminalPause {
|
|
4
4
|
gate?: CheckpointGate;
|
|
@@ -11,12 +11,41 @@ export interface RunTerminalPausedRead extends RunTerminalPause {
|
|
|
11
11
|
code?: string;
|
|
12
12
|
flatStatus?: string;
|
|
13
13
|
}
|
|
14
|
-
export
|
|
15
|
-
kind:
|
|
16
|
-
|
|
14
|
+
export type RunTerminalFailureDetail = RunTerminalProviderRejectedDetail | {
|
|
15
|
+
kind: 'coded';
|
|
16
|
+
detail: {
|
|
17
|
+
readonly [key: string]: RunTerminalJsonValue;
|
|
18
|
+
};
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'model_output_invalid';
|
|
21
|
+
cause: TerminalModelOutputInvalidDetail['cause'];
|
|
22
|
+
outputLimit?: RunTerminalOutputLimit;
|
|
23
|
+
} | {
|
|
24
|
+
kind: 'unrecognized';
|
|
25
|
+
word: string;
|
|
26
|
+
};
|
|
27
|
+
export type RunTerminalJsonValue = string | number | boolean | null | readonly RunTerminalJsonValue[] | {
|
|
28
|
+
readonly [key: string]: RunTerminalJsonValue;
|
|
29
|
+
};
|
|
30
|
+
export interface RunTerminalOutputLimit {
|
|
31
|
+
capStop: boolean;
|
|
32
|
+
outputTokens?: number;
|
|
33
|
+
capTokens?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface RunTerminalProviderRejectedDetail {
|
|
36
|
+
kind: 'provider_rejected';
|
|
37
|
+
status: number;
|
|
17
38
|
code?: string;
|
|
18
39
|
providerCondition?: string;
|
|
19
40
|
providerConditionSource?: string;
|
|
41
|
+
providerResetAtMs?: number;
|
|
42
|
+
route?: RunTerminalRequestRoute;
|
|
43
|
+
}
|
|
44
|
+
export interface RunTerminalRequestRoute {
|
|
45
|
+
credentialSource: string;
|
|
46
|
+
carrier?: string;
|
|
47
|
+
carrierBag?: string;
|
|
48
|
+
root: string;
|
|
20
49
|
}
|
|
21
50
|
export type RunTerminalCompletedDetail = {
|
|
22
51
|
kind: 'finish_reason_unknown';
|
package/dist/runTerminal.js
CHANGED
|
@@ -29,6 +29,123 @@ function ownValueOf(o, k) {
|
|
|
29
29
|
return Object.prototype.hasOwnProperty.call(o, k) ? o[k] : undefined;
|
|
30
30
|
}
|
|
31
31
|
const PROVIDER_REJECTED_DETAIL_KIND = 'provider_rejected';
|
|
32
|
+
const CODED_DETAIL_KIND = 'coded';
|
|
33
|
+
const MODEL_OUTPUT_INVALID_DETAIL_KIND = 'model_output_invalid';
|
|
34
|
+
const MODEL_OUTPUT_INVALID_CAUSES = Object.freeze(['truncated', 'unnamed']);
|
|
35
|
+
const _modelOutputInvalidCausePin = [true, true];
|
|
36
|
+
void _modelOutputInvalidCausePin;
|
|
37
|
+
const CODED_DETAIL_MAX_DEPTH = 40;
|
|
38
|
+
function ownData(o, k) {
|
|
39
|
+
const d = Object.getOwnPropertyDescriptor(o, k);
|
|
40
|
+
return d !== undefined && 'value' in d ? d.value : undefined;
|
|
41
|
+
}
|
|
42
|
+
function isPlainRecord(v) {
|
|
43
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
44
|
+
return false;
|
|
45
|
+
const proto = Object.getPrototypeOf(v);
|
|
46
|
+
return proto === null || Object.getPrototypeOf(proto) === null;
|
|
47
|
+
}
|
|
48
|
+
const CODED_DETAIL_BUDGET = 50_000;
|
|
49
|
+
const CODED_DETAIL_OVER_BUDGET = Symbol('coded-detail-over-budget');
|
|
50
|
+
function jsonSnapshot(v, depth, ctx) {
|
|
51
|
+
ctx.budget -= 1;
|
|
52
|
+
if (ctx.budget < 0)
|
|
53
|
+
throw CODED_DETAIL_OVER_BUDGET;
|
|
54
|
+
if (v === null || typeof v === 'string' || typeof v === 'boolean')
|
|
55
|
+
return v;
|
|
56
|
+
if (typeof v === 'number')
|
|
57
|
+
return Number.isFinite(v) ? v : undefined;
|
|
58
|
+
if (depth >= CODED_DETAIL_MAX_DEPTH)
|
|
59
|
+
return undefined;
|
|
60
|
+
if (typeof v !== 'object' || ctx.path.has(v))
|
|
61
|
+
return undefined;
|
|
62
|
+
if (Array.isArray(v)) {
|
|
63
|
+
const n = ownData(v, 'length');
|
|
64
|
+
if (typeof n !== 'number' || !Number.isSafeInteger(n) || n < 0)
|
|
65
|
+
return undefined;
|
|
66
|
+
ctx.path.add(v);
|
|
67
|
+
try {
|
|
68
|
+
const out = [];
|
|
69
|
+
for (let i = 0; i < n; i += 1) {
|
|
70
|
+
ctx.budget -= 1;
|
|
71
|
+
if (ctx.budget < 0)
|
|
72
|
+
throw CODED_DETAIL_OVER_BUDGET;
|
|
73
|
+
let item;
|
|
74
|
+
try {
|
|
75
|
+
item = jsonSnapshot(ownData(v, String(i)), depth + 1, ctx);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
if (e === CODED_DETAIL_OVER_BUDGET)
|
|
79
|
+
throw e;
|
|
80
|
+
item = undefined;
|
|
81
|
+
}
|
|
82
|
+
if (item !== undefined)
|
|
83
|
+
out.push(item);
|
|
84
|
+
}
|
|
85
|
+
return Object.freeze(out);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
ctx.path.delete(v);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (!isPlainRecord(v))
|
|
92
|
+
return undefined;
|
|
93
|
+
ctx.path.add(v);
|
|
94
|
+
try {
|
|
95
|
+
const out = {};
|
|
96
|
+
for (const k of Object.keys(v)) {
|
|
97
|
+
let item;
|
|
98
|
+
try {
|
|
99
|
+
item = jsonSnapshot(ownData(v, k), depth + 1, ctx);
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
if (e === CODED_DETAIL_OVER_BUDGET)
|
|
103
|
+
throw e;
|
|
104
|
+
item = undefined;
|
|
105
|
+
}
|
|
106
|
+
if (item !== undefined)
|
|
107
|
+
Object.defineProperty(out, k, { value: item, enumerable: true, writable: false, configurable: false });
|
|
108
|
+
}
|
|
109
|
+
return Object.freeze(out);
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
ctx.path.delete(v);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const isCount = (v) => typeof v === 'number' && Number.isInteger(v) && v >= 0;
|
|
116
|
+
function outputLimitOf(d) {
|
|
117
|
+
try {
|
|
118
|
+
const v = ownData(d, 'outputLimit');
|
|
119
|
+
if (!isPlainRecord(v))
|
|
120
|
+
return undefined;
|
|
121
|
+
const capStop = ownData(v, 'capStop');
|
|
122
|
+
if (typeof capStop !== 'boolean')
|
|
123
|
+
return undefined;
|
|
124
|
+
const outputTokens = ownData(v, 'outputTokens');
|
|
125
|
+
const capTokens = ownData(v, 'capTokens');
|
|
126
|
+
return { capStop, ...(isCount(outputTokens) ? { outputTokens } : {}), ...(isCount(capTokens) ? { capTokens } : {}) };
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function requestRouteOf(d) {
|
|
133
|
+
try {
|
|
134
|
+
const v = ownData(d, 'route');
|
|
135
|
+
if (!isPlainRecord(v))
|
|
136
|
+
return undefined;
|
|
137
|
+
const credentialSource = str(ownData(v, 'credentialSource'));
|
|
138
|
+
const root = str(ownData(v, 'root'));
|
|
139
|
+
if (credentialSource === undefined || root === undefined)
|
|
140
|
+
return undefined;
|
|
141
|
+
const carrier = str(ownData(v, 'carrier'));
|
|
142
|
+
const carrierBag = str(ownData(v, 'carrierBag'));
|
|
143
|
+
return { credentialSource, ...(carrier !== undefined ? { carrier } : {}), ...(carrierBag !== undefined ? { carrierBag } : {}), root };
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
32
149
|
function failureDetailOf(cause) {
|
|
33
150
|
try {
|
|
34
151
|
const own = ownValueOf;
|
|
@@ -38,21 +155,59 @@ function failureDetailOf(cause) {
|
|
|
38
155
|
const kind = str(own(v, 'kind'));
|
|
39
156
|
if (kind === undefined)
|
|
40
157
|
return undefined;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
158
|
+
if (kind === PROVIDER_REJECTED_DETAIL_KIND) {
|
|
159
|
+
const rawStatus = own(v, 'status');
|
|
160
|
+
const status = typeof rawStatus === 'number' && Number.isInteger(rawStatus) && rawStatus >= 400 && rawStatus <= 599 ? rawStatus : undefined;
|
|
161
|
+
if (status === undefined)
|
|
162
|
+
return undefined;
|
|
163
|
+
const code = str(own(v, 'code'));
|
|
164
|
+
const providerCondition = optionalDetailString(v, 'providerCondition');
|
|
165
|
+
const providerConditionSource = optionalDetailString(v, 'providerConditionSource');
|
|
166
|
+
let providerResetAtMs;
|
|
167
|
+
try {
|
|
168
|
+
const r = ownData(v, 'providerResetAtMs');
|
|
169
|
+
providerResetAtMs = typeof r === 'number' && Number.isFinite(r) && r >= 0 ? r : undefined;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
providerResetAtMs = undefined;
|
|
173
|
+
}
|
|
174
|
+
const route = requestRouteOf(v);
|
|
175
|
+
return {
|
|
176
|
+
kind: PROVIDER_REJECTED_DETAIL_KIND,
|
|
177
|
+
status,
|
|
178
|
+
...(code !== undefined ? { code } : {}),
|
|
179
|
+
...(providerCondition !== undefined ? { providerCondition } : {}),
|
|
180
|
+
...(providerConditionSource !== undefined ? { providerConditionSource } : {}),
|
|
181
|
+
...(providerResetAtMs !== undefined ? { providerResetAtMs } : {}),
|
|
182
|
+
...(route !== undefined ? { route } : {}),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (kind === CODED_DETAIL_KIND) {
|
|
186
|
+
const inner = ownData(v, 'detail');
|
|
187
|
+
if (!isPlainRecord(inner))
|
|
188
|
+
return undefined;
|
|
189
|
+
let snap;
|
|
190
|
+
try {
|
|
191
|
+
snap = jsonSnapshot(inner, 0, { budget: CODED_DETAIL_BUDGET, path: new Set() });
|
|
192
|
+
}
|
|
193
|
+
catch (e) {
|
|
194
|
+
if (e === CODED_DETAIL_OVER_BUDGET)
|
|
195
|
+
return undefined;
|
|
196
|
+
throw e;
|
|
197
|
+
}
|
|
198
|
+
if (snap === undefined || snap === null || typeof snap !== 'object' || Array.isArray(snap))
|
|
199
|
+
return undefined;
|
|
200
|
+
return { kind: CODED_DETAIL_KIND, detail: snap };
|
|
201
|
+
}
|
|
202
|
+
if (kind === MODEL_OUTPUT_INVALID_DETAIL_KIND) {
|
|
203
|
+
const c = ownData(v, 'cause');
|
|
204
|
+
const cause = MODEL_OUTPUT_INVALID_CAUSES.find((w) => w === c);
|
|
205
|
+
if (cause === undefined)
|
|
206
|
+
return undefined;
|
|
207
|
+
const outputLimit = outputLimitOf(v);
|
|
208
|
+
return { kind: MODEL_OUTPUT_INVALID_DETAIL_KIND, cause, ...(outputLimit !== undefined ? { outputLimit } : {}) };
|
|
209
|
+
}
|
|
210
|
+
return { kind: 'unrecognized', word: kind };
|
|
56
211
|
}
|
|
57
212
|
catch {
|
|
58
213
|
return undefined;
|
package/dist/sdkWireTransit.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { AgentClient } from '@sema-agent/sdk';
|
|
2
2
|
export { isApprovalRequestFrameV1, isApprovalRevokeFrameV1 } from '@sema-agent/sdk';
|
|
3
3
|
export { pushSessionBundle, pullSessionBundle, importSessionBundle, APIError } from '@sema-agent/sdk';
|
|
4
|
-
export
|
|
4
|
+
export { APPROVAL_DECIDE_GATE_KINDS, PLAN_REVIEW_GATE_KINDS } from '@sema-agent/sdk';
|
|
5
|
+
export type { TaskRequest, SessionPermissionRules, SemaSettings, SkillSpec, AgentEvent, RunReceipt, CancelAck, RunRecord, ToolApprovalRespondAck, FleetTaskRow, FleetWorkflowRow, ApprovalCard, ApprovalRequestFrame, ApprovalRiskAxes, AskDecisionAck, AskDecisionBody, PolicyInfo, CcImportLayer, CcImportPrepareResult, CcImportRedeemResult, CcImportSettingsLayer, CcImportSkippedRule, PersistedRule, RuleRevokeRequest, RuleRevokeResult, ApprovalDecideGateKind, PlanReviewGateKind, } from '@sema-agent/sdk';
|
package/dist/sdkWireTransit.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { AgentClient } from '@sema-agent/sdk';
|
|
2
2
|
export { isApprovalRequestFrameV1, isApprovalRevokeFrameV1 } from '@sema-agent/sdk';
|
|
3
3
|
export { pushSessionBundle, pullSessionBundle, importSessionBundle, APIError } from '@sema-agent/sdk';
|
|
4
|
+
export { APPROVAL_DECIDE_GATE_KINDS, PLAN_REVIEW_GATE_KINDS } from '@sema-agent/sdk';
|
|
@@ -28,7 +28,6 @@ export function projectSealedKeyCapability(caps) {
|
|
|
28
28
|
const reader = createEngineCapReader({
|
|
29
29
|
name: 'sealedKey',
|
|
30
30
|
project: projectSealedKeyCapability,
|
|
31
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
32
31
|
});
|
|
33
32
|
export function observedSealedKey(baseUrl = engineWireTarget()?.baseUrl) {
|
|
34
33
|
return reader.observed(baseUrl);
|
package/dist/seatContract.d.ts
CHANGED
|
@@ -68,7 +68,7 @@ export interface ToolPermissionRequest {
|
|
|
68
68
|
ruleOffersAbsence?: string;
|
|
69
69
|
askClass?: string;
|
|
70
70
|
classes?: readonly string[];
|
|
71
|
-
|
|
71
|
+
sessionRow?: true;
|
|
72
72
|
}
|
|
73
73
|
declare const SEAT_EVENT_TYPE_TUPLE: readonly ["start", "close", "session_updated", "message", "stream_event", "chrome_event", "error", "tool_permission_resolved"];
|
|
74
74
|
export type SeatEventType = (typeof SEAT_EVENT_TYPE_TUPLE)[number];
|
|
@@ -343,7 +343,7 @@ export declare const SEAT_METHOD_NAMES: readonly ["start", "sendMessage", "inter
|
|
|
343
343
|
export declare const SEAT_STORE_PROPS: readonly ["sessionsStateStore", "focusedSessionStateStore", "settingsStateStore", "seatCapabilitiesStateStore"];
|
|
344
344
|
export declare const SEAT_EVENT_METHOD_NAMES: readonly ["onEvent", "onToolPermissionRequest"];
|
|
345
345
|
export declare const LOCAL_SESSION_EVENT_KEYS: readonly ["type", "sessionId", "message", "messages", "error", "errorCategory", "code", "request", "data", "sources", "permissionMode", "session", "userMessageUuid", "hasPreClearSession", "requestId", "outcome", "parked", "chrome"];
|
|
346
|
-
export declare const TOOL_PERMISSION_REQUEST_KEYS: readonly ["requestId", "sessionId", "toolName", "toolCallId", "input", "message", "toctouBinding", "createdAtMs", "governanceForced", "delegation", "mandated", "mandate", "origin", "ruleOffersAbsence", "askClass", "classes", "
|
|
346
|
+
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"];
|
|
347
347
|
export declare const LOCAL_SESSION_RECORD_KEYS: readonly ["sessionId", "engineSessionId", "model", "title", "cwd", "isRunning", "createdAt", "lastActivityAt", "queuedMessages", "parked", "pinned"];
|
|
348
348
|
export declare const SEND_MESSAGE_REQUEST_KEYS: readonly ["sessionId", "text", "model", "userMessageUuid", "permissionMode", "attachmentIds", "reasoningEffort", "retainBackgroundProcesses", "forwardSubagentEvents", "retainSubagentSessions", "settings", "scenario", "rewind"];
|
|
349
349
|
export declare const SEAT_SEND_MESSAGE_KEY_ORIGINS: {
|
|
@@ -426,8 +426,8 @@ export declare const SEAT_VALIDATOR_KEY_COVERAGE: {
|
|
|
426
426
|
readonly key: "classes";
|
|
427
427
|
readonly why: "与 askClass 同一对(CC-284),同在同缺、同一只成对窄读(非空、每员非空串、无重复、首员等于 askClass;开集、原样顺序);座位门不设第二判官,理由同 askClass。";
|
|
428
428
|
}, {
|
|
429
|
-
readonly key: "
|
|
430
|
-
readonly why: "
|
|
429
|
+
readonly key: "sessionRow";
|
|
430
|
+
readonly why: "放宽方向的展示位(CC-699),判官在过境口 toolPermissionRequestAskBits(card, requestId):卡上「本会话放行」判官 standingRowsOf 的会话行同一前提 ∧ 本请求 requestId 的域带得走(live: / durable:),严格 true 才上座、永不铸 false;座位门不设第二判官,理由同 mandated(为一个展示位拒掉整条 request = 把安全 ask 丢给引擎 TTL deny)。消费端 `=== true` 才渲「本会话放行」,其余(缺席 / 坏形)一律不渲 —— 缺席是闭合失败,不是「没说就照渲」。不经过境口自铸座位请求的宿主拿不到这一位,座位卡就不给那一档。";
|
|
431
431
|
}, {
|
|
432
432
|
readonly key: "ruleOffersAbsence";
|
|
433
433
|
readonly why: "喂强制判据口 approvalIsMandated 的位(CC-203;寄存行那条腿的强制只以缺席词 mandated 表达),按开集读(非空串原文字节、词表不校);权威窄读在卡口与过境口,座位门不设第二判官,理由同 mandated。坏形读成缺席 ⇒ 这一路不判强制(放宽方向:寄存行上的强制就丢了;另两路 mandated / mandate 照判);表外串只是不等于 mandated。不经过境口自铸座位请求的宿主要自己按同一把窄读。";
|
|
@@ -454,6 +454,9 @@ export declare const SEAT_VALIDATOR_KEY_COVERAGE: {
|
|
|
454
454
|
readonly unchecked: readonly [{
|
|
455
455
|
readonly key: "droppedEntries";
|
|
456
456
|
readonly why: "诊断面(哪些目录条目没被引擎收下),三态读法归 droppedModelEntriesOf(含坏形 malformed);出站门为它拒掉整份目录 = 选单为一行诊断整个消失。";
|
|
457
|
+
}, {
|
|
458
|
+
readonly key: "candidateRejected";
|
|
459
|
+
readonly why: "诊断面(0.97.0 CC-715;当前配置是候选被整拒后回落的那一份),三态读法归 modelCandidateRejectedOf(含坏形 unreadable);出站门为它拒掉整份目录 = 选单为一行诊断整个消失。";
|
|
457
460
|
}];
|
|
458
461
|
};
|
|
459
462
|
readonly SendMessageRequest: {
|
package/dist/seatContract.js
CHANGED
|
@@ -33,6 +33,16 @@ const ownItems = (a) => {
|
|
|
33
33
|
out.push(own(a, String(i)));
|
|
34
34
|
return out;
|
|
35
35
|
};
|
|
36
|
+
const sendableKeysOf = (v) => {
|
|
37
|
+
const keys = [];
|
|
38
|
+
for (const k of Reflect.ownKeys(v)) {
|
|
39
|
+
if (typeof k !== "string")
|
|
40
|
+
continue;
|
|
41
|
+
own(v, k);
|
|
42
|
+
keys.push(k);
|
|
43
|
+
}
|
|
44
|
+
return keys;
|
|
45
|
+
};
|
|
36
46
|
const firstAccessorPath = (root) => {
|
|
37
47
|
const seen = new Set();
|
|
38
48
|
const stack = [[root, ""]];
|
|
@@ -592,9 +602,9 @@ const checkLiveModelCatalog = seatCheck((v) => {
|
|
|
592
602
|
return true;
|
|
593
603
|
});
|
|
594
604
|
const checkSeatRewindIntent = seatCheck((v) => {
|
|
595
|
-
if (!
|
|
596
|
-
return bad("rewind must be
|
|
597
|
-
for (const k of
|
|
605
|
+
if (!isPlainRecord(v))
|
|
606
|
+
return bad("rewind must be a plain object {mode, targetMessageUuid}");
|
|
607
|
+
for (const k of sendableKeysOf(v)) {
|
|
598
608
|
if (!inTuple(SEAT_REWIND_INTENT_KEYS, k))
|
|
599
609
|
return bad(`unknown key (closed shape: ${SEAT_REWIND_INTENT_KEYS.join(", ")})`, k);
|
|
600
610
|
}
|
|
@@ -608,9 +618,9 @@ const checkSeatRewindIntent = seatCheck((v) => {
|
|
|
608
618
|
return true;
|
|
609
619
|
});
|
|
610
620
|
const checkSeatTurnSettings = seatCheck((v) => {
|
|
611
|
-
if (!
|
|
612
|
-
return bad("settings must be
|
|
613
|
-
for (const k of
|
|
621
|
+
if (!isPlainRecord(v))
|
|
622
|
+
return bad("settings must be a plain object");
|
|
623
|
+
for (const k of sendableKeysOf(v)) {
|
|
614
624
|
if (!inTuple(SEAT_TURN_SETTINGS_KEYS, k)) {
|
|
615
625
|
const host = Object.hasOwn(SEAT_TURN_SETTINGS_ORIGINS, k);
|
|
616
626
|
return bad(host ? "this settings key is supplied by the host, not carried by the seat" : `unknown key (closed shape: ${SEAT_TURN_SETTINGS_KEYS.join(", ")})`, k);
|
|
@@ -624,9 +634,9 @@ const checkSeatTurnSettings = seatCheck((v) => {
|
|
|
624
634
|
const checkRetainSubagentSessions = seatCheck((v) => {
|
|
625
635
|
if (typeof v === "boolean")
|
|
626
636
|
return true;
|
|
627
|
-
if (!
|
|
628
|
-
return bad("retainSubagentSessions must be a boolean or {ttlMs?, max?}");
|
|
629
|
-
for (const k of
|
|
637
|
+
if (!isPlainRecord(v))
|
|
638
|
+
return bad("retainSubagentSessions must be a boolean or a plain object {ttlMs?, max?}");
|
|
639
|
+
for (const k of sendableKeysOf(v)) {
|
|
630
640
|
if (k !== "ttlMs" && k !== "max")
|
|
631
641
|
return bad("unknown key (closed shape: ttlMs, max)", k);
|
|
632
642
|
const n = own(v, k);
|
|
@@ -637,13 +647,13 @@ const checkRetainSubagentSessions = seatCheck((v) => {
|
|
|
637
647
|
});
|
|
638
648
|
export function checkSendMessageRequest(v) {
|
|
639
649
|
try {
|
|
640
|
-
if (!
|
|
641
|
-
return bad("sendMessage request is not
|
|
650
|
+
if (!isPlainRecord(v))
|
|
651
|
+
return bad("sendMessage request is not a plain object");
|
|
642
652
|
const at = firstAccessorPath(v);
|
|
643
653
|
if (at !== undefined)
|
|
644
654
|
return bad(NOT_PLAIN_DATA, at);
|
|
645
|
-
const body =
|
|
646
|
-
for (const k of
|
|
655
|
+
const body = Object.create(null);
|
|
656
|
+
for (const k of sendableKeysOf(v)) {
|
|
647
657
|
if (!inTuple(SEND_MESSAGE_REQUEST_KEYS, k))
|
|
648
658
|
return bad(`unknown key (closed shape: ${SEND_MESSAGE_REQUEST_KEYS.join(", ")})`, k);
|
|
649
659
|
body[k] = own(v, k);
|
|
@@ -703,10 +713,10 @@ export function isSendMessageRequest(v) {
|
|
|
703
713
|
return checkSendMessageRequest(v) === true;
|
|
704
714
|
}
|
|
705
715
|
export const checkSessionRowPatchRequest = seatCheck((v) => {
|
|
706
|
-
if (!
|
|
707
|
-
return bad("patchSession request is not
|
|
708
|
-
const body =
|
|
709
|
-
for (const k of
|
|
716
|
+
if (!isPlainRecord(v))
|
|
717
|
+
return bad("patchSession request is not a plain object");
|
|
718
|
+
const body = Object.create(null);
|
|
719
|
+
for (const k of sendableKeysOf(v)) {
|
|
710
720
|
if (!inTuple(SESSION_ROW_PATCH_REQUEST_KEYS, k))
|
|
711
721
|
return bad(`unknown key (closed shape: ${SESSION_ROW_PATCH_REQUEST_KEYS.join(", ")})`, k);
|
|
712
722
|
body[k] = own(v, k);
|
|
@@ -959,7 +969,7 @@ export const TOOL_PERMISSION_REQUEST_KEYS = [
|
|
|
959
969
|
"ruleOffersAbsence",
|
|
960
970
|
"askClass",
|
|
961
971
|
"classes",
|
|
962
|
-
"
|
|
972
|
+
"sessionRow",
|
|
963
973
|
];
|
|
964
974
|
export const LOCAL_SESSION_RECORD_KEYS = [
|
|
965
975
|
"sessionId",
|
|
@@ -1058,8 +1068,8 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1058
1068
|
why: "与 askClass 同一对(CC-284),同在同缺、同一只成对窄读(非空、每员非空串、无重复、首员等于 askClass;开集、原样顺序);座位门不设第二判官,理由同 askClass。",
|
|
1059
1069
|
},
|
|
1060
1070
|
{
|
|
1061
|
-
key: "
|
|
1062
|
-
why: "
|
|
1071
|
+
key: "sessionRow",
|
|
1072
|
+
why: "放宽方向的展示位(CC-699),判官在过境口 toolPermissionRequestAskBits(card, requestId):卡上「本会话放行」判官 standingRowsOf 的会话行同一前提 ∧ 本请求 requestId 的域带得走(live: / durable:),严格 true 才上座、永不铸 false;座位门不设第二判官,理由同 mandated(为一个展示位拒掉整条 request = 把安全 ask 丢给引擎 TTL deny)。消费端 `=== true` 才渲「本会话放行」,其余(缺席 / 坏形)一律不渲 —— 缺席是闭合失败,不是「没说就照渲」。不经过境口自铸座位请求的宿主拿不到这一位,座位卡就不给那一档。",
|
|
1063
1073
|
},
|
|
1064
1074
|
{
|
|
1065
1075
|
key: "ruleOffersAbsence",
|
|
@@ -1110,6 +1120,10 @@ export const SEAT_VALIDATOR_KEY_COVERAGE = {
|
|
|
1110
1120
|
key: "droppedEntries",
|
|
1111
1121
|
why: "诊断面(哪些目录条目没被引擎收下),三态读法归 droppedModelEntriesOf(含坏形 malformed);出站门为它拒掉整份目录 = 选单为一行诊断整个消失。",
|
|
1112
1122
|
},
|
|
1123
|
+
{
|
|
1124
|
+
key: "candidateRejected",
|
|
1125
|
+
why: "诊断面(0.97.0 CC-715;当前配置是候选被整拒后回落的那一份),三态读法归 modelCandidateRejectedOf(含坏形 unreadable);出站门为它拒掉整份目录 = 选单为一行诊断整个消失。",
|
|
1126
|
+
},
|
|
1113
1127
|
],
|
|
1114
1128
|
},
|
|
1115
1129
|
SendMessageRequest: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
|
-
import { createEngineCapReader } from './engineCapReader.js';
|
|
2
|
+
import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
3
3
|
import { ownDataField } from './ownKey.js';
|
|
4
4
|
export function projectSessionPolicyCapability(caps) {
|
|
5
5
|
try {
|
|
@@ -20,7 +20,6 @@ export function projectSessionPolicyCapability(caps) {
|
|
|
20
20
|
const reader = createEngineCapReader({
|
|
21
21
|
name: 'sessionPolicy',
|
|
22
22
|
project: projectSessionPolicyCapability,
|
|
23
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
24
23
|
});
|
|
25
24
|
export function noteEngineCapsForSessionPolicy(baseUrl, caps, opts) {
|
|
26
25
|
reader.note(baseUrl, caps, opts);
|
|
@@ -37,6 +36,8 @@ export function sessionPolicyFaceAvailable(reading) {
|
|
|
37
36
|
}
|
|
38
37
|
export function sessionPolicyDoctorDetail(reading) {
|
|
39
38
|
switch (reading.kind) {
|
|
39
|
+
case 'unreadable':
|
|
40
|
+
return unreadableReadingDetail('per-session rule face');
|
|
40
41
|
case 'unobserved':
|
|
41
42
|
return 'per-session rule face not observed — the engine reports it on /v1/capabilities (sessionPolicy); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
|
|
42
43
|
case 'not_reported':
|
|
@@ -17,7 +17,6 @@ export function projectSessionReadRedactionCapability(caps) {
|
|
|
17
17
|
const reader = createEngineCapReader({
|
|
18
18
|
name: 'sessionReadRedaction',
|
|
19
19
|
project: projectSessionReadRedactionCapability,
|
|
20
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
21
20
|
});
|
|
22
21
|
export function observedSessionReadRedaction(baseUrl = engineWireTarget()?.baseUrl) {
|
|
23
22
|
return reader.observed(baseUrl);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
|
-
import { createEngineCapReader } from './engineCapReader.js';
|
|
2
|
+
import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
3
3
|
import { ownDataField } from './ownKey.js';
|
|
4
4
|
export function projectSessionSyncFileHistoryCapability(caps) {
|
|
5
5
|
try {
|
|
@@ -19,7 +19,6 @@ export function projectSessionSyncFileHistoryCapability(caps) {
|
|
|
19
19
|
const reader = createEngineCapReader({
|
|
20
20
|
name: 'sessionSyncFileHistory',
|
|
21
21
|
project: projectSessionSyncFileHistoryCapability,
|
|
22
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
23
22
|
});
|
|
24
23
|
export function noteEngineCapsForSessionSyncFileHistory(baseUrl, caps, opts) {
|
|
25
24
|
reader.note(baseUrl, caps, opts);
|
|
@@ -36,6 +35,8 @@ export function sessionSyncFileHistoryAvailable(reading) {
|
|
|
36
35
|
}
|
|
37
36
|
export function sessionSyncFileHistoryDoctorDetail(reading) {
|
|
38
37
|
switch (reading.kind) {
|
|
38
|
+
case 'unreadable':
|
|
39
|
+
return unreadableReadingDetail('session-sync file history');
|
|
39
40
|
case 'unobserved':
|
|
40
41
|
return 'session-sync file history not observed — the engine reports it on /v1/capabilities (sessionSyncFileHistory); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
|
|
41
42
|
case 'not_reported':
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
2
|
-
import { createEngineCapReader } from './engineCapReader.js';
|
|
2
|
+
import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
3
3
|
import { ownDataField } from './ownKey.js';
|
|
4
4
|
export function projectSkillToolListsCapability(caps) {
|
|
5
5
|
try {
|
|
@@ -19,7 +19,6 @@ export function projectSkillToolListsCapability(caps) {
|
|
|
19
19
|
const reader = createEngineCapReader({
|
|
20
20
|
name: 'skillToolLists',
|
|
21
21
|
project: projectSkillToolListsCapability,
|
|
22
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
23
22
|
});
|
|
24
23
|
export function noteEngineCapsForSkillToolLists(baseUrl, caps, opts) {
|
|
25
24
|
reader.note(baseUrl, caps, opts);
|
|
@@ -36,6 +35,8 @@ export function skillToolListsAvailable(reading) {
|
|
|
36
35
|
}
|
|
37
36
|
export function skillToolListsDoctorDetail(reading) {
|
|
38
37
|
switch (reading.kind) {
|
|
38
|
+
case 'unreadable':
|
|
39
|
+
return unreadableReadingDetail('skill tool lists');
|
|
39
40
|
case 'unobserved':
|
|
40
41
|
return 'skill tool lists not observed — the engine reports it on /v1/capabilities (skillToolLists); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
|
|
41
42
|
case 'not_reported':
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
2
2
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
3
|
-
import { storeSeatOf, createEngineCapReader } from './engineCapReader.js';
|
|
3
|
+
import { storeSeatOf, createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
4
4
|
import { ownDataField } from './ownKey.js';
|
|
5
5
|
export function projectSqlEngineCapability(caps) {
|
|
6
6
|
try {
|
|
@@ -16,7 +16,7 @@ export function projectSqlEngineCapability(caps) {
|
|
|
16
16
|
return { kind: 'none' };
|
|
17
17
|
return projectSqlEngineView(nested);
|
|
18
18
|
}
|
|
19
|
-
return { kind: 'not_reported' };
|
|
19
|
+
return seat.kind === 'absent' ? { kind: 'not_reported' } : undefined;
|
|
20
20
|
}
|
|
21
21
|
catch {
|
|
22
22
|
return undefined;
|
|
@@ -39,7 +39,6 @@ function projectSqlEngineView(sql) {
|
|
|
39
39
|
const reader = createEngineCapReader({
|
|
40
40
|
name: 'sql',
|
|
41
41
|
project: projectSqlEngineCapability,
|
|
42
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
43
42
|
});
|
|
44
43
|
export function noteEngineCapsForSqlEngine(baseUrl, caps, opts) {
|
|
45
44
|
reader.note(baseUrl, caps, opts);
|
|
@@ -53,6 +52,8 @@ function cleanSqlDetailScalar(v) {
|
|
|
53
52
|
}
|
|
54
53
|
export function sqlEngineDoctorDetail(reading) {
|
|
55
54
|
switch (reading.kind) {
|
|
55
|
+
case 'unreadable':
|
|
56
|
+
return unreadableReadingDetail();
|
|
56
57
|
case 'unobserved':
|
|
57
58
|
return ('not observed — the engine reports it on /v1/capabilities; this process has no usable ' +
|
|
58
59
|
'capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
2
2
|
import { engineWireTarget } from './engineWireTarget.js';
|
|
3
|
-
import { createEngineCapReader } from './engineCapReader.js';
|
|
3
|
+
import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
|
|
4
4
|
import { ownDataField } from './ownKey.js';
|
|
5
5
|
export function projectSteerPriorityCapability(caps) {
|
|
6
6
|
try {
|
|
@@ -25,7 +25,6 @@ export function projectSteerPriorityCapability(caps) {
|
|
|
25
25
|
const reader = createEngineCapReader({
|
|
26
26
|
name: 'fleet.steerPriority',
|
|
27
27
|
project: projectSteerPriorityCapability,
|
|
28
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
29
28
|
});
|
|
30
29
|
export function noteEngineCapsForSteerPriority(baseUrl, caps, opts) {
|
|
31
30
|
reader.note(baseUrl, caps, opts);
|
|
@@ -65,6 +64,8 @@ export function steerPriorityDoctorDetail(reading) {
|
|
|
65
64
|
if (kind === 'not_reported') {
|
|
66
65
|
return 'steer priority not reported by this engine — its capabilities reading carries no fleet.steerPriority (the fleet face is not reported, or the face carries no such field; this client cannot tell which), so a "now" or "later" steer is not sent (steers without a priority work as before)';
|
|
67
66
|
}
|
|
67
|
+
if (kind === 'unreadable')
|
|
68
|
+
return unreadableReadingDetail('steer priority');
|
|
68
69
|
if (kind !== 'present' || typeof word !== 'string' || word.length === 0)
|
|
69
70
|
return unobserved;
|
|
70
71
|
if (word === 'engine')
|