@kenkaiiii/gg-agent 5.24.0 → 5.26.0

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/index.cjs CHANGED
@@ -219,6 +219,9 @@ function isTransportFailure(err) {
219
219
  }
220
220
  return false;
221
221
  }
222
+ function turnBudgetContinuationPrompt() {
223
+ return "[You reached the turn limit for this segment but the work is not finished, so you have been granted more turns. Before continuing, state in one or two sentences what is already done and what remains, then keep going from there \u2014 do not restart work that is already complete.]";
224
+ }
222
225
  function abortableSleep(ms, signal) {
223
226
  if (signal?.aborted) {
224
227
  return Promise.reject(new DOMException("Aborted", "AbortError"));
@@ -238,6 +241,9 @@ function abortableSleep(ms, signal) {
238
241
  }
239
242
  async function* agentLoop(messages, options) {
240
243
  const maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;
244
+ let effectiveMaxTurns = maxTurns;
245
+ const maxTurnExtensions = Math.max(0, options.maxTurnExtensions ?? 2);
246
+ let turnExtensions = 0;
241
247
  const maxContinuations = options.maxContinuations ?? 5;
242
248
  let toolMap = new Map((options.tools ?? []).map((t) => [t.name, t]));
243
249
  const totalUsage = { inputTokens: 0, outputTokens: 0 };
@@ -290,7 +296,7 @@ async function* agentLoop(messages, options) {
290
296
  let firstProviderEventAt;
291
297
  let providerDurationMs = 0;
292
298
  try {
293
- while (turn < maxTurns) {
299
+ while (turn < effectiveMaxTurns) {
294
300
  options.signal?.throwIfAborted();
295
301
  turn++;
296
302
  if (logicalTurnStartedAt === 0) logicalTurnStartedAt = Date.now();
@@ -1003,8 +1009,46 @@ async function* agentLoop(messages, options) {
1003
1009
  }
1004
1010
  }
1005
1011
  }
1006
- if (turn >= maxTurns) {
1007
- hitMaxTurns = true;
1012
+ if (turn >= effectiveMaxTurns) {
1013
+ let extended = false;
1014
+ if (options.onTurnBudgetExhausted && turnExtensions < maxTurnExtensions) {
1015
+ const extension = turnExtensions + 1;
1016
+ let granted = false;
1017
+ try {
1018
+ granted = await options.onTurnBudgetExhausted({
1019
+ turn,
1020
+ maxTurns: effectiveMaxTurns,
1021
+ extension
1022
+ });
1023
+ } catch {
1024
+ granted = false;
1025
+ }
1026
+ if (granted) {
1027
+ turnExtensions = extension;
1028
+ effectiveMaxTurns += maxTurns;
1029
+ extended = true;
1030
+ diag("turn_budget_extended", {
1031
+ turn,
1032
+ grantedTurns: effectiveMaxTurns,
1033
+ extension,
1034
+ provider: options.provider,
1035
+ model: options.model
1036
+ });
1037
+ yield {
1038
+ type: "turn_budget_extended",
1039
+ turn,
1040
+ grantedTurns: effectiveMaxTurns,
1041
+ extension
1042
+ };
1043
+ messages.push({
1044
+ role: "user",
1045
+ content: turnBudgetContinuationPrompt()
1046
+ });
1047
+ }
1048
+ }
1049
+ if (!extended) {
1050
+ hitMaxTurns = true;
1051
+ }
1008
1052
  }
1009
1053
  }
1010
1054
  } finally {
@@ -1020,14 +1064,15 @@ async function* agentLoop(messages, options) {
1020
1064
  if (hitMaxTurns) {
1021
1065
  diag("max_turns_reached", {
1022
1066
  turn,
1023
- maxTurns,
1067
+ maxTurns: effectiveMaxTurns,
1068
+ extensions: turnExtensions,
1024
1069
  provider: options.provider,
1025
1070
  model: options.model
1026
1071
  });
1027
1072
  yield {
1028
1073
  type: "max_turns",
1029
1074
  totalTurns: turn,
1030
- maxTurns
1075
+ maxTurns: effectiveMaxTurns
1031
1076
  };
1032
1077
  }
1033
1078
  yield {