@sema-agent/client-core 0.98.0 → 0.99.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 +199 -0
- package/README.md +35 -22
- package/dist/adapt/arms.js +61 -20
- package/dist/adapt/panelTasks.d.ts +1 -1
- package/dist/adapt/panelTasks.js +2 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +4 -3
- package/dist/adapter/activeRunSelfHeal.js +162 -293
- package/dist/adapter/downstream/eventToSdkMessage.js +52 -4
- package/dist/adapter/runStream.js +52 -37
- package/dist/adapter/types.js +2 -1
- package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
- package/dist/agentsWireCaps.d.ts +0 -3
- package/dist/agentsWireCaps.js +33 -24
- package/dist/cloudConfigWireCaps.d.ts +1 -1
- package/dist/cloudConfigWireCaps.js +26 -4
- package/dist/controlRouter.d.ts +4 -2
- package/dist/controlRouter.js +39 -51
- package/dist/coreValuePorts.d.ts +26 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/corruptSessionCopy.d.ts +2 -1
- package/dist/corruptSessionCopy.js +3 -3
- package/dist/declared/supportFloorDeclared.js +1 -1
- package/dist/detachWire.js +3 -2
- package/dist/devicesFace.d.ts +34 -0
- package/dist/devicesFace.js +90 -0
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +3 -0
- package/dist/engineAgentPanelStore.d.ts +7 -0
- package/dist/engineAgentPanelStore.js +14 -0
- package/dist/engineCapReader.d.ts +2 -1
- package/dist/engineCapReader.js +7 -5
- package/dist/engineCapsCache.d.ts +8 -0
- package/dist/engineCapsCache.js +59 -6
- package/dist/engineCapsChange.d.ts +2 -0
- package/dist/engineCapsChange.js +9 -0
- package/dist/engineErrorCodes.d.ts +2 -1
- package/dist/engineErrorCodes.js +2 -7
- package/dist/engineRowRef.js +3 -0
- package/dist/engineSessionMessages.d.ts +1 -0
- package/dist/engineSessionMessages.js +7 -1
- package/dist/engineTargetSeat.d.ts +27 -0
- package/dist/engineTargetSeat.js +199 -0
- package/dist/engineWireFor.js +3 -8
- package/dist/env/uiLanguage.d.ts +2 -1
- package/dist/env/uiLanguage.js +3 -2
- package/dist/eventLeg.d.ts +8 -0
- package/dist/eventLeg.js +61 -41
- package/dist/fileHistoryCaptureCapability.d.ts +2 -1
- package/dist/fileHistoryCaptureCapability.js +12 -18
- package/dist/fileHistoryLegNotice.d.ts +2 -1
- package/dist/fileHistoryLegNotice.js +3 -3
- package/dist/frameBinding.d.ts +3 -0
- package/dist/frameBinding.js +12 -0
- package/dist/gateOutcome.js +16 -2
- package/dist/gateVocabulary.d.ts +8 -7
- package/dist/gateVocabulary.js +71 -73
- package/dist/generated/engineFactTables.d.ts +17 -1
- package/dist/generated/engineFactTables.js +29 -0
- package/dist/generated/engineNoticeTables.js +9 -3
- package/dist/generated/settingsSchemaFns.d.ts +6 -0
- package/dist/generated/settingsSchemaFns.js +57 -0
- package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
- package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
- package/dist/generated/settingsSchemaTables.d.ts +1 -0
- package/dist/generated/settingsSchemaTables.js +4 -0
- package/dist/generated/settingsSchemaTypes.d.ts +105 -0
- package/dist/generated/settingsSchemaTypes.js +1 -0
- package/dist/hitl/allowRuleShadow.d.ts +2 -1
- package/dist/hitl/allowRuleShadow.js +17 -14
- package/dist/hitl/approvalCardReasons.d.ts +3 -2
- package/dist/hitl/approvalCardReasons.js +27 -28
- package/dist/hitl/approvalHolds.d.ts +3 -0
- package/dist/hitl/approvalHolds.js +73 -29
- package/dist/hitl/askClassPair.d.ts +1 -1
- package/dist/hitl/askClassPair.js +16 -0
- package/dist/hitl/askGateWire.js +2 -1
- package/dist/hitl/askSettlementLine.d.ts +14 -4
- package/dist/hitl/askSettlementLine.js +67 -47
- package/dist/hitl/automaticAnswerVerdict.d.ts +2 -1
- package/dist/hitl/automaticAnswerVerdict.js +8 -8
- package/dist/hitl/crashConvergedNotice.d.ts +5 -4
- package/dist/hitl/crashConvergedNotice.js +28 -41
- package/dist/hitl/frameRouter.js +7 -8
- package/dist/hitl/hitlBridge.d.ts +1 -0
- package/dist/hitl/hitlBridge.js +3 -3
- package/dist/hitl/persistedRulesWire.d.ts +6 -5
- package/dist/hitl/persistedRulesWire.js +55 -73
- package/dist/hitl/planReviewWire.d.ts +5 -0
- package/dist/hitl/planReviewWire.js +8 -0
- package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
- package/dist/hitl/sessionPolicyDeliverable.js +46 -3
- package/dist/hitl/sessionPolicyWire.d.ts +2 -1
- package/dist/hitl/sessionPolicyWire.js +23 -24
- package/dist/hitl/suspendedReopen.d.ts +2 -1
- package/dist/hitl/suspendedReopen.js +7 -10
- package/dist/hitl/toolApprovalWire.d.ts +17 -5
- package/dist/hitl/toolApprovalWire.js +79 -40
- package/dist/hooksWireCaps.js +145 -56
- package/dist/host.d.ts +21 -0
- package/dist/hostTurnSettings.d.ts +71 -0
- package/dist/hostTurnSettings.js +291 -0
- package/dist/humanTurn.d.ts +14 -1
- package/dist/humanTurn.js +100 -12
- package/dist/humanTurnRead.d.ts +2 -0
- package/dist/humanTurnRead.js +22 -1
- package/dist/i18n/messages.en.d.ts +582 -0
- package/dist/i18n/messages.en.js +582 -0
- package/dist/i18n/messages.zh.js +718 -1
- package/dist/index.d.ts +29 -13
- package/dist/index.js +18 -9
- package/dist/inheritEnvCapability.d.ts +3 -2
- package/dist/inheritEnvCapability.js +3 -3
- package/dist/inheritEnvWire.d.ts +3 -2
- package/dist/inheritEnvWire.js +12 -14
- package/dist/interactiveHalt.js +17 -6
- package/dist/liveModelCatalog.d.ts +2 -1
- package/dist/liveModelCatalog.js +14 -8
- package/dist/mcpPanel.d.ts +10 -1
- package/dist/mcpPanel.js +40 -13
- package/dist/mcpProbeCapability.d.ts +2 -1
- package/dist/mcpProbeCapability.js +7 -11
- package/dist/mcpProbeWire.d.ts +3 -1
- package/dist/mcpProbeWire.js +5 -0
- package/dist/mcpWireCaps.d.ts +34 -0
- package/dist/mcpWireCaps.js +117 -17
- package/dist/memoryEntriesWire.js +5 -10
- package/dist/model/onboardJudgement.d.ts +93 -0
- package/dist/model/onboardJudgement.js +415 -0
- package/dist/model/tierVocabulary.d.ts +2 -0
- package/dist/model/tierVocabulary.js +17 -5
- package/dist/modelCapabilityProbe.d.ts +64 -0
- package/dist/modelCapabilityProbe.js +600 -0
- package/dist/modelIdentityResolvability.d.ts +3 -0
- package/dist/modelIdentityResolvability.js +26 -17
- package/dist/ownKey.d.ts +7 -0
- package/dist/ownKey.js +34 -0
- package/dist/panelReduce.d.ts +6 -1
- package/dist/panelReduce.js +50 -3
- package/dist/permissionRuleIssue.js +2 -0
- package/dist/permissionRulesWriteCapability.d.ts +2 -1
- package/dist/permissionRulesWriteCapability.js +8 -6
- package/dist/pluginHooksWire.d.ts +46 -3
- package/dist/pluginHooksWire.js +217 -11
- package/dist/printModelStatus.d.ts +63 -0
- package/dist/printModelStatus.js +155 -0
- package/dist/request/taskRequest.d.ts +11 -5
- package/dist/request/taskRequest.js +112 -16
- package/dist/resumeRefusalCopy.d.ts +12 -9
- package/dist/resumeRefusalCopy.js +70 -143
- package/dist/retryStatus.d.ts +37 -0
- package/dist/retryStatus.js +79 -0
- package/dist/scenarioRefusal.d.ts +9 -0
- package/dist/scenarioRefusal.js +111 -0
- package/dist/seam.d.ts +25 -1
- package/dist/seam.js +10 -1
- package/dist/seatContract.d.ts +260 -10
- package/dist/seatContract.js +692 -19
- package/dist/selfOrchestrationDenial.js +7 -19
- package/dist/sessionIdSegment.d.ts +6 -0
- package/dist/sessionIdSegment.js +24 -0
- package/dist/sessionMemoryStatus.js +6 -11
- package/dist/sessionPolicyCapability.d.ts +2 -1
- package/dist/sessionPolicyCapability.js +8 -6
- package/dist/settingsHooksSalvage.d.ts +44 -0
- package/dist/settingsHooksSalvage.js +211 -0
- package/dist/skillToolListsCapability.d.ts +2 -1
- package/dist/skillToolListsCapability.js +8 -6
- package/dist/sseIdleTriage.js +3 -2
- package/dist/subagent/engineSubagentResume.js +15 -9
- package/dist/subagentContentStore.d.ts +3 -0
- package/dist/subagentContentStore.js +22 -0
- package/dist/toolHistoryMismatch.js +3 -2
- package/dist/toolRoster.d.ts +3 -2
- package/dist/toolRoster.js +21 -20
- package/dist/turnFailurePresentation.d.ts +12 -1
- package/dist/turnFailurePresentation.js +212 -15
- package/dist/usageAnalytics.js +6 -11
- package/dist/userAttachmentEnvelope.d.ts +1 -0
- package/dist/userAttachmentEnvelope.js +37 -7
- package/dist/userAttachmentSeat.d.ts +21 -0
- package/dist/userAttachmentSeat.js +75 -0
- package/dist/userInvokedSkillsCapability.d.ts +11 -1
- package/dist/userInvokedSkillsCapability.js +31 -7
- package/dist/wireErrorTriage.d.ts +7 -0
- package/dist/wireErrorTriage.js +23 -1
- package/dist/wireFailureShape.js +2 -1
- package/dist/wireRefusalCopy.d.ts +13 -1
- package/dist/wireRefusalCopy.js +24 -28
- package/dist/workflowsJournalCapability.d.ts +2 -1
- package/dist/workflowsJournalCapability.js +8 -6
- package/docs/INTEGRATION-CLIENTS.md +542 -30
- package/package.json +5 -5
package/dist/controlRouter.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { cancelConflictContent, cancelConflictFromError } from './wireRefusalCopy.js';
|
|
2
|
-
import { PROTOCOL_ERROR_NAME, protocolErrorNameOf } from './wireFailureShape.js';
|
|
2
|
+
import { PROTOCOL_ERROR_NAME, THROWN_SLOT_UNREADABLE, protocolErrorNameOf, readThrownSlot, readThrownStatusSlot } from './wireFailureShape.js';
|
|
3
3
|
import { steerPriorityMode } from './steerPriorityCapability.js';
|
|
4
4
|
import { preemptReadingOfAck, preemptReadingOfError } from './preemptWire.js';
|
|
5
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
5
6
|
export class ControlSafetyError extends Error {
|
|
6
7
|
code;
|
|
7
8
|
cause;
|
|
@@ -156,10 +157,11 @@ export class ControlRouter {
|
|
|
156
157
|
export function errCodes(e) {
|
|
157
158
|
if (!e || typeof e !== 'object')
|
|
158
159
|
return {};
|
|
159
|
-
const
|
|
160
|
-
const code = typeof
|
|
161
|
-
const
|
|
162
|
-
const
|
|
160
|
+
const rawCode = readThrownSlot(e, 'errorCode', 'data');
|
|
161
|
+
const code = typeof rawCode === 'string' ? rawCode : undefined;
|
|
162
|
+
const rawName = readThrownSlot(e, 'name');
|
|
163
|
+
const name = typeof rawName === 'string' ? rawName : undefined;
|
|
164
|
+
const rawStatus = readThrownStatusSlot(e);
|
|
163
165
|
const status = typeof rawStatus === 'number' ? rawStatus : undefined;
|
|
164
166
|
return { code, name, status };
|
|
165
167
|
}
|
|
@@ -185,48 +187,32 @@ const STEERING_NAME_TO_SAFETY = {
|
|
|
185
187
|
SteeringError: 'steering_other',
|
|
186
188
|
};
|
|
187
189
|
const STEERING_COPY = {
|
|
188
|
-
not_running: {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
},
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
},
|
|
196
|
-
|
|
197
|
-
happened: 'that run is paused and already holds as many waiting messages as it can, so this one was not accepted',
|
|
198
|
-
nextStep: 'send it again once the waiting messages have been delivered (when the run resumes or the session is woken)',
|
|
199
|
-
},
|
|
200
|
-
duplicate_input_id: {
|
|
201
|
-
happened: 'a different instruction was already accepted under this idempotency key, and that earlier instruction stands',
|
|
202
|
-
nextStep: 'if you changed the text, send the new text under a new key; otherwise do not resend it — a new key would deliver the same instruction twice',
|
|
203
|
-
},
|
|
204
|
-
ambiguous_target: {
|
|
205
|
-
happened: 'more than one running agent matches that target, so the message was not delivered',
|
|
206
|
-
nextStep: 'address a sub-agent by its tool-call id; a workflow agent cannot be singled out while another running agent shares its label, so send it again once only one does',
|
|
207
|
-
},
|
|
208
|
-
still_running: {
|
|
209
|
-
happened: 'that agent is still running, so it cannot be resumed',
|
|
210
|
-
nextStep: 'send it a message instead, or wait for it to finish',
|
|
211
|
-
},
|
|
212
|
-
blocked_by_hook: {
|
|
213
|
-
happened: "the message was not accepted: a prompt check on this deployment blocked it, so nothing was delivered",
|
|
214
|
-
nextStep: 'edit the message and send it again — that is not a duplicate submission',
|
|
215
|
-
},
|
|
216
|
-
ledger_unavailable: {
|
|
217
|
-
happened: 'the server could not record the message and refused it before anything reached the engine, so nothing was delivered',
|
|
218
|
-
nextStep: 'send the same text again later',
|
|
219
|
-
},
|
|
220
|
-
steering_other: {
|
|
221
|
-
happened: 'the message was refused for a reason this version does not recognise, so it did not land',
|
|
222
|
-
nextStep: 'report its error code if this keeps happening; do not guess what it means',
|
|
223
|
-
},
|
|
190
|
+
not_running: { happened: 'session.steerRefusal.notRunning.happened', nextStep: 'session.steerRefusal.notRunning.nextStep' },
|
|
191
|
+
invalid_content: { happened: 'session.steerRefusal.invalidContent.happened', nextStep: 'session.steerRefusal.invalidContent.nextStep' },
|
|
192
|
+
queue_full: { happened: 'session.steerRefusal.queueFull.happened', nextStep: 'session.steerRefusal.queueFull.nextStep' },
|
|
193
|
+
duplicate_input_id: { happened: 'session.steerRefusal.duplicateInputId.happened', nextStep: 'session.steerRefusal.duplicateInputId.nextStep' },
|
|
194
|
+
ambiguous_target: { happened: 'session.steerRefusal.ambiguousTarget.happened', nextStep: 'session.steerRefusal.ambiguousTarget.nextStep' },
|
|
195
|
+
still_running: { happened: 'session.steerRefusal.stillRunning.happened', nextStep: 'session.steerRefusal.stillRunning.nextStep' },
|
|
196
|
+
blocked_by_hook: { happened: 'session.steerRefusal.blockedByHook.happened', nextStep: 'session.steerRefusal.blockedByHook.nextStep' },
|
|
197
|
+
ledger_unavailable: { happened: 'session.steerRefusal.ledgerUnavailable.happened', nextStep: 'session.steerRefusal.ledgerUnavailable.nextStep' },
|
|
198
|
+
steering_other: { happened: 'session.steerRefusal.steeringOther.happened', nextStep: 'session.steerRefusal.steeringOther.nextStep' },
|
|
224
199
|
};
|
|
225
|
-
const adviceOfCopy = (c) =>
|
|
226
|
-
|
|
200
|
+
const adviceOfCopy = (c, lang) => renderMessage(msg('session.steerRefusal.advice', { happened: c.happened, nextStep: c.nextStep }), lang);
|
|
201
|
+
function hostQueueFactOf(v) {
|
|
202
|
+
return v === 'queued_until_turn_end' || v === 'dropped' ? v : 'unknown';
|
|
203
|
+
}
|
|
204
|
+
function renderedCopyOf(keys, lang, hostQueue) {
|
|
205
|
+
const happened = renderMessage(msg(keys.happened), lang);
|
|
206
|
+
const tableNextStep = renderMessage(msg(keys.nextStep), lang);
|
|
207
|
+
if (hostQueue === 'queued_until_turn_end')
|
|
208
|
+
return { happened, nextStep: renderMessage(msg('session.steerRefusal.hostQueue.queued'), lang) };
|
|
209
|
+
if (hostQueue === 'dropped')
|
|
210
|
+
return { happened, nextStep: renderMessage(msg('session.steerRefusal.hostQueue.dropped', { nextStep: tableNextStep }), lang) };
|
|
211
|
+
return { happened, nextStep: tableNextStep };
|
|
212
|
+
}
|
|
227
213
|
const STEERING_OTHER_UNKNOWN_COPY = {
|
|
228
|
-
happened: '
|
|
229
|
-
nextStep: '
|
|
214
|
+
happened: 'session.steerRefusal.steeringOtherUnknown.happened',
|
|
215
|
+
nextStep: 'session.steerRefusal.steeringOtherUnknown.nextStep',
|
|
230
216
|
};
|
|
231
217
|
const CANCEL_NOT_FOUND_COPY = {
|
|
232
218
|
happened: 'this server has no run with that id for you — it does not exist, or it belongs to someone else',
|
|
@@ -262,7 +248,7 @@ function steeringCopyOf(e, safety) {
|
|
|
262
248
|
return STEERING_COPY[safety];
|
|
263
249
|
}
|
|
264
250
|
const STEERING_REFUSED_BEFORE_ENGINE = new Map([['ledger_unavailable', 503]]);
|
|
265
|
-
export function steeringRefusedBeforeEngine(e) {
|
|
251
|
+
export function steeringRefusedBeforeEngine(e, hostQueue, lang) {
|
|
266
252
|
try {
|
|
267
253
|
const { status } = errCodes(e);
|
|
268
254
|
if (status === undefined)
|
|
@@ -270,8 +256,8 @@ export function steeringRefusedBeforeEngine(e) {
|
|
|
270
256
|
const safety = steeringVerdict(e);
|
|
271
257
|
if (safety === undefined || STEERING_REFUSED_BEFORE_ENGINE.get(safety) !== status)
|
|
272
258
|
return undefined;
|
|
273
|
-
const copy = STEERING_COPY[safety];
|
|
274
|
-
return { safety, advice:
|
|
259
|
+
const copy = renderedCopyOf(STEERING_COPY[safety], lang, hostQueueFactOf(hostQueue));
|
|
260
|
+
return { safety, advice: adviceOfCopy(copy, lang), happened: copy.happened, nextStep: copy.nextStep };
|
|
275
261
|
}
|
|
276
262
|
catch {
|
|
277
263
|
return undefined;
|
|
@@ -288,17 +274,19 @@ function steeringVerdict(e) {
|
|
|
288
274
|
if (typeof code === 'string' && code.startsWith('steering.')) {
|
|
289
275
|
return STEERING_CODE_TO_SAFETY.get(code) ?? 'steering_other';
|
|
290
276
|
}
|
|
277
|
+
if (readThrownSlot(e, 'errorCode', 'data') === THROWN_SLOT_UNREADABLE)
|
|
278
|
+
return undefined;
|
|
291
279
|
const protocolName = protocolErrorNameOf(e);
|
|
292
280
|
return protocolName !== undefined ? STEERING_NAME_TO_SAFETY[protocolName] : undefined;
|
|
293
281
|
}
|
|
294
|
-
export function steerRefusalAdviceOf(e) {
|
|
282
|
+
export function steerRefusalAdviceOf(e, hostQueue, lang) {
|
|
295
283
|
try {
|
|
296
284
|
const verdict = steeringVerdict(e);
|
|
297
285
|
if (verdict === undefined)
|
|
298
286
|
return undefined;
|
|
299
287
|
const safety = steeringSafetyOf(e, verdict);
|
|
300
|
-
const copy = steeringCopyOf(e, safety);
|
|
301
|
-
return { safety, advice: adviceOfCopy(copy), happened: copy.happened, nextStep: copy.nextStep };
|
|
288
|
+
const copy = renderedCopyOf(steeringCopyOf(e, safety), lang, hostQueueFactOf(hostQueue));
|
|
289
|
+
return { safety, advice: adviceOfCopy(copy, lang), happened: copy.happened, nextStep: copy.nextStep };
|
|
302
290
|
}
|
|
303
291
|
catch {
|
|
304
292
|
return undefined;
|
package/dist/coreValuePorts.d.ts
CHANGED
|
@@ -97,6 +97,27 @@ export interface RuleToolNameVerdictView {
|
|
|
97
97
|
readonly guidance?: string;
|
|
98
98
|
readonly currentName?: string;
|
|
99
99
|
}
|
|
100
|
+
export type RuleEntryReadingView = {
|
|
101
|
+
readonly kind: 'row';
|
|
102
|
+
readonly compiled: RuleEntryCompiledView;
|
|
103
|
+
} | {
|
|
104
|
+
readonly kind: 'inert';
|
|
105
|
+
readonly reason: string;
|
|
106
|
+
readonly verdict?: string;
|
|
107
|
+
readonly guidance?: string;
|
|
108
|
+
readonly currentName?: string;
|
|
109
|
+
readonly valueType?: string;
|
|
110
|
+
};
|
|
111
|
+
export interface RuleEntryCompiledView {
|
|
112
|
+
readonly kind: string;
|
|
113
|
+
}
|
|
114
|
+
export type McpToolAxesReadView = {
|
|
115
|
+
readonly ok: true;
|
|
116
|
+
readonly toolAxes?: Readonly<Record<string, object>>;
|
|
117
|
+
} | {
|
|
118
|
+
readonly ok: false;
|
|
119
|
+
readonly problem: string;
|
|
120
|
+
};
|
|
100
121
|
export interface CoreValuePorts {
|
|
101
122
|
resolveAutonomousLoopPrompt: (prompt: string, opts?: AutonomousLoopPromptOptionsView) => string | null;
|
|
102
123
|
loosenReasons: (prior: SessionPermissionRules, next: SessionPermissionRules) => string[];
|
|
@@ -118,8 +139,10 @@ export interface CoreValuePorts {
|
|
|
118
139
|
adjudicateRoute?(model: RouteModelView, perModelAuth?: PerModelAuthView): RouteAdjudicationView | undefined;
|
|
119
140
|
}, model: RouteModelView, perModelAuth?: PerModelAuthView): RoutePairingStatusView;
|
|
120
141
|
judgeRuleToolName(name: string, roster: ReadonlySet<string>): RuleToolNameVerdictView;
|
|
142
|
+
readRuleEntry(raw: {} | null | undefined, behavior: 'allow' | 'deny', roster?: ReadonlySet<string>): RuleEntryReadingView;
|
|
143
|
+
readMcpToolAxes(declared: {} | null | undefined): McpToolAxesReadView;
|
|
121
144
|
}
|
|
122
|
-
export declare const CORE_VALUE_PORT_NAMES: readonly ["resolveAutonomousLoopPrompt", "loosenReasons", "combinePolicies", "createAllowDenyPolicy", "MCP_NAMESPACE", "protocolOf", "ruleToolGrammarOf", "validatePermissionRules", "mintNamespacePrefix", "compileAllowList", "routeKeyOf", "joinRequestUrl", "resolveRouteCredential", "adjudicateModelRoute", "routePairingStatus", "judgeRuleToolName"];
|
|
145
|
+
export declare const CORE_VALUE_PORT_NAMES: readonly ["resolveAutonomousLoopPrompt", "loosenReasons", "combinePolicies", "createAllowDenyPolicy", "MCP_NAMESPACE", "protocolOf", "ruleToolGrammarOf", "validatePermissionRules", "mintNamespacePrefix", "compileAllowList", "routeKeyOf", "joinRequestUrl", "resolveRouteCredential", "adjudicateModelRoute", "routePairingStatus", "judgeRuleToolName", "readRuleEntry", "readMcpToolAxes"];
|
|
123
146
|
export type CoreValuePortName = (typeof CORE_VALUE_PORT_NAMES)[number];
|
|
124
147
|
export declare function installCoreValuePorts(ports: Partial<CoreValuePorts> | null): () => void;
|
|
125
148
|
export declare function hasCoreValuePorts(): boolean;
|
|
@@ -145,3 +168,5 @@ export declare function adjudicateModelRoute(model: RouteModelView, credential:
|
|
|
145
168
|
export declare function routePairingStatus(brain: {
|
|
146
169
|
adjudicateRoute?(model: RouteModelView, perModelAuth?: PerModelAuthView): RouteAdjudicationView | undefined;
|
|
147
170
|
}, model: RouteModelView, perModelAuth?: PerModelAuthView): RoutePairingStatusView | undefined;
|
|
171
|
+
export declare function readRuleEntry(raw: {} | null | undefined, behavior: 'allow' | 'deny', roster?: ReadonlySet<string>): RuleEntryReadingView | undefined;
|
|
172
|
+
export declare function readMcpToolAxes(declared: {} | null | undefined): McpToolAxesReadView | undefined;
|
package/dist/coreValuePorts.js
CHANGED
|
@@ -15,6 +15,8 @@ export const CORE_VALUE_PORT_NAMES = Object.freeze([
|
|
|
15
15
|
'adjudicateModelRoute',
|
|
16
16
|
'routePairingStatus',
|
|
17
17
|
'judgeRuleToolName',
|
|
18
|
+
'readRuleEntry',
|
|
19
|
+
'readMcpToolAxes',
|
|
18
20
|
]);
|
|
19
21
|
let installed = null;
|
|
20
22
|
export function installCoreValuePorts(ports) {
|
|
@@ -99,3 +101,11 @@ export function routePairingStatus(brain, model, perModelAuth) {
|
|
|
99
101
|
const fn = port('routePairingStatus');
|
|
100
102
|
return fn === undefined ? undefined : fn(brain, model, perModelAuth);
|
|
101
103
|
}
|
|
104
|
+
export function readRuleEntry(raw, behavior, roster) {
|
|
105
|
+
const fn = port('readRuleEntry');
|
|
106
|
+
return fn === undefined ? undefined : fn(raw, behavior, roster);
|
|
107
|
+
}
|
|
108
|
+
export function readMcpToolAxes(declared) {
|
|
109
|
+
const fn = port('readMcpToolAxes');
|
|
110
|
+
return fn === undefined ? undefined : fn(declared);
|
|
111
|
+
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
2
|
+
export declare function corruptSessionContent(lang?: UiLanguage): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
2
|
+
export function corruptSessionContent(lang) {
|
|
3
|
+
return renderMessage(msg('session.corrupt.content'), lang);
|
|
4
4
|
}
|
package/dist/detachWire.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { hostEnv } from './hostEnv.js';
|
|
2
2
|
import { envFlagOff } from './envFlag.js';
|
|
3
|
+
import { readThrownSlot } from './wireFailureShape.js';
|
|
3
4
|
import { resolveWireAuth } from './engineWireSdk.js';
|
|
4
5
|
export const DETACH_HEADER = 'x-detach-on-disconnect';
|
|
5
6
|
export const HEADLESS_DETACH_ENV = 'SEMA_HEADLESS_DETACH';
|
|
@@ -13,10 +14,10 @@ export async function resolveHeadlessDetach(env = hostEnv()) {
|
|
|
13
14
|
}
|
|
14
15
|
export const DETACH_DURABLE_OFF_400_ANCHOR = 'x-detach-on-disconnect requires a durable run';
|
|
15
16
|
export function isDetachDurableOff400(err) {
|
|
17
|
+
if (readThrownSlot(err, 'status', 'data') !== 400)
|
|
18
|
+
return false;
|
|
16
19
|
try {
|
|
17
20
|
const e = err;
|
|
18
|
-
if (e?.status !== 400)
|
|
19
|
-
return false;
|
|
20
21
|
const msg = e?.message;
|
|
21
22
|
return typeof msg === 'string' && msg.includes(DETACH_DURABLE_OFF_400_ANCHOR);
|
|
22
23
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type SeatCapabilityReading } from './seatContract.js';
|
|
2
|
+
import { type DeviceExecutorManagementReading } from './deviceExecutorManagementCapability.js';
|
|
3
|
+
import type { DeviceListOutcome } from './deviceRebind.js';
|
|
4
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
5
|
+
export type DevicesFaceUnavailableWhy = 'host_not_wired' | 'host_not_reported' | 'host_report_unreadable' | 'lane_absent' | 'lane_unreported';
|
|
6
|
+
export type DevicesFace = {
|
|
7
|
+
readonly kind: 'unavailable';
|
|
8
|
+
readonly why: DevicesFaceUnavailableWhy;
|
|
9
|
+
} | {
|
|
10
|
+
readonly kind: 'probe_pending';
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: 'probe_failed';
|
|
13
|
+
readonly retryable: true;
|
|
14
|
+
readonly cause: 'transport' | 'refused' | 'unreadable';
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'verbs_off';
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: 'manage';
|
|
19
|
+
readonly probe: boolean;
|
|
20
|
+
};
|
|
21
|
+
export interface DevicesFaceInput {
|
|
22
|
+
readonly host: {
|
|
23
|
+
readonly kind: 'seat';
|
|
24
|
+
readonly capability: SeatCapabilityReading;
|
|
25
|
+
} | {
|
|
26
|
+
readonly kind: 'direct';
|
|
27
|
+
readonly sliceArmed: boolean;
|
|
28
|
+
};
|
|
29
|
+
readonly engine?: DeviceExecutorManagementReading | undefined;
|
|
30
|
+
readonly lastList?: DeviceListOutcome | undefined;
|
|
31
|
+
}
|
|
32
|
+
export declare function devicesFaceOf(input: DevicesFaceInput): DevicesFace;
|
|
33
|
+
export declare function devicesWritesAllowed(face: DevicesFace): boolean;
|
|
34
|
+
export declare function devicesFaceDetail(face: DevicesFace, lang?: UiLanguage): string | undefined;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { seatCapabilityUnavailableDetail } from './seatContract.js';
|
|
2
|
+
import { deviceLaneOpen, deviceManagementVerbsAvailable } from './deviceExecutorManagementCapability.js';
|
|
3
|
+
import { ownDataField } from './ownKey.js';
|
|
4
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
5
|
+
const freeze = (v) => Object.freeze(v);
|
|
6
|
+
const field = (v, key) => {
|
|
7
|
+
if (v === null || typeof v !== 'object')
|
|
8
|
+
return undefined;
|
|
9
|
+
try {
|
|
10
|
+
return ownDataField(v, key);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function hostProblem(host) {
|
|
17
|
+
const kind = field(host, 'kind');
|
|
18
|
+
if (kind === 'direct')
|
|
19
|
+
return field(host, 'sliceArmed') === true ? undefined : 'host_not_wired';
|
|
20
|
+
if (kind !== 'seat')
|
|
21
|
+
return 'host_report_unreadable';
|
|
22
|
+
const reading = field(host, 'capability');
|
|
23
|
+
const rk = field(reading, 'kind');
|
|
24
|
+
if (rk === 'reported')
|
|
25
|
+
return field(reading, 'available') === true ? undefined : 'host_not_wired';
|
|
26
|
+
if (rk === 'not_reported')
|
|
27
|
+
return 'host_not_reported';
|
|
28
|
+
return 'host_report_unreadable';
|
|
29
|
+
}
|
|
30
|
+
export function devicesFaceOf(input) {
|
|
31
|
+
const engineRaw = field(input, 'engine');
|
|
32
|
+
const engine = { kind: field(engineRaw, 'kind'), management: field(engineRaw, 'management') };
|
|
33
|
+
const lane = deviceLaneOpen(engine);
|
|
34
|
+
const listKind = field(field(input, 'lastList'), 'kind');
|
|
35
|
+
if (lane === 'no' || listKind === 'lane-absent')
|
|
36
|
+
return freeze({ kind: 'unavailable', why: 'lane_absent' });
|
|
37
|
+
const host = field(input, 'host');
|
|
38
|
+
const hostWhy = hostProblem(host);
|
|
39
|
+
if (hostWhy !== undefined)
|
|
40
|
+
return freeze({ kind: 'unavailable', why: hostWhy });
|
|
41
|
+
if (listKind === 'unarmed')
|
|
42
|
+
return freeze({ kind: 'unavailable', why: 'host_not_wired' });
|
|
43
|
+
if (lane === 'unknown') {
|
|
44
|
+
if (field(host, 'kind') === 'direct')
|
|
45
|
+
return freeze({ kind: 'unavailable', why: 'lane_unreported' });
|
|
46
|
+
if (listKind === undefined)
|
|
47
|
+
return freeze({ kind: 'probe_pending' });
|
|
48
|
+
if (listKind === 'ok')
|
|
49
|
+
return freeze({ kind: 'manage', probe: true });
|
|
50
|
+
const cause = listKind === 'transport' || listKind === 'refused' ? listKind : 'unreadable';
|
|
51
|
+
return freeze({ kind: 'probe_failed', retryable: true, cause });
|
|
52
|
+
}
|
|
53
|
+
const verbs = deviceManagementVerbsAvailable(engine);
|
|
54
|
+
if (verbs === 'no')
|
|
55
|
+
return freeze({ kind: 'verbs_off' });
|
|
56
|
+
return freeze({ kind: 'manage', probe: verbs === 'unknown' });
|
|
57
|
+
}
|
|
58
|
+
export function devicesWritesAllowed(face) {
|
|
59
|
+
return field(face, 'kind') === 'manage';
|
|
60
|
+
}
|
|
61
|
+
const UNWIRED = freeze({ kind: 'reported', available: false });
|
|
62
|
+
const NOT_REPORTED = freeze({ kind: 'not_reported' });
|
|
63
|
+
const MALFORMED = freeze({ kind: 'malformed' });
|
|
64
|
+
export function devicesFaceDetail(face, lang) {
|
|
65
|
+
const kind = field(face, 'kind');
|
|
66
|
+
if (kind === 'manage')
|
|
67
|
+
return undefined;
|
|
68
|
+
if (kind === 'probe_pending')
|
|
69
|
+
return renderMessage(msg('session.devices.probePending'), lang);
|
|
70
|
+
if (kind === 'verbs_off')
|
|
71
|
+
return renderMessage(msg('session.devices.verbsOff'), lang);
|
|
72
|
+
if (kind === 'probe_failed') {
|
|
73
|
+
const cause = field(face, 'cause');
|
|
74
|
+
if (cause === 'transport')
|
|
75
|
+
return renderMessage(msg('session.devices.probeFailedTransport'), lang);
|
|
76
|
+
if (cause === 'refused')
|
|
77
|
+
return renderMessage(msg('session.devices.probeFailedRefused'), lang);
|
|
78
|
+
return renderMessage(msg('session.devices.probeFailedUnreadable'), lang);
|
|
79
|
+
}
|
|
80
|
+
const why = kind === 'unavailable' ? field(face, 'why') : undefined;
|
|
81
|
+
if (why === 'lane_absent')
|
|
82
|
+
return renderMessage(msg('session.devices.laneAbsent'), lang);
|
|
83
|
+
if (why === 'lane_unreported')
|
|
84
|
+
return renderMessage(msg('session.devices.laneUnreported'), lang);
|
|
85
|
+
if (why === 'host_not_wired')
|
|
86
|
+
return seatCapabilityUnavailableDetail('devices', UNWIRED);
|
|
87
|
+
if (why === 'host_not_reported')
|
|
88
|
+
return seatCapabilityUnavailableDetail('devices', NOT_REPORTED);
|
|
89
|
+
return seatCapabilityUnavailableDetail('devices', MALFORMED);
|
|
90
|
+
}
|
|
@@ -44,6 +44,7 @@ export declare function credentialWashPasses(text: string, opts?: DisplayUntrust
|
|
|
44
44
|
capped: boolean;
|
|
45
45
|
};
|
|
46
46
|
export declare function displayUntrusted(text: string, opts?: DisplayUntrustedOptions): string;
|
|
47
|
+
export declare function cleanUntrustedScalar(v: string | number | bigint | boolean | null | undefined): string;
|
|
47
48
|
export declare function queryCarriesCredential(query: string): boolean;
|
|
48
49
|
export declare function displayConfiguredUrl(url: string, opts?: DisplayUntrustedOptions): string;
|
|
49
50
|
export declare function quoteUntrustedForSentence(text: string, max: number): string | undefined;
|
package/dist/displayUntrusted.js
CHANGED
|
@@ -4663,6 +4663,9 @@ export function displayUntrusted(text, opts = {}) {
|
|
|
4663
4663
|
const out = renderUntrusted(text, opts, null);
|
|
4664
4664
|
return typeof out === 'string' ? out : out.text;
|
|
4665
4665
|
}
|
|
4666
|
+
export function cleanUntrustedScalar(v) {
|
|
4667
|
+
return displayUntrusted(String(v ?? ''), { credentialUrls: false, credentialWords: false, foldLines: false });
|
|
4668
|
+
}
|
|
4666
4669
|
const NON_SECRET_FIELD_NAMES = new Set([
|
|
4667
4670
|
'deployment', 'deploymentname', 'deploymentid', 'name', 'tenant', 'tenantname', 'tenantid', 'region', 'location', 'zone',
|
|
4668
4671
|
'project', 'projectname', 'projectid', 'workspace', 'workspacename', 'workspaceid', 'resource', 'resourcename', 'resourcegroup',
|
|
@@ -46,6 +46,7 @@ export type EngineAgentPanelEvent = {
|
|
|
46
46
|
report?: string;
|
|
47
47
|
wireTaskId?: string;
|
|
48
48
|
taskIdOrigin?: 'fleet-row' | 'wire';
|
|
49
|
+
sessionId?: string;
|
|
49
50
|
} | {
|
|
50
51
|
kind: 'sweep';
|
|
51
52
|
};
|
|
@@ -58,6 +59,12 @@ export declare function clearEnginePanelTaskResidentByWire(wireTaskId: string, c
|
|
|
58
59
|
export declare function __resetEngineAgentPanelIdentityForTests(): void;
|
|
59
60
|
export declare function __resetEnginePanelStateForTests(): void;
|
|
60
61
|
export declare function publishEngineAgentPanelEvent(ev: EngineAgentPanelEvent): void;
|
|
62
|
+
export interface EngineAgentPanelStart {
|
|
63
|
+
taskId: string;
|
|
64
|
+
startedAt?: number;
|
|
65
|
+
workflowRunId?: string;
|
|
66
|
+
}
|
|
67
|
+
export declare function publishEngineAgentPanelStart(ev: EngineAgentPanelStart): void;
|
|
61
68
|
export declare function subscribeEnginePanelRows(fn: (delta: PanelDelta) => void): () => void;
|
|
62
69
|
export interface EngineAgentPanelAbsence {
|
|
63
70
|
taskId: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isNewEngineAgentPanelCycle, isStaleEngineAgentPanelEnd, panelIsResident, panelResolveTaskId, MAX_HELD_WIRE_TICK_BEATS, } from './panelReduce.js';
|
|
2
|
+
import { guardedRead, readOwnDataFiniteNumber, readOwnDataNonEmptyString } from './ownKey.js';
|
|
2
3
|
import { clearEnginePanelIdentity, panelStateNow, stepEnginePanel, subscribeRows, resetEnginePanelHolder } from './panelStateHolder.js';
|
|
3
4
|
export { isNewEngineAgentPanelCycle, isStaleEngineAgentPanelEnd, MAX_HELD_WIRE_TICK_BEATS };
|
|
4
5
|
const _panelToolUsesLanePins = [true, true];
|
|
@@ -31,6 +32,19 @@ export function __resetEnginePanelStateForTests() {
|
|
|
31
32
|
export function publishEngineAgentPanelEvent(ev) {
|
|
32
33
|
stepEnginePanel(ev);
|
|
33
34
|
}
|
|
35
|
+
export function publishEngineAgentPanelStart(ev) {
|
|
36
|
+
const taskId = guardedRead(() => readOwnDataNonEmptyString(ev, 'taskId'));
|
|
37
|
+
if (taskId === undefined)
|
|
38
|
+
return;
|
|
39
|
+
const startedAt = guardedRead(() => readOwnDataFiniteNumber(ev, 'startedAt'));
|
|
40
|
+
const workflowRunId = guardedRead(() => readOwnDataNonEmptyString(ev, 'workflowRunId'));
|
|
41
|
+
stepEnginePanel({
|
|
42
|
+
kind: 'start',
|
|
43
|
+
taskId,
|
|
44
|
+
...(startedAt !== undefined ? { startedAt } : {}),
|
|
45
|
+
...(workflowRunId !== undefined ? { workflowRunId } : {}),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
34
48
|
export function subscribeEnginePanelRows(fn) {
|
|
35
49
|
return subscribeRows(fn);
|
|
36
50
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
1
2
|
interface EngineCapReaderSpec<R> {
|
|
2
3
|
name: string;
|
|
3
4
|
project: (caps: unknown) => R | undefined;
|
|
@@ -12,7 +13,7 @@ interface EngineCapReader<R> {
|
|
|
12
13
|
observed(baseUrl: string | undefined): R | ReaderUnobserved | ReaderUnreadable;
|
|
13
14
|
}
|
|
14
15
|
export declare function createEngineCapReader<R>(spec: EngineCapReaderSpec<R>): EngineCapReader<R>;
|
|
15
|
-
export declare function unreadableReadingDetail(subject?: string): string;
|
|
16
|
+
export declare function unreadableReadingDetail(subject?: string, lang?: UiLanguage): string;
|
|
16
17
|
export type StoreSeat = {
|
|
17
18
|
kind: 'object';
|
|
18
19
|
store: object;
|
package/dist/engineCapReader.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { engineCapsLandingOf } from './engineCapsCache.js';
|
|
2
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
2
3
|
import { ownDataField } from './ownKey.js';
|
|
3
|
-
const
|
|
4
|
-
const
|
|
4
|
+
const UNOBSERVED = Object.freeze({ kind: 'unobserved' });
|
|
5
|
+
const UNREADABLE = Object.freeze({ kind: 'unreadable' });
|
|
6
|
+
const unobserved = () => UNOBSERVED;
|
|
7
|
+
const unreadable = () => UNREADABLE;
|
|
5
8
|
function freezeReading(reading, seen = new Set()) {
|
|
6
9
|
if (reading === null || typeof reading !== 'object' || seen.has(reading))
|
|
7
10
|
return reading;
|
|
@@ -49,9 +52,8 @@ export function createEngineCapReader(spec) {
|
|
|
49
52
|
},
|
|
50
53
|
};
|
|
51
54
|
}
|
|
52
|
-
export function unreadableReadingDetail(subject) {
|
|
53
|
-
|
|
54
|
-
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`;
|
|
55
|
+
export function unreadableReadingDetail(subject, lang) {
|
|
56
|
+
return renderMessage(typeof subject === 'string' && subject.length > 0 ? msg('notice.capability.unreadable.subject', { subject }) : msg('notice.capability.unreadable.bare'), lang);
|
|
55
57
|
}
|
|
56
58
|
export function storeSeatOf(caps) {
|
|
57
59
|
try {
|
|
@@ -6,6 +6,11 @@ export type EngineCapsLanding = {
|
|
|
6
6
|
} | {
|
|
7
7
|
readonly kind: 'unreadable';
|
|
8
8
|
};
|
|
9
|
+
export interface EngineCapsChange {
|
|
10
|
+
readonly kind: 'landed' | 'invalidated' | 'replaced';
|
|
11
|
+
readonly baseUrl: string;
|
|
12
|
+
readonly generation: number;
|
|
13
|
+
}
|
|
9
14
|
export declare function engineCapsGeneration(baseUrl: string): number;
|
|
10
15
|
export declare function engineCapsLandingOf(baseUrl: string | undefined): EngineCapsLanding;
|
|
11
16
|
export declare function kickEngineCapsProbe(baseUrl: string, probe: () => Promise<unknown>): void;
|
|
@@ -42,6 +47,9 @@ export declare function engineCapString(baseUrl: string | undefined, key: string
|
|
|
42
47
|
export declare function invalidateEngineCaps(baseUrl: string | undefined, probe?: () => Promise<unknown>): void;
|
|
43
48
|
export type EngineCapsProbeRotation = 'started' | 'registered' | 'ignored';
|
|
44
49
|
export declare function rotateEngineCapsProbe(baseUrl: string | undefined, probe: () => Promise<unknown>): EngineCapsProbeRotation;
|
|
50
|
+
export type EngineCapsReprobe = 'reprobed' | 'no_probe' | 'ignored';
|
|
51
|
+
export declare function invalidateEngineCapsAndReprobe(baseUrl: string | undefined): EngineCapsReprobe;
|
|
52
|
+
export declare function registerCapsChangeDelivery(baseUrl: string | undefined, deliver: (change: EngineCapsChange) => void): () => void;
|
|
45
53
|
export declare function refreshEngineCapsOnce(baseUrl: string | undefined, opts?: {
|
|
46
54
|
withinMs?: number;
|
|
47
55
|
}): Promise<'settled' | 'timed_out' | 'no_probe'>;
|
package/dist/engineCapsCache.js
CHANGED
|
@@ -4,11 +4,11 @@ const NOT_LANDED = Object.freeze({ kind: 'not_landed' });
|
|
|
4
4
|
const capsByBase = new Map();
|
|
5
5
|
const inFlight = new Set();
|
|
6
6
|
const settleByBase = new Map();
|
|
7
|
-
const
|
|
7
|
+
const stateByBase = new Map();
|
|
8
8
|
const probeByBase = new Map();
|
|
9
9
|
const refreshByBase = new Map();
|
|
10
10
|
function capsGeneration(baseUrl) {
|
|
11
|
-
return
|
|
11
|
+
return stateByBase.get(baseUrl)?.gen ?? 0;
|
|
12
12
|
}
|
|
13
13
|
export function engineCapsGeneration(baseUrl) {
|
|
14
14
|
return capsGeneration(baseUrl);
|
|
@@ -169,6 +169,7 @@ function landCapsSnapshot(baseUrl, gen, caps) {
|
|
|
169
169
|
? Object.freeze({ kind: 'unreadable' })
|
|
170
170
|
: Object.freeze({ kind: 'landed', caps: snapshot });
|
|
171
171
|
capsByBase.set(baseUrl, record);
|
|
172
|
+
publishCapsChange(baseUrl, 'landed');
|
|
172
173
|
return 'landed';
|
|
173
174
|
}
|
|
174
175
|
function snapshotCapsBody(body) {
|
|
@@ -355,18 +356,25 @@ export function invalidateEngineCaps(baseUrl, probe) {
|
|
|
355
356
|
return;
|
|
356
357
|
if (probe === undefined)
|
|
357
358
|
probeByBase.delete(baseUrl);
|
|
358
|
-
const
|
|
359
|
+
const hadLanding = capsByBase.has(baseUrl);
|
|
360
|
+
const hadState = hadLanding ||
|
|
359
361
|
inFlight.has(baseUrl) ||
|
|
360
362
|
settleByBase.has(baseUrl) ||
|
|
361
|
-
|
|
363
|
+
stateByBase.get(baseUrl)?.gen !== undefined;
|
|
362
364
|
if (hadState) {
|
|
363
|
-
|
|
365
|
+
const st = stateByBase.get(baseUrl);
|
|
366
|
+
if (st === undefined)
|
|
367
|
+
stateByBase.set(baseUrl, { gen: 1, subscribers: new Set() });
|
|
368
|
+
else
|
|
369
|
+
st.gen = capsGeneration(baseUrl) + 1;
|
|
364
370
|
capsByBase.delete(baseUrl);
|
|
365
371
|
inFlight.delete(baseUrl);
|
|
366
372
|
settleByBase.get(baseUrl)?.wake();
|
|
367
373
|
}
|
|
368
374
|
if (probe !== undefined)
|
|
369
375
|
kickEngineCapsProbe(baseUrl, probe);
|
|
376
|
+
if (hadLanding)
|
|
377
|
+
publishCapsChange(baseUrl, probe !== undefined ? 'replaced' : 'invalidated');
|
|
370
378
|
}
|
|
371
379
|
export function rotateEngineCapsProbe(baseUrl, probe) {
|
|
372
380
|
try {
|
|
@@ -381,6 +389,51 @@ export function rotateEngineCapsProbe(baseUrl, probe) {
|
|
|
381
389
|
return 'ignored';
|
|
382
390
|
}
|
|
383
391
|
}
|
|
392
|
+
export function invalidateEngineCapsAndReprobe(baseUrl) {
|
|
393
|
+
try {
|
|
394
|
+
if (typeof baseUrl !== 'string' || baseUrl === '')
|
|
395
|
+
return 'ignored';
|
|
396
|
+
const probe = probeByBase.get(baseUrl);
|
|
397
|
+
if (probe === undefined)
|
|
398
|
+
return 'no_probe';
|
|
399
|
+
invalidateEngineCaps(baseUrl, probe);
|
|
400
|
+
return 'reprobed';
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
return 'ignored';
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
export function registerCapsChangeDelivery(baseUrl, deliver) {
|
|
407
|
+
if (typeof baseUrl !== 'string' || baseUrl === '' || typeof deliver !== 'function')
|
|
408
|
+
return () => { };
|
|
409
|
+
let st = stateByBase.get(baseUrl);
|
|
410
|
+
if (st === undefined) {
|
|
411
|
+
st = { gen: undefined, subscribers: new Set() };
|
|
412
|
+
stateByBase.set(baseUrl, st);
|
|
413
|
+
}
|
|
414
|
+
const sub = { deliver, live: true };
|
|
415
|
+
const owner = st;
|
|
416
|
+
owner.subscribers.add(sub);
|
|
417
|
+
return () => {
|
|
418
|
+
if (!sub.live)
|
|
419
|
+
return;
|
|
420
|
+
sub.live = false;
|
|
421
|
+
owner.subscribers.delete(sub);
|
|
422
|
+
if (owner.subscribers.size === 0 && owner.gen === undefined && stateByBase.get(baseUrl) === owner)
|
|
423
|
+
stateByBase.delete(baseUrl);
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
function publishCapsChange(baseUrl, kind) {
|
|
427
|
+
const subs = stateByBase.get(baseUrl)?.subscribers;
|
|
428
|
+
if (subs === undefined || subs.size === 0)
|
|
429
|
+
return;
|
|
430
|
+
const change = Object.freeze({ kind, baseUrl, generation: capsGeneration(baseUrl) });
|
|
431
|
+
for (const sub of [...subs]) {
|
|
432
|
+
if (!sub.live)
|
|
433
|
+
continue;
|
|
434
|
+
sub.deliver(change);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
384
437
|
export async function refreshEngineCapsOnce(baseUrl, opts) {
|
|
385
438
|
try {
|
|
386
439
|
if (typeof baseUrl !== 'string' || baseUrl === '')
|
|
@@ -454,7 +507,7 @@ export function __resetEngineCapsCacheForTests() {
|
|
|
454
507
|
capsByBase.clear();
|
|
455
508
|
inFlight.clear();
|
|
456
509
|
settleByBase.clear();
|
|
457
|
-
|
|
510
|
+
stateByBase.clear();
|
|
458
511
|
probeByBase.clear();
|
|
459
512
|
refreshByBase.clear();
|
|
460
513
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { registerCapsChangeDelivery } from './engineCapsCache.js';
|
|
2
|
+
import { invokeHostCallbackIsolated } from './hostCallbackGuard.js';
|
|
3
|
+
export function onEngineCapsChange(baseUrl, listener) {
|
|
4
|
+
if (typeof listener !== 'function')
|
|
5
|
+
return () => { };
|
|
6
|
+
return registerCapsChangeDelivery(baseUrl, (change) => {
|
|
7
|
+
invokeHostCallbackIsolated('engineCapsChange: listener', () => listener(change));
|
|
8
|
+
});
|
|
9
|
+
}
|