@sema-agent/client-core 0.87.0 → 0.88.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 +73 -0
- package/README.md +14 -10
- package/dist/adapter/downstream/eventToSdkMessage.js +14 -1
- package/dist/adapter/downstream/wiringManifestView.d.ts +2 -0
- package/dist/adapter/downstream/wiringManifestView.js +1 -0
- package/dist/displayUntrusted.d.ts +4 -0
- package/dist/displayUntrusted.js +1657 -573
- package/dist/engineErrorCodes.d.ts +2 -0
- package/dist/engineErrorCodes.js +1 -0
- package/dist/engineNoticeCodes.d.ts +20 -0
- package/dist/engineNoticeCodes.js +71 -0
- package/dist/engineWireFor.d.ts +1 -0
- package/dist/engineWireFor.js +1 -1
- package/dist/gateOutcome.d.ts +4 -0
- package/dist/gateOutcome.js +5 -0
- package/dist/generated/engineFactTables.d.ts +1 -0
- package/dist/generated/engineFactTables.js +3 -0
- package/dist/generated/engineNoticeTables.js +2 -0
- package/dist/hitl/crashConverged.d.ts +1 -1
- package/dist/hitl/crashConverged.js +6 -1
- package/dist/hitl/planReviewWire.js +30 -10
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/dist/promptDelivery.d.ts +20 -0
- package/dist/promptDelivery.js +153 -0
- package/dist/registryConflict.d.ts +3 -0
- package/dist/registryConflict.js +44 -0
- package/dist/request/taskRequest.d.ts +1 -0
- package/dist/request/taskRequest.js +25 -1
- package/dist/resumeRefusalCopy.d.ts +7 -0
- package/dist/resumeRefusalCopy.js +45 -1
- package/dist/seam.d.ts +1 -0
- package/dist/sessionMemoryErase.d.ts +76 -0
- package/dist/sessionMemoryErase.js +432 -0
- package/dist/subagent/engineSubagentResume.js +2 -1
- package/docs/INTEGRATION-CLIENTS.md +372 -11
- package/package.json +2 -2
|
@@ -48,6 +48,8 @@ export declare const REWIND_ERROR_CODE_PREFIXES: readonly ["resume_at.", "rewind
|
|
|
48
48
|
export declare function isRewindFamilyCode(code: string | undefined): boolean;
|
|
49
49
|
export declare const RESUME_USAGE_WINDOW_EXHAUSTED = "resume.usage_window_exhausted";
|
|
50
50
|
export declare const RESUME_PREFLIGHT_REJECTED = "resume.preflight_rejected";
|
|
51
|
+
export declare const RESUME_SESSION_NOT_FOUND = "resume.session_not_found";
|
|
52
|
+
export type StatusDerivedCoarseCode = (typeof STATUS_DERIVED_COARSE_CODES)[number];
|
|
51
53
|
export declare const RESUME_PLACEMENT_MISMATCH = "resume.placement_mismatch";
|
|
52
54
|
export declare const RESUME_CONTEXT_UNAVAILABLE = "conflict.resume_context_unavailable";
|
|
53
55
|
export declare const RESUME_RETRY_LATER_CODES: readonly string[];
|
package/dist/engineErrorCodes.js
CHANGED
|
@@ -106,6 +106,7 @@ export function isRewindFamilyCode(code) {
|
|
|
106
106
|
}
|
|
107
107
|
export const RESUME_USAGE_WINDOW_EXHAUSTED = 'resume.usage_window_exhausted';
|
|
108
108
|
export const RESUME_PREFLIGHT_REJECTED = 'resume.preflight_rejected';
|
|
109
|
+
export const RESUME_SESSION_NOT_FOUND = 'resume.session_not_found';
|
|
109
110
|
export const RESUME_PLACEMENT_MISMATCH = 'resume.placement_mismatch';
|
|
110
111
|
export const RESUME_CONTEXT_UNAVAILABLE = 'conflict.resume_context_unavailable';
|
|
111
112
|
export const RESUME_RETRY_LATER_CODES = Object.freeze([
|
|
@@ -137,6 +137,24 @@ export interface LegacyModeSeedMigratedFactsView {
|
|
|
137
137
|
runId: string;
|
|
138
138
|
}
|
|
139
139
|
export declare function readLegacyModeSeedMigrated(notice: unknown): LegacyModeSeedMigratedFactsView | undefined;
|
|
140
|
+
export interface ToolTurnRepairView {
|
|
141
|
+
form: string;
|
|
142
|
+
toolCallIds: readonly string[];
|
|
143
|
+
}
|
|
144
|
+
export interface ToolTurnRepairedFactsView {
|
|
145
|
+
repairs: readonly ToolTurnRepairView[];
|
|
146
|
+
sessionId: string;
|
|
147
|
+
runId: string;
|
|
148
|
+
}
|
|
149
|
+
export declare function readToolTurnRepaired(notice: unknown): ToolTurnRepairedFactsView | undefined;
|
|
150
|
+
export interface ModelUnreachableFactsView {
|
|
151
|
+
code: string;
|
|
152
|
+
targetHost: string;
|
|
153
|
+
proxyInUse?: string;
|
|
154
|
+
remedy: string;
|
|
155
|
+
sessionId: string;
|
|
156
|
+
}
|
|
157
|
+
export declare function readModelUnreachable(notice: unknown): ModelUnreachableFactsView | undefined;
|
|
140
158
|
export declare const ENGINE_NOTICE_FACT_READERS: Readonly<{
|
|
141
159
|
readonly 'mcp.injection_dropped': typeof readMcpInjectionDrop;
|
|
142
160
|
readonly 'delegation.ask_unresolvable': typeof readAskUnresolvable;
|
|
@@ -153,6 +171,8 @@ export declare const ENGINE_NOTICE_FACT_READERS: Readonly<{
|
|
|
153
171
|
readonly 'permission.ask_released_by_mode': typeof readAskReleasedByMode;
|
|
154
172
|
readonly 'permission.read_deny_unapplied': typeof readReadDenyUnapplied;
|
|
155
173
|
readonly 'resume.legacy_mode_seed_migrated': typeof readLegacyModeSeedMigrated;
|
|
174
|
+
readonly 'context.tool_turn_repaired': typeof readToolTurnRepaired;
|
|
175
|
+
readonly 'server.model_unreachable': typeof readModelUnreachable;
|
|
156
176
|
}>;
|
|
157
177
|
type FactReaderTable = typeof ENGINE_NOTICE_FACT_READERS;
|
|
158
178
|
export type EngineNoticeFactsCode = keyof FactReaderTable;
|
|
@@ -7,6 +7,7 @@ export const SERVER_NOTICE_AUDIENCE = Object.freeze({
|
|
|
7
7
|
'instructions.source_changed': 'user',
|
|
8
8
|
'memory.layer_locked_legacy': 'operator',
|
|
9
9
|
'session.records_skipped': 'user',
|
|
10
|
+
'server.model_unreachable': 'user',
|
|
10
11
|
});
|
|
11
12
|
function audienceRow(table, code) {
|
|
12
13
|
return Object.hasOwn(table, code) ? table[code] : undefined;
|
|
@@ -483,6 +484,74 @@ function readLegacyModeSeedMigratedOf(notice) {
|
|
|
483
484
|
const permissionMode = nonEmpty(optionalSeat(mo, 'permissionMode'));
|
|
484
485
|
return { ...(permissionMode !== undefined ? { permissionMode } : {}), droppedKeys, sessionId, runId };
|
|
485
486
|
}
|
|
487
|
+
export function readToolTurnRepaired(notice) {
|
|
488
|
+
return guardedRead(notice, readToolTurnRepairedOf);
|
|
489
|
+
}
|
|
490
|
+
function ownSeat(o, key) {
|
|
491
|
+
return Object.hasOwn(o, key) ? o[key] : undefined;
|
|
492
|
+
}
|
|
493
|
+
function optionalOwnSeat(o, key) {
|
|
494
|
+
try {
|
|
495
|
+
return ownSeat(o, key);
|
|
496
|
+
}
|
|
497
|
+
catch {
|
|
498
|
+
return undefined;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
function readToolTurnRepairedOf(notice) {
|
|
502
|
+
if (typeof notice !== 'object' || notice === null || Array.isArray(notice))
|
|
503
|
+
return undefined;
|
|
504
|
+
const n = notice;
|
|
505
|
+
if (n.code !== 'context.tool_turn_repaired')
|
|
506
|
+
return undefined;
|
|
507
|
+
const d = n.detail;
|
|
508
|
+
if (typeof d !== 'object' || d === null || Array.isArray(d))
|
|
509
|
+
return undefined;
|
|
510
|
+
const o = d;
|
|
511
|
+
const rawRepairs = ownSeat(o, 'repairs');
|
|
512
|
+
if (!Array.isArray(rawRepairs) || rawRepairs.length === 0)
|
|
513
|
+
return undefined;
|
|
514
|
+
const count = rawRepairs.length;
|
|
515
|
+
const repairs = [];
|
|
516
|
+
for (let i = 0; i < count; i++) {
|
|
517
|
+
const item = rawRepairs[i];
|
|
518
|
+
if (typeof item !== 'object' || item === null || Array.isArray(item))
|
|
519
|
+
return undefined;
|
|
520
|
+
const it = item;
|
|
521
|
+
const form = nonEmpty(ownSeat(it, 'form'));
|
|
522
|
+
const toolCallIds = nameList(ownSeat(it, 'toolCallIds'));
|
|
523
|
+
if (form === undefined || toolCallIds === undefined || toolCallIds.length === 0)
|
|
524
|
+
return undefined;
|
|
525
|
+
repairs.push(Object.freeze({ form, toolCallIds }));
|
|
526
|
+
}
|
|
527
|
+
const sessionId = nonEmpty(ownSeat(o, 'sessionId'));
|
|
528
|
+
const runId = nonEmpty(ownSeat(o, 'runId'));
|
|
529
|
+
if (sessionId === undefined || runId === undefined)
|
|
530
|
+
return undefined;
|
|
531
|
+
return { repairs: Object.freeze(repairs), sessionId, runId };
|
|
532
|
+
}
|
|
533
|
+
export function readModelUnreachable(notice) {
|
|
534
|
+
return guardedRead(notice, readModelUnreachableOf);
|
|
535
|
+
}
|
|
536
|
+
function readModelUnreachableOf(notice) {
|
|
537
|
+
if (typeof notice !== 'object' || notice === null || Array.isArray(notice))
|
|
538
|
+
return undefined;
|
|
539
|
+
const n = notice;
|
|
540
|
+
if (n.code !== 'server.model_unreachable')
|
|
541
|
+
return undefined;
|
|
542
|
+
const d = n.detail;
|
|
543
|
+
if (typeof d !== 'object' || d === null || Array.isArray(d))
|
|
544
|
+
return undefined;
|
|
545
|
+
const o = d;
|
|
546
|
+
const code = nonEmpty(ownSeat(o, 'code'));
|
|
547
|
+
const targetHost = nonEmpty(ownSeat(o, 'targetHost'));
|
|
548
|
+
const remedy = nonEmpty(ownSeat(o, 'remedy'));
|
|
549
|
+
const sessionId = nonEmpty(ownSeat(o, 'sessionId'));
|
|
550
|
+
if (code === undefined || targetHost === undefined || remedy === undefined || sessionId === undefined)
|
|
551
|
+
return undefined;
|
|
552
|
+
const proxyInUse = nonEmpty(optionalOwnSeat(o, 'proxyInUse'));
|
|
553
|
+
return { code, targetHost, ...(proxyInUse !== undefined ? { proxyInUse } : {}), remedy, sessionId };
|
|
554
|
+
}
|
|
486
555
|
export const ENGINE_NOTICE_FACT_READERS = Object.freeze({
|
|
487
556
|
'mcp.injection_dropped': readMcpInjectionDrop,
|
|
488
557
|
'delegation.ask_unresolvable': readAskUnresolvable,
|
|
@@ -499,6 +568,8 @@ export const ENGINE_NOTICE_FACT_READERS = Object.freeze({
|
|
|
499
568
|
'permission.ask_released_by_mode': readAskReleasedByMode,
|
|
500
569
|
'permission.read_deny_unapplied': readReadDenyUnapplied,
|
|
501
570
|
'resume.legacy_mode_seed_migrated': readLegacyModeSeedMigrated,
|
|
571
|
+
'context.tool_turn_repaired': readToolTurnRepaired,
|
|
572
|
+
'server.model_unreachable': readModelUnreachable,
|
|
502
573
|
});
|
|
503
574
|
const _factReaderTablePin = true;
|
|
504
575
|
void _factReaderTablePin;
|
package/dist/engineWireFor.d.ts
CHANGED
|
@@ -40,4 +40,5 @@ export type EngineWireNoAnswerKind = 'deadline' | 'time-limit' | 'connection-los
|
|
|
40
40
|
export declare function noAnswerKindOf(e: object | null | undefined): EngineWireNoAnswerKind | null;
|
|
41
41
|
export declare function noAnswerDetailFrom(e: object | null | undefined): string | null;
|
|
42
42
|
export declare function sendOnce<T>(signal: AbortSignal | null | undefined, run: () => Promise<T>): Promise<T>;
|
|
43
|
+
export declare function provablyNotSent(e: object | null | undefined): boolean;
|
|
43
44
|
export declare function settleInjected<T>(ms: number, signal: AbortSignal | null | undefined, run: (signal: AbortSignal) => Promise<T>): Promise<T>;
|
package/dist/engineWireFor.js
CHANGED
|
@@ -331,7 +331,7 @@ export async function sendOnce(signal, run) {
|
|
|
331
331
|
throw error;
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
|
-
function provablyNotSent(e) {
|
|
334
|
+
export function provablyNotSent(e) {
|
|
335
335
|
try {
|
|
336
336
|
return e !== null && typeof e === 'object' && (markedNotSent(e) || failedBeforeSend(e));
|
|
337
337
|
}
|
package/dist/gateOutcome.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DeniedBy, Settlement } from '@sema-agent/sdk';
|
|
2
2
|
import { type CcToolDenialKind } from './gateVocabulary.js';
|
|
3
|
+
import { CORE_MODE_RELEASE_REASONS } from './generated/engineFactTables.js';
|
|
3
4
|
export type GateDispositionView = {
|
|
4
5
|
kind: 'allowed';
|
|
5
6
|
classifier?: GateClassifierRoundView;
|
|
@@ -31,6 +32,9 @@ export interface GateModeReleaseView {
|
|
|
31
32
|
mandate?: string;
|
|
32
33
|
reason?: string;
|
|
33
34
|
}
|
|
35
|
+
export declare const GATE_MODE_RELEASE_REASON_WORDS: readonly ["rule_unreadable"];
|
|
36
|
+
export type GateModeReleaseReasonWord = (typeof CORE_MODE_RELEASE_REASONS)[number];
|
|
37
|
+
export declare function isGateModeReleaseReasonWord(v: unknown): v is GateModeReleaseReasonWord;
|
|
34
38
|
export interface SettlementWhoView {
|
|
35
39
|
party: string;
|
|
36
40
|
approver?: string;
|
package/dist/gateOutcome.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { ccToolDenialKindForSettledBy, isCcToolDenialKind, isGateDeniedByWord } from './gateVocabulary.js';
|
|
2
2
|
import { GATE_PARKED_ERROR_CODE } from './engineErrorCodes.js';
|
|
3
|
+
import { CORE_MODE_RELEASE_REASONS } from './generated/engineFactTables.js';
|
|
3
4
|
function str(v) {
|
|
4
5
|
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
5
6
|
}
|
|
7
|
+
export const GATE_MODE_RELEASE_REASON_WORDS = CORE_MODE_RELEASE_REASONS;
|
|
8
|
+
export function isGateModeReleaseReasonWord(v) {
|
|
9
|
+
return typeof v === 'string' && CORE_MODE_RELEASE_REASONS.includes(v);
|
|
10
|
+
}
|
|
6
11
|
export const SETTLEMENT_KIND_WORDS = Object.freeze([
|
|
7
12
|
'human_allowed',
|
|
8
13
|
'human_refused',
|
|
@@ -8,3 +8,4 @@ export declare const CORE_DENIED_BY_VALUES: readonly ["policy", "hook", "org", "
|
|
|
8
8
|
export declare const CORE_PERMISSION_MODE_FOLD_REASONS: readonly string[];
|
|
9
9
|
export declare const CORE_ENGINE_CARD_TYPES: readonly string[];
|
|
10
10
|
export declare const CORE_TOOL_DECLARATION_CODES: readonly string[];
|
|
11
|
+
export declare const CORE_MODE_RELEASE_REASONS: readonly ["rule_unreadable"];
|
|
@@ -65,6 +65,7 @@ export const CORE_ENGINE_NOTICE_CODES = Object.freeze([
|
|
|
65
65
|
"route.base_url_changed_key_unchanged",
|
|
66
66
|
"route.response_model_mismatch",
|
|
67
67
|
"route.tool_call_id_folded",
|
|
68
|
+
"context.tool_turn_repaired",
|
|
68
69
|
"task.user_steer_undrained",
|
|
69
70
|
"task.user_followup_undrained",
|
|
70
71
|
"steering.parked_input_blocked",
|
|
@@ -147,6 +148,7 @@ export const CORE_NOTICE_AUDIENCE = Object.freeze({
|
|
|
147
148
|
"route.base_url_changed_key_unchanged": "operator",
|
|
148
149
|
"route.response_model_mismatch": "operator",
|
|
149
150
|
"route.tool_call_id_folded": "operator",
|
|
151
|
+
"context.tool_turn_repaired": "operator",
|
|
150
152
|
"task.user_steer_undrained": "user",
|
|
151
153
|
"task.user_followup_undrained": "user",
|
|
152
154
|
"steering.parked_input_blocked": "user",
|
|
@@ -8,7 +8,7 @@ export interface CrashConvergedRow {
|
|
|
8
8
|
readonly ts: number;
|
|
9
9
|
readonly expiresAtMs: number;
|
|
10
10
|
readonly decision: 'denied';
|
|
11
|
-
readonly cause: 'crashed_before_park';
|
|
11
|
+
readonly cause: 'crashed_before_park' | 'shutdown_before_park';
|
|
12
12
|
readonly orphanState: CrashConvergedOrphanState;
|
|
13
13
|
readonly originalDecision?: 'approve';
|
|
14
14
|
readonly decidedAtMs?: number;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
const CRASH_CONVERGED_CAUSE_WORDS = Object.freeze({
|
|
2
|
+
crashed_before_park: true,
|
|
3
|
+
shutdown_before_park: true,
|
|
4
|
+
});
|
|
5
|
+
const isCrashConvergedCause = (v) => typeof v === 'string' && Object.hasOwn(CRASH_CONVERGED_CAUSE_WORDS, v);
|
|
1
6
|
const isString = (v) => typeof v === 'string';
|
|
2
7
|
const isNumber = (v) => typeof v === 'number';
|
|
3
8
|
const nonEmptyString = (v) => typeof v === 'string' && v.length > 0;
|
|
@@ -45,7 +50,7 @@ function readCrashConvergedRow(v) {
|
|
|
45
50
|
return null;
|
|
46
51
|
if (o.decision !== 'denied')
|
|
47
52
|
return null;
|
|
48
|
-
if (o.cause
|
|
53
|
+
if (!isCrashConvergedCause(o.cause))
|
|
49
54
|
return null;
|
|
50
55
|
if (o.orphanState !== 'pending' && o.orphanState !== 'decided')
|
|
51
56
|
return null;
|
|
@@ -346,9 +346,11 @@ let decideDispatchSeq = 0;
|
|
|
346
346
|
function planReviewOpsOf(taskId) {
|
|
347
347
|
return planReviewDecisionOps.filter((op) => op.taskId === taskId);
|
|
348
348
|
}
|
|
349
|
-
function settlePlanReviewDecisionOp(op) {
|
|
350
|
-
if (op.settledAt
|
|
351
|
-
|
|
349
|
+
function settlePlanReviewDecisionOp(op, by) {
|
|
350
|
+
if (op.settledAt !== null)
|
|
351
|
+
return;
|
|
352
|
+
op.settledAt = ++planReviewLedgerClock;
|
|
353
|
+
op.settler = by;
|
|
352
354
|
}
|
|
353
355
|
function pushPlanReviewDecisionOp(op) {
|
|
354
356
|
planReviewDecisionOps.push(op);
|
|
@@ -366,18 +368,31 @@ function dropPlanReviewDecisionOp(op) {
|
|
|
366
368
|
if (i >= 0)
|
|
367
369
|
planReviewDecisionOps.splice(i, 1);
|
|
368
370
|
}
|
|
371
|
+
function claimablePlanReviewDecisionOp(taskId) {
|
|
372
|
+
const open = planReviewDecisionOps.find((o) => o.taskId === taskId && o.phase === 'handed' && o.settledAt === null);
|
|
373
|
+
if (open !== undefined)
|
|
374
|
+
return open;
|
|
375
|
+
let leftBehind;
|
|
376
|
+
for (const o of planReviewDecisionOps) {
|
|
377
|
+
if (o.taskId !== taskId || o.phase !== 'handed' || o.settler !== 'gate_left')
|
|
378
|
+
continue;
|
|
379
|
+
if (leftBehind === undefined || o.handedAt > leftBehind.handedAt)
|
|
380
|
+
leftBehind = o;
|
|
381
|
+
}
|
|
382
|
+
return leftBehind;
|
|
383
|
+
}
|
|
369
384
|
export function notePlanReviewDecisionHandedOver(taskId) {
|
|
370
385
|
if (typeof taskId !== 'string' || taskId === '')
|
|
371
386
|
return null;
|
|
372
387
|
if (planReviewDecisionOps.some((op) => op.taskId === taskId && op.settledAt === null))
|
|
373
388
|
return null;
|
|
374
|
-
const op = { taskId, handedAt: ++planReviewLedgerClock, settledAt: null, phase: 'handed', notApplied: false, ownCallOpen: false };
|
|
389
|
+
const op = { taskId, handedAt: ++planReviewLedgerClock, settledAt: null, settler: null, phase: 'handed', notApplied: false, ownCallOpen: false };
|
|
375
390
|
pushPlanReviewDecisionOp(op);
|
|
376
391
|
return {
|
|
377
392
|
settle: () => {
|
|
378
393
|
if (op.phase !== 'handed')
|
|
379
394
|
return;
|
|
380
|
-
settlePlanReviewDecisionOp(op);
|
|
395
|
+
settlePlanReviewDecisionOp(op, 'host');
|
|
381
396
|
},
|
|
382
397
|
revoke: () => {
|
|
383
398
|
if (op.phase !== 'handed' || op.settledAt !== null)
|
|
@@ -412,7 +427,7 @@ export function notePlanReviewGateLeft(taskId) {
|
|
|
412
427
|
if (typeof taskId !== 'string' || taskId === '')
|
|
413
428
|
return;
|
|
414
429
|
for (const op of planReviewOpsOf(taskId))
|
|
415
|
-
settlePlanReviewDecisionOp(op);
|
|
430
|
+
settlePlanReviewDecisionOp(op, 'gate_left');
|
|
416
431
|
}
|
|
417
432
|
export function latestPlanReviewDecisionMark(taskId) {
|
|
418
433
|
if (typeof taskId !== 'string' || taskId === '')
|
|
@@ -434,12 +449,17 @@ async function decidePlanReviewFor(taskId, decision, permissionModeAfter, opts,
|
|
|
434
449
|
hostLog('error', `planReviewWire: decidePlanReview(${decision}) for task ${taskId} REFUSED — a decision for this task is already in flight (duplicate delivery latched)`);
|
|
435
450
|
return;
|
|
436
451
|
}
|
|
437
|
-
let op =
|
|
452
|
+
let op = claimablePlanReviewDecisionOp(taskId);
|
|
438
453
|
if (op === undefined) {
|
|
439
|
-
op = { taskId: typeof taskId === 'string' ? taskId : String(taskId), handedAt: ++planReviewLedgerClock, settledAt: null, phase: 'posting', notApplied: false, ownCallOpen: true };
|
|
454
|
+
op = { taskId: typeof taskId === 'string' ? taskId : String(taskId), handedAt: ++planReviewLedgerClock, settledAt: null, settler: null, phase: 'posting', notApplied: false, ownCallOpen: true };
|
|
440
455
|
pushPlanReviewDecisionOp(op);
|
|
441
456
|
}
|
|
442
457
|
else {
|
|
458
|
+
if (op.settler === 'gate_left') {
|
|
459
|
+
op.settledAt = null;
|
|
460
|
+
op.settler = null;
|
|
461
|
+
op.notApplied = false;
|
|
462
|
+
}
|
|
443
463
|
op.phase = 'posting';
|
|
444
464
|
op.ownCallOpen = true;
|
|
445
465
|
}
|
|
@@ -451,7 +471,7 @@ async function decidePlanReviewFor(taskId, decision, permissionModeAfter, opts,
|
|
|
451
471
|
const settle = (notApplied) => {
|
|
452
472
|
if (notApplied)
|
|
453
473
|
mine.notApplied = true;
|
|
454
|
-
settlePlanReviewDecisionOp(mine);
|
|
474
|
+
settlePlanReviewDecisionOp(mine, 'package');
|
|
455
475
|
};
|
|
456
476
|
const dispatchNo = ++decideDispatchSeq;
|
|
457
477
|
hostLog('debug', `planReviewWire: decidePlanReview dispatch #${dispatchNo} task=${taskId} decision=${decision} mode=${permissionModeAfter ?? '-'}`);
|
|
@@ -460,7 +480,7 @@ async function decidePlanReviewFor(taskId, decision, permissionModeAfter, opts,
|
|
|
460
480
|
}
|
|
461
481
|
finally {
|
|
462
482
|
releaseLatch();
|
|
463
|
-
settlePlanReviewDecisionOp(mine);
|
|
483
|
+
settlePlanReviewDecisionOp(mine, 'package');
|
|
464
484
|
mine.ownCallOpen = false;
|
|
465
485
|
}
|
|
466
486
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -146,6 +146,10 @@ export * from './wireErrorTriage.js';
|
|
|
146
146
|
export * from './corruptSession.js';
|
|
147
147
|
export * from './corruptSessionCopy.js';
|
|
148
148
|
export { classifyToolHistoryMismatch, resolveToolHistoryRewindTarget } from './toolHistoryMismatch.js';
|
|
149
|
+
export { classifyRegistryConflict, isScopeGoneError } from './registryConflict.js';
|
|
150
|
+
export type { RegistryConflictClass } from './registryConflict.js';
|
|
151
|
+
export { createPromptDeliveryLedger, promptKnownUndelivered, withoutUndeliveredPrompts } from './promptDelivery.js';
|
|
152
|
+
export type { PromptDeliveryLedger, PromptDeliveryRecord } from './promptDelivery.js';
|
|
149
153
|
export * from './resumeRefusalCopy.js';
|
|
150
154
|
export * from './wireRefusalCopy.js';
|
|
151
155
|
export * from './inheritEnvWire.js';
|
|
@@ -198,6 +202,8 @@ export { readEngineAgentRegistry, isEngineAgentRegistryListingSuperseded } from
|
|
|
198
202
|
export type { EngineAgentRegistryClient } from './agentSession/engineAgentRegistryRead.js';
|
|
199
203
|
export { stopEngineSessionBackground, engineSessionBackgroundReceiptReadingOf, ENGINE_SESSION_BACKGROUND_RECEIPT_STATES, } from './agentSession/engineSessionBackgroundStop.js';
|
|
200
204
|
export type { EngineSessionBackgroundStopClient, EngineSessionBackgroundStopWire, EngineSessionBackgroundStopOptions, EngineSessionBackgroundReceipt, EngineSessionBackgroundStopUnavailableWhy, EngineSessionBackgroundStopRefusedWhy, EngineSessionBackgroundStopResult, EngineSessionBackgroundReceiptState, EngineSessionBackgroundReceiptReading, } from './agentSession/engineSessionBackgroundStop.js';
|
|
205
|
+
export { eraseSessionMemory, sessionMemoryEraseOutcome, SESSION_MEMORY_ERASE_REFUSAL_REASONS, SESSION_MEMORY_ERASE_UNCONFIRMED_WHYS, SESSION_MEMORY_ERASE_RETRIES, } from './sessionMemoryErase.js';
|
|
206
|
+
export type { SessionMemoryEraseWire, SessionMemoryEraseCall, SessionMemoryEraseOptions, SessionMemoryEraseSent, SessionMemoryEraseNotSentWhy, SessionMemoryEraseJson, SessionMemoryEraseAnswer, SessionMemoryEraseRefusalReason, SessionMemoryEraseUnconfirmedWhy, SessionMemoryEraseRetry, SessionMemoryEraseOutcome, } from './sessionMemoryErase.js';
|
|
201
207
|
export * from './model/catalog.js';
|
|
202
208
|
export * from './model/catalogLoader.js';
|
|
203
209
|
export * from './model/providerAuth.js';
|
package/dist/index.js
CHANGED
|
@@ -134,6 +134,8 @@ export * from './wireErrorTriage.js';
|
|
|
134
134
|
export * from './corruptSession.js';
|
|
135
135
|
export * from './corruptSessionCopy.js';
|
|
136
136
|
export { classifyToolHistoryMismatch, resolveToolHistoryRewindTarget } from './toolHistoryMismatch.js';
|
|
137
|
+
export { classifyRegistryConflict, isScopeGoneError } from './registryConflict.js';
|
|
138
|
+
export { createPromptDeliveryLedger, promptKnownUndelivered, withoutUndeliveredPrompts } from './promptDelivery.js';
|
|
137
139
|
export * from './resumeRefusalCopy.js';
|
|
138
140
|
export * from './wireRefusalCopy.js';
|
|
139
141
|
export * from './inheritEnvWire.js';
|
|
@@ -182,6 +184,7 @@ export * from './agentSession/backgroundView.js';
|
|
|
182
184
|
export { READ_CREDENTIAL_NOT_ACCEPTED_NOTICE } from './readCredentialRefusal.js';
|
|
183
185
|
export { readEngineAgentRegistry, isEngineAgentRegistryListingSuperseded } from './agentSession/engineAgentRegistryRead.js';
|
|
184
186
|
export { stopEngineSessionBackground, engineSessionBackgroundReceiptReadingOf, ENGINE_SESSION_BACKGROUND_RECEIPT_STATES, } from './agentSession/engineSessionBackgroundStop.js';
|
|
187
|
+
export { eraseSessionMemory, sessionMemoryEraseOutcome, SESSION_MEMORY_ERASE_REFUSAL_REASONS, SESSION_MEMORY_ERASE_UNCONFIRMED_WHYS, SESSION_MEMORY_ERASE_RETRIES, } from './sessionMemoryErase.js';
|
|
185
188
|
export * from './model/catalog.js';
|
|
186
189
|
export * from './model/catalogLoader.js';
|
|
187
190
|
export * from './model/providerAuth.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AgentEvent } from '@sema-agent/sdk';
|
|
2
|
+
import { type SelfHealOutcome } from './adapter/activeRunSelfHeal.js';
|
|
3
|
+
export interface PromptDeliveryRecord {
|
|
4
|
+
readonly u: string;
|
|
5
|
+
readonly s: 'a' | 'd';
|
|
6
|
+
}
|
|
7
|
+
export interface PromptDeliveryLedger {
|
|
8
|
+
attempted(batchUuids: readonly string[]): readonly PromptDeliveryRecord[];
|
|
9
|
+
deliveredByFrame(batchUuids: readonly string[], event: AgentEvent): readonly PromptDeliveryRecord[];
|
|
10
|
+
deliveredBySteerReceipt(batchUuids: readonly string[], outcome: SelfHealOutcome): readonly PromptDeliveryRecord[];
|
|
11
|
+
isAttempted(uuid: string): boolean;
|
|
12
|
+
isDelivered(uuid: string): boolean;
|
|
13
|
+
knownUndelivered(uuid: string): boolean;
|
|
14
|
+
batchOf(uuid: string): readonly string[] | undefined;
|
|
15
|
+
toRecords(): readonly PromptDeliveryRecord[];
|
|
16
|
+
fromRecords(records: readonly PromptDeliveryRecord[]): readonly PromptDeliveryRecord[];
|
|
17
|
+
}
|
|
18
|
+
export declare function createPromptDeliveryLedger(): PromptDeliveryLedger;
|
|
19
|
+
export declare function promptKnownUndelivered(ledger: PromptDeliveryLedger, message: object | null | undefined): boolean;
|
|
20
|
+
export declare function withoutUndeliveredPrompts<T>(ledger: PromptDeliveryLedger, messages: readonly T[]): T[];
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { activeRunBusySignal } from './adapter/runStream.js';
|
|
2
|
+
import { selfHealSubmissionDisposition } from './adapter/activeRunSelfHeal.js';
|
|
3
|
+
const uuidOk = (u) => typeof u === 'string' && u.length > 0;
|
|
4
|
+
function cleanBatch(batch) {
|
|
5
|
+
if (!Array.isArray(batch))
|
|
6
|
+
return [];
|
|
7
|
+
const out = [];
|
|
8
|
+
const seen = new Set();
|
|
9
|
+
try {
|
|
10
|
+
for (const u of batch) {
|
|
11
|
+
if (!uuidOk(u) || seen.has(u))
|
|
12
|
+
continue;
|
|
13
|
+
seen.add(u);
|
|
14
|
+
out.push(u);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
function readRecord(rec) {
|
|
23
|
+
if (typeof rec !== 'object' || rec === null || Array.isArray(rec))
|
|
24
|
+
return undefined;
|
|
25
|
+
try {
|
|
26
|
+
const u = rec.u;
|
|
27
|
+
const s = rec.s;
|
|
28
|
+
return uuidOk(u) && (s === 'a' || s === 'd') ? { u, s } : undefined;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const PRE_RUN_FRAME_TYPES = new Set(['meta', 'approval_request', 'approval_revoke']);
|
|
35
|
+
function frameProvesDelivery(event) {
|
|
36
|
+
if (typeof event !== 'object' || event === null || Array.isArray(event))
|
|
37
|
+
return false;
|
|
38
|
+
try {
|
|
39
|
+
const type = event.type;
|
|
40
|
+
if (typeof type !== 'string' || type.length === 0 || PRE_RUN_FRAME_TYPES.has(type))
|
|
41
|
+
return false;
|
|
42
|
+
if (type === 'done') {
|
|
43
|
+
const result = event.result;
|
|
44
|
+
if (typeof result === 'object' && result !== null && !Array.isArray(result) && result.status === undefined) {
|
|
45
|
+
const r = result;
|
|
46
|
+
if (activeRunBusySignal({ type: 'failed', errorCode: r.errorCode, activeTaskId: r.activeTaskId }) !== null)
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return activeRunBusySignal(event) === null;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function outcomeProvesDelivery(outcome) {
|
|
57
|
+
if (typeof outcome !== 'object' || outcome === null || Array.isArray(outcome))
|
|
58
|
+
return false;
|
|
59
|
+
try {
|
|
60
|
+
return selfHealSubmissionDisposition(outcome) === 'handed-off';
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function createPromptDeliveryLedger() {
|
|
67
|
+
const attemptedSet = new Set();
|
|
68
|
+
const deliveredSet = new Set();
|
|
69
|
+
const batchOfMap = new Map();
|
|
70
|
+
const log = [];
|
|
71
|
+
const add = (u, s, into) => {
|
|
72
|
+
const set = s === 'a' ? attemptedSet : deliveredSet;
|
|
73
|
+
if (set.has(u))
|
|
74
|
+
return;
|
|
75
|
+
set.add(u);
|
|
76
|
+
const rec = Object.freeze({ u, s });
|
|
77
|
+
log.push(rec);
|
|
78
|
+
into.push(rec);
|
|
79
|
+
};
|
|
80
|
+
const markDelivered = (batchUuids) => {
|
|
81
|
+
const added = [];
|
|
82
|
+
for (const u of cleanBatch(batchUuids))
|
|
83
|
+
add(u, 'd', added);
|
|
84
|
+
return Object.freeze(added);
|
|
85
|
+
};
|
|
86
|
+
return Object.freeze({
|
|
87
|
+
attempted(batchUuids) {
|
|
88
|
+
const batch = Object.freeze(cleanBatch(batchUuids));
|
|
89
|
+
const added = [];
|
|
90
|
+
for (const u of batch) {
|
|
91
|
+
batchOfMap.set(u, batch);
|
|
92
|
+
add(u, 'a', added);
|
|
93
|
+
}
|
|
94
|
+
return Object.freeze(added);
|
|
95
|
+
},
|
|
96
|
+
deliveredByFrame(batchUuids, event) {
|
|
97
|
+
return frameProvesDelivery(event) ? markDelivered(batchUuids) : Object.freeze([]);
|
|
98
|
+
},
|
|
99
|
+
deliveredBySteerReceipt(batchUuids, outcome) {
|
|
100
|
+
return outcomeProvesDelivery(outcome) ? markDelivered(batchUuids) : Object.freeze([]);
|
|
101
|
+
},
|
|
102
|
+
isAttempted: (uuid) => uuidOk(uuid) && attemptedSet.has(uuid),
|
|
103
|
+
isDelivered: (uuid) => uuidOk(uuid) && deliveredSet.has(uuid),
|
|
104
|
+
knownUndelivered: (uuid) => uuidOk(uuid) && attemptedSet.has(uuid) && !deliveredSet.has(uuid),
|
|
105
|
+
batchOf: (uuid) => (uuidOk(uuid) ? batchOfMap.get(uuid) : undefined),
|
|
106
|
+
toRecords: () => Object.freeze([...log]),
|
|
107
|
+
fromRecords(records) {
|
|
108
|
+
const added = [];
|
|
109
|
+
if (!Array.isArray(records))
|
|
110
|
+
return Object.freeze(added);
|
|
111
|
+
let list;
|
|
112
|
+
try {
|
|
113
|
+
list = [...records];
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return Object.freeze(added);
|
|
117
|
+
}
|
|
118
|
+
for (const raw of list) {
|
|
119
|
+
const rec = readRecord(raw);
|
|
120
|
+
if (rec !== undefined)
|
|
121
|
+
add(rec.u, rec.s, added);
|
|
122
|
+
}
|
|
123
|
+
return Object.freeze(added);
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function uuidOfMessage(m) {
|
|
128
|
+
if (typeof m !== 'object' || m === null)
|
|
129
|
+
return undefined;
|
|
130
|
+
try {
|
|
131
|
+
const u = m.uuid;
|
|
132
|
+
return uuidOk(u) ? u : undefined;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function assertLedger(ledger, fn) {
|
|
139
|
+
if (typeof ledger !== 'object' || ledger === null || typeof ledger.knownUndelivered !== 'function') {
|
|
140
|
+
throw new TypeError(`${fn}: the first argument must be a ledger from createPromptDeliveryLedger()`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export function promptKnownUndelivered(ledger, message) {
|
|
144
|
+
assertLedger(ledger, 'promptKnownUndelivered');
|
|
145
|
+
const u = uuidOfMessage(message);
|
|
146
|
+
return u !== undefined && ledger.knownUndelivered(u);
|
|
147
|
+
}
|
|
148
|
+
export function withoutUndeliveredPrompts(ledger, messages) {
|
|
149
|
+
assertLedger(ledger, 'withoutUndeliveredPrompts');
|
|
150
|
+
if (!Array.isArray(messages))
|
|
151
|
+
return [];
|
|
152
|
+
return messages.filter((m) => !promptKnownUndelivered(ledger, m));
|
|
153
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const SCOPE_GONE_CODE = 'scope_gone';
|
|
2
|
+
const nonBlank = (v) => {
|
|
3
|
+
const s = typeof v === 'string' ? v.trim() : '';
|
|
4
|
+
return s === '' ? undefined : s;
|
|
5
|
+
};
|
|
6
|
+
export function classifyRegistryConflict(status, body) {
|
|
7
|
+
if (status !== 409)
|
|
8
|
+
return 'none';
|
|
9
|
+
try {
|
|
10
|
+
const b = (typeof body === 'object' && body !== null ? body : {});
|
|
11
|
+
const error = b.error;
|
|
12
|
+
const objectForm = typeof error === 'object' && error !== null ? error.code : undefined;
|
|
13
|
+
const code = nonBlank(b.errorCode) ?? nonBlank(objectForm) ?? (typeof error === 'string' ? error : undefined);
|
|
14
|
+
return code === SCOPE_GONE_CODE ? 'gone' : 'conflict';
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return 'gone';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const SCOPE_GONE_ERROR_NAMES = Object.freeze(['ScopeGoneError', 'ControlScopeGoneError']);
|
|
21
|
+
export function isScopeGoneError(err) {
|
|
22
|
+
if ((typeof err !== 'object' && typeof err !== 'function') || err === null)
|
|
23
|
+
return false;
|
|
24
|
+
let status;
|
|
25
|
+
try {
|
|
26
|
+
status = err.status;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (status !== 409)
|
|
32
|
+
return false;
|
|
33
|
+
try {
|
|
34
|
+
const o = err;
|
|
35
|
+
const body = o.body;
|
|
36
|
+
if (body !== undefined && body !== null && classifyRegistryConflict(409, body) === 'gone')
|
|
37
|
+
return true;
|
|
38
|
+
const name = o.name;
|
|
39
|
+
return typeof name === 'string' && SCOPE_GONE_ERROR_NAMES.includes(name);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
}
|