@telnyx/agent-harness 0.1.0-beta.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.
@@ -0,0 +1,650 @@
1
+ import { createHash } from "node:crypto";
2
+ import { AGENT_HARNESS_PORTS_VERSION } from "./ports.js";
3
+ import { createHarnessStepContext } from "./steps.js";
4
+ export const HARNESS_RUN_STATUSES = ["accepted", "running", "awaiting_approval", "resume_pending", "completed", "failed", "canceled", "outcome_unknown"];
5
+ /** Internal control signal: the caller's durable admission fence rejected this run. */
6
+ export class HarnessAdmissionRejected extends Error {
7
+ constructor() {
8
+ super("harness admission was rejected by its durable fence");
9
+ this.name = "HarnessAdmissionRejected";
10
+ }
11
+ }
12
+ /** Internal deterministic crash signal. It intentionally leaves durable state at the interrupted boundary. */
13
+ export class HarnessInjectedCrash extends Error {
14
+ constructor(cause) {
15
+ super(cause instanceof Error ? cause.message : "injected crash");
16
+ this.name = "HarnessInjectedCrash";
17
+ }
18
+ }
19
+ /** Internal control signal: approval state was durably recorded before pausing. */
20
+ export class HarnessApprovalPause extends Error {
21
+ constructor() {
22
+ super("Harness run is awaiting durable approval");
23
+ this.name = "HarnessApprovalPause";
24
+ }
25
+ }
26
+ const scheduleRollbackSteps = new WeakMap();
27
+ /** Internal schedule-only rollback signal that never inspects arbitrary caught errors. */
28
+ export function createScheduleAdmissionRollbackError(step, cause) {
29
+ const error = new Error("schedule admission rolled back", { cause });
30
+ scheduleRollbackSteps.set(error, step);
31
+ return error;
32
+ }
33
+ function scheduleRollbackStep(error) {
34
+ return error !== null && typeof error === "object" ? scheduleRollbackSteps.get(error) : undefined;
35
+ }
36
+ // v6 owns the whole private approval topology. Keeping every table in this
37
+ // transaction prevents a run schema from claiming v6 while approval linkage,
38
+ // envelopes, or audit history are missing or from another protocol.
39
+ const APPROVAL_SCHEMA_VERSION = 6;
40
+ // v7 records the run-owned sequence for the admitted input. v8 adds an
41
+ // out-of-band durable tool-output failure marker.
42
+ const SCHEMA_VERSION = 8;
43
+ const MAX_INPUT_BYTES = 64 * 1024;
44
+ const MAX_KEY_BYTES = 512;
45
+ const TASK_METHOD = "__telnyx_agent_harness_run";
46
+ const APPROVAL_RESUME_TASK_METHOD = "__telnyx_agent_harness_approval_resume";
47
+ const SAFE_FAILURE_CODES = new Set([
48
+ "HARNESS_CANCELLED",
49
+ "HARNESS_OBSERVER_ERROR",
50
+ "HARNESS_PROVIDER_ERROR",
51
+ "HARNESS_STEP_LIMIT",
52
+ "HARNESS_TOOL_OUTPUT_ERROR",
53
+ "HARNESS_APPROVAL_INVALID",
54
+ ]);
55
+ function first(rows) { return rows[0]; }
56
+ function requireBoundedString(value, name, limit) {
57
+ if (Buffer.byteLength(value, "utf8") > limit)
58
+ throw new Error(`${name} exceeds ${limit} UTF-8 bytes`);
59
+ }
60
+ function requireNonblankBoundedString(value, name, limit) {
61
+ if (!value.trim())
62
+ throw new Error(`${name} must not be blank`);
63
+ requireBoundedString(value, name, limit);
64
+ }
65
+ function failureCode(error) {
66
+ try {
67
+ if (error !== null && typeof error === "object") {
68
+ const code = error.code;
69
+ if (code === "expired")
70
+ return "HARNESS_APPROVAL_EXPIRED";
71
+ if (code === "forbidden" || code === "unauthenticated" || code === "identity_unavailable")
72
+ return "HARNESS_AUTHORIZATION_REVOKED";
73
+ if (code === "missing" || code === "replayed" || code === "conflicting" || code === "consumed")
74
+ return "HARNESS_APPROVAL_INVALID";
75
+ if (typeof code === "string" && SAFE_FAILURE_CODES.has(code))
76
+ return code;
77
+ }
78
+ }
79
+ catch {
80
+ // Executor-thrown objects may expose hostile getters or Proxy traps.
81
+ }
82
+ return "HARNESS_RUN_FAILED";
83
+ }
84
+ function isPolicyUnavailable(error) {
85
+ try {
86
+ return error !== null && typeof error === "object" && error.code === "policy_unavailable";
87
+ }
88
+ catch {
89
+ return false;
90
+ }
91
+ }
92
+ function dispatchedRun(task) {
93
+ if (task.name !== TASK_METHOD && task.name !== APPROVAL_RESUME_TASK_METHOD)
94
+ throw new Error("task is not a harness run task");
95
+ if (task.payload === null || typeof task.payload !== "object" || Array.isArray(task.payload)) {
96
+ throw new Error("harness run task payload is invalid");
97
+ }
98
+ const descriptor = Object.getOwnPropertyDescriptor(task.payload, "runId");
99
+ if (descriptor === undefined || !("value" in descriptor) || typeof descriptor.value !== "string" || !descriptor.value) {
100
+ throw new Error("harness run task payload is invalid");
101
+ }
102
+ if (task.name === TASK_METHOD)
103
+ return Object.freeze({ runId: descriptor.value });
104
+ const batch = Object.getOwnPropertyDescriptor(task.payload, "batch");
105
+ if (batch === undefined || !("value" in batch) || typeof batch.value !== "string" || !/^[a-f0-9]{64}$/.test(batch.value)) {
106
+ throw new Error("harness approval resume task payload is invalid");
107
+ }
108
+ return Object.freeze({ runId: descriptor.value, batch: batch.value });
109
+ }
110
+ function publicRun(row) {
111
+ return Object.freeze({
112
+ id: row.id, key: row.key, status: row.status, attempts: row.attempts,
113
+ inputBytes: row.input_bytes, createdAt: row.created_at, updatedAt: row.updated_at,
114
+ ...(row.failure_code === null ? {} : { failureCode: row.failure_code }),
115
+ });
116
+ }
117
+ function createV6ApprovalTopology(ports) {
118
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_run_authority (run_id TEXT PRIMARY KEY NOT NULL, service_account_id TEXT NOT NULL, organization_id TEXT NOT NULL, required_action TEXT NOT NULL, FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs(id))");
119
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_approvals (id TEXT PRIMARY KEY, run_id TEXT NOT NULL, tool_name TEXT NOT NULL, tool_call_id TEXT NOT NULL, arguments TEXT NOT NULL, required_action TEXT NOT NULL, service_account_id TEXT NOT NULL, organization_id TEXT NOT NULL, status TEXT NOT NULL CHECK(status IN ('pending','granted','denied','expired','consumed')), expires_at INTEGER NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, UNIQUE(run_id,tool_call_id))");
120
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_approval_audit (id TEXT PRIMARY KEY, approval_id TEXT NOT NULL, event TEXT NOT NULL, actor TEXT, action TEXT, outcome TEXT, at INTEGER NOT NULL, seq INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(approval_id) REFERENCES __telnyx_agent_harness_approvals(id))");
121
+ // COMPUTE-904: Add the monotonic seq column to existing audit tables.
122
+ const auditColumns = new Set((ports.sql.exec("PRAGMA table_info('__telnyx_agent_harness_approval_audit')").toArray()).map((column) => column.name));
123
+ if (!auditColumns.has("seq"))
124
+ ports.sql.exec("ALTER TABLE __telnyx_agent_harness_approval_audit ADD COLUMN seq INTEGER NOT NULL DEFAULT 0");
125
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_approval_messages (approval_id TEXT PRIMARY KEY, codec_version INTEGER NOT NULL CHECK(codec_version = 1), run_id TEXT NOT NULL, tool_call_id TEXT NOT NULL, tool_name TEXT NOT NULL, journal_seq INTEGER NOT NULL CHECK(journal_seq >= 0), after_message_seq INTEGER NOT NULL CHECK(after_message_seq >= 0), approval_epoch INTEGER NOT NULL CHECK(approval_epoch >= 0), canonical_tool_call TEXT NOT NULL, signature TEXT, approved INTEGER, reason TEXT, response_at INTEGER, UNIQUE(run_id,tool_call_id,journal_seq))");
126
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_approval_linkage (approval_id TEXT PRIMARY KEY, run_id TEXT NOT NULL, approval_epoch INTEGER NOT NULL CHECK(approval_epoch >= 0), tool_name TEXT NOT NULL, ordinal INTEGER NOT NULL CHECK(ordinal >= 0), journal_marker TEXT NOT NULL, provider_call_id TEXT NOT NULL, private_sequence INTEGER NOT NULL CHECK(private_sequence >= 0), canonical_tool_call TEXT NOT NULL, FOREIGN KEY(approval_id) REFERENCES __telnyx_agent_harness_approvals(id), FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs(id))");
127
+ }
128
+ export function ensureHarnessDurabilitySchema(ports) {
129
+ ports.sql.transactionSync(() => {
130
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_schema (version INTEGER PRIMARY KEY)");
131
+ const version = first(ports.sql.exec("SELECT version FROM __telnyx_agent_harness_schema ORDER BY version DESC LIMIT 1").toArray())?.version;
132
+ if (version !== undefined && version > SCHEMA_VERSION) {
133
+ throw new Error("harness ledger schema is newer than this harness");
134
+ }
135
+ if (version !== undefined && version < 1) {
136
+ throw new Error("harness ledger schema migration is unavailable");
137
+ }
138
+ let currentVersion = version;
139
+ let rebuiltV4ChildLedger = false;
140
+ if (currentVersion === undefined) {
141
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_runs (id TEXT PRIMARY KEY, key TEXT NOT NULL UNIQUE, input TEXT NOT NULL, input_bytes INTEGER NOT NULL, status TEXT NOT NULL CHECK(status IN ('accepted','running','awaiting_approval','resume_pending','completed','failed','canceled','outcome_unknown')), attempts INTEGER NOT NULL, task_id TEXT NOT NULL UNIQUE, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, failure_code TEXT)");
142
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_schema(version) VALUES (?)", SCHEMA_VERSION);
143
+ currentVersion = SCHEMA_VERSION;
144
+ }
145
+ else if (currentVersion === 1) {
146
+ ports.sql.exec("CREATE TABLE __telnyx_agent_harness_runs_v2 (id TEXT PRIMARY KEY, key TEXT NOT NULL UNIQUE, input TEXT NOT NULL, input_bytes INTEGER NOT NULL, status TEXT NOT NULL CHECK(status IN ('accepted','running','completed','failed','canceled','outcome_unknown')), attempts INTEGER NOT NULL, task_id TEXT NOT NULL UNIQUE, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, failure_code TEXT)");
147
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_runs_v2 SELECT id,key,input,input_bytes,status,attempts,task_id,created_at,updated_at,failure_code FROM __telnyx_agent_harness_runs");
148
+ ports.sql.exec("DROP TABLE __telnyx_agent_harness_runs");
149
+ ports.sql.exec("ALTER TABLE __telnyx_agent_harness_runs_v2 RENAME TO __telnyx_agent_harness_runs");
150
+ ports.sql.exec("UPDATE __telnyx_agent_harness_schema SET version = 2");
151
+ currentVersion = 2;
152
+ }
153
+ if (currentVersion !== undefined && currentVersion < APPROVAL_SCHEMA_VERSION) {
154
+ // Every pre-v6 run ledger has the legacy status CHECK. SQLite CHECK
155
+ // constraints cannot be altered in place, so rebuild it before v6
156
+ // introduces approval-only states. A populated child ledger would retain
157
+ // a foreign key to the dropped table; reject it before any migration
158
+ // write so callers can reconcile that history without partial state.
159
+ const childTables = [
160
+ "__telnyx_agent_harness_steps",
161
+ "__telnyx_agent_harness_tool_positions",
162
+ "__telnyx_agent_harness_tool_calls",
163
+ "__telnyx_agent_harness_run_authority",
164
+ "__telnyx_agent_harness_approvals",
165
+ "__telnyx_agent_harness_approval_messages",
166
+ "__telnyx_agent_harness_approval_audit",
167
+ "__telnyx_agent_harness_approval_linkage",
168
+ ];
169
+ const v4OwnedChildren = new Set([
170
+ "__telnyx_agent_harness_steps",
171
+ "__telnyx_agent_harness_tool_positions",
172
+ "__telnyx_agent_harness_tool_calls",
173
+ ]);
174
+ for (const table of childTables) {
175
+ const exists = ports.sql.exec("SELECT 1 AS present FROM sqlite_master WHERE type = 'table' AND name = ?", table).toArray().length > 0;
176
+ if ((currentVersion !== 4 || !v4OwnedChildren.has(table)) && exists && ports.sql.exec(`SELECT 1 AS present FROM ${table} LIMIT 1`).toArray().length > 0) {
177
+ throw new Error(`cannot migrate populated v${currentVersion} run ledger with child rows`);
178
+ }
179
+ }
180
+ ports.sql.exec("CREATE TABLE __telnyx_agent_harness_runs_v6 (id TEXT PRIMARY KEY, key TEXT NOT NULL UNIQUE, input TEXT NOT NULL, input_bytes INTEGER NOT NULL, status TEXT NOT NULL CHECK(status IN ('accepted','running','awaiting_approval','resume_pending','completed','failed','canceled','outcome_unknown')), attempts INTEGER NOT NULL, task_id TEXT NOT NULL UNIQUE, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, failure_code TEXT)");
181
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_runs_v6 SELECT id,key,input,input_bytes,status,attempts,task_id,created_at,updated_at,failure_code FROM __telnyx_agent_harness_runs");
182
+ if (currentVersion === 4) {
183
+ // v4 has a known, fully-owned child topology. Rebuild each child table
184
+ // against the v6 parent in this transaction, retaining its rows so the
185
+ // existing NULL-marker quarantine can run below without losing history.
186
+ ports.sql.exec("CREATE TABLE __telnyx_agent_harness_steps_v6 (run_id TEXT NOT NULL, name TEXT NOT NULL, identity TEXT NOT NULL, input_fingerprint TEXT NOT NULL, version TEXT NOT NULL, status TEXT NOT NULL CHECK(status IN ('prepared','effect_started','completed')), output TEXT, journal_seq INTEGER NOT NULL, PRIMARY KEY(run_id,name), UNIQUE(run_id,journal_seq), FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs_v6(id))");
187
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_steps_v6 SELECT run_id,name,identity,input_fingerprint,version,status,output,journal_seq FROM __telnyx_agent_harness_steps");
188
+ ports.sql.exec("CREATE TABLE __telnyx_agent_harness_tool_positions_v6 (run_id TEXT NOT NULL, tool_name TEXT NOT NULL, committed_count INTEGER NOT NULL CHECK(committed_count >= 0), PRIMARY KEY(run_id,tool_name), FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs_v6(id))");
189
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_tool_positions_v6 SELECT run_id,tool_name,committed_count FROM __telnyx_agent_harness_tool_positions");
190
+ ports.sql.exec("CREATE TABLE __telnyx_agent_harness_tool_calls_v6 (run_id TEXT NOT NULL, tool_name TEXT NOT NULL, ordinal INTEGER NOT NULL CHECK(ordinal >= 0), provider_call_id TEXT, journal_marker TEXT, PRIMARY KEY(run_id,tool_name,ordinal), FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs_v6(id))");
191
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_tool_calls_v6(run_id,tool_name,ordinal,provider_call_id) SELECT run_id,tool_name,ordinal,provider_call_id FROM __telnyx_agent_harness_tool_calls");
192
+ ports.sql.exec("DROP TABLE __telnyx_agent_harness_steps");
193
+ ports.sql.exec("DROP TABLE __telnyx_agent_harness_tool_positions");
194
+ ports.sql.exec("DROP TABLE __telnyx_agent_harness_tool_calls");
195
+ rebuiltV4ChildLedger = true;
196
+ }
197
+ ports.sql.exec("DROP TABLE __telnyx_agent_harness_runs");
198
+ ports.sql.exec("ALTER TABLE __telnyx_agent_harness_runs_v6 RENAME TO __telnyx_agent_harness_runs");
199
+ if (rebuiltV4ChildLedger) {
200
+ ports.sql.exec("ALTER TABLE __telnyx_agent_harness_steps_v6 RENAME TO __telnyx_agent_harness_steps");
201
+ ports.sql.exec("ALTER TABLE __telnyx_agent_harness_tool_positions_v6 RENAME TO __telnyx_agent_harness_tool_positions");
202
+ ports.sql.exec("ALTER TABLE __telnyx_agent_harness_tool_calls_v6 RENAME TO __telnyx_agent_harness_tool_calls");
203
+ }
204
+ }
205
+ if (currentVersion !== undefined && currentVersion < APPROVAL_SCHEMA_VERSION) {
206
+ // Approval records are v6-owned. Empty pre-v6 tables have no history to
207
+ // preserve, so replace them instead of stamping their incomplete shapes.
208
+ // Populated variants are rejected above before any migration write.
209
+ for (const table of [
210
+ "__telnyx_agent_harness_approval_linkage",
211
+ "__telnyx_agent_harness_approval_messages",
212
+ "__telnyx_agent_harness_approval_audit",
213
+ "__telnyx_agent_harness_approvals",
214
+ "__telnyx_agent_harness_run_authority",
215
+ ])
216
+ ports.sql.exec(`DROP TABLE IF EXISTS ${table}`);
217
+ }
218
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_steps (run_id TEXT NOT NULL, name TEXT NOT NULL, identity TEXT NOT NULL, input_fingerprint TEXT NOT NULL, version TEXT NOT NULL, status TEXT NOT NULL CHECK(status IN ('prepared','effect_started','completed')), output TEXT, output_failure TEXT, journal_seq INTEGER NOT NULL, PRIMARY KEY(run_id,name), UNIQUE(run_id,journal_seq), FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs(id))");
219
+ const stepColumns = ports.sql.exec("PRAGMA table_info(__telnyx_agent_harness_steps)").toArray();
220
+ if (!stepColumns.some((column) => column.name === "output_failure")) {
221
+ ports.sql.exec("ALTER TABLE __telnyx_agent_harness_steps ADD COLUMN output_failure TEXT");
222
+ }
223
+ if (currentVersion === 4) {
224
+ if (!rebuiltV4ChildLedger)
225
+ ports.sql.exec("ALTER TABLE __telnyx_agent_harness_tool_calls ADD COLUMN journal_marker TEXT");
226
+ // A v4 tool-call row has no harness-owned journal marker. After migration
227
+ // its journal_marker is NULL, which v5 treats as "pending" (not journaled).
228
+ // A nonterminal run with such a row could silently replay a stale memo
229
+ // (the provider legitimately re-emits the same tool/input, and the NULL
230
+ // marker lets nextToolCallOrdinal reuse the ordinal). Because v4 history
231
+ // has no harness-controlled marker and actor-global provider IDs are not
232
+ // authoritative, the journal state of these rows cannot be safely
233
+ // determined. Fail-closed: quarantine nonterminal runs that have v4
234
+ // tool-call rows as outcome_unknown before they can reuse a memo.
235
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'outcome_unknown', failure_code = 'HARNESS_OUTCOME_UNKNOWN', updated_at = ? WHERE status IN ('accepted','running') AND id IN (SELECT DISTINCT run_id FROM __telnyx_agent_harness_tool_calls)", ports.clock.now());
236
+ ports.sql.exec("UPDATE __telnyx_agent_harness_schema SET version = ?", APPROVAL_SCHEMA_VERSION);
237
+ }
238
+ else if (currentVersion === 2 || currentVersion === 3 || currentVersion === 5)
239
+ ports.sql.exec("UPDATE __telnyx_agent_harness_schema SET version = ?", APPROVAL_SCHEMA_VERSION);
240
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_tool_positions (run_id TEXT NOT NULL, tool_name TEXT NOT NULL, committed_count INTEGER NOT NULL CHECK(committed_count >= 0), PRIMARY KEY(run_id,tool_name), FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs(id))");
241
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_tool_calls (run_id TEXT NOT NULL, tool_name TEXT NOT NULL, ordinal INTEGER NOT NULL CHECK(ordinal >= 0), provider_call_id TEXT, journal_marker TEXT, PRIMARY KEY(run_id,tool_name,ordinal), FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs(id))");
242
+ // A harness turn records its final actor-journal boundary before the run
243
+ // completion transaction. Consumers that correlate durable admissions must
244
+ // join through this run-scoped marker, never infer from actor-global state.
245
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_run_journal (run_id TEXT PRIMARY KEY NOT NULL, journal_seq INTEGER NOT NULL CHECK(journal_seq >= 0), FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs(id))");
246
+ // Reserve the exact sequence where this run's admitted input belongs before
247
+ // appending it. Recovery can then determine whether the append committed.
248
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_run_inputs (run_id TEXT PRIMARY KEY NOT NULL, journal_seq INTEGER NOT NULL CHECK(journal_seq > 0), FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs(id))");
249
+ // v6 has no run-owned input boundary. Keep nonterminal v6 runs and accepted
250
+ // runs with a prior attempt in explicit migration state rather than
251
+ // interpreting a missing v7 marker as proof their input was never appended.
252
+ // The turn path can backfill only an exact tail match; every other legacy
253
+ // state fails closed. A never-attempted accepted run remains a fresh input.
254
+ ports.sql.exec("CREATE TABLE IF NOT EXISTS __telnyx_agent_harness_legacy_run_inputs (run_id TEXT PRIMARY KEY NOT NULL, FOREIGN KEY(run_id) REFERENCES __telnyx_agent_harness_runs(id))");
255
+ if (currentVersion !== undefined && currentVersion < SCHEMA_VERSION) {
256
+ ports.sql.exec("INSERT OR IGNORE INTO __telnyx_agent_harness_legacy_run_inputs(run_id) SELECT id FROM __telnyx_agent_harness_runs WHERE status IN ('running','awaiting_approval','resume_pending') OR (status = 'accepted' AND attempts > 0)");
257
+ }
258
+ createV6ApprovalTopology(ports);
259
+ ports.sql.exec("UPDATE __telnyx_agent_harness_schema SET version = ? WHERE version < ?", SCHEMA_VERSION, SCHEMA_VERSION);
260
+ });
261
+ }
262
+ const activeControllersByActivation = new WeakMap();
263
+ function activeControllers(ports) {
264
+ let controllers = activeControllersByActivation.get(ports.activation);
265
+ if (controllers === undefined) {
266
+ controllers = new Map();
267
+ activeControllersByActivation.set(ports.activation, controllers);
268
+ }
269
+ return controllers;
270
+ }
271
+ function assertDurableAdmissionPorts(ports) {
272
+ if (ports.version !== AGENT_HARNESS_PORTS_VERSION) {
273
+ throw new Error(`AgentHarnessPorts v${AGENT_HARNESS_PORTS_VERSION} is required for durable admission`);
274
+ }
275
+ if (ports.activation === null || (typeof ports.activation !== "object" && typeof ports.activation !== "function")) {
276
+ throw new Error("AgentHarnessPorts activation must be a host-owned object");
277
+ }
278
+ }
279
+ export function createHarnessRunLedger(ports, execute, options = {}) {
280
+ const execution = createHarnessRunExecutionLedger(ports, execute, options);
281
+ return Object.freeze({
282
+ accept: execution.accept,
283
+ get: execution.get,
284
+ status: execution.status,
285
+ list: execution.list,
286
+ cancel: execution.cancel,
287
+ recover: execution.recover,
288
+ run: execution.run,
289
+ dispatch: execution.dispatch,
290
+ });
291
+ }
292
+ export function createHarnessRunExecutionLedger(ports, execute, options = {}) {
293
+ let initialized = false;
294
+ let controllers;
295
+ const ensureInitialized = () => {
296
+ if (initialized)
297
+ return;
298
+ assertDurableAdmissionPorts(ports);
299
+ ensureHarnessDurabilitySchema(ports);
300
+ controllers = activeControllers(ports);
301
+ initialized = true;
302
+ };
303
+ // Port wrappers from one live activation share claims. A fresh activation has
304
+ // no in-memory claim and deliberately replays interrupted work.
305
+ const active = () => {
306
+ if (controllers === undefined)
307
+ throw new Error("harness ledger is not initialized");
308
+ return controllers;
309
+ };
310
+ const read = (runId) => first(ports.sql.exec("SELECT id,key,input,input_bytes,status,attempts,task_id,created_at,updated_at,failure_code FROM __telnyx_agent_harness_runs WHERE id = ?", runId).toArray());
311
+ const approvalRunReady = (runId) => {
312
+ const approvals = ports.sql.exec("SELECT approvals.id FROM __telnyx_agent_harness_approvals AS approvals JOIN __telnyx_agent_harness_approval_messages AS messages ON messages.approval_id = approvals.id WHERE approvals.run_id = ? AND messages.run_id = ? AND messages.approval_epoch = (SELECT MAX(approval_epoch) FROM __telnyx_agent_harness_approval_messages WHERE run_id = ?)", runId, runId, runId).toArray();
313
+ if (approvals.length === 0)
314
+ return false;
315
+ const messages = ports.sql.exec("SELECT approval_id FROM __telnyx_agent_harness_approval_messages WHERE run_id = ? AND approval_epoch = (SELECT MAX(approval_epoch) FROM __telnyx_agent_harness_approval_messages WHERE run_id = ?)", runId, runId).toArray();
316
+ if (messages.length !== approvals.length)
317
+ return false;
318
+ const incompleteApproval = ports.sql.exec("SELECT approvals.id FROM __telnyx_agent_harness_approvals AS approvals JOIN __telnyx_agent_harness_approval_messages AS messages ON messages.approval_id = approvals.id WHERE approvals.run_id = ? AND messages.run_id = ? AND messages.approval_epoch = (SELECT MAX(approval_epoch) FROM __telnyx_agent_harness_approval_messages WHERE run_id = ?) AND approvals.status NOT IN ('granted','denied') LIMIT 1", runId, runId, runId).toArray()[0];
319
+ const incompleteResponse = ports.sql.exec("SELECT approval_id FROM __telnyx_agent_harness_approval_messages WHERE run_id = ? AND approval_epoch = (SELECT MAX(approval_epoch) FROM __telnyx_agent_harness_approval_messages WHERE run_id = ?) AND approved IS NULL LIMIT 1", runId, runId).toArray()[0];
320
+ const invalidLinkage = ports.sql.exec("SELECT messages.approval_id FROM __telnyx_agent_harness_approval_messages AS messages LEFT JOIN __telnyx_agent_harness_approval_linkage AS linkage ON linkage.approval_id = messages.approval_id WHERE messages.run_id = ? AND messages.approval_epoch = (SELECT MAX(approval_epoch) FROM __telnyx_agent_harness_approval_messages WHERE run_id = ?) AND (linkage.approval_id IS NULL OR linkage.run_id <> messages.run_id OR linkage.approval_epoch <> messages.approval_epoch OR linkage.tool_name <> messages.tool_name OR linkage.provider_call_id <> messages.tool_call_id OR linkage.private_sequence <> messages.journal_seq OR linkage.ordinal <> messages.journal_seq OR linkage.journal_marker <> ('approval:' || messages.approval_id || ':' || messages.journal_seq) OR linkage.canonical_tool_call <> messages.canonical_tool_call) LIMIT 1", runId, runId).toArray()[0];
321
+ return incompleteApproval === undefined && incompleteResponse === undefined && invalidLinkage === undefined;
322
+ };
323
+ const approvalResumeBatch = (runId) => {
324
+ if (!approvalRunReady(runId))
325
+ return undefined;
326
+ const rows = ports.sql.exec("SELECT approvals.id,messages.approval_epoch FROM __telnyx_agent_harness_approvals AS approvals JOIN __telnyx_agent_harness_approval_messages AS messages ON messages.approval_id = approvals.id WHERE approvals.run_id = ? AND messages.run_id = ? AND messages.approval_epoch = (SELECT MAX(approval_epoch) FROM __telnyx_agent_harness_approval_messages WHERE run_id = ?) AND approvals.status IN ('granted','denied') AND messages.approved IS NOT NULL ORDER BY approvals.id", runId, runId, runId).toArray();
327
+ if (rows.length === 0)
328
+ return undefined;
329
+ return createHash("sha256").update([runId, String(rows[0].approval_epoch), ...rows.map((row) => row.id)].join("\0")).digest("hex");
330
+ };
331
+ const enqueue = async (run) => {
332
+ if (run.status !== "accepted")
333
+ return;
334
+ await ports.tasks.queue(TASK_METHOD, { runId: run.id }, { id: run.task_id, maxRetries: 5 });
335
+ };
336
+ const enqueueApprovalResume = async (run) => {
337
+ if (run.status !== "resume_pending")
338
+ return;
339
+ const batch = approvalResumeBatch(run.id);
340
+ if (batch === undefined)
341
+ return;
342
+ await ports.tasks.queue(APPROVAL_RESUME_TASK_METHOD, { runId: run.id, batch }, {
343
+ id: `${APPROVAL_RESUME_TASK_METHOD}/${batch}`,
344
+ maxRetries: 5,
345
+ });
346
+ };
347
+ let ledger;
348
+ ledger = {
349
+ async accept(input, acceptance) {
350
+ ensureInitialized();
351
+ requireBoundedString(input, "input", MAX_INPUT_BYTES);
352
+ requireNonblankBoundedString(acceptance.key, "idempotency key", MAX_KEY_BYTES);
353
+ const admission = ports.sql.transactionSync(() => {
354
+ const existing = first(ports.sql.exec("SELECT id,key,input,input_bytes,status,attempts,task_id,created_at,updated_at,failure_code FROM __telnyx_agent_harness_runs WHERE key = ?", acceptance.key).toArray());
355
+ if (existing !== undefined) {
356
+ if (existing.input !== input)
357
+ throw new Error("idempotency key is already bound to different input");
358
+ return Object.freeze({ run: existing, duplicate: true });
359
+ }
360
+ if (acceptance.admit !== undefined && !acceptance.admit())
361
+ throw new HarnessAdmissionRejected();
362
+ const now = ports.clock.now();
363
+ const id = `run-${ports.identity.id}-${now}-${crypto.randomUUID()}`;
364
+ const run = Object.freeze({
365
+ id, key: acceptance.key, input, input_bytes: Buffer.byteLength(input, "utf8"), status: "accepted",
366
+ attempts: 0, task_id: `${TASK_METHOD}/${id}`, created_at: now, updated_at: now, failure_code: null,
367
+ });
368
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_runs(id,key,input,input_bytes,status,attempts,task_id,created_at,updated_at,failure_code) VALUES (?,?,?,?,?,?,?,?,?,?)", run.id, run.key, run.input, run.input_bytes, run.status, run.attempts, run.task_id, run.created_at, run.updated_at, run.failure_code);
369
+ if (acceptance.journalSeq !== undefined) {
370
+ if (!Number.isSafeInteger(acceptance.journalSeq) || acceptance.journalSeq < 0)
371
+ throw new Error("journal sequence is invalid");
372
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_run_journal(run_id,journal_seq) VALUES (?,?)", run.id, acceptance.journalSeq);
373
+ }
374
+ const identity = ports.authorization?.identity();
375
+ if (options.requireApprovalIdentity && identity === undefined) {
376
+ throw Object.assign(new Error("Harness authorization identity_unavailable"), { code: "identity_unavailable" });
377
+ }
378
+ if (identity !== undefined) {
379
+ requireNonblankBoundedString(identity.serviceAccountId, "service account id", MAX_KEY_BYTES);
380
+ requireNonblankBoundedString(identity.organizationId, "organization id", MAX_KEY_BYTES);
381
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_run_authority(run_id,service_account_id,organization_id,required_action) VALUES (?,?,?,?)", run.id, identity.serviceAccountId, identity.organizationId, "agent_harness.run");
382
+ }
383
+ return Object.freeze({ run, duplicate: false });
384
+ });
385
+ // This is intentionally outside the SQL transaction: a queue failure leaves an accepted record for recover().
386
+ await enqueue(admission.run);
387
+ return Object.freeze({ runId: admission.run.id, duplicate: admission.duplicate, status: admission.run.status });
388
+ },
389
+ async get(runId) {
390
+ ensureInitialized();
391
+ const run = read(runId);
392
+ return run === undefined ? undefined : publicRun(run);
393
+ },
394
+ async status(runId) {
395
+ ensureInitialized();
396
+ return read(runId)?.status;
397
+ },
398
+ async list(options = {}) {
399
+ ensureInitialized();
400
+ const limit = options.limit ?? 100;
401
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1_000)
402
+ throw new Error("list limit must be 1..1000");
403
+ const rows = options.status === undefined
404
+ ? ports.sql.exec("SELECT id,key,input,input_bytes,status,attempts,task_id,created_at,updated_at,failure_code FROM __telnyx_agent_harness_runs ORDER BY created_at,id LIMIT ?", limit).toArray()
405
+ : ports.sql.exec("SELECT id,key,input,input_bytes,status,attempts,task_id,created_at,updated_at,failure_code FROM __telnyx_agent_harness_runs WHERE status = ? ORDER BY created_at,id LIMIT ?", options.status, limit).toArray();
406
+ return Object.freeze(rows.map(publicRun));
407
+ },
408
+ async cancel(runId) {
409
+ ensureInitialized();
410
+ const preExecutionCancellation = read(runId)?.status === "accepted";
411
+ const canceled = ports.sql.transactionSync(() => {
412
+ const current = read(runId);
413
+ if (current === undefined || current.status === "completed" || current.status === "failed" || current.status === "canceled" || current.status === "outcome_unknown")
414
+ return current;
415
+ const externalEffectStarted = ports.sql.exec("SELECT run_id FROM __telnyx_agent_harness_steps WHERE run_id = ? AND status = 'effect_started' LIMIT 1", runId).toArray().length > 0;
416
+ if (externalEffectStarted) {
417
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'outcome_unknown', failure_code = 'HARNESS_OUTCOME_UNKNOWN', updated_at = ? WHERE id = ? AND status IN ('accepted','running','awaiting_approval','resume_pending')", ports.clock.now(), runId);
418
+ }
419
+ else {
420
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'canceled', updated_at = ? WHERE id = ? AND status IN ('accepted','running','awaiting_approval','resume_pending')", ports.clock.now(), runId);
421
+ if (current.status === "accepted") {
422
+ // An accepted run has not entered execution, so sequence zero is
423
+ // its exact run-owned pre-execution boundary. Commit it with the
424
+ // terminal state so a read fault cannot lose correlation.
425
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_run_journal(run_id,journal_seq) VALUES (?,0) ON CONFLICT(run_id) DO NOTHING", runId);
426
+ }
427
+ }
428
+ return read(runId);
429
+ });
430
+ if (canceled === undefined)
431
+ return undefined;
432
+ active().get(runId)?.abort();
433
+ // Queue cancellation is best-effort; the durable canceled state fences later delivery.
434
+ try {
435
+ await ports.tasks.cancel(canceled.task_id);
436
+ }
437
+ catch { /* durable state is authoritative */ }
438
+ if (canceled.status === "canceled" && !preExecutionCancellation) {
439
+ // An executing or resumed run can already own journal entries, so
440
+ // preserve the existing exact-boundary capture after it is fenced.
441
+ // The terminal durable state is authoritative; recovery can repair
442
+ // this correlation if the journal read is temporarily unavailable.
443
+ try {
444
+ const journalBoundary = await ports.messages.count();
445
+ ports.sql.transactionSync(() => ports.sql.exec("INSERT INTO __telnyx_agent_harness_run_journal(run_id,journal_seq) VALUES (?,?) ON CONFLICT(run_id) DO NOTHING", runId, journalBoundary));
446
+ }
447
+ catch { /* retain durable cancellation; correlation is repairable */ }
448
+ }
449
+ return publicRun(canceled);
450
+ },
451
+ async recover() {
452
+ ensureInitialized();
453
+ const recovered = ports.sql.transactionSync(() => {
454
+ const uncertain = ports.sql.exec("SELECT DISTINCT runs.id FROM __telnyx_agent_harness_runs AS runs JOIN __telnyx_agent_harness_steps AS steps ON steps.run_id = runs.id WHERE runs.status IN ('accepted','running') AND steps.status = 'effect_started'").toArray();
455
+ for (const run of uncertain) {
456
+ if (active().has(run.id))
457
+ continue;
458
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'outcome_unknown', failure_code = 'HARNESS_OUTCOME_UNKNOWN', updated_at = ? WHERE id = ?", ports.clock.now(), run.id);
459
+ }
460
+ // A process crash may leave a running claim. Replaying it is explicitly at-least-once.
461
+ const interrupted = ports.sql.exec("SELECT id FROM __telnyx_agent_harness_runs WHERE status = 'running'").toArray();
462
+ for (const run of interrupted) {
463
+ if (active().has(run.id))
464
+ continue;
465
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'accepted', updated_at = ? WHERE id = ? AND status = 'running'", ports.clock.now(), run.id);
466
+ }
467
+ const recoveryExpiredApprovals = ports.sql.exec("SELECT id FROM __telnyx_agent_harness_approvals WHERE status IN ('pending','granted') AND expires_at <= ?", ports.clock.now()).toArray();
468
+ ports.sql.exec("UPDATE __telnyx_agent_harness_approvals SET status = 'expired', updated_at = ? WHERE status IN ('pending','granted') AND expires_at <= ?", ports.clock.now(), ports.clock.now());
469
+ for (const approval of recoveryExpiredApprovals) {
470
+ ports.sql.exec("INSERT INTO __telnyx_agent_harness_approval_audit(id,approval_id,event,actor,action,outcome,at,seq) VALUES (?,?,?,?,?,?,?,COALESCE((SELECT MAX(seq) FROM __telnyx_agent_harness_approval_audit WHERE approval_id = ?), 0) + 1)", crypto.randomUUID(), approval.id, "recovery_expiry_expired", null, "recovery_expiry", "expired", ports.clock.now(), approval.id);
471
+ }
472
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'failed', failure_code = 'HARNESS_APPROVAL_EXPIRED', updated_at = ? WHERE status IN ('awaiting_approval','resume_pending') AND EXISTS (SELECT 1 FROM __telnyx_agent_harness_approvals WHERE run_id = __telnyx_agent_harness_runs.id AND status = 'expired')", ports.clock.now());
473
+ return ports.sql.exec("SELECT id,key,input,input_bytes,status,attempts,task_id,created_at,updated_at,failure_code FROM __telnyx_agent_harness_runs WHERE status IN ('accepted','resume_pending') ORDER BY created_at,id").toArray();
474
+ });
475
+ for (const run of recovered) {
476
+ if (run.status === "accepted")
477
+ await enqueue(run);
478
+ else
479
+ await enqueueApprovalResume(run);
480
+ }
481
+ return recovered.length;
482
+ },
483
+ async resume(runId) {
484
+ ensureInitialized();
485
+ const resumed = ports.sql.transactionSync(() => {
486
+ const current = read(runId);
487
+ // A final approval decision commits resume_pending before this
488
+ // post-transaction path runs. It still needs deterministic task
489
+ // admission after the original task has been acknowledged/deleted.
490
+ if (current === undefined || current.status === "resume_pending")
491
+ return current;
492
+ if (current.status !== "awaiting_approval")
493
+ return current;
494
+ if (!approvalRunReady(runId))
495
+ return current;
496
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'resume_pending', updated_at = ? WHERE id = ? AND status = 'awaiting_approval'", ports.clock.now(), runId);
497
+ return read(runId);
498
+ });
499
+ if (resumed === undefined)
500
+ return undefined;
501
+ if (resumed.status !== "resume_pending")
502
+ return publicRun(resumed);
503
+ // A direct host dispatch can leave the original admission task visible
504
+ // until acknowledgement. Fence that sibling before admitting the
505
+ // distinct deterministic continuation task.
506
+ try {
507
+ await ports.tasks.cancel(resumed.task_id);
508
+ }
509
+ catch { /* the claim-time batch fence remains authoritative */ }
510
+ for (const task of await ports.tasks.list()) {
511
+ if (task.name !== APPROVAL_RESUME_TASK_METHOD || task.payload === null || typeof task.payload !== "object" || Array.isArray(task.payload))
512
+ continue;
513
+ const taskRunId = Object.getOwnPropertyDescriptor(task.payload, "runId");
514
+ if (taskRunId !== undefined && "value" in taskRunId && taskRunId.value === runId) {
515
+ try {
516
+ await ports.tasks.cancel(task.id);
517
+ }
518
+ catch { /* the current deterministic upsert remains fenced at claim time */ }
519
+ }
520
+ }
521
+ await enqueueApprovalResume(resumed);
522
+ return publicRun(resumed);
523
+ },
524
+ pauseForApproval(runId) {
525
+ ensureInitialized();
526
+ ports.sql.transactionSync(() => {
527
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'awaiting_approval', updated_at = ? WHERE id = ? AND status = 'running'", ports.clock.now(), runId);
528
+ if (read(runId)?.status !== "awaiting_approval")
529
+ throw new Error("approval run transition is invalid");
530
+ });
531
+ },
532
+ resumeForApproval(runId) {
533
+ ensureInitialized();
534
+ ports.sql.transactionSync(() => {
535
+ if (!approvalRunReady(runId))
536
+ return;
537
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'resume_pending', updated_at = ? WHERE id = ? AND status = 'awaiting_approval'", ports.clock.now(), runId);
538
+ if (read(runId)?.status !== "resume_pending")
539
+ throw new Error("approval run transition is invalid");
540
+ });
541
+ },
542
+ cancelForApproval(runId) {
543
+ ensureInitialized();
544
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'canceled', updated_at = ? WHERE id = ? AND status = 'awaiting_approval'", ports.clock.now(), runId);
545
+ if (read(runId)?.status !== "canceled")
546
+ throw new Error("approval run transition is invalid");
547
+ },
548
+ async expireForApproval(runId) {
549
+ ensureInitialized();
550
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'failed', failure_code = 'HARNESS_APPROVAL_EXPIRED', updated_at = ? WHERE id = ? AND status IN ('awaiting_approval','resume_pending')", ports.clock.now(), runId);
551
+ const expired = read(runId);
552
+ if (expired?.status !== "failed" || expired.failure_code !== "HARNESS_APPROVAL_EXPIRED") {
553
+ throw new Error("approval expiry transition is invalid");
554
+ }
555
+ try {
556
+ await ports.tasks.cancel(expired.task_id);
557
+ }
558
+ catch { /* terminal durable state fences late delivery */ }
559
+ },
560
+ async cleanupCanceledRun(runId) {
561
+ ensureInitialized();
562
+ const canceled = read(runId);
563
+ if (canceled === undefined)
564
+ return;
565
+ active().get(runId)?.abort();
566
+ // Queue cancellation is best-effort; the durable canceled state fences later delivery.
567
+ try {
568
+ await ports.tasks.cancel(canceled.task_id);
569
+ }
570
+ catch { /* durable state is authoritative */ }
571
+ },
572
+ async run(runId, resumeBatch) {
573
+ ensureInitialized();
574
+ const claimed = ports.sql.transactionSync(() => {
575
+ const current = read(runId);
576
+ if (current === undefined || (current.status !== "accepted" && current.status !== "resume_pending"))
577
+ return Object.freeze({ run: current, claimed: false, continuation: false });
578
+ if (current.status === "resume_pending" && (resumeBatch === undefined || approvalResumeBatch(runId) !== resumeBatch))
579
+ return Object.freeze({ run: current, claimed: false, continuation: false });
580
+ const continuation = current.status === "resume_pending" || current.attempts > 0;
581
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'running', attempts = attempts + 1, updated_at = ? WHERE id = ? AND status IN ('accepted','resume_pending')", ports.clock.now(), runId);
582
+ return Object.freeze({ run: read(runId), claimed: true, continuation });
583
+ });
584
+ if (!claimed.claimed || claimed.run === undefined) {
585
+ return claimed.run === undefined ? undefined : publicRun(claimed.run);
586
+ }
587
+ const controller = new AbortController();
588
+ active().set(runId, controller);
589
+ try {
590
+ await execute(claimed.run.input, controller.signal, createHarnessStepContext(ports, {
591
+ runId,
592
+ input: claimed.run.input,
593
+ version: "v1",
594
+ isContinuation: claimed.continuation,
595
+ checkpoints: options.checkpoints,
596
+ }));
597
+ try {
598
+ options.checkpoints?.("before_final_run_commit");
599
+ }
600
+ catch (error) {
601
+ throw new HarnessInjectedCrash(error);
602
+ }
603
+ const completed = ports.sql.transactionSync(() => {
604
+ if (read(runId)?.status === "running")
605
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'completed', updated_at = ? WHERE id = ?", ports.clock.now(), runId);
606
+ return read(runId);
607
+ });
608
+ return publicRun(completed);
609
+ }
610
+ catch (error) {
611
+ if (error instanceof HarnessInjectedCrash)
612
+ throw error;
613
+ const failed = ports.sql.transactionSync(() => {
614
+ if (error instanceof HarnessApprovalPause && read(runId)?.status === "running") {
615
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'awaiting_approval', updated_at = ? WHERE id = ? AND status = 'running'", ports.clock.now(), runId);
616
+ return read(runId);
617
+ }
618
+ const rolledBackScheduleStep = scheduleRollbackStep(error);
619
+ if (rolledBackScheduleStep !== undefined)
620
+ ports.sql.exec("UPDATE __telnyx_agent_harness_steps SET status = 'prepared' WHERE run_id = ? AND name = ? AND status = 'effect_started'", runId, rolledBackScheduleStep);
621
+ const uncertain = ports.sql.exec("SELECT run_id FROM __telnyx_agent_harness_steps WHERE run_id = ? AND status = 'effect_started' LIMIT 1", runId).toArray().length > 0;
622
+ if (read(runId)?.status === "running") {
623
+ if (uncertain) {
624
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'outcome_unknown', failure_code = 'HARNESS_OUTCOME_UNKNOWN', updated_at = ? WHERE id = ?", ports.clock.now(), runId);
625
+ }
626
+ else if (isPolicyUnavailable(error)) {
627
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'resume_pending', updated_at = ? WHERE id = ?", ports.clock.now(), runId);
628
+ }
629
+ else {
630
+ ports.sql.exec("UPDATE __telnyx_agent_harness_runs SET status = 'failed', failure_code = ?, updated_at = ? WHERE id = ?", failureCode(error), ports.clock.now(), runId);
631
+ }
632
+ }
633
+ return read(runId);
634
+ });
635
+ if (isPolicyUnavailable(error) && failed.status === "resume_pending")
636
+ await enqueueApprovalResume(failed);
637
+ return publicRun(failed);
638
+ }
639
+ finally {
640
+ active().delete(runId);
641
+ }
642
+ },
643
+ async dispatch(task) {
644
+ const dispatched = dispatchedRun(task);
645
+ return ledger.run(dispatched.runId, dispatched.batch);
646
+ },
647
+ };
648
+ return Object.freeze(ledger);
649
+ }
650
+ //# sourceMappingURL=durable.js.map