@pentoshi/clai 3.12.0 → 3.13.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/agent/compaction-summary.d.ts +20 -12
- package/dist/agent/compaction-summary.js +72 -14
- package/dist/agent/compaction-summary.js.map +1 -1
- package/dist/agent/context-manager.d.ts +2 -0
- package/dist/agent/context-manager.js +64 -35
- package/dist/agent/context-manager.js.map +1 -1
- package/dist/agent/events.d.ts +1 -0
- package/dist/agent/reliability-policy.d.ts +1 -0
- package/dist/agent/reliability-policy.js +13 -9
- package/dist/agent/reliability-policy.js.map +1 -1
- package/dist/agent/runner.js +147 -98
- package/dist/agent/runner.js.map +1 -1
- package/dist/app/adapters/agent-event-adapter.js +1 -0
- package/dist/app/adapters/agent-event-adapter.js.map +1 -1
- package/dist/app/controllers/session-compact-helper.d.ts +3 -1
- package/dist/app/controllers/session-compact-helper.js +86 -42
- package/dist/app/controllers/session-compact-helper.js.map +1 -1
- package/dist/app/controllers/session-context-usage.js +0 -2
- package/dist/app/controllers/session-context-usage.js.map +1 -1
- package/dist/app/controllers/session-controller.js +3 -0
- package/dist/app/controllers/session-controller.js.map +1 -1
- package/dist/app/events/app-event.d.ts +1 -0
- package/dist/app/events/app-event.js.map +1 -1
- package/dist/tools/registry.js +33 -13
- package/dist/tools/registry.js.map +1 -1
- package/dist/tui/state.js +5 -5
- package/dist/tui/state.js.map +1 -1
- package/dist/tui-v2/components/status/status-line.d.ts +1 -0
- package/dist/tui-v2/components/status/status-line.js +62 -3
- package/dist/tui-v2/components/status/status-line.js.map +1 -1
- package/dist/tui-v2/components/transcript/thinking-block.js +2 -2
- package/dist/tui-v2/components/transcript/thinking-block.js.map +1 -1
- package/dist/tui-v2/components/transcript/transcript-scrollbar.d.ts +7 -11
- package/dist/tui-v2/components/transcript/transcript-scrollbar.js +35 -30
- package/dist/tui-v2/components/transcript/transcript-scrollbar.js.map +1 -1
- package/dist/tui-v2/rendering/incremental-strip.js +1 -1
- package/dist/tui-v2/rendering/incremental-strip.js.map +1 -1
- package/dist/tui-v2/rendering/strip-tool-surfaces.d.ts +0 -8
- package/dist/tui-v2/rendering/strip-tool-surfaces.js +32 -14
- package/dist/tui-v2/rendering/strip-tool-surfaces.js.map +1 -1
- package/dist/tui-v2/rendering/thinking-tail.d.ts +1 -0
- package/dist/tui-v2/rendering/thinking-tail.js +21 -0
- package/dist/tui-v2/rendering/thinking-tail.js.map +1 -1
- package/dist/tui-v2/state/transcript-compaction.js +1 -4
- package/dist/tui-v2/state/transcript-compaction.js.map +1 -1
- package/dist/tui-v2/state/transcript-reducer.js +3 -1
- package/dist/tui-v2/state/transcript-reducer.js.map +1 -1
- package/dist/version.generated.d.ts +2 -2
- package/dist/version.generated.js +2 -2
- package/package.json +1 -1
package/dist/agent/runner.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { streamWithProvider } from "../llm/router.js";
|
|
4
|
+
import { modelContextWindow } from "../llm/token-usage.js";
|
|
4
5
|
import { streamAlreadyEmitted } from "../llm/stream-progress.js";
|
|
5
6
|
import { classifyStreamFailure, planStreamRecovery, recordRecoveryAttempt, createStreamRecoveryState, resetStreamRecoveryState, } from "./stream-recovery.js";
|
|
6
7
|
import { modelSupportsVision, resolveToolDialect } from "../llm/capabilities.js";
|
|
@@ -55,7 +56,7 @@ import { analyzeTask, formatTaskAnalysisHint, isNarrowExplicitNmapOperation, } f
|
|
|
55
56
|
import { computeMaxIterations, computeStepBudget } from "./step-budget.js";
|
|
56
57
|
import { isScratchOnlyWrite } from "./scratch-write.js";
|
|
57
58
|
import { buildDurableEnvelope, WorkLedger, } from "./durable-envelope.js";
|
|
58
|
-
import { COMPACTION_SYSTEM_PROMPT, COMPACTION_MAX_COMPLETION_TOKENS, COMPACTION_MAP_MAX_COMPLETION_TOKENS, } from "./compaction-summary.js";
|
|
59
|
+
import { buildCompactionRetryPrompt, compactionSinglePassInputBudget, COMPACTION_SYSTEM_PROMPT, COMPACTION_MAX_COMPLETION_TOKENS, COMPACTION_MAP_MAX_COMPLETION_TOKENS, isCompactionCompletionTruncated, looksLikeIncompleteCompactionSummary, looksLikeTranscriptReplay, normalizeCompactionSummary, } from "./compaction-summary.js";
|
|
59
60
|
import { maybeAppendPlanModeReminder, PLAN_REMINDER_TOAST, } from "./plan-mode-reminders.js";
|
|
60
61
|
import { LoopGuard } from "./loop-guard.js";
|
|
61
62
|
import { appendInterruptedReasoning, interruptedReasoningBrief, isMeaningfulResumptionYield, } from "./interrupted-reasoning.js";
|
|
@@ -315,12 +316,21 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
315
316
|
process.stdout.write(chalk.dim(" ✦ Compacted Context · streaming Markdown\n\n"));
|
|
316
317
|
}
|
|
317
318
|
};
|
|
318
|
-
const writeCompactionDelta = (id, text) => {
|
|
319
|
-
if (!text)
|
|
319
|
+
const writeCompactionDelta = (id, text, replace = false) => {
|
|
320
|
+
if (!text && !replace)
|
|
320
321
|
return;
|
|
321
|
-
emit({
|
|
322
|
-
|
|
323
|
-
|
|
322
|
+
emit({
|
|
323
|
+
type: "compaction-delta",
|
|
324
|
+
id,
|
|
325
|
+
text,
|
|
326
|
+
...(replace ? { replace: true } : {}),
|
|
327
|
+
});
|
|
328
|
+
if (writesDirectly) {
|
|
329
|
+
if (replace)
|
|
330
|
+
process.stdout.write(chalk.dim("\n ↻ rewriting compacted context\n\n"));
|
|
331
|
+
if (text)
|
|
332
|
+
process.stdout.write(text);
|
|
333
|
+
}
|
|
324
334
|
};
|
|
325
335
|
const writeCompactionCompleted = (id, summary, beforeTokens, afterTokens) => {
|
|
326
336
|
emit({
|
|
@@ -913,6 +923,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
913
923
|
// Track consecutive thinking-only responses so we can nudge the model
|
|
914
924
|
// to actually act instead of silently returning an empty answer.
|
|
915
925
|
let emptyVisibleRetries = 0;
|
|
926
|
+
let truncatedBudgetRounds = 0;
|
|
916
927
|
let retryWithoutThinking = false;
|
|
917
928
|
// Robust stream-failure recovery. When a provider stream/complete fails we
|
|
918
929
|
// try working approaches (backoff, compaction, thinking-off, provider
|
|
@@ -1164,6 +1175,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
1164
1175
|
/** Successful file mutation this turn — kills false "error diagnosed but not fixed". */
|
|
1165
1176
|
let sawSuccessfulMutation = false;
|
|
1166
1177
|
let step = -1;
|
|
1178
|
+
let stepMaxTokens = 0;
|
|
1167
1179
|
let nextToolEventId = 0;
|
|
1168
1180
|
const alreadyPrintedIds = new Set();
|
|
1169
1181
|
const promptMutex = {
|
|
@@ -2771,50 +2783,105 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
2771
2783
|
const summarizeForCompaction = async (summaryPrompt, stage) => {
|
|
2772
2784
|
const streamFinalSummary = stage?.phase !== "map";
|
|
2773
2785
|
const compactionId = streamFinalSummary ? activeCompactionId : undefined;
|
|
2774
|
-
const
|
|
2775
|
-
?
|
|
2786
|
+
const maxTokens = stage?.phase === "map"
|
|
2787
|
+
? COMPACTION_MAP_MAX_COMPLETION_TOKENS
|
|
2788
|
+
: COMPACTION_MAX_COMPLETION_TOKENS;
|
|
2789
|
+
const sourceMessages = stage?.sourceMessages;
|
|
2790
|
+
const compactionTools = sourceMessages
|
|
2791
|
+
? selectToolDefs(nativeToolsActive, useCompactSystemPrompt)
|
|
2776
2792
|
: undefined;
|
|
2777
2793
|
const request = {
|
|
2778
2794
|
provider,
|
|
2779
2795
|
model,
|
|
2780
|
-
messages:
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2796
|
+
messages: sourceMessages
|
|
2797
|
+
? [
|
|
2798
|
+
...sourceMessages,
|
|
2799
|
+
{ role: "user", content: summaryPrompt },
|
|
2800
|
+
]
|
|
2801
|
+
: [
|
|
2802
|
+
{ role: "system", content: COMPACTION_SYSTEM_PROMPT },
|
|
2803
|
+
{ role: "user", content: summaryPrompt },
|
|
2804
|
+
],
|
|
2784
2805
|
temperature: 0.1,
|
|
2785
|
-
maxTokens
|
|
2786
|
-
? COMPACTION_MAP_MAX_COMPLETION_TOKENS
|
|
2787
|
-
: COMPACTION_MAX_COMPLETION_TOKENS,
|
|
2806
|
+
maxTokens,
|
|
2788
2807
|
thinking: { enabled: false, effort: "none" },
|
|
2789
2808
|
signal: options.signal,
|
|
2790
2809
|
allowModelFallback: true,
|
|
2810
|
+
...(compactionTools?.length
|
|
2811
|
+
? {
|
|
2812
|
+
tools: compactionTools,
|
|
2813
|
+
toolChoice: "none",
|
|
2814
|
+
}
|
|
2815
|
+
: {}),
|
|
2791
2816
|
};
|
|
2792
|
-
const
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
}
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2817
|
+
const runAttempt = async (attemptRequest, replace = false) => {
|
|
2818
|
+
if (compactionId && replace) {
|
|
2819
|
+
writeCompactionDelta(compactionId, "", true);
|
|
2820
|
+
}
|
|
2821
|
+
const parser = createThinkingStreamParser((text) => {
|
|
2822
|
+
if (compactionId)
|
|
2823
|
+
writeCompactionDelta(compactionId, text);
|
|
2824
|
+
}, undefined, { remember: false });
|
|
2825
|
+
const result = await streamWithProvider(attemptRequest, (token) => parser.push(token), { onStatus: () => undefined, maxRetries: 0 });
|
|
2826
|
+
parser.finish();
|
|
2827
|
+
return result;
|
|
2828
|
+
};
|
|
2829
|
+
const first = await runAttempt(request);
|
|
2830
|
+
let visible = normalizeCompactionSummary(stripThinking(first.text).visible);
|
|
2831
|
+
let retryReason;
|
|
2832
|
+
if (isCompactionCompletionTruncated(first, maxTokens)) {
|
|
2833
|
+
retryReason = "truncated";
|
|
2834
|
+
}
|
|
2835
|
+
else if (!visible) {
|
|
2836
|
+
retryReason = "reasoning-only";
|
|
2837
|
+
}
|
|
2838
|
+
else if (looksLikeTranscriptReplay(visible)) {
|
|
2839
|
+
retryReason = "replayed";
|
|
2840
|
+
}
|
|
2841
|
+
else if (looksLikeIncompleteCompactionSummary(visible)) {
|
|
2842
|
+
retryReason = "incomplete";
|
|
2843
|
+
}
|
|
2844
|
+
if (retryReason) {
|
|
2845
|
+
const retry = await runAttempt({
|
|
2846
|
+
...request,
|
|
2847
|
+
messages: sourceMessages
|
|
2848
|
+
? [
|
|
2849
|
+
...sourceMessages,
|
|
2850
|
+
{
|
|
2851
|
+
role: "user",
|
|
2852
|
+
content: buildCompactionRetryPrompt(summaryPrompt, retryReason),
|
|
2853
|
+
},
|
|
2854
|
+
]
|
|
2855
|
+
: [
|
|
2856
|
+
{
|
|
2857
|
+
role: "system",
|
|
2858
|
+
content: `${COMPACTION_SYSTEM_PROMPT}\nReturn only a complete continuation-memory summary. Do not include analysis, reasoning, or <think> tags.`,
|
|
2859
|
+
},
|
|
2860
|
+
{
|
|
2861
|
+
role: "user",
|
|
2862
|
+
content: buildCompactionRetryPrompt(summaryPrompt, retryReason),
|
|
2863
|
+
},
|
|
2864
|
+
],
|
|
2865
|
+
temperature: 0,
|
|
2866
|
+
maxTokens,
|
|
2867
|
+
thinking: { enabled: false, effort: "none" },
|
|
2868
|
+
allowModelFallback: true,
|
|
2869
|
+
}, true);
|
|
2870
|
+
if (isCompactionCompletionTruncated(retry, maxTokens)) {
|
|
2871
|
+
throw new Error("compaction failed: model hit the summary output limit twice — original context retained");
|
|
2872
|
+
}
|
|
2873
|
+
visible = normalizeCompactionSummary(stripThinking(retry.text).visible);
|
|
2874
|
+
if (!visible) {
|
|
2875
|
+
throw new Error("compaction failed: model returned an empty summary");
|
|
2876
|
+
}
|
|
2877
|
+
if (looksLikeTranscriptReplay(visible)) {
|
|
2878
|
+
throw new Error("compaction failed: model replayed the transcript twice — original context retained");
|
|
2879
|
+
}
|
|
2880
|
+
if (looksLikeIncompleteCompactionSummary(visible)) {
|
|
2881
|
+
throw new Error("compaction failed: model returned an incomplete summary twice — original context retained");
|
|
2882
|
+
}
|
|
2816
2883
|
}
|
|
2817
|
-
return
|
|
2884
|
+
return visible;
|
|
2818
2885
|
};
|
|
2819
2886
|
/**
|
|
2820
2887
|
* Estimate the complete next model request, including attached native-tool
|
|
@@ -2907,9 +2974,12 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
2907
2974
|
activeCompactionId = compactionId;
|
|
2908
2975
|
writeCompactionStarted(compactionId, beforeTokens);
|
|
2909
2976
|
try {
|
|
2977
|
+
const compactionTools = selectToolDefs(nativeToolsActive, useCompactSystemPrompt);
|
|
2978
|
+
const compactionSchemaTokens = buildContextBreakdown([], compactionTools).estimatedTotalTokens;
|
|
2910
2979
|
const result = await compactMessagesWithSummary(messages, summarizeForCompaction, {
|
|
2911
2980
|
budgetTokens: 0,
|
|
2912
2981
|
keepRecent: AUTO_COMPACT_KEEP_RECENT,
|
|
2982
|
+
singlePassInputBudgetTokens: Math.max(0, compactionSinglePassInputBudget(contextLimitTokens ?? modelContextWindow(model, provider)) - compactionSchemaTokens),
|
|
2913
2983
|
...(durableEnvelope ? { durableEnvelope } : {}),
|
|
2914
2984
|
});
|
|
2915
2985
|
const summaryBody = result.messages.find((m) => isCompactionMemoryMessage(m))?.content ??
|
|
@@ -3096,6 +3166,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3096
3166
|
}, 10_000);
|
|
3097
3167
|
heartbeat.unref?.();
|
|
3098
3168
|
const deferredToolCalls = [];
|
|
3169
|
+
const streamedNativeCallNames = new Map();
|
|
3099
3170
|
const deltaParser = writesDirectly
|
|
3100
3171
|
? undefined
|
|
3101
3172
|
: createThinkingStreamParser((text) => emit({ type: "assistant-delta", text }), (text) => {
|
|
@@ -3165,6 +3236,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3165
3236
|
nativeToolsActive,
|
|
3166
3237
|
toolsAttached,
|
|
3167
3238
|
recoveryNudge: retryWithoutThinking,
|
|
3239
|
+
truncationDepth: truncatedBudgetRounds,
|
|
3168
3240
|
}),
|
|
3169
3241
|
});
|
|
3170
3242
|
// Resume / mid-turn abort can leave orphan tool rows or a user
|
|
@@ -3175,10 +3247,11 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3175
3247
|
repairToolProtocol(messages);
|
|
3176
3248
|
assertValidToolProtocol(messages);
|
|
3177
3249
|
// E3: adaptive completion budget (still large enough for writes).
|
|
3178
|
-
|
|
3250
|
+
stepMaxTokens = resolveStepMaxTokens({
|
|
3179
3251
|
nativeToolsActive,
|
|
3180
3252
|
toolsAttached,
|
|
3181
3253
|
recoveryNudge: retryWithoutThinking,
|
|
3254
|
+
truncationDepth: truncatedBudgetRounds,
|
|
3182
3255
|
});
|
|
3183
3256
|
try {
|
|
3184
3257
|
if (responderDelivery &&
|
|
@@ -3204,64 +3277,22 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3204
3277
|
tools: turnTools,
|
|
3205
3278
|
toolChoice: "auto",
|
|
3206
3279
|
parallelToolCalls: true,
|
|
3207
|
-
// P2-3: emit tool cards as soon as the function name arrives.
|
|
3208
3280
|
onToolCallDelta: (delta) => {
|
|
3209
3281
|
if (!delta.name)
|
|
3210
3282
|
return;
|
|
3211
3283
|
const name = fromWireName(delta.name) ?? delta.name;
|
|
3212
|
-
|
|
3213
|
-
if (existing && existing.call.name !== "…") {
|
|
3214
|
-
if (delta.argumentsBytes &&
|
|
3215
|
-
delta.argumentsBytes >= 4096 &&
|
|
3216
|
-
!writesDirectly) {
|
|
3217
|
-
emit({
|
|
3218
|
-
type: "status",
|
|
3219
|
-
text: `${name} (${Math.round(delta.argumentsBytes / 1024)}KB args)`,
|
|
3220
|
-
});
|
|
3221
|
-
}
|
|
3222
|
-
return;
|
|
3223
|
-
}
|
|
3224
|
-
while (deferredToolCalls.length < delta.index) {
|
|
3225
|
-
const slot = deferredToolCalls.length;
|
|
3226
|
-
const placeholderId = `tool-${++nextToolEventId}`;
|
|
3227
|
-
callIds[slot] = placeholderId;
|
|
3228
|
-
deferredToolCalls.push({
|
|
3229
|
-
eventId: placeholderId,
|
|
3230
|
-
call: { name: "…", args: {} },
|
|
3231
|
-
rendered: "",
|
|
3232
|
-
shown: false,
|
|
3233
|
-
});
|
|
3234
|
-
}
|
|
3235
|
-
const call = normalizeToolCall({
|
|
3236
|
-
name,
|
|
3237
|
-
args: {},
|
|
3238
|
-
});
|
|
3239
|
-
const eventId = existing?.eventId ?? `tool-${++nextToolEventId}`;
|
|
3240
|
-
callIds[delta.index] = eventId;
|
|
3241
|
-
alreadyPrintedIds.add(eventId);
|
|
3242
|
-
const toolCallLine = chalk.cyan(` ▶ ${call.name}`) +
|
|
3243
|
-
chalk.gray(` ${formatToolArgs(call)}`);
|
|
3244
|
-
const entry = {
|
|
3245
|
-
eventId,
|
|
3246
|
-
call,
|
|
3247
|
-
rendered: styleToolChatter(call, toolCallLine) + "\n",
|
|
3248
|
-
shown: false,
|
|
3249
|
-
};
|
|
3250
|
-
if (deferredToolCalls.length === delta.index) {
|
|
3251
|
-
deferredToolCalls.push(entry);
|
|
3252
|
-
}
|
|
3253
|
-
else {
|
|
3254
|
-
deferredToolCalls[delta.index] = entry;
|
|
3255
|
-
}
|
|
3256
|
-
streamedCallsCount = Math.max(streamedCallsCount, deferredToolCalls.length);
|
|
3284
|
+
streamedNativeCallNames.set(delta.index, name);
|
|
3257
3285
|
if (!writesDirectly) {
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3286
|
+
emit({
|
|
3287
|
+
type: "status",
|
|
3288
|
+
text: delta.argumentsBytes && delta.argumentsBytes >= 4096
|
|
3289
|
+
? `${name} (${Math.round(delta.argumentsBytes / 1024)}KB args)`
|
|
3290
|
+
: name,
|
|
3291
|
+
});
|
|
3261
3292
|
}
|
|
3262
3293
|
else {
|
|
3263
3294
|
spinner.stop();
|
|
3264
|
-
spinner = startThinkingSpinner(`tool ${
|
|
3295
|
+
spinner = startThinkingSpinner(`tool ${name}…`, options.signal);
|
|
3265
3296
|
}
|
|
3266
3297
|
},
|
|
3267
3298
|
}
|
|
@@ -3279,7 +3310,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3279
3310
|
spinner.stop();
|
|
3280
3311
|
}
|
|
3281
3312
|
while (streamedCallsCount < parsedCalls.length) {
|
|
3282
|
-
const call = parsedCalls[streamedCallsCount];
|
|
3313
|
+
const call = normalizeToolCall(parsedCalls[streamedCallsCount]);
|
|
3283
3314
|
const eventId = `tool-${++nextToolEventId}`;
|
|
3284
3315
|
callIds[streamedCallsCount] = eventId;
|
|
3285
3316
|
alreadyPrintedIds.add(eventId);
|
|
@@ -3767,8 +3798,24 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3767
3798
|
}
|
|
3768
3799
|
}
|
|
3769
3800
|
if (!canonicalAssistantVisible.trim() && !call) {
|
|
3801
|
+
const completionTokens = completion.usage?.completionTokens ?? 0;
|
|
3802
|
+
const hitOutputLimit = completion.finishReason === "length" ||
|
|
3803
|
+
(completionTokens > 0 && stepMaxTokens > 0 && completionTokens >= stepMaxTokens - 64);
|
|
3804
|
+
const truncatedRoundText = collapseRepeatedText(completion.text ?? "");
|
|
3805
|
+
if (hitOutputLimit && truncatedRoundText.trim() && truncatedBudgetRounds < 2) {
|
|
3806
|
+
truncatedBudgetRounds += 1;
|
|
3807
|
+
writeNotice("warn", "response hit the output token limit — continuing from where it stopped", chalk.yellow(" ⚠ response hit the output token limit — continuing from where it stopped\n"));
|
|
3808
|
+
messages.push({
|
|
3809
|
+
role: "assistant",
|
|
3810
|
+
content: sanitizeAssistantText(truncatedRoundText),
|
|
3811
|
+
});
|
|
3812
|
+
messages.push(recoveryUserMessage("Your previous response was cut off by the output token limit before it completed. " +
|
|
3813
|
+
"Continue directly from where it stopped — do not restart the analysis or repeat prior text. " +
|
|
3814
|
+
"Finish briefly: emit the next tool call, or the final answer if the task is complete."));
|
|
3815
|
+
continue;
|
|
3816
|
+
}
|
|
3770
3817
|
const incompleteNativeStream = nativeToolCalls.length === 0 &&
|
|
3771
|
-
|
|
3818
|
+
streamedNativeCallNames.size > 0;
|
|
3772
3819
|
if (incompleteNativeStream) {
|
|
3773
3820
|
const reason = "The provider began this native tool call but never completed it. Nothing ran; reissue a complete call.";
|
|
3774
3821
|
for (const deferred of deferredToolCalls) {
|
|
@@ -3811,6 +3858,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3811
3858
|
else {
|
|
3812
3859
|
// Reset the counter on any successful visible output or recovered call.
|
|
3813
3860
|
emptyVisibleRetries = 0;
|
|
3861
|
+
truncatedBudgetRounds = 0;
|
|
3814
3862
|
retryWithoutThinking = false;
|
|
3815
3863
|
}
|
|
3816
3864
|
let bareArgsOnly = false;
|
|
@@ -4180,13 +4228,14 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
4180
4228
|
let parsed = parseAllToolCalls(assistantText.visible || assistantText.thinkContent);
|
|
4181
4229
|
if (parsed.length === 0 && call)
|
|
4182
4230
|
parsed = [call];
|
|
4183
|
-
bound = parsed.map((
|
|
4231
|
+
bound = parsed.map((rawCall, index) => {
|
|
4232
|
+
const call = normalizeToolCall(rawCall);
|
|
4184
4233
|
const id = syntheticToolCallId(index);
|
|
4185
4234
|
return {
|
|
4186
4235
|
index,
|
|
4187
4236
|
id,
|
|
4188
|
-
call
|
|
4189
|
-
native: { id, name:
|
|
4237
|
+
call,
|
|
4238
|
+
native: { id, name: call.name, args: call.args },
|
|
4190
4239
|
};
|
|
4191
4240
|
});
|
|
4192
4241
|
}
|
|
@@ -4356,7 +4405,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
4356
4405
|
for (const deferred of activeDeferredToolCalls.slice(0, allCalls.length)) {
|
|
4357
4406
|
if (!deferred.call.name || deferred.call.name === "…")
|
|
4358
4407
|
continue;
|
|
4359
|
-
if (!deferred.shown
|
|
4408
|
+
if (!deferred.shown) {
|
|
4360
4409
|
writeToolCall(deferred.eventId, deferred.call, deferred.rendered);
|
|
4361
4410
|
deferred.shown = true;
|
|
4362
4411
|
}
|