@bike4mind/cli 0.2.55 → 0.2.56-feat-cli-tavern-integration.21361
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-524RAWPN.js → chunk-JV4GPGBC.js} +3 -0
- package/dist/{chunk-SA2GRZGG.js → chunk-PJ3VATSD.js} +25 -4
- package/dist/{chunk-25UR2PLZ.js → chunk-SDMU65DA.js} +8 -7
- package/dist/{chunk-G2LYCVZJ.js → chunk-Y4WOJJM3.js} +8 -1
- package/dist/commands/doctorCommand.js +1 -1
- package/dist/commands/headlessCommand.js +2 -2
- package/dist/commands/mcpCommand.js +1 -1
- package/dist/commands/updateCommand.js +1 -1
- package/dist/index.js +718 -16
- package/dist/{store-X5LEOSGZ.js → store-CAB6BV3P.js} +1 -1
- package/package.json +8 -7
|
@@ -397,6 +397,9 @@ var CliConfigSchema = z.object({
|
|
|
397
397
|
disabled: z.array(z.string()),
|
|
398
398
|
config: z.record(z.string(), z.any())
|
|
399
399
|
}),
|
|
400
|
+
features: z.object({
|
|
401
|
+
tavern: z.boolean().optional()
|
|
402
|
+
}).optional().prefault({}),
|
|
400
403
|
trustedTools: z.array(z.string()).optional().prefault([]),
|
|
401
404
|
sandbox: SandboxConfigSchema.optional(),
|
|
402
405
|
additionalDirectories: z.array(z.string()).optional().prefault([])
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
import {
|
|
24
24
|
ConfigStore,
|
|
25
25
|
logger
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-JV4GPGBC.js";
|
|
27
27
|
import {
|
|
28
28
|
ALERT_THRESHOLDS,
|
|
29
29
|
AiEvents,
|
|
@@ -2381,6 +2381,7 @@ function buildCoreSystemPrompt(contextSection, config) {
|
|
|
2381
2381
|
let skillsSection = "";
|
|
2382
2382
|
let dynamicAgentSection = "";
|
|
2383
2383
|
let directoriesSection = "";
|
|
2384
|
+
let featureModulesSection = "";
|
|
2384
2385
|
if (typeof contextSection === "string") {
|
|
2385
2386
|
projectContextSection = contextSection;
|
|
2386
2387
|
if (config) {
|
|
@@ -2393,6 +2394,9 @@ function buildCoreSystemPrompt(contextSection, config) {
|
|
|
2393
2394
|
if (config.enableDynamicAgentCreation) {
|
|
2394
2395
|
dynamicAgentSection = buildDynamicAgentPromptSection();
|
|
2395
2396
|
}
|
|
2397
|
+
if (config.featureModulePrompts) {
|
|
2398
|
+
featureModulesSection = config.featureModulePrompts;
|
|
2399
|
+
}
|
|
2396
2400
|
}
|
|
2397
2401
|
} else if (contextSection && typeof contextSection === "object") {
|
|
2398
2402
|
config = contextSection;
|
|
@@ -2429,6 +2433,9 @@ To access files in additional directories, pass the full path to the 'dir_path'
|
|
|
2429
2433
|
|
|
2430
2434
|
When the user asks about content in an additional directory, search there first using the dir_path parameter.`;
|
|
2431
2435
|
}
|
|
2436
|
+
if (config.featureModulePrompts) {
|
|
2437
|
+
featureModulesSection = config.featureModulePrompts;
|
|
2438
|
+
}
|
|
2432
2439
|
}
|
|
2433
2440
|
return `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
|
|
2434
2441
|
|
|
@@ -2518,7 +2525,7 @@ EXAMPLES:
|
|
|
2518
2525
|
- "what packages installed?" \u2192 ${TOOL_GLOB_FILES} "**/package.json" \u2192 ${TOOL_FILE_READ}
|
|
2519
2526
|
- "find all components using React hooks" \u2192 ${TOOL_SUBAGENT_DELEGATE}(task="find all components using React hooks", type="explore")
|
|
2520
2527
|
|
|
2521
|
-
Remember: Use context from previous messages to understand follow-up questions.${directoriesSection}${projectContextSection}${skillsSection}`;
|
|
2528
|
+
Remember: Use context from previous messages to understand follow-up questions.${directoriesSection}${projectContextSection}${skillsSection}${featureModulesSection}`;
|
|
2522
2529
|
}
|
|
2523
2530
|
function buildDynamicAgentPromptSection() {
|
|
2524
2531
|
return `
|
|
@@ -2610,6 +2617,18 @@ var ServerToolExecutor = class {
|
|
|
2610
2617
|
|
|
2611
2618
|
// src/llm/ToolRouter.ts
|
|
2612
2619
|
var wsToolExecutor = null;
|
|
2620
|
+
var featureModuleTools = /* @__PURE__ */ new Set();
|
|
2621
|
+
function registerFeatureModuleTools(toolNames) {
|
|
2622
|
+
for (const name of toolNames) {
|
|
2623
|
+
featureModuleTools.add(name);
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
function clearFeatureModuleTools() {
|
|
2627
|
+
featureModuleTools.clear();
|
|
2628
|
+
}
|
|
2629
|
+
function isFeatureModuleTool(toolName) {
|
|
2630
|
+
return featureModuleTools.has(toolName);
|
|
2631
|
+
}
|
|
2613
2632
|
function setWebSocketToolExecutor(executor) {
|
|
2614
2633
|
wsToolExecutor = executor;
|
|
2615
2634
|
}
|
|
@@ -2647,7 +2666,7 @@ async function executeTool(toolName, input, apiClient, localToolFn) {
|
|
|
2647
2666
|
logger.debug(`[ToolRouter] Routing ${toolName} to server via HTTP`);
|
|
2648
2667
|
const executor = new ServerToolExecutor(apiClient);
|
|
2649
2668
|
return await executor.executeTool(toolName, input);
|
|
2650
|
-
} else if (isLocalTool(toolName)) {
|
|
2669
|
+
} else if (isLocalTool(toolName) || isFeatureModuleTool(toolName)) {
|
|
2651
2670
|
logger.debug(`[ToolRouter] Executing ${toolName} locally`);
|
|
2652
2671
|
if (!localToolFn) {
|
|
2653
2672
|
throw new Error(`Local tool ${toolName} has no implementation`);
|
|
@@ -15423,7 +15442,7 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
15423
15442
|
if (!permissionManager.needsPermission(toolName, { isSandboxed })) {
|
|
15424
15443
|
return executeAndRecord();
|
|
15425
15444
|
}
|
|
15426
|
-
const { useCliStore } = await import("./store-
|
|
15445
|
+
const { useCliStore } = await import("./store-CAB6BV3P.js");
|
|
15427
15446
|
if (useCliStore.getState().autoAcceptEdits) {
|
|
15428
15447
|
return executeAndRecord();
|
|
15429
15448
|
}
|
|
@@ -19656,6 +19675,8 @@ export {
|
|
|
19656
19675
|
isReadOnlyTool,
|
|
19657
19676
|
buildSkillsPromptSection,
|
|
19658
19677
|
buildCoreSystemPrompt,
|
|
19678
|
+
registerFeatureModuleTools,
|
|
19679
|
+
clearFeatureModuleTools,
|
|
19659
19680
|
setWebSocketToolExecutor,
|
|
19660
19681
|
ALWAYS_DENIED_FOR_AGENTS,
|
|
19661
19682
|
DEFAULT_MAX_ITERATIONS,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@bike4mind/cli",
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.56-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
7
7
|
type: "module",
|
|
8
8
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
9
9
|
license: "UNLICENSED",
|
|
@@ -73,6 +73,7 @@ var package_default = {
|
|
|
73
73
|
diff: "^8.0.2",
|
|
74
74
|
dotenv: "^17.0.0",
|
|
75
75
|
"eventsource-parser": "^3.0.6",
|
|
76
|
+
exceljs: "^4.4.0",
|
|
76
77
|
fdir: "^6.5.0",
|
|
77
78
|
"file-type": "^18.7.0",
|
|
78
79
|
"fuse.js": "^7.1.0",
|
|
@@ -117,11 +118,11 @@ var package_default = {
|
|
|
117
118
|
zustand: "^4.5.4"
|
|
118
119
|
},
|
|
119
120
|
devDependencies: {
|
|
120
|
-
"@bike4mind/agents": "0.2.
|
|
121
|
-
"@bike4mind/common": "2.70.
|
|
122
|
-
"@bike4mind/mcp": "1.33.
|
|
123
|
-
"@bike4mind/services": "2.64.
|
|
124
|
-
"@bike4mind/utils": "2.15.
|
|
121
|
+
"@bike4mind/agents": "0.2.2-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
122
|
+
"@bike4mind/common": "2.70.2-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
123
|
+
"@bike4mind/mcp": "1.33.16-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
124
|
+
"@bike4mind/services": "2.64.4-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
125
|
+
"@bike4mind/utils": "2.15.10-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
125
126
|
"@types/better-sqlite3": "^7.6.13",
|
|
126
127
|
"@types/jsonwebtoken": "^9.0.4",
|
|
127
128
|
"@types/node": "^22.9.0",
|
|
@@ -138,7 +139,7 @@ var package_default = {
|
|
|
138
139
|
optionalDependencies: {
|
|
139
140
|
"@vscode/ripgrep": "^1.17.1"
|
|
140
141
|
},
|
|
141
|
-
gitHead: "
|
|
142
|
+
gitHead: "2f1552bbd1fd89923637cbcf2a6e40b729437a2d"
|
|
142
143
|
};
|
|
143
144
|
|
|
144
145
|
// src/utils/updateChecker.ts
|
|
@@ -128,7 +128,14 @@ var useCliStore = create((set) => ({
|
|
|
128
128
|
clearCompletedGroupNotifications: () => set({ completedGroupNotifications: [] }),
|
|
129
129
|
// Pending background trigger
|
|
130
130
|
pendingBackgroundTrigger: false,
|
|
131
|
-
setPendingBackgroundTrigger: (pending) => set({ pendingBackgroundTrigger: pending })
|
|
131
|
+
setPendingBackgroundTrigger: (pending) => set({ pendingBackgroundTrigger: pending }),
|
|
132
|
+
// Tavern activity log (capped at 200 entries)
|
|
133
|
+
tavernActivityLog: [],
|
|
134
|
+
addTavernLogEntry: (entry) => set((state) => {
|
|
135
|
+
const log = [...state.tavernActivityLog, entry];
|
|
136
|
+
return { tavernActivityLog: log.length > 200 ? log.slice(-200) : log };
|
|
137
|
+
}),
|
|
138
|
+
clearTavernActivityLog: () => set({ tavernActivityLog: [] })
|
|
132
139
|
}));
|
|
133
140
|
var selectActiveBackgroundAgents = (state) => state.backgroundAgents.filter((j) => isActiveStatus(j.status));
|
|
134
141
|
var selectCompletedBackgroundAgents = (state) => state.backgroundAgents.filter((j) => !isActiveStatus(j.status));
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
isReadOnlyTool,
|
|
37
37
|
loadContextFiles,
|
|
38
38
|
setWebSocketToolExecutor
|
|
39
|
-
} from "../chunk-
|
|
39
|
+
} from "../chunk-PJ3VATSD.js";
|
|
40
40
|
import "../chunk-BDQBOLYG.js";
|
|
41
41
|
import "../chunk-XACIOJZ7.js";
|
|
42
42
|
import "../chunk-GQGOWACU.js";
|
|
@@ -48,7 +48,7 @@ import "../chunk-BPFEGDC7.js";
|
|
|
48
48
|
import {
|
|
49
49
|
ConfigStore,
|
|
50
50
|
logger
|
|
51
|
-
} from "../chunk-
|
|
51
|
+
} from "../chunk-JV4GPGBC.js";
|
|
52
52
|
import "../chunk-I5ZF2OVL.js";
|
|
53
53
|
import {
|
|
54
54
|
DEFAULT_SANDBOX_CONFIG
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
WebSocketToolExecutor,
|
|
23
23
|
buildCoreSystemPrompt,
|
|
24
24
|
buildSkillsPromptSection,
|
|
25
|
+
clearFeatureModuleTools,
|
|
25
26
|
createAgentDelegateTool,
|
|
26
27
|
createBackgroundAgentTools,
|
|
27
28
|
createFindDefinitionTool,
|
|
@@ -41,12 +42,13 @@ import {
|
|
|
41
42
|
mergeCommands,
|
|
42
43
|
parseAgentConfig,
|
|
43
44
|
processFileReferences,
|
|
45
|
+
registerFeatureModuleTools,
|
|
44
46
|
searchCommands,
|
|
45
47
|
searchFiles,
|
|
46
48
|
setWebSocketToolExecutor,
|
|
47
49
|
substituteArguments,
|
|
48
50
|
warmFileCache
|
|
49
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-PJ3VATSD.js";
|
|
50
52
|
import "./chunk-BDQBOLYG.js";
|
|
51
53
|
import "./chunk-XACIOJZ7.js";
|
|
52
54
|
import "./chunk-GQGOWACU.js";
|
|
@@ -60,15 +62,15 @@ import "./chunk-BPFEGDC7.js";
|
|
|
60
62
|
import {
|
|
61
63
|
ConfigStore,
|
|
62
64
|
logger
|
|
63
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-JV4GPGBC.js";
|
|
64
66
|
import {
|
|
65
67
|
checkForUpdate,
|
|
66
68
|
package_default
|
|
67
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-SDMU65DA.js";
|
|
68
70
|
import {
|
|
69
71
|
selectActiveBackgroundAgents,
|
|
70
72
|
useCliStore
|
|
71
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-Y4WOJJM3.js";
|
|
72
74
|
import {
|
|
73
75
|
CREDIT_DEDUCT_TRANSACTION_TYPES,
|
|
74
76
|
ChatModels
|
|
@@ -1420,6 +1422,19 @@ function buildConfigItems(availableModels) {
|
|
|
1420
1422
|
enableDynamicAgentCreation: value
|
|
1421
1423
|
}
|
|
1422
1424
|
})
|
|
1425
|
+
},
|
|
1426
|
+
{
|
|
1427
|
+
key: "featuresTavern",
|
|
1428
|
+
label: "Tavern",
|
|
1429
|
+
type: "boolean",
|
|
1430
|
+
getValue: (config) => config.features?.tavern ?? false,
|
|
1431
|
+
setValue: (config, value) => ({
|
|
1432
|
+
...config,
|
|
1433
|
+
features: {
|
|
1434
|
+
...config.features,
|
|
1435
|
+
tavern: value
|
|
1436
|
+
}
|
|
1437
|
+
})
|
|
1423
1438
|
}
|
|
1424
1439
|
);
|
|
1425
1440
|
return items;
|
|
@@ -1431,8 +1446,15 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
|
|
|
1431
1446
|
const [isSaving, setIsSaving] = useState7(false);
|
|
1432
1447
|
const configItems = useMemo3(() => buildConfigItems(availableModels), [availableModels]);
|
|
1433
1448
|
const hasChanges = useMemo3(() => {
|
|
1434
|
-
return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel;
|
|
1435
|
-
}, [
|
|
1449
|
+
return JSON.stringify(config.preferences) !== JSON.stringify(editedConfig.preferences) || config.defaultModel !== editedConfig.defaultModel || JSON.stringify(config.features) !== JSON.stringify(editedConfig.features);
|
|
1450
|
+
}, [
|
|
1451
|
+
config.preferences,
|
|
1452
|
+
editedConfig.preferences,
|
|
1453
|
+
config.defaultModel,
|
|
1454
|
+
editedConfig.defaultModel,
|
|
1455
|
+
config.features,
|
|
1456
|
+
editedConfig.features
|
|
1457
|
+
]);
|
|
1436
1458
|
const handleSaveAndClose = async () => {
|
|
1437
1459
|
if (hasChanges) {
|
|
1438
1460
|
try {
|
|
@@ -2681,6 +2703,599 @@ Unlike agent_delegate (which uses pre-defined agents), this tool lets you compos
|
|
|
2681
2703
|
};
|
|
2682
2704
|
}
|
|
2683
2705
|
|
|
2706
|
+
// src/features/FeatureModuleRegistry.ts
|
|
2707
|
+
var FeatureModuleRegistry = class {
|
|
2708
|
+
constructor() {
|
|
2709
|
+
this.modules = [];
|
|
2710
|
+
}
|
|
2711
|
+
/** Register a feature module */
|
|
2712
|
+
register(module) {
|
|
2713
|
+
if (this.modules.some((m) => m.name === module.name)) {
|
|
2714
|
+
throw new Error(`Feature module '${module.name}' is already registered`);
|
|
2715
|
+
}
|
|
2716
|
+
this.modules.push(module);
|
|
2717
|
+
}
|
|
2718
|
+
/** Collect all tools from all registered modules */
|
|
2719
|
+
getAllTools() {
|
|
2720
|
+
return this.modules.flatMap((m) => m.getTools());
|
|
2721
|
+
}
|
|
2722
|
+
/** Get all tool names from all registered modules */
|
|
2723
|
+
getAllToolNames() {
|
|
2724
|
+
return this.getAllTools().map((t) => t.toolSchema.name);
|
|
2725
|
+
}
|
|
2726
|
+
/** Build combined system prompt section from all modules */
|
|
2727
|
+
getSystemPromptSections() {
|
|
2728
|
+
const sections = this.modules.map((m) => m.getSystemPromptSection()).filter((s) => s.length > 0);
|
|
2729
|
+
return sections.length > 0 ? "\n\n" + sections.join("\n\n") : "";
|
|
2730
|
+
}
|
|
2731
|
+
/** Register all WS handlers from all modules */
|
|
2732
|
+
registerAllWsHandlers(wsManager) {
|
|
2733
|
+
for (const module of this.modules) {
|
|
2734
|
+
module.registerWsHandlers?.(wsManager);
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
/** Cleanup all modules */
|
|
2738
|
+
disposeAll() {
|
|
2739
|
+
for (const module of this.modules) {
|
|
2740
|
+
module.dispose?.();
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
/** Get names of all registered modules */
|
|
2744
|
+
getModuleNames() {
|
|
2745
|
+
return this.modules.map((m) => m.name);
|
|
2746
|
+
}
|
|
2747
|
+
/** Check if any modules are registered */
|
|
2748
|
+
get hasModules() {
|
|
2749
|
+
return this.modules.length > 0;
|
|
2750
|
+
}
|
|
2751
|
+
};
|
|
2752
|
+
|
|
2753
|
+
// src/features/tavern/TavernService.ts
|
|
2754
|
+
var TavernService = class {
|
|
2755
|
+
constructor(apiClient) {
|
|
2756
|
+
this.apiClient = apiClient;
|
|
2757
|
+
}
|
|
2758
|
+
async listAgents() {
|
|
2759
|
+
return this.apiClient.get("/api/agents?limit=100");
|
|
2760
|
+
}
|
|
2761
|
+
async mentionAgent(agentName, message, config) {
|
|
2762
|
+
return this.apiClient.post("/api/tavern/mention", {
|
|
2763
|
+
agentName,
|
|
2764
|
+
message,
|
|
2765
|
+
config
|
|
2766
|
+
});
|
|
2767
|
+
}
|
|
2768
|
+
async listQuests() {
|
|
2769
|
+
return this.apiClient.get("/api/tavern/quests");
|
|
2770
|
+
}
|
|
2771
|
+
async postQuest(request) {
|
|
2772
|
+
return this.apiClient.post("/api/tavern/quests", request);
|
|
2773
|
+
}
|
|
2774
|
+
async deleteQuest(questId) {
|
|
2775
|
+
await this.apiClient.delete(`/api/tavern/quests`, { data: { questId } });
|
|
2776
|
+
}
|
|
2777
|
+
async getAgentNotebook(agentId, limit = 50) {
|
|
2778
|
+
return this.apiClient.get(`/api/tavern/agent-notebook?agentId=${agentId}&limit=${limit}`);
|
|
2779
|
+
}
|
|
2780
|
+
async listGates() {
|
|
2781
|
+
return this.apiClient.get("/api/tavern/gates");
|
|
2782
|
+
}
|
|
2783
|
+
async resolveGate(gateId, resolution) {
|
|
2784
|
+
return this.apiClient.post("/api/tavern/gate-resolve", {
|
|
2785
|
+
gateId,
|
|
2786
|
+
resolution
|
|
2787
|
+
});
|
|
2788
|
+
}
|
|
2789
|
+
async toggleHeartbeats(enabled) {
|
|
2790
|
+
return this.apiClient.post("/api/tavern/toggle-heartbeats", { enabled });
|
|
2791
|
+
}
|
|
2792
|
+
async triggerHeartbeat(config) {
|
|
2793
|
+
return this.apiClient.post("/api/tavern/trigger-heartbeat", { config });
|
|
2794
|
+
}
|
|
2795
|
+
async abortHeartbeats() {
|
|
2796
|
+
await this.apiClient.post("/api/tavern/abort-heartbeats", { abort: true });
|
|
2797
|
+
}
|
|
2798
|
+
};
|
|
2799
|
+
|
|
2800
|
+
// src/features/tavern/types.ts
|
|
2801
|
+
import { z } from "zod";
|
|
2802
|
+
var HeartbeatLogEntrySchema = z.object({
|
|
2803
|
+
id: z.string(),
|
|
2804
|
+
agentId: z.string(),
|
|
2805
|
+
agentName: z.string(),
|
|
2806
|
+
action: z.enum([
|
|
2807
|
+
"idle",
|
|
2808
|
+
"speech",
|
|
2809
|
+
"thought",
|
|
2810
|
+
"memory",
|
|
2811
|
+
"move",
|
|
2812
|
+
"reply",
|
|
2813
|
+
"post_quest",
|
|
2814
|
+
"claim_quest",
|
|
2815
|
+
"complete_quest",
|
|
2816
|
+
"tool_use",
|
|
2817
|
+
"email",
|
|
2818
|
+
"move_decoration",
|
|
2819
|
+
"gate_paused",
|
|
2820
|
+
"gate_timed",
|
|
2821
|
+
"gate_proceed",
|
|
2822
|
+
"yolo_override",
|
|
2823
|
+
"intent",
|
|
2824
|
+
"report",
|
|
2825
|
+
"credits"
|
|
2826
|
+
]),
|
|
2827
|
+
text: z.string().optional(),
|
|
2828
|
+
toolOutput: z.string().optional(),
|
|
2829
|
+
targetAgentName: z.string().optional(),
|
|
2830
|
+
threadId: z.string().optional(),
|
|
2831
|
+
timestamp: z.string(),
|
|
2832
|
+
burstId: z.string().optional(),
|
|
2833
|
+
stepIndex: z.number().optional(),
|
|
2834
|
+
totalSteps: z.number().optional(),
|
|
2835
|
+
confidence: z.number().optional(),
|
|
2836
|
+
confidenceSource: z.string().optional(),
|
|
2837
|
+
creditsUsed: z.number().optional()
|
|
2838
|
+
});
|
|
2839
|
+
var AgentSummarySchema = z.object({
|
|
2840
|
+
_id: z.string(),
|
|
2841
|
+
name: z.string(),
|
|
2842
|
+
description: z.string().optional(),
|
|
2843
|
+
heartbeatConfig: z.object({
|
|
2844
|
+
enabled: z.boolean().optional()
|
|
2845
|
+
}).optional()
|
|
2846
|
+
});
|
|
2847
|
+
var AgentListResponseSchema = z.object({
|
|
2848
|
+
data: z.array(AgentSummarySchema),
|
|
2849
|
+
total: z.number().optional()
|
|
2850
|
+
});
|
|
2851
|
+
var MentionRequestSchema = z.object({
|
|
2852
|
+
agentName: z.string().optional(),
|
|
2853
|
+
message: z.string(),
|
|
2854
|
+
config: z.record(z.string(), z.unknown()).optional()
|
|
2855
|
+
});
|
|
2856
|
+
var DirectedMentionResponseSchema = z.object({
|
|
2857
|
+
success: z.boolean(),
|
|
2858
|
+
agentName: z.string(),
|
|
2859
|
+
agentId: z.string(),
|
|
2860
|
+
warning: z.string().optional()
|
|
2861
|
+
});
|
|
2862
|
+
var AmbientMentionResponseSchema = z.object({
|
|
2863
|
+
success: z.boolean(),
|
|
2864
|
+
mode: z.literal("ambient"),
|
|
2865
|
+
agentCount: z.number(),
|
|
2866
|
+
results: z.array(
|
|
2867
|
+
z.object({
|
|
2868
|
+
agentName: z.string(),
|
|
2869
|
+
status: z.string()
|
|
2870
|
+
})
|
|
2871
|
+
)
|
|
2872
|
+
});
|
|
2873
|
+
var MentionResponseSchema = z.union([DirectedMentionResponseSchema, AmbientMentionResponseSchema]);
|
|
2874
|
+
var TavernQuestSchema = z.object({
|
|
2875
|
+
_id: z.string(),
|
|
2876
|
+
title: z.string(),
|
|
2877
|
+
description: z.string().optional(),
|
|
2878
|
+
status: z.string(),
|
|
2879
|
+
postedBy: z.string(),
|
|
2880
|
+
claimedBy: z.string().optional(),
|
|
2881
|
+
difficulty: z.string().optional(),
|
|
2882
|
+
createdAt: z.string().optional(),
|
|
2883
|
+
updatedAt: z.string().optional()
|
|
2884
|
+
});
|
|
2885
|
+
var QuestListResponseSchema = z.object({
|
|
2886
|
+
quests: z.array(TavernQuestSchema)
|
|
2887
|
+
});
|
|
2888
|
+
var CreateQuestRequestSchema = z.object({
|
|
2889
|
+
title: z.string(),
|
|
2890
|
+
description: z.string().optional(),
|
|
2891
|
+
agentId: z.string(),
|
|
2892
|
+
agentName: z.string(),
|
|
2893
|
+
difficulty: z.enum(["easy", "medium", "hard", "epic"]).optional()
|
|
2894
|
+
});
|
|
2895
|
+
var QuestResponseSchema = z.object({
|
|
2896
|
+
quest: TavernQuestSchema
|
|
2897
|
+
});
|
|
2898
|
+
var NotebookEntrySchema = z.object({
|
|
2899
|
+
_id: z.string(),
|
|
2900
|
+
title: z.string().optional(),
|
|
2901
|
+
content: z.string().optional(),
|
|
2902
|
+
createdAt: z.string().optional()
|
|
2903
|
+
});
|
|
2904
|
+
var NotebookResponseSchema = z.object({
|
|
2905
|
+
sessionId: z.string().nullable(),
|
|
2906
|
+
entries: z.array(NotebookEntrySchema)
|
|
2907
|
+
});
|
|
2908
|
+
var TimedGateSchema = z.object({
|
|
2909
|
+
gateId: z.string(),
|
|
2910
|
+
agentId: z.string(),
|
|
2911
|
+
agentName: z.string(),
|
|
2912
|
+
userId: z.string(),
|
|
2913
|
+
confidence: z.number(),
|
|
2914
|
+
reason: z.string(),
|
|
2915
|
+
createdAt: z.number(),
|
|
2916
|
+
expiresAt: z.number(),
|
|
2917
|
+
delayMs: z.number(),
|
|
2918
|
+
status: z.enum(["pending", "approved", "rejected", "expired", "auto_proceeded"]),
|
|
2919
|
+
resolvedBy: z.enum(["human", "timer"]).optional(),
|
|
2920
|
+
resolvedAt: z.number().optional(),
|
|
2921
|
+
burstId: z.string(),
|
|
2922
|
+
iteration: z.number()
|
|
2923
|
+
});
|
|
2924
|
+
var GateListResponseSchema = z.object({
|
|
2925
|
+
gates: z.array(TimedGateSchema)
|
|
2926
|
+
});
|
|
2927
|
+
var GateResolveRequestSchema = z.object({
|
|
2928
|
+
gateId: z.string(),
|
|
2929
|
+
resolution: z.enum(["approve", "reject"])
|
|
2930
|
+
});
|
|
2931
|
+
var GateResolveResponseSchema = z.object({
|
|
2932
|
+
success: z.boolean(),
|
|
2933
|
+
gate: TimedGateSchema
|
|
2934
|
+
});
|
|
2935
|
+
var HeartbeatToggleResponseSchema = z.object({
|
|
2936
|
+
success: z.boolean(),
|
|
2937
|
+
enabled: z.boolean(),
|
|
2938
|
+
agentCount: z.number()
|
|
2939
|
+
});
|
|
2940
|
+
var TriggerHeartbeatResponseSchema = z.object({
|
|
2941
|
+
triggered: z.number(),
|
|
2942
|
+
results: z.array(
|
|
2943
|
+
z.object({
|
|
2944
|
+
agentId: z.string(),
|
|
2945
|
+
agentName: z.string(),
|
|
2946
|
+
status: z.string(),
|
|
2947
|
+
error: z.string().optional()
|
|
2948
|
+
})
|
|
2949
|
+
)
|
|
2950
|
+
});
|
|
2951
|
+
|
|
2952
|
+
// src/features/tavern/TavernActivityStream.ts
|
|
2953
|
+
var TavernActivityStream = class {
|
|
2954
|
+
constructor(onLogEntry) {
|
|
2955
|
+
this.onLogEntry = onLogEntry;
|
|
2956
|
+
this.wsManager = null;
|
|
2957
|
+
}
|
|
2958
|
+
/** Register the WS handler for tavern_heartbeat_log events */
|
|
2959
|
+
registerHandlers(wsManager) {
|
|
2960
|
+
this.wsManager = wsManager;
|
|
2961
|
+
wsManager.onAction("tavern_heartbeat_log", (message) => {
|
|
2962
|
+
const parsed = message;
|
|
2963
|
+
if (!parsed.entry) return;
|
|
2964
|
+
const result = HeartbeatLogEntrySchema.safeParse(parsed.entry);
|
|
2965
|
+
if (result.success) {
|
|
2966
|
+
this.onLogEntry(result.data);
|
|
2967
|
+
}
|
|
2968
|
+
});
|
|
2969
|
+
}
|
|
2970
|
+
/** Unsubscribe from WS events */
|
|
2971
|
+
dispose() {
|
|
2972
|
+
if (this.wsManager) {
|
|
2973
|
+
this.wsManager.offAction("tavern_heartbeat_log");
|
|
2974
|
+
this.wsManager = null;
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
};
|
|
2978
|
+
|
|
2979
|
+
// src/features/tavern/tavernTools.ts
|
|
2980
|
+
function createTavernTools(service) {
|
|
2981
|
+
return [
|
|
2982
|
+
createListAgentsTool(service),
|
|
2983
|
+
createMentionTool(service),
|
|
2984
|
+
createListQuestsTool(service),
|
|
2985
|
+
createPostQuestTool(service),
|
|
2986
|
+
createDeleteQuestTool(service),
|
|
2987
|
+
createReadNotebookTool(service),
|
|
2988
|
+
createListGatesTool(service),
|
|
2989
|
+
createResolveGateTool(service),
|
|
2990
|
+
createToggleHeartbeatsTool(service),
|
|
2991
|
+
createTriggerHeartbeatTool(service),
|
|
2992
|
+
createAbortHeartbeatsTool(service)
|
|
2993
|
+
];
|
|
2994
|
+
}
|
|
2995
|
+
function createListAgentsTool(service) {
|
|
2996
|
+
return {
|
|
2997
|
+
toolSchema: {
|
|
2998
|
+
name: "tavern_list_agents",
|
|
2999
|
+
description: "List all Tavern agents with their IDs, names, descriptions, and heartbeat status. Use this FIRST to discover agent IDs before using tools that require an agent_id (like tavern_read_notebook or tavern_post_quest).",
|
|
3000
|
+
parameters: {
|
|
3001
|
+
type: "object",
|
|
3002
|
+
properties: {}
|
|
3003
|
+
}
|
|
3004
|
+
},
|
|
3005
|
+
toolFn: async () => {
|
|
3006
|
+
const result = await service.listAgents();
|
|
3007
|
+
return JSON.stringify(result);
|
|
3008
|
+
}
|
|
3009
|
+
};
|
|
3010
|
+
}
|
|
3011
|
+
function createMentionTool(service) {
|
|
3012
|
+
return {
|
|
3013
|
+
toolSchema: {
|
|
3014
|
+
name: "tavern_mention",
|
|
3015
|
+
description: "Send a message to a specific Tavern agent by name, or broadcast an ambient message to all agents if no agent_name is provided. Use this to talk to agents, ask them questions, give them instructions, or announce something to the whole tavern.",
|
|
3016
|
+
parameters: {
|
|
3017
|
+
type: "object",
|
|
3018
|
+
properties: {
|
|
3019
|
+
agent_name: {
|
|
3020
|
+
type: "string",
|
|
3021
|
+
description: "Name of the agent to mention (omit for ambient broadcast to all agents)"
|
|
3022
|
+
},
|
|
3023
|
+
message: {
|
|
3024
|
+
type: "string",
|
|
3025
|
+
description: "The message to send to the agent(s)"
|
|
3026
|
+
}
|
|
3027
|
+
},
|
|
3028
|
+
required: ["message"]
|
|
3029
|
+
}
|
|
3030
|
+
},
|
|
3031
|
+
toolFn: async (params) => {
|
|
3032
|
+
const { agent_name, message } = params;
|
|
3033
|
+
const result = await service.mentionAgent(agent_name, message);
|
|
3034
|
+
return JSON.stringify(result);
|
|
3035
|
+
}
|
|
3036
|
+
};
|
|
3037
|
+
}
|
|
3038
|
+
function createListQuestsTool(service) {
|
|
3039
|
+
return {
|
|
3040
|
+
toolSchema: {
|
|
3041
|
+
name: "tavern_list_quests",
|
|
3042
|
+
description: "List all quests on the Tavern quest board. Shows quest title, status, who posted it, and who claimed it.",
|
|
3043
|
+
parameters: {
|
|
3044
|
+
type: "object",
|
|
3045
|
+
properties: {}
|
|
3046
|
+
}
|
|
3047
|
+
},
|
|
3048
|
+
toolFn: async () => {
|
|
3049
|
+
const result = await service.listQuests();
|
|
3050
|
+
return JSON.stringify(result);
|
|
3051
|
+
}
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
function createPostQuestTool(service) {
|
|
3055
|
+
return {
|
|
3056
|
+
toolSchema: {
|
|
3057
|
+
name: "tavern_post_quest",
|
|
3058
|
+
description: "Post a new quest to the Tavern quest board for agents to discover and claim.",
|
|
3059
|
+
parameters: {
|
|
3060
|
+
type: "object",
|
|
3061
|
+
properties: {
|
|
3062
|
+
title: {
|
|
3063
|
+
type: "string",
|
|
3064
|
+
description: "Quest title"
|
|
3065
|
+
},
|
|
3066
|
+
description: {
|
|
3067
|
+
type: "string",
|
|
3068
|
+
description: "Detailed quest description"
|
|
3069
|
+
},
|
|
3070
|
+
agent_id: {
|
|
3071
|
+
type: "string",
|
|
3072
|
+
description: "ID of the agent posting the quest"
|
|
3073
|
+
},
|
|
3074
|
+
agent_name: {
|
|
3075
|
+
type: "string",
|
|
3076
|
+
description: "Name of the agent posting the quest"
|
|
3077
|
+
},
|
|
3078
|
+
difficulty: {
|
|
3079
|
+
type: "string",
|
|
3080
|
+
description: "Quest difficulty level",
|
|
3081
|
+
enum: ["easy", "medium", "hard", "epic"]
|
|
3082
|
+
}
|
|
3083
|
+
},
|
|
3084
|
+
required: ["title", "agent_id", "agent_name"]
|
|
3085
|
+
}
|
|
3086
|
+
},
|
|
3087
|
+
toolFn: async (params) => {
|
|
3088
|
+
const raw = params;
|
|
3089
|
+
const request = CreateQuestRequestSchema.parse({
|
|
3090
|
+
title: raw.title,
|
|
3091
|
+
description: raw.description,
|
|
3092
|
+
agentId: raw.agent_id,
|
|
3093
|
+
agentName: raw.agent_name,
|
|
3094
|
+
difficulty: raw.difficulty
|
|
3095
|
+
});
|
|
3096
|
+
const result = await service.postQuest(request);
|
|
3097
|
+
return JSON.stringify(result);
|
|
3098
|
+
}
|
|
3099
|
+
};
|
|
3100
|
+
}
|
|
3101
|
+
function createDeleteQuestTool(service) {
|
|
3102
|
+
return {
|
|
3103
|
+
toolSchema: {
|
|
3104
|
+
name: "tavern_delete_quest",
|
|
3105
|
+
description: "Remove a quest from the Tavern quest board by its ID.",
|
|
3106
|
+
parameters: {
|
|
3107
|
+
type: "object",
|
|
3108
|
+
properties: {
|
|
3109
|
+
quest_id: {
|
|
3110
|
+
type: "string",
|
|
3111
|
+
description: "The ID of the quest to delete"
|
|
3112
|
+
}
|
|
3113
|
+
},
|
|
3114
|
+
required: ["quest_id"]
|
|
3115
|
+
}
|
|
3116
|
+
},
|
|
3117
|
+
toolFn: async (params) => {
|
|
3118
|
+
const { quest_id } = params;
|
|
3119
|
+
await service.deleteQuest(quest_id);
|
|
3120
|
+
return JSON.stringify({ success: true });
|
|
3121
|
+
}
|
|
3122
|
+
};
|
|
3123
|
+
}
|
|
3124
|
+
function createReadNotebookTool(service) {
|
|
3125
|
+
return {
|
|
3126
|
+
toolSchema: {
|
|
3127
|
+
name: "tavern_read_notebook",
|
|
3128
|
+
description: `Read a Tavern agent's activity notebook/history. Shows their recent actions, thoughts, conversations, and quest progress. IMPORTANT: agent_id must be a MongoDB ObjectId (e.g. "6540b58d1f703ade3ea1e82b"), NOT the agent name. Use tavern_list_agents first to get the correct ID.`,
|
|
3129
|
+
parameters: {
|
|
3130
|
+
type: "object",
|
|
3131
|
+
properties: {
|
|
3132
|
+
agent_id: {
|
|
3133
|
+
type: "string",
|
|
3134
|
+
description: "The MongoDB ObjectId of the agent (get this from tavern_list_agents, NOT the agent name)"
|
|
3135
|
+
},
|
|
3136
|
+
limit: {
|
|
3137
|
+
type: "number",
|
|
3138
|
+
description: "Maximum number of entries to return (default: 50)"
|
|
3139
|
+
}
|
|
3140
|
+
},
|
|
3141
|
+
required: ["agent_id"]
|
|
3142
|
+
}
|
|
3143
|
+
},
|
|
3144
|
+
toolFn: async (params) => {
|
|
3145
|
+
const { agent_id, limit } = params;
|
|
3146
|
+
const result = await service.getAgentNotebook(agent_id, limit);
|
|
3147
|
+
return JSON.stringify(result);
|
|
3148
|
+
}
|
|
3149
|
+
};
|
|
3150
|
+
}
|
|
3151
|
+
function createListGatesTool(service) {
|
|
3152
|
+
return {
|
|
3153
|
+
toolSchema: {
|
|
3154
|
+
name: "tavern_list_gates",
|
|
3155
|
+
description: "List all pending confidence gates in the Tavern. Gates are pause points where agents need human approval to proceed with low-confidence actions.",
|
|
3156
|
+
parameters: {
|
|
3157
|
+
type: "object",
|
|
3158
|
+
properties: {}
|
|
3159
|
+
}
|
|
3160
|
+
},
|
|
3161
|
+
toolFn: async () => {
|
|
3162
|
+
const result = await service.listGates();
|
|
3163
|
+
return JSON.stringify(result);
|
|
3164
|
+
}
|
|
3165
|
+
};
|
|
3166
|
+
}
|
|
3167
|
+
function createResolveGateTool(service) {
|
|
3168
|
+
return {
|
|
3169
|
+
toolSchema: {
|
|
3170
|
+
name: "tavern_resolve_gate",
|
|
3171
|
+
description: "Approve or reject a pending confidence gate. This lets an agent proceed or stops its current action.",
|
|
3172
|
+
parameters: {
|
|
3173
|
+
type: "object",
|
|
3174
|
+
properties: {
|
|
3175
|
+
gate_id: {
|
|
3176
|
+
type: "string",
|
|
3177
|
+
description: "The ID of the gate to resolve"
|
|
3178
|
+
},
|
|
3179
|
+
resolution: {
|
|
3180
|
+
type: "string",
|
|
3181
|
+
description: "Whether to approve or reject the gate",
|
|
3182
|
+
enum: ["approve", "reject"]
|
|
3183
|
+
}
|
|
3184
|
+
},
|
|
3185
|
+
required: ["gate_id", "resolution"]
|
|
3186
|
+
}
|
|
3187
|
+
},
|
|
3188
|
+
toolFn: async (params) => {
|
|
3189
|
+
const { gate_id, resolution } = params;
|
|
3190
|
+
const result = await service.resolveGate(gate_id, resolution);
|
|
3191
|
+
return JSON.stringify(result);
|
|
3192
|
+
}
|
|
3193
|
+
};
|
|
3194
|
+
}
|
|
3195
|
+
function createToggleHeartbeatsTool(service) {
|
|
3196
|
+
return {
|
|
3197
|
+
toolSchema: {
|
|
3198
|
+
name: "tavern_toggle_heartbeats",
|
|
3199
|
+
description: "Enable or disable background heartbeats for all Tavern agents. When enabled, agents autonomously think, act, and interact on a schedule.",
|
|
3200
|
+
parameters: {
|
|
3201
|
+
type: "object",
|
|
3202
|
+
properties: {
|
|
3203
|
+
enabled: {
|
|
3204
|
+
type: "boolean",
|
|
3205
|
+
description: "true to enable heartbeats, false to disable"
|
|
3206
|
+
}
|
|
3207
|
+
},
|
|
3208
|
+
required: ["enabled"]
|
|
3209
|
+
}
|
|
3210
|
+
},
|
|
3211
|
+
toolFn: async (params) => {
|
|
3212
|
+
const { enabled } = params;
|
|
3213
|
+
const result = await service.toggleHeartbeats(enabled);
|
|
3214
|
+
return JSON.stringify(result);
|
|
3215
|
+
}
|
|
3216
|
+
};
|
|
3217
|
+
}
|
|
3218
|
+
function createTriggerHeartbeatTool(service) {
|
|
3219
|
+
return {
|
|
3220
|
+
toolSchema: {
|
|
3221
|
+
name: "tavern_trigger_heartbeat",
|
|
3222
|
+
description: "Manually trigger a heartbeat cycle for all Tavern agents. Useful for testing or forcing immediate agent activity.",
|
|
3223
|
+
parameters: {
|
|
3224
|
+
type: "object",
|
|
3225
|
+
properties: {
|
|
3226
|
+
config: {
|
|
3227
|
+
type: "object",
|
|
3228
|
+
description: "Optional configuration overrides for the heartbeat (e.g. preferredModelId, costMode)",
|
|
3229
|
+
additionalProperties: true
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
},
|
|
3234
|
+
toolFn: async (params) => {
|
|
3235
|
+
const { config } = params ?? {};
|
|
3236
|
+
const result = await service.triggerHeartbeat(config);
|
|
3237
|
+
return JSON.stringify(result);
|
|
3238
|
+
}
|
|
3239
|
+
};
|
|
3240
|
+
}
|
|
3241
|
+
function createAbortHeartbeatsTool(service) {
|
|
3242
|
+
return {
|
|
3243
|
+
toolSchema: {
|
|
3244
|
+
name: "tavern_abort_heartbeats",
|
|
3245
|
+
description: "Emergency stop \u2014 abort all in-flight Tavern agent heartbeats immediately.",
|
|
3246
|
+
parameters: {
|
|
3247
|
+
type: "object",
|
|
3248
|
+
properties: {}
|
|
3249
|
+
}
|
|
3250
|
+
},
|
|
3251
|
+
toolFn: async () => {
|
|
3252
|
+
await service.abortHeartbeats();
|
|
3253
|
+
return JSON.stringify({ success: true, message: "All in-flight heartbeats aborted" });
|
|
3254
|
+
}
|
|
3255
|
+
};
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
// src/features/tavern/TavernModule.ts
|
|
3259
|
+
var TavernModule = class {
|
|
3260
|
+
constructor(apiClient, onLogEntry) {
|
|
3261
|
+
this.name = "tavern";
|
|
3262
|
+
this.description = "Interact with autonomous AI agents in the B4M Tavern";
|
|
3263
|
+
this.service = new TavernService(apiClient);
|
|
3264
|
+
this.activityStream = new TavernActivityStream(onLogEntry);
|
|
3265
|
+
}
|
|
3266
|
+
getTools() {
|
|
3267
|
+
return createTavernTools(this.service);
|
|
3268
|
+
}
|
|
3269
|
+
getSystemPromptSection() {
|
|
3270
|
+
return `## Tavern Integration
|
|
3271
|
+
You can interact with autonomous AI agents in the B4M Tavern using tavern_* tools.
|
|
3272
|
+
|
|
3273
|
+
IMPORTANT: Many tools require agent IDs (MongoDB ObjectIds like "6540b58d1f703ade3ea1e82b"). Always use tavern_list_agents FIRST to discover agent names and their IDs before using tools that need an agent_id.
|
|
3274
|
+
|
|
3275
|
+
Available actions:
|
|
3276
|
+
- **tavern_list_agents**: List all agents with their IDs, names, and status \u2014 USE THIS FIRST
|
|
3277
|
+
- **tavern_mention**: Talk to a specific agent by name or broadcast to all agents
|
|
3278
|
+
- **tavern_list_quests**: View the quest board
|
|
3279
|
+
- **tavern_post_quest**: Post a new quest for agents to claim
|
|
3280
|
+
- **tavern_delete_quest**: Remove a quest from the board
|
|
3281
|
+
- **tavern_read_notebook**: Read an agent's activity history (requires agent ID from tavern_list_agents)
|
|
3282
|
+
- **tavern_list_gates**: See pending confidence gates awaiting human approval
|
|
3283
|
+
- **tavern_resolve_gate**: Approve or reject a confidence gate
|
|
3284
|
+
- **tavern_toggle_heartbeats**: Enable/disable agent background heartbeats
|
|
3285
|
+
- **tavern_trigger_heartbeat**: Manually trigger a heartbeat cycle
|
|
3286
|
+
- **tavern_abort_heartbeats**: Emergency stop all in-flight heartbeats
|
|
3287
|
+
|
|
3288
|
+
When the user mentions talking to agents, checking the quest board, or managing the tavern, use these tools.
|
|
3289
|
+
Agents have personalities, moods, quests, and memories \u2014 they are autonomous entities, not chatbots.`;
|
|
3290
|
+
}
|
|
3291
|
+
registerWsHandlers(wsManager) {
|
|
3292
|
+
this.activityStream.registerHandlers(wsManager);
|
|
3293
|
+
}
|
|
3294
|
+
dispose() {
|
|
3295
|
+
this.activityStream.dispose();
|
|
3296
|
+
}
|
|
3297
|
+
};
|
|
3298
|
+
|
|
2684
3299
|
// src/index.tsx
|
|
2685
3300
|
process.removeAllListeners("warning");
|
|
2686
3301
|
process.on("warning", (warning) => {
|
|
@@ -2720,7 +3335,8 @@ function CliApp() {
|
|
|
2720
3335
|
sandboxOrchestrator: null,
|
|
2721
3336
|
wsManager: null,
|
|
2722
3337
|
checkpointStore: null,
|
|
2723
|
-
additionalDirectories: []
|
|
3338
|
+
additionalDirectories: [],
|
|
3339
|
+
featureRegistry: null
|
|
2724
3340
|
});
|
|
2725
3341
|
const [isInitialized, setIsInitialized] = useState12(false);
|
|
2726
3342
|
const [initError, setInitError] = useState12(null);
|
|
@@ -2750,6 +3366,9 @@ function CliApp() {
|
|
|
2750
3366
|
})
|
|
2751
3367
|
);
|
|
2752
3368
|
}
|
|
3369
|
+
if (state.featureRegistry) {
|
|
3370
|
+
state.featureRegistry.disposeAll();
|
|
3371
|
+
}
|
|
2753
3372
|
if (state.wsManager) {
|
|
2754
3373
|
state.wsManager.disconnect();
|
|
2755
3374
|
setWebSocketToolExecutor(null);
|
|
@@ -2772,7 +3391,15 @@ function CliApp() {
|
|
|
2772
3391
|
setTimeout(() => {
|
|
2773
3392
|
process.exit(0);
|
|
2774
3393
|
}, 100);
|
|
2775
|
-
}, [
|
|
3394
|
+
}, [
|
|
3395
|
+
state.session,
|
|
3396
|
+
state.sessionStore,
|
|
3397
|
+
state.mcpManager,
|
|
3398
|
+
state.agent,
|
|
3399
|
+
state.imageStore,
|
|
3400
|
+
state.wsManager,
|
|
3401
|
+
state.featureRegistry
|
|
3402
|
+
]);
|
|
2776
3403
|
useInput10((input, key) => {
|
|
2777
3404
|
if (key.escape) {
|
|
2778
3405
|
const store = useCliStore.getState();
|
|
@@ -3199,6 +3826,21 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3199
3826
|
}) : null;
|
|
3200
3827
|
const findDefinitionTool = createFindDefinitionTool();
|
|
3201
3828
|
const getFileStructureTool = createGetFileStructureTool();
|
|
3829
|
+
const featureRegistry = new FeatureModuleRegistry();
|
|
3830
|
+
if (config.features?.tavern) {
|
|
3831
|
+
featureRegistry.register(
|
|
3832
|
+
new TavernModule(apiClient, (entry) => {
|
|
3833
|
+
useCliStore.getState().addTavernLogEntry(entry);
|
|
3834
|
+
})
|
|
3835
|
+
);
|
|
3836
|
+
}
|
|
3837
|
+
const featureModuleToolNames = featureRegistry.getAllToolNames();
|
|
3838
|
+
if (featureModuleToolNames.length > 0) {
|
|
3839
|
+
registerFeatureModuleTools(featureModuleToolNames);
|
|
3840
|
+
}
|
|
3841
|
+
if (wsManager && featureRegistry.hasModules) {
|
|
3842
|
+
featureRegistry.registerAllWsHandlers(wsManager);
|
|
3843
|
+
}
|
|
3202
3844
|
const cliTools = [
|
|
3203
3845
|
agentDelegateTool,
|
|
3204
3846
|
...backgroundTools,
|
|
@@ -3212,7 +3854,8 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3212
3854
|
if (dynamicAgentTool) {
|
|
3213
3855
|
cliTools.push(dynamicAgentTool);
|
|
3214
3856
|
}
|
|
3215
|
-
const
|
|
3857
|
+
const featureTools = featureRegistry.getAllTools();
|
|
3858
|
+
const allTools = [...b4mTools, ...mcpTools, ...cliTools, ...featureTools];
|
|
3216
3859
|
startupLog.push(`\u{1F4C2} Working directory: ${process.cwd()}`);
|
|
3217
3860
|
if (additionalDirectories.length > 0) {
|
|
3218
3861
|
startupLog.push(`\u{1F4C1} Additional directories: ${additionalDirectories.length}`);
|
|
@@ -3228,8 +3871,12 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3228
3871
|
if (dynamicAgentTool) {
|
|
3229
3872
|
startupLog.push(`\u{1F9EA} Dynamic agent creation enabled (experimental)`);
|
|
3230
3873
|
}
|
|
3874
|
+
if (featureRegistry.hasModules) {
|
|
3875
|
+
const moduleNames = featureRegistry.getModuleNames().join(", ");
|
|
3876
|
+
startupLog.push(`\u{1F3F0} Feature modules: ${moduleNames} (${featureTools.length} tools)`);
|
|
3877
|
+
}
|
|
3231
3878
|
logger.debug(
|
|
3232
|
-
`Total tools available to agent: ${allTools.length} (${b4mTools.length} B4M + ${mcpTools.length} MCP + ${cliTools.length} CLI)`
|
|
3879
|
+
`Total tools available to agent: ${allTools.length} (${b4mTools.length} B4M + ${mcpTools.length} MCP + ${cliTools.length} CLI + ${featureTools.length} feature)`
|
|
3233
3880
|
);
|
|
3234
3881
|
if (contextResult.globalContext) {
|
|
3235
3882
|
startupLog.push(`\u{1F4C4} Global context: ${contextResult.globalContext.filename}`);
|
|
@@ -3240,13 +3887,15 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3240
3887
|
for (const error of contextResult.errors) {
|
|
3241
3888
|
startupLog.push(`\u26A0\uFE0F Context file error: ${error}`);
|
|
3242
3889
|
}
|
|
3890
|
+
const featureModulePrompts = featureRegistry.getSystemPromptSections();
|
|
3243
3891
|
const cliSystemPrompt = buildCoreSystemPrompt({
|
|
3244
3892
|
contextContent: contextResult.mergedContent,
|
|
3245
3893
|
agentStore,
|
|
3246
3894
|
customCommands: state.customCommandStore.getAllCommands(),
|
|
3247
3895
|
enableSkillTool,
|
|
3248
3896
|
enableDynamicAgentCreation: config.preferences.enableDynamicAgentCreation === true,
|
|
3249
|
-
additionalDirectories
|
|
3897
|
+
additionalDirectories,
|
|
3898
|
+
featureModulePrompts: featureModulePrompts || void 0
|
|
3250
3899
|
});
|
|
3251
3900
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
3252
3901
|
const agent = new ReActAgent({
|
|
@@ -3314,8 +3963,10 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3314
3963
|
// WebSocket connection manager (null if using SSE fallback)
|
|
3315
3964
|
checkpointStore,
|
|
3316
3965
|
// File change checkpointing for undo/restore
|
|
3317
|
-
additionalDirectories
|
|
3966
|
+
additionalDirectories,
|
|
3318
3967
|
// Store additional directories for file access
|
|
3968
|
+
featureRegistry
|
|
3969
|
+
// Feature module registry for opt-in modules
|
|
3319
3970
|
}));
|
|
3320
3971
|
setStoreSession(newSession);
|
|
3321
3972
|
const bannerLines = [
|
|
@@ -3592,7 +4243,8 @@ Pull a model: ollama pull qwen3.5`
|
|
|
3592
4243
|
agentStore: state.agentStore || void 0,
|
|
3593
4244
|
customCommands: state.customCommandStore.getAllCommands(),
|
|
3594
4245
|
enableSkillTool: config?.preferences.enableSkillTool !== false,
|
|
3595
|
-
additionalDirectories: state.additionalDirectories
|
|
4246
|
+
additionalDirectories: state.additionalDirectories,
|
|
4247
|
+
featureModulePrompts: state.featureRegistry?.getSystemPromptSections() || void 0
|
|
3596
4248
|
});
|
|
3597
4249
|
const contextUsage = tokenCounter2.countSessionTokens(activeSession, systemPrompt);
|
|
3598
4250
|
if (contextUsage.totalTokens >= threshold) {
|
|
@@ -4647,7 +5299,8 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
4647
5299
|
agentStore: state.agentStore || void 0,
|
|
4648
5300
|
customCommands: commands,
|
|
4649
5301
|
enableSkillTool: state.config?.preferences.enableSkillTool !== false,
|
|
4650
|
-
additionalDirectories: state.additionalDirectories
|
|
5302
|
+
additionalDirectories: state.additionalDirectories,
|
|
5303
|
+
featureModulePrompts: state.featureRegistry?.getSystemPromptSections() || void 0
|
|
4651
5304
|
});
|
|
4652
5305
|
const usage = tokenCounter2.countSessionTokens(state.session, systemPrompt);
|
|
4653
5306
|
const totalWithTools = usage.totalTokens + mcpToolsTokens;
|
|
@@ -5203,7 +5856,56 @@ Allowed domains (${domains.length}):`);
|
|
|
5203
5856
|
const handleSaveConfig = async (updatedConfig) => {
|
|
5204
5857
|
await state.configStore.save(updatedConfig);
|
|
5205
5858
|
const modelChanged = state.config?.defaultModel !== updatedConfig.defaultModel;
|
|
5859
|
+
const featuresChanged = JSON.stringify(state.config?.features ?? {}) !== JSON.stringify(updatedConfig.features ?? {});
|
|
5860
|
+
let newFeatureRegistry = state.featureRegistry;
|
|
5861
|
+
if (featuresChanged && state.agent) {
|
|
5862
|
+
state.featureRegistry?.disposeAll();
|
|
5863
|
+
clearFeatureModuleTools();
|
|
5864
|
+
newFeatureRegistry = new FeatureModuleRegistry();
|
|
5865
|
+
const apiClient = new ApiClient(getApiUrl(updatedConfig.apiConfig), state.configStore);
|
|
5866
|
+
if (updatedConfig.features?.tavern) {
|
|
5867
|
+
newFeatureRegistry.register(
|
|
5868
|
+
new TavernModule(apiClient, (entry) => {
|
|
5869
|
+
useCliStore.getState().addTavernLogEntry(entry);
|
|
5870
|
+
})
|
|
5871
|
+
);
|
|
5872
|
+
}
|
|
5873
|
+
const newToolNames = newFeatureRegistry.getAllToolNames();
|
|
5874
|
+
if (newToolNames.length > 0) {
|
|
5875
|
+
registerFeatureModuleTools(newToolNames);
|
|
5876
|
+
}
|
|
5877
|
+
if (state.wsManager && newFeatureRegistry.hasModules) {
|
|
5878
|
+
newFeatureRegistry.registerAllWsHandlers(state.wsManager);
|
|
5879
|
+
}
|
|
5880
|
+
const agentContext = state.agent.context;
|
|
5881
|
+
const oldFeatureToolNames = new Set(state.featureRegistry?.getAllToolNames() ?? []);
|
|
5882
|
+
const baseTools = agentContext.tools.filter((t) => !oldFeatureToolNames.has(t.toolSchema.name));
|
|
5883
|
+
const newFeatureTools = newFeatureRegistry.getAllTools();
|
|
5884
|
+
agentContext.tools = [...baseTools, ...newFeatureTools];
|
|
5885
|
+
const newFeaturePrompts = newFeatureRegistry.getSystemPromptSections();
|
|
5886
|
+
agentContext.systemPrompt = buildCoreSystemPrompt({
|
|
5887
|
+
contextContent: state.contextContent,
|
|
5888
|
+
agentStore: state.agentStore || void 0,
|
|
5889
|
+
customCommands: state.customCommandStore.getAllCommands(),
|
|
5890
|
+
enableSkillTool: updatedConfig.preferences.enableSkillTool !== false,
|
|
5891
|
+
enableDynamicAgentCreation: updatedConfig.preferences.enableDynamicAgentCreation === true,
|
|
5892
|
+
additionalDirectories: state.additionalDirectories,
|
|
5893
|
+
featureModulePrompts: newFeaturePrompts || void 0
|
|
5894
|
+
});
|
|
5895
|
+
const moduleNames = newFeatureRegistry.getModuleNames();
|
|
5896
|
+
if (moduleNames.length > 0) {
|
|
5897
|
+
console.error(`
|
|
5898
|
+
\x1B[36m\u{1F3F0} Feature modules hot-reloaded: ${moduleNames.join(", ")}\x1B[0m`);
|
|
5899
|
+
} else {
|
|
5900
|
+
console.error(`
|
|
5901
|
+
\x1B[36m\u{1F3F0} Feature modules disabled\x1B[0m`);
|
|
5902
|
+
}
|
|
5903
|
+
}
|
|
5206
5904
|
setState((prev) => {
|
|
5905
|
+
const updates = { config: updatedConfig };
|
|
5906
|
+
if (featuresChanged) {
|
|
5907
|
+
updates.featureRegistry = newFeatureRegistry;
|
|
5908
|
+
}
|
|
5207
5909
|
if (modelChanged && prev.session) {
|
|
5208
5910
|
const updatedSession = {
|
|
5209
5911
|
...prev.session,
|
|
@@ -5214,9 +5916,9 @@ Allowed domains (${domains.length}):`);
|
|
|
5214
5916
|
if (prev.agent) {
|
|
5215
5917
|
prev.agent.context.model = updatedConfig.defaultModel;
|
|
5216
5918
|
}
|
|
5217
|
-
return { ...prev,
|
|
5919
|
+
return { ...prev, ...updates, session: updatedSession };
|
|
5218
5920
|
}
|
|
5219
|
-
return { ...prev,
|
|
5921
|
+
return { ...prev, ...updates };
|
|
5220
5922
|
});
|
|
5221
5923
|
if (modelChanged && state.agent) {
|
|
5222
5924
|
const backend = state.agent.context.llm;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.56-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"diff": "^8.0.2",
|
|
71
71
|
"dotenv": "^17.0.0",
|
|
72
72
|
"eventsource-parser": "^3.0.6",
|
|
73
|
+
"exceljs": "^4.4.0",
|
|
73
74
|
"fdir": "^6.5.0",
|
|
74
75
|
"file-type": "^18.7.0",
|
|
75
76
|
"fuse.js": "^7.1.0",
|
|
@@ -114,11 +115,11 @@
|
|
|
114
115
|
"zustand": "^4.5.4"
|
|
115
116
|
},
|
|
116
117
|
"devDependencies": {
|
|
117
|
-
"@bike4mind/agents": "0.2.
|
|
118
|
-
"@bike4mind/common": "2.70.
|
|
119
|
-
"@bike4mind/mcp": "1.33.
|
|
120
|
-
"@bike4mind/services": "2.64.
|
|
121
|
-
"@bike4mind/utils": "2.15.
|
|
118
|
+
"@bike4mind/agents": "0.2.2-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
119
|
+
"@bike4mind/common": "2.70.2-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
120
|
+
"@bike4mind/mcp": "1.33.16-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
121
|
+
"@bike4mind/services": "2.64.4-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
122
|
+
"@bike4mind/utils": "2.15.10-feat-cli-tavern-integration.21361+2f1552bbd",
|
|
122
123
|
"@types/better-sqlite3": "^7.6.13",
|
|
123
124
|
"@types/jsonwebtoken": "^9.0.4",
|
|
124
125
|
"@types/node": "^22.9.0",
|
|
@@ -135,5 +136,5 @@
|
|
|
135
136
|
"optionalDependencies": {
|
|
136
137
|
"@vscode/ripgrep": "^1.17.1"
|
|
137
138
|
},
|
|
138
|
-
"gitHead": "
|
|
139
|
+
"gitHead": "2f1552bbd1fd89923637cbcf2a6e40b729437a2d"
|
|
139
140
|
}
|