@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
|
@@ -3,6 +3,7 @@ import { toCappedSpec } from './skillsWireCaps.js';
|
|
|
3
3
|
import { TIER_ORDER } from './model/tierVocabulary.js';
|
|
4
4
|
import { SETTINGS_NARROW_AT_MENTION } from './generated/settingsSchemaFns.js';
|
|
5
5
|
import { modelsPolicyOf } from './model/modelsPolicy.js';
|
|
6
|
+
import { guardedRead, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
|
|
6
7
|
import { SETTINGS_BUDGET_NUMBER_KEYS, SETTINGS_BUDGET_PER_MODEL_NUMBER_KEYS, SETTINGS_BUDGET_STRING_KEYS, SETTINGS_TIER_GROUP_NAME_RE, } from './generated/settingsSchemaTables.js';
|
|
7
8
|
const asRec = (v) => (typeof v === 'object' && v !== null && !Array.isArray(v) ? v : undefined);
|
|
8
9
|
const asArr = (v) => (Array.isArray(v) ? v : []);
|
|
@@ -96,6 +97,7 @@ export function cloudMcpToSpecs(servers, env) {
|
|
|
96
97
|
...(allowTools.length > 0 ? { allowTools } : {}),
|
|
97
98
|
...(s.elicitation === true ? { elicitation: true } : {}),
|
|
98
99
|
...(s.toolFaces !== undefined ? { toolFaces: s.toolFaces } : {}),
|
|
100
|
+
...(s.toolAxes !== undefined ? { toolAxes: s.toolAxes } : {}),
|
|
99
101
|
});
|
|
100
102
|
}
|
|
101
103
|
return { specs, missingEnv: [...new Set(missingEnv)], droppedServers };
|
|
@@ -140,6 +142,9 @@ const TIER_GROUP_NAME = SETTINGS_TIER_GROUP_NAME_RE;
|
|
|
140
142
|
const setOwn = (o, k, v) => {
|
|
141
143
|
Object.defineProperty(o, k, { value: v, enumerable: true, writable: true, configurable: true });
|
|
142
144
|
};
|
|
145
|
+
function modelsDocPositionOf(m, key) {
|
|
146
|
+
return guardedRead(() => (Object.hasOwn(m, key) ? { value: m[key] } : 'absent')) ?? 'unreadable';
|
|
147
|
+
}
|
|
143
148
|
function modelsDocOf(models, opts) {
|
|
144
149
|
const m = asRec(models);
|
|
145
150
|
if (!m || !Array.isArray(m.models))
|
|
@@ -169,6 +174,7 @@ function modelsDocOf(models, opts) {
|
|
|
169
174
|
};
|
|
170
175
|
const refOf = (v) => (typeof v === 'string' && v !== '' ? { target: v } : {});
|
|
171
176
|
const reasonOf = (v) => typeof v === 'string' && v !== '' ? (rawNames.has(v) ? 'rejected' : 'dangling') : 'unreadable';
|
|
177
|
+
const modelRefVerdict = (v) => names.has(v) ? (accept === undefined ? 'unvouched' : 'accepted') : reasonOf(v);
|
|
172
178
|
let written = stripped;
|
|
173
179
|
let catalogKept = false;
|
|
174
180
|
if (acceptedFlags && stripped.length > 0) {
|
|
@@ -191,41 +197,57 @@ function modelsDocOf(models, opts) {
|
|
|
191
197
|
drop({ key: 'roles', at: 'default', reason: 'unreadable' });
|
|
192
198
|
const dm = policy.defaultModel;
|
|
193
199
|
let defaultRole;
|
|
194
|
-
|
|
195
|
-
|
|
200
|
+
let defaultWinner;
|
|
201
|
+
if (dm !== undefined && dm.from === 'default') {
|
|
202
|
+
const verdict = modelRefVerdict(dm.name);
|
|
203
|
+
if (verdict === 'accepted')
|
|
196
204
|
defaultRole = { model: dm.name };
|
|
197
205
|
else
|
|
198
|
-
drop({ key: 'roles', at: 'default', target: dm.name, reason:
|
|
206
|
+
drop({ key: 'roles', at: 'default', target: dm.name, reason: verdict });
|
|
207
|
+
if (verdict === 'accepted' || verdict === 'unvouched')
|
|
208
|
+
defaultWinner = dm.name;
|
|
199
209
|
}
|
|
200
210
|
const roles = asRec(m.roles);
|
|
201
211
|
const keptRoles = {};
|
|
212
|
+
let sameModelDefaultRole;
|
|
202
213
|
for (const [role, t] of Object.entries(roles ?? {})) {
|
|
203
|
-
if (role === 'default' &&
|
|
204
|
-
|
|
214
|
+
if (role === 'default' && defaultWinner !== undefined) {
|
|
215
|
+
const tr = asRec(t);
|
|
216
|
+
let model;
|
|
217
|
+
let snapshot;
|
|
205
218
|
try {
|
|
206
|
-
|
|
219
|
+
model = tr && Object.hasOwn(tr, 'model') ? tr.model : undefined;
|
|
220
|
+
if (tr !== undefined && typeof model === 'string' && model === defaultWinner) {
|
|
221
|
+
snapshot = {};
|
|
222
|
+
for (const [k, v] of Object.entries(tr))
|
|
223
|
+
setOwn(snapshot, k, v);
|
|
224
|
+
setOwn(snapshot, 'model', model);
|
|
225
|
+
}
|
|
207
226
|
}
|
|
208
227
|
catch {
|
|
209
|
-
|
|
228
|
+
model = undefined;
|
|
229
|
+
snapshot = undefined;
|
|
210
230
|
}
|
|
211
|
-
if (
|
|
212
|
-
|
|
213
|
-
|
|
231
|
+
if (snapshot !== undefined)
|
|
232
|
+
sameModelDefaultRole = snapshot;
|
|
233
|
+
else
|
|
214
234
|
drop({ key: 'roles', at: 'default', ...refOf(model), reason: 'shadowed' });
|
|
215
|
-
}
|
|
216
235
|
continue;
|
|
217
236
|
}
|
|
218
237
|
const tr = asRec(t);
|
|
219
238
|
const model = tr && Object.hasOwn(tr, 'model') ? tr.model : undefined;
|
|
220
|
-
if (typeof model === 'string'
|
|
221
|
-
|
|
222
|
-
|
|
239
|
+
if (typeof model === 'string') {
|
|
240
|
+
const verdict = modelRefVerdict(model);
|
|
241
|
+
if (verdict !== 'accepted') {
|
|
242
|
+
drop({ key: 'roles', at: role, ...refOf(model), reason: verdict });
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
223
245
|
}
|
|
224
246
|
setOwn(keptRoles, role, t);
|
|
225
247
|
}
|
|
226
248
|
const rolesOut = {};
|
|
227
249
|
if (defaultRole !== undefined)
|
|
228
|
-
setOwn(rolesOut, 'default', defaultRole);
|
|
250
|
+
setOwn(rolesOut, 'default', sameModelDefaultRole ?? defaultRole);
|
|
229
251
|
else if (Object.hasOwn(keptRoles, 'default'))
|
|
230
252
|
setOwn(rolesOut, 'default', keptRoles.default);
|
|
231
253
|
for (const [k, v] of Object.entries(keptRoles))
|
|
@@ -260,53 +282,64 @@ function modelsDocOf(models, opts) {
|
|
|
260
282
|
}
|
|
261
283
|
}
|
|
262
284
|
let groupNames;
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
285
|
+
if (accept) {
|
|
286
|
+
const tg = modelsDocPositionOf(m, 'tierGroups');
|
|
287
|
+
const atg = modelsDocPositionOf(m, 'activeTierGroup');
|
|
288
|
+
const tgValue = typeof tg === 'object' ? tg.value : undefined;
|
|
289
|
+
const rawGroupNames = new Set((Array.isArray(tgValue) ? tgValue : []).map((g) => asStr(asRec(g)?.name)).filter((n) => !!n));
|
|
290
|
+
if (tg === 'unreadable') {
|
|
291
|
+
drop({ key: 'tierGroups', at: 'models', reason: 'unreadable' });
|
|
267
292
|
}
|
|
268
|
-
else {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
293
|
+
else if (tg !== 'absent') {
|
|
294
|
+
if (!Array.isArray(tgValue)) {
|
|
295
|
+
drop({ key: 'tierGroups', reason: 'unreadable' });
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
const groups = [];
|
|
299
|
+
groupNames = new Set();
|
|
300
|
+
for (const raw of tgValue) {
|
|
301
|
+
const g = asRec(raw);
|
|
302
|
+
const name = g ? asStr(g.name) : undefined;
|
|
303
|
+
if (!g || !name || !TIER_GROUP_NAME.test(name)) {
|
|
304
|
+
drop({ key: 'tierGroups', ...(name ? { at: name } : {}), reason: 'unreadable' });
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (groupNames.has(name)) {
|
|
308
|
+
drop({ key: 'tierGroups', at: name, reason: 'duplicate' });
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
groupNames.add(name);
|
|
312
|
+
const tiers = {};
|
|
313
|
+
if (Object.hasOwn(g, 'tiers')) {
|
|
314
|
+
const t = asRec(g.tiers);
|
|
315
|
+
if (!t)
|
|
316
|
+
drop({ key: 'tierGroups', at: `${name}.tiers`, reason: 'unreadable' });
|
|
317
|
+
else {
|
|
318
|
+
for (const [tier, model] of Object.entries(t)) {
|
|
319
|
+
if (!TIER_WORDS.includes(tier))
|
|
320
|
+
drop({ key: 'tierGroups', at: `${name}.${tier}`, ...refOf(model), reason: 'unsupported' });
|
|
321
|
+
else if (typeof model === 'string' && names.has(model))
|
|
322
|
+
setOwn(tiers, tier, model);
|
|
323
|
+
else
|
|
324
|
+
drop({ key: 'tierGroups', at: `${name}.${tier}`, ...refOf(model), reason: reasonOf(model) });
|
|
325
|
+
}
|
|
296
326
|
}
|
|
297
327
|
}
|
|
328
|
+
groups.push({ name, tiers, ...(typeof g.notes === 'string' ? { notes: g.notes } : {}) });
|
|
298
329
|
}
|
|
299
|
-
|
|
330
|
+
doc.tierGroups = groups;
|
|
300
331
|
}
|
|
301
|
-
doc.tierGroups = groups;
|
|
302
332
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
333
|
+
if (atg === 'unreadable') {
|
|
334
|
+
drop({ key: 'activeTierGroup', at: 'models', reason: 'unreadable' });
|
|
335
|
+
}
|
|
336
|
+
else if (atg !== 'absent') {
|
|
337
|
+
const a = atg.value;
|
|
338
|
+
if (typeof a === 'string' && groupNames?.has(a))
|
|
339
|
+
doc.activeTierGroup = a;
|
|
340
|
+
else
|
|
341
|
+
drop({ key: 'activeTierGroup', ...refOf(a), reason: typeof a === 'string' && a !== '' ? (rawGroupNames.has(a) ? 'rejected' : 'dangling') : 'unreadable' });
|
|
342
|
+
}
|
|
310
343
|
}
|
|
311
344
|
return { doc, issues };
|
|
312
345
|
}
|
|
@@ -566,6 +599,8 @@ function droppedRefNotice(d) {
|
|
|
566
599
|
case 'roles':
|
|
567
600
|
if (d.at === 'default' && d.reason === 'unreadable')
|
|
568
601
|
return { level: 'warn', text: 'cloud config: the default model setting could not be read, so it was left out — the local engine picks its default from roles and tiers instead' };
|
|
602
|
+
if (d.reason === 'unvouched')
|
|
603
|
+
return { level: 'warn', text: `cloud config: role "${d.at ?? ''}" points at model "${t ?? ''}", but this client was given no way to check that the local engine can use that model — the role was left out and falls back along the engine's role chain` };
|
|
569
604
|
if (d.reason === 'shadowed')
|
|
570
605
|
return { level: 'warn', text: `cloud config: the "${d.at ?? ''}" role${t === undefined ? '' : ` ("${t}")`} is overridden by the default model setting served to you — only one default model can be set, so that role entry was left out` };
|
|
571
606
|
return { level: 'warn', text: `cloud config: role "${d.at ?? ''}" ${t === undefined ? 'names no readable model' : `points at model "${t}", which ${notServed}`} — the role was left out and falls back along the engine's role chain` };
|
|
@@ -582,11 +617,111 @@ function droppedRefNotice(d) {
|
|
|
582
617
|
return { level: 'warn', text: `cloud config: tier "${d.at ?? ''}" is bound to model "${t ?? ''}", which ${notServed} — that tier was left unbound` };
|
|
583
618
|
if (d.reason === 'unsupported')
|
|
584
619
|
return { level: 'warn', text: `cloud config: tier "${d.at ?? ''}" is not a tier the local engine reads (${TIER_WORDS.join(', ')}) — that binding was left out` };
|
|
620
|
+
if (d.at === 'models')
|
|
621
|
+
return { level: 'warn', text: 'cloud config: the tier group settings served to you could not be read by this client — they were left out, so no tier groups are set on the local engine' };
|
|
585
622
|
return { level: 'warn', text: `cloud config: a tier group setting${d.at === undefined ? '' : ` ("${d.at}")`} could not be read and was left out` };
|
|
586
623
|
case 'activeTierGroup':
|
|
587
624
|
return { level: 'warn', text: `cloud config: ${t === undefined ? 'the active tier group setting could not be read' : `the active tier group "${t}" is not among the readable tier groups`} — no tier table is active on the local engine` };
|
|
588
625
|
}
|
|
589
626
|
}
|
|
627
|
+
const MCP_DROP_SENTENCES = {
|
|
628
|
+
'missing-field': {
|
|
629
|
+
level: 'warn',
|
|
630
|
+
text: (who) => `cloud config: MCP server entries left out because a required setting is missing or unreadable (a name, a transport, or its command or address): ${who}`,
|
|
631
|
+
},
|
|
632
|
+
'unknown-transport': {
|
|
633
|
+
level: 'warn',
|
|
634
|
+
text: (who) => `cloud config: MCP server entries left out because their transport is not one this client supports: ${who}`,
|
|
635
|
+
},
|
|
636
|
+
'principal-and-assertion-header': {
|
|
637
|
+
level: 'warn',
|
|
638
|
+
text: (who) => `cloud config: MCP server entries left out because they set both principalHeader and assertionHeader, which name the same identity header — keep only one of the two: ${who}`,
|
|
639
|
+
},
|
|
640
|
+
capped: {
|
|
641
|
+
level: 'warn',
|
|
642
|
+
text: (who) => `cloud config: MCP server entries left out because more than ${MCP_CAPS.items} were served to you and this client passes at most ${MCP_CAPS.items} to the engine: ${who}`,
|
|
643
|
+
},
|
|
644
|
+
disabled: {
|
|
645
|
+
level: 'info',
|
|
646
|
+
text: (who) => `cloud config: MCP server entries switched off in the served settings, so they are not started here: ${who}`,
|
|
647
|
+
},
|
|
648
|
+
};
|
|
649
|
+
const MCP_DROP_UNRECOGNISED = (who) => `cloud config: MCP server entries left out for a reason this client does not recognise: ${who}`;
|
|
650
|
+
const MCP_DROP_LIST_UNREADABLE = 'cloud config: the list of MCP server entries left out could not be read by this client — servers missing from the local tool list may have been left out without notice';
|
|
651
|
+
const MCP_DROP_NAMES_SHOWN = 5;
|
|
652
|
+
function mcpDropWho(names, unnamed) {
|
|
653
|
+
const distinct = [...new Set(names)];
|
|
654
|
+
const parts = distinct.slice(0, MCP_DROP_NAMES_SHOWN).map((n) => `"${n}"`);
|
|
655
|
+
if (distinct.length > MCP_DROP_NAMES_SHOWN)
|
|
656
|
+
parts.push(`+${distinct.length - MCP_DROP_NAMES_SHOWN} more`);
|
|
657
|
+
if (unnamed > 0)
|
|
658
|
+
parts.push(`${unnamed} without a readable name`);
|
|
659
|
+
return parts.join(', ');
|
|
660
|
+
}
|
|
661
|
+
function guarded(read) {
|
|
662
|
+
try {
|
|
663
|
+
return read();
|
|
664
|
+
}
|
|
665
|
+
catch {
|
|
666
|
+
return undefined;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
function droppedMcpNotices(carrier) {
|
|
670
|
+
const listUnreadable = [{ level: 'warn', text: MCP_DROP_LIST_UNREADABLE }];
|
|
671
|
+
let desc;
|
|
672
|
+
try {
|
|
673
|
+
desc = Object.getOwnPropertyDescriptor(carrier, 'droppedMcpServers');
|
|
674
|
+
}
|
|
675
|
+
catch {
|
|
676
|
+
return listUnreadable;
|
|
677
|
+
}
|
|
678
|
+
if (desc === undefined)
|
|
679
|
+
return [];
|
|
680
|
+
if (!Object.hasOwn(desc, 'value'))
|
|
681
|
+
return listUnreadable;
|
|
682
|
+
const rows = desc.value;
|
|
683
|
+
let count = 0;
|
|
684
|
+
try {
|
|
685
|
+
if (!Array.isArray(rows))
|
|
686
|
+
return listUnreadable;
|
|
687
|
+
count = rows.length;
|
|
688
|
+
}
|
|
689
|
+
catch {
|
|
690
|
+
return listUnreadable;
|
|
691
|
+
}
|
|
692
|
+
const known = new Map();
|
|
693
|
+
const unrecognised = { names: [], unnamed: 0 };
|
|
694
|
+
for (let i = 0; i < count; i++) {
|
|
695
|
+
const row = guarded(() => readOwnDataValue(rows, String(i)));
|
|
696
|
+
const rowObj = typeof row === 'object' && row !== null ? row : undefined;
|
|
697
|
+
const reason = guarded(() => {
|
|
698
|
+
const raw = readOwnDataValue(rowObj, 'reason');
|
|
699
|
+
return typeof raw === 'string' && Object.hasOwn(MCP_DROP_SENTENCES, raw) ? raw : undefined;
|
|
700
|
+
});
|
|
701
|
+
const name = guarded(() => readOwnDataNonEmptyString(rowObj, 'name'));
|
|
702
|
+
let bucket = unrecognised;
|
|
703
|
+
if (reason !== undefined) {
|
|
704
|
+
let b = known.get(reason);
|
|
705
|
+
if (b === undefined)
|
|
706
|
+
known.set(reason, (b = { names: [], unnamed: 0 }));
|
|
707
|
+
bucket = b;
|
|
708
|
+
}
|
|
709
|
+
if (name === undefined)
|
|
710
|
+
bucket.unnamed++;
|
|
711
|
+
else
|
|
712
|
+
bucket.names.push(name);
|
|
713
|
+
}
|
|
714
|
+
const out = [];
|
|
715
|
+
for (const reason of Object.keys(MCP_DROP_SENTENCES)) {
|
|
716
|
+
const b = known.get(reason);
|
|
717
|
+
if (b !== undefined)
|
|
718
|
+
out.push({ level: MCP_DROP_SENTENCES[reason].level, text: MCP_DROP_SENTENCES[reason].text(mcpDropWho(b.names, b.unnamed)) });
|
|
719
|
+
}
|
|
720
|
+
if (unrecognised.names.length + unrecognised.unnamed > 0) {
|
|
721
|
+
out.push({ level: 'warn', text: MCP_DROP_UNRECOGNISED(mcpDropWho(unrecognised.names, unrecognised.unnamed)) });
|
|
722
|
+
}
|
|
723
|
+
return out;
|
|
724
|
+
}
|
|
590
725
|
function budgetNotice(r) {
|
|
591
726
|
switch (r.kind) {
|
|
592
727
|
case 'configured': {
|
|
@@ -654,6 +789,7 @@ export function cloudEffectiveNotices(p) {
|
|
|
654
789
|
'the catalog is kept as sent, and a locally started engine rejects the cloud model settings: at startup it uses its own environment catalog instead, and on a later refresh it keeps the previous configuration',
|
|
655
790
|
});
|
|
656
791
|
}
|
|
792
|
+
out.push(...droppedMcpNotices(p));
|
|
657
793
|
out.push(budgetNotice(p.budget));
|
|
658
794
|
out.push(runtimeCapsNotice(p.runtimeCaps));
|
|
659
795
|
return out;
|
|
@@ -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
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
5
5
|
export function projectDeviceExecutorManagementCapability(caps) {
|
|
@@ -43,7 +43,6 @@ export function projectDeviceExecutorManagementCapability(caps) {
|
|
|
43
43
|
const reader = createEngineCapReader({
|
|
44
44
|
name: 'deviceExecutor.management',
|
|
45
45
|
project: projectDeviceExecutorManagementCapability,
|
|
46
|
-
makeUnobserved: () => ({ kind: 'unobserved' }),
|
|
47
46
|
});
|
|
48
47
|
export function noteEngineCapsForDeviceExecutorManagement(baseUrl, caps, opts) {
|
|
49
48
|
reader.note(baseUrl, caps, opts);
|
|
@@ -83,6 +82,8 @@ function laneFactsSuffix(r) {
|
|
|
83
82
|
}
|
|
84
83
|
export function deviceExecutorManagementDoctorDetail(reading) {
|
|
85
84
|
switch (reading.kind) {
|
|
85
|
+
case 'unreadable':
|
|
86
|
+
return unreadableReadingDetail('device management face');
|
|
86
87
|
case 'unobserved':
|
|
87
88
|
return 'device management face not observed — the engine reports it on /v1/capabilities (deviceExecutor.management); 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)';
|
|
88
89
|
case 'not_reported':
|
|
@@ -33,6 +33,9 @@ export interface DisplayUntrustedMarked {
|
|
|
33
33
|
export declare const ESCAPE_FACE: DisplayFace;
|
|
34
34
|
export declare const LABEL_FACE: DisplayFace;
|
|
35
35
|
export declare const PEER_NAME_FACE: DisplayFace;
|
|
36
|
+
export declare const REDACTION_MARKER_MAX_LENGTH: number;
|
|
37
|
+
export declare const DISPLAY_CAP_BACKOFF_MAX: number;
|
|
38
|
+
export declare function markerSafeCut(text: string, cut: number): number;
|
|
36
39
|
export declare function capDisplay(text: string, max: number | undefined, mark: DisplayMark): string;
|
|
37
40
|
export declare function paintAndCap(text: string, face: DisplayFace, max?: number): string;
|
|
38
41
|
export declare function credentialWashPasses(text: string, opts?: DisplayUntrustedOptions | null): {
|
package/dist/displayUntrusted.js
CHANGED
|
@@ -4326,6 +4326,7 @@ function capPaired(t, max) {
|
|
|
4326
4326
|
if (id >= 0)
|
|
4327
4327
|
while (cut > 0 && t.ids[cut - 1] === id)
|
|
4328
4328
|
cut--;
|
|
4329
|
+
cut = markerSafeCut(t.text, cut);
|
|
4329
4330
|
if (cut > 0) {
|
|
4330
4331
|
const code = t.text.charCodeAt(cut - 1);
|
|
4331
4332
|
if (code >= 0xd800 && code <= 0xdbff)
|
|
@@ -4370,6 +4371,19 @@ export const ESCAPE_FACE = Object.freeze({ ...publicFace({ foldLines: false }) }
|
|
|
4370
4371
|
export const LABEL_FACE = Object.freeze({ ...publicFace({}) });
|
|
4371
4372
|
export const PEER_NAME_FACE = Object.freeze({ ...publicFace({ mark: 'space' }) });
|
|
4372
4373
|
const ESCAPE_TOKEN_AT = /^\\u(?:[0-9A-F]{4}|\{[0-9A-F]{1,6}\})/;
|
|
4374
|
+
export const REDACTION_MARKER_MAX_LENGTH = REDACTION_MARKER_PREFIX.length + 2 * (1 + 16) + 1;
|
|
4375
|
+
export const DISPLAY_CAP_BACKOFF_MAX = REDACTION_MARKER_MAX_LENGTH;
|
|
4376
|
+
export function markerSafeCut(text, cut) {
|
|
4377
|
+
if (cut <= 0 || cut >= text.length)
|
|
4378
|
+
return cut;
|
|
4379
|
+
const open = text.lastIndexOf('\u00ab', cut - 1);
|
|
4380
|
+
if (open < 0 || cut - open >= REDACTION_MARKER_MAX_LENGTH)
|
|
4381
|
+
return cut;
|
|
4382
|
+
const close = text.indexOf('\u00bb', open);
|
|
4383
|
+
if (close < cut || close - open + 1 > REDACTION_MARKER_MAX_LENGTH)
|
|
4384
|
+
return cut;
|
|
4385
|
+
return MARKER_RE.test(text.slice(open, close + 1)) ? open : cut;
|
|
4386
|
+
}
|
|
4373
4387
|
export function capDisplay(text, max, mark) {
|
|
4374
4388
|
if (typeof max !== 'number' || !Number.isFinite(max))
|
|
4375
4389
|
return text;
|
|
@@ -4387,6 +4401,7 @@ export function capDisplay(text, max, mark) {
|
|
|
4387
4401
|
break;
|
|
4388
4402
|
}
|
|
4389
4403
|
}
|
|
4404
|
+
cut = markerSafeCut(text, cut);
|
|
4390
4405
|
if (cut > 0) {
|
|
4391
4406
|
const code = text.charCodeAt(cut - 1);
|
|
4392
4407
|
if (code >= 0xd800 && code <= 0xdbff)
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
interface EngineCapReaderSpec<R> {
|
|
2
2
|
name: string;
|
|
3
3
|
project: (caps: unknown) => R | undefined;
|
|
4
|
-
makeUnobserved: () => R;
|
|
5
4
|
}
|
|
5
|
+
type ReaderUnobserved = {
|
|
6
|
+
kind: 'unobserved';
|
|
7
|
+
};
|
|
8
|
+
type ReaderUnreadable = {
|
|
9
|
+
kind: 'unreadable';
|
|
10
|
+
};
|
|
6
11
|
interface EngineCapReader<R> {
|
|
7
12
|
note(baseUrl: string, caps: unknown, opts?: {
|
|
8
13
|
generation?: number;
|
|
9
14
|
}): void;
|
|
10
|
-
observed(baseUrl: string | undefined): R;
|
|
15
|
+
observed(baseUrl: string | undefined): R | ReaderUnobserved | ReaderUnreadable;
|
|
11
16
|
__resetForTests(): void;
|
|
12
17
|
}
|
|
13
18
|
export declare function createEngineCapReader<R>(spec: EngineCapReaderSpec<R>): EngineCapReader<R>;
|
|
19
|
+
export declare function unreadableReadingDetail(subject?: string): string;
|
|
14
20
|
export type StoreSeat = {
|
|
15
21
|
kind: 'object';
|
|
16
22
|
store: object;
|
package/dist/engineCapReader.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { engineCapsLandingOf } from './engineCapsCache.js';
|
|
2
2
|
import { ownDataField } from './ownKey.js';
|
|
3
|
+
const unobserved = () => ({ kind: 'unobserved' });
|
|
4
|
+
const unreadable = () => ({ kind: 'unreadable' });
|
|
3
5
|
function freezeReading(reading, seen = new Set()) {
|
|
4
6
|
if (reading === null || typeof reading !== 'object' || seen.has(reading))
|
|
5
7
|
return reading;
|
|
@@ -18,15 +20,17 @@ export function createEngineCapReader(spec) {
|
|
|
18
20
|
note(_baseUrl, _caps, _opts) { },
|
|
19
21
|
observed(baseUrl) {
|
|
20
22
|
if (typeof baseUrl !== 'string' || baseUrl === '')
|
|
21
|
-
return
|
|
23
|
+
return unobserved();
|
|
22
24
|
const landing = engineCapsLandingOf(baseUrl);
|
|
23
|
-
if (landing ===
|
|
24
|
-
return
|
|
25
|
+
if (landing.kind === 'not_landed')
|
|
26
|
+
return unobserved();
|
|
27
|
+
if (landing.kind === 'unreadable')
|
|
28
|
+
return unreadable();
|
|
25
29
|
const hit = memo.get(landing);
|
|
26
30
|
if (hit === PROJECTING)
|
|
27
|
-
return
|
|
31
|
+
return unobserved();
|
|
28
32
|
if (hit !== undefined)
|
|
29
|
-
return hit.reading === undefined ?
|
|
33
|
+
return hit.reading === undefined ? unreadable() : hit.reading;
|
|
30
34
|
const mine = memo;
|
|
31
35
|
mine.set(landing, PROJECTING);
|
|
32
36
|
let reading;
|
|
@@ -38,17 +42,21 @@ export function createEngineCapReader(spec) {
|
|
|
38
42
|
}
|
|
39
43
|
if (engineCapsLandingOf(baseUrl) !== landing) {
|
|
40
44
|
mine.delete(landing);
|
|
41
|
-
return
|
|
45
|
+
return unobserved();
|
|
42
46
|
}
|
|
43
47
|
const done = { reading: reading === undefined ? undefined : freezeReading(reading) };
|
|
44
48
|
mine.set(landing, done);
|
|
45
|
-
return done.reading === undefined ?
|
|
49
|
+
return done.reading === undefined ? unreadable() : done.reading;
|
|
46
50
|
},
|
|
47
51
|
__resetForTests() {
|
|
48
52
|
memo = new WeakMap();
|
|
49
53
|
},
|
|
50
54
|
};
|
|
51
55
|
}
|
|
56
|
+
export function unreadableReadingDetail(subject) {
|
|
57
|
+
const head = typeof subject === 'string' && subject.length > 0 ? `${subject} could not be read` : 'could not be read';
|
|
58
|
+
return `${head} — the engine's /v1/capabilities report arrived, but this entry is not in a form this client reads, so it is shown as unknown, not as absent; probing the same engine again will not change it while the engine reports it this way`;
|
|
59
|
+
}
|
|
52
60
|
export function storeSeatOf(caps) {
|
|
53
61
|
try {
|
|
54
62
|
const store = ownDataField(caps, 'store');
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
export type EngineCapsLanding = {
|
|
2
|
+
readonly kind: 'landed';
|
|
3
|
+
readonly caps: Readonly<Record<string, unknown>>;
|
|
4
|
+
} | {
|
|
5
|
+
readonly kind: 'not_landed';
|
|
6
|
+
} | {
|
|
7
|
+
readonly kind: 'unreadable';
|
|
8
|
+
};
|
|
1
9
|
export declare function engineCapsGeneration(baseUrl: string): number;
|
|
2
|
-
export declare function engineCapsLandingOf(baseUrl: string):
|
|
3
|
-
readonly caps: object;
|
|
4
|
-
} | undefined;
|
|
10
|
+
export declare function engineCapsLandingOf(baseUrl: string | undefined): EngineCapsLanding;
|
|
5
11
|
export declare function kickEngineCapsProbe(baseUrl: string, probe: () => Promise<unknown>): void;
|
|
6
12
|
export declare function engineCapsSettled(baseUrl: string | undefined, opts?: {
|
|
7
13
|
withinMs?: number;
|
|
@@ -30,6 +36,8 @@ export type EngineCapValueState = {
|
|
|
30
36
|
export declare function engineCapValue(baseUrl: string | undefined, key: string): EngineCapValueState;
|
|
31
37
|
export declare function engineCapString(baseUrl: string | undefined, key: string): string | undefined;
|
|
32
38
|
export declare function invalidateEngineCaps(baseUrl: string | undefined, probe?: () => Promise<unknown>): void;
|
|
39
|
+
export type EngineCapsProbeRotation = 'started' | 'registered' | 'ignored';
|
|
40
|
+
export declare function rotateEngineCapsProbe(baseUrl: string | undefined, probe: () => Promise<unknown>): EngineCapsProbeRotation;
|
|
33
41
|
export declare function refreshEngineCapsOnce(baseUrl: string | undefined, opts?: {
|
|
34
42
|
withinMs?: number;
|
|
35
43
|
}): Promise<'settled' | 'timed_out' | 'no_probe'>;
|