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/evolve.js
CHANGED
|
@@ -7879,7 +7879,7 @@ function copyMessages(messages) {
|
|
|
7879
7879
|
copy.tool_calls = message2.tool_calls.map((call) => ({
|
|
7880
7880
|
id: call.id,
|
|
7881
7881
|
name: call.name,
|
|
7882
|
-
arguments: call.arguments
|
|
7882
|
+
arguments: structuredClone(call.arguments)
|
|
7883
7883
|
}));
|
|
7884
7884
|
}
|
|
7885
7885
|
return copy;
|
|
@@ -7910,6 +7910,75 @@ function copyCompletion(completion) {
|
|
|
7910
7910
|
}
|
|
7911
7911
|
return copy;
|
|
7912
7912
|
}
|
|
7913
|
+
function canonicalMessages(messages) {
|
|
7914
|
+
return JSON.stringify(messages.map((message2) => ({
|
|
7915
|
+
role: message2.role,
|
|
7916
|
+
content: message2.content,
|
|
7917
|
+
...message2.name ? { name: message2.name } : {},
|
|
7918
|
+
...message2.tool_call_id ? { tool_call_id: message2.tool_call_id } : {},
|
|
7919
|
+
...message2.tool_calls?.length ? { tool_calls: message2.tool_calls } : {},
|
|
7920
|
+
...message2.toolOk !== void 0 ? { toolOk: message2.toolOk } : {},
|
|
7921
|
+
...message2.toolError ? {
|
|
7922
|
+
toolError: { name: message2.toolError.name, message: message2.toolError.message }
|
|
7923
|
+
} : {}
|
|
7924
|
+
})));
|
|
7925
|
+
}
|
|
7926
|
+
function freezeRequestData(data) {
|
|
7927
|
+
const visited = /* @__PURE__ */ new Set();
|
|
7928
|
+
const freeze = (value) => {
|
|
7929
|
+
if (typeof value !== "object" || value === null || visited.has(value)) return;
|
|
7930
|
+
visited.add(value);
|
|
7931
|
+
for (const child of Object.values(value)) freeze(child);
|
|
7932
|
+
Object.freeze(value);
|
|
7933
|
+
};
|
|
7934
|
+
freeze(data);
|
|
7935
|
+
}
|
|
7936
|
+
function lockStreamRequest(request) {
|
|
7937
|
+
freezeRequestData(request.messages);
|
|
7938
|
+
request.tools = Object.freeze(request.tools.map((tool) => {
|
|
7939
|
+
const schema = structuredClone(tool.schema);
|
|
7940
|
+
freezeRequestData(schema);
|
|
7941
|
+
return Object.freeze({ ...tool, schema });
|
|
7942
|
+
}));
|
|
7943
|
+
Object.freeze(request.options);
|
|
7944
|
+
Object.freeze(request);
|
|
7945
|
+
}
|
|
7946
|
+
function requestHeaderFor(request, input) {
|
|
7947
|
+
const system = input.find((message2) => message2.role === "system")?.content;
|
|
7948
|
+
const tools2 = request.tools.map((tool) => ({
|
|
7949
|
+
name: tool.schema.name,
|
|
7950
|
+
description: tool.schema.description,
|
|
7951
|
+
...tool.schema.parameters ? { parameters: tool.schema.parameters } : {}
|
|
7952
|
+
}));
|
|
7953
|
+
const config2 = {
|
|
7954
|
+
...request.options.provider ? { provider: request.options.provider } : {},
|
|
7955
|
+
...request.options.model ? { model: request.options.model } : {},
|
|
7956
|
+
...request.options.temperature !== void 0 ? { temperature: request.options.temperature } : {}
|
|
7957
|
+
};
|
|
7958
|
+
return {
|
|
7959
|
+
...Object.keys(config2).length ? { config: config2 } : {},
|
|
7960
|
+
...system !== void 0 ? { system } : {},
|
|
7961
|
+
...tools2.length ? { tools: tools2 } : {}
|
|
7962
|
+
};
|
|
7963
|
+
}
|
|
7964
|
+
async function* completeAsStream(llm, messages, tools2, options) {
|
|
7965
|
+
const id = randomUUID();
|
|
7966
|
+
yield { type: "message_start", id };
|
|
7967
|
+
const completion = await llm.complete(messages, tools2, options);
|
|
7968
|
+
if (completion.content) yield { type: "message_delta", id, delta: completion.content };
|
|
7969
|
+
for (let index = 0; index < (completion.toolCalls?.length ?? 0); index += 1) {
|
|
7970
|
+
const call = completion.toolCalls[index];
|
|
7971
|
+
yield { type: "toolcall_start", id: call.id, index, name: call.name };
|
|
7972
|
+
yield {
|
|
7973
|
+
type: "toolcall_end",
|
|
7974
|
+
id: call.id,
|
|
7975
|
+
index,
|
|
7976
|
+
name: call.name,
|
|
7977
|
+
arguments: call.arguments
|
|
7978
|
+
};
|
|
7979
|
+
}
|
|
7980
|
+
yield { type: "message_stop", id, finishReason: completion.finishReason };
|
|
7981
|
+
}
|
|
7913
7982
|
function isCancelCause(value) {
|
|
7914
7983
|
if (typeof value !== "object" || value === null) return false;
|
|
7915
7984
|
const record2 = value;
|
|
@@ -7930,6 +7999,13 @@ function cancelCauseFromSignal(signal) {
|
|
|
7930
7999
|
if (isCancelCause(reason)) return reason;
|
|
7931
8000
|
return { type: "abort" };
|
|
7932
8001
|
}
|
|
8002
|
+
function abortedToolError(signal) {
|
|
8003
|
+
const cause = cancelCauseFromSignal(signal);
|
|
8004
|
+
return {
|
|
8005
|
+
name: "AbortError",
|
|
8006
|
+
message: `tool call aborted: ${cause?.type ?? "abort"}`
|
|
8007
|
+
};
|
|
8008
|
+
}
|
|
7933
8009
|
function toTurnEndReason(fields) {
|
|
7934
8010
|
const { cancelled, turnError, finishReason, cancelCause } = fields;
|
|
7935
8011
|
if (cancelled || finishReason === "cancelled") {
|
|
@@ -7974,6 +8050,78 @@ async function cancellableDelay(ms, signal) {
|
|
|
7974
8050
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
7975
8051
|
});
|
|
7976
8052
|
}
|
|
8053
|
+
var AssistantStreamAttempt = class {
|
|
8054
|
+
constructor(session2, turn, step, nextRevision) {
|
|
8055
|
+
this.session = session2;
|
|
8056
|
+
this.turn = turn;
|
|
8057
|
+
this.step = step;
|
|
8058
|
+
this.nextRevision = nextRevision;
|
|
8059
|
+
}
|
|
8060
|
+
session;
|
|
8061
|
+
turn;
|
|
8062
|
+
step;
|
|
8063
|
+
nextRevision;
|
|
8064
|
+
attemptId = randomUUID();
|
|
8065
|
+
records = [];
|
|
8066
|
+
ended = false;
|
|
8067
|
+
start() {
|
|
8068
|
+
return { type: "assistant/stream", frame: {
|
|
8069
|
+
type: "start",
|
|
8070
|
+
attemptId: this.attemptId,
|
|
8071
|
+
revision: this.nextRevision(),
|
|
8072
|
+
turn: this.turn,
|
|
8073
|
+
step: this.step
|
|
8074
|
+
} };
|
|
8075
|
+
}
|
|
8076
|
+
push(chunk) {
|
|
8077
|
+
if (this.ended) throw new AgentError("assistant attempt is already settled");
|
|
8078
|
+
const record2 = { time: Date.now(), chunk: structuredClone(chunk) };
|
|
8079
|
+
const index = this.records.length;
|
|
8080
|
+
this.records.push(record2);
|
|
8081
|
+
return { type: "assistant/stream", frame: {
|
|
8082
|
+
type: "chunk",
|
|
8083
|
+
attemptId: this.attemptId,
|
|
8084
|
+
revision: this.nextRevision(),
|
|
8085
|
+
index,
|
|
8086
|
+
...structuredClone(record2)
|
|
8087
|
+
} };
|
|
8088
|
+
}
|
|
8089
|
+
async settle(message2) {
|
|
8090
|
+
if (this.ended) throw new AgentError("assistant attempt is already settled");
|
|
8091
|
+
const eventType = message2 ? "assistant/message" : "assistant/attempt";
|
|
8092
|
+
let event;
|
|
8093
|
+
try {
|
|
8094
|
+
event = message2 ? await this.session.append("assistant/message", { ...message2, stream: this.records }) : await this.session.append("assistant/attempt", { turn: this.turn, step: this.step, stream: this.records });
|
|
8095
|
+
} catch (cause) {
|
|
8096
|
+
this.ended = true;
|
|
8097
|
+
const frame = { type: "assistant/stream", frame: {
|
|
8098
|
+
type: "end",
|
|
8099
|
+
attemptId: this.attemptId,
|
|
8100
|
+
revision: this.nextRevision(),
|
|
8101
|
+
index: this.records.length,
|
|
8102
|
+
outcome: { kind: "abandoned" }
|
|
8103
|
+
} };
|
|
8104
|
+
throw new AttemptSettlementError(cause, frame);
|
|
8105
|
+
}
|
|
8106
|
+
this.ended = true;
|
|
8107
|
+
return { type: "assistant/stream", frame: {
|
|
8108
|
+
type: "end",
|
|
8109
|
+
attemptId: this.attemptId,
|
|
8110
|
+
revision: this.nextRevision(),
|
|
8111
|
+
index: this.records.length,
|
|
8112
|
+
outcome: { kind: "committed", eventType, seq: event.seq }
|
|
8113
|
+
} };
|
|
8114
|
+
}
|
|
8115
|
+
};
|
|
8116
|
+
var AttemptSettlementError = class extends Error {
|
|
8117
|
+
constructor(cause, frame) {
|
|
8118
|
+
super("assistant attempt settlement failed");
|
|
8119
|
+
this.cause = cause;
|
|
8120
|
+
this.frame = frame;
|
|
8121
|
+
}
|
|
8122
|
+
cause;
|
|
8123
|
+
frame;
|
|
8124
|
+
};
|
|
7977
8125
|
var AgentService = class {
|
|
7978
8126
|
constructor(ctx, config2 = {}) {
|
|
7979
8127
|
this.ctx = ctx;
|
|
@@ -7982,9 +8130,24 @@ var AgentService = class {
|
|
|
7982
8130
|
}
|
|
7983
8131
|
ctx;
|
|
7984
8132
|
config;
|
|
8133
|
+
async *settleAttempt(attempt, message2) {
|
|
8134
|
+
try {
|
|
8135
|
+
yield await attempt.settle(message2);
|
|
8136
|
+
} catch (error2) {
|
|
8137
|
+
if (error2 instanceof AttemptSettlementError) {
|
|
8138
|
+
yield error2.frame;
|
|
8139
|
+
throw error2.cause;
|
|
8140
|
+
}
|
|
8141
|
+
throw error2;
|
|
8142
|
+
}
|
|
8143
|
+
}
|
|
7985
8144
|
inbox;
|
|
7986
8145
|
_seriesStarted = false;
|
|
7987
8146
|
_persistedRequest = false;
|
|
8147
|
+
_streamRevision = 0;
|
|
8148
|
+
_attempt(session2, turn, step) {
|
|
8149
|
+
return new AssistantStreamAttempt(session2, turn, step, () => ++this._streamRevision);
|
|
8150
|
+
}
|
|
7988
8151
|
/** Call when a request begins an explicit new model-message series. */
|
|
7989
8152
|
startSeries() {
|
|
7990
8153
|
this._seriesStarted = true;
|
|
@@ -7998,7 +8161,7 @@ var AgentService = class {
|
|
|
7998
8161
|
return this._persistedRequest;
|
|
7999
8162
|
}
|
|
8000
8163
|
async run(input, options = {}) {
|
|
8001
|
-
return consumeAgentStream(this._stream(input, options
|
|
8164
|
+
return consumeAgentStream(this._stream(input, options));
|
|
8002
8165
|
}
|
|
8003
8166
|
async *runStream(input, options = {}) {
|
|
8004
8167
|
const iterator = this._stream(input, options)[Symbol.asyncIterator]();
|
|
@@ -8008,7 +8171,7 @@ var AgentService = class {
|
|
|
8008
8171
|
yield next.value;
|
|
8009
8172
|
}
|
|
8010
8173
|
}
|
|
8011
|
-
async *_stream(input, options = {}
|
|
8174
|
+
async *_stream(input, options = {}) {
|
|
8012
8175
|
const claimed = input ?? this.inbox.claim();
|
|
8013
8176
|
if (!claimed) throw new AgentError("no agent input available");
|
|
8014
8177
|
await this.config.hooks?.beforeRun?.(claimed, options);
|
|
@@ -8016,26 +8179,32 @@ var AgentService = class {
|
|
|
8016
8179
|
const tools2 = this._tools();
|
|
8017
8180
|
const llm = this._llm();
|
|
8018
8181
|
if (!llm) throw new AgentError("no LLM adapter available");
|
|
8182
|
+
const streamAdapter = llm.stream;
|
|
8183
|
+
const persistChunks = streamAdapter !== void 0;
|
|
8019
8184
|
const maxTurns = options.maxTurns ?? this.config.maxTurns ?? 64;
|
|
8020
8185
|
const maxSteps = options.maxSteps ?? this.config.maxSteps ?? 64;
|
|
8021
8186
|
const contextBudget = options.contextBudget ?? this.config.contextBudget;
|
|
8022
8187
|
const injected = this.inbox.injected();
|
|
8023
8188
|
this.ctx.emit("agent/start", { input: claimed, options, injected });
|
|
8024
8189
|
let messages = await this._initialMessages(claimed);
|
|
8190
|
+
let claimedMessages = messages.filter((message2) => message2.role === "user");
|
|
8025
8191
|
const steps = [];
|
|
8026
8192
|
let output = "";
|
|
8027
8193
|
let finishReason = "stop";
|
|
8194
|
+
let lengthReached = false;
|
|
8028
8195
|
this.ctx.emit("agent/turn-start", {
|
|
8029
8196
|
input: claimed,
|
|
8030
8197
|
messages: copyMessages(messages),
|
|
8031
8198
|
injected
|
|
8032
8199
|
});
|
|
8033
|
-
const turn = await session2.nextTurn();
|
|
8034
|
-
|
|
8035
|
-
turn,
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8200
|
+
const turn = options.turn ?? await session2.nextTurn();
|
|
8201
|
+
if (options.turn === void 0) {
|
|
8202
|
+
await session2.append("turn/start", {
|
|
8203
|
+
turn,
|
|
8204
|
+
input: claimed.text ?? claimed,
|
|
8205
|
+
reason: "user"
|
|
8206
|
+
});
|
|
8207
|
+
}
|
|
8039
8208
|
let index = 0;
|
|
8040
8209
|
let finalTurnGranted = false;
|
|
8041
8210
|
let currentStepIndex;
|
|
@@ -8054,20 +8223,22 @@ var AgentService = class {
|
|
|
8054
8223
|
messages = await this._enforceContextBudget(session2, contextBudget, messages);
|
|
8055
8224
|
}
|
|
8056
8225
|
const stepInput = copyMessages(messages);
|
|
8057
|
-
const preStep = this.ctx.
|
|
8226
|
+
const preStep = await this.ctx.waterfallAsync("agent/pre-step", {
|
|
8058
8227
|
index,
|
|
8059
8228
|
turn,
|
|
8060
8229
|
step: index,
|
|
8061
8230
|
messages: stepInput,
|
|
8231
|
+
claimedMessages: copyMessages(claimedMessages),
|
|
8062
8232
|
...options.signal ? { signal: options.signal } : {}
|
|
8063
8233
|
}, (payload) => payload);
|
|
8064
|
-
if (!preStep || !Array.isArray(preStep.messages) || !preStep.messages.length) {
|
|
8234
|
+
if (!preStep || preStep.admission === "reject" || !Array.isArray(preStep.messages) || !preStep.messages.length) {
|
|
8065
8235
|
break;
|
|
8066
8236
|
}
|
|
8067
8237
|
if (preStep.startsRequestSeries) this._seriesStarted = true;
|
|
8068
8238
|
await session2.append("step/start", { turn, step: index });
|
|
8069
8239
|
currentStepIndex = index;
|
|
8070
8240
|
const requestedInput = copyMessages(preStep.messages);
|
|
8241
|
+
const admittedHistory = await session2.deriveMessages();
|
|
8071
8242
|
this.ctx.emit("agent/step", {
|
|
8072
8243
|
index,
|
|
8073
8244
|
turn,
|
|
@@ -8079,93 +8250,85 @@ var AgentService = class {
|
|
|
8079
8250
|
maxSteps: maxSteps - steps.length
|
|
8080
8251
|
};
|
|
8081
8252
|
if (options.signal) completeOptions.signal = options.signal;
|
|
8082
|
-
const request = this.ctx.waterfall("agent/request", {
|
|
8083
|
-
index,
|
|
8084
|
-
messages: requestedInput,
|
|
8085
|
-
tools: availableTools,
|
|
8086
|
-
options: completeOptions
|
|
8087
|
-
}, (payload) => payload);
|
|
8088
|
-
if (!request || !request.options || !request.tools) {
|
|
8089
|
-
throw new AgentError("agent/request must return a request payload");
|
|
8090
|
-
}
|
|
8091
8253
|
let llmMessages = copyMessages(requestedInput);
|
|
8092
8254
|
let completion;
|
|
8093
|
-
|
|
8255
|
+
let activeAttempt;
|
|
8094
8256
|
let attempt = 0;
|
|
8095
|
-
let persistedStepInput = false;
|
|
8096
8257
|
while (true) {
|
|
8097
8258
|
if (options.signal?.aborted) {
|
|
8098
8259
|
finishReason = "cancelled";
|
|
8099
8260
|
break;
|
|
8100
8261
|
}
|
|
8101
8262
|
const streamEvents = [];
|
|
8263
|
+
activeAttempt = this._attempt(session2, turn, index);
|
|
8264
|
+
yield activeAttempt.start();
|
|
8265
|
+
const streamRequest = {
|
|
8266
|
+
index,
|
|
8267
|
+
messages: copyMessages(requestedInput),
|
|
8268
|
+
tools: [...availableTools],
|
|
8269
|
+
options: { ...completeOptions }
|
|
8270
|
+
};
|
|
8102
8271
|
try {
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
return streamMethod(payload.messages, payload.tools, payload.options);
|
|
8118
|
-
}
|
|
8119
|
-
);
|
|
8120
|
-
if (!stream || typeof stream[Symbol.asyncIterator] !== "function") {
|
|
8121
|
-
throw new AgentError("llm/stream must return an async iterable stream");
|
|
8122
|
-
}
|
|
8272
|
+
const request = await this.ctx.waterfallAsync("agent/request", {
|
|
8273
|
+
index,
|
|
8274
|
+
messages: copyMessages(requestedInput),
|
|
8275
|
+
tools: streamRequest.tools,
|
|
8276
|
+
options: streamRequest.options
|
|
8277
|
+
}, (payload) => payload);
|
|
8278
|
+
if (!request || !request.options || !request.tools) {
|
|
8279
|
+
throw new AgentError("agent/request must return a request payload");
|
|
8280
|
+
}
|
|
8281
|
+
streamRequest.tools = request.tools;
|
|
8282
|
+
streamRequest.options = request.options;
|
|
8283
|
+
let preparation;
|
|
8284
|
+
const prepareRequest = () => preparation ??= (async () => {
|
|
8285
|
+
lockStreamRequest(streamRequest);
|
|
8123
8286
|
llmMessages = copyMessages(streamRequest.messages);
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
}
|
|
8151
|
-
persistedStepInput = true;
|
|
8287
|
+
await this._persistStepInput(session2, streamRequest, llmMessages, admittedHistory);
|
|
8288
|
+
await this._assertReplayable(session2, streamRequest, llmMessages);
|
|
8289
|
+
})();
|
|
8290
|
+
const stream = await this.ctx.waterfallAsync(
|
|
8291
|
+
"llm/stream",
|
|
8292
|
+
streamRequest,
|
|
8293
|
+
(payload) => (async function* () {
|
|
8294
|
+
await prepareRequest();
|
|
8295
|
+
yield* streamAdapter ? streamAdapter.call(llm, payload.messages, payload.tools, payload.options) : completeAsStream(llm, payload.messages, payload.tools, payload.options);
|
|
8296
|
+
})()
|
|
8297
|
+
);
|
|
8298
|
+
if (!stream || typeof stream[Symbol.asyncIterator] !== "function") {
|
|
8299
|
+
throw new AgentError("llm/stream must return an async iterable stream");
|
|
8300
|
+
}
|
|
8301
|
+
await prepareRequest();
|
|
8302
|
+
let chunkIndex = 0;
|
|
8303
|
+
for await (const event of stream) {
|
|
8304
|
+
streamEvents.push(structuredClone(event));
|
|
8305
|
+
yield activeAttempt.push(event);
|
|
8306
|
+
if (persistChunks && event.type === "message_delta") {
|
|
8307
|
+
await session2.append("assistant/chunk", {
|
|
8308
|
+
id: event.id,
|
|
8309
|
+
content: event.delta,
|
|
8310
|
+
index: chunkIndex
|
|
8311
|
+
});
|
|
8312
|
+
chunkIndex += 1;
|
|
8152
8313
|
}
|
|
8153
|
-
|
|
8314
|
+
yield event;
|
|
8315
|
+
}
|
|
8316
|
+
completion = completionFromStreamEvents(streamEvents);
|
|
8317
|
+
if (completion.finishReason === "error" || completion.finishReason === "cancelled") {
|
|
8318
|
+
const terminalReason = completion.finishReason;
|
|
8319
|
+
completion = void 0;
|
|
8320
|
+
throw new AgentError(`LLM stream finished with ${terminalReason}`);
|
|
8154
8321
|
}
|
|
8155
8322
|
break;
|
|
8156
8323
|
} catch (error2) {
|
|
8157
|
-
|
|
8158
|
-
if (content) {
|
|
8159
|
-
await session2.append("assistant/message", {
|
|
8160
|
-
content,
|
|
8161
|
-
interrupted: true
|
|
8162
|
-
});
|
|
8163
|
-
llmMessages = await session2.deriveMessages();
|
|
8164
|
-
}
|
|
8324
|
+
yield activeAttempt.push({ type: "stream_error", error: toToolError(error2) });
|
|
8165
8325
|
if (options.signal?.aborted) {
|
|
8326
|
+
const content = partialStreamContent(streamEvents);
|
|
8327
|
+
yield* this.settleAttempt(activeAttempt, content ? { content, interrupted: true } : void 0);
|
|
8166
8328
|
finishReason = "cancelled";
|
|
8167
8329
|
break;
|
|
8168
8330
|
}
|
|
8331
|
+
yield* this.settleAttempt(activeAttempt);
|
|
8169
8332
|
attempt += 1;
|
|
8170
8333
|
const failure = toToolError(error2);
|
|
8171
8334
|
const decision = await this.ctx.waterfallAsync(
|
|
@@ -8174,14 +8337,14 @@ var AgentService = class {
|
|
|
8174
8337
|
index,
|
|
8175
8338
|
turn,
|
|
8176
8339
|
step: index,
|
|
8177
|
-
messages: copyMessages(
|
|
8178
|
-
tools:
|
|
8179
|
-
options:
|
|
8340
|
+
messages: copyMessages(streamRequest.messages),
|
|
8341
|
+
tools: [...streamRequest.tools],
|
|
8342
|
+
options: { ...streamRequest.options },
|
|
8180
8343
|
attempt,
|
|
8181
8344
|
error: error2,
|
|
8182
8345
|
failure,
|
|
8183
|
-
...
|
|
8184
|
-
...
|
|
8346
|
+
...streamRequest.options.provider ? { provider: streamRequest.options.provider } : {},
|
|
8347
|
+
...streamRequest.options.model ? { model: streamRequest.options.model } : {},
|
|
8185
8348
|
...options.signal ? { signal: options.signal } : {}
|
|
8186
8349
|
},
|
|
8187
8350
|
() => void 0
|
|
@@ -8206,16 +8369,30 @@ var AgentService = class {
|
|
|
8206
8369
|
await session2.append("llm/retry-started", { retryId, retry: attempt });
|
|
8207
8370
|
}
|
|
8208
8371
|
}
|
|
8209
|
-
if (
|
|
8210
|
-
|
|
8372
|
+
if (!completion || !activeAttempt) {
|
|
8373
|
+
if (options.signal?.aborted) {
|
|
8374
|
+
finishReason = "cancelled";
|
|
8375
|
+
break;
|
|
8376
|
+
}
|
|
8377
|
+
throw new AgentError("LLM adapter did not produce a completion");
|
|
8378
|
+
}
|
|
8211
8379
|
const toolCalls = completion.toolCalls ?? [];
|
|
8212
|
-
if (
|
|
8380
|
+
if (completion.finishReason === "length") lengthReached = true;
|
|
8381
|
+
if (options.signal?.aborted && toolCalls.length === 0) {
|
|
8382
|
+
yield activeAttempt.push({ type: "stream_error", error: { name: "AbortError", message: "stream aborted" } });
|
|
8383
|
+
yield* this.settleAttempt(activeAttempt);
|
|
8384
|
+
finishReason = "cancelled";
|
|
8385
|
+
break;
|
|
8386
|
+
}
|
|
8387
|
+
if (finalTurnGranted && toolCalls.length && !options.signal?.aborted) {
|
|
8388
|
+
yield activeAttempt.push({ type: "stream_error", error: { name: "AgentError", message: "maximum turns reached" } });
|
|
8389
|
+
yield* this.settleAttempt(activeAttempt);
|
|
8213
8390
|
finishReason = "max_turns";
|
|
8214
8391
|
break;
|
|
8215
8392
|
}
|
|
8216
8393
|
const toolResults = [];
|
|
8217
8394
|
if (toolCalls.length) {
|
|
8218
|
-
|
|
8395
|
+
yield* this.settleAttempt(activeAttempt, {
|
|
8219
8396
|
content: completion.content ?? "",
|
|
8220
8397
|
toolCalls: toolCalls.map((call) => ({
|
|
8221
8398
|
id: call.id,
|
|
@@ -8236,18 +8413,30 @@ var AgentService = class {
|
|
|
8236
8413
|
if (options.signal) toolOptions.signal = options.signal;
|
|
8237
8414
|
const startedAt = Date.now();
|
|
8238
8415
|
let result;
|
|
8239
|
-
|
|
8240
|
-
result = await tools2.execute(call.name, call.arguments, toolOptions);
|
|
8241
|
-
} catch (error2) {
|
|
8416
|
+
if (options.signal?.aborted) {
|
|
8242
8417
|
result = {
|
|
8243
8418
|
ok: false,
|
|
8244
8419
|
name: call.name,
|
|
8245
8420
|
callId: call.id,
|
|
8246
8421
|
input: call.arguments,
|
|
8247
|
-
error:
|
|
8422
|
+
error: abortedToolError(options.signal),
|
|
8248
8423
|
startedAt,
|
|
8249
8424
|
durationMs: Date.now() - startedAt
|
|
8250
8425
|
};
|
|
8426
|
+
} else {
|
|
8427
|
+
try {
|
|
8428
|
+
result = await tools2.execute(call.name, call.arguments, toolOptions);
|
|
8429
|
+
} catch (error2) {
|
|
8430
|
+
result = {
|
|
8431
|
+
ok: false,
|
|
8432
|
+
name: call.name,
|
|
8433
|
+
callId: call.id,
|
|
8434
|
+
input: call.arguments,
|
|
8435
|
+
error: toToolError(error2),
|
|
8436
|
+
startedAt,
|
|
8437
|
+
durationMs: Date.now() - startedAt
|
|
8438
|
+
};
|
|
8439
|
+
}
|
|
8251
8440
|
}
|
|
8252
8441
|
toolResults.push(result);
|
|
8253
8442
|
const toolResultPayload = {
|
|
@@ -8289,7 +8478,7 @@ var AgentService = class {
|
|
|
8289
8478
|
output = completion.content;
|
|
8290
8479
|
}
|
|
8291
8480
|
if (!toolCalls.length) {
|
|
8292
|
-
|
|
8481
|
+
yield* this.settleAttempt(activeAttempt, { content: completion.content ?? "" });
|
|
8293
8482
|
}
|
|
8294
8483
|
await session2.append("step/end", {
|
|
8295
8484
|
turn,
|
|
@@ -8300,19 +8489,19 @@ var AgentService = class {
|
|
|
8300
8489
|
currentStepIndex = void 0;
|
|
8301
8490
|
const nextMessages = this._extendMessages(llmMessages, completion, toolResults);
|
|
8302
8491
|
const concludesTurn = toolResults.some((result) => result.concludesTurn === true);
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
}
|
|
8307
|
-
if (toolCalls.length === 0) {
|
|
8308
|
-
finishReason = completion.finishReason === "length" ? "length" : completion.finishReason === "error" ? "error" : "stop";
|
|
8492
|
+
let nextStepMessages = await this._claimNextStepMessages();
|
|
8493
|
+
if ((toolCalls.length === 0 || concludesTurn) && nextStepMessages.length === 0) {
|
|
8494
|
+
finishReason = lengthReached ? "length" : completion.finishReason === "error" ? "error" : "stop";
|
|
8309
8495
|
const keepGoing = await this.ctx.serial("agent/turn-stopping", {
|
|
8310
8496
|
index,
|
|
8311
8497
|
turn,
|
|
8312
8498
|
steps: copySteps(steps),
|
|
8313
8499
|
finishReason
|
|
8314
8500
|
});
|
|
8315
|
-
if (!keepGoing)
|
|
8501
|
+
if (!keepGoing) {
|
|
8502
|
+
nextStepMessages = await this._claimNextStepMessages();
|
|
8503
|
+
if (nextStepMessages.length === 0) break;
|
|
8504
|
+
}
|
|
8316
8505
|
}
|
|
8317
8506
|
if (index + 1 >= maxTurns && !finalTurnGranted) {
|
|
8318
8507
|
finalTurnGranted = true;
|
|
@@ -8322,7 +8511,8 @@ var AgentService = class {
|
|
|
8322
8511
|
}
|
|
8323
8512
|
if (toolCalls.length) finishReason = "tool_calls";
|
|
8324
8513
|
index += 1;
|
|
8325
|
-
messages = nextMessages;
|
|
8514
|
+
messages = [...nextMessages, ...nextStepMessages];
|
|
8515
|
+
claimedMessages = nextStepMessages.filter((message2) => message2.role === "user");
|
|
8326
8516
|
}
|
|
8327
8517
|
} catch (error2) {
|
|
8328
8518
|
turnError = error2;
|
|
@@ -8408,23 +8598,22 @@ var AgentService = class {
|
|
|
8408
8598
|
});
|
|
8409
8599
|
return compactMessages.map((message2) => copyMessages([message2])[0]);
|
|
8410
8600
|
}
|
|
8411
|
-
async _persistStepInput(session2, request, input) {
|
|
8412
|
-
const
|
|
8413
|
-
const
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
};
|
|
8601
|
+
async _persistStepInput(session2, request, input, admittedHistory) {
|
|
8602
|
+
const surface = await session2.deriveMessages();
|
|
8603
|
+
const owned = admittedHistory.filter((message2) => !isUserOrSystemMessage(message2));
|
|
8604
|
+
let ownerIndex = 0;
|
|
8605
|
+
for (const message2 of input) {
|
|
8606
|
+
if (isUserOrSystemMessage(message2)) continue;
|
|
8607
|
+
const actual = canonicalMessages([message2]);
|
|
8608
|
+
while (ownerIndex < owned.length && canonicalMessages([owned[ownerIndex]]) !== actual) {
|
|
8609
|
+
ownerIndex += 1;
|
|
8610
|
+
}
|
|
8611
|
+
if (ownerIndex === owned.length) {
|
|
8612
|
+
throw new AgentError("request is not reconstructable from session log: unowned or reordered assistant/tool message");
|
|
8613
|
+
}
|
|
8614
|
+
ownerIndex += 1;
|
|
8615
|
+
}
|
|
8616
|
+
const nextHeader = requestHeaderFor(request, input);
|
|
8428
8617
|
const previousHeader = session2.requestHeader();
|
|
8429
8618
|
const isFirstRequest = !this._persistedRequest;
|
|
8430
8619
|
const isResume = isFirstRequest && previousHeader !== void 0;
|
|
@@ -8454,19 +8643,23 @@ var AgentService = class {
|
|
|
8454
8643
|
...request.options.provider ? { provider: request.options.provider } : {},
|
|
8455
8644
|
...request.options.model ? { model: request.options.model } : {}
|
|
8456
8645
|
};
|
|
8646
|
+
if (request.options.contextWindow !== void 0) {
|
|
8647
|
+
nextContext.contextWindow = request.options.contextWindow;
|
|
8648
|
+
}
|
|
8457
8649
|
const llmService = this.ctx.reflect.get("llm", false);
|
|
8458
8650
|
const routeCapacity = llmService?.routeCapacity?.();
|
|
8459
|
-
if (routeCapacity?.contextWindow !== void 0) {
|
|
8651
|
+
if (nextContext.contextWindow === void 0 && routeCapacity?.contextWindow !== void 0) {
|
|
8460
8652
|
nextContext.contextWindow = routeCapacity.contextWindow;
|
|
8461
8653
|
}
|
|
8462
8654
|
const previousContext = session2.requestContext();
|
|
8463
8655
|
if (previousContext?.provider !== nextContext.provider || previousContext?.model !== nextContext.model || previousContext?.contextWindow !== nextContext.contextWindow || previousContext === void 0) {
|
|
8464
8656
|
await session2.append("request/context", nextContext);
|
|
8465
8657
|
}
|
|
8466
|
-
const
|
|
8467
|
-
const
|
|
8468
|
-
const
|
|
8469
|
-
|
|
8658
|
+
const isSurfacePrefix = (messages) => canonicalMessages(messages.slice(0, surface.length)) === canonicalMessages(surface);
|
|
8659
|
+
const requested = surface.length > 0 && input[0]?.role === "system" && input[0].content === nextHeader.system && isSurfacePrefix(input.slice(1)) ? input.slice(1) : input;
|
|
8660
|
+
const tail = requested.slice(surface.length);
|
|
8661
|
+
if (isSurfacePrefix(requested) && tail.every(isUserOrSystemMessage)) {
|
|
8662
|
+
for (const message2 of tail) {
|
|
8470
8663
|
if (message2.role === "user") {
|
|
8471
8664
|
await session2.append("user/message", {
|
|
8472
8665
|
content: message2.content,
|
|
@@ -8479,45 +8672,37 @@ var AgentService = class {
|
|
|
8479
8672
|
});
|
|
8480
8673
|
}
|
|
8481
8674
|
}
|
|
8482
|
-
};
|
|
8483
|
-
if (surface.length === 0) {
|
|
8484
|
-
await appendDurable(requested);
|
|
8485
8675
|
return;
|
|
8486
8676
|
}
|
|
8487
|
-
const
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
if (seenUsers <= durableUsers) continue;
|
|
8493
|
-
newTail.push(message2);
|
|
8494
|
-
}
|
|
8495
|
-
await appendDurable(newTail);
|
|
8677
|
+
const nodes = await session2.surfaceEvents();
|
|
8678
|
+
await session2.append("checkpoint", {
|
|
8679
|
+
messages: copyMessages(requested),
|
|
8680
|
+
surfaceOp: { op: "replace", start: nodes[0].seq, end: nodes.at(-1).seq }
|
|
8681
|
+
});
|
|
8496
8682
|
}
|
|
8497
|
-
async _assertReplayable(session2, input) {
|
|
8683
|
+
async _assertReplayable(session2, request, input) {
|
|
8498
8684
|
const reconstructed = await session2.deriveMessages();
|
|
8499
|
-
const
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
...message2.tool_calls?.length ? { tool_calls: message2.tool_calls.map((call) => ({
|
|
8505
|
-
id: call.id,
|
|
8506
|
-
name: call.name,
|
|
8507
|
-
args: JSON.stringify(call.arguments ?? {})
|
|
8508
|
-
})) } : {}
|
|
8509
|
-
}));
|
|
8510
|
-
const actual = canonical(input);
|
|
8511
|
-
const replay = canonical(reconstructed);
|
|
8512
|
-
if (JSON.stringify(actual) !== JSON.stringify(replay)) {
|
|
8685
|
+
const actual = canonicalMessages(input);
|
|
8686
|
+
const replay = canonicalMessages(reconstructed);
|
|
8687
|
+
const header = session2.requestHeader();
|
|
8688
|
+
const headerOwnsPrefix = input[0]?.role === "system" && input[0].content === header?.system && canonicalMessages(input.slice(1)) === replay;
|
|
8689
|
+
if (actual !== replay && !headerOwnsPrefix) {
|
|
8513
8690
|
throw new AgentError(
|
|
8514
|
-
`request is not reconstructable from session log: actual=${
|
|
8691
|
+
`request is not reconstructable from session log: actual=${actual} replay=${replay}`
|
|
8515
8692
|
);
|
|
8516
8693
|
}
|
|
8694
|
+
const expected = requestHeaderFor(request, input);
|
|
8695
|
+
if (header?.system !== expected.system || JSON.stringify(header?.tools ?? []) !== JSON.stringify(expected.tools ?? []) || JSON.stringify(header?.config ?? {}) !== JSON.stringify(expected.config ?? {})) {
|
|
8696
|
+
throw new AgentError("request envelope is not reconstructable from session log");
|
|
8697
|
+
}
|
|
8698
|
+
}
|
|
8699
|
+
async _claimNextStepMessages() {
|
|
8700
|
+
const inputs = await this.config.claimNextStep?.() ?? [];
|
|
8701
|
+
return inputs.flatMap((input) => input.messages?.length ? copyMessages(input.messages) : input.text ? [{ role: "user", content: input.text }] : input.context !== void 0 ? [{ role: "user", content: stringify(input.context) }] : []);
|
|
8517
8702
|
}
|
|
8518
8703
|
async _initialMessages(input) {
|
|
8519
8704
|
const promptService = this.ctx.reflect.get("systemPrompt", false);
|
|
8520
|
-
const assembled = promptService ? (await promptService.assemble()).text.trim() : void 0;
|
|
8705
|
+
const assembled = promptService ? (await promptService.assemble({}, this.ctx)).text.trim() : void 0;
|
|
8521
8706
|
const systemPrompt = assembled || this.inbox.injected().get("agentSystem");
|
|
8522
8707
|
const systemMessage = typeof systemPrompt === "string" && systemPrompt ? [{ role: "system", content: systemPrompt }] : [];
|
|
8523
8708
|
if (input.messages?.length) {
|
|
@@ -8542,7 +8727,7 @@ var AgentService = class {
|
|
|
8542
8727
|
arguments: call.arguments
|
|
8543
8728
|
}));
|
|
8544
8729
|
}
|
|
8545
|
-
next.push(assistant);
|
|
8730
|
+
if (assistant.content || toolCalls.length) next.push(assistant);
|
|
8546
8731
|
for (const call of toolCalls) {
|
|
8547
8732
|
const result = toolResults.find((candidate) => candidate.callId === call.id);
|
|
8548
8733
|
const content = result ? result.ok ? stringify(result.output) : `error: ${result.error?.message ?? "unknown"}` : "error: missing tool result";
|
|
@@ -8572,7 +8757,8 @@ var AgentService = class {
|
|
|
8572
8757
|
return session2;
|
|
8573
8758
|
}
|
|
8574
8759
|
_tools() {
|
|
8575
|
-
const
|
|
8760
|
+
const scoped = this.ctx.reflect.get("tools", false);
|
|
8761
|
+
const tools2 = scoped ?? this.ctx.tools;
|
|
8576
8762
|
if (!tools2) throw new AgentError("tools service is required");
|
|
8577
8763
|
return tools2;
|
|
8578
8764
|
}
|
|
@@ -8665,178 +8851,6 @@ var agent = {
|
|
|
8665
8851
|
}
|
|
8666
8852
|
};
|
|
8667
8853
|
|
|
8668
|
-
// packages/evolve/src/llm.ts
|
|
8669
|
-
var LlmProposalError = class extends Error {
|
|
8670
|
-
name = "LlmProposalError";
|
|
8671
|
-
};
|
|
8672
|
-
function withSystemPrompt(adapter, system) {
|
|
8673
|
-
return {
|
|
8674
|
-
async complete(messages, tools2, options) {
|
|
8675
|
-
const hasSystem = messages.some((message2) => message2.role === "system");
|
|
8676
|
-
const next = !system || hasSystem ? messages : [{ role: "system", content: system }, ...messages];
|
|
8677
|
-
return adapter.complete(next, tools2, options);
|
|
8678
|
-
}
|
|
8679
|
-
};
|
|
8680
|
-
}
|
|
8681
|
-
function llmCandidate(options) {
|
|
8682
|
-
const config2 = {};
|
|
8683
|
-
if (options.system !== void 0) config2.system = options.system;
|
|
8684
|
-
if (options.maxTurns !== void 0) config2.maxTurns = options.maxTurns;
|
|
8685
|
-
if (options.maxSteps !== void 0) config2.maxSteps = options.maxSteps;
|
|
8686
|
-
const plugin = {
|
|
8687
|
-
name: options.name,
|
|
8688
|
-
apply: async (ctx, rawConfig) => {
|
|
8689
|
-
const candidateConfig = readConfig(rawConfig);
|
|
8690
|
-
const fiber = await ctx.plugin(agent, {
|
|
8691
|
-
llm: withSystemPrompt(options.adapter, candidateConfig.system ?? ""),
|
|
8692
|
-
...candidateConfig.maxTurns !== void 0 ? { maxTurns: candidateConfig.maxTurns } : {},
|
|
8693
|
-
...candidateConfig.maxSteps !== void 0 ? { maxSteps: candidateConfig.maxSteps } : {}
|
|
8694
|
-
});
|
|
8695
|
-
return () => fiber.dispose();
|
|
8696
|
-
}
|
|
8697
|
-
};
|
|
8698
|
-
return {
|
|
8699
|
-
name: options.name,
|
|
8700
|
-
plugin,
|
|
8701
|
-
...options.version ? { version: options.version } : {},
|
|
8702
|
-
config: config2,
|
|
8703
|
-
...options.mutation ? { mutation: options.mutation } : {},
|
|
8704
|
-
...options.rationale ? { rationale: options.rationale } : {},
|
|
8705
|
-
...options.model ? { model: options.model } : {}
|
|
8706
|
-
};
|
|
8707
|
-
}
|
|
8708
|
-
function createLlmProposeRule(options) {
|
|
8709
|
-
const parse3 = options.parse ?? parseLlmProposal;
|
|
8710
|
-
return {
|
|
8711
|
-
id: options.ruleId ?? "llm-propose",
|
|
8712
|
-
description: "use an LLM to propose a system prompt mutation",
|
|
8713
|
-
async apply(context) {
|
|
8714
|
-
const completion = await options.adapter.complete(
|
|
8715
|
-
[{ role: "user", content: buildProposalPrompt(context) }],
|
|
8716
|
-
[],
|
|
8717
|
-
{}
|
|
8718
|
-
);
|
|
8719
|
-
const content = completion.content;
|
|
8720
|
-
if (!content) {
|
|
8721
|
-
throw new LlmProposalError("LLM proposal returned no content");
|
|
8722
|
-
}
|
|
8723
|
-
const proposal = await parse3(content);
|
|
8724
|
-
return llmCandidate({
|
|
8725
|
-
name: proposal.name,
|
|
8726
|
-
system: proposal.system,
|
|
8727
|
-
adapter: options.adapter,
|
|
8728
|
-
...options.maxTurns !== void 0 ? { maxTurns: options.maxTurns } : {},
|
|
8729
|
-
...options.maxSteps !== void 0 ? { maxSteps: options.maxSteps } : {},
|
|
8730
|
-
...options.model ? { model: options.model } : {},
|
|
8731
|
-
mutation: {
|
|
8732
|
-
type: "system-prompt",
|
|
8733
|
-
description: proposal.mutationDescription,
|
|
8734
|
-
patch: { system: proposal.system }
|
|
8735
|
-
},
|
|
8736
|
-
rationale: proposal.rationale
|
|
8737
|
-
});
|
|
8738
|
-
}
|
|
8739
|
-
};
|
|
8740
|
-
}
|
|
8741
|
-
function parseLlmProposal(content) {
|
|
8742
|
-
const json = extractJson(content);
|
|
8743
|
-
let parsed;
|
|
8744
|
-
try {
|
|
8745
|
-
parsed = JSON.parse(json);
|
|
8746
|
-
} catch (error2) {
|
|
8747
|
-
throw new LlmProposalError(`LLM proposal is not valid JSON: ${message(error2)}`);
|
|
8748
|
-
}
|
|
8749
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
8750
|
-
throw new LlmProposalError("LLM proposal must be a JSON object");
|
|
8751
|
-
}
|
|
8752
|
-
const record2 = parsed;
|
|
8753
|
-
const name2 = record2.name;
|
|
8754
|
-
const system = record2.system;
|
|
8755
|
-
const rationale = record2.rationale;
|
|
8756
|
-
const mutationDescription = record2.mutationDescription;
|
|
8757
|
-
if (typeof name2 !== "string" || !name2.trim()) {
|
|
8758
|
-
throw new LlmProposalError("LLM proposal missing string field: name");
|
|
8759
|
-
}
|
|
8760
|
-
if (typeof system !== "string" || !system.trim()) {
|
|
8761
|
-
throw new LlmProposalError("LLM proposal missing string field: system");
|
|
8762
|
-
}
|
|
8763
|
-
if (typeof rationale !== "string" || !rationale.trim()) {
|
|
8764
|
-
throw new LlmProposalError("LLM proposal missing string field: rationale");
|
|
8765
|
-
}
|
|
8766
|
-
if (typeof mutationDescription !== "string" || !mutationDescription.trim()) {
|
|
8767
|
-
throw new LlmProposalError("LLM proposal missing string field: mutationDescription");
|
|
8768
|
-
}
|
|
8769
|
-
return {
|
|
8770
|
-
name: name2.trim(),
|
|
8771
|
-
system: system.trim(),
|
|
8772
|
-
rationale: rationale.trim(),
|
|
8773
|
-
mutationDescription: mutationDescription.trim()
|
|
8774
|
-
};
|
|
8775
|
-
}
|
|
8776
|
-
function readConfig(value) {
|
|
8777
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
8778
|
-
const record2 = value;
|
|
8779
|
-
const config2 = {};
|
|
8780
|
-
if (typeof record2.system === "string") config2.system = record2.system;
|
|
8781
|
-
if (typeof record2.maxTurns === "number") config2.maxTurns = record2.maxTurns;
|
|
8782
|
-
if (typeof record2.maxSteps === "number") config2.maxSteps = record2.maxSteps;
|
|
8783
|
-
return config2;
|
|
8784
|
-
}
|
|
8785
|
-
function buildProposalPrompt(context) {
|
|
8786
|
-
const diagnosis = context.diagnosis;
|
|
8787
|
-
const lines = [
|
|
8788
|
-
"\u4F60\u662F tnega \u7684\u81EA\u8FDB\u5316\u5F15\u64CE\u3002\u6839\u636E\u4E00\u6B21\u8BC4\u6D4B\u7684\u8BCA\u65AD\u7ED3\u679C\uFF0C\u751F\u6210\u4E00\u4E2A\u6539\u8FDB\u540E\u7684 Agent \u7CFB\u7EDF\u63D0\u793A\u8BCD\u5019\u9009\u3002",
|
|
8789
|
-
"\u53EA\u8F93\u51FA\u4E00\u4E2A JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981 Markdown \u4EE3\u7801\u5757\uFF0C\u4E0D\u8981\u989D\u5916\u89E3\u91CA\u3002JSON \u5B57\u6BB5\uFF1A",
|
|
8790
|
-
'{"name":"\u5019\u9009\u540D","system":"\u65B0\u7684\u7CFB\u7EDF\u63D0\u793A\u8BCD","rationale":"\u4FEE\u6539\u7406\u7531","mutationDescription":"\u5177\u4F53\u6539\u52A8\u8BF4\u660E"}',
|
|
8791
|
-
"",
|
|
8792
|
-
`\u8FED\u4EE3\uFF1A${context.iteration}`
|
|
8793
|
-
];
|
|
8794
|
-
if (context.baseline) {
|
|
8795
|
-
const run = context.baseline;
|
|
8796
|
-
lines.push(
|
|
8797
|
-
`baseline: ${run.candidate.name} score=${run.summary.score.toFixed(3)} passed=${run.summary.passed}/${run.summary.total}`
|
|
8798
|
-
);
|
|
8799
|
-
}
|
|
8800
|
-
if (diagnosis.failingTasks.length) {
|
|
8801
|
-
lines.push("\u5931\u8D25\u4EFB\u52A1\uFF1A");
|
|
8802
|
-
for (const taskId of diagnosis.failingTasks) {
|
|
8803
|
-
const modes = diagnosis.failureModes.filter((mode) => mode.taskId === taskId);
|
|
8804
|
-
const reasons = modes.map((mode) => {
|
|
8805
|
-
const reason = mode.reason ? `(${mode.reason})` : "";
|
|
8806
|
-
return `${mode.strategy}=${mode.status}${reason}`;
|
|
8807
|
-
}).join(", ");
|
|
8808
|
-
lines.push(`- ${taskId}: ${reasons}`);
|
|
8809
|
-
}
|
|
8810
|
-
} else if (context.baseline) {
|
|
8811
|
-
lines.push("\u5F53\u524D baseline \u5168\u90E8\u901A\u8FC7\uFF0C\u8BF7\u4FDD\u6301\u6B63\u786E\u884C\u4E3A\uFF0C\u5E76\u5C1D\u8BD5\u8BA9\u8F93\u51FA\u66F4\u7A33\u5B9A\u3002");
|
|
8812
|
-
}
|
|
8813
|
-
if (context.history.length) {
|
|
8814
|
-
lines.push("\u5DF2\u6709\u5019\u9009\uFF08\u907F\u514D\u91CD\u590D\uFF09\uFF1A");
|
|
8815
|
-
for (const node2 of context.history.slice(-5)) {
|
|
8816
|
-
lines.push(`- ${node2.candidate.name}: ${node2.candidate.rationale ?? ""}`);
|
|
8817
|
-
}
|
|
8818
|
-
}
|
|
8819
|
-
lines.push("\u7EA6\u675F\uFF1Asystem \u5FC5\u987B\u662F\u7B80\u6D01\u53EF\u6267\u884C\u7684\u4E2D\u6587\u6216\u82F1\u6587\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF1B\u4E0D\u8981\u5305\u542B JSON \u4E4B\u5916\u7684\u8F93\u51FA\u3002");
|
|
8820
|
-
return lines.join("\n");
|
|
8821
|
-
}
|
|
8822
|
-
function extractJson(content) {
|
|
8823
|
-
const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
8824
|
-
if (fenced?.[1]) return fenced[1];
|
|
8825
|
-
const start = content.indexOf("{");
|
|
8826
|
-
const end = content.lastIndexOf("}");
|
|
8827
|
-
if (start < 0 || end < start) {
|
|
8828
|
-
throw new LlmProposalError("LLM proposal did not contain a JSON object");
|
|
8829
|
-
}
|
|
8830
|
-
return content.slice(start, end + 1);
|
|
8831
|
-
}
|
|
8832
|
-
function message(error2) {
|
|
8833
|
-
if (error2 instanceof Error) return error2.message;
|
|
8834
|
-
return String(error2);
|
|
8835
|
-
}
|
|
8836
|
-
|
|
8837
|
-
// packages/evolve/src/log.ts
|
|
8838
|
-
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
8839
|
-
|
|
8840
8854
|
// packages/core/src/utils.ts
|
|
8841
8855
|
var DisposableList = class {
|
|
8842
8856
|
sn = 0;
|
|
@@ -10112,6 +10126,178 @@ var Service = class _Service {
|
|
|
10112
10126
|
}
|
|
10113
10127
|
};
|
|
10114
10128
|
|
|
10129
|
+
// packages/evolve/src/llm.ts
|
|
10130
|
+
var LlmProposalError = class extends Error {
|
|
10131
|
+
name = "LlmProposalError";
|
|
10132
|
+
};
|
|
10133
|
+
function withSystemPrompt(adapter, system) {
|
|
10134
|
+
return {
|
|
10135
|
+
async complete(messages, tools2, options) {
|
|
10136
|
+
const hasSystem = messages.some((message2) => message2.role === "system");
|
|
10137
|
+
const next = !system || hasSystem ? messages : [{ role: "system", content: system }, ...messages];
|
|
10138
|
+
return adapter.complete(next, tools2, options);
|
|
10139
|
+
}
|
|
10140
|
+
};
|
|
10141
|
+
}
|
|
10142
|
+
function llmCandidate(options) {
|
|
10143
|
+
const config2 = {};
|
|
10144
|
+
if (options.system !== void 0) config2.system = options.system;
|
|
10145
|
+
if (options.maxTurns !== void 0) config2.maxTurns = options.maxTurns;
|
|
10146
|
+
if (options.maxSteps !== void 0) config2.maxSteps = options.maxSteps;
|
|
10147
|
+
const plugin = {
|
|
10148
|
+
name: options.name,
|
|
10149
|
+
apply: async (ctx, rawConfig) => {
|
|
10150
|
+
const candidateConfig = readConfig(rawConfig);
|
|
10151
|
+
const fiber = await ctx.plugin(agent, {
|
|
10152
|
+
llm: withSystemPrompt(options.adapter, candidateConfig.system ?? ""),
|
|
10153
|
+
...candidateConfig.maxTurns !== void 0 ? { maxTurns: candidateConfig.maxTurns } : {},
|
|
10154
|
+
...candidateConfig.maxSteps !== void 0 ? { maxSteps: candidateConfig.maxSteps } : {}
|
|
10155
|
+
});
|
|
10156
|
+
return () => fiber.dispose();
|
|
10157
|
+
}
|
|
10158
|
+
};
|
|
10159
|
+
return {
|
|
10160
|
+
name: options.name,
|
|
10161
|
+
plugin,
|
|
10162
|
+
...options.version ? { version: options.version } : {},
|
|
10163
|
+
config: config2,
|
|
10164
|
+
...options.mutation ? { mutation: options.mutation } : {},
|
|
10165
|
+
...options.rationale ? { rationale: options.rationale } : {},
|
|
10166
|
+
...options.model ? { model: options.model } : {}
|
|
10167
|
+
};
|
|
10168
|
+
}
|
|
10169
|
+
function createLlmProposeRule(options) {
|
|
10170
|
+
const parse3 = options.parse ?? parseLlmProposal;
|
|
10171
|
+
return {
|
|
10172
|
+
id: options.ruleId ?? "llm-propose",
|
|
10173
|
+
description: "use an LLM to propose a system prompt mutation",
|
|
10174
|
+
async apply(context) {
|
|
10175
|
+
const completion = await options.adapter.complete(
|
|
10176
|
+
[{ role: "user", content: buildProposalPrompt(context) }],
|
|
10177
|
+
[],
|
|
10178
|
+
{}
|
|
10179
|
+
);
|
|
10180
|
+
const content = completion.content;
|
|
10181
|
+
if (!content) {
|
|
10182
|
+
throw new LlmProposalError("LLM proposal returned no content");
|
|
10183
|
+
}
|
|
10184
|
+
const proposal = await parse3(content);
|
|
10185
|
+
return llmCandidate({
|
|
10186
|
+
name: proposal.name,
|
|
10187
|
+
system: proposal.system,
|
|
10188
|
+
adapter: options.adapter,
|
|
10189
|
+
...options.maxTurns !== void 0 ? { maxTurns: options.maxTurns } : {},
|
|
10190
|
+
...options.maxSteps !== void 0 ? { maxSteps: options.maxSteps } : {},
|
|
10191
|
+
...options.model ? { model: options.model } : {},
|
|
10192
|
+
mutation: {
|
|
10193
|
+
type: "system-prompt",
|
|
10194
|
+
description: proposal.mutationDescription,
|
|
10195
|
+
patch: { system: proposal.system }
|
|
10196
|
+
},
|
|
10197
|
+
rationale: proposal.rationale
|
|
10198
|
+
});
|
|
10199
|
+
}
|
|
10200
|
+
};
|
|
10201
|
+
}
|
|
10202
|
+
function parseLlmProposal(content) {
|
|
10203
|
+
const json = extractJson(content);
|
|
10204
|
+
let parsed;
|
|
10205
|
+
try {
|
|
10206
|
+
parsed = JSON.parse(json);
|
|
10207
|
+
} catch (error2) {
|
|
10208
|
+
throw new LlmProposalError(`LLM proposal is not valid JSON: ${message(error2)}`);
|
|
10209
|
+
}
|
|
10210
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
10211
|
+
throw new LlmProposalError("LLM proposal must be a JSON object");
|
|
10212
|
+
}
|
|
10213
|
+
const record2 = parsed;
|
|
10214
|
+
const name2 = record2.name;
|
|
10215
|
+
const system = record2.system;
|
|
10216
|
+
const rationale = record2.rationale;
|
|
10217
|
+
const mutationDescription = record2.mutationDescription;
|
|
10218
|
+
if (typeof name2 !== "string" || !name2.trim()) {
|
|
10219
|
+
throw new LlmProposalError("LLM proposal missing string field: name");
|
|
10220
|
+
}
|
|
10221
|
+
if (typeof system !== "string" || !system.trim()) {
|
|
10222
|
+
throw new LlmProposalError("LLM proposal missing string field: system");
|
|
10223
|
+
}
|
|
10224
|
+
if (typeof rationale !== "string" || !rationale.trim()) {
|
|
10225
|
+
throw new LlmProposalError("LLM proposal missing string field: rationale");
|
|
10226
|
+
}
|
|
10227
|
+
if (typeof mutationDescription !== "string" || !mutationDescription.trim()) {
|
|
10228
|
+
throw new LlmProposalError("LLM proposal missing string field: mutationDescription");
|
|
10229
|
+
}
|
|
10230
|
+
return {
|
|
10231
|
+
name: name2.trim(),
|
|
10232
|
+
system: system.trim(),
|
|
10233
|
+
rationale: rationale.trim(),
|
|
10234
|
+
mutationDescription: mutationDescription.trim()
|
|
10235
|
+
};
|
|
10236
|
+
}
|
|
10237
|
+
function readConfig(value) {
|
|
10238
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
10239
|
+
const record2 = value;
|
|
10240
|
+
const config2 = {};
|
|
10241
|
+
if (typeof record2.system === "string") config2.system = record2.system;
|
|
10242
|
+
if (typeof record2.maxTurns === "number") config2.maxTurns = record2.maxTurns;
|
|
10243
|
+
if (typeof record2.maxSteps === "number") config2.maxSteps = record2.maxSteps;
|
|
10244
|
+
return config2;
|
|
10245
|
+
}
|
|
10246
|
+
function buildProposalPrompt(context) {
|
|
10247
|
+
const diagnosis = context.diagnosis;
|
|
10248
|
+
const lines = [
|
|
10249
|
+
"\u4F60\u662F tnega \u7684\u81EA\u8FDB\u5316\u5F15\u64CE\u3002\u6839\u636E\u4E00\u6B21\u8BC4\u6D4B\u7684\u8BCA\u65AD\u7ED3\u679C\uFF0C\u751F\u6210\u4E00\u4E2A\u6539\u8FDB\u540E\u7684 Agent \u7CFB\u7EDF\u63D0\u793A\u8BCD\u5019\u9009\u3002",
|
|
10250
|
+
"\u53EA\u8F93\u51FA\u4E00\u4E2A JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981 Markdown \u4EE3\u7801\u5757\uFF0C\u4E0D\u8981\u989D\u5916\u89E3\u91CA\u3002JSON \u5B57\u6BB5\uFF1A",
|
|
10251
|
+
'{"name":"\u5019\u9009\u540D","system":"\u65B0\u7684\u7CFB\u7EDF\u63D0\u793A\u8BCD","rationale":"\u4FEE\u6539\u7406\u7531","mutationDescription":"\u5177\u4F53\u6539\u52A8\u8BF4\u660E"}',
|
|
10252
|
+
"",
|
|
10253
|
+
`\u8FED\u4EE3\uFF1A${context.iteration}`
|
|
10254
|
+
];
|
|
10255
|
+
if (context.baseline) {
|
|
10256
|
+
const run = context.baseline;
|
|
10257
|
+
lines.push(
|
|
10258
|
+
`baseline: ${run.candidate.name} score=${run.summary.score.toFixed(3)} passed=${run.summary.passed}/${run.summary.total}`
|
|
10259
|
+
);
|
|
10260
|
+
}
|
|
10261
|
+
if (diagnosis.failingTasks.length) {
|
|
10262
|
+
lines.push("\u5931\u8D25\u4EFB\u52A1\uFF1A");
|
|
10263
|
+
for (const taskId of diagnosis.failingTasks) {
|
|
10264
|
+
const modes = diagnosis.failureModes.filter((mode) => mode.taskId === taskId);
|
|
10265
|
+
const reasons = modes.map((mode) => {
|
|
10266
|
+
const reason = mode.reason ? `(${mode.reason})` : "";
|
|
10267
|
+
return `${mode.strategy}=${mode.status}${reason}`;
|
|
10268
|
+
}).join(", ");
|
|
10269
|
+
lines.push(`- ${taskId}: ${reasons}`);
|
|
10270
|
+
}
|
|
10271
|
+
} else if (context.baseline) {
|
|
10272
|
+
lines.push("\u5F53\u524D baseline \u5168\u90E8\u901A\u8FC7\uFF0C\u8BF7\u4FDD\u6301\u6B63\u786E\u884C\u4E3A\uFF0C\u5E76\u5C1D\u8BD5\u8BA9\u8F93\u51FA\u66F4\u7A33\u5B9A\u3002");
|
|
10273
|
+
}
|
|
10274
|
+
if (context.history.length) {
|
|
10275
|
+
lines.push("\u5DF2\u6709\u5019\u9009\uFF08\u907F\u514D\u91CD\u590D\uFF09\uFF1A");
|
|
10276
|
+
for (const node2 of context.history.slice(-5)) {
|
|
10277
|
+
lines.push(`- ${node2.candidate.name}: ${node2.candidate.rationale ?? ""}`);
|
|
10278
|
+
}
|
|
10279
|
+
}
|
|
10280
|
+
lines.push("\u7EA6\u675F\uFF1Asystem \u5FC5\u987B\u662F\u7B80\u6D01\u53EF\u6267\u884C\u7684\u4E2D\u6587\u6216\u82F1\u6587\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF1B\u4E0D\u8981\u5305\u542B JSON \u4E4B\u5916\u7684\u8F93\u51FA\u3002");
|
|
10281
|
+
return lines.join("\n");
|
|
10282
|
+
}
|
|
10283
|
+
function extractJson(content) {
|
|
10284
|
+
const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
10285
|
+
if (fenced?.[1]) return fenced[1];
|
|
10286
|
+
const start = content.indexOf("{");
|
|
10287
|
+
const end = content.lastIndexOf("}");
|
|
10288
|
+
if (start < 0 || end < start) {
|
|
10289
|
+
throw new LlmProposalError("LLM proposal did not contain a JSON object");
|
|
10290
|
+
}
|
|
10291
|
+
return content.slice(start, end + 1);
|
|
10292
|
+
}
|
|
10293
|
+
function message(error2) {
|
|
10294
|
+
if (error2 instanceof Error) return error2.message;
|
|
10295
|
+
return String(error2);
|
|
10296
|
+
}
|
|
10297
|
+
|
|
10298
|
+
// packages/evolve/src/log.ts
|
|
10299
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
10300
|
+
|
|
10115
10301
|
// packages/tools/src/calc.ts
|
|
10116
10302
|
var CONSTANTS = {
|
|
10117
10303
|
e: Math.E,
|