@pentoshi/clai 3.11.1 → 3.11.3
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/runner.js +71 -20
- package/dist/agent/runner.js.map +1 -1
- package/dist/tui-v2/components/transcript/thinking-block.js +6 -7
- package/dist/tui-v2/components/transcript/thinking-block.js.map +1 -1
- package/dist/tui-v2/state/transcript-reducer.js +7 -12
- 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
|
@@ -168,6 +168,37 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
168
168
|
// the normal tool path already surfaced, which would render it twice. Reset
|
|
169
169
|
// at the top of every loop iteration.
|
|
170
170
|
let visibleCommitted = false;
|
|
171
|
+
let interruptedVisible = "";
|
|
172
|
+
const trimExactContinuationOverlap = (previous, current, minLength = 32) => {
|
|
173
|
+
if (previous.length > 0 && current.startsWith(previous)) {
|
|
174
|
+
return current.slice(previous.length);
|
|
175
|
+
}
|
|
176
|
+
const maxLength = Math.min(previous.length, current.length);
|
|
177
|
+
if (maxLength < minLength)
|
|
178
|
+
return current;
|
|
179
|
+
const pattern = current.slice(0, maxLength);
|
|
180
|
+
const fallback = new Uint32Array(maxLength);
|
|
181
|
+
for (let index = 1, matched = 0; index < maxLength; index += 1) {
|
|
182
|
+
while (matched > 0 && pattern[index] !== pattern[matched]) {
|
|
183
|
+
matched = fallback[matched - 1];
|
|
184
|
+
}
|
|
185
|
+
if (pattern[index] === pattern[matched])
|
|
186
|
+
matched += 1;
|
|
187
|
+
fallback[index] = matched;
|
|
188
|
+
}
|
|
189
|
+
let matched = 0;
|
|
190
|
+
for (let index = previous.length - maxLength; index < previous.length; index += 1) {
|
|
191
|
+
while (matched > 0 && previous[index] !== pattern[matched]) {
|
|
192
|
+
matched = fallback[matched - 1];
|
|
193
|
+
}
|
|
194
|
+
if (previous[index] === pattern[matched])
|
|
195
|
+
matched += 1;
|
|
196
|
+
if (matched === maxLength && index < previous.length - 1) {
|
|
197
|
+
matched = fallback[matched - 1];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return matched >= minLength ? current.slice(matched) : current;
|
|
201
|
+
};
|
|
171
202
|
const noopSpinner = {
|
|
172
203
|
setLabel: () => { },
|
|
173
204
|
bumpReasoning: () => { },
|
|
@@ -331,7 +362,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
331
362
|
jobManager.releaseResponderNotificationClaim(notificationId);
|
|
332
363
|
}
|
|
333
364
|
};
|
|
334
|
-
const finishTurn = (answer, steps, status = "succeeded", remainingCriteria = [], reason) => {
|
|
365
|
+
const finishTurn = (answer, steps, status = "succeeded", remainingCriteria = [], reason, displayAnswer) => {
|
|
335
366
|
releaseUnreadResponderClaims();
|
|
336
367
|
const outcome = createTurnOutcome(normalizeTurnOutcomeInput({
|
|
337
368
|
status,
|
|
@@ -340,13 +371,22 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
340
371
|
remainingCriteria,
|
|
341
372
|
reason,
|
|
342
373
|
}));
|
|
343
|
-
const
|
|
374
|
+
const renderOptions = {
|
|
344
375
|
diagnostics: !suppressOutcomeDiagnostics,
|
|
345
|
-
}
|
|
346
|
-
|
|
376
|
+
};
|
|
377
|
+
const rendered = renderTurnOutcome(outcome, renderOptions);
|
|
378
|
+
const displayRendered = displayAnswer === undefined
|
|
379
|
+
? rendered
|
|
380
|
+
: renderTurnOutcome({ ...outcome, answer: displayAnswer }, renderOptions);
|
|
381
|
+
if (displayRendered.trim()) {
|
|
382
|
+
writeAssistantMessage(displayRendered);
|
|
383
|
+
}
|
|
384
|
+
else if (!writesDirectly) {
|
|
385
|
+
emit({ type: "assistant-message", text: "" });
|
|
386
|
+
}
|
|
347
387
|
if (options.onMessages) {
|
|
348
388
|
try {
|
|
349
|
-
options.onMessages(buildTurnHistory(liveMessages,
|
|
389
|
+
options.onMessages(buildTurnHistory(liveMessages, displayRendered));
|
|
350
390
|
}
|
|
351
391
|
catch {
|
|
352
392
|
// Persisting history must never break the turn.
|
|
@@ -3006,6 +3046,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3006
3046
|
options.signal?.throwIfAborted();
|
|
3007
3047
|
let call;
|
|
3008
3048
|
let assistantText;
|
|
3049
|
+
let canonicalAssistantVisible = "";
|
|
3009
3050
|
let recoveredFromBareJson = false;
|
|
3010
3051
|
if (pendingCalls.length > 0) {
|
|
3011
3052
|
call = pendingCalls.shift();
|
|
@@ -3311,15 +3352,16 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3311
3352
|
deltaParser?.finish();
|
|
3312
3353
|
const partial = rememberThinkingFromText(accumulatedText);
|
|
3313
3354
|
const hasShownToolCall = deferredToolCalls.some((entry) => entry.shown);
|
|
3314
|
-
const
|
|
3355
|
+
const rawPartialVisible = textBeforeToolCall(stripThinking(collapseRepeatedText(accumulatedText)).visible);
|
|
3356
|
+
const normalizedPartialVisible = trimExactContinuationOverlap(interruptedVisible, rawPartialVisible);
|
|
3357
|
+
const partialVisible = normalizedPartialVisible.trim();
|
|
3315
3358
|
if (partialVisible) {
|
|
3316
|
-
|
|
3317
|
-
writeAssistantMessage(partialVisible);
|
|
3318
|
-
}
|
|
3359
|
+
writeAssistantMessage(partialVisible);
|
|
3319
3360
|
pushAssistantHistory(partialVisible);
|
|
3361
|
+
interruptedVisible += normalizedPartialVisible;
|
|
3320
3362
|
}
|
|
3321
|
-
else if (!writesDirectly
|
|
3322
|
-
emit({ type: "assistant-message", text:
|
|
3363
|
+
else if (!writesDirectly) {
|
|
3364
|
+
emit({ type: "assistant-message", text: "" });
|
|
3323
3365
|
}
|
|
3324
3366
|
if (partial.hasThinking && !hasShownToolCall) {
|
|
3325
3367
|
writeThinkingBlock(partial.thinkContent);
|
|
@@ -3412,11 +3454,16 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3412
3454
|
const usedNativeProtocol = Boolean(completion.toolCalls?.length) ||
|
|
3413
3455
|
(toolsAttached && !isTextOnlyModel(provider, model));
|
|
3414
3456
|
const assistantTextResult = rememberThinkingFromText(completion.text);
|
|
3415
|
-
|
|
3457
|
+
const continuedVisible = trimExactContinuationOverlap(interruptedVisible, assistantTextResult.visible);
|
|
3458
|
+
canonicalAssistantVisible = interruptedVisible + continuedVisible;
|
|
3459
|
+
assistantText = {
|
|
3460
|
+
...assistantTextResult,
|
|
3461
|
+
visible: continuedVisible,
|
|
3462
|
+
};
|
|
3416
3463
|
const commitAssistantRetry = (historyText) => {
|
|
3417
3464
|
const hasShownToolCall = deferredToolCalls.some((entry) => entry.shown);
|
|
3418
3465
|
if (!hasShownToolCall) {
|
|
3419
|
-
const displayText = textBeforeToolCall(
|
|
3466
|
+
const displayText = textBeforeToolCall(collapseRepeatedText(assistantText.visible)).trim();
|
|
3420
3467
|
if (displayText) {
|
|
3421
3468
|
writeAssistantMessage(displayText);
|
|
3422
3469
|
}
|
|
@@ -3431,6 +3478,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3431
3478
|
}
|
|
3432
3479
|
}
|
|
3433
3480
|
pushAssistantHistory(historyText);
|
|
3481
|
+
interruptedVisible = "";
|
|
3434
3482
|
};
|
|
3435
3483
|
// Only emit a thinking-block event when the classic renderer is
|
|
3436
3484
|
// active (writesDirectly / no deltaParser). In TUI v2 the
|
|
@@ -3600,7 +3648,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3600
3648
|
}
|
|
3601
3649
|
}
|
|
3602
3650
|
}
|
|
3603
|
-
if (!
|
|
3651
|
+
if (!canonicalAssistantVisible.trim() && !call) {
|
|
3604
3652
|
emptyVisibleRetries += 1;
|
|
3605
3653
|
if (emptyVisibleRetries <= 3) {
|
|
3606
3654
|
if (assistantText.hasThinking) {
|
|
@@ -3611,7 +3659,7 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3611
3659
|
}
|
|
3612
3660
|
if (assistantText.hasThinking)
|
|
3613
3661
|
retryWithoutThinking = true;
|
|
3614
|
-
commitAssistantRetry(
|
|
3662
|
+
commitAssistantRetry(assistantText.visible);
|
|
3615
3663
|
// Keep nudges SHORT — cheap models lose the key instruction in long text.
|
|
3616
3664
|
const buildNudge = freshWebSearchRequired && !sawFreshWebSearch
|
|
3617
3665
|
? toolsAttached
|
|
@@ -3817,7 +3865,8 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
3817
3865
|
}
|
|
3818
3866
|
// Exhausted retries — fall through to the normal path.
|
|
3819
3867
|
}
|
|
3820
|
-
const
|
|
3868
|
+
const displayCleaned = collapseRepeatedText(stripSentinelTokens(assistantText.visible));
|
|
3869
|
+
const cleaned = collapseRepeatedText(stripSentinelTokens(canonicalAssistantVisible));
|
|
3821
3870
|
const narratedAction = looksLikeActionNarration(cleaned);
|
|
3822
3871
|
const narratedWebAction = looksLikeWebActionNarration(cleaned);
|
|
3823
3872
|
const reconciledPlanAtCompletion = await reconcileOpenTaskBeforeFinalizing();
|
|
@@ -4089,13 +4138,12 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
4089
4138
|
outcomeStatus,
|
|
4090
4139
|
remainingCriteria,
|
|
4091
4140
|
});
|
|
4092
|
-
writeAssistantMessage(cleaned);
|
|
4093
4141
|
lastAnswer = cleaned;
|
|
4094
4142
|
return finishTurn(lastAnswer, step + 1, outcomeStatus, remainingCriteria, outcomeStatus === "failed"
|
|
4095
4143
|
? "One or more required plan tasks failed."
|
|
4096
4144
|
: outcomeStatus === "partial"
|
|
4097
4145
|
? "Required outcome criteria remain unsupported by current evidence."
|
|
4098
|
-
: undefined);
|
|
4146
|
+
: undefined, displayCleaned);
|
|
4099
4147
|
}
|
|
4100
4148
|
// A valid primary tool call exists for this fresh model turn. Show any
|
|
4101
4149
|
// prose / thinking that preceded it, record the assistant message ONCE.
|
|
@@ -4104,10 +4152,13 @@ export async function runAgentTurn(prompt, options = {}) {
|
|
|
4104
4152
|
: nativeToolCalls.length
|
|
4105
4153
|
? assistantText.visible.trim()
|
|
4106
4154
|
: textBeforeToolCall(assistantText.visible);
|
|
4107
|
-
if (beforeTool
|
|
4108
|
-
!deferredToolCalls.some((entry) => entry.shown)) {
|
|
4155
|
+
if (beforeTool) {
|
|
4109
4156
|
writeAssistantMessage(beforeTool);
|
|
4110
4157
|
}
|
|
4158
|
+
else if (deltaParser) {
|
|
4159
|
+
emit({ type: "assistant-message", text: "" });
|
|
4160
|
+
}
|
|
4161
|
+
interruptedVisible = "";
|
|
4111
4162
|
let bound = [];
|
|
4112
4163
|
if (nativeToolCalls.length) {
|
|
4113
4164
|
bound = nativeToolCalls.map((tc, index) => {
|