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/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, false));
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 = {}, useStream = true) {
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
- await session2.append("turn/start", {
8035
- turn,
8036
- input: claimed.text ?? claimed,
8037
- reason: "user"
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.waterfall("agent/pre-step", {
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
- const streamMethod = useStream ? llm.stream : void 0;
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
- if (streamMethod) {
8104
- const streamRequest = {
8105
- index,
8106
- messages: llmMessages,
8107
- tools: request.tools,
8108
- options: request.options
8109
- };
8110
- const stream = await this.ctx.waterfallAsync(
8111
- "llm/stream",
8112
- streamRequest,
8113
- async (payload) => {
8114
- if (!streamMethod) {
8115
- throw new AgentError("llm.stream is required for streaming runs");
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
- if (!persistedStepInput) {
8125
- await this._persistStepInput(session2, request, llmMessages);
8126
- if (this.config.assertReplayable) {
8127
- await this._assertReplayable(session2, llmMessages);
8128
- }
8129
- persistedStepInput = true;
8130
- }
8131
- let chunkIndex = 0;
8132
- for await (const event of stream) {
8133
- streamEvents.push(event);
8134
- if (event.type === "message_delta") {
8135
- await session2.append("assistant/chunk", {
8136
- id: event.id,
8137
- content: event.delta,
8138
- index: chunkIndex
8139
- });
8140
- chunkIndex += 1;
8141
- }
8142
- yield event;
8143
- }
8144
- completion = completionFromStreamEvents(streamEvents);
8145
- } else {
8146
- if (!persistedStepInput) {
8147
- await this._persistStepInput(session2, request, llmMessages);
8148
- if (this.config.assertReplayable) {
8149
- await this._assertReplayable(session2, llmMessages);
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
- completion = await llm.complete(llmMessages, request.tools, request.options);
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
- const content = partialStreamContent(streamEvents);
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(llmMessages),
8178
- tools: request.tools,
8179
- options: request.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
- ...request.options.provider ? { provider: request.options.provider } : {},
8184
- ...request.options.model ? { model: request.options.model } : {},
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 (options.signal?.aborted) break;
8210
- if (!completion) throw new AgentError("LLM adapter did not produce a completion");
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 (finalTurnGranted && toolCalls.length) {
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
- await session2.append("assistant/message", {
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
- try {
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: toToolError(error2),
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
- await session2.append("assistant/message", { content: completion.content ?? "" });
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
- if (concludesTurn) {
8304
- finishReason = "stop";
8305
- break;
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) break;
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 system = input.find((message2) => message2.role === "system")?.content;
8413
- const tools2 = request.tools.map((tool) => ({
8414
- name: tool.schema.name,
8415
- description: tool.schema.description,
8416
- ...tool.schema.parameters ? { parameters: tool.schema.parameters } : {}
8417
- }));
8418
- const config2 = {
8419
- ...request.options.provider ? { provider: request.options.provider } : {},
8420
- ...request.options.model ? { model: request.options.model } : {},
8421
- ...request.options.temperature !== void 0 ? { temperature: request.options.temperature } : {}
8422
- };
8423
- const nextHeader = {
8424
- ...Object.keys(config2).length ? { config: config2 } : {},
8425
- ...system !== void 0 ? { system } : {},
8426
- ...tools2.length ? { tools: tools2 } : {}
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 requested = input.filter(isUserOrSystemMessage);
8467
- const surface = await session2.deriveMessages();
8468
- const appendDurable = async (messages) => {
8469
- for (const message2 of messages) {
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 durableUsers = surface.filter((message2) => message2.role === "user").length;
8488
- let seenUsers = 0;
8489
- const newTail = [];
8490
- for (const message2 of requested) {
8491
- if (message2.role === "user") seenUsers += 1;
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 canonical = (messages) => messages.filter((message2) => message2.role !== "system").map((message2) => ({
8500
- role: message2.role,
8501
- content: message2.content,
8502
- ...message2.tool_call_id ? { tool_call_id: message2.tool_call_id } : {},
8503
- ...message2.name ? { name: message2.name } : {},
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=${JSON.stringify(actual)} replay=${JSON.stringify(replay)}`
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 tools2 = this.ctx.tools;
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,