@bike4mind/cli 0.2.71-fix-opti-hashi-data-lake-explorer.22040 → 0.2.71
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/{ConfigStore-DH64GYfC.mjs → ConfigStore-CJrPFsAE.mjs} +67 -4
- package/dist/commands/doctorCommand.mjs +1 -1
- package/dist/commands/headlessCommand.mjs +6 -3
- package/dist/commands/mcpCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +1 -1
- package/dist/index.mjs +182 -6
- package/dist/{tools-CcSulyLi.mjs → tools-DmUrRjzs.mjs} +187 -90
- package/dist/{updateChecker-bL3tE6X7.mjs → updateChecker-Cxb7mnxO.mjs} +1 -1
- package/package.json +7 -7
|
@@ -982,7 +982,8 @@ const SreAgentConfigSchema = z.object({
|
|
|
982
982
|
enabled: true,
|
|
983
983
|
minConfidence: 80
|
|
984
984
|
}),
|
|
985
|
-
dryRun: z.boolean().default(false)
|
|
985
|
+
dryRun: z.boolean().default(false),
|
|
986
|
+
maxRevisions: z.number().min(0).max(5).default(2)
|
|
986
987
|
});
|
|
987
988
|
/**
|
|
988
989
|
* Configuration schema for the SecOps Triage feature.
|
|
@@ -1568,7 +1569,8 @@ const KeepCommandType = z.enum([
|
|
|
1568
1569
|
"jupyter_start_kernel",
|
|
1569
1570
|
"jupyter_execute_cell",
|
|
1570
1571
|
"jupyter_stop_kernel",
|
|
1571
|
-
"jupyter_get_kernelspecs"
|
|
1572
|
+
"jupyter_get_kernelspecs",
|
|
1573
|
+
"jupyter_execute_notebook"
|
|
1572
1574
|
]);
|
|
1573
1575
|
/** Web HUD → Server: request a command be sent to the Keep (CLI) */
|
|
1574
1576
|
const KeepCommandRequestAction = z.object({
|
|
@@ -1740,7 +1742,8 @@ const SceneCommandSchema = z.discriminatedUnion("type", [
|
|
|
1740
1742
|
col: z.number(),
|
|
1741
1743
|
row: z.number(),
|
|
1742
1744
|
gid: z.number()
|
|
1743
|
-
}))
|
|
1745
|
+
})),
|
|
1746
|
+
worldVersion: z.number().optional()
|
|
1744
1747
|
})
|
|
1745
1748
|
]);
|
|
1746
1749
|
/** Client → Server: send scene commands to broadcast to all HUD clients */
|
|
@@ -3051,6 +3054,11 @@ const CONTEXT_TELEMETRY_VALIDATION_LIMITS = {
|
|
|
3051
3054
|
max: 18e4,
|
|
3052
3055
|
default: 6e4
|
|
3053
3056
|
},
|
|
3057
|
+
llmAnalysisThreshold: {
|
|
3058
|
+
min: 0,
|
|
3059
|
+
max: 100,
|
|
3060
|
+
default: 30
|
|
3061
|
+
},
|
|
3054
3062
|
alertThreshold: {
|
|
3055
3063
|
min: 0,
|
|
3056
3064
|
max: 100,
|
|
@@ -3081,6 +3089,31 @@ const CONTEXT_TELEMETRY_VALIDATION_LIMITS = {
|
|
|
3081
3089
|
max: 168,
|
|
3082
3090
|
default: 24
|
|
3083
3091
|
},
|
|
3092
|
+
baselineWindowDays: {
|
|
3093
|
+
min: 3,
|
|
3094
|
+
max: 30,
|
|
3095
|
+
default: 7
|
|
3096
|
+
},
|
|
3097
|
+
sloResponseTimeP95Ms: {
|
|
3098
|
+
min: 500,
|
|
3099
|
+
max: 3e5,
|
|
3100
|
+
default: 6e4
|
|
3101
|
+
},
|
|
3102
|
+
sloFirstTokenTimeMs: {
|
|
3103
|
+
min: 500,
|
|
3104
|
+
max: 6e4,
|
|
3105
|
+
default: 5e3
|
|
3106
|
+
},
|
|
3107
|
+
sloErrorRatePercent: {
|
|
3108
|
+
min: 0,
|
|
3109
|
+
max: 100,
|
|
3110
|
+
default: 2
|
|
3111
|
+
},
|
|
3112
|
+
sloContextUtilizationPercent: {
|
|
3113
|
+
min: 50,
|
|
3114
|
+
max: 100,
|
|
3115
|
+
default: 85
|
|
3116
|
+
},
|
|
3084
3117
|
maxIssuesPerHour: {
|
|
3085
3118
|
min: 1,
|
|
3086
3119
|
max: 200,
|
|
@@ -3103,6 +3136,7 @@ const ContextTelemetryAlertsSchema = z.object({
|
|
|
3103
3136
|
temperature: z.number().min(CT.temperature.min).max(CT.temperature.max).default(CT.temperature.default),
|
|
3104
3137
|
maxTokens: z.number().min(CT.maxTokens.min).max(CT.maxTokens.max).default(CT.maxTokens.default),
|
|
3105
3138
|
timeoutMs: z.number().min(CT.timeoutMs.min).max(CT.timeoutMs.max).default(CT.timeoutMs.default),
|
|
3139
|
+
llmAnalysisThreshold: z.number().min(CT.llmAnalysisThreshold.min).max(CT.llmAnalysisThreshold.max).default(CT.llmAnalysisThreshold.default),
|
|
3106
3140
|
alertThreshold: z.number().min(CT.alertThreshold.min).max(CT.alertThreshold.max).default(CT.alertThreshold.default),
|
|
3107
3141
|
criticalThreshold: z.number().min(CT.criticalThreshold.min).max(CT.criticalThreshold.max).default(CT.criticalThreshold.default),
|
|
3108
3142
|
dedupWindowMinutes: z.number().min(CT.dedupWindowMinutes.min).max(CT.dedupWindowMinutes.max).default(CT.dedupWindowMinutes.default),
|
|
@@ -3111,6 +3145,11 @@ const ContextTelemetryAlertsSchema = z.object({
|
|
|
3111
3145
|
duplicateAlertCooldownHours: z.number().min(CT.duplicateAlertCooldownHours.min).max(CT.duplicateAlertCooldownHours.max).default(CT.duplicateAlertCooldownHours.default),
|
|
3112
3146
|
enableLlmPriority: z.boolean().default(false),
|
|
3113
3147
|
promptTemplate: z.string().min(CT.promptTemplate.min, `Prompt template must be at least ${CT.promptTemplate.min} characters`).max(CT.promptTemplate.max, `Prompt template cannot exceed ${CT.promptTemplate.max.toLocaleString()} characters`).trim().optional(),
|
|
3148
|
+
baselineWindowDays: z.number().min(CT.baselineWindowDays.min).max(CT.baselineWindowDays.max).default(CT.baselineWindowDays.default),
|
|
3149
|
+
sloResponseTimeP95Ms: z.number().min(CT.sloResponseTimeP95Ms.min).max(CT.sloResponseTimeP95Ms.max).default(CT.sloResponseTimeP95Ms.default),
|
|
3150
|
+
sloFirstTokenTimeMs: z.number().min(CT.sloFirstTokenTimeMs.min).max(CT.sloFirstTokenTimeMs.max).default(CT.sloFirstTokenTimeMs.default),
|
|
3151
|
+
sloErrorRatePercent: z.number().min(CT.sloErrorRatePercent.min).max(CT.sloErrorRatePercent.max).default(CT.sloErrorRatePercent.default),
|
|
3152
|
+
sloContextUtilizationPercent: z.number().min(CT.sloContextUtilizationPercent.min).max(CT.sloContextUtilizationPercent.max).default(CT.sloContextUtilizationPercent.default),
|
|
3114
3153
|
maxIssuesPerHour: z.number().min(CT.maxIssuesPerHour.min).max(CT.maxIssuesPerHour.max).default(CT.maxIssuesPerHour.default),
|
|
3115
3154
|
dryRun: z.boolean().default(false)
|
|
3116
3155
|
});
|
|
@@ -4921,6 +4960,7 @@ makeStringSetting({
|
|
|
4921
4960
|
temperature: CONTEXT_TELEMETRY_VALIDATION_LIMITS.temperature.default,
|
|
4922
4961
|
maxTokens: CONTEXT_TELEMETRY_VALIDATION_LIMITS.maxTokens.default,
|
|
4923
4962
|
timeoutMs: CONTEXT_TELEMETRY_VALIDATION_LIMITS.timeoutMs.default,
|
|
4963
|
+
llmAnalysisThreshold: CONTEXT_TELEMETRY_VALIDATION_LIMITS.llmAnalysisThreshold.default,
|
|
4924
4964
|
alertThreshold: CONTEXT_TELEMETRY_VALIDATION_LIMITS.alertThreshold.default,
|
|
4925
4965
|
criticalThreshold: CONTEXT_TELEMETRY_VALIDATION_LIMITS.criticalThreshold.default,
|
|
4926
4966
|
dedupWindowMinutes: CONTEXT_TELEMETRY_VALIDATION_LIMITS.dedupWindowMinutes.default,
|
|
@@ -4928,6 +4968,11 @@ makeStringSetting({
|
|
|
4928
4968
|
regressionGracePeriodHours: CONTEXT_TELEMETRY_VALIDATION_LIMITS.regressionGracePeriodHours.default,
|
|
4929
4969
|
duplicateAlertCooldownHours: CONTEXT_TELEMETRY_VALIDATION_LIMITS.duplicateAlertCooldownHours.default,
|
|
4930
4970
|
enableLlmPriority: false,
|
|
4971
|
+
baselineWindowDays: CONTEXT_TELEMETRY_VALIDATION_LIMITS.baselineWindowDays.default,
|
|
4972
|
+
sloResponseTimeP95Ms: CONTEXT_TELEMETRY_VALIDATION_LIMITS.sloResponseTimeP95Ms.default,
|
|
4973
|
+
sloFirstTokenTimeMs: CONTEXT_TELEMETRY_VALIDATION_LIMITS.sloFirstTokenTimeMs.default,
|
|
4974
|
+
sloErrorRatePercent: CONTEXT_TELEMETRY_VALIDATION_LIMITS.sloErrorRatePercent.default,
|
|
4975
|
+
sloContextUtilizationPercent: CONTEXT_TELEMETRY_VALIDATION_LIMITS.sloContextUtilizationPercent.default,
|
|
4931
4976
|
maxIssuesPerHour: CONTEXT_TELEMETRY_VALIDATION_LIMITS.maxIssuesPerHour.default,
|
|
4932
4977
|
dryRun: false
|
|
4933
4978
|
},
|
|
@@ -5192,6 +5237,23 @@ const ALERT_THRESHOLDS = {
|
|
|
5192
5237
|
warning: 30,
|
|
5193
5238
|
critical: 50
|
|
5194
5239
|
};
|
|
5240
|
+
z.object({
|
|
5241
|
+
avgResponseTimeMs: z.number(),
|
|
5242
|
+
p95ResponseTimeMs: z.number(),
|
|
5243
|
+
avgUtilization: z.number(),
|
|
5244
|
+
utilizationRange: z.object({
|
|
5245
|
+
low: z.number(),
|
|
5246
|
+
high: z.number()
|
|
5247
|
+
}),
|
|
5248
|
+
sampleCount: z.number(),
|
|
5249
|
+
windowDays: z.number()
|
|
5250
|
+
});
|
|
5251
|
+
z.enum([
|
|
5252
|
+
"no_action",
|
|
5253
|
+
"monitor",
|
|
5254
|
+
"investigate_soon",
|
|
5255
|
+
"immediate_action"
|
|
5256
|
+
]);
|
|
5195
5257
|
const PromptMetaModelParametersSchema = z.object({
|
|
5196
5258
|
temperature: z.number().optional(),
|
|
5197
5259
|
topP: z.number().optional(),
|
|
@@ -8091,7 +8153,8 @@ const CliConfigSchema = z.object({
|
|
|
8091
8153
|
features: z.object({ tavern: z.boolean().optional() }).optional().prefault({}),
|
|
8092
8154
|
trustedTools: z.array(z.string()).optional().prefault([]),
|
|
8093
8155
|
sandbox: SandboxConfigSchema.optional(),
|
|
8094
|
-
additionalDirectories: z.array(z.string()).optional().prefault([])
|
|
8156
|
+
additionalDirectories: z.array(z.string()).optional().prefault([]),
|
|
8157
|
+
fallbackModels: z.array(z.string()).optional()
|
|
8095
8158
|
});
|
|
8096
8159
|
/**
|
|
8097
8160
|
* Zod schema for ProjectConfig validation
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as version, n as fetchLatestVersion, r as forceCheckForUpdate } from "../updateChecker-
|
|
2
|
+
import { i as version, n as fetchLatestVersion, r as forceCheckForUpdate } from "../updateChecker-Cxb7mnxO.mjs";
|
|
3
3
|
import { execSync } from "child_process";
|
|
4
4
|
import { constants, existsSync, promises } from "fs";
|
|
5
5
|
import { homedir } from "os";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { n as logger, t as ConfigStore } from "../ConfigStore-
|
|
2
|
+
import { B as CustomCommandStore, C as getApiUrl, E as generateCliTools, I as buildCoreSystemPrompt, P as setWebSocketToolExecutor, R as isReadOnlyTool, S as loadContextFiles, T as PermissionManager, U as SessionStore, V as CheckpointStore, _ as ServerLlmBackend, a as createBackgroundAgentTools, c as AgentStore, f as ApiClient, g as WebSocketLlmBackend, h as FallbackLlmBackend, i as createWriteTodosTool, l as SubagentOrchestrator, m as WebSocketConnectionManager, n as createFindDefinitionTool, o as BackgroundAgentManager, p as WebSocketToolExecutor, r as createTodoStore, s as createAgentDelegateTool, t as createGetFileStructureTool, u as createSkillTool, v as McpManager, z as ReActAgent } from "../tools-DmUrRjzs.mjs";
|
|
3
|
+
import { n as logger, t as ConfigStore } from "../ConfigStore-CJrPFsAE.mjs";
|
|
4
4
|
import { t as DEFAULT_SANDBOX_CONFIG } from "../types-DBEjF9YS.mjs";
|
|
5
5
|
import { t as createSandboxRuntime } from "../SandboxRuntimeAdapter-C1B4t20N.mjs";
|
|
6
6
|
import { t as SandboxOrchestrator } from "../SandboxOrchestrator-BEW3rqYi.mjs";
|
|
@@ -97,6 +97,9 @@ async function handleHeadlessCommand(options) {
|
|
|
97
97
|
if (models.length === 0) throw new Error("No models available from server.");
|
|
98
98
|
const modelInfo = models.find((m) => m.id === config.defaultModel) ?? models[0];
|
|
99
99
|
llm.currentModel = modelInfo.id;
|
|
100
|
+
const effectiveLlm = config.fallbackModels && config.fallbackModels.length > 0 ? new FallbackLlmBackend(llm, config.fallbackModels, (fromModel, toModel, error) => {
|
|
101
|
+
process.stderr.write(`⚠️ Model "${fromModel}" failed (${error.message}). Falling back to "${toModel}"...\n`);
|
|
102
|
+
}) : llm;
|
|
100
103
|
const session = {
|
|
101
104
|
id: v4(),
|
|
102
105
|
name: `Headless ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
@@ -195,7 +198,7 @@ async function handleHeadlessCommand(options) {
|
|
|
195
198
|
const agent = new ReActAgent({
|
|
196
199
|
userId: config.userId,
|
|
197
200
|
logger: silentLogger,
|
|
198
|
-
llm,
|
|
201
|
+
llm: effectiveLlm,
|
|
199
202
|
model: modelInfo.id,
|
|
200
203
|
tools: allTools,
|
|
201
204
|
maxIterations,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as version, r as forceCheckForUpdate } from "../updateChecker-
|
|
2
|
+
import { i as version, r as forceCheckForUpdate } from "../updateChecker-Cxb7mnxO.mjs";
|
|
3
3
|
import { execSync } from "child_process";
|
|
4
4
|
//#region src/commands/updateCommand.ts
|
|
5
5
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as useCliStore, t as selectActiveBackgroundAgents } from "./store-Dw1nZX2Y.mjs";
|
|
3
|
-
import { A as
|
|
4
|
-
import { Dt as validateNotebookPath$1, Et as validateJupyterKernelName, g as ChatModels, m as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore } from "./ConfigStore-
|
|
5
|
-
import { i as version, t as checkForUpdate } from "./updateChecker-
|
|
3
|
+
import { A as DEFAULT_RETRY_CONFIG, B as CustomCommandStore, C as getApiUrl, D as ALWAYS_DENIED_FOR_AGENTS, E as generateCliTools, F as OllamaBackend, G as hasFileReferences, H as CommandHistoryStore, I as buildCoreSystemPrompt, J as mergeCommands, K as processFileReferences, L as buildSkillsPromptSection, M as clearFeatureModuleTools, N as registerFeatureModuleTools, O as DEFAULT_AGENT_MODEL, P as setWebSocketToolExecutor, R as isReadOnlyTool, S as loadContextFiles, T as PermissionManager, U as SessionStore, V as CheckpointStore, W as OAuthClient, X as searchFiles, Y as formatFileSize, Z as warmFileCache, _ as ServerLlmBackend, a as createBackgroundAgentTools, b as formatStep, c as AgentStore, d as parseAgentConfig, f as ApiClient, g as WebSocketLlmBackend, h as FallbackLlmBackend, i as createWriteTodosTool, j as DEFAULT_THOROUGHNESS, k as DEFAULT_MAX_ITERATIONS, l as SubagentOrchestrator, m as WebSocketConnectionManager, n as createFindDefinitionTool, o as BackgroundAgentManager, p as WebSocketToolExecutor, q as searchCommands, r as createTodoStore, s as createAgentDelegateTool, t as createGetFileStructureTool, u as createSkillTool, v as McpManager, w as getEnvironmentName, x as extractCompactInstructions, y as substituteArguments, z as ReActAgent } from "./tools-DmUrRjzs.mjs";
|
|
4
|
+
import { Dt as validateNotebookPath$1, Et as validateJupyterKernelName, g as ChatModels, m as CREDIT_DEDUCT_TRANSACTION_TYPES, n as logger, t as ConfigStore } from "./ConfigStore-CJrPFsAE.mjs";
|
|
5
|
+
import { i as version, t as checkForUpdate } from "./updateChecker-Cxb7mnxO.mjs";
|
|
6
6
|
import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
|
|
7
7
|
import { Box, Static, Text, render, useApp, useInput } from "ink";
|
|
8
8
|
import { execSync } from "child_process";
|
|
9
|
-
import { randomBytes } from "crypto";
|
|
9
|
+
import { randomBytes, randomUUID } from "crypto";
|
|
10
10
|
import { existsSync, promises, readFileSync, statSync } from "fs";
|
|
11
11
|
import { homedir } from "os";
|
|
12
12
|
import path, { extname } from "path";
|
|
@@ -2931,6 +2931,171 @@ function createJupyterClientFromEnv() {
|
|
|
2931
2931
|
});
|
|
2932
2932
|
}
|
|
2933
2933
|
//#endregion
|
|
2934
|
+
//#region src/commands/executeNotebookHandler.ts
|
|
2935
|
+
/**
|
|
2936
|
+
* Jupyter Notebook Execution Handler
|
|
2937
|
+
*
|
|
2938
|
+
* Handles the jupyter_execute_notebook Keep command.
|
|
2939
|
+
* Orchestrates cell-by-cell execution of a notebook via local Jupyter server.
|
|
2940
|
+
*/
|
|
2941
|
+
/**
|
|
2942
|
+
* Zod schema for validating execute notebook parameters.
|
|
2943
|
+
* Replaces unsafe `as` casts with proper runtime validation.
|
|
2944
|
+
*/
|
|
2945
|
+
const ExecuteNotebookParams = z.object({
|
|
2946
|
+
notebookJson: z.string().min(1, "notebookJson is required"),
|
|
2947
|
+
sessionId: z.string().min(1, "sessionId is required"),
|
|
2948
|
+
kernelName: z.string().default("python3"),
|
|
2949
|
+
timeoutPerCell: z.number().default(3e4)
|
|
2950
|
+
});
|
|
2951
|
+
/**
|
|
2952
|
+
* Get cell source as string (handles both string and string[] formats).
|
|
2953
|
+
*/
|
|
2954
|
+
function getCellSource(cell) {
|
|
2955
|
+
return Array.isArray(cell.source) ? cell.source.join("") : cell.source;
|
|
2956
|
+
}
|
|
2957
|
+
/**
|
|
2958
|
+
* Execute a Jupyter notebook cell by cell.
|
|
2959
|
+
*
|
|
2960
|
+
* @param params - Validated notebook execution parameters
|
|
2961
|
+
* @param deps - Dependencies (jupyter client, websocket manager, logger)
|
|
2962
|
+
* @returns Execution result with success status and executed notebook
|
|
2963
|
+
*/
|
|
2964
|
+
async function executeNotebook(params, deps) {
|
|
2965
|
+
const { jupyterClient, wsManager, logger, requestId } = deps;
|
|
2966
|
+
const { notebookJson, sessionId, kernelName, timeoutPerCell } = ExecuteNotebookParams.parse(params);
|
|
2967
|
+
let notebook;
|
|
2968
|
+
try {
|
|
2969
|
+
notebook = JSON.parse(notebookJson);
|
|
2970
|
+
if (!notebook.cells || !Array.isArray(notebook.cells)) throw new Error("Invalid notebook: missing cells array");
|
|
2971
|
+
} catch (parseErr) {
|
|
2972
|
+
throw new Error(`Failed to parse notebook JSON: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`);
|
|
2973
|
+
}
|
|
2974
|
+
const totalCodeCells = notebook.cells.filter((c) => c.cell_type === "code").length;
|
|
2975
|
+
logger.info(`[Keep] Starting notebook execution: ${totalCodeCells} code cells, kernel: ${kernelName}`);
|
|
2976
|
+
const tempNotebookPath = `/tmp/b4m-notebook-${randomUUID()}.ipynb`;
|
|
2977
|
+
await promises.writeFile(tempNotebookPath, notebookJson, "utf-8");
|
|
2978
|
+
let jupyterSession = null;
|
|
2979
|
+
let cellsExecuted = 0;
|
|
2980
|
+
let cellsFailed = 0;
|
|
2981
|
+
try {
|
|
2982
|
+
logger.info(`[Keep] Starting Jupyter kernel: ${kernelName}`);
|
|
2983
|
+
jupyterSession = await jupyterClient.startSession(tempNotebookPath, kernelName);
|
|
2984
|
+
const kernelId = jupyterSession.kernel.id;
|
|
2985
|
+
const jupyterSessionId = jupyterSession.id;
|
|
2986
|
+
logger.info(`[Keep] Kernel started: session=${jupyterSessionId}, kernel=${kernelId}`);
|
|
2987
|
+
let codeCellIndex = 0;
|
|
2988
|
+
for (let i = 0; i < notebook.cells.length; i++) {
|
|
2989
|
+
const cell = notebook.cells[i];
|
|
2990
|
+
if (cell.cell_type !== "code") continue;
|
|
2991
|
+
const cellCode = getCellSource(cell);
|
|
2992
|
+
if (!cellCode.trim()) {
|
|
2993
|
+
codeCellIndex++;
|
|
2994
|
+
continue;
|
|
2995
|
+
}
|
|
2996
|
+
logger.info(`[Keep] Executing cell ${codeCellIndex + 1}/${totalCodeCells}`);
|
|
2997
|
+
wsManager?.send({
|
|
2998
|
+
action: "jupyter_cell_output",
|
|
2999
|
+
requestId,
|
|
3000
|
+
sessionId,
|
|
3001
|
+
jupyterSessionId,
|
|
3002
|
+
cellIndex: codeCellIndex,
|
|
3003
|
+
outputType: "stream",
|
|
3004
|
+
content: {
|
|
3005
|
+
text: `Executing cell ${codeCellIndex + 1}/${totalCodeCells}...`,
|
|
3006
|
+
name: "stdout"
|
|
3007
|
+
},
|
|
3008
|
+
executionCount: null,
|
|
3009
|
+
isComplete: false
|
|
3010
|
+
});
|
|
3011
|
+
try {
|
|
3012
|
+
const cellResult = await jupyterClient.executeCell(kernelId, cellCode, timeoutPerCell);
|
|
3013
|
+
cell.outputs = cellResult.outputs;
|
|
3014
|
+
cell.execution_count = cellResult.executionCount;
|
|
3015
|
+
if (cellResult.success) {
|
|
3016
|
+
cellsExecuted++;
|
|
3017
|
+
wsManager?.send({
|
|
3018
|
+
action: "jupyter_cell_output",
|
|
3019
|
+
requestId,
|
|
3020
|
+
sessionId,
|
|
3021
|
+
jupyterSessionId,
|
|
3022
|
+
cellIndex: codeCellIndex,
|
|
3023
|
+
outputType: "execute_result",
|
|
3024
|
+
content: {
|
|
3025
|
+
text: cellResult.outputs.map((o) => {
|
|
3026
|
+
if (o.text) return Array.isArray(o.text) ? o.text.join("") : o.text;
|
|
3027
|
+
if (o.data && typeof o.data === "object" && "text/plain" in o.data) {
|
|
3028
|
+
const textPlain = o.data["text/plain"];
|
|
3029
|
+
return Array.isArray(textPlain) ? textPlain.join("") : String(textPlain);
|
|
3030
|
+
}
|
|
3031
|
+
return "";
|
|
3032
|
+
}).join(""),
|
|
3033
|
+
data: cellResult.outputs.find((o) => o.data)?.data
|
|
3034
|
+
},
|
|
3035
|
+
executionCount: cellResult.executionCount,
|
|
3036
|
+
isComplete: true
|
|
3037
|
+
});
|
|
3038
|
+
} else {
|
|
3039
|
+
cellsFailed++;
|
|
3040
|
+
wsManager?.send({
|
|
3041
|
+
action: "jupyter_cell_output",
|
|
3042
|
+
requestId,
|
|
3043
|
+
sessionId,
|
|
3044
|
+
jupyterSessionId,
|
|
3045
|
+
cellIndex: codeCellIndex,
|
|
3046
|
+
outputType: "error",
|
|
3047
|
+
content: {
|
|
3048
|
+
ename: cellResult.error?.ename || "ExecutionError",
|
|
3049
|
+
evalue: cellResult.error?.evalue || "Cell execution failed",
|
|
3050
|
+
traceback: cellResult.error?.traceback || []
|
|
3051
|
+
},
|
|
3052
|
+
executionCount: cellResult.executionCount,
|
|
3053
|
+
isComplete: true
|
|
3054
|
+
});
|
|
3055
|
+
logger.warn(`[Keep] Cell ${codeCellIndex + 1} failed: ${cellResult.error?.ename}: ${cellResult.error?.evalue}`);
|
|
3056
|
+
}
|
|
3057
|
+
} catch (cellErr) {
|
|
3058
|
+
cellsFailed++;
|
|
3059
|
+
const errMsg = cellErr instanceof Error ? cellErr.message : String(cellErr);
|
|
3060
|
+
wsManager?.send({
|
|
3061
|
+
action: "jupyter_cell_output",
|
|
3062
|
+
requestId,
|
|
3063
|
+
sessionId,
|
|
3064
|
+
jupyterSessionId,
|
|
3065
|
+
cellIndex: codeCellIndex,
|
|
3066
|
+
outputType: "error",
|
|
3067
|
+
content: {
|
|
3068
|
+
ename: "ExecutionError",
|
|
3069
|
+
evalue: errMsg,
|
|
3070
|
+
traceback: []
|
|
3071
|
+
},
|
|
3072
|
+
executionCount: null,
|
|
3073
|
+
isComplete: true
|
|
3074
|
+
});
|
|
3075
|
+
logger.error(`[Keep] Cell ${codeCellIndex + 1} threw error: ${errMsg}`);
|
|
3076
|
+
}
|
|
3077
|
+
codeCellIndex++;
|
|
3078
|
+
}
|
|
3079
|
+
return {
|
|
3080
|
+
success: cellsFailed === 0,
|
|
3081
|
+
cellsExecuted,
|
|
3082
|
+
cellsFailed,
|
|
3083
|
+
totalCodeCells,
|
|
3084
|
+
executedNotebook: JSON.stringify(notebook)
|
|
3085
|
+
};
|
|
3086
|
+
} finally {
|
|
3087
|
+
if (jupyterSession) try {
|
|
3088
|
+
logger.info(`[Keep] Stopping Jupyter session: ${jupyterSession.id}`);
|
|
3089
|
+
await jupyterClient.stopSession(jupyterSession.id);
|
|
3090
|
+
} catch (stopErr) {
|
|
3091
|
+
logger.warn(`[Keep] Failed to stop session: ${stopErr instanceof Error ? stopErr.message : String(stopErr)}`);
|
|
3092
|
+
}
|
|
3093
|
+
try {
|
|
3094
|
+
await promises.unlink(tempNotebookPath);
|
|
3095
|
+
} catch {}
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
//#endregion
|
|
2934
3099
|
//#region src/llm/NotifyingLlmBackend.ts
|
|
2935
3100
|
/**
|
|
2936
3101
|
* LLM backend wrapper that injects background agent notifications
|
|
@@ -3030,7 +3195,8 @@ function createDynamicAgentTool(orchestrator, parentSessionId, backgroundManager
|
|
|
3030
3195
|
deniedTools,
|
|
3031
3196
|
maxIterations: { ...DEFAULT_MAX_ITERATIONS },
|
|
3032
3197
|
defaultThoroughness: DEFAULT_THOROUGHNESS,
|
|
3033
|
-
defaultVariables: params.variables
|
|
3198
|
+
defaultVariables: params.variables,
|
|
3199
|
+
retry: { ...DEFAULT_RETRY_CONFIG }
|
|
3034
3200
|
};
|
|
3035
3201
|
const spawnOptions = {
|
|
3036
3202
|
task: params.task,
|
|
@@ -4408,6 +4574,14 @@ function CliApp() {
|
|
|
4408
4574
|
};
|
|
4409
4575
|
break;
|
|
4410
4576
|
}
|
|
4577
|
+
case "jupyter_execute_notebook":
|
|
4578
|
+
result = await executeNotebook(params, {
|
|
4579
|
+
jupyterClient: getRequiredJupyterClient(),
|
|
4580
|
+
wsManager,
|
|
4581
|
+
logger,
|
|
4582
|
+
requestId
|
|
4583
|
+
});
|
|
4584
|
+
break;
|
|
4411
4585
|
default: throw new Error(`Unknown command type: ${commandType}`);
|
|
4412
4586
|
}
|
|
4413
4587
|
} catch (err) {
|
|
@@ -4606,7 +4780,9 @@ function CliApp() {
|
|
|
4606
4780
|
const agentDelegateTool = createAgentDelegateTool(orchestrator, agentStore, newSession.id, backgroundManager);
|
|
4607
4781
|
const dynamicAgentTool = config.preferences.enableDynamicAgentCreation === true ? createDynamicAgentTool(orchestrator, newSession.id, backgroundManager) : null;
|
|
4608
4782
|
const backgroundTools = createBackgroundAgentTools(backgroundManager);
|
|
4609
|
-
const notifyingLlm = new NotifyingLlmBackend(llm,
|
|
4783
|
+
const notifyingLlm = new NotifyingLlmBackend(config.fallbackModels && config.fallbackModels.length > 0 ? new FallbackLlmBackend(llm, config.fallbackModels, (fromModel, toModel, error) => {
|
|
4784
|
+
logger.warn(`⚠️ Model "${fromModel}" failed (${error.message}) — falling back to "${toModel}"`);
|
|
4785
|
+
}) : llm, backgroundManager);
|
|
4610
4786
|
const writeTodosTool = createWriteTodosTool(createTodoStore());
|
|
4611
4787
|
const enableSkillTool = config.preferences.enableSkillTool !== false;
|
|
4612
4788
|
const skillTool = enableSkillTool ? createSkillTool({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as RegInviteEvents, A as ImageGenerationUsageTransaction, B as OpenAIEmbeddingModel, C as FileEvents, Ct as isGPTImageModel, D as GenericCreditAddTransaction, E as GenerateImageToolCallSchema, F as KnowledgeType, G as ProjectEvents, H as Permission, I as LLMEvents, J as QuestMasterParamsSchema, K as PromptMetaZodSchema, L as MiscEvents, M as InboxEvents, N as InviteEvents, O as GenericCreditDeductTransaction, Ot as CollectionType, P as InviteType, Q as RechartsChartTypeList, R as ModalEvents, S as FeedbackEvents, St as getViewById, T as GEMINI_IMAGE_MODELS, Tt as sanitizeTelemetryError, U as PermissionDeniedError, V as OpenAIImageGenerationInput, W as ProfileEvents, X as RealtimeVoiceUsageTransaction, Y as REASONING_SUPPORTED_MODELS, Z as ReceivedCreditTransaction, _ as CompletionApiUsageTransaction, _t as VoyageAIEmbeddingModel, a as ApiKeyEvents, at as SpeechToTextModels, b as FIXED_TEMPERATURE_MODELS, bt as getDataLakeTags, c as AppFileEvents, ct as TagType, d as BFL_IMAGE_MODELS, dt as ToolUsageTransaction, et as ResearchModeParamsSchema, f as BFL_SAFETY_TOLERANCE, ft as TransferCreditTransaction, g as ChatModels, gt as VideoModels, h as ChatCompletionCreateInputSchema, ht as VideoGenerationUsageTransaction, i as AiEvents, it as SessionEvents, j as ImageModels, k as ImageEditUsageTransaction, l as ArtifactTypeSchema, lt as TaskScheduleHandler, mt as VIDEO_SIZE_CONSTRAINTS, n as logger, nt as ResearchTaskPeriodicFrequencyType, o as ApiKeyScope, ot as SubscriptionCreditTransaction, p as BedrockEmbeddingModel, pt as UiNavigationEvents, q as PurchaseTransaction, r as ALERT_THRESHOLDS, rt as ResearchTaskType, s as ApiKeyType, st as SupportedFabFileMimeTypes, t as ConfigStore, tt as ResearchTaskExecutionType, u as AuthEvents, ut as TextGenerationUsageTransaction, v as DashboardParamsSchema, vt as XAI_IMAGE_MODELS, w as FriendshipEvents, wt as resolveNavigationIntents, x as FavoriteDocumentType, xt as getMcpProviderMetadata, y as ElabsEvents, yt as b4mLLMTools, z as ModelBackend } from "./ConfigStore-
|
|
2
|
+
import { $ as RegInviteEvents, A as ImageGenerationUsageTransaction, B as OpenAIEmbeddingModel, C as FileEvents, Ct as isGPTImageModel, D as GenericCreditAddTransaction, E as GenerateImageToolCallSchema, F as KnowledgeType, G as ProjectEvents, H as Permission, I as LLMEvents, J as QuestMasterParamsSchema, K as PromptMetaZodSchema, L as MiscEvents, M as InboxEvents, N as InviteEvents, O as GenericCreditDeductTransaction, Ot as CollectionType, P as InviteType, Q as RechartsChartTypeList, R as ModalEvents, S as FeedbackEvents, St as getViewById, T as GEMINI_IMAGE_MODELS, Tt as sanitizeTelemetryError, U as PermissionDeniedError, V as OpenAIImageGenerationInput, W as ProfileEvents, X as RealtimeVoiceUsageTransaction, Y as REASONING_SUPPORTED_MODELS, Z as ReceivedCreditTransaction, _ as CompletionApiUsageTransaction, _t as VoyageAIEmbeddingModel, a as ApiKeyEvents, at as SpeechToTextModels, b as FIXED_TEMPERATURE_MODELS, bt as getDataLakeTags, c as AppFileEvents, ct as TagType, d as BFL_IMAGE_MODELS, dt as ToolUsageTransaction, et as ResearchModeParamsSchema, f as BFL_SAFETY_TOLERANCE, ft as TransferCreditTransaction, g as ChatModels, gt as VideoModels, h as ChatCompletionCreateInputSchema, ht as VideoGenerationUsageTransaction, i as AiEvents, it as SessionEvents, j as ImageModels, k as ImageEditUsageTransaction, l as ArtifactTypeSchema, lt as TaskScheduleHandler, mt as VIDEO_SIZE_CONSTRAINTS, n as logger, nt as ResearchTaskPeriodicFrequencyType, o as ApiKeyScope, ot as SubscriptionCreditTransaction, p as BedrockEmbeddingModel, pt as UiNavigationEvents, q as PurchaseTransaction, r as ALERT_THRESHOLDS, rt as ResearchTaskType, s as ApiKeyType, st as SupportedFabFileMimeTypes, t as ConfigStore, tt as ResearchTaskExecutionType, u as AuthEvents, ut as TextGenerationUsageTransaction, v as DashboardParamsSchema, vt as XAI_IMAGE_MODELS, w as FriendshipEvents, wt as resolveNavigationIntents, x as FavoriteDocumentType, xt as getMcpProviderMetadata, y as ElabsEvents, yt as b4mLLMTools, z as ModelBackend } from "./ConfigStore-CJrPFsAE.mjs";
|
|
3
3
|
import { n as isPathAllowed, t as assertPathAllowed } from "./pathValidation-CIytuhr3-Dt5dntLx.mjs";
|
|
4
4
|
import { execFile, execFileSync, spawn } from "child_process";
|
|
5
5
|
import { createHash, randomBytes } from "crypto";
|
|
@@ -16812,6 +16812,13 @@ var HookBlockedError = class extends Error {
|
|
|
16812
16812
|
*/
|
|
16813
16813
|
const ALWAYS_DENIED_FOR_AGENTS = ["agent_delegate", "create_dynamic_agent"];
|
|
16814
16814
|
/**
|
|
16815
|
+
* Default retry configuration for agent execution
|
|
16816
|
+
*/
|
|
16817
|
+
const DEFAULT_RETRY_CONFIG = {
|
|
16818
|
+
maxRetries: 2,
|
|
16819
|
+
initialDelayMs: 1e3
|
|
16820
|
+
};
|
|
16821
|
+
/**
|
|
16815
16822
|
* Schema for a command hook definition
|
|
16816
16823
|
*/
|
|
16817
16824
|
const CommandHookSchema = z.object({
|
|
@@ -16868,7 +16875,11 @@ const AgentFrontmatterSchema = z.object({
|
|
|
16868
16875
|
"very_thorough"
|
|
16869
16876
|
]).optional(),
|
|
16870
16877
|
variables: z.record(z.string(), z.string()).optional(),
|
|
16871
|
-
hooks: AgentHooksSchema
|
|
16878
|
+
hooks: AgentHooksSchema,
|
|
16879
|
+
retry: z.object({
|
|
16880
|
+
maxRetries: z.int().nonnegative().optional(),
|
|
16881
|
+
initialDelay: z.number().positive().optional()
|
|
16882
|
+
}).optional()
|
|
16872
16883
|
});
|
|
16873
16884
|
/**
|
|
16874
16885
|
* Default iteration limits for agents
|
|
@@ -18189,16 +18200,16 @@ var StreamLogger = class StreamLogger {
|
|
|
18189
18200
|
}
|
|
18190
18201
|
};
|
|
18191
18202
|
//#endregion
|
|
18192
|
-
//#region src/llm/
|
|
18203
|
+
//#region src/llm/streamAccumulator.ts
|
|
18193
18204
|
/**
|
|
18194
|
-
* Strip <think>...</think> blocks from text
|
|
18195
|
-
* Claude's extended thinking should not be shown in final output
|
|
18205
|
+
* Strip <think>...</think> blocks from text.
|
|
18206
|
+
* Claude's extended thinking should not be shown in final output.
|
|
18196
18207
|
*/
|
|
18197
|
-
function stripThinkingBlocks
|
|
18208
|
+
function stripThinkingBlocks(text) {
|
|
18198
18209
|
return text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
18199
18210
|
}
|
|
18200
18211
|
/**
|
|
18201
|
-
* Extract usage and credit information
|
|
18212
|
+
* Extract usage and credit information into CompletionInfo shape.
|
|
18202
18213
|
*/
|
|
18203
18214
|
function extractUsageInfo(parsed) {
|
|
18204
18215
|
return {
|
|
@@ -18209,6 +18220,68 @@ function extractUsageInfo(parsed) {
|
|
|
18209
18220
|
};
|
|
18210
18221
|
}
|
|
18211
18222
|
/**
|
|
18223
|
+
* Accumulates streaming LLM response chunks (text, tool calls, thinking blocks, usage)
|
|
18224
|
+
* and fires the completion callback once at the end.
|
|
18225
|
+
*
|
|
18226
|
+
* Shared between ServerLlmBackend (SSE) and WebSocketLlmBackend (WebSocket frames)
|
|
18227
|
+
* so accumulation logic lives in exactly one place.
|
|
18228
|
+
*/
|
|
18229
|
+
var StreamAccumulator = class {
|
|
18230
|
+
constructor() {
|
|
18231
|
+
this.accumulatedText = "";
|
|
18232
|
+
this.toolsUsed = [];
|
|
18233
|
+
this.thinkingBlocks = [];
|
|
18234
|
+
this.lastUsageInfo = {};
|
|
18235
|
+
}
|
|
18236
|
+
onContent(text, usage, credits) {
|
|
18237
|
+
this.accumulatedText += text;
|
|
18238
|
+
if (usage || credits) this.lastUsageInfo = extractUsageInfo({
|
|
18239
|
+
usage,
|
|
18240
|
+
credits
|
|
18241
|
+
});
|
|
18242
|
+
}
|
|
18243
|
+
onToolUse(text, tools, thinking, usage, credits) {
|
|
18244
|
+
if (text) this.accumulatedText += text;
|
|
18245
|
+
if (tools && tools.length > 0) this.toolsUsed = tools;
|
|
18246
|
+
if (thinking && thinking.length > 0) this.thinkingBlocks = thinking;
|
|
18247
|
+
if (usage || credits) this.lastUsageInfo = extractUsageInfo({
|
|
18248
|
+
usage,
|
|
18249
|
+
credits
|
|
18250
|
+
});
|
|
18251
|
+
}
|
|
18252
|
+
/** True when neither text nor tools have been accumulated (stream produced nothing useful). */
|
|
18253
|
+
isEmpty() {
|
|
18254
|
+
return this.accumulatedText.trim().length === 0 && this.toolsUsed.length === 0;
|
|
18255
|
+
}
|
|
18256
|
+
get accumulatedLength() {
|
|
18257
|
+
return this.accumulatedText.length;
|
|
18258
|
+
}
|
|
18259
|
+
get toolCount() {
|
|
18260
|
+
return this.toolsUsed.length;
|
|
18261
|
+
}
|
|
18262
|
+
/** Raw accumulated text before thinking-block stripping (for debug logging). */
|
|
18263
|
+
get rawText() {
|
|
18264
|
+
return this.accumulatedText;
|
|
18265
|
+
}
|
|
18266
|
+
/**
|
|
18267
|
+
* Calls the completion callback with all accumulated content.
|
|
18268
|
+
* Strips thinking blocks from text before delivering.
|
|
18269
|
+
*/
|
|
18270
|
+
async finalize(callback) {
|
|
18271
|
+
const cleanedText = stripThinkingBlocks(this.accumulatedText);
|
|
18272
|
+
if (this.toolsUsed.length > 0) {
|
|
18273
|
+
const info = {
|
|
18274
|
+
toolsUsed: this.toolsUsed,
|
|
18275
|
+
thinking: this.thinkingBlocks.length > 0 ? this.thinkingBlocks : void 0,
|
|
18276
|
+
...this.lastUsageInfo
|
|
18277
|
+
};
|
|
18278
|
+
await callback([cleanedText], info);
|
|
18279
|
+
} else if (cleanedText) await callback([cleanedText], this.lastUsageInfo);
|
|
18280
|
+
}
|
|
18281
|
+
};
|
|
18282
|
+
//#endregion
|
|
18283
|
+
//#region src/llm/ServerLlmBackend.ts
|
|
18284
|
+
/**
|
|
18212
18285
|
* Server-side LLM backend that proxies requests through Bike4Mind API
|
|
18213
18286
|
* Uses Server-Sent Events (SSE) for streaming responses
|
|
18214
18287
|
* API keys remain secure on server - never exposed to CLI
|
|
@@ -18311,10 +18384,7 @@ var ServerLlmBackend = class ServerLlmBackend {
|
|
|
18311
18384
|
const streamLogger = new StreamLogger(logger, "ServerLlmBackend", process.env.B4M_VERBOSE === "1", process.env.B4M_DEBUG_STREAM === "1");
|
|
18312
18385
|
streamLogger.streamStart();
|
|
18313
18386
|
let eventCount = 0;
|
|
18314
|
-
|
|
18315
|
-
let lastUsageInfo = {};
|
|
18316
|
-
let toolsUsed = [];
|
|
18317
|
-
let thinkingBlocks = [];
|
|
18387
|
+
const accumulator = new StreamAccumulator();
|
|
18318
18388
|
let receivedDone = false;
|
|
18319
18389
|
const parser = createParser({ onEvent: (event) => {
|
|
18320
18390
|
eventCount++;
|
|
@@ -18322,28 +18392,15 @@ var ServerLlmBackend = class ServerLlmBackend {
|
|
|
18322
18392
|
const data = event.data;
|
|
18323
18393
|
if (data === "[DONE]") {
|
|
18324
18394
|
receivedDone = true;
|
|
18325
|
-
streamLogger.onCriticalEvent(eventCount, "[DONE]", `accumulated text length: ${
|
|
18326
|
-
|
|
18327
|
-
|
|
18328
|
-
if (toolsUsed.length > 0) {
|
|
18329
|
-
const info = {
|
|
18330
|
-
toolsUsed,
|
|
18331
|
-
thinking: thinkingBlocks.length > 0 ? thinkingBlocks : void 0,
|
|
18332
|
-
...lastUsageInfo
|
|
18333
|
-
};
|
|
18334
|
-
logger.debug(`[ServerLlmBackend] Calling callback with tools, thinking blocks: ${thinkingBlocks.length}`);
|
|
18335
|
-
callback([cleanedText], info).catch((err) => {
|
|
18336
|
-
logger.error("[ServerLlmBackend] Callback error:", err);
|
|
18337
|
-
reject(err);
|
|
18338
|
-
}).then(() => {
|
|
18339
|
-
logger.debug("[ServerLlmBackend] Callback completed, resolving");
|
|
18340
|
-
resolve();
|
|
18341
|
-
});
|
|
18342
|
-
} else if (cleanedText) callback([cleanedText], lastUsageInfo).catch((err) => {
|
|
18395
|
+
streamLogger.onCriticalEvent(eventCount, "[DONE]", `accumulated text length: ${accumulator.accumulatedLength}`);
|
|
18396
|
+
streamLogger.streamComplete(accumulator.rawText);
|
|
18397
|
+
accumulator.finalize(callback).catch((err) => {
|
|
18343
18398
|
logger.error("[ServerLlmBackend] Callback error:", err);
|
|
18344
18399
|
reject(err);
|
|
18345
|
-
}).then(() =>
|
|
18346
|
-
|
|
18400
|
+
}).then(() => {
|
|
18401
|
+
logger.debug("[ServerLlmBackend] Callback completed, resolving");
|
|
18402
|
+
resolve();
|
|
18403
|
+
});
|
|
18347
18404
|
return;
|
|
18348
18405
|
}
|
|
18349
18406
|
try {
|
|
@@ -18355,9 +18412,8 @@ var ServerLlmBackend = class ServerLlmBackend {
|
|
|
18355
18412
|
}
|
|
18356
18413
|
if (parsed.type === "content") {
|
|
18357
18414
|
const textChunk = parsed.text || "";
|
|
18358
|
-
|
|
18359
|
-
|
|
18360
|
-
streamLogger.onContent(eventCount, textChunk, accumulatedText);
|
|
18415
|
+
accumulator.onContent(textChunk, parsed.usage, parsed.credits);
|
|
18416
|
+
streamLogger.onContent(eventCount, textChunk, accumulator.rawText);
|
|
18361
18417
|
} else if (parsed.type === "tool_use") {
|
|
18362
18418
|
streamLogger.onCriticalEvent(eventCount, "TOOL_USE", `tools: ${parsed.tools?.length}`);
|
|
18363
18419
|
if (parsed.tools && parsed.tools.length > 0) for (const tool of parsed.tools) {
|
|
@@ -18369,14 +18425,8 @@ var ServerLlmBackend = class ServerLlmBackend {
|
|
|
18369
18425
|
logger.debug(` Params: [Unable to stringify]`);
|
|
18370
18426
|
}
|
|
18371
18427
|
}
|
|
18372
|
-
|
|
18373
|
-
if (
|
|
18374
|
-
if (parsed.tools && parsed.tools.length > 0) toolsUsed = parsed.tools;
|
|
18375
|
-
if (parsed.thinking && parsed.thinking.length > 0) {
|
|
18376
|
-
thinkingBlocks = parsed.thinking;
|
|
18377
|
-
streamLogger.onCriticalEvent(eventCount, "THINKING", `${thinkingBlocks.length} thinking blocks`);
|
|
18378
|
-
}
|
|
18379
|
-
if (parsed.usage || parsed.credits) lastUsageInfo = extractUsageInfo(parsed);
|
|
18428
|
+
accumulator.onToolUse(parsed.text || "", parsed.tools, parsed.thinking, parsed.usage, parsed.credits);
|
|
18429
|
+
if (parsed.thinking && parsed.thinking.length > 0) streamLogger.onCriticalEvent(eventCount, "THINKING", `${parsed.thinking.length} thinking blocks`);
|
|
18380
18430
|
}
|
|
18381
18431
|
} catch (parseError) {
|
|
18382
18432
|
streamLogger.streamError(parseError);
|
|
@@ -18403,20 +18453,10 @@ var ServerLlmBackend = class ServerLlmBackend {
|
|
|
18403
18453
|
});
|
|
18404
18454
|
response.data.on("end", () => {
|
|
18405
18455
|
if (!receivedDone) {
|
|
18406
|
-
|
|
18407
|
-
|
|
18408
|
-
|
|
18409
|
-
|
|
18410
|
-
streamLogger.streamComplete(accumulatedText);
|
|
18411
|
-
if (toolsUsed.length > 0) {
|
|
18412
|
-
const info = {
|
|
18413
|
-
toolsUsed,
|
|
18414
|
-
thinking: thinkingBlocks.length > 0 ? thinkingBlocks : void 0,
|
|
18415
|
-
...lastUsageInfo
|
|
18416
|
-
};
|
|
18417
|
-
callback([cleanedText], info).then(() => resolve(), reject);
|
|
18418
|
-
} else if (cleanedText) callback([cleanedText], lastUsageInfo).then(() => resolve(), reject);
|
|
18419
|
-
else resolve();
|
|
18456
|
+
logger.warn(`[ServerLlmBackend] Stream ended without [DONE] signal. Accumulated text: ${accumulator.accumulatedLength} chars, tools: ${accumulator.toolCount}`);
|
|
18457
|
+
if (!accumulator.isEmpty()) {
|
|
18458
|
+
streamLogger.streamComplete(accumulator.rawText);
|
|
18459
|
+
accumulator.finalize(callback).then(() => resolve(), reject);
|
|
18420
18460
|
} else reject(/* @__PURE__ */ new Error("Stream ended prematurely without receiving any data. The server may be experiencing issues."));
|
|
18421
18461
|
} else logger.debug("[ServerLlmBackend] Stream ended, [DONE] handler will resolve");
|
|
18422
18462
|
});
|
|
@@ -18537,9 +18577,6 @@ var ServerLlmBackend = class ServerLlmBackend {
|
|
|
18537
18577
|
};
|
|
18538
18578
|
//#endregion
|
|
18539
18579
|
//#region src/llm/WebSocketLlmBackend.ts
|
|
18540
|
-
function stripThinkingBlocks(text) {
|
|
18541
|
-
return text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
18542
|
-
}
|
|
18543
18580
|
/**
|
|
18544
18581
|
* Hybrid HTTP + WebSocket LLM backend for CLI completions.
|
|
18545
18582
|
*
|
|
@@ -18573,10 +18610,7 @@ var WebSocketLlmBackend = class {
|
|
|
18573
18610
|
const streamLogger = new StreamLogger(logger, "WebSocketLlmBackend", process.env.B4M_VERBOSE === "1", process.env.B4M_DEBUG_STREAM === "1");
|
|
18574
18611
|
streamLogger.streamStart();
|
|
18575
18612
|
let eventCount = 0;
|
|
18576
|
-
|
|
18577
|
-
let lastUsageInfo = {};
|
|
18578
|
-
let toolsUsed = [];
|
|
18579
|
-
let thinkingBlocks = [];
|
|
18613
|
+
const accumulator = new StreamAccumulator();
|
|
18580
18614
|
let settled = false;
|
|
18581
18615
|
const settle = (action) => {
|
|
18582
18616
|
if (settled) return;
|
|
@@ -18604,12 +18638,6 @@ var WebSocketLlmBackend = class {
|
|
|
18604
18638
|
}
|
|
18605
18639
|
options.abortSignal.addEventListener("abort", abortHandler, { once: true });
|
|
18606
18640
|
}
|
|
18607
|
-
const updateUsage = (usage) => {
|
|
18608
|
-
if (usage) lastUsageInfo = {
|
|
18609
|
-
inputTokens: usage.inputTokens,
|
|
18610
|
-
outputTokens: usage.outputTokens
|
|
18611
|
-
};
|
|
18612
|
-
};
|
|
18613
18641
|
this.wsManager.onRequest(requestId, (message) => {
|
|
18614
18642
|
if (options.abortSignal?.aborted) return;
|
|
18615
18643
|
const action = message.action;
|
|
@@ -18617,28 +18645,20 @@ var WebSocketLlmBackend = class {
|
|
|
18617
18645
|
eventCount++;
|
|
18618
18646
|
const chunk = message.chunk;
|
|
18619
18647
|
streamLogger.onEvent(eventCount, JSON.stringify(chunk));
|
|
18620
|
-
|
|
18621
|
-
|
|
18622
|
-
|
|
18623
|
-
if (chunk.type === "
|
|
18624
|
-
else if (chunk.type === "tool_use") {
|
|
18648
|
+
if (chunk.type === "content") {
|
|
18649
|
+
accumulator.onContent(chunk.text || "", chunk.usage);
|
|
18650
|
+
streamLogger.onContent(eventCount, chunk.text || "", accumulator.rawText);
|
|
18651
|
+
} else if (chunk.type === "tool_use") {
|
|
18625
18652
|
streamLogger.onCriticalEvent(eventCount, "TOOL_USE", `tools: ${chunk.tools?.length}`);
|
|
18626
|
-
|
|
18627
|
-
if (chunk.thinking && chunk.thinking.length > 0) thinkingBlocks = chunk.thinking;
|
|
18653
|
+
accumulator.onToolUse(chunk.text || "", chunk.tools, chunk.thinking, chunk.usage);
|
|
18628
18654
|
}
|
|
18629
18655
|
} else if (action === "cli_completion_done") {
|
|
18630
|
-
streamLogger.streamComplete(
|
|
18631
|
-
|
|
18632
|
-
if (!cleanedText && toolsUsed.length === 0) {
|
|
18656
|
+
streamLogger.streamComplete(accumulator.rawText);
|
|
18657
|
+
if (accumulator.isEmpty()) {
|
|
18633
18658
|
settleResolve();
|
|
18634
18659
|
return;
|
|
18635
18660
|
}
|
|
18636
|
-
|
|
18637
|
-
...lastUsageInfo,
|
|
18638
|
-
...toolsUsed.length > 0 && { toolsUsed },
|
|
18639
|
-
...thinkingBlocks.length > 0 && { thinking: thinkingBlocks }
|
|
18640
|
-
};
|
|
18641
|
-
callback([cleanedText], info).then(() => settleResolve()).catch((err) => settleReject(err));
|
|
18661
|
+
accumulator.finalize(callback).then(() => settleResolve()).catch((err) => settleReject(err));
|
|
18642
18662
|
} else if (action === "cli_completion_error") {
|
|
18643
18663
|
const errorMsg = message.error || "Server error";
|
|
18644
18664
|
streamLogger.onCriticalEvent(eventCount, "ERROR", errorMsg);
|
|
@@ -18739,6 +18759,65 @@ var WebSocketLlmBackend = class {
|
|
|
18739
18759
|
}
|
|
18740
18760
|
};
|
|
18741
18761
|
//#endregion
|
|
18762
|
+
//#region src/llm/FallbackLlmBackend.ts
|
|
18763
|
+
/**
|
|
18764
|
+
* LLM backend decorator that provides model-level fallback routing.
|
|
18765
|
+
*
|
|
18766
|
+
* When the primary model fails (after the inner backend's own retries are exhausted),
|
|
18767
|
+
* FallbackLlmBackend tries the next model in the configured fallback chain.
|
|
18768
|
+
*
|
|
18769
|
+
* Example chain: Opus → Sonnet → Haiku (graceful degradation under rate limits)
|
|
18770
|
+
*
|
|
18771
|
+
* Configured via `CliConfig.fallbackModels`. Wraps any `ICompletionBackend`,
|
|
18772
|
+
* fitting cleanly into the existing decorator pattern (NotifyingLlmBackend, etc.).
|
|
18773
|
+
*/
|
|
18774
|
+
var FallbackLlmBackend = class {
|
|
18775
|
+
constructor(inner, fallbackModels, onFallback) {
|
|
18776
|
+
this.inner = inner;
|
|
18777
|
+
this.fallbackModels = fallbackModels;
|
|
18778
|
+
this.onFallback = onFallback;
|
|
18779
|
+
}
|
|
18780
|
+
get currentModel() {
|
|
18781
|
+
return this.inner.currentModel;
|
|
18782
|
+
}
|
|
18783
|
+
set currentModel(model) {
|
|
18784
|
+
this.inner.currentModel = model;
|
|
18785
|
+
}
|
|
18786
|
+
async complete(model, messages, options, callback) {
|
|
18787
|
+
if (options.abortSignal?.aborted) return this.inner.complete(model, messages, options, callback);
|
|
18788
|
+
const modelsToTry = [model, ...this.fallbackModels.filter((m) => m !== model)];
|
|
18789
|
+
let callbackInvoked = false;
|
|
18790
|
+
const guardedCallback = async (text, completionInfo) => {
|
|
18791
|
+
callbackInvoked = true;
|
|
18792
|
+
return callback(text, completionInfo);
|
|
18793
|
+
};
|
|
18794
|
+
let lastError;
|
|
18795
|
+
for (let i = 0; i < modelsToTry.length; i++) {
|
|
18796
|
+
const modelToTry = modelsToTry[i];
|
|
18797
|
+
try {
|
|
18798
|
+
await this.inner.complete(modelToTry, messages, options, guardedCallback);
|
|
18799
|
+
return;
|
|
18800
|
+
} catch (error) {
|
|
18801
|
+
if (options.abortSignal?.aborted) throw error;
|
|
18802
|
+
if (callbackInvoked) throw error;
|
|
18803
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
18804
|
+
const nextModel = modelsToTry[i + 1];
|
|
18805
|
+
if (nextModel) {
|
|
18806
|
+
logger.warn(`[FallbackLlmBackend] Model "${modelToTry}" failed: ${lastError.message}`);
|
|
18807
|
+
this.onFallback(modelToTry, nextModel, lastError);
|
|
18808
|
+
}
|
|
18809
|
+
}
|
|
18810
|
+
}
|
|
18811
|
+
throw lastError ?? /* @__PURE__ */ new Error("All fallback models exhausted");
|
|
18812
|
+
}
|
|
18813
|
+
pushToolMessages(messages, tool, result, thinkingBlocks) {
|
|
18814
|
+
this.inner.pushToolMessages(messages, tool, result, thinkingBlocks);
|
|
18815
|
+
}
|
|
18816
|
+
async getModelInfo() {
|
|
18817
|
+
return this.inner.getModelInfo();
|
|
18818
|
+
}
|
|
18819
|
+
};
|
|
18820
|
+
//#endregion
|
|
18742
18821
|
//#region src/ws/WebSocketConnectionManager.ts
|
|
18743
18822
|
const useWsPolyfill = typeof globalThis.WebSocket === "undefined";
|
|
18744
18823
|
const WS = useWsPolyfill ? WsWebSocket : globalThis.WebSocket;
|
|
@@ -19423,7 +19502,7 @@ var SubagentOrchestrator = class {
|
|
|
19423
19502
|
* @returns Agent result with summary
|
|
19424
19503
|
*/
|
|
19425
19504
|
async delegateToAgent(options) {
|
|
19426
|
-
const { task, agentName, thoroughness, variables, parentSessionId, model, allowedTools } = options;
|
|
19505
|
+
const { task, agentName, thoroughness, variables, parentSessionId, model, allowedTools, abortSignal } = options;
|
|
19427
19506
|
let agentDef;
|
|
19428
19507
|
if (options.agentDefinition) agentDef = {
|
|
19429
19508
|
...options.agentDefinition,
|
|
@@ -19498,11 +19577,22 @@ var SubagentOrchestrator = class {
|
|
|
19498
19577
|
const startTime = Date.now();
|
|
19499
19578
|
let result;
|
|
19500
19579
|
try {
|
|
19501
|
-
result = await agent.run(task, {
|
|
19580
|
+
const { result: agentResult, attempts } = await withRetry(() => agent.run(task, {
|
|
19502
19581
|
maxIterations,
|
|
19503
19582
|
parallelExecution: this.deps.enableParallelToolExecution === true,
|
|
19504
19583
|
isReadOnlyTool
|
|
19584
|
+
}), {
|
|
19585
|
+
maxRetries: agentDef.retry.maxRetries,
|
|
19586
|
+
initialDelayMs: agentDef.retry.initialDelayMs,
|
|
19587
|
+
isRetryable: isRetryableError,
|
|
19588
|
+
abortSignal,
|
|
19589
|
+
logger: {
|
|
19590
|
+
info: (msg, meta) => this.deps.logger.info(`[${agentName}] ${msg}`, meta),
|
|
19591
|
+
warn: (msg, meta) => this.deps.logger.warn(`[${agentName}] ${msg}`, meta)
|
|
19592
|
+
}
|
|
19505
19593
|
});
|
|
19594
|
+
if (attempts > 0) this.deps.logger.info(`[${agentName}] Recovered after ${attempts} retry attempt${attempts === 1 ? "" : "s"}`);
|
|
19595
|
+
result = agentResult;
|
|
19506
19596
|
} catch (error) {
|
|
19507
19597
|
if (error instanceof HookBlockedError) {
|
|
19508
19598
|
if (this.afterRunCallback) this.afterRunCallback(agent, agentName);
|
|
@@ -19844,7 +19934,11 @@ var AgentStore = class {
|
|
|
19844
19934
|
hooks: parsed.hooks,
|
|
19845
19935
|
source,
|
|
19846
19936
|
filePath,
|
|
19847
|
-
modelResolved: resolution.resolved
|
|
19937
|
+
modelResolved: resolution.resolved,
|
|
19938
|
+
retry: {
|
|
19939
|
+
maxRetries: parsed.retry?.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries,
|
|
19940
|
+
initialDelayMs: parsed.retry?.initialDelay ?? DEFAULT_RETRY_CONFIG.initialDelayMs
|
|
19941
|
+
}
|
|
19848
19942
|
};
|
|
19849
19943
|
}
|
|
19850
19944
|
/**
|
|
@@ -20297,7 +20391,10 @@ var BackgroundAgentManager = class {
|
|
|
20297
20391
|
this.runningCount++;
|
|
20298
20392
|
this.updateJob(internal.job.id, { status: "running" });
|
|
20299
20393
|
const { job, options } = internal;
|
|
20300
|
-
internal.promise = this.orchestrator.delegateToAgent(
|
|
20394
|
+
internal.promise = this.orchestrator.delegateToAgent({
|
|
20395
|
+
...options,
|
|
20396
|
+
abortSignal: internal.abortController.signal
|
|
20397
|
+
}).then((result) => {
|
|
20301
20398
|
this.updateJob(job.id, {
|
|
20302
20399
|
status: "completed",
|
|
20303
20400
|
endTime: Date.now(),
|
|
@@ -20920,4 +21017,4 @@ function createGetFileStructureTool() {
|
|
|
20920
21017
|
};
|
|
20921
21018
|
}
|
|
20922
21019
|
//#endregion
|
|
20923
|
-
export {
|
|
21020
|
+
export { DEFAULT_RETRY_CONFIG as A, CustomCommandStore as B, getApiUrl as C, ALWAYS_DENIED_FOR_AGENTS as D, generateCliTools as E, OllamaBackend as F, hasFileReferences as G, CommandHistoryStore as H, buildCoreSystemPrompt as I, mergeCommands as J, processFileReferences as K, buildSkillsPromptSection as L, clearFeatureModuleTools as M, registerFeatureModuleTools as N, DEFAULT_AGENT_MODEL as O, setWebSocketToolExecutor as P, isReadOnlyTool as R, loadContextFiles as S, PermissionManager as T, SessionStore as U, CheckpointStore as V, OAuthClient as W, searchFiles as X, formatFileSize$1 as Y, warmFileCache as Z, ServerLlmBackend as _, createBackgroundAgentTools as a, formatStep as b, AgentStore as c, parseAgentConfig as d, ApiClient as f, WebSocketLlmBackend as g, FallbackLlmBackend as h, createWriteTodosTool as i, DEFAULT_THOROUGHNESS as j, DEFAULT_MAX_ITERATIONS as k, SubagentOrchestrator as l, WebSocketConnectionManager as m, createFindDefinitionTool as n, BackgroundAgentManager as o, WebSocketToolExecutor as p, searchCommands as q, createTodoStore as r, createAgentDelegateTool as s, createGetFileStructureTool as t, createSkillTool as u, McpManager as v, getEnvironmentName as w, extractCompactInstructions as x, substituteArguments as y, ReActAgent as z };
|
|
@@ -4,7 +4,7 @@ import { homedir } from "os";
|
|
|
4
4
|
import path from "path";
|
|
5
5
|
import axios from "axios";
|
|
6
6
|
//#region package.json
|
|
7
|
-
var version = "0.2.71
|
|
7
|
+
var version = "0.2.71";
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/utils/updateChecker.ts
|
|
10
10
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.2.71
|
|
3
|
+
"version": "0.2.71",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -115,11 +115,11 @@
|
|
|
115
115
|
"zustand": "^4.5.4"
|
|
116
116
|
},
|
|
117
117
|
"devDependencies": {
|
|
118
|
-
"@bike4mind/agents": "0.4.8
|
|
119
|
-
"@bike4mind/common": "2.
|
|
120
|
-
"@bike4mind/mcp": "1.33.27
|
|
121
|
-
"@bike4mind/services": "2.
|
|
122
|
-
"@bike4mind/utils": "2.16.9
|
|
118
|
+
"@bike4mind/agents": "0.4.8",
|
|
119
|
+
"@bike4mind/common": "2.79.0",
|
|
120
|
+
"@bike4mind/mcp": "1.33.27",
|
|
121
|
+
"@bike4mind/services": "2.72.0",
|
|
122
|
+
"@bike4mind/utils": "2.16.9",
|
|
123
123
|
"@types/better-sqlite3": "^7.6.13",
|
|
124
124
|
"@types/jsonwebtoken": "^9.0.4",
|
|
125
125
|
"@types/node": "^22.9.0",
|
|
@@ -136,5 +136,5 @@
|
|
|
136
136
|
"optionalDependencies": {
|
|
137
137
|
"@vscode/ripgrep": "^1.17.1"
|
|
138
138
|
},
|
|
139
|
-
"gitHead": "
|
|
139
|
+
"gitHead": "1d7b05a3d32a0bda3e9b32aab784a26775eab784"
|
|
140
140
|
}
|