@bike4mind/cli 0.2.30-feat-cli-scrollable-command-autocomplete.19203 → 0.2.30-feat-cli-websocket-streaming.19209
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/{artifactExtractor-SVFEWL53.js → artifactExtractor-PK2WNCBH.js} +1 -1
- package/dist/{chunk-C3K7SH2V.js → chunk-55ZDRTGQ.js} +67 -2
- package/dist/{chunk-BYLWQZ5S.js → chunk-EAFOBAEJ.js} +2 -2
- package/dist/{chunk-65DLNQY2.js → chunk-NRQSEF3E.js} +2 -2
- package/dist/{chunk-B7Z2QQMD.js → chunk-PD5RFLGO.js} +2 -2
- package/dist/{chunk-5HA4JEOV.js → chunk-PIJR5GZP.js} +1 -1
- package/dist/{create-IDGWY5LO.js → create-UABXM6W2.js} +3 -3
- package/dist/index.js +505 -51
- package/dist/{llmMarkdownGenerator-BILRFSX6.js → llmMarkdownGenerator-Q3PRX6UR.js} +1 -1
- package/dist/{markdownGenerator-AI3EZ4Z3.js → markdownGenerator-TFFIS7MF.js} +1 -1
- package/dist/{mementoService-34S5SRX4.js → mementoService-IGCT6MIR.js} +3 -3
- package/dist/{src-QX72HMCT.js → src-QWRGDJYC.js} +13 -1
- package/dist/{src-MDS22ESD.js → src-ZH3FZBEP.js} +2 -2
- package/dist/{subtractCredits-6CK3FPNG.js → subtractCredits-KBC4NVIV.js} +3 -3
- package/package.json +6 -6
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
CurationArtifactType
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-55ZDRTGQ.js";
|
|
5
5
|
|
|
6
6
|
// ../../b4m-core/packages/services/dist/src/notebookCurationService/artifactExtractor.js
|
|
7
7
|
var ARTIFACT_TAG_REGEX = /<artifact\s+(.*?)>([\s\S]*?)<\/artifact>/gi;
|
|
@@ -1181,6 +1181,29 @@ var VoiceSessionSendTranscriptAction = z10.object({
|
|
|
1181
1181
|
conversationItemId: z10.string(),
|
|
1182
1182
|
timestamp: z10.coerce.date().optional()
|
|
1183
1183
|
});
|
|
1184
|
+
var CliCompletionRequestAction = z10.object({
|
|
1185
|
+
action: z10.literal("cli_completion_request"),
|
|
1186
|
+
accessToken: z10.string(),
|
|
1187
|
+
requestId: z10.string().uuid(),
|
|
1188
|
+
model: z10.string(),
|
|
1189
|
+
messages: z10.array(z10.object({
|
|
1190
|
+
role: z10.enum(["user", "assistant", "system"]),
|
|
1191
|
+
content: z10.union([z10.string(), z10.array(z10.unknown())])
|
|
1192
|
+
})),
|
|
1193
|
+
options: z10.object({
|
|
1194
|
+
temperature: z10.number().optional(),
|
|
1195
|
+
maxTokens: z10.number().optional(),
|
|
1196
|
+
stream: z10.boolean().optional(),
|
|
1197
|
+
tools: z10.array(z10.unknown()).optional()
|
|
1198
|
+
}).optional()
|
|
1199
|
+
});
|
|
1200
|
+
var CliToolRequestAction = z10.object({
|
|
1201
|
+
action: z10.literal("cli_tool_request"),
|
|
1202
|
+
accessToken: z10.string(),
|
|
1203
|
+
requestId: z10.string().uuid(),
|
|
1204
|
+
toolName: z10.string(),
|
|
1205
|
+
input: z10.record(z10.unknown())
|
|
1206
|
+
});
|
|
1184
1207
|
var VoiceSessionEndedAction = z10.object({
|
|
1185
1208
|
action: z10.literal("voice_session_ended"),
|
|
1186
1209
|
userId: z10.string(),
|
|
@@ -1469,6 +1492,36 @@ var VoiceCreditsExhaustedAction = z10.object({
|
|
|
1469
1492
|
creditsUsed: z10.number(),
|
|
1470
1493
|
clientId: z10.string().optional()
|
|
1471
1494
|
});
|
|
1495
|
+
var CliCompletionChunkAction = z10.object({
|
|
1496
|
+
action: z10.literal("cli_completion_chunk"),
|
|
1497
|
+
requestId: z10.string(),
|
|
1498
|
+
chunk: z10.object({
|
|
1499
|
+
type: z10.enum(["content", "tool_use"]),
|
|
1500
|
+
text: z10.string(),
|
|
1501
|
+
tools: z10.array(z10.unknown()).optional(),
|
|
1502
|
+
usage: z10.object({
|
|
1503
|
+
inputTokens: z10.number().optional(),
|
|
1504
|
+
outputTokens: z10.number().optional()
|
|
1505
|
+
}).optional(),
|
|
1506
|
+
thinking: z10.array(z10.unknown()).optional()
|
|
1507
|
+
})
|
|
1508
|
+
});
|
|
1509
|
+
var CliCompletionDoneAction = z10.object({
|
|
1510
|
+
action: z10.literal("cli_completion_done"),
|
|
1511
|
+
requestId: z10.string()
|
|
1512
|
+
});
|
|
1513
|
+
var CliCompletionErrorAction = z10.object({
|
|
1514
|
+
action: z10.literal("cli_completion_error"),
|
|
1515
|
+
requestId: z10.string(),
|
|
1516
|
+
error: z10.string()
|
|
1517
|
+
});
|
|
1518
|
+
var CliToolResponseAction = z10.object({
|
|
1519
|
+
action: z10.literal("cli_tool_response"),
|
|
1520
|
+
requestId: z10.string(),
|
|
1521
|
+
success: z10.boolean(),
|
|
1522
|
+
content: z10.unknown().optional(),
|
|
1523
|
+
error: z10.string().optional()
|
|
1524
|
+
});
|
|
1472
1525
|
var SessionCreatedAction = shareableDocumentSchema.extend({
|
|
1473
1526
|
action: z10.literal("session.created"),
|
|
1474
1527
|
id: z10.string(),
|
|
@@ -1503,7 +1556,9 @@ var MessageDataToServer = z10.discriminatedUnion("action", [
|
|
|
1503
1556
|
DataUnsubscribeRequestAction,
|
|
1504
1557
|
HeartbeatAction,
|
|
1505
1558
|
VoiceSessionSendTranscriptAction,
|
|
1506
|
-
VoiceSessionEndedAction
|
|
1559
|
+
VoiceSessionEndedAction,
|
|
1560
|
+
CliCompletionRequestAction,
|
|
1561
|
+
CliToolRequestAction
|
|
1507
1562
|
]);
|
|
1508
1563
|
var MessageDataToClient = z10.discriminatedUnion("action", [
|
|
1509
1564
|
DataSubscriptionUpdateAction,
|
|
@@ -1529,7 +1584,11 @@ var MessageDataToClient = z10.discriminatedUnion("action", [
|
|
|
1529
1584
|
PiHistoryCompleteAction,
|
|
1530
1585
|
PiHistoryErrorAction,
|
|
1531
1586
|
SessionCreatedAction,
|
|
1532
|
-
VoiceCreditsExhaustedAction
|
|
1587
|
+
VoiceCreditsExhaustedAction,
|
|
1588
|
+
CliCompletionChunkAction,
|
|
1589
|
+
CliCompletionDoneAction,
|
|
1590
|
+
CliCompletionErrorAction,
|
|
1591
|
+
CliToolResponseAction
|
|
1533
1592
|
]);
|
|
1534
1593
|
|
|
1535
1594
|
// ../../b4m-core/packages/common/dist/src/schemas/cliCompletions.js
|
|
@@ -8724,6 +8783,8 @@ export {
|
|
|
8724
8783
|
DataUnsubscribeRequestAction,
|
|
8725
8784
|
HeartbeatAction,
|
|
8726
8785
|
VoiceSessionSendTranscriptAction,
|
|
8786
|
+
CliCompletionRequestAction,
|
|
8787
|
+
CliToolRequestAction,
|
|
8727
8788
|
VoiceSessionEndedAction,
|
|
8728
8789
|
DataSubscriptionUpdateAction,
|
|
8729
8790
|
LLMStatusUpdateAction,
|
|
@@ -8748,6 +8809,10 @@ export {
|
|
|
8748
8809
|
ImportHistoryJobProgressUpdateAction,
|
|
8749
8810
|
ResearchModeStreamAction,
|
|
8750
8811
|
VoiceCreditsExhaustedAction,
|
|
8812
|
+
CliCompletionChunkAction,
|
|
8813
|
+
CliCompletionDoneAction,
|
|
8814
|
+
CliCompletionErrorAction,
|
|
8815
|
+
CliToolResponseAction,
|
|
8751
8816
|
SessionCreatedAction,
|
|
8752
8817
|
MessageDataToServer,
|
|
8753
8818
|
MessageDataToClient,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
BadRequestError,
|
|
4
4
|
secureParameters
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-PIJR5GZP.js";
|
|
6
6
|
import {
|
|
7
7
|
CompletionApiUsageTransaction,
|
|
8
8
|
GenericCreditDeductTransaction,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
TextGenerationUsageTransaction,
|
|
13
13
|
TransferCreditTransaction,
|
|
14
14
|
VideoGenerationUsageTransaction
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-55ZDRTGQ.js";
|
|
16
16
|
|
|
17
17
|
// ../../b4m-core/packages/services/dist/src/creditService/subtractCredits.js
|
|
18
18
|
import { z } from "zod";
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
getSettingsByNames,
|
|
7
7
|
obfuscateApiKey,
|
|
8
8
|
secureParameters
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PIJR5GZP.js";
|
|
10
10
|
import {
|
|
11
11
|
ApiKeyType,
|
|
12
12
|
MementoTier,
|
|
13
13
|
isSupportedEmbeddingModel
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-55ZDRTGQ.js";
|
|
15
15
|
|
|
16
16
|
// ../../b4m-core/packages/services/dist/src/apiKeyService/get.js
|
|
17
17
|
import { z } from "zod";
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
getSettingsMap,
|
|
8
8
|
getSettingsValue,
|
|
9
9
|
secureParameters
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PIJR5GZP.js";
|
|
11
11
|
import {
|
|
12
12
|
KnowledgeType,
|
|
13
13
|
SupportedFabFileMimeTypes
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-55ZDRTGQ.js";
|
|
15
15
|
|
|
16
16
|
// ../../b4m-core/packages/services/dist/src/fabFileService/create.js
|
|
17
17
|
import { z } from "zod";
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createFabFile,
|
|
4
4
|
createFabFileSchema
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-PD5RFLGO.js";
|
|
6
|
+
import "./chunk-PIJR5GZP.js";
|
|
7
|
+
import "./chunk-55ZDRTGQ.js";
|
|
8
8
|
import "./chunk-OCYRD7D6.js";
|
|
9
9
|
export {
|
|
10
10
|
createFabFile,
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
getEffectiveApiKey,
|
|
6
6
|
getOpenWeatherKey,
|
|
7
7
|
getSerperKey
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NRQSEF3E.js";
|
|
9
9
|
import "./chunk-RUI6HNLO.js";
|
|
10
10
|
import {
|
|
11
11
|
ConfigStore,
|
|
@@ -15,8 +15,8 @@ import {
|
|
|
15
15
|
selectActiveBackgroundAgents,
|
|
16
16
|
useCliStore
|
|
17
17
|
} from "./chunk-TVW4ZESU.js";
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-EAFOBAEJ.js";
|
|
19
|
+
import "./chunk-PD5RFLGO.js";
|
|
20
20
|
import {
|
|
21
21
|
BFLImageService,
|
|
22
22
|
BaseStorage,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
OpenAIBackend,
|
|
29
29
|
OpenAIImageService,
|
|
30
30
|
XAIImageService
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-PIJR5GZP.js";
|
|
32
32
|
import {
|
|
33
33
|
AiEvents,
|
|
34
34
|
ApiKeyEvents,
|
|
@@ -84,7 +84,7 @@ import {
|
|
|
84
84
|
XAI_IMAGE_MODELS,
|
|
85
85
|
b4mLLMTools,
|
|
86
86
|
getMcpProviderMetadata
|
|
87
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-55ZDRTGQ.js";
|
|
88
88
|
import {
|
|
89
89
|
Logger
|
|
90
90
|
} from "./chunk-OCYRD7D6.js";
|
|
@@ -94,7 +94,7 @@ import React21, { useState as useState10, useEffect as useEffect7, useCallback a
|
|
|
94
94
|
import { render, Box as Box20, Text as Text20, useApp, useInput as useInput9 } from "ink";
|
|
95
95
|
import { execSync } from "child_process";
|
|
96
96
|
import { randomBytes as randomBytes5 } from "crypto";
|
|
97
|
-
import { v4 as
|
|
97
|
+
import { v4 as uuidv413 } from "uuid";
|
|
98
98
|
|
|
99
99
|
// src/components/App.tsx
|
|
100
100
|
import React15, { useState as useState6, useEffect as useEffect5 } from "react";
|
|
@@ -316,23 +316,9 @@ function CommandAutocomplete({ commands, selectedIndex }) {
|
|
|
316
316
|
if (commands.length === 0) {
|
|
317
317
|
return /* @__PURE__ */ React3.createElement(Box2, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "No matching commands"));
|
|
318
318
|
}
|
|
319
|
-
|
|
320
|
-
const totalCommands = commands.length;
|
|
321
|
-
let startIndex = 0;
|
|
322
|
-
let endIndex = Math.min(VIEWPORT_SIZE, totalCommands);
|
|
323
|
-
if (totalCommands > VIEWPORT_SIZE) {
|
|
324
|
-
const halfViewport = Math.floor(VIEWPORT_SIZE / 2);
|
|
325
|
-
startIndex = Math.max(0, selectedIndex - halfViewport);
|
|
326
|
-
endIndex = Math.min(totalCommands, startIndex + VIEWPORT_SIZE);
|
|
327
|
-
if (endIndex === totalCommands) {
|
|
328
|
-
startIndex = Math.max(0, totalCommands - VIEWPORT_SIZE);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
const visibleCommands = commands.slice(startIndex, endIndex);
|
|
332
|
-
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, totalCommands === 1 ? "1 command" : `${totalCommands} commands`, totalCommands > VIEWPORT_SIZE && ` (${selectedIndex + 1}/${totalCommands})`, " \u2022 Use \u2191\u2193 to navigate, Enter to select")), visibleCommands.map((cmd, viewportIndex) => {
|
|
333
|
-
const actualIndex = startIndex + viewportIndex;
|
|
319
|
+
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, commands.length === 1 ? "1 command" : `${commands.length} commands`, " \u2022 Use \u2191\u2193 to navigate, Enter to select")), commands.map((cmd, index) => {
|
|
334
320
|
const args = cmd.args ? ` ${cmd.args}` : "";
|
|
335
|
-
const isSelected =
|
|
321
|
+
const isSelected = index === selectedIndex;
|
|
336
322
|
const sourceIcon = cmd.source === "global" ? "\u{1F3E0} " : cmd.source === "project" ? "\u{1F4C1} " : cmd.source === "built-in" ? "\u{1F527} " : "";
|
|
337
323
|
return /* @__PURE__ */ React3.createElement(Box2, { key: cmd.name, marginLeft: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: isSelected ? "cyan" : void 0, bold: isSelected }, isSelected ? "\u25B8 " : " ", sourceIcon, "/", cmd.name, args, " - ", cmd.description));
|
|
338
324
|
}));
|
|
@@ -12495,6 +12481,10 @@ var ServerToolExecutor = class {
|
|
|
12495
12481
|
};
|
|
12496
12482
|
|
|
12497
12483
|
// src/llm/ToolRouter.ts
|
|
12484
|
+
var wsToolExecutor = null;
|
|
12485
|
+
function setWebSocketToolExecutor(executor) {
|
|
12486
|
+
wsToolExecutor = executor;
|
|
12487
|
+
}
|
|
12498
12488
|
var SERVER_TOOLS = ["weather_info", "web_search", "web_fetch"];
|
|
12499
12489
|
var LOCAL_TOOLS = [
|
|
12500
12490
|
"file_read",
|
|
@@ -12517,7 +12507,15 @@ function isLocalTool(toolName) {
|
|
|
12517
12507
|
}
|
|
12518
12508
|
async function executeTool(toolName, input, apiClient, localToolFn) {
|
|
12519
12509
|
if (isServerTool(toolName)) {
|
|
12520
|
-
|
|
12510
|
+
if (wsToolExecutor) {
|
|
12511
|
+
logger.debug(`[ToolRouter] Routing ${toolName} to server via WebSocket`);
|
|
12512
|
+
const result = await wsToolExecutor.execute(toolName, input);
|
|
12513
|
+
if (!result.success) {
|
|
12514
|
+
return `Error executing ${toolName}: ${result.error || "Tool execution failed"}`;
|
|
12515
|
+
}
|
|
12516
|
+
return typeof result.content === "string" ? result.content : JSON.stringify(result.content ?? "");
|
|
12517
|
+
}
|
|
12518
|
+
logger.debug(`[ToolRouter] Routing ${toolName} to server via HTTP`);
|
|
12521
12519
|
const executor = new ServerToolExecutor(apiClient);
|
|
12522
12520
|
return await executor.executeTool(toolName, input);
|
|
12523
12521
|
} else if (isLocalTool(toolName)) {
|
|
@@ -14479,6 +14477,173 @@ var ServerLlmBackend = class {
|
|
|
14479
14477
|
}
|
|
14480
14478
|
};
|
|
14481
14479
|
|
|
14480
|
+
// src/llm/WebSocketLlmBackend.ts
|
|
14481
|
+
import { v4 as uuidv411 } from "uuid";
|
|
14482
|
+
function stripThinkingBlocks2(text) {
|
|
14483
|
+
return text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
14484
|
+
}
|
|
14485
|
+
var WebSocketLlmBackend = class {
|
|
14486
|
+
constructor(options) {
|
|
14487
|
+
this.wsManager = options.wsManager;
|
|
14488
|
+
this.apiClient = options.apiClient;
|
|
14489
|
+
this.currentModel = options.model;
|
|
14490
|
+
this.tokenGetter = options.tokenGetter;
|
|
14491
|
+
this.wsCompletionUrl = options.wsCompletionUrl;
|
|
14492
|
+
}
|
|
14493
|
+
/**
|
|
14494
|
+
* Send completion request via HTTP POST, receive streaming response via WebSocket.
|
|
14495
|
+
* Collects all streamed chunks, then calls callback once at completion
|
|
14496
|
+
* with the full accumulated content.
|
|
14497
|
+
*/
|
|
14498
|
+
async complete(model, messages, options, callback) {
|
|
14499
|
+
logger.debug(`[WebSocketLlmBackend] Starting complete() with model: ${model}`);
|
|
14500
|
+
if (options.abortSignal?.aborted) {
|
|
14501
|
+
logger.debug("[WebSocketLlmBackend] Request aborted before start");
|
|
14502
|
+
return;
|
|
14503
|
+
}
|
|
14504
|
+
if (!this.wsManager.isConnected) {
|
|
14505
|
+
throw new Error("WebSocket is not connected");
|
|
14506
|
+
}
|
|
14507
|
+
const requestId = uuidv411();
|
|
14508
|
+
return new Promise((resolve3, reject) => {
|
|
14509
|
+
const isVerbose = process.env.B4M_VERBOSE === "1";
|
|
14510
|
+
const isUltraVerbose = process.env.B4M_DEBUG_STREAM === "1";
|
|
14511
|
+
const streamLogger = new StreamLogger(logger, "WebSocketLlmBackend", isVerbose, isUltraVerbose);
|
|
14512
|
+
streamLogger.streamStart();
|
|
14513
|
+
let eventCount = 0;
|
|
14514
|
+
let accumulatedText = "";
|
|
14515
|
+
let lastUsageInfo = {};
|
|
14516
|
+
let toolsUsed = [];
|
|
14517
|
+
let thinkingBlocks = [];
|
|
14518
|
+
let settled = false;
|
|
14519
|
+
const settle = (action) => {
|
|
14520
|
+
if (settled) return;
|
|
14521
|
+
settled = true;
|
|
14522
|
+
this.wsManager.offRequest(requestId);
|
|
14523
|
+
this.wsManager.offDisconnect(onDisconnect);
|
|
14524
|
+
action();
|
|
14525
|
+
};
|
|
14526
|
+
const settleResolve = () => settle(() => resolve3());
|
|
14527
|
+
const settleReject = (err) => settle(() => reject(err));
|
|
14528
|
+
const onDisconnect = () => {
|
|
14529
|
+
logger.debug("[WebSocketLlmBackend] Connection dropped during completion");
|
|
14530
|
+
settleReject(new Error("WebSocket connection lost during completion"));
|
|
14531
|
+
};
|
|
14532
|
+
this.wsManager.onDisconnect(onDisconnect);
|
|
14533
|
+
if (options.abortSignal) {
|
|
14534
|
+
if (options.abortSignal.aborted) {
|
|
14535
|
+
settleResolve();
|
|
14536
|
+
return;
|
|
14537
|
+
}
|
|
14538
|
+
options.abortSignal.addEventListener(
|
|
14539
|
+
"abort",
|
|
14540
|
+
() => {
|
|
14541
|
+
logger.debug("[WebSocketLlmBackend] Abort signal received");
|
|
14542
|
+
settleResolve();
|
|
14543
|
+
},
|
|
14544
|
+
{ once: true }
|
|
14545
|
+
);
|
|
14546
|
+
}
|
|
14547
|
+
const updateUsage = (usage) => {
|
|
14548
|
+
if (usage) {
|
|
14549
|
+
lastUsageInfo = { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens };
|
|
14550
|
+
}
|
|
14551
|
+
};
|
|
14552
|
+
this.wsManager.onRequest(requestId, (message) => {
|
|
14553
|
+
if (options.abortSignal?.aborted) return;
|
|
14554
|
+
const action = message.action;
|
|
14555
|
+
if (action === "cli_completion_chunk") {
|
|
14556
|
+
eventCount++;
|
|
14557
|
+
const chunk = message.chunk;
|
|
14558
|
+
streamLogger.onEvent(eventCount, JSON.stringify(chunk));
|
|
14559
|
+
const textChunk = chunk.text || "";
|
|
14560
|
+
if (textChunk) accumulatedText += textChunk;
|
|
14561
|
+
updateUsage(chunk.usage);
|
|
14562
|
+
if (chunk.type === "content") {
|
|
14563
|
+
streamLogger.onContent(eventCount, textChunk, accumulatedText);
|
|
14564
|
+
} else if (chunk.type === "tool_use") {
|
|
14565
|
+
streamLogger.onCriticalEvent(eventCount, "TOOL_USE", `tools: ${chunk.tools?.length}`);
|
|
14566
|
+
if (chunk.tools && chunk.tools.length > 0) toolsUsed = chunk.tools;
|
|
14567
|
+
if (chunk.thinking && chunk.thinking.length > 0) thinkingBlocks = chunk.thinking;
|
|
14568
|
+
}
|
|
14569
|
+
} else if (action === "cli_completion_done") {
|
|
14570
|
+
streamLogger.streamComplete(accumulatedText);
|
|
14571
|
+
const cleanedText = stripThinkingBlocks2(accumulatedText);
|
|
14572
|
+
if (!cleanedText && toolsUsed.length === 0) {
|
|
14573
|
+
settleResolve();
|
|
14574
|
+
return;
|
|
14575
|
+
}
|
|
14576
|
+
const info = {
|
|
14577
|
+
...lastUsageInfo,
|
|
14578
|
+
...toolsUsed.length > 0 && { toolsUsed },
|
|
14579
|
+
...thinkingBlocks.length > 0 && { thinking: thinkingBlocks }
|
|
14580
|
+
};
|
|
14581
|
+
callback([cleanedText], info).then(() => settleResolve()).catch((err) => settleReject(err));
|
|
14582
|
+
} else if (action === "cli_completion_error") {
|
|
14583
|
+
const errorMsg = message.error || "Server error";
|
|
14584
|
+
streamLogger.onCriticalEvent(eventCount, "ERROR", errorMsg);
|
|
14585
|
+
settleReject(new Error(errorMsg));
|
|
14586
|
+
}
|
|
14587
|
+
});
|
|
14588
|
+
const axiosInstance = this.apiClient.getAxiosInstance();
|
|
14589
|
+
axiosInstance.post(
|
|
14590
|
+
this.wsCompletionUrl,
|
|
14591
|
+
{
|
|
14592
|
+
requestId,
|
|
14593
|
+
model,
|
|
14594
|
+
messages,
|
|
14595
|
+
options: {
|
|
14596
|
+
temperature: options.temperature,
|
|
14597
|
+
maxTokens: options.maxTokens,
|
|
14598
|
+
stream: true,
|
|
14599
|
+
tools: options.tools || []
|
|
14600
|
+
}
|
|
14601
|
+
},
|
|
14602
|
+
{ signal: options.abortSignal }
|
|
14603
|
+
).catch((err) => {
|
|
14604
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
14605
|
+
settleReject(new Error(`HTTP request failed: ${msg}`));
|
|
14606
|
+
});
|
|
14607
|
+
});
|
|
14608
|
+
}
|
|
14609
|
+
/**
|
|
14610
|
+
* Get available models from server (REST call, not streaming).
|
|
14611
|
+
* Delegates to ApiClient -- same as ServerLlmBackend.
|
|
14612
|
+
*/
|
|
14613
|
+
async getModelInfo() {
|
|
14614
|
+
try {
|
|
14615
|
+
logger.debug("[WebSocketLlmBackend] Fetching models from /api/models");
|
|
14616
|
+
const response = await this.apiClient.get("/api/models");
|
|
14617
|
+
if (!response || typeof response !== "object" || !Array.isArray(response.models)) {
|
|
14618
|
+
logger.warn("[WebSocketLlmBackend] Invalid API response format, using fallback models");
|
|
14619
|
+
return this.getFallbackModels();
|
|
14620
|
+
}
|
|
14621
|
+
const filteredModels = response.models.filter(
|
|
14622
|
+
(model) => model.type === "text" && model.supportsTools === true
|
|
14623
|
+
);
|
|
14624
|
+
if (filteredModels.length === 0) {
|
|
14625
|
+
logger.warn("[WebSocketLlmBackend] No CLI-compatible models found, using fallback");
|
|
14626
|
+
return this.getFallbackModels();
|
|
14627
|
+
}
|
|
14628
|
+
logger.debug(`[WebSocketLlmBackend] Loaded ${filteredModels.length} models`);
|
|
14629
|
+
return filteredModels;
|
|
14630
|
+
} catch (error) {
|
|
14631
|
+
logger.warn(
|
|
14632
|
+
`[WebSocketLlmBackend] Failed to fetch models: ${error instanceof Error ? error.message : String(error)}`
|
|
14633
|
+
);
|
|
14634
|
+
return this.getFallbackModels();
|
|
14635
|
+
}
|
|
14636
|
+
}
|
|
14637
|
+
getFallbackModels() {
|
|
14638
|
+
return [
|
|
14639
|
+
{ id: "claude-sonnet-4-5-20250929", name: "Claude 4.5 Sonnet" },
|
|
14640
|
+
{ id: "claude-3-5-haiku-20241022", name: "Claude 3.5 Haiku" },
|
|
14641
|
+
{ id: "gpt-4o", name: "GPT-4o" },
|
|
14642
|
+
{ id: "gpt-4o-mini", name: "GPT-4o Mini" }
|
|
14643
|
+
];
|
|
14644
|
+
}
|
|
14645
|
+
};
|
|
14646
|
+
|
|
14482
14647
|
// src/llm/NotifyingLlmBackend.ts
|
|
14483
14648
|
var NotifyingLlmBackend = class {
|
|
14484
14649
|
constructor(inner, backgroundManager) {
|
|
@@ -14513,6 +14678,253 @@ Please acknowledge these background agent results and incorporate them into your
|
|
|
14513
14678
|
}
|
|
14514
14679
|
};
|
|
14515
14680
|
|
|
14681
|
+
// src/ws/WebSocketConnectionManager.ts
|
|
14682
|
+
var WebSocketConnectionManager = class {
|
|
14683
|
+
constructor(wsUrl, getToken) {
|
|
14684
|
+
this.ws = null;
|
|
14685
|
+
this.heartbeatInterval = null;
|
|
14686
|
+
this.reconnectAttempts = 0;
|
|
14687
|
+
this.maxReconnectDelay = 3e4;
|
|
14688
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
14689
|
+
this.disconnectHandlers = /* @__PURE__ */ new Set();
|
|
14690
|
+
this.reconnectTimer = null;
|
|
14691
|
+
this.connected = false;
|
|
14692
|
+
this.connecting = false;
|
|
14693
|
+
this.closed = false;
|
|
14694
|
+
this.wsUrl = wsUrl;
|
|
14695
|
+
this.getToken = getToken;
|
|
14696
|
+
}
|
|
14697
|
+
/**
|
|
14698
|
+
* Connect to the WebSocket server.
|
|
14699
|
+
* Resolves when connection is established, rejects on failure.
|
|
14700
|
+
*/
|
|
14701
|
+
async connect() {
|
|
14702
|
+
if (this.connected || this.connecting) return;
|
|
14703
|
+
this.connecting = true;
|
|
14704
|
+
const token = await this.getToken();
|
|
14705
|
+
if (!token) {
|
|
14706
|
+
this.connecting = false;
|
|
14707
|
+
throw new Error("No access token available for WebSocket connection");
|
|
14708
|
+
}
|
|
14709
|
+
return new Promise((resolve3, reject) => {
|
|
14710
|
+
logger.debug(`[WS] Connecting to ${this.wsUrl}...`);
|
|
14711
|
+
this.ws = new WebSocket(this.wsUrl, [`access_token.${token}`]);
|
|
14712
|
+
this.ws.onopen = () => {
|
|
14713
|
+
logger.debug("[WS] Connected");
|
|
14714
|
+
this.connected = true;
|
|
14715
|
+
this.connecting = false;
|
|
14716
|
+
this.reconnectAttempts = 0;
|
|
14717
|
+
this.startHeartbeat();
|
|
14718
|
+
resolve3();
|
|
14719
|
+
};
|
|
14720
|
+
this.ws.onmessage = (event) => {
|
|
14721
|
+
try {
|
|
14722
|
+
const data = typeof event.data === "string" ? event.data : event.data.toString();
|
|
14723
|
+
const message = JSON.parse(data);
|
|
14724
|
+
const requestId = message.requestId;
|
|
14725
|
+
if (requestId && this.handlers.has(requestId)) {
|
|
14726
|
+
this.handlers.get(requestId)(message);
|
|
14727
|
+
} else {
|
|
14728
|
+
logger.debug(`[WS] Unhandled message: ${message.action || "unknown"}`);
|
|
14729
|
+
}
|
|
14730
|
+
} catch (err) {
|
|
14731
|
+
logger.debug(`[WS] Failed to parse message: ${err}`);
|
|
14732
|
+
}
|
|
14733
|
+
};
|
|
14734
|
+
this.ws.onclose = () => {
|
|
14735
|
+
logger.debug("[WS] Connection closed");
|
|
14736
|
+
this.cleanup();
|
|
14737
|
+
this.notifyDisconnect();
|
|
14738
|
+
if (!this.closed) {
|
|
14739
|
+
this.scheduleReconnect();
|
|
14740
|
+
}
|
|
14741
|
+
};
|
|
14742
|
+
this.ws.onerror = (err) => {
|
|
14743
|
+
logger.debug(`[WS] Error: ${err}`);
|
|
14744
|
+
if (this.connecting) {
|
|
14745
|
+
this.connecting = false;
|
|
14746
|
+
this.connected = false;
|
|
14747
|
+
reject(new Error("WebSocket connection failed"));
|
|
14748
|
+
}
|
|
14749
|
+
};
|
|
14750
|
+
});
|
|
14751
|
+
}
|
|
14752
|
+
/** Whether the connection is currently established */
|
|
14753
|
+
get isConnected() {
|
|
14754
|
+
return this.connected;
|
|
14755
|
+
}
|
|
14756
|
+
/**
|
|
14757
|
+
* Send a JSON message over the WebSocket connection.
|
|
14758
|
+
*/
|
|
14759
|
+
send(data) {
|
|
14760
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
14761
|
+
throw new Error("WebSocket is not connected");
|
|
14762
|
+
}
|
|
14763
|
+
const payload = JSON.stringify(data);
|
|
14764
|
+
const sizeKB = (payload.length / 1024).toFixed(1);
|
|
14765
|
+
logger.debug(`[WS] Sending ${sizeKB} KB (action: ${data.action})`);
|
|
14766
|
+
if (payload.length > 32e3) {
|
|
14767
|
+
logger.warn(`[WS] Payload ${sizeKB} KB exceeds API Gateway 32 KB frame limit \u2014 connection will be closed`);
|
|
14768
|
+
}
|
|
14769
|
+
this.ws.send(payload);
|
|
14770
|
+
}
|
|
14771
|
+
/**
|
|
14772
|
+
* Register a handler for messages matching a specific requestId.
|
|
14773
|
+
*/
|
|
14774
|
+
onRequest(requestId, handler) {
|
|
14775
|
+
this.handlers.set(requestId, handler);
|
|
14776
|
+
}
|
|
14777
|
+
/**
|
|
14778
|
+
* Remove a handler for a specific requestId.
|
|
14779
|
+
*/
|
|
14780
|
+
offRequest(requestId) {
|
|
14781
|
+
this.handlers.delete(requestId);
|
|
14782
|
+
}
|
|
14783
|
+
/**
|
|
14784
|
+
* Register a handler that fires when the connection drops.
|
|
14785
|
+
*/
|
|
14786
|
+
onDisconnect(handler) {
|
|
14787
|
+
this.disconnectHandlers.add(handler);
|
|
14788
|
+
}
|
|
14789
|
+
/**
|
|
14790
|
+
* Remove a disconnect handler.
|
|
14791
|
+
*/
|
|
14792
|
+
offDisconnect(handler) {
|
|
14793
|
+
this.disconnectHandlers.delete(handler);
|
|
14794
|
+
}
|
|
14795
|
+
/**
|
|
14796
|
+
* Close the connection and stop all heartbeat/reconnect logic.
|
|
14797
|
+
*/
|
|
14798
|
+
disconnect() {
|
|
14799
|
+
this.closed = true;
|
|
14800
|
+
this.cleanup();
|
|
14801
|
+
if (this.ws) {
|
|
14802
|
+
this.ws.close();
|
|
14803
|
+
this.ws = null;
|
|
14804
|
+
}
|
|
14805
|
+
this.handlers.clear();
|
|
14806
|
+
this.disconnectHandlers.clear();
|
|
14807
|
+
}
|
|
14808
|
+
startHeartbeat() {
|
|
14809
|
+
this.stopHeartbeat();
|
|
14810
|
+
this.heartbeatInterval = setInterval(
|
|
14811
|
+
() => {
|
|
14812
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
14813
|
+
this.ws.send(JSON.stringify({ action: "heartbeat" }));
|
|
14814
|
+
logger.debug("[WS] Heartbeat sent");
|
|
14815
|
+
}
|
|
14816
|
+
},
|
|
14817
|
+
5 * 60 * 1e3
|
|
14818
|
+
);
|
|
14819
|
+
}
|
|
14820
|
+
stopHeartbeat() {
|
|
14821
|
+
if (this.heartbeatInterval) {
|
|
14822
|
+
clearInterval(this.heartbeatInterval);
|
|
14823
|
+
this.heartbeatInterval = null;
|
|
14824
|
+
}
|
|
14825
|
+
}
|
|
14826
|
+
cleanup() {
|
|
14827
|
+
this.connected = false;
|
|
14828
|
+
this.connecting = false;
|
|
14829
|
+
this.stopHeartbeat();
|
|
14830
|
+
if (this.reconnectTimer) {
|
|
14831
|
+
clearTimeout(this.reconnectTimer);
|
|
14832
|
+
this.reconnectTimer = null;
|
|
14833
|
+
}
|
|
14834
|
+
}
|
|
14835
|
+
notifyDisconnect() {
|
|
14836
|
+
for (const handler of this.disconnectHandlers) {
|
|
14837
|
+
try {
|
|
14838
|
+
handler();
|
|
14839
|
+
} catch {
|
|
14840
|
+
}
|
|
14841
|
+
}
|
|
14842
|
+
}
|
|
14843
|
+
scheduleReconnect() {
|
|
14844
|
+
if (this.closed) return;
|
|
14845
|
+
this.reconnectAttempts++;
|
|
14846
|
+
const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts - 1), this.maxReconnectDelay);
|
|
14847
|
+
logger.debug(`[WS] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
|
14848
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
14849
|
+
this.reconnectTimer = null;
|
|
14850
|
+
if (this.closed) return;
|
|
14851
|
+
try {
|
|
14852
|
+
await this.connect();
|
|
14853
|
+
} catch {
|
|
14854
|
+
logger.debug("[WS] Reconnection failed");
|
|
14855
|
+
}
|
|
14856
|
+
}, delay);
|
|
14857
|
+
}
|
|
14858
|
+
};
|
|
14859
|
+
|
|
14860
|
+
// src/ws/WebSocketToolExecutor.ts
|
|
14861
|
+
import { v4 as uuidv412 } from "uuid";
|
|
14862
|
+
var WebSocketToolExecutor = class {
|
|
14863
|
+
constructor(wsManager, tokenGetter) {
|
|
14864
|
+
this.wsManager = wsManager;
|
|
14865
|
+
this.tokenGetter = tokenGetter;
|
|
14866
|
+
}
|
|
14867
|
+
/**
|
|
14868
|
+
* Execute a server-side tool via WebSocket.
|
|
14869
|
+
* Returns the tool result or throws on error.
|
|
14870
|
+
*/
|
|
14871
|
+
async execute(toolName, input, abortSignal) {
|
|
14872
|
+
if (!this.wsManager.isConnected) {
|
|
14873
|
+
throw new Error("WebSocket is not connected");
|
|
14874
|
+
}
|
|
14875
|
+
const token = await this.tokenGetter();
|
|
14876
|
+
if (!token) {
|
|
14877
|
+
throw new Error("No access token available");
|
|
14878
|
+
}
|
|
14879
|
+
const requestId = uuidv412();
|
|
14880
|
+
return new Promise((resolve3, reject) => {
|
|
14881
|
+
let settled = false;
|
|
14882
|
+
const settle = (action) => {
|
|
14883
|
+
if (settled) return;
|
|
14884
|
+
settled = true;
|
|
14885
|
+
this.wsManager.offRequest(requestId);
|
|
14886
|
+
this.wsManager.offDisconnect(onDisconnect);
|
|
14887
|
+
action();
|
|
14888
|
+
};
|
|
14889
|
+
const settleResolve = (result) => settle(() => resolve3(result));
|
|
14890
|
+
const settleReject = (err) => settle(() => reject(err));
|
|
14891
|
+
const onDisconnect = () => {
|
|
14892
|
+
settleReject(new Error("WebSocket connection lost during tool execution"));
|
|
14893
|
+
};
|
|
14894
|
+
this.wsManager.onDisconnect(onDisconnect);
|
|
14895
|
+
if (abortSignal) {
|
|
14896
|
+
if (abortSignal.aborted) {
|
|
14897
|
+
settleReject(new Error("Tool execution aborted"));
|
|
14898
|
+
return;
|
|
14899
|
+
}
|
|
14900
|
+
abortSignal.addEventListener("abort", () => settleReject(new Error("Tool execution aborted")), {
|
|
14901
|
+
once: true
|
|
14902
|
+
});
|
|
14903
|
+
}
|
|
14904
|
+
this.wsManager.onRequest(requestId, (message) => {
|
|
14905
|
+
if (message.action === "cli_tool_response") {
|
|
14906
|
+
settleResolve({
|
|
14907
|
+
success: message.success,
|
|
14908
|
+
content: message.content,
|
|
14909
|
+
error: message.error
|
|
14910
|
+
});
|
|
14911
|
+
}
|
|
14912
|
+
});
|
|
14913
|
+
try {
|
|
14914
|
+
this.wsManager.send({
|
|
14915
|
+
action: "cli_tool_request",
|
|
14916
|
+
accessToken: token,
|
|
14917
|
+
requestId,
|
|
14918
|
+
toolName,
|
|
14919
|
+
input
|
|
14920
|
+
});
|
|
14921
|
+
} catch (err) {
|
|
14922
|
+
settleReject(err instanceof Error ? err : new Error(String(err)));
|
|
14923
|
+
}
|
|
14924
|
+
});
|
|
14925
|
+
}
|
|
14926
|
+
};
|
|
14927
|
+
|
|
14516
14928
|
// src/auth/ApiClient.ts
|
|
14517
14929
|
import axios11 from "axios";
|
|
14518
14930
|
var ApiClient = class {
|
|
@@ -14650,7 +15062,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
14650
15062
|
// package.json
|
|
14651
15063
|
var package_default = {
|
|
14652
15064
|
name: "@bike4mind/cli",
|
|
14653
|
-
version: "0.2.30-feat-cli-
|
|
15065
|
+
version: "0.2.30-feat-cli-websocket-streaming.19209+64d4459aa",
|
|
14654
15066
|
type: "module",
|
|
14655
15067
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
14656
15068
|
license: "UNLICENSED",
|
|
@@ -14761,10 +15173,10 @@ var package_default = {
|
|
|
14761
15173
|
},
|
|
14762
15174
|
devDependencies: {
|
|
14763
15175
|
"@bike4mind/agents": "0.1.0",
|
|
14764
|
-
"@bike4mind/common": "2.51.1-feat-cli-
|
|
14765
|
-
"@bike4mind/mcp": "1.30.1-feat-cli-
|
|
14766
|
-
"@bike4mind/services": "2.49.1-feat-cli-
|
|
14767
|
-
"@bike4mind/utils": "2.6.1-feat-cli-
|
|
15176
|
+
"@bike4mind/common": "2.51.1-feat-cli-websocket-streaming.19209+64d4459aa",
|
|
15177
|
+
"@bike4mind/mcp": "1.30.1-feat-cli-websocket-streaming.19209+64d4459aa",
|
|
15178
|
+
"@bike4mind/services": "2.49.1-feat-cli-websocket-streaming.19209+64d4459aa",
|
|
15179
|
+
"@bike4mind/utils": "2.6.1-feat-cli-websocket-streaming.19209+64d4459aa",
|
|
14768
15180
|
"@types/better-sqlite3": "^7.6.13",
|
|
14769
15181
|
"@types/diff": "^5.0.9",
|
|
14770
15182
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -14785,7 +15197,7 @@ var package_default = {
|
|
|
14785
15197
|
optionalDependencies: {
|
|
14786
15198
|
"@vscode/ripgrep": "^1.17.0"
|
|
14787
15199
|
},
|
|
14788
|
-
gitHead: "
|
|
15200
|
+
gitHead: "64d4459aaf9c9ba124dac6513d470113295bd1d1"
|
|
14789
15201
|
};
|
|
14790
15202
|
|
|
14791
15203
|
// src/config/constants.ts
|
|
@@ -16564,7 +16976,8 @@ function CliApp() {
|
|
|
16564
16976
|
agentStore: null,
|
|
16565
16977
|
abortController: null,
|
|
16566
16978
|
contextContent: "",
|
|
16567
|
-
backgroundManager: null
|
|
16979
|
+
backgroundManager: null,
|
|
16980
|
+
wsManager: null
|
|
16568
16981
|
});
|
|
16569
16982
|
const [isInitialized, setIsInitialized] = useState10(false);
|
|
16570
16983
|
const [initError, setInitError] = useState10(null);
|
|
@@ -16592,6 +17005,10 @@ function CliApp() {
|
|
|
16592
17005
|
})
|
|
16593
17006
|
);
|
|
16594
17007
|
}
|
|
17008
|
+
if (state.wsManager) {
|
|
17009
|
+
state.wsManager.disconnect();
|
|
17010
|
+
setWebSocketToolExecutor(null);
|
|
17011
|
+
}
|
|
16595
17012
|
if (state.agent) {
|
|
16596
17013
|
state.agent.removeAllListeners();
|
|
16597
17014
|
}
|
|
@@ -16610,7 +17027,7 @@ function CliApp() {
|
|
|
16610
17027
|
setTimeout(() => {
|
|
16611
17028
|
process.exit(0);
|
|
16612
17029
|
}, 100);
|
|
16613
|
-
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
|
|
17030
|
+
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore, state.wsManager]);
|
|
16614
17031
|
useInput9((input, key) => {
|
|
16615
17032
|
if (key.escape) {
|
|
16616
17033
|
if (state.abortController) {
|
|
@@ -16680,7 +17097,7 @@ function CliApp() {
|
|
|
16680
17097
|
if (!isAuthenticated) {
|
|
16681
17098
|
console.log("\u2139\uFE0F AI features disabled. Available commands: /login, /help, /config\n");
|
|
16682
17099
|
const minimalSession = {
|
|
16683
|
-
id:
|
|
17100
|
+
id: uuidv413(),
|
|
16684
17101
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
16685
17102
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16686
17103
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16708,10 +17125,45 @@ function CliApp() {
|
|
|
16708
17125
|
console.log(`\u{1F30D} API Environment: ${envName} (${apiBaseURL})`);
|
|
16709
17126
|
}
|
|
16710
17127
|
const apiClient = new ApiClient(apiBaseURL, state.configStore);
|
|
16711
|
-
const
|
|
16712
|
-
|
|
16713
|
-
|
|
16714
|
-
}
|
|
17128
|
+
const tokenGetter = async () => {
|
|
17129
|
+
const tokens = await state.configStore.getAuthTokens();
|
|
17130
|
+
return tokens?.accessToken ?? null;
|
|
17131
|
+
};
|
|
17132
|
+
let wsManager = null;
|
|
17133
|
+
let llm;
|
|
17134
|
+
try {
|
|
17135
|
+
const serverConfig = await apiClient.get(
|
|
17136
|
+
"/api/settings/serverConfig"
|
|
17137
|
+
);
|
|
17138
|
+
const wsUrl = serverConfig?.websocketUrl;
|
|
17139
|
+
const wsCompletionUrl = serverConfig?.wsCompletionUrl;
|
|
17140
|
+
if (wsUrl && wsCompletionUrl) {
|
|
17141
|
+
wsManager = new WebSocketConnectionManager(wsUrl, tokenGetter);
|
|
17142
|
+
await wsManager.connect();
|
|
17143
|
+
const wsToolExecutor2 = new WebSocketToolExecutor(wsManager, tokenGetter);
|
|
17144
|
+
setWebSocketToolExecutor(wsToolExecutor2);
|
|
17145
|
+
llm = new WebSocketLlmBackend({
|
|
17146
|
+
wsManager,
|
|
17147
|
+
apiClient,
|
|
17148
|
+
model: config.defaultModel,
|
|
17149
|
+
tokenGetter,
|
|
17150
|
+
wsCompletionUrl
|
|
17151
|
+
});
|
|
17152
|
+
logger.debug("\u{1F50C} Using WebSocket transport (bypasses CloudFront timeout)");
|
|
17153
|
+
} else {
|
|
17154
|
+
throw new Error("No websocketUrl or wsCompletionUrl in server config");
|
|
17155
|
+
}
|
|
17156
|
+
} catch (wsError) {
|
|
17157
|
+
logger.debug(
|
|
17158
|
+
`[WS] WebSocket unavailable, using SSE fallback: ${wsError instanceof Error ? wsError.message : String(wsError)}`
|
|
17159
|
+
);
|
|
17160
|
+
wsManager = null;
|
|
17161
|
+
setWebSocketToolExecutor(null);
|
|
17162
|
+
llm = new ServerLlmBackend({
|
|
17163
|
+
apiClient,
|
|
17164
|
+
model: config.defaultModel
|
|
17165
|
+
});
|
|
17166
|
+
}
|
|
16715
17167
|
const models = await llm.getModelInfo();
|
|
16716
17168
|
if (models.length === 0) {
|
|
16717
17169
|
throw new Error("No models available from server.");
|
|
@@ -16724,7 +17176,7 @@ function CliApp() {
|
|
|
16724
17176
|
}
|
|
16725
17177
|
llm.currentModel = modelInfo.id;
|
|
16726
17178
|
const newSession = {
|
|
16727
|
-
id:
|
|
17179
|
+
id: uuidv413(),
|
|
16728
17180
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
16729
17181
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16730
17182
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16938,8 +17390,10 @@ function CliApp() {
|
|
|
16938
17390
|
// Store agent store for agent management commands
|
|
16939
17391
|
contextContent: contextResult.mergedContent,
|
|
16940
17392
|
// Store raw context for compact instructions
|
|
16941
|
-
backgroundManager
|
|
17393
|
+
backgroundManager,
|
|
16942
17394
|
// Store for grouped notification turn tracking
|
|
17395
|
+
wsManager
|
|
17396
|
+
// WebSocket connection manager (null if using SSE fallback)
|
|
16943
17397
|
}));
|
|
16944
17398
|
setStoreSession(newSession);
|
|
16945
17399
|
const bannerLines = [
|
|
@@ -17034,13 +17488,13 @@ function CliApp() {
|
|
|
17034
17488
|
messageContent = multimodalMessage.content;
|
|
17035
17489
|
}
|
|
17036
17490
|
const userMessage = {
|
|
17037
|
-
id:
|
|
17491
|
+
id: uuidv413(),
|
|
17038
17492
|
role: "user",
|
|
17039
17493
|
content: userMessageContent,
|
|
17040
17494
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17041
17495
|
};
|
|
17042
17496
|
const pendingAssistantMessage = {
|
|
17043
|
-
id:
|
|
17497
|
+
id: uuidv413(),
|
|
17044
17498
|
role: "assistant",
|
|
17045
17499
|
content: "...",
|
|
17046
17500
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17253,13 +17707,13 @@ function CliApp() {
|
|
|
17253
17707
|
userMessageContent = message;
|
|
17254
17708
|
}
|
|
17255
17709
|
const userMessage = {
|
|
17256
|
-
id:
|
|
17710
|
+
id: uuidv413(),
|
|
17257
17711
|
role: "user",
|
|
17258
17712
|
content: userMessageContent,
|
|
17259
17713
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17260
17714
|
};
|
|
17261
17715
|
const pendingAssistantMessage = {
|
|
17262
|
-
id:
|
|
17716
|
+
id: uuidv413(),
|
|
17263
17717
|
role: "assistant",
|
|
17264
17718
|
content: "...",
|
|
17265
17719
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17339,7 +17793,7 @@ function CliApp() {
|
|
|
17339
17793
|
const currentSession = useCliStore.getState().session;
|
|
17340
17794
|
if (currentSession) {
|
|
17341
17795
|
const cancelMessage = {
|
|
17342
|
-
id:
|
|
17796
|
+
id: uuidv413(),
|
|
17343
17797
|
role: "assistant",
|
|
17344
17798
|
content: "\u26A0\uFE0F Operation cancelled by user",
|
|
17345
17799
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17384,7 +17838,7 @@ function CliApp() {
|
|
|
17384
17838
|
setState((prev) => ({ ...prev, abortController }));
|
|
17385
17839
|
try {
|
|
17386
17840
|
const pendingAssistantMessage = {
|
|
17387
|
-
id:
|
|
17841
|
+
id: uuidv413(),
|
|
17388
17842
|
role: "assistant",
|
|
17389
17843
|
content: "...",
|
|
17390
17844
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17412,7 +17866,7 @@ function CliApp() {
|
|
|
17412
17866
|
const currentSession = useCliStore.getState().session;
|
|
17413
17867
|
if (!currentSession) return;
|
|
17414
17868
|
const continuationMessage = {
|
|
17415
|
-
id:
|
|
17869
|
+
id: uuidv413(),
|
|
17416
17870
|
role: "assistant",
|
|
17417
17871
|
content: "---\n\n**Background Agent Results:**\n\n" + result.finalAnswer,
|
|
17418
17872
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17473,13 +17927,13 @@ function CliApp() {
|
|
|
17473
17927
|
isError = true;
|
|
17474
17928
|
}
|
|
17475
17929
|
const userMessage = {
|
|
17476
|
-
id:
|
|
17930
|
+
id: uuidv413(),
|
|
17477
17931
|
role: "user",
|
|
17478
17932
|
content: `$ ${command}`,
|
|
17479
17933
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17480
17934
|
};
|
|
17481
17935
|
const assistantMessage = {
|
|
17482
|
-
id:
|
|
17936
|
+
id: uuidv413(),
|
|
17483
17937
|
role: "assistant",
|
|
17484
17938
|
content: isError ? `\u274C Error:
|
|
17485
17939
|
${output}` : output.trim() || "(no output)",
|
|
@@ -17948,7 +18402,7 @@ Keyboard Shortcuts:
|
|
|
17948
18402
|
console.clear();
|
|
17949
18403
|
const model = state.session?.model || state.config?.defaultModel || "claude-sonnet";
|
|
17950
18404
|
const newSession = {
|
|
17951
|
-
id:
|
|
18405
|
+
id: uuidv413(),
|
|
17952
18406
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
17953
18407
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17954
18408
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -18453,9 +18907,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
18453
18907
|
return { ...prev, config: updatedConfig };
|
|
18454
18908
|
});
|
|
18455
18909
|
if (modelChanged && state.agent) {
|
|
18456
|
-
const
|
|
18457
|
-
if (
|
|
18458
|
-
|
|
18910
|
+
const backend = state.agent.context.llm;
|
|
18911
|
+
if (backend) {
|
|
18912
|
+
backend.currentModel = updatedConfig.defaultModel;
|
|
18459
18913
|
}
|
|
18460
18914
|
}
|
|
18461
18915
|
};
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
findMostSimilarMemento,
|
|
4
4
|
getRelevantMementos
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-NRQSEF3E.js";
|
|
6
|
+
import "./chunk-PIJR5GZP.js";
|
|
7
|
+
import "./chunk-55ZDRTGQ.js";
|
|
8
8
|
import "./chunk-OCYRD7D6.js";
|
|
9
9
|
export {
|
|
10
10
|
findMostSimilarMemento,
|
|
@@ -41,6 +41,12 @@ import {
|
|
|
41
41
|
ChatModels,
|
|
42
42
|
CitableSourceSchema,
|
|
43
43
|
ClaudeArtifactMimeTypes,
|
|
44
|
+
CliCompletionChunkAction,
|
|
45
|
+
CliCompletionDoneAction,
|
|
46
|
+
CliCompletionErrorAction,
|
|
47
|
+
CliCompletionRequestAction,
|
|
48
|
+
CliToolRequestAction,
|
|
49
|
+
CliToolResponseAction,
|
|
44
50
|
CollectionType,
|
|
45
51
|
CompletionApiUsageTransaction,
|
|
46
52
|
CompletionRequestSchema,
|
|
@@ -419,7 +425,7 @@ import {
|
|
|
419
425
|
validateReactArtifactV2,
|
|
420
426
|
validateSvgArtifactV2,
|
|
421
427
|
wikiMarkupToAdf
|
|
422
|
-
} from "./chunk-
|
|
428
|
+
} from "./chunk-55ZDRTGQ.js";
|
|
423
429
|
export {
|
|
424
430
|
ALL_IMAGE_MODELS,
|
|
425
431
|
ALL_IMAGE_SIZES,
|
|
@@ -463,6 +469,12 @@ export {
|
|
|
463
469
|
ChatModels,
|
|
464
470
|
CitableSourceSchema,
|
|
465
471
|
ClaudeArtifactMimeTypes,
|
|
472
|
+
CliCompletionChunkAction,
|
|
473
|
+
CliCompletionDoneAction,
|
|
474
|
+
CliCompletionErrorAction,
|
|
475
|
+
CliCompletionRequestAction,
|
|
476
|
+
CliToolRequestAction,
|
|
477
|
+
CliToolResponseAction,
|
|
466
478
|
CollectionType,
|
|
467
479
|
CompletionApiUsageTransaction,
|
|
468
480
|
CompletionRequestSchema,
|
|
@@ -134,12 +134,12 @@ import {
|
|
|
134
134
|
validateMermaidSyntax,
|
|
135
135
|
warmUpSettingsCache,
|
|
136
136
|
withRetry
|
|
137
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-PIJR5GZP.js";
|
|
138
138
|
import {
|
|
139
139
|
buildRateLimitLogEntry,
|
|
140
140
|
isNearLimit,
|
|
141
141
|
parseRateLimitHeaders
|
|
142
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-55ZDRTGQ.js";
|
|
143
143
|
import {
|
|
144
144
|
Logger,
|
|
145
145
|
NotificationDeduplicator,
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
SubtractCreditsSchema,
|
|
4
4
|
subtractCredits
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-EAFOBAEJ.js";
|
|
6
|
+
import "./chunk-PIJR5GZP.js";
|
|
7
|
+
import "./chunk-55ZDRTGQ.js";
|
|
8
8
|
import "./chunk-OCYRD7D6.js";
|
|
9
9
|
export {
|
|
10
10
|
SubtractCreditsSchema,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.2.30-feat-cli-
|
|
3
|
+
"version": "0.2.30-feat-cli-websocket-streaming.19209+64d4459aa",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -111,10 +111,10 @@
|
|
|
111
111
|
},
|
|
112
112
|
"devDependencies": {
|
|
113
113
|
"@bike4mind/agents": "0.1.0",
|
|
114
|
-
"@bike4mind/common": "2.51.1-feat-cli-
|
|
115
|
-
"@bike4mind/mcp": "1.30.1-feat-cli-
|
|
116
|
-
"@bike4mind/services": "2.49.1-feat-cli-
|
|
117
|
-
"@bike4mind/utils": "2.6.1-feat-cli-
|
|
114
|
+
"@bike4mind/common": "2.51.1-feat-cli-websocket-streaming.19209+64d4459aa",
|
|
115
|
+
"@bike4mind/mcp": "1.30.1-feat-cli-websocket-streaming.19209+64d4459aa",
|
|
116
|
+
"@bike4mind/services": "2.49.1-feat-cli-websocket-streaming.19209+64d4459aa",
|
|
117
|
+
"@bike4mind/utils": "2.6.1-feat-cli-websocket-streaming.19209+64d4459aa",
|
|
118
118
|
"@types/better-sqlite3": "^7.6.13",
|
|
119
119
|
"@types/diff": "^5.0.9",
|
|
120
120
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -135,5 +135,5 @@
|
|
|
135
135
|
"optionalDependencies": {
|
|
136
136
|
"@vscode/ripgrep": "^1.17.0"
|
|
137
137
|
},
|
|
138
|
-
"gitHead": "
|
|
138
|
+
"gitHead": "64d4459aaf9c9ba124dac6513d470113295bd1d1"
|
|
139
139
|
}
|