@sema-agent/client-core 0.83.6 → 0.84.1
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 +176 -0
- package/README.md +20 -13
- package/dist/abortableSleep.d.ts +10 -0
- package/dist/abortableSleep.js +37 -0
- package/dist/adapt/wireShapes.js +3 -2
- package/dist/adapter/activeRunSelfHeal.js +7 -7
- package/dist/adapter/downstream/eventToSdkMessage.js +6 -2
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +1 -0
- package/dist/adapter/downstream/terminalToSdkResult.js +10 -5
- package/dist/adapter/downstream/wiringManifestView.d.ts +3 -1
- package/dist/adapter/downstream/wiringManifestView.js +1 -0
- package/dist/agentSession/engineAgentRegistryRead.d.ts +18 -0
- package/dist/agentSession/engineAgentRegistryRead.js +167 -0
- package/dist/agentsWireCaps.js +10 -1
- package/dist/attachmentsWireCaps.js +2 -2
- package/dist/controlRouter.js +1 -1
- package/dist/decideFailureNote.d.ts +2 -1
- package/dist/decideFailureNote.js +5 -3
- package/dist/detachWire.d.ts +1 -0
- package/dist/detachWire.js +13 -5
- package/dist/displayUntrusted.js +114 -18
- package/dist/engineAgentAbsence.d.ts +37 -0
- package/dist/engineAgentAbsence.js +142 -0
- package/dist/engineErrorCodes.d.ts +2 -0
- package/dist/engineErrorCodes.js +9 -5
- package/dist/engineNoticeCodes.d.ts +43 -0
- package/dist/engineNoticeCodes.js +118 -5
- package/dist/engineWireSdk.d.ts +2 -0
- package/dist/fleet/fleetProjection.js +3 -2
- package/dist/frozenSet.d.ts +1 -0
- package/dist/frozenSet.js +20 -0
- package/dist/handsSeam.d.ts +3 -0
- package/dist/handsSeam.js +19 -0
- package/dist/hitl/askGateWire.d.ts +1 -1
- package/dist/hitl/askGateWire.js +1 -1
- package/dist/hitl/hitlHostSurface.js +1 -1
- package/dist/hitl/parkResolver.d.ts +1 -0
- package/dist/hitl/parkResolver.js +9 -3
- package/dist/hitl/planReviewWire.d.ts +30 -3
- package/dist/hitl/planReviewWire.js +139 -32
- package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
- package/dist/hitl/sessionPolicyDeliverable.js +14 -3
- package/dist/hitl/sessionPolicyWire.d.ts +40 -0
- package/dist/hitl/sessionPolicyWire.js +210 -0
- package/dist/hitl/toolApprovalWire.js +2 -2
- package/dist/index.d.ts +24 -13
- package/dist/index.js +13 -13
- package/dist/liveInitToolFace.js +28 -10
- package/dist/model/catalogLoader.js +3 -3
- package/dist/model/tierVocabulary.js +1 -1
- package/dist/request/taskRequest.js +15 -5
- package/dist/resumeRefusalCopy.d.ts +11 -0
- package/dist/resumeRefusalCopy.js +39 -1
- package/dist/rewindWireCaps.d.ts +0 -1
- package/dist/seam.d.ts +2 -1
- package/dist/seatContract.js +2 -2
- package/dist/systemReminderTag.d.ts +5 -0
- package/dist/systemReminderTag.js +20 -9
- package/dist/toolResult.js +2 -6
- package/dist/toolRoster.d.ts +16 -0
- package/dist/toolRoster.js +46 -5
- package/dist/wireErrorTriage.js +1 -11
- package/dist/workflowClient.js +4 -3
- package/dist/workflowMonitor.d.ts +1 -1
- package/docs/INTEGRATION-CLIENTS.md +701 -37
- package/package.json +3 -3
|
@@ -74,8 +74,15 @@ export const ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
74
74
|
'tool_result.offload_put_failed',
|
|
75
75
|
]);
|
|
76
76
|
const CATALOG = new Set(ENGINE_NOTICE_CODES);
|
|
77
|
+
export const SERVER_NOTICE_AUDIENCE = Object.freeze({
|
|
78
|
+
'instructions.source_changed': 'user',
|
|
79
|
+
'memory.layer_locked_legacy': 'operator',
|
|
80
|
+
});
|
|
81
|
+
function audienceRow(table, code) {
|
|
82
|
+
return Object.hasOwn(table, code) ? table[code] : undefined;
|
|
83
|
+
}
|
|
77
84
|
export function engineNoticeInCatalog(code) {
|
|
78
|
-
return typeof code === 'string' && CATALOG.has(code);
|
|
85
|
+
return typeof code === 'string' && (CATALOG.has(code) || Object.hasOwn(SERVER_NOTICE_AUDIENCE, code));
|
|
79
86
|
}
|
|
80
87
|
export const ENGINE_NOTICE_AUDIENCE = Object.freeze({
|
|
81
88
|
'config.autocompact_window_clamped': 'operator',
|
|
@@ -153,10 +160,9 @@ export const ENGINE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
153
160
|
'tool_result.offload_put_failed': 'operator',
|
|
154
161
|
});
|
|
155
162
|
export function noticeAudienceOf(code) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return row ?? 'operator';
|
|
163
|
+
if (typeof code !== 'string')
|
|
164
|
+
return 'operator';
|
|
165
|
+
return audienceRow(ENGINE_NOTICE_AUDIENCE, code) ?? audienceRow(SERVER_NOTICE_AUDIENCE, code) ?? 'operator';
|
|
160
166
|
}
|
|
161
167
|
export const MCP_INJECTION_DROP_REASONS = Object.freeze([
|
|
162
168
|
'malformed_entry',
|
|
@@ -303,3 +309,110 @@ export function readMcpServerRedialed(notice) {
|
|
|
303
309
|
const reason = str(o.reason);
|
|
304
310
|
return { server, outcome, added, removed, ...(reason !== undefined ? { reason } : {}), sessionId, runId };
|
|
305
311
|
}
|
|
312
|
+
const READ_ROOT_GRANT_COVERS_EXACT = 'exact';
|
|
313
|
+
const _grantCoversPin = true;
|
|
314
|
+
void _grantCoversPin;
|
|
315
|
+
export function readReadRootGrantNotice(notice) {
|
|
316
|
+
try {
|
|
317
|
+
return readRootGrantNoticeOf(notice);
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function readRootGrantNoticeOf(notice) {
|
|
324
|
+
if (typeof notice !== 'object' || notice === null || Array.isArray(notice))
|
|
325
|
+
return undefined;
|
|
326
|
+
const n = notice;
|
|
327
|
+
if (n.code !== 'approval.read_root_granted' && n.code !== 'approval.read_root_grant_rejected')
|
|
328
|
+
return undefined;
|
|
329
|
+
const d = n.detail;
|
|
330
|
+
if (typeof d !== 'object' || d === null || Array.isArray(d))
|
|
331
|
+
return undefined;
|
|
332
|
+
const o = d;
|
|
333
|
+
const str = (v) => (typeof v === 'string' && v.length > 0 ? v : undefined);
|
|
334
|
+
const toolCallId = str(o.toolCallId);
|
|
335
|
+
if (toolCallId === undefined)
|
|
336
|
+
return undefined;
|
|
337
|
+
const sessionId = str(o.sessionId);
|
|
338
|
+
if (n.code === 'approval.read_root_granted') {
|
|
339
|
+
const dir = str(o.dir);
|
|
340
|
+
const root = str(o.root);
|
|
341
|
+
if (dir === undefined || root === undefined)
|
|
342
|
+
return undefined;
|
|
343
|
+
if ('covers' in o && o.covers !== READ_ROOT_GRANT_COVERS_EXACT)
|
|
344
|
+
return undefined;
|
|
345
|
+
return {
|
|
346
|
+
outcome: 'granted',
|
|
347
|
+
toolCallId,
|
|
348
|
+
dir,
|
|
349
|
+
root,
|
|
350
|
+
...('covers' in o ? { covers: READ_ROOT_GRANT_COVERS_EXACT } : {}),
|
|
351
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
const reason = str(o.reason);
|
|
355
|
+
return { outcome: 'rejected', toolCallId, ...(reason !== undefined ? { reason } : {}), ...(sessionId !== undefined ? { sessionId } : {}) };
|
|
356
|
+
}
|
|
357
|
+
function ownPathOrNull(o, key) {
|
|
358
|
+
if (!Object.hasOwn(o, key))
|
|
359
|
+
return undefined;
|
|
360
|
+
const v = o[key];
|
|
361
|
+
if (v === null)
|
|
362
|
+
return null;
|
|
363
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
364
|
+
}
|
|
365
|
+
export function readInstructionsSourceChanged(notice) {
|
|
366
|
+
if (typeof notice !== 'object' || notice === null || Array.isArray(notice))
|
|
367
|
+
return undefined;
|
|
368
|
+
try {
|
|
369
|
+
const n = notice;
|
|
370
|
+
if (n.code !== 'instructions.source_changed')
|
|
371
|
+
return undefined;
|
|
372
|
+
const d = n.detail;
|
|
373
|
+
if (typeof d !== 'object' || d === null || Array.isArray(d))
|
|
374
|
+
return undefined;
|
|
375
|
+
const o = d;
|
|
376
|
+
const previous = ownPathOrNull(o, 'previous');
|
|
377
|
+
const current = ownPathOrNull(o, 'current');
|
|
378
|
+
const sessionId = typeof o.sessionId === 'string' && o.sessionId.length > 0 ? o.sessionId : undefined;
|
|
379
|
+
if (previous === undefined || current === undefined || sessionId === undefined)
|
|
380
|
+
return undefined;
|
|
381
|
+
return { previous, current, sessionId };
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
return undefined;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
export const ENGINE_NOTICE_FACT_READERS = Object.freeze({
|
|
388
|
+
'mcp.injection_dropped': readMcpInjectionDrop,
|
|
389
|
+
'delegation.ask_unresolvable': readAskUnresolvable,
|
|
390
|
+
'config.durable_gate_unavailable': readDurableGateUnavailable,
|
|
391
|
+
'skills.listing_truncated': readSkillsListingTruncated,
|
|
392
|
+
'mcp.server_redialed': readMcpServerRedialed,
|
|
393
|
+
'instructions.source_changed': readInstructionsSourceChanged,
|
|
394
|
+
'approval.read_root_granted': readReadRootGrantNotice,
|
|
395
|
+
'approval.read_root_grant_rejected': readReadRootGrantNotice,
|
|
396
|
+
});
|
|
397
|
+
const _factReaderTablePin = true;
|
|
398
|
+
void _factReaderTablePin;
|
|
399
|
+
export function readEngineNoticeFacts(notice) {
|
|
400
|
+
if (typeof notice !== 'object' || notice === null || Array.isArray(notice))
|
|
401
|
+
return undefined;
|
|
402
|
+
let code;
|
|
403
|
+
let detail;
|
|
404
|
+
try {
|
|
405
|
+
code = notice.code;
|
|
406
|
+
if (typeof code !== 'string' || !Object.hasOwn(ENGINE_NOTICE_FACT_READERS, code))
|
|
407
|
+
return undefined;
|
|
408
|
+
detail = notice.detail;
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
return undefined;
|
|
412
|
+
}
|
|
413
|
+
const k = code;
|
|
414
|
+
const facts = ENGINE_NOTICE_FACT_READERS[k]({ code: k, detail });
|
|
415
|
+
if (facts === undefined)
|
|
416
|
+
return undefined;
|
|
417
|
+
return { code: k, audience: noticeAudienceOf(k), facts };
|
|
418
|
+
}
|
package/dist/engineWireSdk.d.ts
CHANGED
|
@@ -6,11 +6,13 @@ export type WireAuthTokenSource = string | (() => string | undefined);
|
|
|
6
6
|
export declare function isLoopbackWireUrl(url: string): boolean;
|
|
7
7
|
export declare function resolveWireAuth(baseUrl: string | undefined, token?: string): WireAuthToken;
|
|
8
8
|
export declare function wireAuthTokenFor(baseUrl: string, token?: string): WireAuthToken;
|
|
9
|
+
export type EngineProbeClient = Pick<AgentClient, 'capabilities' | 'scenarioCapabilities'>;
|
|
9
10
|
export type EngineProbeOpts = {
|
|
10
11
|
fetchImpl?: typeof fetch;
|
|
11
12
|
timeoutMs?: number;
|
|
12
13
|
authToken?: WireAuthTokenSource | undefined;
|
|
13
14
|
principal?: string | undefined;
|
|
15
|
+
client?: EngineProbeClient;
|
|
14
16
|
};
|
|
15
17
|
export type EngineWireClientConfig = {
|
|
16
18
|
baseUrl: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { collapseLabel, escapeDisplayControlChars, taskDescFromName } from '../fleetTaskDesc.js';
|
|
2
2
|
import { rowIdTail } from '../workflow.js';
|
|
3
|
-
|
|
3
|
+
import { frozenSet } from '../frozenSet.js';
|
|
4
|
+
export const TERMINAL_FLEET_TASK_STATUSES = frozenSet([
|
|
4
5
|
'completed',
|
|
5
6
|
'failed',
|
|
6
7
|
'killed',
|
|
@@ -51,7 +52,7 @@ function deriveAgentLabel(agentType, agentName, name, id) {
|
|
|
51
52
|
const tail = rowIdTail(id).slice(-8);
|
|
52
53
|
return tail ? `agent ${tail}` : 'agent';
|
|
53
54
|
}
|
|
54
|
-
export const CONTROL_TOOL_VERBS =
|
|
55
|
+
export const CONTROL_TOOL_VERBS = frozenSet([
|
|
55
56
|
'Agent',
|
|
56
57
|
'Task',
|
|
57
58
|
'Fork',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function frozenSet<T>(members: Iterable<T>): ReadonlySet<T>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class FrozenVerdictSet extends Set {
|
|
2
|
+
constructor(members) {
|
|
3
|
+
super();
|
|
4
|
+
for (const m of members)
|
|
5
|
+
super.add(m);
|
|
6
|
+
}
|
|
7
|
+
add(_value) {
|
|
8
|
+
throw new TypeError('This set is read-only: it is a verdict table shared by every caller; copy it into a new Set to change it.');
|
|
9
|
+
}
|
|
10
|
+
delete(_value) {
|
|
11
|
+
throw new TypeError('This set is read-only: it is a verdict table shared by every caller; copy it into a new Set to change it.');
|
|
12
|
+
}
|
|
13
|
+
clear() {
|
|
14
|
+
throw new TypeError('This set is read-only: it is a verdict table shared by every caller; copy it into a new Set to change it.');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
Object.freeze(FrozenVerdictSet.prototype);
|
|
18
|
+
export function frozenSet(members) {
|
|
19
|
+
return Object.freeze(new FrozenVerdictSet(members));
|
|
20
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function projectHandsSection(holder) {
|
|
2
|
+
if (!Object.hasOwn(holder, 'hands'))
|
|
3
|
+
return undefined;
|
|
4
|
+
const raw = holder.hands;
|
|
5
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
|
|
6
|
+
return undefined;
|
|
7
|
+
if (!Object.hasOwn(raw, 'mounted'))
|
|
8
|
+
return undefined;
|
|
9
|
+
const mounted = raw.mounted;
|
|
10
|
+
if (typeof mounted !== 'boolean')
|
|
11
|
+
return undefined;
|
|
12
|
+
const reason = Object.hasOwn(raw, 'reason') ? raw.reason : undefined;
|
|
13
|
+
return { mounted, ...(typeof reason === 'string' && reason.length > 0 ? { reason } : {}) };
|
|
14
|
+
}
|
|
15
|
+
export const HANDS_REASON_NO_EXECUTION_ENV = 'no_execution_env';
|
|
16
|
+
const _handsReasonPin = true;
|
|
17
|
+
void _handsReasonPin;
|
|
18
|
+
const _handsViewPin = true;
|
|
19
|
+
void _handsViewPin;
|
|
@@ -8,7 +8,7 @@ export type { AskAnsweredOutput } from './gateLedger.js';
|
|
|
8
8
|
export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
|
|
9
9
|
export { SEMA_DENIAL_KIND_KEY } from './gateLedger.js';
|
|
10
10
|
export type { GateDenyAttribution } from './gateLedger.js';
|
|
11
|
-
export { toAnsweredOutput, isAlreadyResolvedGateReason, isGateStandingErrorCode, GATE_FAILURE_CODES, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
|
|
11
|
+
export { toAnsweredOutput, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure, GATE_FAILURE_CODES, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
|
|
12
12
|
export type { HopBudget, HopRound } from './parkResolver.js';
|
|
13
13
|
export type { GateOutcome, GateFailureCode } from './parkResolver.js';
|
|
14
14
|
export declare function bridgeAskUserQuestionGates(source: AsyncGenerator<AgentEvent>, deps: AskGateWireDeps, opts?: {
|
package/dist/hitl/askGateWire.js
CHANGED
|
@@ -6,7 +6,7 @@ export { HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE } from './frameRouter.js';
|
|
|
6
6
|
export { HITL_POLICY_DENY_MESSAGE } from './frameRouter.js';
|
|
7
7
|
export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
|
|
8
8
|
export { SEMA_DENIAL_KIND_KEY } from './gateLedger.js';
|
|
9
|
-
export { toAnsweredOutput, isAlreadyResolvedGateReason, isGateStandingErrorCode, GATE_FAILURE_CODES, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
|
|
9
|
+
export { toAnsweredOutput, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure, GATE_FAILURE_CODES, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
|
|
10
10
|
export async function* bridgeAskUserQuestionGates(source, deps, opts) {
|
|
11
11
|
const led = createGateLedger();
|
|
12
12
|
const taskId = { current: opts?.taskId };
|
|
@@ -113,7 +113,7 @@ export function observeCancelByDeny(settle, taskId) {
|
|
|
113
113
|
hostLog('debug', `[hitl-cancel-deny] cancel-by-deny no_pending for run ${taskId} (benign — already resolved)`);
|
|
114
114
|
return;
|
|
115
115
|
}
|
|
116
|
-
const rowNote = decideFailureNote(e);
|
|
116
|
+
const rowNote = decideFailureNote(e, 'deny');
|
|
117
117
|
hostLog('error', `[hitl-cancel-deny] cancel-by-deny FAILED for run ${taskId}: ${String(e)}${rowNote}`);
|
|
118
118
|
surfaceCancelDenyWarn(`${CANCEL_DENY_WARN_TEXT}${rowNote}`);
|
|
119
119
|
})
|
|
@@ -34,6 +34,7 @@ export type GateOutcome = {
|
|
|
34
34
|
};
|
|
35
35
|
export declare function isAlreadyResolvedGateReason(reason: unknown): boolean;
|
|
36
36
|
export declare function isGateStandingErrorCode(code: string | null | undefined): boolean;
|
|
37
|
+
export declare function isCodeClassifiedGateFailure(code: string | null | undefined): boolean;
|
|
37
38
|
export declare function toAnsweredOutput(questions: unknown[], answer: QuestionAnswer): AskAnsweredOutput;
|
|
38
39
|
export type ParkResolution = {
|
|
39
40
|
kind: 'reattach';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { putOwnKey } from '../ownKey.js';
|
|
2
2
|
import { DecideTransportRetryExhaustedError, HitlBridge, HitlSafetyError, findPendingForTask, readDecideCurrentPending, readWireErrorCode, } from './hitlBridge.js';
|
|
3
|
-
import { RESUME_POLICY_FOLD_CODE } from '../engineErrorCodes.js';
|
|
3
|
+
import { PARKED_RESUME_STARTUP_FAILED, RESUME_POLICY_FOLD_CODE } from '../engineErrorCodes.js';
|
|
4
4
|
import { publishQuestionFrame, registerLocalQuestionResponder, hasQuestionOverlay, } from '../liveQuestionStore.js';
|
|
5
5
|
import { hostLog } from '../host.js';
|
|
6
6
|
import { surfaceFsApprovalAndDecide } from './toolApprovalWire.js';
|
|
@@ -44,13 +44,16 @@ function isAlreadyResolvedFailure(outcome) {
|
|
|
44
44
|
const code = 'code' in outcome && isGateFailureCode(outcome.code) ? outcome.code : undefined;
|
|
45
45
|
if (code !== undefined)
|
|
46
46
|
return code === 'no_pending';
|
|
47
|
-
if ('errorCode' in outcome &&
|
|
47
|
+
if ('errorCode' in outcome && isCodeClassifiedGateFailure(outcome.errorCode))
|
|
48
48
|
return false;
|
|
49
49
|
return isAlreadyResolvedGateReason(outcome.reason);
|
|
50
50
|
}
|
|
51
51
|
export function isGateStandingErrorCode(code) {
|
|
52
52
|
return code === RESUME_POLICY_FOLD_CODE || code === 'corrupt';
|
|
53
53
|
}
|
|
54
|
+
export function isCodeClassifiedGateFailure(code) {
|
|
55
|
+
return isGateStandingErrorCode(code) || code === PARKED_RESUME_STARTUP_FAILED;
|
|
56
|
+
}
|
|
54
57
|
export function toAnsweredOutput(questions, answer) {
|
|
55
58
|
const answers = {};
|
|
56
59
|
const annotations = {};
|
|
@@ -122,10 +125,12 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
122
125
|
return { kind: 'aborted', gatedCallId };
|
|
123
126
|
}
|
|
124
127
|
let declinedReceipt;
|
|
128
|
+
let attemptedDecision;
|
|
125
129
|
try {
|
|
126
130
|
const entries = answer.answers ?? [];
|
|
127
131
|
const hasContent = entries.some(a => (a.selected?.length ?? 0) > 0 || (a.note?.length ?? 0) > 0);
|
|
128
132
|
if (hasContent) {
|
|
133
|
+
attemptedDecision = 'approve';
|
|
129
134
|
const raw = await bridge.answerQuestion(entries, gatedCallId, signal ? { signal } : undefined, pending);
|
|
130
135
|
const receipt = readDecideReceipt(raw);
|
|
131
136
|
return {
|
|
@@ -136,6 +141,7 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
136
141
|
};
|
|
137
142
|
}
|
|
138
143
|
else {
|
|
144
|
+
attemptedDecision = 'deny';
|
|
139
145
|
const raw = await bridge.decideTool({ decision: 'deny', reason: 'User declined to answer' }, gatedCallId, signal ? { signal } : undefined, pending);
|
|
140
146
|
declinedReceipt = readDecideReceipt(raw);
|
|
141
147
|
}
|
|
@@ -149,7 +155,7 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
149
155
|
kind: 'failed',
|
|
150
156
|
stage: 'decide',
|
|
151
157
|
gatedCallId,
|
|
152
|
-
reason: `decide failed: ${String(e)}${decideFailureNote(e)}`,
|
|
158
|
+
reason: `decide failed: ${String(e)}${decideFailureNote(e, attemptedDecision)}`,
|
|
153
159
|
...(code !== undefined ? { code } : {}),
|
|
154
160
|
...(e instanceof DecideTransportRetryExhaustedError ? { retryExhausted: true } : {}),
|
|
155
161
|
...(currentPending !== undefined ? { currentPending } : {}),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type QuestionAnswer } from '../liveQuestionStore.js';
|
|
2
2
|
import { type PlanReviewModeAfter } from './hitlBridge.js';
|
|
3
|
+
import type { AgentClient } from '@sema-agent/sdk';
|
|
3
4
|
import type { ReopenCardVerdict } from '../adapter/activeRunSelfHeal.js';
|
|
4
5
|
export declare const PLAN_REVIEW_APPROVE_LABEL = "Yes, approve and run the plan";
|
|
5
6
|
export declare const PLAN_REVIEW_REJECT_LABEL = "No, reject it (keep planning)";
|
|
@@ -28,10 +29,13 @@ export declare function _resetArmedPlanReviewsForTest(): void;
|
|
|
28
29
|
export type PlanReviewReopenTrigger = 'user' | 'automatic';
|
|
29
30
|
export type PlanReviewGateInstanceReader = (taskId: string) => Promise<ReadonlySet<string> | null>;
|
|
30
31
|
export declare function clearPlanReviewUserDismissals(sessionKey?: string): void;
|
|
31
|
-
export
|
|
32
|
+
export interface ArmPlanReviewOptions {
|
|
32
33
|
submittedInPlanMode?: boolean;
|
|
33
34
|
readGateInstanceKeys?: PlanReviewGateInstanceReader;
|
|
34
|
-
|
|
35
|
+
wire?: PlanReviewWire;
|
|
36
|
+
onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
|
|
37
|
+
}
|
|
38
|
+
export declare function armPlanReviewApproval(result: unknown, sessionKey?: string, opts?: ArmPlanReviewOptions): boolean;
|
|
35
39
|
export type PlanReviewDecisionEffect = 'took_effect' | 'advanced' | 'still_parked' | 'not_sent' | 'not_applied' | 'unconfirmed';
|
|
36
40
|
export interface PlanReviewOutcomeMeta {
|
|
37
41
|
taskId: string;
|
|
@@ -40,12 +44,35 @@ export interface PlanReviewOutcomeMeta {
|
|
|
40
44
|
effect: PlanReviewDecisionEffect;
|
|
41
45
|
}
|
|
42
46
|
export declare function planReviewOutcomeTail(taskId: string, decision: 'approve' | 'reject', effect: PlanReviewDecisionEffect): string;
|
|
47
|
+
export type PlanReviewWireClient = {
|
|
48
|
+
assistant: Pick<AgentClient['assistant'], 'planReview'>;
|
|
49
|
+
runs: Pick<AgentClient['runs'], 'get'>;
|
|
50
|
+
};
|
|
51
|
+
export interface PlanReviewWire {
|
|
52
|
+
client: PlanReviewWireClient;
|
|
53
|
+
capsBaseUrl?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface PlanReviewDecisionOutcome extends PlanReviewOutcomeMeta {
|
|
56
|
+
detail: string;
|
|
57
|
+
tail: string;
|
|
58
|
+
prompt: string;
|
|
59
|
+
status?: string;
|
|
60
|
+
}
|
|
61
|
+
export interface PlanReviewDeliveryOptions {
|
|
62
|
+
wire?: PlanReviewWire;
|
|
63
|
+
onOutcome?: (outcome: PlanReviewDecisionOutcome) => void;
|
|
64
|
+
}
|
|
65
|
+
export interface DecidePlanReviewOptions extends PlanReviewDeliveryOptions {
|
|
66
|
+
reason?: string;
|
|
67
|
+
}
|
|
43
68
|
export declare function __resetPlanReviewDecisionLatchForTests(): void;
|
|
44
|
-
export declare function decidePlanReview(taskId: string, decision: 'approve' | 'reject', permissionModeAfter?: string): Promise<void>;
|
|
69
|
+
export declare function decidePlanReview(taskId: string, decision: 'approve' | 'reject', permissionModeAfter?: string, opts?: DecidePlanReviewOptions): Promise<void>;
|
|
45
70
|
export interface ReopenPlanReviewOpts {
|
|
46
71
|
mintFreshQuestionId?: boolean;
|
|
47
72
|
deliverDecision?: (taskId: string, decision: 'approve' | 'reject') => void | Promise<void>;
|
|
48
73
|
sessionKey?: string;
|
|
74
|
+
wire?: PlanReviewWire;
|
|
75
|
+
onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
|
|
49
76
|
presentationReceiptMs?: number;
|
|
50
77
|
trigger?: PlanReviewReopenTrigger;
|
|
51
78
|
readGateInstanceKeys?: PlanReviewGateInstanceReader;
|