@bike4mind/cli 0.2.29-feat-session-permission.18877 → 0.2.29-feat-cli-websocket-streaming.18879
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-EE753J4D.js → artifactExtractor-SNWW3EVH.js} +1 -1
- package/dist/{chunk-PKKJ44C5.js → chunk-BXCARBUQ.js} +2 -2
- package/dist/{chunk-ELTTBWAQ.js → chunk-EC2VEDD2.js} +2 -2
- package/dist/{chunk-5GSDPBTM.js → chunk-KPOK6V6E.js} +67 -2
- package/dist/{chunk-BCOGDPUB.js → chunk-QQL3OBKL.js} +2 -2
- package/dist/{chunk-S7BPPS33.js → chunk-TY6Z2UV2.js} +1 -1
- package/dist/{create-O3PVSKFE.js → create-QOJPAIOR.js} +3 -3
- package/dist/index.js +489 -67
- package/dist/{llmMarkdownGenerator-IJKJYJ3U.js → llmMarkdownGenerator-JPDNDGE4.js} +1 -1
- package/dist/{markdownGenerator-SJT7AXLT.js → markdownGenerator-NHN4MNEA.js} +1 -1
- package/dist/{mementoService-PKCNMN4V.js → mementoService-EN7FZK7B.js} +3 -3
- package/dist/{src-GRO5NIC3.js → src-36AL3BJR.js} +13 -1
- package/dist/{src-C5CZFXVM.js → src-JZN5O6F3.js} +2 -2
- package/dist/{subtractCredits-WZZAP57N.js → subtractCredits-FCBMFPIP.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-KPOK6V6E.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;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
BadRequestError,
|
|
4
4
|
secureParameters
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-TY6Z2UV2.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-KPOK6V6E.js";
|
|
16
16
|
|
|
17
17
|
// ../../b4m-core/packages/services/dist/src/creditService/subtractCredits.js
|
|
18
18
|
import { z } from "zod";
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
getSettingsMap,
|
|
8
8
|
getSettingsValue,
|
|
9
9
|
secureParameters
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-TY6Z2UV2.js";
|
|
11
11
|
import {
|
|
12
12
|
KnowledgeType,
|
|
13
13
|
SupportedFabFileMimeTypes
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-KPOK6V6E.js";
|
|
15
15
|
|
|
16
16
|
// ../../b4m-core/packages/services/dist/src/fabFileService/create.js
|
|
17
17
|
import { z } from "zod";
|
|
@@ -1012,6 +1012,29 @@ var VoiceSessionSendTranscriptAction = z10.object({
|
|
|
1012
1012
|
conversationItemId: z10.string(),
|
|
1013
1013
|
timestamp: z10.coerce.date().optional()
|
|
1014
1014
|
});
|
|
1015
|
+
var CliCompletionRequestAction = z10.object({
|
|
1016
|
+
action: z10.literal("cli_completion_request"),
|
|
1017
|
+
accessToken: z10.string(),
|
|
1018
|
+
requestId: z10.string().uuid(),
|
|
1019
|
+
model: z10.string(),
|
|
1020
|
+
messages: z10.array(z10.object({
|
|
1021
|
+
role: z10.enum(["user", "assistant", "system"]),
|
|
1022
|
+
content: z10.union([z10.string(), z10.array(z10.unknown())])
|
|
1023
|
+
})),
|
|
1024
|
+
options: z10.object({
|
|
1025
|
+
temperature: z10.number().optional(),
|
|
1026
|
+
maxTokens: z10.number().optional(),
|
|
1027
|
+
stream: z10.boolean().optional(),
|
|
1028
|
+
tools: z10.array(z10.unknown()).optional()
|
|
1029
|
+
}).optional()
|
|
1030
|
+
});
|
|
1031
|
+
var CliToolRequestAction = z10.object({
|
|
1032
|
+
action: z10.literal("cli_tool_request"),
|
|
1033
|
+
accessToken: z10.string(),
|
|
1034
|
+
requestId: z10.string().uuid(),
|
|
1035
|
+
toolName: z10.string(),
|
|
1036
|
+
input: z10.record(z10.unknown())
|
|
1037
|
+
});
|
|
1015
1038
|
var VoiceSessionEndedAction = z10.object({
|
|
1016
1039
|
action: z10.literal("voice_session_ended"),
|
|
1017
1040
|
userId: z10.string(),
|
|
@@ -1258,6 +1281,36 @@ var ResearchModeStreamAction = z10.object({
|
|
|
1258
1281
|
completionInfo: z10.any().optional()
|
|
1259
1282
|
}).optional()
|
|
1260
1283
|
});
|
|
1284
|
+
var CliCompletionChunkAction = z10.object({
|
|
1285
|
+
action: z10.literal("cli_completion_chunk"),
|
|
1286
|
+
requestId: z10.string(),
|
|
1287
|
+
chunk: z10.object({
|
|
1288
|
+
type: z10.enum(["content", "tool_use"]),
|
|
1289
|
+
text: z10.string(),
|
|
1290
|
+
tools: z10.array(z10.unknown()).optional(),
|
|
1291
|
+
usage: z10.object({
|
|
1292
|
+
inputTokens: z10.number().optional(),
|
|
1293
|
+
outputTokens: z10.number().optional()
|
|
1294
|
+
}).optional(),
|
|
1295
|
+
thinking: z10.array(z10.unknown()).optional()
|
|
1296
|
+
})
|
|
1297
|
+
});
|
|
1298
|
+
var CliCompletionDoneAction = z10.object({
|
|
1299
|
+
action: z10.literal("cli_completion_done"),
|
|
1300
|
+
requestId: z10.string()
|
|
1301
|
+
});
|
|
1302
|
+
var CliCompletionErrorAction = z10.object({
|
|
1303
|
+
action: z10.literal("cli_completion_error"),
|
|
1304
|
+
requestId: z10.string(),
|
|
1305
|
+
error: z10.string()
|
|
1306
|
+
});
|
|
1307
|
+
var CliToolResponseAction = z10.object({
|
|
1308
|
+
action: z10.literal("cli_tool_response"),
|
|
1309
|
+
requestId: z10.string(),
|
|
1310
|
+
success: z10.boolean(),
|
|
1311
|
+
content: z10.unknown().optional(),
|
|
1312
|
+
error: z10.string().optional()
|
|
1313
|
+
});
|
|
1261
1314
|
var SessionCreatedAction = shareableDocumentSchema.extend({
|
|
1262
1315
|
action: z10.literal("session.created"),
|
|
1263
1316
|
id: z10.string(),
|
|
@@ -1292,7 +1345,9 @@ var MessageDataToServer = z10.discriminatedUnion("action", [
|
|
|
1292
1345
|
DataUnsubscribeRequestAction,
|
|
1293
1346
|
HeartbeatAction,
|
|
1294
1347
|
VoiceSessionSendTranscriptAction,
|
|
1295
|
-
VoiceSessionEndedAction
|
|
1348
|
+
VoiceSessionEndedAction,
|
|
1349
|
+
CliCompletionRequestAction,
|
|
1350
|
+
CliToolRequestAction
|
|
1296
1351
|
]);
|
|
1297
1352
|
var MessageDataToClient = z10.discriminatedUnion("action", [
|
|
1298
1353
|
DataSubscriptionUpdateAction,
|
|
@@ -1314,7 +1369,11 @@ var MessageDataToClient = z10.discriminatedUnion("action", [
|
|
|
1314
1369
|
SpiderProgressUpdateAction,
|
|
1315
1370
|
SpiderCompleteAction,
|
|
1316
1371
|
SpiderErrorAction,
|
|
1317
|
-
SessionCreatedAction
|
|
1372
|
+
SessionCreatedAction,
|
|
1373
|
+
CliCompletionChunkAction,
|
|
1374
|
+
CliCompletionDoneAction,
|
|
1375
|
+
CliCompletionErrorAction,
|
|
1376
|
+
CliToolResponseAction
|
|
1318
1377
|
]);
|
|
1319
1378
|
|
|
1320
1379
|
// ../../b4m-core/packages/common/dist/src/schemas/cliCompletions.js
|
|
@@ -7926,6 +7985,8 @@ export {
|
|
|
7926
7985
|
DataUnsubscribeRequestAction,
|
|
7927
7986
|
HeartbeatAction,
|
|
7928
7987
|
VoiceSessionSendTranscriptAction,
|
|
7988
|
+
CliCompletionRequestAction,
|
|
7989
|
+
CliToolRequestAction,
|
|
7929
7990
|
VoiceSessionEndedAction,
|
|
7930
7991
|
DataSubscriptionUpdateAction,
|
|
7931
7992
|
LLMStatusUpdateAction,
|
|
@@ -7946,6 +8007,10 @@ export {
|
|
|
7946
8007
|
UpdateResearchTaskStatusAction,
|
|
7947
8008
|
ImportHistoryJobProgressUpdateAction,
|
|
7948
8009
|
ResearchModeStreamAction,
|
|
8010
|
+
CliCompletionChunkAction,
|
|
8011
|
+
CliCompletionDoneAction,
|
|
8012
|
+
CliCompletionErrorAction,
|
|
8013
|
+
CliToolResponseAction,
|
|
7949
8014
|
SessionCreatedAction,
|
|
7950
8015
|
MessageDataToServer,
|
|
7951
8016
|
MessageDataToClient,
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
getSettingsByNames,
|
|
7
7
|
obfuscateApiKey,
|
|
8
8
|
secureParameters
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-TY6Z2UV2.js";
|
|
10
10
|
import {
|
|
11
11
|
ApiKeyType,
|
|
12
12
|
MementoTier,
|
|
13
13
|
isSupportedEmbeddingModel
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-KPOK6V6E.js";
|
|
15
15
|
|
|
16
16
|
// ../../b4m-core/packages/services/dist/src/apiKeyService/get.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-EC2VEDD2.js";
|
|
6
|
+
import "./chunk-TY6Z2UV2.js";
|
|
7
|
+
import "./chunk-KPOK6V6E.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-QQL3OBKL.js";
|
|
9
9
|
import {
|
|
10
10
|
ConfigStore,
|
|
11
11
|
logger
|
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
selectActiveBackgroundAgents,
|
|
15
15
|
useCliStore
|
|
16
16
|
} from "./chunk-TVW4ZESU.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-BXCARBUQ.js";
|
|
18
|
+
import "./chunk-EC2VEDD2.js";
|
|
19
19
|
import {
|
|
20
20
|
BFLImageService,
|
|
21
21
|
BaseStorage,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
OpenAIBackend,
|
|
28
28
|
OpenAIImageService,
|
|
29
29
|
XAIImageService
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-TY6Z2UV2.js";
|
|
31
31
|
import {
|
|
32
32
|
AiEvents,
|
|
33
33
|
ApiKeyEvents,
|
|
@@ -83,7 +83,7 @@ import {
|
|
|
83
83
|
XAI_IMAGE_MODELS,
|
|
84
84
|
b4mLLMTools,
|
|
85
85
|
getMcpProviderMetadata
|
|
86
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-KPOK6V6E.js";
|
|
87
87
|
import {
|
|
88
88
|
Logger
|
|
89
89
|
} from "./chunk-OCYRD7D6.js";
|
|
@@ -93,7 +93,7 @@ import React21, { useState as useState9, useEffect as useEffect6, useCallback as
|
|
|
93
93
|
import { render, Box as Box20, Text as Text20, useApp, useInput as useInput9 } from "ink";
|
|
94
94
|
import { execSync } from "child_process";
|
|
95
95
|
import { randomBytes as randomBytes5 } from "crypto";
|
|
96
|
-
import { v4 as
|
|
96
|
+
import { v4 as uuidv413 } from "uuid";
|
|
97
97
|
|
|
98
98
|
// src/components/App.tsx
|
|
99
99
|
import React15, { useState as useState5, useEffect as useEffect4 } from "react";
|
|
@@ -1260,12 +1260,10 @@ function PermissionPrompt({
|
|
|
1260
1260
|
}) {
|
|
1261
1261
|
const items = canBeTrusted ? [
|
|
1262
1262
|
{ label: "\u2713 Allow once", value: "allow-once" },
|
|
1263
|
-
{ label: "\u2713 Allow for this session", value: "allow-session" },
|
|
1264
1263
|
{ label: "\u2713 Always allow (trust this tool)", value: "allow-always" },
|
|
1265
1264
|
{ label: "\u2717 Deny", value: "deny" }
|
|
1266
1265
|
] : [
|
|
1267
1266
|
{ label: "\u2713 Allow once", value: "allow-once" },
|
|
1268
|
-
{ label: "\u2713 Allow for this session", value: "allow-session" },
|
|
1269
1267
|
{ label: "\u2717 Deny", value: "deny" }
|
|
1270
1268
|
];
|
|
1271
1269
|
const [selectedIndex, setSelectedIndex] = useState3(0);
|
|
@@ -11511,6 +11509,10 @@ var ServerToolExecutor = class {
|
|
|
11511
11509
|
};
|
|
11512
11510
|
|
|
11513
11511
|
// src/llm/ToolRouter.ts
|
|
11512
|
+
var wsToolExecutor = null;
|
|
11513
|
+
function setWebSocketToolExecutor(executor) {
|
|
11514
|
+
wsToolExecutor = executor;
|
|
11515
|
+
}
|
|
11514
11516
|
var SERVER_TOOLS = ["weather_info", "web_search", "web_fetch"];
|
|
11515
11517
|
var LOCAL_TOOLS = [
|
|
11516
11518
|
"file_read",
|
|
@@ -11533,7 +11535,15 @@ function isLocalTool(toolName) {
|
|
|
11533
11535
|
}
|
|
11534
11536
|
async function executeTool(toolName, input, apiClient, localToolFn) {
|
|
11535
11537
|
if (isServerTool(toolName)) {
|
|
11536
|
-
|
|
11538
|
+
if (wsToolExecutor) {
|
|
11539
|
+
logger.debug(`[ToolRouter] Routing ${toolName} to server via WebSocket`);
|
|
11540
|
+
const result = await wsToolExecutor.execute(toolName, input);
|
|
11541
|
+
if (!result.success) {
|
|
11542
|
+
return `Error executing ${toolName}: ${result.error || "Tool execution failed"}`;
|
|
11543
|
+
}
|
|
11544
|
+
return typeof result.content === "string" ? result.content : JSON.stringify(result.content ?? "");
|
|
11545
|
+
}
|
|
11546
|
+
logger.debug(`[ToolRouter] Routing ${toolName} to server via HTTP`);
|
|
11537
11547
|
const executor = new ServerToolExecutor(apiClient);
|
|
11538
11548
|
return await executor.executeTool(toolName, input);
|
|
11539
11549
|
} else if (isLocalTool(toolName)) {
|
|
@@ -11837,9 +11847,6 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
11837
11847
|
if (response.action === "deny") {
|
|
11838
11848
|
throw new PermissionDeniedError(toolName, args);
|
|
11839
11849
|
}
|
|
11840
|
-
if (response.action === "allow-session") {
|
|
11841
|
-
permissionManager.trustToolForSession(toolName);
|
|
11842
|
-
}
|
|
11843
11850
|
if (response.action === "allow-always") {
|
|
11844
11851
|
const canTrust = permissionManager.trustTool(toolName);
|
|
11845
11852
|
if (canTrust) {
|
|
@@ -12044,7 +12051,6 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
12044
12051
|
var PermissionManager = class {
|
|
12045
12052
|
constructor(trustedTools = [], customCategories, deniedTools) {
|
|
12046
12053
|
this.trustedTools = /* @__PURE__ */ new Set();
|
|
12047
|
-
this.sessionTrustedTools = /* @__PURE__ */ new Set();
|
|
12048
12054
|
this.deniedTools = /* @__PURE__ */ new Set();
|
|
12049
12055
|
this.trustedTools = new Set(trustedTools);
|
|
12050
12056
|
this.customCategories = new Map(Object.entries(customCategories || {}));
|
|
@@ -12070,9 +12076,6 @@ var PermissionManager = class {
|
|
|
12070
12076
|
if (category === "auto_approve") {
|
|
12071
12077
|
return false;
|
|
12072
12078
|
}
|
|
12073
|
-
if (this.sessionTrustedTools.has(toolName)) {
|
|
12074
|
-
return false;
|
|
12075
|
-
}
|
|
12076
12079
|
if (category === "prompt_always") {
|
|
12077
12080
|
return true;
|
|
12078
12081
|
}
|
|
@@ -12140,29 +12143,6 @@ var PermissionManager = class {
|
|
|
12140
12143
|
getDeniedTools() {
|
|
12141
12144
|
return Array.from(this.deniedTools).sort();
|
|
12142
12145
|
}
|
|
12143
|
-
/**
|
|
12144
|
-
* Trust a tool for the current session only (in-memory, no persistence)
|
|
12145
|
-
* Works for all tool categories including prompt_always, but NOT project-denied tools
|
|
12146
|
-
*/
|
|
12147
|
-
trustToolForSession(toolName) {
|
|
12148
|
-
if (this.deniedTools.has(toolName)) {
|
|
12149
|
-
return false;
|
|
12150
|
-
}
|
|
12151
|
-
this.sessionTrustedTools.add(toolName);
|
|
12152
|
-
return true;
|
|
12153
|
-
}
|
|
12154
|
-
/**
|
|
12155
|
-
* Check if a tool is trusted for the current session
|
|
12156
|
-
*/
|
|
12157
|
-
isSessionTrusted(toolName) {
|
|
12158
|
-
return this.sessionTrustedTools.has(toolName);
|
|
12159
|
-
}
|
|
12160
|
-
/**
|
|
12161
|
-
* Clear all session-scoped trust (called on exit or session reset)
|
|
12162
|
-
*/
|
|
12163
|
-
clearSessionTrust() {
|
|
12164
|
-
this.sessionTrustedTools.clear();
|
|
12165
|
-
}
|
|
12166
12146
|
/**
|
|
12167
12147
|
* Clear all trusted tools
|
|
12168
12148
|
*/
|
|
@@ -13493,6 +13473,174 @@ var ServerLlmBackend = class {
|
|
|
13493
13473
|
}
|
|
13494
13474
|
};
|
|
13495
13475
|
|
|
13476
|
+
// src/llm/WebSocketLlmBackend.ts
|
|
13477
|
+
import { v4 as uuidv411 } from "uuid";
|
|
13478
|
+
function stripThinkingBlocks2(text) {
|
|
13479
|
+
return text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
13480
|
+
}
|
|
13481
|
+
var WebSocketLlmBackend = class {
|
|
13482
|
+
constructor(options) {
|
|
13483
|
+
this.wsManager = options.wsManager;
|
|
13484
|
+
this.apiClient = options.apiClient;
|
|
13485
|
+
this.currentModel = options.model;
|
|
13486
|
+
this.tokenGetter = options.tokenGetter;
|
|
13487
|
+
}
|
|
13488
|
+
/**
|
|
13489
|
+
* Make LLM completion request via WebSocket.
|
|
13490
|
+
* Collects all streamed chunks, then calls callback once at completion
|
|
13491
|
+
* with the full accumulated content.
|
|
13492
|
+
*/
|
|
13493
|
+
async complete(model, messages, options, callback) {
|
|
13494
|
+
logger.debug(`[WebSocketLlmBackend] Starting complete() with model: ${model}`);
|
|
13495
|
+
if (options.abortSignal?.aborted) {
|
|
13496
|
+
logger.debug("[WebSocketLlmBackend] Request aborted before start");
|
|
13497
|
+
return;
|
|
13498
|
+
}
|
|
13499
|
+
if (!this.wsManager.isConnected) {
|
|
13500
|
+
throw new Error("WebSocket is not connected");
|
|
13501
|
+
}
|
|
13502
|
+
const requestId = uuidv411();
|
|
13503
|
+
const token = await this.tokenGetter();
|
|
13504
|
+
if (!token) {
|
|
13505
|
+
throw new Error("No access token available");
|
|
13506
|
+
}
|
|
13507
|
+
return new Promise((resolve3, reject) => {
|
|
13508
|
+
const isVerbose = process.env.B4M_VERBOSE === "1";
|
|
13509
|
+
const isUltraVerbose = process.env.B4M_DEBUG_STREAM === "1";
|
|
13510
|
+
const streamLogger = new StreamLogger(logger, "WebSocketLlmBackend", isVerbose, isUltraVerbose);
|
|
13511
|
+
streamLogger.streamStart();
|
|
13512
|
+
let eventCount = 0;
|
|
13513
|
+
let accumulatedText = "";
|
|
13514
|
+
let lastUsageInfo = {};
|
|
13515
|
+
let toolsUsed = [];
|
|
13516
|
+
let thinkingBlocks = [];
|
|
13517
|
+
let settled = false;
|
|
13518
|
+
const settle = (action) => {
|
|
13519
|
+
if (settled) return;
|
|
13520
|
+
settled = true;
|
|
13521
|
+
this.wsManager.offRequest(requestId);
|
|
13522
|
+
this.wsManager.offDisconnect(onDisconnect);
|
|
13523
|
+
action();
|
|
13524
|
+
};
|
|
13525
|
+
const settleResolve = () => settle(() => resolve3());
|
|
13526
|
+
const settleReject = (err) => settle(() => reject(err));
|
|
13527
|
+
const onDisconnect = () => {
|
|
13528
|
+
logger.debug("[WebSocketLlmBackend] Connection dropped during completion");
|
|
13529
|
+
settleReject(new Error("WebSocket connection lost during completion"));
|
|
13530
|
+
};
|
|
13531
|
+
this.wsManager.onDisconnect(onDisconnect);
|
|
13532
|
+
if (options.abortSignal) {
|
|
13533
|
+
if (options.abortSignal.aborted) {
|
|
13534
|
+
settleResolve();
|
|
13535
|
+
return;
|
|
13536
|
+
}
|
|
13537
|
+
options.abortSignal.addEventListener(
|
|
13538
|
+
"abort",
|
|
13539
|
+
() => {
|
|
13540
|
+
logger.debug("[WebSocketLlmBackend] Abort signal received");
|
|
13541
|
+
settleResolve();
|
|
13542
|
+
},
|
|
13543
|
+
{ once: true }
|
|
13544
|
+
);
|
|
13545
|
+
}
|
|
13546
|
+
const updateUsage = (usage) => {
|
|
13547
|
+
if (usage) {
|
|
13548
|
+
lastUsageInfo = { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens };
|
|
13549
|
+
}
|
|
13550
|
+
};
|
|
13551
|
+
this.wsManager.onRequest(requestId, (message) => {
|
|
13552
|
+
if (options.abortSignal?.aborted) return;
|
|
13553
|
+
const action = message.action;
|
|
13554
|
+
if (action === "cli_completion_chunk") {
|
|
13555
|
+
eventCount++;
|
|
13556
|
+
const chunk = message.chunk;
|
|
13557
|
+
streamLogger.onEvent(eventCount, JSON.stringify(chunk));
|
|
13558
|
+
const textChunk = chunk.text || "";
|
|
13559
|
+
if (textChunk) accumulatedText += textChunk;
|
|
13560
|
+
updateUsage(chunk.usage);
|
|
13561
|
+
if (chunk.type === "content") {
|
|
13562
|
+
streamLogger.onContent(eventCount, textChunk, accumulatedText);
|
|
13563
|
+
} else if (chunk.type === "tool_use") {
|
|
13564
|
+
streamLogger.onCriticalEvent(eventCount, "TOOL_USE", `tools: ${chunk.tools?.length}`);
|
|
13565
|
+
if (chunk.tools && chunk.tools.length > 0) toolsUsed = chunk.tools;
|
|
13566
|
+
if (chunk.thinking && chunk.thinking.length > 0) thinkingBlocks = chunk.thinking;
|
|
13567
|
+
}
|
|
13568
|
+
} else if (action === "cli_completion_done") {
|
|
13569
|
+
streamLogger.streamComplete(accumulatedText);
|
|
13570
|
+
const cleanedText = stripThinkingBlocks2(accumulatedText);
|
|
13571
|
+
if (!cleanedText && toolsUsed.length === 0) {
|
|
13572
|
+
settleResolve();
|
|
13573
|
+
return;
|
|
13574
|
+
}
|
|
13575
|
+
const info = {
|
|
13576
|
+
...lastUsageInfo,
|
|
13577
|
+
...toolsUsed.length > 0 && { toolsUsed },
|
|
13578
|
+
...thinkingBlocks.length > 0 && { thinking: thinkingBlocks }
|
|
13579
|
+
};
|
|
13580
|
+
callback([cleanedText], info).then(() => settleResolve()).catch((err) => settleReject(err));
|
|
13581
|
+
} else if (action === "cli_completion_error") {
|
|
13582
|
+
const errorMsg = message.error || "Server error";
|
|
13583
|
+
streamLogger.onCriticalEvent(eventCount, "ERROR", errorMsg);
|
|
13584
|
+
settleReject(new Error(errorMsg));
|
|
13585
|
+
}
|
|
13586
|
+
});
|
|
13587
|
+
try {
|
|
13588
|
+
this.wsManager.send({
|
|
13589
|
+
action: "cli_completion_request",
|
|
13590
|
+
accessToken: token,
|
|
13591
|
+
requestId,
|
|
13592
|
+
model,
|
|
13593
|
+
messages,
|
|
13594
|
+
options: {
|
|
13595
|
+
temperature: options.temperature,
|
|
13596
|
+
maxTokens: options.maxTokens,
|
|
13597
|
+
stream: true,
|
|
13598
|
+
tools: options.tools || []
|
|
13599
|
+
}
|
|
13600
|
+
});
|
|
13601
|
+
} catch (err) {
|
|
13602
|
+
settleReject(err instanceof Error ? err : new Error(String(err)));
|
|
13603
|
+
}
|
|
13604
|
+
});
|
|
13605
|
+
}
|
|
13606
|
+
/**
|
|
13607
|
+
* Get available models from server (REST call, not streaming).
|
|
13608
|
+
* Delegates to ApiClient -- same as ServerLlmBackend.
|
|
13609
|
+
*/
|
|
13610
|
+
async getModelInfo() {
|
|
13611
|
+
try {
|
|
13612
|
+
logger.debug("[WebSocketLlmBackend] Fetching models from /api/models");
|
|
13613
|
+
const response = await this.apiClient.get("/api/models");
|
|
13614
|
+
if (!response || typeof response !== "object" || !Array.isArray(response.models)) {
|
|
13615
|
+
logger.warn("[WebSocketLlmBackend] Invalid API response format, using fallback models");
|
|
13616
|
+
return this.getFallbackModels();
|
|
13617
|
+
}
|
|
13618
|
+
const filteredModels = response.models.filter(
|
|
13619
|
+
(model) => model.type === "text" && model.supportsTools === true
|
|
13620
|
+
);
|
|
13621
|
+
if (filteredModels.length === 0) {
|
|
13622
|
+
logger.warn("[WebSocketLlmBackend] No CLI-compatible models found, using fallback");
|
|
13623
|
+
return this.getFallbackModels();
|
|
13624
|
+
}
|
|
13625
|
+
logger.debug(`[WebSocketLlmBackend] Loaded ${filteredModels.length} models`);
|
|
13626
|
+
return filteredModels;
|
|
13627
|
+
} catch (error) {
|
|
13628
|
+
logger.warn(
|
|
13629
|
+
`[WebSocketLlmBackend] Failed to fetch models: ${error instanceof Error ? error.message : String(error)}`
|
|
13630
|
+
);
|
|
13631
|
+
return this.getFallbackModels();
|
|
13632
|
+
}
|
|
13633
|
+
}
|
|
13634
|
+
getFallbackModels() {
|
|
13635
|
+
return [
|
|
13636
|
+
{ id: "claude-sonnet-4-5-20250929", name: "Claude 4.5 Sonnet" },
|
|
13637
|
+
{ id: "claude-3-5-haiku-20241022", name: "Claude 3.5 Haiku" },
|
|
13638
|
+
{ id: "gpt-4o", name: "GPT-4o" },
|
|
13639
|
+
{ id: "gpt-4o-mini", name: "GPT-4o Mini" }
|
|
13640
|
+
];
|
|
13641
|
+
}
|
|
13642
|
+
};
|
|
13643
|
+
|
|
13496
13644
|
// src/llm/NotifyingLlmBackend.ts
|
|
13497
13645
|
var NotifyingLlmBackend = class {
|
|
13498
13646
|
constructor(inner, backgroundManager) {
|
|
@@ -13527,6 +13675,242 @@ Please acknowledge these background agent results and incorporate them into your
|
|
|
13527
13675
|
}
|
|
13528
13676
|
};
|
|
13529
13677
|
|
|
13678
|
+
// src/ws/WebSocketConnectionManager.ts
|
|
13679
|
+
var WebSocketConnectionManager = class {
|
|
13680
|
+
constructor(wsUrl, getToken) {
|
|
13681
|
+
this.ws = null;
|
|
13682
|
+
this.heartbeatInterval = null;
|
|
13683
|
+
this.reconnectAttempts = 0;
|
|
13684
|
+
this.maxReconnectDelay = 3e4;
|
|
13685
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
13686
|
+
this.disconnectHandlers = /* @__PURE__ */ new Set();
|
|
13687
|
+
this.connected = false;
|
|
13688
|
+
this.connecting = false;
|
|
13689
|
+
this.closed = false;
|
|
13690
|
+
this.wsUrl = wsUrl;
|
|
13691
|
+
this.getToken = getToken;
|
|
13692
|
+
}
|
|
13693
|
+
/**
|
|
13694
|
+
* Connect to the WebSocket server.
|
|
13695
|
+
* Resolves when connection is established, rejects on failure.
|
|
13696
|
+
*/
|
|
13697
|
+
async connect() {
|
|
13698
|
+
if (this.connected || this.connecting) return;
|
|
13699
|
+
this.connecting = true;
|
|
13700
|
+
const token = await this.getToken();
|
|
13701
|
+
if (!token) {
|
|
13702
|
+
this.connecting = false;
|
|
13703
|
+
throw new Error("No access token available for WebSocket connection");
|
|
13704
|
+
}
|
|
13705
|
+
return new Promise((resolve3, reject) => {
|
|
13706
|
+
const url = `${this.wsUrl}?token=${token}`;
|
|
13707
|
+
logger.debug(`[WS] Connecting to ${this.wsUrl}...`);
|
|
13708
|
+
this.ws = new WebSocket(url);
|
|
13709
|
+
this.ws.onopen = () => {
|
|
13710
|
+
logger.debug("[WS] Connected");
|
|
13711
|
+
this.connected = true;
|
|
13712
|
+
this.connecting = false;
|
|
13713
|
+
this.reconnectAttempts = 0;
|
|
13714
|
+
this.startHeartbeat();
|
|
13715
|
+
resolve3();
|
|
13716
|
+
};
|
|
13717
|
+
this.ws.onmessage = (event) => {
|
|
13718
|
+
try {
|
|
13719
|
+
const data = typeof event.data === "string" ? event.data : event.data.toString();
|
|
13720
|
+
const message = JSON.parse(data);
|
|
13721
|
+
const requestId = message.requestId;
|
|
13722
|
+
if (requestId && this.handlers.has(requestId)) {
|
|
13723
|
+
this.handlers.get(requestId)(message);
|
|
13724
|
+
} else {
|
|
13725
|
+
logger.debug(`[WS] Unhandled message: ${message.action || "unknown"}`);
|
|
13726
|
+
}
|
|
13727
|
+
} catch (err) {
|
|
13728
|
+
logger.debug(`[WS] Failed to parse message: ${err}`);
|
|
13729
|
+
}
|
|
13730
|
+
};
|
|
13731
|
+
this.ws.onclose = () => {
|
|
13732
|
+
logger.debug("[WS] Connection closed");
|
|
13733
|
+
this.cleanup();
|
|
13734
|
+
this.notifyDisconnect();
|
|
13735
|
+
if (!this.closed) {
|
|
13736
|
+
this.scheduleReconnect();
|
|
13737
|
+
}
|
|
13738
|
+
};
|
|
13739
|
+
this.ws.onerror = (err) => {
|
|
13740
|
+
logger.debug(`[WS] Error: ${err}`);
|
|
13741
|
+
if (this.connecting) {
|
|
13742
|
+
this.connecting = false;
|
|
13743
|
+
this.connected = false;
|
|
13744
|
+
reject(new Error("WebSocket connection failed"));
|
|
13745
|
+
}
|
|
13746
|
+
};
|
|
13747
|
+
});
|
|
13748
|
+
}
|
|
13749
|
+
/** Whether the connection is currently established */
|
|
13750
|
+
get isConnected() {
|
|
13751
|
+
return this.connected;
|
|
13752
|
+
}
|
|
13753
|
+
/**
|
|
13754
|
+
* Send a JSON message over the WebSocket connection.
|
|
13755
|
+
*/
|
|
13756
|
+
send(data) {
|
|
13757
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
13758
|
+
throw new Error("WebSocket is not connected");
|
|
13759
|
+
}
|
|
13760
|
+
this.ws.send(JSON.stringify(data));
|
|
13761
|
+
}
|
|
13762
|
+
/**
|
|
13763
|
+
* Register a handler for messages matching a specific requestId.
|
|
13764
|
+
*/
|
|
13765
|
+
onRequest(requestId, handler) {
|
|
13766
|
+
this.handlers.set(requestId, handler);
|
|
13767
|
+
}
|
|
13768
|
+
/**
|
|
13769
|
+
* Remove a handler for a specific requestId.
|
|
13770
|
+
*/
|
|
13771
|
+
offRequest(requestId) {
|
|
13772
|
+
this.handlers.delete(requestId);
|
|
13773
|
+
}
|
|
13774
|
+
/**
|
|
13775
|
+
* Register a handler that fires when the connection drops.
|
|
13776
|
+
*/
|
|
13777
|
+
onDisconnect(handler) {
|
|
13778
|
+
this.disconnectHandlers.add(handler);
|
|
13779
|
+
}
|
|
13780
|
+
/**
|
|
13781
|
+
* Remove a disconnect handler.
|
|
13782
|
+
*/
|
|
13783
|
+
offDisconnect(handler) {
|
|
13784
|
+
this.disconnectHandlers.delete(handler);
|
|
13785
|
+
}
|
|
13786
|
+
/**
|
|
13787
|
+
* Close the connection and stop all heartbeat/reconnect logic.
|
|
13788
|
+
*/
|
|
13789
|
+
disconnect() {
|
|
13790
|
+
this.closed = true;
|
|
13791
|
+
this.cleanup();
|
|
13792
|
+
if (this.ws) {
|
|
13793
|
+
this.ws.close();
|
|
13794
|
+
this.ws = null;
|
|
13795
|
+
}
|
|
13796
|
+
this.handlers.clear();
|
|
13797
|
+
this.disconnectHandlers.clear();
|
|
13798
|
+
}
|
|
13799
|
+
startHeartbeat() {
|
|
13800
|
+
this.stopHeartbeat();
|
|
13801
|
+
this.heartbeatInterval = setInterval(
|
|
13802
|
+
() => {
|
|
13803
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
13804
|
+
this.ws.send(JSON.stringify({ action: "heartbeat" }));
|
|
13805
|
+
logger.debug("[WS] Heartbeat sent");
|
|
13806
|
+
}
|
|
13807
|
+
},
|
|
13808
|
+
5 * 60 * 1e3
|
|
13809
|
+
);
|
|
13810
|
+
}
|
|
13811
|
+
stopHeartbeat() {
|
|
13812
|
+
if (this.heartbeatInterval) {
|
|
13813
|
+
clearInterval(this.heartbeatInterval);
|
|
13814
|
+
this.heartbeatInterval = null;
|
|
13815
|
+
}
|
|
13816
|
+
}
|
|
13817
|
+
cleanup() {
|
|
13818
|
+
this.connected = false;
|
|
13819
|
+
this.connecting = false;
|
|
13820
|
+
this.stopHeartbeat();
|
|
13821
|
+
}
|
|
13822
|
+
notifyDisconnect() {
|
|
13823
|
+
for (const handler of this.disconnectHandlers) {
|
|
13824
|
+
try {
|
|
13825
|
+
handler();
|
|
13826
|
+
} catch {
|
|
13827
|
+
}
|
|
13828
|
+
}
|
|
13829
|
+
}
|
|
13830
|
+
scheduleReconnect() {
|
|
13831
|
+
if (this.closed) return;
|
|
13832
|
+
this.reconnectAttempts++;
|
|
13833
|
+
const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts - 1), this.maxReconnectDelay);
|
|
13834
|
+
logger.debug(`[WS] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
|
13835
|
+
setTimeout(async () => {
|
|
13836
|
+
if (this.closed) return;
|
|
13837
|
+
try {
|
|
13838
|
+
await this.connect();
|
|
13839
|
+
} catch {
|
|
13840
|
+
logger.debug("[WS] Reconnection failed");
|
|
13841
|
+
}
|
|
13842
|
+
}, delay);
|
|
13843
|
+
}
|
|
13844
|
+
};
|
|
13845
|
+
|
|
13846
|
+
// src/ws/WebSocketToolExecutor.ts
|
|
13847
|
+
import { v4 as uuidv412 } from "uuid";
|
|
13848
|
+
var WebSocketToolExecutor = class {
|
|
13849
|
+
constructor(wsManager, tokenGetter) {
|
|
13850
|
+
this.wsManager = wsManager;
|
|
13851
|
+
this.tokenGetter = tokenGetter;
|
|
13852
|
+
}
|
|
13853
|
+
/**
|
|
13854
|
+
* Execute a server-side tool via WebSocket.
|
|
13855
|
+
* Returns the tool result or throws on error.
|
|
13856
|
+
*/
|
|
13857
|
+
async execute(toolName, input, abortSignal) {
|
|
13858
|
+
if (!this.wsManager.isConnected) {
|
|
13859
|
+
throw new Error("WebSocket is not connected");
|
|
13860
|
+
}
|
|
13861
|
+
const token = await this.tokenGetter();
|
|
13862
|
+
if (!token) {
|
|
13863
|
+
throw new Error("No access token available");
|
|
13864
|
+
}
|
|
13865
|
+
const requestId = uuidv412();
|
|
13866
|
+
return new Promise((resolve3, reject) => {
|
|
13867
|
+
let settled = false;
|
|
13868
|
+
const settle = (action) => {
|
|
13869
|
+
if (settled) return;
|
|
13870
|
+
settled = true;
|
|
13871
|
+
this.wsManager.offRequest(requestId);
|
|
13872
|
+
this.wsManager.offDisconnect(onDisconnect);
|
|
13873
|
+
action();
|
|
13874
|
+
};
|
|
13875
|
+
const settleResolve = (result) => settle(() => resolve3(result));
|
|
13876
|
+
const settleReject = (err) => settle(() => reject(err));
|
|
13877
|
+
const onDisconnect = () => {
|
|
13878
|
+
settleReject(new Error("WebSocket connection lost during tool execution"));
|
|
13879
|
+
};
|
|
13880
|
+
this.wsManager.onDisconnect(onDisconnect);
|
|
13881
|
+
if (abortSignal) {
|
|
13882
|
+
if (abortSignal.aborted) {
|
|
13883
|
+
settleReject(new Error("Tool execution aborted"));
|
|
13884
|
+
return;
|
|
13885
|
+
}
|
|
13886
|
+
abortSignal.addEventListener("abort", () => settleReject(new Error("Tool execution aborted")), {
|
|
13887
|
+
once: true
|
|
13888
|
+
});
|
|
13889
|
+
}
|
|
13890
|
+
this.wsManager.onRequest(requestId, (message) => {
|
|
13891
|
+
if (message.action === "cli_tool_response") {
|
|
13892
|
+
settleResolve({
|
|
13893
|
+
success: message.success,
|
|
13894
|
+
content: message.content,
|
|
13895
|
+
error: message.error
|
|
13896
|
+
});
|
|
13897
|
+
}
|
|
13898
|
+
});
|
|
13899
|
+
try {
|
|
13900
|
+
this.wsManager.send({
|
|
13901
|
+
action: "cli_tool_request",
|
|
13902
|
+
accessToken: token,
|
|
13903
|
+
requestId,
|
|
13904
|
+
toolName,
|
|
13905
|
+
input
|
|
13906
|
+
});
|
|
13907
|
+
} catch (err) {
|
|
13908
|
+
settleReject(err instanceof Error ? err : new Error(String(err)));
|
|
13909
|
+
}
|
|
13910
|
+
});
|
|
13911
|
+
}
|
|
13912
|
+
};
|
|
13913
|
+
|
|
13530
13914
|
// src/auth/ApiClient.ts
|
|
13531
13915
|
import axios11 from "axios";
|
|
13532
13916
|
var ApiClient = class {
|
|
@@ -13664,7 +14048,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
13664
14048
|
// package.json
|
|
13665
14049
|
var package_default = {
|
|
13666
14050
|
name: "@bike4mind/cli",
|
|
13667
|
-
version: "0.2.29-feat-
|
|
14051
|
+
version: "0.2.29-feat-cli-websocket-streaming.18879+058b16fd8",
|
|
13668
14052
|
type: "module",
|
|
13669
14053
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
13670
14054
|
license: "UNLICENSED",
|
|
@@ -13774,10 +14158,10 @@ var package_default = {
|
|
|
13774
14158
|
},
|
|
13775
14159
|
devDependencies: {
|
|
13776
14160
|
"@bike4mind/agents": "0.1.0",
|
|
13777
|
-
"@bike4mind/common": "2.50.1-feat-
|
|
13778
|
-
"@bike4mind/mcp": "1.29.1-feat-
|
|
13779
|
-
"@bike4mind/services": "2.48.1-feat-
|
|
13780
|
-
"@bike4mind/utils": "2.5.1-feat-
|
|
14161
|
+
"@bike4mind/common": "2.50.1-feat-cli-websocket-streaming.18879+058b16fd8",
|
|
14162
|
+
"@bike4mind/mcp": "1.29.1-feat-cli-websocket-streaming.18879+058b16fd8",
|
|
14163
|
+
"@bike4mind/services": "2.48.1-feat-cli-websocket-streaming.18879+058b16fd8",
|
|
14164
|
+
"@bike4mind/utils": "2.5.1-feat-cli-websocket-streaming.18879+058b16fd8",
|
|
13781
14165
|
"@types/better-sqlite3": "^7.6.13",
|
|
13782
14166
|
"@types/diff": "^5.0.9",
|
|
13783
14167
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -13794,7 +14178,7 @@ var package_default = {
|
|
|
13794
14178
|
optionalDependencies: {
|
|
13795
14179
|
"@vscode/ripgrep": "^1.17.0"
|
|
13796
14180
|
},
|
|
13797
|
-
gitHead: "
|
|
14181
|
+
gitHead: "058b16fd85d5311089d30e3d8ccfbe135b3e90c6"
|
|
13798
14182
|
};
|
|
13799
14183
|
|
|
13800
14184
|
// src/config/constants.ts
|
|
@@ -15573,7 +15957,8 @@ function CliApp() {
|
|
|
15573
15957
|
agentStore: null,
|
|
15574
15958
|
abortController: null,
|
|
15575
15959
|
contextContent: "",
|
|
15576
|
-
backgroundManager: null
|
|
15960
|
+
backgroundManager: null,
|
|
15961
|
+
wsManager: null
|
|
15577
15962
|
});
|
|
15578
15963
|
const [isInitialized, setIsInitialized] = useState9(false);
|
|
15579
15964
|
const [initError, setInitError] = useState9(null);
|
|
@@ -15601,6 +15986,10 @@ function CliApp() {
|
|
|
15601
15986
|
})
|
|
15602
15987
|
);
|
|
15603
15988
|
}
|
|
15989
|
+
if (state.wsManager) {
|
|
15990
|
+
state.wsManager.disconnect();
|
|
15991
|
+
setWebSocketToolExecutor(null);
|
|
15992
|
+
}
|
|
15604
15993
|
if (state.agent) {
|
|
15605
15994
|
state.agent.removeAllListeners();
|
|
15606
15995
|
}
|
|
@@ -15619,7 +16008,7 @@ function CliApp() {
|
|
|
15619
16008
|
setTimeout(() => {
|
|
15620
16009
|
process.exit(0);
|
|
15621
16010
|
}, 100);
|
|
15622
|
-
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
|
|
16011
|
+
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore, state.wsManager]);
|
|
15623
16012
|
useInput9((input, key) => {
|
|
15624
16013
|
if (key.escape) {
|
|
15625
16014
|
if (state.abortController) {
|
|
@@ -15689,7 +16078,7 @@ function CliApp() {
|
|
|
15689
16078
|
if (!isAuthenticated) {
|
|
15690
16079
|
console.log("\u2139\uFE0F AI features disabled. Available commands: /login, /help, /config\n");
|
|
15691
16080
|
const minimalSession = {
|
|
15692
|
-
id:
|
|
16081
|
+
id: uuidv413(),
|
|
15693
16082
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
15694
16083
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15695
16084
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15717,10 +16106,41 @@ function CliApp() {
|
|
|
15717
16106
|
console.log(`\u{1F30D} API Environment: ${envName} (${apiBaseURL})`);
|
|
15718
16107
|
}
|
|
15719
16108
|
const apiClient = new ApiClient(apiBaseURL, state.configStore);
|
|
15720
|
-
const
|
|
15721
|
-
|
|
15722
|
-
|
|
15723
|
-
}
|
|
16109
|
+
const tokenGetter = async () => {
|
|
16110
|
+
const tokens = await state.configStore.getAuthTokens();
|
|
16111
|
+
return tokens?.accessToken ?? null;
|
|
16112
|
+
};
|
|
16113
|
+
let wsManager = null;
|
|
16114
|
+
let llm;
|
|
16115
|
+
try {
|
|
16116
|
+
const serverConfig = await apiClient.get("/api/settings/serverConfig");
|
|
16117
|
+
const wsUrl = serverConfig?.websocketUrl;
|
|
16118
|
+
if (wsUrl) {
|
|
16119
|
+
wsManager = new WebSocketConnectionManager(wsUrl, tokenGetter);
|
|
16120
|
+
await wsManager.connect();
|
|
16121
|
+
const wsToolExecutor2 = new WebSocketToolExecutor(wsManager, tokenGetter);
|
|
16122
|
+
setWebSocketToolExecutor(wsToolExecutor2);
|
|
16123
|
+
llm = new WebSocketLlmBackend({
|
|
16124
|
+
wsManager,
|
|
16125
|
+
apiClient,
|
|
16126
|
+
model: config.defaultModel,
|
|
16127
|
+
tokenGetter
|
|
16128
|
+
});
|
|
16129
|
+
logger.debug("\u{1F50C} Using WebSocket transport (bypasses CloudFront timeout)");
|
|
16130
|
+
} else {
|
|
16131
|
+
throw new Error("No websocketUrl in server config");
|
|
16132
|
+
}
|
|
16133
|
+
} catch (wsError) {
|
|
16134
|
+
logger.debug(
|
|
16135
|
+
`[WS] WebSocket unavailable, using SSE fallback: ${wsError instanceof Error ? wsError.message : String(wsError)}`
|
|
16136
|
+
);
|
|
16137
|
+
wsManager = null;
|
|
16138
|
+
setWebSocketToolExecutor(null);
|
|
16139
|
+
llm = new ServerLlmBackend({
|
|
16140
|
+
apiClient,
|
|
16141
|
+
model: config.defaultModel
|
|
16142
|
+
});
|
|
16143
|
+
}
|
|
15724
16144
|
const models = await llm.getModelInfo();
|
|
15725
16145
|
if (models.length === 0) {
|
|
15726
16146
|
throw new Error("No models available from server.");
|
|
@@ -15733,7 +16153,7 @@ function CliApp() {
|
|
|
15733
16153
|
}
|
|
15734
16154
|
llm.currentModel = modelInfo.id;
|
|
15735
16155
|
const newSession = {
|
|
15736
|
-
id:
|
|
16156
|
+
id: uuidv413(),
|
|
15737
16157
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
15738
16158
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15739
16159
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15947,8 +16367,10 @@ function CliApp() {
|
|
|
15947
16367
|
// Store agent store for agent management commands
|
|
15948
16368
|
contextContent: contextResult.mergedContent,
|
|
15949
16369
|
// Store raw context for compact instructions
|
|
15950
|
-
backgroundManager
|
|
16370
|
+
backgroundManager,
|
|
15951
16371
|
// Store for grouped notification turn tracking
|
|
16372
|
+
wsManager
|
|
16373
|
+
// WebSocket connection manager (null if using SSE fallback)
|
|
15952
16374
|
}));
|
|
15953
16375
|
setStoreSession(newSession);
|
|
15954
16376
|
const bannerLines = [
|
|
@@ -16043,13 +16465,13 @@ function CliApp() {
|
|
|
16043
16465
|
messageContent = multimodalMessage.content;
|
|
16044
16466
|
}
|
|
16045
16467
|
const userMessage = {
|
|
16046
|
-
id:
|
|
16468
|
+
id: uuidv413(),
|
|
16047
16469
|
role: "user",
|
|
16048
16470
|
content: userMessageContent,
|
|
16049
16471
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
16050
16472
|
};
|
|
16051
16473
|
const pendingAssistantMessage = {
|
|
16052
|
-
id:
|
|
16474
|
+
id: uuidv413(),
|
|
16053
16475
|
role: "assistant",
|
|
16054
16476
|
content: "...",
|
|
16055
16477
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16260,13 +16682,13 @@ function CliApp() {
|
|
|
16260
16682
|
userMessageContent = message;
|
|
16261
16683
|
}
|
|
16262
16684
|
const userMessage = {
|
|
16263
|
-
id:
|
|
16685
|
+
id: uuidv413(),
|
|
16264
16686
|
role: "user",
|
|
16265
16687
|
content: userMessageContent,
|
|
16266
16688
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
16267
16689
|
};
|
|
16268
16690
|
const pendingAssistantMessage = {
|
|
16269
|
-
id:
|
|
16691
|
+
id: uuidv413(),
|
|
16270
16692
|
role: "assistant",
|
|
16271
16693
|
content: "...",
|
|
16272
16694
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16344,7 +16766,7 @@ function CliApp() {
|
|
|
16344
16766
|
const currentSession = useCliStore.getState().session;
|
|
16345
16767
|
if (currentSession) {
|
|
16346
16768
|
const cancelMessage = {
|
|
16347
|
-
id:
|
|
16769
|
+
id: uuidv413(),
|
|
16348
16770
|
role: "assistant",
|
|
16349
16771
|
content: "\u26A0\uFE0F Operation cancelled by user",
|
|
16350
16772
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16389,7 +16811,7 @@ function CliApp() {
|
|
|
16389
16811
|
setState((prev) => ({ ...prev, abortController }));
|
|
16390
16812
|
try {
|
|
16391
16813
|
const pendingAssistantMessage = {
|
|
16392
|
-
id:
|
|
16814
|
+
id: uuidv413(),
|
|
16393
16815
|
role: "assistant",
|
|
16394
16816
|
content: "...",
|
|
16395
16817
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16417,7 +16839,7 @@ function CliApp() {
|
|
|
16417
16839
|
const currentSession = useCliStore.getState().session;
|
|
16418
16840
|
if (!currentSession) return;
|
|
16419
16841
|
const continuationMessage = {
|
|
16420
|
-
id:
|
|
16842
|
+
id: uuidv413(),
|
|
16421
16843
|
role: "assistant",
|
|
16422
16844
|
content: "---\n\n**Background Agent Results:**\n\n" + result.finalAnswer,
|
|
16423
16845
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16476,13 +16898,13 @@ function CliApp() {
|
|
|
16476
16898
|
isError = true;
|
|
16477
16899
|
}
|
|
16478
16900
|
const userMessage = {
|
|
16479
|
-
id:
|
|
16901
|
+
id: uuidv413(),
|
|
16480
16902
|
role: "user",
|
|
16481
16903
|
content: `$ ${command}`,
|
|
16482
16904
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
16483
16905
|
};
|
|
16484
16906
|
const assistantMessage = {
|
|
16485
|
-
id:
|
|
16907
|
+
id: uuidv413(),
|
|
16486
16908
|
role: "assistant",
|
|
16487
16909
|
content: isError ? `\u274C Error:
|
|
16488
16910
|
${output}` : output.trim() || "(no output)",
|
|
@@ -16951,7 +17373,7 @@ Keyboard Shortcuts:
|
|
|
16951
17373
|
console.clear();
|
|
16952
17374
|
const model = state.session?.model || state.config?.defaultModel || "claude-sonnet";
|
|
16953
17375
|
const newSession = {
|
|
16954
|
-
id:
|
|
17376
|
+
id: uuidv413(),
|
|
16955
17377
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
16956
17378
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16957
17379
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17456,9 +17878,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
17456
17878
|
return { ...prev, config: updatedConfig };
|
|
17457
17879
|
});
|
|
17458
17880
|
if (modelChanged && state.agent) {
|
|
17459
|
-
const
|
|
17460
|
-
if (
|
|
17461
|
-
|
|
17881
|
+
const backend = state.agent.context.llm;
|
|
17882
|
+
if (backend) {
|
|
17883
|
+
backend.currentModel = updatedConfig.defaultModel;
|
|
17462
17884
|
}
|
|
17463
17885
|
}
|
|
17464
17886
|
};
|
|
@@ -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-QQL3OBKL.js";
|
|
6
|
+
import "./chunk-TY6Z2UV2.js";
|
|
7
|
+
import "./chunk-KPOK6V6E.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,
|
|
@@ -340,7 +346,7 @@ import {
|
|
|
340
346
|
validateReactArtifactV2,
|
|
341
347
|
validateSvgArtifactV2,
|
|
342
348
|
wikiMarkupToAdf
|
|
343
|
-
} from "./chunk-
|
|
349
|
+
} from "./chunk-KPOK6V6E.js";
|
|
344
350
|
export {
|
|
345
351
|
ALL_IMAGE_MODELS,
|
|
346
352
|
ALL_IMAGE_SIZES,
|
|
@@ -384,6 +390,12 @@ export {
|
|
|
384
390
|
ChatModels,
|
|
385
391
|
CitableSourceSchema,
|
|
386
392
|
ClaudeArtifactMimeTypes,
|
|
393
|
+
CliCompletionChunkAction,
|
|
394
|
+
CliCompletionDoneAction,
|
|
395
|
+
CliCompletionErrorAction,
|
|
396
|
+
CliCompletionRequestAction,
|
|
397
|
+
CliToolRequestAction,
|
|
398
|
+
CliToolResponseAction,
|
|
387
399
|
CollectionType,
|
|
388
400
|
CompletionApiUsageTransaction,
|
|
389
401
|
CompletionRequestSchema,
|
|
@@ -134,8 +134,8 @@ import {
|
|
|
134
134
|
validateMermaidSyntax,
|
|
135
135
|
warmUpSettingsCache,
|
|
136
136
|
withRetry
|
|
137
|
-
} from "./chunk-
|
|
138
|
-
import "./chunk-
|
|
137
|
+
} from "./chunk-TY6Z2UV2.js";
|
|
138
|
+
import "./chunk-KPOK6V6E.js";
|
|
139
139
|
import {
|
|
140
140
|
Logger,
|
|
141
141
|
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-BXCARBUQ.js";
|
|
6
|
+
import "./chunk-TY6Z2UV2.js";
|
|
7
|
+
import "./chunk-KPOK6V6E.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.29-feat-
|
|
3
|
+
"version": "0.2.29-feat-cli-websocket-streaming.18879+058b16fd8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -110,10 +110,10 @@
|
|
|
110
110
|
},
|
|
111
111
|
"devDependencies": {
|
|
112
112
|
"@bike4mind/agents": "0.1.0",
|
|
113
|
-
"@bike4mind/common": "2.50.1-feat-
|
|
114
|
-
"@bike4mind/mcp": "1.29.1-feat-
|
|
115
|
-
"@bike4mind/services": "2.48.1-feat-
|
|
116
|
-
"@bike4mind/utils": "2.5.1-feat-
|
|
113
|
+
"@bike4mind/common": "2.50.1-feat-cli-websocket-streaming.18879+058b16fd8",
|
|
114
|
+
"@bike4mind/mcp": "1.29.1-feat-cli-websocket-streaming.18879+058b16fd8",
|
|
115
|
+
"@bike4mind/services": "2.48.1-feat-cli-websocket-streaming.18879+058b16fd8",
|
|
116
|
+
"@bike4mind/utils": "2.5.1-feat-cli-websocket-streaming.18879+058b16fd8",
|
|
117
117
|
"@types/better-sqlite3": "^7.6.13",
|
|
118
118
|
"@types/diff": "^5.0.9",
|
|
119
119
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -130,5 +130,5 @@
|
|
|
130
130
|
"optionalDependencies": {
|
|
131
131
|
"@vscode/ripgrep": "^1.17.0"
|
|
132
132
|
},
|
|
133
|
-
"gitHead": "
|
|
133
|
+
"gitHead": "058b16fd85d5311089d30e3d8ccfbe135b3e90c6"
|
|
134
134
|
}
|