@bike4mind/cli 0.2.49-feat-cli-multiline-input.21032 → 0.2.49-fix-cli-stream-resilience.21034
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/{chunk-U3MM4PII.js → chunk-OPFQTJGV.js} +6 -6
- package/dist/{chunk-623C44JW.js → chunk-QJ47T42W.js} +57 -4
- package/dist/commands/doctorCommand.js +1 -1
- package/dist/commands/headlessCommand.js +1 -1
- package/dist/commands/updateCommand.js +1 -1
- package/dist/index.js +10 -7
- package/package.json +6 -6
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@bike4mind/cli",
|
|
6
|
-
version: "0.2.49-
|
|
6
|
+
version: "0.2.49-fix-cli-stream-resilience.21034+388f30f58",
|
|
7
7
|
type: "module",
|
|
8
8
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
9
9
|
license: "UNLICENSED",
|
|
@@ -118,10 +118,10 @@ var package_default = {
|
|
|
118
118
|
},
|
|
119
119
|
devDependencies: {
|
|
120
120
|
"@bike4mind/agents": "0.1.0",
|
|
121
|
-
"@bike4mind/common": "2.67.1-
|
|
122
|
-
"@bike4mind/mcp": "1.33.11-
|
|
123
|
-
"@bike4mind/services": "2.63.1-
|
|
124
|
-
"@bike4mind/utils": "2.15.4-
|
|
121
|
+
"@bike4mind/common": "2.67.1-fix-cli-stream-resilience.21034+388f30f58",
|
|
122
|
+
"@bike4mind/mcp": "1.33.11-fix-cli-stream-resilience.21034+388f30f58",
|
|
123
|
+
"@bike4mind/services": "2.63.1-fix-cli-stream-resilience.21034+388f30f58",
|
|
124
|
+
"@bike4mind/utils": "2.15.4-fix-cli-stream-resilience.21034+388f30f58",
|
|
125
125
|
"@types/better-sqlite3": "^7.6.13",
|
|
126
126
|
"@types/diff": "^5.0.9",
|
|
127
127
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -140,7 +140,7 @@ var package_default = {
|
|
|
140
140
|
optionalDependencies: {
|
|
141
141
|
"@vscode/ripgrep": "^1.17.0"
|
|
142
142
|
},
|
|
143
|
-
gitHead: "
|
|
143
|
+
gitHead: "388f30f585b055f7cb133fd507e90c8138fed006"
|
|
144
144
|
};
|
|
145
145
|
|
|
146
146
|
// src/utils/updateChecker.ts
|
|
@@ -16146,17 +16146,48 @@ function extractUsageInfo(parsed) {
|
|
|
16146
16146
|
usdCost: parsed.credits?.usdCost
|
|
16147
16147
|
};
|
|
16148
16148
|
}
|
|
16149
|
-
var ServerLlmBackend = class {
|
|
16149
|
+
var ServerLlmBackend = class _ServerLlmBackend {
|
|
16150
16150
|
constructor(options) {
|
|
16151
16151
|
this.completionsEndpoint = "/api/ai/v1/completions";
|
|
16152
16152
|
this.apiClient = options.apiClient;
|
|
16153
16153
|
this.currentModel = options.model;
|
|
16154
16154
|
}
|
|
16155
|
+
static {
|
|
16156
|
+
/** Max retries for transient stream failures (e.g. missing [DONE]) */
|
|
16157
|
+
this.MAX_STREAM_RETRIES = 2;
|
|
16158
|
+
}
|
|
16155
16159
|
/**
|
|
16156
16160
|
* Make authenticated LLM completion request via server
|
|
16157
|
-
* Parses SSE stream and invokes callback for each event
|
|
16161
|
+
* Parses SSE stream and invokes callback for each event.
|
|
16162
|
+
* Automatically retries on transient stream failures (e.g. stream ending prematurely).
|
|
16158
16163
|
*/
|
|
16159
16164
|
async complete(model, messages, options, callback) {
|
|
16165
|
+
let lastError;
|
|
16166
|
+
for (let attempt = 0; attempt <= _ServerLlmBackend.MAX_STREAM_RETRIES; attempt++) {
|
|
16167
|
+
if (attempt > 0) {
|
|
16168
|
+
logger.warn(
|
|
16169
|
+
`[ServerLlmBackend] Retrying stream (attempt ${attempt + 1}/${_ServerLlmBackend.MAX_STREAM_RETRIES + 1})...`
|
|
16170
|
+
);
|
|
16171
|
+
}
|
|
16172
|
+
try {
|
|
16173
|
+
await this.completeOnce(model, messages, options, callback);
|
|
16174
|
+
return;
|
|
16175
|
+
} catch (error) {
|
|
16176
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
16177
|
+
const isTransientStreamError = lastError.message.includes("Stream ended prematurely");
|
|
16178
|
+
const isAborted = options.abortSignal?.aborted;
|
|
16179
|
+
if (!isTransientStreamError || isAborted) {
|
|
16180
|
+
throw lastError;
|
|
16181
|
+
}
|
|
16182
|
+
logger.warn(`[ServerLlmBackend] Transient stream failure: ${lastError.message}`);
|
|
16183
|
+
}
|
|
16184
|
+
}
|
|
16185
|
+
throw lastError ?? new Error("Stream failed after all retry attempts");
|
|
16186
|
+
}
|
|
16187
|
+
/**
|
|
16188
|
+
* Single attempt at completing a streaming request.
|
|
16189
|
+
*/
|
|
16190
|
+
async completeOnce(model, messages, options, callback) {
|
|
16160
16191
|
logger.debug(`[ServerLlmBackend] Starting complete() with model: ${model}`);
|
|
16161
16192
|
if (options.abortSignal?.aborted) {
|
|
16162
16193
|
logger.debug("[ServerLlmBackend] Request aborted before start");
|
|
@@ -16357,8 +16388,30 @@ var ServerLlmBackend = class {
|
|
|
16357
16388
|
});
|
|
16358
16389
|
response.data.on("end", () => {
|
|
16359
16390
|
if (!receivedDone) {
|
|
16360
|
-
|
|
16361
|
-
|
|
16391
|
+
const hasAccumulatedData = accumulatedText.trim().length > 0 || toolsUsed.length > 0;
|
|
16392
|
+
logger.warn(
|
|
16393
|
+
`[ServerLlmBackend] Stream ended without [DONE] signal. Accumulated text: ${accumulatedText.length} chars, tools: ${toolsUsed.length}`
|
|
16394
|
+
);
|
|
16395
|
+
if (hasAccumulatedData) {
|
|
16396
|
+
const cleanedText = stripThinkingBlocks(accumulatedText);
|
|
16397
|
+
streamLogger.streamComplete(accumulatedText);
|
|
16398
|
+
if (toolsUsed.length > 0) {
|
|
16399
|
+
const info = {
|
|
16400
|
+
toolsUsed,
|
|
16401
|
+
thinking: thinkingBlocks.length > 0 ? thinkingBlocks : void 0,
|
|
16402
|
+
...lastUsageInfo
|
|
16403
|
+
};
|
|
16404
|
+
callback([cleanedText], info).catch((err) => reject(err)).then(() => resolve3());
|
|
16405
|
+
} else if (cleanedText) {
|
|
16406
|
+
callback([cleanedText], lastUsageInfo).catch((err) => reject(err)).then(() => resolve3());
|
|
16407
|
+
} else {
|
|
16408
|
+
resolve3();
|
|
16409
|
+
}
|
|
16410
|
+
} else {
|
|
16411
|
+
reject(
|
|
16412
|
+
new Error("Stream ended prematurely without receiving any data. The server may be experiencing issues.")
|
|
16413
|
+
);
|
|
16414
|
+
}
|
|
16362
16415
|
} else {
|
|
16363
16416
|
logger.debug("[ServerLlmBackend] Stream ended, [DONE] handler will resolve");
|
|
16364
16417
|
}
|
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
setWebSocketToolExecutor,
|
|
47
47
|
substituteArguments,
|
|
48
48
|
warmFileCache
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-QJ47T42W.js";
|
|
50
50
|
import "./chunk-BDQBOLYG.js";
|
|
51
51
|
import "./chunk-F6IY547T.js";
|
|
52
52
|
import "./chunk-GQGOWACU.js";
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
import {
|
|
65
65
|
checkForUpdate,
|
|
66
66
|
package_default
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-OPFQTJGV.js";
|
|
68
68
|
import {
|
|
69
69
|
selectActiveBackgroundAgents,
|
|
70
70
|
useCliStore
|
|
@@ -2955,11 +2955,10 @@ function CliApp() {
|
|
|
2955
2955
|
throw new Error("No websocketUrl or wsCompletionUrl in server config");
|
|
2956
2956
|
}
|
|
2957
2957
|
} catch (wsError) {
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
);
|
|
2958
|
+
logger.info("\u26A0\uFE0F WebSocket unavailable, using SSE fallback");
|
|
2959
|
+
logger.debug(`[WebSocket] Fallback reason: ${wsError instanceof Error ? wsError.message : String(wsError)}`);
|
|
2961
2960
|
if (wsError instanceof Error && wsError.stack) {
|
|
2962
|
-
|
|
2961
|
+
logger.debug(`[WebSocket] Stack: ${wsError.stack}`);
|
|
2963
2962
|
}
|
|
2964
2963
|
wsManager = null;
|
|
2965
2964
|
setWebSocketToolExecutor(null);
|
|
@@ -3743,7 +3742,11 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3743
3742
|
return;
|
|
3744
3743
|
}
|
|
3745
3744
|
}
|
|
3746
|
-
|
|
3745
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3746
|
+
console.error(`
|
|
3747
|
+
\u274C ${errorMessage}
|
|
3748
|
+
`);
|
|
3749
|
+
logger.debug(`Full error details: ${error instanceof Error ? error.stack || error.message : String(error)}`);
|
|
3747
3750
|
} finally {
|
|
3748
3751
|
setState((prev) => ({ ...prev, abortController: null }));
|
|
3749
3752
|
useCliStore.getState().setIsThinking(false);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.2.49-
|
|
3
|
+
"version": "0.2.49-fix-cli-stream-resilience.21034+388f30f58",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -115,10 +115,10 @@
|
|
|
115
115
|
},
|
|
116
116
|
"devDependencies": {
|
|
117
117
|
"@bike4mind/agents": "0.1.0",
|
|
118
|
-
"@bike4mind/common": "2.67.1-
|
|
119
|
-
"@bike4mind/mcp": "1.33.11-
|
|
120
|
-
"@bike4mind/services": "2.63.1-
|
|
121
|
-
"@bike4mind/utils": "2.15.4-
|
|
118
|
+
"@bike4mind/common": "2.67.1-fix-cli-stream-resilience.21034+388f30f58",
|
|
119
|
+
"@bike4mind/mcp": "1.33.11-fix-cli-stream-resilience.21034+388f30f58",
|
|
120
|
+
"@bike4mind/services": "2.63.1-fix-cli-stream-resilience.21034+388f30f58",
|
|
121
|
+
"@bike4mind/utils": "2.15.4-fix-cli-stream-resilience.21034+388f30f58",
|
|
122
122
|
"@types/better-sqlite3": "^7.6.13",
|
|
123
123
|
"@types/diff": "^5.0.9",
|
|
124
124
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -137,5 +137,5 @@
|
|
|
137
137
|
"optionalDependencies": {
|
|
138
138
|
"@vscode/ripgrep": "^1.17.0"
|
|
139
139
|
},
|
|
140
|
-
"gitHead": "
|
|
140
|
+
"gitHead": "388f30f585b055f7cb133fd507e90c8138fed006"
|
|
141
141
|
}
|