Skip to content

Commit ea10b80

Browse files
author
Brendan Gray
committed
v1.7.9: Fix-A bubble survives seamless continuation; Fix-B trim continuation prompt
1 parent 27615fd commit ea10b80

2 files changed

Lines changed: 40 additions & 19 deletions

File tree

main/agenticChat.js

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,6 +1263,18 @@ function register(ctx) {
12631263
lastEvaluation: llmEngine.lastEvaluation,
12641264
};
12651265

1266+
// Text-mode tool-bubble state — declared at iteration scope so the conditional
1267+
// done:true send after the _wasTruncated check can access them, and so continuations
1268+
// re-attach the bubble by seeding from _pendingPartialBlock.
1269+
let _tb = _pendingPartialBlock || '';
1270+
let _tIdx = 9000;
1271+
let _tStart = -1;
1272+
let _tName = null;
1273+
if (_pendingPartialBlock) {
1274+
const _seedM = _pendingPartialBlock.match(/\{\s*"tool"\s*:\s*"([^"]+)"/);
1275+
if (_seedM) { _tStart = _seedM.index; _tName = _seedM[1]; }
1276+
}
1277+
12661278
try {
12671279
// Signal UI to record current stream buffer length as iteration start offset.
12681280
// This allows llm-replace-last to preserve prior iterations' text when cleaning fences.
@@ -1315,10 +1327,9 @@ function register(ctx) {
13151327
// IPC event that grammar mode fires so the live streaming bubble appears.
13161328
// Grammar mode fires this from the toolChunk callback (4th arg of generateWithFunctions).
13171329
// Text mode has no equivalent callback, so we detect the JSON inline here.
1318-
let _tb = ''; // raw token accumulator (text path only)
1319-
let _tIdx = 9000; // callIndex sentinel — grammar mode uses 0-based ints
1320-
let _tStart = -1; // offset of opening '{' of current tool call in _tb
1321-
let _tName = null; // tool name once the key has streamed through
1330+
// NOTE: _tb, _tIdx, _tStart, _tName are declared at iteration scope above the try block.
1331+
// They are seeded from _pendingPartialBlock for continuations, and the done:true send
1332+
// is deferred until after the _wasTruncated check so continuations keep the bubble alive.
13221333

13231334
result = await llmEngine.generateStream(currentPrompt, {
13241335
...(context?.params || {}),
@@ -1355,18 +1366,8 @@ function register(ctx) {
13551366
localThinkingBatcher.push(thinkToken);
13561367
});
13571368

1358-
// Mark any in-flight text-mode generating bubble as done.
1359-
// In the happy path the tool-executing IPC event clears generatingToolCalls
1360-
// automatically; this done:true handles edge cases where the model wrote a
1361-
// tool call but execution was skipped or cancelled.
1362-
if (_tStart !== -1 && _tName && mainWindow && !mainWindow.isDestroyed()) {
1363-
mainWindow.webContents.send('llm-tool-generating', {
1364-
callIndex: _tIdx,
1365-
functionName: _tName,
1366-
paramsText: '',
1367-
done: true,
1368-
});
1369-
}
1369+
// done:true for the text-mode bubble is sent AFTER the _wasTruncated check below,
1370+
// so that seamless continuations can keep the bubble alive across passes.
13701371
}
13711372
} finally {
13721373
localTokenBatcher.dispose();
@@ -1715,9 +1716,17 @@ function register(ctx) {
17151716
if (_hasUnclosedToolFence) {
17161717
// EOS fired mid-JSON: tell the model exactly where the output was cut.
17171718
// It must output ONLY the remainder to complete the tool call — no restart.
1719+
// FIX-B: Use only a short tail (~200 chars) of the partial fence content in the prompt
1720+
// instead of the full accumulated content. The full block is preserved in _pendingPartialBlock
1721+
// for MCP reconstruction — the model only needs the tail to know where to continue from.
1722+
// This prevents the prompt from growing by thousands of tokens across continuations,
1723+
// keeping each pass's generation budget large enough to make real progress.
17181724
const _partialFenceContent = _stitchedForMcp.slice(_fenceIdx);
1719-
_pendingPartialBlock = _partialFenceContent; // save so next iter MCP can reconstruct
1720-
_continuationUserMsg = `[You were generating a tool call and the context window was exhausted mid-JSON. The partial output is shown below — output ONLY the remainder of the JSON continuing from exactly where it ends, then close the object and the code fence. Do NOT restart the tool call from the beginning. Do NOT add any preamble or explanation. Continue from:\n\n${_partialFenceContent}]`;
1725+
_pendingPartialBlock = _partialFenceContent; // save full block so MCP can reconstruct
1726+
const _tail = _partialFenceContent.length > 200
1727+
? '\u2026' + _partialFenceContent.slice(-200)
1728+
: _partialFenceContent;
1729+
_continuationUserMsg = `[Continue the tool call JSON from exactly where it was cut. Output ONLY the JSON continuation — the remainder of the current value, any remaining keys, closing brace, and code fence. Do NOT restart the tool call. Do NOT add preamble. Continue from:\n${_tail}]`;
17211730
} else {
17221731
// maxTokens hit mid-text — original behaviour
17231732
_continuationUserMsg = '[Continue your response exactly where you left off. If you were listing steps or planning, STOP — do not add more steps. Call the first tool now to begin execution. If you were in the middle of a tool call, call that tool now to complete the task — do not output tool content as raw text. Output only the continuation — no preamble, no summary, no repeated content.]';
@@ -1730,6 +1739,18 @@ function register(ctx) {
17301739
}
17311740
// Natural stop or max continuations reached — reset counter for next response
17321741
if (!_wasTruncated) continuationCount = 0;
1742+
// FIX-A: Send done:true for the text-mode generating bubble ONLY when NOT continuing.
1743+
// When continuing (above), the bubble must stay alive so the user sees the ongoing stream.
1744+
// In the happy path, onToolExecuting on the renderer already clears the bubble;
1745+
// this handles edge cases where the tool call was written but execution was skipped.
1746+
if (_tStart !== -1 && _tName && !nativeFunctionCalls.length && mainWindow && !mainWindow.isDestroyed()) {
1747+
mainWindow.webContents.send('llm-tool-generating', {
1748+
callIndex: _tIdx,
1749+
functionName: _tName,
1750+
paramsText: '',
1751+
done: true,
1752+
});
1753+
}
17331754

17341755
// Check stale after generation — user may have sent a new message during inference
17351756
if (isStale()) {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "guide-ide",
3-
"version": "1.7.8",
3+
"version": "1.7.9",
44
"description": "guIDE - AI-Powered Offline IDE with local LLM, RAG, MCP tools, browser automation, and integrated terminal",
55
"author": {
66
"name": "Brendan Gray",

0 commit comments

Comments
 (0)