@rowan-agent/agent 0.16.2 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -3
- package/dist/index.d.ts +373 -205
- package/dist/index.js +1821 -486
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -945,7 +945,7 @@ function createRuntimeCoreTools(input = {}) {
|
|
|
945
945
|
import { mkdir as mkdir2, chmod as chmod2, writeFile as writeFile2 } from "fs/promises";
|
|
946
946
|
import { randomUUID } from "crypto";
|
|
947
947
|
import { join as join5 } from "path";
|
|
948
|
-
import { createModelStream } from "@rowan-agent/models";
|
|
948
|
+
import { createModelStream, isValidToolProgress } from "@rowan-agent/models";
|
|
949
949
|
|
|
950
950
|
// src/utils.ts
|
|
951
951
|
function createId(prefix) {
|
|
@@ -961,6 +961,49 @@ function createTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
|
961
961
|
const mm = String(abs % 60).padStart(2, "0");
|
|
962
962
|
return `${iso}${sign}${hh}:${mm}`;
|
|
963
963
|
}
|
|
964
|
+
function combineSignals(signalA, signalB) {
|
|
965
|
+
if (!signalA && !signalB) return new AbortController().signal;
|
|
966
|
+
if (!signalA) return signalB;
|
|
967
|
+
if (!signalB) return signalA;
|
|
968
|
+
if (typeof AbortSignal.any === "function") {
|
|
969
|
+
return AbortSignal.any([signalA, signalB]);
|
|
970
|
+
}
|
|
971
|
+
if (signalA.aborted) return signalA;
|
|
972
|
+
if (signalB.aborted) return signalB;
|
|
973
|
+
const controller = new AbortController();
|
|
974
|
+
const onAbort = (ev) => {
|
|
975
|
+
const target = ev.target;
|
|
976
|
+
controller.abort(target.reason);
|
|
977
|
+
};
|
|
978
|
+
signalA.addEventListener("abort", onAbort, { once: true });
|
|
979
|
+
signalB.addEventListener("abort", onAbort, { once: true });
|
|
980
|
+
return controller.signal;
|
|
981
|
+
}
|
|
982
|
+
function withAbort(promise, signal) {
|
|
983
|
+
if (!signal) return promise;
|
|
984
|
+
if (signal.aborted) {
|
|
985
|
+
const error = signal.reason instanceof Error ? signal.reason : new DOMException(typeof signal.reason === "string" ? signal.reason : "Tool execution aborted.", "AbortError");
|
|
986
|
+
return Promise.reject(error);
|
|
987
|
+
}
|
|
988
|
+
return new Promise((resolve9, reject) => {
|
|
989
|
+
const onAbort = () => {
|
|
990
|
+
signal.removeEventListener("abort", onAbort);
|
|
991
|
+
const error = signal.reason instanceof Error ? signal.reason : new DOMException(typeof signal.reason === "string" ? signal.reason : "Tool execution aborted.", "AbortError");
|
|
992
|
+
reject(error);
|
|
993
|
+
};
|
|
994
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
995
|
+
promise.then(
|
|
996
|
+
(val) => {
|
|
997
|
+
signal.removeEventListener("abort", onAbort);
|
|
998
|
+
resolve9(val);
|
|
999
|
+
},
|
|
1000
|
+
(err) => {
|
|
1001
|
+
signal.removeEventListener("abort", onAbort);
|
|
1002
|
+
reject(err);
|
|
1003
|
+
}
|
|
1004
|
+
);
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
964
1007
|
|
|
965
1008
|
// src/loop/state.ts
|
|
966
1009
|
function snapshotMessage(message) {
|
|
@@ -991,12 +1034,18 @@ function contentBlocksToMessageContent(blocks) {
|
|
|
991
1034
|
if (block.type === "thinking") {
|
|
992
1035
|
return { type: "thinking", thinking: block.thinking, ...block.signature ? { signature: block.signature } : {} };
|
|
993
1036
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1037
|
+
if (block.type === "image") {
|
|
1038
|
+
return { type: "image", data: block.data, mimeType: block.mimeType };
|
|
1039
|
+
}
|
|
1040
|
+
if (block.type === "tool_call") {
|
|
1041
|
+
let input = block.args;
|
|
1042
|
+
try {
|
|
1043
|
+
input = JSON.parse(block.args);
|
|
1044
|
+
} catch {
|
|
1045
|
+
}
|
|
1046
|
+
return { type: "tool_use", id: block.id, name: block.name, input };
|
|
998
1047
|
}
|
|
999
|
-
return { type: "
|
|
1048
|
+
return { type: "text", text: JSON.stringify(block) };
|
|
1000
1049
|
});
|
|
1001
1050
|
}
|
|
1002
1051
|
|
|
@@ -1009,6 +1058,296 @@ function validateMaxAttempts(value) {
|
|
|
1009
1058
|
return value;
|
|
1010
1059
|
}
|
|
1011
1060
|
|
|
1061
|
+
// src/loop/partial-json.ts
|
|
1062
|
+
var COMPLETE_NUMBER_REGEX = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
|
|
1063
|
+
function escapeRawControlChars(s) {
|
|
1064
|
+
let result = "";
|
|
1065
|
+
for (let i = 0; i < s.length; i++) {
|
|
1066
|
+
const ch = s[i];
|
|
1067
|
+
const code = ch.charCodeAt(0);
|
|
1068
|
+
if (code === 10) result += "\\n";
|
|
1069
|
+
else if (code === 13) result += "\\r";
|
|
1070
|
+
else if (code === 9) result += "\\t";
|
|
1071
|
+
else if (code < 32) result += "\\u" + code.toString(16).padStart(4, "0");
|
|
1072
|
+
else result += ch;
|
|
1073
|
+
}
|
|
1074
|
+
return result;
|
|
1075
|
+
}
|
|
1076
|
+
function cleanOpenString(raw) {
|
|
1077
|
+
let s = raw;
|
|
1078
|
+
let backslashes = 0;
|
|
1079
|
+
while (s.length - 1 - backslashes >= 0 && s[s.length - 1 - backslashes] === "\\") {
|
|
1080
|
+
backslashes++;
|
|
1081
|
+
}
|
|
1082
|
+
if (backslashes % 2 === 1) {
|
|
1083
|
+
s = s.slice(0, -1);
|
|
1084
|
+
} else {
|
|
1085
|
+
s = s.replace(/(^|[^\\])(?:\\\\)*\\u[0-9a-fA-F]{0,3}$/, (match) => {
|
|
1086
|
+
const uIndex = match.lastIndexOf("\\u");
|
|
1087
|
+
return match.slice(0, uIndex);
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
return escapeRawControlChars(s) + '"';
|
|
1091
|
+
}
|
|
1092
|
+
function repairPartialJson(input) {
|
|
1093
|
+
const stack = [];
|
|
1094
|
+
let i = 0;
|
|
1095
|
+
let hasTopLevelValue = false;
|
|
1096
|
+
let topLevelSafeEnd = 0;
|
|
1097
|
+
function finishWithSafeEnd(safeEnd) {
|
|
1098
|
+
let result = input.slice(0, safeEnd);
|
|
1099
|
+
for (let j = stack.length - 1; j >= 0; j--) {
|
|
1100
|
+
result += stack[j].kind === "object" ? "}" : "]";
|
|
1101
|
+
}
|
|
1102
|
+
return result;
|
|
1103
|
+
}
|
|
1104
|
+
function closeStackWithPrefix(prefix) {
|
|
1105
|
+
let result = prefix;
|
|
1106
|
+
for (let j = stack.length - 1; j >= 0; j--) {
|
|
1107
|
+
result += stack[j].kind === "object" ? "}" : "]";
|
|
1108
|
+
}
|
|
1109
|
+
return result;
|
|
1110
|
+
}
|
|
1111
|
+
function popContainer(endIndex) {
|
|
1112
|
+
stack.pop();
|
|
1113
|
+
const parent = stack[stack.length - 1];
|
|
1114
|
+
if (parent) {
|
|
1115
|
+
parent.safeEnd = endIndex;
|
|
1116
|
+
parent.state = "after_value";
|
|
1117
|
+
} else {
|
|
1118
|
+
hasTopLevelValue = true;
|
|
1119
|
+
topLevelSafeEnd = endIndex;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
while (i < input.length) {
|
|
1123
|
+
const ch = input[i];
|
|
1124
|
+
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
1125
|
+
i++;
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
1128
|
+
const current = stack[stack.length - 1];
|
|
1129
|
+
if (!current) {
|
|
1130
|
+
if (hasTopLevelValue) break;
|
|
1131
|
+
if (ch === "{") {
|
|
1132
|
+
stack.push({ kind: "object", safeEnd: i + 1, state: "expect_key" });
|
|
1133
|
+
i++;
|
|
1134
|
+
} else if (ch === "[") {
|
|
1135
|
+
stack.push({ kind: "array", safeEnd: i + 1, state: "expect_value" });
|
|
1136
|
+
i++;
|
|
1137
|
+
} else if (ch === '"') {
|
|
1138
|
+
const strStart = i;
|
|
1139
|
+
i++;
|
|
1140
|
+
let closed = false;
|
|
1141
|
+
while (i < input.length) {
|
|
1142
|
+
if (input[i] === "\\") {
|
|
1143
|
+
i += 2;
|
|
1144
|
+
} else if (input[i] === '"') {
|
|
1145
|
+
i++;
|
|
1146
|
+
closed = true;
|
|
1147
|
+
break;
|
|
1148
|
+
} else {
|
|
1149
|
+
i++;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
if (closed) {
|
|
1153
|
+
hasTopLevelValue = true;
|
|
1154
|
+
topLevelSafeEnd = i;
|
|
1155
|
+
} else {
|
|
1156
|
+
return cleanOpenString(input.slice(strStart));
|
|
1157
|
+
}
|
|
1158
|
+
} else {
|
|
1159
|
+
const tokStart = i;
|
|
1160
|
+
while (i < input.length && !/[\s,}\]]/.test(input[i])) {
|
|
1161
|
+
i++;
|
|
1162
|
+
}
|
|
1163
|
+
const tok = input.slice(tokStart, i);
|
|
1164
|
+
if (tok === "true" || tok === "false" || tok === "null" || COMPLETE_NUMBER_REGEX.test(tok)) {
|
|
1165
|
+
hasTopLevelValue = true;
|
|
1166
|
+
topLevelSafeEnd = i;
|
|
1167
|
+
} else {
|
|
1168
|
+
return void 0;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
continue;
|
|
1172
|
+
}
|
|
1173
|
+
if (current.kind === "object") {
|
|
1174
|
+
if (current.state === "expect_key") {
|
|
1175
|
+
if (ch === "}") {
|
|
1176
|
+
i++;
|
|
1177
|
+
popContainer(i);
|
|
1178
|
+
} else if (ch === '"') {
|
|
1179
|
+
i++;
|
|
1180
|
+
let closed = false;
|
|
1181
|
+
while (i < input.length) {
|
|
1182
|
+
if (input[i] === "\\") {
|
|
1183
|
+
i += 2;
|
|
1184
|
+
} else if (input[i] === '"') {
|
|
1185
|
+
i++;
|
|
1186
|
+
closed = true;
|
|
1187
|
+
break;
|
|
1188
|
+
} else {
|
|
1189
|
+
i++;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
if (closed) {
|
|
1193
|
+
current.state = "expect_colon";
|
|
1194
|
+
} else {
|
|
1195
|
+
return finishWithSafeEnd(current.safeEnd);
|
|
1196
|
+
}
|
|
1197
|
+
} else {
|
|
1198
|
+
return finishWithSafeEnd(current.safeEnd);
|
|
1199
|
+
}
|
|
1200
|
+
} else if (current.state === "expect_colon") {
|
|
1201
|
+
if (ch === ":") {
|
|
1202
|
+
current.state = "expect_value";
|
|
1203
|
+
i++;
|
|
1204
|
+
} else {
|
|
1205
|
+
return finishWithSafeEnd(current.safeEnd);
|
|
1206
|
+
}
|
|
1207
|
+
} else if (current.state === "expect_value") {
|
|
1208
|
+
if (ch === '"') {
|
|
1209
|
+
const valStart = i;
|
|
1210
|
+
i++;
|
|
1211
|
+
let closed = false;
|
|
1212
|
+
while (i < input.length) {
|
|
1213
|
+
if (input[i] === "\\") {
|
|
1214
|
+
i += 2;
|
|
1215
|
+
} else if (input[i] === '"') {
|
|
1216
|
+
i++;
|
|
1217
|
+
closed = true;
|
|
1218
|
+
break;
|
|
1219
|
+
} else {
|
|
1220
|
+
i++;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
if (closed) {
|
|
1224
|
+
current.safeEnd = i;
|
|
1225
|
+
current.state = "after_value";
|
|
1226
|
+
} else {
|
|
1227
|
+
const prefix = input.slice(0, valStart);
|
|
1228
|
+
const repairedStr = cleanOpenString(input.slice(valStart));
|
|
1229
|
+
return closeStackWithPrefix(prefix + repairedStr);
|
|
1230
|
+
}
|
|
1231
|
+
} else if (ch === "{") {
|
|
1232
|
+
stack.push({ kind: "object", safeEnd: i + 1, state: "expect_key" });
|
|
1233
|
+
i++;
|
|
1234
|
+
} else if (ch === "[") {
|
|
1235
|
+
stack.push({ kind: "array", safeEnd: i + 1, state: "expect_value" });
|
|
1236
|
+
i++;
|
|
1237
|
+
} else if (ch === "}" || ch === "]") {
|
|
1238
|
+
return finishWithSafeEnd(current.safeEnd);
|
|
1239
|
+
} else {
|
|
1240
|
+
const tokStart = i;
|
|
1241
|
+
while (i < input.length && !/[\s,}\]]/.test(input[i])) {
|
|
1242
|
+
i++;
|
|
1243
|
+
}
|
|
1244
|
+
const tok = input.slice(tokStart, i);
|
|
1245
|
+
if (tok === "true" || tok === "false" || tok === "null" || COMPLETE_NUMBER_REGEX.test(tok)) {
|
|
1246
|
+
current.safeEnd = i;
|
|
1247
|
+
current.state = "after_value";
|
|
1248
|
+
} else {
|
|
1249
|
+
return finishWithSafeEnd(current.safeEnd);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
} else if (current.state === "after_value") {
|
|
1253
|
+
if (ch === ",") {
|
|
1254
|
+
current.state = "expect_key";
|
|
1255
|
+
i++;
|
|
1256
|
+
} else if (ch === "}") {
|
|
1257
|
+
i++;
|
|
1258
|
+
popContainer(i);
|
|
1259
|
+
} else {
|
|
1260
|
+
return finishWithSafeEnd(current.safeEnd);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
} else {
|
|
1264
|
+
if (current.state === "expect_value") {
|
|
1265
|
+
if (ch === "]") {
|
|
1266
|
+
i++;
|
|
1267
|
+
popContainer(i);
|
|
1268
|
+
} else if (ch === '"') {
|
|
1269
|
+
const valStart = i;
|
|
1270
|
+
i++;
|
|
1271
|
+
let closed = false;
|
|
1272
|
+
while (i < input.length) {
|
|
1273
|
+
if (input[i] === "\\") {
|
|
1274
|
+
i += 2;
|
|
1275
|
+
} else if (input[i] === '"') {
|
|
1276
|
+
i++;
|
|
1277
|
+
closed = true;
|
|
1278
|
+
break;
|
|
1279
|
+
} else {
|
|
1280
|
+
i++;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
if (closed) {
|
|
1284
|
+
current.safeEnd = i;
|
|
1285
|
+
current.state = "after_value";
|
|
1286
|
+
} else {
|
|
1287
|
+
const prefix = input.slice(0, valStart);
|
|
1288
|
+
const repairedStr = cleanOpenString(input.slice(valStart));
|
|
1289
|
+
return closeStackWithPrefix(prefix + repairedStr);
|
|
1290
|
+
}
|
|
1291
|
+
} else if (ch === "{") {
|
|
1292
|
+
stack.push({ kind: "object", safeEnd: i + 1, state: "expect_key" });
|
|
1293
|
+
i++;
|
|
1294
|
+
} else if (ch === "[") {
|
|
1295
|
+
stack.push({ kind: "array", safeEnd: i + 1, state: "expect_value" });
|
|
1296
|
+
i++;
|
|
1297
|
+
} else if (ch === "}") {
|
|
1298
|
+
return finishWithSafeEnd(current.safeEnd);
|
|
1299
|
+
} else {
|
|
1300
|
+
const tokStart = i;
|
|
1301
|
+
while (i < input.length && !/[\s,}\]]/.test(input[i])) {
|
|
1302
|
+
i++;
|
|
1303
|
+
}
|
|
1304
|
+
const tok = input.slice(tokStart, i);
|
|
1305
|
+
if (tok === "true" || tok === "false" || tok === "null" || COMPLETE_NUMBER_REGEX.test(tok)) {
|
|
1306
|
+
current.safeEnd = i;
|
|
1307
|
+
current.state = "after_value";
|
|
1308
|
+
} else {
|
|
1309
|
+
return finishWithSafeEnd(current.safeEnd);
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
} else if (current.state === "after_value") {
|
|
1313
|
+
if (ch === ",") {
|
|
1314
|
+
current.state = "expect_value";
|
|
1315
|
+
i++;
|
|
1316
|
+
} else if (ch === "]") {
|
|
1317
|
+
i++;
|
|
1318
|
+
popContainer(i);
|
|
1319
|
+
} else {
|
|
1320
|
+
return finishWithSafeEnd(current.safeEnd);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
if (stack.length > 0) {
|
|
1326
|
+
const current = stack[stack.length - 1];
|
|
1327
|
+
return finishWithSafeEnd(current.safeEnd);
|
|
1328
|
+
}
|
|
1329
|
+
if (hasTopLevelValue) {
|
|
1330
|
+
return input.slice(0, topLevelSafeEnd);
|
|
1331
|
+
}
|
|
1332
|
+
return void 0;
|
|
1333
|
+
}
|
|
1334
|
+
function parsePartialJson(input) {
|
|
1335
|
+
if (typeof input !== "string") return void 0;
|
|
1336
|
+
if (!input.trim()) return void 0;
|
|
1337
|
+
const source = input.trimStart();
|
|
1338
|
+
try {
|
|
1339
|
+
return JSON.parse(source);
|
|
1340
|
+
} catch {
|
|
1341
|
+
}
|
|
1342
|
+
const repaired = repairPartialJson(source);
|
|
1343
|
+
if (repaired === void 0) return void 0;
|
|
1344
|
+
try {
|
|
1345
|
+
return JSON.parse(repaired);
|
|
1346
|
+
} catch {
|
|
1347
|
+
return void 0;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1012
1351
|
// src/loop/errors.ts
|
|
1013
1352
|
var EmptyResponseError = class extends Error {
|
|
1014
1353
|
code = "empty_response";
|
|
@@ -1039,14 +1378,50 @@ var LoopGuard = {
|
|
|
1039
1378
|
// src/loop/stream-collector.ts
|
|
1040
1379
|
var MAX_STREAMED_OUTPUT_CHARACTERS = 1024 * 1024;
|
|
1041
1380
|
async function invokeModel(input) {
|
|
1042
|
-
const
|
|
1381
|
+
const callContext = input.callContext ?? {
|
|
1382
|
+
signal: input.config.signal ?? new AbortController().signal,
|
|
1383
|
+
run: {
|
|
1384
|
+
id: input.config.execution.runId,
|
|
1385
|
+
agentId: input.config.execution.agentId,
|
|
1386
|
+
scope: input.config.execution.scope ?? [],
|
|
1387
|
+
cwd: input.config.execution.cwd ?? input.config.context.cwd ?? ""
|
|
1388
|
+
},
|
|
1389
|
+
interact: async (request) => {
|
|
1390
|
+
const handler = input.config.runtime?.interact ?? input.config.interact;
|
|
1391
|
+
if (!handler) {
|
|
1392
|
+
throw new Error("Run interactions are not supported in this runtime.");
|
|
1393
|
+
}
|
|
1394
|
+
return handler(request);
|
|
1395
|
+
},
|
|
1396
|
+
tools: {
|
|
1397
|
+
list: () => {
|
|
1398
|
+
return input.config.context.tools.map((t) => ({
|
|
1399
|
+
name: t.name,
|
|
1400
|
+
description: t.description,
|
|
1401
|
+
parameters: t.parameters,
|
|
1402
|
+
...t._meta !== void 0 ? { _meta: t._meta } : {}
|
|
1403
|
+
}));
|
|
1404
|
+
},
|
|
1405
|
+
call: async (_name, _args, _options) => {
|
|
1406
|
+
throw new Error("Tool calling is not available in standalone stream collector without callContext.");
|
|
1407
|
+
},
|
|
1408
|
+
report: (update) => {
|
|
1409
|
+
input.config.onToolReport?.({
|
|
1410
|
+
runId: input.config.execution.runId,
|
|
1411
|
+
update
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
const events = input.config.stream(input.request, callContext);
|
|
1043
1417
|
const result = await collectStreamResult({
|
|
1044
1418
|
config: input.config,
|
|
1045
1419
|
message: input.message,
|
|
1046
1420
|
events,
|
|
1047
1421
|
metadataPhase: input.phaseId,
|
|
1048
1422
|
output: input.output,
|
|
1049
|
-
onThinkingDelta: input.onThinkingDelta
|
|
1423
|
+
onThinkingDelta: input.onThinkingDelta,
|
|
1424
|
+
onToolCallDelta: input.onToolCallDelta
|
|
1050
1425
|
});
|
|
1051
1426
|
const response = result.doneResponse ?? {
|
|
1052
1427
|
content: result.text,
|
|
@@ -1077,6 +1452,8 @@ async function collectStreamResult(input) {
|
|
|
1077
1452
|
let streamedOutputCharacters = 0;
|
|
1078
1453
|
const toolCallsWithDeltas = /* @__PURE__ */ new Set();
|
|
1079
1454
|
const thinkingOffsets = /* @__PURE__ */ new Map();
|
|
1455
|
+
const toolNames = /* @__PURE__ */ new Map();
|
|
1456
|
+
const toolArguments = /* @__PURE__ */ new Map();
|
|
1080
1457
|
for await (const event of input.events) {
|
|
1081
1458
|
if (event.type === "text_delta") {
|
|
1082
1459
|
streamedOutputCharacters += event.text.length;
|
|
@@ -1127,6 +1504,26 @@ async function collectStreamResult(input) {
|
|
|
1127
1504
|
}
|
|
1128
1505
|
lastPartial = event.partial;
|
|
1129
1506
|
}
|
|
1507
|
+
if (event.type === "tool_call_start") {
|
|
1508
|
+
toolNames.set(event.id, event.name);
|
|
1509
|
+
}
|
|
1510
|
+
if (event.type === "tool_call_delta") {
|
|
1511
|
+
const accumulated = (toolArguments.get(event.id) ?? "") + event.arguments;
|
|
1512
|
+
toolArguments.set(event.id, accumulated);
|
|
1513
|
+
const toolName = toolNames.get(event.id) ?? event.partial.contentBlocks.find((b) => b.type === "tool_call" && b.id === event.id)?.name ?? "";
|
|
1514
|
+
if (toolName && !toolNames.has(event.id)) {
|
|
1515
|
+
toolNames.set(event.id, toolName);
|
|
1516
|
+
}
|
|
1517
|
+
if (persistAssistant && activeMessageId) {
|
|
1518
|
+
input.onToolCallDelta?.({
|
|
1519
|
+
messageId: activeMessageId,
|
|
1520
|
+
providerToolCallId: event.id,
|
|
1521
|
+
toolName,
|
|
1522
|
+
arguments: accumulated,
|
|
1523
|
+
args: parsePartialJson(accumulated)
|
|
1524
|
+
});
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1130
1527
|
if (event.type === "thinking_delta") {
|
|
1131
1528
|
if (persistAssistant && !activeMessageId) {
|
|
1132
1529
|
activeMessageId = input.message.reserve("assistant", {
|
|
@@ -1239,16 +1636,17 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
|
|
|
1239
1636
|
let outputPayload = phaseIn?.state?.payload;
|
|
1240
1637
|
let nextPhase;
|
|
1241
1638
|
let outputMessage;
|
|
1242
|
-
let settingsProvider;
|
|
1243
1639
|
return {
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1640
|
+
hooks: {
|
|
1641
|
+
on: (eventType, handler) => {
|
|
1642
|
+
assertActive();
|
|
1643
|
+
hooks?.on(eventType, handler);
|
|
1644
|
+
trackCleanup?.(() => hooks?.off(eventType, handler));
|
|
1645
|
+
},
|
|
1646
|
+
off: (eventType, handler) => {
|
|
1647
|
+
assertActive();
|
|
1648
|
+
hooks?.off(eventType, handler);
|
|
1649
|
+
}
|
|
1252
1650
|
},
|
|
1253
1651
|
config: {
|
|
1254
1652
|
get: async (scope) => {
|
|
@@ -1298,9 +1696,28 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
|
|
|
1298
1696
|
return store?.delete(key);
|
|
1299
1697
|
}
|
|
1300
1698
|
};
|
|
1699
|
+
},
|
|
1700
|
+
global: () => {
|
|
1701
|
+
assertActive();
|
|
1702
|
+
const store = options?.state?.global();
|
|
1703
|
+
return {
|
|
1704
|
+
get: async (key) => {
|
|
1705
|
+
assertActive();
|
|
1706
|
+
return store?.get(key);
|
|
1707
|
+
},
|
|
1708
|
+
set: async (key, value) => {
|
|
1709
|
+
assertActive();
|
|
1710
|
+
assertJsonValue(value);
|
|
1711
|
+
return store?.set(key, value);
|
|
1712
|
+
},
|
|
1713
|
+
delete: async (key) => {
|
|
1714
|
+
assertActive();
|
|
1715
|
+
return store?.delete(key);
|
|
1716
|
+
}
|
|
1717
|
+
};
|
|
1301
1718
|
}
|
|
1302
1719
|
},
|
|
1303
|
-
|
|
1720
|
+
tools: {
|
|
1304
1721
|
register: (tool) => {
|
|
1305
1722
|
assertActive();
|
|
1306
1723
|
options?.registerTool?.(tool);
|
|
@@ -1329,14 +1746,16 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
|
|
|
1329
1746
|
};
|
|
1330
1747
|
}
|
|
1331
1748
|
},
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1749
|
+
providers: {
|
|
1750
|
+
register: (config) => {
|
|
1751
|
+
assertActive();
|
|
1752
|
+
options?.registerProvider?.(config);
|
|
1753
|
+
trackCleanup?.(() => options?.unregisterProvider?.(config.id));
|
|
1754
|
+
},
|
|
1755
|
+
unregister: (id) => {
|
|
1756
|
+
assertActive();
|
|
1757
|
+
options?.unregisterProvider?.(id);
|
|
1758
|
+
}
|
|
1340
1759
|
},
|
|
1341
1760
|
manifest: options?.manifest,
|
|
1342
1761
|
utils: {
|
|
@@ -1358,7 +1777,7 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
|
|
|
1358
1777
|
}, off: () => {
|
|
1359
1778
|
}, emit: () => {
|
|
1360
1779
|
}, has: () => false, count: () => 0 },
|
|
1361
|
-
|
|
1780
|
+
phases: {
|
|
1362
1781
|
register: async (registration) => {
|
|
1363
1782
|
assertActive();
|
|
1364
1783
|
await options?.registerPhase?.(registration);
|
|
@@ -1379,19 +1798,37 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
|
|
|
1379
1798
|
nextPhase = id;
|
|
1380
1799
|
},
|
|
1381
1800
|
getNextPhase: () => nextPhase,
|
|
1382
|
-
getMessage: () => outputMessage
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1801
|
+
getMessage: () => outputMessage
|
|
1802
|
+
},
|
|
1803
|
+
ui: {
|
|
1804
|
+
contribute: (contribution) => {
|
|
1805
|
+
assertActive();
|
|
1806
|
+
if (!contribution || typeof contribution !== "object") {
|
|
1807
|
+
throw new TypeError("UI contribution must be an object.");
|
|
1808
|
+
}
|
|
1809
|
+
if (contribution.slot !== "settings" && contribution.slot !== "model-picker") {
|
|
1810
|
+
throw new TypeError(`Unsupported UI contribution slot: "${contribution.slot}".`);
|
|
1811
|
+
}
|
|
1812
|
+
if (typeof contribution.id !== "string" || contribution.id.trim() === "") {
|
|
1813
|
+
throw new TypeError("UI contribution requires a non-empty id.");
|
|
1814
|
+
}
|
|
1815
|
+
if (contribution.slot === "settings") {
|
|
1816
|
+
if (typeof contribution.title !== "string") {
|
|
1817
|
+
throw new TypeError("Settings UI contribution requires a title.");
|
|
1388
1818
|
}
|
|
1389
|
-
if (
|
|
1390
|
-
throw new
|
|
1819
|
+
if (!contribution.settings || typeof contribution.settings !== "object") {
|
|
1820
|
+
throw new TypeError("Settings UI contribution requires a settings definition.");
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
if (contribution.slot === "model-picker") {
|
|
1824
|
+
if (typeof contribution.provider !== "string" || contribution.provider.trim() === "") {
|
|
1825
|
+
throw new TypeError("Model-picker UI contribution requires a provider.");
|
|
1391
1826
|
}
|
|
1392
|
-
settingsProvider = provider;
|
|
1393
|
-
options?.registerSettings?.(provider);
|
|
1394
1827
|
}
|
|
1828
|
+
const dispose = options?.contributeUi ? options.contributeUi(contribution) : () => {
|
|
1829
|
+
};
|
|
1830
|
+
trackCleanup?.(dispose);
|
|
1831
|
+
return dispose;
|
|
1395
1832
|
}
|
|
1396
1833
|
}
|
|
1397
1834
|
};
|
|
@@ -1400,8 +1837,8 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
|
|
|
1400
1837
|
// src/harness/phases/interactions.ts
|
|
1401
1838
|
var RunInteractionCancelledError = class extends Error {
|
|
1402
1839
|
code = "run_interaction_cancelled";
|
|
1403
|
-
constructor() {
|
|
1404
|
-
super(
|
|
1840
|
+
constructor(message = "Run interaction work was cancelled.") {
|
|
1841
|
+
super(message);
|
|
1405
1842
|
this.name = "RunInteractionCancelledError";
|
|
1406
1843
|
}
|
|
1407
1844
|
};
|
|
@@ -1872,17 +2309,6 @@ async function loadPhase(targetPath) {
|
|
|
1872
2309
|
}
|
|
1873
2310
|
return phase;
|
|
1874
2311
|
}
|
|
1875
|
-
async function loadPhaseSettings(phase, context) {
|
|
1876
|
-
if (!phase.factory) return void 0;
|
|
1877
|
-
let provider;
|
|
1878
|
-
const api = createExtensionAPI(void 0, {
|
|
1879
|
-
registerSettings: (candidate) => {
|
|
1880
|
-
provider = candidate;
|
|
1881
|
-
}
|
|
1882
|
-
});
|
|
1883
|
-
await phase.factory(api);
|
|
1884
|
-
return provider ? provider(context) : void 0;
|
|
1885
|
-
}
|
|
1886
2312
|
async function loadPhaseSkills(baseDir) {
|
|
1887
2313
|
const entries = await readdir2(baseDir, { withFileTypes: true });
|
|
1888
2314
|
const skills = [];
|
|
@@ -2324,9 +2750,11 @@ function extractToolResults(transcript) {
|
|
|
2324
2750
|
}
|
|
2325
2751
|
for (const part of msg.content) {
|
|
2326
2752
|
if (part.type !== "tool_result") continue;
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2753
|
+
if (typeof part.content === "string") {
|
|
2754
|
+
const result = parseToolResult(part.content);
|
|
2755
|
+
if (result) {
|
|
2756
|
+
results.push(result);
|
|
2757
|
+
}
|
|
2330
2758
|
}
|
|
2331
2759
|
}
|
|
2332
2760
|
}
|
|
@@ -3069,9 +3497,8 @@ async function runPhaseLoop(config, state, registry) {
|
|
|
3069
3497
|
}
|
|
3070
3498
|
throw new Error("Phase machine exited without a stop or abort transition.");
|
|
3071
3499
|
}
|
|
3072
|
-
var DEFAULT_MAX_RETRIES =
|
|
3073
|
-
var
|
|
3074
|
-
var DEFAULT_MAX_DELAY_MS = 3e4;
|
|
3500
|
+
var DEFAULT_MAX_RETRIES = 10;
|
|
3501
|
+
var DEFAULT_RETRY_DELAY_MS = 5e3;
|
|
3075
3502
|
function isRetryableError(error) {
|
|
3076
3503
|
if (!(error instanceof Error)) return false;
|
|
3077
3504
|
const message = error.message.toLowerCase();
|
|
@@ -3082,21 +3509,36 @@ function isRetryableError(error) {
|
|
|
3082
3509
|
if (message.includes("service unavailable") || message.includes("503")) return true;
|
|
3083
3510
|
if (message.includes("gateway timeout") || message.includes("504")) return true;
|
|
3084
3511
|
if (message.includes("econnreset") || message.includes("econnrefused")) return true;
|
|
3512
|
+
if (message.includes("socket connection was closed") || message.includes("socket hang up")) return true;
|
|
3513
|
+
if (message.includes("fetch failed") || message.includes("etimedout")) return true;
|
|
3514
|
+
if (message.includes("network") || message.includes("connection reset")) return true;
|
|
3085
3515
|
if ("code" in error) {
|
|
3086
3516
|
const code = error.code;
|
|
3087
3517
|
if (code === "invalid_model_schema" || code === "empty_response") return true;
|
|
3088
3518
|
}
|
|
3089
3519
|
return false;
|
|
3090
3520
|
}
|
|
3091
|
-
function
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3521
|
+
function sleepAbortable(delayMs, signal) {
|
|
3522
|
+
return new Promise((resolve9) => {
|
|
3523
|
+
if (signal?.aborted) {
|
|
3524
|
+
resolve9();
|
|
3525
|
+
return;
|
|
3526
|
+
}
|
|
3527
|
+
const onAbort = () => {
|
|
3528
|
+
clearTimeout(timer);
|
|
3529
|
+
signal?.removeEventListener("abort", onAbort);
|
|
3530
|
+
resolve9();
|
|
3531
|
+
};
|
|
3532
|
+
const timer = setTimeout(() => {
|
|
3533
|
+
signal?.removeEventListener("abort", onAbort);
|
|
3534
|
+
resolve9();
|
|
3535
|
+
}, delayMs);
|
|
3536
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
3537
|
+
});
|
|
3095
3538
|
}
|
|
3096
3539
|
async function withRetry(fn, options = {}) {
|
|
3097
3540
|
const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
3098
|
-
const
|
|
3099
|
-
const maxDelayMs = options.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
|
|
3541
|
+
const retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
|
|
3100
3542
|
let lastError;
|
|
3101
3543
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
3102
3544
|
try {
|
|
@@ -3109,9 +3551,9 @@ async function withRetry(fn, options = {}) {
|
|
|
3109
3551
|
if (options.signal?.aborted) {
|
|
3110
3552
|
throw error;
|
|
3111
3553
|
}
|
|
3112
|
-
const
|
|
3113
|
-
options.onRetry?.(
|
|
3114
|
-
await
|
|
3554
|
+
const retryAttempt = attempt + 1;
|
|
3555
|
+
options.onRetry?.(retryAttempt, error, retryDelayMs, maxRetries);
|
|
3556
|
+
await sleepAbortable(retryDelayMs, options.signal);
|
|
3115
3557
|
if (options.signal?.aborted) {
|
|
3116
3558
|
throw lastError;
|
|
3117
3559
|
}
|
|
@@ -3161,10 +3603,10 @@ async function executePhase(ctx) {
|
|
|
3161
3603
|
});
|
|
3162
3604
|
await phase.factory(api);
|
|
3163
3605
|
return {
|
|
3164
|
-
message: api.
|
|
3165
|
-
route: api.
|
|
3606
|
+
message: api.phases.getMessage() ?? `${phase.name} phase completed.`,
|
|
3607
|
+
route: api.phases.getNextPhase() || "stop",
|
|
3166
3608
|
phase: phase.name,
|
|
3167
|
-
payload: api.
|
|
3609
|
+
payload: api.phases.getPayload()
|
|
3168
3610
|
};
|
|
3169
3611
|
}
|
|
3170
3612
|
return executePhaseWithModel(ctx);
|
|
@@ -3176,7 +3618,8 @@ async function executeToolCall(input) {
|
|
|
3176
3618
|
config: input.config,
|
|
3177
3619
|
toolCall: input.toolCall,
|
|
3178
3620
|
contentBlocks: input.contentBlocks,
|
|
3179
|
-
driver: input.driver
|
|
3621
|
+
driver: input.driver,
|
|
3622
|
+
options: input.options
|
|
3180
3623
|
});
|
|
3181
3624
|
} else {
|
|
3182
3625
|
const toolContext = {
|
|
@@ -3189,7 +3632,7 @@ async function executeToolCall(input) {
|
|
|
3189
3632
|
toolContext,
|
|
3190
3633
|
beforeToolCall: input.config.beforeToolCall,
|
|
3191
3634
|
afterToolCall: input.config.afterToolCall,
|
|
3192
|
-
signal: input.config.signal
|
|
3635
|
+
signal: combineSignals(input.config.signal, input.options?.signal)
|
|
3193
3636
|
});
|
|
3194
3637
|
}
|
|
3195
3638
|
return {
|
|
@@ -3221,6 +3664,28 @@ async function executeToolCalls(input) {
|
|
|
3221
3664
|
}
|
|
3222
3665
|
function createPhaseExecution(config, state, phase, messageManager, toolExecutionManager, registry) {
|
|
3223
3666
|
const interaction = createRunInteractionDriver(state, phase.name, config.signal);
|
|
3667
|
+
const executePhaseTool = async (phaseContext, toolCall, options) => {
|
|
3668
|
+
return runTurn(async () => {
|
|
3669
|
+
await toolExecutionManager.start(toolCall.id, toolCall.name, toolCall.args);
|
|
3670
|
+
const tools = phaseContext.tools.filter((tool) => tool.name !== PhaseRouteTool);
|
|
3671
|
+
const result = await executeToolCall({
|
|
3672
|
+
config: {
|
|
3673
|
+
...config,
|
|
3674
|
+
context: {
|
|
3675
|
+
...config.context,
|
|
3676
|
+
tools,
|
|
3677
|
+
skills: phaseContext.skills
|
|
3678
|
+
}
|
|
3679
|
+
},
|
|
3680
|
+
tools,
|
|
3681
|
+
toolCall,
|
|
3682
|
+
driver: interaction,
|
|
3683
|
+
options
|
|
3684
|
+
});
|
|
3685
|
+
await toolExecutionManager.end(result.toolCallId, result.toolName, result, !result.ok);
|
|
3686
|
+
return result;
|
|
3687
|
+
});
|
|
3688
|
+
};
|
|
3224
3689
|
return {
|
|
3225
3690
|
interaction,
|
|
3226
3691
|
messages: messageManager,
|
|
@@ -3264,6 +3729,51 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
|
|
|
3264
3729
|
}));
|
|
3265
3730
|
}
|
|
3266
3731
|
}
|
|
3732
|
+
const scope = config.execution.scope ?? [];
|
|
3733
|
+
const cwd = config.execution.cwd ?? config.context.cwd ?? "";
|
|
3734
|
+
const callContext = {
|
|
3735
|
+
signal: config.signal ?? new AbortController().signal,
|
|
3736
|
+
run: {
|
|
3737
|
+
id: config.execution.runId,
|
|
3738
|
+
agentId: config.execution.agentId,
|
|
3739
|
+
scope,
|
|
3740
|
+
cwd
|
|
3741
|
+
},
|
|
3742
|
+
interact: async (interactionReq) => {
|
|
3743
|
+
const handler = config.runtime?.interact ?? config.interact;
|
|
3744
|
+
if (!handler) {
|
|
3745
|
+
throw new Error("Run interactions are not supported in this runtime.");
|
|
3746
|
+
}
|
|
3747
|
+
return handler(interactionReq);
|
|
3748
|
+
},
|
|
3749
|
+
tools: {
|
|
3750
|
+
list: () => {
|
|
3751
|
+
const tools = phaseContext.tools.filter((tool) => tool.name !== PhaseRouteTool);
|
|
3752
|
+
return tools.map((t) => ({
|
|
3753
|
+
name: t.name,
|
|
3754
|
+
description: t.description,
|
|
3755
|
+
parameters: t.parameters,
|
|
3756
|
+
...t._meta !== void 0 ? { _meta: t._meta } : {}
|
|
3757
|
+
}));
|
|
3758
|
+
},
|
|
3759
|
+
call: async (name, args, options2) => {
|
|
3760
|
+
const toolCallId = createId("call");
|
|
3761
|
+
const toolCall = {
|
|
3762
|
+
id: toolCallId,
|
|
3763
|
+
name,
|
|
3764
|
+
args
|
|
3765
|
+
};
|
|
3766
|
+
const res = await executePhaseTool(phaseContext, toolCall, options2);
|
|
3767
|
+
return res.ok ? { ok: true, content: res.content } : { ok: false, error: res.error ?? "Tool execution failed", ...res.content !== void 0 ? { content: res.content } : {} };
|
|
3768
|
+
},
|
|
3769
|
+
report: (update) => {
|
|
3770
|
+
config.onToolReport?.({
|
|
3771
|
+
runId: config.execution.runId,
|
|
3772
|
+
update
|
|
3773
|
+
});
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
};
|
|
3267
3777
|
const result = await runTurn(
|
|
3268
3778
|
() => withRetry(
|
|
3269
3779
|
() => invokeModel({
|
|
@@ -3272,12 +3782,21 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
|
|
|
3272
3782
|
request,
|
|
3273
3783
|
phaseId: phase.name,
|
|
3274
3784
|
output: options.output,
|
|
3275
|
-
onThinkingDelta: config.onThinkingDelta
|
|
3785
|
+
onThinkingDelta: config.onThinkingDelta,
|
|
3786
|
+
onToolCallDelta: config.onToolCallDelta,
|
|
3787
|
+
callContext
|
|
3276
3788
|
}),
|
|
3277
3789
|
{
|
|
3278
3790
|
signal: config.signal,
|
|
3279
|
-
|
|
3791
|
+
retryDelayMs: config.retryDelayMs,
|
|
3792
|
+
onRetry: (attempt, error, delayMs, maxRetries) => {
|
|
3280
3793
|
state.metrics.retryCount++;
|
|
3794
|
+
config.onModelRetry?.({
|
|
3795
|
+
attempt,
|
|
3796
|
+
maxRetries,
|
|
3797
|
+
delayMs,
|
|
3798
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3799
|
+
});
|
|
3281
3800
|
}
|
|
3282
3801
|
}
|
|
3283
3802
|
)
|
|
@@ -3288,27 +3807,7 @@ function createPhaseExecution(config, state, phase, messageManager, toolExecutio
|
|
|
3288
3807
|
async reportStatus(status) {
|
|
3289
3808
|
await config.onPhaseStatus?.(phase.name, status);
|
|
3290
3809
|
},
|
|
3291
|
-
|
|
3292
|
-
return runTurn(async () => {
|
|
3293
|
-
await toolExecutionManager.start(toolCall.id, toolCall.name, toolCall.args);
|
|
3294
|
-
const tools = phaseContext.tools.filter((tool) => tool.name !== PhaseRouteTool);
|
|
3295
|
-
const result = await executeToolCall({
|
|
3296
|
-
config: {
|
|
3297
|
-
...config,
|
|
3298
|
-
context: {
|
|
3299
|
-
...config.context,
|
|
3300
|
-
tools,
|
|
3301
|
-
skills: phaseContext.skills
|
|
3302
|
-
}
|
|
3303
|
-
},
|
|
3304
|
-
tools,
|
|
3305
|
-
toolCall,
|
|
3306
|
-
driver: interaction
|
|
3307
|
-
});
|
|
3308
|
-
await toolExecutionManager.end(result.toolCallId, result.toolName, result, !result.ok);
|
|
3309
|
-
return result;
|
|
3310
|
-
});
|
|
3311
|
-
},
|
|
3810
|
+
executeTool: executePhaseTool,
|
|
3312
3811
|
async executeTools(phaseContext, toolCalls, contentBlocks) {
|
|
3313
3812
|
return runTurn(async () => {
|
|
3314
3813
|
const tools = phaseContext.tools.filter((tool) => tool.name !== PhaseRouteTool);
|
|
@@ -3571,10 +4070,14 @@ async function executeOnce(input) {
|
|
|
3571
4070
|
onParallelPhaseOutput: input.onParallelPhaseOutput,
|
|
3572
4071
|
onMessageDelta: input.onMessageDelta,
|
|
3573
4072
|
onThinkingDelta: input.onThinkingDelta,
|
|
4073
|
+
onToolCallDelta: input.onToolCallDelta,
|
|
4074
|
+
onModelRetry: input.onModelRetry,
|
|
4075
|
+
retryDelayMs: input.retryDelayMs,
|
|
3574
4076
|
onOutcome: input.onOutcome,
|
|
3575
4077
|
onModelTranscript: input.onModelTranscript,
|
|
3576
4078
|
onPhaseEntered: input.onPhaseEntered,
|
|
3577
4079
|
onPhaseStatus: input.onPhaseStatus,
|
|
4080
|
+
onToolReport: input.onToolReport,
|
|
3578
4081
|
runtime: input.runtime,
|
|
3579
4082
|
waitForInput: async (nextState, request) => {
|
|
3580
4083
|
if (!nextState || !request) throw new Error("Input boundary did not include execution state.");
|
|
@@ -3665,6 +4168,46 @@ function isContinuation(value) {
|
|
|
3665
4168
|
return value.previousResults.every((result) => isRecord2(result) && typeof result.name === "string" && (result.output === void 0 || isJsonValue(result.output))) && (value.pendingInstruction === void 0 || typeof value.pendingInstruction === "string") && (value.previousPhaseMessageId === void 0 || typeof value.previousPhaseMessageId === "string");
|
|
3666
4169
|
}
|
|
3667
4170
|
|
|
4171
|
+
// src/runtime/tool-call-merge.ts
|
|
4172
|
+
function isValidPresentationOutput(output) {
|
|
4173
|
+
if (typeof output !== "object" || output === null || Array.isArray(output)) return false;
|
|
4174
|
+
const o = output;
|
|
4175
|
+
if (o.title !== void 0 && typeof o.title !== "string") return false;
|
|
4176
|
+
if (o.locations !== void 0) {
|
|
4177
|
+
if (!Array.isArray(o.locations)) return false;
|
|
4178
|
+
for (const loc of o.locations) {
|
|
4179
|
+
if (typeof loc !== "object" || loc === null || typeof loc.path !== "string") return false;
|
|
4180
|
+
if (loc.line !== void 0 && typeof loc.line !== "number") return false;
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
if (o.content !== void 0) {
|
|
4184
|
+
if (!Array.isArray(o.content)) return false;
|
|
4185
|
+
for (const c of o.content) {
|
|
4186
|
+
if (typeof c !== "object" || c === null || typeof c.type !== "string") return false;
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
if (o._meta !== void 0) {
|
|
4190
|
+
if (typeof o._meta !== "object" || o._meta === null || Array.isArray(o._meta)) return false;
|
|
4191
|
+
}
|
|
4192
|
+
return true;
|
|
4193
|
+
}
|
|
4194
|
+
function mergeToolCall(target, patch) {
|
|
4195
|
+
if (patch.title !== void 0) target.title = patch.title;
|
|
4196
|
+
if (patch.kind !== void 0) target.kind = patch.kind;
|
|
4197
|
+
if (patch.status !== void 0) target.status = patch.status;
|
|
4198
|
+
if (patch.locations !== void 0) target.locations = structuredClone(patch.locations);
|
|
4199
|
+
if (patch.content !== void 0) target.content = structuredClone(patch.content);
|
|
4200
|
+
if (patch.rawInput !== void 0) target.rawInput = structuredClone(patch.rawInput);
|
|
4201
|
+
if (patch.rawOutput !== void 0) target.rawOutput = structuredClone(patch.rawOutput);
|
|
4202
|
+
if (patch._meta !== void 0) {
|
|
4203
|
+
target._meta = {
|
|
4204
|
+
...target._meta ?? {},
|
|
4205
|
+
...structuredClone(patch._meta)
|
|
4206
|
+
};
|
|
4207
|
+
}
|
|
4208
|
+
return target;
|
|
4209
|
+
}
|
|
4210
|
+
|
|
3668
4211
|
// src/runtime/contracts.ts
|
|
3669
4212
|
var THINKING_LEVELS = [
|
|
3670
4213
|
"off",
|
|
@@ -3675,23 +4218,8 @@ var THINKING_LEVELS = [
|
|
|
3675
4218
|
"xhigh",
|
|
3676
4219
|
"max"
|
|
3677
4220
|
];
|
|
3678
|
-
function
|
|
3679
|
-
|
|
3680
|
-
const mori = record?.mori;
|
|
3681
|
-
if (!isRecord3(mori)) return void 0;
|
|
3682
|
-
const level = mori.thinkingLevel;
|
|
3683
|
-
return typeof level === "string" && THINKING_LEVELS.includes(level) ? level : void 0;
|
|
3684
|
-
}
|
|
3685
|
-
function thinkingLevelFromMessages(messages) {
|
|
3686
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
3687
|
-
const message = messages[index];
|
|
3688
|
-
if (message?.role !== "user") continue;
|
|
3689
|
-
const metadata = message.metadata;
|
|
3690
|
-
const kind = isRecord3(metadata) && typeof metadata.kind === "string" ? metadata.kind : void 0;
|
|
3691
|
-
if (kind === "phase_prompt" || kind === "phase_input") continue;
|
|
3692
|
-
return thinkingLevelFromMetadata(metadata);
|
|
3693
|
-
}
|
|
3694
|
-
return void 0;
|
|
4221
|
+
function thinkingLevelFromUserInput(input) {
|
|
4222
|
+
return typeof input === "string" ? void 0 : input.thinkingLevel;
|
|
3695
4223
|
}
|
|
3696
4224
|
var METADATA_LIMIT = 64 * 1024;
|
|
3697
4225
|
var IDENTITY_LIMIT = 256;
|
|
@@ -3747,8 +4275,13 @@ function isAssistantContent(value) {
|
|
|
3747
4275
|
}
|
|
3748
4276
|
function normalizeUserInput(input) {
|
|
3749
4277
|
const normalized = typeof input === "string" ? { content: input } : input;
|
|
3750
|
-
if (!isRecord3(normalized) || !hasOnlyKeys(normalized, ["content", "metadata"]) || !isUserContent(normalized.content))
|
|
4278
|
+
if (!isRecord3(normalized) || !hasOnlyKeys(normalized, ["content", "metadata", "thinkingLevel"]) || !isUserContent(normalized.content)) {
|
|
4279
|
+
throw new TypeError("input must contain only valid UserContent");
|
|
4280
|
+
}
|
|
3751
4281
|
if (normalized.metadata !== void 0) assertMetadata(normalized.metadata, "input.metadata");
|
|
4282
|
+
if (normalized.thinkingLevel !== void 0 && !THINKING_LEVELS.includes(normalized.thinkingLevel)) {
|
|
4283
|
+
throw new TypeError("input.thinkingLevel must be a valid ThinkingLevel");
|
|
4284
|
+
}
|
|
3752
4285
|
assertJsonValue(normalized, "input");
|
|
3753
4286
|
return normalized;
|
|
3754
4287
|
}
|
|
@@ -3756,9 +4289,16 @@ function isAssistantMessage(value) {
|
|
|
3756
4289
|
return isRecord3(value) && hasOnlyKeys(value, ["id", "agentId", "runId", "messageRevision", "role", "content", "metadata", "sequenceWithinRun", "createdAt", "interrupted"]) && typeof value.id === "string" && typeof value.agentId === "string" && typeof value.runId === "string" && value.role === "assistant" && (value.messageRevision === void 0 || Number.isInteger(value.messageRevision) && value.messageRevision >= 0) && Number.isInteger(value.sequenceWithinRun) && value.sequenceWithinRun >= 0 && typeof value.createdAt === "string" && isAssistantContent(value.content) && (value.metadata === void 0 || isMetadata(value.metadata)) && (value.interrupted === void 0 || typeof value.interrupted === "boolean");
|
|
3757
4290
|
}
|
|
3758
4291
|
function isToolResult(value) {
|
|
3759
|
-
if (!isRecord3(value)
|
|
4292
|
+
if (!isRecord3(value)) return false;
|
|
4293
|
+
if (value.structuredContent !== void 0 && !isJsonValue(value.structuredContent)) return false;
|
|
4294
|
+
if (Array.isArray(value.content)) {
|
|
4295
|
+
if (value.isError !== void 0 && typeof value.isError !== "boolean") return false;
|
|
4296
|
+
return true;
|
|
4297
|
+
}
|
|
4298
|
+
if (!isJsonValue(value.content) || typeof value.ok !== "boolean") return false;
|
|
4299
|
+
const keys = Object.keys(value).filter((k) => k !== "structuredContent").sort();
|
|
3760
4300
|
const expected = value.ok ? ["content", "ok"] : ["content", "error", "ok"];
|
|
3761
|
-
if (JSON.stringify(
|
|
4301
|
+
if (JSON.stringify(keys) !== JSON.stringify(expected)) return false;
|
|
3762
4302
|
return value.ok || typeof value.error === "string";
|
|
3763
4303
|
}
|
|
3764
4304
|
function assertAgentConfiguration(config) {
|
|
@@ -3931,17 +4471,20 @@ function encodeIdempotencyScope(storeIncarnation, scope) {
|
|
|
3931
4471
|
if (typeof storeIncarnation !== "string" || storeIncarnation.length === 0) throw new TypeError("storeIncarnation must be non-empty");
|
|
3932
4472
|
return canonicalJson([storeIncarnation, ...scope]);
|
|
3933
4473
|
}
|
|
3934
|
-
function canonicalStartRunRequest(input, metadata, phasePayload, pinnedConfigToken, entryPhases) {
|
|
4474
|
+
function canonicalStartRunRequest(input, metadata, phasePayload, pinnedConfigToken, entryPhases, scope, cwd) {
|
|
3935
4475
|
const normalized = normalizeUserInput(input);
|
|
3936
4476
|
if (metadata !== void 0) assertUtf8ByteLimit(canonicalJson(metadata), METADATA_JSON_BYTES, "run.metadata");
|
|
3937
4477
|
if (phasePayload !== void 0) assertUtf8ByteLimit(canonicalJson(phasePayload), MESSAGE_CONTENT_JSON_BYTES, "run.phasePayload");
|
|
3938
4478
|
if (entryPhases !== void 0) assertUtf8ByteLimit(canonicalJson(entryPhases), MESSAGE_CONTENT_JSON_BYTES, "run.entryPhases");
|
|
4479
|
+
if (cwd !== void 0 && typeof cwd !== "string") throw new TypeError("run.cwd must be a string");
|
|
3939
4480
|
return canonicalJson({
|
|
3940
4481
|
input: normalized,
|
|
3941
4482
|
...metadata === void 0 ? {} : { metadata },
|
|
3942
4483
|
...phasePayload === void 0 ? {} : { phasePayload },
|
|
3943
4484
|
...entryPhases === void 0 ? {} : { entryPhases },
|
|
3944
|
-
...pinnedConfigToken === void 0 ? {} : { pinnedConfigToken }
|
|
4485
|
+
...pinnedConfigToken === void 0 ? {} : { pinnedConfigToken },
|
|
4486
|
+
...scope === void 0 ? {} : { scope },
|
|
4487
|
+
...cwd === void 0 ? {} : { cwd }
|
|
3945
4488
|
});
|
|
3946
4489
|
}
|
|
3947
4490
|
|
|
@@ -4483,7 +5026,8 @@ function projectToolMessage(message, toolInteractionTexts) {
|
|
|
4483
5026
|
id: message.id,
|
|
4484
5027
|
role: message.role,
|
|
4485
5028
|
content: message.content.map((part) => {
|
|
4486
|
-
const
|
|
5029
|
+
const isError = "isError" in part.result ? Boolean(part.result.isError) : !part.result.ok;
|
|
5030
|
+
const rawResult = Array.isArray(part.result.content) ? part.result.content.map((block) => block?.type === "text" ? block.text : JSON.stringify(block)).join("\n\n") : jsonText(part.result.content);
|
|
4487
5031
|
const interactionTexts = toolInteractionTexts.get(String(part.toolCallId));
|
|
4488
5032
|
let content = rawResult;
|
|
4489
5033
|
if (interactionTexts && interactionTexts.length > 0) {
|
|
@@ -4496,7 +5040,7 @@ ${rawResult}`;
|
|
|
4496
5040
|
type: "tool_result",
|
|
4497
5041
|
toolUseId: part.providerToolCallId ?? String(part.toolCallId),
|
|
4498
5042
|
content,
|
|
4499
|
-
...
|
|
5043
|
+
...isError ? { isError: true } : {}
|
|
4500
5044
|
};
|
|
4501
5045
|
}),
|
|
4502
5046
|
createdAt: message.createdAt,
|
|
@@ -4528,12 +5072,16 @@ function projectAssistantContent(content) {
|
|
|
4528
5072
|
});
|
|
4529
5073
|
}
|
|
4530
5074
|
function projectToolContent(content) {
|
|
4531
|
-
return content.map((part) =>
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
5075
|
+
return content.map((part) => {
|
|
5076
|
+
const isError = "isError" in part.result ? Boolean(part.result.isError) : !part.result.ok;
|
|
5077
|
+
const textContent = Array.isArray(part.result.content) ? part.result.content.map((block) => block?.type === "text" ? block.text : JSON.stringify(block)).join("\n\n") : jsonText(part.result.content);
|
|
5078
|
+
return {
|
|
5079
|
+
type: "tool_result",
|
|
5080
|
+
toolUseId: part.providerToolCallId ?? part.toolCallId,
|
|
5081
|
+
content: textContent,
|
|
5082
|
+
...isError ? { isError: true } : {}
|
|
5083
|
+
};
|
|
5084
|
+
});
|
|
4537
5085
|
}
|
|
4538
5086
|
function inertRunInteraction(signal) {
|
|
4539
5087
|
const controller = signal ? void 0 : new AbortController();
|
|
@@ -4562,15 +5110,18 @@ function projectTool(tool, agentId, runId) {
|
|
|
4562
5110
|
parameters: tool.parameters,
|
|
4563
5111
|
...tool.promptSnippet ? { promptSnippet: tool.promptSnippet } : {},
|
|
4564
5112
|
...tool.promptGuidelines ? { promptGuidelines: [...tool.promptGuidelines] } : {},
|
|
5113
|
+
...tool._meta !== void 0 ? { _meta: tool._meta } : {},
|
|
4565
5114
|
execute: async (args, context, signal) => {
|
|
4566
5115
|
const result = await tool.execute(args, {
|
|
4567
5116
|
agentId,
|
|
4568
5117
|
runId,
|
|
4569
5118
|
toolCallId: context.toolCallId,
|
|
5119
|
+
providerToolCallId: context.toolCallId,
|
|
4570
5120
|
reportProgress: () => void 0,
|
|
4571
5121
|
interaction: context.interaction ?? inertRunInteraction(signal)
|
|
4572
5122
|
}, signal ?? new AbortController().signal);
|
|
4573
|
-
|
|
5123
|
+
const ok = "ok" in result && typeof result.ok === "boolean" ? result.ok : !result.isError;
|
|
5124
|
+
return { toolCallId: context.toolCallId, toolName: tool.name, ok, ...result };
|
|
4574
5125
|
}
|
|
4575
5126
|
};
|
|
4576
5127
|
}
|
|
@@ -4665,20 +5216,38 @@ function resolveDefinitionContext(snapshot, assembled) {
|
|
|
4665
5216
|
systemPrompt: [snapshot.definition.prompt, buildContextDescription(contexts)].filter((section) => section.length > 0).join("\n\n"),
|
|
4666
5217
|
tools,
|
|
4667
5218
|
skills,
|
|
4668
|
-
phases: { phases, entryPhaseId }
|
|
5219
|
+
phases: { phases, entryPhaseId },
|
|
5220
|
+
...snapshot.cwd ? { cwd: snapshot.cwd } : {}
|
|
4669
5221
|
};
|
|
4670
5222
|
}
|
|
4671
5223
|
function toLoopResult(result, toolCallId, toolName) {
|
|
5224
|
+
const ok = "ok" in result && typeof result.ok === "boolean" ? result.ok : !result.isError;
|
|
5225
|
+
const error = "error" in result && typeof result.error === "string" ? result.error : void 0;
|
|
4672
5226
|
return {
|
|
4673
5227
|
toolCallId,
|
|
4674
5228
|
toolName,
|
|
4675
|
-
ok
|
|
5229
|
+
ok,
|
|
4676
5230
|
content: result.content,
|
|
4677
|
-
...!
|
|
5231
|
+
...!ok && error ? { error } : {},
|
|
5232
|
+
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {},
|
|
5233
|
+
...result.isError !== void 0 ? { isError: result.isError } : {}
|
|
4678
5234
|
};
|
|
4679
5235
|
}
|
|
4680
5236
|
function fromLoopResult(result) {
|
|
4681
|
-
|
|
5237
|
+
if (Array.isArray(result.content)) {
|
|
5238
|
+
return {
|
|
5239
|
+
content: result.content,
|
|
5240
|
+
...result.ok !== void 0 ? { ok: result.ok } : {},
|
|
5241
|
+
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {},
|
|
5242
|
+
...result.isError !== void 0 ? { isError: result.isError } : !result.ok ? { isError: true } : {},
|
|
5243
|
+
...result.error !== void 0 ? { error: result.error } : {}
|
|
5244
|
+
};
|
|
5245
|
+
}
|
|
5246
|
+
return {
|
|
5247
|
+
...result.ok ? { ok: true } : { ok: false, error: result.error ?? "Extension hook rejected the Tool result." },
|
|
5248
|
+
content: result.content,
|
|
5249
|
+
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {}
|
|
5250
|
+
};
|
|
4682
5251
|
}
|
|
4683
5252
|
|
|
4684
5253
|
// src/runtime/transient-run-events.ts
|
|
@@ -4709,6 +5278,34 @@ var TransientRunEventSubscription = class {
|
|
|
4709
5278
|
...previous,
|
|
4710
5279
|
text: previous.text + event.text
|
|
4711
5280
|
};
|
|
5281
|
+
} else if (
|
|
5282
|
+
// `arguments` accumulates, so the latest delta of a call replaces the one before.
|
|
5283
|
+
previous?.kind === "tool_call_delta" && event.kind === "tool_call_delta" && previous.executionId === event.executionId && previous.providerToolCallId === event.providerToolCallId
|
|
5284
|
+
) {
|
|
5285
|
+
this.queue[this.queue.length - 1] = event;
|
|
5286
|
+
} else if (event.kind === "tool_state_changed") {
|
|
5287
|
+
const toolCallId = event.toolCall.toolCallId;
|
|
5288
|
+
let index = -1;
|
|
5289
|
+
for (let i = this.queue.length - 1; i >= 0; i -= 1) {
|
|
5290
|
+
const existing = this.queue[i];
|
|
5291
|
+
if (existing && existing.kind === "tool_state_changed" && existing.runId === event.runId && existing.toolCall.toolCallId === toolCallId) {
|
|
5292
|
+
index = i;
|
|
5293
|
+
break;
|
|
5294
|
+
}
|
|
5295
|
+
}
|
|
5296
|
+
if (index !== -1) {
|
|
5297
|
+
const existing = this.queue[index];
|
|
5298
|
+
const mergedCall = { ...existing.toolCall };
|
|
5299
|
+
mergeToolCall(mergedCall, event.toolCall);
|
|
5300
|
+
this.queue[index] = {
|
|
5301
|
+
...existing,
|
|
5302
|
+
transition: { from: existing.transition.from, to: event.transition.to },
|
|
5303
|
+
toolCall: mergedCall
|
|
5304
|
+
};
|
|
5305
|
+
} else {
|
|
5306
|
+
if (this.queue.length >= MAX_BUFFERED_EVENTS) this.queue.shift();
|
|
5307
|
+
this.queue.push(event);
|
|
5308
|
+
}
|
|
4712
5309
|
} else {
|
|
4713
5310
|
if (this.queue.length >= MAX_BUFFERED_EVENTS) this.queue.shift();
|
|
4714
5311
|
this.queue.push(event);
|
|
@@ -4724,7 +5321,7 @@ var TransientRunEventSubscription = class {
|
|
|
4724
5321
|
else {
|
|
4725
5322
|
for (let index = this.queue.length - 1; index >= 0; index -= 1) {
|
|
4726
5323
|
const event = this.queue[index];
|
|
4727
|
-
if (event
|
|
5324
|
+
if (event && "executionId" in event && event.executionId === executionId && !(preserveCompletedPhaseStatus && event.kind === "phase_status" && event.status.state === "completed")) {
|
|
4728
5325
|
this.queue.splice(index, 1);
|
|
4729
5326
|
}
|
|
4730
5327
|
}
|
|
@@ -4734,14 +5331,14 @@ var TransientRunEventSubscription = class {
|
|
|
4734
5331
|
clearMessage(messageId) {
|
|
4735
5332
|
for (let index = this.queue.length - 1; index >= 0; index -= 1) {
|
|
4736
5333
|
const event = this.queue[index];
|
|
4737
|
-
if ((event?.kind === "message_delta" || event?.kind === "thinking_delta") && event.messageId === messageId) this.queue.splice(index, 1);
|
|
5334
|
+
if ((event?.kind === "message_delta" || event?.kind === "thinking_delta" || event?.kind === "tool_call_delta") && event.messageId === messageId) this.queue.splice(index, 1);
|
|
4738
5335
|
}
|
|
4739
5336
|
this.notify();
|
|
4740
5337
|
}
|
|
4741
5338
|
clearTool(toolCallId) {
|
|
4742
5339
|
for (let index = this.queue.length - 1; index >= 0; index -= 1) {
|
|
4743
5340
|
const event = this.queue[index];
|
|
4744
|
-
if (event?.kind === "
|
|
5341
|
+
if (event?.kind === "tool_state_changed" && event.toolCall.toolCallId === toolCallId) this.queue.splice(index, 1);
|
|
4745
5342
|
}
|
|
4746
5343
|
this.notify();
|
|
4747
5344
|
}
|
|
@@ -4885,6 +5482,7 @@ var HooksManager = class {
|
|
|
4885
5482
|
var InMemoryExtensionHost = class {
|
|
4886
5483
|
configs = /* @__PURE__ */ new Map();
|
|
4887
5484
|
agentState = /* @__PURE__ */ new Map();
|
|
5485
|
+
globalState = /* @__PURE__ */ new Map();
|
|
4888
5486
|
listeners = /* @__PURE__ */ new Set();
|
|
4889
5487
|
constructor(options = {}) {
|
|
4890
5488
|
if (options.configs) {
|
|
@@ -4911,8 +5509,18 @@ var InMemoryExtensionHost = class {
|
|
|
4911
5509
|
this.agentState.set(agentId, agentMap);
|
|
4912
5510
|
}
|
|
4913
5511
|
}
|
|
5512
|
+
if (options.globalState) {
|
|
5513
|
+
for (const [extId, stateMap] of Object.entries(options.globalState)) {
|
|
5514
|
+
const map = /* @__PURE__ */ new Map();
|
|
5515
|
+
for (const [key, val] of Object.entries(stateMap)) {
|
|
5516
|
+
assertJsonValue(val);
|
|
5517
|
+
map.set(key, structuredClone(val));
|
|
5518
|
+
}
|
|
5519
|
+
this.globalState.set(extId, map);
|
|
5520
|
+
}
|
|
5521
|
+
}
|
|
4914
5522
|
}
|
|
4915
|
-
setConfig(extensionId, config, scope =
|
|
5523
|
+
setConfig(extensionId, config, scope = []) {
|
|
4916
5524
|
const scopeKey = scopeToKey(scope);
|
|
4917
5525
|
if (!this.configs.has(scopeKey)) {
|
|
4918
5526
|
this.configs.set(scopeKey, /* @__PURE__ */ new Map());
|
|
@@ -4926,19 +5534,18 @@ var InMemoryExtensionHost = class {
|
|
|
4926
5534
|
}
|
|
4927
5535
|
this.notifyConfigChanged(extensionId, scope);
|
|
4928
5536
|
}
|
|
4929
|
-
getConfig(extensionId, scope =
|
|
5537
|
+
getConfig(extensionId, scope = []) {
|
|
5538
|
+
let merged = null;
|
|
4930
5539
|
const globalConfig = this.configs.get("global")?.get(extensionId);
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
const teamConfig = this.configs.get(`team:${scope.teamId}`)?.get(extensionId);
|
|
4934
|
-
if (teamConfig) {
|
|
4935
|
-
merged = { ...merged ?? {}, ...teamConfig };
|
|
4936
|
-
}
|
|
5540
|
+
if (globalConfig) {
|
|
5541
|
+
merged = { ...globalConfig };
|
|
4937
5542
|
}
|
|
4938
|
-
|
|
4939
|
-
const
|
|
4940
|
-
|
|
4941
|
-
|
|
5543
|
+
for (let i = 1; i <= scope.length; i++) {
|
|
5544
|
+
const subScope = scope.slice(0, i);
|
|
5545
|
+
const key = scopeToKey(subScope);
|
|
5546
|
+
const layerConfig = this.configs.get(key)?.get(extensionId);
|
|
5547
|
+
if (layerConfig) {
|
|
5548
|
+
merged = { ...merged ?? {}, ...layerConfig };
|
|
4942
5549
|
}
|
|
4943
5550
|
}
|
|
4944
5551
|
return merged ? structuredClone(merged) : null;
|
|
@@ -4947,7 +5554,7 @@ var InMemoryExtensionHost = class {
|
|
|
4947
5554
|
this.listeners.add(listener);
|
|
4948
5555
|
return () => this.listeners.delete(listener);
|
|
4949
5556
|
}
|
|
4950
|
-
notifyConfigChanged(extensionId, scope =
|
|
5557
|
+
notifyConfigChanged(extensionId, scope = []) {
|
|
4951
5558
|
for (const listener of this.listeners) {
|
|
4952
5559
|
try {
|
|
4953
5560
|
listener(extensionId, scope);
|
|
@@ -4976,29 +5583,26 @@ var InMemoryExtensionHost = class {
|
|
|
4976
5583
|
deleteAgentState(extensionId, agentId, key) {
|
|
4977
5584
|
this.agentState.get(agentId)?.get(extensionId)?.delete(key);
|
|
4978
5585
|
}
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
case "global":
|
|
4983
|
-
return "global";
|
|
4984
|
-
case "team":
|
|
4985
|
-
return `team:${scope.teamId}`;
|
|
4986
|
-
case "project":
|
|
4987
|
-
return `project:${scope.teamId}:${scope.projectId}`;
|
|
5586
|
+
getGlobalState(extensionId, key) {
|
|
5587
|
+
const val = this.globalState.get(extensionId)?.get(key);
|
|
5588
|
+
return val !== void 0 ? structuredClone(val) : void 0;
|
|
4988
5589
|
}
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
return { kind: "project", teamId, projectId };
|
|
4996
|
-
}
|
|
4997
|
-
if (teamId) {
|
|
4998
|
-
return { kind: "team", teamId };
|
|
5590
|
+
setGlobalState(extensionId, key, value) {
|
|
5591
|
+
assertJsonValue(value);
|
|
5592
|
+
let extMap = this.globalState.get(extensionId);
|
|
5593
|
+
if (!extMap) {
|
|
5594
|
+
extMap = /* @__PURE__ */ new Map();
|
|
5595
|
+
this.globalState.set(extensionId, extMap);
|
|
4999
5596
|
}
|
|
5597
|
+
extMap.set(key, structuredClone(value));
|
|
5598
|
+
}
|
|
5599
|
+
deleteGlobalState(extensionId, key) {
|
|
5600
|
+
this.globalState.get(extensionId)?.delete(key);
|
|
5000
5601
|
}
|
|
5001
|
-
|
|
5602
|
+
};
|
|
5603
|
+
function scopeToKey(scope) {
|
|
5604
|
+
if (scope.length === 0) return "global";
|
|
5605
|
+
return scope.map((layer) => `${layer.kind}:${layer.id}`).join("/");
|
|
5002
5606
|
}
|
|
5003
5607
|
|
|
5004
5608
|
// src/extensions/runner.ts
|
|
@@ -5112,8 +5716,9 @@ async function execCommand(command, args, cwd, options) {
|
|
|
5112
5716
|
});
|
|
5113
5717
|
}
|
|
5114
5718
|
function applyProviderRegistration(config) {
|
|
5115
|
-
|
|
5116
|
-
|
|
5719
|
+
unregisterProviderModels(config.id);
|
|
5720
|
+
if (config.stream) {
|
|
5721
|
+
registerApiProvider({ protocol: config.protocol, stream: config.stream });
|
|
5117
5722
|
}
|
|
5118
5723
|
for (const modelConfig of config.models) {
|
|
5119
5724
|
registerModel({
|
|
@@ -5123,12 +5728,13 @@ function applyProviderRegistration(config) {
|
|
|
5123
5728
|
provider: config.id,
|
|
5124
5729
|
baseUrl: config.baseUrl,
|
|
5125
5730
|
apiKey: config.apiKey,
|
|
5126
|
-
reasoning: modelConfig.reasoning,
|
|
5731
|
+
reasoning: modelConfig.reasoning ?? false,
|
|
5127
5732
|
...modelConfig.thinkingLevel !== void 0 ? { thinkingLevel: modelConfig.thinkingLevel } : {},
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5733
|
+
...modelConfig.thinkingLevels !== void 0 ? { thinkingLevels: modelConfig.thinkingLevels } : {},
|
|
5734
|
+
input: modelConfig.input ?? ["text"],
|
|
5735
|
+
cost: modelConfig.cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
5736
|
+
contextWindow: modelConfig.contextWindow ?? 128e3,
|
|
5737
|
+
maxTokens: modelConfig.maxTokens ?? 4096,
|
|
5132
5738
|
...config.headers || modelConfig.headers ? { headers: { ...config.headers, ...modelConfig.headers } } : {},
|
|
5133
5739
|
...config.timeoutMs !== void 0 ? { timeoutMs: config.timeoutMs } : {},
|
|
5134
5740
|
...config.maxRetries !== void 0 ? { maxRetries: config.maxRetries } : {},
|
|
@@ -5164,6 +5770,8 @@ var ExtensionRunner = class {
|
|
|
5164
5770
|
errorListeners = /* @__PURE__ */ new Set();
|
|
5165
5771
|
// Capability change listeners
|
|
5166
5772
|
capabilityListeners = /* @__PURE__ */ new Set();
|
|
5773
|
+
// UI contribution change listeners
|
|
5774
|
+
uiContributionListeners = /* @__PURE__ */ new Set();
|
|
5167
5775
|
/** Current agent context — set by the agent before each phase */
|
|
5168
5776
|
currentContext;
|
|
5169
5777
|
constructor(options) {
|
|
@@ -5267,6 +5875,7 @@ var ExtensionRunner = class {
|
|
|
5267
5875
|
tools: /* @__PURE__ */ new Map(),
|
|
5268
5876
|
phases: /* @__PURE__ */ new Set(),
|
|
5269
5877
|
capabilities: /* @__PURE__ */ new Map(),
|
|
5878
|
+
uiContributions: /* @__PURE__ */ new Map(),
|
|
5270
5879
|
cleanup: [],
|
|
5271
5880
|
runtime: createExtensionRuntime()
|
|
5272
5881
|
};
|
|
@@ -5279,6 +5888,9 @@ var ExtensionRunner = class {
|
|
|
5279
5888
|
if (extension.capabilities.size > 0) {
|
|
5280
5889
|
this.notifyCapabilitiesChanged();
|
|
5281
5890
|
}
|
|
5891
|
+
if (extension.uiContributions.size > 0) {
|
|
5892
|
+
this.notifyUiContributionsChanged();
|
|
5893
|
+
}
|
|
5282
5894
|
} catch (error) {
|
|
5283
5895
|
await this.rollbackExtension(extension);
|
|
5284
5896
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -5407,9 +6019,30 @@ var ExtensionRunner = class {
|
|
|
5407
6019
|
this.capabilityListeners.add(listener);
|
|
5408
6020
|
return () => this.capabilityListeners.delete(listener);
|
|
5409
6021
|
}
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
6022
|
+
/** Get all contributed UI elements across all extensions. */
|
|
6023
|
+
getUiContributions() {
|
|
6024
|
+
const result = [];
|
|
6025
|
+
for (const ext of this.extensions) {
|
|
6026
|
+
for (const contrib of ext.uiContributions.values()) {
|
|
6027
|
+
result.push(contrib);
|
|
6028
|
+
}
|
|
6029
|
+
}
|
|
6030
|
+
return Object.freeze(result);
|
|
6031
|
+
}
|
|
6032
|
+
/**
|
|
6033
|
+
* Subscribe to UI contribution changes (contributions added, removed, or extensions disposed).
|
|
6034
|
+
* Returns an unsubscribe function.
|
|
6035
|
+
*/
|
|
6036
|
+
onUiContributionsChanged(listener) {
|
|
6037
|
+
this.uiContributionListeners.add(listener);
|
|
6038
|
+
return () => this.uiContributionListeners.delete(listener);
|
|
6039
|
+
}
|
|
6040
|
+
triggerUiAction(event) {
|
|
6041
|
+
this.events.emit("ui.action", event);
|
|
6042
|
+
}
|
|
6043
|
+
// ---------------------------------------------------------------------------
|
|
6044
|
+
// Phase management
|
|
6045
|
+
// ---------------------------------------------------------------------------
|
|
5413
6046
|
getPhase(name) {
|
|
5414
6047
|
const reg = this.getRegisteredPhase(name);
|
|
5415
6048
|
if (!reg) return void 0;
|
|
@@ -5524,7 +6157,7 @@ var ExtensionRunner = class {
|
|
|
5524
6157
|
}
|
|
5525
6158
|
}
|
|
5526
6159
|
async emitBeforeToolCall(tool, args, context) {
|
|
5527
|
-
const scope = context?.scope ??
|
|
6160
|
+
const scope = context?.scope ?? [];
|
|
5528
6161
|
const turn = context?.turn ?? {};
|
|
5529
6162
|
const result = await this.emitHook("before_tool_call", {
|
|
5530
6163
|
type: "before_tool_call",
|
|
@@ -5541,7 +6174,7 @@ var ExtensionRunner = class {
|
|
|
5541
6174
|
return result ?? { allow: true };
|
|
5542
6175
|
}
|
|
5543
6176
|
async emitAfterToolCall(tool, result, context) {
|
|
5544
|
-
const scope = context?.scope ??
|
|
6177
|
+
const scope = context?.scope ?? [];
|
|
5545
6178
|
const turn = context?.turn ?? {};
|
|
5546
6179
|
const hookResult = await this.emitHook("after_tool_call", {
|
|
5547
6180
|
type: "after_tool_call",
|
|
@@ -5621,12 +6254,13 @@ var ExtensionRunner = class {
|
|
|
5621
6254
|
registerTool: (tool) => this.registerTool(extension, tool),
|
|
5622
6255
|
unregisterTool: (toolName) => this.unregisterTool(extension, toolName),
|
|
5623
6256
|
contributeCapability: (contribution) => this.contributeCapability(extension, contribution),
|
|
6257
|
+
contributeUi: (contribution) => this.contributeUi(extension, contribution),
|
|
5624
6258
|
context: extContext,
|
|
5625
6259
|
manifest,
|
|
5626
6260
|
trackCleanup: (cleanup) => extension.cleanup.push(cleanup),
|
|
5627
6261
|
config: {
|
|
5628
6262
|
get: async (scope) => {
|
|
5629
|
-
const effectiveScope = scope ??
|
|
6263
|
+
const effectiveScope = scope ?? [];
|
|
5630
6264
|
const res = await runner.host.getConfig(extension.id, effectiveScope);
|
|
5631
6265
|
return res ?? null;
|
|
5632
6266
|
},
|
|
@@ -5655,6 +6289,11 @@ var ExtensionRunner = class {
|
|
|
5655
6289
|
get: async (key) => runner.host.getAgentState(extension.id, agentId, key),
|
|
5656
6290
|
set: async (key, value) => runner.host.setAgentState(extension.id, agentId, key, value),
|
|
5657
6291
|
delete: async (key) => runner.host.deleteAgentState(extension.id, agentId, key)
|
|
6292
|
+
}),
|
|
6293
|
+
global: () => ({
|
|
6294
|
+
get: async (key) => runner.host.getGlobalState(extension.id, key),
|
|
6295
|
+
set: async (key, value) => runner.host.setGlobalState(extension.id, key, value),
|
|
6296
|
+
delete: async (key) => runner.host.deleteGlobalState(extension.id, key)
|
|
5658
6297
|
})
|
|
5659
6298
|
}
|
|
5660
6299
|
}, extension.runtime, this.events);
|
|
@@ -5725,6 +6364,44 @@ var ExtensionRunner = class {
|
|
|
5725
6364
|
}
|
|
5726
6365
|
}
|
|
5727
6366
|
}
|
|
6367
|
+
contributeUi(extension, contribution) {
|
|
6368
|
+
const key = `${contribution.slot}:${contribution.id}`;
|
|
6369
|
+
const entry = {
|
|
6370
|
+
...contribution
|
|
6371
|
+
};
|
|
6372
|
+
extension.uiContributions.set(key, entry);
|
|
6373
|
+
if (this.extensions.includes(extension)) {
|
|
6374
|
+
this.notifyUiContributionsChanged();
|
|
6375
|
+
}
|
|
6376
|
+
let disposed = false;
|
|
6377
|
+
const dispose = () => {
|
|
6378
|
+
if (disposed) return;
|
|
6379
|
+
disposed = true;
|
|
6380
|
+
if (extension.uiContributions.get(key) === entry) {
|
|
6381
|
+
extension.uiContributions.delete(key);
|
|
6382
|
+
if (this.extensions.includes(extension)) {
|
|
6383
|
+
this.notifyUiContributionsChanged();
|
|
6384
|
+
}
|
|
6385
|
+
}
|
|
6386
|
+
};
|
|
6387
|
+
extension.cleanup.push(dispose);
|
|
6388
|
+
return dispose;
|
|
6389
|
+
}
|
|
6390
|
+
notifyUiContributionsChanged() {
|
|
6391
|
+
const contributions = this.getUiContributions();
|
|
6392
|
+
for (const listener of this.uiContributionListeners) {
|
|
6393
|
+
try {
|
|
6394
|
+
listener(contributions);
|
|
6395
|
+
} catch (error) {
|
|
6396
|
+
this.emitError({
|
|
6397
|
+
extensionPath: "<runtime>",
|
|
6398
|
+
event: "ui_contributions_changed",
|
|
6399
|
+
error: error instanceof Error ? error.message : String(error),
|
|
6400
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
6401
|
+
});
|
|
6402
|
+
}
|
|
6403
|
+
}
|
|
6404
|
+
}
|
|
5728
6405
|
async registerPhase(extension, registration) {
|
|
5729
6406
|
if (typeof registration === "string") {
|
|
5730
6407
|
if (registration.length === 0) {
|
|
@@ -5813,6 +6490,8 @@ var ExtensionRunner = class {
|
|
|
5813
6490
|
for (const name of extension.phases) this.phases.delete(name);
|
|
5814
6491
|
const hadCapabilities = extension.capabilities.size > 0;
|
|
5815
6492
|
extension.capabilities.clear();
|
|
6493
|
+
const hadUiContributions = extension.uiContributions.size > 0;
|
|
6494
|
+
extension.uiContributions.clear();
|
|
5816
6495
|
for (const cleanup of [...extension.cleanup].reverse()) {
|
|
5817
6496
|
await Promise.resolve().then(() => cleanup()).catch(() => void 0);
|
|
5818
6497
|
}
|
|
@@ -5823,6 +6502,9 @@ var ExtensionRunner = class {
|
|
|
5823
6502
|
if (hadCapabilities) {
|
|
5824
6503
|
this.notifyCapabilitiesChanged();
|
|
5825
6504
|
}
|
|
6505
|
+
if (hadUiContributions) {
|
|
6506
|
+
this.notifyUiContributionsChanged();
|
|
6507
|
+
}
|
|
5826
6508
|
}
|
|
5827
6509
|
};
|
|
5828
6510
|
function createExtensionRunner(options) {
|
|
@@ -6515,11 +7197,11 @@ function adaptExtensionTool(input) {
|
|
|
6515
7197
|
parameters: definition.parameters,
|
|
6516
7198
|
...definition.promptSnippet ? { promptSnippet: definition.promptSnippet } : {},
|
|
6517
7199
|
...definition.promptGuidelines ? { promptGuidelines: definition.promptGuidelines } : {},
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
7200
|
+
...definition.kind ? { kind: definition.kind } : {},
|
|
7201
|
+
...definition.annotations ? { annotations: definition.annotations } : {},
|
|
7202
|
+
...definition._meta !== void 0 ? { _meta: definition._meta } : {},
|
|
7203
|
+
...definition.present ? { present: definition.present } : {},
|
|
7204
|
+
execute: async (args, context, signal) => definition.execute(args, context, signal)
|
|
6523
7205
|
};
|
|
6524
7206
|
}
|
|
6525
7207
|
|
|
@@ -6587,12 +7269,53 @@ async function spillLargeToolResult(result, archiveDir, toolName) {
|
|
|
6587
7269
|
await writeFile2(path, serialized, { encoding: "utf8", mode: 384 });
|
|
6588
7270
|
await chmod2(path, 384).catch(() => void 0);
|
|
6589
7271
|
const preview = new TextDecoder().decode(bytes.subarray(0, MAX_INLINE_TOOL_RESULT_BYTES));
|
|
6590
|
-
|
|
6591
|
-
...result,
|
|
6592
|
-
content: `${preview}
|
|
7272
|
+
const truncatedText = `${preview}
|
|
6593
7273
|
[truncated]
|
|
6594
7274
|
|
|
6595
|
-
[Full result: ${path}, offset 0]
|
|
7275
|
+
[Full result: ${path}, offset 0]`;
|
|
7276
|
+
if (Array.isArray(result.content)) {
|
|
7277
|
+
return {
|
|
7278
|
+
...result,
|
|
7279
|
+
content: [{ type: "text", text: truncatedText }]
|
|
7280
|
+
};
|
|
7281
|
+
}
|
|
7282
|
+
if (result.ok) {
|
|
7283
|
+
return {
|
|
7284
|
+
ok: true,
|
|
7285
|
+
content: truncatedText,
|
|
7286
|
+
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {}
|
|
7287
|
+
};
|
|
7288
|
+
}
|
|
7289
|
+
return {
|
|
7290
|
+
ok: false,
|
|
7291
|
+
content: truncatedText,
|
|
7292
|
+
error: result.error ?? "Tool execution failed.",
|
|
7293
|
+
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {}
|
|
7294
|
+
};
|
|
7295
|
+
}
|
|
7296
|
+
async function presentToolCall(tool, call) {
|
|
7297
|
+
if (!tool.present) return void 0;
|
|
7298
|
+
try {
|
|
7299
|
+
const res = await tool.present(call);
|
|
7300
|
+
if (!res) return void 0;
|
|
7301
|
+
if (!isValidPresentationOutput(res)) {
|
|
7302
|
+
console.warn(`Tool "${tool.name}" present() returned invalid shape for status "${call.status}":`, res);
|
|
7303
|
+
return void 0;
|
|
7304
|
+
}
|
|
7305
|
+
return res;
|
|
7306
|
+
} catch (err) {
|
|
7307
|
+
console.warn(`Tool "${tool.name}" present() threw for status "${call.status}":`, err);
|
|
7308
|
+
return void 0;
|
|
7309
|
+
}
|
|
7310
|
+
}
|
|
7311
|
+
async function presentToolPending(tool, args) {
|
|
7312
|
+
const pres = await presentToolCall(tool, { status: "pending", args });
|
|
7313
|
+
return {
|
|
7314
|
+
title: pres?.title ?? tool.annotations?.title ?? tool.name,
|
|
7315
|
+
kind: tool.kind ?? "other",
|
|
7316
|
+
...pres?.locations !== void 0 ? { locations: pres.locations } : {},
|
|
7317
|
+
...pres?.content !== void 0 ? { content: pres.content } : {},
|
|
7318
|
+
...pres?._meta !== void 0 ? { _meta: pres._meta } : {}
|
|
6596
7319
|
};
|
|
6597
7320
|
}
|
|
6598
7321
|
var AgentRuntime = class _AgentRuntime {
|
|
@@ -6611,9 +7334,11 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
6611
7334
|
host;
|
|
6612
7335
|
resources;
|
|
6613
7336
|
startedRuns = /* @__PURE__ */ new Set();
|
|
7337
|
+
liveInteractions = /* @__PURE__ */ new Map();
|
|
6614
7338
|
heartbeat;
|
|
6615
7339
|
pumping = false;
|
|
6616
7340
|
closed = false;
|
|
7341
|
+
retryDelayMs;
|
|
6617
7342
|
constructor(options, owned, resources) {
|
|
6618
7343
|
this.host = options.host;
|
|
6619
7344
|
this.owned = owned;
|
|
@@ -6621,6 +7346,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
6621
7346
|
this.storeIncarnation = String(owned.lease.token).split(":")[0];
|
|
6622
7347
|
this.concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
|
|
6623
7348
|
this.resources = resources;
|
|
7349
|
+
this.retryDelayMs = options.retryDelayMs;
|
|
6624
7350
|
}
|
|
6625
7351
|
static async init(options) {
|
|
6626
7352
|
if (!options.store) throw new TypeError("AgentRuntime requires a DurableStore");
|
|
@@ -6644,6 +7370,13 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
6644
7370
|
}
|
|
6645
7371
|
}
|
|
6646
7372
|
async handleRunEnd(runId, agentId, outcome) {
|
|
7373
|
+
const runLive = this.liveInteractions.get(runId);
|
|
7374
|
+
if (runLive) {
|
|
7375
|
+
for (const live of runLive.values()) {
|
|
7376
|
+
live.reject(new RunInteractionCancelledError("Run ended."));
|
|
7377
|
+
}
|
|
7378
|
+
this.liveInteractions.delete(runId);
|
|
7379
|
+
}
|
|
6647
7380
|
if (this.startedRuns.has(runId)) {
|
|
6648
7381
|
this.startedRuns.delete(runId);
|
|
6649
7382
|
try {
|
|
@@ -6787,6 +7520,8 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
6787
7520
|
agentId,
|
|
6788
7521
|
input,
|
|
6789
7522
|
...options.metadata === void 0 ? {} : { metadata: options.metadata },
|
|
7523
|
+
...options.scope === void 0 ? {} : { scope: options.scope },
|
|
7524
|
+
...options.cwd === void 0 ? {} : { cwd: options.cwd },
|
|
6790
7525
|
...phasePayload === void 0 ? {} : { phasePayload },
|
|
6791
7526
|
...options.entryPhases === void 0 ? {} : { entryPhases: options.entryPhases },
|
|
6792
7527
|
...pinnedConfigToken === agent.currentConfigToken ? {} : { pinnedConfigToken },
|
|
@@ -6875,12 +7610,72 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
6875
7610
|
this.assertOpen();
|
|
6876
7611
|
return this.resources.extensionRunner.onCapabilitiesChanged(listener);
|
|
6877
7612
|
}
|
|
7613
|
+
listUiContributions() {
|
|
7614
|
+
this.assertOpen();
|
|
7615
|
+
return this.resources.extensionRunner.getUiContributions();
|
|
7616
|
+
}
|
|
7617
|
+
onUiContributionsChanged(listener) {
|
|
7618
|
+
this.assertOpen();
|
|
7619
|
+
return this.resources.extensionRunner.onUiContributionsChanged(listener);
|
|
7620
|
+
}
|
|
7621
|
+
triggerUiAction(event) {
|
|
7622
|
+
this.assertOpen();
|
|
7623
|
+
this.resources.extensionRunner.triggerUiAction(event);
|
|
7624
|
+
}
|
|
7625
|
+
liveInteract(runId, request, signal) {
|
|
7626
|
+
if (signal.aborted) {
|
|
7627
|
+
return Promise.reject(signal.reason ?? new Error("Run aborted"));
|
|
7628
|
+
}
|
|
7629
|
+
const interactionId = request.id ?? createId("interaction");
|
|
7630
|
+
const interaction = {
|
|
7631
|
+
id: interactionId,
|
|
7632
|
+
phase: "default",
|
|
7633
|
+
kind: request.kind,
|
|
7634
|
+
prompt: request.prompt,
|
|
7635
|
+
payload: request.payload,
|
|
7636
|
+
toolCallId: request.toolCallId,
|
|
7637
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7638
|
+
status: "pending",
|
|
7639
|
+
result: request.result
|
|
7640
|
+
};
|
|
7641
|
+
let runLive = this.liveInteractions.get(runId);
|
|
7642
|
+
if (!runLive) {
|
|
7643
|
+
runLive = /* @__PURE__ */ new Map();
|
|
7644
|
+
this.liveInteractions.set(runId, runLive);
|
|
7645
|
+
}
|
|
7646
|
+
return new Promise((resolve9, reject) => {
|
|
7647
|
+
const onAbort = () => {
|
|
7648
|
+
runLive?.delete(interactionId);
|
|
7649
|
+
if (runLive && runLive.size === 0) this.liveInteractions.delete(runId);
|
|
7650
|
+
signal.removeEventListener("abort", onAbort);
|
|
7651
|
+
reject(signal.reason ?? new Error("Run aborted"));
|
|
7652
|
+
};
|
|
7653
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
7654
|
+
runLive.set(interactionId, {
|
|
7655
|
+
interaction,
|
|
7656
|
+
resolve: (val) => {
|
|
7657
|
+
signal.removeEventListener("abort", onAbort);
|
|
7658
|
+
resolve9(val);
|
|
7659
|
+
},
|
|
7660
|
+
reject: (err) => {
|
|
7661
|
+
signal.removeEventListener("abort", onAbort);
|
|
7662
|
+
reject(err);
|
|
7663
|
+
}
|
|
7664
|
+
});
|
|
7665
|
+
});
|
|
7666
|
+
}
|
|
6878
7667
|
async close() {
|
|
6879
7668
|
if (this.closed) return;
|
|
6880
7669
|
this.closed = true;
|
|
6881
7670
|
if (this.heartbeat) clearInterval(this.heartbeat);
|
|
6882
7671
|
for (const execution of this.executions.values()) execution.controller.abort();
|
|
6883
7672
|
this.executions.clear();
|
|
7673
|
+
for (const runLive of this.liveInteractions.values()) {
|
|
7674
|
+
for (const live of runLive.values()) {
|
|
7675
|
+
live.reject(new RunInteractionCancelledError("Runtime closed."));
|
|
7676
|
+
}
|
|
7677
|
+
}
|
|
7678
|
+
this.liveInteractions.clear();
|
|
6884
7679
|
this.transientEvents.close();
|
|
6885
7680
|
for (const subscription of this.consumers.values()) subscription.controller.abort();
|
|
6886
7681
|
await this.resources.closeExtensions();
|
|
@@ -6888,7 +7683,15 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
6888
7683
|
}
|
|
6889
7684
|
async snapshot(runId) {
|
|
6890
7685
|
this.assertOpen();
|
|
6891
|
-
|
|
7686
|
+
const snap = await this.owned.snapshotRun(runId);
|
|
7687
|
+
const runLive = this.liveInteractions.get(runId);
|
|
7688
|
+
if (runLive && runLive.size > 0 && snap.state === "running") {
|
|
7689
|
+
return {
|
|
7690
|
+
...snap,
|
|
7691
|
+
interactions: [...runLive.values()].map((l) => l.interaction)
|
|
7692
|
+
};
|
|
7693
|
+
}
|
|
7694
|
+
return snap;
|
|
6892
7695
|
}
|
|
6893
7696
|
async history(agentId) {
|
|
6894
7697
|
this.assertOpen();
|
|
@@ -6896,6 +7699,20 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
6896
7699
|
}
|
|
6897
7700
|
async respondInteraction(runId, input) {
|
|
6898
7701
|
this.assertOpen();
|
|
7702
|
+
const runLive = this.liveInteractions.get(runId);
|
|
7703
|
+
const live = runLive?.get(input.interactionId);
|
|
7704
|
+
if (live) {
|
|
7705
|
+
runLive.delete(input.interactionId);
|
|
7706
|
+
if (runLive.size === 0) this.liveInteractions.delete(runId);
|
|
7707
|
+
if (input.cancel) {
|
|
7708
|
+
live.reject(new RunInteractionCancelledError("Run interaction cancelled."));
|
|
7709
|
+
} else if (input.input !== void 0) {
|
|
7710
|
+
live.resolve(input.input);
|
|
7711
|
+
} else {
|
|
7712
|
+
live.reject(new TypeError("respondInteraction requires input or cancel: true"));
|
|
7713
|
+
}
|
|
7714
|
+
return;
|
|
7715
|
+
}
|
|
6899
7716
|
const snapshot = await this.owned.snapshotRun(runId);
|
|
6900
7717
|
if (snapshot.state !== "input_required" || !snapshot.interactions.some((interaction) => interaction.id === input.interactionId)) {
|
|
6901
7718
|
throw new RuntimeError("input_request_conflict", { runId, interactionId: input.interactionId, reason: "not_found" });
|
|
@@ -6905,6 +7722,13 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
6905
7722
|
}
|
|
6906
7723
|
async cancel(runId, reason) {
|
|
6907
7724
|
this.assertOpen();
|
|
7725
|
+
const runLive = this.liveInteractions.get(runId);
|
|
7726
|
+
if (runLive) {
|
|
7727
|
+
for (const live of runLive.values()) {
|
|
7728
|
+
live.reject(new RunInteractionCancelledError(reason ?? "Agent run stopped."));
|
|
7729
|
+
}
|
|
7730
|
+
this.liveInteractions.delete(runId);
|
|
7731
|
+
}
|
|
6908
7732
|
const done = this.executionDone.get(runId);
|
|
6909
7733
|
if (done) {
|
|
6910
7734
|
this.cancellationRequested.add(runId);
|
|
@@ -6963,6 +7787,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
6963
7787
|
async execute(run) {
|
|
6964
7788
|
let claim;
|
|
6965
7789
|
let executionRevision = run.revision;
|
|
7790
|
+
let toolQueue = Promise.resolve();
|
|
6966
7791
|
try {
|
|
6967
7792
|
const agent = await this.requireAgent(run.agentId);
|
|
6968
7793
|
let token = run.pinnedConfigToken ?? agent.currentConfigToken;
|
|
@@ -7050,7 +7875,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7050
7875
|
const assembly = assembleRegisteredExtensions(config, this.resources.extensionRunner, {
|
|
7051
7876
|
toolArchiveDir: this.archiveDirFor(run.agentId)
|
|
7052
7877
|
});
|
|
7053
|
-
|
|
7878
|
+
toolQueue = Promise.resolve();
|
|
7054
7879
|
const model = "stream" in config && config.stream ? config.model : { provider: config.model.provider, id: config.model.id };
|
|
7055
7880
|
const stream = "stream" in config && config.stream ? config.stream : createModelStream(config.model);
|
|
7056
7881
|
const phaseRegistry = normalizePhaseRegistry(assembly.context.phases);
|
|
@@ -7089,10 +7914,12 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7089
7914
|
executionId: claim.execution.executionId,
|
|
7090
7915
|
input: typeof run.input === "string" ? run.input : run.input.content,
|
|
7091
7916
|
...agent.metadata === void 0 ? {} : { agentMetadata: agent.metadata },
|
|
7092
|
-
...run.metadata === void 0 ? {} : { runMetadata: run.metadata }
|
|
7917
|
+
...run.metadata === void 0 ? {} : { runMetadata: run.metadata },
|
|
7918
|
+
...run.scope === void 0 ? {} : { scope: run.scope },
|
|
7919
|
+
...run.cwd === void 0 ? {} : { cwd: run.cwd }
|
|
7093
7920
|
},
|
|
7094
7921
|
model,
|
|
7095
|
-
thinkingLevel:
|
|
7922
|
+
thinkingLevel: thinkingLevelFromUserInput(run.input),
|
|
7096
7923
|
stream,
|
|
7097
7924
|
maxAttempts: config.maxAttempts,
|
|
7098
7925
|
checkpoint: claim.run.checkpoint,
|
|
@@ -7101,9 +7928,9 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7101
7928
|
interactionAnswers: claim.run.interactionAnswers,
|
|
7102
7929
|
signal: controller.signal,
|
|
7103
7930
|
beforePhase: assembly.beforePhase,
|
|
7104
|
-
afterPhase: async (phaseId,
|
|
7105
|
-
const extAfter = assembly.afterPhase ? await assembly.afterPhase(phaseId,
|
|
7106
|
-
const effectiveOutput = extAfter.output ??
|
|
7931
|
+
afterPhase: async (phaseId, output2) => {
|
|
7932
|
+
const extAfter = assembly.afterPhase ? await assembly.afterPhase(phaseId, output2) : {};
|
|
7933
|
+
const effectiveOutput = extAfter.output ?? output2;
|
|
7107
7934
|
if (!extAfter.abort && (phaseId === COMPACT_PHASE_ID || isCompactionOutcome(effectiveOutput.payload))) {
|
|
7108
7935
|
const active = this.executions.get(run.id);
|
|
7109
7936
|
if (active?.executionId === claim.execution.executionId && !this.cancellationRequested.has(run.id) && !controller.signal.aborted) {
|
|
@@ -7155,7 +7982,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7155
7982
|
const active = this.executions.get(run.id);
|
|
7156
7983
|
if (this.closed || controller.signal.aborted || active?.executionId !== claim.execution.executionId) return;
|
|
7157
7984
|
const projected = projectAssistantMessage(message, run.agentId, run.id, 0);
|
|
7158
|
-
const
|
|
7985
|
+
const committed2 = await this.owned.commitPhaseOutput({
|
|
7159
7986
|
runId: run.id,
|
|
7160
7987
|
execution: claim.execution,
|
|
7161
7988
|
expectedRevision: executionRevision,
|
|
@@ -7172,7 +7999,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7172
7999
|
}
|
|
7173
8000
|
}
|
|
7174
8001
|
});
|
|
7175
|
-
executionRevision =
|
|
8002
|
+
executionRevision = committed2.revision;
|
|
7176
8003
|
});
|
|
7177
8004
|
toolQueue = task.then(() => void 0, () => void 0);
|
|
7178
8005
|
return task;
|
|
@@ -7204,9 +8031,65 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7204
8031
|
text: event.text
|
|
7205
8032
|
});
|
|
7206
8033
|
},
|
|
8034
|
+
onToolCallDelta: (event) => {
|
|
8035
|
+
const active = this.executions.get(run.id);
|
|
8036
|
+
if (this.closed || controller.signal.aborted || active?.executionId !== claim.execution.executionId) return;
|
|
8037
|
+
this.transientEvents.publish({
|
|
8038
|
+
kind: "tool_call_delta",
|
|
8039
|
+
durability: "transient",
|
|
8040
|
+
runId: run.id,
|
|
8041
|
+
executionId: claim.execution.executionId,
|
|
8042
|
+
messageId: event.messageId,
|
|
8043
|
+
providerToolCallId: event.providerToolCallId,
|
|
8044
|
+
toolName: event.toolName,
|
|
8045
|
+
arguments: event.arguments,
|
|
8046
|
+
args: event.args
|
|
8047
|
+
});
|
|
8048
|
+
},
|
|
8049
|
+
onModelRetry: (event) => {
|
|
8050
|
+
const active = this.executions.get(run.id);
|
|
8051
|
+
if (this.closed || controller.signal.aborted || active?.executionId !== claim.execution.executionId) return;
|
|
8052
|
+
this.transientEvents.publish({
|
|
8053
|
+
kind: "model_retry",
|
|
8054
|
+
durability: "transient",
|
|
8055
|
+
runId: run.id,
|
|
8056
|
+
executionId: claim.execution.executionId,
|
|
8057
|
+
attempt: event.attempt,
|
|
8058
|
+
maxRetries: event.maxRetries,
|
|
8059
|
+
delayMs: event.delayMs,
|
|
8060
|
+
error: event.error
|
|
8061
|
+
});
|
|
8062
|
+
},
|
|
8063
|
+
onToolReport: (event) => {
|
|
8064
|
+
const active = this.executions.get(run.id);
|
|
8065
|
+
if (this.closed || controller.signal.aborted || active?.executionId !== claim.execution.executionId) return;
|
|
8066
|
+
this.transientEvents.publish({
|
|
8067
|
+
kind: "tool_state_changed",
|
|
8068
|
+
durability: "transient",
|
|
8069
|
+
runId: event.runId,
|
|
8070
|
+
executionId: claim.execution.executionId,
|
|
8071
|
+
transition: { from: null, to: event.update.status ?? "in_progress" },
|
|
8072
|
+
toolCall: event.update,
|
|
8073
|
+
external: true
|
|
8074
|
+
});
|
|
8075
|
+
const task = toolQueue.then(async () => {
|
|
8076
|
+
const active2 = this.executions.get(run.id);
|
|
8077
|
+
if (this.closed || controller.signal.aborted || active2?.executionId !== claim.execution.executionId) return;
|
|
8078
|
+
const recorded = await this.owned.recordToolCall({
|
|
8079
|
+
runId: run.id,
|
|
8080
|
+
execution: claim.execution,
|
|
8081
|
+
update: event.update,
|
|
8082
|
+
external: true
|
|
8083
|
+
});
|
|
8084
|
+
executionRevision = recorded.runRevision;
|
|
8085
|
+
});
|
|
8086
|
+
toolQueue = task.then(() => void 0, () => void 0);
|
|
8087
|
+
},
|
|
8088
|
+
retryDelayMs: this.retryDelayMs,
|
|
7207
8089
|
onContext: assembly.setContext,
|
|
7208
8090
|
runtime: {
|
|
7209
|
-
|
|
8091
|
+
interact: (request) => this.liveInteract(run.id, request, controller.signal),
|
|
8092
|
+
tools: ({ toolCall, contentBlocks, driver, options }) => {
|
|
7210
8093
|
const task = toolQueue.then(async () => {
|
|
7211
8094
|
const execution = await this.executeToolBatch({
|
|
7212
8095
|
run,
|
|
@@ -7218,6 +8101,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7218
8101
|
contentBlocks,
|
|
7219
8102
|
signal: controller.signal,
|
|
7220
8103
|
driver,
|
|
8104
|
+
options,
|
|
7221
8105
|
onRevision: (rev) => {
|
|
7222
8106
|
executionRevision = rev;
|
|
7223
8107
|
}
|
|
@@ -7228,7 +8112,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7228
8112
|
toolQueue = task.then(() => void 0, () => void 0);
|
|
7229
8113
|
return task;
|
|
7230
8114
|
},
|
|
7231
|
-
toolsBatch: ({ toolCalls, contentBlocks, driver }) => {
|
|
8115
|
+
toolsBatch: ({ toolCalls, contentBlocks, driver, options }) => {
|
|
7232
8116
|
const task = toolQueue.then(async () => {
|
|
7233
8117
|
const execution = await this.executeToolBatch({
|
|
7234
8118
|
run,
|
|
@@ -7240,6 +8124,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7240
8124
|
contentBlocks,
|
|
7241
8125
|
signal: controller.signal,
|
|
7242
8126
|
driver,
|
|
8127
|
+
options,
|
|
7243
8128
|
onRevision: (rev) => {
|
|
7244
8129
|
executionRevision = rev;
|
|
7245
8130
|
}
|
|
@@ -7263,14 +8148,15 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7263
8148
|
result = await executeModel(executionContext);
|
|
7264
8149
|
}
|
|
7265
8150
|
}
|
|
8151
|
+
await toolQueue;
|
|
7266
8152
|
if (this.cancellationRequested.has(run.id) || controller.signal.aborted) {
|
|
7267
|
-
const
|
|
8153
|
+
const output2 = latestAssistant(run, result.messages, executionContext.messages.length, true);
|
|
7268
8154
|
const reason = this.cancellationReasons.get(run.id) ?? "Agent run stopped.";
|
|
7269
8155
|
await this.owned.cancelRun({
|
|
7270
8156
|
runId: run.id,
|
|
7271
8157
|
expectedRevision: executionRevision,
|
|
7272
8158
|
reason,
|
|
7273
|
-
...
|
|
8159
|
+
...output2 && hasVisibleAssistantText(output2) ? { output: output2 } : {}
|
|
7274
8160
|
});
|
|
7275
8161
|
this.transientEvents.clear(run.id, claim.execution.executionId);
|
|
7276
8162
|
await this.handleRunEnd(run.id, run.agentId, {
|
|
@@ -7289,12 +8175,12 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7289
8175
|
pendingToolCallIds = result.interactions.map(({ toolCallId }) => toolCallId);
|
|
7290
8176
|
}
|
|
7291
8177
|
const isToolCallInteraction = result.interactions?.some((i) => i.toolCallId !== void 0);
|
|
7292
|
-
const
|
|
8178
|
+
const output2 = isToolCallInteraction ? void 0 : latestAssistant(
|
|
7293
8179
|
run,
|
|
7294
8180
|
result.messages,
|
|
7295
8181
|
executionContext.messages.length
|
|
7296
8182
|
);
|
|
7297
|
-
const prompt = isToolCallInteraction ? void 0 :
|
|
8183
|
+
const prompt = isToolCallInteraction ? void 0 : output2 ?? (result.interactions[0]?.prompt ? promptMessage(run, result.interactions[0].prompt, result.messages.length) : void 0);
|
|
7298
8184
|
await this.owned.commitInputRequired({
|
|
7299
8185
|
runId: run.id,
|
|
7300
8186
|
execution: claim.execution,
|
|
@@ -7310,24 +8196,32 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7310
8196
|
return;
|
|
7311
8197
|
}
|
|
7312
8198
|
if (result.type === "completed") {
|
|
7313
|
-
const
|
|
7314
|
-
await this.owned.commitOutcome({ runId: run.id, execution: claim.execution, expectedRevision: executionRevision, outcome: durableOutcome(result.outcome), ...
|
|
8199
|
+
const output2 = latestAssistant(run, result.messages, executionContext.messages.length);
|
|
8200
|
+
await this.owned.commitOutcome({ runId: run.id, execution: claim.execution, expectedRevision: executionRevision, outcome: durableOutcome(result.outcome), ...output2 ? { output: output2 } : {} });
|
|
7315
8201
|
this.transientEvents.clear(run.id, claim.execution.executionId, true);
|
|
7316
8202
|
await this.handleRunEnd(run.id, run.agentId, result.outcome);
|
|
7317
8203
|
return;
|
|
7318
8204
|
}
|
|
8205
|
+
const output = latestAssistant(run, result.messages, executionContext.messages.length);
|
|
7319
8206
|
const failure = { code: "execution_failed", message: result.error instanceof Error ? result.error.message : "Execution failed." };
|
|
7320
|
-
await this.owned.commitOutcome({
|
|
8207
|
+
const committed = await this.owned.commitOutcome({
|
|
8208
|
+
runId: run.id,
|
|
8209
|
+
execution: claim.execution,
|
|
8210
|
+
expectedRevision: executionRevision,
|
|
8211
|
+
failure,
|
|
8212
|
+
...output ? { output } : {}
|
|
8213
|
+
});
|
|
7321
8214
|
this.transientEvents.clear(run.id, claim.execution.executionId);
|
|
7322
8215
|
await this.handleRunEnd(run.id, run.agentId, {
|
|
7323
8216
|
id: createId("out"),
|
|
7324
8217
|
status: "failed",
|
|
7325
8218
|
message: failure.message,
|
|
7326
|
-
error: failure
|
|
8219
|
+
error: committed.failure ?? failure
|
|
7327
8220
|
});
|
|
7328
8221
|
} catch (error) {
|
|
7329
8222
|
if (!claim && error instanceof RuntimeError && ["run_state_conflict", "runtime_ownership_lost", "run_not_found"].includes(error.code)) return;
|
|
7330
8223
|
if (claim) {
|
|
8224
|
+
await toolQueue;
|
|
7331
8225
|
if (this.cancellationRequested.has(run.id)) {
|
|
7332
8226
|
const reason = this.cancellationReasons.get(run.id) ?? "Agent run stopped.";
|
|
7333
8227
|
await this.owned.cancelRun({
|
|
@@ -7343,7 +8237,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7343
8237
|
return;
|
|
7344
8238
|
}
|
|
7345
8239
|
const failureMessage = error instanceof Error ? error.message : "Execution failed.";
|
|
7346
|
-
await this.owned.commitOutcome({
|
|
8240
|
+
const committed = await this.owned.commitOutcome({
|
|
7347
8241
|
runId: run.id,
|
|
7348
8242
|
execution: claim.execution,
|
|
7349
8243
|
expectedRevision: executionRevision,
|
|
@@ -7353,12 +8247,13 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7353
8247
|
runId: run.id,
|
|
7354
8248
|
reason: commitError instanceof Error ? commitError.message : "Run failure could not be committed."
|
|
7355
8249
|
}).catch(() => void 0);
|
|
8250
|
+
return void 0;
|
|
7356
8251
|
});
|
|
7357
8252
|
await this.handleRunEnd(run.id, run.agentId, {
|
|
7358
8253
|
id: createId("out"),
|
|
7359
8254
|
status: "failed",
|
|
7360
8255
|
message: failureMessage,
|
|
7361
|
-
error: { code: "execution_failed", message: failureMessage }
|
|
8256
|
+
error: committed?.failure ?? { code: "execution_failed", message: failureMessage }
|
|
7362
8257
|
});
|
|
7363
8258
|
return;
|
|
7364
8259
|
}
|
|
@@ -7382,7 +8277,8 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7382
8277
|
return { result: batch.results[0], revision: batch.revision };
|
|
7383
8278
|
}
|
|
7384
8279
|
async executeToolBatch(input) {
|
|
7385
|
-
const scope =
|
|
8280
|
+
const scope = input.run.scope ?? [];
|
|
8281
|
+
const cwd = input.run.cwd;
|
|
7386
8282
|
const turn = typeof input.run.input === "object" && input.run.input !== null && !Array.isArray(input.run.input) ? input.run.input : {};
|
|
7387
8283
|
const checkpoint = input.driver?.checkpoint();
|
|
7388
8284
|
const isSuspensionResume = checkpoint && typeof checkpoint === "object" && checkpoint.kind === "tool_call_suspension";
|
|
@@ -7410,7 +8306,9 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7410
8306
|
...input.agentMetadata === void 0 ? {} : { agentMetadata: input.agentMetadata },
|
|
7411
8307
|
...input.run.metadata === void 0 ? {} : { runMetadata: input.run.metadata },
|
|
7412
8308
|
toolCallId,
|
|
8309
|
+
providerToolCallId: toolCall.id,
|
|
7413
8310
|
scope,
|
|
8311
|
+
...cwd ? { cwd } : {},
|
|
7414
8312
|
turn,
|
|
7415
8313
|
interaction: createRunInteractionDriver({
|
|
7416
8314
|
currentPhase: "default",
|
|
@@ -7438,6 +8336,12 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7438
8336
|
}
|
|
7439
8337
|
}
|
|
7440
8338
|
if (!hasInteraction) {
|
|
8339
|
+
const startPresentations = await Promise.all(
|
|
8340
|
+
input.toolCalls.map(async (tc) => {
|
|
8341
|
+
const t = input.toolConfig.tools.find((c) => c.name === tc.name);
|
|
8342
|
+
return t ? presentToolPending(t, toJsonValue(tc.args)) : void 0;
|
|
8343
|
+
})
|
|
8344
|
+
);
|
|
7441
8345
|
const reserved = await this.owned.reserveToolCalls({
|
|
7442
8346
|
runId: input.run.id,
|
|
7443
8347
|
execution: input.execution,
|
|
@@ -7448,7 +8352,8 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7448
8352
|
toolCallId: toolCallIds[i],
|
|
7449
8353
|
providerToolCallId: tc.id,
|
|
7450
8354
|
name: tc.name,
|
|
7451
|
-
args: toJsonValue(tc.args)
|
|
8355
|
+
args: toJsonValue(tc.args),
|
|
8356
|
+
...startPresentations[i] ?? {}
|
|
7452
8357
|
}))
|
|
7453
8358
|
});
|
|
7454
8359
|
setRevision(reserved.run.revision);
|
|
@@ -7472,7 +8377,9 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7472
8377
|
expectedRevision: revision,
|
|
7473
8378
|
toolCallId,
|
|
7474
8379
|
state: "failed",
|
|
7475
|
-
result: { ok: false, content: null, error: `Tool ${toolCall.name} is not available.` }
|
|
8380
|
+
result: { ok: false, content: null, error: `Tool ${toolCall.name} is not available.` },
|
|
8381
|
+
title: toolCall.name,
|
|
8382
|
+
kind: "other"
|
|
7476
8383
|
});
|
|
7477
8384
|
setRevision(failed.run.revision);
|
|
7478
8385
|
results2.push(protocolFailure(`Tool ${toolCall.name} is not available.`));
|
|
@@ -7486,116 +8393,64 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7486
8393
|
expectedRevision: revision,
|
|
7487
8394
|
toolCallId,
|
|
7488
8395
|
state: "failed",
|
|
7489
|
-
result: { ok: false, content: null, error: decision.reason }
|
|
8396
|
+
result: { ok: false, content: null, error: decision.reason },
|
|
8397
|
+
title: durableTool.annotations?.title ?? durableTool.name,
|
|
8398
|
+
kind: durableTool.kind ?? "other"
|
|
7490
8399
|
});
|
|
7491
8400
|
setRevision(failed.run.revision);
|
|
7492
8401
|
results2.push(protocolFailure(decision.reason));
|
|
7493
8402
|
continue;
|
|
7494
8403
|
}
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
toolCallId,
|
|
7502
|
-
scope,
|
|
7503
|
-
turn,
|
|
7504
|
-
interaction: createToolInteractionDriver(input.driver, {
|
|
7505
|
-
toolCallId,
|
|
7506
|
-
toolCallIds,
|
|
7507
|
-
toolCalls: input.toolCalls,
|
|
7508
|
-
pendingIndex: i,
|
|
7509
|
-
completedResults: results2
|
|
7510
|
-
}),
|
|
7511
|
-
reportProgress: (progress) => {
|
|
7512
|
-
const active = this.executions.get(input.run.id);
|
|
7513
|
-
if (!progressActive || this.closed || input.signal.aborted || active?.executionId !== input.execution.executionId || !isJsonValue(progress)) return;
|
|
7514
|
-
let copy;
|
|
7515
|
-
try {
|
|
7516
|
-
if (JSON.stringify(progress).length > 64 * 1024) return;
|
|
7517
|
-
copy = structuredClone(progress);
|
|
7518
|
-
} catch {
|
|
7519
|
-
return;
|
|
7520
|
-
}
|
|
7521
|
-
this.transientEvents.publish({
|
|
7522
|
-
kind: "tool_progress",
|
|
7523
|
-
durability: "transient",
|
|
7524
|
-
runId: input.run.id,
|
|
7525
|
-
executionId: input.execution.executionId,
|
|
7526
|
-
toolCallId,
|
|
7527
|
-
progress: copy
|
|
7528
|
-
});
|
|
7529
|
-
}
|
|
8404
|
+
const currentToolState = {
|
|
8405
|
+
...startPresentations[i] ?? {
|
|
8406
|
+
title: durableTool.annotations?.title ?? durableTool.name,
|
|
8407
|
+
kind: durableTool.kind ?? "other"
|
|
8408
|
+
},
|
|
8409
|
+
rawInput: toJsonValue(toolCall.args)
|
|
7530
8410
|
};
|
|
8411
|
+
const inProgressPres = await presentToolCall(durableTool, {
|
|
8412
|
+
status: "in_progress",
|
|
8413
|
+
args: toJsonValue(toolCall.args)
|
|
8414
|
+
});
|
|
8415
|
+
if (inProgressPres) mergeToolCall(currentToolState, inProgressPres);
|
|
7531
8416
|
const started = await this.owned.startToolCall({
|
|
7532
8417
|
runId: input.run.id,
|
|
7533
8418
|
execution: input.execution,
|
|
7534
8419
|
expectedRevision: revision,
|
|
7535
|
-
toolCallId
|
|
8420
|
+
toolCallId,
|
|
8421
|
+
title: currentToolState.title ?? durableTool.annotations?.title ?? durableTool.name,
|
|
8422
|
+
kind: currentToolState.kind ?? durableTool.kind ?? "other",
|
|
8423
|
+
...currentToolState.locations !== void 0 ? { locations: currentToolState.locations } : {},
|
|
8424
|
+
...currentToolState.content !== void 0 ? { content: currentToolState.content } : {},
|
|
8425
|
+
...currentToolState._meta !== void 0 ? { _meta: currentToolState._meta } : {}
|
|
7536
8426
|
});
|
|
7537
8427
|
setRevision(started.run.revision);
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
setRevision(committed.run.revision);
|
|
7565
|
-
const projectedResult = await this.foldToolInteractionRecords(result, toolCallId, input.run.agentId);
|
|
7566
|
-
results2.push({
|
|
7567
|
-
toolCallId: providerToolCallId,
|
|
7568
|
-
toolName: toolCall.name,
|
|
7569
|
-
...projectedResult
|
|
7570
|
-
});
|
|
7571
|
-
} catch (error) {
|
|
7572
|
-
if (error instanceof RunInteractionBoundary) {
|
|
7573
|
-
const suspended = await this.owned.suspendToolCall({
|
|
7574
|
-
runId: input.run.id,
|
|
7575
|
-
execution: input.execution,
|
|
7576
|
-
expectedRevision: revision,
|
|
7577
|
-
toolCallId
|
|
7578
|
-
});
|
|
7579
|
-
setRevision(suspended.run.revision);
|
|
7580
|
-
throw error;
|
|
7581
|
-
}
|
|
7582
|
-
if (error instanceof RunInteractionCancelledError) throw error;
|
|
7583
|
-
const reason = error instanceof Error ? error.message : "Tool execution outcome is indeterminate.";
|
|
7584
|
-
const indeterminate = await this.owned.commitToolResult({
|
|
7585
|
-
runId: input.run.id,
|
|
7586
|
-
execution: input.execution,
|
|
7587
|
-
expectedRevision: revision,
|
|
7588
|
-
toolCallId,
|
|
7589
|
-
state: "indeterminate",
|
|
7590
|
-
reason,
|
|
7591
|
-
result: { ok: false, content: null, error: reason }
|
|
7592
|
-
});
|
|
7593
|
-
setRevision(indeterminate.run.revision);
|
|
7594
|
-
results2.push(protocolFailure(reason));
|
|
7595
|
-
} finally {
|
|
7596
|
-
progressActive = false;
|
|
7597
|
-
this.transientEvents.clearTool(input.run.id, toolCallId);
|
|
7598
|
-
}
|
|
8428
|
+
const toolResult2 = await this.executeAndCommitTool({
|
|
8429
|
+
runId: input.run.id,
|
|
8430
|
+
agentId: input.run.agentId,
|
|
8431
|
+
agentMetadata: input.agentMetadata,
|
|
8432
|
+
runMetadata: input.run.metadata,
|
|
8433
|
+
execution: input.execution,
|
|
8434
|
+
revision,
|
|
8435
|
+
setRevision,
|
|
8436
|
+
toolCall,
|
|
8437
|
+
durableTool,
|
|
8438
|
+
toolCallId,
|
|
8439
|
+
providerToolCallId,
|
|
8440
|
+
scope,
|
|
8441
|
+
cwd,
|
|
8442
|
+
turn,
|
|
8443
|
+
driver: input.driver,
|
|
8444
|
+
toolCalls: input.toolCalls,
|
|
8445
|
+
toolCallIds,
|
|
8446
|
+
pendingIndex: i,
|
|
8447
|
+
completedResults: results2,
|
|
8448
|
+
signal: input.signal,
|
|
8449
|
+
afterToolCall: input.toolConfig.afterToolCall,
|
|
8450
|
+
currentToolState,
|
|
8451
|
+
options: input.options
|
|
8452
|
+
});
|
|
8453
|
+
results2.push(toolResult2);
|
|
7599
8454
|
}
|
|
7600
8455
|
return { results: results2, revision };
|
|
7601
8456
|
}
|
|
@@ -7615,7 +8470,7 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7615
8470
|
error
|
|
7616
8471
|
});
|
|
7617
8472
|
if (!durableTool) {
|
|
7618
|
-
const
|
|
8473
|
+
const reserved = await this.owned.reserveToolCalls({
|
|
7619
8474
|
runId: input.run.id,
|
|
7620
8475
|
execution: input.execution,
|
|
7621
8476
|
expectedRevision: revision,
|
|
@@ -7628,60 +8483,70 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7628
8483
|
args: toJsonValue(toolCall.args)
|
|
7629
8484
|
}]
|
|
7630
8485
|
});
|
|
7631
|
-
setRevision(
|
|
8486
|
+
setRevision(reserved.run.revision);
|
|
7632
8487
|
const failed = await this.owned.commitToolResult({
|
|
7633
8488
|
runId: input.run.id,
|
|
7634
8489
|
execution: input.execution,
|
|
7635
8490
|
expectedRevision: revision,
|
|
7636
8491
|
toolCallId,
|
|
7637
8492
|
state: "failed",
|
|
7638
|
-
result: { ok: false, content: null, error: `Tool ${toolCall.name} is not available.` }
|
|
8493
|
+
result: { ok: false, content: null, error: `Tool ${toolCall.name} is not available.` },
|
|
8494
|
+
title: toolCall.name,
|
|
8495
|
+
kind: "other"
|
|
7639
8496
|
});
|
|
7640
8497
|
setRevision(failed.run.revision);
|
|
7641
8498
|
results.push(protocolFailure(`Tool ${toolCall.name} is not available.`));
|
|
7642
8499
|
continue;
|
|
7643
8500
|
}
|
|
7644
|
-
|
|
7645
|
-
const
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
8501
|
+
const pendingPres = await presentToolPending(durableTool, toJsonValue(toolCall.args));
|
|
8502
|
+
const currentToolState = {
|
|
8503
|
+
...pendingPres,
|
|
8504
|
+
rawInput: toJsonValue(toolCall.args)
|
|
8505
|
+
};
|
|
8506
|
+
const resumedStart = suspension && index === suspension.pendingIndex ? await (async () => {
|
|
8507
|
+
const inProgressPres = await presentToolCall(durableTool, {
|
|
8508
|
+
status: "in_progress",
|
|
8509
|
+
args: toJsonValue(toolCall.args)
|
|
8510
|
+
});
|
|
8511
|
+
if (inProgressPres) mergeToolCall(currentToolState, inProgressPres);
|
|
8512
|
+
return this.owned.startToolCall({
|
|
8513
|
+
runId: input.run.id,
|
|
8514
|
+
execution: input.execution,
|
|
8515
|
+
expectedRevision: revision,
|
|
8516
|
+
toolCallId,
|
|
8517
|
+
title: currentToolState.title ?? durableTool.annotations?.title ?? durableTool.name,
|
|
8518
|
+
kind: currentToolState.kind ?? durableTool.kind ?? "other",
|
|
8519
|
+
...currentToolState.locations !== void 0 ? { locations: currentToolState.locations } : {},
|
|
8520
|
+
...currentToolState.content !== void 0 ? { content: currentToolState.content } : {},
|
|
8521
|
+
...currentToolState._meta !== void 0 ? { _meta: currentToolState._meta } : {}
|
|
8522
|
+
});
|
|
8523
|
+
})() : void 0;
|
|
7651
8524
|
if (resumedStart) setRevision(resumedStart.run.revision);
|
|
8525
|
+
const baseDriver = input.driver ?? createRunInteractionDriver({
|
|
8526
|
+
currentPhase: "default",
|
|
8527
|
+
attempt: 0,
|
|
8528
|
+
status: "running",
|
|
8529
|
+
metrics: { iterations: 0, phaseTransitions: [], compactionCount: 0, retryCount: 0, startedAt: (/* @__PURE__ */ new Date()).toISOString(), startedAtMs: Date.now() }
|
|
8530
|
+
}, "default", input.signal);
|
|
8531
|
+
const interactionDriver = createToolInteractionDriver(baseDriver, {
|
|
8532
|
+
toolCallId,
|
|
8533
|
+
...suspension?.toolCallIds === void 0 ? {} : { toolCallIds: suspension.toolCallIds },
|
|
8534
|
+
toolCalls: input.toolCalls,
|
|
8535
|
+
pendingIndex: index,
|
|
8536
|
+
completedResults: results
|
|
8537
|
+
});
|
|
7652
8538
|
const context = {
|
|
7653
8539
|
agentId: input.run.agentId,
|
|
7654
8540
|
runId: input.run.id,
|
|
7655
8541
|
...input.agentMetadata === void 0 ? {} : { agentMetadata: input.agentMetadata },
|
|
7656
8542
|
...input.run.metadata === void 0 ? {} : { runMetadata: input.run.metadata },
|
|
7657
8543
|
toolCallId,
|
|
8544
|
+
providerToolCallId,
|
|
7658
8545
|
scope,
|
|
8546
|
+
...cwd ? { cwd } : {},
|
|
7659
8547
|
turn,
|
|
7660
|
-
interaction:
|
|
7661
|
-
|
|
7662
|
-
...suspension?.toolCallIds === void 0 ? {} : { toolCallIds: suspension.toolCallIds },
|
|
7663
|
-
toolCalls: input.toolCalls,
|
|
7664
|
-
pendingIndex: index,
|
|
7665
|
-
completedResults: results
|
|
7666
|
-
}),
|
|
7667
|
-
reportProgress: (progress) => {
|
|
7668
|
-
const active = this.executions.get(input.run.id);
|
|
7669
|
-
if (!progressActive || this.closed || input.signal.aborted || active?.executionId !== input.execution.executionId || !isJsonValue(progress)) return;
|
|
7670
|
-
let copy;
|
|
7671
|
-
try {
|
|
7672
|
-
if (JSON.stringify(progress).length > 64 * 1024) return;
|
|
7673
|
-
copy = structuredClone(progress);
|
|
7674
|
-
} catch {
|
|
7675
|
-
return;
|
|
7676
|
-
}
|
|
7677
|
-
this.transientEvents.publish({
|
|
7678
|
-
kind: "tool_progress",
|
|
7679
|
-
durability: "transient",
|
|
7680
|
-
runId: input.run.id,
|
|
7681
|
-
executionId: input.execution.executionId,
|
|
7682
|
-
toolCallId,
|
|
7683
|
-
progress: copy
|
|
7684
|
-
});
|
|
8548
|
+
interaction: interactionDriver,
|
|
8549
|
+
reportProgress: () => {
|
|
7685
8550
|
}
|
|
7686
8551
|
};
|
|
7687
8552
|
const answer = suspension && index === suspension.pendingIndex ? suspension.interactionIds?.map((id) => input.driver?.answers().get(id)).find((value) => value !== void 0) : void 0;
|
|
@@ -7698,31 +8563,43 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7698
8563
|
if (!input.driver) {
|
|
7699
8564
|
throw new Error("Tool call requested interaction but no interaction driver is active.");
|
|
7700
8565
|
}
|
|
7701
|
-
|
|
7702
|
-
if (!
|
|
7703
|
-
const
|
|
8566
|
+
interactionDriver.request(decision.interaction);
|
|
8567
|
+
if (!resumedStart) {
|
|
8568
|
+
const reserved = await this.owned.reserveToolCalls({
|
|
7704
8569
|
runId: input.run.id,
|
|
7705
8570
|
execution: input.execution,
|
|
7706
8571
|
expectedRevision: revision,
|
|
7707
8572
|
requestMessageId: createId("msg"),
|
|
7708
8573
|
contentBlocks: input.contentBlocks,
|
|
7709
|
-
calls: [{
|
|
8574
|
+
calls: [{
|
|
8575
|
+
toolCallId,
|
|
8576
|
+
providerToolCallId,
|
|
8577
|
+
name: toolCall.name,
|
|
8578
|
+
args: toJsonValue(toolCall.args),
|
|
8579
|
+
...pendingPres
|
|
8580
|
+
}]
|
|
7710
8581
|
});
|
|
7711
|
-
setRevision(
|
|
8582
|
+
setRevision(reserved.run.revision);
|
|
7712
8583
|
}
|
|
7713
|
-
|
|
8584
|
+
interactionDriver.suspend();
|
|
7714
8585
|
}
|
|
7715
8586
|
if ("allow" in decision && !decision.allow) {
|
|
7716
|
-
if (!
|
|
7717
|
-
const
|
|
8587
|
+
if (!resumedStart) {
|
|
8588
|
+
const reserved = await this.owned.reserveToolCalls({
|
|
7718
8589
|
runId: input.run.id,
|
|
7719
8590
|
execution: input.execution,
|
|
7720
8591
|
expectedRevision: revision,
|
|
7721
8592
|
requestMessageId: createId("msg"),
|
|
7722
8593
|
contentBlocks: input.contentBlocks,
|
|
7723
|
-
calls: [{
|
|
8594
|
+
calls: [{
|
|
8595
|
+
toolCallId,
|
|
8596
|
+
providerToolCallId,
|
|
8597
|
+
name: toolCall.name,
|
|
8598
|
+
args: toJsonValue(toolCall.args),
|
|
8599
|
+
...pendingPres
|
|
8600
|
+
}]
|
|
7724
8601
|
});
|
|
7725
|
-
setRevision(
|
|
8602
|
+
setRevision(reserved.run.revision);
|
|
7726
8603
|
}
|
|
7727
8604
|
const failed = await this.owned.commitToolResult({
|
|
7728
8605
|
runId: input.run.id,
|
|
@@ -7730,9 +8607,27 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7730
8607
|
expectedRevision: revision,
|
|
7731
8608
|
toolCallId,
|
|
7732
8609
|
state: "failed",
|
|
7733
|
-
result: { ok: false, content: null, error: decision.reason }
|
|
8610
|
+
result: { ok: false, content: null, error: decision.reason },
|
|
8611
|
+
title: currentToolState.title ?? durableTool.annotations?.title ?? durableTool.name,
|
|
8612
|
+
kind: currentToolState.kind ?? durableTool.kind ?? "other",
|
|
8613
|
+
locations: currentToolState.locations,
|
|
8614
|
+
content: currentToolState.content,
|
|
8615
|
+
_meta: currentToolState._meta
|
|
7734
8616
|
});
|
|
7735
8617
|
setRevision(failed.run.revision);
|
|
8618
|
+
if (input.options?.onUpdate) {
|
|
8619
|
+
try {
|
|
8620
|
+
input.options.onUpdate(createMergedToolCall(
|
|
8621
|
+
toolCallId,
|
|
8622
|
+
"failed",
|
|
8623
|
+
currentToolState,
|
|
8624
|
+
durableTool.annotations?.title ?? durableTool.name,
|
|
8625
|
+
durableTool.kind ?? "other"
|
|
8626
|
+
));
|
|
8627
|
+
} catch (err) {
|
|
8628
|
+
console.warn(`Error in tool call onUpdate callback:`, err);
|
|
8629
|
+
}
|
|
8630
|
+
}
|
|
7736
8631
|
results.push(protocolFailure(decision.reason));
|
|
7737
8632
|
continue;
|
|
7738
8633
|
}
|
|
@@ -7742,16 +8637,22 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7742
8637
|
throw error;
|
|
7743
8638
|
}
|
|
7744
8639
|
const reason = error instanceof Error ? error.message : "Tool policy rejected the call.";
|
|
7745
|
-
if (!
|
|
7746
|
-
const
|
|
8640
|
+
if (!resumedStart) {
|
|
8641
|
+
const reserved = await this.owned.reserveToolCalls({
|
|
7747
8642
|
runId: input.run.id,
|
|
7748
8643
|
execution: input.execution,
|
|
7749
8644
|
expectedRevision: revision,
|
|
7750
8645
|
requestMessageId: createId("msg"),
|
|
7751
8646
|
contentBlocks: input.contentBlocks,
|
|
7752
|
-
calls: [{
|
|
8647
|
+
calls: [{
|
|
8648
|
+
toolCallId,
|
|
8649
|
+
providerToolCallId,
|
|
8650
|
+
name: toolCall.name,
|
|
8651
|
+
args: toJsonValue(toolCall.args),
|
|
8652
|
+
...pendingPres
|
|
8653
|
+
}]
|
|
7753
8654
|
});
|
|
7754
|
-
setRevision(
|
|
8655
|
+
setRevision(reserved.run.revision);
|
|
7755
8656
|
}
|
|
7756
8657
|
const failed = await this.owned.commitToolResult({
|
|
7757
8658
|
runId: input.run.id,
|
|
@@ -7759,94 +8660,316 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7759
8660
|
expectedRevision: revision,
|
|
7760
8661
|
toolCallId,
|
|
7761
8662
|
state: "failed",
|
|
7762
|
-
result: { ok: false, content: null, error: reason }
|
|
8663
|
+
result: { ok: false, content: null, error: reason },
|
|
8664
|
+
title: currentToolState.title ?? durableTool.annotations?.title ?? durableTool.name,
|
|
8665
|
+
kind: currentToolState.kind ?? durableTool.kind ?? "other",
|
|
8666
|
+
locations: currentToolState.locations,
|
|
8667
|
+
content: currentToolState.content,
|
|
8668
|
+
_meta: currentToolState._meta
|
|
7763
8669
|
});
|
|
7764
8670
|
setRevision(failed.run.revision);
|
|
8671
|
+
if (input.options?.onUpdate) {
|
|
8672
|
+
try {
|
|
8673
|
+
input.options.onUpdate(createMergedToolCall(
|
|
8674
|
+
toolCallId,
|
|
8675
|
+
"failed",
|
|
8676
|
+
currentToolState,
|
|
8677
|
+
durableTool.annotations?.title ?? durableTool.name,
|
|
8678
|
+
durableTool.kind ?? "other"
|
|
8679
|
+
));
|
|
8680
|
+
} catch (err) {
|
|
8681
|
+
console.warn(`Error in tool call onUpdate callback:`, err);
|
|
8682
|
+
}
|
|
8683
|
+
}
|
|
7765
8684
|
results.push(protocolFailure(reason));
|
|
7766
8685
|
continue;
|
|
7767
8686
|
}
|
|
7768
|
-
|
|
7769
|
-
const
|
|
8687
|
+
if (!resumedStart) {
|
|
8688
|
+
const reserved = await this.owned.reserveToolCalls({
|
|
7770
8689
|
runId: input.run.id,
|
|
7771
8690
|
execution: input.execution,
|
|
7772
8691
|
expectedRevision: revision,
|
|
7773
8692
|
requestMessageId: createId("msg"),
|
|
7774
8693
|
contentBlocks: input.contentBlocks,
|
|
7775
|
-
calls: [{
|
|
8694
|
+
calls: [{
|
|
8695
|
+
toolCallId,
|
|
8696
|
+
providerToolCallId,
|
|
8697
|
+
name: toolCall.name,
|
|
8698
|
+
args: toJsonValue(toolCall.args),
|
|
8699
|
+
...pendingPres
|
|
8700
|
+
}]
|
|
7776
8701
|
});
|
|
7777
|
-
setRevision(
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
expectedRevision: revision,
|
|
7782
|
-
toolCallId
|
|
8702
|
+
setRevision(reserved.run.revision);
|
|
8703
|
+
const inProgressPres = await presentToolCall(durableTool, {
|
|
8704
|
+
status: "in_progress",
|
|
8705
|
+
args: toJsonValue(toolCall.args)
|
|
7783
8706
|
});
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
progressActive = true;
|
|
7787
|
-
try {
|
|
7788
|
-
let result = await durableTool.execute(toJsonValue(toolCall.args), context, input.signal);
|
|
7789
|
-
assertToolExecutionResult(result);
|
|
7790
|
-
if (input.toolConfig.afterToolCall) {
|
|
7791
|
-
result = await input.toolConfig.afterToolCall({
|
|
7792
|
-
tool: durableTool,
|
|
7793
|
-
result,
|
|
7794
|
-
context,
|
|
7795
|
-
signal: input.signal
|
|
7796
|
-
});
|
|
7797
|
-
}
|
|
7798
|
-
assertToolExecutionResult(result);
|
|
7799
|
-
result = await spillLargeToolResult(
|
|
7800
|
-
result,
|
|
7801
|
-
this.archiveDirFor(input.run.agentId),
|
|
7802
|
-
toolCall.name
|
|
7803
|
-
);
|
|
7804
|
-
const committed = await this.owned.commitToolResult({
|
|
8707
|
+
if (inProgressPres) mergeToolCall(currentToolState, inProgressPres);
|
|
8708
|
+
const started = await this.owned.startToolCall({
|
|
7805
8709
|
runId: input.run.id,
|
|
7806
8710
|
execution: input.execution,
|
|
7807
8711
|
expectedRevision: revision,
|
|
7808
8712
|
toolCallId,
|
|
7809
|
-
|
|
7810
|
-
|
|
8713
|
+
title: currentToolState.title ?? durableTool.annotations?.title ?? durableTool.name,
|
|
8714
|
+
kind: currentToolState.kind ?? durableTool.kind ?? "other",
|
|
8715
|
+
...currentToolState.locations !== void 0 ? { locations: currentToolState.locations } : {},
|
|
8716
|
+
...currentToolState.content !== void 0 ? { content: currentToolState.content } : {},
|
|
8717
|
+
...currentToolState._meta !== void 0 ? { _meta: currentToolState._meta } : {}
|
|
7811
8718
|
});
|
|
7812
|
-
setRevision(
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
8719
|
+
setRevision(started.run.revision);
|
|
8720
|
+
}
|
|
8721
|
+
const toolResult2 = await this.executeAndCommitTool({
|
|
8722
|
+
runId: input.run.id,
|
|
8723
|
+
agentId: input.run.agentId,
|
|
8724
|
+
agentMetadata: input.agentMetadata,
|
|
8725
|
+
runMetadata: input.run.metadata,
|
|
8726
|
+
execution: input.execution,
|
|
8727
|
+
revision,
|
|
8728
|
+
setRevision,
|
|
8729
|
+
toolCall,
|
|
8730
|
+
durableTool,
|
|
8731
|
+
toolCallId,
|
|
8732
|
+
providerToolCallId,
|
|
8733
|
+
scope,
|
|
8734
|
+
cwd,
|
|
8735
|
+
turn,
|
|
8736
|
+
driver: input.driver,
|
|
8737
|
+
toolCalls: input.toolCalls,
|
|
8738
|
+
toolCallIds: suspension?.toolCallIds,
|
|
8739
|
+
pendingIndex: index,
|
|
8740
|
+
completedResults: results,
|
|
8741
|
+
signal: input.signal,
|
|
8742
|
+
afterToolCall: input.toolConfig.afterToolCall,
|
|
8743
|
+
currentToolState,
|
|
8744
|
+
options: input.options
|
|
8745
|
+
});
|
|
8746
|
+
results.push(toolResult2);
|
|
8747
|
+
}
|
|
8748
|
+
input.driver?.clearCheckpoint();
|
|
8749
|
+
return { results, revision };
|
|
8750
|
+
}
|
|
8751
|
+
async executeAndCommitTool(input) {
|
|
8752
|
+
let progressActive = true;
|
|
8753
|
+
let progressQueue = Promise.resolve();
|
|
8754
|
+
const notifyUpdate = (toolCall, progress) => {
|
|
8755
|
+
if (input.options?.onUpdate) {
|
|
8756
|
+
try {
|
|
8757
|
+
input.options.onUpdate(toolCall, progress);
|
|
8758
|
+
} catch (err) {
|
|
8759
|
+
console.warn(`Error in tool call onUpdate callback:`, err);
|
|
7829
8760
|
}
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
|
|
8761
|
+
}
|
|
8762
|
+
};
|
|
8763
|
+
const startToolCall = createMergedToolCall(
|
|
8764
|
+
input.toolCallId,
|
|
8765
|
+
"in_progress",
|
|
8766
|
+
input.currentToolState,
|
|
8767
|
+
input.durableTool.annotations?.title ?? input.durableTool.name,
|
|
8768
|
+
input.durableTool.kind ?? "other"
|
|
8769
|
+
);
|
|
8770
|
+
notifyUpdate(startToolCall);
|
|
8771
|
+
const effectiveSignal = combineSignals(input.signal, input.options?.signal);
|
|
8772
|
+
const baseDriver = input.driver ?? createRunInteractionDriver({
|
|
8773
|
+
currentPhase: "default",
|
|
8774
|
+
attempt: 0,
|
|
8775
|
+
status: "running",
|
|
8776
|
+
metrics: { iterations: 0, phaseTransitions: [], compactionCount: 0, retryCount: 0, startedAt: (/* @__PURE__ */ new Date()).toISOString(), startedAtMs: Date.now() }
|
|
8777
|
+
}, "default", effectiveSignal);
|
|
8778
|
+
const interactionDriver = createToolInteractionDriver(baseDriver, {
|
|
8779
|
+
toolCallId: input.toolCallId,
|
|
8780
|
+
...input.toolCallIds === void 0 ? {} : { toolCallIds: input.toolCallIds },
|
|
8781
|
+
toolCalls: input.toolCalls,
|
|
8782
|
+
pendingIndex: input.pendingIndex,
|
|
8783
|
+
completedResults: input.completedResults
|
|
8784
|
+
});
|
|
8785
|
+
const context = {
|
|
8786
|
+
agentId: input.agentId,
|
|
8787
|
+
runId: input.runId,
|
|
8788
|
+
...input.agentMetadata === void 0 ? {} : { agentMetadata: input.agentMetadata },
|
|
8789
|
+
...input.runMetadata === void 0 ? {} : { runMetadata: input.runMetadata },
|
|
8790
|
+
toolCallId: input.toolCallId,
|
|
8791
|
+
providerToolCallId: input.providerToolCallId,
|
|
8792
|
+
scope: input.scope,
|
|
8793
|
+
...input.cwd ? { cwd: input.cwd } : {},
|
|
8794
|
+
turn: input.turn,
|
|
8795
|
+
interaction: interactionDriver,
|
|
8796
|
+
reportProgress: (progress) => {
|
|
8797
|
+
const active = this.executions.get(input.runId);
|
|
8798
|
+
if (!progressActive || this.closed || effectiveSignal.aborted || active?.executionId !== input.execution.executionId) return;
|
|
8799
|
+
if (!isValidToolProgress(progress)) {
|
|
8800
|
+
console.warn(`Invalid progress report for tool "${input.durableTool.name}": expected valid ToolProgress shape with finite numbers.`);
|
|
8801
|
+
return;
|
|
8802
|
+
}
|
|
8803
|
+
let copy;
|
|
8804
|
+
try {
|
|
8805
|
+
if (JSON.stringify(progress).length > 64 * 1024) return;
|
|
8806
|
+
copy = structuredClone(progress);
|
|
8807
|
+
} catch {
|
|
8808
|
+
return;
|
|
8809
|
+
}
|
|
8810
|
+
progressQueue = progressQueue.then(async () => {
|
|
8811
|
+
if (!progressActive || this.closed || effectiveSignal.aborted) return;
|
|
8812
|
+
const pres = await presentToolCall(input.durableTool, {
|
|
8813
|
+
status: "in_progress",
|
|
8814
|
+
args: toJsonValue(input.toolCall.args),
|
|
8815
|
+
progress: copy
|
|
8816
|
+
});
|
|
8817
|
+
if (pres) {
|
|
8818
|
+
mergeToolCall(input.currentToolState, pres);
|
|
8819
|
+
const progressToolCall = createMergedToolCall(
|
|
8820
|
+
input.toolCallId,
|
|
8821
|
+
"in_progress",
|
|
8822
|
+
input.currentToolState,
|
|
8823
|
+
input.durableTool.annotations?.title ?? input.durableTool.name,
|
|
8824
|
+
input.durableTool.kind ?? "other"
|
|
8825
|
+
);
|
|
8826
|
+
this.transientEvents.publish({
|
|
8827
|
+
kind: "tool_state_changed",
|
|
8828
|
+
durability: "transient",
|
|
8829
|
+
runId: input.runId,
|
|
8830
|
+
executionId: input.execution.executionId,
|
|
8831
|
+
transition: { from: "in_progress", to: "in_progress" },
|
|
8832
|
+
toolCall: progressToolCall
|
|
8833
|
+
});
|
|
8834
|
+
notifyUpdate(progressToolCall, copy);
|
|
8835
|
+
}
|
|
8836
|
+
}).catch((err) => {
|
|
8837
|
+
console.warn(`Error handling progress report for tool "${input.durableTool.name}":`, err);
|
|
8838
|
+
});
|
|
8839
|
+
}
|
|
8840
|
+
};
|
|
8841
|
+
try {
|
|
8842
|
+
if (input.options?.signal?.aborted) {
|
|
8843
|
+
const error = input.options.signal.reason instanceof Error ? input.options.signal.reason : new DOMException(
|
|
8844
|
+
typeof input.options.signal.reason === "string" ? input.options.signal.reason : "Tool execution aborted.",
|
|
8845
|
+
"AbortError"
|
|
8846
|
+
);
|
|
8847
|
+
throw error;
|
|
8848
|
+
}
|
|
8849
|
+
let result = await withAbort(
|
|
8850
|
+
input.durableTool.execute(toJsonValue(input.toolCall.args), context, effectiveSignal),
|
|
8851
|
+
input.options?.signal
|
|
8852
|
+
);
|
|
8853
|
+
assertToolExecutionResult(result);
|
|
8854
|
+
if (input.afterToolCall) {
|
|
8855
|
+
result = await input.afterToolCall({
|
|
8856
|
+
tool: input.durableTool,
|
|
8857
|
+
result,
|
|
8858
|
+
context,
|
|
8859
|
+
signal: effectiveSignal
|
|
8860
|
+
});
|
|
8861
|
+
}
|
|
8862
|
+
assertToolExecutionResult(result);
|
|
8863
|
+
result = await spillLargeToolResult(
|
|
8864
|
+
result,
|
|
8865
|
+
this.archiveDirFor(input.agentId),
|
|
8866
|
+
input.toolCall.name
|
|
8867
|
+
);
|
|
8868
|
+
await progressQueue.catch(() => {
|
|
8869
|
+
});
|
|
8870
|
+
const finalState = result.ok ? "completed" : "failed";
|
|
8871
|
+
const completionPres = await presentToolCall(input.durableTool, {
|
|
8872
|
+
status: finalState,
|
|
8873
|
+
args: toJsonValue(input.toolCall.args),
|
|
8874
|
+
result
|
|
8875
|
+
});
|
|
8876
|
+
if (completionPres) {
|
|
8877
|
+
mergeToolCall(input.currentToolState, completionPres);
|
|
8878
|
+
}
|
|
8879
|
+
const rawOutput = "structuredContent" in result && result.structuredContent !== void 0 ? toJsonValue(result.structuredContent) : toJsonValue(result.content);
|
|
8880
|
+
if (input.currentToolState.rawOutput === void 0) {
|
|
8881
|
+
input.currentToolState.rawOutput = rawOutput;
|
|
8882
|
+
}
|
|
8883
|
+
const committed = await this.owned.commitToolResult({
|
|
8884
|
+
runId: input.runId,
|
|
8885
|
+
execution: input.execution,
|
|
8886
|
+
expectedRevision: input.revision,
|
|
8887
|
+
toolCallId: input.toolCallId,
|
|
8888
|
+
state: finalState,
|
|
8889
|
+
result,
|
|
8890
|
+
title: input.currentToolState.title ?? input.durableTool.annotations?.title ?? input.durableTool.name,
|
|
8891
|
+
kind: input.currentToolState.kind ?? input.durableTool.kind ?? "other",
|
|
8892
|
+
locations: input.currentToolState.locations,
|
|
8893
|
+
content: input.currentToolState.content,
|
|
8894
|
+
rawOutput: input.currentToolState.rawOutput,
|
|
8895
|
+
_meta: input.currentToolState._meta
|
|
8896
|
+
});
|
|
8897
|
+
input.setRevision(committed.run.revision);
|
|
8898
|
+
const finalToolCall = createMergedToolCall(
|
|
8899
|
+
input.toolCallId,
|
|
8900
|
+
finalState,
|
|
8901
|
+
input.currentToolState,
|
|
8902
|
+
input.durableTool.annotations?.title ?? input.durableTool.name,
|
|
8903
|
+
input.durableTool.kind ?? "other"
|
|
8904
|
+
);
|
|
8905
|
+
notifyUpdate(finalToolCall);
|
|
8906
|
+
const projectedResult = await this.foldToolInteractionRecords(result, input.toolCallId, input.agentId);
|
|
8907
|
+
const ok = "ok" in projectedResult && typeof projectedResult.ok === "boolean" ? projectedResult.ok : !projectedResult.isError;
|
|
8908
|
+
return {
|
|
8909
|
+
toolCallId: input.providerToolCallId,
|
|
8910
|
+
toolName: input.toolCall.name,
|
|
8911
|
+
...projectedResult,
|
|
8912
|
+
ok
|
|
8913
|
+
};
|
|
8914
|
+
} catch (error) {
|
|
8915
|
+
if (error instanceof RunInteractionBoundary) {
|
|
8916
|
+
const suspended = await this.owned.suspendToolCall({
|
|
8917
|
+
runId: input.runId,
|
|
7834
8918
|
execution: input.execution,
|
|
7835
|
-
expectedRevision: revision,
|
|
7836
|
-
toolCallId
|
|
7837
|
-
state: "indeterminate",
|
|
7838
|
-
reason,
|
|
7839
|
-
result: { ok: false, content: null, error: reason }
|
|
8919
|
+
expectedRevision: input.revision,
|
|
8920
|
+
toolCallId: input.toolCallId
|
|
7840
8921
|
});
|
|
7841
|
-
setRevision(
|
|
7842
|
-
|
|
7843
|
-
} finally {
|
|
7844
|
-
progressActive = false;
|
|
7845
|
-
this.transientEvents.clearTool(input.run.id, toolCallId);
|
|
8922
|
+
input.setRevision(suspended.run.revision);
|
|
8923
|
+
throw error;
|
|
7846
8924
|
}
|
|
8925
|
+
if (error instanceof RunInteractionCancelledError) throw error;
|
|
8926
|
+
const isPerCallAbort = Boolean(input.options?.signal?.aborted && !input.signal.aborted);
|
|
8927
|
+
const reason = error instanceof Error ? error.message : isPerCallAbort ? "Tool execution aborted." : "Tool execution outcome is indeterminate.";
|
|
8928
|
+
await progressQueue.catch(() => {
|
|
8929
|
+
});
|
|
8930
|
+
const failurePres = await presentToolCall(input.durableTool, {
|
|
8931
|
+
status: "failed",
|
|
8932
|
+
args: toJsonValue(input.toolCall.args),
|
|
8933
|
+
result: { ok: false, content: null, error: reason }
|
|
8934
|
+
});
|
|
8935
|
+
if (failurePres) {
|
|
8936
|
+
mergeToolCall(input.currentToolState, failurePres);
|
|
8937
|
+
}
|
|
8938
|
+
const commitState = isPerCallAbort ? "failed" : "indeterminate";
|
|
8939
|
+
const committed = await this.owned.commitToolResult({
|
|
8940
|
+
runId: input.runId,
|
|
8941
|
+
execution: input.execution,
|
|
8942
|
+
expectedRevision: input.revision,
|
|
8943
|
+
toolCallId: input.toolCallId,
|
|
8944
|
+
state: commitState,
|
|
8945
|
+
...isPerCallAbort ? {} : { reason },
|
|
8946
|
+
result: { ok: false, content: null, error: reason },
|
|
8947
|
+
title: input.currentToolState.title ?? input.durableTool.annotations?.title ?? input.durableTool.name,
|
|
8948
|
+
kind: input.currentToolState.kind ?? input.durableTool.kind ?? "other",
|
|
8949
|
+
locations: input.currentToolState.locations,
|
|
8950
|
+
content: input.currentToolState.content,
|
|
8951
|
+
_meta: input.currentToolState._meta
|
|
8952
|
+
});
|
|
8953
|
+
input.setRevision(committed.run.revision);
|
|
8954
|
+
const finalToolCall = createMergedToolCall(
|
|
8955
|
+
input.toolCallId,
|
|
8956
|
+
"failed",
|
|
8957
|
+
input.currentToolState,
|
|
8958
|
+
input.durableTool.annotations?.title ?? input.durableTool.name,
|
|
8959
|
+
input.durableTool.kind ?? "other"
|
|
8960
|
+
);
|
|
8961
|
+
notifyUpdate(finalToolCall);
|
|
8962
|
+
return {
|
|
8963
|
+
toolCallId: input.providerToolCallId,
|
|
8964
|
+
toolName: input.toolCall.name,
|
|
8965
|
+
ok: false,
|
|
8966
|
+
content: null,
|
|
8967
|
+
error: reason
|
|
8968
|
+
};
|
|
8969
|
+
} finally {
|
|
8970
|
+
progressActive = false;
|
|
8971
|
+
this.transientEvents.clearTool(input.runId, input.toolCallId);
|
|
7847
8972
|
}
|
|
7848
|
-
input.driver?.clearCheckpoint();
|
|
7849
|
-
return { results, revision };
|
|
7850
8973
|
}
|
|
7851
8974
|
async foldToolInteractionRecords(result, toolCallId, agentId) {
|
|
7852
8975
|
const interactionMessages = (await this.owned.history(agentId)).filter(
|
|
@@ -7855,11 +8978,27 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
7855
8978
|
if (interactionMessages.length === 0) return result;
|
|
7856
8979
|
const interactionText = interactionMessages.filter((message) => message.role === "interaction").map(renderInteractionText).join("\n\n");
|
|
7857
8980
|
const content = typeof result.content === "string" ? result.content : JSON.stringify(result.content) ?? "null";
|
|
7858
|
-
|
|
7859
|
-
...result,
|
|
7860
|
-
content: content === "null" || content.length === 0 ? interactionText : `${interactionText}
|
|
8981
|
+
const appendedText = content === "null" || content.length === 0 ? interactionText : `${interactionText}
|
|
7861
8982
|
|
|
7862
|
-
${content}
|
|
8983
|
+
${content}`;
|
|
8984
|
+
if (Array.isArray(result.content)) {
|
|
8985
|
+
return {
|
|
8986
|
+
...result,
|
|
8987
|
+
content: [{ type: "text", text: appendedText }]
|
|
8988
|
+
};
|
|
8989
|
+
}
|
|
8990
|
+
if (result.ok) {
|
|
8991
|
+
return {
|
|
8992
|
+
ok: true,
|
|
8993
|
+
content: appendedText,
|
|
8994
|
+
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {}
|
|
8995
|
+
};
|
|
8996
|
+
}
|
|
8997
|
+
return {
|
|
8998
|
+
ok: false,
|
|
8999
|
+
content: appendedText,
|
|
9000
|
+
error: result.error ?? "Tool execution failed.",
|
|
9001
|
+
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {}
|
|
7863
9002
|
};
|
|
7864
9003
|
}
|
|
7865
9004
|
async requireAgent(agentId) {
|
|
@@ -7947,8 +9086,8 @@ ${content}`
|
|
|
7947
9086
|
if (event.runId !== runId) continue;
|
|
7948
9087
|
if (event.kind === "message_committed") {
|
|
7949
9088
|
subscription.clearMessage(event.message.id);
|
|
7950
|
-
} else if (event.kind === "tool_state_changed" && ["completed", "failed"
|
|
7951
|
-
subscription.clearTool(event.toolCall.
|
|
9089
|
+
} else if (event.kind === "tool_state_changed" && ["completed", "failed"].includes(event.transition.to)) {
|
|
9090
|
+
subscription.clearTool(event.toolCall.toolCallId);
|
|
7952
9091
|
}
|
|
7953
9092
|
if (event.kind === "run_state_changed" && ["completed", "failed", "cancelled"].includes(event.to)) {
|
|
7954
9093
|
while (true) {
|
|
@@ -8146,6 +9285,19 @@ function toJsonValue(value) {
|
|
|
8146
9285
|
assertJsonValue(value, "tool arguments");
|
|
8147
9286
|
return value;
|
|
8148
9287
|
}
|
|
9288
|
+
function createMergedToolCall(toolCallId, status, current, fallbackTitle, fallbackKind = "other") {
|
|
9289
|
+
return {
|
|
9290
|
+
toolCallId,
|
|
9291
|
+
title: current.title ?? fallbackTitle,
|
|
9292
|
+
kind: current.kind ?? fallbackKind,
|
|
9293
|
+
status,
|
|
9294
|
+
...current.locations !== void 0 ? { locations: current.locations } : {},
|
|
9295
|
+
...current.content !== void 0 ? { content: current.content } : {},
|
|
9296
|
+
...current.rawInput !== void 0 ? { rawInput: current.rawInput } : {},
|
|
9297
|
+
...current.rawOutput !== void 0 ? { rawOutput: current.rawOutput } : {},
|
|
9298
|
+
...current._meta !== void 0 ? { _meta: current._meta } : {}
|
|
9299
|
+
};
|
|
9300
|
+
}
|
|
8149
9301
|
function deferred2() {
|
|
8150
9302
|
let resolve9;
|
|
8151
9303
|
let reject;
|
|
@@ -8158,6 +9310,24 @@ function deferred2() {
|
|
|
8158
9310
|
|
|
8159
9311
|
// src/runtime/durable-store.ts
|
|
8160
9312
|
import { createHash } from "crypto";
|
|
9313
|
+
function defaultToolCallContent(result) {
|
|
9314
|
+
if ("content" in result && Array.isArray(result.content)) {
|
|
9315
|
+
return result.content.map((block) => {
|
|
9316
|
+
if (typeof block === "object" && block !== null && "type" in block && (block.type === "content" || block.type === "diff" || block.type === "terminal")) {
|
|
9317
|
+
return block;
|
|
9318
|
+
}
|
|
9319
|
+
return {
|
|
9320
|
+
type: "content",
|
|
9321
|
+
content: block
|
|
9322
|
+
};
|
|
9323
|
+
});
|
|
9324
|
+
}
|
|
9325
|
+
const content = result.content;
|
|
9326
|
+
if (typeof content === "string") {
|
|
9327
|
+
return [{ type: "content", content: { type: "text", text: content } }];
|
|
9328
|
+
}
|
|
9329
|
+
return [{ type: "content", content: { type: "text", text: JSON.stringify(content ?? null) } }];
|
|
9330
|
+
}
|
|
8161
9331
|
var InMemoryStore = class _InMemoryStore {
|
|
8162
9332
|
incarnation;
|
|
8163
9333
|
agents = /* @__PURE__ */ new Map();
|
|
@@ -8276,7 +9446,7 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
8276
9446
|
}
|
|
8277
9447
|
}
|
|
8278
9448
|
for (const message of state.messages) store.messages.set(message.id, clone(message));
|
|
8279
|
-
for (const toolCall of state.toolCalls ?? []) store.toolCalls.set(toolCall.id, clone(toolCall));
|
|
9449
|
+
for (const toolCall of state.toolCalls ?? []) store.toolCalls.set(toolCall.id ?? toolCall.toolCallId, clone(toolCall));
|
|
8280
9450
|
store.events.push(...clone(state.events));
|
|
8281
9451
|
for (const [key, receipt] of state.idempotency) store.idempotency.set(key, clone(receipt));
|
|
8282
9452
|
for (const [key, receipt] of state.operationReceipts) {
|
|
@@ -8341,10 +9511,10 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
8341
9511
|
this.ownerEpoch = Math.max(this.ownerEpoch, ownerEpoch);
|
|
8342
9512
|
for (const run of this.runs.values()) {
|
|
8343
9513
|
if (run.state !== "running" || run.execution?.ownerEpoch !== ownerEpoch) continue;
|
|
8344
|
-
const activeToolCalls = [...this.toolCalls.values()].filter((toolCall) => toolCall.runId === run.id && toolCall.executionId === run.execution?.executionId && (toolCall.state === "pending" || toolCall.state === "
|
|
9514
|
+
const activeToolCalls = [...this.toolCalls.values()].filter((toolCall) => toolCall.runId === run.id && toolCall.executionId === run.execution?.executionId && (toolCall.status === "pending" || toolCall.status === "in_progress" || toolCall.state === "pending" || toolCall.state === "in_progress"));
|
|
8345
9515
|
const indeterminateToolCallIds = [];
|
|
8346
9516
|
for (const toolCall of activeToolCalls) {
|
|
8347
|
-
if (toolCall.state === "
|
|
9517
|
+
if (toolCall.status === "in_progress" || toolCall.state === "in_progress") indeterminateToolCallIds.push(toolCall.id);
|
|
8348
9518
|
this.interruptToolCall(run, toolCall, message);
|
|
8349
9519
|
}
|
|
8350
9520
|
const failure = indeterminateToolCallIds.length > 0 ? { code: "tool_indeterminate", message, toolCallIds: indeterminateToolCallIds } : { code: "runtime_interrupted", message, ownerEpoch };
|
|
@@ -8604,7 +9774,7 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
8604
9774
|
run.invalidatedBy = { messageId: original.id, messageRevision: actualRevision + 1 };
|
|
8605
9775
|
if (run.state === "running" || run.state === "queued" || run.state === "input_required") {
|
|
8606
9776
|
if (run.state === "running") {
|
|
8607
|
-
const openToolCalls = [...this.toolCalls.values()].filter((toolCall) => toolCall.runId === run.id && toolCall.executionId === run.execution?.executionId && (toolCall.state === "pending" || toolCall.state === "
|
|
9777
|
+
const openToolCalls = [...this.toolCalls.values()].filter((toolCall) => toolCall.runId === run.id && toolCall.executionId === run.execution?.executionId && (toolCall.status === "pending" || toolCall.status === "in_progress" || toolCall.state === "pending" || toolCall.state === "in_progress"));
|
|
8608
9778
|
for (const toolCall of openToolCalls) this.interruptToolCall(run, toolCall, "Run superseded by Message revision.");
|
|
8609
9779
|
} else {
|
|
8610
9780
|
delete run.openInteractions;
|
|
@@ -8700,7 +9870,7 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
8700
9870
|
if (input.phasePayload !== void 0) assertJsonValue(input.phasePayload, "run.phasePayload");
|
|
8701
9871
|
if (input.entryPhases !== void 0) assertEntryPhases(input.entryPhases, "run.entryPhases");
|
|
8702
9872
|
const scope = createIdempotencyScope("start_run", input.agentId, input.idempotencyKey);
|
|
8703
|
-
const payload = canonicalStartRunRequest(normalizedInput, input.metadata, input.phasePayload, input.pinnedConfigToken, input.entryPhases);
|
|
9873
|
+
const payload = canonicalStartRunRequest(normalizedInput, input.metadata, input.phasePayload, input.pinnedConfigToken, input.entryPhases, input.scope, input.cwd);
|
|
8704
9874
|
const replay = this.replay(scope, payload);
|
|
8705
9875
|
if (replay) return clone(replay);
|
|
8706
9876
|
const waitingRun = isControlMetadata(input.metadata) ? void 0 : [...this.runs.values()].find((candidate) => candidate.agentId === input.agentId && candidate.state === "input_required");
|
|
@@ -8756,6 +9926,8 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
8756
9926
|
state: "queued",
|
|
8757
9927
|
input: clone(normalizedInput),
|
|
8758
9928
|
...input.metadata ? { metadata: clone(input.metadata) } : {},
|
|
9929
|
+
...input.scope !== void 0 ? { scope: clone(input.scope) } : {},
|
|
9930
|
+
...input.cwd !== void 0 ? { cwd: input.cwd } : {},
|
|
8759
9931
|
...input.phasePayload === void 0 ? {} : { phasePayload: clone(input.phasePayload) },
|
|
8760
9932
|
...input.entryPhases === void 0 ? {} : { entryPhases: clone(input.entryPhases) },
|
|
8761
9933
|
...input.pinnedConfigToken === void 0 ? {} : { pinnedConfigToken: input.pinnedConfigToken },
|
|
@@ -9031,19 +10203,30 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9031
10203
|
this.assertExecution(run, input.execution, input.expectedRevision);
|
|
9032
10204
|
if (this.messages.has(input.requestMessageId)) throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["running"], actual: run.state });
|
|
9033
10205
|
const timestamp = createTimestamp();
|
|
9034
|
-
const toolCalls = input.calls.map((call) =>
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
|
|
9046
|
-
|
|
10206
|
+
const toolCalls = input.calls.map((call) => {
|
|
10207
|
+
const toolCallId = call.providerToolCallId || (call.toolCallId ?? createId("tool"));
|
|
10208
|
+
return {
|
|
10209
|
+
id: call.toolCallId ?? createId("tool"),
|
|
10210
|
+
toolCallId,
|
|
10211
|
+
...call.providerToolCallId ? { providerToolCallId: call.providerToolCallId } : {},
|
|
10212
|
+
agentId: run.agentId,
|
|
10213
|
+
runId: run.id,
|
|
10214
|
+
executionId: input.execution.executionId,
|
|
10215
|
+
requestMessageId: input.requestMessageId,
|
|
10216
|
+
name: call.name,
|
|
10217
|
+
title: call.title ?? call.name,
|
|
10218
|
+
kind: call.kind ?? "other",
|
|
10219
|
+
status: "pending",
|
|
10220
|
+
state: "pending",
|
|
10221
|
+
...call.content ? { content: clone(call.content) } : {},
|
|
10222
|
+
...call.locations ? { locations: clone(call.locations) } : {},
|
|
10223
|
+
rawInput: clone(call.args),
|
|
10224
|
+
...call._meta ? { _meta: clone(call._meta) } : {},
|
|
10225
|
+
args: clone(call.args),
|
|
10226
|
+
createdAt: timestamp,
|
|
10227
|
+
updatedAt: timestamp
|
|
10228
|
+
};
|
|
10229
|
+
});
|
|
9047
10230
|
for (const toolCall of toolCalls) {
|
|
9048
10231
|
if (this.toolCalls.has(toolCall.id)) throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["running"], actual: run.state });
|
|
9049
10232
|
}
|
|
@@ -9079,15 +10262,27 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9079
10262
|
const run = this.requireRun(input.runId);
|
|
9080
10263
|
this.assertExecution(run, input.execution, input.expectedRevision);
|
|
9081
10264
|
const toolCall = this.requireToolCall(input.toolCallId, run);
|
|
9082
|
-
if (toolCall.state !== "pending") throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["running"], actual: run.state });
|
|
9083
|
-
toolCall.
|
|
10265
|
+
if (toolCall.status !== "pending" && toolCall.state !== "pending") throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["running"], actual: run.state });
|
|
10266
|
+
const from = toolCall.status ?? "pending";
|
|
10267
|
+
toolCall.status = "in_progress";
|
|
10268
|
+
toolCall.state = "in_progress";
|
|
9084
10269
|
toolCall.executionId = input.execution.executionId;
|
|
10270
|
+
if (input.title !== void 0) toolCall.title = input.title;
|
|
10271
|
+
if (input.kind !== void 0) toolCall.kind = input.kind;
|
|
10272
|
+
if (input.locations !== void 0) toolCall.locations = clone(input.locations);
|
|
10273
|
+
if (input.content !== void 0) toolCall.content = clone(input.content);
|
|
10274
|
+
if (input._meta !== void 0) {
|
|
10275
|
+
toolCall._meta = {
|
|
10276
|
+
...toolCall._meta ?? {},
|
|
10277
|
+
...clone(input._meta)
|
|
10278
|
+
};
|
|
10279
|
+
}
|
|
9085
10280
|
toolCall.updatedAt = createTimestamp();
|
|
9086
10281
|
this.storeToolCall(toolCall);
|
|
9087
10282
|
run.revision += 1;
|
|
9088
10283
|
run.updatedAt = toolCall.updatedAt;
|
|
9089
10284
|
this.touchRun(run);
|
|
9090
|
-
this.appendToolTransition(run, { from
|
|
10285
|
+
this.appendToolTransition(run, { from, to: "in_progress" }, toolCall);
|
|
9091
10286
|
const result = { run: clone(run), toolCall: clone(toolCall) };
|
|
9092
10287
|
this.writeOperationReceipt(operationKey, operationPayload, result, run.id);
|
|
9093
10288
|
return result;
|
|
@@ -9101,16 +10296,18 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9101
10296
|
const run = this.requireRun(input.runId);
|
|
9102
10297
|
this.assertExecution(run, input.execution, input.expectedRevision);
|
|
9103
10298
|
const toolCall = this.requireToolCall(input.toolCallId, run);
|
|
9104
|
-
if (toolCall.state !== "
|
|
10299
|
+
if (toolCall.status !== "in_progress" && toolCall.state !== "in_progress" || toolCall.executionId !== input.execution.executionId) {
|
|
9105
10300
|
throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["running"], actual: run.state });
|
|
9106
10301
|
}
|
|
10302
|
+
const from = toolCall.status ?? "in_progress";
|
|
10303
|
+
toolCall.status = "pending";
|
|
9107
10304
|
toolCall.state = "pending";
|
|
9108
10305
|
toolCall.updatedAt = createTimestamp();
|
|
9109
10306
|
this.storeToolCall(toolCall);
|
|
9110
10307
|
run.revision += 1;
|
|
9111
10308
|
run.updatedAt = toolCall.updatedAt;
|
|
9112
10309
|
this.touchRun(run);
|
|
9113
|
-
this.appendToolTransition(run, { from
|
|
10310
|
+
this.appendToolTransition(run, { from, to: "pending" }, toolCall);
|
|
9114
10311
|
const result = { run: clone(run), toolCall: clone(toolCall) };
|
|
9115
10312
|
this.writeOperationReceipt(operationKey, operationPayload, result, run.id);
|
|
9116
10313
|
return result;
|
|
@@ -9119,8 +10316,9 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9119
10316
|
this.assertOwner(lease);
|
|
9120
10317
|
assertToolExecutionResult(input.result);
|
|
9121
10318
|
assertToolValue(input.result, "tool.result");
|
|
9122
|
-
|
|
9123
|
-
if (input.state
|
|
10319
|
+
const isCompleted = "ok" in input.result ? input.result.ok : !input.result.isError;
|
|
10320
|
+
if (input.state === "completed" && !isCompleted) throw new TypeError("completed ToolCall requires a successful result");
|
|
10321
|
+
if (input.state !== "completed" && isCompleted) throw new TypeError(`${input.state} ToolCall requires a failed result`);
|
|
9124
10322
|
if (input.state === "indeterminate" && (!input.reason || input.reason.trim().length === 0)) throw new TypeError("indeterminate ToolCall requires a reason");
|
|
9125
10323
|
const operationKey = `tool_commit:${input.toolCallId}`;
|
|
9126
10324
|
const operationPayload = canonicalJson([input.runId, input.expectedRevision, input.execution.executionId, input.state, input.result, input.reason ?? null]);
|
|
@@ -9130,10 +10328,9 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9130
10328
|
this.assertExecution(run, input.execution, input.expectedRevision);
|
|
9131
10329
|
const toolCall = this.requireToolCall(input.toolCallId, run);
|
|
9132
10330
|
if (toolCall.executionId !== input.execution.executionId) throw new RuntimeError("runtime_ownership_lost", { reason: "epoch_advanced", expectedEpoch: input.execution.ownerEpoch, actualEpoch: this.ownerEpoch });
|
|
9133
|
-
const
|
|
9134
|
-
|
|
9135
|
-
|
|
9136
|
-
const durableResult = { toolCallId: toolCall.id, toolName: toolCall.name, ...clone(input.result) };
|
|
10331
|
+
const fromStatus = toolCall.status ?? (toolCall.state === "in_progress" ? "in_progress" : toolCall.state);
|
|
10332
|
+
const toStatus = input.state === "completed" ? "completed" : "failed";
|
|
10333
|
+
const durableResult = { toolCallId: toolCall.id, toolName: toolCall.name ?? toolCall.title, ...clone(input.result) };
|
|
9137
10334
|
const resultMessageId = createId("msg");
|
|
9138
10335
|
const message = {
|
|
9139
10336
|
id: resultMessageId,
|
|
@@ -9145,7 +10342,21 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9145
10342
|
createdAt: createTimestamp()
|
|
9146
10343
|
};
|
|
9147
10344
|
this.storeMessage(message);
|
|
9148
|
-
toolCall.
|
|
10345
|
+
toolCall.status = toStatus;
|
|
10346
|
+
toolCall.state = toStatus;
|
|
10347
|
+
if (input.title !== void 0) toolCall.title = input.title;
|
|
10348
|
+
if (input.kind !== void 0) toolCall.kind = input.kind;
|
|
10349
|
+
if (input.locations !== void 0) toolCall.locations = clone(input.locations);
|
|
10350
|
+
if (input.content !== void 0) toolCall.content = clone(input.content);
|
|
10351
|
+
else if (toolCall.content === void 0) toolCall.content = defaultToolCallContent(input.result);
|
|
10352
|
+
if (input.rawOutput !== void 0) toolCall.rawOutput = clone(input.rawOutput);
|
|
10353
|
+
else if (toolCall.rawOutput === void 0) toolCall.rawOutput = "structuredContent" in input.result && input.result.structuredContent !== void 0 ? clone(input.result.structuredContent) : clone(input.result.content);
|
|
10354
|
+
if (input._meta !== void 0) {
|
|
10355
|
+
toolCall._meta = {
|
|
10356
|
+
...toolCall._meta ?? {},
|
|
10357
|
+
...clone(input._meta)
|
|
10358
|
+
};
|
|
10359
|
+
}
|
|
9149
10360
|
toolCall.result = durableResult;
|
|
9150
10361
|
toolCall.resultMessageId = resultMessageId;
|
|
9151
10362
|
if (input.state === "indeterminate") toolCall.reason = input.reason;
|
|
@@ -9155,13 +10366,13 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9155
10366
|
run.revision += 1;
|
|
9156
10367
|
run.updatedAt = message.createdAt;
|
|
9157
10368
|
this.touchRun(run);
|
|
9158
|
-
this.appendToolTransition(run, { from, to:
|
|
10369
|
+
this.appendToolTransition(run, { from: fromStatus, to: toStatus }, toolCall);
|
|
9159
10370
|
this.appendMessage(run, message);
|
|
9160
10371
|
if (input.state === "indeterminate") {
|
|
9161
|
-
const openToolCalls = [...this.toolCalls.values()].filter((candidate) => candidate.runId === run.id && candidate.executionId === input.execution.executionId && candidate.id !== toolCall.id && (candidate.state === "pending" || candidate.state === "
|
|
10372
|
+
const openToolCalls = [...this.toolCalls.values()].filter((candidate) => candidate.runId === run.id && candidate.executionId === input.execution.executionId && candidate.id !== toolCall.id && (candidate.status === "pending" || candidate.status === "in_progress" || candidate.state === "pending" || candidate.state === "in_progress"));
|
|
9162
10373
|
const indeterminateToolCallIds = [toolCall.id];
|
|
9163
10374
|
for (const candidate of openToolCalls) {
|
|
9164
|
-
if (candidate.state === "
|
|
10375
|
+
if (candidate.status === "in_progress" || candidate.state === "in_progress") indeterminateToolCallIds.push(candidate.id);
|
|
9165
10376
|
this.interruptToolCall(run, candidate, input.reason);
|
|
9166
10377
|
}
|
|
9167
10378
|
const failure = {
|
|
@@ -9203,7 +10414,11 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9203
10414
|
}
|
|
9204
10415
|
run.state = nextState;
|
|
9205
10416
|
if (input.outcome) run.outcome = clone(input.outcome);
|
|
9206
|
-
|
|
10417
|
+
let failure = input.failure ? clone(input.failure) : void 0;
|
|
10418
|
+
if (nextState === "failed" && failure) {
|
|
10419
|
+
failure = this.withdrawUserInputIfNoOutput(run, failure, output);
|
|
10420
|
+
run.failure = failure;
|
|
10421
|
+
}
|
|
9207
10422
|
this.dropClaimReceipt(run.execution);
|
|
9208
10423
|
delete run.execution;
|
|
9209
10424
|
delete run.openInteractions;
|
|
@@ -9211,7 +10426,7 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9211
10426
|
run.revision += 1;
|
|
9212
10427
|
run.updatedAt = createTimestamp();
|
|
9213
10428
|
this.touchRun(run);
|
|
9214
|
-
this.appendTransition(run, "running", nextState, { outcome: input.outcome, failure
|
|
10429
|
+
this.appendTransition(run, "running", nextState, { outcome: input.outcome, failure, output });
|
|
9215
10430
|
this.dropRunOperationReceipts(run.id);
|
|
9216
10431
|
const result = clone(run);
|
|
9217
10432
|
return result;
|
|
@@ -9236,14 +10451,14 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9236
10451
|
return result2;
|
|
9237
10452
|
}
|
|
9238
10453
|
const from = run.state;
|
|
9239
|
-
const activeToolCalls = run.execution ? [...this.toolCalls.values()].filter((toolCall) => toolCall.runId === run.id && toolCall.executionId === run.execution?.executionId && (toolCall.state === "pending" || toolCall.state === "
|
|
10454
|
+
const activeToolCalls = run.execution ? [...this.toolCalls.values()].filter((toolCall) => toolCall.runId === run.id && toolCall.executionId === run.execution?.executionId && (toolCall.status === "pending" || toolCall.status === "in_progress" || toolCall.state === "pending" || toolCall.state === "in_progress")) : run.state === "input_required" && run.checkpoint?.data && typeof run.checkpoint.data === "object" && !Array.isArray(run.checkpoint.data) ? (() => {
|
|
9240
10455
|
const interactionState = run.checkpoint.data.runInteractions;
|
|
9241
10456
|
const interactionCheckpoint = interactionState && typeof interactionState === "object" && !Array.isArray(interactionState) ? interactionState.checkpoint : void 0;
|
|
9242
10457
|
const ids = interactionCheckpoint && typeof interactionCheckpoint === "object" && !Array.isArray(interactionCheckpoint) ? interactionCheckpoint.toolCallIds : void 0;
|
|
9243
10458
|
const allowed = new Set(Array.isArray(ids) ? ids : []);
|
|
9244
|
-
return [...this.toolCalls.values()].filter((toolCall) => toolCall.runId === run.id && toolCall.state === "pending" && allowed.has(toolCall.id));
|
|
10459
|
+
return [...this.toolCalls.values()].filter((toolCall) => toolCall.runId === run.id && (toolCall.status === "pending" || toolCall.state === "pending") && allowed.has(toolCall.id));
|
|
9245
10460
|
})() : [];
|
|
9246
|
-
const indeterminateToolCallIds = activeToolCalls.filter((toolCall) => toolCall.state === "
|
|
10461
|
+
const indeterminateToolCallIds = activeToolCalls.filter((toolCall) => toolCall.status === "in_progress" || toolCall.state === "in_progress").map((toolCall) => toolCall.id);
|
|
9247
10462
|
for (const toolCall of activeToolCalls) this.interruptToolCall(run, toolCall, input.reason ?? "The Run was cancelled.");
|
|
9248
10463
|
if (input.output && (typeof input.output.content === "string" ? input.output.content.length > 0 : input.output.content.length > 0)) {
|
|
9249
10464
|
const output = { ...clone(input.output), sequenceWithinRun: this.nextMessageSequence(run.id) };
|
|
@@ -9290,6 +10505,74 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9290
10505
|
const result = clone(run);
|
|
9291
10506
|
return result;
|
|
9292
10507
|
}
|
|
10508
|
+
recordToolCall(lease, input) {
|
|
10509
|
+
this.assertOwner(lease);
|
|
10510
|
+
const run = this.requireRun(input.runId);
|
|
10511
|
+
if (input.execution) {
|
|
10512
|
+
if (run.state !== "running" || !run.execution || run.execution.executionId !== input.execution.executionId || run.execution.ownerEpoch !== input.execution.ownerEpoch) {
|
|
10513
|
+
throw new RuntimeError("runtime_ownership_lost", {
|
|
10514
|
+
reason: "epoch_advanced",
|
|
10515
|
+
expectedEpoch: input.execution.ownerEpoch,
|
|
10516
|
+
actualEpoch: this.ownerEpoch
|
|
10517
|
+
});
|
|
10518
|
+
}
|
|
10519
|
+
}
|
|
10520
|
+
const toolCallId = input.update.toolCallId;
|
|
10521
|
+
const existing = this.toolCalls.get(toolCallId);
|
|
10522
|
+
const fromStatus = existing ? existing.status : null;
|
|
10523
|
+
const toStatus = input.update.status ?? (existing ? existing.status : "in_progress");
|
|
10524
|
+
const timestamp = createTimestamp();
|
|
10525
|
+
let stored;
|
|
10526
|
+
if (existing) {
|
|
10527
|
+
mergeToolCall(existing, input.update);
|
|
10528
|
+
existing.status = toStatus;
|
|
10529
|
+
existing.state = toStatus;
|
|
10530
|
+
if (input.external !== void 0) existing.external = input.external;
|
|
10531
|
+
existing.updatedAt = timestamp;
|
|
10532
|
+
stored = existing;
|
|
10533
|
+
} else {
|
|
10534
|
+
stored = {
|
|
10535
|
+
id: toolCallId,
|
|
10536
|
+
toolCallId,
|
|
10537
|
+
providerToolCallId: toolCallId,
|
|
10538
|
+
agentId: run.agentId,
|
|
10539
|
+
runId: run.id,
|
|
10540
|
+
executionId: input.execution?.executionId,
|
|
10541
|
+
title: "title" in input.update && input.update.title ? input.update.title : "external_tool",
|
|
10542
|
+
kind: "kind" in input.update && input.update.kind ? input.update.kind : "other",
|
|
10543
|
+
status: toStatus,
|
|
10544
|
+
state: toStatus,
|
|
10545
|
+
external: input.external ?? false,
|
|
10546
|
+
createdAt: timestamp,
|
|
10547
|
+
updatedAt: timestamp
|
|
10548
|
+
};
|
|
10549
|
+
mergeToolCall(stored, input.update);
|
|
10550
|
+
this.toolCalls.set(stored.id, stored);
|
|
10551
|
+
}
|
|
10552
|
+
this.storeToolCall(stored);
|
|
10553
|
+
run.revision += 1;
|
|
10554
|
+
run.updatedAt = timestamp;
|
|
10555
|
+
this.touchRun(run);
|
|
10556
|
+
const acpToolCall = {
|
|
10557
|
+
toolCallId: stored.toolCallId,
|
|
10558
|
+
title: stored.title,
|
|
10559
|
+
kind: stored.kind,
|
|
10560
|
+
status: stored.status,
|
|
10561
|
+
...stored.content !== void 0 ? { content: clone(stored.content) } : {},
|
|
10562
|
+
...stored.locations !== void 0 ? { locations: clone(stored.locations) } : {},
|
|
10563
|
+
...stored.rawInput !== void 0 ? { rawInput: clone(stored.rawInput) } : {},
|
|
10564
|
+
...stored.rawOutput !== void 0 ? { rawOutput: clone(stored.rawOutput) } : {},
|
|
10565
|
+
...stored._meta !== void 0 ? { _meta: clone(stored._meta) } : {}
|
|
10566
|
+
};
|
|
10567
|
+
const event = this.baseEvent(run, {
|
|
10568
|
+
kind: "tool_state_changed",
|
|
10569
|
+
transition: { from: fromStatus, to: toStatus },
|
|
10570
|
+
toolCall: acpToolCall,
|
|
10571
|
+
...input.external ? { external: true } : {}
|
|
10572
|
+
});
|
|
10573
|
+
this.appendEvent(event);
|
|
10574
|
+
return event;
|
|
10575
|
+
}
|
|
9293
10576
|
snapshotRun(lease, runId) {
|
|
9294
10577
|
this.assertOwner(lease);
|
|
9295
10578
|
const run = this.requireRun(runId);
|
|
@@ -9300,6 +10583,8 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9300
10583
|
revision: run.revision,
|
|
9301
10584
|
input: clone(run.input),
|
|
9302
10585
|
...run.metadata ? { metadata: clone(run.metadata) } : {},
|
|
10586
|
+
...run.scope !== void 0 ? { scope: clone(run.scope) } : {},
|
|
10587
|
+
...run.cwd !== void 0 ? { cwd: run.cwd } : {},
|
|
9303
10588
|
...run.phasePayload === void 0 ? {} : { phasePayload: clone(run.phasePayload) },
|
|
9304
10589
|
...run.entryPhases === void 0 ? {} : { entryPhases: clone(run.entryPhases) },
|
|
9305
10590
|
messageCount: this.messagesForRun(run.id).length,
|
|
@@ -9386,7 +10671,7 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9386
10671
|
if (run.state === "running") blockedRunIds.add(run.id);
|
|
9387
10672
|
}
|
|
9388
10673
|
for (const tool of this.toolCalls.values()) {
|
|
9389
|
-
if (tool.
|
|
10674
|
+
if (tool.status === "pending" || tool.status === "in_progress" || tool.state === "pending" || tool.state === "in_progress") {
|
|
9390
10675
|
blockedRunIds.add(tool.runId);
|
|
9391
10676
|
}
|
|
9392
10677
|
}
|
|
@@ -9527,13 +10812,13 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9527
10812
|
}
|
|
9528
10813
|
assertNoOpenTools(run, allowedPendingToolCallIds = []) {
|
|
9529
10814
|
const allowed = new Set(allowedPendingToolCallIds);
|
|
9530
|
-
if ([...this.toolCalls.values()].some((toolCall) => toolCall.runId === run.id && (toolCall.state === "
|
|
10815
|
+
if ([...this.toolCalls.values()].some((toolCall) => toolCall.runId === run.id && (toolCall.status === "in_progress" || toolCall.state === "in_progress" || (toolCall.status === "pending" || toolCall.state === "pending") && !allowed.has(toolCall.id)))) {
|
|
9531
10816
|
throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["running"], actual: run.state });
|
|
9532
10817
|
}
|
|
9533
10818
|
}
|
|
9534
10819
|
interruptToolCall(run, toolCall, reason) {
|
|
9535
10820
|
const result = { ok: false, content: null, error: reason };
|
|
9536
|
-
const durableResult = { toolCallId: toolCall.id, toolName: toolCall.name, ...result };
|
|
10821
|
+
const durableResult = { toolCallId: toolCall.id, toolName: toolCall.name ?? toolCall.title, ...result };
|
|
9537
10822
|
const message = {
|
|
9538
10823
|
id: createId("msg"),
|
|
9539
10824
|
agentId: run.agentId,
|
|
@@ -9543,13 +10828,14 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9543
10828
|
sequenceWithinRun: this.nextMessageSequence(run.id),
|
|
9544
10829
|
createdAt: createTimestamp()
|
|
9545
10830
|
};
|
|
9546
|
-
const from = toolCall.state;
|
|
9547
|
-
const to =
|
|
10831
|
+
const from = toolCall.status ?? toolCall.state ?? "in_progress";
|
|
10832
|
+
const to = "failed";
|
|
9548
10833
|
this.storeMessage(message);
|
|
9549
10834
|
toolCall.state = to;
|
|
10835
|
+
toolCall.status = to;
|
|
9550
10836
|
toolCall.result = durableResult;
|
|
9551
10837
|
toolCall.resultMessageId = message.id;
|
|
9552
|
-
|
|
10838
|
+
toolCall.reason = reason;
|
|
9553
10839
|
toolCall.updatedAt = message.createdAt;
|
|
9554
10840
|
this.storeToolCall(toolCall);
|
|
9555
10841
|
run.revision += 1;
|
|
@@ -9586,6 +10872,28 @@ var InMemoryStore = class _InMemoryStore {
|
|
|
9586
10872
|
messagesForRun(runId) {
|
|
9587
10873
|
return [...this.messages.values()].filter((message) => message.runId === runId).sort((a, b) => a.sequenceWithinRun - b.sequenceWithinRun);
|
|
9588
10874
|
}
|
|
10875
|
+
withdrawUserInputIfNoOutput(run, failure, output) {
|
|
10876
|
+
const runMessages = this.messagesForRun(run.id);
|
|
10877
|
+
const hasAssistantMessage = runMessages.some((m) => m.role === "assistant") || output !== void 0;
|
|
10878
|
+
const hasToolMessage = runMessages.some((m) => m.role === "tool");
|
|
10879
|
+
const hasToolCalls = [...this.toolCalls.values()].some((tc) => tc.runId === run.id);
|
|
10880
|
+
if (hasAssistantMessage || hasToolMessage || hasToolCalls) {
|
|
10881
|
+
return failure;
|
|
10882
|
+
}
|
|
10883
|
+
const userInputMessage = runMessages.find((m) => m.role === "user");
|
|
10884
|
+
if (!userInputMessage) {
|
|
10885
|
+
return failure;
|
|
10886
|
+
}
|
|
10887
|
+
this.messages.delete(userInputMessage.id);
|
|
10888
|
+
this.recorder?.onMessageDelete(userInputMessage.id);
|
|
10889
|
+
return {
|
|
10890
|
+
...failure,
|
|
10891
|
+
withdrawnInput: {
|
|
10892
|
+
messageId: userInputMessage.id,
|
|
10893
|
+
content: clone(userInputMessage.content)
|
|
10894
|
+
}
|
|
10895
|
+
};
|
|
10896
|
+
}
|
|
9589
10897
|
history(lease, agentId) {
|
|
9590
10898
|
this.assertOwner(lease);
|
|
9591
10899
|
this.requireAgent(agentId);
|
|
@@ -9678,18 +10986,34 @@ ${record.summary}`,
|
|
|
9678
10986
|
to,
|
|
9679
10987
|
...to === "input_required" ? { interactions: clone(options?.interactions ?? []), answers: clone(options?.answers ?? {}) } : {},
|
|
9680
10988
|
...to === "completed" && options?.outcome ? { outcome: options.outcome, ...options.output ? { output: options.output } : {} } : {},
|
|
9681
|
-
...to === "failed" && options?.failure ? {
|
|
10989
|
+
...to === "failed" && options?.failure ? {
|
|
10990
|
+
failure: options.failure,
|
|
10991
|
+
...options.failure.withdrawnInput ? { withdrawnInput: options.failure.withdrawnInput } : {}
|
|
10992
|
+
} : {},
|
|
9682
10993
|
...to === "cancelled" && options?.reason ? { reason: options.reason } : {}
|
|
9683
10994
|
};
|
|
9684
10995
|
this.touchRun(run);
|
|
9685
10996
|
this.appendEvent(transition);
|
|
9686
10997
|
}
|
|
9687
10998
|
appendToolTransition(run, transition, toolCall) {
|
|
9688
|
-
|
|
10999
|
+
const acpToolCall = {
|
|
11000
|
+
toolCallId: toolCall.toolCallId ?? toolCall.id,
|
|
11001
|
+
title: toolCall.title ?? toolCall.name ?? toolCall.toolCallId,
|
|
11002
|
+
kind: toolCall.kind ?? "other",
|
|
11003
|
+
status: toolCall.status ?? toolCall.state,
|
|
11004
|
+
...toolCall.content ? { content: clone(toolCall.content) } : {},
|
|
11005
|
+
...toolCall.locations ? { locations: clone(toolCall.locations) } : {},
|
|
11006
|
+
...toolCall.rawInput !== void 0 ? { rawInput: clone(toolCall.rawInput) } : {},
|
|
11007
|
+
...toolCall.rawOutput !== void 0 ? { rawOutput: clone(toolCall.rawOutput) } : {},
|
|
11008
|
+
...toolCall._meta ? { _meta: clone(toolCall._meta) } : {}
|
|
11009
|
+
};
|
|
11010
|
+
this.appendEvent({
|
|
11011
|
+
...this.baseEvent(run),
|
|
9689
11012
|
kind: "tool_state_changed",
|
|
9690
11013
|
transition,
|
|
9691
|
-
toolCall:
|
|
9692
|
-
|
|
11014
|
+
toolCall: acpToolCall,
|
|
11015
|
+
...toolCall.external ? { external: true } : {}
|
|
11016
|
+
});
|
|
9693
11017
|
}
|
|
9694
11018
|
baseEvent(run, extra) {
|
|
9695
11019
|
this.eventSequence += 1;
|
|
@@ -9791,6 +11115,9 @@ var MemoryOwnedStore = class {
|
|
|
9791
11115
|
async cancelRun(input) {
|
|
9792
11116
|
return this.store.cancelRun(this.lease, input);
|
|
9793
11117
|
}
|
|
11118
|
+
async recordToolCall(input) {
|
|
11119
|
+
return this.store.recordToolCall(this.lease, input);
|
|
11120
|
+
}
|
|
9794
11121
|
async snapshotRun(runId) {
|
|
9795
11122
|
return this.store.snapshotRun(this.lease, runId);
|
|
9796
11123
|
}
|
|
@@ -9934,19 +11261,19 @@ function requestMessageContent(toolCalls, contentBlocks) {
|
|
|
9934
11261
|
const toolUse = (toolCall) => ({
|
|
9935
11262
|
type: "tool_use",
|
|
9936
11263
|
toolCallId: toolCall.id,
|
|
9937
|
-
providerToolCallId: toolCall.providerToolCallId,
|
|
9938
|
-
name: toolCall.name,
|
|
9939
|
-
input: clone(toolCall.args)
|
|
11264
|
+
...toolCall.providerToolCallId !== void 0 ? { providerToolCallId: toolCall.providerToolCallId } : {},
|
|
11265
|
+
name: toolCall.name ?? toolCall.title ?? "tool",
|
|
11266
|
+
input: clone(toolCall.args !== void 0 ? toolCall.args : toolCall.rawInput !== void 0 ? toolCall.rawInput : {})
|
|
9940
11267
|
});
|
|
9941
11268
|
if (!contentBlocks) return toolCalls.map(toolUse);
|
|
9942
|
-
const reserved = new Map(toolCalls.map((toolCall) => [toolCall.providerToolCallId, toolCall]));
|
|
11269
|
+
const reserved = new Map(toolCalls.map((toolCall) => [toolCall.providerToolCallId ?? toolCall.id, toolCall]));
|
|
9943
11270
|
const parts = [];
|
|
9944
11271
|
for (const block of contentBlocks) {
|
|
9945
11272
|
if (block.type === "text") {
|
|
9946
11273
|
parts.push({ type: "text", text: block.text });
|
|
9947
11274
|
} else if (block.type === "thinking") {
|
|
9948
11275
|
parts.push({ type: "thinking", thinking: block.thinking, ...block.signature ? { signature: block.signature } : {} });
|
|
9949
|
-
} else {
|
|
11276
|
+
} else if (block.type === "tool_call") {
|
|
9950
11277
|
const toolCall = reserved.get(block.id);
|
|
9951
11278
|
if (!toolCall) continue;
|
|
9952
11279
|
reserved.delete(block.id);
|
|
@@ -10343,6 +11670,9 @@ var SqliteStore = class {
|
|
|
10343
11670
|
async cancelRun(lease, input) {
|
|
10344
11671
|
return this.invoke(lease, (store, current) => store.cancelRun(current, input));
|
|
10345
11672
|
}
|
|
11673
|
+
async recordToolCall(lease, input) {
|
|
11674
|
+
return this.invoke(lease, (store, current) => store.recordToolCall(current, input));
|
|
11675
|
+
}
|
|
10346
11676
|
async snapshotRun(lease, runId) {
|
|
10347
11677
|
return this.invoke(lease, (store, current) => store.snapshotRun(current, runId), false);
|
|
10348
11678
|
}
|
|
@@ -10643,7 +11973,9 @@ var SqliteStore = class {
|
|
|
10643
11973
|
}
|
|
10644
11974
|
getStmtInsertEvent() {
|
|
10645
11975
|
return this.stmtInsertEvent ??= this.database.prepare(
|
|
10646
|
-
|
|
11976
|
+
`INSERT INTO run_events (id, run_id, payload_json, created_at)
|
|
11977
|
+
VALUES (?, ?, ?, ?)
|
|
11978
|
+
ON CONFLICT(id) DO UPDATE SET payload_json = excluded.payload_json`
|
|
10647
11979
|
);
|
|
10648
11980
|
}
|
|
10649
11981
|
getStmtDeleteEvent() {
|
|
@@ -10726,7 +12058,7 @@ var SqliteStore = class {
|
|
|
10726
12058
|
toolCall.id,
|
|
10727
12059
|
toolCall.runId,
|
|
10728
12060
|
toolCall.executionId,
|
|
10729
|
-
toolCall.state,
|
|
12061
|
+
toolCall.status ?? toolCall.state ?? "in_progress",
|
|
10730
12062
|
JSON.stringify(toolCall)
|
|
10731
12063
|
);
|
|
10732
12064
|
}
|
|
@@ -11114,6 +12446,9 @@ var SqliteOwnedStore = class {
|
|
|
11114
12446
|
cancelRun(input) {
|
|
11115
12447
|
return this.store.cancelRun(this.lease, input);
|
|
11116
12448
|
}
|
|
12449
|
+
recordToolCall(input) {
|
|
12450
|
+
return this.store.recordToolCall(this.lease, input);
|
|
12451
|
+
}
|
|
11117
12452
|
snapshotRun(runId) {
|
|
11118
12453
|
return this.store.snapshotRun(this.lease, runId);
|
|
11119
12454
|
}
|
|
@@ -11199,10 +12534,10 @@ export {
|
|
|
11199
12534
|
isRuntimeError,
|
|
11200
12535
|
loadExtensionsFromPath as loadExtensions,
|
|
11201
12536
|
loadPhase,
|
|
11202
|
-
loadPhaseSettings,
|
|
11203
12537
|
loadPhases,
|
|
11204
12538
|
loadSkill,
|
|
11205
12539
|
loadSkills,
|
|
12540
|
+
mergeToolCall,
|
|
11206
12541
|
parseAgentDefinition,
|
|
11207
12542
|
parseFrontmatter,
|
|
11208
12543
|
resolveConfigurationSnapshot
|