@sema-agent/client-core 0.105.0 → 0.107.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 +301 -0
- package/README.md +40 -21
- package/dist/adapt/arms.js +10 -1
- package/dist/adapter/activeRunSelfHeal.d.ts +21 -2
- package/dist/adapter/activeRunSelfHeal.js +129 -28
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +0 -5
- package/dist/adapter/downstream/eventToSdkMessage.js +20 -19
- package/dist/adapter/downstream/terminalToSdkResult.js +2 -3
- package/dist/adapter/downstream/wiringManifestView.d.ts +1 -3
- package/dist/adapter/downstream/wiringManifestView.js +0 -1
- package/dist/adapter/runStream.js +3 -4
- package/dist/approvalReachWire.d.ts +1 -0
- package/dist/approvalReachWire.js +4 -1
- package/dist/approvalSeat.d.ts +21 -0
- package/dist/approvalSeat.js +73 -0
- package/dist/assistantInbox.d.ts +2 -0
- package/dist/assistantInbox.js +3 -0
- package/dist/checkpointRowVerdict.d.ts +29 -0
- package/dist/checkpointRowVerdict.js +98 -0
- package/dist/coreValuePorts.d.ts +12 -1
- package/dist/coreValuePorts.js +10 -0
- package/dist/decideFailureNote.js +3 -1
- package/dist/decideReceipt.d.ts +9 -0
- package/dist/decideReceipt.js +29 -1
- package/dist/declared/supportFloorDeclared.js +2 -2
- package/dist/deviceRebind.d.ts +7 -0
- package/dist/deviceRebind.js +39 -5
- package/dist/displayUntrusted.d.ts +5 -3
- package/dist/displayUntrusted.js +50 -41
- package/dist/engineAddress.d.ts +3 -0
- package/dist/engineAddress.js +25 -0
- package/dist/engineDirectory.js +9 -17
- package/dist/engineErrorCodes.d.ts +8 -0
- package/dist/engineErrorCodes.js +8 -0
- package/dist/engineNoticeCodes.d.ts +38 -3
- package/dist/engineNoticeCodes.js +167 -11
- package/dist/engineRowRef.js +1 -1
- package/dist/errorSupplementRoles.js +4 -1
- package/dist/eventLeg.d.ts +2 -2
- package/dist/eventLeg.js +2 -1
- package/dist/executionLaneCapability.js +3 -2
- package/dist/executionLaneWords.d.ts +1 -0
- package/dist/executionLaneWords.js +3 -0
- package/dist/fleet/fleetProjection.js +26 -5
- package/dist/generated/engineFactTables.d.ts +2 -1
- package/dist/generated/engineFactTables.js +3 -1
- package/dist/generated/engineNoticeTables.js +28 -7
- package/dist/generated/sdkFactTables.d.ts +3 -0
- package/dist/generated/sdkFactTables.js +15 -0
- package/dist/generated/settingsSchemaFns.d.ts +11 -0
- package/dist/generated/settingsSchemaFns.js +2 -1
- package/dist/generated/settingsSchemaSafetyMergeSpec.js +1 -1
- package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -1
- package/dist/generated/settingsSchemaSettingsSources.js +22 -2
- package/dist/hitl/approvalLiveFace.d.ts +17 -0
- package/dist/hitl/approvalLiveFace.js +35 -0
- package/dist/hitl/approvalQueueRow.d.ts +21 -0
- package/dist/hitl/approvalQueueRow.js +69 -0
- package/dist/hitl/approvalResolution.d.ts +5 -1
- package/dist/hitl/approvalResolution.js +18 -1
- package/dist/hitl/approvalsFeed.d.ts +5 -4
- package/dist/hitl/approvalsFeed.js +39 -6
- package/dist/hitl/askParkRowRouting.d.ts +4 -3
- package/dist/hitl/askParkRowRouting.js +27 -3
- package/dist/hitl/automaticAnswerVerdict.js +13 -10
- package/dist/hitl/crashConverged.d.ts +5 -1
- package/dist/hitl/decisionConflict.js +2 -1
- package/dist/hitl/decisionRefusal.js +1 -1
- package/dist/hitl/decisionSend.d.ts +3 -0
- package/dist/hitl/decisionSend.js +32 -6
- package/dist/hitl/frameRouter.js +4 -5
- package/dist/hitl/hitlBridge.d.ts +6 -2
- package/dist/hitl/hitlBridge.js +53 -7
- package/dist/hitl/livePendingAsk.d.ts +5 -0
- package/dist/hitl/livePendingAsk.js +10 -3
- package/dist/hitl/parkOwnership.js +4 -5
- package/dist/hitl/parkResolver.js +9 -5
- package/dist/hitl/parkRowBirthWait.d.ts +7 -0
- package/dist/hitl/parkRowBirthWait.js +1 -1
- package/dist/hitl/parkRowDelegation.d.ts +6 -0
- package/dist/hitl/parkRowDelegation.js +33 -0
- package/dist/hitl/persistedRulesWire.d.ts +15 -3
- package/dist/hitl/persistedRulesWire.js +102 -20
- package/dist/hitl/planReviewCard.d.ts +2 -0
- package/dist/hitl/planReviewCard.js +21 -0
- package/dist/hitl/planReviewWire.d.ts +2 -2
- package/dist/hitl/planReviewWire.js +105 -38
- package/dist/hitl/sessionAllowRoute.d.ts +7 -0
- package/dist/hitl/sessionAllowRoute.js +49 -0
- package/dist/hitl/sessionPolicyWire.d.ts +1 -7
- package/dist/hitl/sessionPolicyWire.js +3 -43
- package/dist/hitl/standingRows.js +10 -10
- package/dist/hitl/subagentSource.d.ts +1 -0
- package/dist/hitl/subagentSource.js +13 -0
- package/dist/hitl/toolApprovalWire.d.ts +3 -2
- package/dist/hitl/toolApprovalWire.js +100 -44
- package/dist/hostSettingsSource.d.ts +4 -1
- package/dist/hostSettingsSource.js +11 -6
- package/dist/hostTurnSettings.d.ts +4 -5
- package/dist/hostTurnSettings.js +80 -19
- package/dist/i18n/messages.en.d.ts +41 -12
- package/dist/i18n/messages.en.js +42 -13
- package/dist/i18n/messages.zh.js +45 -13
- package/dist/index.d.ts +22 -2
- package/dist/index.js +12 -2
- package/dist/injectionLaneNotice.js +2 -1
- package/dist/liveInitToolFace.js +0 -1
- package/dist/liveModelCatalog.d.ts +15 -0
- package/dist/liveModelCatalog.js +40 -0
- package/dist/mcpWireCaps.js +1 -1
- package/dist/modelCapabilityProbe.js +66 -33
- package/dist/noticePresentation.js +2 -0
- package/dist/ownKey.d.ts +0 -1
- package/dist/ownKey.js +0 -2
- package/dist/permissionsDeclaration.d.ts +2 -2
- package/dist/permissionsDeclaration.js +12 -14
- package/dist/projectSeed.d.ts +39 -0
- package/dist/projectSeed.js +80 -0
- package/dist/promptDelivery.js +1 -1
- package/dist/replayBody.d.ts +7 -6
- package/dist/replayBody.js +62 -7
- package/dist/request/taskRequest.js +3 -4
- package/dist/ruleCompileVerdict.d.ts +0 -2
- package/dist/ruleCompileVerdict.js +0 -31
- package/dist/ruleRefusalSentence.js +0 -3
- package/dist/runReattachPolicy.d.ts +3 -0
- package/dist/runReattachPolicy.js +15 -2
- package/dist/runTerminal.js +30 -8
- package/dist/sandboxWire.d.ts +0 -3
- package/dist/sandboxWire.js +0 -9
- package/dist/sdkWireTransit.d.ts +1 -1
- package/dist/seam.d.ts +14 -7
- package/dist/seam.js +12 -0
- package/dist/seatContract.d.ts +58 -7
- package/dist/seatContract.js +135 -4
- package/dist/serverSupportRange.d.ts +18 -0
- package/dist/serverSupportRange.js +25 -0
- package/dist/sessionEngine.d.ts +156 -0
- package/dist/sessionEngine.js +464 -0
- package/dist/sessionMap.d.ts +11 -1
- package/dist/sessionMap.js +35 -9
- package/dist/sessionMemorySync.d.ts +31 -0
- package/dist/sessionMemorySync.js +95 -0
- package/dist/sessionRowTag.d.ts +4 -0
- package/dist/sessionRowTag.js +18 -0
- package/dist/settingsLayerAdmission.d.ts +1 -0
- package/dist/settingsLayerAdmission.js +4 -1
- package/dist/toolResult.js +1 -1
- package/dist/wireRefusalCopy.d.ts +6 -1
- package/dist/wireRefusalCopy.js +9 -7
- package/docs/INTEGRATION-CLIENTS.md +1393 -18
- package/package.json +5 -5
|
@@ -10,6 +10,7 @@ import { readDecisionNoteAudit } from './approvalDecisionNoteAudit.js';
|
|
|
10
10
|
import { carrierReadOf, deliverWithAttributionLadder, isLocalSafetyStop } from './attributionLadder.js';
|
|
11
11
|
import { budgetSpent, deliverApprovalDecision, deliveryTiming, isAborted, newSendTally, PARKING_WAIT_CAP_MS, setDeliveryTimingForTests, sleepFor, settledTransportReadingOf, withTransportRetry, deliveryReadingOf, } from './approvalDelivery.js';
|
|
12
12
|
import { ASK_DECIDED_CODE, classifyDeliveredDecisionRefusal, decisionRefusalClosesOut, notPendingAfterRetry } from './decisionRefusal.js';
|
|
13
|
+
import { sessionAllowEligible } from './sessionAllowRoute.js';
|
|
13
14
|
import { addDecisionOpKeys, closeDecisionOp, decisionLedgerKeysOf, decisionOpsWithKey, openDecisionOp } from './decisionLedger.js';
|
|
14
15
|
import { hostHoldIsActive, takeHostHoldLedgerOp, tryHoldApprovalNow } from './approvalHolds.js';
|
|
15
16
|
import { answerPayloadFor, decisionAttributionKeyOf, isToolApprovalRespondReplayed, readApprovalDenySettledBy, readToolApprovalRespondAck, readToolApprovalRespondParking, } from './toolApprovalWire.js';
|
|
@@ -183,6 +184,9 @@ function bodyFacts(answer, payload, rememberUnsupported) {
|
|
|
183
184
|
...(rememberUnsupported && answer.kind === 'allow' && answer.allowSession === true ? { rememberDropped: true } : {}),
|
|
184
185
|
};
|
|
185
186
|
}
|
|
187
|
+
function answerGateCannotTake(out) {
|
|
188
|
+
return out.kind === 'not_applied' && (out.cause === 'gone' || out.cause === 'parking' || out.cause === 'lane_disabled');
|
|
189
|
+
}
|
|
186
190
|
function ownTrue(raw, key) {
|
|
187
191
|
return typeof raw === 'object' && raw !== null && guardedRead(() => readOwnDataValue(raw, key)) === true;
|
|
188
192
|
}
|
|
@@ -190,6 +194,14 @@ async function sendAskFamily(respondForFallback, decideAsk, req, ctx) {
|
|
|
190
194
|
const payload = answerPayloadFor(req.answer, 'respond', { approvalDecisionNoteCapable: ctx.noteCapable });
|
|
191
195
|
if (payload === undefined)
|
|
192
196
|
return { family: 'ask', attempts: ctx.tally.attempts, kind: 'not_sent', cause: 'not_an_answer' };
|
|
197
|
+
let fallbackRespond = respondForFallback;
|
|
198
|
+
if (req.answer.kind === 'allow' && req.answer.allowSession === true && respondForFallback !== undefined && req.approvalId !== undefined) {
|
|
199
|
+
const viaAnswerGate = await sendApprovalFamily(respondForFallback, req.approvalId, req.answer, ctx);
|
|
200
|
+
if (!answerGateCannotTake(viaAnswerGate))
|
|
201
|
+
return { ...viaAnswerGate, family: 'ask', allowSessionCarried: true };
|
|
202
|
+
hostLog('debug', `decisionSend: session-allow-fallback ask=${req.askId} cause=${String(viaAnswerGate.cause)} via=ask-decide-once`);
|
|
203
|
+
fallbackRespond = undefined;
|
|
204
|
+
}
|
|
193
205
|
const verdict = verdictOf(payload.decision) ?? 'deny';
|
|
194
206
|
const attribution = req.answer.kind === 'deny' ? decisionAttributionKeyOf(ctx.decidedBy, readApprovalDenySettledBy(req.answer)) : {};
|
|
195
207
|
const body = {
|
|
@@ -232,8 +244,8 @@ async function sendAskFamily(respondForFallback, decideAsk, req, ctx) {
|
|
|
232
244
|
}
|
|
233
245
|
const out = outcomeOfThrown(e, 'ask', verdict, ctx.signal, ctx.tally, ctx.noteCapable, settled);
|
|
234
246
|
if (out.kind === 'not_applied' && out.cause === 'lane_disabled' && code === ASK_DECISION_LANE_DISABLED && req.approvalId !== undefined) {
|
|
235
|
-
if (
|
|
236
|
-
const fb = await sendApprovalFamily(
|
|
247
|
+
if (fallbackRespond !== undefined && ctx.signal?.aborted !== true) {
|
|
248
|
+
const fb = await sendApprovalFamily(fallbackRespond, req.approvalId, req.answer, ctx);
|
|
237
249
|
return { ...fb, family: 'ask', fallback: 'approval' };
|
|
238
250
|
}
|
|
239
251
|
}
|
|
@@ -374,6 +386,14 @@ function snapshotAnswer(raw) {
|
|
|
374
386
|
}
|
|
375
387
|
return typeof kind === 'string' ? Object.freeze({ kind }) : undefined;
|
|
376
388
|
}
|
|
389
|
+
function sessionGatedAnswer(answer, card) {
|
|
390
|
+
if (answer.kind !== 'allow' || answer.allowSession !== true)
|
|
391
|
+
return { answer };
|
|
392
|
+
const why = card === undefined ? 'card_absent' : typeof card === 'object' && card !== null ? sessionAllowEligible(card) : 'card_unreadable';
|
|
393
|
+
if (why === 'given')
|
|
394
|
+
return { answer };
|
|
395
|
+
return { answer: Object.freeze({ ...answer, allowSession: false }), dropped: why };
|
|
396
|
+
}
|
|
377
397
|
function readRequest(req) {
|
|
378
398
|
if (typeof req !== 'object' || req === null)
|
|
379
399
|
return undefined;
|
|
@@ -387,17 +407,19 @@ function readRequest(req) {
|
|
|
387
407
|
const rawAnswer = guardedRead(() => readOwnDataValue(req, 'answer'));
|
|
388
408
|
if (typeof rawAnswer !== 'object' || rawAnswer === null)
|
|
389
409
|
return undefined;
|
|
390
|
-
const
|
|
391
|
-
if (
|
|
410
|
+
const snapshot = snapshotAnswer(rawAnswer);
|
|
411
|
+
if (snapshot === undefined)
|
|
392
412
|
return undefined;
|
|
413
|
+
const { answer, dropped } = sessionGatedAnswer(snapshot, guardedRead(() => readOwnDataValue(req, 'card')));
|
|
414
|
+
const droppedFact = dropped !== undefined ? { sessionAllowDropped: dropped } : {};
|
|
393
415
|
if (family === 'approval') {
|
|
394
416
|
const approvalId = s('approvalId');
|
|
395
|
-
return approvalId !== undefined ? { family, approvalId, taskId: s('taskId'), toolCallId: s('toolCallId'), answer } : undefined;
|
|
417
|
+
return approvalId !== undefined ? { family, approvalId, taskId: s('taskId'), toolCallId: s('toolCallId'), answer, ...droppedFact } : undefined;
|
|
396
418
|
}
|
|
397
419
|
if (family === 'ask') {
|
|
398
420
|
const taskId = s('taskId');
|
|
399
421
|
const askId = s('askId');
|
|
400
|
-
return taskId !== undefined && askId !== undefined ? { family, taskId, askId, approvalId: s('approvalId'), toolCallId: s('toolCallId'), answer } : undefined;
|
|
422
|
+
return taskId !== undefined && askId !== undefined ? { family, taskId, askId, approvalId: s('approvalId'), toolCallId: s('toolCallId'), answer, ...droppedFact } : undefined;
|
|
401
423
|
}
|
|
402
424
|
return undefined;
|
|
403
425
|
}
|
|
@@ -507,6 +529,10 @@ export async function sendHitlDecision(request, deps) {
|
|
|
507
529
|
out = outcomeOfThrown(e, 'elicitation', undefined, signal, ctx.tally, false);
|
|
508
530
|
}
|
|
509
531
|
}
|
|
532
|
+
if (req.family !== 'elicitation' && req.sessionAllowDropped !== undefined) {
|
|
533
|
+
hostLog('debug', `decisionSend: session-allow-not-eligible ${req.family}=${req.family === 'ask' ? req.askId : req.approvalId} why=${req.sessionAllowDropped} via=allow-once`);
|
|
534
|
+
out = { ...out, rememberDropped: true };
|
|
535
|
+
}
|
|
510
536
|
const ambiguous = out.kind === 'unconfirmed' || (out.kind === 'not_applied' && (out.cause === 'parking' || out.cause === 'refused' || out.cause === 'idempotency_crossed'));
|
|
511
537
|
if (ambiguous && out.cause !== 'aborted') {
|
|
512
538
|
const gate = req.family === 'elicitation'
|
package/dist/hitl/frameRouter.js
CHANGED
|
@@ -20,6 +20,7 @@ import { ccToolDenialKindForSettledBy } from '../gateVocabulary.js';
|
|
|
20
20
|
import { REJECT_MESSAGE } from '../adapt/wireShapes.js';
|
|
21
21
|
import { RUN_CANCELLED_CODE } from '../runCancelContext.js';
|
|
22
22
|
import { durableDecideLegOf } from '../adapter/activeRunSelfHeal.js';
|
|
23
|
+
import { subagentSourceSessionOf } from './subagentSource.js';
|
|
23
24
|
export const HITL_REJECT_MESSAGE = REJECT_MESSAGE;
|
|
24
25
|
export const HITL_POLICY_DENY_MESSAGE = 'Permission for this tool use was denied: it requires interactive approval, and permission prompts are ' +
|
|
25
26
|
'not available in this session. The action was NOT performed. Do not claim it succeeded, and do not retry ' +
|
|
@@ -135,13 +136,11 @@ export function parkGateArmOf(gate) {
|
|
|
135
136
|
return null;
|
|
136
137
|
}
|
|
137
138
|
const leg = durableDecideLegOf(typeof kind === 'string' ? { gateKind: kind } : null);
|
|
138
|
-
if (leg !== 'approval'
|
|
139
|
+
if (leg !== 'approval')
|
|
139
140
|
return null;
|
|
140
141
|
if (questionCardVerdict(gate) ?? isAskToolLoose(toolName))
|
|
141
142
|
return 'ask';
|
|
142
|
-
|
|
143
|
-
return 'fs';
|
|
144
|
-
return isFsOrShellToolName(toolName) ? 'fs' : null;
|
|
143
|
+
return 'fs';
|
|
145
144
|
}
|
|
146
145
|
const ENGINE_GATE_PARKED_ERROR_CODE = GATE_PARKED_ERROR_CODE;
|
|
147
146
|
function isEngineAbortToolEnd(ev) {
|
|
@@ -336,7 +335,7 @@ async function routeToolApprovalFrame(ev, ctx) {
|
|
|
336
335
|
}
|
|
337
336
|
}
|
|
338
337
|
const fromSubagent = isFromSubagent(ev);
|
|
339
|
-
hostLog('debug', `liveHitlAskWire: tool_approval frame ${ev.approvalId} tool=${String(ev.toolName)}${fromSubagent ? ` from-subagent=${String(ev
|
|
338
|
+
hostLog('debug', `liveHitlAskWire: tool_approval frame ${ev.approvalId} tool=${String(ev.toolName)}${fromSubagent ? ` from-subagent=${String(subagentSourceSessionOf(ev) ?? ev.sourceAgentName ?? 'explicit')}` : ''}`);
|
|
340
339
|
const frameCallId = !fromSubagent && typeof ev.toolCallId === 'string' && ev.toolCallId !== '' ? ev.toolCallId : undefined;
|
|
341
340
|
const gatedCallId = fromSubagent ? undefined : frameCallId ?? led.lastPendingFsCall();
|
|
342
341
|
const argsCallId = frameCallId === undefined ? gatedCallId : typeof ev.toolName === 'string' && toolNameIsFsWrite(ev.toolName) ? frameCallId : undefined;
|
|
@@ -3,6 +3,7 @@ import type { PermissionResult } from '@sema-agent/agent-types';
|
|
|
3
3
|
import { type CapturedLocalCode, type CauseSlotRead } from '../engineWireFor.js';
|
|
4
4
|
import type { ApprovalsListEnvelope } from './crashConverged.js';
|
|
5
5
|
import { type SuspendedReopenReading } from './suspendedReopen.js';
|
|
6
|
+
import type { CheckpointRowVerdictReading } from '../checkpointRowVerdict.js';
|
|
6
7
|
export declare const DEFAULT_DENY_REASON = "The user rejected this tool use";
|
|
7
8
|
export declare const MAX_DENY_REASON_CHARS = 4096;
|
|
8
9
|
export declare function denyReasonForWire(reason: string | undefined, tag: string): string | undefined;
|
|
@@ -26,7 +27,7 @@ export interface AssistantResourceLike {
|
|
|
26
27
|
planReview(taskId: string, req: PlanReviewRequest, opts?: {
|
|
27
28
|
signal?: AbortSignal;
|
|
28
29
|
}): Promise<AssistantTaskStatus>;
|
|
29
|
-
resume(taskId: string, opts?: {
|
|
30
|
+
resume(taskId: string, body?: undefined, opts?: {
|
|
30
31
|
signal?: AbortSignal;
|
|
31
32
|
}): Promise<AssistantTaskStatus>;
|
|
32
33
|
}
|
|
@@ -132,7 +133,10 @@ export type FindPendingOutcome = {
|
|
|
132
133
|
} | {
|
|
133
134
|
ok: false;
|
|
134
135
|
reason: string;
|
|
135
|
-
code?: 'no_pending' | 'wrong_gate';
|
|
136
|
+
code?: 'no_pending' | 'wrong_gate' | 'row_unresumable';
|
|
137
|
+
rowVerdict?: Exclude<CheckpointRowVerdictReading, {
|
|
138
|
+
readonly kind: 'ok';
|
|
139
|
+
}>;
|
|
136
140
|
};
|
|
137
141
|
export declare function findPendingForTask(client: HitlClientLike, taskId: string, matches: (toolName: string | undefined) => boolean, opts?: {
|
|
138
142
|
signal?: AbortSignal;
|
package/dist/hitl/hitlBridge.js
CHANGED
|
@@ -10,6 +10,9 @@ import { APPROVAL_BINDING_MISMATCH, CHECKPOINT_INVALID_OUTCOME, RESUME_POLICY_FO
|
|
|
10
10
|
import { suspendedReopenOf } from './suspendedReopen.js';
|
|
11
11
|
import { closeDecisionOp, decisionLedgerKeysOf, openDecisionOp } from './decisionLedger.js';
|
|
12
12
|
import { askParkBlockGeneration, noteAskParkDecideSettled } from './askParkAutoReopenBlock.js';
|
|
13
|
+
import { checkpointQueueRowSortOf, QUEUE_ROW_FAMILY_UNREADABLE_GATE } from './approvalQueueRow.js';
|
|
14
|
+
import { checkpointRowBarOf, checkpointRowBarSentence } from '../checkpointRowVerdict.js';
|
|
15
|
+
import { msg, renderMessage } from '../i18n/translate.js';
|
|
13
16
|
export const DEFAULT_DENY_REASON = 'The user rejected this tool use';
|
|
14
17
|
export const MAX_DENY_REASON_CHARS = 4096;
|
|
15
18
|
export function denyReasonForWire(reason, tag) {
|
|
@@ -28,6 +31,15 @@ export function denyReasonForWire(reason, tag) {
|
|
|
28
31
|
`(server caps approval reason at ${MAX_DENY_REASON_CHARS}; over-cap is a 413 reason_too_large that would drop the DECISION, not just the reason)`);
|
|
29
32
|
return cut;
|
|
30
33
|
}
|
|
34
|
+
function resumeTakesRestatementBody(client) {
|
|
35
|
+
if (typeof Reflect.get(client.approvals, 'decidePeerInbound') === 'function')
|
|
36
|
+
return true;
|
|
37
|
+
return client.assistant.resume.length >= 3;
|
|
38
|
+
}
|
|
39
|
+
const _realClientFitsHitlSlice = true;
|
|
40
|
+
void _realClientFitsHitlSlice;
|
|
41
|
+
const _bindingKeysEchoed = true;
|
|
42
|
+
void _bindingKeysEchoed;
|
|
31
43
|
export const PLAN_REVIEW_MODE_AFTER_WORDS = Object.freeze(['default', 'acceptEdits']);
|
|
32
44
|
export function isPlanReviewModeAfter(v) {
|
|
33
45
|
return v !== undefined && PLAN_REVIEW_MODE_AFTER_WORDS.includes(v);
|
|
@@ -258,7 +270,13 @@ export async function findPendingForTask(client, taskId, matches, opts, callId,
|
|
|
258
270
|
hostLog('debug', `hitlBridge: approvals.list failed: ${t.log}`);
|
|
259
271
|
return { ok: false, reason: `approvals.list failed: ${t.reason}` };
|
|
260
272
|
}
|
|
261
|
-
const readings = rows.
|
|
273
|
+
const readings = rows.flatMap((r) => {
|
|
274
|
+
const sort = checkpointQueueRowSortOf(r);
|
|
275
|
+
if (sort === 'excluded')
|
|
276
|
+
return [];
|
|
277
|
+
const cp = r;
|
|
278
|
+
return [{ r: cp, foreign: sort === 'unreadable' ? QUEUE_ROW_FAMILY_UNREADABLE_GATE : askParkForeignGateKind(cp) }];
|
|
279
|
+
});
|
|
262
280
|
const decidable = readings.filter((x) => x.foreign === null).map((x) => x.r);
|
|
263
281
|
const identityRow = callId !== undefined
|
|
264
282
|
? decidable.find((r) => r.taskId === taskId && (r.boundCallId === callId || r.toolCallId === callId))
|
|
@@ -267,6 +285,9 @@ export async function findPendingForTask(client, taskId, matches, opts, callId,
|
|
|
267
285
|
? readings.find((x) => x.r.taskId === taskId && (x.r.boundCallId === callId || x.r.toolCallId === callId) && x.foreign !== null)
|
|
268
286
|
: undefined;
|
|
269
287
|
if (identityForeign !== undefined) {
|
|
288
|
+
const identityBar = identityForeign.foreign === QUEUE_ROW_FAMILY_UNREADABLE_GATE ? checkpointRowBarOf(identityForeign.r) : undefined;
|
|
289
|
+
if (identityBar !== undefined)
|
|
290
|
+
return { ok: false, reason: checkpointRowBarSentence(identityBar), code: 'row_unresumable', rowVerdict: identityBar };
|
|
270
291
|
return {
|
|
271
292
|
ok: false,
|
|
272
293
|
reason: `the pending row this park names (call ${callId}) is parked on a '${String(identityForeign.foreign)}' gate — not an approval this leg decides; refusing to decide a different row`,
|
|
@@ -278,8 +299,19 @@ export async function findPendingForTask(client, taskId, matches, opts, callId,
|
|
|
278
299
|
const pending = (identityConflicts ? undefined : identityRow) ??
|
|
279
300
|
pool.find((r) => r.taskId === taskId && matches(typeof r.toolName === 'string' ? r.toolName : undefined)) ??
|
|
280
301
|
pool.find((r) => r.taskId === taskId);
|
|
281
|
-
if (!pending)
|
|
302
|
+
if (!pending) {
|
|
303
|
+
for (const x of readings) {
|
|
304
|
+
if (x.r.taskId !== taskId || x.foreign !== QUEUE_ROW_FAMILY_UNREADABLE_GATE)
|
|
305
|
+
continue;
|
|
306
|
+
const unreadableBar = checkpointRowBarOf(x.r);
|
|
307
|
+
if (unreadableBar !== undefined)
|
|
308
|
+
return { ok: false, reason: checkpointRowBarSentence(unreadableBar), code: 'row_unresumable', rowVerdict: unreadableBar };
|
|
309
|
+
}
|
|
282
310
|
return { ok: false, reason: 'no pending checkpoint for this run (resolved/expired?)', code: 'no_pending' };
|
|
311
|
+
}
|
|
312
|
+
const bar = checkpointRowBarOf(pending);
|
|
313
|
+
if (bar !== undefined)
|
|
314
|
+
return { ok: false, reason: checkpointRowBarSentence(bar), code: 'row_unresumable', rowVerdict: bar };
|
|
283
315
|
return { ok: true, pending, gatedCallId: pending.toolCallId ?? pending.boundCallId ?? undefined };
|
|
284
316
|
}
|
|
285
317
|
export class HitlBridge {
|
|
@@ -328,18 +360,22 @@ export class HitlBridge {
|
|
|
328
360
|
throw new Error(found.reason);
|
|
329
361
|
}
|
|
330
362
|
bindingOf(p) {
|
|
331
|
-
|
|
363
|
+
const boundCallId = readOwnDataValue(p, 'boundCallId');
|
|
364
|
+
const boundInputHash = readOwnDataValue(p, 'boundInputHash');
|
|
365
|
+
if (typeof boundCallId !== 'string' || boundCallId.length === 0 || typeof boundInputHash !== 'string' || boundInputHash.length === 0) {
|
|
332
366
|
throw new HitlSafetyError(`pending checkpoint ${p.id ?? '<no-id>'} is missing D-1 binding fields ` +
|
|
333
|
-
`(boundCallId=${String(
|
|
334
|
-
|
|
367
|
+
`(boundCallId=${String(boundCallId)}, boundInputHash=${String(boundInputHash)}) — ` +
|
|
368
|
+
`the row itself carries no binding to echo, so ${renderMessage(msg('approval.decide.unboundWayOut'))}`, 'binding_missing');
|
|
335
369
|
}
|
|
336
|
-
return { boundCallId
|
|
370
|
+
return { boundCallId, boundInputHash };
|
|
337
371
|
}
|
|
338
372
|
async decideTool(outcome, toolUseID, opts, preResolvedPending) {
|
|
339
373
|
const pending = preResolvedPending ?? (await this.pendingForDecide(toolUseID, wireOptsOf(opts)));
|
|
340
374
|
if (!pending) {
|
|
341
375
|
throw new HitlSafetyError('no pending checkpoint to decide (resolved/expired under the human) — refetch + re-present', 'no_pending');
|
|
342
376
|
}
|
|
377
|
+
if (preResolvedPending !== undefined)
|
|
378
|
+
assertPendingRowResumable(preResolvedPending);
|
|
343
379
|
const decision = outcome.decision === 'approve'
|
|
344
380
|
? {
|
|
345
381
|
decision: 'approve',
|
|
@@ -365,6 +401,8 @@ export class HitlBridge {
|
|
|
365
401
|
if (!pending) {
|
|
366
402
|
throw new HitlSafetyError('no pending AskUserQuestion checkpoint to answer — refetch + re-present', 'no_pending');
|
|
367
403
|
}
|
|
404
|
+
if (preResolvedPending !== undefined)
|
|
405
|
+
assertPendingRowResumable(preResolvedPending);
|
|
368
406
|
const decision = {
|
|
369
407
|
decision: 'approve',
|
|
370
408
|
answer: { answers: answers.map((a) => marshalAnswer(a)) },
|
|
@@ -406,7 +444,10 @@ export class HitlBridge {
|
|
|
406
444
|
if (kind && kind !== 'resource_limit') {
|
|
407
445
|
throw new HitlSafetyError(`cannot resume a "${kind}" gate — "continue" must never bypass a human approval; use decide`, 'wrong_gate');
|
|
408
446
|
}
|
|
409
|
-
|
|
447
|
+
const assistant = this.client.assistant;
|
|
448
|
+
if (resumeTakesRestatementBody(this.client))
|
|
449
|
+
return assistant.resume(this.taskId, undefined, opts);
|
|
450
|
+
return Reflect.apply(assistant.resume, assistant, [this.taskId, opts]);
|
|
410
451
|
}
|
|
411
452
|
async decideRaw(sessionId, decision, optsIn) {
|
|
412
453
|
const opts = wireOptsOf(optsIn);
|
|
@@ -520,6 +561,11 @@ export function makeHitlCanUseTool(bridge, prompt) {
|
|
|
520
561
|
return decision;
|
|
521
562
|
};
|
|
522
563
|
}
|
|
564
|
+
function assertPendingRowResumable(pending) {
|
|
565
|
+
const bar = checkpointRowBarOf(pending);
|
|
566
|
+
if (bar !== undefined)
|
|
567
|
+
throw new Error(checkpointRowBarSentence(bar));
|
|
568
|
+
}
|
|
523
569
|
function assertAnswersSendable(answers) {
|
|
524
570
|
if (!Array.isArray(answers) || answers.length === 0) {
|
|
525
571
|
throw new HitlSafetyError('refusing to send an EMPTY AskUserQuestion answer set — `{answers:[]}` is the wire\'s DENY/NO_HUMAN form, ' +
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ApprovalRequestFrame } from '@sema-agent/sdk';
|
|
2
2
|
import type { ApprovalResolution } from './approvalResolution.js';
|
|
3
3
|
import type { ApprovalsFeedEmission } from './approvalsFeed.js';
|
|
4
|
+
import type { ApprovalMandateWord } from '../gateVocabulary.js';
|
|
4
5
|
import { type RespondToolApprovalFn, type ToolApprovalFrame, type ToolApprovalFrameLaneOpts } from './toolApprovalWire.js';
|
|
5
6
|
export interface LivePendingAskView {
|
|
6
7
|
approvalId: string;
|
|
@@ -13,6 +14,10 @@ export interface LivePendingAskView {
|
|
|
13
14
|
fromSubagent?: true;
|
|
14
15
|
originTaskId?: string;
|
|
15
16
|
frame?: ToolApprovalFrame | ApprovalRequestFrame;
|
|
17
|
+
mandated?: true;
|
|
18
|
+
mandate?: ApprovalMandateWord;
|
|
19
|
+
origin?: string;
|
|
20
|
+
liveFactsUnknown?: true;
|
|
16
21
|
}
|
|
17
22
|
export type LivePendingReading = {
|
|
18
23
|
kind: 'not_reported';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { isApprovalRequestFrameV1 } from '@sema-agent/sdk';
|
|
2
2
|
import { appendOwnElement } from '../ownKey.js';
|
|
3
3
|
import { readRequiresRealApproval } from './approvalCardReading.js';
|
|
4
|
+
import { pendingRowIsOfSession } from './parkRowDelegation.js';
|
|
5
|
+
import { approvalLiveFaceOf, liveFaceCarried } from './approvalLiveFace.js';
|
|
4
6
|
import { THROWN_SLOT_UNREADABLE, readThrownSlot } from '../wireFailureShape.js';
|
|
5
7
|
import { isToolApprovalFrame, surfaceToolApprovalFrameAndRespond, } from './toolApprovalWire.js';
|
|
6
8
|
function nonEmptyString(v) {
|
|
@@ -61,6 +63,8 @@ export function readLivePendingRows(body) {
|
|
|
61
63
|
continue;
|
|
62
64
|
}
|
|
63
65
|
seen.add(o.approvalId);
|
|
66
|
+
const opening = openingFrameOf(o.frame);
|
|
67
|
+
const frame = opening !== undefined && opening.approvalId === o.approvalId ? opening : undefined;
|
|
64
68
|
rows.push({
|
|
65
69
|
approvalId: o.approvalId,
|
|
66
70
|
toolName: o.toolName,
|
|
@@ -71,7 +75,8 @@ export function readLivePendingRows(body) {
|
|
|
71
75
|
...(o.governanceForced === true ? { governanceForced: true } : {}),
|
|
72
76
|
...(o.fromSubagent === true ? { fromSubagent: true } : {}),
|
|
73
77
|
...(nonEmptyString(o.originTaskId) ? { originTaskId: o.originTaskId } : {}),
|
|
74
|
-
...(
|
|
78
|
+
...(frame !== undefined ? { frame } : {}),
|
|
79
|
+
...(frame === undefined ? liveFaceCarried(approvalLiveFaceOf(o)) : {}),
|
|
75
80
|
});
|
|
76
81
|
}
|
|
77
82
|
if (members.length > 0 && rows.length === 0)
|
|
@@ -120,7 +125,8 @@ export function countApprovalsAwaitingDecision(snapshot, filter) {
|
|
|
120
125
|
if (snapshot.kind === 'unknown')
|
|
121
126
|
return { durable: null, live: null, suspendedSubagent: null };
|
|
122
127
|
const bySession = (rows) => scope.kind === 'session' ? rows.filter(r => r.sessionId === scope.sessionId) : [...rows];
|
|
123
|
-
const
|
|
128
|
+
const durableOfSession = (rows) => scope.kind === 'session' ? rows.filter(r => pendingRowIsOfSession(r, scope.sessionId)).length : rows.length;
|
|
129
|
+
const durable = (snapshot.pendingDropped ?? 0) > 0 ? null : Array.isArray(snapshot.pending) ? durableOfSession(snapshot.pending) : null;
|
|
124
130
|
if (!Array.isArray(snapshot.livePending))
|
|
125
131
|
return { durable, live: null, suspendedSubagent: null };
|
|
126
132
|
if ((snapshot.livePendingDropped ?? 0) > 0)
|
|
@@ -134,9 +140,10 @@ export function livePendingRowToApprovalFrame(row) {
|
|
|
134
140
|
approvalId: row.approvalId,
|
|
135
141
|
toolName: row.toolName,
|
|
136
142
|
...(row.fromSubagent === true ? { fromSubagent: true } : {}),
|
|
137
|
-
...(row.originTaskId !== undefined ? {
|
|
143
|
+
...(row.originTaskId !== undefined ? { sourceSessionId: row.originTaskId } : {}),
|
|
138
144
|
...(row.governanceForced === true ? { governanceForced: true } : {}),
|
|
139
145
|
...(readRequiresRealApproval(row) ? { requiresRealApproval: true } : {}),
|
|
146
|
+
...liveFaceCarried(approvalLiveFaceOf(row)),
|
|
140
147
|
};
|
|
141
148
|
}
|
|
142
149
|
export function surfaceSuspendedAskAndRespond(row, respond, signal, lane) {
|
|
@@ -2,6 +2,7 @@ import { isOwnEngineRun } from '../subagentContentStore.js';
|
|
|
2
2
|
import { rowIdTail } from '../workflow.js';
|
|
3
3
|
import { hostSessionFor } from '../host.js';
|
|
4
4
|
import { DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
5
|
+
import { pendingRowIsOfSession } from './parkRowDelegation.js';
|
|
5
6
|
export function pendingRowIsOwnedByThisSession(row, deps) {
|
|
6
7
|
const sessionKey = deps?.sessionKey ?? DEFAULT_SESSION_KEY;
|
|
7
8
|
const rowTaskId = typeof row.taskId === 'string' ? row.taskId : '';
|
|
@@ -14,11 +15,9 @@ export function pendingRowIsOwnedByThisSession(row, deps) {
|
|
|
14
15
|
}
|
|
15
16
|
const currentSessionId = deps?.currentSessionId ?? (() => hostSessionFor(sessionKey)?.currentSessionId());
|
|
16
17
|
const sessionId = currentSessionId();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
rowSessionId.length > 0 &&
|
|
21
|
-
rowSessionId === sessionId);
|
|
18
|
+
if (typeof sessionId !== 'string' || sessionId.length === 0)
|
|
19
|
+
return false;
|
|
20
|
+
return pendingRowIsOfSession(row, sessionId);
|
|
22
21
|
}
|
|
23
22
|
export function askQuestionsFromPending(pending) {
|
|
24
23
|
const input = pending.input;
|
|
@@ -12,6 +12,7 @@ import { approvalCallKey, askGateQuestionId } from './gateIdentity.js';
|
|
|
12
12
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
13
13
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
14
14
|
import { wireFailureTextsOf } from '../wireFailureShape.js';
|
|
15
|
+
import { msg, renderMessage } from '../i18n/translate.js';
|
|
15
16
|
export const MAX_GATE_HOPS = 2;
|
|
16
17
|
export function nextHopBudget(prev, round) {
|
|
17
18
|
const total = (prev?.total ?? 0) + 1;
|
|
@@ -63,7 +64,7 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
63
64
|
}
|
|
64
65
|
const found = await findPendingForTask(deps.client, taskId, isAskTool, signal ? { signal } : undefined, parkGatedCallId, (row) => isAskTool(typeof row.toolName === 'string' ? row.toolName : undefined));
|
|
65
66
|
if (!found.ok)
|
|
66
|
-
return { kind: 'not_sent', lane: 'ask', cause: found.code ?? 'fetch_failed', ...(found.reason !== '' ? { detail: found.reason } : {}) };
|
|
67
|
+
return { kind: 'not_sent', lane: 'ask', cause: found.code ?? 'fetch_failed', ...(found.reason !== '' ? { detail: found.reason } : {}), ...(found.rowVerdict !== undefined ? { rowVerdict: found.rowVerdict } : {}) };
|
|
67
68
|
const { pending, gatedCallId } = found;
|
|
68
69
|
const at = { lane: 'ask', ...(gatedCallId !== undefined ? { gatedCallId } : {}) };
|
|
69
70
|
const fromArgs = gatedCallId
|
|
@@ -284,7 +285,8 @@ export async function resolvePark(park, ctx) {
|
|
|
284
285
|
? 'the approval card was retracted by the host without a decision (nothing was sent; the run stays parked and remains decidable elsewhere)'
|
|
285
286
|
: failureReasonOf(outcome);
|
|
286
287
|
const noDecisionSurface = outcome.kind === 'not_sent' && outcome.cause === 'card_unavailable' && outcome.detail !== undefined && isNoDecisionSurfaceReason(outcome.detail);
|
|
287
|
-
|
|
288
|
+
const undecidableHere = outcome.kind === 'not_sent' && (outcome.cause === 'row_unresumable' || (outcome.cause === 'safety_stop' && outcome.safetyCode === 'binding_missing'));
|
|
289
|
+
return { kind: 'failsoft', events: failsoftEvents(park, ctx, interrupted, failedReason, undefined, noDecisionSurface, undecidableHere) };
|
|
288
290
|
}
|
|
289
291
|
led.dropHeldForDecidedPark(outcome.gatedCallId, park.gatedCallId);
|
|
290
292
|
if (outcome.gatedCallId) {
|
|
@@ -307,15 +309,17 @@ export async function resolvePark(park, ctx) {
|
|
|
307
309
|
...(handoffTaskId !== undefined ? { handoffTaskId } : {}),
|
|
308
310
|
};
|
|
309
311
|
}
|
|
310
|
-
function failsoftReasonSentence(park, failedReason, terminal) {
|
|
312
|
+
function failsoftReasonSentence(park, failedReason, terminal, reasonCarriesWayOut = false) {
|
|
311
313
|
if (terminal !== undefined)
|
|
312
314
|
return terminal.errorMessage;
|
|
313
315
|
if (failedReason === undefined)
|
|
314
316
|
return undefined;
|
|
317
|
+
if (reasonCarriesWayOut)
|
|
318
|
+
return renderMessage(msg('approval.park.stillParked', { gate: park.gate === 'fs' ? 'Tool approval' : 'AskUserQuestion', reason: failedReason }));
|
|
315
319
|
return (`${park.gate === 'fs' ? 'Tool approval' : 'AskUserQuestion'} gate could not be answered: ${failedReason}` +
|
|
316
320
|
' — the run is still parked on this approval: decide it on the card when it is shown again, or cancel the run.');
|
|
317
321
|
}
|
|
318
|
-
function failsoftEvents(park, ctx, gateAbortedByUser, failedReason, terminal, noDecisionSurface = false) {
|
|
322
|
+
function failsoftEvents(park, ctx, gateAbortedByUser, failedReason, terminal, noDecisionSurface = false, reasonCarriesWayOut = false) {
|
|
319
323
|
const events = [
|
|
320
324
|
...flushHeldWithInterruptRewrite(ctx.led, {
|
|
321
325
|
terminal: park.pendingDone,
|
|
@@ -323,7 +327,7 @@ function failsoftEvents(park, ctx, gateAbortedByUser, failedReason, terminal, no
|
|
|
323
327
|
gateAbortedByUser,
|
|
324
328
|
}),
|
|
325
329
|
];
|
|
326
|
-
const reason = failsoftReasonSentence(park, failedReason, terminal);
|
|
330
|
+
const reason = failsoftReasonSentence(park, failedReason, terminal, reasonCarriesWayOut);
|
|
327
331
|
if (park.pendingDone) {
|
|
328
332
|
events.push(reason === undefined || noDecisionSurface ? park.pendingDone : inheritFrameBinding(park.pendingDone, { ...park.pendingDone, _sema_park_failed_reason: reason }));
|
|
329
333
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CheckpointRowVerdictReading } from '../checkpointRowVerdict.js';
|
|
1
2
|
export type ParkRowProbe<Row> = {
|
|
2
3
|
kind: 'row';
|
|
3
4
|
row: Row;
|
|
@@ -7,6 +8,9 @@ export type ParkRowProbe<Row> = {
|
|
|
7
8
|
} | {
|
|
8
9
|
kind: 'settled';
|
|
9
10
|
reason: string;
|
|
11
|
+
rowVerdict?: Exclude<CheckpointRowVerdictReading, {
|
|
12
|
+
readonly kind: 'ok';
|
|
13
|
+
}>;
|
|
10
14
|
};
|
|
11
15
|
export type ParkRowWaitVerdict<Row> = {
|
|
12
16
|
kind: 'row';
|
|
@@ -23,6 +27,9 @@ export type ParkRowWaitVerdict<Row> = {
|
|
|
23
27
|
reason: string;
|
|
24
28
|
waitedMs: number;
|
|
25
29
|
probes: number;
|
|
30
|
+
rowVerdict?: Exclude<CheckpointRowVerdictReading, {
|
|
31
|
+
readonly kind: 'ok';
|
|
32
|
+
}>;
|
|
26
33
|
} | {
|
|
27
34
|
kind: 'aborted';
|
|
28
35
|
waitedMs: number;
|
|
@@ -103,7 +103,7 @@ export async function waitForParkRowBirth(deps) {
|
|
|
103
103
|
if (probed.kind === 'row')
|
|
104
104
|
return { kind: 'row', row: probed.row, waitedMs: now() - startedAt, probes };
|
|
105
105
|
if (probed.kind === 'settled') {
|
|
106
|
-
return { kind: 'settled', reason: probed.reason, waitedMs: now() - startedAt, probes };
|
|
106
|
+
return { kind: 'settled', reason: probed.reason, waitedMs: now() - startedAt, probes, ...(probed.rowVerdict !== undefined ? { rowVerdict: probed.rowVerdict } : {}) };
|
|
107
107
|
}
|
|
108
108
|
lastReason = probed.reason;
|
|
109
109
|
const remainingMs = budgetMs - (now() - startedAt);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface ParkRowDelegationLinks {
|
|
2
|
+
readonly parentSessionId?: string;
|
|
3
|
+
readonly rootSessionId?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function pendingRowIsOfSession(row: object, sessionId: string): boolean;
|
|
6
|
+
export declare function parkRowDelegationLinksOf(row: object | null | undefined): ParkRowDelegationLinks | undefined;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { slotReadOf } from '../wireFailureShape.js';
|
|
2
|
+
export function pendingRowIsOfSession(row, sessionId) {
|
|
3
|
+
if (sessionId.length === 0)
|
|
4
|
+
return false;
|
|
5
|
+
const rowSessionId = typeof row.sessionId === 'string' ? row.sessionId : '';
|
|
6
|
+
if (rowSessionId.length > 0 && rowSessionId === sessionId)
|
|
7
|
+
return true;
|
|
8
|
+
const links = parkRowDelegationLinksOf(row);
|
|
9
|
+
return links !== undefined && (links.parentSessionId === sessionId || links.rootSessionId === sessionId);
|
|
10
|
+
}
|
|
11
|
+
export function parkRowDelegationLinksOf(row) {
|
|
12
|
+
try {
|
|
13
|
+
if (typeof row !== 'object' || row === null)
|
|
14
|
+
return undefined;
|
|
15
|
+
const a = slotReadOf(row, 'agent');
|
|
16
|
+
if (a.presence !== 'present' || typeof a.value !== 'object' || a.value === null)
|
|
17
|
+
return undefined;
|
|
18
|
+
const agent = a.value;
|
|
19
|
+
const link = (key) => {
|
|
20
|
+
const r = slotReadOf(agent, key);
|
|
21
|
+
return r.presence === 'present' && typeof r.value === 'string' && r.value !== '' ? r.value : undefined;
|
|
22
|
+
};
|
|
23
|
+
const parentSessionId = link('parentSessionId');
|
|
24
|
+
const rootSessionId = link('rootSessionId');
|
|
25
|
+
return Object.freeze({
|
|
26
|
+
...(parentSessionId !== undefined ? { parentSessionId } : {}),
|
|
27
|
+
...(rootSessionId !== undefined ? { rootSessionId } : {}),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CcImportLayer, CcImportPrepareResult,
|
|
1
|
+
import type { CcImportLayer, CcImportPrepareResult, PersistedRule, RuleBehavior, RuleListParams, RuleListResult, RuleRevokeRequest, RemovalLiveness, RuleRevokeResult, RuleWriteRequest, RuleWriteResult, RulesResource } from '@sema-agent/sdk';
|
|
2
2
|
import type { UiLanguage } from '../env/uiLanguage.js';
|
|
3
3
|
export interface RulesFacade {
|
|
4
4
|
list(params?: RuleListParams, opts?: {
|
|
@@ -15,17 +15,29 @@ export interface RulesFacade {
|
|
|
15
15
|
}): Promise<CcImportPrepareResult>;
|
|
16
16
|
ccImportRedeem(ticket: string, opts?: {
|
|
17
17
|
signal?: AbortSignal;
|
|
18
|
-
}):
|
|
18
|
+
}): ReturnType<RulesResource['ccImportRedeem']>;
|
|
19
19
|
}
|
|
20
20
|
export type RulesListFacade = Pick<RulesFacade, 'list'>;
|
|
21
21
|
export declare function persistedRulesLaneAvailable(baseUrl: string | undefined): boolean;
|
|
22
22
|
export declare function persistedRulesGovernanceAvailable(baseUrl: string | undefined): boolean;
|
|
23
23
|
export declare function persistedRulesWriteAvailable(baseUrl: string | undefined): boolean;
|
|
24
|
+
export interface CcImportRedeemIndeterminate {
|
|
25
|
+
readonly key?: CcImportRedeemRuleKey;
|
|
26
|
+
readonly reason?: string;
|
|
27
|
+
readonly detail?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface CcImportRedeemRuleKey {
|
|
30
|
+
readonly behavior: string;
|
|
31
|
+
readonly rule: string;
|
|
32
|
+
readonly scope: string;
|
|
33
|
+
}
|
|
24
34
|
export interface CcImportRedeemCounts {
|
|
25
35
|
persisted: number;
|
|
26
36
|
deduped: number;
|
|
37
|
+
indeterminate: readonly CcImportRedeemIndeterminate[];
|
|
27
38
|
}
|
|
28
|
-
export
|
|
39
|
+
export type CcImportReceiptOutcome = 'persisted' | 'no-op' | 'indeterminate';
|
|
40
|
+
export declare function readCcImportRedeemCounts(body: unknown): CcImportRedeemCounts | null;
|
|
29
41
|
export type RulesFailure = {
|
|
30
42
|
kind: 'lane-unavailable';
|
|
31
43
|
message: string;
|