@blockrun/franklin 3.15.44 → 3.15.45

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.
@@ -258,7 +258,29 @@ function buildExecute(deps) {
258
258
  const result = await response.json();
259
259
  const imageData = result.data?.[0];
260
260
  if (!imageData) {
261
- return { output: 'No image data returned from API', isError: true };
261
+ // Some gateways return 200 with an `error` / `message` field for
262
+ // moderation, quota, or upstream-model failures instead of using
263
+ // HTTP error codes. Without surfacing those, the agent sees only
264
+ // "No image data returned from API" and starts guessing — verified
265
+ // 2026-05-04: agent guessed "gpt-image-2 is forced to 1024x1024
266
+ // per the tool docs" and burned a retry on a size param that
267
+ // wasn't the actual cause. Surface the diagnostic so the agent
268
+ // (or user) can react.
269
+ const bits = [];
270
+ if (result.error !== undefined) {
271
+ bits.push(`error=${JSON.stringify(result.error).slice(0, 240)}`);
272
+ }
273
+ if (result.message !== undefined) {
274
+ bits.push(`message=${String(result.message).slice(0, 240)}`);
275
+ }
276
+ if (Array.isArray(result.data) && result.data.length === 0) {
277
+ bits.push('data=[] (empty array — likely content moderation)');
278
+ }
279
+ else if (result.data === undefined) {
280
+ bits.push('data field missing');
281
+ }
282
+ const detail = bits.length > 0 ? ` — ${bits.join('; ')}` : '';
283
+ return { output: `No image data returned from API${detail}`, isError: true };
262
284
  }
263
285
  // Save image. The /v1/images/image2image endpoint returns Gemini results
264
286
  // as a data URI in `url`, so decode those locally instead of going through
@@ -192,7 +192,18 @@ function buildExecute(deps) {
192
192
  ctx.abortSignal.removeEventListener('abort', submitAbort);
193
193
  }
194
194
  if (!submitResult.poll_url || !paymentHeaders) {
195
- return { output: 'API did not return a poll_url for the video job', isError: true };
195
+ // Surface any diagnostic the body contained same rationale as
196
+ // imagegen.ts: "missing field" tells the agent nothing about
197
+ // whether it was moderation, quota, or upstream model failure.
198
+ const bits = [];
199
+ if (!paymentHeaders)
200
+ bits.push('payment headers missing');
201
+ if (submitResult?.error !== undefined)
202
+ bits.push(`error=${JSON.stringify(submitResult.error).slice(0, 240)}`);
203
+ if (submitResult?.message !== undefined)
204
+ bits.push(`message=${String(submitResult.message).slice(0, 240)}`);
205
+ const detail = bits.length > 0 ? ` — ${bits.join('; ')}` : '';
206
+ return { output: `API did not return a poll_url for the video job${detail}`, isError: true };
196
207
  }
197
208
  // Phase 2: poll GET /v1/videos/generations/{id} with the SAME signed
198
209
  // x-payment header until the job completes. Server settles on the first
@@ -218,7 +229,17 @@ function buildExecute(deps) {
218
229
  const videoData = outcome.data;
219
230
  const videoUrl = videoData.url;
220
231
  if (!videoUrl) {
221
- return { output: 'No video URL returned from API', isError: true };
232
+ // Same diagnostic pattern as the submit-side path above.
233
+ const d = videoData;
234
+ const bits = [];
235
+ if (d.error !== undefined)
236
+ bits.push(`error=${JSON.stringify(d.error).slice(0, 240)}`);
237
+ if (d.message !== undefined)
238
+ bits.push(`message=${String(d.message).slice(0, 240)}`);
239
+ if (d.status !== undefined)
240
+ bits.push(`status=${String(d.status).slice(0, 80)}`);
241
+ const detail = bits.length > 0 ? ` — ${bits.join('; ')}` : '';
242
+ return { output: `No video URL returned from API${detail}`, isError: true };
222
243
  }
223
244
  try {
224
245
  // Download the MP4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/franklin",
3
- "version": "3.15.44",
3
+ "version": "3.15.45",
4
4
  "description": "Franklin — The AI agent with a wallet. Spends USDC autonomously to get real work done. Pay per action, no subscriptions.",
5
5
  "type": "module",
6
6
  "exports": {