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/cli-runtime.js
CHANGED
|
@@ -9078,17 +9078,88 @@ function checkMonotonicSeq(events) {
|
|
|
9078
9078
|
}
|
|
9079
9079
|
return failures;
|
|
9080
9080
|
}
|
|
9081
|
+
function isRecord(value) {
|
|
9082
|
+
return typeof value === "object" && value !== null && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
9083
|
+
}
|
|
9084
|
+
function isNonNegativeInteger(value) {
|
|
9085
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
9086
|
+
}
|
|
9087
|
+
function isJsonValue(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
9088
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
9089
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
9090
|
+
if (typeof value !== "object" || ancestors.has(value)) return false;
|
|
9091
|
+
if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return false;
|
|
9092
|
+
ancestors.add(value);
|
|
9093
|
+
const valid = (Array.isArray(value) ? Array.from(value) : Object.values(value)).every((member) => isJsonValue(member, ancestors));
|
|
9094
|
+
ancestors.delete(value);
|
|
9095
|
+
return valid;
|
|
9096
|
+
}
|
|
9097
|
+
function isStreamRecord(value) {
|
|
9098
|
+
if (!isRecord(value) || !isNonNegativeInteger(value.time) || !isRecord(value.chunk)) return false;
|
|
9099
|
+
const chunk = value.chunk;
|
|
9100
|
+
if (chunk.type === "stream_error") {
|
|
9101
|
+
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");
|
|
9102
|
+
}
|
|
9103
|
+
if (typeof chunk.id !== "string") return false;
|
|
9104
|
+
switch (chunk.type) {
|
|
9105
|
+
case "message_start":
|
|
9106
|
+
return chunk.model === void 0 || typeof chunk.model === "string";
|
|
9107
|
+
case "message_delta":
|
|
9108
|
+
return typeof chunk.delta === "string";
|
|
9109
|
+
case "toolcall_start":
|
|
9110
|
+
case "toolcall_end":
|
|
9111
|
+
return isNonNegativeInteger(chunk.index) && typeof chunk.name === "string" && (chunk.type === "toolcall_start" || isJsonValue(chunk.arguments));
|
|
9112
|
+
case "message_stop":
|
|
9113
|
+
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";
|
|
9114
|
+
default:
|
|
9115
|
+
return false;
|
|
9116
|
+
}
|
|
9117
|
+
}
|
|
9118
|
+
function checkAssistantAttempts(events) {
|
|
9119
|
+
const turns = /* @__PURE__ */ new Set();
|
|
9120
|
+
const steps = /* @__PURE__ */ new Map();
|
|
9121
|
+
const failures = [];
|
|
9122
|
+
for (const event of events) {
|
|
9123
|
+
if (event.type === "turn/start") turns.add(event.payload.turn);
|
|
9124
|
+
if (event.type === "turn/end") {
|
|
9125
|
+
turns.delete(event.payload.turn);
|
|
9126
|
+
for (const [key, turn] of steps) {
|
|
9127
|
+
if (turn === event.payload.turn) steps.delete(key);
|
|
9128
|
+
}
|
|
9129
|
+
}
|
|
9130
|
+
if (event.type === "step/start" && turns.has(event.payload.turn)) {
|
|
9131
|
+
steps.set(`${event.payload.turn}:${event.payload.step}`, event.payload.turn);
|
|
9132
|
+
}
|
|
9133
|
+
if (event.type === "step/end") steps.delete(`${event.payload.turn}:${event.payload.step}`);
|
|
9134
|
+
if (event.type !== "assistant/attempt") continue;
|
|
9135
|
+
const payload = event.payload;
|
|
9136
|
+
if (!isRecord(payload) || !isNonNegativeInteger(payload.turn) || !isNonNegativeInteger(payload.step) || !turns.has(payload.turn) || !steps.has(`${payload.turn}:${payload.step}`)) {
|
|
9137
|
+
failures.push({
|
|
9138
|
+
name: "assistant/attempt-without-open-step",
|
|
9139
|
+
detail: `assistant/attempt at seq ${event.seq} has no matching open turn and step`
|
|
9140
|
+
});
|
|
9141
|
+
}
|
|
9142
|
+
if (!isRecord(payload) || !Array.isArray(payload.stream) || !payload.stream.every(isStreamRecord)) {
|
|
9143
|
+
failures.push({
|
|
9144
|
+
name: "assistant/attempt-invalid-stream",
|
|
9145
|
+
detail: `assistant/attempt at seq ${event.seq} must contain an ordered array of normalized stream records`
|
|
9146
|
+
});
|
|
9147
|
+
}
|
|
9148
|
+
}
|
|
9149
|
+
return failures;
|
|
9150
|
+
}
|
|
9081
9151
|
function checkSessionInvariants(events) {
|
|
9082
9152
|
return [
|
|
9083
9153
|
...checkBalancedTurns(events),
|
|
9084
9154
|
...checkBalancedSteps(events),
|
|
9085
9155
|
...checkBalancedToolCalls(events),
|
|
9086
|
-
...checkMonotonicSeq(events)
|
|
9156
|
+
...checkMonotonicSeq(events),
|
|
9157
|
+
...checkAssistantAttempts(events)
|
|
9087
9158
|
];
|
|
9088
9159
|
}
|
|
9089
9160
|
|
|
9090
9161
|
// packages/session/src/index.ts
|
|
9091
|
-
var SESSION_FORMAT_VERSION =
|
|
9162
|
+
var SESSION_FORMAT_VERSION = 10;
|
|
9092
9163
|
var SessionFormatError = class extends Error {
|
|
9093
9164
|
name = "SessionFormatError";
|
|
9094
9165
|
};
|
|
@@ -9260,7 +9331,7 @@ function transcriptEvents(events) {
|
|
|
9260
9331
|
const structure = events.filter((event) => !inSkeleton.has(event.id)).filter((event) => event.type !== "compaction/start" && event.type !== "compaction/end").filter((event) => event.type !== "checkpoint").filter((event) => !(event.type === "tool/call" && declaredCalls.has(event.payload.id)));
|
|
9261
9332
|
const ordered = [...skeleton];
|
|
9262
9333
|
for (const event of structure) {
|
|
9263
|
-
let index =
|
|
9334
|
+
let index = 0;
|
|
9264
9335
|
for (let cursor = ordered.length - 1; cursor >= 0; cursor -= 1) {
|
|
9265
9336
|
if (ordered[cursor].seq <= event.seq) {
|
|
9266
9337
|
index = cursor + 1;
|
|
@@ -9357,6 +9428,7 @@ function estimateEventTokens(event) {
|
|
|
9357
9428
|
return Math.ceil(raw.length / 4);
|
|
9358
9429
|
}
|
|
9359
9430
|
case "plan":
|
|
9431
|
+
case "assistant/attempt":
|
|
9360
9432
|
return 0;
|
|
9361
9433
|
case "checkpoint":
|
|
9362
9434
|
return estimateMessageTokens(event.payload.messages);
|
|
@@ -9491,9 +9563,15 @@ function estimateContextUsage(messages, limit = DEFAULT_CONTEXT_LIMIT) {
|
|
|
9491
9563
|
};
|
|
9492
9564
|
}
|
|
9493
9565
|
var SessionLog = class {
|
|
9494
|
-
constructor(file, _broadcast) {
|
|
9566
|
+
constructor(file, _broadcast, publicationContext) {
|
|
9495
9567
|
this.file = file;
|
|
9496
9568
|
this._broadcast = _broadcast;
|
|
9569
|
+
if (!this._broadcast && publicationContext) {
|
|
9570
|
+
this._broadcast = (type, payload) => {
|
|
9571
|
+
if (type === "event") publicationContext.emit("session/event", payload);
|
|
9572
|
+
else publicationContext.emit("session/flush", payload);
|
|
9573
|
+
};
|
|
9574
|
+
}
|
|
9497
9575
|
}
|
|
9498
9576
|
file;
|
|
9499
9577
|
_broadcast;
|
|
@@ -9662,7 +9740,7 @@ var SessionLog = class {
|
|
|
9662
9740
|
selected.push(clone(event));
|
|
9663
9741
|
continue;
|
|
9664
9742
|
}
|
|
9665
|
-
if (event.type === "meta" || event.type === "llm/retry" || event.type === "llm/retry-started" || event.type.startsWith("turn/") || event.type.startsWith("step/")) {
|
|
9743
|
+
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/")) {
|
|
9666
9744
|
continue;
|
|
9667
9745
|
}
|
|
9668
9746
|
if (event.type === "checkpoint") {
|
|
@@ -10012,7 +10090,7 @@ function copyMessages(messages) {
|
|
|
10012
10090
|
copy.tool_calls = message3.tool_calls.map((call) => ({
|
|
10013
10091
|
id: call.id,
|
|
10014
10092
|
name: call.name,
|
|
10015
|
-
arguments: call.arguments
|
|
10093
|
+
arguments: structuredClone(call.arguments)
|
|
10016
10094
|
}));
|
|
10017
10095
|
}
|
|
10018
10096
|
return copy;
|
|
@@ -10043,6 +10121,75 @@ function copyCompletion(completion) {
|
|
|
10043
10121
|
}
|
|
10044
10122
|
return copy;
|
|
10045
10123
|
}
|
|
10124
|
+
function canonicalMessages(messages) {
|
|
10125
|
+
return JSON.stringify(messages.map((message3) => ({
|
|
10126
|
+
role: message3.role,
|
|
10127
|
+
content: message3.content,
|
|
10128
|
+
...message3.name ? { name: message3.name } : {},
|
|
10129
|
+
...message3.tool_call_id ? { tool_call_id: message3.tool_call_id } : {},
|
|
10130
|
+
...message3.tool_calls?.length ? { tool_calls: message3.tool_calls } : {},
|
|
10131
|
+
...message3.toolOk !== void 0 ? { toolOk: message3.toolOk } : {},
|
|
10132
|
+
...message3.toolError ? {
|
|
10133
|
+
toolError: { name: message3.toolError.name, message: message3.toolError.message }
|
|
10134
|
+
} : {}
|
|
10135
|
+
})));
|
|
10136
|
+
}
|
|
10137
|
+
function freezeRequestData(data) {
|
|
10138
|
+
const visited = /* @__PURE__ */ new Set();
|
|
10139
|
+
const freeze = (value) => {
|
|
10140
|
+
if (typeof value !== "object" || value === null || visited.has(value)) return;
|
|
10141
|
+
visited.add(value);
|
|
10142
|
+
for (const child of Object.values(value)) freeze(child);
|
|
10143
|
+
Object.freeze(value);
|
|
10144
|
+
};
|
|
10145
|
+
freeze(data);
|
|
10146
|
+
}
|
|
10147
|
+
function lockStreamRequest(request) {
|
|
10148
|
+
freezeRequestData(request.messages);
|
|
10149
|
+
request.tools = Object.freeze(request.tools.map((tool) => {
|
|
10150
|
+
const schema = structuredClone(tool.schema);
|
|
10151
|
+
freezeRequestData(schema);
|
|
10152
|
+
return Object.freeze({ ...tool, schema });
|
|
10153
|
+
}));
|
|
10154
|
+
Object.freeze(request.options);
|
|
10155
|
+
Object.freeze(request);
|
|
10156
|
+
}
|
|
10157
|
+
function requestHeaderFor(request, input) {
|
|
10158
|
+
const system = input.find((message3) => message3.role === "system")?.content;
|
|
10159
|
+
const tools2 = request.tools.map((tool) => ({
|
|
10160
|
+
name: tool.schema.name,
|
|
10161
|
+
description: tool.schema.description,
|
|
10162
|
+
...tool.schema.parameters ? { parameters: tool.schema.parameters } : {}
|
|
10163
|
+
}));
|
|
10164
|
+
const config2 = {
|
|
10165
|
+
...request.options.provider ? { provider: request.options.provider } : {},
|
|
10166
|
+
...request.options.model ? { model: request.options.model } : {},
|
|
10167
|
+
...request.options.temperature !== void 0 ? { temperature: request.options.temperature } : {}
|
|
10168
|
+
};
|
|
10169
|
+
return {
|
|
10170
|
+
...Object.keys(config2).length ? { config: config2 } : {},
|
|
10171
|
+
...system !== void 0 ? { system } : {},
|
|
10172
|
+
...tools2.length ? { tools: tools2 } : {}
|
|
10173
|
+
};
|
|
10174
|
+
}
|
|
10175
|
+
async function* completeAsStream(llm, messages, tools2, options) {
|
|
10176
|
+
const id = randomUUID2();
|
|
10177
|
+
yield { type: "message_start", id };
|
|
10178
|
+
const completion = await llm.complete(messages, tools2, options);
|
|
10179
|
+
if (completion.content) yield { type: "message_delta", id, delta: completion.content };
|
|
10180
|
+
for (let index = 0; index < (completion.toolCalls?.length ?? 0); index += 1) {
|
|
10181
|
+
const call = completion.toolCalls[index];
|
|
10182
|
+
yield { type: "toolcall_start", id: call.id, index, name: call.name };
|
|
10183
|
+
yield {
|
|
10184
|
+
type: "toolcall_end",
|
|
10185
|
+
id: call.id,
|
|
10186
|
+
index,
|
|
10187
|
+
name: call.name,
|
|
10188
|
+
arguments: call.arguments
|
|
10189
|
+
};
|
|
10190
|
+
}
|
|
10191
|
+
yield { type: "message_stop", id, finishReason: completion.finishReason };
|
|
10192
|
+
}
|
|
10046
10193
|
function isCancelCause(value) {
|
|
10047
10194
|
if (typeof value !== "object" || value === null) return false;
|
|
10048
10195
|
const record3 = value;
|
|
@@ -10063,6 +10210,13 @@ function cancelCauseFromSignal(signal) {
|
|
|
10063
10210
|
if (isCancelCause(reason)) return reason;
|
|
10064
10211
|
return { type: "abort" };
|
|
10065
10212
|
}
|
|
10213
|
+
function abortedToolError(signal) {
|
|
10214
|
+
const cause = cancelCauseFromSignal(signal);
|
|
10215
|
+
return {
|
|
10216
|
+
name: "AbortError",
|
|
10217
|
+
message: `tool call aborted: ${cause?.type ?? "abort"}`
|
|
10218
|
+
};
|
|
10219
|
+
}
|
|
10066
10220
|
function toTurnEndReason(fields) {
|
|
10067
10221
|
const { cancelled, turnError, finishReason, cancelCause } = fields;
|
|
10068
10222
|
if (cancelled || finishReason === "cancelled") {
|
|
@@ -10107,6 +10261,78 @@ async function cancellableDelay(ms, signal) {
|
|
|
10107
10261
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
10108
10262
|
});
|
|
10109
10263
|
}
|
|
10264
|
+
var AssistantStreamAttempt = class {
|
|
10265
|
+
constructor(session2, turn, step, nextRevision) {
|
|
10266
|
+
this.session = session2;
|
|
10267
|
+
this.turn = turn;
|
|
10268
|
+
this.step = step;
|
|
10269
|
+
this.nextRevision = nextRevision;
|
|
10270
|
+
}
|
|
10271
|
+
session;
|
|
10272
|
+
turn;
|
|
10273
|
+
step;
|
|
10274
|
+
nextRevision;
|
|
10275
|
+
attemptId = randomUUID2();
|
|
10276
|
+
records = [];
|
|
10277
|
+
ended = false;
|
|
10278
|
+
start() {
|
|
10279
|
+
return { type: "assistant/stream", frame: {
|
|
10280
|
+
type: "start",
|
|
10281
|
+
attemptId: this.attemptId,
|
|
10282
|
+
revision: this.nextRevision(),
|
|
10283
|
+
turn: this.turn,
|
|
10284
|
+
step: this.step
|
|
10285
|
+
} };
|
|
10286
|
+
}
|
|
10287
|
+
push(chunk) {
|
|
10288
|
+
if (this.ended) throw new AgentError("assistant attempt is already settled");
|
|
10289
|
+
const record3 = { time: Date.now(), chunk: structuredClone(chunk) };
|
|
10290
|
+
const index = this.records.length;
|
|
10291
|
+
this.records.push(record3);
|
|
10292
|
+
return { type: "assistant/stream", frame: {
|
|
10293
|
+
type: "chunk",
|
|
10294
|
+
attemptId: this.attemptId,
|
|
10295
|
+
revision: this.nextRevision(),
|
|
10296
|
+
index,
|
|
10297
|
+
...structuredClone(record3)
|
|
10298
|
+
} };
|
|
10299
|
+
}
|
|
10300
|
+
async settle(message3) {
|
|
10301
|
+
if (this.ended) throw new AgentError("assistant attempt is already settled");
|
|
10302
|
+
const eventType = message3 ? "assistant/message" : "assistant/attempt";
|
|
10303
|
+
let event;
|
|
10304
|
+
try {
|
|
10305
|
+
event = message3 ? await this.session.append("assistant/message", { ...message3, stream: this.records }) : await this.session.append("assistant/attempt", { turn: this.turn, step: this.step, stream: this.records });
|
|
10306
|
+
} catch (cause) {
|
|
10307
|
+
this.ended = true;
|
|
10308
|
+
const frame = { type: "assistant/stream", frame: {
|
|
10309
|
+
type: "end",
|
|
10310
|
+
attemptId: this.attemptId,
|
|
10311
|
+
revision: this.nextRevision(),
|
|
10312
|
+
index: this.records.length,
|
|
10313
|
+
outcome: { kind: "abandoned" }
|
|
10314
|
+
} };
|
|
10315
|
+
throw new AttemptSettlementError(cause, frame);
|
|
10316
|
+
}
|
|
10317
|
+
this.ended = true;
|
|
10318
|
+
return { type: "assistant/stream", frame: {
|
|
10319
|
+
type: "end",
|
|
10320
|
+
attemptId: this.attemptId,
|
|
10321
|
+
revision: this.nextRevision(),
|
|
10322
|
+
index: this.records.length,
|
|
10323
|
+
outcome: { kind: "committed", eventType, seq: event.seq }
|
|
10324
|
+
} };
|
|
10325
|
+
}
|
|
10326
|
+
};
|
|
10327
|
+
var AttemptSettlementError = class extends Error {
|
|
10328
|
+
constructor(cause, frame) {
|
|
10329
|
+
super("assistant attempt settlement failed");
|
|
10330
|
+
this.cause = cause;
|
|
10331
|
+
this.frame = frame;
|
|
10332
|
+
}
|
|
10333
|
+
cause;
|
|
10334
|
+
frame;
|
|
10335
|
+
};
|
|
10110
10336
|
var AgentService = class {
|
|
10111
10337
|
constructor(ctx, config2 = {}) {
|
|
10112
10338
|
this.ctx = ctx;
|
|
@@ -10115,9 +10341,24 @@ var AgentService = class {
|
|
|
10115
10341
|
}
|
|
10116
10342
|
ctx;
|
|
10117
10343
|
config;
|
|
10344
|
+
async *settleAttempt(attempt, message3) {
|
|
10345
|
+
try {
|
|
10346
|
+
yield await attempt.settle(message3);
|
|
10347
|
+
} catch (error2) {
|
|
10348
|
+
if (error2 instanceof AttemptSettlementError) {
|
|
10349
|
+
yield error2.frame;
|
|
10350
|
+
throw error2.cause;
|
|
10351
|
+
}
|
|
10352
|
+
throw error2;
|
|
10353
|
+
}
|
|
10354
|
+
}
|
|
10118
10355
|
inbox;
|
|
10119
10356
|
_seriesStarted = false;
|
|
10120
10357
|
_persistedRequest = false;
|
|
10358
|
+
_streamRevision = 0;
|
|
10359
|
+
_attempt(session2, turn, step) {
|
|
10360
|
+
return new AssistantStreamAttempt(session2, turn, step, () => ++this._streamRevision);
|
|
10361
|
+
}
|
|
10121
10362
|
/** Call when a request begins an explicit new model-message series. */
|
|
10122
10363
|
startSeries() {
|
|
10123
10364
|
this._seriesStarted = true;
|
|
@@ -10131,7 +10372,7 @@ var AgentService = class {
|
|
|
10131
10372
|
return this._persistedRequest;
|
|
10132
10373
|
}
|
|
10133
10374
|
async run(input, options = {}) {
|
|
10134
|
-
return consumeAgentStream(this._stream(input, options
|
|
10375
|
+
return consumeAgentStream(this._stream(input, options));
|
|
10135
10376
|
}
|
|
10136
10377
|
async *runStream(input, options = {}) {
|
|
10137
10378
|
const iterator = this._stream(input, options)[Symbol.asyncIterator]();
|
|
@@ -10141,7 +10382,7 @@ var AgentService = class {
|
|
|
10141
10382
|
yield next.value;
|
|
10142
10383
|
}
|
|
10143
10384
|
}
|
|
10144
|
-
async *_stream(input, options = {}
|
|
10385
|
+
async *_stream(input, options = {}) {
|
|
10145
10386
|
const claimed = input ?? this.inbox.claim();
|
|
10146
10387
|
if (!claimed) throw new AgentError("no agent input available");
|
|
10147
10388
|
await this.config.hooks?.beforeRun?.(claimed, options);
|
|
@@ -10149,26 +10390,32 @@ var AgentService = class {
|
|
|
10149
10390
|
const tools2 = this._tools();
|
|
10150
10391
|
const llm = this._llm();
|
|
10151
10392
|
if (!llm) throw new AgentError("no LLM adapter available");
|
|
10393
|
+
const streamAdapter = llm.stream;
|
|
10394
|
+
const persistChunks = streamAdapter !== void 0;
|
|
10152
10395
|
const maxTurns = options.maxTurns ?? this.config.maxTurns ?? 64;
|
|
10153
10396
|
const maxSteps = options.maxSteps ?? this.config.maxSteps ?? 64;
|
|
10154
10397
|
const contextBudget = options.contextBudget ?? this.config.contextBudget;
|
|
10155
10398
|
const injected = this.inbox.injected();
|
|
10156
10399
|
this.ctx.emit("agent/start", { input: claimed, options, injected });
|
|
10157
10400
|
let messages = await this._initialMessages(claimed);
|
|
10401
|
+
let claimedMessages = messages.filter((message3) => message3.role === "user");
|
|
10158
10402
|
const steps = [];
|
|
10159
10403
|
let output = "";
|
|
10160
10404
|
let finishReason = "stop";
|
|
10405
|
+
let lengthReached = false;
|
|
10161
10406
|
this.ctx.emit("agent/turn-start", {
|
|
10162
10407
|
input: claimed,
|
|
10163
10408
|
messages: copyMessages(messages),
|
|
10164
10409
|
injected
|
|
10165
10410
|
});
|
|
10166
|
-
const turn = await session2.nextTurn();
|
|
10167
|
-
|
|
10168
|
-
turn,
|
|
10169
|
-
|
|
10170
|
-
|
|
10171
|
-
|
|
10411
|
+
const turn = options.turn ?? await session2.nextTurn();
|
|
10412
|
+
if (options.turn === void 0) {
|
|
10413
|
+
await session2.append("turn/start", {
|
|
10414
|
+
turn,
|
|
10415
|
+
input: claimed.text ?? claimed,
|
|
10416
|
+
reason: "user"
|
|
10417
|
+
});
|
|
10418
|
+
}
|
|
10172
10419
|
let index = 0;
|
|
10173
10420
|
let finalTurnGranted = false;
|
|
10174
10421
|
let currentStepIndex;
|
|
@@ -10187,20 +10434,22 @@ var AgentService = class {
|
|
|
10187
10434
|
messages = await this._enforceContextBudget(session2, contextBudget, messages);
|
|
10188
10435
|
}
|
|
10189
10436
|
const stepInput = copyMessages(messages);
|
|
10190
|
-
const preStep = this.ctx.
|
|
10437
|
+
const preStep = await this.ctx.waterfallAsync("agent/pre-step", {
|
|
10191
10438
|
index,
|
|
10192
10439
|
turn,
|
|
10193
10440
|
step: index,
|
|
10194
10441
|
messages: stepInput,
|
|
10442
|
+
claimedMessages: copyMessages(claimedMessages),
|
|
10195
10443
|
...options.signal ? { signal: options.signal } : {}
|
|
10196
10444
|
}, (payload) => payload);
|
|
10197
|
-
if (!preStep || !Array.isArray(preStep.messages) || !preStep.messages.length) {
|
|
10445
|
+
if (!preStep || preStep.admission === "reject" || !Array.isArray(preStep.messages) || !preStep.messages.length) {
|
|
10198
10446
|
break;
|
|
10199
10447
|
}
|
|
10200
10448
|
if (preStep.startsRequestSeries) this._seriesStarted = true;
|
|
10201
10449
|
await session2.append("step/start", { turn, step: index });
|
|
10202
10450
|
currentStepIndex = index;
|
|
10203
10451
|
const requestedInput = copyMessages(preStep.messages);
|
|
10452
|
+
const admittedHistory = await session2.deriveMessages();
|
|
10204
10453
|
this.ctx.emit("agent/step", {
|
|
10205
10454
|
index,
|
|
10206
10455
|
turn,
|
|
@@ -10212,93 +10461,85 @@ var AgentService = class {
|
|
|
10212
10461
|
maxSteps: maxSteps - steps.length
|
|
10213
10462
|
};
|
|
10214
10463
|
if (options.signal) completeOptions.signal = options.signal;
|
|
10215
|
-
const request = this.ctx.waterfall("agent/request", {
|
|
10216
|
-
index,
|
|
10217
|
-
messages: requestedInput,
|
|
10218
|
-
tools: availableTools,
|
|
10219
|
-
options: completeOptions
|
|
10220
|
-
}, (payload) => payload);
|
|
10221
|
-
if (!request || !request.options || !request.tools) {
|
|
10222
|
-
throw new AgentError("agent/request must return a request payload");
|
|
10223
|
-
}
|
|
10224
10464
|
let llmMessages = copyMessages(requestedInput);
|
|
10225
10465
|
let completion;
|
|
10226
|
-
|
|
10466
|
+
let activeAttempt;
|
|
10227
10467
|
let attempt = 0;
|
|
10228
|
-
let persistedStepInput = false;
|
|
10229
10468
|
while (true) {
|
|
10230
10469
|
if (options.signal?.aborted) {
|
|
10231
10470
|
finishReason = "cancelled";
|
|
10232
10471
|
break;
|
|
10233
10472
|
}
|
|
10234
10473
|
const streamEvents = [];
|
|
10474
|
+
activeAttempt = this._attempt(session2, turn, index);
|
|
10475
|
+
yield activeAttempt.start();
|
|
10476
|
+
const streamRequest = {
|
|
10477
|
+
index,
|
|
10478
|
+
messages: copyMessages(requestedInput),
|
|
10479
|
+
tools: [...availableTools],
|
|
10480
|
+
options: { ...completeOptions }
|
|
10481
|
+
};
|
|
10235
10482
|
try {
|
|
10236
|
-
|
|
10237
|
-
|
|
10238
|
-
|
|
10239
|
-
|
|
10240
|
-
|
|
10241
|
-
|
|
10242
|
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
return streamMethod(payload.messages, payload.tools, payload.options);
|
|
10251
|
-
}
|
|
10252
|
-
);
|
|
10253
|
-
if (!stream || typeof stream[Symbol.asyncIterator] !== "function") {
|
|
10254
|
-
throw new AgentError("llm/stream must return an async iterable stream");
|
|
10255
|
-
}
|
|
10483
|
+
const request = await this.ctx.waterfallAsync("agent/request", {
|
|
10484
|
+
index,
|
|
10485
|
+
messages: copyMessages(requestedInput),
|
|
10486
|
+
tools: streamRequest.tools,
|
|
10487
|
+
options: streamRequest.options
|
|
10488
|
+
}, (payload) => payload);
|
|
10489
|
+
if (!request || !request.options || !request.tools) {
|
|
10490
|
+
throw new AgentError("agent/request must return a request payload");
|
|
10491
|
+
}
|
|
10492
|
+
streamRequest.tools = request.tools;
|
|
10493
|
+
streamRequest.options = request.options;
|
|
10494
|
+
let preparation;
|
|
10495
|
+
const prepareRequest = () => preparation ??= (async () => {
|
|
10496
|
+
lockStreamRequest(streamRequest);
|
|
10256
10497
|
llmMessages = copyMessages(streamRequest.messages);
|
|
10257
|
-
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10265
|
-
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
|
|
10283
|
-
}
|
|
10284
|
-
persistedStepInput = true;
|
|
10498
|
+
await this._persistStepInput(session2, streamRequest, llmMessages, admittedHistory);
|
|
10499
|
+
await this._assertReplayable(session2, streamRequest, llmMessages);
|
|
10500
|
+
})();
|
|
10501
|
+
const stream = await this.ctx.waterfallAsync(
|
|
10502
|
+
"llm/stream",
|
|
10503
|
+
streamRequest,
|
|
10504
|
+
(payload) => (async function* () {
|
|
10505
|
+
await prepareRequest();
|
|
10506
|
+
yield* streamAdapter ? streamAdapter.call(llm, payload.messages, payload.tools, payload.options) : completeAsStream(llm, payload.messages, payload.tools, payload.options);
|
|
10507
|
+
})()
|
|
10508
|
+
);
|
|
10509
|
+
if (!stream || typeof stream[Symbol.asyncIterator] !== "function") {
|
|
10510
|
+
throw new AgentError("llm/stream must return an async iterable stream");
|
|
10511
|
+
}
|
|
10512
|
+
await prepareRequest();
|
|
10513
|
+
let chunkIndex = 0;
|
|
10514
|
+
for await (const event of stream) {
|
|
10515
|
+
streamEvents.push(structuredClone(event));
|
|
10516
|
+
yield activeAttempt.push(event);
|
|
10517
|
+
if (persistChunks && event.type === "message_delta") {
|
|
10518
|
+
await session2.append("assistant/chunk", {
|
|
10519
|
+
id: event.id,
|
|
10520
|
+
content: event.delta,
|
|
10521
|
+
index: chunkIndex
|
|
10522
|
+
});
|
|
10523
|
+
chunkIndex += 1;
|
|
10285
10524
|
}
|
|
10286
|
-
|
|
10525
|
+
yield event;
|
|
10526
|
+
}
|
|
10527
|
+
completion = completionFromStreamEvents(streamEvents);
|
|
10528
|
+
if (completion.finishReason === "error" || completion.finishReason === "cancelled") {
|
|
10529
|
+
const terminalReason = completion.finishReason;
|
|
10530
|
+
completion = void 0;
|
|
10531
|
+
throw new AgentError(`LLM stream finished with ${terminalReason}`);
|
|
10287
10532
|
}
|
|
10288
10533
|
break;
|
|
10289
10534
|
} catch (error2) {
|
|
10290
|
-
|
|
10291
|
-
if (content) {
|
|
10292
|
-
await session2.append("assistant/message", {
|
|
10293
|
-
content,
|
|
10294
|
-
interrupted: true
|
|
10295
|
-
});
|
|
10296
|
-
llmMessages = await session2.deriveMessages();
|
|
10297
|
-
}
|
|
10535
|
+
yield activeAttempt.push({ type: "stream_error", error: toToolError(error2) });
|
|
10298
10536
|
if (options.signal?.aborted) {
|
|
10537
|
+
const content = partialStreamContent(streamEvents);
|
|
10538
|
+
yield* this.settleAttempt(activeAttempt, content ? { content, interrupted: true } : void 0);
|
|
10299
10539
|
finishReason = "cancelled";
|
|
10300
10540
|
break;
|
|
10301
10541
|
}
|
|
10542
|
+
yield* this.settleAttempt(activeAttempt);
|
|
10302
10543
|
attempt += 1;
|
|
10303
10544
|
const failure = toToolError(error2);
|
|
10304
10545
|
const decision = await this.ctx.waterfallAsync(
|
|
@@ -10307,14 +10548,14 @@ var AgentService = class {
|
|
|
10307
10548
|
index,
|
|
10308
10549
|
turn,
|
|
10309
10550
|
step: index,
|
|
10310
|
-
messages: copyMessages(
|
|
10311
|
-
tools:
|
|
10312
|
-
options:
|
|
10551
|
+
messages: copyMessages(streamRequest.messages),
|
|
10552
|
+
tools: [...streamRequest.tools],
|
|
10553
|
+
options: { ...streamRequest.options },
|
|
10313
10554
|
attempt,
|
|
10314
10555
|
error: error2,
|
|
10315
10556
|
failure,
|
|
10316
|
-
...
|
|
10317
|
-
...
|
|
10557
|
+
...streamRequest.options.provider ? { provider: streamRequest.options.provider } : {},
|
|
10558
|
+
...streamRequest.options.model ? { model: streamRequest.options.model } : {},
|
|
10318
10559
|
...options.signal ? { signal: options.signal } : {}
|
|
10319
10560
|
},
|
|
10320
10561
|
() => void 0
|
|
@@ -10339,16 +10580,30 @@ var AgentService = class {
|
|
|
10339
10580
|
await session2.append("llm/retry-started", { retryId, retry: attempt });
|
|
10340
10581
|
}
|
|
10341
10582
|
}
|
|
10342
|
-
if (
|
|
10343
|
-
|
|
10583
|
+
if (!completion || !activeAttempt) {
|
|
10584
|
+
if (options.signal?.aborted) {
|
|
10585
|
+
finishReason = "cancelled";
|
|
10586
|
+
break;
|
|
10587
|
+
}
|
|
10588
|
+
throw new AgentError("LLM adapter did not produce a completion");
|
|
10589
|
+
}
|
|
10344
10590
|
const toolCalls = completion.toolCalls ?? [];
|
|
10345
|
-
if (
|
|
10591
|
+
if (completion.finishReason === "length") lengthReached = true;
|
|
10592
|
+
if (options.signal?.aborted && toolCalls.length === 0) {
|
|
10593
|
+
yield activeAttempt.push({ type: "stream_error", error: { name: "AbortError", message: "stream aborted" } });
|
|
10594
|
+
yield* this.settleAttempt(activeAttempt);
|
|
10595
|
+
finishReason = "cancelled";
|
|
10596
|
+
break;
|
|
10597
|
+
}
|
|
10598
|
+
if (finalTurnGranted && toolCalls.length && !options.signal?.aborted) {
|
|
10599
|
+
yield activeAttempt.push({ type: "stream_error", error: { name: "AgentError", message: "maximum turns reached" } });
|
|
10600
|
+
yield* this.settleAttempt(activeAttempt);
|
|
10346
10601
|
finishReason = "max_turns";
|
|
10347
10602
|
break;
|
|
10348
10603
|
}
|
|
10349
10604
|
const toolResults = [];
|
|
10350
10605
|
if (toolCalls.length) {
|
|
10351
|
-
|
|
10606
|
+
yield* this.settleAttempt(activeAttempt, {
|
|
10352
10607
|
content: completion.content ?? "",
|
|
10353
10608
|
toolCalls: toolCalls.map((call) => ({
|
|
10354
10609
|
id: call.id,
|
|
@@ -10369,18 +10624,30 @@ var AgentService = class {
|
|
|
10369
10624
|
if (options.signal) toolOptions.signal = options.signal;
|
|
10370
10625
|
const startedAt = Date.now();
|
|
10371
10626
|
let result;
|
|
10372
|
-
|
|
10373
|
-
result = await tools2.execute(call.name, call.arguments, toolOptions);
|
|
10374
|
-
} catch (error2) {
|
|
10627
|
+
if (options.signal?.aborted) {
|
|
10375
10628
|
result = {
|
|
10376
10629
|
ok: false,
|
|
10377
10630
|
name: call.name,
|
|
10378
10631
|
callId: call.id,
|
|
10379
10632
|
input: call.arguments,
|
|
10380
|
-
error:
|
|
10633
|
+
error: abortedToolError(options.signal),
|
|
10381
10634
|
startedAt,
|
|
10382
10635
|
durationMs: Date.now() - startedAt
|
|
10383
10636
|
};
|
|
10637
|
+
} else {
|
|
10638
|
+
try {
|
|
10639
|
+
result = await tools2.execute(call.name, call.arguments, toolOptions);
|
|
10640
|
+
} catch (error2) {
|
|
10641
|
+
result = {
|
|
10642
|
+
ok: false,
|
|
10643
|
+
name: call.name,
|
|
10644
|
+
callId: call.id,
|
|
10645
|
+
input: call.arguments,
|
|
10646
|
+
error: toToolError(error2),
|
|
10647
|
+
startedAt,
|
|
10648
|
+
durationMs: Date.now() - startedAt
|
|
10649
|
+
};
|
|
10650
|
+
}
|
|
10384
10651
|
}
|
|
10385
10652
|
toolResults.push(result);
|
|
10386
10653
|
const toolResultPayload = {
|
|
@@ -10422,7 +10689,7 @@ var AgentService = class {
|
|
|
10422
10689
|
output = completion.content;
|
|
10423
10690
|
}
|
|
10424
10691
|
if (!toolCalls.length) {
|
|
10425
|
-
|
|
10692
|
+
yield* this.settleAttempt(activeAttempt, { content: completion.content ?? "" });
|
|
10426
10693
|
}
|
|
10427
10694
|
await session2.append("step/end", {
|
|
10428
10695
|
turn,
|
|
@@ -10433,19 +10700,19 @@ var AgentService = class {
|
|
|
10433
10700
|
currentStepIndex = void 0;
|
|
10434
10701
|
const nextMessages = this._extendMessages(llmMessages, completion, toolResults);
|
|
10435
10702
|
const concludesTurn = toolResults.some((result) => result.concludesTurn === true);
|
|
10436
|
-
|
|
10437
|
-
|
|
10438
|
-
|
|
10439
|
-
}
|
|
10440
|
-
if (toolCalls.length === 0) {
|
|
10441
|
-
finishReason = completion.finishReason === "length" ? "length" : completion.finishReason === "error" ? "error" : "stop";
|
|
10703
|
+
let nextStepMessages = await this._claimNextStepMessages();
|
|
10704
|
+
if ((toolCalls.length === 0 || concludesTurn) && nextStepMessages.length === 0) {
|
|
10705
|
+
finishReason = lengthReached ? "length" : completion.finishReason === "error" ? "error" : "stop";
|
|
10442
10706
|
const keepGoing = await this.ctx.serial("agent/turn-stopping", {
|
|
10443
10707
|
index,
|
|
10444
10708
|
turn,
|
|
10445
10709
|
steps: copySteps(steps),
|
|
10446
10710
|
finishReason
|
|
10447
10711
|
});
|
|
10448
|
-
if (!keepGoing)
|
|
10712
|
+
if (!keepGoing) {
|
|
10713
|
+
nextStepMessages = await this._claimNextStepMessages();
|
|
10714
|
+
if (nextStepMessages.length === 0) break;
|
|
10715
|
+
}
|
|
10449
10716
|
}
|
|
10450
10717
|
if (index + 1 >= maxTurns && !finalTurnGranted) {
|
|
10451
10718
|
finalTurnGranted = true;
|
|
@@ -10455,7 +10722,8 @@ var AgentService = class {
|
|
|
10455
10722
|
}
|
|
10456
10723
|
if (toolCalls.length) finishReason = "tool_calls";
|
|
10457
10724
|
index += 1;
|
|
10458
|
-
messages = nextMessages;
|
|
10725
|
+
messages = [...nextMessages, ...nextStepMessages];
|
|
10726
|
+
claimedMessages = nextStepMessages.filter((message3) => message3.role === "user");
|
|
10459
10727
|
}
|
|
10460
10728
|
} catch (error2) {
|
|
10461
10729
|
turnError = error2;
|
|
@@ -10541,23 +10809,22 @@ var AgentService = class {
|
|
|
10541
10809
|
});
|
|
10542
10810
|
return compactMessages.map((message3) => copyMessages([message3])[0]);
|
|
10543
10811
|
}
|
|
10544
|
-
async _persistStepInput(session2, request, input) {
|
|
10545
|
-
const
|
|
10546
|
-
const
|
|
10547
|
-
|
|
10548
|
-
|
|
10549
|
-
|
|
10550
|
-
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
10554
|
-
|
|
10555
|
-
|
|
10556
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
};
|
|
10812
|
+
async _persistStepInput(session2, request, input, admittedHistory) {
|
|
10813
|
+
const surface = await session2.deriveMessages();
|
|
10814
|
+
const owned = admittedHistory.filter((message3) => !isUserOrSystemMessage(message3));
|
|
10815
|
+
let ownerIndex = 0;
|
|
10816
|
+
for (const message3 of input) {
|
|
10817
|
+
if (isUserOrSystemMessage(message3)) continue;
|
|
10818
|
+
const actual = canonicalMessages([message3]);
|
|
10819
|
+
while (ownerIndex < owned.length && canonicalMessages([owned[ownerIndex]]) !== actual) {
|
|
10820
|
+
ownerIndex += 1;
|
|
10821
|
+
}
|
|
10822
|
+
if (ownerIndex === owned.length) {
|
|
10823
|
+
throw new AgentError("request is not reconstructable from session log: unowned or reordered assistant/tool message");
|
|
10824
|
+
}
|
|
10825
|
+
ownerIndex += 1;
|
|
10826
|
+
}
|
|
10827
|
+
const nextHeader = requestHeaderFor(request, input);
|
|
10561
10828
|
const previousHeader = session2.requestHeader();
|
|
10562
10829
|
const isFirstRequest = !this._persistedRequest;
|
|
10563
10830
|
const isResume = isFirstRequest && previousHeader !== void 0;
|
|
@@ -10587,19 +10854,23 @@ var AgentService = class {
|
|
|
10587
10854
|
...request.options.provider ? { provider: request.options.provider } : {},
|
|
10588
10855
|
...request.options.model ? { model: request.options.model } : {}
|
|
10589
10856
|
};
|
|
10857
|
+
if (request.options.contextWindow !== void 0) {
|
|
10858
|
+
nextContext.contextWindow = request.options.contextWindow;
|
|
10859
|
+
}
|
|
10590
10860
|
const llmService = this.ctx.reflect.get("llm", false);
|
|
10591
10861
|
const routeCapacity = llmService?.routeCapacity?.();
|
|
10592
|
-
if (routeCapacity?.contextWindow !== void 0) {
|
|
10862
|
+
if (nextContext.contextWindow === void 0 && routeCapacity?.contextWindow !== void 0) {
|
|
10593
10863
|
nextContext.contextWindow = routeCapacity.contextWindow;
|
|
10594
10864
|
}
|
|
10595
10865
|
const previousContext = session2.requestContext();
|
|
10596
10866
|
if (previousContext?.provider !== nextContext.provider || previousContext?.model !== nextContext.model || previousContext?.contextWindow !== nextContext.contextWindow || previousContext === void 0) {
|
|
10597
10867
|
await session2.append("request/context", nextContext);
|
|
10598
10868
|
}
|
|
10599
|
-
const
|
|
10600
|
-
const
|
|
10601
|
-
const
|
|
10602
|
-
|
|
10869
|
+
const isSurfacePrefix = (messages) => canonicalMessages(messages.slice(0, surface.length)) === canonicalMessages(surface);
|
|
10870
|
+
const requested = surface.length > 0 && input[0]?.role === "system" && input[0].content === nextHeader.system && isSurfacePrefix(input.slice(1)) ? input.slice(1) : input;
|
|
10871
|
+
const tail = requested.slice(surface.length);
|
|
10872
|
+
if (isSurfacePrefix(requested) && tail.every(isUserOrSystemMessage)) {
|
|
10873
|
+
for (const message3 of tail) {
|
|
10603
10874
|
if (message3.role === "user") {
|
|
10604
10875
|
await session2.append("user/message", {
|
|
10605
10876
|
content: message3.content,
|
|
@@ -10612,45 +10883,37 @@ var AgentService = class {
|
|
|
10612
10883
|
});
|
|
10613
10884
|
}
|
|
10614
10885
|
}
|
|
10615
|
-
};
|
|
10616
|
-
if (surface.length === 0) {
|
|
10617
|
-
await appendDurable(requested);
|
|
10618
10886
|
return;
|
|
10619
10887
|
}
|
|
10620
|
-
const
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
if (seenUsers <= durableUsers) continue;
|
|
10626
|
-
newTail.push(message3);
|
|
10627
|
-
}
|
|
10628
|
-
await appendDurable(newTail);
|
|
10888
|
+
const nodes = await session2.surfaceEvents();
|
|
10889
|
+
await session2.append("checkpoint", {
|
|
10890
|
+
messages: copyMessages(requested),
|
|
10891
|
+
surfaceOp: { op: "replace", start: nodes[0].seq, end: nodes.at(-1).seq }
|
|
10892
|
+
});
|
|
10629
10893
|
}
|
|
10630
|
-
async _assertReplayable(session2, input) {
|
|
10894
|
+
async _assertReplayable(session2, request, input) {
|
|
10631
10895
|
const reconstructed = await session2.deriveMessages();
|
|
10632
|
-
const
|
|
10633
|
-
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
...message3.tool_calls?.length ? { tool_calls: message3.tool_calls.map((call) => ({
|
|
10638
|
-
id: call.id,
|
|
10639
|
-
name: call.name,
|
|
10640
|
-
args: JSON.stringify(call.arguments ?? {})
|
|
10641
|
-
})) } : {}
|
|
10642
|
-
}));
|
|
10643
|
-
const actual = canonical(input);
|
|
10644
|
-
const replay = canonical(reconstructed);
|
|
10645
|
-
if (JSON.stringify(actual) !== JSON.stringify(replay)) {
|
|
10896
|
+
const actual = canonicalMessages(input);
|
|
10897
|
+
const replay = canonicalMessages(reconstructed);
|
|
10898
|
+
const header = session2.requestHeader();
|
|
10899
|
+
const headerOwnsPrefix = input[0]?.role === "system" && input[0].content === header?.system && canonicalMessages(input.slice(1)) === replay;
|
|
10900
|
+
if (actual !== replay && !headerOwnsPrefix) {
|
|
10646
10901
|
throw new AgentError(
|
|
10647
|
-
`request is not reconstructable from session log: actual=${
|
|
10902
|
+
`request is not reconstructable from session log: actual=${actual} replay=${replay}`
|
|
10648
10903
|
);
|
|
10649
10904
|
}
|
|
10905
|
+
const expected = requestHeaderFor(request, input);
|
|
10906
|
+
if (header?.system !== expected.system || JSON.stringify(header?.tools ?? []) !== JSON.stringify(expected.tools ?? []) || JSON.stringify(header?.config ?? {}) !== JSON.stringify(expected.config ?? {})) {
|
|
10907
|
+
throw new AgentError("request envelope is not reconstructable from session log");
|
|
10908
|
+
}
|
|
10909
|
+
}
|
|
10910
|
+
async _claimNextStepMessages() {
|
|
10911
|
+
const inputs = await this.config.claimNextStep?.() ?? [];
|
|
10912
|
+
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) }] : []);
|
|
10650
10913
|
}
|
|
10651
10914
|
async _initialMessages(input) {
|
|
10652
10915
|
const promptService = this.ctx.reflect.get("systemPrompt", false);
|
|
10653
|
-
const assembled = promptService ? (await promptService.assemble()).text.trim() : void 0;
|
|
10916
|
+
const assembled = promptService ? (await promptService.assemble({}, this.ctx)).text.trim() : void 0;
|
|
10654
10917
|
const systemPrompt3 = assembled || this.inbox.injected().get("agentSystem");
|
|
10655
10918
|
const systemMessage = typeof systemPrompt3 === "string" && systemPrompt3 ? [{ role: "system", content: systemPrompt3 }] : [];
|
|
10656
10919
|
if (input.messages?.length) {
|
|
@@ -10675,7 +10938,7 @@ var AgentService = class {
|
|
|
10675
10938
|
arguments: call.arguments
|
|
10676
10939
|
}));
|
|
10677
10940
|
}
|
|
10678
|
-
next.push(assistant);
|
|
10941
|
+
if (assistant.content || toolCalls.length) next.push(assistant);
|
|
10679
10942
|
for (const call of toolCalls) {
|
|
10680
10943
|
const result = toolResults.find((candidate) => candidate.callId === call.id);
|
|
10681
10944
|
const content = result ? result.ok ? stringify2(result.output) : `error: ${result.error?.message ?? "unknown"}` : "error: missing tool result";
|
|
@@ -10705,7 +10968,8 @@ var AgentService = class {
|
|
|
10705
10968
|
return session2;
|
|
10706
10969
|
}
|
|
10707
10970
|
_tools() {
|
|
10708
|
-
const
|
|
10971
|
+
const scoped = this.ctx.reflect.get("tools", false);
|
|
10972
|
+
const tools2 = scoped ?? this.ctx.tools;
|
|
10709
10973
|
if (!tools2) throw new AgentError("tools service is required");
|
|
10710
10974
|
return tools2;
|
|
10711
10975
|
}
|
|
@@ -10888,67 +11152,77 @@ var DurableInbox = class _DurableInbox {
|
|
|
10888
11152
|
_session;
|
|
10889
11153
|
_nextTurn = [];
|
|
10890
11154
|
_nextStep = [];
|
|
11155
|
+
_operationTail = Promise.resolve();
|
|
10891
11156
|
get size() {
|
|
10892
11157
|
return this._nextTurn.length + this._nextStep.length;
|
|
10893
11158
|
}
|
|
10894
11159
|
async insert(input, target = "next-turn") {
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
11160
|
+
return this._run(async () => {
|
|
11161
|
+
const message3 = {
|
|
11162
|
+
id: randomUUID3(),
|
|
11163
|
+
...input.text !== void 0 ? { text: input.text } : {},
|
|
11164
|
+
...input.content !== void 0 ? { content: input.content } : {}
|
|
11165
|
+
};
|
|
11166
|
+
const list = target === "next-step" ? this._nextStep : this._nextTurn;
|
|
11167
|
+
const index = list.length;
|
|
11168
|
+
await this._session.append("agent/inbox/spliced", {
|
|
11169
|
+
target,
|
|
11170
|
+
index,
|
|
11171
|
+
inserted: [{
|
|
11172
|
+
id: message3.id,
|
|
11173
|
+
content: contentOf(message3),
|
|
11174
|
+
...payloadOf(message3) !== void 0 ? { payload: payloadOf(message3) } : {}
|
|
11175
|
+
}]
|
|
11176
|
+
});
|
|
11177
|
+
list.push(message3);
|
|
11178
|
+
return message3;
|
|
10910
11179
|
});
|
|
10911
|
-
return message3;
|
|
10912
11180
|
}
|
|
10913
11181
|
async steer(input) {
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
await this._session.append("agent/inbox/spliced", {
|
|
10921
|
-
target: "next-step",
|
|
10922
|
-
index: 0,
|
|
10923
|
-
inserted: [{
|
|
10924
|
-
id: message3.id,
|
|
10925
|
-
content: contentOf(message3),
|
|
10926
|
-
...payloadOf(message3) !== void 0 ? { payload: payloadOf(message3) } : {},
|
|
10927
|
-
mode: "steer"
|
|
10928
|
-
}]
|
|
10929
|
-
});
|
|
10930
|
-
return message3;
|
|
10931
|
-
}
|
|
10932
|
-
async claim() {
|
|
10933
|
-
const steered = this._nextStep.shift();
|
|
10934
|
-
if (steered) {
|
|
11182
|
+
return this._run(async () => {
|
|
11183
|
+
const message3 = {
|
|
11184
|
+
id: randomUUID3(),
|
|
11185
|
+
...input.text !== void 0 ? { text: input.text } : {},
|
|
11186
|
+
...input.content !== void 0 ? { content: input.content } : {}
|
|
11187
|
+
};
|
|
10935
11188
|
await this._session.append("agent/inbox/spliced", {
|
|
10936
11189
|
target: "next-step",
|
|
10937
|
-
index:
|
|
10938
|
-
|
|
11190
|
+
index: this._nextStep.length,
|
|
11191
|
+
inserted: [{
|
|
11192
|
+
id: message3.id,
|
|
11193
|
+
content: contentOf(message3),
|
|
11194
|
+
...payloadOf(message3) !== void 0 ? { payload: payloadOf(message3) } : {},
|
|
11195
|
+
mode: "steer"
|
|
11196
|
+
}]
|
|
10939
11197
|
});
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
10946
|
-
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
10950
|
-
|
|
10951
|
-
|
|
11198
|
+
this._nextStep.push(message3);
|
|
11199
|
+
return message3;
|
|
11200
|
+
});
|
|
11201
|
+
}
|
|
11202
|
+
async claim() {
|
|
11203
|
+
return this._run(async () => {
|
|
11204
|
+
const steered = this._nextStep[0];
|
|
11205
|
+
if (steered) {
|
|
11206
|
+
await this._session.append("agent/inbox/spliced", {
|
|
11207
|
+
target: "next-step",
|
|
11208
|
+
index: 0,
|
|
11209
|
+
deleteCount: 1
|
|
11210
|
+
});
|
|
11211
|
+
this._nextStep.shift();
|
|
11212
|
+
return steered;
|
|
11213
|
+
}
|
|
11214
|
+
const next = this._nextTurn[0];
|
|
11215
|
+
if (next) {
|
|
11216
|
+
await this._session.append("agent/inbox/spliced", {
|
|
11217
|
+
target: "next-turn",
|
|
11218
|
+
index: 0,
|
|
11219
|
+
deleteCount: 1
|
|
11220
|
+
});
|
|
11221
|
+
this._nextTurn.shift();
|
|
11222
|
+
return next;
|
|
11223
|
+
}
|
|
11224
|
+
return void 0;
|
|
11225
|
+
});
|
|
10952
11226
|
}
|
|
10953
11227
|
/**
|
|
10954
11228
|
* Claim the complete proposed step batch: every pending next-step input plus
|
|
@@ -10956,105 +11230,108 @@ var DurableInbox = class _DurableInbox {
|
|
|
10956
11230
|
* nothing is pending.
|
|
10957
11231
|
*/
|
|
10958
11232
|
async claimBatch() {
|
|
10959
|
-
|
|
10960
|
-
|
|
10961
|
-
const
|
|
10962
|
-
claimed.push(
|
|
11233
|
+
return this._run(async () => {
|
|
11234
|
+
const claimed = [...this._nextStep];
|
|
11235
|
+
const nextTurn = this._nextTurn[0];
|
|
11236
|
+
if (nextTurn) claimed.push(nextTurn);
|
|
11237
|
+
if (!claimed.length) return [];
|
|
11238
|
+
const deleteCounts = { nextStep: this._nextStep.length, nextTurn: nextTurn ? 1 : 0 };
|
|
11239
|
+
await this._session.append("agent/inbox/spliced", { target: "all", deleteCounts });
|
|
11240
|
+
this._nextStep.splice(0, deleteCounts.nextStep);
|
|
11241
|
+
this._nextTurn.splice(0, deleteCounts.nextTurn);
|
|
11242
|
+
return claimed;
|
|
11243
|
+
});
|
|
11244
|
+
}
|
|
11245
|
+
/** Claim every input waiting for the next step, without consuming a turn. */
|
|
11246
|
+
async claimNextStep() {
|
|
11247
|
+
return this._run(async () => {
|
|
11248
|
+
if (!this._nextStep.length) return [];
|
|
11249
|
+
const claimed = [...this._nextStep];
|
|
10963
11250
|
await this._session.append("agent/inbox/spliced", {
|
|
10964
11251
|
target: "next-step",
|
|
10965
11252
|
index: 0,
|
|
10966
|
-
deleteCount:
|
|
10967
|
-
});
|
|
10968
|
-
}
|
|
10969
|
-
const nextTurn = this._nextTurn.shift();
|
|
10970
|
-
if (nextTurn) {
|
|
10971
|
-
claimed.push(nextTurn);
|
|
10972
|
-
await this._session.append("agent/inbox/spliced", {
|
|
10973
|
-
target: "next-turn",
|
|
10974
|
-
index: 0,
|
|
10975
|
-
deleteCount: 1
|
|
11253
|
+
deleteCount: claimed.length
|
|
10976
11254
|
});
|
|
10977
|
-
|
|
10978
|
-
|
|
11255
|
+
this._nextStep.splice(0, claimed.length);
|
|
11256
|
+
return claimed;
|
|
11257
|
+
});
|
|
10979
11258
|
}
|
|
10980
11259
|
async clear() {
|
|
10981
|
-
|
|
10982
|
-
this._nextTurn
|
|
11260
|
+
return this._run(async () => {
|
|
11261
|
+
if (!this._nextTurn.length && !this._nextStep.length) return;
|
|
10983
11262
|
await this._session.append("agent/inbox/spliced", {
|
|
10984
|
-
target: "
|
|
10985
|
-
index: 0,
|
|
10986
|
-
deleteCount: Number.POSITIVE_INFINITY
|
|
11263
|
+
target: "all"
|
|
10987
11264
|
});
|
|
10988
|
-
|
|
10989
|
-
if (this._nextStep.length) {
|
|
11265
|
+
this._nextTurn = [];
|
|
10990
11266
|
this._nextStep = [];
|
|
10991
|
-
|
|
10992
|
-
target: "next-step",
|
|
10993
|
-
index: 0,
|
|
10994
|
-
deleteCount: Number.POSITIVE_INFINITY
|
|
10995
|
-
});
|
|
10996
|
-
}
|
|
11267
|
+
});
|
|
10997
11268
|
}
|
|
10998
11269
|
/** Insert a message at an explicit target/index boundary. */
|
|
10999
11270
|
async insertAt(input, target, index, mode = "followup") {
|
|
11000
|
-
|
|
11001
|
-
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
|
|
11006
|
-
|
|
11007
|
-
|
|
11008
|
-
|
|
11009
|
-
|
|
11010
|
-
|
|
11011
|
-
|
|
11012
|
-
|
|
11013
|
-
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11271
|
+
return this._run(async () => {
|
|
11272
|
+
const message3 = {
|
|
11273
|
+
id: randomUUID3(),
|
|
11274
|
+
...input.text !== void 0 ? { text: input.text } : {},
|
|
11275
|
+
...input.content !== void 0 ? { content: input.content } : {}
|
|
11276
|
+
};
|
|
11277
|
+
const list = target === "next-step" ? this._nextStep : this._nextTurn;
|
|
11278
|
+
const safeIndex = Math.max(0, Math.min(index, list.length));
|
|
11279
|
+
await this._session.append("agent/inbox/spliced", {
|
|
11280
|
+
target,
|
|
11281
|
+
index: safeIndex,
|
|
11282
|
+
inserted: [{
|
|
11283
|
+
id: message3.id,
|
|
11284
|
+
content: contentOf(message3),
|
|
11285
|
+
...payloadOf(message3) !== void 0 ? { payload: payloadOf(message3) } : {},
|
|
11286
|
+
mode
|
|
11287
|
+
}]
|
|
11288
|
+
});
|
|
11289
|
+
list.splice(safeIndex, 0, message3);
|
|
11290
|
+
return message3;
|
|
11017
11291
|
});
|
|
11018
|
-
return message3;
|
|
11019
11292
|
}
|
|
11020
11293
|
/**
|
|
11021
11294
|
* Replace one pending message by id. The old message is emitted as
|
|
11022
11295
|
* discarded and the new one as inserted, matching the DSH inbox contract.
|
|
11023
11296
|
*/
|
|
11024
11297
|
async replace(messageId, input) {
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
|
|
11029
|
-
|
|
11030
|
-
|
|
11031
|
-
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11298
|
+
return this._run(async () => {
|
|
11299
|
+
const entry = this._find(messageId);
|
|
11300
|
+
if (!entry) return void 0;
|
|
11301
|
+
const replacement = {
|
|
11302
|
+
id: randomUUID3(),
|
|
11303
|
+
...input.text !== void 0 ? { text: input.text } : {},
|
|
11304
|
+
...input.content !== void 0 ? { content: input.content } : {}
|
|
11305
|
+
};
|
|
11306
|
+
const target = entry.target;
|
|
11307
|
+
const index = entry.index;
|
|
11308
|
+
await this._session.append("agent/inbox/spliced", {
|
|
11309
|
+
target,
|
|
11310
|
+
index,
|
|
11311
|
+
deleteCount: 1,
|
|
11312
|
+
inserted: [{
|
|
11313
|
+
id: replacement.id,
|
|
11314
|
+
content: contentOf(replacement),
|
|
11315
|
+
...payloadOf(replacement) !== void 0 ? { payload: payloadOf(replacement) } : {}
|
|
11316
|
+
}]
|
|
11317
|
+
});
|
|
11318
|
+
entry.list.splice(index, 1, replacement);
|
|
11319
|
+
return replacement;
|
|
11044
11320
|
});
|
|
11045
|
-
return replacement;
|
|
11046
11321
|
}
|
|
11047
11322
|
/** Remove one pending message by id. */
|
|
11048
11323
|
async remove(messageId) {
|
|
11049
|
-
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11324
|
+
return this._run(async () => {
|
|
11325
|
+
const entry = this._find(messageId);
|
|
11326
|
+
if (!entry) return void 0;
|
|
11327
|
+
await this._session.append("agent/inbox/spliced", {
|
|
11328
|
+
target: entry.target,
|
|
11329
|
+
index: entry.index,
|
|
11330
|
+
deleteCount: 1
|
|
11331
|
+
});
|
|
11332
|
+
entry.list.splice(entry.index, 1);
|
|
11333
|
+
return entry.message;
|
|
11056
11334
|
});
|
|
11057
|
-
return entry.message;
|
|
11058
11335
|
}
|
|
11059
11336
|
/** Return the first pending message by id across both queues. */
|
|
11060
11337
|
get(messageId) {
|
|
@@ -11066,6 +11343,12 @@ var DurableInbox = class _DurableInbox {
|
|
|
11066
11343
|
nextStep: [...this._nextStep]
|
|
11067
11344
|
};
|
|
11068
11345
|
}
|
|
11346
|
+
/** Keep the entire read → append → apply transition ordered, including claims. */
|
|
11347
|
+
_run(operation) {
|
|
11348
|
+
const result = this._operationTail.then(operation);
|
|
11349
|
+
this._operationTail = result.then(() => void 0, () => void 0);
|
|
11350
|
+
return result;
|
|
11351
|
+
}
|
|
11069
11352
|
_find(messageId) {
|
|
11070
11353
|
for (const target of ["next-step", "next-turn"]) {
|
|
11071
11354
|
const list = target === "next-step" ? this._nextStep : this._nextTurn;
|
|
@@ -11083,6 +11366,11 @@ var DurableInbox = class _DurableInbox {
|
|
|
11083
11366
|
for (const event of events) {
|
|
11084
11367
|
if (event.type !== "agent/inbox/spliced") continue;
|
|
11085
11368
|
const payload = event.payload;
|
|
11369
|
+
if (payload.target === "all") {
|
|
11370
|
+
this._nextTurn.splice(0, payload.deleteCounts?.nextTurn ?? this._nextTurn.length);
|
|
11371
|
+
this._nextStep.splice(0, payload.deleteCounts?.nextStep ?? this._nextStep.length);
|
|
11372
|
+
continue;
|
|
11373
|
+
}
|
|
11086
11374
|
const list = payload.target === "next-step" ? this._nextStep : this._nextTurn;
|
|
11087
11375
|
const count = payload.deleteCount ?? 0;
|
|
11088
11376
|
if (count === Number.POSITIVE_INFINITY) {
|
|
@@ -11112,8 +11400,29 @@ var DurableInbox = class _DurableInbox {
|
|
|
11112
11400
|
};
|
|
11113
11401
|
|
|
11114
11402
|
// packages/agent/src/live.ts
|
|
11403
|
+
function createAgentRuntimeContext(agentCtx) {
|
|
11404
|
+
const runtimeCtx = agentCtx.extend();
|
|
11405
|
+
Object.defineProperty(runtimeCtx, Context.filter, {
|
|
11406
|
+
value: (target) => {
|
|
11407
|
+
const targetScope = target[symbols.isolate].agentScope;
|
|
11408
|
+
let ancestor = agentCtx;
|
|
11409
|
+
while (true) {
|
|
11410
|
+
if (targetScope === ancestor[symbols.isolate].agentScope) return true;
|
|
11411
|
+
if (ancestor.fiber.parent.fiber === ancestor.fiber) return false;
|
|
11412
|
+
ancestor = ancestor.fiber.parent;
|
|
11413
|
+
}
|
|
11414
|
+
}
|
|
11415
|
+
});
|
|
11416
|
+
const events = agentCtx.events;
|
|
11417
|
+
for (const method of ["emit", "parallel", "serial", "bail", "waterfall", "waterfallAsync"]) {
|
|
11418
|
+
Object.defineProperty(runtimeCtx, method, {
|
|
11419
|
+
value: (...args) => events[method](runtimeCtx, ...args)
|
|
11420
|
+
});
|
|
11421
|
+
}
|
|
11422
|
+
return runtimeCtx;
|
|
11423
|
+
}
|
|
11115
11424
|
var LiveAgentImpl = class {
|
|
11116
|
-
constructor(_ctx, _agentCtx, _service, id, inbox, session2, durable, meta2, manualStreaming = false) {
|
|
11425
|
+
constructor(_ctx, _agentCtx, _service, id, inbox, session2, durable, meta2, manualStreaming = false, wakeReserved = false) {
|
|
11117
11426
|
this._ctx = _ctx;
|
|
11118
11427
|
this._agentCtx = _agentCtx;
|
|
11119
11428
|
this._service = _service;
|
|
@@ -11123,6 +11432,7 @@ var LiveAgentImpl = class {
|
|
|
11123
11432
|
this.meta = meta2;
|
|
11124
11433
|
this._durable = durable;
|
|
11125
11434
|
this._manualStreaming = manualStreaming;
|
|
11435
|
+
this._wakeReserved = wakeReserved;
|
|
11126
11436
|
}
|
|
11127
11437
|
_ctx;
|
|
11128
11438
|
_agentCtx;
|
|
@@ -11144,8 +11454,9 @@ var LiveAgentImpl = class {
|
|
|
11144
11454
|
_setupDisposers = [];
|
|
11145
11455
|
_scopeClosed = false;
|
|
11146
11456
|
_durable;
|
|
11147
|
-
_agentSystem;
|
|
11148
11457
|
_manualStreaming = false;
|
|
11458
|
+
_wakeReserved = false;
|
|
11459
|
+
_loop;
|
|
11149
11460
|
get agentType() {
|
|
11150
11461
|
return this.meta.agentType;
|
|
11151
11462
|
}
|
|
@@ -11172,13 +11483,41 @@ var LiveAgentImpl = class {
|
|
|
11172
11483
|
return this._ctx;
|
|
11173
11484
|
}
|
|
11174
11485
|
followup(input) {
|
|
11175
|
-
this._send(input, "followup");
|
|
11486
|
+
return this._send(input, "followup");
|
|
11487
|
+
}
|
|
11488
|
+
setLoop(loop) {
|
|
11489
|
+
this._loop = loop;
|
|
11490
|
+
}
|
|
11491
|
+
async _closeCustomTurn(turn, run) {
|
|
11492
|
+
const events = await this.session.read();
|
|
11493
|
+
if (events.some((event) => event.type === "turn/end" && event.payload.turn === turn)) return;
|
|
11494
|
+
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" };
|
|
11495
|
+
await this.session.append("turn/end", {
|
|
11496
|
+
turn,
|
|
11497
|
+
finishReason: run.finishReason,
|
|
11498
|
+
reason,
|
|
11499
|
+
...run.output ? { output: run.output } : {},
|
|
11500
|
+
...run.steps.length ? { steps: run.steps.length } : {}
|
|
11501
|
+
});
|
|
11502
|
+
}
|
|
11503
|
+
async _closeFailedCustomTurn(turn, error2) {
|
|
11504
|
+
const events = await this.session.read();
|
|
11505
|
+
if (events.some((event) => event.type === "turn/end" && event.payload.turn === turn)) return;
|
|
11506
|
+
const failure = error2 instanceof Error ? { name: error2.name, message: error2.message, ...error2.stack ? { stack: error2.stack } : {} } : { name: "Error", message: String(error2) };
|
|
11507
|
+
await this.session.append("turn/end", {
|
|
11508
|
+
turn,
|
|
11509
|
+
finishReason: "error",
|
|
11510
|
+
reason: { kind: "error", error: failure },
|
|
11511
|
+
interrupted: true,
|
|
11512
|
+
error: failure
|
|
11513
|
+
});
|
|
11176
11514
|
}
|
|
11177
11515
|
/** Replace one pending inbox message by durable message id. */
|
|
11178
11516
|
replaceMessage(messageId, input) {
|
|
11179
|
-
this._mutatePending(async () => {
|
|
11517
|
+
return this._mutatePending(async () => {
|
|
11180
11518
|
const previous = this._durable.get(messageId);
|
|
11181
|
-
|
|
11519
|
+
const target = this._findTarget(messageId);
|
|
11520
|
+
if (!previous || !target) return;
|
|
11182
11521
|
const replacement = await this._durable.replace(messageId, {
|
|
11183
11522
|
text: input.text ?? "",
|
|
11184
11523
|
...input.messages !== void 0 || input.context !== void 0 ? { content: input.messages ?? input.context } : {}
|
|
@@ -11189,18 +11528,19 @@ var LiveAgentImpl = class {
|
|
|
11189
11528
|
agent: this,
|
|
11190
11529
|
message: previous
|
|
11191
11530
|
});
|
|
11192
|
-
|
|
11531
|
+
const event = {
|
|
11193
11532
|
id: this.id,
|
|
11194
11533
|
agent: this,
|
|
11195
|
-
target
|
|
11534
|
+
target,
|
|
11196
11535
|
input: replacement,
|
|
11197
11536
|
inboxSeq: this._durable.size
|
|
11198
|
-
}
|
|
11537
|
+
};
|
|
11538
|
+
this._ctx.emit("agent/inbox/inserted", event);
|
|
11199
11539
|
});
|
|
11200
11540
|
}
|
|
11201
11541
|
/** Remove one pending inbox message by durable message id. */
|
|
11202
11542
|
removeMessage(messageId) {
|
|
11203
|
-
this._mutatePending(async () => {
|
|
11543
|
+
return this._mutatePending(async () => {
|
|
11204
11544
|
const removed = await this._durable.remove(messageId);
|
|
11205
11545
|
if (!removed) return;
|
|
11206
11546
|
this._ctx.emit("agent/inbox/discarded", {
|
|
@@ -11211,48 +11551,54 @@ var LiveAgentImpl = class {
|
|
|
11211
11551
|
});
|
|
11212
11552
|
}
|
|
11213
11553
|
steer(input) {
|
|
11214
|
-
this._send(input, "steer");
|
|
11554
|
+
return this._send(input, "steer");
|
|
11215
11555
|
}
|
|
11216
|
-
inject(
|
|
11217
|
-
|
|
11218
|
-
this._agentSystem = value;
|
|
11219
|
-
}
|
|
11556
|
+
inject(input) {
|
|
11557
|
+
return this._send(input, "inject");
|
|
11220
11558
|
}
|
|
11221
11559
|
send(input, options = {}) {
|
|
11222
|
-
this._send(input, options.mode === "steer" ? "steer" : "followup");
|
|
11560
|
+
return this._send(input, options.mode === "steer" ? "steer" : "followup");
|
|
11223
11561
|
}
|
|
11224
11562
|
_send(input, target) {
|
|
11225
|
-
if (this._disposed) throw new Error(`agent disposed: ${this.id}`);
|
|
11226
11563
|
const text = input.text ?? "";
|
|
11227
11564
|
const content = input.messages ?? input.context;
|
|
11228
|
-
const
|
|
11229
|
-
|
|
11230
|
-
this.
|
|
11565
|
+
const steeredAfterAbort = target === "steer" && this._controller?.signal.aborted === true;
|
|
11566
|
+
return this._mutatePending(async () => {
|
|
11567
|
+
const message3 = 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");
|
|
11568
|
+
if (target !== "inject") this._wakeReserved = true;
|
|
11569
|
+
const event = {
|
|
11231
11570
|
id: this.id,
|
|
11571
|
+
agent: this,
|
|
11232
11572
|
target,
|
|
11233
11573
|
input: message3,
|
|
11234
11574
|
inboxSeq: this._durable.size
|
|
11235
|
-
}
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
});
|
|
11239
|
-
this._writeTail = task;
|
|
11240
|
-
this._pendingWrite = task;
|
|
11241
|
-
task.finally(() => {
|
|
11242
|
-
if (this._pendingWrite === task) this._pendingWrite = void 0;
|
|
11243
|
-
queueMicrotask(() => this._wake());
|
|
11244
|
-
});
|
|
11575
|
+
};
|
|
11576
|
+
this._ctx.emit("agent/inbox/inserted", event);
|
|
11577
|
+
}, target !== "inject");
|
|
11245
11578
|
}
|
|
11246
|
-
_mutatePending(task) {
|
|
11247
|
-
if (this._disposed
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
|
|
11579
|
+
_mutatePending(task, wakes = false, allowDisposed = false) {
|
|
11580
|
+
if (this._disposed && !allowDisposed) {
|
|
11581
|
+
return Promise.reject(new Error(`agent disposed: ${this.id}`));
|
|
11582
|
+
}
|
|
11583
|
+
const result = this._writeTail.then(task);
|
|
11584
|
+
const recovered = result.catch((error2) => {
|
|
11585
|
+
try {
|
|
11586
|
+
this._ctx.emit("agent/error", { id: this.id, error: error2 });
|
|
11587
|
+
} catch {
|
|
11588
|
+
}
|
|
11255
11589
|
});
|
|
11590
|
+
this._writeTail = recovered;
|
|
11591
|
+
this._pendingWrite = recovered;
|
|
11592
|
+
void result.then(
|
|
11593
|
+
() => {
|
|
11594
|
+
if (this._pendingWrite === recovered) this._pendingWrite = void 0;
|
|
11595
|
+
if (wakes) queueMicrotask(() => this._wake());
|
|
11596
|
+
},
|
|
11597
|
+
() => {
|
|
11598
|
+
if (this._pendingWrite === recovered) this._pendingWrite = void 0;
|
|
11599
|
+
}
|
|
11600
|
+
);
|
|
11601
|
+
return result;
|
|
11256
11602
|
}
|
|
11257
11603
|
_findTarget(messageId) {
|
|
11258
11604
|
const snapshot = this._durable.snapshot();
|
|
@@ -11262,27 +11608,21 @@ var LiveAgentImpl = class {
|
|
|
11262
11608
|
}
|
|
11263
11609
|
cancel(cause, options = {}) {
|
|
11264
11610
|
if (!options.keepInbox) {
|
|
11265
|
-
|
|
11611
|
+
void this._mutatePending(async () => {
|
|
11266
11612
|
const before = this._durable.snapshot();
|
|
11613
|
+
await this._durable.clear();
|
|
11267
11614
|
for (const message3 of [...before.nextStep, ...before.nextTurn]) {
|
|
11268
11615
|
this._ctx.emit("agent/inbox/discarded", { id: this.id, message: message3 });
|
|
11269
11616
|
}
|
|
11270
|
-
|
|
11271
|
-
}
|
|
11272
|
-
this._ctx.emit("agent/error", { id: this.id, error: error2 });
|
|
11273
|
-
});
|
|
11274
|
-
this._writeTail = task;
|
|
11275
|
-
this._pendingWrite = task;
|
|
11276
|
-
task.finally(() => {
|
|
11277
|
-
if (this._pendingWrite === task) this._pendingWrite = void 0;
|
|
11278
|
-
});
|
|
11617
|
+
this._wakeReserved = false;
|
|
11618
|
+
}, false, true);
|
|
11279
11619
|
}
|
|
11280
11620
|
this._controller?.abort(cause);
|
|
11281
11621
|
this._maintenance?.controller.abort(cause);
|
|
11282
11622
|
}
|
|
11283
11623
|
async whenIdle() {
|
|
11284
|
-
while (this._pendingWrite) await this._pendingWrite;
|
|
11285
11624
|
while (true) {
|
|
11625
|
+
while (this._pendingWrite) await this._pendingWrite;
|
|
11286
11626
|
const maintenance = this._maintenance;
|
|
11287
11627
|
if (maintenance) {
|
|
11288
11628
|
await maintenance.promise.catch(() => void 0);
|
|
@@ -11293,7 +11633,7 @@ var LiveAgentImpl = class {
|
|
|
11293
11633
|
await drain.catch(() => void 0);
|
|
11294
11634
|
continue;
|
|
11295
11635
|
}
|
|
11296
|
-
if (!this.
|
|
11636
|
+
if (!this._hasQueuedWork()) break;
|
|
11297
11637
|
await new Promise((resolve12) => setTimeout(resolve12, 0));
|
|
11298
11638
|
}
|
|
11299
11639
|
}
|
|
@@ -11335,6 +11675,7 @@ var LiveAgentImpl = class {
|
|
|
11335
11675
|
this._pendingWrite = void 0;
|
|
11336
11676
|
await writeTail.catch(() => void 0);
|
|
11337
11677
|
}
|
|
11678
|
+
await this.session.close();
|
|
11338
11679
|
this._setStatus("idle");
|
|
11339
11680
|
}
|
|
11340
11681
|
/** Publish the agent lifecycle session-start notification once. */
|
|
@@ -11364,13 +11705,23 @@ var LiveAgentImpl = class {
|
|
|
11364
11705
|
if (this._disposed || this._manualStreaming || this._drainPromise || this._busy || this._maintenanceBusy) return;
|
|
11365
11706
|
const task = this._drainAll();
|
|
11366
11707
|
this._drainPromise = task;
|
|
11367
|
-
task.
|
|
11368
|
-
|
|
11369
|
-
|
|
11708
|
+
void task.then(
|
|
11709
|
+
() => {
|
|
11710
|
+
if (this._drainPromise === task) this._drainPromise = void 0;
|
|
11711
|
+
if (this._hasQueuedWork()) queueMicrotask(() => this._wake());
|
|
11712
|
+
},
|
|
11713
|
+
(error2) => {
|
|
11714
|
+
if (this._drainPromise === task) this._drainPromise = void 0;
|
|
11715
|
+
try {
|
|
11716
|
+
this._ctx.emit("agent/error", { id: this.id, agent: this, error: error2 });
|
|
11717
|
+
} catch {
|
|
11718
|
+
}
|
|
11719
|
+
}
|
|
11720
|
+
);
|
|
11370
11721
|
}
|
|
11371
11722
|
async _drainAll() {
|
|
11372
11723
|
await this._writeTail.catch(() => void 0);
|
|
11373
|
-
if (this.
|
|
11724
|
+
if (this._hasQueuedWork()) {
|
|
11374
11725
|
for await (const _ of this._streamTurns()) void _;
|
|
11375
11726
|
}
|
|
11376
11727
|
}
|
|
@@ -11386,10 +11737,13 @@ var LiveAgentImpl = class {
|
|
|
11386
11737
|
this._setStatus("running");
|
|
11387
11738
|
try {
|
|
11388
11739
|
while (!this._disposed) {
|
|
11389
|
-
const
|
|
11390
|
-
if (!
|
|
11391
|
-
const input = await this._inputForBatch(batch);
|
|
11740
|
+
const snapshot = this._durable.snapshot();
|
|
11741
|
+
if (!snapshot.nextTurn.length && !this._wakeReserved) break;
|
|
11392
11742
|
const turn = await this._nextTurnNumber();
|
|
11743
|
+
await this.session.append("turn/start", { turn, reason: "user" });
|
|
11744
|
+
const batch = await this._durable.claimBatch();
|
|
11745
|
+
this._wakeReserved = false;
|
|
11746
|
+
const input = batch.length ? await this._inputForBatch(batch, true) : { text: "" };
|
|
11393
11747
|
for (const message3 of batch) {
|
|
11394
11748
|
this._ctx.emit("agent/inbox/claimed", {
|
|
11395
11749
|
id: this.id,
|
|
@@ -11406,11 +11760,21 @@ var LiveAgentImpl = class {
|
|
|
11406
11760
|
else signal?.addEventListener("abort", forward, { once: true });
|
|
11407
11761
|
try {
|
|
11408
11762
|
if (this._manualStreaming) {
|
|
11409
|
-
|
|
11763
|
+
if (this._loop) {
|
|
11764
|
+
const run = await this._loop(input, { signal: controller.signal, turn });
|
|
11765
|
+
await this._closeCustomTurn(turn, run);
|
|
11766
|
+
yield { type: "run/end", run };
|
|
11767
|
+
} else {
|
|
11768
|
+
yield* this._service.runStream(input, { signal: controller.signal, turn });
|
|
11769
|
+
}
|
|
11410
11770
|
} else {
|
|
11411
|
-
|
|
11771
|
+
if (this._loop) {
|
|
11772
|
+
const run = await this._loop(input, { signal: controller.signal, turn });
|
|
11773
|
+
await this._closeCustomTurn(turn, run);
|
|
11774
|
+
} else await this._service.run(input, { signal: controller.signal, turn });
|
|
11412
11775
|
}
|
|
11413
11776
|
} catch (error2) {
|
|
11777
|
+
if (this._loop) await this._closeFailedCustomTurn(turn, error2);
|
|
11414
11778
|
if (!controller.signal.aborted) {
|
|
11415
11779
|
const step = await this._failedStep();
|
|
11416
11780
|
this._ctx.emit("agent/error", {
|
|
@@ -11428,26 +11792,37 @@ var LiveAgentImpl = class {
|
|
|
11428
11792
|
}
|
|
11429
11793
|
} finally {
|
|
11430
11794
|
this._busy = false;
|
|
11795
|
+
if (!this._durable.size) this._wakeReserved = false;
|
|
11431
11796
|
this._setStatus("idle");
|
|
11432
11797
|
}
|
|
11433
11798
|
}
|
|
11434
|
-
|
|
11435
|
-
const
|
|
11436
|
-
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11446
|
-
|
|
11447
|
-
|
|
11448
|
-
|
|
11799
|
+
_hasQueuedWork() {
|
|
11800
|
+
const snapshot = this._durable.snapshot();
|
|
11801
|
+
return snapshot.nextTurn.length > 0 || this._wakeReserved && snapshot.nextStep.length > 0;
|
|
11802
|
+
}
|
|
11803
|
+
async _inputForBatch(batch, includeHistory) {
|
|
11804
|
+
const history = includeHistory ? await this.session.deriveMessages() : [];
|
|
11805
|
+
const messages = batch.flatMap((message3) => message3.content !== void 0 ? Array.isArray(message3.content) ? message3.content : [{ role: "user", content: String(message3.content ?? "") }] : message3.text !== void 0 ? [{ role: "user", content: message3.text }] : []);
|
|
11806
|
+
if (history.length || messages.length > 1) return { messages: [...history, ...messages] };
|
|
11807
|
+
return { text: messages[0]?.content ?? "" };
|
|
11808
|
+
}
|
|
11809
|
+
async claimNextStepInputs() {
|
|
11810
|
+
await this._writeTail;
|
|
11811
|
+
const batch = await this._durable.claimNextStep();
|
|
11812
|
+
this._wakeReserved = false;
|
|
11813
|
+
if (batch.length) {
|
|
11814
|
+
const turn = await this._nextTurnNumber() - 1;
|
|
11815
|
+
for (const message3 of batch) {
|
|
11816
|
+
this._ctx.emit("agent/inbox/claimed", {
|
|
11817
|
+
id: this.id,
|
|
11818
|
+
agent: this,
|
|
11819
|
+
message: message3,
|
|
11820
|
+
input: { text: message3.text ?? "" },
|
|
11821
|
+
turn
|
|
11822
|
+
});
|
|
11823
|
+
}
|
|
11449
11824
|
}
|
|
11450
|
-
return
|
|
11825
|
+
return batch.length ? [await this._inputForBatch(batch, false)] : [];
|
|
11451
11826
|
}
|
|
11452
11827
|
_setStatus(status) {
|
|
11453
11828
|
const previous = this._status;
|
|
@@ -11543,112 +11918,156 @@ async function buildHandle(ctx, options, resume = false) {
|
|
|
11543
11918
|
}
|
|
11544
11919
|
const agentId = fileMeta?.agentId ?? requestedId;
|
|
11545
11920
|
if (!agentId) throw new AgentError("agent requires a stable identity");
|
|
11546
|
-
|
|
11547
|
-
options.file,
|
|
11548
|
-
(type, payload) => {
|
|
11549
|
-
if (type === "event") ctx.emit("session/event", payload);
|
|
11550
|
-
else ctx.emit("session/flush", payload);
|
|
11551
|
-
}
|
|
11552
|
-
);
|
|
11553
|
-
await log.init();
|
|
11554
|
-
const fileEvents = await log.read();
|
|
11555
|
-
const durableMeta = readDurableAgentMeta(fileEvents);
|
|
11556
|
-
if (durableMeta) {
|
|
11557
|
-
if (durableMeta.agentId !== agentId) {
|
|
11558
|
-
throw new AgentError(
|
|
11559
|
-
`agent id mismatch: session belongs to ${durableMeta.agentId}, requested ${agentId}`
|
|
11560
|
-
);
|
|
11561
|
-
}
|
|
11562
|
-
if (options.agentType && durableMeta.agentType !== options.agentType) {
|
|
11563
|
-
throw new AgentError(
|
|
11564
|
-
`agent type mismatch: session is ${durableMeta.agentType ?? "untyped"}, requested ${options.agentType}`
|
|
11565
|
-
);
|
|
11566
|
-
}
|
|
11567
|
-
if (options.mode && durableMeta.mode !== options.mode) {
|
|
11568
|
-
throw new AgentError(
|
|
11569
|
-
`agent mode mismatch: session is ${durableMeta.mode ?? "unset"}, requested ${options.mode}`
|
|
11570
|
-
);
|
|
11571
|
-
}
|
|
11572
|
-
}
|
|
11573
|
-
const boundMeta = {
|
|
11574
|
-
...fileMeta,
|
|
11575
|
-
...durableMeta ?? {},
|
|
11576
|
-
...options.title ? { title: options.title } : {},
|
|
11577
|
-
...options.owner ? { owner: options.owner } : {},
|
|
11578
|
-
...options.parentSessionId ? { parentSessionId: options.parentSessionId } : {},
|
|
11579
|
-
...options.forkedAtMessageId ? { forkedAtMessageId: options.forkedAtMessageId } : {},
|
|
11580
|
-
agentId
|
|
11581
|
-
};
|
|
11582
|
-
const resolvedAgentType = options.agentType ?? durableMeta?.agentType;
|
|
11583
|
-
if (resolvedAgentType) boundMeta.agentType = resolvedAgentType;
|
|
11584
|
-
const resolvedMode = options.mode ?? durableMeta?.mode;
|
|
11585
|
-
if (resolvedMode) boundMeta.mode = resolvedMode;
|
|
11586
|
-
if (!durableMeta) {
|
|
11587
|
-
await log.append("meta", {
|
|
11588
|
-
kind: "agent",
|
|
11589
|
-
agentId,
|
|
11590
|
-
...boundMeta.agentType ? { agentType: boundMeta.agentType } : {},
|
|
11591
|
-
...boundMeta.mode ? { mode: boundMeta.mode } : {},
|
|
11592
|
-
...boundMeta.title ? { title: boundMeta.title } : {},
|
|
11593
|
-
...boundMeta.owner ? { owner: boundMeta.owner } : {},
|
|
11594
|
-
...boundMeta.parentSessionId ? { parentSessionId: boundMeta.parentSessionId } : {},
|
|
11595
|
-
...boundMeta.forkedAtMessageId ? { forkedAtMessageId: boundMeta.forkedAtMessageId } : {},
|
|
11596
|
-
...boundMeta.createdAt !== void 0 ? { createdAt: boundMeta.createdAt } : {}
|
|
11597
|
-
});
|
|
11598
|
-
}
|
|
11599
|
-
const durable = resume ? await DurableInbox.restore(log) : new DurableInbox(log);
|
|
11600
|
-
const injected = new AgentInbox();
|
|
11601
|
-
const inboxView = {
|
|
11602
|
-
get size() {
|
|
11603
|
-
return durable.size;
|
|
11604
|
-
},
|
|
11605
|
-
snapshot: () => durable.snapshot()
|
|
11606
|
-
};
|
|
11607
|
-
const service = new AgentService(ctx, {
|
|
11608
|
-
session: log,
|
|
11609
|
-
inbox: injected,
|
|
11610
|
-
...options.llm ? { llm: options.llm } : {},
|
|
11611
|
-
...options.maxTurns !== void 0 ? { maxTurns: options.maxTurns } : {},
|
|
11612
|
-
...options.maxSteps !== void 0 ? { maxSteps: options.maxSteps } : {},
|
|
11613
|
-
...options.contextBudget ? { contextBudget: options.contextBudget } : {},
|
|
11614
|
-
...options.hooks ? { hooks: options.hooks } : {}
|
|
11615
|
-
});
|
|
11616
|
-
if (options.system) injected.inject("agentSystem", options.system);
|
|
11921
|
+
let agentCtx;
|
|
11617
11922
|
const agentScope = await ctx.inject([], (scopeCtx) => {
|
|
11618
|
-
scopeCtx.isolate("agentScope").
|
|
11923
|
+
agentCtx = scopeCtx.isolate("agentScope").isolate("llm").isolate("tools").isolate("systemPrompt");
|
|
11924
|
+
agentCtx.provide("agentScope", agentCtx);
|
|
11619
11925
|
});
|
|
11620
11926
|
await agentScope;
|
|
11621
|
-
const
|
|
11622
|
-
const
|
|
11623
|
-
ctx,
|
|
11624
|
-
agentCtx,
|
|
11625
|
-
service,
|
|
11626
|
-
agentId,
|
|
11627
|
-
inboxView,
|
|
11628
|
-
log,
|
|
11629
|
-
durable,
|
|
11630
|
-
boundMeta,
|
|
11631
|
-
options.manualStreaming === true
|
|
11632
|
-
);
|
|
11633
|
-
agent2.trackSetupDispose(() => agentScope.dispose());
|
|
11634
|
-
if (options.system) agent2.inject("agentSystem", options.system);
|
|
11635
|
-
let setupResult;
|
|
11927
|
+
const runtimeCtx = createAgentRuntimeContext(agentCtx);
|
|
11928
|
+
const log = new SessionLog(options.file, void 0, runtimeCtx);
|
|
11636
11929
|
try {
|
|
11637
|
-
|
|
11638
|
-
|
|
11930
|
+
await log.init();
|
|
11931
|
+
const fileEvents = await log.read();
|
|
11932
|
+
const durableMeta = readDurableAgentMeta(fileEvents);
|
|
11933
|
+
if (durableMeta) {
|
|
11934
|
+
if (durableMeta.agentId !== agentId) {
|
|
11935
|
+
throw new AgentError(
|
|
11936
|
+
`agent id mismatch: session belongs to ${durableMeta.agentId}, requested ${agentId}`
|
|
11937
|
+
);
|
|
11938
|
+
}
|
|
11939
|
+
if (options.agentType && durableMeta.agentType !== options.agentType) {
|
|
11940
|
+
throw new AgentError(
|
|
11941
|
+
`agent type mismatch: session is ${durableMeta.agentType ?? "untyped"}, requested ${options.agentType}`
|
|
11942
|
+
);
|
|
11943
|
+
}
|
|
11944
|
+
if (options.mode && durableMeta.mode !== options.mode) {
|
|
11945
|
+
throw new AgentError(
|
|
11946
|
+
`agent mode mismatch: session is ${durableMeta.mode ?? "unset"}, requested ${options.mode}`
|
|
11947
|
+
);
|
|
11948
|
+
}
|
|
11949
|
+
}
|
|
11950
|
+
const boundMeta = {
|
|
11951
|
+
...fileMeta,
|
|
11952
|
+
...durableMeta ?? {},
|
|
11953
|
+
...options.title ? { title: options.title } : {},
|
|
11954
|
+
...options.owner ? { owner: options.owner } : {},
|
|
11955
|
+
...options.parentSessionId ? { parentSessionId: options.parentSessionId } : {},
|
|
11956
|
+
...options.forkedAtMessageId ? { forkedAtMessageId: options.forkedAtMessageId } : {},
|
|
11957
|
+
agentId
|
|
11958
|
+
};
|
|
11959
|
+
const resolvedAgentType = options.agentType ?? durableMeta?.agentType;
|
|
11960
|
+
if (resolvedAgentType) boundMeta.agentType = resolvedAgentType;
|
|
11961
|
+
const resolvedMode = options.mode ?? durableMeta?.mode;
|
|
11962
|
+
if (resolvedMode) boundMeta.mode = resolvedMode;
|
|
11963
|
+
if (!durableMeta) {
|
|
11964
|
+
await log.append("meta", {
|
|
11965
|
+
kind: "agent",
|
|
11966
|
+
agentId,
|
|
11967
|
+
...boundMeta.agentType ? { agentType: boundMeta.agentType } : {},
|
|
11968
|
+
...boundMeta.mode ? { mode: boundMeta.mode } : {},
|
|
11969
|
+
...boundMeta.title ? { title: boundMeta.title } : {},
|
|
11970
|
+
...boundMeta.owner ? { owner: boundMeta.owner } : {},
|
|
11971
|
+
...boundMeta.parentSessionId ? { parentSessionId: boundMeta.parentSessionId } : {},
|
|
11972
|
+
...boundMeta.forkedAtMessageId ? { forkedAtMessageId: boundMeta.forkedAtMessageId } : {},
|
|
11973
|
+
...boundMeta.createdAt !== void 0 ? { createdAt: boundMeta.createdAt } : {}
|
|
11974
|
+
});
|
|
11975
|
+
}
|
|
11976
|
+
const durable = resume ? await DurableInbox.restore(log) : new DurableInbox(log);
|
|
11977
|
+
const restoredWakeReservation = resume && hasRestoredWakeReservation(fileEvents);
|
|
11978
|
+
const injected = new AgentInbox();
|
|
11979
|
+
const inboxView = {
|
|
11980
|
+
get size() {
|
|
11981
|
+
return durable.size;
|
|
11982
|
+
},
|
|
11983
|
+
snapshot: () => durable.snapshot()
|
|
11984
|
+
};
|
|
11985
|
+
let claimNextStep = async () => [];
|
|
11986
|
+
const service = new AgentService(runtimeCtx, {
|
|
11987
|
+
session: log,
|
|
11988
|
+
inbox: injected,
|
|
11989
|
+
...options.llm ? { llm: options.llm } : {},
|
|
11990
|
+
...options.maxTurns !== void 0 ? { maxTurns: options.maxTurns } : {},
|
|
11991
|
+
...options.maxSteps !== void 0 ? { maxSteps: options.maxSteps } : {},
|
|
11992
|
+
...options.contextBudget ? { contextBudget: options.contextBudget } : {},
|
|
11993
|
+
...options.hooks ? { hooks: options.hooks } : {},
|
|
11994
|
+
claimNextStep: () => claimNextStep()
|
|
11995
|
+
});
|
|
11996
|
+
if (options.system) injected.inject("agentSystem", options.system);
|
|
11997
|
+
const agent2 = new LiveAgentImpl(
|
|
11998
|
+
runtimeCtx,
|
|
11999
|
+
agentCtx,
|
|
12000
|
+
service,
|
|
12001
|
+
agentId,
|
|
12002
|
+
inboxView,
|
|
12003
|
+
log,
|
|
12004
|
+
durable,
|
|
12005
|
+
boundMeta,
|
|
12006
|
+
options.manualStreaming === true,
|
|
12007
|
+
restoredWakeReservation
|
|
12008
|
+
);
|
|
12009
|
+
claimNextStep = () => agent2.claimNextStepInputs();
|
|
12010
|
+
agent2.trackSetupDispose(() => agentScope.dispose());
|
|
12011
|
+
let setupResult;
|
|
12012
|
+
try {
|
|
12013
|
+
setupResult = await options.setup?.(agentCtx);
|
|
12014
|
+
for (const name2 of ["llm", "systemPrompt"]) {
|
|
12015
|
+
if (agentCtx.reflect.get(name2, false) !== void 0) continue;
|
|
12016
|
+
const inherited = ctx.reflect.get(name2, false);
|
|
12017
|
+
if (inherited !== void 0) agentCtx.provide(name2, inherited);
|
|
12018
|
+
}
|
|
12019
|
+
const loop = agentCtx.reflect.get("agentLoop", false);
|
|
12020
|
+
agent2.setLoop(loop);
|
|
12021
|
+
setupResult?.commit();
|
|
12022
|
+
} catch (error2) {
|
|
12023
|
+
await agent2.dispose().catch(() => void 0);
|
|
12024
|
+
await log.close().catch(() => void 0);
|
|
12025
|
+
throw error2;
|
|
12026
|
+
}
|
|
12027
|
+
await agent2.publishSessionStart(resume ? "resume" : "startup");
|
|
12028
|
+
for (const input of options.initial ?? []) {
|
|
12029
|
+
if (!resume) await durable.insert({ text: input.text ?? "" });
|
|
12030
|
+
}
|
|
12031
|
+
if (resume && (durable.snapshot().nextTurn.length || restoredWakeReservation) && options.manualStreaming !== true) {
|
|
12032
|
+
setTimeout(() => agent2.wakeNow(), 0);
|
|
12033
|
+
}
|
|
12034
|
+
return { agent: agent2, dispose: () => agent2.dispose() };
|
|
11639
12035
|
} catch (error2) {
|
|
11640
|
-
await
|
|
11641
|
-
await log.close().catch(() => void 0);
|
|
12036
|
+
await Promise.resolve().then(() => agentScope.dispose()).catch(() => void 0);
|
|
11642
12037
|
throw error2;
|
|
11643
12038
|
}
|
|
11644
|
-
|
|
11645
|
-
|
|
11646
|
-
|
|
11647
|
-
|
|
11648
|
-
|
|
11649
|
-
|
|
12039
|
+
}
|
|
12040
|
+
function hasRestoredWakeReservation(events) {
|
|
12041
|
+
const nextTurn = [];
|
|
12042
|
+
const nextStep = [];
|
|
12043
|
+
for (const event of events) {
|
|
12044
|
+
if (event.type !== "agent/inbox/spliced") continue;
|
|
12045
|
+
const payload = event.payload;
|
|
12046
|
+
if (payload.target === "all") {
|
|
12047
|
+
nextTurn.splice(0, payload.deleteCounts?.nextTurn ?? nextTurn.length);
|
|
12048
|
+
nextStep.splice(0, payload.deleteCounts?.nextStep ?? nextStep.length);
|
|
12049
|
+
continue;
|
|
12050
|
+
}
|
|
12051
|
+
const list = payload.target === "next-step" ? nextStep : nextTurn;
|
|
12052
|
+
const count = payload.deleteCount ?? 0;
|
|
12053
|
+
if (count === Number.POSITIVE_INFINITY) {
|
|
12054
|
+
list.length = 0;
|
|
12055
|
+
} else if (count > 0 && payload.index !== void 0) {
|
|
12056
|
+
list.splice(payload.index, count);
|
|
12057
|
+
}
|
|
12058
|
+
let insertedOffset = 0;
|
|
12059
|
+
for (const inserted of payload.inserted ?? []) {
|
|
12060
|
+
const entry = { wakes: payload.target === "next-step" && inserted.mode === "steer" };
|
|
12061
|
+
if (inserted.mode === "steer") {
|
|
12062
|
+
list.unshift(entry);
|
|
12063
|
+
} else {
|
|
12064
|
+
const index = payload.index === void 0 ? list.length : Math.min(list.length, payload.index + insertedOffset);
|
|
12065
|
+
list.splice(index, 0, entry);
|
|
12066
|
+
insertedOffset += 1;
|
|
12067
|
+
}
|
|
12068
|
+
}
|
|
11650
12069
|
}
|
|
11651
|
-
return
|
|
12070
|
+
return nextStep.some((entry) => entry.wakes);
|
|
11652
12071
|
}
|
|
11653
12072
|
async function readAgentMeta(file) {
|
|
11654
12073
|
const lines = await import("node:fs/promises").then((fs2) => fs2.readFile(file, "utf8")).catch((error2) => {
|
|
@@ -12098,7 +12517,9 @@ function anthropicMessagesAdapter(config2 = {}) {
|
|
|
12098
12517
|
}
|
|
12099
12518
|
let sawEvent = false;
|
|
12100
12519
|
try {
|
|
12101
|
-
|
|
12520
|
+
const contentType2 = response.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
|
|
12521
|
+
const events = contentType2 === "application/json" ? parseJSONCompletionStream(response) : parseAnthropicStream(response.body);
|
|
12522
|
+
for await (const event of events) {
|
|
12102
12523
|
sawEvent = true;
|
|
12103
12524
|
yield event;
|
|
12104
12525
|
}
|
|
@@ -12139,7 +12560,7 @@ function buildRequest(messages, tools2, config2, signal, stream = false) {
|
|
|
12139
12560
|
headers: {
|
|
12140
12561
|
"content-type": "application/json",
|
|
12141
12562
|
"anthropic-version": ANTHROPIC_VERSION,
|
|
12142
|
-
...config2.apiKey ? { "x-api-key": config2.apiKey } : {}
|
|
12563
|
+
...config2.apiKey ? { [config2.apiKeyHeader ?? "x-api-key"]: config2.apiKey } : {}
|
|
12143
12564
|
},
|
|
12144
12565
|
body: JSON.stringify(body),
|
|
12145
12566
|
...signal ? { signal } : {}
|
|
@@ -12431,6 +12852,26 @@ async function* parseAnthropicStream(body) {
|
|
|
12431
12852
|
function toIndex(block) {
|
|
12432
12853
|
return typeof block.index === "number" ? block.index : 0;
|
|
12433
12854
|
}
|
|
12855
|
+
async function* parseJSONCompletionStream(response) {
|
|
12856
|
+
const payload = await parseJson(response);
|
|
12857
|
+
const completion = parseCompletion(payload);
|
|
12858
|
+
const record3 = payload;
|
|
12859
|
+
const id = typeof record3?.id === "string" && record3.id ? record3.id : randomUUID5();
|
|
12860
|
+
const model = typeof record3?.model === "string" && record3.model ? record3.model : void 0;
|
|
12861
|
+
yield { type: "message_start", id, ...model ? { model } : {} };
|
|
12862
|
+
if (completion.content) yield { type: "message_delta", id, delta: completion.content };
|
|
12863
|
+
for (const [index, call] of (completion.toolCalls ?? []).entries()) {
|
|
12864
|
+
yield { type: "toolcall_start", id: call.id, index, name: call.name };
|
|
12865
|
+
yield {
|
|
12866
|
+
type: "toolcall_end",
|
|
12867
|
+
id: call.id,
|
|
12868
|
+
index,
|
|
12869
|
+
name: call.name,
|
|
12870
|
+
arguments: call.arguments
|
|
12871
|
+
};
|
|
12872
|
+
}
|
|
12873
|
+
yield { type: "message_stop", id, finishReason: completion.finishReason };
|
|
12874
|
+
}
|
|
12434
12875
|
function toStreamError(error2, timeoutMs) {
|
|
12435
12876
|
if (isAbortLike(error2)) {
|
|
12436
12877
|
return new OpenAICompatibleError(
|
|
@@ -12519,7 +12960,9 @@ function openaiCompatAdapter(config2 = {}) {
|
|
|
12519
12960
|
}
|
|
12520
12961
|
let sawEvent = false;
|
|
12521
12962
|
try {
|
|
12522
|
-
|
|
12963
|
+
const contentType2 = response.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
|
|
12964
|
+
const events = contentType2 === "application/json" ? parseJSONCompletionStream2(response) : parseOpenAIStream(response.body);
|
|
12965
|
+
for await (const event of events) {
|
|
12523
12966
|
sawEvent = true;
|
|
12524
12967
|
yield event;
|
|
12525
12968
|
}
|
|
@@ -12711,6 +13154,26 @@ async function* parseOpenAIStream(body) {
|
|
|
12711
13154
|
}
|
|
12712
13155
|
yield* finalizeStreamEvents(messageId, content, calls, finishReason);
|
|
12713
13156
|
}
|
|
13157
|
+
async function* parseJSONCompletionStream2(response) {
|
|
13158
|
+
const payload = await parseJson(response);
|
|
13159
|
+
const completion = parseCompletion2(payload);
|
|
13160
|
+
const record3 = payload;
|
|
13161
|
+
const id = typeof record3?.id === "string" && record3.id ? record3.id : randomUUID6();
|
|
13162
|
+
const model = typeof record3?.model === "string" && record3.model ? record3.model : void 0;
|
|
13163
|
+
yield { type: "message_start", id, ...model ? { model } : {} };
|
|
13164
|
+
if (completion.content) yield { type: "message_delta", id, delta: completion.content };
|
|
13165
|
+
for (const [index, call] of (completion.toolCalls ?? []).entries()) {
|
|
13166
|
+
yield { type: "toolcall_start", id: call.id, index, name: call.name };
|
|
13167
|
+
yield {
|
|
13168
|
+
type: "toolcall_end",
|
|
13169
|
+
id: call.id,
|
|
13170
|
+
index,
|
|
13171
|
+
name: call.name,
|
|
13172
|
+
arguments: call.arguments
|
|
13173
|
+
};
|
|
13174
|
+
}
|
|
13175
|
+
yield { type: "message_stop", id, finishReason: completion.finishReason };
|
|
13176
|
+
}
|
|
12714
13177
|
function processStreamChunk(payload, state, progress, calls) {
|
|
12715
13178
|
const record3 = payload;
|
|
12716
13179
|
const events = [];
|
|
@@ -30049,7 +30512,7 @@ async function updateSystemConfig(patch, file = systemConfigPath()) {
|
|
|
30049
30512
|
}
|
|
30050
30513
|
function effectiveLlmConfig(config2, env = process.env) {
|
|
30051
30514
|
const envConfig = resolveLlmEnv(env);
|
|
30052
|
-
const apiKey =
|
|
30515
|
+
const apiKey = effectiveApiKey(config2, env);
|
|
30053
30516
|
const baseUrl = envConfig.baseUrl ?? config2.baseUrl ?? DEFAULT_OPENCODE_GO_BASE_URL;
|
|
30054
30517
|
const model = envConfig.model ?? config2.model ?? DEFAULT_MODEL;
|
|
30055
30518
|
const result = {
|
|
@@ -30058,15 +30521,18 @@ function effectiveLlmConfig(config2, env = process.env) {
|
|
|
30058
30521
|
model
|
|
30059
30522
|
};
|
|
30060
30523
|
if (config2.protocol) result.protocol = config2.protocol;
|
|
30524
|
+
if (config2.apiKeyHeader) result.apiKeyHeader = config2.apiKeyHeader;
|
|
30061
30525
|
if (config2.temperature !== void 0) result.temperature = config2.temperature;
|
|
30062
30526
|
return result;
|
|
30063
30527
|
}
|
|
30064
30528
|
function effectiveApiKey(config2, env = process.env) {
|
|
30529
|
+
if (env.TNEGA_API_KEY) return env.TNEGA_API_KEY;
|
|
30530
|
+
if (config2.protocol && config2.apiKey) return config2.apiKey;
|
|
30065
30531
|
return resolveLlmEnv(env).apiKey ?? config2.apiKey;
|
|
30066
30532
|
}
|
|
30067
30533
|
function resolveLlmEnv(env = process.env) {
|
|
30068
30534
|
const config2 = {};
|
|
30069
|
-
const apiKey = env.OPENCODE_GO_API_KEY || env.OPENAI_API_KEY || env.DEEPSEEK_API_KEY;
|
|
30535
|
+
const apiKey = env.TNEGA_API_KEY || env.OPENCODE_GO_API_KEY || env.OPENAI_API_KEY || env.DEEPSEEK_API_KEY;
|
|
30070
30536
|
if (apiKey) config2.apiKey = apiKey;
|
|
30071
30537
|
if (env.OPENCODE_GO_BASE_URL) config2.baseUrl = env.OPENCODE_GO_BASE_URL;
|
|
30072
30538
|
if (env.OPENCODE_GO_MODEL) config2.model = env.OPENCODE_GO_MODEL;
|
|
@@ -30082,6 +30548,9 @@ function normalizeConfig2(value) {
|
|
|
30082
30548
|
if (record3.protocol === "anthropic" || record3.protocol === "openai") {
|
|
30083
30549
|
config2.protocol = record3.protocol;
|
|
30084
30550
|
}
|
|
30551
|
+
if (record3.apiKeyHeader === "x-api-key" || record3.apiKeyHeader === "api-key") {
|
|
30552
|
+
config2.apiKeyHeader = record3.apiKeyHeader;
|
|
30553
|
+
}
|
|
30085
30554
|
if (typeof record3.temperature === "number" && Number.isFinite(record3.temperature)) {
|
|
30086
30555
|
config2.temperature = record3.temperature;
|
|
30087
30556
|
}
|
|
@@ -31141,10 +31610,10 @@ async function runCommand3(options) {
|
|
|
31141
31610
|
if (candidate.coding) {
|
|
31142
31611
|
const systemConfig = await readSystemConfig();
|
|
31143
31612
|
const envConfig = resolveLlmEnv(process.env);
|
|
31144
|
-
const apiKey =
|
|
31613
|
+
const apiKey = effectiveApiKey(systemConfig);
|
|
31145
31614
|
if (!apiKey) {
|
|
31146
31615
|
throw new CliError(
|
|
31147
|
-
"missing LLM API key for coding eval; set
|
|
31616
|
+
"missing LLM API key for coding eval; set TNEGA_API_KEY (or OPENCODE_GO_API_KEY / OPENAI_API_KEY / DEEPSEEK_API_KEY) or configure it in the tnega config file"
|
|
31148
31617
|
);
|
|
31149
31618
|
}
|
|
31150
31619
|
const model = options.model ?? envConfig.model ?? systemConfig.model ?? candidate.coding.model;
|
|
@@ -31154,6 +31623,7 @@ async function runCommand3(options) {
|
|
|
31154
31623
|
...model ? { model } : {},
|
|
31155
31624
|
...baseUrl ? { baseUrl } : {},
|
|
31156
31625
|
...systemConfig.protocol ? { protocol: systemConfig.protocol } : {},
|
|
31626
|
+
...systemConfig.apiKeyHeader ? { apiKeyHeader: systemConfig.apiKeyHeader } : {},
|
|
31157
31627
|
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
31158
31628
|
...options.temperature !== void 0 ? { temperature: options.temperature } : {},
|
|
31159
31629
|
...systemConfig.temperature !== void 0 && options.temperature === void 0 ? { temperature: systemConfig.temperature } : {},
|
|
@@ -31221,10 +31691,10 @@ async function runAgentCommand(options) {
|
|
|
31221
31691
|
const profileOptions = profile?.options ?? {};
|
|
31222
31692
|
const systemConfig = await readSystemConfig(configFile);
|
|
31223
31693
|
const envConfig = resolveLlmEnv(process.env);
|
|
31224
|
-
const apiKey =
|
|
31694
|
+
const apiKey = effectiveApiKey(systemConfig);
|
|
31225
31695
|
if (!apiKey) {
|
|
31226
31696
|
throw new CliError(
|
|
31227
|
-
"missing LLM API key; set
|
|
31697
|
+
"missing LLM API key; set TNEGA_API_KEY (or OPENCODE_GO_API_KEY / OPENAI_API_KEY / DEEPSEEK_API_KEY) or configure it in the tnega config file"
|
|
31228
31698
|
);
|
|
31229
31699
|
}
|
|
31230
31700
|
const model = options.model ?? profileOptions.model ?? envConfig.model ?? systemConfig.model;
|
|
@@ -31235,6 +31705,7 @@ async function runAgentCommand(options) {
|
|
|
31235
31705
|
...typeof model === "string" && model ? { model } : {},
|
|
31236
31706
|
...baseUrl ? { baseUrl } : {},
|
|
31237
31707
|
...protocolFrom(profileOptions) ?? systemConfig.protocol ? { protocol: protocolFrom(profileOptions) ?? systemConfig.protocol } : {},
|
|
31708
|
+
...systemConfig.apiKeyHeader ? { apiKeyHeader: systemConfig.apiKeyHeader } : {},
|
|
31238
31709
|
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
31239
31710
|
...options.maxTokens === void 0 && typeof profileOptions.maxTokens === "number" ? { maxTokens: profileOptions.maxTokens } : {},
|
|
31240
31711
|
...options.temperature !== void 0 ? { temperature: options.temperature } : {},
|
|
@@ -31365,10 +31836,10 @@ async function runEvolveCommand(options) {
|
|
|
31365
31836
|
const configFile = options.configFile ?? systemConfigPath();
|
|
31366
31837
|
const systemConfig = await readSystemConfig(configFile);
|
|
31367
31838
|
const envConfig = resolveLlmEnv(process.env);
|
|
31368
|
-
const apiKey =
|
|
31839
|
+
const apiKey = effectiveApiKey(systemConfig);
|
|
31369
31840
|
if (!apiKey) {
|
|
31370
31841
|
throw new CliError(
|
|
31371
|
-
"missing LLM API key; set
|
|
31842
|
+
"missing LLM API key; set TNEGA_API_KEY (or OPENCODE_GO_API_KEY / OPENAI_API_KEY / DEEPSEEK_API_KEY) or configure it in the tnega config file"
|
|
31372
31843
|
);
|
|
31373
31844
|
}
|
|
31374
31845
|
const model = options.model ?? envConfig.model ?? systemConfig.model;
|
|
@@ -31378,6 +31849,7 @@ async function runEvolveCommand(options) {
|
|
|
31378
31849
|
...model ? { model } : {},
|
|
31379
31850
|
...baseUrl ? { baseUrl } : {},
|
|
31380
31851
|
...systemConfig.protocol ? { protocol: systemConfig.protocol } : {},
|
|
31852
|
+
...systemConfig.apiKeyHeader ? { apiKeyHeader: systemConfig.apiKeyHeader } : {},
|
|
31381
31853
|
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
31382
31854
|
...options.temperature !== void 0 ? { temperature: options.temperature } : {},
|
|
31383
31855
|
...systemConfig.temperature !== void 0 && options.temperature === void 0 ? { temperature: systemConfig.temperature } : {},
|
|
@@ -32744,6 +33216,7 @@ function adapterFromConfig(effective, apiKey) {
|
|
|
32744
33216
|
model: effective.model
|
|
32745
33217
|
};
|
|
32746
33218
|
if (effective.protocol) options.protocol = effective.protocol;
|
|
33219
|
+
if (effective.apiKeyHeader) options.apiKeyHeader = effective.apiKeyHeader;
|
|
32747
33220
|
if (effective.temperature !== void 0) options.temperature = effective.temperature;
|
|
32748
33221
|
return createLlmAdapter(options);
|
|
32749
33222
|
}
|
|
@@ -33380,6 +33853,7 @@ export {
|
|
|
33380
33853
|
bootAgentRuntimeFromFile,
|
|
33381
33854
|
compareCommand,
|
|
33382
33855
|
createAgentRuntime,
|
|
33856
|
+
effectiveApiKey,
|
|
33383
33857
|
ensureProfileDir,
|
|
33384
33858
|
formatAgentRun,
|
|
33385
33859
|
formatBenchmarkImport,
|