@tangle-network/agent-runtime 0.15.0 → 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/index.d.ts +361 -3
- package/dist/index.js +381 -4
- package/dist/index.js.map +1 -1
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -1040,6 +1040,29 @@ var D1DurableRunStore = class {
|
|
|
1040
1040
|
const row = await this.db.prepare("SELECT * FROM durable_events WHERE run_id = ? AND key = ?").bind(runId, key).first();
|
|
1041
1041
|
return row ? rowToEventRecord(row) : void 0;
|
|
1042
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
|
+
}
|
|
1043
1066
|
async close() {
|
|
1044
1067
|
}
|
|
1045
1068
|
/** Inspect the currently-applied schema version. */
|
|
@@ -1069,7 +1092,17 @@ function rowToRunRecord(row) {
|
|
|
1069
1092
|
leaseHolderId: row.lease_holder_id ?? void 0,
|
|
1070
1093
|
leaseExpiresAt: row.lease_expires_at ?? void 0,
|
|
1071
1094
|
outcome: row.outcome_json ? JSON.parse(row.outcome_json) : void 0,
|
|
1072
|
-
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
|
|
1073
1106
|
};
|
|
1074
1107
|
}
|
|
1075
1108
|
function rowToStepRecord(row) {
|
|
@@ -1134,6 +1167,7 @@ var FileSystemDurableRunStore = class {
|
|
|
1134
1167
|
await this.writeLease(input.runId, { workerId: input.workerId, leaseExpiresAt });
|
|
1135
1168
|
await appendFile(join(dir, "steps.jsonl"), "", "utf8");
|
|
1136
1169
|
await appendFile(join(dir, "events.jsonl"), "", "utf8");
|
|
1170
|
+
await appendFile(join(dir, "stream-events.jsonl"), "", "utf8");
|
|
1137
1171
|
return { run: record2, completedSteps: [], leaseExpiresAt };
|
|
1138
1172
|
}
|
|
1139
1173
|
const record = await this.readRun(input.runId);
|
|
@@ -1296,8 +1330,48 @@ var FileSystemDurableRunStore = class {
|
|
|
1296
1330
|
}
|
|
1297
1331
|
return void 0;
|
|
1298
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
|
+
}
|
|
1299
1362
|
async close() {
|
|
1300
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
|
+
}
|
|
1301
1375
|
/** @internal — used by tests to list runs in the store. */
|
|
1302
1376
|
async _listRunIds() {
|
|
1303
1377
|
if (!existsSync(this.root)) return [];
|
|
@@ -1393,7 +1467,7 @@ var InMemoryDurableRunStore = class {
|
|
|
1393
1467
|
leaseExpiresAt,
|
|
1394
1468
|
stepCount: 0
|
|
1395
1469
|
};
|
|
1396
|
-
state = { record, steps: /* @__PURE__ */ new Map(), events: /* @__PURE__ */ new Map() };
|
|
1470
|
+
state = { record, steps: /* @__PURE__ */ new Map(), events: /* @__PURE__ */ new Map(), streamEvents: [] };
|
|
1397
1471
|
this.runs.set(input.runId, state);
|
|
1398
1472
|
return { run: { ...record }, completedSteps: [], leaseExpiresAt };
|
|
1399
1473
|
}
|
|
@@ -1534,6 +1608,31 @@ var InMemoryDurableRunStore = class {
|
|
|
1534
1608
|
const rec = state.events.get(key);
|
|
1535
1609
|
return rec ? { ...rec } : void 0;
|
|
1536
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
|
+
}
|
|
1537
1636
|
async close() {
|
|
1538
1637
|
this.runs.clear();
|
|
1539
1638
|
}
|
|
@@ -1793,7 +1892,7 @@ function cryptoRandomUuid() {
|
|
|
1793
1892
|
}
|
|
1794
1893
|
|
|
1795
1894
|
// src/durable/schema.ts
|
|
1796
|
-
var DURABLE_SCHEMA_VERSION =
|
|
1895
|
+
var DURABLE_SCHEMA_VERSION = 2;
|
|
1797
1896
|
var DURABLE_SCHEMA_SQL = `-- Durable-run substrate \u2014 versioned schema for D1 / SQLite.
|
|
1798
1897
|
--
|
|
1799
1898
|
-- Apply once per database. Subsequent migrations append; never rewrite a
|
|
@@ -1861,8 +1960,198 @@ CREATE TABLE IF NOT EXISTS durable_events (
|
|
|
1861
1960
|
|
|
1862
1961
|
INSERT OR IGNORE INTO durable_schema_info (version, applied_at)
|
|
1863
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'));
|
|
1864
1992
|
`;
|
|
1865
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
|
+
|
|
1866
2155
|
// src/durable/workflows.ts
|
|
1867
2156
|
async function runOnWorkflowStep(workflowStep, input) {
|
|
1868
2157
|
const stepCfg = input.stepConfig;
|
|
@@ -1983,6 +2272,85 @@ function classifyIntent(profile, message, opts = {}) {
|
|
|
1983
2272
|
return { id: bestId, subagent: bestSubagent, score: bestScore, scores, evaluated };
|
|
1984
2273
|
}
|
|
1985
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
|
+
|
|
1986
2354
|
// src/profile-conformance.ts
|
|
1987
2355
|
var DEFAULT_SHELL_CAPS = [
|
|
1988
2356
|
"bash",
|
|
@@ -3187,6 +3555,7 @@ export {
|
|
|
3187
3555
|
ChatTurnError,
|
|
3188
3556
|
ConfigError,
|
|
3189
3557
|
D1DurableRunStore,
|
|
3558
|
+
DEFAULT_ROUTER_BASE_URL,
|
|
3190
3559
|
DURABLE_SCHEMA_SQL,
|
|
3191
3560
|
DURABLE_SCHEMA_VERSION,
|
|
3192
3561
|
DurableAwaitEventTimeoutError,
|
|
@@ -3209,25 +3578,31 @@ export {
|
|
|
3209
3578
|
canonicalHash,
|
|
3210
3579
|
canonicalJson,
|
|
3211
3580
|
classifyIntent,
|
|
3581
|
+
cleanModelId,
|
|
3212
3582
|
composeTurnProfile,
|
|
3213
3583
|
createIterableBackend,
|
|
3214
3584
|
createOpenAICompatibleBackend,
|
|
3215
3585
|
createRuntimeEventCollector,
|
|
3216
3586
|
createRuntimeStreamEventCollector,
|
|
3217
3587
|
createSandboxPromptBackend,
|
|
3588
|
+
createSessionSupervisorDO,
|
|
3218
3589
|
createTraceBridge,
|
|
3219
3590
|
decideKnowledgeReadiness,
|
|
3220
3591
|
deriveWorkerId,
|
|
3221
3592
|
durableChatTurnEngine,
|
|
3222
3593
|
encodeServerSentEvent,
|
|
3594
|
+
getModels,
|
|
3223
3595
|
manifestHash,
|
|
3224
3596
|
readinessServerSentEvent,
|
|
3597
|
+
resolveChatModel,
|
|
3598
|
+
resolveRouterBaseUrl,
|
|
3225
3599
|
runAgentTask,
|
|
3226
3600
|
runAgentTaskStream,
|
|
3227
3601
|
runChatTurn,
|
|
3228
3602
|
runDurable,
|
|
3229
3603
|
runDurableTurn,
|
|
3230
3604
|
runOnWorkflowStep,
|
|
3605
|
+
runSupervisedTurn,
|
|
3231
3606
|
runtimeStreamServerSentEvent,
|
|
3232
3607
|
sandboxAsChatTurnTarget,
|
|
3233
3608
|
sanitizeAgentRuntimeEvent,
|
|
@@ -3236,6 +3611,8 @@ export {
|
|
|
3236
3611
|
startRuntimeRun,
|
|
3237
3612
|
stepId,
|
|
3238
3613
|
summarizeAgentTaskRun,
|
|
3239
|
-
toAgentEvalTrace
|
|
3614
|
+
toAgentEvalTrace,
|
|
3615
|
+
validateChatModelId,
|
|
3616
|
+
withConfiguredModels
|
|
3240
3617
|
};
|
|
3241
3618
|
//# sourceMappingURL=index.js.map
|