@sema-agent/client-core 0.83.6 → 0.84.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 +78 -0
- package/README.md +10 -10
- 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/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 +2 -1
- package/dist/attachmentsWireCaps.js +2 -2
- package/dist/controlRouter.js +1 -1
- package/dist/engineAgentAbsence.d.ts +37 -0
- package/dist/engineAgentAbsence.js +142 -0
- package/dist/engineErrorCodes.js +6 -5
- package/dist/engineNoticeCodes.d.ts +17 -0
- package/dist/engineNoticeCodes.js +45 -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/index.d.ts +23 -13
- package/dist/index.js +12 -13
- package/dist/model/catalogLoader.js +3 -3
- package/dist/model/tierVocabulary.js +1 -1
- package/dist/request/taskRequest.js +15 -5
- package/dist/rewindWireCaps.d.ts +0 -1
- package/dist/seam.d.ts +2 -1
- package/dist/seatContract.js +2 -2
- 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 +248 -29
- package/package.json +3 -3
|
@@ -14,6 +14,7 @@ export function wiringManifestViewOf(s) {
|
|
|
14
14
|
...(isObj(s._sema_writeProtection) ? { writeProtection: s._sema_writeProtection } : {}),
|
|
15
15
|
...(isObj(s._sema_autoConsolidation) ? { autoConsolidation: s._sema_autoConsolidation } : {}),
|
|
16
16
|
...(isObj(s._sema_readDeny) ? { readDeny: s._sema_readDeny } : {}),
|
|
17
|
+
...(isObj(s._sema_hands) && typeof s._sema_hands.mounted === 'boolean' ? { hands: s._sema_hands } : {}),
|
|
17
18
|
};
|
|
18
19
|
if (Object.keys(view).length === 0)
|
|
19
20
|
return undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentClient, Capabilities } from '@sema-agent/sdk';
|
|
2
|
+
import type { EngineAgentRegistryListing, EngineAgentRegistryRowView } from '../engineAgentAbsence.js';
|
|
3
|
+
export interface EngineAgentRegistryClient {
|
|
4
|
+
readonly sessions: Pick<AgentClient['sessions'], 'background'>;
|
|
5
|
+
}
|
|
6
|
+
export declare function registryClockNowMs(): number;
|
|
7
|
+
export interface RegistryListingProvenance {
|
|
8
|
+
readonly superseded: boolean;
|
|
9
|
+
readonly sessionId: string;
|
|
10
|
+
readonly rows: readonly EngineAgentRegistryRowView[];
|
|
11
|
+
readonly rawRowCount: number;
|
|
12
|
+
firstSeenAtMs(id: string): number | undefined;
|
|
13
|
+
}
|
|
14
|
+
export declare function registryListingProvenanceOf(listing: EngineAgentRegistryListing | null | undefined): RegistryListingProvenance | undefined;
|
|
15
|
+
export declare function isEngineAgentRegistryListingSuperseded(listing: EngineAgentRegistryListing | null | undefined): boolean;
|
|
16
|
+
export declare function readEngineAgentRegistry(client: EngineAgentRegistryClient, sessionId: string, caps: Pick<Capabilities, 'background'> | null | undefined, opts?: {
|
|
17
|
+
readonly signal?: AbortSignal;
|
|
18
|
+
}): Promise<EngineAgentRegistryListing>;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { errCodes } from '../controlRouter.js';
|
|
2
|
+
import { hostLog } from '../host.js';
|
|
3
|
+
const unavailable = (why) => ({
|
|
4
|
+
kind: 'unavailable',
|
|
5
|
+
why,
|
|
6
|
+
});
|
|
7
|
+
function noteReadFailed(cause, diag) {
|
|
8
|
+
try {
|
|
9
|
+
const bits = [
|
|
10
|
+
diag?.status !== undefined ? `status=${diag.status}` : '',
|
|
11
|
+
diag?.errorCode !== undefined ? `errorCode=${diag.errorCode}` : '',
|
|
12
|
+
].filter((b) => b.length > 0);
|
|
13
|
+
hostLog('debug', `[sema][registry] read_failed (${cause})${bits.length > 0 ? ` ${bits.join(' ')}` : ''}`);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const readLedgers = new WeakMap();
|
|
19
|
+
const listingRecords = new WeakMap();
|
|
20
|
+
function ledgerFor(sessions, sessionId) {
|
|
21
|
+
let bySession = readLedgers.get(sessions);
|
|
22
|
+
if (bySession === undefined) {
|
|
23
|
+
bySession = new Map();
|
|
24
|
+
readLedgers.set(sessions, bySession);
|
|
25
|
+
}
|
|
26
|
+
let ledger = bySession.get(sessionId);
|
|
27
|
+
if (ledger === undefined) {
|
|
28
|
+
ledger = { issued: 0, deliveredMax: 0, firstSeen: new Map() };
|
|
29
|
+
bySession.set(sessionId, ledger);
|
|
30
|
+
}
|
|
31
|
+
return ledger;
|
|
32
|
+
}
|
|
33
|
+
export function registryClockNowMs() {
|
|
34
|
+
const p = globalThis.performance;
|
|
35
|
+
if (typeof p === 'object' && p !== null && typeof p.now === 'function' && typeof p.timeOrigin === 'number') {
|
|
36
|
+
const v = p.timeOrigin + p.now.call(p);
|
|
37
|
+
if (Number.isFinite(v))
|
|
38
|
+
return v;
|
|
39
|
+
}
|
|
40
|
+
return Date.now();
|
|
41
|
+
}
|
|
42
|
+
export function registryListingProvenanceOf(listing) {
|
|
43
|
+
if (typeof listing !== 'object' || listing === null)
|
|
44
|
+
return undefined;
|
|
45
|
+
const rec = listingRecords.get(listing);
|
|
46
|
+
if (rec === undefined)
|
|
47
|
+
return undefined;
|
|
48
|
+
return {
|
|
49
|
+
superseded: rec.ledger.deliveredMax > rec.seq,
|
|
50
|
+
sessionId: rec.sessionId,
|
|
51
|
+
rows: rec.rows,
|
|
52
|
+
rawRowCount: rec.rawRowCount,
|
|
53
|
+
firstSeenAtMs: (id) => rec.ledger.firstSeen.get(id),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function isEngineAgentRegistryListingSuperseded(listing) {
|
|
57
|
+
return registryListingProvenanceOf(listing)?.superseded === true;
|
|
58
|
+
}
|
|
59
|
+
function listFaceOn(caps) {
|
|
60
|
+
if (typeof caps !== 'object' || caps === null || !Object.hasOwn(caps, 'background'))
|
|
61
|
+
return false;
|
|
62
|
+
const bg = caps.background;
|
|
63
|
+
if (typeof bg !== 'object' || bg === null || !Object.hasOwn(bg, 'listFace'))
|
|
64
|
+
return false;
|
|
65
|
+
return bg.listFace === true;
|
|
66
|
+
}
|
|
67
|
+
function readRow(v) {
|
|
68
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
69
|
+
return undefined;
|
|
70
|
+
const o = v;
|
|
71
|
+
const id = Object.hasOwn(o, 'id') ? o.id : undefined;
|
|
72
|
+
const type = Object.hasOwn(o, 'type') ? o.type : undefined;
|
|
73
|
+
const status = Object.hasOwn(o, 'status') ? o.status : undefined;
|
|
74
|
+
if (typeof id !== 'string' || id.length === 0 || typeof type !== 'string' || type.length === 0 || typeof status !== 'string' || status.length === 0)
|
|
75
|
+
return undefined;
|
|
76
|
+
const description = Object.hasOwn(o, 'description') ? o.description : undefined;
|
|
77
|
+
const createdAt = Object.hasOwn(o, 'createdAt') ? o.createdAt : undefined;
|
|
78
|
+
return {
|
|
79
|
+
id,
|
|
80
|
+
type,
|
|
81
|
+
status,
|
|
82
|
+
...(typeof description === 'string' && description.length > 0 ? { description } : {}),
|
|
83
|
+
...(typeof createdAt === 'number' && Number.isFinite(createdAt) ? { createdAt } : {}),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export async function readEngineAgentRegistry(client, sessionId, caps, opts) {
|
|
87
|
+
try {
|
|
88
|
+
return await readOnce(client, sessionId, caps, opts);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
noteReadFailed('reader threw');
|
|
92
|
+
return unavailable('read_failed');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function readOnce(client, sessionId, caps, opts) {
|
|
96
|
+
if (!listFaceOn(caps))
|
|
97
|
+
return unavailable('no_list_face');
|
|
98
|
+
if (typeof sessionId !== 'string' || sessionId.length === 0) {
|
|
99
|
+
noteReadFailed('bad session id');
|
|
100
|
+
return unavailable('read_failed');
|
|
101
|
+
}
|
|
102
|
+
if (typeof client !== 'object' || client === null) {
|
|
103
|
+
noteReadFailed('bad client');
|
|
104
|
+
return unavailable('read_failed');
|
|
105
|
+
}
|
|
106
|
+
const sessions = client.sessions;
|
|
107
|
+
if (typeof sessions !== 'object' || sessions === null) {
|
|
108
|
+
noteReadFailed('bad client');
|
|
109
|
+
return unavailable('read_failed');
|
|
110
|
+
}
|
|
111
|
+
const ledger = ledgerFor(sessions, sessionId);
|
|
112
|
+
const seq = ++ledger.issued;
|
|
113
|
+
let body;
|
|
114
|
+
try {
|
|
115
|
+
const signal = opts?.signal;
|
|
116
|
+
body = await sessions.background(sessionId, signal !== undefined ? { signal } : undefined);
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
const { code, status } = errCodes(e);
|
|
120
|
+
if (status === 404 && code === 'not_found.route')
|
|
121
|
+
return unavailable('route_absent');
|
|
122
|
+
if (status === 501 && code === 'capability.session_ownership_required')
|
|
123
|
+
return unavailable('ownership_required');
|
|
124
|
+
const diag = {
|
|
125
|
+
...(typeof status === 'number' && Number.isInteger(status) ? { status } : {}),
|
|
126
|
+
...(typeof code === 'string' && code.length > 0 ? { errorCode: code } : {}),
|
|
127
|
+
};
|
|
128
|
+
noteReadFailed('request failed', diag);
|
|
129
|
+
return { kind: 'unavailable', why: 'read_failed', ...diag };
|
|
130
|
+
}
|
|
131
|
+
if (typeof body !== 'object' || body === null || !Object.hasOwn(body, 'rows')) {
|
|
132
|
+
noteReadFailed('body is not { rows }');
|
|
133
|
+
return unavailable('read_failed');
|
|
134
|
+
}
|
|
135
|
+
const raw = body.rows;
|
|
136
|
+
if (!Array.isArray(raw)) {
|
|
137
|
+
noteReadFailed('body is not { rows }');
|
|
138
|
+
return unavailable('read_failed');
|
|
139
|
+
}
|
|
140
|
+
const rows = [];
|
|
141
|
+
for (const r of raw) {
|
|
142
|
+
const row = readRow(r);
|
|
143
|
+
if (row === undefined) {
|
|
144
|
+
noteReadFailed('a row could not be read');
|
|
145
|
+
return unavailable('read_failed');
|
|
146
|
+
}
|
|
147
|
+
rows.push(Object.freeze(row));
|
|
148
|
+
}
|
|
149
|
+
const rawRowCount = raw.length;
|
|
150
|
+
if (seq > ledger.deliveredMax) {
|
|
151
|
+
ledger.deliveredMax = seq;
|
|
152
|
+
const now = registryClockNowMs();
|
|
153
|
+
const present = new Set();
|
|
154
|
+
for (const row of rows) {
|
|
155
|
+
present.add(row.id);
|
|
156
|
+
if (!ledger.firstSeen.has(row.id))
|
|
157
|
+
ledger.firstSeen.set(row.id, now);
|
|
158
|
+
}
|
|
159
|
+
for (const id of [...ledger.firstSeen.keys()])
|
|
160
|
+
if (!present.has(id))
|
|
161
|
+
ledger.firstSeen.delete(id);
|
|
162
|
+
}
|
|
163
|
+
const frozenRows = Object.freeze(rows);
|
|
164
|
+
const listing = Object.freeze({ kind: 'rows', rows: frozenRows, sessionId, seq });
|
|
165
|
+
listingRecords.set(listing, { ledger, seq, sessionId, rows: frozenRows, rawRowCount });
|
|
166
|
+
return listing;
|
|
167
|
+
}
|
package/dist/agentsWireCaps.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { hostEnv } from './hostEnv.js';
|
|
2
2
|
import { makeEngineWireClient } from './engineWireSdk.js';
|
|
3
|
+
import { frozenSet } from './frozenSet.js';
|
|
3
4
|
export const MAX_TASK_AGENTS = 32;
|
|
4
5
|
export const MAX_AGENT_NAME_CHARS = 64;
|
|
5
6
|
export const MAX_AGENT_TEXT_CHARS = 4_096;
|
|
@@ -25,7 +26,7 @@ export const TASK_AGENT_WIRE_FIELDS = [
|
|
|
25
26
|
'observer',
|
|
26
27
|
'observerMessage',
|
|
27
28
|
];
|
|
28
|
-
export const AGENT_MEMORY_WORDS =
|
|
29
|
+
export const AGENT_MEMORY_WORDS = frozenSet(['user', 'project', 'local']);
|
|
29
30
|
const SOURCE_RANK = {
|
|
30
31
|
policySettings: 0,
|
|
31
32
|
flagSettings: 1,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { hostEnv } from './hostEnv.js';
|
|
2
2
|
import { envFlagOff } from './envFlag.js';
|
|
3
3
|
export const ATTACHMENTS_ENV = 'SEMA_ATTACHMENTS';
|
|
4
|
-
export const ATTACHMENTS_SPEC_KEYS = [
|
|
4
|
+
export const ATTACHMENTS_SPEC_KEYS = Object.freeze([
|
|
5
5
|
'todoReminder',
|
|
6
6
|
'todoReminderMode',
|
|
7
7
|
'changedFiles',
|
|
@@ -12,7 +12,7 @@ export const ATTACHMENTS_SPEC_KEYS = [
|
|
|
12
12
|
'mcpInstructions',
|
|
13
13
|
'agentListing',
|
|
14
14
|
'skillsListing',
|
|
15
|
-
];
|
|
15
|
+
]);
|
|
16
16
|
export const ATTACHMENTS_DEFAULT_ON_KEYS = ['agentListing', 'skillsListing', 'backgroundTasks'];
|
|
17
17
|
const OPT_IN_KEYS = [
|
|
18
18
|
'todoReminder',
|
package/dist/controlRouter.js
CHANGED
|
@@ -83,7 +83,7 @@ export class ControlRouter {
|
|
|
83
83
|
}
|
|
84
84
|
if (isCancelSuspendedConflict(e)) {
|
|
85
85
|
throw new ControlSafetyError('runs.cancel 409 — the pending gate was decided or expired concurrently (lost CAS race); ' +
|
|
86
|
-
'
|
|
86
|
+
'check what that decision did to the run before retrying the cancel', 'cancel_lost_race', e);
|
|
87
87
|
}
|
|
88
88
|
if (isNotFound(e)) {
|
|
89
89
|
throw new ControlSafetyError('runs.cancel 404 — non-owner / unknown run (no existence leak)', 'not_found', e);
|
|
@@ -49,4 +49,41 @@ export interface EngineAgentAbsenceReapOptions {
|
|
|
49
49
|
export declare function reapEngineAgentAbsentRows(rows: Readonly<Record<string, EngineAgentAbsenceReapRow | null | undefined>>, opts: EngineAgentAbsenceReapOptions): EngineAgentAbsenceReap;
|
|
50
50
|
export declare function engineAgentAbsenceDroppedLine(label: string, ttlMs?: number, removeReason?: string | null): string;
|
|
51
51
|
export declare function engineAgentTerminalAfterDropLine(label: string, status: RunTerminalStatus, hasReport: boolean): string;
|
|
52
|
+
export interface EngineAgentRegistryRowView {
|
|
53
|
+
readonly id: string;
|
|
54
|
+
readonly type: string;
|
|
55
|
+
readonly status: string;
|
|
56
|
+
readonly description?: string;
|
|
57
|
+
readonly createdAt?: number;
|
|
58
|
+
}
|
|
59
|
+
export type EngineAgentRegistryUnavailableWhy = 'no_list_face' | 'route_absent' | 'ownership_required' | 'read_failed';
|
|
60
|
+
export type EngineAgentRegistryListing = {
|
|
61
|
+
readonly kind: 'rows';
|
|
62
|
+
readonly rows: readonly EngineAgentRegistryRowView[];
|
|
63
|
+
readonly sessionId: string;
|
|
64
|
+
readonly seq: number;
|
|
65
|
+
} | {
|
|
66
|
+
readonly kind: 'unavailable';
|
|
67
|
+
readonly why: EngineAgentRegistryUnavailableWhy;
|
|
68
|
+
readonly status?: number;
|
|
69
|
+
readonly errorCode?: string;
|
|
70
|
+
};
|
|
71
|
+
export declare function engineAgentRegistryKeyOf(ev: Pick<EngineAgentPanelAbsence, 'taskId' | 'wireTaskId'> | null | undefined): string | undefined;
|
|
72
|
+
export interface EngineAgentRegistryReadingOptions {
|
|
73
|
+
readonly singleReplica?: true;
|
|
74
|
+
readonly sessionId?: string;
|
|
75
|
+
}
|
|
76
|
+
export declare function engineAgentRegistryReadingOf(listing: EngineAgentRegistryListing | null | undefined, registryKey: string | null | undefined, opts?: EngineAgentRegistryReadingOptions | null): EngineAgentRegistryReading;
|
|
77
|
+
export interface EngineAgentRegistryMissingRow {
|
|
78
|
+
readonly id: string;
|
|
79
|
+
readonly status: string;
|
|
80
|
+
readonly description?: string;
|
|
81
|
+
readonly createdAt: number;
|
|
82
|
+
}
|
|
83
|
+
export interface EngineAgentRegistryFillOptions {
|
|
84
|
+
readonly nowMs?: number;
|
|
85
|
+
readonly goneSinceRead?: ReadonlySet<string> | readonly string[];
|
|
86
|
+
readonly sessionId?: string;
|
|
87
|
+
}
|
|
88
|
+
export declare function engineAgentRegistryRowsMissingFromHost(listing: EngineAgentRegistryListing | null | undefined, hostRegistryKeys: ReadonlySet<string> | readonly string[], opts?: EngineAgentRegistryFillOptions | null): readonly EngineAgentRegistryMissingRow[];
|
|
52
89
|
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { registryClockNowMs, registryListingProvenanceOf } from './agentSession/engineAgentRegistryRead.js';
|
|
1
2
|
import { displayUntrusted } from './displayUntrusted.js';
|
|
3
|
+
import { ABSENT_SETTLE_MS } from './fleetAgentPanelProjection.js';
|
|
2
4
|
import { isEnginePanelTaskResident, isStaleEngineAgentPanelEnd, } from './engineAgentPanelStore.js';
|
|
3
5
|
export const ENGINE_AGENT_ABSENT_ROW_TEXT = 'engine no longer reports this agent · it may still be running';
|
|
4
6
|
export const ENGINE_AGENT_ABSENCE_TTL_MS = 30 * 60_000;
|
|
@@ -129,3 +131,143 @@ export function engineAgentTerminalAfterDropLine(label, status, hasReport) {
|
|
|
129
131
|
const tail = hasReport ? ' · its final report arrived too late to keep in the panel' : '';
|
|
130
132
|
return `${displayUntrusted(label)} reported ${displayUntrusted(status)} after it was dropped from the task panel${tail}`;
|
|
131
133
|
}
|
|
134
|
+
const REGISTRY_LIST_LIMIT = 500;
|
|
135
|
+
const REGISTRY_AGENT_HANDLE_RE = /^a[0-9a-f]{6,32}$/;
|
|
136
|
+
const REGISTRY_AGENT_TYPE = 'background_agent';
|
|
137
|
+
function registryStatusReading(status) {
|
|
138
|
+
const s = status;
|
|
139
|
+
switch (s) {
|
|
140
|
+
case 'pending':
|
|
141
|
+
case 'running':
|
|
142
|
+
case 'parked':
|
|
143
|
+
return 'running';
|
|
144
|
+
case 'completed':
|
|
145
|
+
case 'failed':
|
|
146
|
+
case 'killed':
|
|
147
|
+
case 'cancelled':
|
|
148
|
+
return 'ended';
|
|
149
|
+
default: {
|
|
150
|
+
const unhandled = s;
|
|
151
|
+
void unhandled;
|
|
152
|
+
return 'unknown';
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
export function engineAgentRegistryKeyOf(ev) {
|
|
157
|
+
if (typeof ev !== 'object' || ev === null)
|
|
158
|
+
return undefined;
|
|
159
|
+
const w = ev.wireTaskId;
|
|
160
|
+
const t = ev.taskId;
|
|
161
|
+
const wire = typeof w === 'string' && w.length > 0 ? w : undefined;
|
|
162
|
+
const task = typeof t === 'string' && t.length > 0 ? t : undefined;
|
|
163
|
+
if (wire !== undefined && REGISTRY_AGENT_HANDLE_RE.test(wire))
|
|
164
|
+
return wire;
|
|
165
|
+
if (task !== undefined && REGISTRY_AGENT_HANDLE_RE.test(task))
|
|
166
|
+
return task;
|
|
167
|
+
return wire ?? task;
|
|
168
|
+
}
|
|
169
|
+
function ownOpt(opts, key) {
|
|
170
|
+
if (typeof opts !== 'object' || opts === null || !Object.hasOwn(opts, key))
|
|
171
|
+
return { given: false, value: undefined };
|
|
172
|
+
const value = opts[key];
|
|
173
|
+
return { given: value !== undefined, value };
|
|
174
|
+
}
|
|
175
|
+
function sessionMismatch(readSessionId, opts) {
|
|
176
|
+
const { given, value } = ownOpt(opts, 'sessionId');
|
|
177
|
+
if (!given)
|
|
178
|
+
return false;
|
|
179
|
+
return typeof value !== 'string' || value.length === 0 || readSessionId !== value;
|
|
180
|
+
}
|
|
181
|
+
export function engineAgentRegistryReadingOf(listing, registryKey, opts) {
|
|
182
|
+
try {
|
|
183
|
+
return readingOf(listing, registryKey, opts);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return 'unknown';
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function readingOf(listing, registryKey, opts) {
|
|
190
|
+
const rec = registryListingProvenanceOf(listing);
|
|
191
|
+
if (rec === undefined || rec.superseded)
|
|
192
|
+
return 'unknown';
|
|
193
|
+
if (sessionMismatch(rec.sessionId, opts))
|
|
194
|
+
return 'unknown';
|
|
195
|
+
return readingFromRecord(rec, registryKey, opts);
|
|
196
|
+
}
|
|
197
|
+
function readingFromRecord(rec, registryKey, opts) {
|
|
198
|
+
if (typeof registryKey !== 'string' || registryKey.length === 0)
|
|
199
|
+
return 'unknown';
|
|
200
|
+
let reading;
|
|
201
|
+
for (const r of rec.rows) {
|
|
202
|
+
if (r.id !== registryKey)
|
|
203
|
+
continue;
|
|
204
|
+
const here = r.type === REGISTRY_AGENT_TYPE ? registryStatusReading(r.status) : 'unknown';
|
|
205
|
+
reading = reading === undefined || reading === here ? here : 'unknown';
|
|
206
|
+
}
|
|
207
|
+
if (reading !== undefined)
|
|
208
|
+
return reading;
|
|
209
|
+
if (rec.rawRowCount >= REGISTRY_LIST_LIMIT)
|
|
210
|
+
return 'unknown';
|
|
211
|
+
if (!ownOpt(opts, 'sessionId').given)
|
|
212
|
+
return 'unknown';
|
|
213
|
+
const single = ownOpt(opts, 'singleReplica');
|
|
214
|
+
return single.given && single.value === true && REGISTRY_AGENT_HANDLE_RE.test(registryKey) ? 'not_listed' : 'unknown';
|
|
215
|
+
}
|
|
216
|
+
function keySetOf(v) {
|
|
217
|
+
if (v instanceof Set)
|
|
218
|
+
return (k) => v.has(k);
|
|
219
|
+
if (Array.isArray(v))
|
|
220
|
+
return (k) => v.includes(k);
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
export function engineAgentRegistryRowsMissingFromHost(listing, hostRegistryKeys, opts) {
|
|
224
|
+
try {
|
|
225
|
+
return rowsMissingFromHost(listing, hostRegistryKeys, opts);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function rowsMissingFromHost(listing, hostRegistryKeys, opts) {
|
|
232
|
+
const rec = registryListingProvenanceOf(listing);
|
|
233
|
+
if (rec === undefined || rec.superseded)
|
|
234
|
+
return [];
|
|
235
|
+
if (sessionMismatch(rec.sessionId, opts))
|
|
236
|
+
return [];
|
|
237
|
+
const has = keySetOf(hostRegistryKeys);
|
|
238
|
+
if (has === undefined)
|
|
239
|
+
return [];
|
|
240
|
+
const goneOpt = ownOpt(opts, 'goneSinceRead');
|
|
241
|
+
const gone = goneOpt.given ? keySetOf(goneOpt.value) : () => false;
|
|
242
|
+
if (gone === undefined)
|
|
243
|
+
return [];
|
|
244
|
+
const nowOpt = ownOpt(opts, 'nowMs');
|
|
245
|
+
const now = nowOpt.given ? nowOpt.value : registryClockNowMs();
|
|
246
|
+
if (typeof now !== 'number' || !Number.isFinite(now))
|
|
247
|
+
return [];
|
|
248
|
+
const out = [];
|
|
249
|
+
const seen = new Set();
|
|
250
|
+
for (const r of rec.rows) {
|
|
251
|
+
if (r.type !== REGISTRY_AGENT_TYPE)
|
|
252
|
+
continue;
|
|
253
|
+
if (seen.has(r.id))
|
|
254
|
+
continue;
|
|
255
|
+
if (readingFromRecord(rec, r.id, undefined) !== 'running')
|
|
256
|
+
continue;
|
|
257
|
+
seen.add(r.id);
|
|
258
|
+
if (has(r.id) || gone(r.id))
|
|
259
|
+
continue;
|
|
260
|
+
const firstSeen = rec.firstSeenAtMs(r.id);
|
|
261
|
+
if (firstSeen === undefined || now - firstSeen <= ABSENT_SETTLE_MS)
|
|
262
|
+
continue;
|
|
263
|
+
if (typeof r.createdAt !== 'number' || !Number.isFinite(r.createdAt))
|
|
264
|
+
continue;
|
|
265
|
+
out.push({
|
|
266
|
+
id: r.id,
|
|
267
|
+
status: r.status,
|
|
268
|
+
...(typeof r.description === 'string' && r.description.length > 0 ? { description: r.description } : {}),
|
|
269
|
+
createdAt: r.createdAt,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return out;
|
|
273
|
+
}
|
package/dist/engineErrorCodes.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { frozenSet } from './frozenSet.js';
|
|
1
2
|
export const LIMITS_MAX_TOKENS_EXCEEDED = 'limits.max_tokens_exceeded';
|
|
2
3
|
export const LIMITS_MAX_COST_EXCEEDED = 'limits.max_cost_exceeded';
|
|
3
4
|
export const LIMITS_MAX_TURNS_EXCEEDED = 'limits.max_turns_exceeded';
|
|
@@ -15,7 +16,7 @@ export const CONFIG_LIMIT_UNKNOWN_KEY = 'config.limit_unknown_key';
|
|
|
15
16
|
export const CONFIG_DELEGATION_ENTRY_CAPS = 'config.delegation_entry_caps';
|
|
16
17
|
export const CONFIG_MEMORY_PROJECT_KEY_SPELLING = 'config.memory_project_key_spelling';
|
|
17
18
|
export const CONFIG_MEMORY_WRITE_SCOPE_MISMATCH = 'config.memory_write_scope_mismatch';
|
|
18
|
-
export const CONFIG_REFUSAL_CODES =
|
|
19
|
+
export const CONFIG_REFUSAL_CODES = frozenSet([
|
|
19
20
|
CONFIG_LIMIT_INVALID,
|
|
20
21
|
CONFIG_STRATEGY_FIND_LIMIT_INVALID,
|
|
21
22
|
CONFIG_STRATEGY_MAX_SIZE_INVALID,
|
|
@@ -26,7 +27,7 @@ export const CONFIG_REFUSAL_CODES = new Set([
|
|
|
26
27
|
]);
|
|
27
28
|
export const DELEGATION_CONCURRENCY_CAP = 'delegation.concurrency_cap';
|
|
28
29
|
export const DELEGATION_SESSION_CAP = 'delegation.session_cap';
|
|
29
|
-
export const DELEGATION_CAP_CODES =
|
|
30
|
+
export const DELEGATION_CAP_CODES = frozenSet([
|
|
30
31
|
DELEGATION_CONCURRENCY_CAP,
|
|
31
32
|
DELEGATION_SESSION_CAP,
|
|
32
33
|
]);
|
|
@@ -61,17 +62,17 @@ export const STOP_PARK_RESUME_WON = 'stop.park_resume_won';
|
|
|
61
62
|
export const STOP_NOT_LANDED = 'stop.not_landed';
|
|
62
63
|
export const STOP_NOT_LOCAL = 'stop.not_local';
|
|
63
64
|
export const STOP_PARKED = 'stop.parked';
|
|
64
|
-
export const STOP_CONFLICT_CODES = [
|
|
65
|
+
export const STOP_CONFLICT_CODES = Object.freeze([
|
|
65
66
|
STOP_PARK_ARBITER_UNREACHABLE,
|
|
66
67
|
STOP_PARK_RESUME_WON,
|
|
67
68
|
STOP_NOT_LANDED,
|
|
68
69
|
STOP_NOT_LOCAL,
|
|
69
70
|
STOP_PARKED,
|
|
70
|
-
];
|
|
71
|
+
]);
|
|
71
72
|
export const OUTPUT_INVALID = 'output.invalid';
|
|
72
73
|
export const RESUME_POLICY_FOLD_CODE = 'resume_blocked_by_policy';
|
|
73
74
|
export const RESUME_AT_ERROR_CODE_PREFIX = 'resume_at.';
|
|
74
|
-
export const REWIND_ERROR_CODE_PREFIXES = [RESUME_AT_ERROR_CODE_PREFIX, 'rewind_snapshot.'];
|
|
75
|
+
export const REWIND_ERROR_CODE_PREFIXES = Object.freeze([RESUME_AT_ERROR_CODE_PREFIX, 'rewind_snapshot.']);
|
|
75
76
|
export function isRewindFamilyCode(code) {
|
|
76
77
|
return typeof code === 'string' && REWIND_ERROR_CODE_PREFIXES.some((p) => code.startsWith(p));
|
|
77
78
|
}
|
|
@@ -52,3 +52,20 @@ export interface McpServerRedialedFactsView {
|
|
|
52
52
|
runId: string;
|
|
53
53
|
}
|
|
54
54
|
export declare function readMcpServerRedialed(notice: unknown): McpServerRedialedFactsView | undefined;
|
|
55
|
+
export type ReadRootGrantNoticeFactsView = {
|
|
56
|
+
outcome: 'granted';
|
|
57
|
+
toolCallId: string;
|
|
58
|
+
dir: string;
|
|
59
|
+
root: string;
|
|
60
|
+
covers?: 'exact';
|
|
61
|
+
sessionId?: string;
|
|
62
|
+
} | {
|
|
63
|
+
outcome: 'rejected';
|
|
64
|
+
toolCallId: string;
|
|
65
|
+
reason?: string;
|
|
66
|
+
sessionId?: string;
|
|
67
|
+
};
|
|
68
|
+
export declare function readReadRootGrantNotice(notice: {
|
|
69
|
+
readonly code?: string;
|
|
70
|
+
readonly detail?: object | null;
|
|
71
|
+
} | null | undefined): ReadRootGrantNoticeFactsView | undefined;
|
|
@@ -303,3 +303,48 @@ export function readMcpServerRedialed(notice) {
|
|
|
303
303
|
const reason = str(o.reason);
|
|
304
304
|
return { server, outcome, added, removed, ...(reason !== undefined ? { reason } : {}), sessionId, runId };
|
|
305
305
|
}
|
|
306
|
+
const READ_ROOT_GRANT_COVERS_EXACT = 'exact';
|
|
307
|
+
const _grantCoversPin = true;
|
|
308
|
+
void _grantCoversPin;
|
|
309
|
+
export function readReadRootGrantNotice(notice) {
|
|
310
|
+
try {
|
|
311
|
+
return readRootGrantNoticeOf(notice);
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
return undefined;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function readRootGrantNoticeOf(notice) {
|
|
318
|
+
if (typeof notice !== 'object' || notice === null || Array.isArray(notice))
|
|
319
|
+
return undefined;
|
|
320
|
+
const n = notice;
|
|
321
|
+
if (n.code !== 'approval.read_root_granted' && n.code !== 'approval.read_root_grant_rejected')
|
|
322
|
+
return undefined;
|
|
323
|
+
const d = n.detail;
|
|
324
|
+
if (typeof d !== 'object' || d === null || Array.isArray(d))
|
|
325
|
+
return undefined;
|
|
326
|
+
const o = d;
|
|
327
|
+
const str = (v) => (typeof v === 'string' && v.length > 0 ? v : undefined);
|
|
328
|
+
const toolCallId = str(o.toolCallId);
|
|
329
|
+
if (toolCallId === undefined)
|
|
330
|
+
return undefined;
|
|
331
|
+
const sessionId = str(o.sessionId);
|
|
332
|
+
if (n.code === 'approval.read_root_granted') {
|
|
333
|
+
const dir = str(o.dir);
|
|
334
|
+
const root = str(o.root);
|
|
335
|
+
if (dir === undefined || root === undefined)
|
|
336
|
+
return undefined;
|
|
337
|
+
if ('covers' in o && o.covers !== READ_ROOT_GRANT_COVERS_EXACT)
|
|
338
|
+
return undefined;
|
|
339
|
+
return {
|
|
340
|
+
outcome: 'granted',
|
|
341
|
+
toolCallId,
|
|
342
|
+
dir,
|
|
343
|
+
root,
|
|
344
|
+
...('covers' in o ? { covers: READ_ROOT_GRANT_COVERS_EXACT } : {}),
|
|
345
|
+
...(sessionId !== undefined ? { sessionId } : {}),
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
const reason = str(o.reason);
|
|
349
|
+
return { outcome: 'rejected', toolCallId, ...(reason !== undefined ? { reason } : {}), ...(sessionId !== undefined ? { sessionId } : {}) };
|
|
350
|
+
}
|
|
@@ -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;
|