@bike4mind/cli 0.2.29-feat-quantum-optimize-architecture.18875 → 0.2.29-feat-cli-websocket-streaming.18881
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{artifactExtractor-FZXFXCQR.js → artifactExtractor-SNWW3EVH.js} +1 -1
- package/dist/{chunk-Z7V2ITXT.js → chunk-BXCARBUQ.js} +2 -2
- package/dist/{chunk-KFGSOQ6A.js → chunk-EC2VEDD2.js} +2 -2
- package/dist/{chunk-KISWANWA.js → chunk-KPOK6V6E.js} +70 -631
- package/dist/{chunk-MHDNMNRT.js → chunk-QQL3OBKL.js} +2 -2
- package/dist/{chunk-H66G775W.js → chunk-TY6Z2UV2.js} +1 -1
- package/dist/{create-G7TEBA4G.js → create-QOJPAIOR.js} +3 -3
- package/dist/index.js +805 -1525
- package/dist/{llmMarkdownGenerator-KPG7F7QB.js → llmMarkdownGenerator-JPDNDGE4.js} +1 -1
- package/dist/{markdownGenerator-W2NSNHET.js → markdownGenerator-NHN4MNEA.js} +1 -1
- package/dist/{mementoService-MMKUXPLN.js → mementoService-EN7FZK7B.js} +3 -3
- package/dist/{src-37LZNPYL.js → src-36AL3BJR.js} +13 -11
- package/dist/{src-DHPEY75W.js → src-JZN5O6F3.js} +2 -2
- package/dist/{subtractCredits-J3ULMOTE.js → subtractCredits-FCBMFPIP.js} +3 -3
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
getEffectiveApiKey,
|
|
6
6
|
getOpenWeatherKey,
|
|
7
7
|
getSerperKey
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QQL3OBKL.js";
|
|
9
9
|
import {
|
|
10
10
|
ConfigStore,
|
|
11
11
|
logger
|
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
selectActiveBackgroundAgents,
|
|
15
15
|
useCliStore
|
|
16
16
|
} from "./chunk-TVW4ZESU.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-BXCARBUQ.js";
|
|
18
|
+
import "./chunk-EC2VEDD2.js";
|
|
19
19
|
import {
|
|
20
20
|
BFLImageService,
|
|
21
21
|
BaseStorage,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
OpenAIBackend,
|
|
28
28
|
OpenAIImageService,
|
|
29
29
|
XAIImageService
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-TY6Z2UV2.js";
|
|
31
31
|
import {
|
|
32
32
|
AiEvents,
|
|
33
33
|
ApiKeyEvents,
|
|
@@ -82,10 +82,8 @@ import {
|
|
|
82
82
|
VideoModels,
|
|
83
83
|
XAI_IMAGE_MODELS,
|
|
84
84
|
b4mLLMTools,
|
|
85
|
-
getMcpProviderMetadata
|
|
86
|
-
|
|
87
|
-
resolveNavigationIntents
|
|
88
|
-
} from "./chunk-KISWANWA.js";
|
|
85
|
+
getMcpProviderMetadata
|
|
86
|
+
} from "./chunk-KPOK6V6E.js";
|
|
89
87
|
import {
|
|
90
88
|
Logger
|
|
91
89
|
} from "./chunk-OCYRD7D6.js";
|
|
@@ -95,7 +93,7 @@ import React21, { useState as useState9, useEffect as useEffect6, useCallback as
|
|
|
95
93
|
import { render, Box as Box20, Text as Text20, useApp, useInput as useInput9 } from "ink";
|
|
96
94
|
import { execSync } from "child_process";
|
|
97
95
|
import { randomBytes as randomBytes5 } from "crypto";
|
|
98
|
-
import { v4 as
|
|
96
|
+
import { v4 as uuidv413 } from "uuid";
|
|
99
97
|
|
|
100
98
|
// src/components/App.tsx
|
|
101
99
|
import React15, { useState as useState5, useEffect as useEffect4 } from "react";
|
|
@@ -3589,6 +3587,50 @@ function isReadOnlyTool(toolName, customCategories) {
|
|
|
3589
3587
|
return getToolCategory(toolName, customCategories) !== "prompt_always";
|
|
3590
3588
|
}
|
|
3591
3589
|
|
|
3590
|
+
// src/core/skillsPrompt.ts
|
|
3591
|
+
function getSkillDisplayName(cmd) {
|
|
3592
|
+
return cmd.displayName || cmd.name;
|
|
3593
|
+
}
|
|
3594
|
+
function formatSkillEntry(cmd) {
|
|
3595
|
+
const displayName = getSkillDisplayName(cmd);
|
|
3596
|
+
const argHint = cmd.argumentHint ? ` ${cmd.argumentHint}` : "";
|
|
3597
|
+
const nameDisplay = cmd.displayName && cmd.displayName !== cmd.name ? `**${displayName}** (\`${cmd.name}\`)` : `**${cmd.name}**`;
|
|
3598
|
+
return `- ${nameDisplay}${argHint}: ${cmd.description}
|
|
3599
|
+
`;
|
|
3600
|
+
}
|
|
3601
|
+
function formatSkillGroup(heading, commands) {
|
|
3602
|
+
if (commands.length === 0) {
|
|
3603
|
+
return "";
|
|
3604
|
+
}
|
|
3605
|
+
return `
|
|
3606
|
+
### ${heading}
|
|
3607
|
+
${commands.map(formatSkillEntry).join("")}`;
|
|
3608
|
+
}
|
|
3609
|
+
function filterAIVisibleSkills(commands) {
|
|
3610
|
+
return commands.filter((cmd) => !cmd.disableModelInvocation);
|
|
3611
|
+
}
|
|
3612
|
+
function filterSkillsByAllowedList(commands, allowedSkills) {
|
|
3613
|
+
if (!allowedSkills || allowedSkills.length === 0) {
|
|
3614
|
+
return commands;
|
|
3615
|
+
}
|
|
3616
|
+
return commands.filter((cmd) => allowedSkills.includes(cmd.name));
|
|
3617
|
+
}
|
|
3618
|
+
function buildSkillsPromptSection(commands, allowedSkills) {
|
|
3619
|
+
const filteredByAllowed = filterSkillsByAllowedList(commands, allowedSkills);
|
|
3620
|
+
const visibleCommands = filterAIVisibleSkills(filteredByAllowed);
|
|
3621
|
+
if (visibleCommands.length === 0) {
|
|
3622
|
+
return "";
|
|
3623
|
+
}
|
|
3624
|
+
const projectSkills = visibleCommands.filter((c) => c.source === "project");
|
|
3625
|
+
const globalSkills = visibleCommands.filter((c) => c.source === "global");
|
|
3626
|
+
return `
|
|
3627
|
+
|
|
3628
|
+
## Available Skills
|
|
3629
|
+
|
|
3630
|
+
Use the \`skill\` tool to invoke these. Example: skill({ skill: "commit" })
|
|
3631
|
+
` + formatSkillGroup("Project Skills", projectSkills) + formatSkillGroup("Global Skills", globalSkills);
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3592
3634
|
// src/core/prompts.ts
|
|
3593
3635
|
var TOOL_GREP_SEARCH = "grep_search";
|
|
3594
3636
|
var TOOL_GLOB_FILES = "glob_files";
|
|
@@ -3599,7 +3641,38 @@ var TOOL_BASH_EXECUTE = "bash_execute";
|
|
|
3599
3641
|
var TOOL_SUBAGENT_DELEGATE = "subagent_delegate";
|
|
3600
3642
|
var TOOL_WRITE_TODOS = "write_todos";
|
|
3601
3643
|
var EXPLORE_SUBAGENT_TYPE = "explore";
|
|
3602
|
-
function buildCoreSystemPrompt(contextSection
|
|
3644
|
+
function buildCoreSystemPrompt(contextSection, config) {
|
|
3645
|
+
let projectContextSection = "";
|
|
3646
|
+
let agentDirectoryContext = "";
|
|
3647
|
+
let skillsSection = "";
|
|
3648
|
+
if (typeof contextSection === "string") {
|
|
3649
|
+
projectContextSection = contextSection;
|
|
3650
|
+
if (config) {
|
|
3651
|
+
if (config.enableSkillTool !== false && config.customCommands && config.customCommands.length > 0) {
|
|
3652
|
+
skillsSection = buildSkillsPromptSection(config.customCommands);
|
|
3653
|
+
}
|
|
3654
|
+
if (config.agentStore) {
|
|
3655
|
+
agentDirectoryContext = config.agentStore.getDirectoryContext();
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3658
|
+
} else if (contextSection && typeof contextSection === "object") {
|
|
3659
|
+
config = contextSection;
|
|
3660
|
+
if (config.contextContent) {
|
|
3661
|
+
projectContextSection = `
|
|
3662
|
+
|
|
3663
|
+
## Project Context
|
|
3664
|
+
|
|
3665
|
+
Follow these project-specific instructions:
|
|
3666
|
+
|
|
3667
|
+
${config.contextContent}`;
|
|
3668
|
+
}
|
|
3669
|
+
if (config.enableSkillTool !== false && config.customCommands && config.customCommands.length > 0) {
|
|
3670
|
+
skillsSection = buildSkillsPromptSection(config.customCommands);
|
|
3671
|
+
}
|
|
3672
|
+
if (config.agentStore) {
|
|
3673
|
+
agentDirectoryContext = config.agentStore.getDirectoryContext();
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3603
3676
|
return `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
|
|
3604
3677
|
|
|
3605
3678
|
CORE BEHAVIOR:
|
|
@@ -3629,12 +3702,8 @@ When requested to perform tasks like fixing bugs, adding features, refactoring,
|
|
|
3629
3702
|
|
|
3630
3703
|
SUBAGENT DELEGATION:
|
|
3631
3704
|
- You have access to specialized subagents via the ${TOOL_SUBAGENT_DELEGATE} tool
|
|
3632
|
-
-
|
|
3633
|
-
* explore: Fast read-only codebase search (e.g., "find all auth files", "locate API endpoints")
|
|
3634
|
-
* plan: Break down complex tasks into actionable steps
|
|
3635
|
-
* review: Analyze code quality and identify issues
|
|
3705
|
+
- ${agentDirectoryContext ? `${agentDirectoryContext}` : ""}
|
|
3636
3706
|
- Subagents keep the main conversation clean and run faster with optimized models
|
|
3637
|
-
- Delegate when you need to search extensively or analyze code structure
|
|
3638
3707
|
|
|
3639
3708
|
CODE SEARCH BEST PRACTICES:
|
|
3640
3709
|
When searching code, follow this hierarchy for speed and efficiency:
|
|
@@ -3691,7 +3760,7 @@ EXAMPLES:
|
|
|
3691
3760
|
- "what packages installed?" \u2192 ${TOOL_GLOB_FILES} "**/package.json" \u2192 ${TOOL_FILE_READ}
|
|
3692
3761
|
- "find all components using React hooks" \u2192 ${TOOL_SUBAGENT_DELEGATE}(task="find all components using React hooks", type="explore")
|
|
3693
3762
|
|
|
3694
|
-
Remember: Use context from previous messages to understand follow-up questions.${
|
|
3763
|
+
Remember: Use context from previous messages to understand follow-up questions.${projectContextSection}${skillsSection}`;
|
|
3695
3764
|
}
|
|
3696
3765
|
|
|
3697
3766
|
// ../../b4m-core/packages/services/dist/src/referService/generateCodes.js
|
|
@@ -8781,8 +8850,8 @@ var getHeliocentricCoords = (planet, T) => {
|
|
|
8781
8850
|
const sinNode = Math.sin(longNode);
|
|
8782
8851
|
const x = r * (cosNode * cosOmega - sinNode * sinOmega * cosI);
|
|
8783
8852
|
const y = r * (sinNode * cosOmega + cosNode * sinOmega * cosI);
|
|
8784
|
-
const
|
|
8785
|
-
return { x, y, z:
|
|
8853
|
+
const z147 = r * sinOmega * sinI;
|
|
8854
|
+
return { x, y, z: z147, r };
|
|
8786
8855
|
};
|
|
8787
8856
|
var getGeocentricEcliptic = (planet, earth) => {
|
|
8788
8857
|
const dx = planet.x - earth.x;
|
|
@@ -9666,13 +9735,13 @@ function formatSearchResults(files) {
|
|
|
9666
9735
|
const notes = file.notes ? `
|
|
9667
9736
|
Notes: ${file.notes}` : "";
|
|
9668
9737
|
const fileType = file.type || "FILE";
|
|
9669
|
-
return `${index + 1}. **${file.fileName}**
|
|
9738
|
+
return `${index + 1}. **${file.fileName}**
|
|
9670
9739
|
Type: ${fileType} | MIME: ${file.mimeType}
|
|
9671
9740
|
Tags: ${tags}${notes}`;
|
|
9672
9741
|
});
|
|
9673
9742
|
return `Found ${files.length} document(s) in your knowledge base:
|
|
9674
9743
|
|
|
9675
|
-
` + formattedFiles.join("\n\n") + "\n\n*
|
|
9744
|
+
` + formattedFiles.join("\n\n") + "\n\n*To use these documents in your conversation, you can ask me to reference specific files by name.*";
|
|
9676
9745
|
}
|
|
9677
9746
|
var knowledgeBaseSearchTool = {
|
|
9678
9747
|
name: "search_knowledge_base",
|
|
@@ -9699,8 +9768,6 @@ var knowledgeBaseSearchTool = {
|
|
|
9699
9768
|
by: "fileName",
|
|
9700
9769
|
direction: "asc"
|
|
9701
9770
|
}, {
|
|
9702
|
-
textSearch: true,
|
|
9703
|
-
// Search across fileName + tags + notes for better recall
|
|
9704
9771
|
includeShared: true,
|
|
9705
9772
|
// Include owned + explicitly shared + org-shared files
|
|
9706
9773
|
userGroups: context.user.groups || []
|
|
@@ -9715,18 +9782,18 @@ var knowledgeBaseSearchTool = {
|
|
|
9715
9782
|
},
|
|
9716
9783
|
toolSchema: {
|
|
9717
9784
|
name: "search_knowledge_base",
|
|
9718
|
-
description: "Search the user's uploaded knowledge base (fab files).
|
|
9785
|
+
description: "Search the user's uploaded knowledge base (fab files). Returns relevant documents from the user's own files, organization-shared files, and files explicitly shared with them. Use this tool when the user asks about their own documents, uploaded files, or organization knowledge.",
|
|
9719
9786
|
parameters: {
|
|
9720
9787
|
type: "object",
|
|
9721
9788
|
properties: {
|
|
9722
9789
|
query: {
|
|
9723
9790
|
type: "string",
|
|
9724
|
-
description: "The search query to find relevant documents
|
|
9791
|
+
description: "The search query to find relevant documents by filename or content"
|
|
9725
9792
|
},
|
|
9726
9793
|
tags: {
|
|
9727
9794
|
type: "array",
|
|
9728
9795
|
items: { type: "string" },
|
|
9729
|
-
description:
|
|
9796
|
+
description: "Optional: filter results to only include files with these tags"
|
|
9730
9797
|
},
|
|
9731
9798
|
file_type: {
|
|
9732
9799
|
type: "string",
|
|
@@ -9746,1297 +9813,68 @@ var knowledgeBaseSearchTool = {
|
|
|
9746
9813
|
})
|
|
9747
9814
|
};
|
|
9748
9815
|
|
|
9749
|
-
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/
|
|
9750
|
-
|
|
9751
|
-
|
|
9752
|
-
var
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
9759
|
-
|
|
9760
|
-
|
|
9761
|
-
return "Error: You must provide at least one of file_id, tags, or query.";
|
|
9762
|
-
}
|
|
9763
|
-
if (!context.db.fabfiles) {
|
|
9764
|
-
context.logger.error("\u274C Knowledge Retrieve: fabfiles repository not available");
|
|
9765
|
-
return "Knowledge base retrieval is not available at this time.";
|
|
9766
|
-
}
|
|
9767
|
-
if (!context.db.fabfilechunks) {
|
|
9768
|
-
context.logger.error("\u274C Knowledge Retrieve: fabfilechunks repository not available");
|
|
9769
|
-
return "Knowledge base retrieval is not available at this time (chunk reader unavailable).";
|
|
9770
|
-
}
|
|
9771
|
-
try {
|
|
9772
|
-
let files = [];
|
|
9773
|
-
if (file_id) {
|
|
9774
|
-
const file = await context.db.fabfiles.findByIdAndUserId(file_id, context.userId);
|
|
9775
|
-
if (file) {
|
|
9776
|
-
files = [file];
|
|
9777
|
-
} else {
|
|
9778
|
-
const searchResults = await context.db.fabfiles.search(context.userId, file_id, { tags: [], shared: false }, { page: 1, limit: 1 }, { by: "fileName", direction: "asc" }, { textSearch: true, includeShared: true, userGroups: context.user.groups || [] });
|
|
9779
|
-
files = searchResults.data;
|
|
9780
|
-
}
|
|
9781
|
-
if (files.length === 0) {
|
|
9782
|
-
return `No document found with ID "${file_id}". The file may not exist or you may not have access to it. Try using search_knowledge_base to find the correct file ID.`;
|
|
9783
|
-
}
|
|
9784
|
-
}
|
|
9785
|
-
if (files.length === 0 && (tags?.length || query)) {
|
|
9786
|
-
const searchResults = await context.db.fabfiles.search(context.userId, query || "", { tags: tags || [], shared: false }, { page: 1, limit: 5 }, { by: "fileName", direction: "asc" }, { textSearch: true, includeShared: true, userGroups: context.user.groups || [] });
|
|
9787
|
-
files = searchResults.data;
|
|
9788
|
-
if (files.length === 0) {
|
|
9789
|
-
const searchDesc = [
|
|
9790
|
-
query && `query "${query}"`,
|
|
9791
|
-
tags?.length && `tags [${tags.join(", ")}]`
|
|
9792
|
-
].filter(Boolean).join(" and ");
|
|
9793
|
-
return `No documents found matching ${searchDesc}. Try broadening your search with search_knowledge_base.`;
|
|
9794
|
-
}
|
|
9795
|
-
}
|
|
9796
|
-
let totalCharsUsed = 0;
|
|
9797
|
-
const sections = [];
|
|
9798
|
-
let filesRetrieved = 0;
|
|
9799
|
-
for (const file of files) {
|
|
9800
|
-
if (totalCharsUsed >= charBudget)
|
|
9801
|
-
break;
|
|
9802
|
-
const chunks = await context.db.fabfilechunks.findByFabFileId(file.id);
|
|
9803
|
-
if (chunks.length === 0) {
|
|
9804
|
-
context.logger.log(`\u{1F4D6} Knowledge Retrieve: No chunks for file ${file.fileName} (${file.id})`);
|
|
9805
|
-
continue;
|
|
9806
|
-
}
|
|
9807
|
-
const fullText = chunks.map((c) => c.text).join("\n");
|
|
9808
|
-
const remainingBudget = charBudget - totalCharsUsed;
|
|
9809
|
-
const truncated = fullText.length > remainingBudget;
|
|
9810
|
-
const content = truncated ? fullText.slice(0, remainingBudget) : fullText;
|
|
9811
|
-
const fileTags = file.tags?.map((t) => t.name).join(", ") || "none";
|
|
9812
|
-
const charLabel = truncated ? `${content.length} (truncated from ${fullText.length})` : `${content.length}`;
|
|
9813
|
-
sections.push(`### ${file.fileName} (ID: ${file.id})
|
|
9814
|
-
Tags: ${fileTags}
|
|
9815
|
-
Chunks: ${chunks.length} | Characters: ${charLabel}
|
|
9816
|
-
---
|
|
9817
|
-
` + content);
|
|
9818
|
-
totalCharsUsed += content.length;
|
|
9819
|
-
filesRetrieved++;
|
|
9820
|
-
}
|
|
9821
|
-
if (filesRetrieved === 0) {
|
|
9822
|
-
return "Found matching documents but they have no indexed content. The files may not have been processed yet.";
|
|
9823
|
-
}
|
|
9824
|
-
const header = `Retrieved content from ${filesRetrieved} of ${files.length} document(s):
|
|
9825
|
-
`;
|
|
9826
|
-
return header + "\n" + sections.join("\n\n---\n\n");
|
|
9827
|
-
} catch (error) {
|
|
9828
|
-
context.logger.error("\u274C Knowledge Retrieve: Error during retrieval:", error);
|
|
9829
|
-
return "An error occurred while retrieving document content. Please try again.";
|
|
9830
|
-
}
|
|
9831
|
-
},
|
|
9832
|
-
toolSchema: {
|
|
9833
|
-
name: "retrieve_knowledge_content",
|
|
9834
|
-
description: "Read the actual text content of knowledge base documents. Use this after search_knowledge_base to read documents by file ID, or provide tags/query to find and read documents in one step. Returns the full text content (up to the character budget) for grounding your responses in the user's curated knowledge.",
|
|
9835
|
-
parameters: {
|
|
9836
|
-
type: "object",
|
|
9837
|
-
properties: {
|
|
9838
|
-
file_id: {
|
|
9839
|
-
type: "string",
|
|
9840
|
-
description: "The file ID to retrieve (from search_knowledge_base results). Most efficient for single-document retrieval."
|
|
9841
|
-
},
|
|
9842
|
-
tags: {
|
|
9843
|
-
type: "array",
|
|
9844
|
-
items: { type: "string" },
|
|
9845
|
-
description: 'Filter documents by tags. For optimization docs, use tags like "opti:family:scheduling", "opti:solver:highs", etc.'
|
|
9846
|
-
},
|
|
9847
|
-
query: {
|
|
9848
|
-
type: "string",
|
|
9849
|
-
description: "Search query to find documents. Can be combined with tags for more targeted retrieval."
|
|
9850
|
-
},
|
|
9851
|
-
max_chars: {
|
|
9852
|
-
type: "number",
|
|
9853
|
-
description: "Maximum characters of content to return (default: 8000, max: 16000). Lower values for quick lookups, higher for detailed reading.",
|
|
9854
|
-
minimum: 500,
|
|
9855
|
-
maximum: 16e3
|
|
9856
|
-
}
|
|
9857
|
-
}
|
|
9858
|
-
}
|
|
9859
|
-
}
|
|
9860
|
-
})
|
|
9861
|
-
};
|
|
9862
|
-
|
|
9863
|
-
// ../../b4m-core/packages/quantum/dist/src/types.js
|
|
9864
|
-
import { z as z139 } from "zod";
|
|
9865
|
-
var OperationSchema = z139.object({
|
|
9866
|
-
jobId: z139.number(),
|
|
9867
|
-
machineId: z139.number(),
|
|
9868
|
-
duration: z139.number().positive()
|
|
9869
|
-
});
|
|
9870
|
-
var JobSchema = z139.object({
|
|
9871
|
-
id: z139.number(),
|
|
9872
|
-
name: z139.string(),
|
|
9873
|
-
operations: z139.array(OperationSchema)
|
|
9874
|
-
});
|
|
9875
|
-
var MachineSchema = z139.object({
|
|
9876
|
-
id: z139.number(),
|
|
9877
|
-
name: z139.string()
|
|
9878
|
-
});
|
|
9879
|
-
var SchedulingProblemSchema = z139.object({
|
|
9880
|
-
name: z139.string(),
|
|
9881
|
-
description: z139.string().optional(),
|
|
9882
|
-
jobs: z139.array(JobSchema),
|
|
9883
|
-
machines: z139.array(MachineSchema)
|
|
9884
|
-
});
|
|
9885
|
-
var SolverIdSchema = z139.enum([
|
|
9886
|
-
"greedy",
|
|
9887
|
-
"naive",
|
|
9888
|
-
"random-restart",
|
|
9889
|
-
"simulated-annealing",
|
|
9890
|
-
"simulated-annealing-medium",
|
|
9891
|
-
"simulated-annealing-large",
|
|
9892
|
-
"tabu",
|
|
9893
|
-
"genetic-algorithm",
|
|
9894
|
-
"ant-colony",
|
|
9895
|
-
"highs"
|
|
9896
|
-
]);
|
|
9897
|
-
|
|
9898
|
-
// ../../b4m-core/packages/quantum/dist/src/solvers/greedy-solver.js
|
|
9899
|
-
var greedySolver = {
|
|
9900
|
-
id: "greedy",
|
|
9901
|
-
name: "Greedy (Earliest Start)",
|
|
9902
|
-
description: "Schedules each operation at the earliest available time on its machine, respecting job ordering.",
|
|
9903
|
-
async solve(problem, options) {
|
|
9904
|
-
const startTime = performance.now();
|
|
9905
|
-
const machineAvailableAt = /* @__PURE__ */ new Map();
|
|
9906
|
-
for (const machine of problem.machines) {
|
|
9907
|
-
machineAvailableAt.set(machine.id, 0);
|
|
9908
|
-
}
|
|
9909
|
-
const jobCompletedAt = /* @__PURE__ */ new Map();
|
|
9910
|
-
for (const job of problem.jobs) {
|
|
9911
|
-
jobCompletedAt.set(job.id, 0);
|
|
9912
|
-
}
|
|
9913
|
-
const schedule = [];
|
|
9914
|
-
const totalOps = problem.jobs.reduce((sum2, job) => sum2 + job.operations.length, 0);
|
|
9915
|
-
let opsScheduled = 0;
|
|
9916
|
-
for (const job of problem.jobs) {
|
|
9917
|
-
for (let opIndex = 0; opIndex < job.operations.length; opIndex++) {
|
|
9918
|
-
const op = job.operations[opIndex];
|
|
9919
|
-
const machineReady = machineAvailableAt.get(op.machineId) ?? 0;
|
|
9920
|
-
const jobReady = jobCompletedAt.get(job.id) ?? 0;
|
|
9921
|
-
const opStart = Math.max(machineReady, jobReady);
|
|
9922
|
-
const opEnd = opStart + op.duration;
|
|
9923
|
-
schedule.push({
|
|
9924
|
-
jobId: job.id,
|
|
9925
|
-
machineId: op.machineId,
|
|
9926
|
-
operationIndex: opIndex,
|
|
9927
|
-
startTime: opStart,
|
|
9928
|
-
endTime: opEnd
|
|
9929
|
-
});
|
|
9930
|
-
machineAvailableAt.set(op.machineId, opEnd);
|
|
9931
|
-
jobCompletedAt.set(job.id, opEnd);
|
|
9932
|
-
opsScheduled++;
|
|
9933
|
-
if (options?.onProgress) {
|
|
9934
|
-
options.onProgress({
|
|
9935
|
-
solverId: "greedy",
|
|
9936
|
-
percentage: Math.round(opsScheduled / totalOps * 100),
|
|
9937
|
-
bestMakespan: opEnd,
|
|
9938
|
-
currentIteration: opsScheduled,
|
|
9939
|
-
totalIterations: totalOps
|
|
9940
|
-
});
|
|
9941
|
-
}
|
|
9942
|
-
}
|
|
9943
|
-
}
|
|
9944
|
-
const makespan = Math.max(...schedule.map((op) => op.endTime));
|
|
9945
|
-
const elapsedMs = performance.now() - startTime;
|
|
9946
|
-
return {
|
|
9947
|
-
solverId: "greedy",
|
|
9948
|
-
solverName: "Greedy (Earliest Start)",
|
|
9949
|
-
makespan,
|
|
9950
|
-
schedule,
|
|
9951
|
-
elapsedMs,
|
|
9952
|
-
iterations: totalOps
|
|
9953
|
-
};
|
|
9954
|
-
}
|
|
9955
|
-
};
|
|
9956
|
-
|
|
9957
|
-
// ../../b4m-core/packages/quantum/dist/src/solvers/schedule-utils.js
|
|
9958
|
-
function buildOperationList(problem) {
|
|
9959
|
-
const ops = [];
|
|
9960
|
-
for (const job of problem.jobs) {
|
|
9961
|
-
for (let i = 0; i < job.operations.length; i++) {
|
|
9962
|
-
ops.push({ jobId: job.id, opIndex: i });
|
|
9963
|
-
}
|
|
9964
|
-
}
|
|
9965
|
-
return ops;
|
|
9966
|
-
}
|
|
9967
|
-
function decodePermutation(permutation, problem) {
|
|
9968
|
-
const schedule = [];
|
|
9969
|
-
const machineAvailableAt = /* @__PURE__ */ new Map();
|
|
9970
|
-
const jobCompletedAt = /* @__PURE__ */ new Map();
|
|
9971
|
-
const jobNextOp = /* @__PURE__ */ new Map();
|
|
9972
|
-
for (const machine of problem.machines) {
|
|
9973
|
-
machineAvailableAt.set(machine.id, 0);
|
|
9974
|
-
}
|
|
9975
|
-
for (const job of problem.jobs) {
|
|
9976
|
-
jobCompletedAt.set(job.id, 0);
|
|
9977
|
-
jobNextOp.set(job.id, 0);
|
|
9978
|
-
}
|
|
9979
|
-
const remaining = [...permutation];
|
|
9980
|
-
const maxPasses = remaining.length * remaining.length;
|
|
9981
|
-
let passes = 0;
|
|
9982
|
-
while (remaining.length > 0 && passes < maxPasses) {
|
|
9983
|
-
let scheduled = false;
|
|
9984
|
-
for (let i = 0; i < remaining.length; i++) {
|
|
9985
|
-
const ref = remaining[i];
|
|
9986
|
-
const nextOp = jobNextOp.get(ref.jobId) ?? 0;
|
|
9987
|
-
if (ref.opIndex !== nextOp)
|
|
9988
|
-
continue;
|
|
9989
|
-
const job = problem.jobs.find((j) => j.id === ref.jobId);
|
|
9990
|
-
const op = job.operations[ref.opIndex];
|
|
9991
|
-
const machineReady = machineAvailableAt.get(op.machineId) ?? 0;
|
|
9992
|
-
const jobReady = jobCompletedAt.get(ref.jobId) ?? 0;
|
|
9993
|
-
const start = Math.max(machineReady, jobReady);
|
|
9994
|
-
const end = start + op.duration;
|
|
9995
|
-
schedule.push({
|
|
9996
|
-
jobId: ref.jobId,
|
|
9997
|
-
machineId: op.machineId,
|
|
9998
|
-
operationIndex: ref.opIndex,
|
|
9999
|
-
startTime: start,
|
|
10000
|
-
endTime: end
|
|
10001
|
-
});
|
|
10002
|
-
machineAvailableAt.set(op.machineId, end);
|
|
10003
|
-
jobCompletedAt.set(ref.jobId, end);
|
|
10004
|
-
jobNextOp.set(ref.jobId, nextOp + 1);
|
|
10005
|
-
remaining.splice(i, 1);
|
|
10006
|
-
scheduled = true;
|
|
10007
|
-
break;
|
|
10008
|
-
}
|
|
10009
|
-
if (!scheduled) {
|
|
10010
|
-
remaining.push(remaining.shift());
|
|
10011
|
-
}
|
|
10012
|
-
passes++;
|
|
10013
|
-
}
|
|
10014
|
-
return schedule;
|
|
10015
|
-
}
|
|
10016
|
-
function computeMakespan(schedule) {
|
|
10017
|
-
if (schedule.length === 0)
|
|
10018
|
-
return 0;
|
|
10019
|
-
return Math.max(...schedule.map((op) => op.endTime));
|
|
10020
|
-
}
|
|
10021
|
-
function randomPermutation(problem, rng = Math.random) {
|
|
10022
|
-
const ops = buildOperationList(problem);
|
|
10023
|
-
for (let i = ops.length - 1; i > 0; i--) {
|
|
10024
|
-
const j = Math.floor(rng() * (i + 1));
|
|
10025
|
-
[ops[i], ops[j]] = [ops[j], ops[i]];
|
|
10026
|
-
}
|
|
10027
|
-
return ops;
|
|
10028
|
-
}
|
|
10029
|
-
function swapNeighbor(perm, rng = Math.random) {
|
|
10030
|
-
const newPerm = [...perm];
|
|
10031
|
-
const i = Math.floor(rng() * newPerm.length);
|
|
10032
|
-
let j = Math.floor(rng() * (newPerm.length - 1));
|
|
10033
|
-
if (j >= i)
|
|
10034
|
-
j++;
|
|
10035
|
-
[newPerm[i], newPerm[j]] = [newPerm[j], newPerm[i]];
|
|
10036
|
-
return newPerm;
|
|
10037
|
-
}
|
|
10038
|
-
function createRng(seed) {
|
|
10039
|
-
let s = seed | 0;
|
|
10040
|
-
return () => {
|
|
10041
|
-
s = s + 1831565813 | 0;
|
|
10042
|
-
let t = Math.imul(s ^ s >>> 15, 1 | s);
|
|
10043
|
-
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
10044
|
-
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
10045
|
-
};
|
|
10046
|
-
}
|
|
10047
|
-
|
|
10048
|
-
// ../../b4m-core/packages/quantum/dist/src/solvers/naive-solver.js
|
|
10049
|
-
var MAX_PERMUTATIONS = 40320;
|
|
10050
|
-
function* permutations(arr) {
|
|
10051
|
-
if (arr.length <= 1) {
|
|
10052
|
-
yield [...arr];
|
|
10053
|
-
return;
|
|
10054
|
-
}
|
|
10055
|
-
for (let i = 0; i < arr.length; i++) {
|
|
10056
|
-
const rest = [...arr.slice(0, i), ...arr.slice(i + 1)];
|
|
10057
|
-
for (const perm of permutations(rest)) {
|
|
10058
|
-
yield [arr[i], ...perm];
|
|
10059
|
-
}
|
|
10060
|
-
}
|
|
10061
|
-
}
|
|
10062
|
-
var naiveSolver = {
|
|
10063
|
-
id: "naive",
|
|
10064
|
-
name: "Naive (Brute Force)",
|
|
10065
|
-
description: "Evaluates all permutations to find the optimal schedule. Only feasible for small problems.",
|
|
10066
|
-
async solve(problem, options) {
|
|
10067
|
-
const startTime = performance.now();
|
|
10068
|
-
const ops = buildOperationList(problem);
|
|
10069
|
-
const totalPerms = factorial(ops.length);
|
|
10070
|
-
const cappedTotal = Math.min(totalPerms, MAX_PERMUTATIONS);
|
|
10071
|
-
let bestMakespan = Infinity;
|
|
10072
|
-
let bestSchedule = decodePermutation(ops, problem);
|
|
10073
|
-
let count = 0;
|
|
10074
|
-
for (const perm of permutations(ops)) {
|
|
10075
|
-
if (count >= MAX_PERMUTATIONS)
|
|
10076
|
-
break;
|
|
10077
|
-
const schedule = decodePermutation(perm, problem);
|
|
10078
|
-
const makespan = computeMakespan(schedule);
|
|
10079
|
-
if (makespan < bestMakespan) {
|
|
10080
|
-
bestMakespan = makespan;
|
|
10081
|
-
bestSchedule = schedule;
|
|
10082
|
-
}
|
|
10083
|
-
count++;
|
|
10084
|
-
if (options?.onProgress && count % 100 === 0) {
|
|
10085
|
-
options.onProgress({
|
|
10086
|
-
solverId: "naive",
|
|
10087
|
-
percentage: Math.min(99, Math.round(count / cappedTotal * 100)),
|
|
10088
|
-
bestMakespan,
|
|
10089
|
-
currentIteration: count,
|
|
10090
|
-
totalIterations: cappedTotal
|
|
10091
|
-
});
|
|
10092
|
-
}
|
|
10093
|
-
}
|
|
10094
|
-
options?.onProgress?.({
|
|
10095
|
-
solverId: "naive",
|
|
10096
|
-
percentage: 100,
|
|
10097
|
-
bestMakespan,
|
|
10098
|
-
currentIteration: count,
|
|
10099
|
-
totalIterations: cappedTotal
|
|
10100
|
-
});
|
|
10101
|
-
return {
|
|
10102
|
-
solverId: "naive",
|
|
10103
|
-
solverName: "Naive (Brute Force)",
|
|
10104
|
-
makespan: bestMakespan,
|
|
10105
|
-
schedule: bestSchedule,
|
|
10106
|
-
elapsedMs: performance.now() - startTime,
|
|
10107
|
-
iterations: count
|
|
10108
|
-
};
|
|
10109
|
-
}
|
|
10110
|
-
};
|
|
10111
|
-
function factorial(n) {
|
|
10112
|
-
if (n <= 1)
|
|
10113
|
-
return 1;
|
|
10114
|
-
let result = 1;
|
|
10115
|
-
for (let i = 2; i <= n; i++)
|
|
10116
|
-
result *= i;
|
|
10117
|
-
return result;
|
|
10118
|
-
}
|
|
10119
|
-
|
|
10120
|
-
// ../../b4m-core/packages/quantum/dist/src/solvers/random-restart-solver.js
|
|
10121
|
-
var RESTARTS = 50;
|
|
10122
|
-
var HILL_CLIMB_ITERATIONS = 500;
|
|
10123
|
-
var randomRestartSolver = {
|
|
10124
|
-
id: "random-restart",
|
|
10125
|
-
name: "Random Restart Hill Climbing",
|
|
10126
|
-
description: "Multiple random starts with local search improvement via operation swaps.",
|
|
10127
|
-
async solve(problem, options) {
|
|
10128
|
-
const startTime = performance.now();
|
|
10129
|
-
const timeoutMs = options?.timeoutMs ?? 1e4;
|
|
10130
|
-
const rng = createRng(42);
|
|
10131
|
-
let globalBestMakespan = Infinity;
|
|
10132
|
-
let globalBestSchedule = decodePermutation(randomPermutation(problem, rng), problem);
|
|
10133
|
-
let totalIterations = 0;
|
|
10134
|
-
for (let restart = 0; restart < RESTARTS; restart++) {
|
|
10135
|
-
if (performance.now() - startTime > timeoutMs)
|
|
10136
|
-
break;
|
|
10137
|
-
let currentPerm = randomPermutation(problem, rng);
|
|
10138
|
-
let currentSchedule = decodePermutation(currentPerm, problem);
|
|
10139
|
-
let currentMakespan = computeMakespan(currentSchedule);
|
|
10140
|
-
for (let i = 0; i < HILL_CLIMB_ITERATIONS; i++) {
|
|
10141
|
-
if (performance.now() - startTime > timeoutMs)
|
|
10142
|
-
break;
|
|
10143
|
-
const neighborPerm = swapNeighbor(currentPerm, rng);
|
|
10144
|
-
const neighborSchedule = decodePermutation(neighborPerm, problem);
|
|
10145
|
-
const neighborMakespan = computeMakespan(neighborSchedule);
|
|
10146
|
-
if (neighborMakespan < currentMakespan) {
|
|
10147
|
-
currentPerm = neighborPerm;
|
|
10148
|
-
currentSchedule = neighborSchedule;
|
|
10149
|
-
currentMakespan = neighborMakespan;
|
|
10150
|
-
}
|
|
10151
|
-
totalIterations++;
|
|
10152
|
-
}
|
|
10153
|
-
if (currentMakespan < globalBestMakespan) {
|
|
10154
|
-
globalBestMakespan = currentMakespan;
|
|
10155
|
-
globalBestSchedule = currentSchedule;
|
|
10156
|
-
}
|
|
10157
|
-
options?.onProgress?.({
|
|
10158
|
-
solverId: "random-restart",
|
|
10159
|
-
percentage: Math.round((restart + 1) / RESTARTS * 100),
|
|
10160
|
-
bestMakespan: globalBestMakespan,
|
|
10161
|
-
currentIteration: restart + 1,
|
|
10162
|
-
totalIterations: RESTARTS
|
|
10163
|
-
});
|
|
10164
|
-
}
|
|
10165
|
-
return {
|
|
10166
|
-
solverId: "random-restart",
|
|
10167
|
-
solverName: "Random Restart Hill Climbing",
|
|
10168
|
-
makespan: globalBestMakespan,
|
|
10169
|
-
schedule: globalBestSchedule,
|
|
10170
|
-
elapsedMs: performance.now() - startTime,
|
|
10171
|
-
iterations: totalIterations
|
|
10172
|
-
};
|
|
10173
|
-
}
|
|
10174
|
-
};
|
|
10175
|
-
|
|
10176
|
-
// ../../b4m-core/packages/quantum/dist/src/solvers/simulated-annealing-solver.js
|
|
10177
|
-
var SA_CONFIGS = [
|
|
9816
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/bashExecute/index.js
|
|
9817
|
+
import { spawn } from "child_process";
|
|
9818
|
+
import path11 from "path";
|
|
9819
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
9820
|
+
var MAX_OUTPUT_SIZE = 100 * 1024;
|
|
9821
|
+
var DANGEROUS_PATTERNS = [
|
|
9822
|
+
// Destructive file operations
|
|
9823
|
+
{
|
|
9824
|
+
pattern: /\brm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*r).*\//i,
|
|
9825
|
+
reason: "Recursive delete with path",
|
|
9826
|
+
block: true
|
|
9827
|
+
},
|
|
10178
9828
|
{
|
|
10179
|
-
|
|
10180
|
-
|
|
10181
|
-
|
|
10182
|
-
initialTemp: 100,
|
|
10183
|
-
coolingRate: 0.995,
|
|
10184
|
-
iterations: 5e3
|
|
9829
|
+
pattern: /\brm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*f).*--no-preserve-root/i,
|
|
9830
|
+
reason: "Force delete without preserve root",
|
|
9831
|
+
block: true
|
|
10185
9832
|
},
|
|
10186
9833
|
{
|
|
10187
|
-
|
|
10188
|
-
|
|
10189
|
-
|
|
10190
|
-
initialTemp: 200,
|
|
10191
|
-
coolingRate: 0.9985,
|
|
10192
|
-
iterations: 25e3
|
|
9834
|
+
pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\//i,
|
|
9835
|
+
reason: "Recursive force delete on root paths",
|
|
9836
|
+
block: true
|
|
10193
9837
|
},
|
|
10194
9838
|
{
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
}
|
|
10202
|
-
|
|
10203
|
-
|
|
10204
|
-
|
|
10205
|
-
|
|
10206
|
-
|
|
10207
|
-
|
|
10208
|
-
|
|
10209
|
-
|
|
10210
|
-
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
bestMakespan = currentMakespan;
|
|
10235
|
-
}
|
|
10236
|
-
}
|
|
10237
|
-
temperature *= config.coolingRate;
|
|
10238
|
-
if (options?.onProgress && i % progressInterval === 0) {
|
|
10239
|
-
options.onProgress({
|
|
10240
|
-
solverId: config.id,
|
|
10241
|
-
percentage: Math.round(i / config.iterations * 100),
|
|
10242
|
-
bestMakespan,
|
|
10243
|
-
currentIteration: i,
|
|
10244
|
-
totalIterations: config.iterations
|
|
10245
|
-
});
|
|
10246
|
-
}
|
|
10247
|
-
}
|
|
10248
|
-
options?.onProgress?.({
|
|
10249
|
-
solverId: config.id,
|
|
10250
|
-
percentage: 100,
|
|
10251
|
-
bestMakespan,
|
|
10252
|
-
currentIteration: config.iterations,
|
|
10253
|
-
totalIterations: config.iterations
|
|
10254
|
-
});
|
|
10255
|
-
return {
|
|
10256
|
-
solverId: config.id,
|
|
10257
|
-
solverName: config.name,
|
|
10258
|
-
makespan: bestMakespan,
|
|
10259
|
-
schedule: bestSchedule,
|
|
10260
|
-
elapsedMs: performance.now() - startTime,
|
|
10261
|
-
iterations: config.iterations
|
|
10262
|
-
};
|
|
10263
|
-
}
|
|
10264
|
-
};
|
|
10265
|
-
}
|
|
10266
|
-
var simulatedAnnealingSolver = createSASolver(SA_CONFIGS[0]);
|
|
10267
|
-
var simulatedAnnealingMediumSolver = createSASolver(SA_CONFIGS[1]);
|
|
10268
|
-
var simulatedAnnealingLargeSolver = createSASolver(SA_CONFIGS[2]);
|
|
10269
|
-
|
|
10270
|
-
// ../../b4m-core/packages/quantum/dist/src/solvers/tabu-solver.js
|
|
10271
|
-
var ITERATIONS = 1e4;
|
|
10272
|
-
var TABU_TENURE = 15;
|
|
10273
|
-
var NEIGHBORHOOD_SIZE = 20;
|
|
10274
|
-
var tabuSolver = {
|
|
10275
|
-
id: "tabu",
|
|
10276
|
-
name: "Tabu Search",
|
|
10277
|
-
description: "Hill climbing with short-term memory to avoid revisiting recent solutions.",
|
|
10278
|
-
async solve(problem, options) {
|
|
10279
|
-
const startTime = performance.now();
|
|
10280
|
-
const timeoutMs = options?.timeoutMs ?? 15e3;
|
|
10281
|
-
const rng = createRng(42);
|
|
10282
|
-
let currentPerm = randomPermutation(problem, rng);
|
|
10283
|
-
let currentSchedule = decodePermutation(currentPerm, problem);
|
|
10284
|
-
let currentMakespan = computeMakespan(currentSchedule);
|
|
10285
|
-
let bestSchedule = currentSchedule;
|
|
10286
|
-
let bestMakespan = currentMakespan;
|
|
10287
|
-
const tabuList = /* @__PURE__ */ new Map();
|
|
10288
|
-
const progressInterval = Math.max(1, Math.floor(ITERATIONS / 100));
|
|
10289
|
-
for (let iter = 0; iter < ITERATIONS; iter++) {
|
|
10290
|
-
if (performance.now() - startTime > timeoutMs)
|
|
10291
|
-
break;
|
|
10292
|
-
let bestNeighborPerm = null;
|
|
10293
|
-
let bestNeighborMakespan = Infinity;
|
|
10294
|
-
let bestSwapKey = "";
|
|
10295
|
-
for (let n = 0; n < NEIGHBORHOOD_SIZE; n++) {
|
|
10296
|
-
const i = Math.floor(rng() * currentPerm.length);
|
|
10297
|
-
let j = Math.floor(rng() * (currentPerm.length - 1));
|
|
10298
|
-
if (j >= i)
|
|
10299
|
-
j++;
|
|
10300
|
-
const swapKey = `${Math.min(i, j)},${Math.max(i, j)}`;
|
|
10301
|
-
const candidatePerm = [...currentPerm];
|
|
10302
|
-
[candidatePerm[i], candidatePerm[j]] = [candidatePerm[j], candidatePerm[i]];
|
|
10303
|
-
const candidateSchedule = decodePermutation(candidatePerm, problem);
|
|
10304
|
-
const candidateMakespan = computeMakespan(candidateSchedule);
|
|
10305
|
-
const isTabu = (tabuList.get(swapKey) ?? 0) > iter;
|
|
10306
|
-
const aspirationMet = candidateMakespan < bestMakespan;
|
|
10307
|
-
if ((!isTabu || aspirationMet) && candidateMakespan < bestNeighborMakespan) {
|
|
10308
|
-
bestNeighborPerm = candidatePerm;
|
|
10309
|
-
bestNeighborMakespan = candidateMakespan;
|
|
10310
|
-
bestSwapKey = swapKey;
|
|
10311
|
-
}
|
|
10312
|
-
}
|
|
10313
|
-
if (bestNeighborPerm) {
|
|
10314
|
-
currentPerm = bestNeighborPerm;
|
|
10315
|
-
currentSchedule = decodePermutation(currentPerm, problem);
|
|
10316
|
-
currentMakespan = bestNeighborMakespan;
|
|
10317
|
-
tabuList.set(bestSwapKey, iter + TABU_TENURE);
|
|
10318
|
-
if (currentMakespan < bestMakespan) {
|
|
10319
|
-
bestMakespan = currentMakespan;
|
|
10320
|
-
bestSchedule = currentSchedule;
|
|
10321
|
-
}
|
|
10322
|
-
}
|
|
10323
|
-
if (iter % 100 === 0) {
|
|
10324
|
-
for (const [key, expiry] of tabuList) {
|
|
10325
|
-
if (expiry <= iter)
|
|
10326
|
-
tabuList.delete(key);
|
|
10327
|
-
}
|
|
10328
|
-
}
|
|
10329
|
-
if (options?.onProgress && iter % progressInterval === 0) {
|
|
10330
|
-
options.onProgress({
|
|
10331
|
-
solverId: "tabu",
|
|
10332
|
-
percentage: Math.round(iter / ITERATIONS * 100),
|
|
10333
|
-
bestMakespan,
|
|
10334
|
-
currentIteration: iter,
|
|
10335
|
-
totalIterations: ITERATIONS
|
|
10336
|
-
});
|
|
10337
|
-
}
|
|
10338
|
-
}
|
|
10339
|
-
options?.onProgress?.({
|
|
10340
|
-
solverId: "tabu",
|
|
10341
|
-
percentage: 100,
|
|
10342
|
-
bestMakespan,
|
|
10343
|
-
currentIteration: ITERATIONS,
|
|
10344
|
-
totalIterations: ITERATIONS
|
|
10345
|
-
});
|
|
10346
|
-
return {
|
|
10347
|
-
solverId: "tabu",
|
|
10348
|
-
solverName: "Tabu Search",
|
|
10349
|
-
makespan: bestMakespan,
|
|
10350
|
-
schedule: bestSchedule,
|
|
10351
|
-
elapsedMs: performance.now() - startTime,
|
|
10352
|
-
iterations: ITERATIONS
|
|
10353
|
-
};
|
|
10354
|
-
}
|
|
10355
|
-
};
|
|
10356
|
-
|
|
10357
|
-
// ../../b4m-core/packages/quantum/dist/src/solvers/genetic-algorithm-solver.js
|
|
10358
|
-
var POPULATION_SIZE = 50;
|
|
10359
|
-
var GENERATIONS = 200;
|
|
10360
|
-
var TOURNAMENT_SIZE = 5;
|
|
10361
|
-
var MUTATION_RATE = 0.15;
|
|
10362
|
-
var geneticAlgorithmSolver = {
|
|
10363
|
-
id: "genetic-algorithm",
|
|
10364
|
-
name: "Genetic Algorithm",
|
|
10365
|
-
description: "Population-based search with tournament selection, crossover, and mutation.",
|
|
10366
|
-
async solve(problem, options) {
|
|
10367
|
-
const startTime = performance.now();
|
|
10368
|
-
const timeoutMs = options?.timeoutMs ?? 2e4;
|
|
10369
|
-
const rng = createRng(42);
|
|
10370
|
-
let population = [];
|
|
10371
|
-
for (let i = 0; i < POPULATION_SIZE; i++) {
|
|
10372
|
-
const perm = randomPermutation(problem, rng);
|
|
10373
|
-
const schedule = decodePermutation(perm, problem);
|
|
10374
|
-
const makespan = computeMakespan(schedule);
|
|
10375
|
-
population.push({ perm, makespan });
|
|
10376
|
-
}
|
|
10377
|
-
let bestIndividual = population.reduce((best, ind) => ind.makespan < best.makespan ? ind : best);
|
|
10378
|
-
for (let gen = 0; gen < GENERATIONS; gen++) {
|
|
10379
|
-
if (performance.now() - startTime > timeoutMs)
|
|
10380
|
-
break;
|
|
10381
|
-
const newPopulation = [];
|
|
10382
|
-
newPopulation.push({ ...bestIndividual });
|
|
10383
|
-
while (newPopulation.length < POPULATION_SIZE) {
|
|
10384
|
-
const parent1 = tournamentSelect(population, TOURNAMENT_SIZE, rng);
|
|
10385
|
-
const parent2 = tournamentSelect(population, TOURNAMENT_SIZE, rng);
|
|
10386
|
-
let childPerm = crossover(parent1.perm, parent2.perm, rng);
|
|
10387
|
-
if (rng() < MUTATION_RATE) {
|
|
10388
|
-
childPerm = swapNeighbor(childPerm, rng);
|
|
10389
|
-
}
|
|
10390
|
-
const childSchedule = decodePermutation(childPerm, problem);
|
|
10391
|
-
const childMakespan = computeMakespan(childSchedule);
|
|
10392
|
-
newPopulation.push({ perm: childPerm, makespan: childMakespan });
|
|
10393
|
-
}
|
|
10394
|
-
population = newPopulation;
|
|
10395
|
-
const genBest = population.reduce((best, ind) => ind.makespan < best.makespan ? ind : best);
|
|
10396
|
-
if (genBest.makespan < bestIndividual.makespan) {
|
|
10397
|
-
bestIndividual = genBest;
|
|
10398
|
-
}
|
|
10399
|
-
options?.onProgress?.({
|
|
10400
|
-
solverId: "genetic-algorithm",
|
|
10401
|
-
percentage: Math.round((gen + 1) / GENERATIONS * 100),
|
|
10402
|
-
bestMakespan: bestIndividual.makespan,
|
|
10403
|
-
currentIteration: gen + 1,
|
|
10404
|
-
totalIterations: GENERATIONS
|
|
10405
|
-
});
|
|
10406
|
-
}
|
|
10407
|
-
const bestSchedule = decodePermutation(bestIndividual.perm, problem);
|
|
10408
|
-
return {
|
|
10409
|
-
solverId: "genetic-algorithm",
|
|
10410
|
-
solverName: "Genetic Algorithm",
|
|
10411
|
-
makespan: bestIndividual.makespan,
|
|
10412
|
-
schedule: bestSchedule,
|
|
10413
|
-
elapsedMs: performance.now() - startTime,
|
|
10414
|
-
iterations: GENERATIONS * POPULATION_SIZE
|
|
10415
|
-
};
|
|
10416
|
-
}
|
|
10417
|
-
};
|
|
10418
|
-
function tournamentSelect(population, size, rng) {
|
|
10419
|
-
let best = population[Math.floor(rng() * population.length)];
|
|
10420
|
-
for (let i = 1; i < size; i++) {
|
|
10421
|
-
const candidate = population[Math.floor(rng() * population.length)];
|
|
10422
|
-
if (candidate.makespan < best.makespan) {
|
|
10423
|
-
best = candidate;
|
|
10424
|
-
}
|
|
10425
|
-
}
|
|
10426
|
-
return best;
|
|
10427
|
-
}
|
|
10428
|
-
function crossover(parent1, parent2, rng) {
|
|
10429
|
-
const len = parent1.length;
|
|
10430
|
-
const start = Math.floor(rng() * len);
|
|
10431
|
-
const end = start + Math.floor(rng() * (len - start));
|
|
10432
|
-
const child = new Array(len).fill(null);
|
|
10433
|
-
const used = /* @__PURE__ */ new Set();
|
|
10434
|
-
for (let i = start; i <= end && i < len; i++) {
|
|
10435
|
-
child[i] = parent1[i];
|
|
10436
|
-
used.add(`${parent1[i].jobId}-${parent1[i].opIndex}`);
|
|
10437
|
-
}
|
|
10438
|
-
let pos = 0;
|
|
10439
|
-
for (const op of parent2) {
|
|
10440
|
-
const key = `${op.jobId}-${op.opIndex}`;
|
|
10441
|
-
if (!used.has(key)) {
|
|
10442
|
-
while (child[pos] !== null)
|
|
10443
|
-
pos++;
|
|
10444
|
-
child[pos] = op;
|
|
10445
|
-
used.add(key);
|
|
10446
|
-
}
|
|
10447
|
-
}
|
|
10448
|
-
return child;
|
|
10449
|
-
}
|
|
10450
|
-
|
|
10451
|
-
// ../../b4m-core/packages/quantum/dist/src/solvers/ant-colony-solver.js
|
|
10452
|
-
var NUM_ANTS = 20;
|
|
10453
|
-
var ITERATIONS2 = 100;
|
|
10454
|
-
var ALPHA = 1;
|
|
10455
|
-
var BETA = 2;
|
|
10456
|
-
var EVAPORATION = 0.1;
|
|
10457
|
-
var Q = 100;
|
|
10458
|
-
var antColonySolver = {
|
|
10459
|
-
id: "ant-colony",
|
|
10460
|
-
name: "Ant Colony Optimization",
|
|
10461
|
-
description: "Swarm intelligence using pheromone trails to guide solution construction.",
|
|
10462
|
-
async solve(problem, options) {
|
|
10463
|
-
const startTime = performance.now();
|
|
10464
|
-
const timeoutMs = options?.timeoutMs ?? 2e4;
|
|
10465
|
-
const rng = createRng(42);
|
|
10466
|
-
const allOps = buildOperationList(problem);
|
|
10467
|
-
const numOps = allOps.length;
|
|
10468
|
-
const pheromone = Array.from({ length: numOps }, () => new Array(numOps).fill(1));
|
|
10469
|
-
const heuristic = allOps.map((ref) => {
|
|
10470
|
-
const job = problem.jobs.find((j) => j.id === ref.jobId);
|
|
10471
|
-
const op = job.operations[ref.opIndex];
|
|
10472
|
-
return 1 / op.duration;
|
|
10473
|
-
});
|
|
10474
|
-
let bestMakespan = Infinity;
|
|
10475
|
-
let bestSchedule = decodePermutation(allOps, problem);
|
|
10476
|
-
for (let iter = 0; iter < ITERATIONS2; iter++) {
|
|
10477
|
-
if (performance.now() - startTime > timeoutMs)
|
|
10478
|
-
break;
|
|
10479
|
-
const antSolutions = [];
|
|
10480
|
-
for (let ant = 0; ant < NUM_ANTS; ant++) {
|
|
10481
|
-
const perm = constructSolution(allOps, pheromone, heuristic, rng);
|
|
10482
|
-
const schedule = decodePermutation(perm, problem);
|
|
10483
|
-
const makespan = computeMakespan(schedule);
|
|
10484
|
-
antSolutions.push({ perm, makespan });
|
|
10485
|
-
if (makespan < bestMakespan) {
|
|
10486
|
-
bestMakespan = makespan;
|
|
10487
|
-
bestSchedule = schedule;
|
|
10488
|
-
}
|
|
10489
|
-
}
|
|
10490
|
-
for (let i = 0; i < numOps; i++) {
|
|
10491
|
-
for (let j = 0; j < numOps; j++) {
|
|
10492
|
-
pheromone[i][j] *= 1 - EVAPORATION;
|
|
10493
|
-
}
|
|
10494
|
-
}
|
|
10495
|
-
for (const solution of antSolutions) {
|
|
10496
|
-
const deposit = Q / solution.makespan;
|
|
10497
|
-
for (let pos = 0; pos < solution.perm.length; pos++) {
|
|
10498
|
-
const opIdx = allOps.findIndex((o) => o.jobId === solution.perm[pos].jobId && o.opIndex === solution.perm[pos].opIndex);
|
|
10499
|
-
if (opIdx >= 0) {
|
|
10500
|
-
pheromone[pos][opIdx] += deposit;
|
|
10501
|
-
}
|
|
10502
|
-
}
|
|
10503
|
-
}
|
|
10504
|
-
options?.onProgress?.({
|
|
10505
|
-
solverId: "ant-colony",
|
|
10506
|
-
percentage: Math.round((iter + 1) / ITERATIONS2 * 100),
|
|
10507
|
-
bestMakespan,
|
|
10508
|
-
currentIteration: iter + 1,
|
|
10509
|
-
totalIterations: ITERATIONS2
|
|
10510
|
-
});
|
|
10511
|
-
}
|
|
10512
|
-
return {
|
|
10513
|
-
solverId: "ant-colony",
|
|
10514
|
-
solverName: "Ant Colony Optimization",
|
|
10515
|
-
makespan: bestMakespan,
|
|
10516
|
-
schedule: bestSchedule,
|
|
10517
|
-
elapsedMs: performance.now() - startTime,
|
|
10518
|
-
iterations: ITERATIONS2 * NUM_ANTS
|
|
10519
|
-
};
|
|
10520
|
-
}
|
|
10521
|
-
};
|
|
10522
|
-
function constructSolution(allOps, pheromone, heuristic, rng) {
|
|
10523
|
-
const remaining = new Set(allOps.map((_, i) => i));
|
|
10524
|
-
const result = [];
|
|
10525
|
-
for (let pos = 0; pos < allOps.length; pos++) {
|
|
10526
|
-
const candidates = Array.from(remaining);
|
|
10527
|
-
const weights = candidates.map((opIdx) => {
|
|
10528
|
-
const tau = Math.pow(pheromone[pos][opIdx], ALPHA);
|
|
10529
|
-
const eta = Math.pow(heuristic[opIdx], BETA);
|
|
10530
|
-
return tau * eta;
|
|
10531
|
-
});
|
|
10532
|
-
const totalWeight = weights.reduce((sum2, w) => sum2 + w, 0);
|
|
10533
|
-
let r = rng() * totalWeight;
|
|
10534
|
-
let selectedIdx = candidates[0];
|
|
10535
|
-
for (let i = 0; i < candidates.length; i++) {
|
|
10536
|
-
r -= weights[i];
|
|
10537
|
-
if (r <= 0) {
|
|
10538
|
-
selectedIdx = candidates[i];
|
|
10539
|
-
break;
|
|
10540
|
-
}
|
|
10541
|
-
}
|
|
10542
|
-
result.push(allOps[selectedIdx]);
|
|
10543
|
-
remaining.delete(selectedIdx);
|
|
10544
|
-
}
|
|
10545
|
-
return result;
|
|
10546
|
-
}
|
|
10547
|
-
|
|
10548
|
-
// ../../b4m-core/packages/quantum/dist/src/solvers/index.js
|
|
10549
|
-
var allSolvers = [
|
|
10550
|
-
greedySolver,
|
|
10551
|
-
naiveSolver,
|
|
10552
|
-
randomRestartSolver,
|
|
10553
|
-
simulatedAnnealingSolver,
|
|
10554
|
-
simulatedAnnealingMediumSolver,
|
|
10555
|
-
simulatedAnnealingLargeSolver,
|
|
10556
|
-
tabuSolver,
|
|
10557
|
-
geneticAlgorithmSolver,
|
|
10558
|
-
antColonySolver
|
|
10559
|
-
];
|
|
10560
|
-
var solverRegistry = new Map(allSolvers.map((s) => [s.id, s]));
|
|
10561
|
-
function getSolver(id) {
|
|
10562
|
-
return solverRegistry.get(id);
|
|
10563
|
-
}
|
|
10564
|
-
function getAvailableSolverIds() {
|
|
10565
|
-
return Array.from(solverRegistry.keys());
|
|
10566
|
-
}
|
|
10567
|
-
|
|
10568
|
-
// ../../b4m-core/packages/quantum/dist/src/prompts/system-prompt.js
|
|
10569
|
-
var QUANTUM_CANVASSER_SYSTEM_PROMPT = `You are the Optimization Canvasser, an AI agent specializing in combinatorial optimization and job-shop scheduling. You help users formulate scheduling problems, run solver algorithms, and interpret optimization results. You are solver-agnostic \u2014 you route problems to the best solver whether classical (greedy, simulated annealing, genetic algorithms, HiGHS MIP) or quantum (QAOA), building credibility through honest recommendations.
|
|
10570
|
-
|
|
10571
|
-
## Your Capabilities
|
|
10572
|
-
|
|
10573
|
-
You have two specialized tools:
|
|
10574
|
-
|
|
10575
|
-
### quantum_formulate
|
|
10576
|
-
Converts natural language descriptions into structured SchedulingProblem definitions. When a user describes a scheduling scenario in plain English, use this tool to extract:
|
|
10577
|
-
- Jobs (ordered sequences of operations)
|
|
10578
|
-
- Machines (resources that process operations)
|
|
10579
|
-
- Operation durations and machine assignments
|
|
10580
|
-
- Precedence constraints (operations within a job must execute in order)
|
|
10581
|
-
|
|
10582
|
-
### quantum_schedule
|
|
10583
|
-
Runs optimization solvers on a structured SchedulingProblem. Available solvers:
|
|
10584
|
-
${allSolvers.map((s) => `- **${s.name}** (\`${s.id}\`): ${s.description}`).join("\n")}
|
|
10585
|
-
|
|
10586
|
-
## How to Help Users
|
|
10587
|
-
|
|
10588
|
-
### Problem Formulation
|
|
10589
|
-
When a user describes a scheduling scenario:
|
|
10590
|
-
1. Use \`quantum_formulate\` to convert their description into a structured problem
|
|
10591
|
-
2. Present the formulated problem clearly, showing jobs, machines, and operation sequences
|
|
10592
|
-
3. Ask if adjustments are needed before solving
|
|
10593
|
-
|
|
10594
|
-
### Running Solvers
|
|
10595
|
-
When solving a problem:
|
|
10596
|
-
1. Start with the \`greedy\` solver for a quick baseline result
|
|
10597
|
-
2. For better solutions, suggest running multiple solvers: \`greedy\`, \`simulated-annealing\`, \`tabu\`, \`genetic-algorithm\`
|
|
10598
|
-
3. Explain that metaheuristic solvers explore larger solution spaces but take longer
|
|
10599
|
-
4. Compare results across solvers when multiple are run
|
|
10600
|
-
|
|
10601
|
-
### Interpreting Results
|
|
10602
|
-
When presenting solver results:
|
|
10603
|
-
- Explain the **makespan** (total schedule length) and why lower is better
|
|
10604
|
-
- Walk through the schedule showing which jobs run on which machines at what times
|
|
10605
|
-
- Identify bottleneck machines (those with the most continuous utilization)
|
|
10606
|
-
- Suggest improvements if the problem structure allows (e.g., rebalancing operations)
|
|
10607
|
-
|
|
10608
|
-
### QUBO Encoding
|
|
10609
|
-
If asked about quantum computing aspects:
|
|
10610
|
-
- Explain how scheduling problems are encoded as QUBO (Quadratic Unconstrained Binary Optimization) matrices
|
|
10611
|
-
- Time-indexed binary variables: x_{o,t} = 1 if operation o starts at time t
|
|
10612
|
-
- Three constraint families: exactly-once (each operation starts exactly once), no-overlap (no two operations on same machine at same time), precedence (operations within a job maintain order)
|
|
10613
|
-
- QUBO matrices can be solved by quantum annealers (D-Wave) or quantum-inspired classical solvers
|
|
10614
|
-
|
|
10615
|
-
## Communication Style
|
|
10616
|
-
- Be precise with numbers and scheduling terminology
|
|
10617
|
-
- Use clear formatting: tables for schedules, bullet points for comparisons
|
|
10618
|
-
- When explaining optimization concepts, ground them in the user's specific problem
|
|
10619
|
-
- Proactively suggest next steps (e.g., "Would you like to try more solvers?" or "Should I adjust the problem?")
|
|
10620
|
-
|
|
10621
|
-
## Important Notes
|
|
10622
|
-
- All solvers run client-side in the browser via Web Workers \u2014 no server compute needed
|
|
10623
|
-
- The greedy solver is deterministic and instant; metaheuristic solvers involve randomness
|
|
10624
|
-
- For very large problems (50+ operations), recommend the greedy and simulated-annealing solvers
|
|
10625
|
-
- The HiGHS MIP solver uses WASM and provides optimal solutions for small problems but may be slow on large ones`;
|
|
10626
|
-
var PROBLEM_FORMULATION_PROMPT = `You are a job-shop scheduling problem formulator. Convert the user's natural language description into a structured SchedulingProblem JSON object.
|
|
10627
|
-
|
|
10628
|
-
RULES:
|
|
10629
|
-
1. Each job has an id (number starting from 0), a name, and an ordered array of operations
|
|
10630
|
-
2. Each machine has an id (number starting from 0) and a name
|
|
10631
|
-
3. Each operation has jobId (matching its parent job), machineId (which machine it runs on), and duration (positive integer)
|
|
10632
|
-
4. Operations within a job execute in order (first operation must finish before second starts)
|
|
10633
|
-
5. Each machine can only process one operation at a time
|
|
10634
|
-
6. Assign reasonable durations if not specified (use whole numbers)
|
|
10635
|
-
7. Create meaningful names for jobs and machines based on context
|
|
10636
|
-
|
|
10637
|
-
RESPOND WITH ONLY A JSON OBJECT matching this schema:
|
|
10638
|
-
{
|
|
10639
|
-
"name": "string - descriptive problem name",
|
|
10640
|
-
"description": "string - brief description",
|
|
10641
|
-
"jobs": [
|
|
10642
|
-
{
|
|
10643
|
-
"id": 0,
|
|
10644
|
-
"name": "Job Name",
|
|
10645
|
-
"operations": [
|
|
10646
|
-
{ "jobId": 0, "machineId": 0, "duration": 3 }
|
|
10647
|
-
]
|
|
10648
|
-
}
|
|
10649
|
-
],
|
|
10650
|
-
"machines": [
|
|
10651
|
-
{ "id": 0, "name": "Machine Name" }
|
|
10652
|
-
]
|
|
10653
|
-
}
|
|
10654
|
-
|
|
10655
|
-
No markdown, no explanation, no code blocks \u2014 just the raw JSON object.`;
|
|
10656
|
-
|
|
10657
|
-
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/quantumSchedule/index.js
|
|
10658
|
-
function formatResult(result) {
|
|
10659
|
-
const lines = [
|
|
10660
|
-
`Solver: ${result.solverName} (${result.solverId})`,
|
|
10661
|
-
`Makespan: ${result.makespan}`,
|
|
10662
|
-
`Elapsed: ${result.elapsedMs.toFixed(1)}ms`
|
|
10663
|
-
];
|
|
10664
|
-
if (result.iterations !== void 0) {
|
|
10665
|
-
lines.push(`Iterations: ${result.iterations}`);
|
|
10666
|
-
}
|
|
10667
|
-
lines.push("Schedule:");
|
|
10668
|
-
const byMachine = /* @__PURE__ */ new Map();
|
|
10669
|
-
for (const op of result.schedule) {
|
|
10670
|
-
if (!byMachine.has(op.machineId))
|
|
10671
|
-
byMachine.set(op.machineId, []);
|
|
10672
|
-
byMachine.get(op.machineId).push(op);
|
|
10673
|
-
}
|
|
10674
|
-
for (const [machineId, ops] of byMachine) {
|
|
10675
|
-
const sorted = ops.sort((a, b) => a.startTime - b.startTime);
|
|
10676
|
-
const timeline = sorted.map((op) => `Job${op.jobId}[${op.startTime}-${op.endTime}]`).join(" -> ");
|
|
10677
|
-
lines.push(` Machine ${machineId}: ${timeline}`);
|
|
10678
|
-
}
|
|
10679
|
-
return lines.join("\n");
|
|
10680
|
-
}
|
|
10681
|
-
async function runQuantumSchedule(params) {
|
|
10682
|
-
const parseResult = SchedulingProblemSchema.safeParse(params.problem);
|
|
10683
|
-
if (!parseResult.success) {
|
|
10684
|
-
return `Error: Invalid scheduling problem format.
|
|
10685
|
-
${parseResult.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n")}
|
|
10686
|
-
|
|
10687
|
-
Expected format: { name, jobs: [{ id, name, operations: [{ jobId, machineId, duration }] }], machines: [{ id, name }] }`;
|
|
10688
|
-
}
|
|
10689
|
-
const problem = parseResult.data;
|
|
10690
|
-
let solverIds;
|
|
10691
|
-
if (params.solverIds && params.solverIds.length > 0) {
|
|
10692
|
-
const invalid = params.solverIds.filter((id) => !SolverIdSchema.safeParse(id).success);
|
|
10693
|
-
if (invalid.length > 0) {
|
|
10694
|
-
return `Error: Unknown solver IDs: ${invalid.join(", ")}.
|
|
10695
|
-
Available solvers: ${getAvailableSolverIds().join(", ")}`;
|
|
10696
|
-
}
|
|
10697
|
-
solverIds = params.solverIds;
|
|
10698
|
-
} else {
|
|
10699
|
-
solverIds = ["greedy"];
|
|
10700
|
-
}
|
|
10701
|
-
const timeoutMs = params.timeoutMs ?? 1e4;
|
|
10702
|
-
const results = [];
|
|
10703
|
-
const errors = [];
|
|
10704
|
-
for (const solverId of solverIds) {
|
|
10705
|
-
const solver = getSolver(solverId);
|
|
10706
|
-
if (!solver) {
|
|
10707
|
-
errors.push(`Solver "${solverId}" not found`);
|
|
10708
|
-
continue;
|
|
10709
|
-
}
|
|
10710
|
-
try {
|
|
10711
|
-
const result = await solver.solve(problem, { timeoutMs });
|
|
10712
|
-
results.push(result);
|
|
10713
|
-
} catch (err) {
|
|
10714
|
-
errors.push(`${solver.name}: ${err instanceof Error ? err.message : String(err)}`);
|
|
10715
|
-
}
|
|
10716
|
-
}
|
|
10717
|
-
if (results.length === 0) {
|
|
10718
|
-
return `Error: No solvers completed successfully.
|
|
10719
|
-
${errors.join("\n")}`;
|
|
10720
|
-
}
|
|
10721
|
-
results.sort((a, b) => a.makespan - b.makespan);
|
|
10722
|
-
const lines = [];
|
|
10723
|
-
lines.push(`## Scheduling Results for "${problem.name}"`);
|
|
10724
|
-
lines.push(`Problem: ${problem.jobs.length} jobs, ${problem.machines.length} machines, ${problem.jobs.reduce((s, j) => s + j.operations.length, 0)} operations`);
|
|
10725
|
-
lines.push("");
|
|
10726
|
-
if (results.length > 1) {
|
|
10727
|
-
lines.push(`### Winner: ${results[0].solverName} (makespan: ${results[0].makespan})`);
|
|
10728
|
-
lines.push("");
|
|
10729
|
-
}
|
|
10730
|
-
for (const result of results) {
|
|
10731
|
-
lines.push(`### ${result.solverName}`);
|
|
10732
|
-
lines.push(formatResult(result));
|
|
10733
|
-
lines.push("");
|
|
10734
|
-
}
|
|
10735
|
-
if (errors.length > 0) {
|
|
10736
|
-
lines.push("### Errors");
|
|
10737
|
-
errors.forEach((e) => lines.push(`- ${e}`));
|
|
10738
|
-
}
|
|
10739
|
-
return lines.join("\n");
|
|
10740
|
-
}
|
|
10741
|
-
var quantumScheduleTool = {
|
|
10742
|
-
name: "quantum_schedule",
|
|
10743
|
-
implementation: () => ({
|
|
10744
|
-
toolFn: (value) => runQuantumSchedule(value),
|
|
10745
|
-
toolSchema: {
|
|
10746
|
-
name: "quantum_schedule",
|
|
10747
|
-
description: `Run quantum-inspired optimization solvers on a job-shop scheduling problem. Finds optimal or near-optimal schedules that minimize makespan (total completion time).
|
|
10748
|
-
|
|
10749
|
-
Available solvers: ${allSolvers.map((s) => `${s.id} (${s.name})`).join(", ")}.
|
|
10750
|
-
|
|
10751
|
-
The "greedy" solver runs instantly. Metaheuristic solvers (simulated-annealing, tabu, genetic-algorithm, ant-colony) explore larger solution spaces but take longer. Use multiple solvers to race them against each other.
|
|
10752
|
-
|
|
10753
|
-
The problem must define jobs (each with ordered operations) and machines. Each operation runs on a specific machine for a specific duration. Operations within a job must run in order.`,
|
|
10754
|
-
parameters: {
|
|
10755
|
-
type: "object",
|
|
10756
|
-
properties: {
|
|
10757
|
-
problem: {
|
|
10758
|
-
type: "object",
|
|
10759
|
-
description: "The scheduling problem to solve. Must include name, jobs array, and machines array.",
|
|
10760
|
-
properties: {
|
|
10761
|
-
name: { type: "string", description: "Name of the scheduling problem" },
|
|
10762
|
-
description: { type: "string", description: "Optional description" },
|
|
10763
|
-
jobs: {
|
|
10764
|
-
type: "array",
|
|
10765
|
-
description: "Array of jobs, each with id, name, and operations",
|
|
10766
|
-
items: {
|
|
10767
|
-
type: "object",
|
|
10768
|
-
properties: {
|
|
10769
|
-
id: { type: "number" },
|
|
10770
|
-
name: { type: "string" },
|
|
10771
|
-
operations: {
|
|
10772
|
-
type: "array",
|
|
10773
|
-
items: {
|
|
10774
|
-
type: "object",
|
|
10775
|
-
properties: {
|
|
10776
|
-
jobId: { type: "number", description: "Must match the parent job id" },
|
|
10777
|
-
machineId: { type: "number", description: "Which machine this operation runs on" },
|
|
10778
|
-
duration: { type: "number", description: "Processing time" }
|
|
10779
|
-
},
|
|
10780
|
-
required: ["jobId", "machineId", "duration"]
|
|
10781
|
-
}
|
|
10782
|
-
}
|
|
10783
|
-
},
|
|
10784
|
-
required: ["id", "name", "operations"]
|
|
10785
|
-
}
|
|
10786
|
-
},
|
|
10787
|
-
machines: {
|
|
10788
|
-
type: "array",
|
|
10789
|
-
description: "Array of machines with id and name",
|
|
10790
|
-
items: {
|
|
10791
|
-
type: "object",
|
|
10792
|
-
properties: {
|
|
10793
|
-
id: { type: "number" },
|
|
10794
|
-
name: { type: "string" }
|
|
10795
|
-
},
|
|
10796
|
-
required: ["id", "name"]
|
|
10797
|
-
}
|
|
10798
|
-
}
|
|
10799
|
-
},
|
|
10800
|
-
required: ["name", "jobs", "machines"]
|
|
10801
|
-
},
|
|
10802
|
-
solverIds: {
|
|
10803
|
-
type: "array",
|
|
10804
|
-
items: { type: "string" },
|
|
10805
|
-
description: `Which solvers to run. Defaults to ["greedy"]. Available: ${getAvailableSolverIds().join(", ")}. Use multiple to race solvers.`
|
|
10806
|
-
},
|
|
10807
|
-
timeoutMs: {
|
|
10808
|
-
type: "number",
|
|
10809
|
-
description: "Maximum time per solver in milliseconds (default: 10000)"
|
|
10810
|
-
}
|
|
10811
|
-
},
|
|
10812
|
-
required: ["problem"]
|
|
10813
|
-
}
|
|
10814
|
-
}
|
|
10815
|
-
})
|
|
10816
|
-
};
|
|
10817
|
-
|
|
10818
|
-
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/quantumFormulate/index.js
|
|
10819
|
-
var quantumFormulateTool = {
|
|
10820
|
-
name: "quantum_formulate",
|
|
10821
|
-
implementation: (context) => ({
|
|
10822
|
-
toolFn: async (value) => {
|
|
10823
|
-
const params = value;
|
|
10824
|
-
const userDescription = params.description?.trim();
|
|
10825
|
-
if (!userDescription) {
|
|
10826
|
-
return "Error: Please provide a description of the scheduling problem to formulate.";
|
|
10827
|
-
}
|
|
10828
|
-
try {
|
|
10829
|
-
let rawContent = "";
|
|
10830
|
-
await context.llm.complete(context.model ?? "gpt-4", [
|
|
10831
|
-
{ role: "system", content: PROBLEM_FORMULATION_PROMPT },
|
|
10832
|
-
{ role: "user", content: userDescription }
|
|
10833
|
-
], { temperature: 0.2, stream: false }, async (texts) => {
|
|
10834
|
-
rawContent = texts.filter((t) => t !== null && t !== void 0).join("");
|
|
10835
|
-
});
|
|
10836
|
-
let jsonStr = rawContent.trim();
|
|
10837
|
-
const codeBlockMatch = jsonStr.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
10838
|
-
if (codeBlockMatch) {
|
|
10839
|
-
jsonStr = codeBlockMatch[1].trim();
|
|
10840
|
-
}
|
|
10841
|
-
let parsed;
|
|
10842
|
-
try {
|
|
10843
|
-
parsed = JSON.parse(jsonStr);
|
|
10844
|
-
} catch {
|
|
10845
|
-
return `Error: Could not parse LLM response as JSON. Raw response:
|
|
10846
|
-
${rawContent}
|
|
10847
|
-
|
|
10848
|
-
Please try rephrasing your description with more specific details about jobs, machines, and processing times.`;
|
|
10849
|
-
}
|
|
10850
|
-
const validated = SchedulingProblemSchema.safeParse(parsed);
|
|
10851
|
-
if (!validated.success) {
|
|
10852
|
-
return `Error: LLM generated an invalid problem structure.
|
|
10853
|
-
${validated.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n")}
|
|
10854
|
-
|
|
10855
|
-
Raw output:
|
|
10856
|
-
${jsonStr}
|
|
10857
|
-
|
|
10858
|
-
Please try rephrasing your description.`;
|
|
10859
|
-
}
|
|
10860
|
-
const problem = validated.data;
|
|
10861
|
-
const totalOps = problem.jobs.reduce((s, j) => s + j.operations.length, 0);
|
|
10862
|
-
const lines = [
|
|
10863
|
-
`## Formulated: "${problem.name}"`,
|
|
10864
|
-
problem.description ? `
|
|
10865
|
-
${problem.description}` : "",
|
|
10866
|
-
"",
|
|
10867
|
-
`**${problem.jobs.length} jobs, ${problem.machines.length} machines, ${totalOps} operations**`,
|
|
10868
|
-
"",
|
|
10869
|
-
"### Jobs:",
|
|
10870
|
-
...problem.jobs.map((j) => {
|
|
10871
|
-
const ops = j.operations.map((op, i) => {
|
|
10872
|
-
const machine = problem.machines.find((m) => m.id === op.machineId);
|
|
10873
|
-
return `Step ${i + 1}: ${machine?.name ?? `Machine ${op.machineId}`} (${op.duration}t)`;
|
|
10874
|
-
});
|
|
10875
|
-
return `- **${j.name}**: ${ops.join(" -> ")}`;
|
|
10876
|
-
}),
|
|
10877
|
-
"",
|
|
10878
|
-
"### Machines:",
|
|
10879
|
-
...problem.machines.map((m) => `- ${m.name} (id: ${m.id})`),
|
|
10880
|
-
"",
|
|
10881
|
-
"### Structured Problem (JSON):",
|
|
10882
|
-
"```json",
|
|
10883
|
-
JSON.stringify(problem, null, 2),
|
|
10884
|
-
"```",
|
|
10885
|
-
"",
|
|
10886
|
-
"You can now use the `quantum_schedule` tool to solve this problem with various optimization algorithms."
|
|
10887
|
-
];
|
|
10888
|
-
return lines.filter((l) => l !== void 0).join("\n");
|
|
10889
|
-
} catch (err) {
|
|
10890
|
-
return `Error formulating problem: ${err instanceof Error ? err.message : String(err)}`;
|
|
10891
|
-
}
|
|
10892
|
-
},
|
|
10893
|
-
toolSchema: {
|
|
10894
|
-
name: "quantum_formulate",
|
|
10895
|
-
description: `Convert a natural language description of a scheduling/optimization problem into a structured SchedulingProblem that can be solved by the quantum_schedule tool.
|
|
10896
|
-
|
|
10897
|
-
Describe the problem in plain English \u2014 what jobs need to be done, what machines or resources are available, how long each step takes, and any ordering constraints. The tool will produce a structured problem definition.
|
|
10898
|
-
|
|
10899
|
-
Examples:
|
|
10900
|
-
- "I have 3 orders to manufacture. Each needs cutting, welding, and painting. Cutting takes 2h, welding 3h, painting 1h."
|
|
10901
|
-
- "Schedule 4 software builds across 2 CI runners. Build A needs compile (5min) then test (3min)..."
|
|
10902
|
-
- "A bakery needs to make 5 cakes. Each cake goes through mixing, baking, and decorating on separate stations."`,
|
|
10903
|
-
parameters: {
|
|
10904
|
-
type: "object",
|
|
10905
|
-
properties: {
|
|
10906
|
-
description: {
|
|
10907
|
-
type: "string",
|
|
10908
|
-
description: "Natural language description of the scheduling problem to formulate"
|
|
10909
|
-
}
|
|
10910
|
-
},
|
|
10911
|
-
required: ["description"]
|
|
10912
|
-
}
|
|
10913
|
-
}
|
|
10914
|
-
})
|
|
10915
|
-
};
|
|
10916
|
-
|
|
10917
|
-
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/navigateView/index.js
|
|
10918
|
-
var navigateViewTool = {
|
|
10919
|
-
name: "navigate_view",
|
|
10920
|
-
implementation: (context) => ({
|
|
10921
|
-
toolFn: async (value) => {
|
|
10922
|
-
const params = value;
|
|
10923
|
-
const { suggestions } = params;
|
|
10924
|
-
context.logger.log("\u{1F9ED} navigate_view: Received suggestions:", JSON.stringify(suggestions));
|
|
10925
|
-
if (!suggestions || !Array.isArray(suggestions) || suggestions.length === 0) {
|
|
10926
|
-
return "No navigation suggestions provided.";
|
|
10927
|
-
}
|
|
10928
|
-
const capped = suggestions.slice(0, 3);
|
|
10929
|
-
const invalid = capped.filter((s) => !getViewById(s.viewId));
|
|
10930
|
-
if (invalid.length > 0) {
|
|
10931
|
-
context.logger.log("\u{1F9ED} navigate_view: Unknown viewIds:", invalid.map((s) => s.viewId));
|
|
10932
|
-
}
|
|
10933
|
-
const isAdmin = context.user?.isAdmin === true;
|
|
10934
|
-
const intents = resolveNavigationIntents(capped, isAdmin);
|
|
10935
|
-
if (intents.length === 0) {
|
|
10936
|
-
return "No valid navigation views matched the provided viewIds.";
|
|
10937
|
-
}
|
|
10938
|
-
context.logger.log("\u{1F9ED} navigate_view: Resolved intents:", intents.map((i) => i.viewId));
|
|
10939
|
-
return JSON.stringify({
|
|
10940
|
-
__navigationIntents: true,
|
|
10941
|
-
intents,
|
|
10942
|
-
message: `Suggested ${intents.length} navigation option(s): ${intents.map((i) => i.label).join(", ")}`
|
|
10943
|
-
});
|
|
10944
|
-
},
|
|
10945
|
-
toolSchema: {
|
|
10946
|
-
name: "navigate_view",
|
|
10947
|
-
description: "Suggest navigation to relevant app views. Returns inline action buttons the user can click. ALWAYS use this tool when your response discusses a topic that has a matching view (e.g., scheduling \u2192 opti.scheduling, user management \u2192 admin.users). Call this tool alongside your text answer \u2014 answer the question AND suggest where to go.",
|
|
10948
|
-
parameters: {
|
|
10949
|
-
type: "object",
|
|
10950
|
-
properties: {
|
|
10951
|
-
suggestions: {
|
|
10952
|
-
type: "array",
|
|
10953
|
-
description: "Navigation suggestions (1-3 items). Each suggests a view the user might want to visit.",
|
|
10954
|
-
items: {
|
|
10955
|
-
type: "object",
|
|
10956
|
-
properties: {
|
|
10957
|
-
viewId: {
|
|
10958
|
-
type: "string",
|
|
10959
|
-
description: 'The view ID from the available views list (e.g., "opti.scheduling", "admin.users")'
|
|
10960
|
-
},
|
|
10961
|
-
reason: {
|
|
10962
|
-
type: "string",
|
|
10963
|
-
description: "Brief reason why this view is relevant (max 80 chars, shown as tooltip)"
|
|
10964
|
-
}
|
|
10965
|
-
},
|
|
10966
|
-
required: ["viewId", "reason"]
|
|
10967
|
-
},
|
|
10968
|
-
maxItems: 3,
|
|
10969
|
-
minItems: 1
|
|
10970
|
-
}
|
|
10971
|
-
},
|
|
10972
|
-
required: ["suggestions"]
|
|
10973
|
-
}
|
|
10974
|
-
}
|
|
10975
|
-
})
|
|
10976
|
-
};
|
|
10977
|
-
|
|
10978
|
-
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/bashExecute/index.js
|
|
10979
|
-
import { spawn } from "child_process";
|
|
10980
|
-
import path11 from "path";
|
|
10981
|
-
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
10982
|
-
var MAX_OUTPUT_SIZE = 100 * 1024;
|
|
10983
|
-
var DANGEROUS_PATTERNS = [
|
|
10984
|
-
// Destructive file operations
|
|
10985
|
-
{
|
|
10986
|
-
pattern: /\brm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*r).*\//i,
|
|
10987
|
-
reason: "Recursive delete with path",
|
|
10988
|
-
block: true
|
|
10989
|
-
},
|
|
10990
|
-
{
|
|
10991
|
-
pattern: /\brm\s+(-[a-zA-Z]*f[a-zA-Z]*\s+|.*\s+-[a-zA-Z]*f).*--no-preserve-root/i,
|
|
10992
|
-
reason: "Force delete without preserve root",
|
|
10993
|
-
block: true
|
|
10994
|
-
},
|
|
10995
|
-
{
|
|
10996
|
-
pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\//i,
|
|
10997
|
-
reason: "Recursive force delete on root paths",
|
|
10998
|
-
block: true
|
|
10999
|
-
},
|
|
11000
|
-
{
|
|
11001
|
-
pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*r[a-zA-Z]*\s+\//i,
|
|
11002
|
-
reason: "Force recursive delete on root paths",
|
|
11003
|
-
block: true
|
|
11004
|
-
},
|
|
11005
|
-
// System-level dangerous commands
|
|
11006
|
-
{ pattern: /\bsudo\b/i, reason: "Elevated privileges (sudo)", block: true },
|
|
11007
|
-
{ pattern: /\bsu\s+(-|root)/i, reason: "Switch to root user", block: true },
|
|
11008
|
-
{ pattern: /\bchmod\s+777\b/i, reason: "Overly permissive chmod", block: false },
|
|
11009
|
-
{ pattern: /\bchown\s+-R\s+root/i, reason: "Recursive chown to root", block: true },
|
|
11010
|
-
// Disk/partition operations
|
|
11011
|
-
{ pattern: /\bmkfs\b/i, reason: "Filesystem creation", block: true },
|
|
11012
|
-
{ pattern: /\bfdisk\b/i, reason: "Disk partitioning", block: true },
|
|
11013
|
-
{ pattern: /\bdd\s+.*of=\/dev\//i, reason: "Direct disk write", block: true },
|
|
11014
|
-
// Network attacks
|
|
11015
|
-
{ pattern: /\b(nc|netcat)\s+.*-e\s+\/bin\/(ba)?sh/i, reason: "Reverse shell attempt", block: true },
|
|
11016
|
-
{ pattern: /\bcurl\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
11017
|
-
{ pattern: /\bwget\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
11018
|
-
// Fork bombs and resource exhaustion
|
|
11019
|
-
{ pattern: /:\(\)\s*\{\s*:\|:&\s*\}\s*;/i, reason: "Fork bomb", block: true },
|
|
11020
|
-
{ pattern: /\bwhile\s+true.*do.*done.*&/i, reason: "Infinite loop in background", block: false },
|
|
11021
|
-
// Credential/sensitive data access
|
|
11022
|
-
{ pattern: /\/etc\/shadow/i, reason: "Access to shadow file", block: true },
|
|
11023
|
-
{ pattern: /\/etc\/passwd.*>/i, reason: "Modifying passwd file", block: true },
|
|
11024
|
-
{ pattern: /\baws\s+.*--profile\s+/i, reason: "AWS profile access", block: false },
|
|
11025
|
-
// History/log manipulation
|
|
11026
|
-
{ pattern: /\bhistory\s+-c\b/i, reason: "Clearing shell history", block: false },
|
|
11027
|
-
{ pattern: />\s*\/var\/log\//i, reason: "Overwriting system logs", block: true },
|
|
11028
|
-
// Dangerous redirects
|
|
11029
|
-
{ pattern: />\s*\/dev\/sda/i, reason: "Writing to block device", block: true },
|
|
11030
|
-
{ pattern: />\s*\/dev\/null.*2>&1.*</i, reason: "Potentially hiding output", block: false },
|
|
11031
|
-
// Environment manipulation
|
|
11032
|
-
{ pattern: /\bexport\s+PATH\s*=\s*[^$]/i, reason: "Overwriting PATH", block: false },
|
|
11033
|
-
{ pattern: /\bexport\s+LD_PRELOAD/i, reason: "LD_PRELOAD manipulation", block: true },
|
|
11034
|
-
// Process/system control
|
|
11035
|
-
{ pattern: /\bkill\s+-9\s+(-1|1)\b/i, reason: "Killing all processes", block: true },
|
|
11036
|
-
{ pattern: /\bkillall\s+-9\b/i, reason: "Force killing processes", block: false },
|
|
11037
|
-
{ pattern: /\bshutdown\b/i, reason: "System shutdown", block: true },
|
|
11038
|
-
{ pattern: /\breboot\b/i, reason: "System reboot", block: true },
|
|
11039
|
-
{ pattern: /\binit\s+[06]\b/i, reason: "System runlevel change", block: true }
|
|
9839
|
+
pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*r[a-zA-Z]*\s+\//i,
|
|
9840
|
+
reason: "Force recursive delete on root paths",
|
|
9841
|
+
block: true
|
|
9842
|
+
},
|
|
9843
|
+
// System-level dangerous commands
|
|
9844
|
+
{ pattern: /\bsudo\b/i, reason: "Elevated privileges (sudo)", block: true },
|
|
9845
|
+
{ pattern: /\bsu\s+(-|root)/i, reason: "Switch to root user", block: true },
|
|
9846
|
+
{ pattern: /\bchmod\s+777\b/i, reason: "Overly permissive chmod", block: false },
|
|
9847
|
+
{ pattern: /\bchown\s+-R\s+root/i, reason: "Recursive chown to root", block: true },
|
|
9848
|
+
// Disk/partition operations
|
|
9849
|
+
{ pattern: /\bmkfs\b/i, reason: "Filesystem creation", block: true },
|
|
9850
|
+
{ pattern: /\bfdisk\b/i, reason: "Disk partitioning", block: true },
|
|
9851
|
+
{ pattern: /\bdd\s+.*of=\/dev\//i, reason: "Direct disk write", block: true },
|
|
9852
|
+
// Network attacks
|
|
9853
|
+
{ pattern: /\b(nc|netcat)\s+.*-e\s+\/bin\/(ba)?sh/i, reason: "Reverse shell attempt", block: true },
|
|
9854
|
+
{ pattern: /\bcurl\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
9855
|
+
{ pattern: /\bwget\s+.*\|\s*(ba)?sh/i, reason: "Piping remote script to shell", block: true },
|
|
9856
|
+
// Fork bombs and resource exhaustion
|
|
9857
|
+
{ pattern: /:\(\)\s*\{\s*:\|:&\s*\}\s*;/i, reason: "Fork bomb", block: true },
|
|
9858
|
+
{ pattern: /\bwhile\s+true.*do.*done.*&/i, reason: "Infinite loop in background", block: false },
|
|
9859
|
+
// Credential/sensitive data access
|
|
9860
|
+
{ pattern: /\/etc\/shadow/i, reason: "Access to shadow file", block: true },
|
|
9861
|
+
{ pattern: /\/etc\/passwd.*>/i, reason: "Modifying passwd file", block: true },
|
|
9862
|
+
{ pattern: /\baws\s+.*--profile\s+/i, reason: "AWS profile access", block: false },
|
|
9863
|
+
// History/log manipulation
|
|
9864
|
+
{ pattern: /\bhistory\s+-c\b/i, reason: "Clearing shell history", block: false },
|
|
9865
|
+
{ pattern: />\s*\/var\/log\//i, reason: "Overwriting system logs", block: true },
|
|
9866
|
+
// Dangerous redirects
|
|
9867
|
+
{ pattern: />\s*\/dev\/sda/i, reason: "Writing to block device", block: true },
|
|
9868
|
+
{ pattern: />\s*\/dev\/null.*2>&1.*</i, reason: "Potentially hiding output", block: false },
|
|
9869
|
+
// Environment manipulation
|
|
9870
|
+
{ pattern: /\bexport\s+PATH\s*=\s*[^$]/i, reason: "Overwriting PATH", block: false },
|
|
9871
|
+
{ pattern: /\bexport\s+LD_PRELOAD/i, reason: "LD_PRELOAD manipulation", block: true },
|
|
9872
|
+
// Process/system control
|
|
9873
|
+
{ pattern: /\bkill\s+-9\s+(-1|1)\b/i, reason: "Killing all processes", block: true },
|
|
9874
|
+
{ pattern: /\bkillall\s+-9\b/i, reason: "Force killing processes", block: false },
|
|
9875
|
+
{ pattern: /\bshutdown\b/i, reason: "System shutdown", block: true },
|
|
9876
|
+
{ pattern: /\breboot\b/i, reason: "System reboot", block: true },
|
|
9877
|
+
{ pattern: /\binit\s+[06]\b/i, reason: "System runlevel change", block: true }
|
|
11040
9878
|
];
|
|
11041
9879
|
var SAFE_COMMAND_PREFIXES = [
|
|
11042
9880
|
"ls",
|
|
@@ -11224,7 +10062,7 @@ async function executeBashCommand(params) {
|
|
|
11224
10062
|
});
|
|
11225
10063
|
});
|
|
11226
10064
|
}
|
|
11227
|
-
function
|
|
10065
|
+
function formatResult(result, command) {
|
|
11228
10066
|
const parts = [];
|
|
11229
10067
|
parts.push(`$ ${command}`);
|
|
11230
10068
|
parts.push("");
|
|
@@ -11278,7 +10116,7 @@ var bashExecuteTool = {
|
|
|
11278
10116
|
}
|
|
11279
10117
|
try {
|
|
11280
10118
|
const result = await executeBashCommand(params);
|
|
11281
|
-
const formattedResult =
|
|
10119
|
+
const formattedResult = formatResult(result, params.command);
|
|
11282
10120
|
context.logger.info("Bash: Command completed", {
|
|
11283
10121
|
exitCode: result.exitCode,
|
|
11284
10122
|
timedOut: result.timedOut,
|
|
@@ -11634,7 +10472,7 @@ async function getFileStats(files, since, filterPath) {
|
|
|
11634
10472
|
});
|
|
11635
10473
|
});
|
|
11636
10474
|
}
|
|
11637
|
-
function
|
|
10475
|
+
function formatResult2(result) {
|
|
11638
10476
|
const parts = [];
|
|
11639
10477
|
if (result.error) {
|
|
11640
10478
|
parts.push(`Error: ${result.error}`);
|
|
@@ -11709,7 +10547,7 @@ var recentChangesTool = {
|
|
|
11709
10547
|
}
|
|
11710
10548
|
try {
|
|
11711
10549
|
const result = await getRecentChanges(params);
|
|
11712
|
-
const formattedResult =
|
|
10550
|
+
const formattedResult = formatResult2(result);
|
|
11713
10551
|
context.logger.info("RecentChanges: Retrieved file changes", {
|
|
11714
10552
|
totalFiles: result.totalFiles,
|
|
11715
10553
|
displayedFiles: result.files.length,
|
|
@@ -11807,14 +10645,8 @@ var b4mTools = {
|
|
|
11807
10645
|
sunrise_sunset: sunriseSunsetTool,
|
|
11808
10646
|
iss_tracker: issTrackerTool,
|
|
11809
10647
|
planet_visibility: planetVisibilityTool,
|
|
11810
|
-
// Knowledge base
|
|
11811
|
-
search_knowledge_base: knowledgeBaseSearchTool
|
|
11812
|
-
retrieve_knowledge_content: knowledgeBaseRetrieveTool,
|
|
11813
|
-
// Quantum optimization tools
|
|
11814
|
-
quantum_schedule: quantumScheduleTool,
|
|
11815
|
-
quantum_formulate: quantumFormulateTool,
|
|
11816
|
-
// Navigation tool
|
|
11817
|
-
navigate_view: navigateViewTool
|
|
10648
|
+
// Knowledge base search
|
|
10649
|
+
search_knowledge_base: knowledgeBaseSearchTool
|
|
11818
10650
|
};
|
|
11819
10651
|
var cliOnlyTools = {
|
|
11820
10652
|
// File operation tools
|
|
@@ -11937,49 +10769,49 @@ var generateMcpTools = async (mcpData) => {
|
|
|
11937
10769
|
import throttle2 from "lodash/throttle.js";
|
|
11938
10770
|
|
|
11939
10771
|
// ../../b4m-core/packages/services/dist/src/llm/ChatCompletionFeatures.js
|
|
11940
|
-
import { z as
|
|
10772
|
+
import { z as z139 } from "zod";
|
|
11941
10773
|
import uniq4 from "lodash/uniq.js";
|
|
11942
|
-
var QuestStartBodySchema =
|
|
11943
|
-
userId:
|
|
11944
|
-
sessionId:
|
|
11945
|
-
questId:
|
|
11946
|
-
message:
|
|
11947
|
-
messageFileIds:
|
|
11948
|
-
historyCount:
|
|
11949
|
-
fabFileIds:
|
|
10774
|
+
var QuestStartBodySchema = z139.object({
|
|
10775
|
+
userId: z139.string(),
|
|
10776
|
+
sessionId: z139.string(),
|
|
10777
|
+
questId: z139.string(),
|
|
10778
|
+
message: z139.string(),
|
|
10779
|
+
messageFileIds: z139.array(z139.string()),
|
|
10780
|
+
historyCount: z139.number(),
|
|
10781
|
+
fabFileIds: z139.array(z139.string()),
|
|
11950
10782
|
params: ChatCompletionCreateInputSchema,
|
|
11951
10783
|
dashboardParams: DashboardParamsSchema.optional(),
|
|
11952
|
-
enableQuestMaster:
|
|
11953
|
-
enableMementos:
|
|
11954
|
-
enableArtifacts:
|
|
11955
|
-
enableAgents:
|
|
10784
|
+
enableQuestMaster: z139.boolean().optional(),
|
|
10785
|
+
enableMementos: z139.boolean().optional(),
|
|
10786
|
+
enableArtifacts: z139.boolean().optional(),
|
|
10787
|
+
enableAgents: z139.boolean().optional(),
|
|
11956
10788
|
promptMeta: PromptMetaZodSchema,
|
|
11957
|
-
tools:
|
|
11958
|
-
mcpServers:
|
|
11959
|
-
projectId:
|
|
11960
|
-
organizationId:
|
|
10789
|
+
tools: z139.array(z139.union([b4mLLMTools, z139.string()])).optional(),
|
|
10790
|
+
mcpServers: z139.array(z139.string()).optional(),
|
|
10791
|
+
projectId: z139.string().optional(),
|
|
10792
|
+
organizationId: z139.string().nullable().optional(),
|
|
11961
10793
|
questMaster: QuestMasterParamsSchema.optional(),
|
|
11962
|
-
toolPromptId:
|
|
10794
|
+
toolPromptId: z139.string().optional(),
|
|
11963
10795
|
researchMode: ResearchModeParamsSchema.optional(),
|
|
11964
|
-
fallbackModel:
|
|
11965
|
-
embeddingModel:
|
|
11966
|
-
queryComplexity:
|
|
10796
|
+
fallbackModel: z139.string().optional(),
|
|
10797
|
+
embeddingModel: z139.string().optional(),
|
|
10798
|
+
queryComplexity: z139.string(),
|
|
11967
10799
|
imageConfig: GenerateImageToolCallSchema.optional(),
|
|
11968
|
-
deepResearchConfig:
|
|
11969
|
-
maxDepth:
|
|
11970
|
-
duration:
|
|
10800
|
+
deepResearchConfig: z139.object({
|
|
10801
|
+
maxDepth: z139.number().optional(),
|
|
10802
|
+
duration: z139.number().optional(),
|
|
11971
10803
|
// Note: searchers are passed via ToolContext and not through this API schema
|
|
11972
|
-
searchers:
|
|
10804
|
+
searchers: z139.array(z139.any()).optional()
|
|
11973
10805
|
}).optional(),
|
|
11974
|
-
extraContextMessages:
|
|
11975
|
-
role:
|
|
11976
|
-
content:
|
|
11977
|
-
fabFileIds:
|
|
10806
|
+
extraContextMessages: z139.array(z139.object({
|
|
10807
|
+
role: z139.enum(["user", "assistant", "system", "function", "tool"]),
|
|
10808
|
+
content: z139.union([z139.string(), z139.array(z139.any())]),
|
|
10809
|
+
fabFileIds: z139.array(z139.string()).optional()
|
|
11978
10810
|
})).optional(),
|
|
11979
10811
|
/** User's timezone (IANA format, e.g., "America/New_York") */
|
|
11980
|
-
timezone:
|
|
10812
|
+
timezone: z139.string().optional(),
|
|
11981
10813
|
/** Pre-fetched API key table from invoke phase — avoids redundant DB call in process (#6616 P1-a) */
|
|
11982
|
-
apiKeyTable:
|
|
10814
|
+
apiKeyTable: z139.record(z139.string(), z139.string().nullable()).optional()
|
|
11983
10815
|
});
|
|
11984
10816
|
|
|
11985
10817
|
// ../../b4m-core/packages/services/dist/src/llm/StatusManager.js
|
|
@@ -12479,89 +11311,89 @@ var BUILT_IN_TOOL_SET = new Set(b4mLLMTools.options);
|
|
|
12479
11311
|
import axios8 from "axios";
|
|
12480
11312
|
import { fileTypeFromBuffer as fileTypeFromBuffer4 } from "file-type";
|
|
12481
11313
|
import { v4 as uuidv47 } from "uuid";
|
|
12482
|
-
import { z as
|
|
11314
|
+
import { z as z140 } from "zod";
|
|
12483
11315
|
import { fromZodError as fromZodError2 } from "zod-validation-error";
|
|
12484
11316
|
var ImageGenerationBodySchema = OpenAIImageGenerationInput.extend({
|
|
12485
|
-
sessionId:
|
|
12486
|
-
questId:
|
|
12487
|
-
userId:
|
|
12488
|
-
prompt:
|
|
12489
|
-
organizationId:
|
|
12490
|
-
safety_tolerance:
|
|
12491
|
-
prompt_upsampling:
|
|
12492
|
-
seed:
|
|
12493
|
-
output_format:
|
|
12494
|
-
width:
|
|
12495
|
-
height:
|
|
12496
|
-
aspect_ratio:
|
|
12497
|
-
fabFileIds:
|
|
11317
|
+
sessionId: z140.string(),
|
|
11318
|
+
questId: z140.string(),
|
|
11319
|
+
userId: z140.string(),
|
|
11320
|
+
prompt: z140.string(),
|
|
11321
|
+
organizationId: z140.string().nullable().optional(),
|
|
11322
|
+
safety_tolerance: z140.number().min(BFL_SAFETY_TOLERANCE.MIN).max(BFL_SAFETY_TOLERANCE.MAX).optional().default(BFL_SAFETY_TOLERANCE.DEFAULT),
|
|
11323
|
+
prompt_upsampling: z140.boolean().optional().default(false),
|
|
11324
|
+
seed: z140.number().nullable().optional(),
|
|
11325
|
+
output_format: z140.enum(["jpeg", "png"]).nullable().optional().default("png"),
|
|
11326
|
+
width: z140.number().optional(),
|
|
11327
|
+
height: z140.number().optional(),
|
|
11328
|
+
aspect_ratio: z140.string().optional(),
|
|
11329
|
+
fabFileIds: z140.array(z140.string()).optional()
|
|
12498
11330
|
});
|
|
12499
11331
|
|
|
12500
11332
|
// ../../b4m-core/packages/services/dist/src/llm/VideoGeneration.js
|
|
12501
11333
|
import axios9 from "axios";
|
|
12502
11334
|
import { v4 as uuidv48 } from "uuid";
|
|
12503
|
-
import { z as
|
|
11335
|
+
import { z as z141 } from "zod";
|
|
12504
11336
|
import { fromZodError as fromZodError3 } from "zod-validation-error";
|
|
12505
|
-
var VideoGenerationBodySchema =
|
|
12506
|
-
sessionId:
|
|
12507
|
-
questId:
|
|
12508
|
-
userId:
|
|
12509
|
-
prompt:
|
|
12510
|
-
model:
|
|
12511
|
-
seconds:
|
|
12512
|
-
size:
|
|
12513
|
-
organizationId:
|
|
11337
|
+
var VideoGenerationBodySchema = z141.object({
|
|
11338
|
+
sessionId: z141.string(),
|
|
11339
|
+
questId: z141.string(),
|
|
11340
|
+
userId: z141.string(),
|
|
11341
|
+
prompt: z141.string(),
|
|
11342
|
+
model: z141.nativeEnum(VideoModels).default(VideoModels.SORA_2),
|
|
11343
|
+
seconds: z141.union([z141.literal(4), z141.literal(8), z141.literal(12)]).default(4),
|
|
11344
|
+
size: z141.enum(["720x1280", "1280x720", "1024x1792", "1792x1024"]).default(VIDEO_SIZE_CONSTRAINTS.SORA.defaultSize),
|
|
11345
|
+
organizationId: z141.string().nullable().optional()
|
|
12514
11346
|
});
|
|
12515
11347
|
|
|
12516
11348
|
// ../../b4m-core/packages/services/dist/src/llm/ImageEdit.js
|
|
12517
11349
|
import axios10 from "axios";
|
|
12518
11350
|
import { fileTypeFromBuffer as fileTypeFromBuffer5 } from "file-type";
|
|
12519
11351
|
import { v4 as uuidv49 } from "uuid";
|
|
12520
|
-
import { z as
|
|
11352
|
+
import { z as z142 } from "zod";
|
|
12521
11353
|
import { fromZodError as fromZodError4 } from "zod-validation-error";
|
|
12522
11354
|
var ImageEditBodySchema = OpenAIImageGenerationInput.extend({
|
|
12523
|
-
sessionId:
|
|
12524
|
-
questId:
|
|
12525
|
-
userId:
|
|
12526
|
-
prompt:
|
|
12527
|
-
organizationId:
|
|
12528
|
-
safety_tolerance:
|
|
12529
|
-
prompt_upsampling:
|
|
12530
|
-
seed:
|
|
12531
|
-
output_format:
|
|
12532
|
-
width:
|
|
12533
|
-
height:
|
|
12534
|
-
aspect_ratio:
|
|
12535
|
-
size:
|
|
12536
|
-
fabFileIds:
|
|
12537
|
-
image:
|
|
11355
|
+
sessionId: z142.string(),
|
|
11356
|
+
questId: z142.string(),
|
|
11357
|
+
userId: z142.string(),
|
|
11358
|
+
prompt: z142.string(),
|
|
11359
|
+
organizationId: z142.string().nullable().optional(),
|
|
11360
|
+
safety_tolerance: z142.number().min(BFL_SAFETY_TOLERANCE.MIN).max(BFL_SAFETY_TOLERANCE.MAX).optional().default(BFL_SAFETY_TOLERANCE.DEFAULT),
|
|
11361
|
+
prompt_upsampling: z142.boolean().optional().default(false),
|
|
11362
|
+
seed: z142.number().nullable().optional(),
|
|
11363
|
+
output_format: z142.enum(["jpeg", "png"]).optional().default("png"),
|
|
11364
|
+
width: z142.number().optional(),
|
|
11365
|
+
height: z142.number().optional(),
|
|
11366
|
+
aspect_ratio: z142.string().optional(),
|
|
11367
|
+
size: z142.string().optional(),
|
|
11368
|
+
fabFileIds: z142.array(z142.string()).optional(),
|
|
11369
|
+
image: z142.string()
|
|
12538
11370
|
});
|
|
12539
11371
|
|
|
12540
11372
|
// ../../b4m-core/packages/services/dist/src/llm/refineText.js
|
|
12541
|
-
import { z as
|
|
12542
|
-
var refineTextLLMSchema =
|
|
12543
|
-
text:
|
|
12544
|
-
context:
|
|
11373
|
+
import { z as z143 } from "zod";
|
|
11374
|
+
var refineTextLLMSchema = z143.object({
|
|
11375
|
+
text: z143.string(),
|
|
11376
|
+
context: z143.string().optional()
|
|
12545
11377
|
// tone: z.enum(['formal', 'informal', 'neutral']).optional(),
|
|
12546
11378
|
// style: z.enum(['technical', 'creative', 'academic', 'business', 'narrative']).optional(),
|
|
12547
11379
|
});
|
|
12548
11380
|
|
|
12549
11381
|
// ../../b4m-core/packages/services/dist/src/llm/MementoEvaluationService.js
|
|
12550
|
-
import { z as
|
|
12551
|
-
var SingleMementoEvalSchema =
|
|
12552
|
-
importance:
|
|
11382
|
+
import { z as z144 } from "zod";
|
|
11383
|
+
var SingleMementoEvalSchema = z144.object({
|
|
11384
|
+
importance: z144.number().min(1).max(10),
|
|
12553
11385
|
// 1-10 scale for personal info importance
|
|
12554
|
-
summary:
|
|
12555
|
-
tags:
|
|
11386
|
+
summary: z144.string(),
|
|
11387
|
+
tags: z144.array(z144.string()).optional()
|
|
12556
11388
|
});
|
|
12557
|
-
var MementoEvalResponseSchema =
|
|
12558
|
-
isPersonal:
|
|
12559
|
-
mementos:
|
|
11389
|
+
var MementoEvalResponseSchema = z144.object({
|
|
11390
|
+
isPersonal: z144.boolean(),
|
|
11391
|
+
mementos: z144.array(SingleMementoEvalSchema).optional()
|
|
12560
11392
|
// Array of distinct personal information
|
|
12561
11393
|
});
|
|
12562
11394
|
|
|
12563
11395
|
// ../../b4m-core/packages/services/dist/src/llm/SmallLLMService.js
|
|
12564
|
-
import { z as
|
|
11396
|
+
import { z as z145 } from "zod";
|
|
12565
11397
|
|
|
12566
11398
|
// ../../b4m-core/packages/services/dist/src/auth/AccessTokenGeneratorService.js
|
|
12567
11399
|
import jwt2 from "jsonwebtoken";
|
|
@@ -12677,6 +11509,10 @@ var ServerToolExecutor = class {
|
|
|
12677
11509
|
};
|
|
12678
11510
|
|
|
12679
11511
|
// src/llm/ToolRouter.ts
|
|
11512
|
+
var wsToolExecutor = null;
|
|
11513
|
+
function setWebSocketToolExecutor(executor) {
|
|
11514
|
+
wsToolExecutor = executor;
|
|
11515
|
+
}
|
|
12680
11516
|
var SERVER_TOOLS = ["weather_info", "web_search", "web_fetch"];
|
|
12681
11517
|
var LOCAL_TOOLS = [
|
|
12682
11518
|
"file_read",
|
|
@@ -12699,7 +11535,15 @@ function isLocalTool(toolName) {
|
|
|
12699
11535
|
}
|
|
12700
11536
|
async function executeTool(toolName, input, apiClient, localToolFn) {
|
|
12701
11537
|
if (isServerTool(toolName)) {
|
|
12702
|
-
|
|
11538
|
+
if (wsToolExecutor) {
|
|
11539
|
+
logger.debug(`[ToolRouter] Routing ${toolName} to server via WebSocket`);
|
|
11540
|
+
const result = await wsToolExecutor.execute(toolName, input);
|
|
11541
|
+
if (!result.success) {
|
|
11542
|
+
return `Error executing ${toolName}: ${result.error || "Tool execution failed"}`;
|
|
11543
|
+
}
|
|
11544
|
+
return typeof result.content === "string" ? result.content : JSON.stringify(result.content ?? "");
|
|
11545
|
+
}
|
|
11546
|
+
logger.debug(`[ToolRouter] Routing ${toolName} to server via HTTP`);
|
|
12703
11547
|
const executor = new ServerToolExecutor(apiClient);
|
|
12704
11548
|
return await executor.executeTool(toolName, input);
|
|
12705
11549
|
} else if (isLocalTool(toolName)) {
|
|
@@ -12854,7 +11698,7 @@ function buildHookContext(params) {
|
|
|
12854
11698
|
}
|
|
12855
11699
|
|
|
12856
11700
|
// src/agents/types.ts
|
|
12857
|
-
import { z as
|
|
11701
|
+
import { z as z146 } from "zod";
|
|
12858
11702
|
var HookBlockedError = class extends Error {
|
|
12859
11703
|
constructor(toolName, reason) {
|
|
12860
11704
|
super(`Hook blocked execution of ${toolName}: ${reason || "No reason provided"}`);
|
|
@@ -12866,40 +11710,40 @@ var ALWAYS_DENIED_FOR_AGENTS = [
|
|
|
12866
11710
|
"agent_delegate"
|
|
12867
11711
|
// No agent chaining
|
|
12868
11712
|
];
|
|
12869
|
-
var CommandHookSchema =
|
|
12870
|
-
type:
|
|
12871
|
-
command:
|
|
12872
|
-
timeout:
|
|
11713
|
+
var CommandHookSchema = z146.object({
|
|
11714
|
+
type: z146.literal("command"),
|
|
11715
|
+
command: z146.string().min(1, "Command is required for command hooks"),
|
|
11716
|
+
timeout: z146.number().optional()
|
|
12873
11717
|
});
|
|
12874
|
-
var PromptHookSchema =
|
|
12875
|
-
type:
|
|
12876
|
-
prompt:
|
|
12877
|
-
timeout:
|
|
11718
|
+
var PromptHookSchema = z146.object({
|
|
11719
|
+
type: z146.literal("prompt"),
|
|
11720
|
+
prompt: z146.string().min(1, "Prompt is required for prompt hooks"),
|
|
11721
|
+
timeout: z146.number().optional()
|
|
12878
11722
|
});
|
|
12879
|
-
var HookDefinitionSchema =
|
|
12880
|
-
var HookMatcherSchema =
|
|
12881
|
-
matcher:
|
|
12882
|
-
hooks:
|
|
11723
|
+
var HookDefinitionSchema = z146.discriminatedUnion("type", [CommandHookSchema, PromptHookSchema]);
|
|
11724
|
+
var HookMatcherSchema = z146.object({
|
|
11725
|
+
matcher: z146.string().optional(),
|
|
11726
|
+
hooks: z146.array(HookDefinitionSchema)
|
|
12883
11727
|
});
|
|
12884
|
-
var AgentHooksSchema =
|
|
12885
|
-
PreToolUse:
|
|
12886
|
-
PostToolUse:
|
|
12887
|
-
PostToolUseFailure:
|
|
12888
|
-
Stop:
|
|
11728
|
+
var AgentHooksSchema = z146.object({
|
|
11729
|
+
PreToolUse: z146.array(HookMatcherSchema).optional(),
|
|
11730
|
+
PostToolUse: z146.array(HookMatcherSchema).optional(),
|
|
11731
|
+
PostToolUseFailure: z146.array(HookMatcherSchema).optional(),
|
|
11732
|
+
Stop: z146.array(HookMatcherSchema).optional()
|
|
12889
11733
|
}).optional();
|
|
12890
|
-
var AgentFrontmatterSchema =
|
|
12891
|
-
description:
|
|
12892
|
-
model:
|
|
12893
|
-
"allowed-tools":
|
|
12894
|
-
"denied-tools":
|
|
12895
|
-
skills:
|
|
12896
|
-
"max-iterations":
|
|
12897
|
-
quick:
|
|
12898
|
-
medium:
|
|
12899
|
-
very_thorough:
|
|
11734
|
+
var AgentFrontmatterSchema = z146.object({
|
|
11735
|
+
description: z146.string().min(1, "Agent description is required"),
|
|
11736
|
+
model: z146.string().optional(),
|
|
11737
|
+
"allowed-tools": z146.array(z146.string()).optional(),
|
|
11738
|
+
"denied-tools": z146.array(z146.string()).optional(),
|
|
11739
|
+
skills: z146.array(z146.string()).optional(),
|
|
11740
|
+
"max-iterations": z146.object({
|
|
11741
|
+
quick: z146.number().int().positive().optional(),
|
|
11742
|
+
medium: z146.number().int().positive().optional(),
|
|
11743
|
+
very_thorough: z146.number().int().positive().optional()
|
|
12900
11744
|
}).optional(),
|
|
12901
|
-
"default-thoroughness":
|
|
12902
|
-
variables:
|
|
11745
|
+
"default-thoroughness": z146.enum(["quick", "medium", "very_thorough"]).optional(),
|
|
11746
|
+
variables: z146.record(z146.string()).optional(),
|
|
12903
11747
|
hooks: AgentHooksSchema
|
|
12904
11748
|
});
|
|
12905
11749
|
var DEFAULT_MAX_ITERATIONS = {
|
|
@@ -14629,6 +13473,173 @@ var ServerLlmBackend = class {
|
|
|
14629
13473
|
}
|
|
14630
13474
|
};
|
|
14631
13475
|
|
|
13476
|
+
// src/llm/WebSocketLlmBackend.ts
|
|
13477
|
+
import { v4 as uuidv411 } from "uuid";
|
|
13478
|
+
function stripThinkingBlocks2(text) {
|
|
13479
|
+
return text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
13480
|
+
}
|
|
13481
|
+
var WebSocketLlmBackend = class {
|
|
13482
|
+
constructor(options) {
|
|
13483
|
+
this.wsManager = options.wsManager;
|
|
13484
|
+
this.apiClient = options.apiClient;
|
|
13485
|
+
this.currentModel = options.model;
|
|
13486
|
+
this.tokenGetter = options.tokenGetter;
|
|
13487
|
+
this.wsCompletionUrl = options.wsCompletionUrl;
|
|
13488
|
+
}
|
|
13489
|
+
/**
|
|
13490
|
+
* Send completion request via HTTP POST, receive streaming response via WebSocket.
|
|
13491
|
+
* Collects all streamed chunks, then calls callback once at completion
|
|
13492
|
+
* with the full accumulated content.
|
|
13493
|
+
*/
|
|
13494
|
+
async complete(model, messages, options, callback) {
|
|
13495
|
+
logger.debug(`[WebSocketLlmBackend] Starting complete() with model: ${model}`);
|
|
13496
|
+
if (options.abortSignal?.aborted) {
|
|
13497
|
+
logger.debug("[WebSocketLlmBackend] Request aborted before start");
|
|
13498
|
+
return;
|
|
13499
|
+
}
|
|
13500
|
+
if (!this.wsManager.isConnected) {
|
|
13501
|
+
throw new Error("WebSocket is not connected");
|
|
13502
|
+
}
|
|
13503
|
+
const requestId = uuidv411();
|
|
13504
|
+
return new Promise((resolve3, reject) => {
|
|
13505
|
+
const isVerbose = process.env.B4M_VERBOSE === "1";
|
|
13506
|
+
const isUltraVerbose = process.env.B4M_DEBUG_STREAM === "1";
|
|
13507
|
+
const streamLogger = new StreamLogger(logger, "WebSocketLlmBackend", isVerbose, isUltraVerbose);
|
|
13508
|
+
streamLogger.streamStart();
|
|
13509
|
+
let eventCount = 0;
|
|
13510
|
+
let accumulatedText = "";
|
|
13511
|
+
let lastUsageInfo = {};
|
|
13512
|
+
let toolsUsed = [];
|
|
13513
|
+
let thinkingBlocks = [];
|
|
13514
|
+
let settled = false;
|
|
13515
|
+
const settle = (action) => {
|
|
13516
|
+
if (settled) return;
|
|
13517
|
+
settled = true;
|
|
13518
|
+
this.wsManager.offRequest(requestId);
|
|
13519
|
+
this.wsManager.offDisconnect(onDisconnect);
|
|
13520
|
+
action();
|
|
13521
|
+
};
|
|
13522
|
+
const settleResolve = () => settle(() => resolve3());
|
|
13523
|
+
const settleReject = (err) => settle(() => reject(err));
|
|
13524
|
+
const onDisconnect = () => {
|
|
13525
|
+
logger.debug("[WebSocketLlmBackend] Connection dropped during completion");
|
|
13526
|
+
settleReject(new Error("WebSocket connection lost during completion"));
|
|
13527
|
+
};
|
|
13528
|
+
this.wsManager.onDisconnect(onDisconnect);
|
|
13529
|
+
if (options.abortSignal) {
|
|
13530
|
+
if (options.abortSignal.aborted) {
|
|
13531
|
+
settleResolve();
|
|
13532
|
+
return;
|
|
13533
|
+
}
|
|
13534
|
+
options.abortSignal.addEventListener(
|
|
13535
|
+
"abort",
|
|
13536
|
+
() => {
|
|
13537
|
+
logger.debug("[WebSocketLlmBackend] Abort signal received");
|
|
13538
|
+
settleResolve();
|
|
13539
|
+
},
|
|
13540
|
+
{ once: true }
|
|
13541
|
+
);
|
|
13542
|
+
}
|
|
13543
|
+
const updateUsage = (usage) => {
|
|
13544
|
+
if (usage) {
|
|
13545
|
+
lastUsageInfo = { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens };
|
|
13546
|
+
}
|
|
13547
|
+
};
|
|
13548
|
+
this.wsManager.onRequest(requestId, (message) => {
|
|
13549
|
+
if (options.abortSignal?.aborted) return;
|
|
13550
|
+
const action = message.action;
|
|
13551
|
+
if (action === "cli_completion_chunk") {
|
|
13552
|
+
eventCount++;
|
|
13553
|
+
const chunk = message.chunk;
|
|
13554
|
+
streamLogger.onEvent(eventCount, JSON.stringify(chunk));
|
|
13555
|
+
const textChunk = chunk.text || "";
|
|
13556
|
+
if (textChunk) accumulatedText += textChunk;
|
|
13557
|
+
updateUsage(chunk.usage);
|
|
13558
|
+
if (chunk.type === "content") {
|
|
13559
|
+
streamLogger.onContent(eventCount, textChunk, accumulatedText);
|
|
13560
|
+
} else if (chunk.type === "tool_use") {
|
|
13561
|
+
streamLogger.onCriticalEvent(eventCount, "TOOL_USE", `tools: ${chunk.tools?.length}`);
|
|
13562
|
+
if (chunk.tools && chunk.tools.length > 0) toolsUsed = chunk.tools;
|
|
13563
|
+
if (chunk.thinking && chunk.thinking.length > 0) thinkingBlocks = chunk.thinking;
|
|
13564
|
+
}
|
|
13565
|
+
} else if (action === "cli_completion_done") {
|
|
13566
|
+
streamLogger.streamComplete(accumulatedText);
|
|
13567
|
+
const cleanedText = stripThinkingBlocks2(accumulatedText);
|
|
13568
|
+
if (!cleanedText && toolsUsed.length === 0) {
|
|
13569
|
+
settleResolve();
|
|
13570
|
+
return;
|
|
13571
|
+
}
|
|
13572
|
+
const info = {
|
|
13573
|
+
...lastUsageInfo,
|
|
13574
|
+
...toolsUsed.length > 0 && { toolsUsed },
|
|
13575
|
+
...thinkingBlocks.length > 0 && { thinking: thinkingBlocks }
|
|
13576
|
+
};
|
|
13577
|
+
callback([cleanedText], info).then(() => settleResolve()).catch((err) => settleReject(err));
|
|
13578
|
+
} else if (action === "cli_completion_error") {
|
|
13579
|
+
const errorMsg = message.error || "Server error";
|
|
13580
|
+
streamLogger.onCriticalEvent(eventCount, "ERROR", errorMsg);
|
|
13581
|
+
settleReject(new Error(errorMsg));
|
|
13582
|
+
}
|
|
13583
|
+
});
|
|
13584
|
+
const axiosInstance = this.apiClient.getAxiosInstance();
|
|
13585
|
+
axiosInstance.post(
|
|
13586
|
+
this.wsCompletionUrl,
|
|
13587
|
+
{
|
|
13588
|
+
requestId,
|
|
13589
|
+
model,
|
|
13590
|
+
messages,
|
|
13591
|
+
options: {
|
|
13592
|
+
temperature: options.temperature,
|
|
13593
|
+
maxTokens: options.maxTokens,
|
|
13594
|
+
stream: true,
|
|
13595
|
+
tools: options.tools || []
|
|
13596
|
+
}
|
|
13597
|
+
},
|
|
13598
|
+
{ signal: options.abortSignal }
|
|
13599
|
+
).catch((err) => {
|
|
13600
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
13601
|
+
settleReject(new Error(`HTTP request failed: ${msg}`));
|
|
13602
|
+
});
|
|
13603
|
+
});
|
|
13604
|
+
}
|
|
13605
|
+
/**
|
|
13606
|
+
* Get available models from server (REST call, not streaming).
|
|
13607
|
+
* Delegates to ApiClient -- same as ServerLlmBackend.
|
|
13608
|
+
*/
|
|
13609
|
+
async getModelInfo() {
|
|
13610
|
+
try {
|
|
13611
|
+
logger.debug("[WebSocketLlmBackend] Fetching models from /api/models");
|
|
13612
|
+
const response = await this.apiClient.get("/api/models");
|
|
13613
|
+
if (!response || typeof response !== "object" || !Array.isArray(response.models)) {
|
|
13614
|
+
logger.warn("[WebSocketLlmBackend] Invalid API response format, using fallback models");
|
|
13615
|
+
return this.getFallbackModels();
|
|
13616
|
+
}
|
|
13617
|
+
const filteredModels = response.models.filter(
|
|
13618
|
+
(model) => model.type === "text" && model.supportsTools === true
|
|
13619
|
+
);
|
|
13620
|
+
if (filteredModels.length === 0) {
|
|
13621
|
+
logger.warn("[WebSocketLlmBackend] No CLI-compatible models found, using fallback");
|
|
13622
|
+
return this.getFallbackModels();
|
|
13623
|
+
}
|
|
13624
|
+
logger.debug(`[WebSocketLlmBackend] Loaded ${filteredModels.length} models`);
|
|
13625
|
+
return filteredModels;
|
|
13626
|
+
} catch (error) {
|
|
13627
|
+
logger.warn(
|
|
13628
|
+
`[WebSocketLlmBackend] Failed to fetch models: ${error instanceof Error ? error.message : String(error)}`
|
|
13629
|
+
);
|
|
13630
|
+
return this.getFallbackModels();
|
|
13631
|
+
}
|
|
13632
|
+
}
|
|
13633
|
+
getFallbackModels() {
|
|
13634
|
+
return [
|
|
13635
|
+
{ id: "claude-sonnet-4-5-20250929", name: "Claude 4.5 Sonnet" },
|
|
13636
|
+
{ id: "claude-3-5-haiku-20241022", name: "Claude 3.5 Haiku" },
|
|
13637
|
+
{ id: "gpt-4o", name: "GPT-4o" },
|
|
13638
|
+
{ id: "gpt-4o-mini", name: "GPT-4o Mini" }
|
|
13639
|
+
];
|
|
13640
|
+
}
|
|
13641
|
+
};
|
|
13642
|
+
|
|
14632
13643
|
// src/llm/NotifyingLlmBackend.ts
|
|
14633
13644
|
var NotifyingLlmBackend = class {
|
|
14634
13645
|
constructor(inner, backgroundManager) {
|
|
@@ -14663,6 +13674,253 @@ Please acknowledge these background agent results and incorporate them into your
|
|
|
14663
13674
|
}
|
|
14664
13675
|
};
|
|
14665
13676
|
|
|
13677
|
+
// src/ws/WebSocketConnectionManager.ts
|
|
13678
|
+
var WebSocketConnectionManager = class {
|
|
13679
|
+
constructor(wsUrl, getToken) {
|
|
13680
|
+
this.ws = null;
|
|
13681
|
+
this.heartbeatInterval = null;
|
|
13682
|
+
this.reconnectAttempts = 0;
|
|
13683
|
+
this.maxReconnectDelay = 3e4;
|
|
13684
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
13685
|
+
this.disconnectHandlers = /* @__PURE__ */ new Set();
|
|
13686
|
+
this.reconnectTimer = null;
|
|
13687
|
+
this.connected = false;
|
|
13688
|
+
this.connecting = false;
|
|
13689
|
+
this.closed = false;
|
|
13690
|
+
this.wsUrl = wsUrl;
|
|
13691
|
+
this.getToken = getToken;
|
|
13692
|
+
}
|
|
13693
|
+
/**
|
|
13694
|
+
* Connect to the WebSocket server.
|
|
13695
|
+
* Resolves when connection is established, rejects on failure.
|
|
13696
|
+
*/
|
|
13697
|
+
async connect() {
|
|
13698
|
+
if (this.connected || this.connecting) return;
|
|
13699
|
+
this.connecting = true;
|
|
13700
|
+
const token = await this.getToken();
|
|
13701
|
+
if (!token) {
|
|
13702
|
+
this.connecting = false;
|
|
13703
|
+
throw new Error("No access token available for WebSocket connection");
|
|
13704
|
+
}
|
|
13705
|
+
return new Promise((resolve3, reject) => {
|
|
13706
|
+
logger.debug(`[WS] Connecting to ${this.wsUrl}...`);
|
|
13707
|
+
this.ws = new WebSocket(this.wsUrl, [`access_token.${token}`]);
|
|
13708
|
+
this.ws.onopen = () => {
|
|
13709
|
+
logger.debug("[WS] Connected");
|
|
13710
|
+
this.connected = true;
|
|
13711
|
+
this.connecting = false;
|
|
13712
|
+
this.reconnectAttempts = 0;
|
|
13713
|
+
this.startHeartbeat();
|
|
13714
|
+
resolve3();
|
|
13715
|
+
};
|
|
13716
|
+
this.ws.onmessage = (event) => {
|
|
13717
|
+
try {
|
|
13718
|
+
const data = typeof event.data === "string" ? event.data : event.data.toString();
|
|
13719
|
+
const message = JSON.parse(data);
|
|
13720
|
+
const requestId = message.requestId;
|
|
13721
|
+
if (requestId && this.handlers.has(requestId)) {
|
|
13722
|
+
this.handlers.get(requestId)(message);
|
|
13723
|
+
} else {
|
|
13724
|
+
logger.debug(`[WS] Unhandled message: ${message.action || "unknown"}`);
|
|
13725
|
+
}
|
|
13726
|
+
} catch (err) {
|
|
13727
|
+
logger.debug(`[WS] Failed to parse message: ${err}`);
|
|
13728
|
+
}
|
|
13729
|
+
};
|
|
13730
|
+
this.ws.onclose = () => {
|
|
13731
|
+
logger.debug("[WS] Connection closed");
|
|
13732
|
+
this.cleanup();
|
|
13733
|
+
this.notifyDisconnect();
|
|
13734
|
+
if (!this.closed) {
|
|
13735
|
+
this.scheduleReconnect();
|
|
13736
|
+
}
|
|
13737
|
+
};
|
|
13738
|
+
this.ws.onerror = (err) => {
|
|
13739
|
+
logger.debug(`[WS] Error: ${err}`);
|
|
13740
|
+
if (this.connecting) {
|
|
13741
|
+
this.connecting = false;
|
|
13742
|
+
this.connected = false;
|
|
13743
|
+
reject(new Error("WebSocket connection failed"));
|
|
13744
|
+
}
|
|
13745
|
+
};
|
|
13746
|
+
});
|
|
13747
|
+
}
|
|
13748
|
+
/** Whether the connection is currently established */
|
|
13749
|
+
get isConnected() {
|
|
13750
|
+
return this.connected;
|
|
13751
|
+
}
|
|
13752
|
+
/**
|
|
13753
|
+
* Send a JSON message over the WebSocket connection.
|
|
13754
|
+
*/
|
|
13755
|
+
send(data) {
|
|
13756
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
13757
|
+
throw new Error("WebSocket is not connected");
|
|
13758
|
+
}
|
|
13759
|
+
const payload = JSON.stringify(data);
|
|
13760
|
+
const sizeKB = (payload.length / 1024).toFixed(1);
|
|
13761
|
+
logger.debug(`[WS] Sending ${sizeKB} KB (action: ${data.action})`);
|
|
13762
|
+
if (payload.length > 32e3) {
|
|
13763
|
+
logger.warn(`[WS] Payload ${sizeKB} KB exceeds API Gateway 32 KB frame limit \u2014 connection will be closed`);
|
|
13764
|
+
}
|
|
13765
|
+
this.ws.send(payload);
|
|
13766
|
+
}
|
|
13767
|
+
/**
|
|
13768
|
+
* Register a handler for messages matching a specific requestId.
|
|
13769
|
+
*/
|
|
13770
|
+
onRequest(requestId, handler) {
|
|
13771
|
+
this.handlers.set(requestId, handler);
|
|
13772
|
+
}
|
|
13773
|
+
/**
|
|
13774
|
+
* Remove a handler for a specific requestId.
|
|
13775
|
+
*/
|
|
13776
|
+
offRequest(requestId) {
|
|
13777
|
+
this.handlers.delete(requestId);
|
|
13778
|
+
}
|
|
13779
|
+
/**
|
|
13780
|
+
* Register a handler that fires when the connection drops.
|
|
13781
|
+
*/
|
|
13782
|
+
onDisconnect(handler) {
|
|
13783
|
+
this.disconnectHandlers.add(handler);
|
|
13784
|
+
}
|
|
13785
|
+
/**
|
|
13786
|
+
* Remove a disconnect handler.
|
|
13787
|
+
*/
|
|
13788
|
+
offDisconnect(handler) {
|
|
13789
|
+
this.disconnectHandlers.delete(handler);
|
|
13790
|
+
}
|
|
13791
|
+
/**
|
|
13792
|
+
* Close the connection and stop all heartbeat/reconnect logic.
|
|
13793
|
+
*/
|
|
13794
|
+
disconnect() {
|
|
13795
|
+
this.closed = true;
|
|
13796
|
+
this.cleanup();
|
|
13797
|
+
if (this.ws) {
|
|
13798
|
+
this.ws.close();
|
|
13799
|
+
this.ws = null;
|
|
13800
|
+
}
|
|
13801
|
+
this.handlers.clear();
|
|
13802
|
+
this.disconnectHandlers.clear();
|
|
13803
|
+
}
|
|
13804
|
+
startHeartbeat() {
|
|
13805
|
+
this.stopHeartbeat();
|
|
13806
|
+
this.heartbeatInterval = setInterval(
|
|
13807
|
+
() => {
|
|
13808
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
13809
|
+
this.ws.send(JSON.stringify({ action: "heartbeat" }));
|
|
13810
|
+
logger.debug("[WS] Heartbeat sent");
|
|
13811
|
+
}
|
|
13812
|
+
},
|
|
13813
|
+
5 * 60 * 1e3
|
|
13814
|
+
);
|
|
13815
|
+
}
|
|
13816
|
+
stopHeartbeat() {
|
|
13817
|
+
if (this.heartbeatInterval) {
|
|
13818
|
+
clearInterval(this.heartbeatInterval);
|
|
13819
|
+
this.heartbeatInterval = null;
|
|
13820
|
+
}
|
|
13821
|
+
}
|
|
13822
|
+
cleanup() {
|
|
13823
|
+
this.connected = false;
|
|
13824
|
+
this.connecting = false;
|
|
13825
|
+
this.stopHeartbeat();
|
|
13826
|
+
if (this.reconnectTimer) {
|
|
13827
|
+
clearTimeout(this.reconnectTimer);
|
|
13828
|
+
this.reconnectTimer = null;
|
|
13829
|
+
}
|
|
13830
|
+
}
|
|
13831
|
+
notifyDisconnect() {
|
|
13832
|
+
for (const handler of this.disconnectHandlers) {
|
|
13833
|
+
try {
|
|
13834
|
+
handler();
|
|
13835
|
+
} catch {
|
|
13836
|
+
}
|
|
13837
|
+
}
|
|
13838
|
+
}
|
|
13839
|
+
scheduleReconnect() {
|
|
13840
|
+
if (this.closed) return;
|
|
13841
|
+
this.reconnectAttempts++;
|
|
13842
|
+
const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts - 1), this.maxReconnectDelay);
|
|
13843
|
+
logger.debug(`[WS] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
|
13844
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
13845
|
+
this.reconnectTimer = null;
|
|
13846
|
+
if (this.closed) return;
|
|
13847
|
+
try {
|
|
13848
|
+
await this.connect();
|
|
13849
|
+
} catch {
|
|
13850
|
+
logger.debug("[WS] Reconnection failed");
|
|
13851
|
+
}
|
|
13852
|
+
}, delay);
|
|
13853
|
+
}
|
|
13854
|
+
};
|
|
13855
|
+
|
|
13856
|
+
// src/ws/WebSocketToolExecutor.ts
|
|
13857
|
+
import { v4 as uuidv412 } from "uuid";
|
|
13858
|
+
var WebSocketToolExecutor = class {
|
|
13859
|
+
constructor(wsManager, tokenGetter) {
|
|
13860
|
+
this.wsManager = wsManager;
|
|
13861
|
+
this.tokenGetter = tokenGetter;
|
|
13862
|
+
}
|
|
13863
|
+
/**
|
|
13864
|
+
* Execute a server-side tool via WebSocket.
|
|
13865
|
+
* Returns the tool result or throws on error.
|
|
13866
|
+
*/
|
|
13867
|
+
async execute(toolName, input, abortSignal) {
|
|
13868
|
+
if (!this.wsManager.isConnected) {
|
|
13869
|
+
throw new Error("WebSocket is not connected");
|
|
13870
|
+
}
|
|
13871
|
+
const token = await this.tokenGetter();
|
|
13872
|
+
if (!token) {
|
|
13873
|
+
throw new Error("No access token available");
|
|
13874
|
+
}
|
|
13875
|
+
const requestId = uuidv412();
|
|
13876
|
+
return new Promise((resolve3, reject) => {
|
|
13877
|
+
let settled = false;
|
|
13878
|
+
const settle = (action) => {
|
|
13879
|
+
if (settled) return;
|
|
13880
|
+
settled = true;
|
|
13881
|
+
this.wsManager.offRequest(requestId);
|
|
13882
|
+
this.wsManager.offDisconnect(onDisconnect);
|
|
13883
|
+
action();
|
|
13884
|
+
};
|
|
13885
|
+
const settleResolve = (result) => settle(() => resolve3(result));
|
|
13886
|
+
const settleReject = (err) => settle(() => reject(err));
|
|
13887
|
+
const onDisconnect = () => {
|
|
13888
|
+
settleReject(new Error("WebSocket connection lost during tool execution"));
|
|
13889
|
+
};
|
|
13890
|
+
this.wsManager.onDisconnect(onDisconnect);
|
|
13891
|
+
if (abortSignal) {
|
|
13892
|
+
if (abortSignal.aborted) {
|
|
13893
|
+
settleReject(new Error("Tool execution aborted"));
|
|
13894
|
+
return;
|
|
13895
|
+
}
|
|
13896
|
+
abortSignal.addEventListener("abort", () => settleReject(new Error("Tool execution aborted")), {
|
|
13897
|
+
once: true
|
|
13898
|
+
});
|
|
13899
|
+
}
|
|
13900
|
+
this.wsManager.onRequest(requestId, (message) => {
|
|
13901
|
+
if (message.action === "cli_tool_response") {
|
|
13902
|
+
settleResolve({
|
|
13903
|
+
success: message.success,
|
|
13904
|
+
content: message.content,
|
|
13905
|
+
error: message.error
|
|
13906
|
+
});
|
|
13907
|
+
}
|
|
13908
|
+
});
|
|
13909
|
+
try {
|
|
13910
|
+
this.wsManager.send({
|
|
13911
|
+
action: "cli_tool_request",
|
|
13912
|
+
accessToken: token,
|
|
13913
|
+
requestId,
|
|
13914
|
+
toolName,
|
|
13915
|
+
input
|
|
13916
|
+
});
|
|
13917
|
+
} catch (err) {
|
|
13918
|
+
settleReject(err instanceof Error ? err : new Error(String(err)));
|
|
13919
|
+
}
|
|
13920
|
+
});
|
|
13921
|
+
}
|
|
13922
|
+
};
|
|
13923
|
+
|
|
14666
13924
|
// src/auth/ApiClient.ts
|
|
14667
13925
|
import axios11 from "axios";
|
|
14668
13926
|
var ApiClient = class {
|
|
@@ -14800,7 +14058,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
14800
14058
|
// package.json
|
|
14801
14059
|
var package_default = {
|
|
14802
14060
|
name: "@bike4mind/cli",
|
|
14803
|
-
version: "0.2.29-feat-
|
|
14061
|
+
version: "0.2.29-feat-cli-websocket-streaming.18881+1cfcea5f6",
|
|
14804
14062
|
type: "module",
|
|
14805
14063
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
14806
14064
|
license: "UNLICENSED",
|
|
@@ -14910,10 +14168,10 @@ var package_default = {
|
|
|
14910
14168
|
},
|
|
14911
14169
|
devDependencies: {
|
|
14912
14170
|
"@bike4mind/agents": "0.1.0",
|
|
14913
|
-
"@bike4mind/common": "2.50.1-feat-
|
|
14914
|
-
"@bike4mind/mcp": "1.29.1-feat-
|
|
14915
|
-
"@bike4mind/services": "2.48.1-feat-
|
|
14916
|
-
"@bike4mind/utils": "2.5.1-feat-
|
|
14171
|
+
"@bike4mind/common": "2.50.1-feat-cli-websocket-streaming.18881+1cfcea5f6",
|
|
14172
|
+
"@bike4mind/mcp": "1.29.1-feat-cli-websocket-streaming.18881+1cfcea5f6",
|
|
14173
|
+
"@bike4mind/services": "2.48.1-feat-cli-websocket-streaming.18881+1cfcea5f6",
|
|
14174
|
+
"@bike4mind/utils": "2.5.1-feat-cli-websocket-streaming.18881+1cfcea5f6",
|
|
14917
14175
|
"@types/better-sqlite3": "^7.6.13",
|
|
14918
14176
|
"@types/diff": "^5.0.9",
|
|
14919
14177
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -14930,7 +14188,7 @@ var package_default = {
|
|
|
14930
14188
|
optionalDependencies: {
|
|
14931
14189
|
"@vscode/ripgrep": "^1.17.0"
|
|
14932
14190
|
},
|
|
14933
|
-
gitHead: "
|
|
14191
|
+
gitHead: "1cfcea5f6e4c3d36587681e0d276669b66cdcc4e"
|
|
14934
14192
|
};
|
|
14935
14193
|
|
|
14936
14194
|
// src/config/constants.ts
|
|
@@ -15167,50 +14425,6 @@ ${expandedBody}
|
|
|
15167
14425
|
};
|
|
15168
14426
|
}
|
|
15169
14427
|
|
|
15170
|
-
// src/core/skillsPrompt.ts
|
|
15171
|
-
function getSkillDisplayName(cmd) {
|
|
15172
|
-
return cmd.displayName || cmd.name;
|
|
15173
|
-
}
|
|
15174
|
-
function formatSkillEntry(cmd) {
|
|
15175
|
-
const displayName = getSkillDisplayName(cmd);
|
|
15176
|
-
const argHint = cmd.argumentHint ? ` ${cmd.argumentHint}` : "";
|
|
15177
|
-
const nameDisplay = cmd.displayName && cmd.displayName !== cmd.name ? `**${displayName}** (\`${cmd.name}\`)` : `**${cmd.name}**`;
|
|
15178
|
-
return `- ${nameDisplay}${argHint}: ${cmd.description}
|
|
15179
|
-
`;
|
|
15180
|
-
}
|
|
15181
|
-
function formatSkillGroup(heading, commands) {
|
|
15182
|
-
if (commands.length === 0) {
|
|
15183
|
-
return "";
|
|
15184
|
-
}
|
|
15185
|
-
return `
|
|
15186
|
-
### ${heading}
|
|
15187
|
-
${commands.map(formatSkillEntry).join("")}`;
|
|
15188
|
-
}
|
|
15189
|
-
function filterAIVisibleSkills(commands) {
|
|
15190
|
-
return commands.filter((cmd) => !cmd.disableModelInvocation);
|
|
15191
|
-
}
|
|
15192
|
-
function filterSkillsByAllowedList(commands, allowedSkills) {
|
|
15193
|
-
if (!allowedSkills || allowedSkills.length === 0) {
|
|
15194
|
-
return commands;
|
|
15195
|
-
}
|
|
15196
|
-
return commands.filter((cmd) => allowedSkills.includes(cmd.name));
|
|
15197
|
-
}
|
|
15198
|
-
function buildSkillsPromptSection(commands, allowedSkills) {
|
|
15199
|
-
const filteredByAllowed = filterSkillsByAllowedList(commands, allowedSkills);
|
|
15200
|
-
const visibleCommands = filterAIVisibleSkills(filteredByAllowed);
|
|
15201
|
-
if (visibleCommands.length === 0) {
|
|
15202
|
-
return "";
|
|
15203
|
-
}
|
|
15204
|
-
const projectSkills = visibleCommands.filter((c) => c.source === "project");
|
|
15205
|
-
const globalSkills = visibleCommands.filter((c) => c.source === "global");
|
|
15206
|
-
return `
|
|
15207
|
-
|
|
15208
|
-
## Available Skills
|
|
15209
|
-
|
|
15210
|
-
Use the \`skill\` tool to invoke these. Example: skill({ skill: "commit" })
|
|
15211
|
-
` + formatSkillGroup("Project Skills", projectSkills) + formatSkillGroup("Global Skills", globalSkills);
|
|
15212
|
-
}
|
|
15213
|
-
|
|
15214
14428
|
// src/agents/SubagentOrchestrator.ts
|
|
15215
14429
|
var SubagentOrchestrator = class {
|
|
15216
14430
|
constructor(deps) {
|
|
@@ -15791,6 +15005,21 @@ Describe the expected output format here.
|
|
|
15791
15005
|
}
|
|
15792
15006
|
return { builtin, global, project, total: this.agents.size };
|
|
15793
15007
|
}
|
|
15008
|
+
/**
|
|
15009
|
+
* Generates a markdown "Phone Book" of available agents and their schemas.
|
|
15010
|
+
* This MUST be injected into the System Prompt of the parent agent.
|
|
15011
|
+
*/
|
|
15012
|
+
getDirectoryContext() {
|
|
15013
|
+
if (this.agents.size === 0) {
|
|
15014
|
+
return "No sub-agents are currently available.";
|
|
15015
|
+
}
|
|
15016
|
+
let context = "Use `subagent_delegate` for complex tasks requiring specialized analysis.\n";
|
|
15017
|
+
for (const [name, def] of this.agents) {
|
|
15018
|
+
context += ` - **${name}**: ${def.description}
|
|
15019
|
+
`;
|
|
15020
|
+
}
|
|
15021
|
+
return context;
|
|
15022
|
+
}
|
|
15794
15023
|
};
|
|
15795
15024
|
|
|
15796
15025
|
// src/agents/delegateTool.ts
|
|
@@ -16738,7 +15967,8 @@ function CliApp() {
|
|
|
16738
15967
|
agentStore: null,
|
|
16739
15968
|
abortController: null,
|
|
16740
15969
|
contextContent: "",
|
|
16741
|
-
backgroundManager: null
|
|
15970
|
+
backgroundManager: null,
|
|
15971
|
+
wsManager: null
|
|
16742
15972
|
});
|
|
16743
15973
|
const [isInitialized, setIsInitialized] = useState9(false);
|
|
16744
15974
|
const [initError, setInitError] = useState9(null);
|
|
@@ -16766,6 +15996,10 @@ function CliApp() {
|
|
|
16766
15996
|
})
|
|
16767
15997
|
);
|
|
16768
15998
|
}
|
|
15999
|
+
if (state.wsManager) {
|
|
16000
|
+
state.wsManager.disconnect();
|
|
16001
|
+
setWebSocketToolExecutor(null);
|
|
16002
|
+
}
|
|
16769
16003
|
if (state.agent) {
|
|
16770
16004
|
state.agent.removeAllListeners();
|
|
16771
16005
|
}
|
|
@@ -16784,7 +16018,7 @@ function CliApp() {
|
|
|
16784
16018
|
setTimeout(() => {
|
|
16785
16019
|
process.exit(0);
|
|
16786
16020
|
}, 100);
|
|
16787
|
-
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
|
|
16021
|
+
}, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore, state.wsManager]);
|
|
16788
16022
|
useInput9((input, key) => {
|
|
16789
16023
|
if (key.escape) {
|
|
16790
16024
|
if (state.abortController) {
|
|
@@ -16854,7 +16088,7 @@ function CliApp() {
|
|
|
16854
16088
|
if (!isAuthenticated) {
|
|
16855
16089
|
console.log("\u2139\uFE0F AI features disabled. Available commands: /login, /help, /config\n");
|
|
16856
16090
|
const minimalSession = {
|
|
16857
|
-
id:
|
|
16091
|
+
id: uuidv413(),
|
|
16858
16092
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
16859
16093
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16860
16094
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -16882,10 +16116,45 @@ function CliApp() {
|
|
|
16882
16116
|
console.log(`\u{1F30D} API Environment: ${envName} (${apiBaseURL})`);
|
|
16883
16117
|
}
|
|
16884
16118
|
const apiClient = new ApiClient(apiBaseURL, state.configStore);
|
|
16885
|
-
const
|
|
16886
|
-
|
|
16887
|
-
|
|
16888
|
-
}
|
|
16119
|
+
const tokenGetter = async () => {
|
|
16120
|
+
const tokens = await state.configStore.getAuthTokens();
|
|
16121
|
+
return tokens?.accessToken ?? null;
|
|
16122
|
+
};
|
|
16123
|
+
let wsManager = null;
|
|
16124
|
+
let llm;
|
|
16125
|
+
try {
|
|
16126
|
+
const serverConfig = await apiClient.get(
|
|
16127
|
+
"/api/settings/serverConfig"
|
|
16128
|
+
);
|
|
16129
|
+
const wsUrl = serverConfig?.websocketUrl;
|
|
16130
|
+
const wsCompletionUrl = serverConfig?.wsCompletionUrl;
|
|
16131
|
+
if (wsUrl && wsCompletionUrl) {
|
|
16132
|
+
wsManager = new WebSocketConnectionManager(wsUrl, tokenGetter);
|
|
16133
|
+
await wsManager.connect();
|
|
16134
|
+
const wsToolExecutor2 = new WebSocketToolExecutor(wsManager, tokenGetter);
|
|
16135
|
+
setWebSocketToolExecutor(wsToolExecutor2);
|
|
16136
|
+
llm = new WebSocketLlmBackend({
|
|
16137
|
+
wsManager,
|
|
16138
|
+
apiClient,
|
|
16139
|
+
model: config.defaultModel,
|
|
16140
|
+
tokenGetter,
|
|
16141
|
+
wsCompletionUrl
|
|
16142
|
+
});
|
|
16143
|
+
logger.debug("\u{1F50C} Using WebSocket transport (bypasses CloudFront timeout)");
|
|
16144
|
+
} else {
|
|
16145
|
+
throw new Error("No websocketUrl or wsCompletionUrl in server config");
|
|
16146
|
+
}
|
|
16147
|
+
} catch (wsError) {
|
|
16148
|
+
logger.debug(
|
|
16149
|
+
`[WS] WebSocket unavailable, using SSE fallback: ${wsError instanceof Error ? wsError.message : String(wsError)}`
|
|
16150
|
+
);
|
|
16151
|
+
wsManager = null;
|
|
16152
|
+
setWebSocketToolExecutor(null);
|
|
16153
|
+
llm = new ServerLlmBackend({
|
|
16154
|
+
apiClient,
|
|
16155
|
+
model: config.defaultModel
|
|
16156
|
+
});
|
|
16157
|
+
}
|
|
16889
16158
|
const models = await llm.getModelInfo();
|
|
16890
16159
|
if (models.length === 0) {
|
|
16891
16160
|
throw new Error("No models available from server.");
|
|
@@ -16898,7 +16167,7 @@ function CliApp() {
|
|
|
16898
16167
|
}
|
|
16899
16168
|
llm.currentModel = modelInfo.id;
|
|
16900
16169
|
const newSession = {
|
|
16901
|
-
id:
|
|
16170
|
+
id: uuidv413(),
|
|
16902
16171
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
16903
16172
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16904
16173
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17048,18 +16317,12 @@ function CliApp() {
|
|
|
17048
16317
|
for (const error of contextResult.errors) {
|
|
17049
16318
|
startupLog.push(`\u26A0\uFE0F Context file error: ${error}`);
|
|
17050
16319
|
}
|
|
17051
|
-
|
|
17052
|
-
|
|
17053
|
-
|
|
17054
|
-
|
|
17055
|
-
|
|
17056
|
-
|
|
17057
|
-
${contextResult.mergedContent}` : "";
|
|
17058
|
-
if (enableSkillTool) {
|
|
17059
|
-
const commands = state.customCommandStore.getAllCommands();
|
|
17060
|
-
contextSection += buildSkillsPromptSection(commands);
|
|
17061
|
-
}
|
|
17062
|
-
const cliSystemPrompt = buildCoreSystemPrompt(contextSection);
|
|
16320
|
+
const cliSystemPrompt = buildCoreSystemPrompt({
|
|
16321
|
+
contextContent: contextResult.mergedContent,
|
|
16322
|
+
agentStore,
|
|
16323
|
+
customCommands: state.customCommandStore.getAllCommands(),
|
|
16324
|
+
enableSkillTool
|
|
16325
|
+
});
|
|
17063
16326
|
const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
|
|
17064
16327
|
const agent = new ReActAgent({
|
|
17065
16328
|
userId: config.userId,
|
|
@@ -17118,8 +16381,10 @@ ${contextResult.mergedContent}` : "";
|
|
|
17118
16381
|
// Store agent store for agent management commands
|
|
17119
16382
|
contextContent: contextResult.mergedContent,
|
|
17120
16383
|
// Store raw context for compact instructions
|
|
17121
|
-
backgroundManager
|
|
16384
|
+
backgroundManager,
|
|
17122
16385
|
// Store for grouped notification turn tracking
|
|
16386
|
+
wsManager
|
|
16387
|
+
// WebSocket connection manager (null if using SSE fallback)
|
|
17123
16388
|
}));
|
|
17124
16389
|
setStoreSession(newSession);
|
|
17125
16390
|
const bannerLines = [
|
|
@@ -17214,13 +16479,13 @@ ${contextResult.mergedContent}` : "";
|
|
|
17214
16479
|
messageContent = multimodalMessage.content;
|
|
17215
16480
|
}
|
|
17216
16481
|
const userMessage = {
|
|
17217
|
-
id:
|
|
16482
|
+
id: uuidv413(),
|
|
17218
16483
|
role: "user",
|
|
17219
16484
|
content: userMessageContent,
|
|
17220
16485
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17221
16486
|
};
|
|
17222
16487
|
const pendingAssistantMessage = {
|
|
17223
|
-
id:
|
|
16488
|
+
id: uuidv413(),
|
|
17224
16489
|
role: "assistant",
|
|
17225
16490
|
content: "...",
|
|
17226
16491
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17389,7 +16654,12 @@ ${contextResult.mergedContent}` : "";
|
|
|
17389
16654
|
const tokenCounter2 = getTokenCounter();
|
|
17390
16655
|
const contextWindow = tokenCounter2.getContextWindow(activeSession.model, state.availableModels);
|
|
17391
16656
|
const threshold = contextWindow * 0.8;
|
|
17392
|
-
const systemPrompt = buildCoreSystemPrompt(
|
|
16657
|
+
const systemPrompt = buildCoreSystemPrompt({
|
|
16658
|
+
contextContent: state.contextContent,
|
|
16659
|
+
agentStore: state.agentStore || void 0,
|
|
16660
|
+
customCommands: state.customCommandStore.getAllCommands(),
|
|
16661
|
+
enableSkillTool: config?.preferences.enableSkillTool !== false
|
|
16662
|
+
});
|
|
17393
16663
|
const contextUsage = tokenCounter2.countSessionTokens(activeSession, systemPrompt);
|
|
17394
16664
|
if (contextUsage.totalTokens >= threshold) {
|
|
17395
16665
|
console.log("\n\u26A0\uFE0F Context window 80% full. Auto-compacting...\n");
|
|
@@ -17426,13 +16696,13 @@ ${contextResult.mergedContent}` : "";
|
|
|
17426
16696
|
userMessageContent = message;
|
|
17427
16697
|
}
|
|
17428
16698
|
const userMessage = {
|
|
17429
|
-
id:
|
|
16699
|
+
id: uuidv413(),
|
|
17430
16700
|
role: "user",
|
|
17431
16701
|
content: userMessageContent,
|
|
17432
16702
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17433
16703
|
};
|
|
17434
16704
|
const pendingAssistantMessage = {
|
|
17435
|
-
id:
|
|
16705
|
+
id: uuidv413(),
|
|
17436
16706
|
role: "assistant",
|
|
17437
16707
|
content: "...",
|
|
17438
16708
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17510,7 +16780,7 @@ ${contextResult.mergedContent}` : "";
|
|
|
17510
16780
|
const currentSession = useCliStore.getState().session;
|
|
17511
16781
|
if (currentSession) {
|
|
17512
16782
|
const cancelMessage = {
|
|
17513
|
-
id:
|
|
16783
|
+
id: uuidv413(),
|
|
17514
16784
|
role: "assistant",
|
|
17515
16785
|
content: "\u26A0\uFE0F Operation cancelled by user",
|
|
17516
16786
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17555,7 +16825,7 @@ ${contextResult.mergedContent}` : "";
|
|
|
17555
16825
|
setState((prev) => ({ ...prev, abortController }));
|
|
17556
16826
|
try {
|
|
17557
16827
|
const pendingAssistantMessage = {
|
|
17558
|
-
id:
|
|
16828
|
+
id: uuidv413(),
|
|
17559
16829
|
role: "assistant",
|
|
17560
16830
|
content: "...",
|
|
17561
16831
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17583,7 +16853,7 @@ ${contextResult.mergedContent}` : "";
|
|
|
17583
16853
|
const currentSession = useCliStore.getState().session;
|
|
17584
16854
|
if (!currentSession) return;
|
|
17585
16855
|
const continuationMessage = {
|
|
17586
|
-
id:
|
|
16856
|
+
id: uuidv413(),
|
|
17587
16857
|
role: "assistant",
|
|
17588
16858
|
content: "---\n\n**Background Agent Results:**\n\n" + result.finalAnswer,
|
|
17589
16859
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -17642,13 +16912,13 @@ ${contextResult.mergedContent}` : "";
|
|
|
17642
16912
|
isError = true;
|
|
17643
16913
|
}
|
|
17644
16914
|
const userMessage = {
|
|
17645
|
-
id:
|
|
16915
|
+
id: uuidv413(),
|
|
17646
16916
|
role: "user",
|
|
17647
16917
|
content: `$ ${command}`,
|
|
17648
16918
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17649
16919
|
};
|
|
17650
16920
|
const assistantMessage = {
|
|
17651
|
-
id:
|
|
16921
|
+
id: uuidv413(),
|
|
17652
16922
|
role: "assistant",
|
|
17653
16923
|
content: isError ? `\u274C Error:
|
|
17654
16924
|
${output}` : output.trim() || "(no output)",
|
|
@@ -18117,7 +17387,7 @@ Keyboard Shortcuts:
|
|
|
18117
17387
|
console.clear();
|
|
18118
17388
|
const model = state.session?.model || state.config?.defaultModel || "claude-sonnet";
|
|
18119
17389
|
const newSession = {
|
|
18120
|
-
id:
|
|
17390
|
+
id: uuidv413(),
|
|
18121
17391
|
name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
18122
17392
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18123
17393
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -18307,15 +17577,21 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
18307
17577
|
}
|
|
18308
17578
|
const tokenCounter2 = getTokenCounter();
|
|
18309
17579
|
const contextWindow = tokenCounter2.getContextWindow(state.session.model, state.availableModels);
|
|
18310
|
-
const corePromptTokens = tokenCounter2.countTokens(buildCoreSystemPrompt(
|
|
17580
|
+
const corePromptTokens = tokenCounter2.countTokens(buildCoreSystemPrompt());
|
|
18311
17581
|
const projectContextTokens = state.contextContent ? tokenCounter2.countTokens(state.contextContent) : 0;
|
|
18312
17582
|
const commands = state.customCommandStore.getAllCommands();
|
|
18313
17583
|
const skillsSection = buildSkillsPromptSection(commands);
|
|
18314
17584
|
const skillsTokens = skillsSection ? tokenCounter2.countTokens(skillsSection) : 0;
|
|
17585
|
+
const agentDirectoryTokens = state.agentStore ? tokenCounter2.countTokens(state.agentStore.getDirectoryContext()) : 0;
|
|
18315
17586
|
const mcpTools = state.mcpManager?.getTools() || [];
|
|
18316
17587
|
const mcpToolsTokens = tokenCounter2.countToolSchemaTokens(mcpTools);
|
|
18317
17588
|
const mcpToolCount = state.mcpManager?.getToolCount() || [];
|
|
18318
|
-
const systemPrompt = buildCoreSystemPrompt(
|
|
17589
|
+
const systemPrompt = buildCoreSystemPrompt({
|
|
17590
|
+
contextContent: state.contextContent,
|
|
17591
|
+
agentStore: state.agentStore || void 0,
|
|
17592
|
+
customCommands: commands,
|
|
17593
|
+
enableSkillTool: state.config?.preferences.enableSkillTool !== false
|
|
17594
|
+
});
|
|
18319
17595
|
const usage = tokenCounter2.countSessionTokens(state.session, systemPrompt);
|
|
18320
17596
|
const totalWithTools = usage.totalTokens + mcpToolsTokens;
|
|
18321
17597
|
const usagePercent = totalWithTools / contextWindow * 100;
|
|
@@ -18334,6 +17610,10 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
18334
17610
|
if (commands.length > 0) {
|
|
18335
17611
|
console.log(` Skills Section: ${skillsTokens.toLocaleString()} tokens (${commands.length} skills)`);
|
|
18336
17612
|
}
|
|
17613
|
+
if (agentDirectoryTokens > 0) {
|
|
17614
|
+
const agentCount = state.agentStore?.getAgentCount() || 0;
|
|
17615
|
+
console.log(` Agent Directory: ${agentDirectoryTokens.toLocaleString()} tokens (${agentCount} agents)`);
|
|
17616
|
+
}
|
|
18337
17617
|
if (mcpTools.length > 0) {
|
|
18338
17618
|
console.log("\nMCP Tools:");
|
|
18339
17619
|
console.log(` Total: ${mcpToolsTokens.toLocaleString()} tokens (${mcpTools.length} tools)`);
|
|
@@ -18612,9 +17892,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
|
|
|
18612
17892
|
return { ...prev, config: updatedConfig };
|
|
18613
17893
|
});
|
|
18614
17894
|
if (modelChanged && state.agent) {
|
|
18615
|
-
const
|
|
18616
|
-
if (
|
|
18617
|
-
|
|
17895
|
+
const backend = state.agent.context.llm;
|
|
17896
|
+
if (backend) {
|
|
17897
|
+
backend.currentModel = updatedConfig.defaultModel;
|
|
18618
17898
|
}
|
|
18619
17899
|
}
|
|
18620
17900
|
};
|