@debugg-ai/debugg-ai-mcp 1.0.39 → 1.0.41

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.
@@ -99,10 +99,10 @@ export async function testPageChangesHandler(input, context, progressCallback) {
99
99
  }
100
100
  }
101
101
  }
102
- // --- Build context data (targetUrl is the tunnel URL for localhost, original URL otherwise) ---
102
+ // --- Build context data (camelCase here axiosTransport auto-converts to snake_case) ---
103
103
  const contextData = {
104
104
  targetUrl: ctx.targetUrl ?? originalUrl,
105
- goal: input.description,
105
+ question: input.description,
106
106
  };
107
107
  if (projectUuid) {
108
108
  contextData.projectId = projectUuid;
@@ -120,6 +120,7 @@ export async function testPageChangesHandler(input, context, progressCallback) {
120
120
  if (input.password)
121
121
  env.password = input.password;
122
122
  // --- Execute ---
123
+ logger.info('Sending contextData', { contextData, env: Object.keys(env).length > 0 ? env : undefined });
123
124
  if (progressCallback) {
124
125
  await progressCallback({ progress: 3, total: TOTAL_STEPS, message: 'Queuing workflow execution...' });
125
126
  }
@@ -167,10 +168,10 @@ export async function testPageChangesHandler(input, context, progressCallback) {
167
168
  if (stepsTaken > 0) {
168
169
  // Extract the latest brain.step to show what the agent is doing
169
170
  const latestStep = (exec.nodeExecutions ?? [])
170
- .filter(n => n.nodeType === 'brain.step' && n.outputData?.decision)
171
+ .filter(n => n.nodeType === 'brain.step' && n.outputData)
171
172
  .sort((a, b) => b.executionOrder - a.executionOrder)[0];
172
- if (latestStep?.outputData?.decision) {
173
- const d = latestStep.outputData.decision;
173
+ const d = latestStep?.outputData?.decision ?? latestStep?.outputData;
174
+ if (d) {
174
175
  const action = d.actionType ?? d.action_type ?? 'working';
175
176
  const intent = d.intent;
176
177
  message = intent
@@ -198,12 +199,16 @@ export async function testPageChangesHandler(input, context, progressCallback) {
198
199
  // --- Format result ---
199
200
  const outcome = finalExecution.state?.outcome ?? finalExecution.status;
200
201
  const nodes = finalExecution.nodeExecutions ?? [];
201
- // Extract step-by-step action trace from brain.step nodes
202
+ // subworkflow.run is the current graph shape — carries outcome, actionHistory, screenshot
203
+ const subworkflowNode = nodes.find(n => n.nodeType === 'subworkflow.run');
204
+ // surfer.execute_task and brain.step/brain.evaluate are older graph shapes
205
+ const surferNode = nodes.find(n => n.nodeType === 'surfer.execute_task');
206
+ // Action trace: brain.step nodes (old) → subworkflow.run actionHistory (new)
202
207
  const brainSteps = nodes
203
- .filter(n => n.nodeType === 'brain.step' && n.outputData?.decision)
208
+ .filter(n => n.nodeType === 'brain.step' && n.outputData)
204
209
  .sort((a, b) => a.executionOrder - b.executionOrder);
205
210
  const actionTrace = brainSteps.map((n, i) => {
206
- const d = n.outputData.decision;
211
+ const d = n.outputData.decision ?? n.outputData;
207
212
  return {
208
213
  step: i + 1,
209
214
  action: d.actionType ?? d.action_type,
@@ -214,33 +219,52 @@ export async function testPageChangesHandler(input, context, progressCallback) {
214
219
  durationMs: n.executionTimeMs,
215
220
  };
216
221
  });
217
- // Extract evaluation from brain.evaluate node
222
+ const subworkflowHistory = subworkflowNode?.outputData?.actionHistory;
223
+ if (actionTrace.length === 0 && Array.isArray(subworkflowHistory) && subworkflowHistory.length > 0) {
224
+ subworkflowHistory.forEach((step, i) => {
225
+ actionTrace.push({
226
+ step: i + 1,
227
+ action: step.actionType ?? step.action_type ?? step.action,
228
+ intent: step.intent,
229
+ target: step.target,
230
+ value: step.value ?? undefined,
231
+ success: step.success ?? true,
232
+ durationMs: step.durationMs ?? step.duration_ms ?? undefined,
233
+ });
234
+ });
235
+ }
236
+ // Evaluation: brain.evaluate (old) → subworkflow.run outcome/success (new)
218
237
  const evalNode = nodes.find(n => n.nodeType === 'brain.evaluate');
219
- const evaluation = evalNode?.outputData ? {
220
- passed: evalNode.outputData.passed,
221
- outcome: evalNode.outputData.outcome,
222
- reason: evalNode.outputData.reason,
223
- verifications: evalNode.outputData.verifications,
224
- } : undefined;
225
- // Also check for surfer.execute_task (older workflow graphs)
226
- const surferNode = nodes.find(n => n.nodeType === 'surfer.execute_task');
238
+ let evaluation;
239
+ if (evalNode?.outputData) {
240
+ evaluation = {
241
+ passed: evalNode.outputData.passed,
242
+ outcome: evalNode.outputData.outcome,
243
+ reason: evalNode.outputData.reason,
244
+ verifications: evalNode.outputData.verifications,
245
+ };
246
+ }
247
+ else if (subworkflowNode?.outputData) {
248
+ const sw = subworkflowNode.outputData;
249
+ evaluation = {
250
+ passed: sw.success,
251
+ outcome: sw.outcome,
252
+ reason: sw.error || undefined,
253
+ };
254
+ }
227
255
  const responsePayload = {
228
256
  outcome,
229
- success: finalExecution.state?.success ?? false,
257
+ success: finalExecution.state?.success ?? subworkflowNode?.outputData?.success ?? false,
230
258
  status: finalExecution.status,
231
- stepsTaken: finalExecution.state?.stepsTaken ?? actionTrace.length ?? 0,
259
+ stepsTaken: finalExecution.state?.stepsTaken ?? subworkflowNode?.outputData?.stepsTaken ?? actionTrace.length,
232
260
  targetUrl: originalUrl,
233
261
  executionId: executionUuid,
234
262
  durationMs: finalExecution.durationMs ?? duration,
235
263
  };
236
- // The step-by-step action trace — what the browser agent did and why
237
- if (actionTrace.length > 0) {
264
+ if (actionTrace.length > 0)
238
265
  responsePayload.actionTrace = actionTrace;
239
- }
240
- // The final evaluation — pass/fail with reasoning
241
- if (evaluation) {
266
+ if (evaluation)
242
267
  responsePayload.evaluation = evaluation;
243
- }
244
268
  if (finalExecution.state?.error)
245
269
  responsePayload.agentError = finalExecution.state.error;
246
270
  if (finalExecution.errorMessage)
@@ -261,15 +285,23 @@ export async function testPageChangesHandler(input, context, progressCallback) {
261
285
  const content = [
262
286
  { type: 'text', text: JSON.stringify(responsePayload, null, 2) },
263
287
  ];
264
- // Search all node outputs for screenshot/gif URLs not just the surfer node
265
- const SCREENSHOT_KEYS = ['finalScreenshot', 'screenshot', 'screenshotUrl', 'screenshotUri'];
288
+ // Screenshot: check for already-base64 field first (subworkflow.run), then URL-based fields
289
+ const SCREENSHOT_URL_KEYS = ['finalScreenshot', 'screenshot', 'screenshotUrl', 'screenshotUri'];
266
290
  const GIF_KEYS = ['runGif', 'gifUrl', 'gif', 'videoUrl', 'recordingUrl'];
267
- let screenshotUrl = null;
291
+ let screenshotEmbedded = false;
268
292
  let gifUrl = null;
269
- for (const node of finalExecution.nodeExecutions ?? []) {
293
+ // subworkflow.run carries screenshotB64 directly no fetch needed
294
+ const screenshotB64 = subworkflowNode?.outputData?.screenshotB64;
295
+ if (typeof screenshotB64 === 'string' && screenshotB64) {
296
+ logger.info('Embedding inline base64 screenshot from subworkflow.run');
297
+ content.push(imageContentBlock(screenshotB64, 'image/png'));
298
+ screenshotEmbedded = true;
299
+ }
300
+ let screenshotUrl = null;
301
+ for (const node of nodes) {
270
302
  const data = node.outputData ?? {};
271
- if (!screenshotUrl) {
272
- for (const key of SCREENSHOT_KEYS) {
303
+ if (!screenshotEmbedded && !screenshotUrl) {
304
+ for (const key of SCREENSHOT_URL_KEYS) {
273
305
  if (typeof data[key] === 'string' && data[key]) {
274
306
  screenshotUrl = data[key];
275
307
  break;
@@ -284,10 +316,10 @@ export async function testPageChangesHandler(input, context, progressCallback) {
284
316
  }
285
317
  }
286
318
  }
287
- if (screenshotUrl && gifUrl)
319
+ if ((screenshotEmbedded || screenshotUrl) && gifUrl)
288
320
  break;
289
321
  }
290
- if (screenshotUrl) {
322
+ if (!screenshotEmbedded && screenshotUrl) {
291
323
  logger.info(`Embedding screenshot: ${screenshotUrl}`);
292
324
  const img = await fetchImageAsBase64(screenshotUrl).catch(() => null);
293
325
  if (img)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@debugg-ai/debugg-ai-mcp",
3
- "version": "1.0.39",
3
+ "version": "1.0.41",
4
4
  "description": "Zero-Config, Fully AI-Managed End-to-End Testing for all code gen platforms.",
5
5
  "type": "module",
6
6
  "bin": {