@tangle-network/agent-runtime 0.14.1 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -84
- package/dist/agent.d.ts +1 -1
- package/dist/index.d.ts +363 -5
- package/dist/index.js +433 -4
- package/dist/index.js.map +1 -1
- package/dist/{types-jr_EFhrD.d.ts → types-CYxfw14J.d.ts} +9 -0
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -293,6 +293,36 @@ function mapCommonBackendEvent(event, context) {
|
|
|
293
293
|
timestamp: nowIso()
|
|
294
294
|
};
|
|
295
295
|
}
|
|
296
|
+
if (type === "artifact") {
|
|
297
|
+
const artifactId = stringValue(data.artifactId) ?? stringValue(data.id) ?? stringValue(record.artifactId);
|
|
298
|
+
if (!artifactId) return void 0;
|
|
299
|
+
return {
|
|
300
|
+
type: "artifact",
|
|
301
|
+
task: context.task,
|
|
302
|
+
session: context.session,
|
|
303
|
+
artifactId,
|
|
304
|
+
name: stringValue(data.name) ?? stringValue(record.name),
|
|
305
|
+
mimeType: stringValue(data.mimeType) ?? stringValue(record.mimeType),
|
|
306
|
+
uri: stringValue(data.uri) ?? stringValue(record.uri),
|
|
307
|
+
content: stringValue(data.content) ?? stringValue(data.body) ?? stringValue(record.content),
|
|
308
|
+
metadata: data.metadata && typeof data.metadata === "object" ? data.metadata : void 0,
|
|
309
|
+
timestamp: nowIso()
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
if (type === "proposal_created" || type === "proposal" || type === "filing") {
|
|
313
|
+
const proposalId = stringValue(data.proposalId) ?? stringValue(data.id) ?? stringValue(record.proposalId);
|
|
314
|
+
if (!proposalId) return void 0;
|
|
315
|
+
const status = stringValue(data.status) ?? stringValue(record.status);
|
|
316
|
+
return {
|
|
317
|
+
type: "proposal_created",
|
|
318
|
+
task: context.task,
|
|
319
|
+
session: context.session,
|
|
320
|
+
proposalId,
|
|
321
|
+
title: stringValue(data.title) ?? stringValue(record.title) ?? proposalId,
|
|
322
|
+
status: status === "pending" || status === "approved" || status === "rejected" ? status : void 0,
|
|
323
|
+
timestamp: nowIso()
|
|
324
|
+
};
|
|
325
|
+
}
|
|
296
326
|
if (type === "result" || type === "final") {
|
|
297
327
|
const text = stringValue(data.finalText) ?? stringValue(data.text) ?? stringValue(record.text);
|
|
298
328
|
return text ? {
|
|
@@ -1010,6 +1040,29 @@ var D1DurableRunStore = class {
|
|
|
1010
1040
|
const row = await this.db.prepare("SELECT * FROM durable_events WHERE run_id = ? AND key = ?").bind(runId, key).first();
|
|
1011
1041
|
return row ? rowToEventRecord(row) : void 0;
|
|
1012
1042
|
}
|
|
1043
|
+
async appendStreamEvent(input) {
|
|
1044
|
+
const nowIso2 = new Date(this.now()).toISOString();
|
|
1045
|
+
const res = await this.db.prepare(
|
|
1046
|
+
`INSERT OR IGNORE INTO durable_stream_events (run_id, seq, event_id, payload_json, appended_at)
|
|
1047
|
+
VALUES (
|
|
1048
|
+
?,
|
|
1049
|
+
(SELECT COALESCE(MAX(seq), -1) + 1 FROM durable_stream_events WHERE run_id = ?),
|
|
1050
|
+
?, ?, ?
|
|
1051
|
+
)`
|
|
1052
|
+
).bind(input.runId, input.runId, input.eventId, JSON.stringify(input.payload ?? null), nowIso2).run();
|
|
1053
|
+
const accepted = (res.meta?.changes ?? 0) > 0;
|
|
1054
|
+
const row = await this.db.prepare("SELECT * FROM durable_stream_events WHERE run_id = ? AND event_id = ?").bind(input.runId, input.eventId).first();
|
|
1055
|
+
if (!row) throw new Error("durable-runs: appendStreamEvent failed to persist or read back");
|
|
1056
|
+
return { accepted, record: rowToStreamEventRecord(row) };
|
|
1057
|
+
}
|
|
1058
|
+
async readStreamEvents(runId, afterSeq) {
|
|
1059
|
+
const { results } = await this.db.prepare("SELECT * FROM durable_stream_events WHERE run_id = ? AND seq > ? ORDER BY seq").bind(runId, afterSeq ?? -1).all();
|
|
1060
|
+
return results.map(rowToStreamEventRecord);
|
|
1061
|
+
}
|
|
1062
|
+
async setRunHandle(input) {
|
|
1063
|
+
const nowIso2 = new Date(this.now()).toISOString();
|
|
1064
|
+
await this.db.prepare("UPDATE durable_runs SET handle_json = ?, updated_at = ? WHERE run_id = ?").bind(JSON.stringify(input.handle), nowIso2, input.runId).run();
|
|
1065
|
+
}
|
|
1013
1066
|
async close() {
|
|
1014
1067
|
}
|
|
1015
1068
|
/** Inspect the currently-applied schema version. */
|
|
@@ -1039,7 +1092,17 @@ function rowToRunRecord(row) {
|
|
|
1039
1092
|
leaseHolderId: row.lease_holder_id ?? void 0,
|
|
1040
1093
|
leaseExpiresAt: row.lease_expires_at ?? void 0,
|
|
1041
1094
|
outcome: row.outcome_json ? JSON.parse(row.outcome_json) : void 0,
|
|
1042
|
-
stepCount: row.step_count
|
|
1095
|
+
stepCount: row.step_count,
|
|
1096
|
+
handle: row.handle_json ? JSON.parse(row.handle_json) : void 0
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
function rowToStreamEventRecord(row) {
|
|
1100
|
+
return {
|
|
1101
|
+
runId: row.run_id,
|
|
1102
|
+
seq: row.seq,
|
|
1103
|
+
eventId: row.event_id,
|
|
1104
|
+
payload: row.payload_json ? JSON.parse(row.payload_json) : null,
|
|
1105
|
+
appendedAt: row.appended_at
|
|
1043
1106
|
};
|
|
1044
1107
|
}
|
|
1045
1108
|
function rowToStepRecord(row) {
|
|
@@ -1104,6 +1167,7 @@ var FileSystemDurableRunStore = class {
|
|
|
1104
1167
|
await this.writeLease(input.runId, { workerId: input.workerId, leaseExpiresAt });
|
|
1105
1168
|
await appendFile(join(dir, "steps.jsonl"), "", "utf8");
|
|
1106
1169
|
await appendFile(join(dir, "events.jsonl"), "", "utf8");
|
|
1170
|
+
await appendFile(join(dir, "stream-events.jsonl"), "", "utf8");
|
|
1107
1171
|
return { run: record2, completedSteps: [], leaseExpiresAt };
|
|
1108
1172
|
}
|
|
1109
1173
|
const record = await this.readRun(input.runId);
|
|
@@ -1266,8 +1330,48 @@ var FileSystemDurableRunStore = class {
|
|
|
1266
1330
|
}
|
|
1267
1331
|
return void 0;
|
|
1268
1332
|
}
|
|
1333
|
+
async appendStreamEvent(input) {
|
|
1334
|
+
const existing = await this.readStreamEventsRaw(input.runId);
|
|
1335
|
+
const dup = existing.find((e) => e.eventId === input.eventId);
|
|
1336
|
+
if (dup) return { accepted: false, record: dup };
|
|
1337
|
+
const rec = {
|
|
1338
|
+
runId: input.runId,
|
|
1339
|
+
seq: existing.length,
|
|
1340
|
+
eventId: input.eventId,
|
|
1341
|
+
payload: input.payload,
|
|
1342
|
+
appendedAt: new Date(this.now()).toISOString()
|
|
1343
|
+
};
|
|
1344
|
+
await appendFile(
|
|
1345
|
+
join(this.runDir(input.runId), "stream-events.jsonl"),
|
|
1346
|
+
`${JSON.stringify(rec)}
|
|
1347
|
+
`,
|
|
1348
|
+
"utf8"
|
|
1349
|
+
);
|
|
1350
|
+
return { accepted: true, record: rec };
|
|
1351
|
+
}
|
|
1352
|
+
async readStreamEvents(runId, afterSeq) {
|
|
1353
|
+
const cutoff = afterSeq ?? -1;
|
|
1354
|
+
return (await this.readStreamEventsRaw(runId)).filter((e) => e.seq > cutoff);
|
|
1355
|
+
}
|
|
1356
|
+
async setRunHandle(input) {
|
|
1357
|
+
const record = await this.readRun(input.runId);
|
|
1358
|
+
record.handle = input.handle;
|
|
1359
|
+
record.updatedAt = new Date(this.now()).toISOString();
|
|
1360
|
+
await this.writeRun(record);
|
|
1361
|
+
}
|
|
1269
1362
|
async close() {
|
|
1270
1363
|
}
|
|
1364
|
+
async readStreamEventsRaw(runId) {
|
|
1365
|
+
const path = join(this.runDir(runId), "stream-events.jsonl");
|
|
1366
|
+
if (!existsSync(path)) return [];
|
|
1367
|
+
const content = await readFile(path, "utf8");
|
|
1368
|
+
const out = [];
|
|
1369
|
+
for (const line of content.split("\n")) {
|
|
1370
|
+
if (!line) continue;
|
|
1371
|
+
out.push(JSON.parse(line));
|
|
1372
|
+
}
|
|
1373
|
+
return out.sort((a, b) => a.seq - b.seq);
|
|
1374
|
+
}
|
|
1271
1375
|
/** @internal — used by tests to list runs in the store. */
|
|
1272
1376
|
async _listRunIds() {
|
|
1273
1377
|
if (!existsSync(this.root)) return [];
|
|
@@ -1363,7 +1467,7 @@ var InMemoryDurableRunStore = class {
|
|
|
1363
1467
|
leaseExpiresAt,
|
|
1364
1468
|
stepCount: 0
|
|
1365
1469
|
};
|
|
1366
|
-
state = { record, steps: /* @__PURE__ */ new Map(), events: /* @__PURE__ */ new Map() };
|
|
1470
|
+
state = { record, steps: /* @__PURE__ */ new Map(), events: /* @__PURE__ */ new Map(), streamEvents: [] };
|
|
1367
1471
|
this.runs.set(input.runId, state);
|
|
1368
1472
|
return { run: { ...record }, completedSteps: [], leaseExpiresAt };
|
|
1369
1473
|
}
|
|
@@ -1504,6 +1608,31 @@ var InMemoryDurableRunStore = class {
|
|
|
1504
1608
|
const rec = state.events.get(key);
|
|
1505
1609
|
return rec ? { ...rec } : void 0;
|
|
1506
1610
|
}
|
|
1611
|
+
async appendStreamEvent(input) {
|
|
1612
|
+
const state = this.requireRun(input.runId);
|
|
1613
|
+
const existing = state.streamEvents.find((e) => e.eventId === input.eventId);
|
|
1614
|
+
if (existing) return { accepted: false, record: { ...existing } };
|
|
1615
|
+
const rec = {
|
|
1616
|
+
runId: input.runId,
|
|
1617
|
+
seq: state.streamEvents.length,
|
|
1618
|
+
eventId: input.eventId,
|
|
1619
|
+
payload: input.payload,
|
|
1620
|
+
appendedAt: new Date(this.now()).toISOString()
|
|
1621
|
+
};
|
|
1622
|
+
state.streamEvents.push(rec);
|
|
1623
|
+
return { accepted: true, record: { ...rec } };
|
|
1624
|
+
}
|
|
1625
|
+
async readStreamEvents(runId, afterSeq) {
|
|
1626
|
+
const state = this.runs.get(runId);
|
|
1627
|
+
if (!state) return [];
|
|
1628
|
+
const cutoff = afterSeq ?? -1;
|
|
1629
|
+
return state.streamEvents.filter((e) => e.seq > cutoff).map((e) => ({ ...e }));
|
|
1630
|
+
}
|
|
1631
|
+
async setRunHandle(input) {
|
|
1632
|
+
const state = this.requireRun(input.runId);
|
|
1633
|
+
state.record.handle = { ...input.handle };
|
|
1634
|
+
state.record.updatedAt = new Date(this.now()).toISOString();
|
|
1635
|
+
}
|
|
1507
1636
|
async close() {
|
|
1508
1637
|
this.runs.clear();
|
|
1509
1638
|
}
|
|
@@ -1763,7 +1892,7 @@ function cryptoRandomUuid() {
|
|
|
1763
1892
|
}
|
|
1764
1893
|
|
|
1765
1894
|
// src/durable/schema.ts
|
|
1766
|
-
var DURABLE_SCHEMA_VERSION =
|
|
1895
|
+
var DURABLE_SCHEMA_VERSION = 2;
|
|
1767
1896
|
var DURABLE_SCHEMA_SQL = `-- Durable-run substrate \u2014 versioned schema for D1 / SQLite.
|
|
1768
1897
|
--
|
|
1769
1898
|
-- Apply once per database. Subsequent migrations append; never rewrite a
|
|
@@ -1831,8 +1960,198 @@ CREATE TABLE IF NOT EXISTS durable_events (
|
|
|
1831
1960
|
|
|
1832
1961
|
INSERT OR IGNORE INTO durable_schema_info (version, applied_at)
|
|
1833
1962
|
VALUES (1, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'));
|
|
1963
|
+
|
|
1964
|
+
-- \u2500\u2500 Migration v2 \u2014 durable event-stream log + run handle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1965
|
+
-- Run once on a database created at v1. \`ALTER TABLE\` is not idempotent; the
|
|
1966
|
+
-- version trail in \`durable_schema_info\` is how migrations are sequenced \u2014
|
|
1967
|
+
-- never by blind re-execution of this block.
|
|
1968
|
+
--
|
|
1969
|
+
-- - \`durable_stream_events\` is the ordered, replayable per-run event log.
|
|
1970
|
+
-- \`seq\` is the store-assigned monotonic cursor; the UNIQUE index on
|
|
1971
|
+
-- (run_id, event_id) makes appends idempotent \u2014 a reconnecting adapter
|
|
1972
|
+
-- that re-yields a boundary event cannot double-log it.
|
|
1973
|
+
-- - \`durable_runs.handle_json\` is the pointer (sandbox + substrate run id +
|
|
1974
|
+
-- cursor) a fresh supervisor re-attaches by.
|
|
1975
|
+
|
|
1976
|
+
ALTER TABLE durable_runs ADD COLUMN handle_json TEXT;
|
|
1977
|
+
|
|
1978
|
+
CREATE TABLE IF NOT EXISTS durable_stream_events (
|
|
1979
|
+
run_id TEXT NOT NULL,
|
|
1980
|
+
seq INTEGER NOT NULL,
|
|
1981
|
+
event_id TEXT NOT NULL,
|
|
1982
|
+
payload_json TEXT,
|
|
1983
|
+
appended_at TEXT NOT NULL,
|
|
1984
|
+
PRIMARY KEY (run_id, seq)
|
|
1985
|
+
);
|
|
1986
|
+
|
|
1987
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_durable_stream_events_event_id
|
|
1988
|
+
ON durable_stream_events(run_id, event_id);
|
|
1989
|
+
|
|
1990
|
+
INSERT OR IGNORE INTO durable_schema_info (version, applied_at)
|
|
1991
|
+
VALUES (2, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'));
|
|
1834
1992
|
`;
|
|
1835
1993
|
|
|
1994
|
+
// src/durable/supervisor.ts
|
|
1995
|
+
var TURN_STEP = 0;
|
|
1996
|
+
function runSupervisedTurn(options) {
|
|
1997
|
+
const { store, runId, manifest, workerId, adapter } = options;
|
|
1998
|
+
const leaseMs = options.leaseMs ?? 6e4;
|
|
1999
|
+
const heartbeatMs = options.heartbeatMs ?? 3e4;
|
|
2000
|
+
const intent = options.intent ?? "turn";
|
|
2001
|
+
const now = options.now ?? (() => Date.now());
|
|
2002
|
+
const inputHash = canonicalHash(manifest.input);
|
|
2003
|
+
let mode = "fresh";
|
|
2004
|
+
let finalRecord;
|
|
2005
|
+
let currentHandle;
|
|
2006
|
+
let leaseLost = false;
|
|
2007
|
+
async function* drain(source) {
|
|
2008
|
+
let lastRenew = now();
|
|
2009
|
+
for await (const event of source) {
|
|
2010
|
+
if (event.handle) {
|
|
2011
|
+
currentHandle = event.handle;
|
|
2012
|
+
await store.setRunHandle({ runId, handle: event.handle });
|
|
2013
|
+
}
|
|
2014
|
+
const { accepted } = await store.appendStreamEvent({
|
|
2015
|
+
runId,
|
|
2016
|
+
eventId: event.eventId,
|
|
2017
|
+
payload: event.payload
|
|
2018
|
+
});
|
|
2019
|
+
if (now() - lastRenew >= heartbeatMs) {
|
|
2020
|
+
const renewed = await store.renewLease({ runId, workerId, leaseMs });
|
|
2021
|
+
if (!renewed.ok) {
|
|
2022
|
+
leaseLost = true;
|
|
2023
|
+
throw new Error(`durable-runs: lease lost on ${runId} \u2014 another supervisor took over`);
|
|
2024
|
+
}
|
|
2025
|
+
lastRenew = now();
|
|
2026
|
+
}
|
|
2027
|
+
if (accepted) yield event.payload;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
async function* stream() {
|
|
2031
|
+
const { run, completedSteps } = await store.startOrResume({
|
|
2032
|
+
runId,
|
|
2033
|
+
manifest,
|
|
2034
|
+
workerId,
|
|
2035
|
+
leaseMs
|
|
2036
|
+
});
|
|
2037
|
+
if (completedSteps.some((s) => s.stepIndex === TURN_STEP && s.status === "completed")) {
|
|
2038
|
+
mode = "replayed";
|
|
2039
|
+
for (const e of await store.readStreamEvents(runId)) yield e.payload;
|
|
2040
|
+
finalRecord = await store.endRun({ runId, workerId, status: "completed" });
|
|
2041
|
+
return;
|
|
2042
|
+
}
|
|
2043
|
+
const logged = await store.readStreamEvents(runId);
|
|
2044
|
+
const priorHandle = run.handle;
|
|
2045
|
+
const resumable = priorHandle !== void 0 && priorHandle.status === "running" && typeof priorHandle.runId === "string";
|
|
2046
|
+
let source;
|
|
2047
|
+
if (resumable && priorHandle) {
|
|
2048
|
+
mode = "resumed";
|
|
2049
|
+
currentHandle = priorHandle;
|
|
2050
|
+
for (const e of logged) yield e.payload;
|
|
2051
|
+
const cursor = logged.length > 0 ? logged[logged.length - 1].eventId : priorHandle.cursor;
|
|
2052
|
+
source = adapter.attach(priorHandle, cursor);
|
|
2053
|
+
} else {
|
|
2054
|
+
mode = "fresh";
|
|
2055
|
+
source = adapter.start();
|
|
2056
|
+
}
|
|
2057
|
+
await store.beginStep({ runId, stepIndex: TURN_STEP, intent, kind: "llm", inputHash });
|
|
2058
|
+
try {
|
|
2059
|
+
yield* drain(source);
|
|
2060
|
+
const eventCount = (await store.readStreamEvents(runId)).length;
|
|
2061
|
+
await store.completeStep({ runId, stepIndex: TURN_STEP, result: { eventCount } });
|
|
2062
|
+
if (currentHandle && currentHandle.status === "running") {
|
|
2063
|
+
await store.setRunHandle({ runId, handle: { ...currentHandle, status: "completed" } });
|
|
2064
|
+
}
|
|
2065
|
+
finalRecord = await store.endRun({
|
|
2066
|
+
runId,
|
|
2067
|
+
workerId,
|
|
2068
|
+
status: "completed",
|
|
2069
|
+
outcome: { notes: intent, metadata: { events: eventCount, mode } }
|
|
2070
|
+
});
|
|
2071
|
+
} catch (err) {
|
|
2072
|
+
if (!leaseLost) {
|
|
2073
|
+
await store.failStep({
|
|
2074
|
+
runId,
|
|
2075
|
+
stepIndex: TURN_STEP,
|
|
2076
|
+
error: { message: err instanceof Error ? err.message : String(err) }
|
|
2077
|
+
});
|
|
2078
|
+
finalRecord = await store.endRun({ runId, workerId, status: "failed" });
|
|
2079
|
+
}
|
|
2080
|
+
throw err;
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
return {
|
|
2084
|
+
stream: stream(),
|
|
2085
|
+
mode: () => mode,
|
|
2086
|
+
record: () => finalRecord
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
// src/durable/session-supervisor-do.ts
|
|
2091
|
+
var ACTIVE_RUN_KEY = "agent-runtime:active-run-id";
|
|
2092
|
+
async function drainHeadless(stream) {
|
|
2093
|
+
let next = await stream.next();
|
|
2094
|
+
while (!next.done) next = await stream.next();
|
|
2095
|
+
}
|
|
2096
|
+
function createSessionSupervisorDO(config) {
|
|
2097
|
+
const orphanCheckMs = config.orphanCheckMs ?? 6e4;
|
|
2098
|
+
const now = config.now ?? (() => Date.now());
|
|
2099
|
+
return class {
|
|
2100
|
+
constructor(state, env) {
|
|
2101
|
+
this.state = state;
|
|
2102
|
+
this.env = env;
|
|
2103
|
+
}
|
|
2104
|
+
state;
|
|
2105
|
+
env;
|
|
2106
|
+
async fetch(request) {
|
|
2107
|
+
const opts = await config.resolveRun(request, this.env, this.state);
|
|
2108
|
+
if (!opts) return new Response("no run for this request", { status: 404 });
|
|
2109
|
+
await this.state.storage.put(ACTIVE_RUN_KEY, opts.runId);
|
|
2110
|
+
await this.state.storage.setAlarm(now() + orphanCheckMs);
|
|
2111
|
+
const supervised = runSupervisedTurn(opts);
|
|
2112
|
+
const storage = this.state.storage;
|
|
2113
|
+
const encoder2 = new TextEncoder();
|
|
2114
|
+
const body = new ReadableStream({
|
|
2115
|
+
async pull(controller) {
|
|
2116
|
+
try {
|
|
2117
|
+
const next = await supervised.stream.next();
|
|
2118
|
+
if (next.done) {
|
|
2119
|
+
await storage.delete(ACTIVE_RUN_KEY);
|
|
2120
|
+
controller.close();
|
|
2121
|
+
return;
|
|
2122
|
+
}
|
|
2123
|
+
controller.enqueue(encoder2.encode(config.encodeEvent(next.value)));
|
|
2124
|
+
} catch (err) {
|
|
2125
|
+
controller.error(err instanceof Error ? err : new Error(String(err)));
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
});
|
|
2129
|
+
return new Response(body, {
|
|
2130
|
+
headers: { "content-type": "text/event-stream", "cache-control": "no-cache" }
|
|
2131
|
+
});
|
|
2132
|
+
}
|
|
2133
|
+
async alarm() {
|
|
2134
|
+
const runId = await this.state.storage.get(ACTIVE_RUN_KEY);
|
|
2135
|
+
if (!runId) return;
|
|
2136
|
+
const opts = await config.resolveOrphan(runId, this.env, this.state);
|
|
2137
|
+
if (!opts) {
|
|
2138
|
+
await this.state.storage.delete(ACTIVE_RUN_KEY);
|
|
2139
|
+
return;
|
|
2140
|
+
}
|
|
2141
|
+
try {
|
|
2142
|
+
await drainHeadless(runSupervisedTurn(opts).stream);
|
|
2143
|
+
await this.state.storage.delete(ACTIVE_RUN_KEY);
|
|
2144
|
+
} catch (err) {
|
|
2145
|
+
if (err instanceof DurableRunLeaseHeldError) {
|
|
2146
|
+
await this.state.storage.setAlarm(now() + orphanCheckMs);
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
await this.state.storage.delete(ACTIVE_RUN_KEY);
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
};
|
|
2153
|
+
}
|
|
2154
|
+
|
|
1836
2155
|
// src/durable/workflows.ts
|
|
1837
2156
|
async function runOnWorkflowStep(workflowStep, input) {
|
|
1838
2157
|
const stepCfg = input.stepConfig;
|
|
@@ -1953,6 +2272,85 @@ function classifyIntent(profile, message, opts = {}) {
|
|
|
1953
2272
|
return { id: bestId, subagent: bestSubagent, score: bestScore, scores, evaluated };
|
|
1954
2273
|
}
|
|
1955
2274
|
|
|
2275
|
+
// src/model-resolution.ts
|
|
2276
|
+
var DEFAULT_ROUTER_BASE_URL = "https://router.tangle.tools";
|
|
2277
|
+
function resolveRouterBaseUrl(env = {}) {
|
|
2278
|
+
return (env.TANGLE_ROUTER_URL ?? env.TANGLE_ROUTER_BASE_URL ?? DEFAULT_ROUTER_BASE_URL).replace(/\/v1\/?$/, "").replace(/\/$/, "");
|
|
2279
|
+
}
|
|
2280
|
+
async function getModels(routerBaseUrl = DEFAULT_ROUTER_BASE_URL) {
|
|
2281
|
+
const res = await fetch(`${routerBaseUrl}/v1/models`, {
|
|
2282
|
+
headers: { Accept: "application/json" }
|
|
2283
|
+
});
|
|
2284
|
+
if (!res.ok) throw new Error(`router /v1/models ${res.status}`);
|
|
2285
|
+
const body = await res.json();
|
|
2286
|
+
return Array.isArray(body.data) ? body.data : [];
|
|
2287
|
+
}
|
|
2288
|
+
function withConfiguredModels(models, extraIds) {
|
|
2289
|
+
const known = new Set(models.map((model) => model.id));
|
|
2290
|
+
const extra = extraIds.map((id) => cleanModelId(id)).filter((id) => id !== void 0 && !known.has(id)).map(
|
|
2291
|
+
(id) => ({
|
|
2292
|
+
id,
|
|
2293
|
+
name: id,
|
|
2294
|
+
description: "Configured chat model for this environment.",
|
|
2295
|
+
architecture: {
|
|
2296
|
+
modality: "text->text",
|
|
2297
|
+
input_modalities: ["text"],
|
|
2298
|
+
output_modalities: ["text"]
|
|
2299
|
+
}
|
|
2300
|
+
})
|
|
2301
|
+
);
|
|
2302
|
+
return extra.length > 0 ? [...extra, ...models] : models;
|
|
2303
|
+
}
|
|
2304
|
+
function cleanModelId(value) {
|
|
2305
|
+
if (typeof value !== "string") return void 0;
|
|
2306
|
+
const trimmed = value.trim();
|
|
2307
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
2308
|
+
}
|
|
2309
|
+
function resolveChatModel(candidates, fallback) {
|
|
2310
|
+
for (const candidate of candidates) {
|
|
2311
|
+
const model = cleanModelId(candidate.model);
|
|
2312
|
+
if (model) return { source: candidate.source, model };
|
|
2313
|
+
}
|
|
2314
|
+
return fallback;
|
|
2315
|
+
}
|
|
2316
|
+
var WELL_FORMED_MODEL_ID = /^[A-Za-z0-9._/@:-]+$/;
|
|
2317
|
+
function isWellFormedModelId(modelId) {
|
|
2318
|
+
return modelId.length <= 200 && WELL_FORMED_MODEL_ID.test(modelId);
|
|
2319
|
+
}
|
|
2320
|
+
function catalogIdsForModel(model) {
|
|
2321
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2322
|
+
const id = cleanModelId(model.id);
|
|
2323
|
+
if (id) ids.add(id);
|
|
2324
|
+
const provider = cleanModelId(model._provider) ?? cleanModelId(model.provider);
|
|
2325
|
+
if (provider && id && !id.includes("/")) ids.add(`${provider}/${id}`);
|
|
2326
|
+
return [...ids];
|
|
2327
|
+
}
|
|
2328
|
+
async function validateChatModelId(modelId, options = {}) {
|
|
2329
|
+
const {
|
|
2330
|
+
allowlist = [],
|
|
2331
|
+
routerBaseUrl = DEFAULT_ROUTER_BASE_URL,
|
|
2332
|
+
loadModels = getModels
|
|
2333
|
+
} = options;
|
|
2334
|
+
const cleaned = cleanModelId(modelId);
|
|
2335
|
+
if (!cleaned) return { succeeded: false, error: "Model id must be a non-empty string." };
|
|
2336
|
+
if (!isWellFormedModelId(cleaned)) {
|
|
2337
|
+
return { succeeded: false, error: `Model id is malformed: ${cleaned}` };
|
|
2338
|
+
}
|
|
2339
|
+
if (allowlist.some((id) => cleanModelId(id) === cleaned)) {
|
|
2340
|
+
return { succeeded: true, value: cleaned };
|
|
2341
|
+
}
|
|
2342
|
+
let catalog;
|
|
2343
|
+
try {
|
|
2344
|
+
catalog = await loadModels(routerBaseUrl);
|
|
2345
|
+
} catch (err) {
|
|
2346
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2347
|
+
return { succeeded: false, error: `Could not validate model catalog: ${message}` };
|
|
2348
|
+
}
|
|
2349
|
+
const ids = new Set(catalog.flatMap(catalogIdsForModel));
|
|
2350
|
+
if (!ids.has(cleaned)) return { succeeded: false, error: `Model is not available: ${cleaned}` };
|
|
2351
|
+
return { succeeded: true, value: cleaned };
|
|
2352
|
+
}
|
|
2353
|
+
|
|
1956
2354
|
// src/profile-conformance.ts
|
|
1957
2355
|
var DEFAULT_SHELL_CAPS = [
|
|
1958
2356
|
"bash",
|
|
@@ -2726,9 +3124,21 @@ function sanitizeRuntimeStreamEvent(event, options = {}) {
|
|
|
2726
3124
|
name: event.name,
|
|
2727
3125
|
mimeType: event.mimeType,
|
|
2728
3126
|
uri: options.includeEvidenceIds ? event.uri : void 0,
|
|
3127
|
+
content: options.includeControlPayloads ? event.content : void 0,
|
|
2729
3128
|
metadata: options.includeMetadata ? event.metadata : void 0
|
|
2730
3129
|
};
|
|
2731
3130
|
}
|
|
3131
|
+
if (event.type === "proposal_created") {
|
|
3132
|
+
return {
|
|
3133
|
+
type: event.type,
|
|
3134
|
+
...withTask,
|
|
3135
|
+
...withSession,
|
|
3136
|
+
timestamp: event.timestamp,
|
|
3137
|
+
proposalId: event.proposalId,
|
|
3138
|
+
title: options.includeControlPayloads ? event.title : void 0,
|
|
3139
|
+
status: event.status
|
|
3140
|
+
};
|
|
3141
|
+
}
|
|
2732
3142
|
if (event.type === "final") {
|
|
2733
3143
|
return {
|
|
2734
3144
|
type: event.type,
|
|
@@ -3102,6 +3512,16 @@ function projectToTraceEvent(event) {
|
|
|
3102
3512
|
mimeType: event.mimeType
|
|
3103
3513
|
}
|
|
3104
3514
|
};
|
|
3515
|
+
case "proposal_created":
|
|
3516
|
+
return {
|
|
3517
|
+
kind: "state_mutation",
|
|
3518
|
+
payload: {
|
|
3519
|
+
phase: "proposal_created",
|
|
3520
|
+
proposalId: event.proposalId,
|
|
3521
|
+
title: event.title,
|
|
3522
|
+
status: event.status
|
|
3523
|
+
}
|
|
3524
|
+
};
|
|
3105
3525
|
case "task_end":
|
|
3106
3526
|
return {
|
|
3107
3527
|
kind: event.status === "failed" || event.status === "aborted" ? "error" : "log",
|
|
@@ -3135,6 +3555,7 @@ export {
|
|
|
3135
3555
|
ChatTurnError,
|
|
3136
3556
|
ConfigError,
|
|
3137
3557
|
D1DurableRunStore,
|
|
3558
|
+
DEFAULT_ROUTER_BASE_URL,
|
|
3138
3559
|
DURABLE_SCHEMA_SQL,
|
|
3139
3560
|
DURABLE_SCHEMA_VERSION,
|
|
3140
3561
|
DurableAwaitEventTimeoutError,
|
|
@@ -3157,25 +3578,31 @@ export {
|
|
|
3157
3578
|
canonicalHash,
|
|
3158
3579
|
canonicalJson,
|
|
3159
3580
|
classifyIntent,
|
|
3581
|
+
cleanModelId,
|
|
3160
3582
|
composeTurnProfile,
|
|
3161
3583
|
createIterableBackend,
|
|
3162
3584
|
createOpenAICompatibleBackend,
|
|
3163
3585
|
createRuntimeEventCollector,
|
|
3164
3586
|
createRuntimeStreamEventCollector,
|
|
3165
3587
|
createSandboxPromptBackend,
|
|
3588
|
+
createSessionSupervisorDO,
|
|
3166
3589
|
createTraceBridge,
|
|
3167
3590
|
decideKnowledgeReadiness,
|
|
3168
3591
|
deriveWorkerId,
|
|
3169
3592
|
durableChatTurnEngine,
|
|
3170
3593
|
encodeServerSentEvent,
|
|
3594
|
+
getModels,
|
|
3171
3595
|
manifestHash,
|
|
3172
3596
|
readinessServerSentEvent,
|
|
3597
|
+
resolveChatModel,
|
|
3598
|
+
resolveRouterBaseUrl,
|
|
3173
3599
|
runAgentTask,
|
|
3174
3600
|
runAgentTaskStream,
|
|
3175
3601
|
runChatTurn,
|
|
3176
3602
|
runDurable,
|
|
3177
3603
|
runDurableTurn,
|
|
3178
3604
|
runOnWorkflowStep,
|
|
3605
|
+
runSupervisedTurn,
|
|
3179
3606
|
runtimeStreamServerSentEvent,
|
|
3180
3607
|
sandboxAsChatTurnTarget,
|
|
3181
3608
|
sanitizeAgentRuntimeEvent,
|
|
@@ -3184,6 +3611,8 @@ export {
|
|
|
3184
3611
|
startRuntimeRun,
|
|
3185
3612
|
stepId,
|
|
3186
3613
|
summarizeAgentTaskRun,
|
|
3187
|
-
toAgentEvalTrace
|
|
3614
|
+
toAgentEvalTrace,
|
|
3615
|
+
validateChatModelId,
|
|
3616
|
+
withConfiguredModels
|
|
3188
3617
|
};
|
|
3189
3618
|
//# sourceMappingURL=index.js.map
|