@nomad-e/bluma-cli 0.1.58 → 0.1.59
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 +2 -2
- package/dist/config/native_tools.json +3 -3
- package/dist/config/skills/git-pr/SKILL.md +1 -1
- package/dist/config/skills/pdf/SKILL.md +153 -22
- package/dist/config/skills/pdf/scripts/__pycache__/create_report.cpython-312.pyc +0 -0
- package/dist/config/skills/pdf/scripts/create_report.py +607 -209
- package/dist/config/skills/pdf/scripts/merge_pdfs.py +1 -1
- package/dist/config/skills/skill-creator/SKILL.md +1 -1
- package/dist/main.js +59 -6
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ Merge multiple PDF files into a single output PDF.
|
|
|
3
3
|
|
|
4
4
|
Usage:
|
|
5
5
|
python merge_pdfs.py --output merged.pdf file1.pdf file2.pdf file3.pdf
|
|
6
|
-
python merge_pdfs.py --output
|
|
6
|
+
python merge_pdfs.py --output ./.bluma/artifacts/combined.pdf *.pdf
|
|
7
7
|
"""
|
|
8
8
|
import argparse
|
|
9
9
|
import sys
|
|
@@ -193,7 +193,7 @@ Example script header:
|
|
|
193
193
|
{description of what this script does}
|
|
194
194
|
|
|
195
195
|
Usage:
|
|
196
|
-
python {script_name}.py --input data.csv --output
|
|
196
|
+
python {script_name}.py --input data.csv --output ./.bluma/artifacts/result.pdf
|
|
197
197
|
"""
|
|
198
198
|
import argparse
|
|
199
199
|
```
|
package/dist/main.js
CHANGED
|
@@ -113,6 +113,20 @@ function isPathInsideWorkspace(targetPath, policy = getSandboxPolicy()) {
|
|
|
113
113
|
const relative = path6.relative(policy.workspaceRoot, resolved);
|
|
114
114
|
return relative === "" || !relative.startsWith("..") && !path6.isAbsolute(relative);
|
|
115
115
|
}
|
|
116
|
+
function redirectTopLevelArtifactsPath(resolvedAbsolute, workspaceRoot) {
|
|
117
|
+
const wr = path6.resolve(workspaceRoot);
|
|
118
|
+
const abs = path6.resolve(resolvedAbsolute);
|
|
119
|
+
const rel = path6.relative(wr, abs);
|
|
120
|
+
if (rel.startsWith("..") || path6.isAbsolute(rel)) {
|
|
121
|
+
return abs;
|
|
122
|
+
}
|
|
123
|
+
const segments = rel.split(path6.sep).filter((s) => s.length > 0);
|
|
124
|
+
if (segments.length === 0 || segments[0] !== "artifacts") {
|
|
125
|
+
return abs;
|
|
126
|
+
}
|
|
127
|
+
const tail = segments.slice(1);
|
|
128
|
+
return tail.length > 0 ? path6.join(wr, ".bluma", "artifacts", ...tail) : path6.join(wr, ".bluma", "artifacts");
|
|
129
|
+
}
|
|
116
130
|
function resolveWorkspacePath(inputPath, policy = getSandboxPolicy()) {
|
|
117
131
|
const candidate = path6.isAbsolute(inputPath) ? path6.resolve(inputPath) : path6.resolve(policy.workspaceRoot, inputPath);
|
|
118
132
|
if (policy.isSandbox && !isPathInsideWorkspace(candidate, policy)) {
|
|
@@ -120,7 +134,7 @@ function resolveWorkspacePath(inputPath, policy = getSandboxPolicy()) {
|
|
|
120
134
|
`Path "${inputPath}" escapes the sandbox workspace root ${policy.workspaceRoot}`
|
|
121
135
|
);
|
|
122
136
|
}
|
|
123
|
-
return candidate;
|
|
137
|
+
return redirectTopLevelArtifactsPath(candidate, policy.workspaceRoot);
|
|
124
138
|
}
|
|
125
139
|
function resolveCommandCwd(cwd, policy = getSandboxPolicy()) {
|
|
126
140
|
const base = cwd ? path6.resolve(cwd) : policy.workspaceRoot;
|
|
@@ -8519,10 +8533,16 @@ var AdvancedFeedbackSystem = class {
|
|
|
8519
8533
|
score: penalty,
|
|
8520
8534
|
message: "You are attempting a direct message without a tool_call. All replies must contain tool_call.",
|
|
8521
8535
|
correction: `
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8536
|
+
## PROTOCOL VIOLATION \u2014 STOP WRITING PLAIN ASSISTANT TEXT
|
|
8537
|
+
|
|
8538
|
+
You streamed or returned **user-visible markdown as assistant content** instead of using the **\`message\` tool**. That is prohibited and **does not end the turn** \u2014 the runtime will loop until timeout.
|
|
8539
|
+
|
|
8540
|
+
Do this **immediately** in your next step (single tool call, no prose outside tools):
|
|
8541
|
+
|
|
8542
|
+
- Call **\`message\`** with **\`message_type\`: \`"result"\`**, put the user-facing summary in **\`content\`**, and put deliverable paths in **\`attachments\`** (absolute paths).
|
|
8543
|
+
|
|
8544
|
+
Do **not** repeat the same summary as plain assistant text again.
|
|
8545
|
+
PENALTY APPLIED: ${penalty.toFixed(1)} points deducted.
|
|
8526
8546
|
`.trim()
|
|
8527
8547
|
};
|
|
8528
8548
|
}
|
|
@@ -9945,6 +9965,7 @@ The \\\`message\\\` tool has TWO types \u2014 use them CORRECTLY:
|
|
|
9945
9965
|
- **Use when**: Task is complete, artifacts ready for delivery
|
|
9946
9966
|
- **Use ONCE per turn** \u2014 only at the very end
|
|
9947
9967
|
- **Ends the turn** \u2014 agent waits for next input
|
|
9968
|
+
- **CRITICAL:** Plain assistant markdown (streaming or not) **does not** end the worker or close the HTTP job \u2014 only a \\\`message\\\` tool call with \\\`message_type: "result"\\\` does. If you only write text in chat, the process loops until **timeout** (e.g. 300s).
|
|
9948
9969
|
|
|
9949
9970
|
#### \u274C WRONG: Using "info" to ask questions
|
|
9950
9971
|
\\\`\\\`\\\`typescript
|
|
@@ -10063,6 +10084,7 @@ You (Bluma):
|
|
|
10063
10084
|
|
|
10064
10085
|
- **Sandbox is safe** - You can't break the host system
|
|
10065
10086
|
- **But workspace matters** - Don't pollute /workspace with junk files
|
|
10087
|
+
- **Deliverables path** - Never use a top-level \`./artifacts/\` folder in the job root; use \`./.bluma/artifacts/\` (or the \`artifacts_dir\` from \`task_boundary\`). Shell redirects must use that path \u2014 \`file_write\` remaps \`artifacts/...\` to \`.bluma/artifacts/...\` automatically.
|
|
10066
10088
|
- **Clean up after yourself** - Remove temporary files when done
|
|
10067
10089
|
- **Respect session boundaries** - Stay in your session workspace
|
|
10068
10090
|
|
|
@@ -10288,6 +10310,10 @@ Auto-generated map (may be stale after pull/install). Confirm with tools before
|
|
|
10288
10310
|
<<<BLUMA_WORKSPACE_SNAPSHOT_BODY>>>
|
|
10289
10311
|
</workspace_snapshot>
|
|
10290
10312
|
|
|
10313
|
+
<deliverables>
|
|
10314
|
+
**Local and sandbox:** generated artifacts (reports, PDFs, exports, plans you attach) must live under \`<workdir>/.bluma/\` \u2014 use \`.bluma/artifacts/\` (or the \`artifacts_dir\` path returned by \`task_boundary\` after starting a task). Do **not** create a top-level \`./artifacts/\` folder in the project root. \`file_write\` / \`edit_tool\` / \`read_file_lines\` automatically remap \`artifacts/...\` \u2192 \`.bluma/artifacts/...\`. For \`shell_command\` redirects (\`>\` / \`>>\`), target \`.bluma/artifacts/...\` explicitly.
|
|
10315
|
+
</deliverables>
|
|
10316
|
+
|
|
10291
10317
|
<coding_memory>
|
|
10292
10318
|
Persistent store (~/.bluma/coding_memory.json). Do not invent entries: \`list\` / \`search\` if unsure. \`<coding_memory_snapshot>\` is bootstrap only \u2014 after add/update/remove, list or search again. Operations: add | list | search | update (id) | remove (id), one mutating call at a time.
|
|
10293
10319
|
</coding_memory>
|
|
@@ -10313,7 +10339,7 @@ Output is truncated (~30KB / ~200 lines); use head/tail or write to a file. Use
|
|
|
10313
10339
|
The user **only** sees chat content you send through the \`message\` tool (\`content\` as Markdown). Bare assistant text is **not** a substitute \u2014 **you should use \`message\` liberally**.
|
|
10314
10340
|
|
|
10315
10341
|
**Types**
|
|
10316
|
-
- \`message_type: "result"\` \u2014 **ends the turn**: final answer, deliverable, or a **question** that needs a user reply; then the agent waits for the user.
|
|
10342
|
+
- \`message_type: "result"\` \u2014 **ends the turn**: final answer, deliverable, or a **question** that needs a user reply; then the agent waits for the user. **Sandbox/worker:** only this stops the job; writing markdown as normal assistant output does **not** finish the task and can cause a **timeout loop**.
|
|
10317
10343
|
- \`message_type: "info"\` \u2014 **non-terminal**: shown in chat, does **not** end the turn. **Expected behavior:** call \`info\` **multiple times** in a single turn whenever there is something worth saying (even briefly). Under-using \`info\` is a **mistake** in this product.
|
|
10318
10344
|
|
|
10319
10345
|
**\u26A0\uFE0F CRITICAL: "info" is for INFORMATION ONLY \u2014 NEVER for asking questions**
|
|
@@ -11449,6 +11475,8 @@ var BluMaAgent = class {
|
|
|
11449
11475
|
factorRouterTurnClosed = false;
|
|
11450
11476
|
/** Passos seguidos sem tool_calls nem texto visível (só raciocínio) — evita loop lento no mesmo turno. */
|
|
11451
11477
|
emptyAssistantReplySteps = 0;
|
|
11478
|
+
/** Passos seguidos com texto do assistente sem tool_calls (violação de protocolo) — evita loop até timeout do job. */
|
|
11479
|
+
directTextProtocolSteps = 0;
|
|
11452
11480
|
constructor(sessionId, eventBus, llm, mcpClient, feedbackSystem) {
|
|
11453
11481
|
this.sessionId = sessionId;
|
|
11454
11482
|
this.eventBus = eventBus;
|
|
@@ -11592,6 +11620,7 @@ var BluMaAgent = class {
|
|
|
11592
11620
|
const userContent = buildUserMessageContent(inputText, process.cwd());
|
|
11593
11621
|
this.history.push({ role: "user", content: userContent });
|
|
11594
11622
|
this.emptyAssistantReplySteps = 0;
|
|
11623
|
+
this.directTextProtocolSteps = 0;
|
|
11595
11624
|
this.eventBus.emit(
|
|
11596
11625
|
"backend_message",
|
|
11597
11626
|
buildTurnStartBackendMessage({
|
|
@@ -12149,6 +12178,7 @@ ${editData.error.display}`;
|
|
|
12149
12178
|
this.history.push(normalizedMessage);
|
|
12150
12179
|
if (normalizedMessage.tool_calls && normalizedMessage.tool_calls.length > 0) {
|
|
12151
12180
|
this.emptyAssistantReplySteps = 0;
|
|
12181
|
+
this.directTextProtocolSteps = 0;
|
|
12152
12182
|
const validToolCalls = normalizedMessage.tool_calls.filter(
|
|
12153
12183
|
(call) => ToolCallNormalizer.isValidToolCall(call)
|
|
12154
12184
|
);
|
|
@@ -12188,9 +12218,20 @@ ${editData.error.display}`;
|
|
|
12188
12218
|
}
|
|
12189
12219
|
} else if (trimmedText) {
|
|
12190
12220
|
this.emptyAssistantReplySteps = 0;
|
|
12221
|
+
this.directTextProtocolSteps += 1;
|
|
12222
|
+
const MAX_DIRECT_TEXT_PROTOCOL = 3;
|
|
12191
12223
|
if (!hasEmittedStart) {
|
|
12192
12224
|
this.eventBus.emit("backend_message", { type: "assistant_message", content: accumulatedContent });
|
|
12193
12225
|
}
|
|
12226
|
+
if (this.directTextProtocolSteps >= MAX_DIRECT_TEXT_PROTOCOL) {
|
|
12227
|
+
this.eventBus.emit("backend_message", {
|
|
12228
|
+
type: "error",
|
|
12229
|
+
message: 'Agent kept answering with plain assistant text instead of the `message` tool with message_type "result". Turn forcibly closed to avoid job timeout; fix prompts or model routing.'
|
|
12230
|
+
});
|
|
12231
|
+
await this.notifyFactorTurnEndIfNeeded("protocol_direct_text_exhausted");
|
|
12232
|
+
this.emitTurnCompleted();
|
|
12233
|
+
return;
|
|
12234
|
+
}
|
|
12194
12235
|
const feedback = this.feedbackSystem.generateFeedback({
|
|
12195
12236
|
event: "protocol_violation_direct_text",
|
|
12196
12237
|
details: { violationContent: accumulatedContent }
|
|
@@ -12226,6 +12267,7 @@ ${editData.error.display}`;
|
|
|
12226
12267
|
this.history.push(message2);
|
|
12227
12268
|
if (message2.tool_calls && message2.tool_calls.length > 0) {
|
|
12228
12269
|
this.emptyAssistantReplySteps = 0;
|
|
12270
|
+
this.directTextProtocolSteps = 0;
|
|
12229
12271
|
const validToolCalls = message2.tool_calls.filter(
|
|
12230
12272
|
(call) => ToolCallNormalizer.isValidToolCall(call)
|
|
12231
12273
|
);
|
|
@@ -12265,7 +12307,18 @@ ${editData.error.display}`;
|
|
|
12265
12307
|
}
|
|
12266
12308
|
} else if (typeof message2.content === "string" && message2.content.trim()) {
|
|
12267
12309
|
this.emptyAssistantReplySteps = 0;
|
|
12310
|
+
this.directTextProtocolSteps += 1;
|
|
12311
|
+
const MAX_DIRECT_TEXT_PROTOCOL = 3;
|
|
12268
12312
|
this.eventBus.emit("backend_message", { type: "assistant_message", content: message2.content });
|
|
12313
|
+
if (this.directTextProtocolSteps >= MAX_DIRECT_TEXT_PROTOCOL) {
|
|
12314
|
+
this.eventBus.emit("backend_message", {
|
|
12315
|
+
type: "error",
|
|
12316
|
+
message: 'Agent kept answering with plain assistant text instead of the `message` tool with message_type "result". Turn forcibly closed to avoid job timeout.'
|
|
12317
|
+
});
|
|
12318
|
+
await this.notifyFactorTurnEndIfNeeded("protocol_direct_text_exhausted");
|
|
12319
|
+
this.emitTurnCompleted();
|
|
12320
|
+
return;
|
|
12321
|
+
}
|
|
12269
12322
|
const feedback = this.feedbackSystem.generateFeedback({
|
|
12270
12323
|
event: "protocol_violation_direct_text",
|
|
12271
12324
|
details: { violationContent: message2.content }
|