tnega 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/agent.js +2207 -513
- package/dist/agent.js.map +4 -4
- package/dist/bin.js +942 -469
- package/dist/bin.js.map +3 -3
- package/dist/cli-runtime.js +943 -469
- package/dist/cli-runtime.js.map +3 -3
- package/dist/coding-agent.js +1623 -162
- package/dist/coding-agent.js.map +4 -4
- package/dist/eval.js +422 -158
- package/dist/eval.js.map +3 -3
- package/dist/evolve.js +512 -326
- package/dist/evolve.js.map +4 -4
- package/dist/index.js +951 -469
- package/dist/index.js.map +3 -3
- package/dist/llm.js +47 -3
- package/dist/llm.js.map +3 -3
- package/dist/session.js +91 -5
- package/dist/session.js.map +2 -2
- package/dist/types/packages/agent/src/inbox-durable.d.ts +5 -0
- package/dist/types/packages/agent/src/live.d.ts +24 -8
- package/dist/types/packages/agent/src/service.d.ts +8 -2
- package/dist/types/packages/agent/src/types.d.ts +40 -2
- package/dist/types/packages/cli/src/config.d.ts +2 -0
- package/dist/types/packages/cli/src/index.d.ts +1 -0
- package/dist/types/packages/llm/src/types.d.ts +2 -0
- package/dist/types/packages/session/src/index.d.ts +68 -7
- package/dist/types/packages/session/src/invariant.d.ts +2 -0
- package/dist/types/src/index.d.ts +2 -2
- package/dist/web/assets/{index-45pokiBH.js → index-Bq0i29_u.js} +30 -30
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -107,17 +107,88 @@ function checkMonotonicSeq(events) {
|
|
|
107
107
|
}
|
|
108
108
|
return failures;
|
|
109
109
|
}
|
|
110
|
+
function isRecord(value) {
|
|
111
|
+
return typeof value === "object" && value !== null && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
112
|
+
}
|
|
113
|
+
function isNonNegativeInteger(value) {
|
|
114
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
115
|
+
}
|
|
116
|
+
function isJsonValue(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
117
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
118
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
119
|
+
if (typeof value !== "object" || ancestors.has(value)) return false;
|
|
120
|
+
if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return false;
|
|
121
|
+
ancestors.add(value);
|
|
122
|
+
const valid = (Array.isArray(value) ? Array.from(value) : Object.values(value)).every((member) => isJsonValue(member, ancestors));
|
|
123
|
+
ancestors.delete(value);
|
|
124
|
+
return valid;
|
|
125
|
+
}
|
|
126
|
+
function isStreamRecord(value) {
|
|
127
|
+
if (!isRecord(value) || !isNonNegativeInteger(value.time) || !isRecord(value.chunk)) return false;
|
|
128
|
+
const chunk = value.chunk;
|
|
129
|
+
if (chunk.type === "stream_error") {
|
|
130
|
+
return isRecord(chunk.error) && typeof chunk.error.message === "string" && (chunk.error.name === void 0 || typeof chunk.error.name === "string") && (chunk.error.stack === void 0 || typeof chunk.error.stack === "string");
|
|
131
|
+
}
|
|
132
|
+
if (typeof chunk.id !== "string") return false;
|
|
133
|
+
switch (chunk.type) {
|
|
134
|
+
case "message_start":
|
|
135
|
+
return chunk.model === void 0 || typeof chunk.model === "string";
|
|
136
|
+
case "message_delta":
|
|
137
|
+
return typeof chunk.delta === "string";
|
|
138
|
+
case "toolcall_start":
|
|
139
|
+
case "toolcall_end":
|
|
140
|
+
return isNonNegativeInteger(chunk.index) && typeof chunk.name === "string" && (chunk.type === "toolcall_start" || isJsonValue(chunk.arguments));
|
|
141
|
+
case "message_stop":
|
|
142
|
+
return chunk.finishReason === "stop" || chunk.finishReason === "tool_calls" || chunk.finishReason === "length" || chunk.finishReason === "max_turns" || chunk.finishReason === "max_steps" || chunk.finishReason === "error" || chunk.finishReason === "cancelled";
|
|
143
|
+
default:
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function checkAssistantAttempts(events) {
|
|
148
|
+
const turns = /* @__PURE__ */ new Set();
|
|
149
|
+
const steps = /* @__PURE__ */ new Map();
|
|
150
|
+
const failures = [];
|
|
151
|
+
for (const event of events) {
|
|
152
|
+
if (event.type === "turn/start") turns.add(event.payload.turn);
|
|
153
|
+
if (event.type === "turn/end") {
|
|
154
|
+
turns.delete(event.payload.turn);
|
|
155
|
+
for (const [key, turn] of steps) {
|
|
156
|
+
if (turn === event.payload.turn) steps.delete(key);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (event.type === "step/start" && turns.has(event.payload.turn)) {
|
|
160
|
+
steps.set(`${event.payload.turn}:${event.payload.step}`, event.payload.turn);
|
|
161
|
+
}
|
|
162
|
+
if (event.type === "step/end") steps.delete(`${event.payload.turn}:${event.payload.step}`);
|
|
163
|
+
if (event.type !== "assistant/attempt") continue;
|
|
164
|
+
const payload = event.payload;
|
|
165
|
+
if (!isRecord(payload) || !isNonNegativeInteger(payload.turn) || !isNonNegativeInteger(payload.step) || !turns.has(payload.turn) || !steps.has(`${payload.turn}:${payload.step}`)) {
|
|
166
|
+
failures.push({
|
|
167
|
+
name: "assistant/attempt-without-open-step",
|
|
168
|
+
detail: `assistant/attempt at seq ${event.seq} has no matching open turn and step`
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (!isRecord(payload) || !Array.isArray(payload.stream) || !payload.stream.every(isStreamRecord)) {
|
|
172
|
+
failures.push({
|
|
173
|
+
name: "assistant/attempt-invalid-stream",
|
|
174
|
+
detail: `assistant/attempt at seq ${event.seq} must contain an ordered array of normalized stream records`
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return failures;
|
|
179
|
+
}
|
|
110
180
|
function checkSessionInvariants(events) {
|
|
111
181
|
return [
|
|
112
182
|
...checkBalancedTurns(events),
|
|
113
183
|
...checkBalancedSteps(events),
|
|
114
184
|
...checkBalancedToolCalls(events),
|
|
115
|
-
...checkMonotonicSeq(events)
|
|
185
|
+
...checkMonotonicSeq(events),
|
|
186
|
+
...checkAssistantAttempts(events)
|
|
116
187
|
];
|
|
117
188
|
}
|
|
118
189
|
|
|
119
190
|
// packages/session/src/index.ts
|
|
120
|
-
var SESSION_FORMAT_VERSION =
|
|
191
|
+
var SESSION_FORMAT_VERSION = 10;
|
|
121
192
|
var SessionFormatError = class extends Error {
|
|
122
193
|
name = "SessionFormatError";
|
|
123
194
|
};
|
|
@@ -332,6 +403,7 @@ function estimateEventTokens(event) {
|
|
|
332
403
|
return Math.ceil(raw.length / 4);
|
|
333
404
|
}
|
|
334
405
|
case "plan":
|
|
406
|
+
case "assistant/attempt":
|
|
335
407
|
return 0;
|
|
336
408
|
case "checkpoint":
|
|
337
409
|
return estimateMessageTokens(event.payload.messages);
|
|
@@ -466,9 +538,15 @@ function estimateContextUsage(messages, limit = DEFAULT_CONTEXT_LIMIT) {
|
|
|
466
538
|
};
|
|
467
539
|
}
|
|
468
540
|
var SessionLog = class {
|
|
469
|
-
constructor(file, _broadcast) {
|
|
541
|
+
constructor(file, _broadcast, publicationContext) {
|
|
470
542
|
this.file = file;
|
|
471
543
|
this._broadcast = _broadcast;
|
|
544
|
+
if (!this._broadcast && publicationContext) {
|
|
545
|
+
this._broadcast = (type, payload) => {
|
|
546
|
+
if (type === "event") publicationContext.emit("session/event", payload);
|
|
547
|
+
else publicationContext.emit("session/flush", payload);
|
|
548
|
+
};
|
|
549
|
+
}
|
|
472
550
|
}
|
|
473
551
|
file;
|
|
474
552
|
_broadcast;
|
|
@@ -637,7 +715,7 @@ var SessionLog = class {
|
|
|
637
715
|
selected.push(clone(event));
|
|
638
716
|
continue;
|
|
639
717
|
}
|
|
640
|
-
if (event.type === "meta" || event.type === "llm/retry" || event.type === "llm/retry-started" || event.type.startsWith("turn/") || event.type.startsWith("step/")) {
|
|
718
|
+
if (event.type === "meta" || event.type === "llm/retry" || event.type === "llm/retry-started" || event.type === "assistant/attempt" || event.type.startsWith("turn/") || event.type.startsWith("step/")) {
|
|
641
719
|
continue;
|
|
642
720
|
}
|
|
643
721
|
if (event.type === "checkpoint") {
|
|
@@ -975,7 +1053,7 @@ function copyMessages(messages) {
|
|
|
975
1053
|
copy.tool_calls = message.tool_calls.map((call) => ({
|
|
976
1054
|
id: call.id,
|
|
977
1055
|
name: call.name,
|
|
978
|
-
arguments: call.arguments
|
|
1056
|
+
arguments: structuredClone(call.arguments)
|
|
979
1057
|
}));
|
|
980
1058
|
}
|
|
981
1059
|
return copy;
|
|
@@ -1006,6 +1084,75 @@ function copyCompletion(completion) {
|
|
|
1006
1084
|
}
|
|
1007
1085
|
return copy;
|
|
1008
1086
|
}
|
|
1087
|
+
function canonicalMessages(messages) {
|
|
1088
|
+
return JSON.stringify(messages.map((message) => ({
|
|
1089
|
+
role: message.role,
|
|
1090
|
+
content: message.content,
|
|
1091
|
+
...message.name ? { name: message.name } : {},
|
|
1092
|
+
...message.tool_call_id ? { tool_call_id: message.tool_call_id } : {},
|
|
1093
|
+
...message.tool_calls?.length ? { tool_calls: message.tool_calls } : {},
|
|
1094
|
+
...message.toolOk !== void 0 ? { toolOk: message.toolOk } : {},
|
|
1095
|
+
...message.toolError ? {
|
|
1096
|
+
toolError: { name: message.toolError.name, message: message.toolError.message }
|
|
1097
|
+
} : {}
|
|
1098
|
+
})));
|
|
1099
|
+
}
|
|
1100
|
+
function freezeRequestData(data) {
|
|
1101
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1102
|
+
const freeze = (value) => {
|
|
1103
|
+
if (typeof value !== "object" || value === null || visited.has(value)) return;
|
|
1104
|
+
visited.add(value);
|
|
1105
|
+
for (const child of Object.values(value)) freeze(child);
|
|
1106
|
+
Object.freeze(value);
|
|
1107
|
+
};
|
|
1108
|
+
freeze(data);
|
|
1109
|
+
}
|
|
1110
|
+
function lockStreamRequest(request) {
|
|
1111
|
+
freezeRequestData(request.messages);
|
|
1112
|
+
request.tools = Object.freeze(request.tools.map((tool) => {
|
|
1113
|
+
const schema = structuredClone(tool.schema);
|
|
1114
|
+
freezeRequestData(schema);
|
|
1115
|
+
return Object.freeze({ ...tool, schema });
|
|
1116
|
+
}));
|
|
1117
|
+
Object.freeze(request.options);
|
|
1118
|
+
Object.freeze(request);
|
|
1119
|
+
}
|
|
1120
|
+
function requestHeaderFor(request, input) {
|
|
1121
|
+
const system = input.find((message) => message.role === "system")?.content;
|
|
1122
|
+
const tools = request.tools.map((tool) => ({
|
|
1123
|
+
name: tool.schema.name,
|
|
1124
|
+
description: tool.schema.description,
|
|
1125
|
+
...tool.schema.parameters ? { parameters: tool.schema.parameters } : {}
|
|
1126
|
+
}));
|
|
1127
|
+
const config = {
|
|
1128
|
+
...request.options.provider ? { provider: request.options.provider } : {},
|
|
1129
|
+
...request.options.model ? { model: request.options.model } : {},
|
|
1130
|
+
...request.options.temperature !== void 0 ? { temperature: request.options.temperature } : {}
|
|
1131
|
+
};
|
|
1132
|
+
return {
|
|
1133
|
+
...Object.keys(config).length ? { config } : {},
|
|
1134
|
+
...system !== void 0 ? { system } : {},
|
|
1135
|
+
...tools.length ? { tools } : {}
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
async function* completeAsStream(llm, messages, tools, options) {
|
|
1139
|
+
const id = randomUUID2();
|
|
1140
|
+
yield { type: "message_start", id };
|
|
1141
|
+
const completion = await llm.complete(messages, tools, options);
|
|
1142
|
+
if (completion.content) yield { type: "message_delta", id, delta: completion.content };
|
|
1143
|
+
for (let index = 0; index < (completion.toolCalls?.length ?? 0); index += 1) {
|
|
1144
|
+
const call = completion.toolCalls[index];
|
|
1145
|
+
yield { type: "toolcall_start", id: call.id, index, name: call.name };
|
|
1146
|
+
yield {
|
|
1147
|
+
type: "toolcall_end",
|
|
1148
|
+
id: call.id,
|
|
1149
|
+
index,
|
|
1150
|
+
name: call.name,
|
|
1151
|
+
arguments: call.arguments
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
yield { type: "message_stop", id, finishReason: completion.finishReason };
|
|
1155
|
+
}
|
|
1009
1156
|
function isCancelCause(value) {
|
|
1010
1157
|
if (typeof value !== "object" || value === null) return false;
|
|
1011
1158
|
const record = value;
|
|
@@ -1026,6 +1173,13 @@ function cancelCauseFromSignal(signal) {
|
|
|
1026
1173
|
if (isCancelCause(reason)) return reason;
|
|
1027
1174
|
return { type: "abort" };
|
|
1028
1175
|
}
|
|
1176
|
+
function abortedToolError(signal) {
|
|
1177
|
+
const cause = cancelCauseFromSignal(signal);
|
|
1178
|
+
return {
|
|
1179
|
+
name: "AbortError",
|
|
1180
|
+
message: `tool call aborted: ${cause?.type ?? "abort"}`
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1029
1183
|
function toTurnEndReason(fields) {
|
|
1030
1184
|
const { cancelled, turnError, finishReason, cancelCause } = fields;
|
|
1031
1185
|
if (cancelled || finishReason === "cancelled") {
|
|
@@ -1070,6 +1224,78 @@ async function cancellableDelay(ms, signal) {
|
|
|
1070
1224
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1071
1225
|
});
|
|
1072
1226
|
}
|
|
1227
|
+
var AssistantStreamAttempt = class {
|
|
1228
|
+
constructor(session, turn, step, nextRevision) {
|
|
1229
|
+
this.session = session;
|
|
1230
|
+
this.turn = turn;
|
|
1231
|
+
this.step = step;
|
|
1232
|
+
this.nextRevision = nextRevision;
|
|
1233
|
+
}
|
|
1234
|
+
session;
|
|
1235
|
+
turn;
|
|
1236
|
+
step;
|
|
1237
|
+
nextRevision;
|
|
1238
|
+
attemptId = randomUUID2();
|
|
1239
|
+
records = [];
|
|
1240
|
+
ended = false;
|
|
1241
|
+
start() {
|
|
1242
|
+
return { type: "assistant/stream", frame: {
|
|
1243
|
+
type: "start",
|
|
1244
|
+
attemptId: this.attemptId,
|
|
1245
|
+
revision: this.nextRevision(),
|
|
1246
|
+
turn: this.turn,
|
|
1247
|
+
step: this.step
|
|
1248
|
+
} };
|
|
1249
|
+
}
|
|
1250
|
+
push(chunk) {
|
|
1251
|
+
if (this.ended) throw new AgentError("assistant attempt is already settled");
|
|
1252
|
+
const record = { time: Date.now(), chunk: structuredClone(chunk) };
|
|
1253
|
+
const index = this.records.length;
|
|
1254
|
+
this.records.push(record);
|
|
1255
|
+
return { type: "assistant/stream", frame: {
|
|
1256
|
+
type: "chunk",
|
|
1257
|
+
attemptId: this.attemptId,
|
|
1258
|
+
revision: this.nextRevision(),
|
|
1259
|
+
index,
|
|
1260
|
+
...structuredClone(record)
|
|
1261
|
+
} };
|
|
1262
|
+
}
|
|
1263
|
+
async settle(message) {
|
|
1264
|
+
if (this.ended) throw new AgentError("assistant attempt is already settled");
|
|
1265
|
+
const eventType = message ? "assistant/message" : "assistant/attempt";
|
|
1266
|
+
let event;
|
|
1267
|
+
try {
|
|
1268
|
+
event = message ? await this.session.append("assistant/message", { ...message, stream: this.records }) : await this.session.append("assistant/attempt", { turn: this.turn, step: this.step, stream: this.records });
|
|
1269
|
+
} catch (cause) {
|
|
1270
|
+
this.ended = true;
|
|
1271
|
+
const frame = { type: "assistant/stream", frame: {
|
|
1272
|
+
type: "end",
|
|
1273
|
+
attemptId: this.attemptId,
|
|
1274
|
+
revision: this.nextRevision(),
|
|
1275
|
+
index: this.records.length,
|
|
1276
|
+
outcome: { kind: "abandoned" }
|
|
1277
|
+
} };
|
|
1278
|
+
throw new AttemptSettlementError(cause, frame);
|
|
1279
|
+
}
|
|
1280
|
+
this.ended = true;
|
|
1281
|
+
return { type: "assistant/stream", frame: {
|
|
1282
|
+
type: "end",
|
|
1283
|
+
attemptId: this.attemptId,
|
|
1284
|
+
revision: this.nextRevision(),
|
|
1285
|
+
index: this.records.length,
|
|
1286
|
+
outcome: { kind: "committed", eventType, seq: event.seq }
|
|
1287
|
+
} };
|
|
1288
|
+
}
|
|
1289
|
+
};
|
|
1290
|
+
var AttemptSettlementError = class extends Error {
|
|
1291
|
+
constructor(cause, frame) {
|
|
1292
|
+
super("assistant attempt settlement failed");
|
|
1293
|
+
this.cause = cause;
|
|
1294
|
+
this.frame = frame;
|
|
1295
|
+
}
|
|
1296
|
+
cause;
|
|
1297
|
+
frame;
|
|
1298
|
+
};
|
|
1073
1299
|
var AgentService = class {
|
|
1074
1300
|
constructor(ctx, config = {}) {
|
|
1075
1301
|
this.ctx = ctx;
|
|
@@ -1078,9 +1304,24 @@ var AgentService = class {
|
|
|
1078
1304
|
}
|
|
1079
1305
|
ctx;
|
|
1080
1306
|
config;
|
|
1307
|
+
async *settleAttempt(attempt, message) {
|
|
1308
|
+
try {
|
|
1309
|
+
yield await attempt.settle(message);
|
|
1310
|
+
} catch (error) {
|
|
1311
|
+
if (error instanceof AttemptSettlementError) {
|
|
1312
|
+
yield error.frame;
|
|
1313
|
+
throw error.cause;
|
|
1314
|
+
}
|
|
1315
|
+
throw error;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1081
1318
|
inbox;
|
|
1082
1319
|
_seriesStarted = false;
|
|
1083
1320
|
_persistedRequest = false;
|
|
1321
|
+
_streamRevision = 0;
|
|
1322
|
+
_attempt(session, turn, step) {
|
|
1323
|
+
return new AssistantStreamAttempt(session, turn, step, () => ++this._streamRevision);
|
|
1324
|
+
}
|
|
1084
1325
|
/** Call when a request begins an explicit new model-message series. */
|
|
1085
1326
|
startSeries() {
|
|
1086
1327
|
this._seriesStarted = true;
|
|
@@ -1094,7 +1335,7 @@ var AgentService = class {
|
|
|
1094
1335
|
return this._persistedRequest;
|
|
1095
1336
|
}
|
|
1096
1337
|
async run(input, options = {}) {
|
|
1097
|
-
return consumeAgentStream(this._stream(input, options
|
|
1338
|
+
return consumeAgentStream(this._stream(input, options));
|
|
1098
1339
|
}
|
|
1099
1340
|
async *runStream(input, options = {}) {
|
|
1100
1341
|
const iterator = this._stream(input, options)[Symbol.asyncIterator]();
|
|
@@ -1104,7 +1345,7 @@ var AgentService = class {
|
|
|
1104
1345
|
yield next.value;
|
|
1105
1346
|
}
|
|
1106
1347
|
}
|
|
1107
|
-
async *_stream(input, options = {}
|
|
1348
|
+
async *_stream(input, options = {}) {
|
|
1108
1349
|
const claimed = input ?? this.inbox.claim();
|
|
1109
1350
|
if (!claimed) throw new AgentError("no agent input available");
|
|
1110
1351
|
await this.config.hooks?.beforeRun?.(claimed, options);
|
|
@@ -1112,26 +1353,32 @@ var AgentService = class {
|
|
|
1112
1353
|
const tools = this._tools();
|
|
1113
1354
|
const llm = this._llm();
|
|
1114
1355
|
if (!llm) throw new AgentError("no LLM adapter available");
|
|
1356
|
+
const streamAdapter = llm.stream;
|
|
1357
|
+
const persistChunks = streamAdapter !== void 0;
|
|
1115
1358
|
const maxTurns = options.maxTurns ?? this.config.maxTurns ?? 64;
|
|
1116
1359
|
const maxSteps = options.maxSteps ?? this.config.maxSteps ?? 64;
|
|
1117
1360
|
const contextBudget = options.contextBudget ?? this.config.contextBudget;
|
|
1118
1361
|
const injected = this.inbox.injected();
|
|
1119
1362
|
this.ctx.emit("agent/start", { input: claimed, options, injected });
|
|
1120
1363
|
let messages = await this._initialMessages(claimed);
|
|
1364
|
+
let claimedMessages = messages.filter((message) => message.role === "user");
|
|
1121
1365
|
const steps = [];
|
|
1122
1366
|
let output = "";
|
|
1123
1367
|
let finishReason = "stop";
|
|
1368
|
+
let lengthReached = false;
|
|
1124
1369
|
this.ctx.emit("agent/turn-start", {
|
|
1125
1370
|
input: claimed,
|
|
1126
1371
|
messages: copyMessages(messages),
|
|
1127
1372
|
injected
|
|
1128
1373
|
});
|
|
1129
|
-
const turn = await session.nextTurn();
|
|
1130
|
-
|
|
1131
|
-
turn,
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1374
|
+
const turn = options.turn ?? await session.nextTurn();
|
|
1375
|
+
if (options.turn === void 0) {
|
|
1376
|
+
await session.append("turn/start", {
|
|
1377
|
+
turn,
|
|
1378
|
+
input: claimed.text ?? claimed,
|
|
1379
|
+
reason: "user"
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1135
1382
|
let index = 0;
|
|
1136
1383
|
let finalTurnGranted = false;
|
|
1137
1384
|
let currentStepIndex;
|
|
@@ -1150,20 +1397,22 @@ var AgentService = class {
|
|
|
1150
1397
|
messages = await this._enforceContextBudget(session, contextBudget, messages);
|
|
1151
1398
|
}
|
|
1152
1399
|
const stepInput = copyMessages(messages);
|
|
1153
|
-
const preStep = this.ctx.
|
|
1400
|
+
const preStep = await this.ctx.waterfallAsync("agent/pre-step", {
|
|
1154
1401
|
index,
|
|
1155
1402
|
turn,
|
|
1156
1403
|
step: index,
|
|
1157
1404
|
messages: stepInput,
|
|
1405
|
+
claimedMessages: copyMessages(claimedMessages),
|
|
1158
1406
|
...options.signal ? { signal: options.signal } : {}
|
|
1159
1407
|
}, (payload) => payload);
|
|
1160
|
-
if (!preStep || !Array.isArray(preStep.messages) || !preStep.messages.length) {
|
|
1408
|
+
if (!preStep || preStep.admission === "reject" || !Array.isArray(preStep.messages) || !preStep.messages.length) {
|
|
1161
1409
|
break;
|
|
1162
1410
|
}
|
|
1163
1411
|
if (preStep.startsRequestSeries) this._seriesStarted = true;
|
|
1164
1412
|
await session.append("step/start", { turn, step: index });
|
|
1165
1413
|
currentStepIndex = index;
|
|
1166
1414
|
const requestedInput = copyMessages(preStep.messages);
|
|
1415
|
+
const admittedHistory = await session.deriveMessages();
|
|
1167
1416
|
this.ctx.emit("agent/step", {
|
|
1168
1417
|
index,
|
|
1169
1418
|
turn,
|
|
@@ -1175,93 +1424,85 @@ var AgentService = class {
|
|
|
1175
1424
|
maxSteps: maxSteps - steps.length
|
|
1176
1425
|
};
|
|
1177
1426
|
if (options.signal) completeOptions.signal = options.signal;
|
|
1178
|
-
const request = this.ctx.waterfall("agent/request", {
|
|
1179
|
-
index,
|
|
1180
|
-
messages: requestedInput,
|
|
1181
|
-
tools: availableTools,
|
|
1182
|
-
options: completeOptions
|
|
1183
|
-
}, (payload) => payload);
|
|
1184
|
-
if (!request || !request.options || !request.tools) {
|
|
1185
|
-
throw new AgentError("agent/request must return a request payload");
|
|
1186
|
-
}
|
|
1187
1427
|
let llmMessages = copyMessages(requestedInput);
|
|
1188
1428
|
let completion;
|
|
1189
|
-
|
|
1429
|
+
let activeAttempt;
|
|
1190
1430
|
let attempt = 0;
|
|
1191
|
-
let persistedStepInput = false;
|
|
1192
1431
|
while (true) {
|
|
1193
1432
|
if (options.signal?.aborted) {
|
|
1194
1433
|
finishReason = "cancelled";
|
|
1195
1434
|
break;
|
|
1196
1435
|
}
|
|
1197
1436
|
const streamEvents = [];
|
|
1437
|
+
activeAttempt = this._attempt(session, turn, index);
|
|
1438
|
+
yield activeAttempt.start();
|
|
1439
|
+
const streamRequest = {
|
|
1440
|
+
index,
|
|
1441
|
+
messages: copyMessages(requestedInput),
|
|
1442
|
+
tools: [...availableTools],
|
|
1443
|
+
options: { ...completeOptions }
|
|
1444
|
+
};
|
|
1198
1445
|
try {
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
return streamMethod(payload.messages, payload.tools, payload.options);
|
|
1214
|
-
}
|
|
1215
|
-
);
|
|
1216
|
-
if (!stream || typeof stream[Symbol.asyncIterator] !== "function") {
|
|
1217
|
-
throw new AgentError("llm/stream must return an async iterable stream");
|
|
1218
|
-
}
|
|
1446
|
+
const request = await this.ctx.waterfallAsync("agent/request", {
|
|
1447
|
+
index,
|
|
1448
|
+
messages: copyMessages(requestedInput),
|
|
1449
|
+
tools: streamRequest.tools,
|
|
1450
|
+
options: streamRequest.options
|
|
1451
|
+
}, (payload) => payload);
|
|
1452
|
+
if (!request || !request.options || !request.tools) {
|
|
1453
|
+
throw new AgentError("agent/request must return a request payload");
|
|
1454
|
+
}
|
|
1455
|
+
streamRequest.tools = request.tools;
|
|
1456
|
+
streamRequest.options = request.options;
|
|
1457
|
+
let preparation;
|
|
1458
|
+
const prepareRequest = () => preparation ??= (async () => {
|
|
1459
|
+
lockStreamRequest(streamRequest);
|
|
1219
1460
|
llmMessages = copyMessages(streamRequest.messages);
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
}
|
|
1247
|
-
persistedStepInput = true;
|
|
1461
|
+
await this._persistStepInput(session, streamRequest, llmMessages, admittedHistory);
|
|
1462
|
+
await this._assertReplayable(session, streamRequest, llmMessages);
|
|
1463
|
+
})();
|
|
1464
|
+
const stream = await this.ctx.waterfallAsync(
|
|
1465
|
+
"llm/stream",
|
|
1466
|
+
streamRequest,
|
|
1467
|
+
(payload) => (async function* () {
|
|
1468
|
+
await prepareRequest();
|
|
1469
|
+
yield* streamAdapter ? streamAdapter.call(llm, payload.messages, payload.tools, payload.options) : completeAsStream(llm, payload.messages, payload.tools, payload.options);
|
|
1470
|
+
})()
|
|
1471
|
+
);
|
|
1472
|
+
if (!stream || typeof stream[Symbol.asyncIterator] !== "function") {
|
|
1473
|
+
throw new AgentError("llm/stream must return an async iterable stream");
|
|
1474
|
+
}
|
|
1475
|
+
await prepareRequest();
|
|
1476
|
+
let chunkIndex = 0;
|
|
1477
|
+
for await (const event of stream) {
|
|
1478
|
+
streamEvents.push(structuredClone(event));
|
|
1479
|
+
yield activeAttempt.push(event);
|
|
1480
|
+
if (persistChunks && event.type === "message_delta") {
|
|
1481
|
+
await session.append("assistant/chunk", {
|
|
1482
|
+
id: event.id,
|
|
1483
|
+
content: event.delta,
|
|
1484
|
+
index: chunkIndex
|
|
1485
|
+
});
|
|
1486
|
+
chunkIndex += 1;
|
|
1248
1487
|
}
|
|
1249
|
-
|
|
1488
|
+
yield event;
|
|
1489
|
+
}
|
|
1490
|
+
completion = completionFromStreamEvents(streamEvents);
|
|
1491
|
+
if (completion.finishReason === "error" || completion.finishReason === "cancelled") {
|
|
1492
|
+
const terminalReason = completion.finishReason;
|
|
1493
|
+
completion = void 0;
|
|
1494
|
+
throw new AgentError(`LLM stream finished with ${terminalReason}`);
|
|
1250
1495
|
}
|
|
1251
1496
|
break;
|
|
1252
1497
|
} catch (error) {
|
|
1253
|
-
|
|
1254
|
-
if (content) {
|
|
1255
|
-
await session.append("assistant/message", {
|
|
1256
|
-
content,
|
|
1257
|
-
interrupted: true
|
|
1258
|
-
});
|
|
1259
|
-
llmMessages = await session.deriveMessages();
|
|
1260
|
-
}
|
|
1498
|
+
yield activeAttempt.push({ type: "stream_error", error: toToolError(error) });
|
|
1261
1499
|
if (options.signal?.aborted) {
|
|
1500
|
+
const content = partialStreamContent(streamEvents);
|
|
1501
|
+
yield* this.settleAttempt(activeAttempt, content ? { content, interrupted: true } : void 0);
|
|
1262
1502
|
finishReason = "cancelled";
|
|
1263
1503
|
break;
|
|
1264
1504
|
}
|
|
1505
|
+
yield* this.settleAttempt(activeAttempt);
|
|
1265
1506
|
attempt += 1;
|
|
1266
1507
|
const failure = toToolError(error);
|
|
1267
1508
|
const decision = await this.ctx.waterfallAsync(
|
|
@@ -1270,14 +1511,14 @@ var AgentService = class {
|
|
|
1270
1511
|
index,
|
|
1271
1512
|
turn,
|
|
1272
1513
|
step: index,
|
|
1273
|
-
messages: copyMessages(
|
|
1274
|
-
tools:
|
|
1275
|
-
options:
|
|
1514
|
+
messages: copyMessages(streamRequest.messages),
|
|
1515
|
+
tools: [...streamRequest.tools],
|
|
1516
|
+
options: { ...streamRequest.options },
|
|
1276
1517
|
attempt,
|
|
1277
1518
|
error,
|
|
1278
1519
|
failure,
|
|
1279
|
-
...
|
|
1280
|
-
...
|
|
1520
|
+
...streamRequest.options.provider ? { provider: streamRequest.options.provider } : {},
|
|
1521
|
+
...streamRequest.options.model ? { model: streamRequest.options.model } : {},
|
|
1281
1522
|
...options.signal ? { signal: options.signal } : {}
|
|
1282
1523
|
},
|
|
1283
1524
|
() => void 0
|
|
@@ -1302,16 +1543,30 @@ var AgentService = class {
|
|
|
1302
1543
|
await session.append("llm/retry-started", { retryId, retry: attempt });
|
|
1303
1544
|
}
|
|
1304
1545
|
}
|
|
1305
|
-
if (
|
|
1306
|
-
|
|
1546
|
+
if (!completion || !activeAttempt) {
|
|
1547
|
+
if (options.signal?.aborted) {
|
|
1548
|
+
finishReason = "cancelled";
|
|
1549
|
+
break;
|
|
1550
|
+
}
|
|
1551
|
+
throw new AgentError("LLM adapter did not produce a completion");
|
|
1552
|
+
}
|
|
1307
1553
|
const toolCalls = completion.toolCalls ?? [];
|
|
1308
|
-
if (
|
|
1554
|
+
if (completion.finishReason === "length") lengthReached = true;
|
|
1555
|
+
if (options.signal?.aborted && toolCalls.length === 0) {
|
|
1556
|
+
yield activeAttempt.push({ type: "stream_error", error: { name: "AbortError", message: "stream aborted" } });
|
|
1557
|
+
yield* this.settleAttempt(activeAttempt);
|
|
1558
|
+
finishReason = "cancelled";
|
|
1559
|
+
break;
|
|
1560
|
+
}
|
|
1561
|
+
if (finalTurnGranted && toolCalls.length && !options.signal?.aborted) {
|
|
1562
|
+
yield activeAttempt.push({ type: "stream_error", error: { name: "AgentError", message: "maximum turns reached" } });
|
|
1563
|
+
yield* this.settleAttempt(activeAttempt);
|
|
1309
1564
|
finishReason = "max_turns";
|
|
1310
1565
|
break;
|
|
1311
1566
|
}
|
|
1312
1567
|
const toolResults = [];
|
|
1313
1568
|
if (toolCalls.length) {
|
|
1314
|
-
|
|
1569
|
+
yield* this.settleAttempt(activeAttempt, {
|
|
1315
1570
|
content: completion.content ?? "",
|
|
1316
1571
|
toolCalls: toolCalls.map((call) => ({
|
|
1317
1572
|
id: call.id,
|
|
@@ -1332,18 +1587,30 @@ var AgentService = class {
|
|
|
1332
1587
|
if (options.signal) toolOptions.signal = options.signal;
|
|
1333
1588
|
const startedAt = Date.now();
|
|
1334
1589
|
let result;
|
|
1335
|
-
|
|
1336
|
-
result = await tools.execute(call.name, call.arguments, toolOptions);
|
|
1337
|
-
} catch (error) {
|
|
1590
|
+
if (options.signal?.aborted) {
|
|
1338
1591
|
result = {
|
|
1339
1592
|
ok: false,
|
|
1340
1593
|
name: call.name,
|
|
1341
1594
|
callId: call.id,
|
|
1342
1595
|
input: call.arguments,
|
|
1343
|
-
error:
|
|
1596
|
+
error: abortedToolError(options.signal),
|
|
1344
1597
|
startedAt,
|
|
1345
1598
|
durationMs: Date.now() - startedAt
|
|
1346
1599
|
};
|
|
1600
|
+
} else {
|
|
1601
|
+
try {
|
|
1602
|
+
result = await tools.execute(call.name, call.arguments, toolOptions);
|
|
1603
|
+
} catch (error) {
|
|
1604
|
+
result = {
|
|
1605
|
+
ok: false,
|
|
1606
|
+
name: call.name,
|
|
1607
|
+
callId: call.id,
|
|
1608
|
+
input: call.arguments,
|
|
1609
|
+
error: toToolError(error),
|
|
1610
|
+
startedAt,
|
|
1611
|
+
durationMs: Date.now() - startedAt
|
|
1612
|
+
};
|
|
1613
|
+
}
|
|
1347
1614
|
}
|
|
1348
1615
|
toolResults.push(result);
|
|
1349
1616
|
const toolResultPayload = {
|
|
@@ -1385,7 +1652,7 @@ var AgentService = class {
|
|
|
1385
1652
|
output = completion.content;
|
|
1386
1653
|
}
|
|
1387
1654
|
if (!toolCalls.length) {
|
|
1388
|
-
|
|
1655
|
+
yield* this.settleAttempt(activeAttempt, { content: completion.content ?? "" });
|
|
1389
1656
|
}
|
|
1390
1657
|
await session.append("step/end", {
|
|
1391
1658
|
turn,
|
|
@@ -1396,19 +1663,19 @@ var AgentService = class {
|
|
|
1396
1663
|
currentStepIndex = void 0;
|
|
1397
1664
|
const nextMessages = this._extendMessages(llmMessages, completion, toolResults);
|
|
1398
1665
|
const concludesTurn = toolResults.some((result) => result.concludesTurn === true);
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
}
|
|
1403
|
-
if (toolCalls.length === 0) {
|
|
1404
|
-
finishReason = completion.finishReason === "length" ? "length" : completion.finishReason === "error" ? "error" : "stop";
|
|
1666
|
+
let nextStepMessages = await this._claimNextStepMessages();
|
|
1667
|
+
if ((toolCalls.length === 0 || concludesTurn) && nextStepMessages.length === 0) {
|
|
1668
|
+
finishReason = lengthReached ? "length" : completion.finishReason === "error" ? "error" : "stop";
|
|
1405
1669
|
const keepGoing = await this.ctx.serial("agent/turn-stopping", {
|
|
1406
1670
|
index,
|
|
1407
1671
|
turn,
|
|
1408
1672
|
steps: copySteps(steps),
|
|
1409
1673
|
finishReason
|
|
1410
1674
|
});
|
|
1411
|
-
if (!keepGoing)
|
|
1675
|
+
if (!keepGoing) {
|
|
1676
|
+
nextStepMessages = await this._claimNextStepMessages();
|
|
1677
|
+
if (nextStepMessages.length === 0) break;
|
|
1678
|
+
}
|
|
1412
1679
|
}
|
|
1413
1680
|
if (index + 1 >= maxTurns && !finalTurnGranted) {
|
|
1414
1681
|
finalTurnGranted = true;
|
|
@@ -1418,7 +1685,8 @@ var AgentService = class {
|
|
|
1418
1685
|
}
|
|
1419
1686
|
if (toolCalls.length) finishReason = "tool_calls";
|
|
1420
1687
|
index += 1;
|
|
1421
|
-
messages = nextMessages;
|
|
1688
|
+
messages = [...nextMessages, ...nextStepMessages];
|
|
1689
|
+
claimedMessages = nextStepMessages.filter((message) => message.role === "user");
|
|
1422
1690
|
}
|
|
1423
1691
|
} catch (error) {
|
|
1424
1692
|
turnError = error;
|
|
@@ -1504,23 +1772,22 @@ var AgentService = class {
|
|
|
1504
1772
|
});
|
|
1505
1773
|
return compactMessages.map((message) => copyMessages([message])[0]);
|
|
1506
1774
|
}
|
|
1507
|
-
async _persistStepInput(session, request, input) {
|
|
1508
|
-
const
|
|
1509
|
-
const
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
};
|
|
1775
|
+
async _persistStepInput(session, request, input, admittedHistory) {
|
|
1776
|
+
const surface = await session.deriveMessages();
|
|
1777
|
+
const owned = admittedHistory.filter((message) => !isUserOrSystemMessage(message));
|
|
1778
|
+
let ownerIndex = 0;
|
|
1779
|
+
for (const message of input) {
|
|
1780
|
+
if (isUserOrSystemMessage(message)) continue;
|
|
1781
|
+
const actual = canonicalMessages([message]);
|
|
1782
|
+
while (ownerIndex < owned.length && canonicalMessages([owned[ownerIndex]]) !== actual) {
|
|
1783
|
+
ownerIndex += 1;
|
|
1784
|
+
}
|
|
1785
|
+
if (ownerIndex === owned.length) {
|
|
1786
|
+
throw new AgentError("request is not reconstructable from session log: unowned or reordered assistant/tool message");
|
|
1787
|
+
}
|
|
1788
|
+
ownerIndex += 1;
|
|
1789
|
+
}
|
|
1790
|
+
const nextHeader = requestHeaderFor(request, input);
|
|
1524
1791
|
const previousHeader = session.requestHeader();
|
|
1525
1792
|
const isFirstRequest = !this._persistedRequest;
|
|
1526
1793
|
const isResume = isFirstRequest && previousHeader !== void 0;
|
|
@@ -1550,19 +1817,23 @@ var AgentService = class {
|
|
|
1550
1817
|
...request.options.provider ? { provider: request.options.provider } : {},
|
|
1551
1818
|
...request.options.model ? { model: request.options.model } : {}
|
|
1552
1819
|
};
|
|
1820
|
+
if (request.options.contextWindow !== void 0) {
|
|
1821
|
+
nextContext.contextWindow = request.options.contextWindow;
|
|
1822
|
+
}
|
|
1553
1823
|
const llmService2 = this.ctx.reflect.get("llm", false);
|
|
1554
1824
|
const routeCapacity = llmService2?.routeCapacity?.();
|
|
1555
|
-
if (routeCapacity?.contextWindow !== void 0) {
|
|
1825
|
+
if (nextContext.contextWindow === void 0 && routeCapacity?.contextWindow !== void 0) {
|
|
1556
1826
|
nextContext.contextWindow = routeCapacity.contextWindow;
|
|
1557
1827
|
}
|
|
1558
1828
|
const previousContext = session.requestContext();
|
|
1559
1829
|
if (previousContext?.provider !== nextContext.provider || previousContext?.model !== nextContext.model || previousContext?.contextWindow !== nextContext.contextWindow || previousContext === void 0) {
|
|
1560
1830
|
await session.append("request/context", nextContext);
|
|
1561
1831
|
}
|
|
1562
|
-
const
|
|
1563
|
-
const
|
|
1564
|
-
const
|
|
1565
|
-
|
|
1832
|
+
const isSurfacePrefix = (messages) => canonicalMessages(messages.slice(0, surface.length)) === canonicalMessages(surface);
|
|
1833
|
+
const requested = surface.length > 0 && input[0]?.role === "system" && input[0].content === nextHeader.system && isSurfacePrefix(input.slice(1)) ? input.slice(1) : input;
|
|
1834
|
+
const tail = requested.slice(surface.length);
|
|
1835
|
+
if (isSurfacePrefix(requested) && tail.every(isUserOrSystemMessage)) {
|
|
1836
|
+
for (const message of tail) {
|
|
1566
1837
|
if (message.role === "user") {
|
|
1567
1838
|
await session.append("user/message", {
|
|
1568
1839
|
content: message.content,
|
|
@@ -1575,45 +1846,37 @@ var AgentService = class {
|
|
|
1575
1846
|
});
|
|
1576
1847
|
}
|
|
1577
1848
|
}
|
|
1578
|
-
};
|
|
1579
|
-
if (surface.length === 0) {
|
|
1580
|
-
await appendDurable(requested);
|
|
1581
1849
|
return;
|
|
1582
1850
|
}
|
|
1583
|
-
const
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
if (seenUsers <= durableUsers) continue;
|
|
1589
|
-
newTail.push(message);
|
|
1590
|
-
}
|
|
1591
|
-
await appendDurable(newTail);
|
|
1851
|
+
const nodes = await session.surfaceEvents();
|
|
1852
|
+
await session.append("checkpoint", {
|
|
1853
|
+
messages: copyMessages(requested),
|
|
1854
|
+
surfaceOp: { op: "replace", start: nodes[0].seq, end: nodes.at(-1).seq }
|
|
1855
|
+
});
|
|
1592
1856
|
}
|
|
1593
|
-
async _assertReplayable(session, input) {
|
|
1857
|
+
async _assertReplayable(session, request, input) {
|
|
1594
1858
|
const reconstructed = await session.deriveMessages();
|
|
1595
|
-
const
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
...message.tool_calls?.length ? { tool_calls: message.tool_calls.map((call) => ({
|
|
1601
|
-
id: call.id,
|
|
1602
|
-
name: call.name,
|
|
1603
|
-
args: JSON.stringify(call.arguments ?? {})
|
|
1604
|
-
})) } : {}
|
|
1605
|
-
}));
|
|
1606
|
-
const actual = canonical(input);
|
|
1607
|
-
const replay = canonical(reconstructed);
|
|
1608
|
-
if (JSON.stringify(actual) !== JSON.stringify(replay)) {
|
|
1859
|
+
const actual = canonicalMessages(input);
|
|
1860
|
+
const replay = canonicalMessages(reconstructed);
|
|
1861
|
+
const header = session.requestHeader();
|
|
1862
|
+
const headerOwnsPrefix = input[0]?.role === "system" && input[0].content === header?.system && canonicalMessages(input.slice(1)) === replay;
|
|
1863
|
+
if (actual !== replay && !headerOwnsPrefix) {
|
|
1609
1864
|
throw new AgentError(
|
|
1610
|
-
`request is not reconstructable from session log: actual=${
|
|
1865
|
+
`request is not reconstructable from session log: actual=${actual} replay=${replay}`
|
|
1611
1866
|
);
|
|
1612
1867
|
}
|
|
1868
|
+
const expected = requestHeaderFor(request, input);
|
|
1869
|
+
if (header?.system !== expected.system || JSON.stringify(header?.tools ?? []) !== JSON.stringify(expected.tools ?? []) || JSON.stringify(header?.config ?? {}) !== JSON.stringify(expected.config ?? {})) {
|
|
1870
|
+
throw new AgentError("request envelope is not reconstructable from session log");
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
async _claimNextStepMessages() {
|
|
1874
|
+
const inputs = await this.config.claimNextStep?.() ?? [];
|
|
1875
|
+
return inputs.flatMap((input) => input.messages?.length ? copyMessages(input.messages) : input.text ? [{ role: "user", content: input.text }] : input.context !== void 0 ? [{ role: "user", content: stringify2(input.context) }] : []);
|
|
1613
1876
|
}
|
|
1614
1877
|
async _initialMessages(input) {
|
|
1615
1878
|
const promptService = this.ctx.reflect.get("systemPrompt", false);
|
|
1616
|
-
const assembled = promptService ? (await promptService.assemble()).text.trim() : void 0;
|
|
1879
|
+
const assembled = promptService ? (await promptService.assemble({}, this.ctx)).text.trim() : void 0;
|
|
1617
1880
|
const systemPrompt2 = assembled || this.inbox.injected().get("agentSystem");
|
|
1618
1881
|
const systemMessage = typeof systemPrompt2 === "string" && systemPrompt2 ? [{ role: "system", content: systemPrompt2 }] : [];
|
|
1619
1882
|
if (input.messages?.length) {
|
|
@@ -1638,7 +1901,7 @@ var AgentService = class {
|
|
|
1638
1901
|
arguments: call.arguments
|
|
1639
1902
|
}));
|
|
1640
1903
|
}
|
|
1641
|
-
next.push(assistant);
|
|
1904
|
+
if (assistant.content || toolCalls.length) next.push(assistant);
|
|
1642
1905
|
for (const call of toolCalls) {
|
|
1643
1906
|
const result = toolResults.find((candidate) => candidate.callId === call.id);
|
|
1644
1907
|
const content = result ? result.ok ? stringify2(result.output) : `error: ${result.error?.message ?? "unknown"}` : "error: missing tool result";
|
|
@@ -1668,7 +1931,8 @@ var AgentService = class {
|
|
|
1668
1931
|
return session;
|
|
1669
1932
|
}
|
|
1670
1933
|
_tools() {
|
|
1671
|
-
const
|
|
1934
|
+
const scoped = this.ctx.reflect.get("tools", false);
|
|
1935
|
+
const tools = scoped ?? this.ctx.tools;
|
|
1672
1936
|
if (!tools) throw new AgentError("tools service is required");
|
|
1673
1937
|
return tools;
|
|
1674
1938
|
}
|
|
@@ -1837,206 +2101,1500 @@ function defineAgent(definition) {
|
|
|
1837
2101
|
// packages/agent/src/live.ts
|
|
1838
2102
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
1839
2103
|
|
|
1840
|
-
// packages/
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
}
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
this.
|
|
2104
|
+
// packages/core/src/utils.ts
|
|
2105
|
+
var DisposableList = class {
|
|
2106
|
+
sn = 0;
|
|
2107
|
+
map = /* @__PURE__ */ new Map();
|
|
2108
|
+
weak = /* @__PURE__ */ new WeakMap();
|
|
2109
|
+
get length() {
|
|
2110
|
+
return this.map.size;
|
|
2111
|
+
}
|
|
2112
|
+
push(value) {
|
|
2113
|
+
const sn = ++this.sn;
|
|
2114
|
+
this.map.set(sn, value);
|
|
2115
|
+
this.weak.set(value, sn);
|
|
2116
|
+
return () => this.map.delete(sn);
|
|
2117
|
+
}
|
|
2118
|
+
unshift(value) {
|
|
2119
|
+
const sn = ++this.sn;
|
|
2120
|
+
const entries = [...this.map.entries()];
|
|
2121
|
+
this.map.clear();
|
|
2122
|
+
this.map.set(sn, value);
|
|
2123
|
+
this.weak.set(value, sn);
|
|
2124
|
+
for (const [oldSn, oldValue] of entries) {
|
|
2125
|
+
this.map.set(oldSn, oldValue);
|
|
2126
|
+
}
|
|
2127
|
+
return () => this.map.delete(sn);
|
|
1851
2128
|
}
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
return this._nextTurn.length + this._nextStep.length;
|
|
2129
|
+
delete(value) {
|
|
2130
|
+
const sn = this.weak.get(value);
|
|
2131
|
+
if (!sn) return false;
|
|
2132
|
+
return this.map.delete(sn);
|
|
1857
2133
|
}
|
|
1858
|
-
|
|
1859
|
-
const
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
...input.content !== void 0 ? { content: input.content } : {}
|
|
1863
|
-
};
|
|
1864
|
-
const list = target === "next-step" ? this._nextStep : this._nextTurn;
|
|
1865
|
-
list.push(message);
|
|
1866
|
-
await this._session.append("agent/inbox/spliced", {
|
|
1867
|
-
target,
|
|
1868
|
-
index: list.length - 1,
|
|
1869
|
-
inserted: [{
|
|
1870
|
-
id: message.id,
|
|
1871
|
-
content: contentOf(message),
|
|
1872
|
-
...payloadOf(message) !== void 0 ? { payload: payloadOf(message) } : {}
|
|
1873
|
-
}]
|
|
1874
|
-
});
|
|
1875
|
-
return message;
|
|
2134
|
+
clear() {
|
|
2135
|
+
const values = [...this.map.values()];
|
|
2136
|
+
this.map.clear();
|
|
2137
|
+
return values.reverse();
|
|
1876
2138
|
}
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
id: randomUUID3(),
|
|
1880
|
-
...input.text !== void 0 ? { text: input.text } : {},
|
|
1881
|
-
...input.content !== void 0 ? { content: input.content } : {}
|
|
1882
|
-
};
|
|
1883
|
-
this._nextStep.unshift(message);
|
|
1884
|
-
await this._session.append("agent/inbox/spliced", {
|
|
1885
|
-
target: "next-step",
|
|
1886
|
-
index: 0,
|
|
1887
|
-
inserted: [{
|
|
1888
|
-
id: message.id,
|
|
1889
|
-
content: contentOf(message),
|
|
1890
|
-
...payloadOf(message) !== void 0 ? { payload: payloadOf(message) } : {},
|
|
1891
|
-
mode: "steer"
|
|
1892
|
-
}]
|
|
1893
|
-
});
|
|
1894
|
-
return message;
|
|
2139
|
+
[Symbol.iterator]() {
|
|
2140
|
+
return this.map.values();
|
|
1895
2141
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
if (steered) {
|
|
1899
|
-
await this._session.append("agent/inbox/spliced", {
|
|
1900
|
-
target: "next-step",
|
|
1901
|
-
index: 0,
|
|
1902
|
-
deleteCount: 1
|
|
1903
|
-
});
|
|
1904
|
-
return steered;
|
|
1905
|
-
}
|
|
1906
|
-
const next = this._nextTurn.shift();
|
|
1907
|
-
if (next) {
|
|
1908
|
-
await this._session.append("agent/inbox/spliced", {
|
|
1909
|
-
target: "next-turn",
|
|
1910
|
-
index: 0,
|
|
1911
|
-
deleteCount: 1
|
|
1912
|
-
});
|
|
1913
|
-
return next;
|
|
1914
|
-
}
|
|
1915
|
-
return void 0;
|
|
2142
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
2143
|
+
return [...this];
|
|
1916
2144
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
2145
|
+
};
|
|
2146
|
+
var symbols = {
|
|
2147
|
+
shadow: /* @__PURE__ */ Symbol.for("tnega.shadow"),
|
|
2148
|
+
caller: /* @__PURE__ */ Symbol.for("tnega.caller"),
|
|
2149
|
+
receiver: /* @__PURE__ */ Symbol.for("tnega.receiver"),
|
|
2150
|
+
original: /* @__PURE__ */ Symbol.for("tnega.original"),
|
|
2151
|
+
metadata: /* @__PURE__ */ Symbol.for("tnega.metadata"),
|
|
2152
|
+
initHooks: /* @__PURE__ */ Symbol.for("tnega.initHooks"),
|
|
2153
|
+
checkProto: /* @__PURE__ */ Symbol.for("tnega.checkProto"),
|
|
2154
|
+
effect: /* @__PURE__ */ Symbol.for("tnega.effect"),
|
|
2155
|
+
filter: /* @__PURE__ */ Symbol.for("tnega.filter"),
|
|
2156
|
+
isolate: /* @__PURE__ */ Symbol.for("tnega.isolate"),
|
|
2157
|
+
intercept: /* @__PURE__ */ Symbol.for("tnega.intercept"),
|
|
2158
|
+
init: /* @__PURE__ */ Symbol.for("tnega.init"),
|
|
2159
|
+
check: /* @__PURE__ */ Symbol.for("tnega.check"),
|
|
2160
|
+
config: /* @__PURE__ */ Symbol.for("tnega.config"),
|
|
2161
|
+
invoke: /* @__PURE__ */ Symbol.for("tnega.invoke"),
|
|
2162
|
+
extend: /* @__PURE__ */ Symbol.for("tnega.extend"),
|
|
2163
|
+
tracker: /* @__PURE__ */ Symbol.for("tnega.tracker"),
|
|
2164
|
+
resolveConfig: /* @__PURE__ */ Symbol.for("tnega.resolveConfig")
|
|
2165
|
+
};
|
|
2166
|
+
var GeneratorFunction = function* () {
|
|
2167
|
+
}.constructor;
|
|
2168
|
+
var AsyncGeneratorFunction = async function* () {
|
|
2169
|
+
}.constructor;
|
|
2170
|
+
function isConstructor(func) {
|
|
2171
|
+
if (typeof func !== "function") return false;
|
|
2172
|
+
if (func instanceof GeneratorFunction) return false;
|
|
2173
|
+
if (AsyncGeneratorFunction !== Function && func instanceof AsyncGeneratorFunction) return false;
|
|
2174
|
+
return /^class\s/.test(Function.prototype.toString.call(func));
|
|
2175
|
+
}
|
|
2176
|
+
function isObject(value) {
|
|
2177
|
+
return !!value && (typeof value === "object" || typeof value === "function");
|
|
2178
|
+
}
|
|
2179
|
+
function isNullable(value) {
|
|
2180
|
+
return value == null;
|
|
2181
|
+
}
|
|
2182
|
+
function joinPrototype(proto1, proto2) {
|
|
2183
|
+
if (proto1 === Object.prototype) return proto2;
|
|
2184
|
+
const result = Object.create(joinPrototype(Object.getPrototypeOf(proto1), proto2));
|
|
2185
|
+
for (const key of Reflect.ownKeys(proto1)) {
|
|
2186
|
+
Object.defineProperty(result, key, Reflect.getOwnPropertyDescriptor(proto1, key));
|
|
2187
|
+
}
|
|
2188
|
+
return result;
|
|
2189
|
+
}
|
|
2190
|
+
function getPropertyDescriptor(target, prop) {
|
|
2191
|
+
let proto = target;
|
|
2192
|
+
while (proto) {
|
|
2193
|
+
const desc = Reflect.getOwnPropertyDescriptor(proto, prop);
|
|
2194
|
+
if (desc) return desc;
|
|
2195
|
+
proto = Object.getPrototypeOf(proto);
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
function getTraceable(ctx, value) {
|
|
2199
|
+
if (!isObject(value)) return value;
|
|
2200
|
+
if (Object.hasOwn(value, symbols.shadow)) {
|
|
2201
|
+
return Object.getPrototypeOf(value);
|
|
2202
|
+
}
|
|
2203
|
+
const tracker = value[symbols.tracker];
|
|
2204
|
+
if (!tracker) return value;
|
|
2205
|
+
return createTraceable(ctx, value, tracker);
|
|
2206
|
+
}
|
|
2207
|
+
function withProps(target, props) {
|
|
2208
|
+
if (!props) return target;
|
|
2209
|
+
return new Proxy(target, {
|
|
2210
|
+
get: (target2, prop, receiver) => {
|
|
2211
|
+
if (prop in props && prop !== "constructor") return Reflect.get(props, prop, receiver);
|
|
2212
|
+
return Reflect.get(target2, prop, receiver);
|
|
2213
|
+
},
|
|
2214
|
+
set: (target2, prop, value, receiver) => {
|
|
2215
|
+
if (prop in props && prop !== "constructor") return Reflect.set(props, prop, value, receiver);
|
|
2216
|
+
return Reflect.set(target2, prop, value, receiver);
|
|
1932
2217
|
}
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
function withProp(target, prop, value) {
|
|
2221
|
+
return withProps(target, Object.defineProperty(/* @__PURE__ */ Object.create(null), prop, {
|
|
2222
|
+
value,
|
|
2223
|
+
writable: false
|
|
2224
|
+
}));
|
|
2225
|
+
}
|
|
2226
|
+
function createShadow(ctx, target, property, receiver) {
|
|
2227
|
+
if (!property) return receiver;
|
|
2228
|
+
const origin = getPropertyDescriptor(target, property)?.value;
|
|
2229
|
+
if (!origin) return receiver;
|
|
2230
|
+
return withProp(receiver, property, ctx.extend({ [symbols.shadow]: origin }));
|
|
2231
|
+
}
|
|
2232
|
+
function createShadowMethod(ctx, value, outer, shadow) {
|
|
2233
|
+
const proxy = new Proxy(value, {
|
|
2234
|
+
apply: (target, thisArg, args) => {
|
|
2235
|
+
if (thisArg === outer) thisArg = shadow;
|
|
2236
|
+
return getTraceable(ctx, Reflect.apply(target, thisArg, args));
|
|
1941
2237
|
}
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
2238
|
+
});
|
|
2239
|
+
return proxy;
|
|
2240
|
+
}
|
|
2241
|
+
function createTraceable(ctx, value, tracker) {
|
|
2242
|
+
const caller = ctx[symbols.shadow] ?? ctx;
|
|
2243
|
+
if (ctx[symbols.shadow]) {
|
|
2244
|
+
ctx = Object.getPrototypeOf(ctx);
|
|
2245
|
+
}
|
|
2246
|
+
const proxy = new Proxy(value, {
|
|
2247
|
+
get: (target, prop, receiver) => {
|
|
2248
|
+
if (prop === symbols.original) return target;
|
|
2249
|
+
if (prop === symbols.caller) return caller;
|
|
2250
|
+
if (prop === tracker.property) return ctx;
|
|
2251
|
+
if (typeof prop === "symbol") {
|
|
2252
|
+
return Reflect.get(target, prop, receiver);
|
|
2253
|
+
}
|
|
2254
|
+
if (tracker.associate && ctx.reflect.props[`${tracker.associate}.${prop}`]) {
|
|
2255
|
+
return Reflect.get(ctx, `${tracker.associate}.${prop}`, withProp(ctx, symbols.receiver, receiver));
|
|
2256
|
+
}
|
|
2257
|
+
let shadow;
|
|
2258
|
+
let innerValue;
|
|
2259
|
+
const desc = getPropertyDescriptor(target, prop);
|
|
2260
|
+
if (desc?.value !== void 0) {
|
|
2261
|
+
innerValue = desc.value;
|
|
2262
|
+
} else {
|
|
2263
|
+
shadow = createShadow(ctx, target, tracker.property, receiver);
|
|
2264
|
+
innerValue = Reflect.get(target, prop, shadow);
|
|
2265
|
+
}
|
|
2266
|
+
const innerTracker = innerValue?.[symbols.tracker];
|
|
2267
|
+
if (innerTracker) {
|
|
2268
|
+
return createTraceable(ctx, innerValue, innerTracker);
|
|
2269
|
+
} else if (!tracker.noShadow && typeof innerValue === "function") {
|
|
2270
|
+
shadow ??= createShadow(ctx, target, tracker.property, receiver);
|
|
2271
|
+
return createShadowMethod(ctx, innerValue, receiver, shadow);
|
|
2272
|
+
} else {
|
|
2273
|
+
return innerValue;
|
|
2274
|
+
}
|
|
2275
|
+
},
|
|
2276
|
+
set: (target, prop, value2, receiver) => {
|
|
2277
|
+
if (prop === symbols.original || prop === symbols.caller || prop === tracker.property) return false;
|
|
2278
|
+
if (typeof prop === "symbol") {
|
|
2279
|
+
return Reflect.set(target, prop, value2, receiver);
|
|
2280
|
+
}
|
|
2281
|
+
if (tracker.associate && ctx.reflect.props[`${tracker.associate}.${prop}`]) {
|
|
2282
|
+
return Reflect.set(ctx, `${tracker.associate}.${prop}`, value2, withProp(ctx, symbols.receiver, receiver));
|
|
2283
|
+
}
|
|
2284
|
+
const shadow = createShadow(ctx, target, tracker.property, receiver);
|
|
2285
|
+
return Reflect.set(target, prop, value2, shadow);
|
|
2286
|
+
},
|
|
2287
|
+
apply: (target, thisArg, args) => {
|
|
2288
|
+
const receiver = tracker.noShadow ? proxy : createShadow(ctx, target, tracker.property, proxy);
|
|
2289
|
+
return applyTraceable(receiver, target, thisArg, args);
|
|
1952
2290
|
}
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
2291
|
+
});
|
|
2292
|
+
return proxy;
|
|
2293
|
+
}
|
|
2294
|
+
function applyTraceable(proxy, value, thisArg, args) {
|
|
2295
|
+
if (!value[symbols.invoke]) return Reflect.apply(value, thisArg, args);
|
|
2296
|
+
return value[symbols.invoke].apply(proxy, args);
|
|
2297
|
+
}
|
|
2298
|
+
function createCallable(name2, proto, tracker) {
|
|
2299
|
+
const self = function(...args) {
|
|
2300
|
+
const proxy = createTraceable(self.ctx, self, tracker);
|
|
2301
|
+
return Reflect.apply(proxy, this, args);
|
|
2302
|
+
};
|
|
2303
|
+
Object.defineProperty(self, "name", { value: name2, configurable: true, writable: true });
|
|
2304
|
+
return Object.setPrototypeOf(self, proto);
|
|
2305
|
+
}
|
|
2306
|
+
function handleError(info, reason, getOuterStack) {
|
|
2307
|
+
const innerLines = info.error.stack.split("\n");
|
|
2308
|
+
if (typeof reason?.stack !== "string") {
|
|
2309
|
+
const outerError = new Error(reason);
|
|
2310
|
+
const lines2 = outerError.stack.split("\n");
|
|
2311
|
+
lines2.splice(1, Infinity, ...getOuterStack());
|
|
2312
|
+
outerError.stack = lines2.join("\n");
|
|
2313
|
+
throw outerError;
|
|
2314
|
+
}
|
|
2315
|
+
const lines = reason.stack.split("\n");
|
|
2316
|
+
const index = lines.indexOf(innerLines[2]);
|
|
2317
|
+
if (index === -1) throw reason;
|
|
2318
|
+
lines.splice(index - info.offset, Infinity, ...getOuterStack());
|
|
2319
|
+
reason.stack = lines.join("\n");
|
|
2320
|
+
throw reason;
|
|
2321
|
+
}
|
|
2322
|
+
function composeError(callback, getOuterStack = buildOuterStack()) {
|
|
2323
|
+
const info = { offset: 1, error: new Error() };
|
|
2324
|
+
try {
|
|
2325
|
+
const result = callback(info);
|
|
2326
|
+
if (isObject(result) && "then" in result) {
|
|
2327
|
+
return result.then(void 0, (reason) => handleError(info, reason, getOuterStack));
|
|
1960
2328
|
}
|
|
2329
|
+
return result;
|
|
2330
|
+
} catch (reason) {
|
|
2331
|
+
handleError(info, reason, getOuterStack);
|
|
1961
2332
|
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
content: contentOf(message),
|
|
1978
|
-
...payloadOf(message) !== void 0 ? { payload: payloadOf(message) } : {},
|
|
1979
|
-
mode
|
|
1980
|
-
}]
|
|
2333
|
+
}
|
|
2334
|
+
function buildOuterStack(offset = 0) {
|
|
2335
|
+
const outerError = new Error();
|
|
2336
|
+
return () => outerError.stack.split("\n").slice(3 + offset);
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
// packages/core/src/events.ts
|
|
2340
|
+
function isBailed(value) {
|
|
2341
|
+
return value !== null && value !== false && value !== void 0;
|
|
2342
|
+
}
|
|
2343
|
+
var EventsService = class {
|
|
2344
|
+
constructor(ctx) {
|
|
2345
|
+
this.ctx = ctx;
|
|
2346
|
+
Object.defineProperty(this, symbols.tracker, {
|
|
2347
|
+
value: { property: "ctx", noShadow: true }
|
|
1981
2348
|
});
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
async replace(messageId, input) {
|
|
1989
|
-
const entry = this._find(messageId);
|
|
1990
|
-
if (!entry) return void 0;
|
|
1991
|
-
const replacement = {
|
|
1992
|
-
id: randomUUID3(),
|
|
1993
|
-
...input.text !== void 0 ? { text: input.text } : {},
|
|
1994
|
-
...input.content !== void 0 ? { content: input.content } : {}
|
|
1995
|
-
};
|
|
1996
|
-
const target = entry.target;
|
|
1997
|
-
const index = entry.index;
|
|
1998
|
-
entry.list.splice(index, 1, replacement);
|
|
1999
|
-
await this._session.append("agent/inbox/spliced", {
|
|
2000
|
-
target,
|
|
2001
|
-
index,
|
|
2002
|
-
deleteCount: 1,
|
|
2003
|
-
inserted: [{
|
|
2004
|
-
id: replacement.id,
|
|
2005
|
-
content: contentOf(replacement),
|
|
2006
|
-
...payloadOf(replacement) !== void 0 ? { payload: payloadOf(replacement) } : {}
|
|
2007
|
-
}]
|
|
2349
|
+
this.on("internal/listener", function(name2, listener, options) {
|
|
2350
|
+
if (name2 === "internal/update" && !options.global) {
|
|
2351
|
+
const hooks = this.fiber._hooks["internal/update"] ??= new DisposableList();
|
|
2352
|
+
const method = options.prepend ? "unshift" : "push";
|
|
2353
|
+
return hooks[method](listener);
|
|
2354
|
+
}
|
|
2008
2355
|
});
|
|
2009
|
-
|
|
2356
|
+
this.on("internal/update", function(config, noSave, next) {
|
|
2357
|
+
const cbs = [...this.fiber._hooks["internal/update"] ?? []];
|
|
2358
|
+
const _next = () => {
|
|
2359
|
+
const cb = cbs.shift() ?? next;
|
|
2360
|
+
return cb.call(this, config, noSave, _next);
|
|
2361
|
+
};
|
|
2362
|
+
return _next();
|
|
2363
|
+
}, { global: true, prepend: true });
|
|
2010
2364
|
}
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2365
|
+
ctx;
|
|
2366
|
+
_hooks = /* @__PURE__ */ Object.create(null);
|
|
2367
|
+
_resolve(type, args) {
|
|
2368
|
+
const thisArg = typeof args[0] === "object" || typeof args[0] === "function" ? args.shift() : null;
|
|
2369
|
+
const name2 = args.shift();
|
|
2370
|
+
if (!name2.startsWith("internal/") && this._hooks["internal/dispatch"]?.length) {
|
|
2371
|
+
this.emit("internal/dispatch", type, name2, args, thisArg);
|
|
2372
|
+
}
|
|
2373
|
+
const filter = thisArg?.[Context.filter];
|
|
2374
|
+
return [thisArg, (this._hooks[name2] || []).filter((hook) => hook.global || !filter || filter.call(thisArg, hook.ctx)).map((hook) => hook.callback)];
|
|
2375
|
+
}
|
|
2376
|
+
dispatch(type, args) {
|
|
2377
|
+
const [thisArg, callbacks] = this._resolve(type, args);
|
|
2378
|
+
return callbacks.map((callback) => callback.bind(thisArg));
|
|
2379
|
+
}
|
|
2380
|
+
async parallel(...args) {
|
|
2381
|
+
const [thisArg, callbacks] = this._resolve("parallel", args);
|
|
2382
|
+
const results = await Promise.allSettled(callbacks.map(async (callback) => Reflect.apply(callback, thisArg, args)));
|
|
2383
|
+
const errors = results.filter((result) => result.status === "rejected").map((result) => result.reason);
|
|
2384
|
+
if (errors.length) throw new AggregateError(errors);
|
|
2385
|
+
}
|
|
2386
|
+
emit(...args) {
|
|
2387
|
+
const [thisArg, callbacks] = this._resolve("emit", args);
|
|
2388
|
+
for (const callback of callbacks) Reflect.apply(callback, thisArg, args);
|
|
2389
|
+
}
|
|
2390
|
+
async serial(...args) {
|
|
2391
|
+
const [thisArg, callbacks] = this._resolve("serial", args);
|
|
2392
|
+
for (const callback of callbacks) {
|
|
2393
|
+
const result = await Reflect.apply(callback, thisArg, args);
|
|
2394
|
+
if (isBailed(result)) return result;
|
|
2395
|
+
}
|
|
2022
2396
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2397
|
+
bail(...args) {
|
|
2398
|
+
const [thisArg, callbacks] = this._resolve("bail", args);
|
|
2399
|
+
for (const callback of callbacks) {
|
|
2400
|
+
const result = Reflect.apply(callback, thisArg, args);
|
|
2401
|
+
if (isBailed(result)) return result;
|
|
2402
|
+
}
|
|
2026
2403
|
}
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2404
|
+
waterfall(...args) {
|
|
2405
|
+
const [thisArg, callbacks] = this._resolve("waterfall", args);
|
|
2406
|
+
const inner = args.pop();
|
|
2407
|
+
const next = () => {
|
|
2408
|
+
const callback = callbacks.shift();
|
|
2409
|
+
return callback ? Reflect.apply(callback, thisArg, args) : inner(...args);
|
|
2031
2410
|
};
|
|
2411
|
+
args.push(next);
|
|
2412
|
+
return next();
|
|
2413
|
+
}
|
|
2414
|
+
async waterfallAsync(...args) {
|
|
2415
|
+
const [thisArg, callbacks] = this._resolve("waterfallAsync", args);
|
|
2416
|
+
const inner = args.pop();
|
|
2417
|
+
const next = async () => {
|
|
2418
|
+
const callback = callbacks.shift();
|
|
2419
|
+
return callback ? await Reflect.apply(callback, thisArg, args) : inner(...args);
|
|
2420
|
+
};
|
|
2421
|
+
args.push(next);
|
|
2422
|
+
return next();
|
|
2423
|
+
}
|
|
2424
|
+
register(label, hooks, callback, options) {
|
|
2425
|
+
const method = options.prepend ? "unshift" : "push";
|
|
2426
|
+
return this.ctx.fiber.effect(() => {
|
|
2427
|
+
hooks[method]({ ctx: this.ctx, callback, ...options });
|
|
2428
|
+
return () => this.unregister(hooks, callback);
|
|
2429
|
+
}, label);
|
|
2430
|
+
}
|
|
2431
|
+
unregister(hooks, callback) {
|
|
2432
|
+
const index = hooks.findIndex((hook) => hook.callback === callback);
|
|
2433
|
+
if (index >= 0) {
|
|
2434
|
+
hooks.splice(index, 1);
|
|
2435
|
+
return true;
|
|
2436
|
+
}
|
|
2032
2437
|
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
const index = list.findIndex((message) => message.id === messageId);
|
|
2037
|
-
if (index >= 0) return { list, target, index, message: list[index] };
|
|
2438
|
+
on(name2, listener, options = {}) {
|
|
2439
|
+
if (typeof options !== "object") {
|
|
2440
|
+
options = { prepend: options };
|
|
2038
2441
|
}
|
|
2039
|
-
|
|
2442
|
+
this.ctx.fiber.assertActive();
|
|
2443
|
+
listener = this.ctx.reflect.bind(listener);
|
|
2444
|
+
const result = this.bail(this.ctx, "internal/listener", name2, listener, options);
|
|
2445
|
+
if (result) return result;
|
|
2446
|
+
const hooks = this._hooks[name2] ??= [];
|
|
2447
|
+
return this.register(`ctx.on(${JSON.stringify(name2)})`, hooks, listener, options);
|
|
2448
|
+
}
|
|
2449
|
+
once(name2, listener, options = {}) {
|
|
2450
|
+
const dispose = this.on(name2, function(...args) {
|
|
2451
|
+
dispose();
|
|
2452
|
+
return listener.apply(this, args);
|
|
2453
|
+
}, options);
|
|
2454
|
+
return dispose;
|
|
2455
|
+
}
|
|
2456
|
+
};
|
|
2457
|
+
|
|
2458
|
+
// packages/core/src/fiber.ts
|
|
2459
|
+
var INACTIVE = "__INACTIVE__";
|
|
2460
|
+
var ValidationError = class extends TypeError {
|
|
2461
|
+
name = "ValidationError";
|
|
2462
|
+
constructor(issues) {
|
|
2463
|
+
super("invalid config:\n" + issues.map((issue) => {
|
|
2464
|
+
if (issue.path) {
|
|
2465
|
+
return ` - ${issue.message} (at ${issue.path.join(".")})`;
|
|
2466
|
+
}
|
|
2467
|
+
return ` - ${issue.message}`;
|
|
2468
|
+
}).join("\n"));
|
|
2469
|
+
}
|
|
2470
|
+
};
|
|
2471
|
+
function resolveConfig(runtime, config) {
|
|
2472
|
+
if (!runtime.Config) return config;
|
|
2473
|
+
const schema = runtime.Config;
|
|
2474
|
+
if (typeof schema === "function") return schema(config);
|
|
2475
|
+
const validate = schema?.["~standard"]?.validate;
|
|
2476
|
+
if (typeof validate === "function") {
|
|
2477
|
+
const result = validate(config);
|
|
2478
|
+
if ("then" in result) {
|
|
2479
|
+
throw new TypeError("Async config validation is not supported");
|
|
2480
|
+
}
|
|
2481
|
+
if (result.issues) {
|
|
2482
|
+
throw new ValidationError(result.issues);
|
|
2483
|
+
}
|
|
2484
|
+
return result.value;
|
|
2485
|
+
}
|
|
2486
|
+
return config;
|
|
2487
|
+
}
|
|
2488
|
+
var CordisErrorCode = {
|
|
2489
|
+
INACTIVE_EFFECT: "cannot create effect on inactive context"
|
|
2490
|
+
};
|
|
2491
|
+
var CordisError = class extends Error {
|
|
2492
|
+
constructor(code, message) {
|
|
2493
|
+
super(message ?? CordisErrorCode[code]);
|
|
2494
|
+
this.code = code;
|
|
2495
|
+
}
|
|
2496
|
+
code;
|
|
2497
|
+
};
|
|
2498
|
+
var Fiber = class {
|
|
2499
|
+
constructor(parent, config, inject, runtime, getOuterStack) {
|
|
2500
|
+
this.parent = parent;
|
|
2501
|
+
this.inject = inject;
|
|
2502
|
+
this.runtime = runtime;
|
|
2503
|
+
const collect = (dispose) => {
|
|
2504
|
+
this._disposables.push(dispose);
|
|
2505
|
+
};
|
|
2506
|
+
if (runtime) {
|
|
2507
|
+
this.uid = parent.registry.counter;
|
|
2508
|
+
this.ctx = this.context = parent.extend({ fiber: this });
|
|
2509
|
+
const injectEntries = Object.entries(this.inject);
|
|
2510
|
+
if (injectEntries.length) {
|
|
2511
|
+
this.ctx[symbols.intercept] = Object.create(parent[symbols.intercept]);
|
|
2512
|
+
for (const [name2, config2] of injectEntries) {
|
|
2513
|
+
if (isNullable(config2)) continue;
|
|
2514
|
+
this.ctx[symbols.intercept][name2] = config2;
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
this._runner = {
|
|
2518
|
+
epoch: INACTIVE,
|
|
2519
|
+
getOuterStack,
|
|
2520
|
+
execute: () => {
|
|
2521
|
+
if (isConstructor(runtime.callback)) {
|
|
2522
|
+
const instance = new runtime.callback(this.ctx, this.config);
|
|
2523
|
+
for (const hook of instance?.[symbols.initHooks] ?? []) {
|
|
2524
|
+
hook();
|
|
2525
|
+
}
|
|
2526
|
+
return instance?.[symbols.init]?.();
|
|
2527
|
+
} else {
|
|
2528
|
+
return runtime.callback(this.ctx, this.config);
|
|
2529
|
+
}
|
|
2530
|
+
},
|
|
2531
|
+
collect
|
|
2532
|
+
};
|
|
2533
|
+
this.context.emit(this, "internal/plugin");
|
|
2534
|
+
for (const name2 of Object.keys(this.inject)) {
|
|
2535
|
+
this._checkImpl(name2);
|
|
2536
|
+
}
|
|
2537
|
+
this.dispose = parent.fiber.effect(() => {
|
|
2538
|
+
const remove = runtime.fibers.push(this);
|
|
2539
|
+
try {
|
|
2540
|
+
this.config = resolveConfig(runtime, config);
|
|
2541
|
+
this._refresh();
|
|
2542
|
+
} catch (error) {
|
|
2543
|
+
this.ctx.logger.error(error);
|
|
2544
|
+
this._error = error;
|
|
2545
|
+
}
|
|
2546
|
+
return async () => {
|
|
2547
|
+
this.uid = null;
|
|
2548
|
+
this.context.emit(this, "internal/plugin");
|
|
2549
|
+
if (this.ctx.registry.has(runtime.callback)) {
|
|
2550
|
+
remove();
|
|
2551
|
+
if (!runtime.fibers.length) {
|
|
2552
|
+
this.ctx.registry.delete(runtime.callback);
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
this._setEpoch(INACTIVE);
|
|
2556
|
+
while (this.inertia) {
|
|
2557
|
+
await this.inertia;
|
|
2558
|
+
}
|
|
2559
|
+
};
|
|
2560
|
+
}, "ctx.plugin()");
|
|
2561
|
+
} else {
|
|
2562
|
+
this.uid = 0;
|
|
2563
|
+
this.ctx = this.context = parent;
|
|
2564
|
+
this.state = 2 /* ACTIVE */;
|
|
2565
|
+
this.store = /* @__PURE__ */ Object.create(null);
|
|
2566
|
+
this._runner = {
|
|
2567
|
+
epoch: "",
|
|
2568
|
+
getOuterStack,
|
|
2569
|
+
execute: () => {
|
|
2570
|
+
},
|
|
2571
|
+
collect
|
|
2572
|
+
};
|
|
2573
|
+
this.dispose = () => this.restart();
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
parent;
|
|
2577
|
+
inject;
|
|
2578
|
+
runtime;
|
|
2579
|
+
uid;
|
|
2580
|
+
ctx;
|
|
2581
|
+
config;
|
|
2582
|
+
state = 0 /* PENDING */;
|
|
2583
|
+
dispose;
|
|
2584
|
+
store;
|
|
2585
|
+
inertia;
|
|
2586
|
+
_hooks = /* @__PURE__ */ Object.create(null);
|
|
2587
|
+
_disposables = new DisposableList();
|
|
2588
|
+
context;
|
|
2589
|
+
_error = void 0;
|
|
2590
|
+
_runner;
|
|
2591
|
+
_store = /* @__PURE__ */ Object.create(null);
|
|
2592
|
+
_restarting;
|
|
2593
|
+
get name() {
|
|
2594
|
+
if (this.runtime?.name) return this.runtime.name;
|
|
2595
|
+
let fiber = this.parent.fiber;
|
|
2596
|
+
while (fiber !== fiber.parent.fiber) {
|
|
2597
|
+
if (fiber.runtime?.name) return fiber.runtime.name;
|
|
2598
|
+
fiber = fiber.parent.fiber;
|
|
2599
|
+
}
|
|
2600
|
+
return "root";
|
|
2601
|
+
}
|
|
2602
|
+
assertActive() {
|
|
2603
|
+
if (this.uid !== null) return;
|
|
2604
|
+
throw new CordisError("INACTIVE_EFFECT");
|
|
2605
|
+
}
|
|
2606
|
+
_execute(runner) {
|
|
2607
|
+
const oldEpoch = runner.epoch;
|
|
2608
|
+
return composeError((info) => {
|
|
2609
|
+
const safeCollect = (dispose) => {
|
|
2610
|
+
if (typeof dispose === "function") {
|
|
2611
|
+
runner.collect(dispose);
|
|
2612
|
+
} else if (!isNullable(dispose)) {
|
|
2613
|
+
throw new TypeError("Invalid effect");
|
|
2614
|
+
}
|
|
2615
|
+
};
|
|
2616
|
+
const effect = runner.execute.call(this);
|
|
2617
|
+
if (typeof effect === "function") {
|
|
2618
|
+
return runner.collect(effect);
|
|
2619
|
+
} else if (isNullable(effect)) {
|
|
2620
|
+
return;
|
|
2621
|
+
} else if (!isObject(effect)) {
|
|
2622
|
+
throw new TypeError("Invalid effect");
|
|
2623
|
+
} else if ("then" in effect) {
|
|
2624
|
+
return effect.then(safeCollect);
|
|
2625
|
+
} else if (Symbol.iterator in effect) {
|
|
2626
|
+
info.error = new Error();
|
|
2627
|
+
const iter = effect[Symbol.iterator]();
|
|
2628
|
+
while (true) {
|
|
2629
|
+
const result = iter.next();
|
|
2630
|
+
safeCollect(result.value);
|
|
2631
|
+
if (result.done) return;
|
|
2632
|
+
}
|
|
2633
|
+
} else if (Symbol.asyncIterator in effect) {
|
|
2634
|
+
const iter = effect[Symbol.asyncIterator]();
|
|
2635
|
+
return (async () => {
|
|
2636
|
+
await Promise.resolve();
|
|
2637
|
+
info.error = new Error();
|
|
2638
|
+
while (true) {
|
|
2639
|
+
if (runner.epoch !== oldEpoch) return;
|
|
2640
|
+
const result = await iter.next();
|
|
2641
|
+
safeCollect(result.value);
|
|
2642
|
+
if (result.done) return;
|
|
2643
|
+
}
|
|
2644
|
+
})();
|
|
2645
|
+
} else {
|
|
2646
|
+
throw new TypeError("Invalid effect");
|
|
2647
|
+
}
|
|
2648
|
+
}, runner.getOuterStack);
|
|
2649
|
+
}
|
|
2650
|
+
effect(execute, label = "anonymous") {
|
|
2651
|
+
this.assertActive();
|
|
2652
|
+
const disposables = [];
|
|
2653
|
+
const dispose = () => {
|
|
2654
|
+
let task2;
|
|
2655
|
+
for (const dispose2 of disposables.splice(0).reverse()) {
|
|
2656
|
+
if (task2) {
|
|
2657
|
+
task2 = task2.then(dispose2);
|
|
2658
|
+
} else {
|
|
2659
|
+
const result = dispose2();
|
|
2660
|
+
if (isObject(result) && "then" in result) {
|
|
2661
|
+
task2 = result;
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
return task2;
|
|
2666
|
+
};
|
|
2667
|
+
const meta = { label, children: [] };
|
|
2668
|
+
const runner = {
|
|
2669
|
+
execute,
|
|
2670
|
+
epoch: true,
|
|
2671
|
+
collect: (dispose2) => {
|
|
2672
|
+
disposables.push(dispose2);
|
|
2673
|
+
this._disposables.delete(dispose2);
|
|
2674
|
+
if (dispose2[symbols.effect]) {
|
|
2675
|
+
meta.children.push(dispose2[symbols.effect]);
|
|
2676
|
+
}
|
|
2677
|
+
},
|
|
2678
|
+
getOuterStack: buildOuterStack()
|
|
2679
|
+
};
|
|
2680
|
+
let task;
|
|
2681
|
+
try {
|
|
2682
|
+
task = this._execute(runner);
|
|
2683
|
+
} catch (reason) {
|
|
2684
|
+
dispose();
|
|
2685
|
+
throw reason;
|
|
2686
|
+
}
|
|
2687
|
+
task?.catch(dispose).catch((error) => this.ctx.logger.error(error));
|
|
2688
|
+
const wrapper = Object.defineProperty(() => {
|
|
2689
|
+
if (!runner.epoch) return;
|
|
2690
|
+
runner.epoch = false;
|
|
2691
|
+
return task ? task.then(dispose) : dispose();
|
|
2692
|
+
}, symbols.effect, { value: meta });
|
|
2693
|
+
const disposeAsync = () => {
|
|
2694
|
+
if (!runner.epoch) return;
|
|
2695
|
+
runner.epoch = false;
|
|
2696
|
+
return dispose();
|
|
2697
|
+
};
|
|
2698
|
+
wrapper.then = async (onFulfilled, onRejected) => {
|
|
2699
|
+
return Promise.resolve(task).then(() => disposeAsync).then(onFulfilled, onRejected);
|
|
2700
|
+
};
|
|
2701
|
+
disposables.push(this._disposables.push(wrapper));
|
|
2702
|
+
return wrapper;
|
|
2703
|
+
}
|
|
2704
|
+
getEffects() {
|
|
2705
|
+
return [...this._disposables].map((dispose) => dispose[symbols.effect]).filter(Boolean);
|
|
2706
|
+
}
|
|
2707
|
+
_getState() {
|
|
2708
|
+
if (this.uid === null) return 4 /* DISPOSED */;
|
|
2709
|
+
if (this._error) return 3 /* FAILED */;
|
|
2710
|
+
if (this._runner.epoch !== INACTIVE) return 2 /* ACTIVE */;
|
|
2711
|
+
return 0 /* PENDING */;
|
|
2712
|
+
}
|
|
2713
|
+
_updateState(callback) {
|
|
2714
|
+
const oldState = this.state;
|
|
2715
|
+
this.state = callback?.() ?? this._getState();
|
|
2716
|
+
if (oldState === this.state) return;
|
|
2717
|
+
this.context.emit(this, "internal/status", oldState);
|
|
2718
|
+
if (oldState !== 2 /* ACTIVE */ && this.state !== 2 /* ACTIVE */) return;
|
|
2719
|
+
for (const key of Reflect.ownKeys(this.ctx.reflect.store)) {
|
|
2720
|
+
const impl = this.ctx.reflect.store[key];
|
|
2721
|
+
if (!impl) continue;
|
|
2722
|
+
if (impl.fiber !== this) continue;
|
|
2723
|
+
this.ctx.reflect.notify([impl.name]);
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
_checkImpl(name2) {
|
|
2727
|
+
const impl = this.ctx.reflect._getImpl(name2, true);
|
|
2728
|
+
if (!impl) return delete this._store[name2];
|
|
2729
|
+
try {
|
|
2730
|
+
if (impl.check && !impl.check.call(getTraceable(this.ctx, impl.value))) {
|
|
2731
|
+
return delete this._store[name2];
|
|
2732
|
+
}
|
|
2733
|
+
} catch (error) {
|
|
2734
|
+
impl.fiber.ctx.logger.error(error);
|
|
2735
|
+
return delete this._store[name2];
|
|
2736
|
+
}
|
|
2737
|
+
this._store[name2] = impl;
|
|
2738
|
+
}
|
|
2739
|
+
_refresh() {
|
|
2740
|
+
let epoch = "";
|
|
2741
|
+
for (const name2 of Object.keys(this.inject)) {
|
|
2742
|
+
const impl = this._store[name2];
|
|
2743
|
+
if (!impl) {
|
|
2744
|
+
epoch = INACTIVE;
|
|
2745
|
+
break;
|
|
2746
|
+
}
|
|
2747
|
+
epoch += ":" + impl.fiber.uid;
|
|
2748
|
+
}
|
|
2749
|
+
this._setEpoch(epoch);
|
|
2750
|
+
}
|
|
2751
|
+
_setEpoch(epoch) {
|
|
2752
|
+
const oldEpoch = this._runner.epoch;
|
|
2753
|
+
if (epoch === oldEpoch) return;
|
|
2754
|
+
this._runner.epoch = epoch;
|
|
2755
|
+
if (this.inertia) return;
|
|
2756
|
+
this._updateState(() => {
|
|
2757
|
+
if (epoch !== INACTIVE && oldEpoch === INACTIVE) {
|
|
2758
|
+
this.inertia = this._reload();
|
|
2759
|
+
return 1 /* LOADING */;
|
|
2760
|
+
} else {
|
|
2761
|
+
this.inertia = this._unload();
|
|
2762
|
+
return 5 /* UNLOADING */;
|
|
2763
|
+
}
|
|
2764
|
+
});
|
|
2765
|
+
}
|
|
2766
|
+
async _reload() {
|
|
2767
|
+
this.store = { ...this._store };
|
|
2768
|
+
const oldEpoch = this._runner.epoch;
|
|
2769
|
+
try {
|
|
2770
|
+
await Promise.resolve();
|
|
2771
|
+
await this._execute(this._runner);
|
|
2772
|
+
} catch (reason) {
|
|
2773
|
+
this.ctx.logger.error(reason);
|
|
2774
|
+
this._error = reason;
|
|
2775
|
+
this._runner.epoch = INACTIVE;
|
|
2776
|
+
}
|
|
2777
|
+
this._updateState(() => {
|
|
2778
|
+
if (this._runner.epoch === oldEpoch) {
|
|
2779
|
+
this.inertia = void 0;
|
|
2780
|
+
} else {
|
|
2781
|
+
this.inertia = this._unload();
|
|
2782
|
+
return 5 /* UNLOADING */;
|
|
2783
|
+
}
|
|
2784
|
+
});
|
|
2785
|
+
}
|
|
2786
|
+
async _unload() {
|
|
2787
|
+
await Promise.all(this._disposables.clear().map(async (dispose) => {
|
|
2788
|
+
try {
|
|
2789
|
+
await composeError(async (info) => {
|
|
2790
|
+
await Promise.resolve();
|
|
2791
|
+
info.error = new Error();
|
|
2792
|
+
await dispose();
|
|
2793
|
+
}, this._runner.getOuterStack);
|
|
2794
|
+
} catch (reason) {
|
|
2795
|
+
this.ctx.logger.error(reason);
|
|
2796
|
+
}
|
|
2797
|
+
}));
|
|
2798
|
+
this.store = void 0;
|
|
2799
|
+
this._updateState(() => {
|
|
2800
|
+
if (this._runner.epoch === INACTIVE) {
|
|
2801
|
+
this.inertia = void 0;
|
|
2802
|
+
} else {
|
|
2803
|
+
this.inertia = this._reload();
|
|
2804
|
+
return 1 /* LOADING */;
|
|
2805
|
+
}
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
async await() {
|
|
2809
|
+
while (this.inertia || this._restarting) {
|
|
2810
|
+
await Promise.all([this.inertia, this._restarting].filter((task) => !!task));
|
|
2811
|
+
}
|
|
2812
|
+
if (this._error) throw this._error;
|
|
2813
|
+
return this;
|
|
2814
|
+
}
|
|
2815
|
+
async restart() {
|
|
2816
|
+
const fiber = this.ctx.fiber;
|
|
2817
|
+
fiber.assertActive();
|
|
2818
|
+
if (fiber._restarting) return fiber._restarting.then(() => void 0);
|
|
2819
|
+
let resolve2;
|
|
2820
|
+
const restarting = new Promise((resolvePromise) => {
|
|
2821
|
+
resolve2 = resolvePromise;
|
|
2822
|
+
});
|
|
2823
|
+
fiber._restarting = restarting;
|
|
2824
|
+
try {
|
|
2825
|
+
await this._runRestart(fiber);
|
|
2826
|
+
} finally {
|
|
2827
|
+
fiber._restarting = void 0;
|
|
2828
|
+
resolve2();
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
async _runRestart(fiber) {
|
|
2832
|
+
if (fiber.inertia) {
|
|
2833
|
+
fiber._setEpoch(INACTIVE);
|
|
2834
|
+
while (fiber.inertia) await fiber.inertia;
|
|
2835
|
+
}
|
|
2836
|
+
fiber._setEpoch(INACTIVE);
|
|
2837
|
+
fiber._refresh();
|
|
2838
|
+
while (fiber.inertia) await fiber.inertia;
|
|
2839
|
+
}
|
|
2840
|
+
update(config, noSave = false) {
|
|
2841
|
+
const fiber = this.ctx.fiber;
|
|
2842
|
+
fiber.assertActive();
|
|
2843
|
+
config = resolveConfig(fiber.runtime, config);
|
|
2844
|
+
fiber.context.waterfall(fiber.context, "internal/update", config, noSave, () => {
|
|
2845
|
+
fiber.config = config;
|
|
2846
|
+
fiber._error = void 0;
|
|
2847
|
+
return fiber.restart();
|
|
2848
|
+
});
|
|
2849
|
+
}
|
|
2850
|
+
};
|
|
2851
|
+
|
|
2852
|
+
// packages/core/src/logger.ts
|
|
2853
|
+
var Logger = class {
|
|
2854
|
+
constructor(options, service) {
|
|
2855
|
+
this.service = service;
|
|
2856
|
+
this.name = options.name;
|
|
2857
|
+
this.level = options.level;
|
|
2858
|
+
this.error = this._method("error");
|
|
2859
|
+
this.info = this._method("info");
|
|
2860
|
+
this.warn = this._method("warn");
|
|
2861
|
+
this.debug = this._method("debug");
|
|
2862
|
+
}
|
|
2863
|
+
service;
|
|
2864
|
+
name;
|
|
2865
|
+
level;
|
|
2866
|
+
error;
|
|
2867
|
+
info;
|
|
2868
|
+
warn;
|
|
2869
|
+
debug;
|
|
2870
|
+
_method(type) {
|
|
2871
|
+
return (...args) => this.service._log({ name: this.name, type, args });
|
|
2872
|
+
}
|
|
2873
|
+
};
|
|
2874
|
+
var LoggerService = class {
|
|
2875
|
+
buffer = [];
|
|
2876
|
+
ctx;
|
|
2877
|
+
_snMessage = 0;
|
|
2878
|
+
_snExporter = 0;
|
|
2879
|
+
exporters = /* @__PURE__ */ new Map();
|
|
2880
|
+
constructor(ctx) {
|
|
2881
|
+
const tracker = {
|
|
2882
|
+
property: "ctx",
|
|
2883
|
+
noShadow: true
|
|
2884
|
+
};
|
|
2885
|
+
const self = createCallable("logger", joinPrototype(Object.getPrototypeOf(this), Function.prototype), tracker);
|
|
2886
|
+
Object.assign(self, this);
|
|
2887
|
+
self.ctx = ctx;
|
|
2888
|
+
Object.defineProperty(self, symbols.tracker, { value: tracker });
|
|
2889
|
+
self.exporter({
|
|
2890
|
+
export: (message) => {
|
|
2891
|
+
self.buffer.push(message);
|
|
2892
|
+
}
|
|
2893
|
+
});
|
|
2894
|
+
ctx.reflect.provide("logger", self);
|
|
2895
|
+
return self;
|
|
2896
|
+
}
|
|
2897
|
+
exporter(exporter) {
|
|
2898
|
+
return this.ctx.fiber.effect(() => {
|
|
2899
|
+
const id = ++this._snExporter;
|
|
2900
|
+
this.exporters.set(id, exporter);
|
|
2901
|
+
return () => this.exporters.delete(id);
|
|
2902
|
+
}, "ctx.logger.exporter()");
|
|
2903
|
+
}
|
|
2904
|
+
[symbols.invoke](name2) {
|
|
2905
|
+
const caller = this[symbols.caller];
|
|
2906
|
+
const fiber = (caller ?? this.ctx).fiber;
|
|
2907
|
+
return new Logger({
|
|
2908
|
+
name: name2 ?? fiber.name
|
|
2909
|
+
}, this);
|
|
2910
|
+
}
|
|
2911
|
+
_log(message) {
|
|
2912
|
+
const sn = ++this._snMessage;
|
|
2913
|
+
const ts = Date.now();
|
|
2914
|
+
for (const exporter of this.exporters.values()) {
|
|
2915
|
+
if (exporter.level != null && exporter.level < 0) continue;
|
|
2916
|
+
exporter.export({ sn, ts, ...message });
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
error(...args) {
|
|
2920
|
+
return this().error(...args);
|
|
2921
|
+
}
|
|
2922
|
+
info(...args) {
|
|
2923
|
+
return this().info(...args);
|
|
2924
|
+
}
|
|
2925
|
+
warn(...args) {
|
|
2926
|
+
return this().warn(...args);
|
|
2927
|
+
}
|
|
2928
|
+
debug(...args) {
|
|
2929
|
+
return this().debug(...args);
|
|
2930
|
+
}
|
|
2931
|
+
};
|
|
2932
|
+
|
|
2933
|
+
// packages/core/src/reflect.ts
|
|
2934
|
+
function enhanceError(error) {
|
|
2935
|
+
const lines = error.stack.split("\n");
|
|
2936
|
+
lines.splice(0, 2, `Error: ${error.message}`);
|
|
2937
|
+
error.stack = lines.join("\n");
|
|
2938
|
+
return error;
|
|
2939
|
+
}
|
|
2940
|
+
var RESERVED_WORDS = ["prototype", "then"];
|
|
2941
|
+
function isSpecialProperty(prop) {
|
|
2942
|
+
return typeof prop === "symbol" || RESERVED_WORDS.includes(prop) || parseInt(prop).toString() === prop || prop.startsWith("_");
|
|
2943
|
+
}
|
|
2944
|
+
var ReflectService = class {
|
|
2945
|
+
constructor(ctx) {
|
|
2946
|
+
this.ctx = ctx;
|
|
2947
|
+
Object.defineProperty(this, symbols.tracker, {
|
|
2948
|
+
value: { property: "ctx", noShadow: true }
|
|
2949
|
+
});
|
|
2950
|
+
this.mixin("reflect", ["get", "set", "provide", "accessor", "mixin"]);
|
|
2951
|
+
this.mixin("fiber", ["runtime", "effect"]);
|
|
2952
|
+
this.mixin("registry", ["inject", "plugin"]);
|
|
2953
|
+
this.mixin("events", [
|
|
2954
|
+
"on",
|
|
2955
|
+
"once",
|
|
2956
|
+
"parallel",
|
|
2957
|
+
"emit",
|
|
2958
|
+
"serial",
|
|
2959
|
+
"bail",
|
|
2960
|
+
"waterfall",
|
|
2961
|
+
"waterfallAsync"
|
|
2962
|
+
]);
|
|
2963
|
+
}
|
|
2964
|
+
ctx;
|
|
2965
|
+
static handler = {
|
|
2966
|
+
get: (target, prop, ctx) => {
|
|
2967
|
+
if (isSpecialProperty(prop)) {
|
|
2968
|
+
return Reflect.get(target, prop, ctx);
|
|
2969
|
+
}
|
|
2970
|
+
if (Reflect.has(target, prop)) {
|
|
2971
|
+
return getTraceable(ctx, Reflect.get(target, prop, ctx));
|
|
2972
|
+
}
|
|
2973
|
+
const error = new Error(`cannot get property "${String(prop)}" without inject`);
|
|
2974
|
+
try {
|
|
2975
|
+
const def = target.reflect.props[prop];
|
|
2976
|
+
if (def?.type === "accessor") {
|
|
2977
|
+
return def.get.call(ctx, ctx[symbols.receiver], error);
|
|
2978
|
+
}
|
|
2979
|
+
if (!ctx.fiber.runtime) return ctx.reflect.get(prop, false);
|
|
2980
|
+
return ctx.events.waterfall(ctx, "internal/get", prop, error, () => {
|
|
2981
|
+
const key = target[symbols.isolate][prop];
|
|
2982
|
+
let fiber = (ctx[symbols.shadow] ?? ctx).fiber;
|
|
2983
|
+
while (true) {
|
|
2984
|
+
const impl = fiber.store?.[prop];
|
|
2985
|
+
if (impl) return getTraceable(ctx, impl.value);
|
|
2986
|
+
if (prop in fiber.inject) {
|
|
2987
|
+
error.message = `cannot get required service "${String(prop)}" in inactive context`;
|
|
2988
|
+
throw error;
|
|
2989
|
+
}
|
|
2990
|
+
if (!fiber.runtime) throw error;
|
|
2991
|
+
if (fiber.parent[symbols.isolate][prop] !== key) throw error;
|
|
2992
|
+
fiber = fiber.parent.fiber;
|
|
2993
|
+
}
|
|
2994
|
+
});
|
|
2995
|
+
} catch (e) {
|
|
2996
|
+
throw e === error ? enhanceError(e) : e;
|
|
2997
|
+
}
|
|
2998
|
+
},
|
|
2999
|
+
set: (target, prop, value, ctx) => {
|
|
3000
|
+
if (isSpecialProperty(prop)) {
|
|
3001
|
+
return Reflect.set(target, prop, value, ctx);
|
|
3002
|
+
}
|
|
3003
|
+
const error = new Error(`cannot set property "${String(prop)}" without provide`);
|
|
3004
|
+
const def = target.reflect.props[prop];
|
|
3005
|
+
try {
|
|
3006
|
+
if (def?.type === "accessor") {
|
|
3007
|
+
if (!def.set) return false;
|
|
3008
|
+
return def.set.call(ctx, value, ctx[symbols.receiver], error);
|
|
3009
|
+
}
|
|
3010
|
+
if (!def && !ctx.fiber.runtime) {
|
|
3011
|
+
return Reflect.set(target, prop, value, ctx);
|
|
3012
|
+
}
|
|
3013
|
+
return ctx.events.waterfall(ctx, "internal/set", prop, value, error, () => {
|
|
3014
|
+
if (!def) throw error;
|
|
3015
|
+
return ctx.reflect.set(prop, value);
|
|
3016
|
+
});
|
|
3017
|
+
} catch (e) {
|
|
3018
|
+
throw e === error ? enhanceError(e) : e;
|
|
3019
|
+
}
|
|
3020
|
+
},
|
|
3021
|
+
has: (target, prop) => {
|
|
3022
|
+
if (isSpecialProperty(prop)) {
|
|
3023
|
+
return Reflect.has(target, prop);
|
|
3024
|
+
}
|
|
3025
|
+
if (Reflect.has(target, prop)) return true;
|
|
3026
|
+
return !!target.reflect.props[prop];
|
|
3027
|
+
}
|
|
3028
|
+
};
|
|
3029
|
+
store = /* @__PURE__ */ Object.create(null);
|
|
3030
|
+
props = /* @__PURE__ */ Object.create(null);
|
|
3031
|
+
get(name2, strict = true) {
|
|
3032
|
+
return getTraceable(this.ctx, this._getImpl(name2, strict)?.value);
|
|
3033
|
+
}
|
|
3034
|
+
_getImpl(name2, strict = true) {
|
|
3035
|
+
const key = this.ctx[symbols.isolate][name2];
|
|
3036
|
+
const impl = key && this.store[key];
|
|
3037
|
+
if (!impl) return;
|
|
3038
|
+
if (strict && impl.fiber.state !== 2 /* ACTIVE */) return;
|
|
3039
|
+
return impl;
|
|
3040
|
+
}
|
|
3041
|
+
set(name2, value) {
|
|
3042
|
+
const key = this.ctx[symbols.isolate][name2];
|
|
3043
|
+
const impl = key && this.store[key];
|
|
3044
|
+
if (!impl) {
|
|
3045
|
+
throw new Error(`cannot set property "${name2}" without provide`);
|
|
3046
|
+
}
|
|
3047
|
+
if (impl.fiber !== this.ctx.fiber) {
|
|
3048
|
+
throw new Error(`cannot set property "${name2}" in multiple fibers`);
|
|
3049
|
+
}
|
|
3050
|
+
impl.value = value;
|
|
3051
|
+
return true;
|
|
3052
|
+
}
|
|
3053
|
+
provide(name2, value, check) {
|
|
3054
|
+
return this.ctx.fiber.effect(() => {
|
|
3055
|
+
if (!this.props[name2]) {
|
|
3056
|
+
this.props[name2] = { type: "service" };
|
|
3057
|
+
} else if (this.props[name2].type !== "service") {
|
|
3058
|
+
throw new Error(`property "${name2}" is already declared as ${this.props[name2].type}`);
|
|
3059
|
+
}
|
|
3060
|
+
this.props[name2] = { type: "service" };
|
|
3061
|
+
this.ctx.root[symbols.isolate][name2] ??= Symbol(name2);
|
|
3062
|
+
const key = this.ctx[symbols.isolate][name2];
|
|
3063
|
+
const impl = {
|
|
3064
|
+
name: name2,
|
|
3065
|
+
value,
|
|
3066
|
+
fiber: this.ctx.fiber,
|
|
3067
|
+
...check ? { check } : {}
|
|
3068
|
+
};
|
|
3069
|
+
if (key && this.store[key]) {
|
|
3070
|
+
throw new Error(`service "${name2}" has been registered at <${this.store[key].fiber.name}>`);
|
|
3071
|
+
}
|
|
3072
|
+
this.store[key] = impl;
|
|
3073
|
+
this.ctx.fiber.store[name2] = impl;
|
|
3074
|
+
if (this.ctx.fiber.state === 2 /* ACTIVE */) {
|
|
3075
|
+
this.notify([name2]);
|
|
3076
|
+
}
|
|
3077
|
+
return async () => {
|
|
3078
|
+
delete this.store[key];
|
|
3079
|
+
const fibers = this.notify([name2]);
|
|
3080
|
+
await Promise.allSettled(fibers.map((fiber) => fiber.await()));
|
|
3081
|
+
delete this.ctx.fiber.store[name2];
|
|
3082
|
+
};
|
|
3083
|
+
}, `ctx.provide(${JSON.stringify(name2)})`);
|
|
3084
|
+
}
|
|
3085
|
+
notify(names, filter = (ctx, name2) => ctx[symbols.isolate][name2] === this.ctx[symbols.isolate][name2]) {
|
|
3086
|
+
const fibers = [];
|
|
3087
|
+
for (const runtime of this.ctx.registry.values()) {
|
|
3088
|
+
for (const fiber of runtime.fibers) {
|
|
3089
|
+
let hasUpdate = false;
|
|
3090
|
+
for (const name2 of names) {
|
|
3091
|
+
if (!(name2 in fiber.inject)) continue;
|
|
3092
|
+
if (!filter(fiber.ctx, name2)) continue;
|
|
3093
|
+
hasUpdate = true;
|
|
3094
|
+
fiber._checkImpl(name2);
|
|
3095
|
+
}
|
|
3096
|
+
if (!hasUpdate) continue;
|
|
3097
|
+
fiber._refresh();
|
|
3098
|
+
fibers.push(fiber);
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
for (const name2 of names) {
|
|
3102
|
+
const self = Object.create(this.ctx);
|
|
3103
|
+
self[symbols.filter] = (target) => filter(target, name2);
|
|
3104
|
+
this.ctx.events.emit(self, "internal/service", name2, this._getImpl(name2, false)?.value);
|
|
3105
|
+
}
|
|
3106
|
+
return fibers;
|
|
3107
|
+
}
|
|
3108
|
+
accessor(name2, options) {
|
|
3109
|
+
return this.ctx.fiber.effect(() => {
|
|
3110
|
+
if (name2 in this.props) {
|
|
3111
|
+
throw new Error(`property "${name2}" is already declared as ${this.props[name2].type}`);
|
|
3112
|
+
}
|
|
3113
|
+
this.props[name2] = { type: "accessor", ...options };
|
|
3114
|
+
return () => delete this.props[name2];
|
|
3115
|
+
}, `ctx.accessor(${JSON.stringify(name2)})`);
|
|
3116
|
+
}
|
|
3117
|
+
mixin(source, mixins) {
|
|
3118
|
+
return this.ctx.fiber.effect(() => {
|
|
3119
|
+
const entries = Array.isArray(mixins) ? mixins.map((key) => [key, key]) : Object.entries(mixins);
|
|
3120
|
+
const getTarget = (target) => target[source];
|
|
3121
|
+
return entries.map(([key, value]) => {
|
|
3122
|
+
return this.accessor(value, {
|
|
3123
|
+
get(receiver) {
|
|
3124
|
+
const service = getTarget(this);
|
|
3125
|
+
if (service == null) return service;
|
|
3126
|
+
const mixin = receiver ? withProps(receiver, service) : service;
|
|
3127
|
+
const result = Reflect.get(service, key, mixin);
|
|
3128
|
+
if (typeof result !== "function") return result;
|
|
3129
|
+
return result.bind(mixin ?? service);
|
|
3130
|
+
},
|
|
3131
|
+
set(value2, receiver) {
|
|
3132
|
+
const service = getTarget(this);
|
|
3133
|
+
const mixin = receiver ? withProps(receiver, service) : service;
|
|
3134
|
+
return Reflect.set(service, key, value2, mixin);
|
|
3135
|
+
}
|
|
3136
|
+
});
|
|
3137
|
+
});
|
|
3138
|
+
}, `ctx.mixin(${JSON.stringify(source)})`);
|
|
3139
|
+
}
|
|
3140
|
+
trace(value) {
|
|
3141
|
+
return getTraceable(this.ctx, value);
|
|
3142
|
+
}
|
|
3143
|
+
bind(callback) {
|
|
3144
|
+
return new Proxy(callback, {
|
|
3145
|
+
apply: (target, thisArg, args) => {
|
|
3146
|
+
return Reflect.apply(target, this.trace(thisArg), args.map((arg) => this.trace(arg)));
|
|
3147
|
+
},
|
|
3148
|
+
construct: (target, args, newTarget) => {
|
|
3149
|
+
return Reflect.construct(target, args.map((arg) => this.trace(arg)), newTarget);
|
|
3150
|
+
}
|
|
3151
|
+
});
|
|
3152
|
+
}
|
|
3153
|
+
};
|
|
3154
|
+
|
|
3155
|
+
// packages/core/src/registry.ts
|
|
3156
|
+
function isApplicable(object) {
|
|
3157
|
+
return object && typeof object === "object" && typeof object.apply === "function";
|
|
3158
|
+
}
|
|
3159
|
+
function resolveInject(inject, result = /* @__PURE__ */ Object.create(null)) {
|
|
3160
|
+
if (!inject) return result;
|
|
3161
|
+
if (Array.isArray(inject)) {
|
|
3162
|
+
for (const name2 of inject) {
|
|
3163
|
+
result[name2] = null;
|
|
3164
|
+
}
|
|
3165
|
+
} else if (Reflect.has(inject, symbols.checkProto)) {
|
|
3166
|
+
Object.assign(result, resolveInject(Object.getPrototypeOf(inject)));
|
|
3167
|
+
for (const name2 of Object.keys(inject)) {
|
|
3168
|
+
result[name2] = inject[name2] ?? null;
|
|
3169
|
+
}
|
|
3170
|
+
} else {
|
|
3171
|
+
for (const name2 of Object.keys(inject)) {
|
|
3172
|
+
result[name2] = inject[name2] ?? null;
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
return result;
|
|
3176
|
+
}
|
|
3177
|
+
var RegistryService = class {
|
|
3178
|
+
constructor(ctx) {
|
|
3179
|
+
this.ctx = ctx;
|
|
3180
|
+
Object.defineProperty(this, symbols.tracker, {
|
|
3181
|
+
value: { property: "ctx", noShadow: true }
|
|
3182
|
+
});
|
|
3183
|
+
}
|
|
3184
|
+
ctx;
|
|
3185
|
+
_counter = 0;
|
|
3186
|
+
_internal = /* @__PURE__ */ new Map();
|
|
3187
|
+
get counter() {
|
|
3188
|
+
return ++this._counter;
|
|
3189
|
+
}
|
|
3190
|
+
get size() {
|
|
3191
|
+
return this._internal.size;
|
|
3192
|
+
}
|
|
3193
|
+
resolve(plugin) {
|
|
3194
|
+
try {
|
|
3195
|
+
if (typeof plugin === "function") return plugin;
|
|
3196
|
+
if (isApplicable(plugin)) return plugin.apply;
|
|
3197
|
+
} catch {
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
get(plugin) {
|
|
3201
|
+
const key = this.resolve(plugin);
|
|
3202
|
+
return key && this._internal.get(key);
|
|
3203
|
+
}
|
|
3204
|
+
has(plugin) {
|
|
3205
|
+
const key = this.resolve(plugin);
|
|
3206
|
+
return !!key && this._internal.has(key);
|
|
3207
|
+
}
|
|
3208
|
+
delete(plugin) {
|
|
3209
|
+
const key = this.resolve(plugin);
|
|
3210
|
+
const runtime = key && this._internal.get(key);
|
|
3211
|
+
if (!runtime) return;
|
|
3212
|
+
this._internal.delete(key);
|
|
3213
|
+
for (const fiber of [...runtime.fibers]) {
|
|
3214
|
+
fiber.dispose();
|
|
3215
|
+
}
|
|
3216
|
+
return runtime;
|
|
3217
|
+
}
|
|
3218
|
+
keys() {
|
|
3219
|
+
return this._internal.keys();
|
|
3220
|
+
}
|
|
3221
|
+
values() {
|
|
3222
|
+
return this._internal.values();
|
|
3223
|
+
}
|
|
3224
|
+
entries() {
|
|
3225
|
+
return this._internal.entries();
|
|
3226
|
+
}
|
|
3227
|
+
forEach(callback) {
|
|
3228
|
+
return this._internal.forEach(callback);
|
|
3229
|
+
}
|
|
3230
|
+
inject(inject, callback) {
|
|
3231
|
+
const name2 = callback.name || void 0;
|
|
3232
|
+
return this.plugin(Object.assign(
|
|
3233
|
+
{ inject, apply: callback },
|
|
3234
|
+
name2 ? { name: name2 } : {}
|
|
3235
|
+
));
|
|
3236
|
+
}
|
|
3237
|
+
plugin(plugin, config, getOuterStack = buildOuterStack()) {
|
|
3238
|
+
const callback = this.resolve(plugin);
|
|
3239
|
+
if (!callback) throw new Error('invalid plugin, expect function or object with an "apply" method, received ' + typeof plugin);
|
|
3240
|
+
this.ctx.fiber.assertActive();
|
|
3241
|
+
let runtime = this._internal.get(callback);
|
|
3242
|
+
if (!runtime) {
|
|
3243
|
+
let name2 = plugin.name;
|
|
3244
|
+
if (name2 === "apply") name2 = void 0;
|
|
3245
|
+
runtime = {
|
|
3246
|
+
callback,
|
|
3247
|
+
fibers: new DisposableList(),
|
|
3248
|
+
...name2 ? { name: name2 } : {},
|
|
3249
|
+
...plugin.Config ? { Config: plugin.Config } : {}
|
|
3250
|
+
};
|
|
3251
|
+
this._internal.set(callback, runtime);
|
|
3252
|
+
}
|
|
3253
|
+
const fiber = new Fiber(this.ctx, config, resolveInject(plugin.inject), runtime, getOuterStack);
|
|
3254
|
+
const wrapped = Object.create(fiber);
|
|
3255
|
+
wrapped.then = (onFulfilled, onRejected) => {
|
|
3256
|
+
return fiber.await().then(onFulfilled, onRejected);
|
|
3257
|
+
};
|
|
3258
|
+
return wrapped;
|
|
3259
|
+
}
|
|
3260
|
+
};
|
|
3261
|
+
|
|
3262
|
+
// packages/core/src/context.ts
|
|
3263
|
+
var Context = class _Context {
|
|
3264
|
+
static effect = symbols.effect;
|
|
3265
|
+
static filter = symbols.filter;
|
|
3266
|
+
static isolate = symbols.isolate;
|
|
3267
|
+
static intercept = symbols.intercept;
|
|
3268
|
+
static marker = /* @__PURE__ */ Symbol.for("tnega.is");
|
|
3269
|
+
static is(value) {
|
|
3270
|
+
return !!value?.[_Context.marker];
|
|
3271
|
+
}
|
|
3272
|
+
static {
|
|
3273
|
+
_Context.prototype[_Context.marker] = true;
|
|
3274
|
+
}
|
|
3275
|
+
constructor() {
|
|
3276
|
+
this[symbols.isolate] = /* @__PURE__ */ Object.create(null);
|
|
3277
|
+
this[symbols.intercept] = /* @__PURE__ */ Object.create(null);
|
|
3278
|
+
const self = new Proxy(this, ReflectService.handler);
|
|
3279
|
+
this.root = self;
|
|
3280
|
+
this.baseUrl = void 0;
|
|
3281
|
+
this.fiber = new Fiber(self, {}, /* @__PURE__ */ Object.create(null), null, () => []);
|
|
3282
|
+
this.reflect = new ReflectService(self);
|
|
3283
|
+
this.registry = new RegistryService(self);
|
|
3284
|
+
this.events = new EventsService(self);
|
|
3285
|
+
this.logger = new LoggerService(self);
|
|
3286
|
+
this.fiber._disposables.clear();
|
|
3287
|
+
return self;
|
|
3288
|
+
}
|
|
3289
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
3290
|
+
return `Context <${this.fiber.name}>`;
|
|
3291
|
+
}
|
|
3292
|
+
extend(meta = {}) {
|
|
3293
|
+
const shadow = Reflect.getOwnPropertyDescriptor(this, symbols.shadow)?.value;
|
|
3294
|
+
const self = Object.create(getTraceable(this, this));
|
|
3295
|
+
for (const prop of Reflect.ownKeys(meta)) {
|
|
3296
|
+
Object.defineProperty(self, prop, Reflect.getOwnPropertyDescriptor(meta, prop));
|
|
3297
|
+
}
|
|
3298
|
+
if (!shadow) return self;
|
|
3299
|
+
return Object.assign(Object.create(self), { [symbols.shadow]: shadow });
|
|
3300
|
+
}
|
|
3301
|
+
isolate(name2, label) {
|
|
3302
|
+
const shadow = Object.create(this[symbols.isolate]);
|
|
3303
|
+
shadow[name2] = label ?? Symbol(name2);
|
|
3304
|
+
return this.extend({ [symbols.isolate]: shadow });
|
|
3305
|
+
}
|
|
3306
|
+
intercept(name2, config) {
|
|
3307
|
+
const intercept = Object.create(this[symbols.intercept]);
|
|
3308
|
+
intercept[name2] = config;
|
|
3309
|
+
return this.extend({ [symbols.intercept]: intercept });
|
|
3310
|
+
}
|
|
3311
|
+
};
|
|
3312
|
+
|
|
3313
|
+
// packages/core/src/service.ts
|
|
3314
|
+
var Service = class _Service {
|
|
3315
|
+
constructor(ctx, name2) {
|
|
3316
|
+
this.ctx = ctx;
|
|
3317
|
+
name2 ??= this.constructor.provide;
|
|
3318
|
+
const tracker = {
|
|
3319
|
+
associate: name2,
|
|
3320
|
+
property: "ctx"
|
|
3321
|
+
};
|
|
3322
|
+
const self = this[symbols.invoke] ? createCallable(name2, joinPrototype(Object.getPrototypeOf(this), Function.prototype), tracker) : this;
|
|
3323
|
+
self.ctx = ctx;
|
|
3324
|
+
self.name = name2;
|
|
3325
|
+
Object.defineProperty(self, symbols.tracker, { value: tracker });
|
|
3326
|
+
self.ctx.reflect.provide(name2, self, this[symbols.check]);
|
|
3327
|
+
return self;
|
|
3328
|
+
}
|
|
3329
|
+
ctx;
|
|
3330
|
+
static init = symbols.init;
|
|
3331
|
+
static check = symbols.check;
|
|
3332
|
+
static config = symbols.config;
|
|
3333
|
+
static invoke = symbols.invoke;
|
|
3334
|
+
static extend = symbols.extend;
|
|
3335
|
+
static tracker = symbols.tracker;
|
|
3336
|
+
static resolveConfig = symbols.resolveConfig;
|
|
3337
|
+
name;
|
|
3338
|
+
[symbols.filter](ctx) {
|
|
3339
|
+
return ctx[symbols.isolate][this.name] === this.ctx[symbols.isolate][this.name];
|
|
3340
|
+
}
|
|
3341
|
+
[symbols.extend](props) {
|
|
3342
|
+
let self;
|
|
3343
|
+
if (this[_Service.invoke]) {
|
|
3344
|
+
self = createCallable(this.name, this, this[symbols.tracker]);
|
|
3345
|
+
} else {
|
|
3346
|
+
self = Object.create(this);
|
|
3347
|
+
}
|
|
3348
|
+
return Object.assign(self, props);
|
|
3349
|
+
}
|
|
3350
|
+
[symbols.resolveConfig](base, head) {
|
|
3351
|
+
let intercept = this.ctx[symbols.intercept];
|
|
3352
|
+
const configs = [];
|
|
3353
|
+
while (this.name in intercept) {
|
|
3354
|
+
if (Object.hasOwn(intercept, this.name)) {
|
|
3355
|
+
configs.unshift(intercept[this.name]);
|
|
3356
|
+
}
|
|
3357
|
+
intercept = Object.getPrototypeOf(intercept);
|
|
3358
|
+
}
|
|
3359
|
+
if (base) configs.unshift(base);
|
|
3360
|
+
if (head) configs.push(head);
|
|
3361
|
+
if (this["Config"]?.merge) {
|
|
3362
|
+
return this["Config"].merge(...configs);
|
|
3363
|
+
} else {
|
|
3364
|
+
return Object.assign({}, ...configs);
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
static [Symbol.hasInstance](instance) {
|
|
3368
|
+
if (!instance) return false;
|
|
3369
|
+
let constructor = instance.constructor;
|
|
3370
|
+
while (constructor) {
|
|
3371
|
+
constructor = constructor.prototype?.constructor;
|
|
3372
|
+
if (constructor === this) return true;
|
|
3373
|
+
constructor &&= Object.getPrototypeOf(constructor);
|
|
3374
|
+
}
|
|
3375
|
+
return false;
|
|
3376
|
+
}
|
|
3377
|
+
};
|
|
3378
|
+
|
|
3379
|
+
// packages/agent/src/inbox-durable.ts
|
|
3380
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
3381
|
+
function contentOf(input) {
|
|
3382
|
+
return input.text ?? "";
|
|
3383
|
+
}
|
|
3384
|
+
function payloadOf(input) {
|
|
3385
|
+
return input.content !== void 0 ? input.content : void 0;
|
|
3386
|
+
}
|
|
3387
|
+
var DurableInbox = class _DurableInbox {
|
|
3388
|
+
constructor(_session) {
|
|
3389
|
+
this._session = _session;
|
|
3390
|
+
}
|
|
3391
|
+
_session;
|
|
3392
|
+
_nextTurn = [];
|
|
3393
|
+
_nextStep = [];
|
|
3394
|
+
_operationTail = Promise.resolve();
|
|
3395
|
+
get size() {
|
|
3396
|
+
return this._nextTurn.length + this._nextStep.length;
|
|
3397
|
+
}
|
|
3398
|
+
async insert(input, target = "next-turn") {
|
|
3399
|
+
return this._run(async () => {
|
|
3400
|
+
const message = {
|
|
3401
|
+
id: randomUUID3(),
|
|
3402
|
+
...input.text !== void 0 ? { text: input.text } : {},
|
|
3403
|
+
...input.content !== void 0 ? { content: input.content } : {}
|
|
3404
|
+
};
|
|
3405
|
+
const list = target === "next-step" ? this._nextStep : this._nextTurn;
|
|
3406
|
+
const index = list.length;
|
|
3407
|
+
await this._session.append("agent/inbox/spliced", {
|
|
3408
|
+
target,
|
|
3409
|
+
index,
|
|
3410
|
+
inserted: [{
|
|
3411
|
+
id: message.id,
|
|
3412
|
+
content: contentOf(message),
|
|
3413
|
+
...payloadOf(message) !== void 0 ? { payload: payloadOf(message) } : {}
|
|
3414
|
+
}]
|
|
3415
|
+
});
|
|
3416
|
+
list.push(message);
|
|
3417
|
+
return message;
|
|
3418
|
+
});
|
|
3419
|
+
}
|
|
3420
|
+
async steer(input) {
|
|
3421
|
+
return this._run(async () => {
|
|
3422
|
+
const message = {
|
|
3423
|
+
id: randomUUID3(),
|
|
3424
|
+
...input.text !== void 0 ? { text: input.text } : {},
|
|
3425
|
+
...input.content !== void 0 ? { content: input.content } : {}
|
|
3426
|
+
};
|
|
3427
|
+
await this._session.append("agent/inbox/spliced", {
|
|
3428
|
+
target: "next-step",
|
|
3429
|
+
index: this._nextStep.length,
|
|
3430
|
+
inserted: [{
|
|
3431
|
+
id: message.id,
|
|
3432
|
+
content: contentOf(message),
|
|
3433
|
+
...payloadOf(message) !== void 0 ? { payload: payloadOf(message) } : {},
|
|
3434
|
+
mode: "steer"
|
|
3435
|
+
}]
|
|
3436
|
+
});
|
|
3437
|
+
this._nextStep.push(message);
|
|
3438
|
+
return message;
|
|
3439
|
+
});
|
|
3440
|
+
}
|
|
3441
|
+
async claim() {
|
|
3442
|
+
return this._run(async () => {
|
|
3443
|
+
const steered = this._nextStep[0];
|
|
3444
|
+
if (steered) {
|
|
3445
|
+
await this._session.append("agent/inbox/spliced", {
|
|
3446
|
+
target: "next-step",
|
|
3447
|
+
index: 0,
|
|
3448
|
+
deleteCount: 1
|
|
3449
|
+
});
|
|
3450
|
+
this._nextStep.shift();
|
|
3451
|
+
return steered;
|
|
3452
|
+
}
|
|
3453
|
+
const next = this._nextTurn[0];
|
|
3454
|
+
if (next) {
|
|
3455
|
+
await this._session.append("agent/inbox/spliced", {
|
|
3456
|
+
target: "next-turn",
|
|
3457
|
+
index: 0,
|
|
3458
|
+
deleteCount: 1
|
|
3459
|
+
});
|
|
3460
|
+
this._nextTurn.shift();
|
|
3461
|
+
return next;
|
|
3462
|
+
}
|
|
3463
|
+
return void 0;
|
|
3464
|
+
});
|
|
3465
|
+
}
|
|
3466
|
+
/**
|
|
3467
|
+
* Claim the complete proposed step batch: every pending next-step input plus
|
|
3468
|
+
* one next-turn message at a turn boundary. Returns an empty array when
|
|
3469
|
+
* nothing is pending.
|
|
3470
|
+
*/
|
|
3471
|
+
async claimBatch() {
|
|
3472
|
+
return this._run(async () => {
|
|
3473
|
+
const claimed = [...this._nextStep];
|
|
3474
|
+
const nextTurn = this._nextTurn[0];
|
|
3475
|
+
if (nextTurn) claimed.push(nextTurn);
|
|
3476
|
+
if (!claimed.length) return [];
|
|
3477
|
+
const deleteCounts = { nextStep: this._nextStep.length, nextTurn: nextTurn ? 1 : 0 };
|
|
3478
|
+
await this._session.append("agent/inbox/spliced", { target: "all", deleteCounts });
|
|
3479
|
+
this._nextStep.splice(0, deleteCounts.nextStep);
|
|
3480
|
+
this._nextTurn.splice(0, deleteCounts.nextTurn);
|
|
3481
|
+
return claimed;
|
|
3482
|
+
});
|
|
3483
|
+
}
|
|
3484
|
+
/** Claim every input waiting for the next step, without consuming a turn. */
|
|
3485
|
+
async claimNextStep() {
|
|
3486
|
+
return this._run(async () => {
|
|
3487
|
+
if (!this._nextStep.length) return [];
|
|
3488
|
+
const claimed = [...this._nextStep];
|
|
3489
|
+
await this._session.append("agent/inbox/spliced", {
|
|
3490
|
+
target: "next-step",
|
|
3491
|
+
index: 0,
|
|
3492
|
+
deleteCount: claimed.length
|
|
3493
|
+
});
|
|
3494
|
+
this._nextStep.splice(0, claimed.length);
|
|
3495
|
+
return claimed;
|
|
3496
|
+
});
|
|
3497
|
+
}
|
|
3498
|
+
async clear() {
|
|
3499
|
+
return this._run(async () => {
|
|
3500
|
+
if (!this._nextTurn.length && !this._nextStep.length) return;
|
|
3501
|
+
await this._session.append("agent/inbox/spliced", {
|
|
3502
|
+
target: "all"
|
|
3503
|
+
});
|
|
3504
|
+
this._nextTurn = [];
|
|
3505
|
+
this._nextStep = [];
|
|
3506
|
+
});
|
|
3507
|
+
}
|
|
3508
|
+
/** Insert a message at an explicit target/index boundary. */
|
|
3509
|
+
async insertAt(input, target, index, mode = "followup") {
|
|
3510
|
+
return this._run(async () => {
|
|
3511
|
+
const message = {
|
|
3512
|
+
id: randomUUID3(),
|
|
3513
|
+
...input.text !== void 0 ? { text: input.text } : {},
|
|
3514
|
+
...input.content !== void 0 ? { content: input.content } : {}
|
|
3515
|
+
};
|
|
3516
|
+
const list = target === "next-step" ? this._nextStep : this._nextTurn;
|
|
3517
|
+
const safeIndex = Math.max(0, Math.min(index, list.length));
|
|
3518
|
+
await this._session.append("agent/inbox/spliced", {
|
|
3519
|
+
target,
|
|
3520
|
+
index: safeIndex,
|
|
3521
|
+
inserted: [{
|
|
3522
|
+
id: message.id,
|
|
3523
|
+
content: contentOf(message),
|
|
3524
|
+
...payloadOf(message) !== void 0 ? { payload: payloadOf(message) } : {},
|
|
3525
|
+
mode
|
|
3526
|
+
}]
|
|
3527
|
+
});
|
|
3528
|
+
list.splice(safeIndex, 0, message);
|
|
3529
|
+
return message;
|
|
3530
|
+
});
|
|
3531
|
+
}
|
|
3532
|
+
/**
|
|
3533
|
+
* Replace one pending message by id. The old message is emitted as
|
|
3534
|
+
* discarded and the new one as inserted, matching the DSH inbox contract.
|
|
3535
|
+
*/
|
|
3536
|
+
async replace(messageId, input) {
|
|
3537
|
+
return this._run(async () => {
|
|
3538
|
+
const entry = this._find(messageId);
|
|
3539
|
+
if (!entry) return void 0;
|
|
3540
|
+
const replacement = {
|
|
3541
|
+
id: randomUUID3(),
|
|
3542
|
+
...input.text !== void 0 ? { text: input.text } : {},
|
|
3543
|
+
...input.content !== void 0 ? { content: input.content } : {}
|
|
3544
|
+
};
|
|
3545
|
+
const target = entry.target;
|
|
3546
|
+
const index = entry.index;
|
|
3547
|
+
await this._session.append("agent/inbox/spliced", {
|
|
3548
|
+
target,
|
|
3549
|
+
index,
|
|
3550
|
+
deleteCount: 1,
|
|
3551
|
+
inserted: [{
|
|
3552
|
+
id: replacement.id,
|
|
3553
|
+
content: contentOf(replacement),
|
|
3554
|
+
...payloadOf(replacement) !== void 0 ? { payload: payloadOf(replacement) } : {}
|
|
3555
|
+
}]
|
|
3556
|
+
});
|
|
3557
|
+
entry.list.splice(index, 1, replacement);
|
|
3558
|
+
return replacement;
|
|
3559
|
+
});
|
|
3560
|
+
}
|
|
3561
|
+
/** Remove one pending message by id. */
|
|
3562
|
+
async remove(messageId) {
|
|
3563
|
+
return this._run(async () => {
|
|
3564
|
+
const entry = this._find(messageId);
|
|
3565
|
+
if (!entry) return void 0;
|
|
3566
|
+
await this._session.append("agent/inbox/spliced", {
|
|
3567
|
+
target: entry.target,
|
|
3568
|
+
index: entry.index,
|
|
3569
|
+
deleteCount: 1
|
|
3570
|
+
});
|
|
3571
|
+
entry.list.splice(entry.index, 1);
|
|
3572
|
+
return entry.message;
|
|
3573
|
+
});
|
|
3574
|
+
}
|
|
3575
|
+
/** Return the first pending message by id across both queues. */
|
|
3576
|
+
get(messageId) {
|
|
3577
|
+
return this._find(messageId)?.message;
|
|
3578
|
+
}
|
|
3579
|
+
snapshot() {
|
|
3580
|
+
return {
|
|
3581
|
+
nextTurn: [...this._nextTurn],
|
|
3582
|
+
nextStep: [...this._nextStep]
|
|
3583
|
+
};
|
|
3584
|
+
}
|
|
3585
|
+
/** Keep the entire read → append → apply transition ordered, including claims. */
|
|
3586
|
+
_run(operation) {
|
|
3587
|
+
const result = this._operationTail.then(operation);
|
|
3588
|
+
this._operationTail = result.then(() => void 0, () => void 0);
|
|
3589
|
+
return result;
|
|
3590
|
+
}
|
|
3591
|
+
_find(messageId) {
|
|
3592
|
+
for (const target of ["next-step", "next-turn"]) {
|
|
3593
|
+
const list = target === "next-step" ? this._nextStep : this._nextTurn;
|
|
3594
|
+
const index = list.findIndex((message) => message.id === messageId);
|
|
3595
|
+
if (index >= 0) return { list, target, index, message: list[index] };
|
|
3596
|
+
}
|
|
3597
|
+
return void 0;
|
|
2040
3598
|
}
|
|
2041
3599
|
static async restore(session) {
|
|
2042
3600
|
const inbox = new _DurableInbox(session);
|
|
@@ -2047,6 +3605,11 @@ var DurableInbox = class _DurableInbox {
|
|
|
2047
3605
|
for (const event of events) {
|
|
2048
3606
|
if (event.type !== "agent/inbox/spliced") continue;
|
|
2049
3607
|
const payload = event.payload;
|
|
3608
|
+
if (payload.target === "all") {
|
|
3609
|
+
this._nextTurn.splice(0, payload.deleteCounts?.nextTurn ?? this._nextTurn.length);
|
|
3610
|
+
this._nextStep.splice(0, payload.deleteCounts?.nextStep ?? this._nextStep.length);
|
|
3611
|
+
continue;
|
|
3612
|
+
}
|
|
2050
3613
|
const list = payload.target === "next-step" ? this._nextStep : this._nextTurn;
|
|
2051
3614
|
const count = payload.deleteCount ?? 0;
|
|
2052
3615
|
if (count === Number.POSITIVE_INFINITY) {
|
|
@@ -2076,8 +3639,29 @@ var DurableInbox = class _DurableInbox {
|
|
|
2076
3639
|
};
|
|
2077
3640
|
|
|
2078
3641
|
// packages/agent/src/live.ts
|
|
3642
|
+
function createAgentRuntimeContext(agentCtx) {
|
|
3643
|
+
const runtimeCtx = agentCtx.extend();
|
|
3644
|
+
Object.defineProperty(runtimeCtx, Context.filter, {
|
|
3645
|
+
value: (target) => {
|
|
3646
|
+
const targetScope = target[symbols.isolate].agentScope;
|
|
3647
|
+
let ancestor = agentCtx;
|
|
3648
|
+
while (true) {
|
|
3649
|
+
if (targetScope === ancestor[symbols.isolate].agentScope) return true;
|
|
3650
|
+
if (ancestor.fiber.parent.fiber === ancestor.fiber) return false;
|
|
3651
|
+
ancestor = ancestor.fiber.parent;
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
});
|
|
3655
|
+
const events = agentCtx.events;
|
|
3656
|
+
for (const method of ["emit", "parallel", "serial", "bail", "waterfall", "waterfallAsync"]) {
|
|
3657
|
+
Object.defineProperty(runtimeCtx, method, {
|
|
3658
|
+
value: (...args) => events[method](runtimeCtx, ...args)
|
|
3659
|
+
});
|
|
3660
|
+
}
|
|
3661
|
+
return runtimeCtx;
|
|
3662
|
+
}
|
|
2079
3663
|
var LiveAgentImpl = class {
|
|
2080
|
-
constructor(_ctx, _agentCtx, _service, id, inbox, session, durable, meta, manualStreaming = false) {
|
|
3664
|
+
constructor(_ctx, _agentCtx, _service, id, inbox, session, durable, meta, manualStreaming = false, wakeReserved = false) {
|
|
2081
3665
|
this._ctx = _ctx;
|
|
2082
3666
|
this._agentCtx = _agentCtx;
|
|
2083
3667
|
this._service = _service;
|
|
@@ -2087,6 +3671,7 @@ var LiveAgentImpl = class {
|
|
|
2087
3671
|
this.meta = meta;
|
|
2088
3672
|
this._durable = durable;
|
|
2089
3673
|
this._manualStreaming = manualStreaming;
|
|
3674
|
+
this._wakeReserved = wakeReserved;
|
|
2090
3675
|
}
|
|
2091
3676
|
_ctx;
|
|
2092
3677
|
_agentCtx;
|
|
@@ -2108,8 +3693,9 @@ var LiveAgentImpl = class {
|
|
|
2108
3693
|
_setupDisposers = [];
|
|
2109
3694
|
_scopeClosed = false;
|
|
2110
3695
|
_durable;
|
|
2111
|
-
_agentSystem;
|
|
2112
3696
|
_manualStreaming = false;
|
|
3697
|
+
_wakeReserved = false;
|
|
3698
|
+
_loop;
|
|
2113
3699
|
get agentType() {
|
|
2114
3700
|
return this.meta.agentType;
|
|
2115
3701
|
}
|
|
@@ -2136,13 +3722,41 @@ var LiveAgentImpl = class {
|
|
|
2136
3722
|
return this._ctx;
|
|
2137
3723
|
}
|
|
2138
3724
|
followup(input) {
|
|
2139
|
-
this._send(input, "followup");
|
|
3725
|
+
return this._send(input, "followup");
|
|
3726
|
+
}
|
|
3727
|
+
setLoop(loop) {
|
|
3728
|
+
this._loop = loop;
|
|
3729
|
+
}
|
|
3730
|
+
async _closeCustomTurn(turn, run) {
|
|
3731
|
+
const events = await this.session.read();
|
|
3732
|
+
if (events.some((event) => event.type === "turn/end" && event.payload.turn === turn)) return;
|
|
3733
|
+
const reason = run.finishReason === "length" ? { kind: "max-tokens" } : run.finishReason === "max_steps" ? { kind: "max-steps" } : run.finishReason === "max_turns" ? { kind: "max-turns" } : run.finishReason === "cancelled" ? { kind: "interrupted" } : run.finishReason === "error" ? { kind: "interrupted" } : { kind: "completed" };
|
|
3734
|
+
await this.session.append("turn/end", {
|
|
3735
|
+
turn,
|
|
3736
|
+
finishReason: run.finishReason,
|
|
3737
|
+
reason,
|
|
3738
|
+
...run.output ? { output: run.output } : {},
|
|
3739
|
+
...run.steps.length ? { steps: run.steps.length } : {}
|
|
3740
|
+
});
|
|
3741
|
+
}
|
|
3742
|
+
async _closeFailedCustomTurn(turn, error) {
|
|
3743
|
+
const events = await this.session.read();
|
|
3744
|
+
if (events.some((event) => event.type === "turn/end" && event.payload.turn === turn)) return;
|
|
3745
|
+
const failure = error instanceof Error ? { name: error.name, message: error.message, ...error.stack ? { stack: error.stack } : {} } : { name: "Error", message: String(error) };
|
|
3746
|
+
await this.session.append("turn/end", {
|
|
3747
|
+
turn,
|
|
3748
|
+
finishReason: "error",
|
|
3749
|
+
reason: { kind: "error", error: failure },
|
|
3750
|
+
interrupted: true,
|
|
3751
|
+
error: failure
|
|
3752
|
+
});
|
|
2140
3753
|
}
|
|
2141
3754
|
/** Replace one pending inbox message by durable message id. */
|
|
2142
3755
|
replaceMessage(messageId, input) {
|
|
2143
|
-
this._mutatePending(async () => {
|
|
3756
|
+
return this._mutatePending(async () => {
|
|
2144
3757
|
const previous = this._durable.get(messageId);
|
|
2145
|
-
|
|
3758
|
+
const target = this._findTarget(messageId);
|
|
3759
|
+
if (!previous || !target) return;
|
|
2146
3760
|
const replacement = await this._durable.replace(messageId, {
|
|
2147
3761
|
text: input.text ?? "",
|
|
2148
3762
|
...input.messages !== void 0 || input.context !== void 0 ? { content: input.messages ?? input.context } : {}
|
|
@@ -2153,18 +3767,19 @@ var LiveAgentImpl = class {
|
|
|
2153
3767
|
agent: this,
|
|
2154
3768
|
message: previous
|
|
2155
3769
|
});
|
|
2156
|
-
|
|
3770
|
+
const event = {
|
|
2157
3771
|
id: this.id,
|
|
2158
3772
|
agent: this,
|
|
2159
|
-
target
|
|
3773
|
+
target,
|
|
2160
3774
|
input: replacement,
|
|
2161
3775
|
inboxSeq: this._durable.size
|
|
2162
|
-
}
|
|
3776
|
+
};
|
|
3777
|
+
this._ctx.emit("agent/inbox/inserted", event);
|
|
2163
3778
|
});
|
|
2164
3779
|
}
|
|
2165
3780
|
/** Remove one pending inbox message by durable message id. */
|
|
2166
3781
|
removeMessage(messageId) {
|
|
2167
|
-
this._mutatePending(async () => {
|
|
3782
|
+
return this._mutatePending(async () => {
|
|
2168
3783
|
const removed = await this._durable.remove(messageId);
|
|
2169
3784
|
if (!removed) return;
|
|
2170
3785
|
this._ctx.emit("agent/inbox/discarded", {
|
|
@@ -2175,48 +3790,54 @@ var LiveAgentImpl = class {
|
|
|
2175
3790
|
});
|
|
2176
3791
|
}
|
|
2177
3792
|
steer(input) {
|
|
2178
|
-
this._send(input, "steer");
|
|
3793
|
+
return this._send(input, "steer");
|
|
2179
3794
|
}
|
|
2180
|
-
inject(
|
|
2181
|
-
|
|
2182
|
-
this._agentSystem = value;
|
|
2183
|
-
}
|
|
3795
|
+
inject(input) {
|
|
3796
|
+
return this._send(input, "inject");
|
|
2184
3797
|
}
|
|
2185
3798
|
send(input, options = {}) {
|
|
2186
|
-
this._send(input, options.mode === "steer" ? "steer" : "followup");
|
|
3799
|
+
return this._send(input, options.mode === "steer" ? "steer" : "followup");
|
|
2187
3800
|
}
|
|
2188
3801
|
_send(input, target) {
|
|
2189
|
-
if (this._disposed) throw new Error(`agent disposed: ${this.id}`);
|
|
2190
3802
|
const text = input.text ?? "";
|
|
2191
3803
|
const content = input.messages ?? input.context;
|
|
2192
|
-
const
|
|
2193
|
-
|
|
2194
|
-
this.
|
|
3804
|
+
const steeredAfterAbort = target === "steer" && this._controller?.signal.aborted === true;
|
|
3805
|
+
return this._mutatePending(async () => {
|
|
3806
|
+
const message = target === "followup" ? await this._durable.insert({ text, ...content !== void 0 ? { content } : {} }) : target === "steer" ? steeredAfterAbort ? await this._durable.insert({ text, ...content !== void 0 ? { content } : {} }) : await this._durable.steer({ text, ...content !== void 0 ? { content } : {} }) : await this._durable.insert({ text, ...content !== void 0 ? { content } : {} }, "next-step");
|
|
3807
|
+
if (target !== "inject") this._wakeReserved = true;
|
|
3808
|
+
const event = {
|
|
2195
3809
|
id: this.id,
|
|
3810
|
+
agent: this,
|
|
2196
3811
|
target,
|
|
2197
3812
|
input: message,
|
|
2198
3813
|
inboxSeq: this._durable.size
|
|
2199
|
-
}
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
});
|
|
2203
|
-
this._writeTail = task;
|
|
2204
|
-
this._pendingWrite = task;
|
|
2205
|
-
task.finally(() => {
|
|
2206
|
-
if (this._pendingWrite === task) this._pendingWrite = void 0;
|
|
2207
|
-
queueMicrotask(() => this._wake());
|
|
2208
|
-
});
|
|
3814
|
+
};
|
|
3815
|
+
this._ctx.emit("agent/inbox/inserted", event);
|
|
3816
|
+
}, target !== "inject");
|
|
2209
3817
|
}
|
|
2210
|
-
_mutatePending(task) {
|
|
2211
|
-
if (this._disposed
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
3818
|
+
_mutatePending(task, wakes = false, allowDisposed = false) {
|
|
3819
|
+
if (this._disposed && !allowDisposed) {
|
|
3820
|
+
return Promise.reject(new Error(`agent disposed: ${this.id}`));
|
|
3821
|
+
}
|
|
3822
|
+
const result = this._writeTail.then(task);
|
|
3823
|
+
const recovered = result.catch((error) => {
|
|
3824
|
+
try {
|
|
3825
|
+
this._ctx.emit("agent/error", { id: this.id, error });
|
|
3826
|
+
} catch {
|
|
3827
|
+
}
|
|
2219
3828
|
});
|
|
3829
|
+
this._writeTail = recovered;
|
|
3830
|
+
this._pendingWrite = recovered;
|
|
3831
|
+
void result.then(
|
|
3832
|
+
() => {
|
|
3833
|
+
if (this._pendingWrite === recovered) this._pendingWrite = void 0;
|
|
3834
|
+
if (wakes) queueMicrotask(() => this._wake());
|
|
3835
|
+
},
|
|
3836
|
+
() => {
|
|
3837
|
+
if (this._pendingWrite === recovered) this._pendingWrite = void 0;
|
|
3838
|
+
}
|
|
3839
|
+
);
|
|
3840
|
+
return result;
|
|
2220
3841
|
}
|
|
2221
3842
|
_findTarget(messageId) {
|
|
2222
3843
|
const snapshot = this._durable.snapshot();
|
|
@@ -2226,27 +3847,21 @@ var LiveAgentImpl = class {
|
|
|
2226
3847
|
}
|
|
2227
3848
|
cancel(cause, options = {}) {
|
|
2228
3849
|
if (!options.keepInbox) {
|
|
2229
|
-
|
|
3850
|
+
void this._mutatePending(async () => {
|
|
2230
3851
|
const before = this._durable.snapshot();
|
|
3852
|
+
await this._durable.clear();
|
|
2231
3853
|
for (const message of [...before.nextStep, ...before.nextTurn]) {
|
|
2232
3854
|
this._ctx.emit("agent/inbox/discarded", { id: this.id, message });
|
|
2233
3855
|
}
|
|
2234
|
-
|
|
2235
|
-
}
|
|
2236
|
-
this._ctx.emit("agent/error", { id: this.id, error });
|
|
2237
|
-
});
|
|
2238
|
-
this._writeTail = task;
|
|
2239
|
-
this._pendingWrite = task;
|
|
2240
|
-
task.finally(() => {
|
|
2241
|
-
if (this._pendingWrite === task) this._pendingWrite = void 0;
|
|
2242
|
-
});
|
|
3856
|
+
this._wakeReserved = false;
|
|
3857
|
+
}, false, true);
|
|
2243
3858
|
}
|
|
2244
3859
|
this._controller?.abort(cause);
|
|
2245
3860
|
this._maintenance?.controller.abort(cause);
|
|
2246
3861
|
}
|
|
2247
3862
|
async whenIdle() {
|
|
2248
|
-
while (this._pendingWrite) await this._pendingWrite;
|
|
2249
3863
|
while (true) {
|
|
3864
|
+
while (this._pendingWrite) await this._pendingWrite;
|
|
2250
3865
|
const maintenance = this._maintenance;
|
|
2251
3866
|
if (maintenance) {
|
|
2252
3867
|
await maintenance.promise.catch(() => void 0);
|
|
@@ -2257,7 +3872,7 @@ var LiveAgentImpl = class {
|
|
|
2257
3872
|
await drain.catch(() => void 0);
|
|
2258
3873
|
continue;
|
|
2259
3874
|
}
|
|
2260
|
-
if (!this.
|
|
3875
|
+
if (!this._hasQueuedWork()) break;
|
|
2261
3876
|
await new Promise((resolve2) => setTimeout(resolve2, 0));
|
|
2262
3877
|
}
|
|
2263
3878
|
}
|
|
@@ -2299,6 +3914,7 @@ var LiveAgentImpl = class {
|
|
|
2299
3914
|
this._pendingWrite = void 0;
|
|
2300
3915
|
await writeTail.catch(() => void 0);
|
|
2301
3916
|
}
|
|
3917
|
+
await this.session.close();
|
|
2302
3918
|
this._setStatus("idle");
|
|
2303
3919
|
}
|
|
2304
3920
|
/** Publish the agent lifecycle session-start notification once. */
|
|
@@ -2328,13 +3944,23 @@ var LiveAgentImpl = class {
|
|
|
2328
3944
|
if (this._disposed || this._manualStreaming || this._drainPromise || this._busy || this._maintenanceBusy) return;
|
|
2329
3945
|
const task = this._drainAll();
|
|
2330
3946
|
this._drainPromise = task;
|
|
2331
|
-
task.
|
|
2332
|
-
|
|
2333
|
-
|
|
3947
|
+
void task.then(
|
|
3948
|
+
() => {
|
|
3949
|
+
if (this._drainPromise === task) this._drainPromise = void 0;
|
|
3950
|
+
if (this._hasQueuedWork()) queueMicrotask(() => this._wake());
|
|
3951
|
+
},
|
|
3952
|
+
(error) => {
|
|
3953
|
+
if (this._drainPromise === task) this._drainPromise = void 0;
|
|
3954
|
+
try {
|
|
3955
|
+
this._ctx.emit("agent/error", { id: this.id, agent: this, error });
|
|
3956
|
+
} catch {
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
);
|
|
2334
3960
|
}
|
|
2335
3961
|
async _drainAll() {
|
|
2336
3962
|
await this._writeTail.catch(() => void 0);
|
|
2337
|
-
if (this.
|
|
3963
|
+
if (this._hasQueuedWork()) {
|
|
2338
3964
|
for await (const _ of this._streamTurns()) void _;
|
|
2339
3965
|
}
|
|
2340
3966
|
}
|
|
@@ -2350,10 +3976,13 @@ var LiveAgentImpl = class {
|
|
|
2350
3976
|
this._setStatus("running");
|
|
2351
3977
|
try {
|
|
2352
3978
|
while (!this._disposed) {
|
|
2353
|
-
const
|
|
2354
|
-
if (!
|
|
2355
|
-
const input = await this._inputForBatch(batch);
|
|
3979
|
+
const snapshot = this._durable.snapshot();
|
|
3980
|
+
if (!snapshot.nextTurn.length && !this._wakeReserved) break;
|
|
2356
3981
|
const turn = await this._nextTurnNumber();
|
|
3982
|
+
await this.session.append("turn/start", { turn, reason: "user" });
|
|
3983
|
+
const batch = await this._durable.claimBatch();
|
|
3984
|
+
this._wakeReserved = false;
|
|
3985
|
+
const input = batch.length ? await this._inputForBatch(batch, true) : { text: "" };
|
|
2357
3986
|
for (const message of batch) {
|
|
2358
3987
|
this._ctx.emit("agent/inbox/claimed", {
|
|
2359
3988
|
id: this.id,
|
|
@@ -2370,11 +3999,21 @@ var LiveAgentImpl = class {
|
|
|
2370
3999
|
else signal?.addEventListener("abort", forward, { once: true });
|
|
2371
4000
|
try {
|
|
2372
4001
|
if (this._manualStreaming) {
|
|
2373
|
-
|
|
4002
|
+
if (this._loop) {
|
|
4003
|
+
const run = await this._loop(input, { signal: controller.signal, turn });
|
|
4004
|
+
await this._closeCustomTurn(turn, run);
|
|
4005
|
+
yield { type: "run/end", run };
|
|
4006
|
+
} else {
|
|
4007
|
+
yield* this._service.runStream(input, { signal: controller.signal, turn });
|
|
4008
|
+
}
|
|
2374
4009
|
} else {
|
|
2375
|
-
|
|
4010
|
+
if (this._loop) {
|
|
4011
|
+
const run = await this._loop(input, { signal: controller.signal, turn });
|
|
4012
|
+
await this._closeCustomTurn(turn, run);
|
|
4013
|
+
} else await this._service.run(input, { signal: controller.signal, turn });
|
|
2376
4014
|
}
|
|
2377
4015
|
} catch (error) {
|
|
4016
|
+
if (this._loop) await this._closeFailedCustomTurn(turn, error);
|
|
2378
4017
|
if (!controller.signal.aborted) {
|
|
2379
4018
|
const step = await this._failedStep();
|
|
2380
4019
|
this._ctx.emit("agent/error", {
|
|
@@ -2392,26 +4031,37 @@ var LiveAgentImpl = class {
|
|
|
2392
4031
|
}
|
|
2393
4032
|
} finally {
|
|
2394
4033
|
this._busy = false;
|
|
4034
|
+
if (!this._durable.size) this._wakeReserved = false;
|
|
2395
4035
|
this._setStatus("idle");
|
|
2396
4036
|
}
|
|
2397
4037
|
}
|
|
2398
|
-
|
|
2399
|
-
const
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
4038
|
+
_hasQueuedWork() {
|
|
4039
|
+
const snapshot = this._durable.snapshot();
|
|
4040
|
+
return snapshot.nextTurn.length > 0 || this._wakeReserved && snapshot.nextStep.length > 0;
|
|
4041
|
+
}
|
|
4042
|
+
async _inputForBatch(batch, includeHistory) {
|
|
4043
|
+
const history = includeHistory ? await this.session.deriveMessages() : [];
|
|
4044
|
+
const messages = batch.flatMap((message) => message.content !== void 0 ? Array.isArray(message.content) ? message.content : [{ role: "user", content: String(message.content ?? "") }] : message.text !== void 0 ? [{ role: "user", content: message.text }] : []);
|
|
4045
|
+
if (history.length || messages.length > 1) return { messages: [...history, ...messages] };
|
|
4046
|
+
return { text: messages[0]?.content ?? "" };
|
|
4047
|
+
}
|
|
4048
|
+
async claimNextStepInputs() {
|
|
4049
|
+
await this._writeTail;
|
|
4050
|
+
const batch = await this._durable.claimNextStep();
|
|
4051
|
+
this._wakeReserved = false;
|
|
4052
|
+
if (batch.length) {
|
|
4053
|
+
const turn = await this._nextTurnNumber() - 1;
|
|
4054
|
+
for (const message of batch) {
|
|
4055
|
+
this._ctx.emit("agent/inbox/claimed", {
|
|
4056
|
+
id: this.id,
|
|
4057
|
+
agent: this,
|
|
4058
|
+
message,
|
|
4059
|
+
input: { text: message.text ?? "" },
|
|
4060
|
+
turn
|
|
4061
|
+
});
|
|
4062
|
+
}
|
|
2413
4063
|
}
|
|
2414
|
-
return
|
|
4064
|
+
return batch.length ? [await this._inputForBatch(batch, false)] : [];
|
|
2415
4065
|
}
|
|
2416
4066
|
_setStatus(status) {
|
|
2417
4067
|
const previous = this._status;
|
|
@@ -2507,112 +4157,156 @@ async function buildHandle(ctx, options, resume = false) {
|
|
|
2507
4157
|
}
|
|
2508
4158
|
const agentId = fileMeta?.agentId ?? requestedId;
|
|
2509
4159
|
if (!agentId) throw new AgentError("agent requires a stable identity");
|
|
2510
|
-
|
|
2511
|
-
options.file,
|
|
2512
|
-
(type, payload) => {
|
|
2513
|
-
if (type === "event") ctx.emit("session/event", payload);
|
|
2514
|
-
else ctx.emit("session/flush", payload);
|
|
2515
|
-
}
|
|
2516
|
-
);
|
|
2517
|
-
await log.init();
|
|
2518
|
-
const fileEvents = await log.read();
|
|
2519
|
-
const durableMeta = readDurableAgentMeta(fileEvents);
|
|
2520
|
-
if (durableMeta) {
|
|
2521
|
-
if (durableMeta.agentId !== agentId) {
|
|
2522
|
-
throw new AgentError(
|
|
2523
|
-
`agent id mismatch: session belongs to ${durableMeta.agentId}, requested ${agentId}`
|
|
2524
|
-
);
|
|
2525
|
-
}
|
|
2526
|
-
if (options.agentType && durableMeta.agentType !== options.agentType) {
|
|
2527
|
-
throw new AgentError(
|
|
2528
|
-
`agent type mismatch: session is ${durableMeta.agentType ?? "untyped"}, requested ${options.agentType}`
|
|
2529
|
-
);
|
|
2530
|
-
}
|
|
2531
|
-
if (options.mode && durableMeta.mode !== options.mode) {
|
|
2532
|
-
throw new AgentError(
|
|
2533
|
-
`agent mode mismatch: session is ${durableMeta.mode ?? "unset"}, requested ${options.mode}`
|
|
2534
|
-
);
|
|
2535
|
-
}
|
|
2536
|
-
}
|
|
2537
|
-
const boundMeta = {
|
|
2538
|
-
...fileMeta,
|
|
2539
|
-
...durableMeta ?? {},
|
|
2540
|
-
...options.title ? { title: options.title } : {},
|
|
2541
|
-
...options.owner ? { owner: options.owner } : {},
|
|
2542
|
-
...options.parentSessionId ? { parentSessionId: options.parentSessionId } : {},
|
|
2543
|
-
...options.forkedAtMessageId ? { forkedAtMessageId: options.forkedAtMessageId } : {},
|
|
2544
|
-
agentId
|
|
2545
|
-
};
|
|
2546
|
-
const resolvedAgentType = options.agentType ?? durableMeta?.agentType;
|
|
2547
|
-
if (resolvedAgentType) boundMeta.agentType = resolvedAgentType;
|
|
2548
|
-
const resolvedMode = options.mode ?? durableMeta?.mode;
|
|
2549
|
-
if (resolvedMode) boundMeta.mode = resolvedMode;
|
|
2550
|
-
if (!durableMeta) {
|
|
2551
|
-
await log.append("meta", {
|
|
2552
|
-
kind: "agent",
|
|
2553
|
-
agentId,
|
|
2554
|
-
...boundMeta.agentType ? { agentType: boundMeta.agentType } : {},
|
|
2555
|
-
...boundMeta.mode ? { mode: boundMeta.mode } : {},
|
|
2556
|
-
...boundMeta.title ? { title: boundMeta.title } : {},
|
|
2557
|
-
...boundMeta.owner ? { owner: boundMeta.owner } : {},
|
|
2558
|
-
...boundMeta.parentSessionId ? { parentSessionId: boundMeta.parentSessionId } : {},
|
|
2559
|
-
...boundMeta.forkedAtMessageId ? { forkedAtMessageId: boundMeta.forkedAtMessageId } : {},
|
|
2560
|
-
...boundMeta.createdAt !== void 0 ? { createdAt: boundMeta.createdAt } : {}
|
|
2561
|
-
});
|
|
2562
|
-
}
|
|
2563
|
-
const durable = resume ? await DurableInbox.restore(log) : new DurableInbox(log);
|
|
2564
|
-
const injected = new AgentInbox();
|
|
2565
|
-
const inboxView = {
|
|
2566
|
-
get size() {
|
|
2567
|
-
return durable.size;
|
|
2568
|
-
},
|
|
2569
|
-
snapshot: () => durable.snapshot()
|
|
2570
|
-
};
|
|
2571
|
-
const service = new AgentService(ctx, {
|
|
2572
|
-
session: log,
|
|
2573
|
-
inbox: injected,
|
|
2574
|
-
...options.llm ? { llm: options.llm } : {},
|
|
2575
|
-
...options.maxTurns !== void 0 ? { maxTurns: options.maxTurns } : {},
|
|
2576
|
-
...options.maxSteps !== void 0 ? { maxSteps: options.maxSteps } : {},
|
|
2577
|
-
...options.contextBudget ? { contextBudget: options.contextBudget } : {},
|
|
2578
|
-
...options.hooks ? { hooks: options.hooks } : {}
|
|
2579
|
-
});
|
|
2580
|
-
if (options.system) injected.inject("agentSystem", options.system);
|
|
4160
|
+
let agentCtx;
|
|
2581
4161
|
const agentScope = await ctx.inject([], (scopeCtx) => {
|
|
2582
|
-
scopeCtx.isolate("agentScope").
|
|
4162
|
+
agentCtx = scopeCtx.isolate("agentScope").isolate("llm").isolate("tools").isolate("systemPrompt");
|
|
4163
|
+
agentCtx.provide("agentScope", agentCtx);
|
|
2583
4164
|
});
|
|
2584
4165
|
await agentScope;
|
|
2585
|
-
const
|
|
2586
|
-
const
|
|
2587
|
-
ctx,
|
|
2588
|
-
agentCtx,
|
|
2589
|
-
service,
|
|
2590
|
-
agentId,
|
|
2591
|
-
inboxView,
|
|
2592
|
-
log,
|
|
2593
|
-
durable,
|
|
2594
|
-
boundMeta,
|
|
2595
|
-
options.manualStreaming === true
|
|
2596
|
-
);
|
|
2597
|
-
agent2.trackSetupDispose(() => agentScope.dispose());
|
|
2598
|
-
if (options.system) agent2.inject("agentSystem", options.system);
|
|
2599
|
-
let setupResult;
|
|
4166
|
+
const runtimeCtx = createAgentRuntimeContext(agentCtx);
|
|
4167
|
+
const log = new SessionLog(options.file, void 0, runtimeCtx);
|
|
2600
4168
|
try {
|
|
2601
|
-
|
|
2602
|
-
|
|
4169
|
+
await log.init();
|
|
4170
|
+
const fileEvents = await log.read();
|
|
4171
|
+
const durableMeta = readDurableAgentMeta(fileEvents);
|
|
4172
|
+
if (durableMeta) {
|
|
4173
|
+
if (durableMeta.agentId !== agentId) {
|
|
4174
|
+
throw new AgentError(
|
|
4175
|
+
`agent id mismatch: session belongs to ${durableMeta.agentId}, requested ${agentId}`
|
|
4176
|
+
);
|
|
4177
|
+
}
|
|
4178
|
+
if (options.agentType && durableMeta.agentType !== options.agentType) {
|
|
4179
|
+
throw new AgentError(
|
|
4180
|
+
`agent type mismatch: session is ${durableMeta.agentType ?? "untyped"}, requested ${options.agentType}`
|
|
4181
|
+
);
|
|
4182
|
+
}
|
|
4183
|
+
if (options.mode && durableMeta.mode !== options.mode) {
|
|
4184
|
+
throw new AgentError(
|
|
4185
|
+
`agent mode mismatch: session is ${durableMeta.mode ?? "unset"}, requested ${options.mode}`
|
|
4186
|
+
);
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
const boundMeta = {
|
|
4190
|
+
...fileMeta,
|
|
4191
|
+
...durableMeta ?? {},
|
|
4192
|
+
...options.title ? { title: options.title } : {},
|
|
4193
|
+
...options.owner ? { owner: options.owner } : {},
|
|
4194
|
+
...options.parentSessionId ? { parentSessionId: options.parentSessionId } : {},
|
|
4195
|
+
...options.forkedAtMessageId ? { forkedAtMessageId: options.forkedAtMessageId } : {},
|
|
4196
|
+
agentId
|
|
4197
|
+
};
|
|
4198
|
+
const resolvedAgentType = options.agentType ?? durableMeta?.agentType;
|
|
4199
|
+
if (resolvedAgentType) boundMeta.agentType = resolvedAgentType;
|
|
4200
|
+
const resolvedMode = options.mode ?? durableMeta?.mode;
|
|
4201
|
+
if (resolvedMode) boundMeta.mode = resolvedMode;
|
|
4202
|
+
if (!durableMeta) {
|
|
4203
|
+
await log.append("meta", {
|
|
4204
|
+
kind: "agent",
|
|
4205
|
+
agentId,
|
|
4206
|
+
...boundMeta.agentType ? { agentType: boundMeta.agentType } : {},
|
|
4207
|
+
...boundMeta.mode ? { mode: boundMeta.mode } : {},
|
|
4208
|
+
...boundMeta.title ? { title: boundMeta.title } : {},
|
|
4209
|
+
...boundMeta.owner ? { owner: boundMeta.owner } : {},
|
|
4210
|
+
...boundMeta.parentSessionId ? { parentSessionId: boundMeta.parentSessionId } : {},
|
|
4211
|
+
...boundMeta.forkedAtMessageId ? { forkedAtMessageId: boundMeta.forkedAtMessageId } : {},
|
|
4212
|
+
...boundMeta.createdAt !== void 0 ? { createdAt: boundMeta.createdAt } : {}
|
|
4213
|
+
});
|
|
4214
|
+
}
|
|
4215
|
+
const durable = resume ? await DurableInbox.restore(log) : new DurableInbox(log);
|
|
4216
|
+
const restoredWakeReservation = resume && hasRestoredWakeReservation(fileEvents);
|
|
4217
|
+
const injected = new AgentInbox();
|
|
4218
|
+
const inboxView = {
|
|
4219
|
+
get size() {
|
|
4220
|
+
return durable.size;
|
|
4221
|
+
},
|
|
4222
|
+
snapshot: () => durable.snapshot()
|
|
4223
|
+
};
|
|
4224
|
+
let claimNextStep = async () => [];
|
|
4225
|
+
const service = new AgentService(runtimeCtx, {
|
|
4226
|
+
session: log,
|
|
4227
|
+
inbox: injected,
|
|
4228
|
+
...options.llm ? { llm: options.llm } : {},
|
|
4229
|
+
...options.maxTurns !== void 0 ? { maxTurns: options.maxTurns } : {},
|
|
4230
|
+
...options.maxSteps !== void 0 ? { maxSteps: options.maxSteps } : {},
|
|
4231
|
+
...options.contextBudget ? { contextBudget: options.contextBudget } : {},
|
|
4232
|
+
...options.hooks ? { hooks: options.hooks } : {},
|
|
4233
|
+
claimNextStep: () => claimNextStep()
|
|
4234
|
+
});
|
|
4235
|
+
if (options.system) injected.inject("agentSystem", options.system);
|
|
4236
|
+
const agent2 = new LiveAgentImpl(
|
|
4237
|
+
runtimeCtx,
|
|
4238
|
+
agentCtx,
|
|
4239
|
+
service,
|
|
4240
|
+
agentId,
|
|
4241
|
+
inboxView,
|
|
4242
|
+
log,
|
|
4243
|
+
durable,
|
|
4244
|
+
boundMeta,
|
|
4245
|
+
options.manualStreaming === true,
|
|
4246
|
+
restoredWakeReservation
|
|
4247
|
+
);
|
|
4248
|
+
claimNextStep = () => agent2.claimNextStepInputs();
|
|
4249
|
+
agent2.trackSetupDispose(() => agentScope.dispose());
|
|
4250
|
+
let setupResult;
|
|
4251
|
+
try {
|
|
4252
|
+
setupResult = await options.setup?.(agentCtx);
|
|
4253
|
+
for (const name2 of ["llm", "systemPrompt"]) {
|
|
4254
|
+
if (agentCtx.reflect.get(name2, false) !== void 0) continue;
|
|
4255
|
+
const inherited = ctx.reflect.get(name2, false);
|
|
4256
|
+
if (inherited !== void 0) agentCtx.provide(name2, inherited);
|
|
4257
|
+
}
|
|
4258
|
+
const loop = agentCtx.reflect.get("agentLoop", false);
|
|
4259
|
+
agent2.setLoop(loop);
|
|
4260
|
+
setupResult?.commit();
|
|
4261
|
+
} catch (error) {
|
|
4262
|
+
await agent2.dispose().catch(() => void 0);
|
|
4263
|
+
await log.close().catch(() => void 0);
|
|
4264
|
+
throw error;
|
|
4265
|
+
}
|
|
4266
|
+
await agent2.publishSessionStart(resume ? "resume" : "startup");
|
|
4267
|
+
for (const input of options.initial ?? []) {
|
|
4268
|
+
if (!resume) await durable.insert({ text: input.text ?? "" });
|
|
4269
|
+
}
|
|
4270
|
+
if (resume && (durable.snapshot().nextTurn.length || restoredWakeReservation) && options.manualStreaming !== true) {
|
|
4271
|
+
setTimeout(() => agent2.wakeNow(), 0);
|
|
4272
|
+
}
|
|
4273
|
+
return { agent: agent2, dispose: () => agent2.dispose() };
|
|
2603
4274
|
} catch (error) {
|
|
2604
|
-
await
|
|
2605
|
-
await log.close().catch(() => void 0);
|
|
4275
|
+
await Promise.resolve().then(() => agentScope.dispose()).catch(() => void 0);
|
|
2606
4276
|
throw error;
|
|
2607
4277
|
}
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
4278
|
+
}
|
|
4279
|
+
function hasRestoredWakeReservation(events) {
|
|
4280
|
+
const nextTurn = [];
|
|
4281
|
+
const nextStep = [];
|
|
4282
|
+
for (const event of events) {
|
|
4283
|
+
if (event.type !== "agent/inbox/spliced") continue;
|
|
4284
|
+
const payload = event.payload;
|
|
4285
|
+
if (payload.target === "all") {
|
|
4286
|
+
nextTurn.splice(0, payload.deleteCounts?.nextTurn ?? nextTurn.length);
|
|
4287
|
+
nextStep.splice(0, payload.deleteCounts?.nextStep ?? nextStep.length);
|
|
4288
|
+
continue;
|
|
4289
|
+
}
|
|
4290
|
+
const list = payload.target === "next-step" ? nextStep : nextTurn;
|
|
4291
|
+
const count = payload.deleteCount ?? 0;
|
|
4292
|
+
if (count === Number.POSITIVE_INFINITY) {
|
|
4293
|
+
list.length = 0;
|
|
4294
|
+
} else if (count > 0 && payload.index !== void 0) {
|
|
4295
|
+
list.splice(payload.index, count);
|
|
4296
|
+
}
|
|
4297
|
+
let insertedOffset = 0;
|
|
4298
|
+
for (const inserted of payload.inserted ?? []) {
|
|
4299
|
+
const entry = { wakes: payload.target === "next-step" && inserted.mode === "steer" };
|
|
4300
|
+
if (inserted.mode === "steer") {
|
|
4301
|
+
list.unshift(entry);
|
|
4302
|
+
} else {
|
|
4303
|
+
const index = payload.index === void 0 ? list.length : Math.min(list.length, payload.index + insertedOffset);
|
|
4304
|
+
list.splice(index, 0, entry);
|
|
4305
|
+
insertedOffset += 1;
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
2614
4308
|
}
|
|
2615
|
-
return
|
|
4309
|
+
return nextStep.some((entry) => entry.wakes);
|
|
2616
4310
|
}
|
|
2617
4311
|
async function readAgentMeta(file) {
|
|
2618
4312
|
const lines = await import("node:fs/promises").then((fs) => fs.readFile(file, "utf8")).catch((error) => {
|