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