@hamp10/agentforge 0.2.29 → 0.2.30

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hamp10/agentforge",
3
- "version": "0.2.29",
3
+ "version": "0.2.30",
4
4
  "description": "AgentForge worker — connect your machine to agentforge.ai",
5
5
  "type": "module",
6
6
  "bin": {
@@ -949,6 +949,21 @@ assert.match(
949
949
  /taskId,\n\s*iteration,/i,
950
950
  'direct fast path should receive taskId so UI peer context is task-scoped'
951
951
  );
952
+ assert.match(
953
+ openClawSource,
954
+ /const semanticTask = String\(directOptions\.rawUserTask \|\| task \|\| ''\);[\s\S]*_guardDirectFileWritePath\(fileWriteTarget, workDir, \{ task: semanticTask \}\)/i,
955
+ 'direct scope guards should use the raw user task, not expanded retry/platform context'
956
+ );
957
+ assert.match(
958
+ openClawSource,
959
+ /rawUserTask: rawUserTask \|\| task/i,
960
+ 'direct fast path should pass the raw task separately from the expanded runtime prompt'
961
+ );
962
+ assert.match(
963
+ workerSource,
964
+ /imageGenerationModel \|\| null,\n\s*scopeAwareUserMessage/i,
965
+ 'worker should pass the resolved raw user scope into direct agent execution'
966
+ );
952
967
  assert.match(
953
968
  openClawSource,
954
969
  /persistDirectUiContext\(\);/i,
@@ -4352,9 +4352,10 @@ export class OpenClawCLI extends EventEmitter {
4352
4352
  'For local browser verification, use the URL or port proven by project code, server output, or an already successful browser result. Do not try arbitrary localhost ports such as 3000 or 5000 just because they are common defaults.',
4353
4353
  'For git-backed projects with a remote, do not finish with intended changes only on disk. Stage the final intended changes, commit them, push to the configured upstream, and verify the resulting state unless the user explicitly asked not to. Do not create confirmation/status files just to prove the task is done.',
4354
4354
  ].join('\n');
4355
- const taskRequiresFileChange = /\b(make|create|build|add|implement|update|edit|change|fix|improve|redesign|refactor|write|generate|scaffold|wire|ship|work on|delete|remove|drop|unpublish|decommission|take down|take offline)\b/i.test(task);
4356
- const taskAllowsDeletedScopedPages = this._allowsDirectScopedPageSourcesToRemainDeleted(task);
4357
- const taskRequiresVisualVerification = !taskAllowsDeletedScopedPages && /\b(ui|ux|visual|design|frontend|css|html|pages?|dashboard|website|web app|app screen|layout|component|responsive|professional|polish(?:ed)?|vibecoded|vibe-coded|interface|screen|arena|competitive|competition|scoreboard|ranking|visual hierarchy|user experience|design system|readability|readable|legibility|contrast|accessibility)\b/i.test(task);
4355
+ const semanticTask = String(directOptions.rawUserTask || task || '');
4356
+ const taskRequiresFileChange = /\b(make|create|build|add|implement|update|edit|change|fix|improve|redesign|refactor|write|generate|scaffold|wire|ship|work on|delete|remove|drop|unpublish|decommission|take down|take offline)\b/i.test(semanticTask);
4357
+ const taskAllowsDeletedScopedPages = this._allowsDirectScopedPageSourcesToRemainDeleted(semanticTask);
4358
+ const taskRequiresVisualVerification = !taskAllowsDeletedScopedPages && /\b(ui|ux|visual|design|frontend|css|html|pages?|dashboard|website|web app|app screen|layout|component|responsive|professional|polish(?:ed)?|vibecoded|vibe-coded|interface|screen|arena|competitive|competition|scoreboard|ranking|visual hierarchy|user experience|design system|readability|readable|legibility|contrast|accessibility)\b/i.test(semanticTask);
4358
4359
  const directRequestTimeoutMs = Math.max(
4359
4360
  30_000,
4360
4361
  Number(process.env.AGENTFORGE_DIRECT_LLM_REQUEST_TIMEOUT_MS || (taskRequiresVisualVerification ? 120_000 : 90_000))
@@ -4370,7 +4371,7 @@ export class OpenClawCLI extends EventEmitter {
4370
4371
  let directMutationCount = 0;
4371
4372
  let lastCleanLocalVerificationMutationCount = 0;
4372
4373
  let lastDirectVisualWarning = '';
4373
- const explicitScopeForTask = this._extractDirectExplicitScope(task);
4374
+ const explicitScopeForTask = this._extractDirectExplicitScope(semanticTask);
4374
4375
  const explicitScopeSlugsForTask = explicitScopeForTask.slugs || [];
4375
4376
  const taskRequiresComparableUiContext =
4376
4377
  taskRequiresVisualVerification &&
@@ -4815,7 +4816,7 @@ export class OpenClawCLI extends EventEmitter {
4815
4816
  });
4816
4817
  const result = await this._runDirectTool(agentId, 'browser', { action: 'open', url }, workDir, {
4817
4818
  signal: directAbortController.signal,
4818
- task,
4819
+ task: semanticTask,
4819
4820
  imageModel: directOptions.imageModel,
4820
4821
  agentModel: directOptions.agentModel || model,
4821
4822
  fallbackVisionModels: directOptions.fallbackVisionModels,
@@ -4856,7 +4857,7 @@ export class OpenClawCLI extends EventEmitter {
4856
4857
  const match = text.match(/^URL:\s*(.+)$/mi);
4857
4858
  const urlText = match?.[1]?.trim() || '';
4858
4859
  if (!urlText) return false;
4859
- const { slugs } = this._extractDirectExplicitScope(task);
4860
+ const { slugs } = this._extractDirectExplicitScope(semanticTask);
4860
4861
  if (slugs.length > 0 && scopeSlugsMatchingText(urlText, slugs).length === 0) return false;
4861
4862
  return /^(?:https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(?::\d+)?(?:\/|$)|file:)/i.test(urlText);
4862
4863
  };
@@ -4868,7 +4869,7 @@ export class OpenClawCLI extends EventEmitter {
4868
4869
  return warnings.join('\n').slice(0, 1200);
4869
4870
  };
4870
4871
  const directStopResponse = (reason, forceIncomplete = false) => {
4871
- const pendingGitDelivery = this._directGitPendingDeliveryMessage(workDir, task, { directMutationCount, taskRequiresFileChange });
4872
+ const pendingGitDelivery = this._directGitPendingDeliveryMessage(workDir, semanticTask, { directMutationCount, taskRequiresFileChange });
4872
4873
  const noDeliverable = taskRequiresFileChange && directMutationCount === 0 && !pendingGitDelivery;
4873
4874
  const missingScopedMutation = missingScopedMutationSlugs();
4874
4875
  const missingVisualVerification = taskRequiresVisualVerification && directMutationCount > 0 && !hasCleanLocalVerificationForLatestMutation();
@@ -4955,7 +4956,7 @@ export class OpenClawCLI extends EventEmitter {
4955
4956
  usedTools: directToolCount > 0,
4956
4957
  };
4957
4958
  }
4958
- const delivery = this._directMaybeAutoDeliverGitChanges(workDir, task, { directMutationCount, taskRequiresFileChange });
4959
+ const delivery = this._directMaybeAutoDeliverGitChanges(workDir, semanticTask, { directMutationCount, taskRequiresFileChange });
4959
4960
  if (delivery.delivered) {
4960
4961
  recordDirectToolSummary('git', delivery.message);
4961
4962
  } else if (delivery.pending) {
@@ -4990,7 +4991,7 @@ export class OpenClawCLI extends EventEmitter {
4990
4991
  return `I am checking the live browser${url} to judge the actual product surface before deciding the next change.`;
4991
4992
  }
4992
4993
  if (name === 'read_file' || name === 'read') {
4993
- const scope = extractExplicitScope(task);
4994
+ const scope = extractExplicitScope(semanticTask);
4994
4995
  const targetText = String(targetPath || base || '').toLowerCase();
4995
4996
  const looksLikePageSource = /\.(html?|css|s[ac]ss|jsx?|tsx?|vue|svelte|astro|mdx?)$/i.test(targetText);
4996
4997
  const isNamedTarget = scope.slugs.length > 0 && scopeSlugsMatchingText(targetText, scope.slugs).length > 0;
@@ -5073,7 +5074,7 @@ export class OpenClawCLI extends EventEmitter {
5073
5074
  const text = parts.filter(p => p.text).map(p => p.text).join('');
5074
5075
  if (!functionCalls.length) {
5075
5076
  if (step > 0) {
5076
- const pendingGitDelivery = this._directGitPendingDeliveryMessage(workDir, task, { directMutationCount, taskRequiresFileChange });
5077
+ const pendingGitDelivery = this._directGitPendingDeliveryMessage(workDir, semanticTask, { directMutationCount, taskRequiresFileChange });
5077
5078
  if (taskRequiresFileChange && directMutationCount === 0 && !pendingGitDelivery && directInternalNudgeCount < 2) {
5078
5079
  directInternalNudgeCount += 1;
5079
5080
  contents.push(content);
@@ -5215,7 +5216,7 @@ export class OpenClawCLI extends EventEmitter {
5215
5216
  const fileWriteTarget = directFileWriteTargetPath(name, args);
5216
5217
  if (fileWriteTarget) {
5217
5218
  try {
5218
- this._guardDirectFileWritePath(fileWriteTarget, workDir, { task });
5219
+ this._guardDirectFileWritePath(fileWriteTarget, workDir, { task: semanticTask });
5219
5220
  } catch (err) {
5220
5221
  if (err.code === 'AGENTFORGE_SCOPE_VIOLATION') {
5221
5222
  directScopeViolationCount += 1;
@@ -5270,7 +5271,7 @@ export class OpenClawCLI extends EventEmitter {
5270
5271
  responses.push({ functionResponse: { name, response: { error: message } } });
5271
5272
  continue;
5272
5273
  }
5273
- const dirtyDeliveryMessage = this._directGitDirtyDeliveryMessage(workDir, task, command);
5274
+ const dirtyDeliveryMessage = this._directGitDirtyDeliveryMessage(workDir, semanticTask, command);
5274
5275
  if (/\bgit\b[\s\S]*\b(?:commit|push)\b/i.test(command) && dirtyDeliveryMessage) {
5275
5276
  emitDirectThought('AgentForge blocked commit/push because the staged delivery does not match the final working tree.');
5276
5277
  this.emit('tool_activity', {
@@ -5295,7 +5296,7 @@ export class OpenClawCLI extends EventEmitter {
5295
5296
  try {
5296
5297
  const result = await this._runDirectTool(agentId, name, args, workDir, {
5297
5298
  signal: directAbortController.signal,
5298
- task,
5299
+ task: semanticTask,
5299
5300
  imageModel: directOptions.imageModel,
5300
5301
  agentModel: directOptions.agentModel || model,
5301
5302
  fallbackVisionModels: directOptions.fallbackVisionModels,
@@ -5701,7 +5702,7 @@ export class OpenClawCLI extends EventEmitter {
5701
5702
  * Run an agent task
5702
5703
  * Images are saved to workspace and referenced in message for vision model analysis
5703
5704
  */
5704
- async runAgentTask(agentId, task, workDir, sessionId = null, image = null, browserProfile = null, imageWorkDir = null, agentModel = null, customSystemPrompt = null, conversationHistory = null, allImages = null, providerKeys = null, imageModel = null, taskId = null, iteration = 1, fallbackVisionModels = null, imageGenerationModel = null) {
5705
+ async runAgentTask(agentId, task, workDir, sessionId = null, image = null, browserProfile = null, imageWorkDir = null, agentModel = null, customSystemPrompt = null, conversationHistory = null, allImages = null, providerKeys = null, imageModel = null, taskId = null, iteration = 1, fallbackVisionModels = null, imageGenerationModel = null, rawUserTask = null) {
5705
5706
  // Gateway auth comes from per-agent auth-profiles.json, not subprocess env.
5706
5707
  // Seed real Anthropic API keys up front so anthropic/* models do not fall back
5707
5708
  // to Claude account/OAuth tokens and fail with claude.ai "extra usage" limits.
@@ -5840,10 +5841,10 @@ export class OpenClawCLI extends EventEmitter {
5840
5841
  // OpenClaw subprocess after a model compatibility fallback.
5841
5842
  // If LLM answers with plain text → done in ~1-3s.
5842
5843
  // If LLM returns tool calls → fall through to gateway/subprocess as usual.
5843
- const directTaskText = String(taskForRuntime || '');
5844
- const directTaskRequiresFileChange = /\b(make|create|build|add|implement|update|edit|change|fix|improve|redesign|refactor|write|generate|scaffold|wire|ship|work on)\b/i.test(directTaskText);
5844
+ const directSemanticTaskText = String(rawUserTask || task || taskForRuntime || '');
5845
+ const directTaskRequiresFileChange = /\b(make|create|build|add|implement|update|edit|change|fix|improve|redesign|refactor|write|generate|scaffold|wire|ship|work on)\b/i.test(directSemanticTaskText);
5845
5846
  const directTaskRequiresVisualImplementation = directTaskRequiresFileChange &&
5846
- /\b(ui|ux|visual|design|frontend|css|html|pages?|dashboard|website|web app|app screen|layout|component|responsive|professional|polish(?:ed)?|vibecoded|vibe-coded|interface|screen|visual hierarchy|user experience|design system)\b/i.test(directTaskText);
5847
+ /\b(ui|ux|visual|design|frontend|css|html|pages?|dashboard|website|web app|app screen|layout|component|responsive|professional|polish(?:ed)?|vibecoded|vibe-coded|interface|screen|visual hierarchy|user experience|design system)\b/i.test(directSemanticTaskText);
5847
5848
  const forceSubprocessForVisual = /^(1|true|yes)$/i.test(process.env.AGENTFORGE_FORCE_OPENCLAW_VISUAL || '');
5848
5849
  const skipDirectFastPath = directTaskRequiresVisualImplementation && forceSubprocessForVisual;
5849
5850
  if (skipDirectFastPath && agentModel) {
@@ -5858,6 +5859,7 @@ export class OpenClawCLI extends EventEmitter {
5858
5859
  fallbackVisionModels,
5859
5860
  taskId,
5860
5861
  iteration,
5862
+ rawUserTask: rawUserTask || task,
5861
5863
  });
5862
5864
  if (fastResult !== null) {
5863
5865
  if (fastResult.hasToolCalls) {
package/src/worker.js CHANGED
@@ -3768,7 +3768,8 @@ export class AgentForgeWorker extends EventEmitter {
3768
3768
  providerKeys || null, effectiveImageModel || null,
3769
3769
  taskId, iteration,
3770
3770
  effectiveFallbackVisionModels,
3771
- imageGenerationModel || null
3771
+ imageGenerationModel || null,
3772
+ scopeAwareUserMessage
3772
3773
  );
3773
3774
  runtimeStallRetryCount = 0;
3774
3775
  } catch (runError) {