@telepat/ideon 0.1.30 → 0.1.31

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.
Files changed (2) hide show
  1. package/dist/ideon.js +317 -29
  2. package/package.json +1 -1
package/dist/ideon.js CHANGED
@@ -552,7 +552,8 @@ var baseT2ISettingsSchema = z2.preprocess(
552
552
  z2.object({
553
553
  modelId: z2.string().default(DEFAULT_LIMN_MODEL_ID),
554
554
  replicateModelId: z2.string().optional(),
555
- inputOverrides: z2.record(z2.string(), z2.unknown()).default({})
555
+ inputOverrides: z2.record(z2.string(), z2.unknown()).default({}),
556
+ maxAttempts: z2.number().int().min(1).max(10).default(4)
556
557
  })
557
558
  );
558
559
  var notificationsSettingsSchema = z2.object({
@@ -562,6 +563,7 @@ var appSettingsSchema = z2.object({
562
563
  model: z2.string().default("deepseek/deepseek-v4-pro"),
563
564
  modelSettings: modelSettingsSchema.default(modelSettingsSchema.parse({})),
564
565
  modelRequestTimeoutMs: z2.number().int().positive().default(9e4),
566
+ modelRequestMaxAttempts: z2.number().int().min(1).max(10).default(4),
565
567
  t2i: baseT2ISettingsSchema.default(baseT2ISettingsSchema.parse({})),
566
568
  notifications: notificationsSettingsSchema.default(notificationsSettingsSchema.parse({})),
567
569
  contentTargets: z2.array(contentTargetSchema).min(1).refine((targets) => targets.filter((target) => target.role === "primary").length === 1, {
@@ -580,6 +582,7 @@ var envSettingsSchema = z2.object({
580
582
  maxTokens: z2.number().int().positive().optional(),
581
583
  topP: z2.number().min(0).max(1).optional(),
582
584
  modelRequestTimeoutMs: z2.number().int().positive().optional(),
585
+ modelRequestMaxAttempts: z2.number().int().min(1).max(10).optional(),
583
586
  notificationsEnabled: z2.boolean().optional(),
584
587
  style: z2.enum(writingStyleValues).optional(),
585
588
  intent: z2.enum(contentIntentValues).optional(),
@@ -624,6 +627,7 @@ function readEnvSettings(env = process.env) {
624
627
  maxTokens: parseNumber(env.IDEON_MAX_TOKENS),
625
628
  topP: parseNumber(env.IDEON_TOP_P),
626
629
  modelRequestTimeoutMs: parseNumber(env.IDEON_MODEL_REQUEST_TIMEOUT_MS),
630
+ modelRequestMaxAttempts: parseNumber(env.IDEON_MODEL_REQUEST_MAX_ATTEMPTS),
627
631
  notificationsEnabled: parseBoolean(env.IDEON_NOTIFICATIONS_ENABLED),
628
632
  style: env.IDEON_STYLE,
629
633
  intent: env.IDEON_INTENT,
@@ -1424,7 +1428,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
1424
1428
  // package.json
1425
1429
  var package_default = {
1426
1430
  name: "@telepat/ideon",
1427
- version: "0.1.30",
1431
+ version: "0.1.31",
1428
1432
  description: "CLI for generating rich articles and images from ideas.",
1429
1433
  type: "module",
1430
1434
  repository: {
@@ -1547,6 +1551,7 @@ async function resolveRunInput(input) {
1547
1551
  ...job?.settings ?? {},
1548
1552
  ...envSettings.model ? { model: envSettings.model } : {},
1549
1553
  ...envSettings.modelRequestTimeoutMs !== void 0 ? { modelRequestTimeoutMs: envSettings.modelRequestTimeoutMs } : {},
1554
+ ...envSettings.modelRequestMaxAttempts !== void 0 ? { modelRequestMaxAttempts: envSettings.modelRequestMaxAttempts } : {},
1550
1555
  ...envSettings.notificationsEnabled !== void 0 ? {
1551
1556
  notifications: {
1552
1557
  ...savedSettings.notifications,
@@ -3181,6 +3186,212 @@ function buildImagePromptMessages(plan, image, section) {
3181
3186
  ];
3182
3187
  }
3183
3188
 
3189
+ // src/llm/retry.ts
3190
+ var DEFAULT_BASE_BACKOFF_MS = 1500;
3191
+ var DEFAULT_MAX_BACKOFF_MS = 6e4;
3192
+ var DEFAULT_JITTER_MS = 250;
3193
+ var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 409, 425, 429]);
3194
+ var TRANSIENT_ERROR_PATTERN = /timeout|network|fetch|temporarily|aborted|ECONNRESET|ECONNREFUSED|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|socket hang up/i;
3195
+ async function withRetry(op, opts) {
3196
+ const maxAttempts = Math.max(1, Math.floor(opts.maxAttempts));
3197
+ const baseBackoffMs = opts.baseBackoffMs ?? DEFAULT_BASE_BACKOFF_MS;
3198
+ const maxBackoffMs = opts.maxBackoffMs ?? DEFAULT_MAX_BACKOFF_MS;
3199
+ const jitterMs = opts.jitterMs ?? DEFAULT_JITTER_MS;
3200
+ const sleep = opts.sleep ?? defaultSleep;
3201
+ const randomFraction = opts.randomFraction ?? Math.random;
3202
+ let lastError;
3203
+ let lastClassification = null;
3204
+ let attemptsMade = 0;
3205
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
3206
+ attemptsMade = attempt;
3207
+ try {
3208
+ return await op(attempt);
3209
+ } catch (error) {
3210
+ lastError = error;
3211
+ const classification = classifyHttpError(error);
3212
+ lastClassification = classification;
3213
+ if (!classification.retryable || attempt >= maxAttempts) {
3214
+ break;
3215
+ }
3216
+ const delayMs = computeDelayMs({
3217
+ retryAfterMs: classification.retryAfterMs,
3218
+ attempt,
3219
+ baseBackoffMs,
3220
+ maxBackoffMs,
3221
+ jitterMs,
3222
+ randomFraction
3223
+ });
3224
+ opts.onRetry?.({
3225
+ attempt,
3226
+ delayMs,
3227
+ reason: classification.reason,
3228
+ statusCode: classification.statusCode
3229
+ });
3230
+ await sleep(delayMs);
3231
+ }
3232
+ }
3233
+ throw buildFinalError(opts.operationLabel, attemptsMade, lastError, lastClassification);
3234
+ }
3235
+ function computeDelayMs(input) {
3236
+ if (typeof input.retryAfterMs === "number" && input.retryAfterMs > 0) {
3237
+ return Math.min(input.maxBackoffMs, input.retryAfterMs);
3238
+ }
3239
+ const exponential = input.baseBackoffMs * 2 ** (input.attempt - 1);
3240
+ const capped = Math.min(input.maxBackoffMs, exponential);
3241
+ const jitter = input.jitterMs > 0 ? input.randomFraction() * input.jitterMs : 0;
3242
+ return Math.floor(capped + jitter);
3243
+ }
3244
+ function classifyHttpError(error) {
3245
+ if (!error) {
3246
+ return { retryable: true, reason: "Empty error value treated as transient." };
3247
+ }
3248
+ const message = errorMessage(error);
3249
+ const statusFromObject = extractStatusFromObject(error);
3250
+ const statusFromMessage = statusFromObject ?? extractStatusFromMessage(message);
3251
+ const retryAfterMs = extractRetryAfterMs(error, message);
3252
+ if (statusFromMessage !== void 0) {
3253
+ if (RETRYABLE_STATUS_CODES.has(statusFromMessage) || statusFromMessage >= 500) {
3254
+ return {
3255
+ retryable: true,
3256
+ statusCode: statusFromMessage,
3257
+ retryAfterMs,
3258
+ reason: `HTTP ${statusFromMessage}`
3259
+ };
3260
+ }
3261
+ return {
3262
+ retryable: false,
3263
+ statusCode: statusFromMessage,
3264
+ reason: `HTTP ${statusFromMessage}`
3265
+ };
3266
+ }
3267
+ if (TRANSIENT_ERROR_PATTERN.test(message)) {
3268
+ return {
3269
+ retryable: true,
3270
+ retryAfterMs,
3271
+ reason: "Transient network or timeout error."
3272
+ };
3273
+ }
3274
+ return {
3275
+ retryable: true,
3276
+ retryAfterMs,
3277
+ reason: "Unknown error treated as transient."
3278
+ };
3279
+ }
3280
+ function extractStatusFromObject(error) {
3281
+ if (typeof error !== "object" || error === null) {
3282
+ return void 0;
3283
+ }
3284
+ const record = error;
3285
+ const direct = numberFrom(record.status);
3286
+ if (direct !== void 0) {
3287
+ return direct;
3288
+ }
3289
+ const response = record.response;
3290
+ if (typeof response === "object" && response !== null) {
3291
+ const responseStatus = numberFrom(response.status);
3292
+ if (responseStatus !== void 0) {
3293
+ return responseStatus;
3294
+ }
3295
+ }
3296
+ return void 0;
3297
+ }
3298
+ function extractStatusFromMessage(message) {
3299
+ const match = message.match(/status\s+(\d{3})/i);
3300
+ if (!match) {
3301
+ return void 0;
3302
+ }
3303
+ const parsed = Number.parseInt(match[1], 10);
3304
+ return Number.isInteger(parsed) ? parsed : void 0;
3305
+ }
3306
+ function extractRetryAfterMs(error, message) {
3307
+ const headerSeconds = extractRetryAfterHeader(error);
3308
+ if (headerSeconds !== void 0) {
3309
+ return Math.round(headerSeconds * 1e3);
3310
+ }
3311
+ const bodyMatch = message.match(/"?retry_after"?\s*[:=]\s*(\d+(?:\.\d+)?)/i);
3312
+ if (bodyMatch) {
3313
+ const seconds = Number.parseFloat(bodyMatch[1]);
3314
+ if (Number.isFinite(seconds) && seconds > 0) {
3315
+ return Math.round(seconds * 1e3);
3316
+ }
3317
+ }
3318
+ return void 0;
3319
+ }
3320
+ function extractRetryAfterHeader(error) {
3321
+ if (typeof error !== "object" || error === null) {
3322
+ return void 0;
3323
+ }
3324
+ const response = error.response;
3325
+ if (typeof response !== "object" || response === null) {
3326
+ return void 0;
3327
+ }
3328
+ const headers = response.headers;
3329
+ if (!headers) {
3330
+ return void 0;
3331
+ }
3332
+ let rawValue;
3333
+ if (typeof headers === "object" && typeof headers.get === "function") {
3334
+ rawValue = headers.get("retry-after");
3335
+ } else if (typeof headers === "object") {
3336
+ const entries = headers;
3337
+ rawValue = entries["retry-after"] ?? entries["Retry-After"];
3338
+ }
3339
+ if (typeof rawValue !== "string" && typeof rawValue !== "number") {
3340
+ return void 0;
3341
+ }
3342
+ const stringValue = String(rawValue).trim();
3343
+ if (!stringValue) {
3344
+ return void 0;
3345
+ }
3346
+ const numeric = Number.parseFloat(stringValue);
3347
+ if (Number.isFinite(numeric) && numeric > 0) {
3348
+ return numeric;
3349
+ }
3350
+ const dateMs = Date.parse(stringValue);
3351
+ if (Number.isFinite(dateMs)) {
3352
+ const diffSeconds = (dateMs - Date.now()) / 1e3;
3353
+ return diffSeconds > 0 ? diffSeconds : void 0;
3354
+ }
3355
+ return void 0;
3356
+ }
3357
+ function numberFrom(value2) {
3358
+ if (typeof value2 === "number" && Number.isFinite(value2)) {
3359
+ return value2;
3360
+ }
3361
+ if (typeof value2 === "string") {
3362
+ const parsed = Number.parseFloat(value2);
3363
+ return Number.isFinite(parsed) ? parsed : void 0;
3364
+ }
3365
+ return void 0;
3366
+ }
3367
+ function errorMessage(error) {
3368
+ if (error instanceof Error) {
3369
+ return error.message;
3370
+ }
3371
+ if (typeof error === "string") {
3372
+ return error;
3373
+ }
3374
+ try {
3375
+ return JSON.stringify(error);
3376
+ } catch {
3377
+ return String(error);
3378
+ }
3379
+ }
3380
+ function buildFinalError(operationLabel, attempts, cause, classification) {
3381
+ const detail = errorMessage(cause) || classification?.reason || "unknown error";
3382
+ const message = `${operationLabel} failed after ${attempts} attempt${attempts === 1 ? "" : "s"}: ${detail}`;
3383
+ const wrapped = new Error(message, cause instanceof Error ? { cause } : void 0);
3384
+ if (!(cause instanceof Error) && cause !== void 0) {
3385
+ wrapped.cause = cause;
3386
+ }
3387
+ return wrapped;
3388
+ }
3389
+ function defaultSleep(ms) {
3390
+ return new Promise((resolve) => {
3391
+ setTimeout(resolve, ms);
3392
+ });
3393
+ }
3394
+
3184
3395
  // src/pipeline/analytics.ts
3185
3396
  var LLM_USD_PER_1K_TOKENS = {
3186
3397
  // AUTO-GENERATED:OPENROUTER_PRICING_START
@@ -3433,8 +3644,26 @@ async function renderExpandedImages({
3433
3644
  ...replicateModelOverride && isReplicateModelIdForFamily(family, replicateModelOverride) ? { replicateModel: replicateModelOverride } : {}
3434
3645
  };
3435
3646
  const renderStartedAtMs = Date.now();
3647
+ let attemptsMade = 0;
3648
+ let retryCount = 0;
3649
+ let retryBackoffMs = 0;
3436
3650
  try {
3437
- const result = await limn.generate(prompt.prompt, family, limnOptions);
3651
+ const result = await withRetry(
3652
+ () => {
3653
+ attemptsMade += 1;
3654
+ return limn.generate(prompt.prompt, family, limnOptions);
3655
+ },
3656
+ {
3657
+ operationLabel: `Replicate ${prompt.kind} image (${prompt.id})`,
3658
+ maxAttempts: settings.t2i.maxAttempts,
3659
+ baseBackoffMs: 1500,
3660
+ maxBackoffMs: 6e4,
3661
+ onRetry({ delayMs }) {
3662
+ retryCount += 1;
3663
+ retryBackoffMs += delayMs;
3664
+ }
3665
+ }
3666
+ );
3438
3667
  const ext = mimeTypeToExtension(result.mimeType);
3439
3668
  const liveFileName = `${prompt.kind === "cover" ? "cover" : `inline-${prompt.anchorAfterSection}`}-${index + 1}.${ext}`;
3440
3669
  const liveOutputPath = path6.join(assetDir, liveFileName);
@@ -3456,9 +3685,9 @@ async function renderExpandedImages({
3456
3685
  kind: prompt.kind,
3457
3686
  modelId: result.modelSlug,
3458
3687
  durationMs: result.analytics.totalDurationMs,
3459
- attempts: 1,
3460
- retries: 0,
3461
- retryBackoffMs: 0,
3688
+ attempts: attemptsMade,
3689
+ retries: retryCount,
3690
+ retryBackoffMs,
3462
3691
  outputBytes: result.image.byteLength,
3463
3692
  costUsd: result.analytics.totalEstimatedCostUsd,
3464
3693
  costSource
@@ -3472,9 +3701,9 @@ async function renderExpandedImages({
3472
3701
  startedAt: new Date(renderStartedAtMs).toISOString(),
3473
3702
  endedAt: (/* @__PURE__ */ new Date()).toISOString(),
3474
3703
  durationMs: result.analytics.totalDurationMs,
3475
- attempts: 1,
3476
- retries: 0,
3477
- retryBackoffMs: 0,
3704
+ attempts: attemptsMade,
3705
+ retries: retryCount,
3706
+ retryBackoffMs,
3478
3707
  status: "succeeded",
3479
3708
  prompt: prompt.prompt,
3480
3709
  input: {},
@@ -3491,9 +3720,9 @@ async function renderExpandedImages({
3491
3720
  startedAt: new Date(renderStartedAtMs).toISOString(),
3492
3721
  endedAt: (/* @__PURE__ */ new Date()).toISOString(),
3493
3722
  durationMs,
3494
- attempts: 1,
3495
- retries: 0,
3496
- retryBackoffMs: 0,
3723
+ attempts: Math.max(attemptsMade, 1),
3724
+ retries: retryCount,
3725
+ retryBackoffMs,
3497
3726
  status: "failed",
3498
3727
  prompt: prompt.prompt,
3499
3728
  input: {},
@@ -3553,8 +3782,9 @@ var OpenRouterClient = class {
3553
3782
  }
3554
3783
  async requestStructured(request) {
3555
3784
  let aggregatedMetrics = null;
3785
+ const maxParseAttempts = Math.max(1, request.settings.modelRequestMaxAttempts);
3556
3786
  try {
3557
- for (let attempt = 0; attempt < 3; attempt += 1) {
3787
+ for (let attempt = 0; attempt < maxParseAttempts; attempt += 1) {
3558
3788
  const response = await this.sendCompletion({
3559
3789
  messages: request.messages,
3560
3790
  settings: request.settings,
@@ -3579,7 +3809,7 @@ var OpenRouterClient = class {
3579
3809
  request.onMetrics?.(aggregatedMetrics);
3580
3810
  return structured;
3581
3811
  } catch (parseError) {
3582
- if (attempt < 2 && shouldRetryStructuredParseError(parseError)) {
3812
+ if (attempt < maxParseAttempts - 1 && shouldRetryStructuredParseError(parseError)) {
3583
3813
  const backoff = backoffMs(attempt);
3584
3814
  aggregatedMetrics = recordParseRetryMetrics(aggregatedMetrics, backoff);
3585
3815
  await wait(backoff);
@@ -3645,7 +3875,8 @@ var OpenRouterClient = class {
3645
3875
  let attempts = 0;
3646
3876
  let retries = 0;
3647
3877
  let retryBackoffMs = 0;
3648
- for (let attempt = 0; attempt < 3; attempt += 1) {
3878
+ const maxAttempts = Math.max(1, settings.modelRequestMaxAttempts);
3879
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
3649
3880
  attempts = attempt + 1;
3650
3881
  const attemptStartedAtMs = Date.now();
3651
3882
  const controller = new AbortController();
@@ -3695,8 +3926,9 @@ var OpenRouterClient = class {
3695
3926
  const providerMessage = json?.error?.message ?? `OpenRouter request failed with status ${response.status}`;
3696
3927
  const raw = json?.error?.metadata?.raw;
3697
3928
  const message = raw ? `${raw} (OpenRouter: ${providerMessage})` : providerMessage;
3698
- if (shouldRetryStatus(response.status) && attempt < 2) {
3699
- const backoff = backoffMs(attempt);
3929
+ if (shouldRetryStatus(response.status) && attempt < maxAttempts - 1) {
3930
+ const advisedMs = extractRetryAfterFromResponse(response, json, rawBody);
3931
+ const backoff = advisedMs !== null ? Math.min(MAX_RETRY_BACKOFF_MS, advisedMs) : backoffMs(attempt);
3700
3932
  retries += 1;
3701
3933
  retryBackoffMs += backoff;
3702
3934
  onInteraction?.({
@@ -3722,7 +3954,7 @@ var OpenRouterClient = class {
3722
3954
  throw new Error(message);
3723
3955
  }
3724
3956
  const content = json.choices?.[0]?.message?.content;
3725
- if (!content && attempt < 2) {
3957
+ if (!content && attempt < maxAttempts - 1) {
3726
3958
  const backoff = backoffMs(attempt);
3727
3959
  retries += 1;
3728
3960
  retryBackoffMs += backoff;
@@ -3798,7 +4030,7 @@ var OpenRouterClient = class {
3798
4030
  responseBody: responseBodyRaw,
3799
4031
  errorMessage: lastError.message
3800
4032
  });
3801
- if (attempt < 2 && shouldRetryError(lastError)) {
4033
+ if (attempt < maxAttempts - 1 && shouldRetryError(lastError)) {
3802
4034
  const backoff = backoffMs(attempt);
3803
4035
  retries += 1;
3804
4036
  retryBackoffMs += backoff;
@@ -3925,6 +4157,61 @@ function normalizeClientError(error, timeoutMs) {
3925
4157
  function backoffMs(attempt) {
3926
4158
  return 500 * (attempt + 1);
3927
4159
  }
4160
+ var MAX_RETRY_BACKOFF_MS = 6e4;
4161
+ function extractRetryAfterFromResponse(response, json, rawBody) {
4162
+ const headerValue = typeof response.headers?.get === "function" ? response.headers.get("retry-after") : null;
4163
+ if (headerValue) {
4164
+ const numeric = Number.parseFloat(headerValue);
4165
+ if (Number.isFinite(numeric) && numeric > 0) {
4166
+ return Math.round(numeric * 1e3);
4167
+ }
4168
+ const dateMs = Date.parse(headerValue);
4169
+ if (Number.isFinite(dateMs)) {
4170
+ const diff = dateMs - Date.now();
4171
+ if (diff > 0) {
4172
+ return diff;
4173
+ }
4174
+ }
4175
+ }
4176
+ const metadata = json?.error?.metadata;
4177
+ if (metadata) {
4178
+ const fromMetadata = metadata["retry_after"] ?? metadata["retryAfter"];
4179
+ const numeric = toFiniteNumber(fromMetadata);
4180
+ if (numeric !== null && numeric > 0) {
4181
+ return Math.round(numeric * 1e3);
4182
+ }
4183
+ const rawCandidate = metadata["raw"];
4184
+ if (typeof rawCandidate === "string") {
4185
+ const fromRaw = extractRetryAfterFromString(rawCandidate);
4186
+ if (fromRaw !== null) {
4187
+ return fromRaw;
4188
+ }
4189
+ }
4190
+ }
4191
+ const fromBody = extractRetryAfterFromString(rawBody);
4192
+ if (fromBody !== null) {
4193
+ return fromBody;
4194
+ }
4195
+ return null;
4196
+ }
4197
+ function extractRetryAfterFromString(value2) {
4198
+ const bodyMatch = value2.match(/\\?"retry_after\\?"\s*:\s*(\d+(?:\.\d+)?)/i);
4199
+ if (!bodyMatch) {
4200
+ return null;
4201
+ }
4202
+ const numeric = Number.parseFloat(bodyMatch[1]);
4203
+ return Number.isFinite(numeric) && numeric > 0 ? Math.round(numeric * 1e3) : null;
4204
+ }
4205
+ function toFiniteNumber(value2) {
4206
+ if (typeof value2 === "number" && Number.isFinite(value2)) {
4207
+ return value2;
4208
+ }
4209
+ if (typeof value2 === "string") {
4210
+ const parsed = Number.parseFloat(value2);
4211
+ return Number.isFinite(parsed) ? parsed : null;
4212
+ }
4213
+ return null;
4214
+ }
3928
4215
  function aggregateLlmMetrics(total, next) {
3929
4216
  if (!total) {
3930
4217
  return { ...next };
@@ -4333,7 +4620,7 @@ async function runPipelineShell(input, options = {}) {
4333
4620
  const llmInteractions = [];
4334
4621
  const t2iInteractions = [];
4335
4622
  let writeSession;
4336
- const applyRetryUpdate = (stageId, retryIncrement, errorMessage) => {
4623
+ const applyRetryUpdate = (stageId, retryIncrement, errorMessage2) => {
4337
4624
  if (retryIncrement <= 0) {
4338
4625
  return;
4339
4626
  }
@@ -4344,7 +4631,7 @@ async function runPipelineShell(input, options = {}) {
4344
4631
  const existing = stageRetryState.get(stageId) ?? { retries: 0, lastError: null };
4345
4632
  const next = {
4346
4633
  retries: existing.retries + retryIncrement,
4347
- lastError: errorMessage && errorMessage.trim().length > 0 ? errorMessage : existing.lastError
4634
+ lastError: errorMessage2 && errorMessage2.trim().length > 0 ? errorMessage2 : existing.lastError
4348
4635
  };
4349
4636
  stageRetryState.set(stageId, next);
4350
4637
  stages[stageIndex] = {
@@ -7384,7 +7671,8 @@ function SettingsFlow({ initialSettings, initialSecrets, onDone }) {
7384
7671
  t2i: {
7385
7672
  modelId: item.value,
7386
7673
  replicateModelId: current.t2i.replicateModelId && isReplicateModelIdForFamily(item.value, current.t2i.replicateModelId) ? current.t2i.replicateModelId : void 0,
7387
- inputOverrides: {}
7674
+ inputOverrides: {},
7675
+ maxAttempts: current.t2i.maxAttempts
7388
7676
  }
7389
7677
  }));
7390
7678
  setShowModelSelect(false);
@@ -9710,13 +9998,13 @@ function PipelinePresenter({
9710
9998
  prompt,
9711
9999
  stages,
9712
10000
  result,
9713
- errorMessage
10001
+ errorMessage: errorMessage2
9714
10002
  }) {
9715
10003
  const visibleStages = getVisibleStages(stages);
9716
10004
  const maxVisibleItems = computeMaxVisibleItemsPerStage({
9717
10005
  terminalRows: process.stdout.rows,
9718
10006
  visibleStageCount: visibleStages.length,
9719
- hasError: Boolean(errorMessage),
10007
+ hasError: Boolean(errorMessage2),
9720
10008
  hasResult: Boolean(result)
9721
10009
  });
9722
10010
  return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingX: 1, children: [
@@ -9732,7 +10020,7 @@ function PipelinePresenter({
9732
10020
  },
9733
10021
  stage.id
9734
10022
  )) }),
9735
- errorMessage ? /* @__PURE__ */ jsx5(Box4, { marginTop: 1, borderStyle: "round", borderColor: "red", paddingX: 1, children: /* @__PURE__ */ jsx5(Text4, { color: "red", children: errorMessage }) }) : null,
10023
+ errorMessage2 ? /* @__PURE__ */ jsx5(Box4, { marginTop: 1, borderStyle: "round", borderColor: "red", paddingX: 1, children: /* @__PURE__ */ jsx5(Text4, { color: "red", children: errorMessage2 }) }) : null,
9736
10024
  result ? /* @__PURE__ */ jsx5(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx5(FinalSummary, { artifact: result.artifact, analytics: result.analytics }) }) : null
9737
10025
  ] });
9738
10026
  }
@@ -10267,7 +10555,7 @@ function WriteApp({
10267
10555
  () => createInitialStages()
10268
10556
  );
10269
10557
  const [result, setResult] = useState4(null);
10270
- const [errorMessage, setErrorMessage] = useState4(null);
10558
+ const [errorMessage2, setErrorMessage] = useState4(null);
10271
10559
  useEffect3(() => {
10272
10560
  let mounted = true;
10273
10561
  void (async () => {
@@ -10320,7 +10608,7 @@ function WriteApp({
10320
10608
  };
10321
10609
  }, [dryRun, enrichLinks2, input, links, unlinks, maxLinks, maxImages, onError, runMode]);
10322
10610
  useEffect3(() => {
10323
- if (!result && !errorMessage) {
10611
+ if (!result && !errorMessage2) {
10324
10612
  return;
10325
10613
  }
10326
10614
  const exitTimer = setTimeout(() => {
@@ -10329,8 +10617,8 @@ function WriteApp({
10329
10617
  return () => {
10330
10618
  clearTimeout(exitTimer);
10331
10619
  };
10332
- }, [errorMessage, exit, result]);
10333
- return /* @__PURE__ */ jsx7(PipelinePresenter, { prompt: input.idea, stages, result, errorMessage });
10620
+ }, [errorMessage2, exit, result]);
10621
+ return /* @__PURE__ */ jsx7(PipelinePresenter, { prompt: input.idea, stages, result, errorMessage: errorMessage2 });
10334
10622
  }
10335
10623
  async function runWriteCommand(options) {
10336
10624
  const input = await resolveInputWithInteractiveIdeaFallback(options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telepat/ideon",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "description": "CLI for generating rich articles and images from ideas.",
5
5
  "type": "module",
6
6
  "repository": {