@bike4mind/cli 0.2.29-feat-session-permission.18841 → 0.2.29-feat-cli-websocket-streaming.18841
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 +482 -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);
|
|
@@ -11440,6 +11438,10 @@ var ServerToolExecutor = class {
|
|
|
11440
11438
|
};
|
|
11441
11439
|
|
|
11442
11440
|
// src/llm/ToolRouter.ts
|
|
11441
|
+
var wsToolExecutor = null;
|
|
11442
|
+
function setWebSocketToolExecutor(executor) {
|
|
11443
|
+
wsToolExecutor = executor;
|
|
11444
|
+
}
|
|
11443
11445
|
var SERVER_TOOLS = ["weather_info", "web_search", "web_fetch"];
|
|
11444
11446
|
var LOCAL_TOOLS = [
|
|
11445
11447
|
"file_read",
|
|
@@ -11462,7 +11464,15 @@ function isLocalTool(toolName) {
|
|
|
11462
11464
|
}
|
|
11463
11465
|
async function executeTool(toolName, input, apiClient, localToolFn) {
|
|
11464
11466
|
if (isServerTool(toolName)) {
|
|
11465
|
-
|
|
11467
|
+
if (wsToolExecutor) {
|
|
11468
|
+
logger.debug(`[ToolRouter] Routing ${toolName} to server via WebSocket`);
|
|
11469
|
+
const result = await wsToolExecutor.execute(toolName, input);
|
|
11470
|
+
if (!result.success) {
|
|
11471
|
+
return `Error executing ${toolName}: ${result.error || "Tool execution failed"}`;
|
|
11472
|
+
}
|
|
11473
|
+
return typeof result.content === "string" ? result.content : JSON.stringify(result.content ?? "");
|
|
11474
|
+
}
|
|
11475
|
+
logger.debug(`[ToolRouter] Routing ${toolName} to server via HTTP`);
|
|
11466
11476
|
const executor = new ServerToolExecutor(apiClient);
|
|
11467
11477
|
return await executor.executeTool(toolName, input);
|
|
11468
11478
|
} else if (isLocalTool(toolName)) {
|
|
@@ -11766,9 +11776,6 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
11766
11776
|
if (response.action === "deny") {
|
|
11767
11777
|
throw new PermissionDeniedError(toolName, args);
|
|
11768
11778
|
}
|
|
11769
|
-
if (response.action === "allow-session") {
|
|
11770
|
-
permissionManager.trustToolForSession(toolName);
|
|
11771
|
-
}
|
|
11772
11779
|
if (response.action === "allow-always") {
|
|
11773
11780
|
const canTrust = permissionManager.trustTool(toolName);
|
|
11774
11781
|
if (canTrust) {
|
|
@@ -11973,7 +11980,6 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
11973
11980
|
var PermissionManager = class {
|
|
11974
11981
|
constructor(trustedTools = [], customCategories, deniedTools) {
|
|
11975
11982
|
this.trustedTools = /* @__PURE__ */ new Set();
|
|
11976
|
-
this.sessionTrustedTools = /* @__PURE__ */ new Set();
|
|
11977
11983
|
this.deniedTools = /* @__PURE__ */ new Set();
|
|
11978
11984
|
this.trustedTools = new Set(trustedTools);
|
|
11979
11985
|
this.customCategories = new Map(Object.entries(customCategories || {}));
|
|
@@ -11999,9 +12005,6 @@ var PermissionManager = class {
|
|
|
11999
12005
|
if (category === "auto_approve") {
|
|
12000
12006
|
return false;
|
|
12001
12007
|
}
|
|
12002
|
-
if (this.sessionTrustedTools.has(toolName)) {
|
|
12003
|
-
return false;
|
|
12004
|
-
}
|
|
12005
12008
|
if (category === "prompt_always") {
|
|
12006
12009
|
return true;
|
|
12007
12010
|
}
|
|
@@ -12069,29 +12072,6 @@ var PermissionManager = class {
|
|
|
12069
12072
|
getDeniedTools() {
|
|
12070
12073
|
return Array.from(this.deniedTools).sort();
|
|
12071
12074
|
}
|
|
12072
|
-
/**
|
|
12073
|
-
* Trust a tool for the current session only (in-memory, no persistence)
|
|
12074
|
-
* Works for all tool categories including prompt_always, but NOT project-denied tools
|
|
12075
|
-
*/
|
|
12076
|
-
trustToolForSession(toolName) {
|
|
12077
|
-
if (this.deniedTools.has(toolName)) {
|
|
12078
|
-
return false;
|
|
12079
|
-
}
|
|
12080
|
-
this.sessionTrustedTools.add(toolName);
|
|
12081
|
-
return true;
|
|
12082
|
-
}
|
|
12083
|
-
/**
|
|
12084
|
-
* Check if a tool is trusted for the current session
|
|
12085
|
-
*/
|
|
12086
|
-
isSessionTrusted(toolName) {
|
|
12087
|
-
return this.sessionTrustedTools.has(toolName);
|
|
12088
|
-
}
|
|
12089
|
-
/**
|
|
12090
|
-
* Clear all session-scoped trust (called on exit or session reset)
|
|
12091
|
-
*/
|
|
12092
|
-
clearSessionTrust() {
|
|
12093
|
-
this.sessionTrustedTools.clear();
|
|
12094
|
-
}
|
|
12095
12075
|
/**
|
|
12096
12076
|
* Clear all trusted tools
|
|
12097
12077
|
*/
|
|
@@ -13422,6 +13402,186 @@ var ServerLlmBackend = class {
|
|
|
13422
13402
|
}
|
|
13423
13403
|
};
|
|
13424
13404
|
|
|
13405
|
+
// src/llm/WebSocketLlmBackend.ts
|
|
13406
|
+
import { v4 as uuidv411 } from "uuid";
|
|
13407
|
+
function stripThinkingBlocks2(text) {
|
|
13408
|
+
return text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
13409
|
+
}
|
|
13410
|
+
var WebSocketLlmBackend = class {
|
|
13411
|
+
constructor(options) {
|
|
13412
|
+
this.wsManager = options.wsManager;
|
|
13413
|
+
this.apiClient = options.apiClient;
|
|
13414
|
+
this.currentModel = options.model;
|
|
13415
|
+
this.tokenGetter = options.tokenGetter;
|
|
13416
|
+
}
|
|
13417
|
+
/**
|
|
13418
|
+
* Make LLM completion request via WebSocket.
|
|
13419
|
+
* Mirrors ServerLlmBackend accumulation logic — collects all chunks,
|
|
13420
|
+
* calls callback once at completion with full accumulated content.
|
|
13421
|
+
*/
|
|
13422
|
+
async complete(model, messages, options, callback) {
|
|
13423
|
+
logger.debug(`[WebSocketLlmBackend] Starting complete() with model: ${model}`);
|
|
13424
|
+
if (options.abortSignal?.aborted) {
|
|
13425
|
+
logger.debug("[WebSocketLlmBackend] Request aborted before start");
|
|
13426
|
+
return;
|
|
13427
|
+
}
|
|
13428
|
+
if (!this.wsManager.isConnected) {
|
|
13429
|
+
throw new Error("WebSocket is not connected");
|
|
13430
|
+
}
|
|
13431
|
+
const requestId = uuidv411();
|
|
13432
|
+
const token = await this.tokenGetter();
|
|
13433
|
+
if (!token) {
|
|
13434
|
+
throw new Error("No access token available");
|
|
13435
|
+
}
|
|
13436
|
+
return new Promise((resolve3, reject) => {
|
|
13437
|
+
const isVerbose = process.env.B4M_VERBOSE === "1";
|
|
13438
|
+
const isUltraVerbose = process.env.B4M_DEBUG_STREAM === "1";
|
|
13439
|
+
const streamLogger = new StreamLogger(logger, "WebSocketLlmBackend", isVerbose, isUltraVerbose);
|
|
13440
|
+
streamLogger.streamStart();
|
|
13441
|
+
let eventCount = 0;
|
|
13442
|
+
let accumulatedText = "";
|
|
13443
|
+
let lastUsageInfo = {};
|
|
13444
|
+
let toolsUsed = [];
|
|
13445
|
+
let thinkingBlocks = [];
|
|
13446
|
+
let settled = false;
|
|
13447
|
+
const cleanup = () => {
|
|
13448
|
+
this.wsManager.offRequest(requestId);
|
|
13449
|
+
};
|
|
13450
|
+
const settleResolve = () => {
|
|
13451
|
+
if (settled) return;
|
|
13452
|
+
settled = true;
|
|
13453
|
+
cleanup();
|
|
13454
|
+
resolve3();
|
|
13455
|
+
};
|
|
13456
|
+
const settleReject = (err) => {
|
|
13457
|
+
if (settled) return;
|
|
13458
|
+
settled = true;
|
|
13459
|
+
cleanup();
|
|
13460
|
+
reject(err);
|
|
13461
|
+
};
|
|
13462
|
+
if (options.abortSignal) {
|
|
13463
|
+
const abortHandler = () => {
|
|
13464
|
+
logger.debug("[WebSocketLlmBackend] Abort signal received");
|
|
13465
|
+
settleResolve();
|
|
13466
|
+
};
|
|
13467
|
+
if (options.abortSignal.aborted) {
|
|
13468
|
+
settleResolve();
|
|
13469
|
+
return;
|
|
13470
|
+
}
|
|
13471
|
+
options.abortSignal.addEventListener("abort", abortHandler, { once: true });
|
|
13472
|
+
}
|
|
13473
|
+
this.wsManager.onRequest(requestId, (message) => {
|
|
13474
|
+
if (options.abortSignal?.aborted) return;
|
|
13475
|
+
const action = message.action;
|
|
13476
|
+
if (action === "cli_completion_chunk") {
|
|
13477
|
+
eventCount++;
|
|
13478
|
+
const chunk = message.chunk;
|
|
13479
|
+
streamLogger.onEvent(eventCount, JSON.stringify(chunk));
|
|
13480
|
+
if (chunk.type === "content") {
|
|
13481
|
+
const textChunk = chunk.text || "";
|
|
13482
|
+
accumulatedText += textChunk;
|
|
13483
|
+
streamLogger.onContent(eventCount, textChunk, accumulatedText);
|
|
13484
|
+
if (chunk.usage) {
|
|
13485
|
+
lastUsageInfo = {
|
|
13486
|
+
inputTokens: chunk.usage.inputTokens,
|
|
13487
|
+
outputTokens: chunk.usage.outputTokens
|
|
13488
|
+
};
|
|
13489
|
+
}
|
|
13490
|
+
} else if (chunk.type === "tool_use") {
|
|
13491
|
+
streamLogger.onCriticalEvent(eventCount, "TOOL_USE", `tools: ${chunk.tools?.length}`);
|
|
13492
|
+
const textChunk = chunk.text || "";
|
|
13493
|
+
if (textChunk) accumulatedText += textChunk;
|
|
13494
|
+
if (chunk.tools && chunk.tools.length > 0) {
|
|
13495
|
+
toolsUsed = chunk.tools;
|
|
13496
|
+
}
|
|
13497
|
+
if (chunk.thinking && chunk.thinking.length > 0) {
|
|
13498
|
+
thinkingBlocks = chunk.thinking;
|
|
13499
|
+
}
|
|
13500
|
+
if (chunk.usage) {
|
|
13501
|
+
lastUsageInfo = {
|
|
13502
|
+
inputTokens: chunk.usage.inputTokens,
|
|
13503
|
+
outputTokens: chunk.usage.outputTokens
|
|
13504
|
+
};
|
|
13505
|
+
}
|
|
13506
|
+
}
|
|
13507
|
+
} else if (action === "cli_completion_done") {
|
|
13508
|
+
streamLogger.streamComplete(accumulatedText);
|
|
13509
|
+
const cleanedText = stripThinkingBlocks2(accumulatedText);
|
|
13510
|
+
if (toolsUsed.length > 0) {
|
|
13511
|
+
const info = {
|
|
13512
|
+
toolsUsed,
|
|
13513
|
+
thinking: thinkingBlocks.length > 0 ? thinkingBlocks : void 0,
|
|
13514
|
+
...lastUsageInfo
|
|
13515
|
+
};
|
|
13516
|
+
callback([cleanedText], info).then(() => settleResolve()).catch((err) => settleReject(err));
|
|
13517
|
+
} else if (cleanedText) {
|
|
13518
|
+
callback([cleanedText], lastUsageInfo).then(() => settleResolve()).catch((err) => settleReject(err));
|
|
13519
|
+
} else {
|
|
13520
|
+
settleResolve();
|
|
13521
|
+
}
|
|
13522
|
+
} else if (action === "cli_completion_error") {
|
|
13523
|
+
const errorMsg = message.error || "Server error";
|
|
13524
|
+
streamLogger.onCriticalEvent(eventCount, "ERROR", errorMsg);
|
|
13525
|
+
settleReject(new Error(errorMsg));
|
|
13526
|
+
}
|
|
13527
|
+
});
|
|
13528
|
+
try {
|
|
13529
|
+
this.wsManager.send({
|
|
13530
|
+
action: "cli_completion_request",
|
|
13531
|
+
accessToken: token,
|
|
13532
|
+
requestId,
|
|
13533
|
+
model,
|
|
13534
|
+
messages,
|
|
13535
|
+
options: {
|
|
13536
|
+
temperature: options.temperature,
|
|
13537
|
+
maxTokens: options.maxTokens,
|
|
13538
|
+
stream: true,
|
|
13539
|
+
tools: options.tools || []
|
|
13540
|
+
}
|
|
13541
|
+
});
|
|
13542
|
+
} catch (err) {
|
|
13543
|
+
settleReject(err instanceof Error ? err : new Error(String(err)));
|
|
13544
|
+
}
|
|
13545
|
+
});
|
|
13546
|
+
}
|
|
13547
|
+
/**
|
|
13548
|
+
* Get available models from server (REST call, not streaming).
|
|
13549
|
+
* Delegates to ApiClient — same as ServerLlmBackend.
|
|
13550
|
+
*/
|
|
13551
|
+
async getModelInfo() {
|
|
13552
|
+
try {
|
|
13553
|
+
logger.debug("[WebSocketLlmBackend] Fetching models from /api/models");
|
|
13554
|
+
const response = await this.apiClient.get("/api/models");
|
|
13555
|
+
if (!response || typeof response !== "object" || !Array.isArray(response.models)) {
|
|
13556
|
+
logger.warn("[WebSocketLlmBackend] Invalid API response format, using fallback models");
|
|
13557
|
+
return this.getFallbackModels();
|
|
13558
|
+
}
|
|
13559
|
+
const filteredModels = response.models.filter(
|
|
13560
|
+
(model) => model.type === "text" && model.supportsTools === true
|
|
13561
|
+
);
|
|
13562
|
+
if (filteredModels.length === 0) {
|
|
13563
|
+
logger.warn("[WebSocketLlmBackend] No CLI-compatible models found, using fallback");
|
|
13564
|
+
return this.getFallbackModels();
|
|
13565
|
+
}
|
|
13566
|
+
logger.debug(`[WebSocketLlmBackend] Loaded ${filteredModels.length} models`);
|
|
13567
|
+
return filteredModels;
|
|
13568
|
+
} catch (error) {
|
|
13569
|
+
logger.warn(
|
|
13570
|
+
`[WebSocketLlmBackend] Failed to fetch models: ${error instanceof Error ? error.message : String(error)}`
|
|
13571
|
+
);
|
|
13572
|
+
return this.getFallbackModels();
|
|
13573
|
+
}
|
|
13574
|
+
}
|
|
13575
|
+
getFallbackModels() {
|
|
13576
|
+
return [
|
|
13577
|
+
{ id: "claude-sonnet-4-5-20250929", name: "Claude 4.5 Sonnet" },
|
|
13578
|
+
{ id: "claude-3-5-haiku-20241022", name: "Claude 3.5 Haiku" },
|
|
13579
|
+
{ id: "gpt-4o", name: "GPT-4o" },
|
|
13580
|
+
{ id: "gpt-4o-mini", name: "GPT-4o Mini" }
|
|
13581
|
+
];
|
|
13582
|
+
}
|
|
13583
|
+
};
|
|
13584
|
+
|
|
13425
13585
|
// src/llm/NotifyingLlmBackend.ts
|
|
13426
13586
|
var NotifyingLlmBackend = class {
|
|
13427
13587
|
constructor(inner, backgroundManager) {
|
|
@@ -13456,6 +13616,223 @@ Please acknowledge these background agent results and incorporate them into your
|
|
|
13456
13616
|
}
|
|
13457
13617
|
};
|
|
13458
13618
|
|
|
13619
|
+
// src/ws/WebSocketConnectionManager.ts
|
|
13620
|
+
var WebSocketConnectionManager = class {
|
|
13621
|
+
constructor(wsUrl, getToken) {
|
|
13622
|
+
this.ws = null;
|
|
13623
|
+
this.heartbeatInterval = null;
|
|
13624
|
+
this.reconnectAttempts = 0;
|
|
13625
|
+
this.maxReconnectDelay = 3e4;
|
|
13626
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
13627
|
+
this.connected = false;
|
|
13628
|
+
this.connecting = false;
|
|
13629
|
+
this.closed = false;
|
|
13630
|
+
this.wsUrl = wsUrl;
|
|
13631
|
+
this.getToken = getToken;
|
|
13632
|
+
}
|
|
13633
|
+
/**
|
|
13634
|
+
* Connect to the WebSocket server.
|
|
13635
|
+
* Resolves when connection is established, rejects on failure.
|
|
13636
|
+
*/
|
|
13637
|
+
async connect() {
|
|
13638
|
+
if (this.connected || this.connecting) return;
|
|
13639
|
+
this.connecting = true;
|
|
13640
|
+
const token = await this.getToken();
|
|
13641
|
+
if (!token) {
|
|
13642
|
+
this.connecting = false;
|
|
13643
|
+
throw new Error("No access token available for WebSocket connection");
|
|
13644
|
+
}
|
|
13645
|
+
return new Promise((resolve3, reject) => {
|
|
13646
|
+
const url = `${this.wsUrl}?token=${token}`;
|
|
13647
|
+
logger.debug(`[WS] Connecting to ${this.wsUrl}...`);
|
|
13648
|
+
this.ws = new WebSocket(url);
|
|
13649
|
+
this.ws.onopen = () => {
|
|
13650
|
+
logger.debug("[WS] Connected");
|
|
13651
|
+
this.connected = true;
|
|
13652
|
+
this.connecting = false;
|
|
13653
|
+
this.reconnectAttempts = 0;
|
|
13654
|
+
this.startHeartbeat();
|
|
13655
|
+
resolve3();
|
|
13656
|
+
};
|
|
13657
|
+
this.ws.onmessage = (event) => {
|
|
13658
|
+
try {
|
|
13659
|
+
const data = typeof event.data === "string" ? event.data : event.data.toString();
|
|
13660
|
+
const message = JSON.parse(data);
|
|
13661
|
+
const requestId = message.requestId;
|
|
13662
|
+
if (requestId && this.handlers.has(requestId)) {
|
|
13663
|
+
this.handlers.get(requestId)(message);
|
|
13664
|
+
} else {
|
|
13665
|
+
logger.debug(`[WS] Unhandled message: ${message.action || "unknown"}`);
|
|
13666
|
+
}
|
|
13667
|
+
} catch (err) {
|
|
13668
|
+
logger.debug(`[WS] Failed to parse message: ${err}`);
|
|
13669
|
+
}
|
|
13670
|
+
};
|
|
13671
|
+
this.ws.onclose = () => {
|
|
13672
|
+
logger.debug("[WS] Connection closed");
|
|
13673
|
+
this.cleanup();
|
|
13674
|
+
if (!this.closed) {
|
|
13675
|
+
this.scheduleReconnect();
|
|
13676
|
+
}
|
|
13677
|
+
};
|
|
13678
|
+
this.ws.onerror = (err) => {
|
|
13679
|
+
logger.debug(`[WS] Error: ${err}`);
|
|
13680
|
+
if (this.connecting) {
|
|
13681
|
+
this.connecting = false;
|
|
13682
|
+
this.connected = false;
|
|
13683
|
+
reject(new Error("WebSocket connection failed"));
|
|
13684
|
+
}
|
|
13685
|
+
};
|
|
13686
|
+
});
|
|
13687
|
+
}
|
|
13688
|
+
/** Whether the connection is currently established */
|
|
13689
|
+
get isConnected() {
|
|
13690
|
+
return this.connected;
|
|
13691
|
+
}
|
|
13692
|
+
/**
|
|
13693
|
+
* Send a JSON message over the WebSocket connection.
|
|
13694
|
+
*/
|
|
13695
|
+
send(data) {
|
|
13696
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
13697
|
+
throw new Error("WebSocket is not connected");
|
|
13698
|
+
}
|
|
13699
|
+
this.ws.send(JSON.stringify(data));
|
|
13700
|
+
}
|
|
13701
|
+
/**
|
|
13702
|
+
* Register a handler for messages matching a specific requestId.
|
|
13703
|
+
*/
|
|
13704
|
+
onRequest(requestId, handler) {
|
|
13705
|
+
this.handlers.set(requestId, handler);
|
|
13706
|
+
}
|
|
13707
|
+
/**
|
|
13708
|
+
* Remove a handler for a specific requestId.
|
|
13709
|
+
*/
|
|
13710
|
+
offRequest(requestId) {
|
|
13711
|
+
this.handlers.delete(requestId);
|
|
13712
|
+
}
|
|
13713
|
+
/**
|
|
13714
|
+
* Close the connection and stop all heartbeat/reconnect logic.
|
|
13715
|
+
*/
|
|
13716
|
+
disconnect() {
|
|
13717
|
+
this.closed = true;
|
|
13718
|
+
this.cleanup();
|
|
13719
|
+
if (this.ws) {
|
|
13720
|
+
this.ws.close();
|
|
13721
|
+
this.ws = null;
|
|
13722
|
+
}
|
|
13723
|
+
this.handlers.clear();
|
|
13724
|
+
}
|
|
13725
|
+
startHeartbeat() {
|
|
13726
|
+
this.stopHeartbeat();
|
|
13727
|
+
this.heartbeatInterval = setInterval(
|
|
13728
|
+
() => {
|
|
13729
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
13730
|
+
this.ws.send(JSON.stringify({ action: "heartbeat" }));
|
|
13731
|
+
logger.debug("[WS] Heartbeat sent");
|
|
13732
|
+
}
|
|
13733
|
+
},
|
|
13734
|
+
5 * 60 * 1e3
|
|
13735
|
+
);
|
|
13736
|
+
}
|
|
13737
|
+
stopHeartbeat() {
|
|
13738
|
+
if (this.heartbeatInterval) {
|
|
13739
|
+
clearInterval(this.heartbeatInterval);
|
|
13740
|
+
this.heartbeatInterval = null;
|
|
13741
|
+
}
|
|
13742
|
+
}
|
|
13743
|
+
cleanup() {
|
|
13744
|
+
this.connected = false;
|
|
13745
|
+
this.connecting = false;
|
|
13746
|
+
this.stopHeartbeat();
|
|
13747
|
+
}
|
|
13748
|
+
scheduleReconnect() {
|
|
13749
|
+
if (this.closed) return;
|
|
13750
|
+
this.reconnectAttempts++;
|
|
13751
|
+
const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts - 1), this.maxReconnectDelay);
|
|
13752
|
+
logger.debug(`[WS] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
|
13753
|
+
setTimeout(async () => {
|
|
13754
|
+
if (this.closed) return;
|
|
13755
|
+
try {
|
|
13756
|
+
await this.connect();
|
|
13757
|
+
} catch {
|
|
13758
|
+
logger.debug("[WS] Reconnection failed");
|
|
13759
|
+
}
|
|
13760
|
+
}, delay);
|
|
13761
|
+
}
|
|
13762
|
+
};
|
|
13763
|
+
|
|
13764
|
+
// src/ws/WebSocketToolExecutor.ts
|
|
13765
|
+
import { v4 as uuidv412 } from "uuid";
|
|
13766
|
+
var WebSocketToolExecutor = class {
|
|
13767
|
+
constructor(wsManager, tokenGetter) {
|
|
13768
|
+
this.wsManager = wsManager;
|
|
13769
|
+
this.tokenGetter = tokenGetter;
|
|
13770
|
+
}
|
|
13771
|
+
/**
|
|
13772
|
+
* Execute a server-side tool via WebSocket.
|
|
13773
|
+
* Returns the tool result or throws on error.
|
|
13774
|
+
*/
|
|
13775
|
+
async execute(toolName, input, abortSignal) {
|
|
13776
|
+
if (!this.wsManager.isConnected) {
|
|
13777
|
+
throw new Error("WebSocket is not connected");
|
|
13778
|
+
}
|
|
13779
|
+
const token = await this.tokenGetter();
|
|
13780
|
+
if (!token) {
|
|
13781
|
+
throw new Error("No access token available");
|
|
13782
|
+
}
|
|
13783
|
+
const requestId = uuidv412();
|
|
13784
|
+
return new Promise((resolve3, reject) => {
|
|
13785
|
+
let settled = false;
|
|
13786
|
+
const cleanup = () => {
|
|
13787
|
+
this.wsManager.offRequest(requestId);
|
|
13788
|
+
};
|
|
13789
|
+
const settleResolve = (result) => {
|
|
13790
|
+
if (settled) return;
|
|
13791
|
+
settled = true;
|
|
13792
|
+
cleanup();
|
|
13793
|
+
resolve3(result);
|
|
13794
|
+
};
|
|
13795
|
+
const settleReject = (err) => {
|
|
13796
|
+
if (settled) return;
|
|
13797
|
+
settled = true;
|
|
13798
|
+
cleanup();
|
|
13799
|
+
reject(err);
|
|
13800
|
+
};
|
|
13801
|
+
if (abortSignal) {
|
|
13802
|
+
const abortHandler = () => {
|
|
13803
|
+
settleReject(new Error("Tool execution aborted"));
|
|
13804
|
+
};
|
|
13805
|
+
if (abortSignal.aborted) {
|
|
13806
|
+
settleReject(new Error("Tool execution aborted"));
|
|
13807
|
+
return;
|
|
13808
|
+
}
|
|
13809
|
+
abortSignal.addEventListener("abort", abortHandler, { once: true });
|
|
13810
|
+
}
|
|
13811
|
+
this.wsManager.onRequest(requestId, (message) => {
|
|
13812
|
+
const action = message.action;
|
|
13813
|
+
if (action === "cli_tool_response") {
|
|
13814
|
+
settleResolve({
|
|
13815
|
+
success: message.success,
|
|
13816
|
+
content: message.content,
|
|
13817
|
+
error: message.error
|
|
13818
|
+
});
|
|
13819
|
+
}
|
|
13820
|
+
});
|
|
13821
|
+
try {
|
|
13822
|
+
this.wsManager.send({
|
|
13823
|
+
action: "cli_tool_request",
|
|
13824
|
+
accessToken: token,
|
|
13825
|
+
requestId,
|
|
13826
|
+
toolName,
|
|
13827
|
+
input
|
|
13828
|
+
});
|
|
13829
|
+
} catch (err) {
|
|
13830
|
+
settleReject(err instanceof Error ? err : new Error(String(err)));
|
|
13831
|
+
}
|
|
13832
|
+
});
|
|
13833
|
+
}
|
|
13834
|
+
};
|
|
13835
|
+
|
|
13459
13836
|
// src/auth/ApiClient.ts
|
|
13460
13837
|
import axios11 from "axios";
|
|
13461
13838
|
var ApiClient = class {
|
|
@@ -13593,7 +13970,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
13593
13970
|
// package.json
|
|
13594
13971
|
var package_default = {
|
|
13595
13972
|
name: "@bike4mind/cli",
|
|
13596
|
-
version: "0.2.29-feat-
|
|
13973
|
+
version: "0.2.29-feat-cli-websocket-streaming.18841+5c940d031",
|
|
13597
13974
|
type: "module",
|
|
13598
13975
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
13599
13976
|
license: "UNLICENSED",
|
|
@@ -13703,10 +14080,10 @@ var package_default = {
|
|
|
13703
14080
|
},
|
|
13704
14081
|
devDependencies: {
|
|
13705
14082
|
"@bike4mind/agents": "0.1.0",
|
|
13706
|
-
"@bike4mind/common": "2.50.1-feat-
|
|
13707
|
-
"@bike4mind/mcp": "1.29.1-feat-
|
|
13708
|
-
"@bike4mind/services": "2.48.1-feat-
|
|
13709
|
-
"@bike4mind/utils": "2.5.1-feat-
|
|
14083
|
+
"@bike4mind/common": "2.50.1-feat-cli-websocket-streaming.18841+5c940d031",
|
|
14084
|
+
"@bike4mind/mcp": "1.29.1-feat-cli-websocket-streaming.18841+5c940d031",
|
|
14085
|
+
"@bike4mind/services": "2.48.1-feat-cli-websocket-streaming.18841+5c940d031",
|
|
14086
|
+
"@bike4mind/utils": "2.5.1-feat-cli-websocket-streaming.18841+5c940d031",
|
|
13710
14087
|
"@types/better-sqlite3": "^7.6.13",
|
|
13711
14088
|
"@types/diff": "^5.0.9",
|
|
13712
14089
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -13723,7 +14100,7 @@ var package_default = {
|
|
|
13723
14100
|
optionalDependencies: {
|
|
13724
14101
|
"@vscode/ripgrep": "^1.17.0"
|
|
13725
14102
|
},
|
|
13726
|
-
gitHead: "
|
|
14103
|
+
gitHead: "5c940d031610617c76d3c12cc611b71db8bb4caf"
|
|
13727
14104
|
};
|
|
13728
14105
|
|
|
13729
14106
|
// src/config/constants.ts
|
|
@@ -15531,7 +15908,8 @@ function CliApp() {
|
|
|
15531
15908
|
agentStore: null,
|
|
15532
15909
|
abortController: null,
|
|
15533
15910
|
contextContent: "",
|
|
15534
|
-
backgroundManager: null
|
|
15911
|
+
backgroundManager: null,
|
|
15912
|
+
wsManager: null
|
|
15535
15913
|
});
|
|
15536
15914
|
const [isInitialized, setIsInitialized] = useState9(false);
|
|
15537
15915
|
const [initError, setInitError] = useState9(null);
|
|
@@ -15559,6 +15937,10 @@ function CliApp() {
|
|
|
15559
15937
|
})
|
|
15560
15938
|
);
|
|
15561
15939
|
}
|
|
15940
|
+
if (state.wsManager) {
|
|
15941
|
+
state.wsManager.disconnect();
|
|
15942
|
+
setWebSocketToolExecutor(null);
|
|
15943
|
+
}
|
|
15562
15944
|
if (state.agent) {
|
|
15563
15945
|
state.agent.removeAllListeners();
|
|
15564
15946
|
}
|
|
@@ -15577,7 +15959,7 @@ function CliApp() {
|
|
|
15577
15959
|
setTimeout(() => {
|
|
15578
15960
|
process.exit(0);
|
|
15579
15961
|
}, 100);
|
|
15580
|
-
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
|
|
15962
|
+
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore, state.wsManager]);
|
|
15581
15963
|
useInput9((input, key) => {
|
|
15582
15964
|
if (key.escape) {
|
|
15583
15965
|
if (state.abortController) {
|
|
@@ -15647,7 +16029,7 @@ function CliApp() {
|
|
|
15647
16029
|
if (!isAuthenticated) {
|
|
15648
16030
|
console.log("\u2139\uFE0F AI features disabled. Available commands: /login, /help, /config\n");
|
|
15649
16031
|
const minimalSession = {
|
|
15650
|
-
id:
|
|
16032
|
+
id: uuidv413(),
|
|
15651
16033
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
15652
16034
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15653
16035
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15675,10 +16057,41 @@ function CliApp() {
|
|
|
15675
16057
|
console.log(`\u{1F30D} API Environment: ${envName} (${apiBaseURL})`);
|
|
15676
16058
|
}
|
|
15677
16059
|
const apiClient = new ApiClient(apiBaseURL, state.configStore);
|
|
15678
|
-
const
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
}
|
|
16060
|
+
const tokenGetter = async () => {
|
|
16061
|
+
const tokens = await state.configStore.getAuthTokens();
|
|
16062
|
+
return tokens?.accessToken ?? null;
|
|
16063
|
+
};
|
|
16064
|
+
let wsManager = null;
|
|
16065
|
+
let llm;
|
|
16066
|
+
try {
|
|
16067
|
+
const serverConfig = await apiClient.get("/api/settings/serverConfig");
|
|
16068
|
+
const wsUrl = serverConfig?.websocketUrl;
|
|
16069
|
+
if (wsUrl) {
|
|
16070
|
+
wsManager = new WebSocketConnectionManager(wsUrl, tokenGetter);
|
|
16071
|
+
await wsManager.connect();
|
|
16072
|
+
const wsToolExecutor2 = new WebSocketToolExecutor(wsManager, tokenGetter);
|
|
16073
|
+
setWebSocketToolExecutor(wsToolExecutor2);
|
|
16074
|
+
llm = new WebSocketLlmBackend({
|
|
16075
|
+
wsManager,
|
|
16076
|
+
apiClient,
|
|
16077
|
+
model: config.defaultModel,
|
|
16078
|
+
tokenGetter
|
|
16079
|
+
});
|
|
16080
|
+
logger.debug("\u{1F50C} Using WebSocket transport (bypasses CloudFront timeout)");
|
|
16081
|
+
} else {
|
|
16082
|
+
throw new Error("No websocketUrl in server config");
|
|
16083
|
+
}
|
|
16084
|
+
} catch (wsError) {
|
|
16085
|
+
logger.debug(
|
|
16086
|
+
`[WS] WebSocket unavailable, using SSE fallback: ${wsError instanceof Error ? wsError.message : String(wsError)}`
|
|
16087
|
+
);
|
|
16088
|
+
wsManager = null;
|
|
16089
|
+
setWebSocketToolExecutor(null);
|
|
16090
|
+
llm = new ServerLlmBackend({
|
|
16091
|
+
apiClient,
|
|
16092
|
+
model: config.defaultModel
|
|
16093
|
+
});
|
|
16094
|
+
}
|
|
15682
16095
|
const models = await llm.getModelInfo();
|
|
15683
16096
|
if (models.length === 0) {
|
|
15684
16097
|
throw new Error("No models available from server.");
|
|
@@ -15691,7 +16104,7 @@ function CliApp() {
|
|
|
15691
16104
|
}
|
|
15692
16105
|
llm.currentModel = modelInfo.id;
|
|
15693
16106
|
const newSession = {
|
|
15694
|
-
id:
|
|
16107
|
+
id: uuidv413(),
|
|
15695
16108
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
15696
16109
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15697
16110
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15911,8 +16324,10 @@ ${contextResult.mergedContent}` : "";
|
|
|
15911
16324
|
// Store agent store for agent management commands
|
|
15912
16325
|
contextContent: contextResult.mergedContent,
|
|
15913
16326
|
// Store raw context for compact instructions
|
|
15914
|
-
backgroundManager
|
|
16327
|
+
backgroundManager,
|
|
15915
16328
|
// Store for grouped notification turn tracking
|
|
16329
|
+
wsManager
|
|
16330
|
+
// WebSocket connection manager (null if using SSE fallback)
|
|
15916
16331
|
}));
|
|
15917
16332
|
setStoreSession(newSession);
|
|
15918
16333
|
const bannerLines = [
|
|
@@ -16007,13 +16422,13 @@ ${contextResult.mergedContent}` : "";
|
|
|
16007
16422
|
messageContent = multimodalMessage.content;
|
|
16008
16423
|
}
|
|
16009
16424
|
const userMessage = {
|
|
16010
|
-
id:
|
|
16425
|
+
id: uuidv413(),
|
|
16011
16426
|
role: "user",
|
|
16012
16427
|
content: userMessageContent,
|
|
16013
16428
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
16014
16429
|
};
|
|
16015
16430
|
const pendingAssistantMessage = {
|
|
16016
|
-
id:
|
|
16431
|
+
id: uuidv413(),
|
|
16017
16432
|
role: "assistant",
|
|
16018
16433
|
content: "...",
|
|
16019
16434
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16219,13 +16634,13 @@ ${contextResult.mergedContent}` : "";
|
|
|
16219
16634
|
userMessageContent = message;
|
|
16220
16635
|
}
|
|
16221
16636
|
const userMessage = {
|
|
16222
|
-
id:
|
|
16637
|
+
id: uuidv413(),
|
|
16223
16638
|
role: "user",
|
|
16224
16639
|
content: userMessageContent,
|
|
16225
16640
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
16226
16641
|
};
|
|
16227
16642
|
const pendingAssistantMessage = {
|
|
16228
|
-
id:
|
|
16643
|
+
id: uuidv413(),
|
|
16229
16644
|
role: "assistant",
|
|
16230
16645
|
content: "...",
|
|
16231
16646
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16303,7 +16718,7 @@ ${contextResult.mergedContent}` : "";
|
|
|
16303
16718
|
const currentSession = useCliStore.getState().session;
|
|
16304
16719
|
if (currentSession) {
|
|
16305
16720
|
const cancelMessage = {
|
|
16306
|
-
id:
|
|
16721
|
+
id: uuidv413(),
|
|
16307
16722
|
role: "assistant",
|
|
16308
16723
|
content: "\u26A0\uFE0F Operation cancelled by user",
|
|
16309
16724
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16348,7 +16763,7 @@ ${contextResult.mergedContent}` : "";
|
|
|
16348
16763
|
setState((prev) => ({ ...prev, abortController }));
|
|
16349
16764
|
try {
|
|
16350
16765
|
const pendingAssistantMessage = {
|
|
16351
|
-
id:
|
|
16766
|
+
id: uuidv413(),
|
|
16352
16767
|
role: "assistant",
|
|
16353
16768
|
content: "...",
|
|
16354
16769
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16376,7 +16791,7 @@ ${contextResult.mergedContent}` : "";
|
|
|
16376
16791
|
const currentSession = useCliStore.getState().session;
|
|
16377
16792
|
if (!currentSession) return;
|
|
16378
16793
|
const continuationMessage = {
|
|
16379
|
-
id:
|
|
16794
|
+
id: uuidv413(),
|
|
16380
16795
|
role: "assistant",
|
|
16381
16796
|
content: "---\n\n**Background Agent Results:**\n\n" + result.finalAnswer,
|
|
16382
16797
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16435,13 +16850,13 @@ ${contextResult.mergedContent}` : "";
|
|
|
16435
16850
|
isError = true;
|
|
16436
16851
|
}
|
|
16437
16852
|
const userMessage = {
|
|
16438
|
-
id:
|
|
16853
|
+
id: uuidv413(),
|
|
16439
16854
|
role: "user",
|
|
16440
16855
|
content: `$ ${command}`,
|
|
16441
16856
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
16442
16857
|
};
|
|
16443
16858
|
const assistantMessage = {
|
|
16444
|
-
id:
|
|
16859
|
+
id: uuidv413(),
|
|
16445
16860
|
role: "assistant",
|
|
16446
16861
|
content: isError ? `\u274C Error:
|
|
16447
16862
|
${output}` : output.trim() || "(no output)",
|
|
@@ -16910,7 +17325,7 @@ Keyboard Shortcuts:
|
|
|
16910
17325
|
console.clear();
|
|
16911
17326
|
const model = state.session?.model || state.config?.defaultModel || "claude-sonnet";
|
|
16912
17327
|
const newSession = {
|
|
16913
|
-
id:
|
|
17328
|
+
id: uuidv413(),
|
|
16914
17329
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
16915
17330
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16916
17331
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17405,9 +17820,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
17405
17820
|
return { ...prev, config: updatedConfig };
|
|
17406
17821
|
});
|
|
17407
17822
|
if (modelChanged && state.agent) {
|
|
17408
|
-
const
|
|
17409
|
-
if (
|
|
17410
|
-
|
|
17823
|
+
const backend = state.agent.context.llm;
|
|
17824
|
+
if (backend) {
|
|
17825
|
+
backend.currentModel = updatedConfig.defaultModel;
|
|
17411
17826
|
}
|
|
17412
17827
|
}
|
|
17413
17828
|
};
|
|
@@ -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.18841+5c940d031",
|
|
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.18841+5c940d031",
|
|
114
|
+
"@bike4mind/mcp": "1.29.1-feat-cli-websocket-streaming.18841+5c940d031",
|
|
115
|
+
"@bike4mind/services": "2.48.1-feat-cli-websocket-streaming.18841+5c940d031",
|
|
116
|
+
"@bike4mind/utils": "2.5.1-feat-cli-websocket-streaming.18841+5c940d031",
|
|
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": "5c940d031610617c76d3c12cc611b71db8bb4caf"
|
|
134
134
|
}
|