@hamp10/agentforge 0.2.17 → 0.2.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/agentforge.js CHANGED
@@ -967,6 +967,16 @@ fi
967
967
  --disable-sync \\
968
968
  --disable-component-update \\
969
969
  --safebrowsing-disable-auto-update \\
970
+ --disable-background-networking \\
971
+ --disable-background-timer-throttling \\
972
+ --disable-backgrounding-occluded-windows \\
973
+ --disable-renderer-backgrounding \\
974
+ --disable-features=TranslateUI,BlinkGenPropertyTrees \\
975
+ --disable-ipc-flooding-protection \\
976
+ --disable-hang-monitor \\
977
+ --disable-prompt-on-repost \\
978
+ --metrics-recording-only \\
979
+ --no-pings \\
970
980
  "$@"
971
981
  `);
972
982
  fs.chmodSync(execPath, 0o755);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hamp10/agentforge",
3
- "version": "0.2.17",
3
+ "version": "0.2.19",
4
4
  "description": "AgentForge worker — connect your machine to agentforge.ai",
5
5
  "type": "module",
6
6
  "bin": {
@@ -817,7 +817,7 @@ export class OpenClawCLI extends EventEmitter {
817
817
  * Run an agent task
818
818
  * Images are saved to workspace and referenced in message for vision model analysis
819
819
  */
820
- async runAgentTask(agentId, task, workDir, sessionId = null, image = null, browserProfile = null, imageWorkDir = null, agentModel = null) {
820
+ async runAgentTask(agentId, task, workDir, sessionId = null, image = null, browserProfile = null, imageWorkDir = null, agentModel = null, customSystemPrompt = null, conversationHistory = null, allImages = null) {
821
821
  // Apply per-agent model override before running (writes to openclaw.json + signals gateway)
822
822
  if (agentModel) {
823
823
  await this.setAgentModel(agentId, agentModel);
@@ -825,7 +825,7 @@ export class OpenClawCLI extends EventEmitter {
825
825
  // ── Gateway path disabled — subprocess shows live tool activity ──────────
826
826
  // Gateway path: SSE token streaming — tokens arrive live as the model generates.
827
827
  // Dashboard buffers tokens into sentences before showing each as a complete bubble.
828
- if (!image && this.gatewayPort && this.gatewayToken) {
828
+ if (!(allImages?.length > 0 || image) && this.gatewayPort && this.gatewayToken) {
829
829
  console.log(`\n🤖 Running agent (streaming): ${agentId}`);
830
830
  console.log(` Task: ${task.slice(0, 120)}${task.length > 120 ? '…' : ''}`);
831
831
  try {
@@ -885,34 +885,49 @@ export class OpenClawCLI extends EventEmitter {
885
885
  let imagePath = null;
886
886
  let modifiedTask = task;
887
887
 
888
- // Handle image by saving to workspace
889
- if (image) {
888
+ // Handle image(s) by saving to workspace
889
+ // Build canonical list: allImages[] wins if provided, else fall back to single image
890
+ const imagesToSave = (allImages && allImages.length > 0)
891
+ ? allImages
892
+ : (image ? [image] : []);
893
+
894
+ if (imagesToSave.length > 0) {
890
895
  try {
891
896
  const fs = await import('fs/promises');
892
897
  const path = await import('path');
893
898
 
894
899
  // Use imageWorkDir (agent's actual workspace) if provided, otherwise fall back to workDir
895
900
  const imageDir = imageWorkDir || workDir;
896
-
901
+
897
902
  // Ensure workspace directory exists before saving image
898
903
  await fs.mkdir(imageDir, { recursive: true });
899
904
 
900
- // Extract base64 data (remove data:image/png;base64, prefix if present)
901
- const base64Data = image.replace(/^data:image\/\w+;base64,/, '');
902
- const buffer = Buffer.from(base64Data, 'base64');
903
-
904
- // Save to workspace with timestamp to avoid conflicts
905
+ const savedNames = [];
905
906
  const timestamp = Date.now();
906
- const imageFileName = `uploaded_image_${timestamp}.png`;
907
- imagePath = path.join(imageDir, imageFileName);
908
907
 
909
- await fs.writeFile(imagePath, buffer);
910
- console.log(` 📷 Image saved to: ${imagePath}`);
908
+ for (let i = 0; i < imagesToSave.length; i++) {
909
+ const imgData = imagesToSave[i];
910
+ // Extract base64 data (remove data:image/png;base64, prefix if present)
911
+ const base64Data = imgData.replace(/^data:image\/\w+;base64,/, '');
912
+ const buffer = Buffer.from(base64Data, 'base64');
913
+ // Use suffix for multiple images so names don't collide
914
+ const suffix = imagesToSave.length > 1 ? `_${i + 1}` : '';
915
+ const imageFileName = `uploaded_image_${timestamp}${suffix}.png`;
916
+ const imgPath = path.join(imageDir, imageFileName);
917
+ await fs.writeFile(imgPath, buffer);
918
+ console.log(` 📷 Image ${i + 1}/${imagesToSave.length} saved to: ${imgPath}`);
919
+ savedNames.push(imageFileName);
920
+ if (i === 0) imagePath = imgPath; // track first for cleanup
921
+ }
911
922
 
912
- // Modify task to reference the image
913
- modifiedTask = `${task}\n\n[There is an image file in the workspace: ${imageFileName}]`;
923
+ // Modify task to reference the image file(s)
924
+ if (savedNames.length === 1) {
925
+ modifiedTask = `${task}\n\n[There is an image file in the workspace: ${savedNames[0]}]`;
926
+ } else {
927
+ modifiedTask = `${task}\n\n[There are ${savedNames.length} image files in the workspace: ${savedNames.join(', ')}]`;
928
+ }
914
929
  } catch (error) {
915
- console.error(` ⚠️ Failed to save image: ${error.message}`);
930
+ console.error(` ⚠️ Failed to save image(s): ${error.message}`);
916
931
  }
917
932
  }
918
933
 
@@ -151,7 +151,8 @@ export async function browserAction(input) {
151
151
  const page = await getPage();
152
152
  await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
153
153
  _activePage = page;
154
- await _wait(800);
154
+ // Brief pause for initial render, then snapshot
155
+ await _wait(400);
155
156
  return await _snapshot(page);
156
157
  }
157
158
 
@@ -166,8 +167,7 @@ export async function browserAction(input) {
166
167
  }
167
168
  if (!target) return `Tab not found. Available tabs:\n${open.map((p,i) => `[${i}] ${p.url()}`).join('\n')}`;
168
169
  await target.bringToFront();
169
- _activePage = target; // update cached active page
170
- await _wait(300);
170
+ _activePage = target;
171
171
  return await _snapshot(target);
172
172
  }
173
173
 
@@ -215,8 +215,8 @@ export async function browserAction(input) {
215
215
  : `No visible element found matching "${input.text || input.selector}"`;
216
216
  }
217
217
 
218
- // Wait for page to react (animations, dynamic content, network requests)
219
- await _wait(1200);
218
+ // Brief pause for dynamic content to render
219
+ await _wait(300);
220
220
 
221
221
  // Always return a fresh snapshot after clicking so agent immediately sees what changed
222
222
  const snap = await _snapshot(page);
package/src/worker.js CHANGED
@@ -782,14 +782,16 @@ export class AgentForgeWorker extends EventEmitter {
782
782
  }
783
783
  }
784
784
 
785
- async executeTaskNow({ taskId, agentId, sessionId, message: userMessage, workDir, defaultProjectsPath, image, roomId, roomContext, isMaestro, conversationHistory, browserProfile, agentName, agentEmoji, runnerType, agentModel, customSystemPrompt }) {
785
+ async executeTaskNow({ taskId, agentId, sessionId, message: userMessage, workDir, defaultProjectsPath, image, images: extraImages, roomId, roomContext, isMaestro, conversationHistory, browserProfile, agentName, agentEmoji, runnerType, agentModel, customSystemPrompt }) {
786
+ // Build canonical images array: images[] takes priority, fall back to single image field
787
+ const allImages = extraImages && extraImages.length > 0 ? extraImages : (image ? [image] : []);
786
788
  const isMaestroTask = isMaestro || agentId === 'maestro';
787
789
  console.log(`🤖 Executing task ${taskId} for agent ${agentId}${isMaestroTask ? ' (MAESTRO)' : ''}${browserProfile ? ` [browser: ${browserProfile}]` : ''}`);
788
790
  if (sessionId) {
789
791
  console.log(` Session: ${sessionId} (resuming conversation)`);
790
792
  }
791
- if (image) {
792
- console.log(` Image: Provided`);
793
+ if (allImages.length > 0) {
794
+ console.log(` Image${allImages.length > 1 ? 's' : ''}: ${allImages.length} provided`);
793
795
  }
794
796
  if (roomId) {
795
797
  console.log(` Room: ${roomId}`);
@@ -1321,7 +1323,7 @@ export class AgentForgeWorker extends EventEmitter {
1321
1323
  console.log(`[${taskId}] 🏃 Runner: ${useHampagent ? '⚡ HAMPAGENT' : '🔧 OPENCLAW'} — agent ${agentId} iteration ${iteration}`);
1322
1324
  const runAgentStart = Date.now();
1323
1325
  taskResult = await activeRunner.runAgentTask(
1324
- agentId, iterationMessage, taskCwd, sessionId, iteration === 1 ? image : null, browserProfile, actualWorkDir, agentModel || null, customSystemPrompt || null, conversationHistory || null
1326
+ agentId, iterationMessage, taskCwd, sessionId, iteration === 1 ? (allImages[0] || null) : null, browserProfile, actualWorkDir, agentModel || null, customSystemPrompt || null, conversationHistory || null, iteration === 1 ? allImages : null
1325
1327
  );
1326
1328
  const runAgentDuration = Date.now() - runAgentStart;
1327
1329
  console.log(`[${taskId}] runAgentTask iteration ${iteration} returned after ${runAgentDuration}ms, success=${taskResult?.success}`);
@@ -1432,6 +1434,24 @@ export class AgentForgeWorker extends EventEmitter {
1432
1434
  }
1433
1435
 
1434
1436
  console.log(`[${taskId}] Sending completion message...`);
1437
+
1438
+ // ── Native macOS notification (no Chrome required) ────────────────────
1439
+ try {
1440
+ const { exec: execChild } = await import('child_process');
1441
+
1442
+ const agentLabel = (identity?.name || agentId || 'Agent')
1443
+ .replace(/\\/g, '').replace(/"/g, '').replace(/'/g, '');
1444
+ const preview = (finalOutput || 'Task complete')
1445
+ .replace(/✓\s*TASK_COMPLETE/g, '').replace(/[\r\n]+/g, ' ').trim().slice(0, 60)
1446
+ .replace(/\\/g, '').replace(/"/g, '').replace(/'/g, '');
1447
+
1448
+ // osascript is reliable and already authorized on this machine
1449
+ const script = `display notification "${preview}" with title "AgentForge" subtitle "${agentLabel}"`;
1450
+ execChild(`osascript -e '${script}'`, { timeout: 3000 }, (err) => {
1451
+ if (err) console.warn(`[${taskId}] macOS notification failed: ${err.message}`);
1452
+ });
1453
+ } catch (_) {}
1454
+
1435
1455
  this.send(completionMessage);
1436
1456
 
1437
1457
  console.log(`✅ Task ${taskId} completed (${identity.identityName})`);