@kenkaiiii/gg-agent 5.44.0 → 5.44.2

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.d.cts CHANGED
@@ -55,6 +55,13 @@ interface AgentToolCallEndEvent {
55
55
  details?: unknown;
56
56
  isError: boolean;
57
57
  durationMs: number;
58
+ /**
59
+ * Set only when the call failed schema validation: how many consecutive
60
+ * times this tool produced this same validation error. 1 means the model
61
+ * still has room to self-correct; 3 is the threshold that ends the turn.
62
+ * Logged so a retry loop shows up as a count instead of identical lines.
63
+ */
64
+ invalidArgAttempt?: number;
58
65
  }
59
66
  interface AgentTurnTiming {
60
67
  /** Logical turn start, before context transforms or provider retries. Unix epoch milliseconds. */
@@ -133,7 +140,7 @@ interface AgentTurnBudgetExtendedEvent {
133
140
  */
134
141
  interface AgentTruncatedEvent {
135
142
  type: "truncated";
136
- reason: "max_tokens" | "refusal" | "provider_error";
143
+ reason: "max_tokens" | "refusal" | "provider_error" | "empty_response";
137
144
  /** True when the loop injected a continuation and will keep going. */
138
145
  continued: boolean;
139
146
  }
package/dist/index.d.ts CHANGED
@@ -55,6 +55,13 @@ interface AgentToolCallEndEvent {
55
55
  details?: unknown;
56
56
  isError: boolean;
57
57
  durationMs: number;
58
+ /**
59
+ * Set only when the call failed schema validation: how many consecutive
60
+ * times this tool produced this same validation error. 1 means the model
61
+ * still has room to self-correct; 3 is the threshold that ends the turn.
62
+ * Logged so a retry loop shows up as a count instead of identical lines.
63
+ */
64
+ invalidArgAttempt?: number;
58
65
  }
59
66
  interface AgentTurnTiming {
60
67
  /** Logical turn start, before context transforms or provider retries. Unix epoch milliseconds. */
@@ -133,7 +140,7 @@ interface AgentTurnBudgetExtendedEvent {
133
140
  */
134
141
  interface AgentTruncatedEvent {
135
142
  type: "truncated";
136
- reason: "max_tokens" | "refusal" | "provider_error";
143
+ reason: "max_tokens" | "refusal" | "provider_error" | "empty_response";
137
144
  /** True when the loop injected a continuation and will keep going. */
138
145
  continued: boolean;
139
146
  }
package/dist/index.js CHANGED
@@ -864,6 +864,7 @@ async function* agentLoop(messages, options) {
864
864
  continue;
865
865
  }
866
866
  }
867
+ const emptyExhausted = !hasActionableContent;
867
868
  emptyResponseRetries = 0;
868
869
  useNonStreamingFallback = false;
869
870
  totalUsage.inputTokens += response.usage.inputTokens;
@@ -877,9 +878,11 @@ async function* agentLoop(messages, options) {
877
878
  if (response.usage.cacheWrite) {
878
879
  totalUsage.cacheWrite = (totalUsage.cacheWrite ?? 0) + response.usage.cacheWrite;
879
880
  }
880
- messages.push(response.message);
881
- latestProviderUsage = response.usage;
882
- usageAnchorIndex = messages.length - 1;
881
+ if (!emptyExhausted) {
882
+ messages.push(response.message);
883
+ latestProviderUsage = response.usage;
884
+ usageAnchorIndex = messages.length - 1;
885
+ }
883
886
  const completedAt = Date.now();
884
887
  const outputTokensPerSecond = providerDurationMs > 0 && response.usage.outputTokens > 0 ? response.usage.outputTokens / (providerDurationMs / 1e3) : void 0;
885
888
  const timing = {
@@ -911,8 +914,15 @@ async function* agentLoop(messages, options) {
911
914
  }
912
915
  consecutivePauses = 0;
913
916
  const allToolCalls = extractToolCalls(response.message.content);
914
- if (response.stopReason !== "tool_use" && allToolCalls.length === 0) {
915
- if (response.stopReason === "max_tokens") {
917
+ if (emptyExhausted || response.stopReason !== "tool_use" && allToolCalls.length === 0) {
918
+ if (emptyExhausted) {
919
+ diag("empty_response_exhausted", {
920
+ provider: options.provider,
921
+ model: options.model,
922
+ stopReason: response.stopReason
923
+ });
924
+ yield { type: "truncated", reason: "empty_response", continued: false };
925
+ } else if (response.stopReason === "max_tokens") {
916
926
  if (maxTokensContinuations < MAX_OUTPUT_CONTINUATIONS) {
917
927
  maxTokensContinuations++;
918
928
  diag("max_tokens_continuation", {
@@ -1134,6 +1144,7 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
1134
1144
  let resultContent;
1135
1145
  let details;
1136
1146
  let isError = false;
1147
+ let invalidArgAttempt;
1137
1148
  const tool = options.toolMap.get(toolCall.name);
1138
1149
  if (!tool) {
1139
1150
  resultContent = `Unknown tool: ${toolCall.name}`;
@@ -1168,6 +1179,7 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
1168
1179
  const failureKey = `${toolCall.name}:${prettyError}`;
1169
1180
  const failureCount = (options.invalidToolArgumentCounts.get(failureKey) ?? 0) + 1;
1170
1181
  options.invalidToolArgumentCounts.set(failureKey, failureCount);
1182
+ invalidArgAttempt = failureCount;
1171
1183
  resultContent = `Invalid arguments for tool \`${toolCall.name}\`:
1172
1184
  ` + prettyError + "\nRe-issue the call with each field as the correct type.";
1173
1185
  if (failureCount >= 3) {
@@ -1198,7 +1210,8 @@ async function executeSingleToolCall(toolCall, options, pushEvent) {
1198
1210
  result: toolResultPreview(resultContent),
1199
1211
  details,
1200
1212
  isError,
1201
- durationMs
1213
+ durationMs,
1214
+ ...invalidArgAttempt === void 0 ? {} : { invalidArgAttempt }
1202
1215
  });
1203
1216
  return { toolCallId: toolCall.id, content: resultContent, isError };
1204
1217
  }