@bike4mind/cli 0.2.10-slack-metrics-admin-dashboard.17271 → 0.2.11-cli-cancel-pending-message.17326
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/bin/bike4mind-cli.mjs +9 -1
- package/dist/{artifactExtractor-JAGU7QRL.js → artifactExtractor-BZNU5FMW.js} +1 -1
- package/dist/{chunk-GO75FMLY.js → chunk-DGAIF2QC.js} +2 -2
- package/dist/{chunk-AQBZVAYO.js → chunk-RA3CZOUX.js} +2 -2
- package/dist/{chunk-VZU4Z7WI.js → chunk-RBZRTCAY.js} +2 -2
- package/dist/{chunk-GCVIRGIN.js → chunk-SQBLLN7K.js} +24 -5
- package/dist/{chunk-DJPXSSP4.js → chunk-WCYNJOOX.js} +4 -0
- package/dist/{create-ZDOTF7XD.js → create-4KCG4N2U.js} +3 -3
- package/dist/index.js +911 -212
- package/dist/{llmMarkdownGenerator-LXUGJ7QH.js → llmMarkdownGenerator-TUFLBYA3.js} +1 -1
- package/dist/{markdownGenerator-IMDG6OX6.js → markdownGenerator-2WSEU4QD.js} +1 -1
- package/dist/{mementoService-TURUS3OH.js → mementoService-75KFGFQT.js} +3 -3
- package/dist/{src-6ZRXGE5J.js → src-JZRDAJFC.js} +2 -2
- package/dist/{src-YNY32ELR.js → src-UHKJ3EHY.js} +1 -1
- package/dist/{subtractCredits-GOVKM3IR.js → subtractCredits-MOVABDWW.js} +3 -3
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
getEffectiveApiKey,
|
|
5
5
|
getOpenWeatherKey,
|
|
6
6
|
getSerperKey
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-DGAIF2QC.js";
|
|
8
|
+
import "./chunk-RBZRTCAY.js";
|
|
9
|
+
import "./chunk-RA3CZOUX.js";
|
|
10
10
|
import {
|
|
11
11
|
BFLImageService,
|
|
12
12
|
BaseStorage,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
OpenAIBackend,
|
|
16
16
|
OpenAIImageService,
|
|
17
17
|
XAIImageService
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-SQBLLN7K.js";
|
|
19
19
|
import {
|
|
20
20
|
Logger
|
|
21
21
|
} from "./chunk-AMDXHL6S.js";
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
XAI_IMAGE_MODELS,
|
|
74
74
|
b4mLLMTools,
|
|
75
75
|
getMcpProviderMetadata
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-WCYNJOOX.js";
|
|
77
77
|
import {
|
|
78
78
|
__require
|
|
79
79
|
} from "./chunk-PDX44BCA.js";
|
|
@@ -82,7 +82,7 @@ import {
|
|
|
82
82
|
import React17, { useState as useState8, useEffect as useEffect3, useCallback, useRef as useRef2 } from "react";
|
|
83
83
|
import { render, Box as Box16, Text as Text16, useApp, useInput as useInput6 } from "ink";
|
|
84
84
|
import { execSync } from "child_process";
|
|
85
|
-
import { v4 as
|
|
85
|
+
import { v4 as uuidv410 } from "uuid";
|
|
86
86
|
|
|
87
87
|
// src/components/App.tsx
|
|
88
88
|
import React11, { useState as useState4 } from "react";
|
|
@@ -107,7 +107,8 @@ function CustomTextInput({
|
|
|
107
107
|
onChange,
|
|
108
108
|
onSubmit,
|
|
109
109
|
placeholder = "",
|
|
110
|
-
showCursor = true
|
|
110
|
+
showCursor = true,
|
|
111
|
+
disabled = false
|
|
111
112
|
}) {
|
|
112
113
|
const [cursorOffset, setCursorOffset] = useState(value.length);
|
|
113
114
|
useInput(
|
|
@@ -188,7 +189,7 @@ function CustomTextInput({
|
|
|
188
189
|
setCursorOffset(cursorOffset + 1);
|
|
189
190
|
}
|
|
190
191
|
},
|
|
191
|
-
{ isActive:
|
|
192
|
+
{ isActive: !disabled }
|
|
192
193
|
);
|
|
193
194
|
const hasValue = value.length > 0;
|
|
194
195
|
if (!hasValue) {
|
|
@@ -827,56 +828,59 @@ function InputPrompt({
|
|
|
827
828
|
useEffect(() => {
|
|
828
829
|
setFileSelectedIndex(0);
|
|
829
830
|
}, [filteredFiles]);
|
|
830
|
-
useInput2(
|
|
831
|
-
|
|
832
|
-
if (
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
831
|
+
useInput2(
|
|
832
|
+
(_input, key) => {
|
|
833
|
+
if (fileAutocomplete?.active && filteredFiles.length > 0) {
|
|
834
|
+
if (key.upArrow) {
|
|
835
|
+
setFileSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredFiles.length - 1);
|
|
836
|
+
return;
|
|
837
|
+
} else if (key.downArrow) {
|
|
838
|
+
setFileSelectedIndex((prev) => prev < filteredFiles.length - 1 ? prev + 1 : 0);
|
|
839
|
+
return;
|
|
840
|
+
} else if (key.tab) {
|
|
841
|
+
const selectedFile = filteredFiles[fileSelectedIndex];
|
|
842
|
+
if (selectedFile) {
|
|
843
|
+
insertSelectedFile(selectedFile);
|
|
844
|
+
}
|
|
845
|
+
return;
|
|
846
|
+
} else if (key.escape) {
|
|
847
|
+
setFileAutocomplete(null);
|
|
848
|
+
return;
|
|
842
849
|
}
|
|
843
|
-
return;
|
|
844
|
-
} else if (key.escape) {
|
|
845
|
-
setFileAutocomplete(null);
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
|
|
850
|
-
if (key.upArrow) {
|
|
851
|
-
setSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredCommands.length - 1);
|
|
852
|
-
} else if (key.downArrow) {
|
|
853
|
-
setSelectedIndex((prev) => prev < filteredCommands.length - 1 ? prev + 1 : 0);
|
|
854
850
|
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
setTempInput(value);
|
|
861
|
-
setHistoryIndex(0);
|
|
862
|
-
setValue(history[0]);
|
|
863
|
-
} else if (historyIndex < history.length - 1) {
|
|
864
|
-
const newIndex = historyIndex + 1;
|
|
865
|
-
setHistoryIndex(newIndex);
|
|
866
|
-
setValue(history[newIndex]);
|
|
851
|
+
if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
|
|
852
|
+
if (key.upArrow) {
|
|
853
|
+
setSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredCommands.length - 1);
|
|
854
|
+
} else if (key.downArrow) {
|
|
855
|
+
setSelectedIndex((prev) => prev < filteredCommands.length - 1 ? prev + 1 : 0);
|
|
867
856
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
if (!shouldShowCommandAutocomplete && !fileAutocomplete?.active && history.length > 0) {
|
|
860
|
+
if (key.upArrow) {
|
|
861
|
+
if (historyIndex === -1) {
|
|
862
|
+
setTempInput(value);
|
|
863
|
+
setHistoryIndex(0);
|
|
864
|
+
setValue(history[0]);
|
|
865
|
+
} else if (historyIndex < history.length - 1) {
|
|
866
|
+
const newIndex = historyIndex + 1;
|
|
867
|
+
setHistoryIndex(newIndex);
|
|
868
|
+
setValue(history[newIndex]);
|
|
869
|
+
}
|
|
870
|
+
} else if (key.downArrow) {
|
|
871
|
+
if (historyIndex > 0) {
|
|
872
|
+
const newIndex = historyIndex - 1;
|
|
873
|
+
setHistoryIndex(newIndex);
|
|
874
|
+
setValue(history[newIndex]);
|
|
875
|
+
} else if (historyIndex === 0) {
|
|
876
|
+
setHistoryIndex(-1);
|
|
877
|
+
setValue(tempInput);
|
|
878
|
+
}
|
|
876
879
|
}
|
|
877
880
|
}
|
|
878
|
-
}
|
|
879
|
-
|
|
881
|
+
},
|
|
882
|
+
{ isActive: !disabled }
|
|
883
|
+
);
|
|
880
884
|
const insertSelectedFile = (file) => {
|
|
881
885
|
if (!fileAutocomplete) return;
|
|
882
886
|
const beforeAt = value.slice(0, fileAutocomplete.startIndex);
|
|
@@ -970,7 +974,8 @@ function InputPrompt({
|
|
|
970
974
|
onChange: handleChange,
|
|
971
975
|
onSubmit: handleSubmit,
|
|
972
976
|
placeholder: getPlaceholder(),
|
|
973
|
-
showCursor: !disabled
|
|
977
|
+
showCursor: !disabled,
|
|
978
|
+
disabled
|
|
974
979
|
}
|
|
975
980
|
)), shouldShowCommandAutocomplete && /* @__PURE__ */ React5.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React5.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
|
|
976
981
|
}
|
|
@@ -983,8 +988,8 @@ import { Box as Box6 } from "ink";
|
|
|
983
988
|
import React6 from "react";
|
|
984
989
|
import { Box as Box5, Text as Text6 } from "ink";
|
|
985
990
|
import Spinner from "ink-spinner";
|
|
986
|
-
var ThoughtStream = React6.memo(function ThoughtStream2({
|
|
987
|
-
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", gap: 1 },
|
|
991
|
+
var ThoughtStream = React6.memo(function ThoughtStream2({ isThinking }) {
|
|
992
|
+
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", gap: 1 }, isThinking && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " Thinking...")));
|
|
988
993
|
});
|
|
989
994
|
|
|
990
995
|
// src/store/index.ts
|
|
@@ -1029,12 +1034,6 @@ var useCliStore = create((set) => ({
|
|
|
1029
1034
|
// UI state
|
|
1030
1035
|
isThinking: false,
|
|
1031
1036
|
setIsThinking: (thinking) => set({ isThinking: thinking }),
|
|
1032
|
-
agentSteps: [],
|
|
1033
|
-
addAgentStep: (step) => set((state) => ({
|
|
1034
|
-
agentSteps: [...state.agentSteps, step]
|
|
1035
|
-
})),
|
|
1036
|
-
setAgentSteps: (steps) => set({ agentSteps: steps }),
|
|
1037
|
-
clearAgentSteps: () => set({ agentSteps: [] }),
|
|
1038
1037
|
// Permission prompt
|
|
1039
1038
|
permissionPrompt: null,
|
|
1040
1039
|
setPermissionPrompt: (prompt) => set({ permissionPrompt: prompt }),
|
|
@@ -1049,11 +1048,10 @@ var useCliStore = create((set) => ({
|
|
|
1049
1048
|
// src/components/AgentThinking.tsx
|
|
1050
1049
|
var AgentThinking = React7.memo(function AgentThinking2() {
|
|
1051
1050
|
const isThinking = useCliStore((state) => state.isThinking);
|
|
1052
|
-
const agentSteps = useCliStore((state) => state.agentSteps);
|
|
1053
1051
|
if (!isThinking) {
|
|
1054
1052
|
return null;
|
|
1055
1053
|
}
|
|
1056
|
-
return /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, {
|
|
1054
|
+
return /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { isThinking }));
|
|
1057
1055
|
});
|
|
1058
1056
|
|
|
1059
1057
|
// src/components/PermissionPrompt.tsx
|
|
@@ -1091,7 +1089,10 @@ function PermissionPrompt({
|
|
|
1091
1089
|
{ label: "\u2713 Allow once", value: "allow-once" },
|
|
1092
1090
|
{ label: "\u2717 Deny", value: "deny" }
|
|
1093
1091
|
];
|
|
1094
|
-
const
|
|
1092
|
+
const MAX_ARGS_LENGTH = 500;
|
|
1093
|
+
const rawArgsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
|
|
1094
|
+
const argsString = rawArgsString.length > MAX_ARGS_LENGTH ? rawArgsString.slice(0, MAX_ARGS_LENGTH) + `
|
|
1095
|
+
... (${rawArgsString.length - MAX_ARGS_LENGTH} more chars)` : rawArgsString;
|
|
1095
1096
|
return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", padding: 1, marginY: 1 }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "yellow" }, "\u26A0\uFE0F Permission Required")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "Tool: "), /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, toolName)), toolDescription && /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "Action: "), /* @__PURE__ */ React8.createElement(Text7, null, toolDescription)), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { bold: true }, "Arguments:"), /* @__PURE__ */ React8.createElement(Box7, { paddingLeft: 2, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, argsString))), preview && /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { bold: true }, "Preview:"), /* @__PURE__ */ React8.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column" }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "red", dimColor: true }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(SelectInput, { items, onSelect: (item) => onResponse(item.value) })));
|
|
1096
1097
|
}
|
|
1097
1098
|
|
|
@@ -1523,7 +1524,7 @@ ${errorBlock}`;
|
|
|
1523
1524
|
onSave: onSaveConfig,
|
|
1524
1525
|
onClose: () => setShowConfigEditor(false)
|
|
1525
1526
|
}
|
|
1526
|
-
)) : permissionPrompt
|
|
1527
|
+
)) : /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Static, { items: messages }, (message) => /* @__PURE__ */ React11.createElement(Box10, { key: message.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(MessageItem, { message }))), /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column" }, pendingMessages.map((message) => /* @__PURE__ */ React11.createElement(Box10, { key: message.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(MessageItem, { message })))), permissionPrompt && /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(
|
|
1527
1528
|
PermissionPrompt,
|
|
1528
1529
|
{
|
|
1529
1530
|
toolName: permissionPrompt.toolName,
|
|
@@ -1532,13 +1533,13 @@ ${errorBlock}`;
|
|
|
1532
1533
|
canBeTrusted: permissionPrompt.canBeTrusted,
|
|
1533
1534
|
onResponse: onPermissionResponse
|
|
1534
1535
|
}
|
|
1535
|
-
))
|
|
1536
|
+
)), !permissionPrompt && /* @__PURE__ */ React11.createElement(AgentThinking, null), exitRequested && /* @__PURE__ */ React11.createElement(Box10, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text10, { color: "yellow", bold: true }, "Press Ctrl+C again to exit")), /* @__PURE__ */ React11.createElement(Box10, { borderStyle: "single", borderColor: isBashMode ? "yellow" : "cyan", paddingX: 1 }, /* @__PURE__ */ React11.createElement(
|
|
1536
1537
|
InputPrompt,
|
|
1537
1538
|
{
|
|
1538
1539
|
onSubmit: handleSubmit,
|
|
1539
1540
|
onBashCommand,
|
|
1540
1541
|
onImageDetected,
|
|
1541
|
-
disabled: isThinking,
|
|
1542
|
+
disabled: isThinking || !!permissionPrompt,
|
|
1542
1543
|
history: commandHistory,
|
|
1543
1544
|
commands,
|
|
1544
1545
|
prefillInput,
|
|
@@ -1932,6 +1933,7 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
|
|
|
1932
1933
|
import { promises as fs3 } from "fs";
|
|
1933
1934
|
import path3 from "path";
|
|
1934
1935
|
import { homedir } from "os";
|
|
1936
|
+
import { v4 as uuidv4 } from "uuid";
|
|
1935
1937
|
var SessionStore = class {
|
|
1936
1938
|
constructor(basePath) {
|
|
1937
1939
|
this.basePath = basePath || path3.join(homedir(), ".bike4mind", "sessions");
|
|
@@ -1967,7 +1969,14 @@ var SessionStore = class {
|
|
|
1967
1969
|
const filePath = path3.join(this.basePath, `${id}.json`);
|
|
1968
1970
|
try {
|
|
1969
1971
|
const data = await fs3.readFile(filePath, "utf-8");
|
|
1970
|
-
|
|
1972
|
+
const session = JSON.parse(data);
|
|
1973
|
+
session.messages = session.messages.map((msg) => {
|
|
1974
|
+
if (!msg.id) {
|
|
1975
|
+
return { ...msg, id: uuidv4() };
|
|
1976
|
+
}
|
|
1977
|
+
return msg;
|
|
1978
|
+
});
|
|
1979
|
+
return session;
|
|
1971
1980
|
} catch (error) {
|
|
1972
1981
|
if (error.code === "ENOENT") {
|
|
1973
1982
|
return null;
|
|
@@ -1996,7 +2005,14 @@ var SessionStore = class {
|
|
|
1996
2005
|
jsonFiles.map(async (file) => {
|
|
1997
2006
|
const filePath = path3.join(this.basePath, file);
|
|
1998
2007
|
const data = await fs3.readFile(filePath, "utf-8");
|
|
1999
|
-
|
|
2008
|
+
const session = JSON.parse(data);
|
|
2009
|
+
session.messages = session.messages.map((msg) => {
|
|
2010
|
+
if (!msg.id) {
|
|
2011
|
+
return { ...msg, id: uuidv4() };
|
|
2012
|
+
}
|
|
2013
|
+
return msg;
|
|
2014
|
+
});
|
|
2015
|
+
return session;
|
|
2000
2016
|
})
|
|
2001
2017
|
);
|
|
2002
2018
|
return sessions.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
@@ -2050,7 +2066,7 @@ var SessionStore = class {
|
|
|
2050
2066
|
import { promises as fs4, existsSync as existsSync3 } from "fs";
|
|
2051
2067
|
import path4 from "path";
|
|
2052
2068
|
import { homedir as homedir2 } from "os";
|
|
2053
|
-
import { v4 as
|
|
2069
|
+
import { v4 as uuidv42 } from "uuid";
|
|
2054
2070
|
import { z } from "zod";
|
|
2055
2071
|
var AuthTokensSchema = z.object({
|
|
2056
2072
|
accessToken: z.string(),
|
|
@@ -2144,7 +2160,7 @@ var ProjectLocalConfigSchema = z.object({
|
|
|
2144
2160
|
});
|
|
2145
2161
|
var DEFAULT_CONFIG = {
|
|
2146
2162
|
version: "0.1.0",
|
|
2147
|
-
userId:
|
|
2163
|
+
userId: uuidv42(),
|
|
2148
2164
|
defaultModel: "claude-sonnet-4-5-20250929",
|
|
2149
2165
|
toolApiKeys: {
|
|
2150
2166
|
openweather: void 0,
|
|
@@ -2361,15 +2377,19 @@ var ConfigStore = class {
|
|
|
2361
2377
|
throw error;
|
|
2362
2378
|
}
|
|
2363
2379
|
}
|
|
2364
|
-
this.projectConfigDir = findProjectConfigDir();
|
|
2365
2380
|
let projectConfig = null;
|
|
2366
2381
|
let projectLocalConfig = null;
|
|
2367
|
-
if (
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2382
|
+
if (process.env.B4M_NO_PROJECT_CONFIG !== "1") {
|
|
2383
|
+
this.projectConfigDir = findProjectConfigDir();
|
|
2384
|
+
if (this.projectConfigDir) {
|
|
2385
|
+
projectConfig = await loadProjectConfig(this.projectConfigDir);
|
|
2386
|
+
projectLocalConfig = await loadProjectLocalConfig(this.projectConfigDir);
|
|
2387
|
+
if (projectConfig) {
|
|
2388
|
+
console.log(`\u{1F4C1} Project config loaded from: ${this.projectConfigDir}/.bike4mind/`);
|
|
2389
|
+
}
|
|
2372
2390
|
}
|
|
2391
|
+
} else {
|
|
2392
|
+
this.projectConfigDir = null;
|
|
2373
2393
|
}
|
|
2374
2394
|
this.config = mergeConfigs(globalConfig, projectConfig, projectLocalConfig);
|
|
2375
2395
|
return this.config;
|
|
@@ -2426,7 +2446,7 @@ var ConfigStore = class {
|
|
|
2426
2446
|
* Reset configuration to defaults
|
|
2427
2447
|
*/
|
|
2428
2448
|
async reset() {
|
|
2429
|
-
this.config = { ...DEFAULT_CONFIG, userId:
|
|
2449
|
+
this.config = { ...DEFAULT_CONFIG, userId: uuidv42() };
|
|
2430
2450
|
await this.save();
|
|
2431
2451
|
return this.config;
|
|
2432
2452
|
}
|
|
@@ -3129,6 +3149,7 @@ ${options.context}` : this.getSystemPrompt()
|
|
|
3129
3149
|
}
|
|
3130
3150
|
if (completionInfo.toolsUsed && completionInfo.toolsUsed.length > 0) {
|
|
3131
3151
|
hadToolCalls = true;
|
|
3152
|
+
const thinkingBlocks = completionInfo.thinking || [];
|
|
3132
3153
|
for (const toolUse of completionInfo.toolsUsed) {
|
|
3133
3154
|
const toolCallId = `${toolUse.name}_${JSON.stringify(toolUse.arguments)}`;
|
|
3134
3155
|
if (processedToolIds.has(toolCallId)) {
|
|
@@ -3161,16 +3182,23 @@ ${options.context}` : this.getSystemPrompt()
|
|
|
3161
3182
|
const params = typeof toolUse.arguments === "string" ? JSON.parse(toolUse.arguments) : toolUse.arguments;
|
|
3162
3183
|
observation = await tool.toolFn(params);
|
|
3163
3184
|
const toolCallId2 = `${toolUse.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
3185
|
+
const assistantContent = [
|
|
3186
|
+
// Include thinking blocks first (required by Anthropic when thinking is enabled)
|
|
3187
|
+
...thinkingBlocks,
|
|
3188
|
+
// Then the tool use
|
|
3189
|
+
{
|
|
3190
|
+
type: "tool_use",
|
|
3191
|
+
id: toolCallId2,
|
|
3192
|
+
name: toolUse.name,
|
|
3193
|
+
input: params
|
|
3194
|
+
}
|
|
3195
|
+
];
|
|
3196
|
+
this.context.logger.debug(
|
|
3197
|
+
`[assistantContent] ${assistantContent.length} blocks (${thinkingBlocks.length} thinking, 1 tool_use)`
|
|
3198
|
+
);
|
|
3164
3199
|
messages.push({
|
|
3165
3200
|
role: "assistant",
|
|
3166
|
-
content:
|
|
3167
|
-
{
|
|
3168
|
-
type: "tool_use",
|
|
3169
|
-
id: toolCallId2,
|
|
3170
|
-
name: toolUse.name,
|
|
3171
|
-
input: params
|
|
3172
|
-
}
|
|
3173
|
-
]
|
|
3201
|
+
content: assistantContent
|
|
3174
3202
|
});
|
|
3175
3203
|
messages.push({
|
|
3176
3204
|
role: "user",
|
|
@@ -3328,6 +3356,59 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
|
|
|
3328
3356
|
}
|
|
3329
3357
|
};
|
|
3330
3358
|
|
|
3359
|
+
// src/core/prompts.ts
|
|
3360
|
+
function buildCoreSystemPrompt(contextSection = "") {
|
|
3361
|
+
return `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
|
|
3362
|
+
|
|
3363
|
+
CORE BEHAVIOR:
|
|
3364
|
+
- Be proactive: Take action instead of asking for permission or clarification
|
|
3365
|
+
- Make smart assumptions: If unclear, choose the most reasonable interpretation
|
|
3366
|
+
- Use conversation history: Reference previous exchanges to understand context
|
|
3367
|
+
- Complete tasks fully: Don't just show what to do - actually do it
|
|
3368
|
+
|
|
3369
|
+
FOR SOFTWARE ENGINEERING TASKS:
|
|
3370
|
+
When requested to perform tasks like fixing bugs, adding features, refactoring, or explaining code, follow this sequence:
|
|
3371
|
+
1. **Understand:** Think about the user's request and the relevant codebase context. Use 'grep_search' and 'glob_files' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use 'file_read' to understand context and validate any assumptions you may have. If you need to read multiple files, you should make multiple parallel calls to 'file_read'.
|
|
3372
|
+
2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution.
|
|
3373
|
+
3. **Implement:** Use the available tools (e.g., 'edit_local_file', 'create_file', 'bash_execute' ...) to act on the plan, strictly adhering to the project's established conventions.
|
|
3374
|
+
4. **Verify (Tests):** If applicable and feasible, verify the changes using the project's testing procedures. Identify the correct test commands and frameworks by examining 'README' files, build/package configuration (e.g., 'package.json'), or existing test execution patterns. NEVER assume standard test commands. When executing test commands, prefer "run once" or "CI" modes to ensure the command terminates after completion.
|
|
3375
|
+
5. **Verify (Standards):** VERY IMPORTANT: After making code changes, execute the project-specific build, linting and type-checking commands (e.g., 'tsc', 'npm run lint', 'ruff check .') that you have identified for this project (or obtained from the user). This ensures code quality and adherence to standards.
|
|
3376
|
+
6. **Finalize:** After all verification passes, consider the task complete. Do not remove or revert any changes or created files (like tests). Await the user's next instruction.
|
|
3377
|
+
|
|
3378
|
+
SUBAGENT DELEGATION:
|
|
3379
|
+
- You have access to specialized subagents via the subagent_delegate tool
|
|
3380
|
+
- Use subagents for focused exploration, planning, or review tasks:
|
|
3381
|
+
* explore: Fast read-only codebase search (e.g., "find all auth files", "locate API endpoints")
|
|
3382
|
+
* plan: Break down complex tasks into actionable steps
|
|
3383
|
+
* review: Analyze code quality and identify issues
|
|
3384
|
+
- Subagents keep the main conversation clean and run faster with optimized models
|
|
3385
|
+
- Delegate when you need to search extensively or analyze code structure
|
|
3386
|
+
|
|
3387
|
+
FOR GENERAL TASKS:
|
|
3388
|
+
- Use available tools to get information (weather, web search, calculations, etc.)
|
|
3389
|
+
- When user asks follow-up questions, use conversation context to understand what they're referring to
|
|
3390
|
+
- If user asks "how about X?" after a previous question, apply the same question type to X
|
|
3391
|
+
|
|
3392
|
+
## Shell tool output token efficiency:
|
|
3393
|
+
IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION.
|
|
3394
|
+
|
|
3395
|
+
- Always prefer command flags that reduce output verbosity when using 'bash_execute'.
|
|
3396
|
+
- Aim to minimize tool output tokens while still capturing necessary information.
|
|
3397
|
+
- If a command is expected to produce a lot of output, use quiet or silent flags where available and appropriate.
|
|
3398
|
+
- Always consider the trade-off between output verbosity and the need for information. If a command's full output is essential for understanding the result, avoid overly aggressive quieting that might obscure important details.
|
|
3399
|
+
- If a command does not have quiet/silent flags or for commands with potentially long output that may not be useful, redirect stdout and stderr to temp files in the project's temporary directory. For example: 'command > <temp_dir>/out.log 2> <temp_dir>/err.log'.
|
|
3400
|
+
- After the command runs, inspect the temp files (e.g. '<temp_dir>/out.log' and '<temp_dir>/err.log') using commands like 'grep', 'tail', 'head', ... (or platform equivalents). Remove the temp files when done.
|
|
3401
|
+
|
|
3402
|
+
EXAMPLES:
|
|
3403
|
+
- "what should I wear in Texas?" \u2192 use weather tool for Texas
|
|
3404
|
+
- "how about Japan?" \u2192 use weather tool for Japan (applying same question from context)
|
|
3405
|
+
- "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
|
|
3406
|
+
- "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
|
|
3407
|
+
- "find all components using React hooks" \u2192 subagent_delegate(task="find all components using React hooks", type="explore")
|
|
3408
|
+
|
|
3409
|
+
Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
|
|
3410
|
+
}
|
|
3411
|
+
|
|
3331
3412
|
// ../../b4m-core/packages/services/dist/src/referService/generateCodes.js
|
|
3332
3413
|
import { randomBytes } from "crypto";
|
|
3333
3414
|
import range from "lodash/range.js";
|
|
@@ -4336,7 +4417,7 @@ var listFabFilesSchema = z86.object({
|
|
|
4336
4417
|
|
|
4337
4418
|
// ../../b4m-core/packages/services/dist/src/fabFileService/update.js
|
|
4338
4419
|
import mime from "mime-types";
|
|
4339
|
-
import { v4 as
|
|
4420
|
+
import { v4 as uuidv43 } from "uuid";
|
|
4340
4421
|
import { z as z87 } from "zod";
|
|
4341
4422
|
var updateFabFileSchema = z87.object({
|
|
4342
4423
|
id: z87.string(),
|
|
@@ -4457,7 +4538,7 @@ var editFabFileSchema = z98.object({
|
|
|
4457
4538
|
|
|
4458
4539
|
// ../../b4m-core/packages/services/dist/src/fabFileService/applyEdit.js
|
|
4459
4540
|
import mime2 from "mime-types";
|
|
4460
|
-
import { v4 as
|
|
4541
|
+
import { v4 as uuidv44 } from "uuid";
|
|
4461
4542
|
import { z as z99 } from "zod";
|
|
4462
4543
|
var applyEditSchema = z99.object({
|
|
4463
4544
|
id: z99.string(),
|
|
@@ -5285,7 +5366,7 @@ import { toFile } from "openai/uploads";
|
|
|
5285
5366
|
import { Readable } from "stream";
|
|
5286
5367
|
import { TranscribeClient, StartTranscriptionJobCommand, GetTranscriptionJobCommand, LanguageCode, MediaFormat } from "@aws-sdk/client-transcribe";
|
|
5287
5368
|
import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand } from "@aws-sdk/client-s3";
|
|
5288
|
-
import { v4 as
|
|
5369
|
+
import { v4 as uuidv45 } from "uuid";
|
|
5289
5370
|
|
|
5290
5371
|
// ../../b4m-core/packages/services/dist/src/emailIngestionService/processIngestedEmail.js
|
|
5291
5372
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
@@ -5446,7 +5527,7 @@ var weatherTool = {
|
|
|
5446
5527
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/imageGeneration/index.js
|
|
5447
5528
|
import axios6 from "axios";
|
|
5448
5529
|
import { fileTypeFromBuffer as fileTypeFromBuffer2 } from "file-type";
|
|
5449
|
-
import { v4 as
|
|
5530
|
+
import { v4 as uuidv46 } from "uuid";
|
|
5450
5531
|
async function downloadImage(url) {
|
|
5451
5532
|
if (url.startsWith("data:image/")) {
|
|
5452
5533
|
const base64Data = url.split(",")[1];
|
|
@@ -5460,9 +5541,9 @@ async function processAndStoreImages(images, context) {
|
|
|
5460
5541
|
return Promise.all(images.map(async (image) => {
|
|
5461
5542
|
const buffer = await downloadImage(image);
|
|
5462
5543
|
const fileType = await fileTypeFromBuffer2(buffer);
|
|
5463
|
-
const filename = `${
|
|
5464
|
-
const
|
|
5465
|
-
return
|
|
5544
|
+
const filename = `${uuidv46()}.${fileType?.ext}`;
|
|
5545
|
+
const path17 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
5546
|
+
return path17;
|
|
5466
5547
|
}));
|
|
5467
5548
|
}
|
|
5468
5549
|
async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
|
|
@@ -6629,7 +6710,7 @@ Return only the edited content without any markdown code blocks or explanations.
|
|
|
6629
6710
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/imageEdit/index.js
|
|
6630
6711
|
import axios7 from "axios";
|
|
6631
6712
|
import { fileTypeFromBuffer as fileTypeFromBuffer3 } from "file-type";
|
|
6632
|
-
import { v4 as
|
|
6713
|
+
import { v4 as uuidv47 } from "uuid";
|
|
6633
6714
|
async function downloadImage2(url) {
|
|
6634
6715
|
if (url.startsWith("data:image/")) {
|
|
6635
6716
|
const base64Data = url.split(",")[1];
|
|
@@ -6673,9 +6754,9 @@ async function getImageFromFileId(fileId, context) {
|
|
|
6673
6754
|
async function processAndStoreImage(imageUrl, context) {
|
|
6674
6755
|
const buffer = await downloadImage2(imageUrl);
|
|
6675
6756
|
const fileType = await fileTypeFromBuffer3(buffer);
|
|
6676
|
-
const filename = `${
|
|
6677
|
-
const
|
|
6678
|
-
return
|
|
6757
|
+
const filename = `${uuidv47()}.${fileType?.ext}`;
|
|
6758
|
+
const path17 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
6759
|
+
return path17;
|
|
6679
6760
|
}
|
|
6680
6761
|
async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
|
|
6681
6762
|
await context.onFinish?.("edit_image", storedImagePath);
|
|
@@ -8579,7 +8660,8 @@ var fileReadTool = {
|
|
|
8579
8660
|
return content;
|
|
8580
8661
|
} catch (error) {
|
|
8581
8662
|
context.logger.error("\u274C FileRead: Failed", error);
|
|
8582
|
-
|
|
8663
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
8664
|
+
return `Error reading file: ${errorMessage}`;
|
|
8583
8665
|
}
|
|
8584
8666
|
},
|
|
8585
8667
|
toolSchema: {
|
|
@@ -9462,6 +9544,104 @@ BLOCKED OPERATIONS:
|
|
|
9462
9544
|
})
|
|
9463
9545
|
};
|
|
9464
9546
|
|
|
9547
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/editLocalFile/index.js
|
|
9548
|
+
import { promises as fs11 } from "fs";
|
|
9549
|
+
import { existsSync as existsSync7 } from "fs";
|
|
9550
|
+
import path13 from "path";
|
|
9551
|
+
import { diffLines as diffLines3 } from "diff";
|
|
9552
|
+
function generateDiff(original, modified) {
|
|
9553
|
+
const differences = diffLines3(original, modified);
|
|
9554
|
+
let diffString = "";
|
|
9555
|
+
let additions = 0;
|
|
9556
|
+
let deletions = 0;
|
|
9557
|
+
differences.forEach((part) => {
|
|
9558
|
+
if (part.added) {
|
|
9559
|
+
additions += part.count || 0;
|
|
9560
|
+
diffString += part.value.split("\n").filter((line) => line).map((line) => `+ ${line}`).join("\n");
|
|
9561
|
+
if (diffString && !diffString.endsWith("\n"))
|
|
9562
|
+
diffString += "\n";
|
|
9563
|
+
} else if (part.removed) {
|
|
9564
|
+
deletions += part.count || 0;
|
|
9565
|
+
diffString += part.value.split("\n").filter((line) => line).map((line) => `- ${line}`).join("\n");
|
|
9566
|
+
if (diffString && !diffString.endsWith("\n"))
|
|
9567
|
+
diffString += "\n";
|
|
9568
|
+
}
|
|
9569
|
+
});
|
|
9570
|
+
return { additions, deletions, diff: diffString.trim() };
|
|
9571
|
+
}
|
|
9572
|
+
async function editLocalFile(params) {
|
|
9573
|
+
const { path: filePath, old_string, new_string } = params;
|
|
9574
|
+
const normalizedPath = path13.normalize(filePath);
|
|
9575
|
+
const resolvedPath = path13.resolve(process.cwd(), normalizedPath);
|
|
9576
|
+
const cwd = path13.resolve(process.cwd());
|
|
9577
|
+
if (!resolvedPath.startsWith(cwd)) {
|
|
9578
|
+
throw new Error(`Access denied: Cannot edit files outside of current working directory`);
|
|
9579
|
+
}
|
|
9580
|
+
if (!existsSync7(resolvedPath)) {
|
|
9581
|
+
throw new Error(`File not found: ${filePath}`);
|
|
9582
|
+
}
|
|
9583
|
+
const currentContent = await fs11.readFile(resolvedPath, "utf-8");
|
|
9584
|
+
if (!currentContent.includes(old_string)) {
|
|
9585
|
+
const preview = old_string.length > 100 ? old_string.substring(0, 100) + "..." : old_string;
|
|
9586
|
+
throw new Error(`String to replace not found in file. Make sure the old_string matches exactly (including whitespace and line endings). Searched for: "${preview}"`);
|
|
9587
|
+
}
|
|
9588
|
+
const occurrences = currentContent.split(old_string).length - 1;
|
|
9589
|
+
if (occurrences > 1) {
|
|
9590
|
+
throw new Error(`Found ${occurrences} occurrences of the string to replace. Please provide a more specific old_string that matches exactly one location.`);
|
|
9591
|
+
}
|
|
9592
|
+
const newContent = currentContent.replace(old_string, new_string);
|
|
9593
|
+
await fs11.writeFile(resolvedPath, newContent, "utf-8");
|
|
9594
|
+
const diffResult = generateDiff(old_string, new_string);
|
|
9595
|
+
return `File edited successfully: ${filePath}
|
|
9596
|
+
Changes: +${diffResult.additions} lines, -${diffResult.deletions} lines
|
|
9597
|
+
|
|
9598
|
+
Diff:
|
|
9599
|
+
${diffResult.diff}`;
|
|
9600
|
+
}
|
|
9601
|
+
var editLocalFileTool = {
|
|
9602
|
+
name: "edit_local_file",
|
|
9603
|
+
implementation: (context) => ({
|
|
9604
|
+
toolFn: async (value) => {
|
|
9605
|
+
const params = value;
|
|
9606
|
+
context.logger.info(`\u{1F4DD} EditLocalFile: Editing file`, {
|
|
9607
|
+
path: params.path,
|
|
9608
|
+
oldStringLength: params.old_string.length,
|
|
9609
|
+
newStringLength: params.new_string.length
|
|
9610
|
+
});
|
|
9611
|
+
try {
|
|
9612
|
+
const result = await editLocalFile(params);
|
|
9613
|
+
context.logger.info("\u2705 EditLocalFile: Success", { path: params.path });
|
|
9614
|
+
return result;
|
|
9615
|
+
} catch (error) {
|
|
9616
|
+
context.logger.error("\u274C EditLocalFile: Failed", error);
|
|
9617
|
+
throw error;
|
|
9618
|
+
}
|
|
9619
|
+
},
|
|
9620
|
+
toolSchema: {
|
|
9621
|
+
name: "edit_local_file",
|
|
9622
|
+
description: "Edit a file by replacing a specific string with new content. The old_string must match exactly one location in the file (including whitespace). Use this for precise edits to existing files. For creating new files or complete rewrites, use create_file instead.",
|
|
9623
|
+
parameters: {
|
|
9624
|
+
type: "object",
|
|
9625
|
+
properties: {
|
|
9626
|
+
path: {
|
|
9627
|
+
type: "string",
|
|
9628
|
+
description: "Path to the file to edit (relative to current working directory)"
|
|
9629
|
+
},
|
|
9630
|
+
old_string: {
|
|
9631
|
+
type: "string",
|
|
9632
|
+
description: "The exact string to find and replace. Must match exactly one location in the file, including all whitespace and line endings."
|
|
9633
|
+
},
|
|
9634
|
+
new_string: {
|
|
9635
|
+
type: "string",
|
|
9636
|
+
description: "The string to replace old_string with. Can be empty to delete the old_string."
|
|
9637
|
+
}
|
|
9638
|
+
},
|
|
9639
|
+
required: ["path", "old_string", "new_string"]
|
|
9640
|
+
}
|
|
9641
|
+
}
|
|
9642
|
+
})
|
|
9643
|
+
};
|
|
9644
|
+
|
|
9465
9645
|
// ../../b4m-core/packages/services/dist/src/llm/tools/index.js
|
|
9466
9646
|
var tools = {
|
|
9467
9647
|
dice_roll: diceRollTool,
|
|
@@ -9487,6 +9667,7 @@ var tools = {
|
|
|
9487
9667
|
planet_visibility: planetVisibilityTool,
|
|
9488
9668
|
file_read: fileReadTool,
|
|
9489
9669
|
create_file: createFileTool,
|
|
9670
|
+
edit_local_file: editLocalFileTool,
|
|
9490
9671
|
glob_files: globFilesTool,
|
|
9491
9672
|
grep_search: grepSearchTool,
|
|
9492
9673
|
delete_file: deleteFileTool,
|
|
@@ -9649,7 +9830,7 @@ var QuestStartBodySchema = z139.object({
|
|
|
9649
9830
|
// ../../b4m-core/packages/services/dist/src/llm/ImageGeneration.js
|
|
9650
9831
|
import axios8 from "axios";
|
|
9651
9832
|
import { fileTypeFromBuffer as fileTypeFromBuffer4 } from "file-type";
|
|
9652
|
-
import { v4 as
|
|
9833
|
+
import { v4 as uuidv48 } from "uuid";
|
|
9653
9834
|
import { z as z140 } from "zod";
|
|
9654
9835
|
import { fromZodError as fromZodError2 } from "zod-validation-error";
|
|
9655
9836
|
var ImageGenerationBodySchema = OpenAIImageGenerationInput.extend({
|
|
@@ -9670,7 +9851,7 @@ var ImageGenerationBodySchema = OpenAIImageGenerationInput.extend({
|
|
|
9670
9851
|
// ../../b4m-core/packages/services/dist/src/llm/ImageEdit.js
|
|
9671
9852
|
import axios9 from "axios";
|
|
9672
9853
|
import { fileTypeFromBuffer as fileTypeFromBuffer5 } from "file-type";
|
|
9673
|
-
import { v4 as
|
|
9854
|
+
import { v4 as uuidv49 } from "uuid";
|
|
9674
9855
|
import { z as z141 } from "zod";
|
|
9675
9856
|
import { fromZodError as fromZodError3 } from "zod-validation-error";
|
|
9676
9857
|
var ImageEditBodySchema = OpenAIImageGenerationInput.extend({
|
|
@@ -9730,10 +9911,10 @@ var ToolErrorType;
|
|
|
9730
9911
|
// src/utils/diffPreview.ts
|
|
9731
9912
|
import * as Diff from "diff";
|
|
9732
9913
|
import { readFile } from "fs/promises";
|
|
9733
|
-
import { existsSync as
|
|
9914
|
+
import { existsSync as existsSync8 } from "fs";
|
|
9734
9915
|
async function generateFileDiffPreview(args) {
|
|
9735
9916
|
try {
|
|
9736
|
-
if (!
|
|
9917
|
+
if (!existsSync8(args.path)) {
|
|
9737
9918
|
const lines2 = args.content.split("\n");
|
|
9738
9919
|
const preview = lines2.slice(0, 20).join("\n");
|
|
9739
9920
|
const hasMore = lines2.length > 20;
|
|
@@ -9755,18 +9936,26 @@ ${preview}${hasMore ? `
|
|
|
9755
9936
|
// Show 3 lines of context around changes
|
|
9756
9937
|
);
|
|
9757
9938
|
const lines = patch.split("\n");
|
|
9758
|
-
const
|
|
9759
|
-
return
|
|
9939
|
+
const diffLines4 = lines.slice(4);
|
|
9940
|
+
return diffLines4.join("\n");
|
|
9760
9941
|
} catch (error) {
|
|
9761
9942
|
return `[Error generating diff preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
9762
9943
|
}
|
|
9763
9944
|
}
|
|
9945
|
+
function generateEditLocalFilePreview(args) {
|
|
9946
|
+
const patch = Diff.createPatch(args.path, args.old_string, args.new_string, "Current", "Proposed", { context: 3 });
|
|
9947
|
+
const lines = patch.split("\n");
|
|
9948
|
+
const diffLines4 = lines.slice(4);
|
|
9949
|
+
return `[Edit in: ${args.path}]
|
|
9950
|
+
|
|
9951
|
+
${diffLines4.join("\n")}`;
|
|
9952
|
+
}
|
|
9764
9953
|
async function generateFileDeletePreview(args) {
|
|
9765
9954
|
try {
|
|
9766
|
-
if (!
|
|
9955
|
+
if (!existsSync8(args.path)) {
|
|
9767
9956
|
return `[File does not exist: ${args.path}]`;
|
|
9768
9957
|
}
|
|
9769
|
-
const stats = await import("fs/promises").then((
|
|
9958
|
+
const stats = await import("fs/promises").then((fs14) => fs14.stat(args.path));
|
|
9770
9959
|
return `[File will be deleted]
|
|
9771
9960
|
|
|
9772
9961
|
Path: ${args.path}
|
|
@@ -9778,8 +9967,8 @@ Last modified: ${stats.mtime.toLocaleString()}`;
|
|
|
9778
9967
|
}
|
|
9779
9968
|
|
|
9780
9969
|
// src/utils/Logger.ts
|
|
9781
|
-
import
|
|
9782
|
-
import
|
|
9970
|
+
import fs12 from "fs/promises";
|
|
9971
|
+
import path14 from "path";
|
|
9783
9972
|
import os2 from "os";
|
|
9784
9973
|
var Logger2 = class _Logger {
|
|
9785
9974
|
constructor() {
|
|
@@ -9802,9 +9991,9 @@ var Logger2 = class _Logger {
|
|
|
9802
9991
|
*/
|
|
9803
9992
|
async initialize(sessionId) {
|
|
9804
9993
|
this.sessionId = sessionId;
|
|
9805
|
-
const debugDir =
|
|
9806
|
-
await
|
|
9807
|
-
this.logFilePath =
|
|
9994
|
+
const debugDir = path14.join(os2.homedir(), ".bike4mind", "debug");
|
|
9995
|
+
await fs12.mkdir(debugDir, { recursive: true });
|
|
9996
|
+
this.logFilePath = path14.join(debugDir, `${sessionId}.txt`);
|
|
9808
9997
|
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
9809
9998
|
}
|
|
9810
9999
|
/**
|
|
@@ -9868,7 +10057,7 @@ var Logger2 = class _Logger {
|
|
|
9868
10057
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
|
|
9869
10058
|
const logEntry = `[${timestamp}] [${level}] ${message}
|
|
9870
10059
|
`;
|
|
9871
|
-
await
|
|
10060
|
+
await fs12.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
9872
10061
|
} catch (error) {
|
|
9873
10062
|
console.error("File logging failed:", error);
|
|
9874
10063
|
}
|
|
@@ -10014,15 +10203,15 @@ var Logger2 = class _Logger {
|
|
|
10014
10203
|
async cleanupOldLogs() {
|
|
10015
10204
|
if (!this.fileLoggingEnabled) return;
|
|
10016
10205
|
try {
|
|
10017
|
-
const debugDir =
|
|
10018
|
-
const files = await
|
|
10206
|
+
const debugDir = path14.join(os2.homedir(), ".bike4mind", "debug");
|
|
10207
|
+
const files = await fs12.readdir(debugDir);
|
|
10019
10208
|
const now = Date.now();
|
|
10020
10209
|
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
10021
10210
|
for (const file of files) {
|
|
10022
|
-
const filePath =
|
|
10023
|
-
const stats = await
|
|
10211
|
+
const filePath = path14.join(debugDir, file);
|
|
10212
|
+
const stats = await fs12.stat(filePath);
|
|
10024
10213
|
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
10025
|
-
await
|
|
10214
|
+
await fs12.unlink(filePath);
|
|
10026
10215
|
}
|
|
10027
10216
|
}
|
|
10028
10217
|
} catch (error) {
|
|
@@ -10079,10 +10268,10 @@ var SERVER_TOOLS = ["weather_info", "web_search"];
|
|
|
10079
10268
|
var LOCAL_TOOLS = [
|
|
10080
10269
|
"file_read",
|
|
10081
10270
|
"create_file",
|
|
10271
|
+
"edit_local_file",
|
|
10082
10272
|
"glob_files",
|
|
10083
10273
|
"grep_search",
|
|
10084
10274
|
"delete_file",
|
|
10085
|
-
"edit_file",
|
|
10086
10275
|
"dice_roll",
|
|
10087
10276
|
"math_evaluate",
|
|
10088
10277
|
"current_datetime",
|
|
@@ -10116,21 +10305,21 @@ var NoOpStorage = class extends BaseStorage {
|
|
|
10116
10305
|
async upload(input, destination, options) {
|
|
10117
10306
|
return `/tmp/${destination}`;
|
|
10118
10307
|
}
|
|
10119
|
-
async download(
|
|
10308
|
+
async download(path17) {
|
|
10120
10309
|
throw new Error("Download not supported in CLI");
|
|
10121
10310
|
}
|
|
10122
|
-
async delete(
|
|
10311
|
+
async delete(path17) {
|
|
10123
10312
|
}
|
|
10124
|
-
async getSignedUrl(
|
|
10125
|
-
return `/tmp/${
|
|
10313
|
+
async getSignedUrl(path17) {
|
|
10314
|
+
return `/tmp/${path17}`;
|
|
10126
10315
|
}
|
|
10127
|
-
getPublicUrl(
|
|
10128
|
-
return `/tmp/${
|
|
10316
|
+
getPublicUrl(path17) {
|
|
10317
|
+
return `/tmp/${path17}`;
|
|
10129
10318
|
}
|
|
10130
|
-
async getPreview(
|
|
10131
|
-
return `/tmp/${
|
|
10319
|
+
async getPreview(path17) {
|
|
10320
|
+
return `/tmp/${path17}`;
|
|
10132
10321
|
}
|
|
10133
|
-
async getMetadata(
|
|
10322
|
+
async getMetadata(path17) {
|
|
10134
10323
|
return { size: 0, contentType: "application/octet-stream" };
|
|
10135
10324
|
}
|
|
10136
10325
|
};
|
|
@@ -10162,11 +10351,12 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
10162
10351
|
return result2;
|
|
10163
10352
|
}
|
|
10164
10353
|
let preview;
|
|
10165
|
-
if (toolName === "
|
|
10354
|
+
if (toolName === "edit_local_file" && args?.path && args?.old_string && typeof args?.new_string === "string") {
|
|
10166
10355
|
try {
|
|
10167
|
-
preview =
|
|
10356
|
+
preview = generateEditLocalFilePreview({
|
|
10168
10357
|
path: args.path,
|
|
10169
|
-
|
|
10358
|
+
old_string: args.old_string,
|
|
10359
|
+
new_string: args.new_string
|
|
10170
10360
|
});
|
|
10171
10361
|
} catch (error) {
|
|
10172
10362
|
preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
@@ -10224,7 +10414,31 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
10224
10414
|
}
|
|
10225
10415
|
};
|
|
10226
10416
|
}
|
|
10227
|
-
|
|
10417
|
+
var TOOL_NAME_MAPPING = {
|
|
10418
|
+
// Claude Code -> B4M
|
|
10419
|
+
read: "file_read",
|
|
10420
|
+
write: "create_file",
|
|
10421
|
+
edit: "edit_file",
|
|
10422
|
+
delete: "delete_file",
|
|
10423
|
+
glob: "glob_files",
|
|
10424
|
+
grep: "grep_search",
|
|
10425
|
+
bash: "bash_execute",
|
|
10426
|
+
// B4M -> Claude Code (reverse mapping)
|
|
10427
|
+
file_read: "read",
|
|
10428
|
+
create_file: "write",
|
|
10429
|
+
edit_file: "edit",
|
|
10430
|
+
delete_file: "delete",
|
|
10431
|
+
glob_files: "glob",
|
|
10432
|
+
grep_search: "grep",
|
|
10433
|
+
bash_execute: "bash"
|
|
10434
|
+
};
|
|
10435
|
+
function normalizeToolName(toolName) {
|
|
10436
|
+
if (toolName.includes("_")) {
|
|
10437
|
+
return toolName;
|
|
10438
|
+
}
|
|
10439
|
+
return TOOL_NAME_MAPPING[toolName] || toolName;
|
|
10440
|
+
}
|
|
10441
|
+
function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, toolFilter) {
|
|
10228
10442
|
const logger2 = new CliLogger();
|
|
10229
10443
|
const storage = new NoOpStorage();
|
|
10230
10444
|
const user = {
|
|
@@ -10259,6 +10473,7 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
10259
10473
|
// File operation tools (CLI-specific, local execution)
|
|
10260
10474
|
file_read: {},
|
|
10261
10475
|
create_file: {},
|
|
10476
|
+
edit_local_file: {},
|
|
10262
10477
|
glob_files: {},
|
|
10263
10478
|
grep_search: {},
|
|
10264
10479
|
delete_file: {},
|
|
@@ -10294,9 +10509,24 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
10294
10509
|
toolConfig,
|
|
10295
10510
|
model
|
|
10296
10511
|
);
|
|
10297
|
-
|
|
10512
|
+
let tools2 = Object.entries(toolsMap).filter(([key]) => toolConfig[key] !== void 0).map(
|
|
10298
10513
|
([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient)
|
|
10299
10514
|
);
|
|
10515
|
+
if (toolFilter) {
|
|
10516
|
+
const { allowedTools, deniedTools } = toolFilter;
|
|
10517
|
+
const normalizedAllowed = allowedTools?.map(normalizeToolName);
|
|
10518
|
+
const normalizedDenied = deniedTools?.map(normalizeToolName);
|
|
10519
|
+
tools2 = tools2.filter((tool) => {
|
|
10520
|
+
const toolName = tool.toolSchema.name;
|
|
10521
|
+
if (normalizedDenied && normalizedDenied.includes(toolName)) {
|
|
10522
|
+
return false;
|
|
10523
|
+
}
|
|
10524
|
+
if (normalizedAllowed && normalizedAllowed.length > 0) {
|
|
10525
|
+
return normalizedAllowed.includes(toolName);
|
|
10526
|
+
}
|
|
10527
|
+
return true;
|
|
10528
|
+
});
|
|
10529
|
+
}
|
|
10300
10530
|
return { tools: tools2, agentContext };
|
|
10301
10531
|
}
|
|
10302
10532
|
|
|
@@ -10326,6 +10556,7 @@ var DEFAULT_TOOL_CATEGORIES = {
|
|
|
10326
10556
|
// These tools can modify files, execute code, or have other dangerous side effects
|
|
10327
10557
|
// They ALWAYS require permission and cannot be trusted automatically
|
|
10328
10558
|
edit_file: "prompt_always",
|
|
10559
|
+
edit_local_file: "prompt_always",
|
|
10329
10560
|
create_file: "prompt_always",
|
|
10330
10561
|
delete_file: "prompt_always",
|
|
10331
10562
|
shell_execute: "prompt_always",
|
|
@@ -10492,8 +10723,8 @@ function getEnvironmentName(configApiConfig) {
|
|
|
10492
10723
|
}
|
|
10493
10724
|
|
|
10494
10725
|
// src/utils/contextLoader.ts
|
|
10495
|
-
import * as
|
|
10496
|
-
import * as
|
|
10726
|
+
import * as fs13 from "fs";
|
|
10727
|
+
import * as path15 from "path";
|
|
10497
10728
|
import { homedir as homedir4 } from "os";
|
|
10498
10729
|
var CONTEXT_FILE_SIZE_LIMIT = 100 * 1024;
|
|
10499
10730
|
var PROJECT_CONTEXT_FILES = [
|
|
@@ -10514,9 +10745,9 @@ function formatFileSize2(bytes) {
|
|
|
10514
10745
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
10515
10746
|
}
|
|
10516
10747
|
function tryReadContextFile(dir, filename, source) {
|
|
10517
|
-
const filePath =
|
|
10748
|
+
const filePath = path15.join(dir, filename);
|
|
10518
10749
|
try {
|
|
10519
|
-
const stats =
|
|
10750
|
+
const stats = fs13.lstatSync(filePath);
|
|
10520
10751
|
if (stats.isDirectory()) {
|
|
10521
10752
|
return null;
|
|
10522
10753
|
}
|
|
@@ -10530,7 +10761,7 @@ function tryReadContextFile(dir, filename, source) {
|
|
|
10530
10761
|
error: `${source === "global" ? "Global" : "Project"} ${filename} exceeds 100KB limit (${formatFileSize2(stats.size)})`
|
|
10531
10762
|
};
|
|
10532
10763
|
}
|
|
10533
|
-
const content =
|
|
10764
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
10534
10765
|
return {
|
|
10535
10766
|
filename,
|
|
10536
10767
|
content,
|
|
@@ -10582,7 +10813,7 @@ ${project.content}`;
|
|
|
10582
10813
|
}
|
|
10583
10814
|
async function loadContextFiles(projectDir) {
|
|
10584
10815
|
const errors = [];
|
|
10585
|
-
const globalDir =
|
|
10816
|
+
const globalDir = path15.join(homedir4(), ".bike4mind");
|
|
10586
10817
|
const projectDirectory = projectDir || process.cwd();
|
|
10587
10818
|
const [globalResult, projectResult] = await Promise.all([
|
|
10588
10819
|
Promise.resolve(findContextFile(globalDir, GLOBAL_CONTEXT_FILES, "global")),
|
|
@@ -10618,8 +10849,8 @@ function substituteArguments(template, args) {
|
|
|
10618
10849
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
10619
10850
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
10620
10851
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
10621
|
-
import
|
|
10622
|
-
import { existsSync as
|
|
10852
|
+
import path16 from "path";
|
|
10853
|
+
import { existsSync as existsSync9, readdirSync as readdirSync3 } from "fs";
|
|
10623
10854
|
var MCPClient = class {
|
|
10624
10855
|
// Note: This class handles MCP server communication with repository filtering
|
|
10625
10856
|
mcp;
|
|
@@ -10659,18 +10890,18 @@ var MCPClient = class {
|
|
|
10659
10890
|
const root = process.env.INIT_CWD || process.cwd();
|
|
10660
10891
|
const candidatePaths = [
|
|
10661
10892
|
// When running from SST Lambda with node_modules structure (copyFiles)
|
|
10662
|
-
|
|
10893
|
+
path16.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
|
|
10663
10894
|
// When running from SST Lambda deployed environment (/var/task)
|
|
10664
|
-
|
|
10895
|
+
path16.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10665
10896
|
// When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
|
|
10666
|
-
|
|
10897
|
+
path16.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10667
10898
|
// When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
|
|
10668
|
-
|
|
10899
|
+
path16.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10669
10900
|
// Original paths (backward compatibility)
|
|
10670
|
-
|
|
10671
|
-
|
|
10901
|
+
path16.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10902
|
+
path16.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
|
|
10672
10903
|
];
|
|
10673
|
-
const serverScriptPath = candidatePaths.find((p) =>
|
|
10904
|
+
const serverScriptPath = candidatePaths.find((p) => existsSync9(p));
|
|
10674
10905
|
if (!serverScriptPath) {
|
|
10675
10906
|
const getDirectories = (source) => readdirSync3(source, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
10676
10907
|
console.error(`[MCP] Server script not found. Tried paths:`, candidatePaths);
|
|
@@ -11079,6 +11310,7 @@ var ServerLlmBackend = class {
|
|
|
11079
11310
|
let accumulatedText = "";
|
|
11080
11311
|
let lastUsageInfo = {};
|
|
11081
11312
|
let toolsUsed = [];
|
|
11313
|
+
let thinkingBlocks = [];
|
|
11082
11314
|
let receivedDone = false;
|
|
11083
11315
|
const parser = createParser({
|
|
11084
11316
|
onEvent: (event) => {
|
|
@@ -11092,9 +11324,12 @@ var ServerLlmBackend = class {
|
|
|
11092
11324
|
if (toolsUsed.length > 0) {
|
|
11093
11325
|
const info = {
|
|
11094
11326
|
toolsUsed,
|
|
11327
|
+
thinking: thinkingBlocks.length > 0 ? thinkingBlocks : void 0,
|
|
11095
11328
|
...lastUsageInfo
|
|
11096
11329
|
};
|
|
11097
|
-
logger.debug(
|
|
11330
|
+
logger.debug(
|
|
11331
|
+
`[ServerLlmBackend] Calling callback with tools, thinking blocks: ${thinkingBlocks.length}`
|
|
11332
|
+
);
|
|
11098
11333
|
callback([cleanedText], info).catch((err) => {
|
|
11099
11334
|
logger.error("[ServerLlmBackend] Callback error:", err);
|
|
11100
11335
|
reject(err);
|
|
@@ -11150,6 +11385,10 @@ var ServerLlmBackend = class {
|
|
|
11150
11385
|
if (parsed.tools && parsed.tools.length > 0) {
|
|
11151
11386
|
toolsUsed = parsed.tools;
|
|
11152
11387
|
}
|
|
11388
|
+
if (parsed.thinking && parsed.thinking.length > 0) {
|
|
11389
|
+
thinkingBlocks = parsed.thinking;
|
|
11390
|
+
logger.debug(`[ServerLlmBackend] Received ${thinkingBlocks.length} thinking blocks`);
|
|
11391
|
+
}
|
|
11153
11392
|
if (parsed.usage) {
|
|
11154
11393
|
lastUsageInfo = {
|
|
11155
11394
|
inputTokens: parsed.usage.inputTokens,
|
|
@@ -11472,7 +11711,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
11472
11711
|
// package.json
|
|
11473
11712
|
var package_default = {
|
|
11474
11713
|
name: "@bike4mind/cli",
|
|
11475
|
-
version: "0.2.
|
|
11714
|
+
version: "0.2.11-cli-cancel-pending-message.17326+24dfb0510",
|
|
11476
11715
|
type: "module",
|
|
11477
11716
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
11478
11717
|
license: "UNLICENSED",
|
|
@@ -11576,10 +11815,10 @@ var package_default = {
|
|
|
11576
11815
|
},
|
|
11577
11816
|
devDependencies: {
|
|
11578
11817
|
"@bike4mind/agents": "0.1.0",
|
|
11579
|
-
"@bike4mind/common": "2.
|
|
11580
|
-
"@bike4mind/mcp": "1.20.
|
|
11581
|
-
"@bike4mind/services": "2.
|
|
11582
|
-
"@bike4mind/utils": "2.1.
|
|
11818
|
+
"@bike4mind/common": "2.40.1-cli-cancel-pending-message.17326+24dfb0510",
|
|
11819
|
+
"@bike4mind/mcp": "1.20.5-cli-cancel-pending-message.17326+24dfb0510",
|
|
11820
|
+
"@bike4mind/services": "2.35.1-cli-cancel-pending-message.17326+24dfb0510",
|
|
11821
|
+
"@bike4mind/utils": "2.1.5-cli-cancel-pending-message.17326+24dfb0510",
|
|
11583
11822
|
"@types/better-sqlite3": "^7.6.13",
|
|
11584
11823
|
"@types/diff": "^5.0.9",
|
|
11585
11824
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -11592,7 +11831,7 @@ var package_default = {
|
|
|
11592
11831
|
typescript: "^5.9.3",
|
|
11593
11832
|
vitest: "^3.2.4"
|
|
11594
11833
|
},
|
|
11595
|
-
gitHead: "
|
|
11834
|
+
gitHead: "24dfb0510b2c3e1385417da0a3fe6c3604cdf8f8"
|
|
11596
11835
|
};
|
|
11597
11836
|
|
|
11598
11837
|
// src/config/constants.ts
|
|
@@ -11600,6 +11839,354 @@ var USAGE_DAYS = 30;
|
|
|
11600
11839
|
var MODEL_NAME_COLUMN_WIDTH = 18;
|
|
11601
11840
|
var USAGE_CACHE_TTL = 5 * 60 * 1e3;
|
|
11602
11841
|
|
|
11842
|
+
// src/agents/SubagentOrchestrator.ts
|
|
11843
|
+
var SubagentOrchestrator = class {
|
|
11844
|
+
constructor(deps) {
|
|
11845
|
+
this.beforeRunCallback = null;
|
|
11846
|
+
this.afterRunCallback = null;
|
|
11847
|
+
this.deps = deps;
|
|
11848
|
+
}
|
|
11849
|
+
/**
|
|
11850
|
+
* Set a callback to be invoked before each subagent.run()
|
|
11851
|
+
* Use this to subscribe to agent events (e.g., subagent.on('action', handler))
|
|
11852
|
+
*/
|
|
11853
|
+
setBeforeRunCallback(callback) {
|
|
11854
|
+
this.beforeRunCallback = callback;
|
|
11855
|
+
}
|
|
11856
|
+
/**
|
|
11857
|
+
* Set a callback to be invoked after each subagent.run()
|
|
11858
|
+
* Use this to unsubscribe from agent events (e.g., subagent.off('action', handler))
|
|
11859
|
+
*/
|
|
11860
|
+
setAfterRunCallback(callback) {
|
|
11861
|
+
this.afterRunCallback = callback;
|
|
11862
|
+
}
|
|
11863
|
+
/**
|
|
11864
|
+
* Delegate a task to a specialized subagent
|
|
11865
|
+
*
|
|
11866
|
+
* @param options - Configuration for subagent execution
|
|
11867
|
+
* @returns Subagent result with summary
|
|
11868
|
+
*/
|
|
11869
|
+
async delegateToSubagent(options) {
|
|
11870
|
+
const { task, type, thoroughness, parentSessionId, config: configOverride } = options;
|
|
11871
|
+
const baseConfig = this.deps.subagentConfigs.get(type);
|
|
11872
|
+
if (!baseConfig) {
|
|
11873
|
+
throw new Error(`No configuration found for subagent type: ${type}`);
|
|
11874
|
+
}
|
|
11875
|
+
const config = {
|
|
11876
|
+
...baseConfig,
|
|
11877
|
+
...configOverride,
|
|
11878
|
+
type
|
|
11879
|
+
};
|
|
11880
|
+
const model = config.model || "claude-3-5-haiku-20241022";
|
|
11881
|
+
const maxIterations = this.getMaxIterations(config, thoroughness);
|
|
11882
|
+
const toolFilter = {
|
|
11883
|
+
allowedTools: config.allowedTools,
|
|
11884
|
+
deniedTools: config.deniedTools
|
|
11885
|
+
};
|
|
11886
|
+
const agentContext = {
|
|
11887
|
+
currentAgent: null,
|
|
11888
|
+
observationQueue: []
|
|
11889
|
+
};
|
|
11890
|
+
const { tools: tools2, agentContext: updatedContext } = generateCliTools(
|
|
11891
|
+
this.deps.userId,
|
|
11892
|
+
this.deps.llm,
|
|
11893
|
+
model,
|
|
11894
|
+
this.deps.permissionManager,
|
|
11895
|
+
this.deps.showPermissionPrompt,
|
|
11896
|
+
agentContext,
|
|
11897
|
+
this.deps.configStore,
|
|
11898
|
+
this.deps.apiClient,
|
|
11899
|
+
toolFilter
|
|
11900
|
+
);
|
|
11901
|
+
this.deps.logger.debug(`Spawning ${type} subagent with ${tools2.length} tools, thoroughness: ${thoroughness}`);
|
|
11902
|
+
const subagent = new ReActAgent({
|
|
11903
|
+
userId: this.deps.userId,
|
|
11904
|
+
logger: this.deps.logger,
|
|
11905
|
+
llm: this.deps.llm,
|
|
11906
|
+
model,
|
|
11907
|
+
tools: tools2,
|
|
11908
|
+
maxIterations,
|
|
11909
|
+
systemPrompt: config.systemPrompt || this.getDefaultSystemPrompt(type)
|
|
11910
|
+
});
|
|
11911
|
+
updatedContext.currentAgent = subagent;
|
|
11912
|
+
if (this.beforeRunCallback) {
|
|
11913
|
+
this.beforeRunCallback(subagent, type);
|
|
11914
|
+
}
|
|
11915
|
+
const startTime = Date.now();
|
|
11916
|
+
const result = await subagent.run(task, {
|
|
11917
|
+
maxIterations
|
|
11918
|
+
});
|
|
11919
|
+
const duration = Date.now() - startTime;
|
|
11920
|
+
if (this.afterRunCallback) {
|
|
11921
|
+
this.afterRunCallback(subagent, type);
|
|
11922
|
+
}
|
|
11923
|
+
this.deps.logger.debug(
|
|
11924
|
+
`Subagent completed in ${duration}ms, ${result.completionInfo.iterations} iterations, ${result.completionInfo.totalTokens} tokens`
|
|
11925
|
+
);
|
|
11926
|
+
const summary = this.summarizeResult(result, type);
|
|
11927
|
+
const subagentResult = {
|
|
11928
|
+
...result,
|
|
11929
|
+
subagentType: type,
|
|
11930
|
+
thoroughness,
|
|
11931
|
+
summary,
|
|
11932
|
+
parentSessionId
|
|
11933
|
+
};
|
|
11934
|
+
return subagentResult;
|
|
11935
|
+
}
|
|
11936
|
+
/**
|
|
11937
|
+
* Get max iterations based on thoroughness and config
|
|
11938
|
+
*/
|
|
11939
|
+
getMaxIterations(config, thoroughness) {
|
|
11940
|
+
const defaults = {
|
|
11941
|
+
quick: 2,
|
|
11942
|
+
medium: 5,
|
|
11943
|
+
very_thorough: 10
|
|
11944
|
+
};
|
|
11945
|
+
const configIterations = config.maxIterations || defaults;
|
|
11946
|
+
return configIterations[thoroughness];
|
|
11947
|
+
}
|
|
11948
|
+
/**
|
|
11949
|
+
* Get default system prompt for subagent type
|
|
11950
|
+
*/
|
|
11951
|
+
getDefaultSystemPrompt(type) {
|
|
11952
|
+
switch (type) {
|
|
11953
|
+
case "explore":
|
|
11954
|
+
return `You are a code exploration specialist. Your job is to search and analyze codebases efficiently.
|
|
11955
|
+
|
|
11956
|
+
Focus on:
|
|
11957
|
+
- Finding relevant files and functions
|
|
11958
|
+
- Understanding code structure and patterns
|
|
11959
|
+
- Providing clear, concise summaries
|
|
11960
|
+
|
|
11961
|
+
You have read-only access. Use file_read, grep_search, and glob_files to explore.
|
|
11962
|
+
|
|
11963
|
+
When you find what you're looking for, provide a clear summary including:
|
|
11964
|
+
1. What you found (files, functions, patterns)
|
|
11965
|
+
2. Key insights or observations
|
|
11966
|
+
3. Relevant code locations
|
|
11967
|
+
|
|
11968
|
+
Be thorough but concise. Your summary will be used by the main agent.`;
|
|
11969
|
+
case "plan":
|
|
11970
|
+
return `You are a task planning specialist. Your job is to break down complex tasks into clear, actionable steps.
|
|
11971
|
+
|
|
11972
|
+
Focus on:
|
|
11973
|
+
- Identifying dependencies and blockers
|
|
11974
|
+
- Creating logical sequence of steps
|
|
11975
|
+
- Estimating scope and priorities
|
|
11976
|
+
|
|
11977
|
+
Provide a structured plan that the main agent can execute.`;
|
|
11978
|
+
case "review":
|
|
11979
|
+
return `You are a code review specialist. Your job is to analyze code quality and identify issues.
|
|
11980
|
+
|
|
11981
|
+
Focus on:
|
|
11982
|
+
- Code quality and best practices
|
|
11983
|
+
- Potential bugs and edge cases
|
|
11984
|
+
- Performance and security considerations
|
|
11985
|
+
|
|
11986
|
+
Provide actionable feedback with specific file and line references.`;
|
|
11987
|
+
default:
|
|
11988
|
+
return "You are a helpful AI assistant.";
|
|
11989
|
+
}
|
|
11990
|
+
}
|
|
11991
|
+
/**
|
|
11992
|
+
* Summarize subagent result for parent agent
|
|
11993
|
+
*/
|
|
11994
|
+
summarizeResult(result, type) {
|
|
11995
|
+
const { finalAnswer, steps, completionInfo } = result;
|
|
11996
|
+
const toolCalls = steps.filter((s) => s.type === "action");
|
|
11997
|
+
const filesRead = toolCalls.filter((s) => s.metadata?.toolName === "file_read").length;
|
|
11998
|
+
const searches = toolCalls.filter((s) => s.metadata?.toolName === "grep_search").length;
|
|
11999
|
+
const globs = toolCalls.filter((s) => s.metadata?.toolName === "glob_files").length;
|
|
12000
|
+
let summary = `**${type.charAt(0).toUpperCase() + type.slice(1)} Subagent Results**
|
|
12001
|
+
|
|
12002
|
+
`;
|
|
12003
|
+
summary += `*Execution: ${completionInfo.iterations} iterations, ${completionInfo.toolCalls} tool calls*
|
|
12004
|
+
|
|
12005
|
+
`;
|
|
12006
|
+
if (type === "explore") {
|
|
12007
|
+
summary += `*Exploration: ${filesRead} files read, ${searches} searches, ${globs} glob patterns*
|
|
12008
|
+
|
|
12009
|
+
`;
|
|
12010
|
+
}
|
|
12011
|
+
const maxLength = 1e3;
|
|
12012
|
+
if (finalAnswer.length > maxLength) {
|
|
12013
|
+
summary += finalAnswer.slice(0, maxLength) + "\n\n...(truncated)";
|
|
12014
|
+
} else {
|
|
12015
|
+
summary += finalAnswer;
|
|
12016
|
+
}
|
|
12017
|
+
return summary;
|
|
12018
|
+
}
|
|
12019
|
+
};
|
|
12020
|
+
|
|
12021
|
+
// src/agents/configs.ts
|
|
12022
|
+
var EXPLORE_CONFIG = {
|
|
12023
|
+
type: "explore",
|
|
12024
|
+
model: "claude-3-5-haiku-20241022",
|
|
12025
|
+
systemPrompt: `You are a code exploration specialist. Your job is to search and analyze codebases efficiently.
|
|
12026
|
+
|
|
12027
|
+
Focus on:
|
|
12028
|
+
- Finding relevant files and functions
|
|
12029
|
+
- Understanding code structure and patterns
|
|
12030
|
+
- Providing clear, concise summaries
|
|
12031
|
+
|
|
12032
|
+
You have read-only access. Use file_read, grep_search, and glob_files to explore.
|
|
12033
|
+
|
|
12034
|
+
When you find what you're looking for, provide a clear summary including:
|
|
12035
|
+
1. What you found (files, functions, patterns)
|
|
12036
|
+
2. Key insights or observations
|
|
12037
|
+
3. Relevant code locations
|
|
12038
|
+
|
|
12039
|
+
Be thorough but concise. Your summary will be used by the main agent.`,
|
|
12040
|
+
allowedTools: [
|
|
12041
|
+
"file_read",
|
|
12042
|
+
"grep_search",
|
|
12043
|
+
"glob_files",
|
|
12044
|
+
"bash_execute",
|
|
12045
|
+
// Only for read-only commands like ls, cat, find
|
|
12046
|
+
"current_datetime",
|
|
12047
|
+
"math_evaluate"
|
|
12048
|
+
],
|
|
12049
|
+
deniedTools: [
|
|
12050
|
+
"create_file",
|
|
12051
|
+
"edit_file",
|
|
12052
|
+
"delete_file",
|
|
12053
|
+
"web_search",
|
|
12054
|
+
"weather_info",
|
|
12055
|
+
"blog_publish",
|
|
12056
|
+
"blog_edit",
|
|
12057
|
+
"blog_draft"
|
|
12058
|
+
],
|
|
12059
|
+
maxIterations: {
|
|
12060
|
+
quick: 2,
|
|
12061
|
+
medium: 5,
|
|
12062
|
+
very_thorough: 10
|
|
12063
|
+
},
|
|
12064
|
+
defaultThoroughness: "medium"
|
|
12065
|
+
};
|
|
12066
|
+
var PLAN_CONFIG = {
|
|
12067
|
+
type: "plan",
|
|
12068
|
+
model: "claude-3-5-haiku-20241022",
|
|
12069
|
+
systemPrompt: `You are a task planning specialist. Your job is to break down complex tasks into clear, actionable steps.
|
|
12070
|
+
|
|
12071
|
+
Focus on:
|
|
12072
|
+
- Identifying dependencies and blockers
|
|
12073
|
+
- Creating logical sequence of steps
|
|
12074
|
+
- Estimating scope and priorities
|
|
12075
|
+
|
|
12076
|
+
You have read-only access to analyze code.
|
|
12077
|
+
You can explore the codebase to understand the current architecture before planning.
|
|
12078
|
+
|
|
12079
|
+
Provide a structured plan that the main agent can execute.`,
|
|
12080
|
+
allowedTools: ["file_read", "grep_search", "glob_files", "bash_execute", "current_datetime", "math_evaluate"],
|
|
12081
|
+
deniedTools: ["create_file", "edit_file", "delete_file", "web_search", "weather_info"],
|
|
12082
|
+
maxIterations: {
|
|
12083
|
+
quick: 3,
|
|
12084
|
+
medium: 7,
|
|
12085
|
+
very_thorough: 12
|
|
12086
|
+
},
|
|
12087
|
+
defaultThoroughness: "medium"
|
|
12088
|
+
};
|
|
12089
|
+
var REVIEW_CONFIG = {
|
|
12090
|
+
type: "review",
|
|
12091
|
+
model: "claude-sonnet-4-5-20250929",
|
|
12092
|
+
// Use latest Sonnet for better reasoning
|
|
12093
|
+
systemPrompt: `You are a code review specialist. Your job is to analyze code quality and identify issues.
|
|
12094
|
+
|
|
12095
|
+
Focus on:
|
|
12096
|
+
- Code quality and best practices
|
|
12097
|
+
- Potential bugs and edge cases
|
|
12098
|
+
- Performance and security considerations
|
|
12099
|
+
|
|
12100
|
+
You have read-only access to analyze code.
|
|
12101
|
+
|
|
12102
|
+
Provide actionable feedback with specific file and line references.`,
|
|
12103
|
+
allowedTools: ["file_read", "grep_search", "glob_files", "bash_execute", "current_datetime"],
|
|
12104
|
+
deniedTools: ["create_file", "edit_file", "delete_file", "web_search", "weather_info"],
|
|
12105
|
+
maxIterations: {
|
|
12106
|
+
quick: 3,
|
|
12107
|
+
medium: 8,
|
|
12108
|
+
very_thorough: 15
|
|
12109
|
+
},
|
|
12110
|
+
defaultThoroughness: "medium"
|
|
12111
|
+
};
|
|
12112
|
+
function getDefaultSubagentConfigs() {
|
|
12113
|
+
return /* @__PURE__ */ new Map([
|
|
12114
|
+
["explore", EXPLORE_CONFIG],
|
|
12115
|
+
["plan", PLAN_CONFIG],
|
|
12116
|
+
["review", REVIEW_CONFIG]
|
|
12117
|
+
]);
|
|
12118
|
+
}
|
|
12119
|
+
|
|
12120
|
+
// src/agents/delegateTool.ts
|
|
12121
|
+
function createSubagentDelegateTool(orchestrator, parentSessionId) {
|
|
12122
|
+
return {
|
|
12123
|
+
toolFn: async (args) => {
|
|
12124
|
+
const params = args;
|
|
12125
|
+
if (!params.task) {
|
|
12126
|
+
throw new Error("subagent_delegate: task parameter is required");
|
|
12127
|
+
}
|
|
12128
|
+
if (!params.type) {
|
|
12129
|
+
throw new Error("subagent_delegate: type parameter is required");
|
|
12130
|
+
}
|
|
12131
|
+
const thoroughness = params.thoroughness || "medium";
|
|
12132
|
+
const type = params.type;
|
|
12133
|
+
const result = await orchestrator.delegateToSubagent({
|
|
12134
|
+
task: params.task,
|
|
12135
|
+
type,
|
|
12136
|
+
thoroughness,
|
|
12137
|
+
parentSessionId
|
|
12138
|
+
});
|
|
12139
|
+
return result.summary;
|
|
12140
|
+
},
|
|
12141
|
+
toolSchema: {
|
|
12142
|
+
name: "subagent_delegate",
|
|
12143
|
+
description: `Delegate a task to a specialized subagent for focused work.
|
|
12144
|
+
|
|
12145
|
+
**When to use this tool:**
|
|
12146
|
+
- **Explore**: When you need to search through the codebase, find files, or understand code structure (read-only)
|
|
12147
|
+
- **Plan**: When you need to break down a complex task into actionable steps
|
|
12148
|
+
- **Review**: When you need to analyze code quality and identify potential issues
|
|
12149
|
+
|
|
12150
|
+
**Benefits:**
|
|
12151
|
+
- Keeps main conversation focused and clean
|
|
12152
|
+
- Uses specialized prompts optimized for each task type
|
|
12153
|
+
- Faster execution with appropriate models (Haiku for explore/plan, Sonnet for review)
|
|
12154
|
+
|
|
12155
|
+
**Example uses:**
|
|
12156
|
+
- "Find all files that use the authentication system" \u2192 explore
|
|
12157
|
+
- "Search for components that handle user input" \u2192 explore
|
|
12158
|
+
- "Break down implementing a new feature into steps" \u2192 plan
|
|
12159
|
+
- "Review this module for potential bugs" \u2192 review`,
|
|
12160
|
+
parameters: {
|
|
12161
|
+
type: "object",
|
|
12162
|
+
properties: {
|
|
12163
|
+
task: {
|
|
12164
|
+
type: "string",
|
|
12165
|
+
description: "Clear description of what you want the subagent to do. Be specific about what you're looking for or what needs to be accomplished."
|
|
12166
|
+
},
|
|
12167
|
+
type: {
|
|
12168
|
+
type: "string",
|
|
12169
|
+
enum: ["explore", "plan", "review"],
|
|
12170
|
+
description: `Type of subagent to use:
|
|
12171
|
+
- explore: Read-only codebase exploration and search (fast, uses Haiku)
|
|
12172
|
+
- plan: Task breakdown and planning (uses Haiku)
|
|
12173
|
+
- review: Code quality analysis and review (uses Sonnet for better reasoning)`
|
|
12174
|
+
},
|
|
12175
|
+
thoroughness: {
|
|
12176
|
+
type: "string",
|
|
12177
|
+
enum: ["quick", "medium", "very_thorough"],
|
|
12178
|
+
description: `How thoroughly to execute:
|
|
12179
|
+
- quick: Fast lookup, 1-2 iterations
|
|
12180
|
+
- medium: Balanced exploration, 3-5 iterations (default)
|
|
12181
|
+
- very_thorough: Comprehensive analysis, 8-10 iterations`
|
|
12182
|
+
}
|
|
12183
|
+
},
|
|
12184
|
+
required: ["task", "type"]
|
|
12185
|
+
}
|
|
12186
|
+
}
|
|
12187
|
+
};
|
|
12188
|
+
}
|
|
12189
|
+
|
|
11603
12190
|
// src/index.tsx
|
|
11604
12191
|
process.removeAllListeners("warning");
|
|
11605
12192
|
process.on("warning", (warning) => {
|
|
@@ -11630,7 +12217,9 @@ function CliApp() {
|
|
|
11630
12217
|
permissionPrompt: null,
|
|
11631
12218
|
trustLocationSelector: null,
|
|
11632
12219
|
rewindSelector: null,
|
|
11633
|
-
sessionSelector: null
|
|
12220
|
+
sessionSelector: null,
|
|
12221
|
+
orchestrator: null,
|
|
12222
|
+
abortController: null
|
|
11634
12223
|
});
|
|
11635
12224
|
const [isInitialized, setIsInitialized] = useState8(false);
|
|
11636
12225
|
const [initError, setInitError] = useState8(null);
|
|
@@ -11676,6 +12265,15 @@ function CliApp() {
|
|
|
11676
12265
|
}, 100);
|
|
11677
12266
|
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
|
|
11678
12267
|
useInput6((input, key) => {
|
|
12268
|
+
if (key.escape) {
|
|
12269
|
+
if (state.abortController) {
|
|
12270
|
+
logger.debug("[ABORT] ESC pressed - aborting current operation...");
|
|
12271
|
+
state.abortController.abort();
|
|
12272
|
+
setState((prev) => ({ ...prev, abortController: null }));
|
|
12273
|
+
console.log("\n\u26A0\uFE0F Operation cancelled by user (ESC)\n");
|
|
12274
|
+
}
|
|
12275
|
+
return;
|
|
12276
|
+
}
|
|
11679
12277
|
if (key.ctrl && input === "c") {
|
|
11680
12278
|
const now = Date.now();
|
|
11681
12279
|
if (exitTimestamp && now - exitTimestamp < EXIT_TIMEOUT_MS) {
|
|
@@ -11730,7 +12328,7 @@ function CliApp() {
|
|
|
11730
12328
|
if (!isAuthenticated) {
|
|
11731
12329
|
console.log("\u2139\uFE0F AI features disabled. Available commands: /login, /help, /config\n");
|
|
11732
12330
|
const minimalSession = {
|
|
11733
|
-
id:
|
|
12331
|
+
id: uuidv410(),
|
|
11734
12332
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
11735
12333
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11736
12334
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -11774,7 +12372,7 @@ function CliApp() {
|
|
|
11774
12372
|
}
|
|
11775
12373
|
llm.currentModel = modelInfo.id;
|
|
11776
12374
|
const newSession = {
|
|
11777
|
-
id:
|
|
12375
|
+
id: uuidv410(),
|
|
11778
12376
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
11779
12377
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11780
12378
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -11847,7 +12445,34 @@ function CliApp() {
|
|
|
11847
12445
|
console.log(` \u{1F4E1} ${serverName}: ${count} tool(s)`);
|
|
11848
12446
|
});
|
|
11849
12447
|
}
|
|
11850
|
-
const
|
|
12448
|
+
const subagentConfigs = getDefaultSubagentConfigs();
|
|
12449
|
+
if (config.subagents) {
|
|
12450
|
+
if (config.subagents.explore) {
|
|
12451
|
+
const currentConfig = subagentConfigs.get("explore");
|
|
12452
|
+
subagentConfigs.set("explore", { ...currentConfig, ...config.subagents.explore });
|
|
12453
|
+
}
|
|
12454
|
+
if (config.subagents.plan) {
|
|
12455
|
+
const currentConfig = subagentConfigs.get("plan");
|
|
12456
|
+
subagentConfigs.set("plan", { ...currentConfig, ...config.subagents.plan });
|
|
12457
|
+
}
|
|
12458
|
+
if (config.subagents.review) {
|
|
12459
|
+
const currentConfig = subagentConfigs.get("review");
|
|
12460
|
+
subagentConfigs.set("review", { ...currentConfig, ...config.subagents.review });
|
|
12461
|
+
}
|
|
12462
|
+
}
|
|
12463
|
+
const orchestrator = new SubagentOrchestrator({
|
|
12464
|
+
userId: config.userId,
|
|
12465
|
+
llm,
|
|
12466
|
+
logger: silentLogger,
|
|
12467
|
+
permissionManager,
|
|
12468
|
+
showPermissionPrompt: promptFn,
|
|
12469
|
+
configStore: state.configStore,
|
|
12470
|
+
apiClient,
|
|
12471
|
+
subagentConfigs
|
|
12472
|
+
});
|
|
12473
|
+
const subagentDelegateTool = createSubagentDelegateTool(orchestrator, newSession.id);
|
|
12474
|
+
const allTools = [...b4mTools, ...mcpTools, subagentDelegateTool];
|
|
12475
|
+
console.log(`\u{1F916} Subagent delegation enabled (explore, plan, review)`);
|
|
11851
12476
|
const projectDir = state.configStore.getProjectConfigDir();
|
|
11852
12477
|
const contextResult = await loadContextFiles(projectDir);
|
|
11853
12478
|
if (contextResult.globalContext) {
|
|
@@ -11866,36 +12491,7 @@ function CliApp() {
|
|
|
11866
12491
|
Follow these project-specific instructions:
|
|
11867
12492
|
|
|
11868
12493
|
${contextResult.mergedContent}` : "";
|
|
11869
|
-
const cliSystemPrompt =
|
|
11870
|
-
|
|
11871
|
-
CORE BEHAVIOR:
|
|
11872
|
-
- Be proactive: Take action instead of asking for permission or clarification
|
|
11873
|
-
- Make smart assumptions: If unclear, choose the most reasonable interpretation
|
|
11874
|
-
- Use conversation history: Reference previous exchanges to understand context
|
|
11875
|
-
- Complete tasks fully: Don't just show what to do - actually do it
|
|
11876
|
-
|
|
11877
|
-
FOR CODING TASKS:
|
|
11878
|
-
- You have file system access (file_read, create_file, glob_files, grep_search, delete_file)
|
|
11879
|
-
- When user says "enhance", "update", "fix", "improve" a file:
|
|
11880
|
-
* Use file_read to get current content
|
|
11881
|
-
* Generate the improved version
|
|
11882
|
-
* Use create_file to write it back
|
|
11883
|
-
* Don't just show suggestions - make the changes
|
|
11884
|
-
- When searching for code: Use grep_search or glob_files to find relevant files
|
|
11885
|
-
- Permission system will ask for approval before any file writes
|
|
11886
|
-
|
|
11887
|
-
FOR GENERAL TASKS:
|
|
11888
|
-
- Use available tools to get information (weather, web search, calculations, etc.)
|
|
11889
|
-
- When user asks follow-up questions, use conversation context to understand what they're referring to
|
|
11890
|
-
- If user asks "how about X?" after a previous question, apply the same question type to X
|
|
11891
|
-
|
|
11892
|
-
EXAMPLES:
|
|
11893
|
-
- "what should I wear in Texas?" \u2192 use weather tool for Texas
|
|
11894
|
-
- "how about Japan?" \u2192 use weather tool for Japan (applying same question from context)
|
|
11895
|
-
- "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
|
|
11896
|
-
- "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
|
|
11897
|
-
|
|
11898
|
-
Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
|
|
12494
|
+
const cliSystemPrompt = buildCoreSystemPrompt(contextSection);
|
|
11899
12495
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
11900
12496
|
const agent = new ReActAgent({
|
|
11901
12497
|
userId: config.userId,
|
|
@@ -11910,6 +12506,45 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
11910
12506
|
});
|
|
11911
12507
|
agentContext.currentAgent = agent;
|
|
11912
12508
|
agent.observationQueue = agentContext.observationQueue;
|
|
12509
|
+
const stepHandler = (step) => {
|
|
12510
|
+
const { pendingMessages, updatePendingMessage } = useCliStore.getState();
|
|
12511
|
+
const lastIdx = pendingMessages.length - 1;
|
|
12512
|
+
if (lastIdx >= 0 && pendingMessages[lastIdx].role === "assistant") {
|
|
12513
|
+
const existingSteps = pendingMessages[lastIdx].metadata?.steps || [];
|
|
12514
|
+
const MAX_INPUT_LENGTH = 500;
|
|
12515
|
+
let truncatedStep = step;
|
|
12516
|
+
if (step.type === "action" && step.metadata?.toolInput) {
|
|
12517
|
+
const inputStr = typeof step.metadata.toolInput === "string" ? step.metadata.toolInput : JSON.stringify(step.metadata.toolInput);
|
|
12518
|
+
if (inputStr.length > MAX_INPUT_LENGTH) {
|
|
12519
|
+
const truncatedInput = inputStr.slice(0, MAX_INPUT_LENGTH) + `... (${inputStr.length - MAX_INPUT_LENGTH} more chars)`;
|
|
12520
|
+
truncatedStep = {
|
|
12521
|
+
...step,
|
|
12522
|
+
metadata: {
|
|
12523
|
+
...step.metadata,
|
|
12524
|
+
toolInput: truncatedInput
|
|
12525
|
+
}
|
|
12526
|
+
};
|
|
12527
|
+
}
|
|
12528
|
+
}
|
|
12529
|
+
updatePendingMessage(lastIdx, {
|
|
12530
|
+
...pendingMessages[lastIdx],
|
|
12531
|
+
metadata: {
|
|
12532
|
+
...pendingMessages[lastIdx].metadata,
|
|
12533
|
+
steps: [...existingSteps, truncatedStep]
|
|
12534
|
+
}
|
|
12535
|
+
});
|
|
12536
|
+
}
|
|
12537
|
+
};
|
|
12538
|
+
agent.on("thought", stepHandler);
|
|
12539
|
+
agent.on("action", stepHandler);
|
|
12540
|
+
orchestrator.setBeforeRunCallback((subagent, _subagentType) => {
|
|
12541
|
+
subagent.on("thought", stepHandler);
|
|
12542
|
+
subagent.on("action", stepHandler);
|
|
12543
|
+
});
|
|
12544
|
+
orchestrator.setAfterRunCallback((subagent, _subagentType) => {
|
|
12545
|
+
subagent.off("thought", stepHandler);
|
|
12546
|
+
subagent.off("action", stepHandler);
|
|
12547
|
+
});
|
|
11913
12548
|
setState((prev) => ({
|
|
11914
12549
|
...prev,
|
|
11915
12550
|
session: newSession,
|
|
@@ -11918,8 +12553,10 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
11918
12553
|
permissionManager,
|
|
11919
12554
|
config,
|
|
11920
12555
|
// Store config for synchronous access
|
|
11921
|
-
availableModels: models
|
|
12556
|
+
availableModels: models,
|
|
11922
12557
|
// Store models for ConfigEditor
|
|
12558
|
+
orchestrator
|
|
12559
|
+
// Store orchestrator for step handler updates
|
|
11923
12560
|
}));
|
|
11924
12561
|
setStoreSession(newSession);
|
|
11925
12562
|
setIsInitialized(true);
|
|
@@ -11952,6 +12589,8 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
11952
12589
|
return;
|
|
11953
12590
|
}
|
|
11954
12591
|
useCliStore.getState().setIsThinking(true);
|
|
12592
|
+
const abortController = new AbortController();
|
|
12593
|
+
setState((prev) => ({ ...prev, abortController }));
|
|
11955
12594
|
const currentSteps = [];
|
|
11956
12595
|
const stepHandler = (step) => {
|
|
11957
12596
|
currentSteps.push(step);
|
|
@@ -11974,6 +12613,7 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
11974
12613
|
}
|
|
11975
12614
|
}
|
|
11976
12615
|
};
|
|
12616
|
+
state.agent.on("thought", stepHandler);
|
|
11977
12617
|
state.agent.on("action", stepHandler);
|
|
11978
12618
|
try {
|
|
11979
12619
|
let messageContent = fullTemplate;
|
|
@@ -11983,11 +12623,13 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
11983
12623
|
messageContent = multimodalMessage.content;
|
|
11984
12624
|
}
|
|
11985
12625
|
const userMessage = {
|
|
12626
|
+
id: uuidv410(),
|
|
11986
12627
|
role: "user",
|
|
11987
12628
|
content: userMessageContent,
|
|
11988
12629
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11989
12630
|
};
|
|
11990
12631
|
const pendingAssistantMessage = {
|
|
12632
|
+
id: uuidv410(),
|
|
11991
12633
|
role: "assistant",
|
|
11992
12634
|
content: "...",
|
|
11993
12635
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -12008,8 +12650,13 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12008
12650
|
content: msg.content
|
|
12009
12651
|
}));
|
|
12010
12652
|
const result = await state.agent.run(messageContent, {
|
|
12011
|
-
previousMessages: previousMessages.length > 0 ? previousMessages : void 0
|
|
12653
|
+
previousMessages: previousMessages.length > 0 ? previousMessages : void 0,
|
|
12654
|
+
signal: abortController.signal
|
|
12012
12655
|
});
|
|
12656
|
+
if (abortController.signal.aborted) {
|
|
12657
|
+
logger.debug("[ABORT] Custom command was cancelled, discarding result");
|
|
12658
|
+
return;
|
|
12659
|
+
}
|
|
12013
12660
|
const permissionDenied = result.finalAnswer.startsWith("Permission denied for tool");
|
|
12014
12661
|
if (permissionDenied) {
|
|
12015
12662
|
console.log("\n\u26A0\uFE0F Action denied by user\n");
|
|
@@ -12018,7 +12665,10 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12018
12665
|
const currentSession = useCliStore.getState().session;
|
|
12019
12666
|
if (!currentSession) return;
|
|
12020
12667
|
const updatedMessages = [...currentSession.messages];
|
|
12668
|
+
const lastMessage = updatedMessages[updatedMessages.length - 1];
|
|
12021
12669
|
updatedMessages[updatedMessages.length - 1] = {
|
|
12670
|
+
id: lastMessage.id,
|
|
12671
|
+
// Preserve the original message ID
|
|
12022
12672
|
role: "assistant",
|
|
12023
12673
|
content: result.finalAnswer,
|
|
12024
12674
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -12050,6 +12700,33 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12050
12700
|
useCliStore.getState().setIsThinking(false);
|
|
12051
12701
|
} catch (error) {
|
|
12052
12702
|
useCliStore.getState().setIsThinking(false);
|
|
12703
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
12704
|
+
logger.debug("[ABORT] Custom command aborted by user");
|
|
12705
|
+
const currentSession2 = useCliStore.getState().session;
|
|
12706
|
+
if (currentSession2) {
|
|
12707
|
+
const messages2 = [...currentSession2.messages];
|
|
12708
|
+
const lastMessage2 = messages2[messages2.length - 1];
|
|
12709
|
+
if (lastMessage2 && lastMessage2.role === "assistant") {
|
|
12710
|
+
messages2[messages2.length - 1] = {
|
|
12711
|
+
...lastMessage2,
|
|
12712
|
+
content: "\u26A0\uFE0F Operation cancelled by user",
|
|
12713
|
+
metadata: {
|
|
12714
|
+
...lastMessage2.metadata,
|
|
12715
|
+
cancelled: true
|
|
12716
|
+
}
|
|
12717
|
+
};
|
|
12718
|
+
}
|
|
12719
|
+
const sessionWithCancel = {
|
|
12720
|
+
...currentSession2,
|
|
12721
|
+
messages: messages2,
|
|
12722
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12723
|
+
};
|
|
12724
|
+
setState((prev) => ({ ...prev, session: sessionWithCancel }));
|
|
12725
|
+
setStoreSession(sessionWithCancel);
|
|
12726
|
+
await state.sessionStore.save(sessionWithCancel);
|
|
12727
|
+
}
|
|
12728
|
+
return;
|
|
12729
|
+
}
|
|
12053
12730
|
if (error?.message?.includes("Permission denied")) {
|
|
12054
12731
|
console.log("\n\u26A0\uFE0F Action blocked by permission settings");
|
|
12055
12732
|
const currentSession2 = useCliStore.getState().session;
|
|
@@ -12090,6 +12767,8 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12090
12767
|
setState((prev) => ({ ...prev, session: sessionWithError }));
|
|
12091
12768
|
setStoreSession(sessionWithError);
|
|
12092
12769
|
} finally {
|
|
12770
|
+
setState((prev) => ({ ...prev, abortController: null }));
|
|
12771
|
+
state.agent.off("thought", stepHandler);
|
|
12093
12772
|
state.agent.off("action", stepHandler);
|
|
12094
12773
|
}
|
|
12095
12774
|
};
|
|
@@ -12108,22 +12787,8 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12108
12787
|
return;
|
|
12109
12788
|
}
|
|
12110
12789
|
useCliStore.getState().setIsThinking(true);
|
|
12111
|
-
const
|
|
12112
|
-
|
|
12113
|
-
currentSteps.push(step);
|
|
12114
|
-
const { pendingMessages, updatePendingMessage } = useCliStore.getState();
|
|
12115
|
-
const lastIdx = pendingMessages.length - 1;
|
|
12116
|
-
if (lastIdx >= 0 && pendingMessages[lastIdx].role === "assistant") {
|
|
12117
|
-
updatePendingMessage(lastIdx, {
|
|
12118
|
-
...pendingMessages[lastIdx],
|
|
12119
|
-
metadata: {
|
|
12120
|
-
...pendingMessages[lastIdx].metadata,
|
|
12121
|
-
steps: [...currentSteps]
|
|
12122
|
-
}
|
|
12123
|
-
});
|
|
12124
|
-
}
|
|
12125
|
-
};
|
|
12126
|
-
state.agent.on("action", stepHandler);
|
|
12790
|
+
const abortController = new AbortController();
|
|
12791
|
+
setState((prev) => ({ ...prev, abortController }));
|
|
12127
12792
|
try {
|
|
12128
12793
|
let messageContent = message;
|
|
12129
12794
|
let userMessageContent = message;
|
|
@@ -12133,11 +12798,13 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12133
12798
|
userMessageContent = message;
|
|
12134
12799
|
}
|
|
12135
12800
|
const userMessage = {
|
|
12801
|
+
id: uuidv410(),
|
|
12136
12802
|
role: "user",
|
|
12137
12803
|
content: userMessageContent,
|
|
12138
12804
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
12139
12805
|
};
|
|
12140
12806
|
const pendingAssistantMessage = {
|
|
12807
|
+
id: uuidv410(),
|
|
12141
12808
|
role: "assistant",
|
|
12142
12809
|
content: "...",
|
|
12143
12810
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -12159,14 +12826,21 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12159
12826
|
content: msg.content
|
|
12160
12827
|
}));
|
|
12161
12828
|
const result = await state.agent.run(messageContent, {
|
|
12162
|
-
previousMessages: previousMessages.length > 0 ? previousMessages : void 0
|
|
12829
|
+
previousMessages: previousMessages.length > 0 ? previousMessages : void 0,
|
|
12830
|
+
signal: abortController.signal
|
|
12163
12831
|
});
|
|
12832
|
+
if (abortController.signal.aborted) {
|
|
12833
|
+
logger.debug("[ABORT] Operation was cancelled, discarding result");
|
|
12834
|
+
return;
|
|
12835
|
+
}
|
|
12164
12836
|
const permissionDenied = result.finalAnswer.startsWith("Permission denied for tool");
|
|
12165
12837
|
if (permissionDenied) {
|
|
12166
12838
|
console.log("\n\u26A0\uFE0F Action denied by user\n");
|
|
12167
12839
|
}
|
|
12168
12840
|
const successfulToolCalls = result.steps.filter((s) => s.type === "observation").length;
|
|
12169
12841
|
const finalAssistantMessage = {
|
|
12842
|
+
id: pendingAssistantMessage.id,
|
|
12843
|
+
// Preserve the original message ID
|
|
12170
12844
|
role: "assistant",
|
|
12171
12845
|
content: result.finalAnswer,
|
|
12172
12846
|
timestamp: pendingAssistantMessage.timestamp,
|
|
@@ -12197,6 +12871,30 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12197
12871
|
await state.sessionStore.save(updatedSession);
|
|
12198
12872
|
} catch (error) {
|
|
12199
12873
|
useCliStore.getState().clearPendingMessages();
|
|
12874
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
12875
|
+
logger.debug("[ABORT] Operation aborted by user");
|
|
12876
|
+
const currentSession = useCliStore.getState().session;
|
|
12877
|
+
if (currentSession) {
|
|
12878
|
+
const cancelMessage = {
|
|
12879
|
+
id: uuidv410(),
|
|
12880
|
+
role: "assistant",
|
|
12881
|
+
content: "\u26A0\uFE0F Operation cancelled by user",
|
|
12882
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12883
|
+
metadata: {
|
|
12884
|
+
cancelled: true
|
|
12885
|
+
}
|
|
12886
|
+
};
|
|
12887
|
+
const sessionWithCancel = {
|
|
12888
|
+
...currentSession,
|
|
12889
|
+
messages: [...currentSession.messages, cancelMessage],
|
|
12890
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12891
|
+
};
|
|
12892
|
+
setState((prev) => ({ ...prev, session: sessionWithCancel }));
|
|
12893
|
+
setStoreSession(sessionWithCancel);
|
|
12894
|
+
await state.sessionStore.save(sessionWithCancel);
|
|
12895
|
+
}
|
|
12896
|
+
return;
|
|
12897
|
+
}
|
|
12200
12898
|
if (error instanceof Error) {
|
|
12201
12899
|
if (error.message.includes("Authentication failed") || error.message.includes("Authentication expired")) {
|
|
12202
12900
|
console.log("\n\u274C Authentication failed");
|
|
@@ -12206,7 +12904,8 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12206
12904
|
}
|
|
12207
12905
|
console.error("Error processing message:", error);
|
|
12208
12906
|
} finally {
|
|
12209
|
-
|
|
12907
|
+
setState((prev) => ({ ...prev, abortController: null }));
|
|
12908
|
+
useCliStore.getState().setIsThinking(false);
|
|
12210
12909
|
}
|
|
12211
12910
|
};
|
|
12212
12911
|
const handleBashCommand = useCallback(
|
|
@@ -12228,11 +12927,13 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12228
12927
|
isError = true;
|
|
12229
12928
|
}
|
|
12230
12929
|
const userMessage = {
|
|
12930
|
+
id: uuidv410(),
|
|
12231
12931
|
role: "user",
|
|
12232
12932
|
content: `$ ${command}`,
|
|
12233
12933
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
12234
12934
|
};
|
|
12235
12935
|
const assistantMessage = {
|
|
12936
|
+
id: uuidv410(),
|
|
12236
12937
|
role: "assistant",
|
|
12237
12938
|
content: isError ? `\u274C Error:
|
|
12238
12939
|
${output}` : output.trim() || "(no output)",
|
|
@@ -12423,7 +13124,6 @@ Custom Commands:
|
|
|
12423
13124
|
logger.debug("=== Session Resumed ===");
|
|
12424
13125
|
setState((prev) => ({ ...prev, session: loadedSession }));
|
|
12425
13126
|
setStoreSession(loadedSession);
|
|
12426
|
-
useCliStore.getState().clearAgentSteps();
|
|
12427
13127
|
useCliStore.getState().clearPendingMessages();
|
|
12428
13128
|
usageCache = null;
|
|
12429
13129
|
console.log(`
|
|
@@ -12643,7 +13343,7 @@ Custom Commands:
|
|
|
12643
13343
|
console.clear();
|
|
12644
13344
|
const model = state.session?.model || state.config?.defaultModel || "claude-sonnet";
|
|
12645
13345
|
const newSession = {
|
|
12646
|
-
id:
|
|
13346
|
+
id: uuidv410(),
|
|
12647
13347
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
12648
13348
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12649
13349
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -12659,7 +13359,6 @@ Custom Commands:
|
|
|
12659
13359
|
logger.debug("=== New Session Started via /clear ===");
|
|
12660
13360
|
setState((prev) => ({ ...prev, session: newSession }));
|
|
12661
13361
|
setStoreSession(newSession);
|
|
12662
|
-
useCliStore.getState().clearAgentSteps();
|
|
12663
13362
|
useCliStore.getState().clearPendingMessages();
|
|
12664
13363
|
usageCache = null;
|
|
12665
13364
|
console.log("New session started.");
|