@sema-agent/client-core 0.109.0 → 0.110.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +173 -0
- package/README.md +46 -22
- package/dist/adapt/arms.js +20 -7
- package/dist/adapter/downstream/eventToSdkMessage.js +11 -6
- package/dist/declared/supportFloorDeclared.js +1 -1
- package/dist/displayUntrusted.js +132 -14
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +3 -0
- package/dist/engineHealthFacts.d.ts +9 -0
- package/dist/engineHealthFacts.js +21 -1
- package/dist/engineInlineTaskStats.d.ts +4 -3
- package/dist/engineInlineTaskStats.js +18 -2
- package/dist/engineNoticeCodes.d.ts +10 -0
- package/dist/engineNoticeCodes.js +33 -1
- package/dist/engineRepoint.d.ts +140 -0
- package/dist/engineRepoint.js +285 -0
- package/dist/engineRowRef.js +2 -0
- package/dist/engineSessionMessages.d.ts +2 -1
- package/dist/engineSessionMessages.js +5 -0
- package/dist/errorSupplementRoles.js +2 -1
- package/dist/fleet/fleetProjection.js +3 -2
- package/dist/generated/engineFactTables.d.ts +2 -0
- package/dist/generated/engineFactTables.js +12 -0
- package/dist/generated/sdkFactTables.d.ts +1 -0
- package/dist/generated/sdkFactTables.js +4 -0
- package/dist/hitl/approvalAskers.d.ts +6 -0
- package/dist/hitl/approvalAskers.js +30 -0
- package/dist/hitl/approvalCardReasons.js +6 -3
- package/dist/hitl/approvalRequestFrameReading.d.ts +7 -0
- package/dist/hitl/approvalRequestFrameReading.js +11 -0
- package/dist/hitl/approvalResolution.d.ts +8 -1
- package/dist/hitl/approvalResolution.js +4 -0
- package/dist/hitl/askGateWire.js +0 -2
- package/dist/hitl/automaticAnswerVerdict.js +2 -2
- package/dist/hitl/decisionConflict.js +6 -3
- package/dist/hitl/decisionRefusal.js +1 -0
- package/dist/hitl/decisionSend.d.ts +3 -0
- package/dist/hitl/decisionSend.js +29 -11
- package/dist/hitl/editedApprovalAcceptance.d.ts +25 -0
- package/dist/hitl/editedApprovalAcceptance.js +26 -0
- package/dist/hitl/frameRouter.js +4 -18
- package/dist/hitl/gateLedger.d.ts +0 -4
- package/dist/hitl/gateLedger.js +0 -19
- package/dist/hitl/hitlBridge.d.ts +1 -0
- package/dist/hitl/hitlBridge.js +4 -4
- package/dist/hitl/hitlHostSurface.d.ts +1 -0
- package/dist/hitl/hitlHostSurface.js +7 -2
- package/dist/hitl/hostWithdrawal.d.ts +15 -0
- package/dist/hitl/hostWithdrawal.js +38 -0
- package/dist/hitl/parkResolver.js +25 -9
- package/dist/hitl/persistedRulesWire.js +2 -2
- package/dist/hitl/planReviewWire.js +14 -4
- package/dist/hitl/sessionPolicyWire.js +6 -4
- package/dist/hitl/standingRows.d.ts +1 -0
- package/dist/hitl/standingRows.js +15 -1
- package/dist/hitl/toolApprovalWire.d.ts +35 -8
- package/dist/hitl/toolApprovalWire.js +235 -33
- package/dist/hooksWireCaps.js +31 -1
- package/dist/hostTurnSettings.d.ts +10 -4
- package/dist/hostTurnSettings.js +112 -5
- package/dist/i18n/messages.en.d.ts +83 -0
- package/dist/i18n/messages.en.js +86 -2
- package/dist/i18n/messages.zh.js +96 -2
- package/dist/index.d.ts +21 -7
- package/dist/index.js +14 -4
- package/dist/inheritEnvCapability.js +2 -0
- package/dist/inputAuthor.d.ts +16 -0
- package/dist/inputAuthor.js +44 -0
- package/dist/interruptRefusalNote.d.ts +2 -0
- package/dist/interruptRefusalNote.js +17 -0
- package/dist/liveModelCatalog.d.ts +2 -0
- package/dist/liveModelCatalog.js +21 -7
- package/dist/liveQuestionStore.d.ts +4 -1
- package/dist/liveQuestionStore.js +12 -3
- package/dist/mcpEngineLeg.d.ts +3 -0
- package/dist/mcpEngineLeg.js +38 -1
- package/dist/mcpPanel.js +2 -0
- package/dist/mcpReconnect.d.ts +9 -1
- package/dist/mcpReconnect.js +121 -16
- package/dist/modelCapabilityProbe.js +4 -3
- package/dist/modsFace.d.ts +8 -1
- package/dist/modsFace.js +27 -0
- package/dist/notifications.d.ts +17 -6
- package/dist/notifications.js +67 -19
- package/dist/ownKey.d.ts +0 -5
- package/dist/ownKey.js +0 -7
- package/dist/peerFrames.d.ts +40 -2
- package/dist/peerFrames.js +158 -3
- package/dist/pluginHooksWire.d.ts +2 -1
- package/dist/pluginHooksWire.js +56 -1
- package/dist/replayBody.js +10 -2
- package/dist/request/taskRequest.d.ts +5 -0
- package/dist/request/taskRequest.js +138 -21
- package/dist/resumeRefusalCopy.d.ts +1 -3
- package/dist/resumeRefusalCopy.js +2 -1
- package/dist/retryStatus.d.ts +2 -2
- package/dist/retryStatus.js +2 -0
- package/dist/seam.d.ts +12 -1
- package/dist/seam.js +7 -1
- package/dist/seatContract.d.ts +86 -9
- package/dist/seatContract.js +196 -7
- package/dist/sessionBackground.js +2 -1
- package/dist/sessionBackgroundHandoff.js +2 -1
- package/dist/sessionEngine.d.ts +2 -0
- package/dist/sessionEngine.js +111 -0
- package/dist/sessionMemoryStatus.d.ts +2 -1
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +28 -0
- package/dist/sseIdleTriage.d.ts +13 -1
- package/dist/sseIdleTriage.js +24 -6
- package/dist/subagent/engineSubagentTail.js +6 -0
- package/dist/terminalStatuses.d.ts +1 -0
- package/dist/terminalStatuses.js +4 -1
- package/dist/turnFailurePresentation.js +9 -2
- package/dist/typePins.d.ts +11 -0
- package/dist/usageAnalytics.d.ts +17 -0
- package/dist/usageAnalytics.js +44 -2
- package/dist/wireFailureShape.d.ts +2 -5
- package/dist/wireFailureShape.js +10 -20
- package/dist/wireRefusalCopy.d.ts +10 -0
- package/dist/wireRefusalCopy.js +76 -0
- package/docs/INTEGRATION-CLIENTS.md +2126 -20
- package/package.json +3 -3
package/dist/mcpReconnect.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { capForDisplay } from './fleetTaskDesc.js';
|
|
2
2
|
import { ownDataField } from './ownKey.js';
|
|
3
3
|
import { isSessionIdPathSegment } from './sessionIdSegment.js';
|
|
4
|
-
import { inSlotReadOf, inValueOf } from './wireFailureShape.js';
|
|
4
|
+
import { inSlotReadOf, inValueOf, slotReadOf } from './wireFailureShape.js';
|
|
5
5
|
import { readMcpAuthorization } from './mcpLiveness.js';
|
|
6
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
6
7
|
export const MCP_RECONNECT_OUTCOMES = Object.freeze(['accepted', 'refused', 'unsupported']);
|
|
7
8
|
export const MCP_RECONNECT_TRANSACTION_NOTICE = 'Reconnecting closes the current connection before dialing again. On a healthy server this is a transaction, ' +
|
|
8
9
|
'not a refresh: a failed re-dial leaves the server down and withdraws its tools from the model until a later re-dial succeeds.';
|
|
9
|
-
export const MCP_RECONNECT_UNSETTLED_NOTICE = '
|
|
10
|
-
"Check the server's state before re-dialing it again — a second request that arrives after the dial has settled closes the connection and dials once more.";
|
|
10
|
+
export const MCP_RECONNECT_UNSETTLED_NOTICE = renderMessage(msg('session.mcpReconnect.unsettled'));
|
|
11
11
|
const UNSETTLED_CODE = 'state.mcp_reconnect_unsettled';
|
|
12
12
|
const _sdkClientIsAnInjection = [true];
|
|
13
13
|
void _sdkClientIsAnInjection;
|
|
@@ -196,23 +196,128 @@ export function projectMcpReconnectCapability(caps) {
|
|
|
196
196
|
return undefined;
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
|
-
|
|
199
|
+
function reasonTailOf(reason, lang) {
|
|
200
|
+
return reason === undefined ? '' : renderMessage(msg('session.mcpReconnect.reasonTail', { reason }), lang);
|
|
201
|
+
}
|
|
202
|
+
function outcomeSentence(f, lang) {
|
|
203
|
+
switch (f.outcome) {
|
|
204
|
+
case 'accepted':
|
|
205
|
+
return renderMessage(msg(f.toolCount === 1 ? 'session.mcpReconnect.accepted.one' : 'session.mcpReconnect.accepted.other', { server: f.name, toolCount: f.toolCount, added: f.added, removed: f.removed }), lang);
|
|
206
|
+
case 'refused': {
|
|
207
|
+
const why = reasonTailOf(f.reason, lang);
|
|
208
|
+
if (f.roster === undefined)
|
|
209
|
+
return renderMessage(msg('session.mcpReconnect.refused.untouched', { server: f.name, why }), lang);
|
|
210
|
+
if (f.roster === 0)
|
|
211
|
+
return renderMessage(msg('session.mcpReconnect.refused.noTools', { server: f.name, why }), lang);
|
|
212
|
+
return renderMessage(msg(f.roster === 1 ? 'session.mcpReconnect.refused.listed.one' : 'session.mcpReconnect.refused.listed.other', { server: f.name, toolCount: f.roster, why }), lang);
|
|
213
|
+
}
|
|
214
|
+
case 'unsupported':
|
|
215
|
+
return renderMessage(msg('session.mcpReconnect.undeclared', { server: f.name, why: reasonTailOf(f.reason, lang) }), lang);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
export function mcpReconnectOutcomeDetail(view, lang) {
|
|
200
219
|
const name = capForDisplay(view.server, RECONNECT_WORD_MAX);
|
|
201
220
|
switch (view.outcome) {
|
|
202
221
|
case 'accepted':
|
|
203
|
-
return
|
|
222
|
+
return outcomeSentence({ outcome: 'accepted', name, toolCount: view.toolCount, added: view.added.length, removed: view.removed.length }, lang);
|
|
223
|
+
case 'refused':
|
|
224
|
+
return outcomeSentence({ outcome: 'refused', name, roster: view.toolNames?.length, reason: view.reason }, lang);
|
|
225
|
+
case 'unsupported':
|
|
226
|
+
return outcomeSentence({ outcome: 'unsupported', name, reason: view.reason }, lang);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function verdictDetailKey(kind) {
|
|
230
|
+
switch (kind) {
|
|
231
|
+
case 'not_running':
|
|
232
|
+
return 'session.mcpReconnect.notRunning';
|
|
233
|
+
case 'unsupported':
|
|
234
|
+
return 'session.mcpReconnect.unsupported';
|
|
235
|
+
case 'not_found':
|
|
236
|
+
return 'session.mcpReconnect.notFound';
|
|
237
|
+
case 'invalid':
|
|
238
|
+
return 'session.mcpReconnect.invalid';
|
|
239
|
+
case 'failed':
|
|
240
|
+
return 'session.mcpReconnect.failed';
|
|
241
|
+
case 'no_session':
|
|
242
|
+
return 'session.mcpReconnect.noSession';
|
|
243
|
+
case 'unavailable':
|
|
244
|
+
return 'session.mcpReconnect.unavailable';
|
|
245
|
+
case 'unsettled':
|
|
246
|
+
return 'session.mcpReconnect.unsettled';
|
|
247
|
+
default:
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function fieldOf(o, key) {
|
|
252
|
+
const s = slotReadOf(o, key);
|
|
253
|
+
return s.presence === 'present' ? { kind: 'value', value: s.value } : s.presence === 'absent' ? { kind: 'absent' } : { kind: 'unreadable' };
|
|
254
|
+
}
|
|
255
|
+
function okOutcomeFactsOf(verdict, server) {
|
|
256
|
+
const slot = fieldOf(verdict, 'result');
|
|
257
|
+
if (slot.kind !== 'value')
|
|
258
|
+
return undefined;
|
|
259
|
+
const r = slot.value;
|
|
260
|
+
if (r === null || typeof r !== 'object' || Array.isArray(r))
|
|
261
|
+
return undefined;
|
|
262
|
+
const outcome = fieldOf(r, 'outcome');
|
|
263
|
+
const echoed = fieldOf(r, 'server');
|
|
264
|
+
if (outcome.kind !== 'value' || echoed.kind !== 'value' || echoed.value !== server)
|
|
265
|
+
return undefined;
|
|
266
|
+
const rs = fieldOf(r, 'reason');
|
|
267
|
+
if (rs.kind === 'unreadable' || (rs.kind === 'value' && typeof rs.value !== 'string'))
|
|
268
|
+
return undefined;
|
|
269
|
+
const reason = rs.kind === 'value' ? rs.value : undefined;
|
|
270
|
+
const name = capForDisplay(server, RECONNECT_WORD_MAX);
|
|
271
|
+
switch (outcome.value) {
|
|
272
|
+
case 'unsupported':
|
|
273
|
+
return { outcome: 'unsupported', name, reason };
|
|
274
|
+
case 'accepted': {
|
|
275
|
+
const toolCount = fieldOf(r, 'toolCount');
|
|
276
|
+
const added = fieldOf(r, 'added');
|
|
277
|
+
const removed = fieldOf(r, 'removed');
|
|
278
|
+
if (toolCount.kind !== 'value' || added.kind !== 'value' || removed.kind !== 'value')
|
|
279
|
+
return undefined;
|
|
280
|
+
const n = toolCount.value;
|
|
281
|
+
const addedList = stringList(added.value);
|
|
282
|
+
const removedList = stringList(removed.value);
|
|
283
|
+
if (typeof n !== 'number' || !Number.isInteger(n) || n < 0 || addedList === undefined || removedList === undefined)
|
|
284
|
+
return undefined;
|
|
285
|
+
return { outcome: 'accepted', name, toolCount: n, added: addedList.length, removed: removedList.length };
|
|
286
|
+
}
|
|
204
287
|
case 'refused': {
|
|
205
|
-
const
|
|
206
|
-
if (
|
|
207
|
-
return
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
288
|
+
const names = fieldOf(r, 'toolNames');
|
|
289
|
+
if (names.kind === 'unreadable')
|
|
290
|
+
return undefined;
|
|
291
|
+
if (names.kind === 'absent')
|
|
292
|
+
return { outcome: 'refused', name, roster: undefined, reason };
|
|
293
|
+
const roster = stringList(names.value);
|
|
294
|
+
if (roster === undefined)
|
|
295
|
+
return undefined;
|
|
296
|
+
return { outcome: 'refused', name, roster: roster.length, reason };
|
|
213
297
|
}
|
|
214
|
-
|
|
215
|
-
return
|
|
216
|
-
|
|
298
|
+
default:
|
|
299
|
+
return undefined;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
export function mcpReconnectVerdictDetail(verdict, server, lang) {
|
|
303
|
+
try {
|
|
304
|
+
if (verdict === null || typeof verdict !== 'object')
|
|
305
|
+
return undefined;
|
|
306
|
+
const kindSlot = slotReadOf(verdict, 'kind');
|
|
307
|
+
if (kindSlot.presence !== 'present' || typeof kindSlot.value !== 'string')
|
|
308
|
+
return undefined;
|
|
309
|
+
if (!nonEmpty(server))
|
|
310
|
+
return undefined;
|
|
311
|
+
if (kindSlot.value === 'ok') {
|
|
312
|
+
const facts = okOutcomeFactsOf(verdict, server);
|
|
313
|
+
return facts === undefined ? undefined : outcomeSentence(facts, lang);
|
|
314
|
+
}
|
|
315
|
+
const key = verdictDetailKey(kindSlot.value);
|
|
316
|
+
if (key === undefined)
|
|
317
|
+
return undefined;
|
|
318
|
+
return renderMessage(msg(key, { server: capForDisplay(server, RECONNECT_WORD_MAX) }), lang);
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
return undefined;
|
|
217
322
|
}
|
|
218
323
|
}
|
|
@@ -128,15 +128,16 @@ export async function probeModelCapability(entry, send) {
|
|
|
128
128
|
evidence: { baseline, attempts, lowEffortAccepted: !low.refused },
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
|
+
const _capabilityBitsPin = true;
|
|
132
|
+
void _capabilityBitsPin;
|
|
131
133
|
export function applyProbeToEntry(entry, result) {
|
|
132
134
|
if (result.verdict === 'inconclusive')
|
|
133
135
|
return entry;
|
|
134
136
|
const compatIn = typeof entry.compat === 'object' && entry.compat !== null && !Array.isArray(entry.compat)
|
|
135
137
|
? entry.compat
|
|
136
138
|
: undefined;
|
|
137
|
-
if (result.verdict === 'no_reasoning')
|
|
138
|
-
return
|
|
139
|
-
}
|
|
139
|
+
if (result.verdict === 'no_reasoning')
|
|
140
|
+
return entry;
|
|
140
141
|
if (result.verdict === 'disabled_via' && typeof result.thinkingFormat === 'string') {
|
|
141
142
|
return { ...entry, reasoning: true, compat: { ...compatIn, thinkingFormat: result.thinkingFormat } };
|
|
142
143
|
}
|
package/dist/modsFace.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import type { WiringManifestModRefusedView } from './adapter/downstream/eventToSdkMessage.js';
|
|
1
|
+
import type { WiringManifestModRefusedView, WiringManifestModView } from './adapter/downstream/eventToSdkMessage.js';
|
|
2
|
+
import type { SessionModsView } from './seatContract.js';
|
|
3
|
+
import type { DeviceUnreadable } from './deviceRebind.js';
|
|
2
4
|
import type { EngineNoticeChromeEvent } from './seam.js';
|
|
3
5
|
import type { UiLanguage } from './env/uiLanguage.js';
|
|
6
|
+
import { type ApprovalRequestedBy } from './hitl/approvalAskers.js';
|
|
4
7
|
export declare const MOD_LOADER_VERBS: readonly ["list", "load", "unload", "status"];
|
|
5
8
|
export type ModLoaderVerb = (typeof MOD_LOADER_VERBS)[number];
|
|
6
9
|
export declare function readModRegistrationRefusedNotice(ev: EngineNoticeChromeEvent): WiringManifestModRefusedView | undefined;
|
|
10
|
+
export declare function sessionModsOf(manifest: {
|
|
11
|
+
readonly mods?: readonly WiringManifestModView[];
|
|
12
|
+
} | null | undefined): SessionModsView | DeviceUnreadable;
|
|
7
13
|
export declare function modCardSentence(input: object | null | undefined, lang?: UiLanguage): string | undefined;
|
|
14
|
+
export declare function approvalRequestedBySentence(by: ApprovalRequestedBy | null | undefined, lang?: UiLanguage): string | undefined;
|
|
8
15
|
export declare function modLoaderFailureSentence(name: string, error: unknown, lang?: UiLanguage): string;
|
package/dist/modsFace.js
CHANGED
|
@@ -4,6 +4,7 @@ import { displayUntrusted } from './displayUntrusted.js';
|
|
|
4
4
|
import { WIRE_FAILURE_UNRENDERABLE_TEXT, wireFailureTextsOf } from './wireFailureShape.js';
|
|
5
5
|
import { gateOutcomeOf, isDeniedGate, rewriteExtensionNamesOf, toolInputRewriteOf } from './gateOutcome.js';
|
|
6
6
|
import { guardedRead, readOwnDataNonEmptyString, readOwnDataValue, toolResultBlockOf } from './ownKey.js';
|
|
7
|
+
import { requestedByViewOf } from './hitl/approvalAskers.js';
|
|
7
8
|
const isCardRecordObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
8
9
|
export const MOD_LOADER_VERBS = Object.freeze(['list', 'load', 'unload', 'status']);
|
|
9
10
|
const modRowOf = (r) => modRowsOf([r])?.[0];
|
|
@@ -21,6 +22,18 @@ export function readModRegistrationRefusedNotice(ev) {
|
|
|
21
22
|
return undefined;
|
|
22
23
|
}
|
|
23
24
|
}
|
|
25
|
+
export function sessionModsOf(manifest) {
|
|
26
|
+
try {
|
|
27
|
+
if (!isCardRecordObject(manifest))
|
|
28
|
+
return sessionModsUnreadable();
|
|
29
|
+
const rows = modRowsOf(readOwnDataValue(manifest, 'mods'));
|
|
30
|
+
return rows === undefined ? sessionModsUnreadable() : Object.freeze({ rows: Object.freeze(rows.slice()) });
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return sessionModsUnreadable();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const sessionModsUnreadable = () => Object.freeze({ kind: 'unreadable', why: renderMessage(msg('config.mods.session.unreadable')) });
|
|
24
37
|
const MOD_NAME_SHOWN_MAX = 64;
|
|
25
38
|
const MOD_REASON_SHOWN_MAX = 160;
|
|
26
39
|
const shownName = (s) => displayUntrusted(s, { blanks: true, max: MOD_NAME_SHOWN_MAX });
|
|
@@ -54,6 +67,20 @@ export function modCardSentence(input, lang) {
|
|
|
54
67
|
return undefined;
|
|
55
68
|
}
|
|
56
69
|
}
|
|
70
|
+
export function approvalRequestedBySentence(by, lang) {
|
|
71
|
+
try {
|
|
72
|
+
const view = requestedByViewOf(by);
|
|
73
|
+
if (view === undefined)
|
|
74
|
+
return undefined;
|
|
75
|
+
const name = shownName(view.name);
|
|
76
|
+
if (name.trim() === '')
|
|
77
|
+
return undefined;
|
|
78
|
+
return renderMessage(msg('config.mods.request.by', { by: name }), lang);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
57
84
|
export function modLoaderFailureSentence(name, error, lang) {
|
|
58
85
|
const shown = guardedRead(() => (typeof name === 'string' ? shownName(name) : undefined)) ?? '';
|
|
59
86
|
const { reason } = wireFailureTextsOf(error);
|
package/dist/notifications.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface TaskNotificationFields {
|
|
|
9
9
|
outputFile?: string;
|
|
10
10
|
diagnostics?: string;
|
|
11
11
|
result?: string;
|
|
12
|
+
error?: string;
|
|
12
13
|
stoppedBy?: string;
|
|
13
14
|
partial?: boolean;
|
|
14
15
|
exitCode?: number;
|
|
@@ -93,11 +94,21 @@ export declare function noteWorkflowCompletionCardEnqueued(runId: string): void;
|
|
|
93
94
|
export declare function listNotifiedRuns(): string[];
|
|
94
95
|
export declare function listWorkflowCompletionCardsEnqueued(): string[];
|
|
95
96
|
export declare function isWorkflowCompletionCardEnqueued(runId: string): boolean;
|
|
96
|
-
type
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
export type WorkflowRunReader = (runId: string) => Promise<unknown>;
|
|
98
|
+
export type WorkflowRunTerminalReading = {
|
|
99
|
+
readonly state: 'running';
|
|
100
|
+
} | {
|
|
101
|
+
readonly state: 'awaiting approval';
|
|
102
|
+
} | {
|
|
103
|
+
readonly state: 'completed' | 'failed';
|
|
104
|
+
readonly result?: string;
|
|
105
|
+
readonly error?: string;
|
|
106
|
+
readonly pointer: 'absent';
|
|
107
|
+
} | {
|
|
108
|
+
readonly state: 'unknown';
|
|
109
|
+
readonly why: 'body_unreadable' | 'status_unreadable' | 'status_unrecognized';
|
|
110
|
+
};
|
|
111
|
+
export declare function workflowRunTerminalReadingOf(body: unknown): WorkflowRunTerminalReading;
|
|
101
112
|
export declare function outstandingWorkflowCount(): number;
|
|
102
113
|
export declare function outstandingDeliverableWorkflowCount(): number;
|
|
103
114
|
export declare function subscribeOutstandingWorkflows(listener: () => void): () => void;
|
|
@@ -111,7 +122,7 @@ export interface NotificationDropCounters {
|
|
|
111
122
|
bgWatchCollectedUnprobed: number;
|
|
112
123
|
}
|
|
113
124
|
export declare function notificationDropCounters(): NotificationDropCounters;
|
|
114
|
-
export declare function
|
|
125
|
+
export declare function installWorkflowRunReader(reader: WorkflowRunReader | null): void;
|
|
115
126
|
type BgTaskStatusProbe = (taskId: string) => Promise<{
|
|
116
127
|
terminal: boolean;
|
|
117
128
|
status: string;
|
package/dist/notifications.js
CHANGED
|
@@ -2,10 +2,11 @@ import { hostEnv } from './hostEnv.js';
|
|
|
2
2
|
import { unrefTimer } from './unrefTimer.js';
|
|
3
3
|
import { clearEnginePanelTaskResidentByWire, publishEngineAgentPanelEvent, } from './engineAgentPanelStore.js';
|
|
4
4
|
import { panelEndFact } from './panelReduce.js';
|
|
5
|
-
import { isCoreTaskNotificationTerminal, isCoreTaskNotificationTerminalNotSuccess } from './terminalStatuses.js';
|
|
5
|
+
import { isCoreTaskNotificationTerminal, isCoreTaskNotificationTerminalNotSuccess, isCoreWorkflowRunParkedEnd, isCoreWorkflowRunTerminal } from './terminalStatuses.js';
|
|
6
6
|
import { cycleSeqValue } from './cycleOrder.js';
|
|
7
7
|
import { CORE_ENGINE_AUTHORITY_ENVELOPE_TAGS } from './generated/engineFactTables.js';
|
|
8
8
|
import { guardedRead, ownSnapshot, ownSnapshotRecord, ownSnapshotTyped, readOwnDataValue, workflowCompletionExtrasOf } from './ownKey.js';
|
|
9
|
+
import { displayUntrusted } from './displayUntrusted.js';
|
|
9
10
|
function escapeXml(v) {
|
|
10
11
|
return v.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
11
12
|
}
|
|
@@ -102,6 +103,7 @@ export function freezeTaskNotificationFields(n) {
|
|
|
102
103
|
...(n.outputFile !== undefined ? { outputFile: n.outputFile } : {}),
|
|
103
104
|
...(n.diagnostics !== undefined ? { diagnostics: n.diagnostics } : {}),
|
|
104
105
|
...(n.result !== undefined ? { result: n.result } : {}),
|
|
106
|
+
...(n.error !== undefined ? { error: n.error } : {}),
|
|
105
107
|
...(n.stoppedBy !== undefined ? { stoppedBy: n.stoppedBy } : {}),
|
|
106
108
|
...(n.partial !== undefined ? { partial: n.partial } : {}),
|
|
107
109
|
...(n.exitCode !== undefined ? { exitCode: n.exitCode } : {}),
|
|
@@ -128,7 +130,7 @@ export function taskNotificationOf(carrier) {
|
|
|
128
130
|
if (typeof taskId !== 'string' || taskId.length === 0 || typeof status !== 'string' || typeof summary !== 'string')
|
|
129
131
|
return undefined;
|
|
130
132
|
const out = { taskId, status, summary };
|
|
131
|
-
for (const k of ['taskType', 'toolUseId', 'outputFile', 'diagnostics', 'result', 'stoppedBy', 'externalSource']) {
|
|
133
|
+
for (const k of ['taskType', 'toolUseId', 'outputFile', 'diagnostics', 'result', 'error', 'stoppedBy', 'externalSource']) {
|
|
132
134
|
const v = slot(k);
|
|
133
135
|
if (typeof v === 'string')
|
|
134
136
|
out[k] = v;
|
|
@@ -478,6 +480,50 @@ const cardEnqueuedRunIds = new Set();
|
|
|
478
480
|
export function isWorkflowCompletionCardEnqueued(runId) {
|
|
479
481
|
return cardEnqueuedRunIds.has(runId);
|
|
480
482
|
}
|
|
483
|
+
export function workflowRunTerminalReadingOf(body) {
|
|
484
|
+
const snap = probeAnswerSnapshot(body);
|
|
485
|
+
if (snap === null)
|
|
486
|
+
return Object.freeze({ state: 'unknown', why: 'body_unreadable' });
|
|
487
|
+
const status = guardedRead(() => readOwnDataValue(snap, 'status'));
|
|
488
|
+
if (typeof status !== 'string')
|
|
489
|
+
return Object.freeze({ state: 'unknown', why: 'status_unreadable' });
|
|
490
|
+
if (status === 'running')
|
|
491
|
+
return Object.freeze({ state: 'running' });
|
|
492
|
+
if (!isCoreWorkflowRunTerminal(status))
|
|
493
|
+
return Object.freeze({ state: 'unknown', why: 'status_unrecognized' });
|
|
494
|
+
if (isCoreWorkflowRunParkedEnd(status, guardedRead(() => readOwnDataValue(snap, 'errorCode'))))
|
|
495
|
+
return Object.freeze({ state: 'awaiting approval' });
|
|
496
|
+
const result = guardedRead(() => readOwnDataValue(snap, 'result'));
|
|
497
|
+
const error = status === 'failed' ? guardedRead(() => readOwnDataValue(snap, 'error')) : undefined;
|
|
498
|
+
const shownError = typeof error === 'string' && error.length > 0 ? shownRunError(error) : '';
|
|
499
|
+
return Object.freeze({
|
|
500
|
+
state: status,
|
|
501
|
+
...(typeof result === 'string' && result.length > 0 ? { result } : {}),
|
|
502
|
+
...(shownError.length > 0 ? { error: shownError } : {}),
|
|
503
|
+
pointer: 'absent',
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
const WORKFLOW_RUN_ERROR_MAX = 200;
|
|
507
|
+
function shownRunError(raw) {
|
|
508
|
+
const opts = { foldLines: false, escapeBackslashes: 'auto' };
|
|
509
|
+
const whole = displayUntrusted(raw, opts);
|
|
510
|
+
return whole.length <= WORKFLOW_RUN_ERROR_MAX ? whole : `${displayUntrusted(raw, { ...opts, max: WORKFLOW_RUN_ERROR_MAX - 1 })}…`;
|
|
511
|
+
}
|
|
512
|
+
function workflowPollDecisionOf(delivered, reading) {
|
|
513
|
+
if (delivered)
|
|
514
|
+
return { act: 'stop', why: 'delivered' };
|
|
515
|
+
if (reading.state === 'running')
|
|
516
|
+
return { act: 'wait', why: 'running' };
|
|
517
|
+
if (reading.state === 'awaiting approval')
|
|
518
|
+
return { act: 'wait', why: 'awaiting approval' };
|
|
519
|
+
if (reading.state === 'unknown')
|
|
520
|
+
return { act: 'wait', why: 'unknown' };
|
|
521
|
+
return { act: 'emit', status: reading.state, ...(reading.result !== undefined ? { result: reading.result } : {}), ...(reading.error !== undefined ? { error: reading.error } : {}) };
|
|
522
|
+
}
|
|
523
|
+
function workflowPollCompletionSummary(status, error) {
|
|
524
|
+
const head = `workflow ${status} (read from its run record; no handle to the full record is available)`;
|
|
525
|
+
return error === undefined ? head : `${head} — failure reason from the run record: ${error}`;
|
|
526
|
+
}
|
|
481
527
|
const outstandingRuns = new Map();
|
|
482
528
|
const outstandingListeners = new Set();
|
|
483
529
|
function notifyOutstanding() {
|
|
@@ -493,7 +539,7 @@ export function outstandingWorkflowCount() {
|
|
|
493
539
|
return outstandingRuns.size;
|
|
494
540
|
}
|
|
495
541
|
export function outstandingDeliverableWorkflowCount() {
|
|
496
|
-
return
|
|
542
|
+
return workflowRunReader ? outstandingRuns.size : 0;
|
|
497
543
|
}
|
|
498
544
|
export function subscribeOutstandingWorkflows(listener) {
|
|
499
545
|
outstandingListeners.add(listener);
|
|
@@ -531,12 +577,12 @@ export function notificationDropCounters() {
|
|
|
531
577
|
bgWatchCollectedUnprobed,
|
|
532
578
|
};
|
|
533
579
|
}
|
|
534
|
-
let
|
|
580
|
+
let workflowRunReader = null;
|
|
535
581
|
let watchTimer = null;
|
|
536
582
|
const WATCH_INTERVAL_MS = 5000;
|
|
537
583
|
const WATCH_TTL_MS = 2 * 60 * 60 * 1000;
|
|
538
|
-
export function
|
|
539
|
-
|
|
584
|
+
export function installWorkflowRunReader(reader) {
|
|
585
|
+
workflowRunReader = reader;
|
|
540
586
|
}
|
|
541
587
|
const BG_FIRST_SEQ = 1;
|
|
542
588
|
function normalizeBgSeq(seq) {
|
|
@@ -762,26 +808,25 @@ async function tickWatchInner(now) {
|
|
|
762
808
|
bgProbeInFlight.delete(key);
|
|
763
809
|
}
|
|
764
810
|
}
|
|
765
|
-
const
|
|
811
|
+
const reader = workflowRunReader;
|
|
766
812
|
for (const runId of [...outstandingRuns.keys()]) {
|
|
767
813
|
if (notifiedRunIds.has(runId)) {
|
|
768
814
|
if (outstandingRuns.delete(runId))
|
|
769
815
|
notifyOutstanding();
|
|
770
816
|
continue;
|
|
771
817
|
}
|
|
772
|
-
if (!
|
|
818
|
+
if (!reader)
|
|
773
819
|
continue;
|
|
774
820
|
runProbeInFlight.set(runId, now);
|
|
775
821
|
try {
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
});
|
|
822
|
+
const reading = workflowRunTerminalReadingOf(await withProbeDeadline(reader(runId), probeTimeoutMs()));
|
|
823
|
+
const decision = workflowPollDecisionOf(notifiedRunIds.has(runId), reading);
|
|
824
|
+
if (decision.act === 'wait')
|
|
825
|
+
continue;
|
|
826
|
+
if (outstandingRuns.delete(runId))
|
|
827
|
+
notifyOutstanding();
|
|
828
|
+
if (decision.act === 'emit') {
|
|
829
|
+
enqueueWorkflowCompletion({ runId, status: decision.status, summary: workflowPollCompletionSummary(decision.status, decision.error) }, { ...(decision.result !== undefined ? { result: decision.result } : {}), ...(decision.error !== undefined ? { error: decision.error } : {}) });
|
|
785
830
|
}
|
|
786
831
|
}
|
|
787
832
|
catch {
|
|
@@ -845,6 +890,9 @@ export function enqueueEngineWorkflowNotification(raw) {
|
|
|
845
890
|
traceNotif('workflow-notification dropped:payload-unreadable');
|
|
846
891
|
return;
|
|
847
892
|
}
|
|
893
|
+
enqueueWorkflowCompletion(c, completionIdOnly(workflowCompletionExtrasOf(c)));
|
|
894
|
+
}
|
|
895
|
+
function enqueueWorkflowCompletion(c, body) {
|
|
848
896
|
if (notifiedRunIds.has(c.runId)) {
|
|
849
897
|
workflowDedupDropped++;
|
|
850
898
|
traceNotif(`workflow notification suppressed (run already notified) runId=${c.runId} status=${c.status}`);
|
|
@@ -852,7 +900,7 @@ export function enqueueEngineWorkflowNotification(raw) {
|
|
|
852
900
|
}
|
|
853
901
|
markRunNotified(c.runId);
|
|
854
902
|
cardEnqueuedRunIds.add(c.runId);
|
|
855
|
-
port()?.enqueuePendingNotification(taskNotificationQueueCommand({ taskId: c.runId, taskType: 'workflow', status: c.status, summary: c.summary, ...
|
|
903
|
+
port()?.enqueuePendingNotification(taskNotificationQueueCommand({ taskId: c.runId, taskType: 'workflow', status: c.status, summary: c.summary, ...body }));
|
|
856
904
|
}
|
|
857
905
|
export function _resetEngineTaskNotificationForTest() {
|
|
858
906
|
notifiedRunIds.clear();
|
|
@@ -867,7 +915,7 @@ export function _resetEngineTaskNotificationForTest() {
|
|
|
867
915
|
bgProbeInFlight.clear();
|
|
868
916
|
runProbeInFlight.clear();
|
|
869
917
|
tickGeneration = 0;
|
|
870
|
-
|
|
918
|
+
workflowRunReader = null;
|
|
871
919
|
bgStatusProbe = null;
|
|
872
920
|
tickStartedAtMs = null;
|
|
873
921
|
abandonedCount = 0;
|
package/dist/ownKey.d.ts
CHANGED
|
@@ -39,11 +39,6 @@ export interface HumanInputAttachmentDeclinedByView {
|
|
|
39
39
|
name: string;
|
|
40
40
|
}
|
|
41
41
|
export declare function humanInputAttachmentsOf(frame: {} | null | undefined): HumanInputAttachmentView[] | undefined;
|
|
42
|
-
export interface HumanInputAuthorKeys {
|
|
43
|
-
author?: string;
|
|
44
|
-
extension?: string;
|
|
45
|
-
}
|
|
46
|
-
export declare function humanInputAuthorKeys(frame: {} | null | undefined): HumanInputAuthorKeys;
|
|
47
42
|
export declare function markMcpSectionDroppedNamedRows(rows: object, dropped: ReadonlyMap<string, number>): void;
|
|
48
43
|
export declare function mcpSectionDroppedNamedRowsOf(rows: object | null | undefined, name: string): number;
|
|
49
44
|
export interface PromptManifestSectionRow {
|
package/dist/ownKey.js
CHANGED
|
@@ -193,13 +193,6 @@ export function humanInputAttachmentsOf(frame) {
|
|
|
193
193
|
return undefined;
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
|
-
export function humanInputAuthorKeys(frame) {
|
|
197
|
-
if (typeof frame !== 'object' || frame === null || Array.isArray(frame))
|
|
198
|
-
return {};
|
|
199
|
-
const author = guardedRead(() => readOwnDataNonEmptyString(frame, 'author'));
|
|
200
|
-
const extension = guardedRead(() => readOwnDataNonEmptyString(frame, 'extension'));
|
|
201
|
-
return { ...(author !== undefined ? { author } : {}), ...(extension !== undefined ? { extension } : {}) };
|
|
202
|
-
}
|
|
203
196
|
const DROPPED_NAMED_ROWS = Symbol.for('@sema-agent/client-core/mcpSectionDroppedNamedRows');
|
|
204
197
|
export function markMcpSectionDroppedNamedRows(rows, dropped) {
|
|
205
198
|
if (dropped.size === 0)
|
package/dist/peerFrames.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { UiLanguage } from './env/uiLanguage.js';
|
|
1
2
|
export declare const AGENT_MESSAGE_TAG = "agent-message";
|
|
2
3
|
export declare const CROSS_SESSION_MESSAGE_TAG = "cross-session-message";
|
|
3
|
-
export declare const PEER_FRAME_LANES: readonly ["agent_message", "cross_session_message", "cross_session_notice"];
|
|
4
|
+
export declare const PEER_FRAME_LANES: readonly ["agent_message", "cross_session_message", "cross_session_notice", "inbox_notice"];
|
|
4
5
|
export declare const CROSS_SESSION_NOTICE_KINDS: readonly ["delivery_notice", "idle_notice"];
|
|
5
6
|
export type CrossSessionNoticeKind = (typeof CROSS_SESSION_NOTICE_KINDS)[number];
|
|
6
7
|
export declare const PEER_MODE_CLASSES: readonly ["bypass", "prompting"];
|
|
@@ -22,13 +23,50 @@ export type CrossSessionMessageFrame = {
|
|
|
22
23
|
fromScope?: string;
|
|
23
24
|
seq?: number;
|
|
24
25
|
};
|
|
26
|
+
export type PeerNoticeFacts = {
|
|
27
|
+
state: string;
|
|
28
|
+
recipient?: string;
|
|
29
|
+
target?: string;
|
|
30
|
+
detail?: string;
|
|
31
|
+
dropReason?: string;
|
|
32
|
+
refSeq?: number;
|
|
33
|
+
finishedAt?: number;
|
|
34
|
+
};
|
|
25
35
|
export type CrossSessionNoticeFrame = {
|
|
26
36
|
lane: 'cross_session_notice';
|
|
27
37
|
kind: CrossSessionNoticeKind;
|
|
28
38
|
text: string;
|
|
39
|
+
notice?: PeerNoticeFacts;
|
|
40
|
+
};
|
|
41
|
+
export type InboxNoticeFrame = {
|
|
42
|
+
lane: 'inbox_notice';
|
|
43
|
+
pending: number;
|
|
44
|
+
delivered: number;
|
|
45
|
+
urgent?: number;
|
|
46
|
+
resupplied?: number;
|
|
29
47
|
};
|
|
30
|
-
export type PeerFrameProjection = AgentMessageFrame | CrossSessionMessageFrame | CrossSessionNoticeFrame;
|
|
48
|
+
export type PeerFrameProjection = AgentMessageFrame | CrossSessionMessageFrame | CrossSessionNoticeFrame | InboxNoticeFrame;
|
|
31
49
|
export declare function classifyPeerNotification(raw: Record<string, unknown>): PeerFrameProjection | null;
|
|
50
|
+
export type SessionBoxNoticeFacts = {
|
|
51
|
+
noticeKind: 'inbox';
|
|
52
|
+
pending: number;
|
|
53
|
+
delivered: number;
|
|
54
|
+
urgent?: number;
|
|
55
|
+
resupplied?: number;
|
|
56
|
+
} | {
|
|
57
|
+
noticeKind: 'delivery' | 'idle';
|
|
58
|
+
state: string;
|
|
59
|
+
peerLabel?: string;
|
|
60
|
+
detail?: string;
|
|
61
|
+
dropReason?: string;
|
|
62
|
+
refSeq?: number;
|
|
63
|
+
finishedAt?: number;
|
|
64
|
+
};
|
|
65
|
+
export type SessionBoxNoticeBody = SessionBoxNoticeFacts & {
|
|
66
|
+
text: string;
|
|
67
|
+
};
|
|
68
|
+
export declare function sessionBoxNoticeSentence(facts: SessionBoxNoticeFacts, lang?: UiLanguage): string | undefined;
|
|
69
|
+
export declare function sessionBoxNoticeOf(p: PeerFrameProjection): SessionBoxNoticeBody | undefined;
|
|
32
70
|
export declare function renderPeerFrameTranscriptText(p: PeerFrameProjection): string;
|
|
33
71
|
export declare function parsePeerFrameText(text: string): AgentMessageFrame | CrossSessionMessageFrame | null;
|
|
34
72
|
export declare function peerFrameDisplayName(p: AgentMessageFrame | CrossSessionMessageFrame): string;
|