@nomad-e/bluma-cli 0.1.14 → 0.1.17
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/README.md +160 -0
- package/dist/config/models_config.json +78 -0
- package/dist/config/native_tools.json +33 -0
- package/dist/main.js +300 -69
- package/dist/skills/git-conventional/LICENSE.txt +3 -0
- package/dist/skills/git-conventional/SKILL.md +83 -0
- package/dist/skills/skill-creator/SKILL.md +495 -0
- package/dist/skills/testing/LICENSE.txt +3 -0
- package/dist/skills/testing/SKILL.md +114 -0
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -331,6 +331,7 @@ var init_async_command = __esm({
|
|
|
331
331
|
import React11 from "react";
|
|
332
332
|
import { render } from "ink";
|
|
333
333
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
334
|
+
import fs14 from "fs";
|
|
334
335
|
import { v4 as uuidv43 } from "uuid";
|
|
335
336
|
|
|
336
337
|
// src/app/ui/App.tsx
|
|
@@ -342,7 +343,7 @@ import { Box, Text } from "ink";
|
|
|
342
343
|
import { memo } from "react";
|
|
343
344
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
344
345
|
var HeaderComponent = ({
|
|
345
|
-
sessionId
|
|
346
|
+
sessionId,
|
|
346
347
|
workdir
|
|
347
348
|
}) => {
|
|
348
349
|
const dirName = workdir.split("/").pop() || workdir;
|
|
@@ -353,13 +354,13 @@ var HeaderComponent = ({
|
|
|
353
354
|
/* @__PURE__ */ jsx(Text, { color: "cyan", children: dirName }),
|
|
354
355
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " | " }),
|
|
355
356
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "session " }),
|
|
356
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children:
|
|
357
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: sessionId.slice(0, 8) })
|
|
357
358
|
] })
|
|
358
359
|
] });
|
|
359
360
|
};
|
|
360
361
|
var Header = memo(HeaderComponent);
|
|
361
362
|
var SessionInfoComponent = ({
|
|
362
|
-
sessionId
|
|
363
|
+
sessionId,
|
|
363
364
|
workdir,
|
|
364
365
|
toolsCount,
|
|
365
366
|
mcpStatus
|
|
@@ -2934,8 +2935,8 @@ async function getArtifactsDir() {
|
|
|
2934
2935
|
if (artifactsDir) return artifactsDir;
|
|
2935
2936
|
const homeDir = os3.homedir();
|
|
2936
2937
|
const baseDir = path9.join(homeDir, ".bluma", "artifacts");
|
|
2937
|
-
const
|
|
2938
|
-
artifactsDir = path9.join(baseDir,
|
|
2938
|
+
const sessionId = Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
|
|
2939
|
+
artifactsDir = path9.join(baseDir, sessionId);
|
|
2939
2940
|
await fs7.mkdir(artifactsDir, { recursive: true });
|
|
2940
2941
|
return artifactsDir;
|
|
2941
2942
|
}
|
|
@@ -3482,9 +3483,9 @@ var MCPClient = class {
|
|
|
3482
3483
|
nativeToolInvoker;
|
|
3483
3484
|
eventBus;
|
|
3484
3485
|
// <<< ADICIONA A PROPRIEDADE
|
|
3485
|
-
constructor(nativeToolInvoker,
|
|
3486
|
+
constructor(nativeToolInvoker, eventBus) {
|
|
3486
3487
|
this.nativeToolInvoker = nativeToolInvoker;
|
|
3487
|
-
this.eventBus =
|
|
3488
|
+
this.eventBus = eventBus;
|
|
3488
3489
|
}
|
|
3489
3490
|
// ... (método initialize inalterado) ...
|
|
3490
3491
|
async initialize() {
|
|
@@ -3762,9 +3763,9 @@ async function ensureSessionDir() {
|
|
|
3762
3763
|
await fs10.mkdir(sessionDir, { recursive: true });
|
|
3763
3764
|
return sessionDir;
|
|
3764
3765
|
}
|
|
3765
|
-
async function loadOrcreateSession(
|
|
3766
|
+
async function loadOrcreateSession(sessionId) {
|
|
3766
3767
|
const sessionDir = await ensureSessionDir();
|
|
3767
|
-
const sessionFile = path12.join(sessionDir, `${
|
|
3768
|
+
const sessionFile = path12.join(sessionDir, `${sessionId}.json`);
|
|
3768
3769
|
try {
|
|
3769
3770
|
await fs10.access(sessionFile);
|
|
3770
3771
|
const fileContent = await fs10.readFile(sessionFile, "utf-8");
|
|
@@ -3772,7 +3773,7 @@ async function loadOrcreateSession(sessionId2) {
|
|
|
3772
3773
|
return [sessionFile, [], []];
|
|
3773
3774
|
} catch (error) {
|
|
3774
3775
|
const newSessionData = {
|
|
3775
|
-
session_id:
|
|
3776
|
+
session_id: sessionId,
|
|
3776
3777
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3777
3778
|
conversation_history: []
|
|
3778
3779
|
};
|
|
@@ -3800,9 +3801,9 @@ async function doSaveSessionHistory(sessionFile, history) {
|
|
|
3800
3801
|
console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
|
|
3801
3802
|
}
|
|
3802
3803
|
}
|
|
3803
|
-
const
|
|
3804
|
+
const sessionId = path12.basename(sessionFile, ".json");
|
|
3804
3805
|
sessionData = {
|
|
3805
|
-
session_id:
|
|
3806
|
+
session_id: sessionId,
|
|
3806
3807
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3807
3808
|
conversation_history: []
|
|
3808
3809
|
};
|
|
@@ -4414,6 +4415,68 @@ You communicate because you respect your teammate.
|
|
|
4414
4415
|
Let's build something great, {username}.
|
|
4415
4416
|
</personality>
|
|
4416
4417
|
`;
|
|
4418
|
+
var SANDBOX_PROMPT_SUFFIX = `
|
|
4419
|
+
|
|
4420
|
+
---
|
|
4421
|
+
|
|
4422
|
+
<sandbox_context>
|
|
4423
|
+
## Sandbox Context
|
|
4424
|
+
|
|
4425
|
+
Sandbox Name: {sandbox_name}
|
|
4426
|
+
|
|
4427
|
+
You are running INSIDE an orchestrated sandbox / API container.
|
|
4428
|
+
|
|
4429
|
+
In this mode:
|
|
4430
|
+
|
|
4431
|
+
- You are NOT talking directly to a human; all inputs come from JSON payloads provided by an orchestrator (the Sandbox API).
|
|
4432
|
+
- You MUST avoid interactive flows (no REPL, no prompts that wait for human input, no TUI/CLI menus).
|
|
4433
|
+
- You MUST keep all outputs deterministic, concise and structured so that external systems can log and replay your reasoning.
|
|
4434
|
+
|
|
4435
|
+
### Execution Capabilities (Python-only)
|
|
4436
|
+
|
|
4437
|
+
- You are allowed to:
|
|
4438
|
+
- Generate and modify **Python code** (modules, scripts, notebooks, tests).
|
|
4439
|
+
- Propose and run **Python commands only**, e.g.:
|
|
4440
|
+
- \`python main.py\`
|
|
4441
|
+
- \`python -m pytest\`
|
|
4442
|
+
- Use the existing Python environment and preinstalled libraries inside the sandbox (e.g. pandas and other whitelisted packages).
|
|
4443
|
+
|
|
4444
|
+
- You are NOT allowed to:
|
|
4445
|
+
- Execute arbitrary shell commands (\`bash\`, \`sh\`, \`zsh\`, \`fish\`, \`cmd\`, \`powershell\`).
|
|
4446
|
+
- Run system-level tools (\`docker\`, \`npm\`, \`node\`, \`git\`, \`curl\`, \`wget\`, package managers, etc.).
|
|
4447
|
+
- Change global system configuration, users, permissions, or network settings.
|
|
4448
|
+
- Depend on interactive stdin/stdout behavior (no \`input()\`, no click/typer prompts).
|
|
4449
|
+
|
|
4450
|
+
### Filesystem & IO
|
|
4451
|
+
|
|
4452
|
+
- Assume you are working in a **project directory managed by the orchestrator**.
|
|
4453
|
+
- You MAY:
|
|
4454
|
+
- Read and write project files (source, tests, configs) as requested by the job.
|
|
4455
|
+
- Create temporary Python files or modules needed to execute the job.
|
|
4456
|
+
- You MUST NOT:
|
|
4457
|
+
- Access files outside the project directory tree.
|
|
4458
|
+
- Store secrets or credentials in code or logs.
|
|
4459
|
+
- Rely on long-lived state: each job is independent and may run in a fresh environment.
|
|
4460
|
+
|
|
4461
|
+
### Logging & Observability
|
|
4462
|
+
|
|
4463
|
+
- Treat every step as being logged and parsed by the orchestrator.
|
|
4464
|
+
- Prefer **structured, step-wise logs** (JSON lines) over free-form prose when emitting tool logs:
|
|
4465
|
+
- Each log entry SHOULD include at least: \`event_type\`, \`level\`, \`message\`, \`timestamp\`, and optional \`data\`.
|
|
4466
|
+
- Final results MUST be clearly separated from intermediate logs, using a dedicated \`"result"\` event when appropriate.
|
|
4467
|
+
|
|
4468
|
+
### Security & Privacy (CRITICAL)
|
|
4469
|
+
|
|
4470
|
+
- You MUST treat all environment variables, API keys, tokens and credentials as **sensitive**.
|
|
4471
|
+
- You MUST NEVER:
|
|
4472
|
+
- Run commands whose primary purpose is to dump or enumerate environment variables (e.g. \`env\`, \`set\`, \`print(os.environ)\`, or equivalents).
|
|
4473
|
+
- Expose the values of any variables matching patterns like \`*_KEY\`, \`*_TOKEN\`, \`*_SECRET\` or similar.
|
|
4474
|
+
- Print full raw environment listings (PATH, HOSTNAME, PORT, etc.) unless **explicitly** allowed by the sandbox specification and strictly necessary.
|
|
4475
|
+
- If the user explicitly asks for environment details or secrets, you MUST explain that you **cannot** reveal them and instead describe capabilities at a high level (e.g. "I can access an LLM via an external API" instead of showing keys/URLs).
|
|
4476
|
+
|
|
4477
|
+
In summary: in sandbox mode you are a Python-focused, non-interactive, deterministic agent. You generate and execute Python code inside a controlled environment, and all interactions are mediated by JSON payloads and structured logs, while strictly protecting environment variables and secrets from disclosure.
|
|
4478
|
+
</sandbox_context>
|
|
4479
|
+
`;
|
|
4417
4480
|
function getUnifiedSystemPrompt(availableSkills) {
|
|
4418
4481
|
const cwd = process.cwd();
|
|
4419
4482
|
const env = {
|
|
@@ -4432,11 +4495,14 @@ function getUnifiedSystemPrompt(availableSkills) {
|
|
|
4432
4495
|
package_manager: getPackageManager(cwd),
|
|
4433
4496
|
project_type: getProjectType(cwd),
|
|
4434
4497
|
test_framework: getTestFramework(cwd),
|
|
4435
|
-
test_command: getTestCommand(cwd)
|
|
4498
|
+
test_command: getTestCommand(cwd),
|
|
4499
|
+
sandbox_mode: process.env.BLUMA_SANDBOX === "true" ? "yes" : "no",
|
|
4500
|
+
sandbox_name: process.env.BLUMA_SANDBOX_NAME || "local"
|
|
4436
4501
|
};
|
|
4502
|
+
const basePrompt = env.sandbox_mode === "yes" ? SYSTEM_PROMPT + SANDBOX_PROMPT_SUFFIX : SYSTEM_PROMPT;
|
|
4437
4503
|
let prompt = Object.entries(env).reduce(
|
|
4438
4504
|
(p, [key, value]) => p.replaceAll(`{${key}}`, value),
|
|
4439
|
-
|
|
4505
|
+
basePrompt
|
|
4440
4506
|
);
|
|
4441
4507
|
if (availableSkills && availableSkills.length > 0) {
|
|
4442
4508
|
const skillsList = availableSkills.map((s) => `- ${s.name}: ${s.description}`).join("\n");
|
|
@@ -4825,9 +4891,9 @@ var BluMaAgent = class {
|
|
|
4825
4891
|
skillLoader;
|
|
4826
4892
|
maxContextTurns = 5;
|
|
4827
4893
|
isInterrupted = false;
|
|
4828
|
-
constructor(
|
|
4829
|
-
this.sessionId =
|
|
4830
|
-
this.eventBus =
|
|
4894
|
+
constructor(sessionId, eventBus, llm, model, mcpClient, feedbackSystem) {
|
|
4895
|
+
this.sessionId = sessionId;
|
|
4896
|
+
this.eventBus = eventBus;
|
|
4831
4897
|
this.llm = llm;
|
|
4832
4898
|
this.model = model;
|
|
4833
4899
|
this.mcpClient = mcpClient;
|
|
@@ -5068,7 +5134,7 @@ ${editData.error.display}`;
|
|
|
5068
5134
|
messages: contextWindow,
|
|
5069
5135
|
temperature: 0,
|
|
5070
5136
|
tools: this.mcpClient.getAvailableTools(),
|
|
5071
|
-
tool_choice:
|
|
5137
|
+
//tool_choice: 'required',
|
|
5072
5138
|
parallel_tool_calls: false
|
|
5073
5139
|
});
|
|
5074
5140
|
for await (const chunk of stream) {
|
|
@@ -5130,6 +5196,7 @@ ${editData.error.display}`;
|
|
|
5130
5196
|
await this._continueConversation();
|
|
5131
5197
|
return;
|
|
5132
5198
|
}
|
|
5199
|
+
const isSandbox = process.env.BLUMA_SANDBOX === "true";
|
|
5133
5200
|
const autoApprovedTools = [
|
|
5134
5201
|
"message",
|
|
5135
5202
|
"ls_tool",
|
|
@@ -5137,10 +5204,11 @@ ${editData.error.display}`;
|
|
|
5137
5204
|
"read_file_lines",
|
|
5138
5205
|
"todo",
|
|
5139
5206
|
"load_skill",
|
|
5140
|
-
"search_web"
|
|
5207
|
+
"search_web",
|
|
5208
|
+
"coding_memory"
|
|
5141
5209
|
];
|
|
5142
5210
|
const toolToCall = validToolCalls[0];
|
|
5143
|
-
const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
|
|
5211
|
+
const isSafeTool = isSandbox || autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
|
|
5144
5212
|
if (isSafeTool) {
|
|
5145
5213
|
await this.handleToolResponse({ type: "user_decision_execute", tool_calls: validToolCalls });
|
|
5146
5214
|
} else {
|
|
@@ -5159,7 +5227,6 @@ ${editData.error.display}`;
|
|
|
5159
5227
|
event: "protocol_violation_direct_text",
|
|
5160
5228
|
details: { violationContent: accumulatedContent }
|
|
5161
5229
|
});
|
|
5162
|
-
this.eventBus.emit("backend_message", { type: "protocol_violation", message: feedback.message, content: accumulatedContent });
|
|
5163
5230
|
this.history.push({ role: "system", content: feedback.correction });
|
|
5164
5231
|
await this._continueConversation();
|
|
5165
5232
|
} else {
|
|
@@ -5173,7 +5240,7 @@ ${editData.error.display}`;
|
|
|
5173
5240
|
messages: contextWindow,
|
|
5174
5241
|
temperature: 0,
|
|
5175
5242
|
tools: this.mcpClient.getAvailableTools(),
|
|
5176
|
-
tool_choice:
|
|
5243
|
+
//tool_choice: 'required',
|
|
5177
5244
|
parallel_tool_calls: false
|
|
5178
5245
|
});
|
|
5179
5246
|
if (this.isInterrupted) {
|
|
@@ -5202,6 +5269,7 @@ ${editData.error.display}`;
|
|
|
5202
5269
|
await this._continueConversation();
|
|
5203
5270
|
return;
|
|
5204
5271
|
}
|
|
5272
|
+
const isSandbox = process.env.BLUMA_SANDBOX === "true";
|
|
5205
5273
|
const autoApprovedTools = [
|
|
5206
5274
|
"message",
|
|
5207
5275
|
"ls_tool",
|
|
@@ -5209,10 +5277,11 @@ ${editData.error.display}`;
|
|
|
5209
5277
|
"read_file_lines",
|
|
5210
5278
|
"todo",
|
|
5211
5279
|
"load_skill",
|
|
5212
|
-
"search_web"
|
|
5280
|
+
"search_web",
|
|
5281
|
+
"coding_memory"
|
|
5213
5282
|
];
|
|
5214
5283
|
const toolToCall = validToolCalls[0];
|
|
5215
|
-
const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
|
|
5284
|
+
const isSafeTool = isSandbox || autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
|
|
5216
5285
|
if (isSafeTool) {
|
|
5217
5286
|
await this.handleToolResponse({ type: "user_decision_execute", tool_calls: validToolCalls });
|
|
5218
5287
|
} else {
|
|
@@ -5267,7 +5336,7 @@ var LLMService = class {
|
|
|
5267
5336
|
model: params.model || this.defaultModel,
|
|
5268
5337
|
messages: params.messages,
|
|
5269
5338
|
tools: params.tools,
|
|
5270
|
-
tool_choice: params.tool_choice,
|
|
5339
|
+
//tool_choice: params.tool_choice,
|
|
5271
5340
|
parallel_tool_calls: params.parallel_tool_calls,
|
|
5272
5341
|
temperature: params.temperature,
|
|
5273
5342
|
max_tokens: params.max_tokens
|
|
@@ -5289,7 +5358,7 @@ var LLMService = class {
|
|
|
5289
5358
|
model: params.model || this.defaultModel,
|
|
5290
5359
|
messages: params.messages,
|
|
5291
5360
|
tools: params.tools,
|
|
5292
|
-
tool_choice: params.tool_choice,
|
|
5361
|
+
//tool_choice: params.tool_choice,
|
|
5293
5362
|
parallel_tool_calls: params.parallel_tool_calls,
|
|
5294
5363
|
temperature: params.temperature,
|
|
5295
5364
|
max_tokens: params.max_tokens,
|
|
@@ -5566,8 +5635,8 @@ var BaseLLMSubAgent = class {
|
|
|
5566
5635
|
return { history: this.history };
|
|
5567
5636
|
}
|
|
5568
5637
|
async initializeHistory() {
|
|
5569
|
-
const
|
|
5570
|
-
const [sessionFile, history] = await loadOrcreateSession(
|
|
5638
|
+
const sessionId = `${this.id}`;
|
|
5639
|
+
const [sessionFile, history] = await loadOrcreateSession(sessionId);
|
|
5571
5640
|
this.sessionFile = sessionFile;
|
|
5572
5641
|
this.history = history || [];
|
|
5573
5642
|
const systemPromptContent = getInitPrompt();
|
|
@@ -5604,7 +5673,7 @@ ${editData.error.display}`;
|
|
|
5604
5673
|
model: this.ctx.policy?.llmDeployment || "default",
|
|
5605
5674
|
messages: contextWindow,
|
|
5606
5675
|
tools: this.ctx.mcpClient.getAvailableTools(),
|
|
5607
|
-
tool_choice:
|
|
5676
|
+
//tool_choice: 'required',
|
|
5608
5677
|
parallel_tool_calls: false
|
|
5609
5678
|
});
|
|
5610
5679
|
if (this.isInterrupted) {
|
|
@@ -5810,12 +5879,12 @@ var Agent = class {
|
|
|
5810
5879
|
core;
|
|
5811
5880
|
subAgents;
|
|
5812
5881
|
toolInvoker;
|
|
5813
|
-
constructor(
|
|
5814
|
-
this.sessionId =
|
|
5815
|
-
this.eventBus =
|
|
5882
|
+
constructor(sessionId, eventBus) {
|
|
5883
|
+
this.sessionId = sessionId;
|
|
5884
|
+
this.eventBus = eventBus;
|
|
5816
5885
|
const nativeToolInvoker = new ToolInvoker();
|
|
5817
5886
|
this.toolInvoker = nativeToolInvoker;
|
|
5818
|
-
this.mcpClient = new MCPClient(nativeToolInvoker,
|
|
5887
|
+
this.mcpClient = new MCPClient(nativeToolInvoker, eventBus);
|
|
5819
5888
|
this.feedbackSystem = new AdvancedFeedbackSystem();
|
|
5820
5889
|
const apiKey = process.env.NOMAD_API_KEY;
|
|
5821
5890
|
const baseUrl = process.env.NOMAD_BASE_URL;
|
|
@@ -5913,22 +5982,22 @@ var Agent = class {
|
|
|
5913
5982
|
import { useState as useState4, useEffect as useEffect4, memo as memo5 } from "react";
|
|
5914
5983
|
import { Box as Box7, Text as Text7 } from "ink";
|
|
5915
5984
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
5916
|
-
var WorkingTimerComponent = ({ eventBus
|
|
5985
|
+
var WorkingTimerComponent = ({ eventBus, taskName, taskStatus }) => {
|
|
5917
5986
|
const [currentAction, setCurrentAction] = useState4("Thinking...");
|
|
5918
5987
|
const [shinePosition, setShinePosition] = useState4(0);
|
|
5919
5988
|
const [dots, setDots] = useState4("");
|
|
5920
5989
|
useEffect4(() => {
|
|
5921
|
-
if (!
|
|
5990
|
+
if (!eventBus) return;
|
|
5922
5991
|
const handleActionStatus = (data) => {
|
|
5923
5992
|
if (data.action) {
|
|
5924
5993
|
setCurrentAction(data.action);
|
|
5925
5994
|
}
|
|
5926
5995
|
};
|
|
5927
|
-
|
|
5996
|
+
eventBus.on("action_status", handleActionStatus);
|
|
5928
5997
|
return () => {
|
|
5929
|
-
|
|
5998
|
+
eventBus.off("action_status", handleActionStatus);
|
|
5930
5999
|
};
|
|
5931
|
-
}, [
|
|
6000
|
+
}, [eventBus]);
|
|
5932
6001
|
useEffect4(() => {
|
|
5933
6002
|
const shineTimer = setInterval(() => {
|
|
5934
6003
|
setShinePosition((prev) => (prev + 1) % 30);
|
|
@@ -6262,7 +6331,7 @@ var ToolCallDisplayComponent = ({ toolName, args, preview }) => {
|
|
|
6262
6331
|
if (toolName.includes("message")) {
|
|
6263
6332
|
return null;
|
|
6264
6333
|
}
|
|
6265
|
-
const Renderer = ToolRenderDisplay[toolName] || ((
|
|
6334
|
+
const Renderer = ToolRenderDisplay[toolName] || ((props) => renderGeneric2({ ...props, toolName }));
|
|
6266
6335
|
return /* @__PURE__ */ jsx9(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsx9(Renderer, { toolName, args, preview }) });
|
|
6267
6336
|
};
|
|
6268
6337
|
var ToolCallDisplay = memo6(ToolCallDisplayComponent);
|
|
@@ -6903,7 +6972,7 @@ var ReasoningDisplay = memo9(ReasoningDisplayComponent);
|
|
|
6903
6972
|
import { useState as useState6, useEffect as useEffect5, useRef as useRef4, memo as memo10 } from "react";
|
|
6904
6973
|
import { Box as Box16, Text as Text15 } from "ink";
|
|
6905
6974
|
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
6906
|
-
var StreamingTextComponent = ({ eventBus
|
|
6975
|
+
var StreamingTextComponent = ({ eventBus, onReasoningComplete }) => {
|
|
6907
6976
|
const [reasoning, setReasoning] = useState6("");
|
|
6908
6977
|
const [isStreaming, setIsStreaming] = useState6(false);
|
|
6909
6978
|
const reasoningRef = useRef4("");
|
|
@@ -6945,15 +7014,15 @@ var StreamingTextComponent = ({ eventBus: eventBus2, onReasoningComplete }) => {
|
|
|
6945
7014
|
setReasoning("");
|
|
6946
7015
|
reasoningRef.current = "";
|
|
6947
7016
|
};
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
7017
|
+
eventBus.on("stream_start", handleStart);
|
|
7018
|
+
eventBus.on("stream_reasoning_chunk", handleReasoningChunk);
|
|
7019
|
+
eventBus.on("stream_end", handleEnd);
|
|
6951
7020
|
return () => {
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
7021
|
+
eventBus.off("stream_start", handleStart);
|
|
7022
|
+
eventBus.off("stream_reasoning_chunk", handleReasoningChunk);
|
|
7023
|
+
eventBus.off("stream_end", handleEnd);
|
|
6955
7024
|
};
|
|
6956
|
-
}, [
|
|
7025
|
+
}, [eventBus, onReasoningComplete]);
|
|
6957
7026
|
if (!isStreaming || !reasoning) {
|
|
6958
7027
|
return null;
|
|
6959
7028
|
}
|
|
@@ -6993,7 +7062,7 @@ var SAFE_AUTO_APPROVE_TOOLS = [
|
|
|
6993
7062
|
// Status de comandos (read-only)
|
|
6994
7063
|
"command_status"
|
|
6995
7064
|
];
|
|
6996
|
-
var AppComponent = ({ eventBus
|
|
7065
|
+
var AppComponent = ({ eventBus, sessionId }) => {
|
|
6997
7066
|
const agentInstance = useRef5(null);
|
|
6998
7067
|
const [history, setHistory] = useState7([]);
|
|
6999
7068
|
const [statusMessage, setStatusMessage] = useState7(
|
|
@@ -7018,7 +7087,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
|
|
|
7018
7087
|
const [toolCallCount, setToolCallCount] = useState7(0);
|
|
7019
7088
|
const handleInterrupt = useCallback2(() => {
|
|
7020
7089
|
if (!isProcessing) return;
|
|
7021
|
-
|
|
7090
|
+
eventBus.emit("user_interrupt");
|
|
7022
7091
|
setIsProcessing(false);
|
|
7023
7092
|
setHistory((prev) => [
|
|
7024
7093
|
...prev,
|
|
@@ -7027,7 +7096,7 @@ var AppComponent = ({ eventBus: eventBus2, sessionId: sessionId2 }) => {
|
|
|
7027
7096
|
component: /* @__PURE__ */ jsx17(Text16, { color: "yellow", children: "-- Task cancelled by dev. --" })
|
|
7028
7097
|
}
|
|
7029
7098
|
]);
|
|
7030
|
-
}, [isProcessing,
|
|
7099
|
+
}, [isProcessing, eventBus]);
|
|
7031
7100
|
const handleSubmit = useCallback2(
|
|
7032
7101
|
(text) => {
|
|
7033
7102
|
if (!text || isProcessing || !agentInstance.current) return;
|
|
@@ -7167,19 +7236,19 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7167
7236
|
[]
|
|
7168
7237
|
);
|
|
7169
7238
|
useEffect6(() => {
|
|
7170
|
-
setHistory([{ id: 0, component: /* @__PURE__ */ jsx17(Header, { sessionId
|
|
7239
|
+
setHistory([{ id: 0, component: /* @__PURE__ */ jsx17(Header, { sessionId, workdir }) }]);
|
|
7171
7240
|
const initializeAgent = async () => {
|
|
7172
7241
|
try {
|
|
7173
|
-
agentInstance.current = new Agent(
|
|
7242
|
+
agentInstance.current = new Agent(sessionId, eventBus);
|
|
7174
7243
|
await agentInstance.current.initialize();
|
|
7175
|
-
|
|
7244
|
+
eventBus.emit("backend_message", {
|
|
7176
7245
|
type: "status",
|
|
7177
7246
|
status: "mcp_connected",
|
|
7178
7247
|
tools: agentInstance.current.getAvailableTools().length
|
|
7179
7248
|
});
|
|
7180
7249
|
} catch (error) {
|
|
7181
7250
|
const errorMessage = error instanceof Error ? error.message : "Unknown error during Agent initialization.";
|
|
7182
|
-
|
|
7251
|
+
eventBus.emit("backend_message", {
|
|
7183
7252
|
type: "error",
|
|
7184
7253
|
message: errorMessage
|
|
7185
7254
|
});
|
|
@@ -7320,16 +7389,16 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7320
7389
|
}
|
|
7321
7390
|
};
|
|
7322
7391
|
const handleUiOverlay = (data) => {
|
|
7323
|
-
|
|
7392
|
+
eventBus.emit("user_overlay", data);
|
|
7324
7393
|
};
|
|
7325
7394
|
uiEventBus.on("user_overlay", handleUiOverlay);
|
|
7326
|
-
|
|
7395
|
+
eventBus.on("backend_message", handleBackendMessage);
|
|
7327
7396
|
initializeAgent();
|
|
7328
7397
|
return () => {
|
|
7329
7398
|
uiEventBus.off("user_overlay", handleUiOverlay);
|
|
7330
|
-
|
|
7399
|
+
eventBus.off("backend_message", handleBackendMessage);
|
|
7331
7400
|
};
|
|
7332
|
-
}, [
|
|
7401
|
+
}, [eventBus, sessionId, handleConfirmation]);
|
|
7333
7402
|
const renderInteractiveComponent = () => {
|
|
7334
7403
|
if (mcpStatus !== "connected") {
|
|
7335
7404
|
return;
|
|
@@ -7348,7 +7417,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7348
7417
|
);
|
|
7349
7418
|
}
|
|
7350
7419
|
return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", children: [
|
|
7351
|
-
isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx17(WorkingTimer, { eventBus
|
|
7420
|
+
isProcessing && !pendingConfirmation && /* @__PURE__ */ jsx17(WorkingTimer, { eventBus }),
|
|
7352
7421
|
/* @__PURE__ */ jsx17(
|
|
7353
7422
|
InputPrompt,
|
|
7354
7423
|
{
|
|
@@ -7365,7 +7434,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
7365
7434
|
/* @__PURE__ */ jsx17(
|
|
7366
7435
|
StreamingText,
|
|
7367
7436
|
{
|
|
7368
|
-
eventBus
|
|
7437
|
+
eventBus,
|
|
7369
7438
|
onReasoningComplete: (reasoning) => {
|
|
7370
7439
|
if (reasoning) {
|
|
7371
7440
|
setHistory((prev) => [
|
|
@@ -7441,12 +7510,174 @@ function stopTitleKeeper() {
|
|
|
7441
7510
|
}
|
|
7442
7511
|
|
|
7443
7512
|
// src/main.ts
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7513
|
+
function writeJsonl(event) {
|
|
7514
|
+
try {
|
|
7515
|
+
process.stdout.write(JSON.stringify(event) + "\n");
|
|
7516
|
+
} catch {
|
|
7517
|
+
}
|
|
7518
|
+
}
|
|
7519
|
+
async function runAgentMode() {
|
|
7520
|
+
const args = process.argv.slice(2);
|
|
7521
|
+
const inputFileIndex = args.indexOf("--input-file");
|
|
7522
|
+
const inputIndex = args.indexOf("--input");
|
|
7523
|
+
let rawPayload = "";
|
|
7524
|
+
try {
|
|
7525
|
+
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
7526
|
+
const filePath = args[inputFileIndex + 1];
|
|
7527
|
+
rawPayload = fs14.readFileSync(filePath, "utf-8");
|
|
7528
|
+
} else {
|
|
7529
|
+
rawPayload = fs14.readFileSync(0, "utf-8");
|
|
7530
|
+
}
|
|
7531
|
+
} catch (err) {
|
|
7532
|
+
writeJsonl({
|
|
7533
|
+
event_type: "result",
|
|
7534
|
+
status: "error",
|
|
7535
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7536
|
+
error: {
|
|
7537
|
+
message: "Failed to read agent payload",
|
|
7538
|
+
details: err?.message
|
|
7539
|
+
}
|
|
7540
|
+
});
|
|
7541
|
+
process.exit(1);
|
|
7542
|
+
return;
|
|
7543
|
+
}
|
|
7544
|
+
let envelope;
|
|
7545
|
+
try {
|
|
7546
|
+
envelope = JSON.parse(rawPayload);
|
|
7547
|
+
} catch (err) {
|
|
7548
|
+
writeJsonl({
|
|
7549
|
+
event_type: "result",
|
|
7550
|
+
status: "error",
|
|
7551
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7552
|
+
error: {
|
|
7553
|
+
message: "Invalid JSON payload for agent mode",
|
|
7554
|
+
details: err?.message
|
|
7555
|
+
}
|
|
7556
|
+
});
|
|
7557
|
+
process.exit(1);
|
|
7558
|
+
return;
|
|
7559
|
+
}
|
|
7560
|
+
const eventBus = new EventEmitter2();
|
|
7561
|
+
const sessionId = envelope.message_id || uuidv43();
|
|
7562
|
+
let lastAssistantMessage = null;
|
|
7563
|
+
let reasoningBuffer = null;
|
|
7564
|
+
let resultEmitted = false;
|
|
7565
|
+
eventBus.on("backend_message", (payload) => {
|
|
7566
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
7567
|
+
writeJsonl({
|
|
7568
|
+
event_type: "backend_message",
|
|
7569
|
+
backend_type: String(payload?.type || "unknown"),
|
|
7570
|
+
timestamp,
|
|
7571
|
+
payload
|
|
7572
|
+
});
|
|
7573
|
+
if (payload?.type === "assistant_message" && typeof payload.content === "string") {
|
|
7574
|
+
lastAssistantMessage = payload.content;
|
|
7575
|
+
}
|
|
7576
|
+
if (payload?.type === "reasoning" && typeof payload.content === "string") {
|
|
7577
|
+
reasoningBuffer = (reasoningBuffer || "") + payload.content;
|
|
7578
|
+
}
|
|
7579
|
+
if (payload?.type === "tool_result" && payload.tool_name === "message") {
|
|
7580
|
+
try {
|
|
7581
|
+
const rawResult = payload.result;
|
|
7582
|
+
const parsed = typeof rawResult === "string" ? JSON.parse(rawResult) : rawResult;
|
|
7583
|
+
const body = parsed?.content?.body;
|
|
7584
|
+
if (typeof body === "string") {
|
|
7585
|
+
lastAssistantMessage = body;
|
|
7586
|
+
}
|
|
7587
|
+
} catch {
|
|
7588
|
+
}
|
|
7589
|
+
}
|
|
7590
|
+
if (!resultEmitted && payload?.type === "done") {
|
|
7591
|
+
resultEmitted = true;
|
|
7592
|
+
writeJsonl({
|
|
7593
|
+
event_type: "result",
|
|
7594
|
+
status: "success",
|
|
7595
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7596
|
+
data: {
|
|
7597
|
+
message_id: envelope.message_id || sessionId,
|
|
7598
|
+
action: envelope.action || "unknown",
|
|
7599
|
+
last_assistant_message: lastAssistantMessage,
|
|
7600
|
+
reasoning: reasoningBuffer
|
|
7601
|
+
}
|
|
7602
|
+
});
|
|
7603
|
+
process.exit(0);
|
|
7604
|
+
}
|
|
7605
|
+
});
|
|
7606
|
+
eventBus.on("action_status", (payload) => {
|
|
7607
|
+
writeJsonl({
|
|
7608
|
+
event_type: "action_status",
|
|
7609
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7610
|
+
payload
|
|
7611
|
+
});
|
|
7612
|
+
});
|
|
7613
|
+
writeJsonl({
|
|
7614
|
+
event_type: "log",
|
|
7615
|
+
level: "info",
|
|
7616
|
+
message: "Starting agent mode execution",
|
|
7617
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7618
|
+
data: {
|
|
7619
|
+
message_id: envelope.message_id,
|
|
7620
|
+
action: envelope.action,
|
|
7621
|
+
from_agent: envelope.from_agent,
|
|
7622
|
+
to_agent: envelope.to_agent
|
|
7623
|
+
}
|
|
7624
|
+
});
|
|
7625
|
+
try {
|
|
7626
|
+
const agent = new Agent(sessionId, eventBus);
|
|
7627
|
+
await agent.initialize();
|
|
7628
|
+
const userContent = JSON.stringify({
|
|
7629
|
+
message_id: envelope.message_id || sessionId,
|
|
7630
|
+
from_agent: envelope.from_agent || "sandbox-api",
|
|
7631
|
+
to_agent: envelope.to_agent || "bluma",
|
|
7632
|
+
action: envelope.action || "unknown",
|
|
7633
|
+
context: envelope.context || {},
|
|
7634
|
+
metadata: envelope.metadata || {}
|
|
7635
|
+
});
|
|
7636
|
+
await agent.processTurn({ content: userContent });
|
|
7637
|
+
if (!resultEmitted) {
|
|
7638
|
+
resultEmitted = true;
|
|
7639
|
+
writeJsonl({
|
|
7640
|
+
event_type: "result",
|
|
7641
|
+
status: "success",
|
|
7642
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7643
|
+
data: {
|
|
7644
|
+
message_id: envelope.message_id || sessionId,
|
|
7645
|
+
action: envelope.action || "unknown",
|
|
7646
|
+
last_assistant_message: lastAssistantMessage,
|
|
7647
|
+
reasoning: reasoningBuffer
|
|
7648
|
+
}
|
|
7649
|
+
});
|
|
7650
|
+
process.exit(0);
|
|
7651
|
+
}
|
|
7652
|
+
} catch (err) {
|
|
7653
|
+
if (!resultEmitted) {
|
|
7654
|
+
writeJsonl({
|
|
7655
|
+
event_type: "result",
|
|
7656
|
+
status: "error",
|
|
7657
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7658
|
+
error: {
|
|
7659
|
+
message: "Agent mode execution failed",
|
|
7660
|
+
details: err?.message
|
|
7661
|
+
}
|
|
7662
|
+
});
|
|
7663
|
+
}
|
|
7664
|
+
process.exit(1);
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
function runCliMode() {
|
|
7668
|
+
const BLUMA_TITLE = process.env.BLUMA_TITLE || "BluMa - NomadEngenuity";
|
|
7669
|
+
startTitleKeeper(BLUMA_TITLE);
|
|
7670
|
+
const eventBus = new EventEmitter2();
|
|
7671
|
+
const sessionId = uuidv43();
|
|
7672
|
+
const props = {
|
|
7673
|
+
eventBus,
|
|
7674
|
+
sessionId
|
|
7675
|
+
};
|
|
7676
|
+
render(React11.createElement(App_default, props));
|
|
7677
|
+
}
|
|
7678
|
+
var argv = process.argv.slice(2);
|
|
7679
|
+
if (argv[0] === "agent") {
|
|
7680
|
+
runAgentMode();
|
|
7681
|
+
} else {
|
|
7682
|
+
runCliMode();
|
|
7683
|
+
}
|