@sema-agent/client-core 0.109.0 → 0.111.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 +342 -0
- package/README.md +88 -32
- package/dist/abortableSleep.d.ts +7 -0
- package/dist/abortableSleep.js +37 -0
- package/dist/adapt/arms.js +45 -11
- package/dist/adapt/toolCards.d.ts +3 -1
- package/dist/adapt/toolCards.js +4 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +39 -0
- package/dist/adapter/activeRunSelfHeal.js +171 -3
- package/dist/adapter/downstream/eventToSdkMessage.js +20 -15
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -0
- package/dist/adapter/runStream.d.ts +5 -0
- package/dist/adapter/runStream.js +15 -3
- package/dist/attachmentRoute.d.ts +20 -0
- package/dist/attachmentRoute.js +39 -0
- package/dist/attachmentsWireCaps.js +1 -1
- package/dist/builtinOutputStyles.d.ts +12 -0
- package/dist/builtinOutputStyles.js +147 -0
- package/dist/compactionStatus.d.ts +9 -0
- package/dist/compactionStatus.js +29 -5
- package/dist/controlRouter.js +2 -1
- package/dist/coreValuePorts.d.ts +39 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/declared/supportFloorDeclared.js +1 -1
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +138 -14
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +3 -0
- package/dist/engineHealthFacts.d.ts +20 -0
- package/dist/engineHealthFacts.js +42 -1
- package/dist/engineHealthProbeVerdict.d.ts +23 -0
- package/dist/engineHealthProbeVerdict.js +115 -0
- package/dist/engineInlineTaskStats.d.ts +4 -3
- package/dist/engineInlineTaskStats.js +18 -2
- package/dist/engineNoticeCodes.d.ts +10 -0
- package/dist/engineNoticeCodes.js +36 -6
- package/dist/engineRepoint.d.ts +147 -0
- package/dist/engineRepoint.js +310 -0
- package/dist/engineRowRef.d.ts +3 -0
- package/dist/engineRowRef.js +13 -1
- package/dist/engineSessionMessages.d.ts +2 -1
- package/dist/engineSessionMessages.js +5 -0
- package/dist/engineSwapCrossing.d.ts +57 -0
- package/dist/engineSwapCrossing.js +297 -0
- package/dist/engineUnavailable.d.ts +44 -0
- package/dist/engineUnavailable.js +492 -0
- package/dist/errorSupplementRoles.js +2 -1
- package/dist/eventLeg.js +3 -3
- 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 +2 -1
- package/dist/generated/sdkFactTables.js +5 -0
- package/dist/generated/settingsSchemaTables.d.ts +4 -0
- package/dist/generated/settingsSchemaTables.js +1 -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/approvalDelivery.d.ts +1 -0
- package/dist/hitl/approvalDelivery.js +1 -1
- package/dist/hitl/approvalRequestFrameReading.d.ts +7 -0
- package/dist/hitl/approvalRequestFrameReading.js +11 -0
- package/dist/hitl/approvalResolution.d.ts +9 -2
- package/dist/hitl/approvalResolution.js +6 -1
- package/dist/hitl/askGateWire.js +5 -8
- package/dist/hitl/automaticAnswerVerdict.js +2 -2
- package/dist/hitl/decisionConflict.js +6 -3
- package/dist/hitl/decisionRefusal.d.ts +2 -0
- package/dist/hitl/decisionRefusal.js +8 -8
- package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
- package/dist/hitl/decisionRefusalCarrier.js +348 -0
- package/dist/hitl/decisionSend.d.ts +10 -0
- package/dist/hitl/decisionSend.js +57 -17
- package/dist/hitl/editedApprovalAcceptance.d.ts +25 -0
- package/dist/hitl/editedApprovalAcceptance.js +26 -0
- package/dist/hitl/elicitationRefusal.d.ts +4 -0
- package/dist/hitl/elicitationRefusal.js +23 -0
- package/dist/hitl/frameRouter.d.ts +2 -2
- package/dist/hitl/frameRouter.js +12 -33
- package/dist/hitl/gateIdentity.d.ts +5 -0
- package/dist/hitl/gateIdentity.js +23 -0
- package/dist/hitl/gateLedger.d.ts +0 -4
- package/dist/hitl/gateLedger.js +0 -19
- package/dist/hitl/hitlBridge.d.ts +7 -0
- package/dist/hitl/hitlBridge.js +14 -8
- package/dist/hitl/hitlHostSurface.d.ts +3 -1
- package/dist/hitl/hitlHostSurface.js +14 -4
- package/dist/hitl/hostWithdrawal.d.ts +15 -0
- package/dist/hitl/hostWithdrawal.js +38 -0
- package/dist/hitl/localAllowRedemption.d.ts +67 -0
- package/dist/hitl/localAllowRedemption.js +256 -0
- package/dist/hitl/parkResolver.js +32 -13
- package/dist/hitl/persistedRulesWire.d.ts +16 -0
- package/dist/hitl/persistedRulesWire.js +72 -2
- package/dist/hitl/planReviewWire.d.ts +3 -0
- package/dist/hitl/planReviewWire.js +37 -10
- package/dist/hitl/policyDenyCause.d.ts +1 -1
- package/dist/hitl/policyDenyCause.js +1 -1
- package/dist/hitl/resumeRunningCard.d.ts +1 -0
- package/dist/hitl/resumeRunningCard.js +1 -0
- package/dist/hitl/screenCardCarriers.d.ts +15 -0
- package/dist/hitl/screenCardCarriers.js +41 -0
- package/dist/hitl/screenDecisionCards.d.ts +98 -0
- package/dist/hitl/screenDecisionCards.js +362 -0
- package/dist/hitl/sessionPolicyWire.js +6 -4
- package/dist/hitl/standingRows.d.ts +4 -1
- package/dist/hitl/standingRows.js +33 -1
- package/dist/hitl/toolApprovalWire.d.ts +64 -15
- package/dist/hitl/toolApprovalWire.js +470 -125
- package/dist/hooksWireCaps.js +31 -1
- package/dist/hostSettingNoticeArm.d.ts +3 -0
- package/dist/hostSettingNoticeArm.js +12 -0
- package/dist/hostTurnSettings.d.ts +13 -4
- package/dist/hostTurnSettings.js +150 -10
- package/dist/humanTurnRead.js +11 -1
- package/dist/i18n/messages.en.d.ts +212 -0
- package/dist/i18n/messages.en.js +217 -5
- package/dist/i18n/messages.zh.js +235 -5
- package/dist/i18n/translate.d.ts +3 -0
- package/dist/i18n/translate.js +78 -10
- package/dist/i18n/zh.d.ts +1 -0
- package/dist/i18n/zh.js +1 -0
- package/dist/index.d.ts +56 -16
- package/dist/index.js +40 -12
- package/dist/inheritEnvCapability.js +2 -0
- package/dist/inputAuthor.d.ts +16 -0
- package/dist/inputAuthor.js +44 -0
- package/dist/interactiveHalt.js +2 -1
- package/dist/interactiveInterrupt.js +20 -2
- package/dist/interruptRefusalNote.d.ts +2 -0
- package/dist/interruptRefusalNote.js +17 -0
- package/dist/liveModelCatalog.d.ts +2 -0
- package/dist/liveModelCatalog.js +23 -9
- package/dist/liveQuestionStore.d.ts +4 -1
- package/dist/liveQuestionStore.js +12 -3
- package/dist/localEngineSeatReading.d.ts +2 -2
- package/dist/localEngineSeatReading.js +5 -3
- package/dist/localEngineSpawn.d.ts +0 -7
- package/dist/localEngineSpawn.js +0 -92
- package/dist/localEngineStep.d.ts +2 -2
- package/dist/localEngineStep.js +2 -0
- 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 +124 -19
- package/dist/mcpWireCaps.js +1 -1
- package/dist/model/engineModelWords.d.ts +3 -0
- package/dist/model/engineModelWords.js +13 -0
- package/dist/model/subagentModelWord.d.ts +21 -2
- package/dist/model/subagentModelWord.js +100 -29
- package/dist/modelCapabilityProbe.js +7 -43
- package/dist/modsFace.d.ts +8 -1
- package/dist/modsFace.js +27 -0
- package/dist/notifications.d.ts +36 -6
- package/dist/notifications.js +170 -20
- package/dist/ownKey.d.ts +6 -5
- package/dist/ownKey.js +31 -7
- package/dist/peerFrames.d.ts +40 -2
- package/dist/peerFrames.js +158 -3
- package/dist/pendingUserRow.d.ts +4 -0
- package/dist/pendingUserRow.js +16 -0
- package/dist/permissionsDeclaration.d.ts +1 -0
- package/dist/permissionsDeclaration.js +11 -1
- package/dist/planReviewCardFacts.d.ts +3 -0
- package/dist/planReviewCardFacts.js +52 -2
- package/dist/pluginHooksWire.d.ts +10 -1
- package/dist/pluginHooksWire.js +96 -7
- package/dist/printToolResultFrame.js +4 -2
- package/dist/promptBlockedCopy.js +11 -6
- package/dist/promptSuggestionBatch.d.ts +7 -0
- package/dist/promptSuggestionBatch.js +9 -0
- package/dist/promptSuggestionsTail.d.ts +39 -0
- package/dist/promptSuggestionsTail.js +116 -0
- package/dist/replayBody.js +10 -2
- package/dist/request/taskRequest.d.ts +5 -0
- package/dist/request/taskRequest.js +142 -21
- package/dist/requestCoordinate.d.ts +1 -0
- package/dist/requestCoordinate.js +13 -0
- 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/rewindArchiveReading.js +4 -4
- package/dist/runCancelContext.d.ts +2 -1
- package/dist/runCancelContext.js +1 -0
- package/dist/runPermissionModeSwitch.js +2 -2
- package/dist/scenarioRefusal.js +11 -13
- package/dist/scenarioSkills.js +11 -6
- package/dist/seam.d.ts +27 -2
- package/dist/seam.js +17 -1
- package/dist/seatContract.d.ts +189 -12
- package/dist/seatContract.js +401 -9
- package/dist/sessionBackground.js +2 -1
- package/dist/sessionBackgroundHandoff.js +2 -1
- package/dist/sessionCostReading.d.ts +70 -0
- package/dist/sessionCostReading.js +150 -0
- package/dist/sessionEngine.d.ts +2 -0
- package/dist/sessionEngine.js +111 -0
- package/dist/sessionHooksRoster.d.ts +4 -0
- package/dist/sessionHooksRoster.js +158 -0
- package/dist/sessionMemoryStatus.d.ts +2 -1
- package/dist/sessionMemoryStatus.js +2 -2
- package/dist/sessionReadRedaction.d.ts +7 -0
- package/dist/sessionReadRedaction.js +26 -0
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +27 -0
- package/dist/settingsHooksSalvage.js +2 -1
- package/dist/sseIdleTriage.d.ts +13 -1
- package/dist/sseIdleTriage.js +25 -6
- package/dist/storeDurabilityWord.d.ts +15 -0
- package/dist/storeDurabilityWord.js +18 -0
- package/dist/storePostureCapability.d.ts +7 -3
- package/dist/storePostureCapability.js +69 -39
- package/dist/subagent/engineSubagentResume.js +2 -2
- package/dist/subagent/engineSubagentTail.js +8 -1
- package/dist/subagentContentStore.d.ts +11 -0
- package/dist/subagentContentStore.js +28 -2
- package/dist/terminalStatuses.d.ts +1 -0
- package/dist/terminalStatuses.js +4 -1
- package/dist/toolResult.d.ts +1 -0
- package/dist/toolResult.js +2 -0
- 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/userAttachmentEnvelope.d.ts +2 -1
- package/dist/userAttachmentEnvelope.js +10 -0
- package/dist/wireErrorTriage.js +2 -1
- package/dist/wireFailureShape.d.ts +6 -5
- package/dist/wireFailureShape.js +150 -38
- package/dist/wireRefusalCopy.d.ts +16 -5
- package/dist/wireRefusalCopy.js +119 -86
- package/docs/INTEGRATION-CLIENTS.md +4228 -21
- package/package.json +7 -3
package/dist/notifications.js
CHANGED
|
@@ -2,10 +2,12 @@ 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
|
-
import { guardedRead, ownSnapshot, ownSnapshotRecord, ownSnapshotTyped, readOwnDataValue, workflowCompletionExtrasOf } from './ownKey.js';
|
|
8
|
+
import { guardedRead, ownSnapshot, ownSnapshotRecord, ownSnapshotTyped, readOwnDataNonEmptyString, readOwnDataValue, resupplyTruncatedFactsOf, resupplyTruncatedOf, workflowCompletionExtrasOf } from './ownKey.js';
|
|
9
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
10
|
+
import { displayUntrustedCapped } from './displayUntrusted.js';
|
|
9
11
|
function escapeXml(v) {
|
|
10
12
|
return v.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
11
13
|
}
|
|
@@ -102,6 +104,7 @@ export function freezeTaskNotificationFields(n) {
|
|
|
102
104
|
...(n.outputFile !== undefined ? { outputFile: n.outputFile } : {}),
|
|
103
105
|
...(n.diagnostics !== undefined ? { diagnostics: n.diagnostics } : {}),
|
|
104
106
|
...(n.result !== undefined ? { result: n.result } : {}),
|
|
107
|
+
...(n.error !== undefined ? { error: n.error } : {}),
|
|
105
108
|
...(n.stoppedBy !== undefined ? { stoppedBy: n.stoppedBy } : {}),
|
|
106
109
|
...(n.partial !== undefined ? { partial: n.partial } : {}),
|
|
107
110
|
...(n.exitCode !== undefined ? { exitCode: n.exitCode } : {}),
|
|
@@ -128,7 +131,7 @@ export function taskNotificationOf(carrier) {
|
|
|
128
131
|
if (typeof taskId !== 'string' || taskId.length === 0 || typeof status !== 'string' || typeof summary !== 'string')
|
|
129
132
|
return undefined;
|
|
130
133
|
const out = { taskId, status, summary };
|
|
131
|
-
for (const k of ['taskType', 'toolUseId', 'outputFile', 'diagnostics', 'result', 'stoppedBy', 'externalSource']) {
|
|
134
|
+
for (const k of ['taskType', 'toolUseId', 'outputFile', 'diagnostics', 'result', 'error', 'stoppedBy', 'externalSource']) {
|
|
132
135
|
const v = slot(k);
|
|
133
136
|
if (typeof v === 'string')
|
|
134
137
|
out[k] = v;
|
|
@@ -211,6 +214,7 @@ export function normalizeTaskNotification(raw) {
|
|
|
211
214
|
? n.lines.filter((l) => typeof l === 'string')
|
|
212
215
|
: [];
|
|
213
216
|
const recentSteps = deriveNotificationResidualLines(n);
|
|
217
|
+
const failureReason = failureReasonOf(status, n.error);
|
|
214
218
|
return {
|
|
215
219
|
taskId,
|
|
216
220
|
status,
|
|
@@ -228,6 +232,7 @@ export function normalizeTaskNotification(raw) {
|
|
|
228
232
|
? { diagnostics: n.diagnostics }
|
|
229
233
|
: {}),
|
|
230
234
|
...(typeof n.result === 'string' && n.result.length > 0 ? { result: n.result } : {}),
|
|
235
|
+
...(failureReason !== undefined ? { error: failureReason } : {}),
|
|
231
236
|
...(typeof n.stoppedBy === 'string' && n.stoppedBy.length > 0 ? { stoppedBy: n.stoppedBy } : {}),
|
|
232
237
|
...(n.partial === true ? { partial: true } : {}),
|
|
233
238
|
...(typeof n.exitCode === 'number' ? { exitCode: n.exitCode } : {}),
|
|
@@ -420,6 +425,7 @@ export function enqueuePlanReviewOutcome(value, meta) {
|
|
|
420
425
|
queuePortMisses++;
|
|
421
426
|
return false;
|
|
422
427
|
}
|
|
428
|
+
const questionId = meta === undefined ? undefined : guardedRead(() => readOwnDataNonEmptyString(meta, 'questionId'));
|
|
423
429
|
p.enqueueMetaPrompt({
|
|
424
430
|
value,
|
|
425
431
|
mode: 'prompt',
|
|
@@ -434,12 +440,34 @@ export function enqueuePlanReviewOutcome(value, meta) {
|
|
|
434
440
|
decision: meta.decision,
|
|
435
441
|
effect: meta.effect,
|
|
436
442
|
...(meta.effect === 'still_parked' && meta.cause === 'stored_form_unsupported' ? { cause: meta.cause } : {}),
|
|
443
|
+
...(questionId !== undefined ? { questionId } : {}),
|
|
437
444
|
}),
|
|
438
445
|
}
|
|
439
446
|
: {}),
|
|
440
447
|
});
|
|
441
448
|
return true;
|
|
442
449
|
}
|
|
450
|
+
export function resupplyTruncatedSentence(facts, lang) {
|
|
451
|
+
try {
|
|
452
|
+
const f = resupplyTruncatedFactsOf(facts);
|
|
453
|
+
if (f === undefined)
|
|
454
|
+
return undefined;
|
|
455
|
+
const count = f.droppedKeys.length;
|
|
456
|
+
return renderMessage(msg(count === 1 ? 'notice.resupply.truncated.one' : 'notice.resupply.truncated.other', count === 1 ? { bytes: f.bytes } : { bytes: f.bytes, count }), lang);
|
|
457
|
+
}
|
|
458
|
+
catch {
|
|
459
|
+
return undefined;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
export function resupplyTruncatedArmBody(carrier, source, taskId) {
|
|
463
|
+
const facts = resupplyTruncatedOf(carrier);
|
|
464
|
+
if (facts === undefined)
|
|
465
|
+
return undefined;
|
|
466
|
+
const text = resupplyTruncatedSentence(facts);
|
|
467
|
+
if (text === undefined)
|
|
468
|
+
return undefined;
|
|
469
|
+
return { source, taskId, bytes: facts.bytes, droppedKeys: facts.droppedKeys, text };
|
|
470
|
+
}
|
|
443
471
|
export function dropQueuedNotificationsForRun(taskId) {
|
|
444
472
|
const needle = `<${TASK_ID_TAG}>${escapeXml(taskId)}</${TASK_ID_TAG}>`;
|
|
445
473
|
const p = port();
|
|
@@ -478,6 +506,61 @@ const cardEnqueuedRunIds = new Set();
|
|
|
478
506
|
export function isWorkflowCompletionCardEnqueued(runId) {
|
|
479
507
|
return cardEnqueuedRunIds.has(runId);
|
|
480
508
|
}
|
|
509
|
+
export function workflowRunTerminalReadingOf(body) {
|
|
510
|
+
const snap = probeAnswerSnapshot(body);
|
|
511
|
+
if (snap === null)
|
|
512
|
+
return Object.freeze({ state: 'unknown', why: 'body_unreadable' });
|
|
513
|
+
const status = guardedRead(() => readOwnDataValue(snap, 'status'));
|
|
514
|
+
if (typeof status !== 'string')
|
|
515
|
+
return Object.freeze({ state: 'unknown', why: 'status_unreadable' });
|
|
516
|
+
if (status === 'running')
|
|
517
|
+
return Object.freeze({ state: 'running' });
|
|
518
|
+
if (!isCoreWorkflowRunTerminal(status))
|
|
519
|
+
return Object.freeze({ state: 'unknown', why: 'status_unrecognized' });
|
|
520
|
+
if (isCoreWorkflowRunParkedEnd(status, guardedRead(() => readOwnDataValue(snap, 'errorCode'))))
|
|
521
|
+
return Object.freeze({ state: 'awaiting approval' });
|
|
522
|
+
const result = guardedRead(() => readOwnDataValue(snap, 'result'));
|
|
523
|
+
const shownError = failureReasonOf(status, guardedRead(() => readOwnDataValue(snap, 'error')));
|
|
524
|
+
const resultFull = guardedRead(() => readOwnDataValue(snap, 'resultFull'));
|
|
525
|
+
return Object.freeze({
|
|
526
|
+
state: status,
|
|
527
|
+
...(typeof result === 'string' && result.length > 0 ? { result } : {}),
|
|
528
|
+
...(shownError !== undefined ? { error: shownError } : {}),
|
|
529
|
+
pointer: 'absent',
|
|
530
|
+
...(typeof resultFull === 'string' && resultFull.length > 0 ? { truncated: true } : {}),
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
const WORKFLOW_RUN_ERROR_MAX = 200;
|
|
534
|
+
function shownRunError(raw) {
|
|
535
|
+
return displayUntrustedCapped(raw, WORKFLOW_RUN_ERROR_MAX, { foldLines: false, escapeBackslashes: 'auto' });
|
|
536
|
+
}
|
|
537
|
+
function failureReasonOf(status, raw) {
|
|
538
|
+
if (status !== 'failed' || typeof raw !== 'string' || raw.length === 0)
|
|
539
|
+
return undefined;
|
|
540
|
+
const shown = shownRunError(raw);
|
|
541
|
+
return shown.length > 0 ? shown : undefined;
|
|
542
|
+
}
|
|
543
|
+
function workflowPollDecisionOf(delivered, reading) {
|
|
544
|
+
if (delivered)
|
|
545
|
+
return { act: 'stop', why: 'delivered' };
|
|
546
|
+
if (reading.state === 'running')
|
|
547
|
+
return { act: 'wait', why: 'running' };
|
|
548
|
+
if (reading.state === 'awaiting approval')
|
|
549
|
+
return { act: 'wait', why: 'awaiting approval' };
|
|
550
|
+
if (reading.state === 'unknown')
|
|
551
|
+
return { act: 'wait', why: 'unknown' };
|
|
552
|
+
return {
|
|
553
|
+
act: 'emit',
|
|
554
|
+
status: reading.state,
|
|
555
|
+
...(reading.result !== undefined ? { result: reading.result } : {}),
|
|
556
|
+
...(reading.error !== undefined ? { error: reading.error } : {}),
|
|
557
|
+
...(reading.truncated === true ? { truncated: true } : {}),
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
function workflowPollCompletionSummary(status, error) {
|
|
561
|
+
const head = `workflow ${status} (read from its run record; no handle to the full record is available)`;
|
|
562
|
+
return error === undefined ? head : `${head} — failure reason from the run record: ${error}`;
|
|
563
|
+
}
|
|
481
564
|
const outstandingRuns = new Map();
|
|
482
565
|
const outstandingListeners = new Set();
|
|
483
566
|
function notifyOutstanding() {
|
|
@@ -493,7 +576,7 @@ export function outstandingWorkflowCount() {
|
|
|
493
576
|
return outstandingRuns.size;
|
|
494
577
|
}
|
|
495
578
|
export function outstandingDeliverableWorkflowCount() {
|
|
496
|
-
return
|
|
579
|
+
return workflowRunReader ? outstandingRuns.size : 0;
|
|
497
580
|
}
|
|
498
581
|
export function subscribeOutstandingWorkflows(listener) {
|
|
499
582
|
outstandingListeners.add(listener);
|
|
@@ -531,12 +614,12 @@ export function notificationDropCounters() {
|
|
|
531
614
|
bgWatchCollectedUnprobed,
|
|
532
615
|
};
|
|
533
616
|
}
|
|
534
|
-
let
|
|
617
|
+
let workflowRunReader = null;
|
|
535
618
|
let watchTimer = null;
|
|
536
619
|
const WATCH_INTERVAL_MS = 5000;
|
|
537
620
|
const WATCH_TTL_MS = 2 * 60 * 60 * 1000;
|
|
538
|
-
export function
|
|
539
|
-
|
|
621
|
+
export function installWorkflowRunReader(reader) {
|
|
622
|
+
workflowRunReader = reader;
|
|
540
623
|
}
|
|
541
624
|
const BG_FIRST_SEQ = 1;
|
|
542
625
|
function normalizeBgSeq(seq) {
|
|
@@ -762,26 +845,25 @@ async function tickWatchInner(now) {
|
|
|
762
845
|
bgProbeInFlight.delete(key);
|
|
763
846
|
}
|
|
764
847
|
}
|
|
765
|
-
const
|
|
848
|
+
const reader = workflowRunReader;
|
|
766
849
|
for (const runId of [...outstandingRuns.keys()]) {
|
|
767
850
|
if (notifiedRunIds.has(runId)) {
|
|
768
851
|
if (outstandingRuns.delete(runId))
|
|
769
852
|
notifyOutstanding();
|
|
770
853
|
continue;
|
|
771
854
|
}
|
|
772
|
-
if (!
|
|
855
|
+
if (!reader)
|
|
773
856
|
continue;
|
|
774
857
|
runProbeInFlight.set(runId, now);
|
|
775
858
|
try {
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
});
|
|
859
|
+
const reading = workflowRunTerminalReadingOf(await withProbeDeadline(reader(runId), probeTimeoutMs()));
|
|
860
|
+
const decision = workflowPollDecisionOf(notifiedRunIds.has(runId), reading);
|
|
861
|
+
if (decision.act === 'wait')
|
|
862
|
+
continue;
|
|
863
|
+
if (outstandingRuns.delete(runId))
|
|
864
|
+
notifyOutstanding();
|
|
865
|
+
if (decision.act === 'emit') {
|
|
866
|
+
enqueueWorkflowCompletion({ runId, status: decision.status, summary: workflowPollCompletionSummary(decision.status, decision.error) }, { ...(decision.result !== undefined ? { result: decision.result } : {}), ...(decision.error !== undefined ? { error: decision.error } : {}) }, { truncated: decision.truncated === true });
|
|
785
867
|
}
|
|
786
868
|
}
|
|
787
869
|
catch {
|
|
@@ -845,6 +927,17 @@ export function enqueueEngineWorkflowNotification(raw) {
|
|
|
845
927
|
traceNotif('workflow-notification dropped:payload-unreadable');
|
|
846
928
|
return;
|
|
847
929
|
}
|
|
930
|
+
const extras = workflowCompletionExtrasOf(c);
|
|
931
|
+
if (notifiedRunIds.has(c.runId)) {
|
|
932
|
+
const supplement = takeWorkflowPointerSupplement(c.runId, c.status, extras.diagnostics, extras.completionId);
|
|
933
|
+
if (supplement !== undefined) {
|
|
934
|
+
port()?.enqueuePendingNotification(taskNotificationQueueCommand(supplement));
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
enqueueWorkflowCompletion(c, completionIdOnly(extras));
|
|
939
|
+
}
|
|
940
|
+
function enqueueWorkflowCompletion(c, body, poll) {
|
|
848
941
|
if (notifiedRunIds.has(c.runId)) {
|
|
849
942
|
workflowDedupDropped++;
|
|
850
943
|
traceNotif(`workflow notification suppressed (run already notified) runId=${c.runId} status=${c.status}`);
|
|
@@ -852,11 +945,68 @@ export function enqueueEngineWorkflowNotification(raw) {
|
|
|
852
945
|
}
|
|
853
946
|
markRunNotified(c.runId);
|
|
854
947
|
cardEnqueuedRunIds.add(c.runId);
|
|
855
|
-
|
|
948
|
+
if (poll !== undefined)
|
|
949
|
+
notePointerOwed(c.runId, poll.truncated);
|
|
950
|
+
port()?.enqueuePendingNotification(taskNotificationQueueCommand({ taskId: c.runId, taskType: 'workflow', status: c.status, summary: c.summary, ...body }));
|
|
951
|
+
}
|
|
952
|
+
const pointerOwedRuns = new Map();
|
|
953
|
+
const POINTER_OWED_MAX = 512;
|
|
954
|
+
function notePointerOwed(runId, truncated) {
|
|
955
|
+
pointerOwedRuns.delete(runId);
|
|
956
|
+
pointerOwedRuns.set(runId, { truncated });
|
|
957
|
+
while (pointerOwedRuns.size > POINTER_OWED_MAX) {
|
|
958
|
+
const oldest = pointerOwedRuns.keys().next();
|
|
959
|
+
if (oldest.done === true)
|
|
960
|
+
break;
|
|
961
|
+
pointerOwedRuns.delete(oldest.value);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
const WORKFLOW_RECORD_REF_SENTENCE = /Full record \(the result and every agent's row\): read it with ReadToolResult \(ref "([A-Za-z0-9_.~-]{1,518})"\) before assuming an empty or unexpected result\./g;
|
|
965
|
+
export function workflowRecordRefOf(diagnostics) {
|
|
966
|
+
if (typeof diagnostics !== 'string' || diagnostics.length === 0)
|
|
967
|
+
return undefined;
|
|
968
|
+
try {
|
|
969
|
+
let ref;
|
|
970
|
+
for (const m of diagnostics.matchAll(WORKFLOW_RECORD_REF_SENTENCE))
|
|
971
|
+
ref = m[1];
|
|
972
|
+
return ref;
|
|
973
|
+
}
|
|
974
|
+
catch {
|
|
975
|
+
return undefined;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
function workflowPointerSupplementSummary(ref, truncated) {
|
|
979
|
+
const head = `Full record of this workflow run (the result and every agent's row): read it with ReadToolResult (ref "${ref}")`;
|
|
980
|
+
return truncated ? `${head} — the result delivered earlier was cut short; the full text is in this record.` : `${head}.`;
|
|
981
|
+
}
|
|
982
|
+
export function takeWorkflowPointerSupplement(runId, status, diagnostics, completionId) {
|
|
983
|
+
try {
|
|
984
|
+
const owed = pointerOwedRuns.get(runId);
|
|
985
|
+
if (owed === undefined)
|
|
986
|
+
return undefined;
|
|
987
|
+
const ref = workflowRecordRefOf(diagnostics);
|
|
988
|
+
if (ref === undefined)
|
|
989
|
+
return undefined;
|
|
990
|
+
pointerOwedRuns.delete(runId);
|
|
991
|
+
return freezeTaskNotificationFields({
|
|
992
|
+
taskId: runId,
|
|
993
|
+
taskType: 'workflow',
|
|
994
|
+
status,
|
|
995
|
+
summary: workflowPointerSupplementSummary(ref, owed.truncated),
|
|
996
|
+
...(completionId !== undefined ? { completionId } : {}),
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
catch {
|
|
1000
|
+
return undefined;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
export function settleWorkflowPointerOwed(runId) {
|
|
1004
|
+
pointerOwedRuns.delete(runId);
|
|
856
1005
|
}
|
|
857
1006
|
export function _resetEngineTaskNotificationForTest() {
|
|
858
1007
|
notifiedRunIds.clear();
|
|
859
1008
|
notifiedBgCycleHigh.clear();
|
|
1009
|
+
pointerOwedRuns.clear();
|
|
860
1010
|
cardEnqueuedRunIds.clear();
|
|
861
1011
|
outstandingRuns.clear();
|
|
862
1012
|
outstandingBgTasks.clear();
|
|
@@ -867,7 +1017,7 @@ export function _resetEngineTaskNotificationForTest() {
|
|
|
867
1017
|
bgProbeInFlight.clear();
|
|
868
1018
|
runProbeInFlight.clear();
|
|
869
1019
|
tickGeneration = 0;
|
|
870
|
-
|
|
1020
|
+
workflowRunReader = null;
|
|
871
1021
|
bgStatusProbe = null;
|
|
872
1022
|
tickStartedAtMs = null;
|
|
873
1023
|
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 {
|
|
@@ -84,3 +79,9 @@ export declare function workflowCompletionExtrasOf(c: object): {
|
|
|
84
79
|
completionId?: string;
|
|
85
80
|
diagnostics?: string;
|
|
86
81
|
};
|
|
82
|
+
export interface ResupplyTruncatedFacts {
|
|
83
|
+
readonly bytes: number;
|
|
84
|
+
readonly droppedKeys: readonly string[];
|
|
85
|
+
}
|
|
86
|
+
export declare function resupplyTruncatedFactsOf(slot: {} | null | undefined): ResupplyTruncatedFacts | undefined;
|
|
87
|
+
export declare function resupplyTruncatedOf(carrier: object | null | undefined): ResupplyTruncatedFacts | undefined;
|
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)
|
|
@@ -460,3 +453,34 @@ export function workflowCompletionExtrasOf(c) {
|
|
|
460
453
|
...(diagnostics !== undefined ? { diagnostics } : {}),
|
|
461
454
|
};
|
|
462
455
|
}
|
|
456
|
+
const DROPPED_KEYS_MAX = 256;
|
|
457
|
+
const DROPPED_KEY_NAME_MAX = 128;
|
|
458
|
+
export function resupplyTruncatedFactsOf(slot) {
|
|
459
|
+
try {
|
|
460
|
+
if (typeof slot !== 'object' || slot === null || Array.isArray(slot))
|
|
461
|
+
return undefined;
|
|
462
|
+
const bytes = guardedRead(() => readOwnDataValue(slot, 'bytes'));
|
|
463
|
+
if (typeof bytes !== 'number' || !Number.isSafeInteger(bytes) || bytes <= 0)
|
|
464
|
+
return undefined;
|
|
465
|
+
const keys = guardedRead(() => readOwnDataValue(slot, 'droppedKeys'));
|
|
466
|
+
if (!Array.isArray(keys))
|
|
467
|
+
return undefined;
|
|
468
|
+
const length = guardedRead(() => keys.length);
|
|
469
|
+
if (typeof length !== 'number' || length < 1 || length > DROPPED_KEYS_MAX)
|
|
470
|
+
return undefined;
|
|
471
|
+
const names = [];
|
|
472
|
+
for (let i = 0; i < length; i++) {
|
|
473
|
+
const name = guardedRead(() => readOwnDataValue(keys, String(i)));
|
|
474
|
+
if (typeof name !== 'string' || name.length === 0 || name.length > DROPPED_KEY_NAME_MAX)
|
|
475
|
+
return undefined;
|
|
476
|
+
appendOwnElement(names, name);
|
|
477
|
+
}
|
|
478
|
+
return Object.freeze({ bytes, droppedKeys: Object.freeze(names) });
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
return undefined;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
export function resupplyTruncatedOf(carrier) {
|
|
485
|
+
return resupplyTruncatedFactsOf(guardedRead(() => readOwnDataValue(carrier, 'payloadTruncated')));
|
|
486
|
+
}
|
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;
|
package/dist/peerFrames.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { applyDisplayFace, PEER_NAME_FACE } from './displayUntrusted.js';
|
|
1
|
+
import { applyDisplayFace, displayUntrusted, PEER_NAME_FACE } from './displayUntrusted.js';
|
|
2
|
+
import { msg, renderMessage } from './i18n/translate.js';
|
|
2
3
|
import { ownSnapshotRecord } from './ownKey.js';
|
|
3
4
|
import { CORE_ENGINE_AUTHORITY_ENVELOPE_TAGS, CORE_PERMISSION_MODE_CLASSES } from './generated/engineFactTables.js';
|
|
4
5
|
const WIRE_KEY_FROM = 'from';
|
|
@@ -12,6 +13,20 @@ const WIRE_KEY_AGENT_TYPE = 'agentType';
|
|
|
12
13
|
const WIRE_KEY_AGENT_MESSAGE = 'agentMessage';
|
|
13
14
|
const WIRE_KEY_CROSS_SESSION_MESSAGE = 'crossSessionMessage';
|
|
14
15
|
const WIRE_KEY_CROSS_SESSION_NOTICE = 'crossSessionNotice';
|
|
16
|
+
const WIRE_KEY_INBOX_NOTICE = 'inboxNotice';
|
|
17
|
+
const WIRE_KEY_PENDING = 'pending';
|
|
18
|
+
const WIRE_KEY_DELIVERED = 'delivered';
|
|
19
|
+
const WIRE_KEY_URGENT = 'urgent';
|
|
20
|
+
const WIRE_KEY_RESUPPLIED = 'resupplied';
|
|
21
|
+
const WIRE_KEY_PEER_META = 'peerMeta';
|
|
22
|
+
const WIRE_KEY_NOTICE = 'notice';
|
|
23
|
+
const WIRE_KEY_STATE = 'state';
|
|
24
|
+
const WIRE_KEY_REF_SEQ = 'refSeq';
|
|
25
|
+
const WIRE_KEY_RECIPIENT = 'recipient';
|
|
26
|
+
const WIRE_KEY_TARGET = 'target';
|
|
27
|
+
const WIRE_KEY_DETAIL = 'detail';
|
|
28
|
+
const WIRE_KEY_DROP_REASON = 'dropReason';
|
|
29
|
+
const WIRE_KEY_FINISHED_AT = 'finishedAt';
|
|
15
30
|
const WIRE_KEY_PROVENANCE = '_sema_provenance';
|
|
16
31
|
const WIRE_KEY_FROM_SESSION = 'fromSession';
|
|
17
32
|
const WIRE_KEY_FROM_NAME = 'fromName';
|
|
@@ -20,7 +35,7 @@ const WIRE_KEY_FROM_SCOPE = 'fromScope';
|
|
|
20
35
|
const FROM_ATTR = WIRE_KEY_FROM;
|
|
21
36
|
export const AGENT_MESSAGE_TAG = 'agent-message';
|
|
22
37
|
export const CROSS_SESSION_MESSAGE_TAG = 'cross-session-message';
|
|
23
|
-
export const PEER_FRAME_LANES = Object.freeze(['agent_message', 'cross_session_message', 'cross_session_notice']);
|
|
38
|
+
export const PEER_FRAME_LANES = Object.freeze(['agent_message', 'cross_session_message', 'cross_session_notice', 'inbox_notice']);
|
|
24
39
|
export const CROSS_SESSION_NOTICE_KINDS = Object.freeze(['delivery_notice', 'idle_notice']);
|
|
25
40
|
export const PEER_MODE_CLASSES = CORE_PERMISSION_MODE_CLASSES;
|
|
26
41
|
function dataProp(o, key) {
|
|
@@ -43,6 +58,40 @@ function nonEmptyString(v) {
|
|
|
43
58
|
function finiteNumber(v) {
|
|
44
59
|
return typeof v === 'number' && Number.isFinite(v) ? v : undefined;
|
|
45
60
|
}
|
|
61
|
+
function countOf(v) {
|
|
62
|
+
return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0 ? v : undefined;
|
|
63
|
+
}
|
|
64
|
+
function shownLabel(v, max) {
|
|
65
|
+
if (typeof v !== 'string')
|
|
66
|
+
return undefined;
|
|
67
|
+
const s = displayUntrusted(v, { blanks: true, max });
|
|
68
|
+
return s.length > 0 ? s : undefined;
|
|
69
|
+
}
|
|
70
|
+
const NOTICE_LABEL_MAX = 64;
|
|
71
|
+
const NOTICE_TEXT_MAX = 200;
|
|
72
|
+
function peerNoticeOf(n) {
|
|
73
|
+
const notice = dataProp(dataProp(dataProp(n, WIRE_KEY_PROVENANCE), WIRE_KEY_PEER_META), WIRE_KEY_NOTICE);
|
|
74
|
+
if (notice === null || typeof notice !== 'object')
|
|
75
|
+
return undefined;
|
|
76
|
+
const state = nonEmptyString(dataProp(notice, WIRE_KEY_STATE));
|
|
77
|
+
if (state === undefined)
|
|
78
|
+
return undefined;
|
|
79
|
+
const recipient = shownLabel(dataProp(notice, WIRE_KEY_RECIPIENT), NOTICE_LABEL_MAX);
|
|
80
|
+
const target = shownLabel(dataProp(notice, WIRE_KEY_TARGET), NOTICE_LABEL_MAX);
|
|
81
|
+
const detail = shownLabel(dataProp(notice, WIRE_KEY_DETAIL), NOTICE_TEXT_MAX);
|
|
82
|
+
const dropReason = shownLabel(dataProp(notice, WIRE_KEY_DROP_REASON), NOTICE_TEXT_MAX);
|
|
83
|
+
const refSeq = countOf(dataProp(notice, WIRE_KEY_REF_SEQ));
|
|
84
|
+
const finishedAt = countOf(dataProp(notice, WIRE_KEY_FINISHED_AT));
|
|
85
|
+
return {
|
|
86
|
+
state,
|
|
87
|
+
...(recipient !== undefined ? { recipient } : {}),
|
|
88
|
+
...(target !== undefined ? { target } : {}),
|
|
89
|
+
...(detail !== undefined ? { detail } : {}),
|
|
90
|
+
...(dropReason !== undefined ? { dropReason } : {}),
|
|
91
|
+
...(refSeq !== undefined ? { refSeq } : {}),
|
|
92
|
+
...(finishedAt !== undefined ? { finishedAt } : {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
46
95
|
function provenanceAgrees(n, lane, carrierFromRaw) {
|
|
47
96
|
const prov = dataProp(n, WIRE_KEY_PROVENANCE);
|
|
48
97
|
if (prov === null || typeof prov !== 'object')
|
|
@@ -112,7 +161,24 @@ export function classifyPeerNotification(raw) {
|
|
|
112
161
|
const text = nonEmptyString(dataProp(crossSessionNotice, WIRE_KEY_TEXT));
|
|
113
162
|
if (kind === undefined || text === undefined || !provenanceAgrees(n, 'cross_session_notice'))
|
|
114
163
|
return null;
|
|
115
|
-
|
|
164
|
+
const notice = peerNoticeOf(n);
|
|
165
|
+
return { lane: 'cross_session_notice', kind, text, ...(notice !== undefined ? { notice } : {}) };
|
|
166
|
+
}
|
|
167
|
+
const inboxNotice = dataProp(n, WIRE_KEY_INBOX_NOTICE);
|
|
168
|
+
if (inboxNotice !== undefined) {
|
|
169
|
+
const pending = countOf(dataProp(inboxNotice, WIRE_KEY_PENDING));
|
|
170
|
+
const delivered = countOf(dataProp(inboxNotice, WIRE_KEY_DELIVERED));
|
|
171
|
+
if (pending === undefined || delivered === undefined || !provenanceAgrees(n, 'inbox_notice'))
|
|
172
|
+
return null;
|
|
173
|
+
const urgent = countOf(dataProp(inboxNotice, WIRE_KEY_URGENT));
|
|
174
|
+
const resupplied = countOf(dataProp(inboxNotice, WIRE_KEY_RESUPPLIED));
|
|
175
|
+
return {
|
|
176
|
+
lane: 'inbox_notice',
|
|
177
|
+
pending,
|
|
178
|
+
delivered,
|
|
179
|
+
...(urgent !== undefined ? { urgent } : {}),
|
|
180
|
+
...(resupplied !== undefined ? { resupplied } : {}),
|
|
181
|
+
};
|
|
116
182
|
}
|
|
117
183
|
return null;
|
|
118
184
|
}
|
|
@@ -140,9 +206,98 @@ function attr(v) {
|
|
|
140
206
|
function unattr(v) {
|
|
141
207
|
return v.replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
|
|
142
208
|
}
|
|
209
|
+
const DELIVERY_SENTENCE_KEYS = Object.freeze({
|
|
210
|
+
delivered: 'notice.sessionBox.delivery.delivered',
|
|
211
|
+
held: 'notice.sessionBox.delivery.held',
|
|
212
|
+
held_by_policy: 'notice.sessionBox.delivery.heldByPolicy',
|
|
213
|
+
denied: 'notice.sessionBox.delivery.denied',
|
|
214
|
+
refused: 'notice.sessionBox.delivery.refused',
|
|
215
|
+
expired: 'notice.sessionBox.delivery.expired',
|
|
216
|
+
});
|
|
217
|
+
const IDLE_SENTENCE_KEYS = Object.freeze({
|
|
218
|
+
exited: 'notice.sessionBox.idle.exited',
|
|
219
|
+
unavailable: 'notice.sessionBox.idle.unavailable',
|
|
220
|
+
expired: 'notice.sessionBox.idle.expired',
|
|
221
|
+
});
|
|
222
|
+
function sentenceKeyOf(table, word) {
|
|
223
|
+
return Object.hasOwn(table, word) ? table[word] : undefined;
|
|
224
|
+
}
|
|
225
|
+
function joinParts(parts, lang) {
|
|
226
|
+
return parts.join(lang === 'zh' ? '' : ' ');
|
|
227
|
+
}
|
|
228
|
+
function inboxLine(pending, urgent, resupplied, lang) {
|
|
229
|
+
const parts = [renderMessage(pending === 1 ? msg('notice.sessionBox.inbox.one') : msg('notice.sessionBox.inbox.many', { pending }), lang)];
|
|
230
|
+
if (urgent !== undefined)
|
|
231
|
+
parts.push(renderMessage(msg('notice.sessionBox.inbox.urgent', { urgent }), lang));
|
|
232
|
+
if (resupplied !== undefined)
|
|
233
|
+
parts.push(renderMessage(msg('notice.sessionBox.inbox.resupplied', { resupplied }), lang));
|
|
234
|
+
return joinParts(parts, lang);
|
|
235
|
+
}
|
|
236
|
+
export function sessionBoxNoticeSentence(facts, lang) {
|
|
237
|
+
try {
|
|
238
|
+
const noticeKind = dataProp(facts, 'noticeKind');
|
|
239
|
+
if (noticeKind === 'inbox') {
|
|
240
|
+
const pending = countOf(dataProp(facts, WIRE_KEY_PENDING));
|
|
241
|
+
if (pending === undefined)
|
|
242
|
+
return undefined;
|
|
243
|
+
return inboxLine(pending, countOf(dataProp(facts, WIRE_KEY_URGENT)), countOf(dataProp(facts, WIRE_KEY_RESUPPLIED)), lang);
|
|
244
|
+
}
|
|
245
|
+
if (noticeKind !== 'delivery' && noticeKind !== 'idle')
|
|
246
|
+
return undefined;
|
|
247
|
+
const state = nonEmptyString(dataProp(facts, WIRE_KEY_STATE));
|
|
248
|
+
if (state === undefined)
|
|
249
|
+
return undefined;
|
|
250
|
+
const label = shownLabel(dataProp(facts, 'peerLabel'), NOTICE_LABEL_MAX);
|
|
251
|
+
const detail = shownLabel(dataProp(facts, WIRE_KEY_DETAIL), NOTICE_TEXT_MAX);
|
|
252
|
+
const dropReason = shownLabel(dataProp(facts, WIRE_KEY_DROP_REASON), NOTICE_TEXT_MAX);
|
|
253
|
+
if (noticeKind === 'delivery') {
|
|
254
|
+
const peer = label ?? renderMessage(msg('notice.sessionBox.peer.another'), lang);
|
|
255
|
+
if (state === 'dropped')
|
|
256
|
+
return renderMessage(dropReason !== undefined ? msg('notice.sessionBox.delivery.dropped', { peer, reason: dropReason }) : msg('notice.sessionBox.delivery.droppedPlain', { peer }), lang);
|
|
257
|
+
return renderMessage(msg(sentenceKeyOf(DELIVERY_SENTENCE_KEYS, state) ?? 'notice.sessionBox.delivery.other', { peer }), lang);
|
|
258
|
+
}
|
|
259
|
+
const peer = label ?? renderMessage(msg('notice.sessionBox.peer.anotherStart'), lang);
|
|
260
|
+
if (state === 'idle')
|
|
261
|
+
return renderMessage(detail !== undefined ? msg('notice.sessionBox.idle.finishedDetail', { peer, detail }) : msg('notice.sessionBox.idle.finished', { peer }), lang);
|
|
262
|
+
return renderMessage(msg(sentenceKeyOf(IDLE_SENTENCE_KEYS, state) ?? 'notice.sessionBox.idle.other', { peer }), lang);
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
export function sessionBoxNoticeOf(p) {
|
|
269
|
+
if (p.lane === 'inbox_notice') {
|
|
270
|
+
const facts = {
|
|
271
|
+
noticeKind: 'inbox',
|
|
272
|
+
pending: p.pending,
|
|
273
|
+
delivered: p.delivered,
|
|
274
|
+
...(p.urgent !== undefined ? { urgent: p.urgent } : {}),
|
|
275
|
+
...(p.resupplied !== undefined ? { resupplied: p.resupplied } : {}),
|
|
276
|
+
};
|
|
277
|
+
const text = sessionBoxNoticeSentence(facts);
|
|
278
|
+
return text === undefined ? undefined : { ...facts, text };
|
|
279
|
+
}
|
|
280
|
+
if (p.lane !== 'cross_session_notice' || p.notice === undefined)
|
|
281
|
+
return undefined;
|
|
282
|
+
const delivery = p.kind === 'delivery_notice';
|
|
283
|
+
const peerLabel = delivery ? (p.notice.recipient ?? p.notice.target) : (p.notice.target ?? p.notice.recipient);
|
|
284
|
+
const facts = {
|
|
285
|
+
noticeKind: delivery ? 'delivery' : 'idle',
|
|
286
|
+
state: p.notice.state,
|
|
287
|
+
...(peerLabel !== undefined ? { peerLabel } : {}),
|
|
288
|
+
...(p.notice.detail !== undefined ? { detail: p.notice.detail } : {}),
|
|
289
|
+
...(p.notice.dropReason !== undefined ? { dropReason: p.notice.dropReason } : {}),
|
|
290
|
+
...(p.notice.refSeq !== undefined ? { refSeq: p.notice.refSeq } : {}),
|
|
291
|
+
...(p.notice.finishedAt !== undefined ? { finishedAt: p.notice.finishedAt } : {}),
|
|
292
|
+
};
|
|
293
|
+
const text = sessionBoxNoticeSentence(facts);
|
|
294
|
+
return text === undefined ? undefined : { ...facts, text };
|
|
295
|
+
}
|
|
143
296
|
export function renderPeerFrameTranscriptText(p) {
|
|
144
297
|
if (p.lane === 'cross_session_notice')
|
|
145
298
|
return escapeEnvelopeTag(CROSS_SESSION_MESSAGE_TAG, escapeEnvelopeTag(AGENT_MESSAGE_TAG, neutralizeAuthorityTags(p.text)));
|
|
299
|
+
if (p.lane === 'inbox_notice')
|
|
300
|
+
return inboxLine(p.pending, p.urgent, p.resupplied, undefined);
|
|
146
301
|
if (p.lane === 'agent_message') {
|
|
147
302
|
const body = escapeEnvelopeTag(AGENT_MESSAGE_TAG, neutralizeAuthorityTags(p.body));
|
|
148
303
|
return `<${AGENT_MESSAGE_TAG} ${FROM_ATTR}="${attr(p.from)}">\n${body}\n</${AGENT_MESSAGE_TAG}>`;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const PENDING_USER_ROW_ID_PREFIX = "pending-";
|
|
2
|
+
export declare function pendingUserRowIdOf(uuid: string): string | undefined;
|
|
3
|
+
export declare function pendingUserRowUuidOf(id: string | null | undefined): string | undefined;
|
|
4
|
+
export declare function isPendingUserRowId(id: string | null | undefined): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const PENDING_USER_ROW_ID_PREFIX = 'pending-';
|
|
2
|
+
const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
3
|
+
export function pendingUserRowIdOf(uuid) {
|
|
4
|
+
if (typeof uuid !== 'string' || !UUID_V4.test(uuid))
|
|
5
|
+
return undefined;
|
|
6
|
+
return PENDING_USER_ROW_ID_PREFIX + uuid;
|
|
7
|
+
}
|
|
8
|
+
export function pendingUserRowUuidOf(id) {
|
|
9
|
+
if (typeof id !== 'string' || !id.startsWith(PENDING_USER_ROW_ID_PREFIX))
|
|
10
|
+
return undefined;
|
|
11
|
+
const uuid = id.slice(PENDING_USER_ROW_ID_PREFIX.length);
|
|
12
|
+
return pendingUserRowIdOf(uuid) === id ? uuid : undefined;
|
|
13
|
+
}
|
|
14
|
+
export function isPendingUserRowId(id) {
|
|
15
|
+
return pendingUserRowUuidOf(id) !== undefined;
|
|
16
|
+
}
|