{"version":3,"sources":["../src/handler.ts","../src/mongoJobStore.ts","../src/redisJobStore.ts","../src/localBridge.ts","../src/retryConfig.ts","../src/tokenBudget.ts"],"sourcesContent":["/**\n * Generic Lambda handler wrapper for worker agents.\n * Handles SQS events, executes user handlers, and sends webhook callbacks.\n * Job store: MongoDB only. Never uses HTTP/origin URL for job updates.\n */\n\nimport type { SQSEvent, SQSRecord, Context as LambdaContext } from 'aws-lambda';\nimport type { ZodType } from 'zod';\nimport { SQSClient, SendMessageCommand, GetQueueUrlCommand } from '@aws-sdk/client-sqs';\nimport {\n  createMongoJobStore,\n  upsertJob,\n  isMongoJobStoreConfigured,\n  getJobById as getMongoJobById,\n} from './mongoJobStore';\nimport {\n  createRedisJobStore,\n  upsertRedisJob,\n  isRedisJobStoreConfigured,\n  loadJob as loadRedisJob,\n} from './redisJobStore';\nimport {\n  appendQueueJobStepInStore,\n  updateQueueJobStepInStore,\n  upsertInitialQueueJob,\n  getQueueJob,\n} from './queueJobStore';\nimport {\n  createLocalJobStore,\n  upsertLocalJob,\n  loadLocalJob,\n} from './localJobStore';\nimport { getLocalDispatchBridge } from './localBridge';\nimport type { WorkerQueueContext, ChainContext, HitlResumeContext, QueueStepOutput, LoopContext } from './queue';\nimport { QUEUE_ORCHESTRATION_KEYS } from './queue';\nimport { type SmartRetryConfig, type RetryContext, executeWithRetry, matchesRetryPattern } from './retryConfig.js';\nimport { type TokenUsage, TokenBudgetExceededError, createTokenTracker } from './tokenBudget.js';\n\nexport interface JobStoreUpdate {\n  status?: 'queued' | 'running' | 'completed' | 'failed';\n  metadata?: Record<string, any>;\n  progress?: number;\n  progressMessage?: string;\n  output?: any;\n  error?: {\n    message: string;\n    stack?: string;\n    name?: string;\n  };\n}\n\nexport interface JobRecord {\n  jobId: string;\n  workerId: string;\n  status: 'queued' | 'running' | 'completed' | 'failed';\n  input: any;\n  output?: any;\n  error?: { message: string; stack?: string };\n  metadata?: Record<string, any>;\n  internalJobs?: Array<{ jobId: string; workerId: string; awaited?: boolean; delaySeconds?: number }>;\n  userId?: string;\n  createdAt: string;\n  updatedAt: string;\n  completedAt?: string;\n}\n\nexport interface JobStore {\n  /**\n   * Update job in job store.\n   * @param update - Update object with status, metadata, progress, output, or error\n   */\n  update(update: JobStoreUpdate): Promise<void>;\n  /**\n   * Get current job record from job store.\n   * @returns Job record or null if not found\n   */\n  get(): Promise<JobRecord | null>;\n  /**\n   * Append an internal (child) job to the current job's internalJobs list.\n   * Used when this worker dispatches another worker. `awaited` records whether the parent\n   * blocked on the child (dispatchWorker await:true) or fired it and moved on (await:false),\n   * so observability can distinguish the two.\n   */\n  appendInternalJob?(entry: {\n    jobId: string;\n    workerId: string;\n    awaited?: boolean;\n    delaySeconds?: number;\n  }): Promise<void>;\n  /**\n   * Get any job by jobId (e.g. to poll child job status when await: true).\n   * @returns Job record or null if not found\n   */\n  getJob?(jobId: string): Promise<JobRecord | null>;\n}\n\n/** Max SQS delay in seconds (AWS limit). */\nexport const SQS_MAX_DELAY_SECONDS = 900;\n\n/** Options for ctx.dispatchWorker (worker-to-worker). */\nexport interface DispatchWorkerOptions {\n  webhookUrl?: string;\n  metadata?: Record<string, any>;\n  /** Optional job ID for the child job (default: generated). */\n  jobId?: string;\n  /** If true, poll job store until child completes or fails; otherwise fire-and-forget. */\n  await?: boolean;\n  pollIntervalMs?: number;\n  pollTimeoutMs?: number;\n  /**\n   * Delay before the child is invoked (fire-and-forget only; ignored when await is true).\n   * Uses SQS DelaySeconds (0–900). In local mode, waits this many seconds before sending the trigger request.\n   */\n  delaySeconds?: number;\n}\n\n/**\n * Logger provided on ctx with prefixed levels: [INFO], [WARN], [ERROR], [DEBUG].\n * Each method accepts a message and optional data (logged as JSON).\n */\nexport interface WorkerLogger {\n  info(message: string, data?: Record<string, unknown>): void;\n  warn(message: string, data?: Record<string, unknown>): void;\n  error(message: string, data?: Record<string, unknown>): void;\n  debug(message: string, data?: Record<string, unknown>): void;\n}\n\nexport function createWorkerLogger(jobId: string, workerId: string): WorkerLogger {\n  const prefix = (level: string) => `[${level}] [${workerId}] [${jobId}]`;\n  return {\n    info(msg: string, data?: Record<string, unknown>) {\n      console.log(prefix('INFO'), msg, data !== undefined ? JSON.stringify(data) : '');\n    },\n    warn(msg: string, data?: Record<string, unknown>) {\n      console.warn(prefix('WARN'), msg, data !== undefined ? JSON.stringify(data) : '');\n    },\n    error(msg: string, data?: Record<string, unknown>) {\n      console.error(prefix('ERROR'), msg, data !== undefined ? JSON.stringify(data) : '');\n    },\n    debug(msg: string, data?: Record<string, unknown>) {\n      if (process.env.DEBUG || process.env.WORKER_DEBUG) {\n        console.debug(prefix('DEBUG'), msg, data !== undefined ? JSON.stringify(data) : '');\n      }\n    },\n  };\n}\n\nexport interface WorkerHandlerParams<INPUT, OUTPUT> {\n  input: INPUT;\n  ctx: {\n    jobId: string;\n    workerId: string;\n    requestId?: string;\n    /** ID of the user who triggered this job. Pass via DispatchOptions.userId from your API route. */\n    userId?: string;\n    /**\n     * Job store interface for updating and retrieving job state.\n     * Uses MongoDB directly when configured; never HTTP/origin URL.\n     */\n    jobStore?: JobStore;\n    /**\n     * Logger with prefixed levels: ctx.logger.info(), .warn(), .error(), .debug().\n     */\n    logger: WorkerLogger;\n    /**\n     * Dispatch another worker (fire-and-forget or await). Uses WORKER_QUEUE_URL_<SANITIZED_ID> env.\n     * Always provided by the runtime (Lambda and local).\n     */\n    dispatchWorker: (\n      workerId: string,\n      input: unknown,\n      options?: DispatchWorkerOptions\n    ) => Promise<{ jobId: string; messageId?: string; output?: unknown }>;\n    /**\n     * Report token usage after an LLM call. Accumulates across all calls in this job.\n     * Throws TokenBudgetExceededError if the configured maxTokens budget is exceeded.\n     * Also persists usage to the job store for observability.\n     *\n     * @example\n     * ```ts\n     * const result = await anthropic.messages.create({ ... });\n     * await ctx.reportTokenUsage({\n     *   inputTokens: result.usage.input_tokens,\n     *   outputTokens: result.usage.output_tokens,\n     * });\n     * ```\n     */\n    reportTokenUsage: (usage: TokenUsage) => Promise<void>;\n    /**\n     * Get the current token usage and remaining budget for this job.\n     * Returns `{ used, budget: null, remaining: null }` when no maxTokens was set.\n     */\n    getTokenBudget: () => { used: number; budget: number | null; remaining: number | null };\n    /**\n     * Populated on retry attempts (attempt >= 2). Contains info about the previous failure\n     * so the handler can self-correct (e.g. inject the error message into the next prompt).\n     * `undefined` on the first attempt — use `if (ctx.retryContext)` to detect retries.\n     */\n    retryContext?: RetryContext;\n    [key: string]: any;\n  };\n}\n\n// Re-export retry and token types so consumers can import from '@microfox/ai-worker'\nexport type { SmartRetryConfig, RetryContext, BuiltInRetryPattern, CustomRetryPattern, RetryPattern } from './retryConfig.js';\nexport type { TokenUsage, TokenBudgetState } from './tokenBudget.js';\nexport { TokenBudgetExceededError } from './tokenBudget.js';\n\nexport type WorkerHandler<INPUT, OUTPUT> = (\n  params: WorkerHandlerParams<INPUT, OUTPUT>\n) => Promise<OUTPUT>;\n\n/** Result of getNextStep for queue chaining. */\nexport interface QueueNextStep {\n  workerId: string;\n  delaySeconds?: number;\n  requiresApproval?: boolean;\n  /** Whether this step has a `chain` function (or built-in string) defined. */\n  hasChain?: boolean;\n  /** Whether this step has a `resume` function defined. */\n  hasResume?: boolean;\n  /** Optional HITL metadata from queue step config (UI/tooling only). */\n  hitl?: { ui?: unknown } | unknown;\n  /** Smart retry config for this step. Overrides worker-level retry for this step only. */\n  retry?: SmartRetryConfig;\n}\n\n// QueueStepOutput, ChainContext, HitlResumeContext are imported from './queue'\n// and re-exported via index.ts. No local definitions needed.\n\n/**\n * @deprecated Use {@link ChainContext} for the normal chain path and\n * {@link HitlResumeContext} for the HITL resume path instead.\n * Kept for backwards compatibility with queue files written against the old API.\n */\nexport interface MapStepInputContext {\n  initialInput: unknown;\n  previousOutputs: QueueStepOutput[];\n  /** @deprecated Use HitlResumeContext.reviewerInput instead. */\n  hitlInput?: unknown;\n  /** @deprecated Use HitlResumeContext.pendingInput instead. */\n  pendingStepInput?: Record<string, unknown>;\n}\n\n// Re-export new types so consumers can import from '@microfox/ai-worker/handler'\nexport type { ChainContext, HitlResumeContext, QueueStepOutput, LoopContext } from './queue';\n\n/** Runtime helpers for queue-aware wrappers (provided by generated registry). */\nexport interface QueueRuntime {\n  getNextStep(queueId: string, stepIndex: number): QueueNextStep | undefined;\n  /** Step config at `stepIndex`. */\n  getStepAt?(queueId: string, stepIndex: number): QueueNextStep | undefined;\n  /** Optional: when provided, mappers can use outputs from any previous step. */\n  getQueueJob?(queueJobId: string): Promise<{ steps: Array<{ workerId: string; output?: unknown }> } | null>;\n  /**\n   * Build the input for a step when the queue advances normally (no HITL resume).\n   * Calls the step's `chain` function, or the built-in passthrough/continueFromPrevious.\n   */\n  invokeChain?(queueId: string, stepIndex: number, ctx: ChainContext): Promise<unknown> | unknown;\n  /**\n   * Build the domain input for a step when it resumes after HITL approval.\n   * Calls the step's `resume` function, or merges pendingInput + reviewerInput by default.\n   */\n  invokeResume?(queueId: string, stepIndex: number, ctx: HitlResumeContext): Promise<unknown> | unknown;\n  /**\n   * Evaluate whether a looping step should run again.\n   * Calls the step's `loop.shouldContinue` function. Returns false if none defined.\n   */\n  invokeLoop?(queueId: string, stepIndex: number, ctx: LoopContext): Promise<boolean> | boolean;\n}\n\nconst WORKER_QUEUE_KEY = '__workerQueue';\n\n/** Build previous step outputs when resuming step `stepIndex` (excludes step `stepIndex` itself). */\nasync function loadPreviousOutputsBeforeStep(\n  queueRuntime: QueueRuntime,\n  queueJobId: string | undefined,\n  beforeStepIndex: number\n): Promise<QueueStepOutput[]> {\n  if (!queueJobId || typeof queueRuntime.getQueueJob !== 'function') {\n    return [];\n  }\n  try {\n    const job = await queueRuntime.getQueueJob(queueJobId);\n    if (!job?.steps) return [];\n    return job.steps\n      .slice(0, beforeStepIndex)\n      .map((s, i) => ({ stepIndex: i, workerId: s.workerId, output: s.output }));\n  } catch (e: any) {\n    if (process.env.AI_WORKER_QUEUES_DEBUG === '1') {\n      console.warn('[Worker] getQueueJob failed (resume mapping):', e?.message ?? e);\n    }\n    return [];\n  }\n}\n\n/**\n * When POST /approve forwards `__hitlInput`, call the step's `resume` function\n * (via `queueRuntime.invokeResume`) to merge reviewer payload with the pending\n * domain input. Runs before the user handler so it receives clean merged input.\n */\nasync function maybeApplyHitlResumeMapper<INPUT, OUTPUT>(\n  params: WorkerHandlerParams<INPUT, OUTPUT>,\n  queueRuntime: QueueRuntime\n): Promise<void> {\n  const inputObj = params.input as Record<string, unknown> | null;\n  if (!inputObj || typeof inputObj !== 'object') return;\n  if (!('__hitlInput' in inputObj)) return;\n\n  const wq = inputObj[WORKER_QUEUE_KEY] as WorkerQueueContext | undefined;\n  if (!wq?.id || typeof wq.stepIndex !== 'number') return;\n\n  const queueId = wq.id;\n  const stepIndex = wq.stepIndex;\n  const initialInput = wq.initialInput;\n  const queueJobId = wq.queueJobId;\n  const previousOutputs = await loadPreviousOutputsBeforeStep(queueRuntime, queueJobId, stepIndex);\n\n  // Build pending domain input — strip all envelope keys.\n  const pendingInput: Record<string, unknown> = { ...inputObj };\n  for (const key of QUEUE_ORCHESTRATION_KEYS) {\n    delete pendingInput[key];\n  }\n  delete pendingInput[WORKER_QUEUE_KEY];\n\n  const reviewerInput = inputObj.__hitlInput;\n  const decision = inputObj.__hitlDecision;\n\n  let merged: unknown;\n  if (typeof queueRuntime.invokeResume === 'function') {\n    merged = await queueRuntime.invokeResume(queueId, stepIndex, {\n      initialInput,\n      previousOutputs,\n      reviewerInput,\n      pendingInput,\n    });\n  } else {\n    // Default: shallow merge pendingInput + reviewerInput.\n    merged = {\n      ...pendingInput,\n      ...(reviewerInput !== null && typeof reviewerInput === 'object'\n        ? (reviewerInput as Record<string, unknown>)\n        : {}),\n    };\n  }\n\n  const mergedObj =\n    merged !== null && typeof merged === 'object'\n      ? (merged as Record<string, unknown>)\n      : { value: merged };\n\n  (params as { input: INPUT }).input = {\n    ...mergedObj,\n    [WORKER_QUEUE_KEY]: wq,\n    ...(decision !== undefined ? { __hitlDecision: decision } : {}),\n  } as INPUT;\n}\n\n/** Read embedded queue context from job input or metadata without `as any`. */\nfunction getWorkerQueueContext(\n  input: unknown,\n  metadata?: Record<string, unknown>\n): WorkerQueueContext | undefined {\n  const fromInput =\n    input !== null && typeof input === 'object' && WORKER_QUEUE_KEY in input\n      ? (input as Record<string, unknown>)[WORKER_QUEUE_KEY]\n      : undefined;\n  const fromMeta =\n    metadata !== undefined && typeof metadata === 'object' && WORKER_QUEUE_KEY in metadata\n      ? (metadata as Record<string, unknown>)[WORKER_QUEUE_KEY]\n      : undefined;\n  const q = fromInput ?? fromMeta;\n  if (q === null || typeof q !== 'object') return undefined;\n  return q as WorkerQueueContext;\n}\n\nasync function notifyQueueJobStep(\n  queueJobId: string,\n  action: 'start' | 'awaiting_approval' | 'complete' | 'fail' | 'append',\n  params: {\n    stepIndex?: number;\n    workerJobId: string;\n    workerId?: string;\n    output?: unknown;\n    error?: { message: string };\n    input?: unknown;\n    queueId?: string;\n  }\n): Promise<void> {\n  try {\n    if (action === 'append') {\n      if (!params.workerId || !params.workerJobId) return;\n    await appendQueueJobStepInStore({\n      queueJobId,\n      workerId: params.workerId,\n      workerJobId: params.workerJobId,\n    });\n    if (process.env.DEBUG_WORKER_QUEUES === '1') {\n      console.log('[Worker] Queue job step appended', {\n        queueJobId,\n        workerId: params.workerId,\n        workerJobId: params.workerJobId,\n      });\n    }\n      return;\n    }\n\n    if (params.stepIndex === undefined) return;\n\n    const status =\n      action === 'start'\n        ? 'running'\n        : action === 'awaiting_approval'\n          ? 'awaiting_approval'\n        : action === 'complete'\n          ? 'completed'\n          : action === 'fail'\n            ? 'failed'\n            : undefined;\n    if (!status) return;\n\n    await updateQueueJobStepInStore({\n      queueJobId,\n      stepIndex: params.stepIndex,\n      workerId: params.workerId || '',\n      workerJobId: params.workerJobId,\n      status,\n      input: params.input,\n      output: params.output,\n      error: params.error,\n    });\n    // Always log queue step updates so logs show which queue and step ran\n    console.log('[Worker] Queue job step updated', {\n      queueId: params.queueId ?? queueJobId,\n      queueJobId,\n      stepIndex: params.stepIndex,\n      workerId: params.workerId,\n      status,\n    });\n  } catch (err: any) {\n    // Append must succeed before we can complete the current step with a \"next\" step;\n    // otherwise step 0 complete + only 1 row in store marks the whole queue completed.\n    if (action === 'append') {\n      console.error('[Worker] Queue append failed (rethrowing):', {\n        queueJobId,\n        error: err?.message ?? String(err),\n      });\n      throw err;\n    }\n    console.warn('[Worker] Queue job update error:', {\n      queueJobId,\n      action,\n      error: err?.message ?? String(err),\n    });\n  }\n}\n\n/**\n * Wraps a user handler so that when the job has `__workerQueue` context (from\n * `dispatchQueue` or queue cron), it dispatches the next worker in the sequence\n * **after** the handler completes.\n *\n * All queue/HITL envelope keys (`__workerQueue`, `__hitlInput`, `__hitlDecision`,\n * `__hitlPending`, `hitl`) are **stripped from `params.input` before the user handler\n * runs** — workers receive clean domain input and do not need to accept these keys\n * in their Zod schemas.\n *\n * **HITL resume:** When `__hitlInput` is present, `invokeResume` is called first to\n * produce the merged domain input. **Chain advancement:** After a step completes,\n * `invokeChain` is called to compute the next step's input.\n */\nexport function wrapHandlerForQueue<INPUT, OUTPUT>(\n  handler: WorkerHandler<INPUT, OUTPUT>,\n  queueRuntime: QueueRuntime\n): WorkerHandler<INPUT, OUTPUT> {\n  return async (params) => {\n    // 1. On HITL resume, merge reviewer payload into domain input first.\n    await maybeApplyHitlResumeMapper(params, queueRuntime);\n\n    const inputObj =\n      params.input !== null && typeof params.input === 'object'\n        ? (params.input as Record<string, unknown>)\n        : {};\n\n    // 2. Save queue context before stripping (needed for chain dispatch after handler).\n    const queueContextRaw = inputObj[WORKER_QUEUE_KEY];\n\n    // Resolve step-level retry config before stripping (uses queueId + stepIndex from envelope).\n    const queueCtxForRetry =\n      queueContextRaw && typeof queueContextRaw === 'object'\n        ? (queueContextRaw as WorkerQueueContext)\n        : undefined;\n    const stepRetryConfig: SmartRetryConfig | undefined =\n      queueCtxForRetry?.id && typeof queueCtxForRetry.stepIndex === 'number' &&\n      typeof queueRuntime.getStepAt === 'function'\n        ? (queueRuntime.getStepAt(queueCtxForRetry.id, queueCtxForRetry.stepIndex) as any)?.retry\n        : undefined;\n\n    // 3. Strip all orchestration keys so the user handler sees only domain input.\n    const domainInput: Record<string, unknown> = { ...inputObj };\n    for (const key of QUEUE_ORCHESTRATION_KEYS) {\n      delete domainInput[key];\n    }\n    delete domainInput[WORKER_QUEUE_KEY];\n    (params as { input: unknown }).input = domainInput;\n\n    // 4. Run user handler with clean domain input (with optional step-level retry).\n    let output: OUTPUT;\n    if (stepRetryConfig && stepRetryConfig.on.length > 0) {\n      output = await executeWithRetry(\n        async (retryCtx) => {\n          (params.ctx as any).retryContext = retryCtx;\n          return handler(params);\n        },\n        stepRetryConfig,\n        (retryCtx, delayMs) => {\n          const logger = (params.ctx as any).logger;\n          if (logger?.warn) {\n            logger.warn(\n              `[queue-retry] Retrying step (attempt ${retryCtx.attempt}/${retryCtx.maxAttempts}): ${retryCtx.lastError.message}`,\n              { delayMs }\n            );\n          } else {\n            console.warn('[queue-retry] Step retry', { attempt: retryCtx.attempt, error: retryCtx.lastError.message, delayMs });\n          }\n        }\n      );\n    } else {\n      output = await handler(params);\n    }\n\n    if (!queueContextRaw || typeof queueContextRaw !== 'object') {\n      return output;\n    }\n    const queueContext = queueContextRaw as WorkerQueueContext;\n    if (!queueContext.id) {\n      return output;\n    }\n\n    const { id: queueId, stepIndex, initialInput, queueJobId } = queueContext;\n    // arrayStepIndex tracks the actual steps[] position — differs from stepIndex for loop iterations.\n    const arrayStepIndex = (queueContext as WorkerQueueContext).arrayStepIndex ?? stepIndex;\n    const jobId = params.ctx.jobId;\n    const workerId = params.ctx.workerId ?? '';\n\n    const next = queueRuntime.getNextStep(queueId, stepIndex);\n    const childJobId = next ? `job-${Date.now()}-${Math.random().toString(36).slice(2, 11)}` : undefined;\n\n    // 5a. Check loop BEFORE appending next step or marking current complete.\n    // This fixes two bugs in the original ordering:\n    //   1. Premature queue completion: if this is the last step and the loop fires,\n    //      marking complete before appending the loop step closes the queue early.\n    //   2. Double-append: if there IS a next step and the loop fires, both the next step\n    //      and the loop step get appended, orphaning the next step.\n    const iterationCount = (queueContext as WorkerQueueContext).iterationCount ?? 0;\n    if (typeof queueRuntime.invokeLoop === 'function') {\n      const currentStep = typeof queueRuntime.getStepAt === 'function'\n        ? queueRuntime.getStepAt(queueId, stepIndex)\n        : undefined;\n      const maxIterations = (currentStep as any)?.loop?.maxIterations ?? 50;\n      if (iterationCount < maxIterations - 1) {\n        let previousOutputsForLoop: QueueStepOutput[] = [];\n        // Capture steps.length before appending so we know the array index of the\n        // new loop step (used for awaiting_approval and as arrayStepIndex next iteration).\n        let stepsLengthBeforeAppend = arrayStepIndex + 1; // fallback\n        if (queueJobId && typeof queueRuntime.getQueueJob === 'function') {\n          try {\n            const job = await queueRuntime.getQueueJob(queueJobId);\n            if (job?.steps) {\n              previousOutputsForLoop = job.steps\n                .slice(0, stepIndex)\n                .map((s, i) => ({ stepIndex: i, workerId: s.workerId, output: s.output }));\n              stepsLengthBeforeAppend = job.steps.length;\n            }\n          } catch { /* ignore */ }\n        }\n        previousOutputsForLoop = previousOutputsForLoop.concat([{ stepIndex, workerId, output }]);\n\n        const shouldLoop = await queueRuntime.invokeLoop(queueId, stepIndex, {\n          output,\n          stepIndex,\n          iterationCount,\n          initialInput,\n          previousOutputs: previousOutputsForLoop,\n        });\n\n        if (shouldLoop) {\n          const loopJobId = `job-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n          // Build loop-iteration input via chain (same step, re-mapped from current output).\n          let loopInput: unknown = output;\n          if (typeof queueRuntime.invokeChain === 'function') {\n            loopInput = await queueRuntime.invokeChain(queueId, stepIndex, {\n              initialInput,\n              previousOutputs: previousOutputsForLoop,\n            });\n          }\n          const loopInputWithQueue = {\n            ...(loopInput !== null && typeof loopInput === 'object'\n              ? (loopInput as Record<string, unknown>)\n              : { value: loopInput }),\n            [WORKER_QUEUE_KEY]: {\n              id: queueId,\n              stepIndex,                           // definition index stays fixed\n              arrayStepIndex: stepsLengthBeforeAppend, // actual index for next iteration\n              initialInput,\n              queueJobId,\n              iterationCount: iterationCount + 1,\n            },\n          };\n\n          // Append loop step FIRST so mark-complete sees it — keeps queue running.\n          if (queueJobId) {\n            await notifyQueueJobStep(queueJobId, 'append', { workerJobId: loopJobId, workerId });\n          }\n          // Now mark current step complete using its actual array index.\n          if (queueJobId && typeof arrayStepIndex === 'number') {\n            await notifyQueueJobStep(queueJobId, 'complete', {\n              queueId,\n              stepIndex: arrayStepIndex,\n              workerJobId: jobId,\n              workerId,\n              output,\n            });\n          }\n\n          if (currentStep?.requiresApproval && queueJobId) {\n            const hitlUiSpec =\n              currentStep.hitl && typeof currentStep.hitl === 'object' && 'ui' in (currentStep.hitl as Record<string, unknown>)\n                ? (currentStep.hitl as Record<string, unknown>).ui\n                : undefined;\n            const pendingInput = {\n              ...loopInputWithQueue,\n              ...(hitlUiSpec !== undefined ? { hitl: { uiSpec: hitlUiSpec } } : {}),\n              __hitlPending: {\n                queueId,\n                queueJobId,\n                stepIndex,\n                workerId,\n                createdAt: new Date().toISOString(),\n              },\n            };\n            // Use stepsLengthBeforeAppend as the array index of the just-appended loop step.\n            await notifyQueueJobStep(queueJobId, 'awaiting_approval', {\n              queueId,\n              stepIndex: stepsLengthBeforeAppend,\n              workerJobId: loopJobId,\n              workerId,\n              input: pendingInput,\n            });\n            return output;\n          }\n\n          await params.ctx.dispatchWorker(workerId, loopInputWithQueue, {\n            await: false,\n            jobId: loopJobId,\n          });\n          return output;\n        }\n      }\n    }\n\n    // No loop fired — normal advance: append next step first, then mark current complete.\n    if (next && queueJobId) {\n      // Append next step first so complete-step update sees steps.length > 1 (queue not yet done).\n      await notifyQueueJobStep(queueJobId, 'append', {\n        workerJobId: childJobId!,\n        workerId: next.workerId,\n      });\n    }\n\n    // Notify current step complete using its actual array index.\n    if (queueJobId && typeof arrayStepIndex === 'number') {\n      await notifyQueueJobStep(queueJobId, 'complete', {\n        queueId,\n        stepIndex: arrayStepIndex,\n        workerJobId: jobId,\n        workerId,\n        output,\n      });\n    }\n\n    if (!next) {\n      return output;\n    }\n\n    // 5c. Build next step input via invokeChain (uses the step's chain fn or built-in).\n    let nextInput: unknown = output;\n    if (typeof queueRuntime.invokeChain === 'function') {\n      let previousOutputs: QueueStepOutput[] = [];\n      if (queueJobId && typeof queueRuntime.getQueueJob === 'function') {\n        try {\n          const job = await queueRuntime.getQueueJob(queueJobId);\n          if (job?.steps) {\n            const fromStore = job.steps\n              .slice(0, stepIndex)\n              .map((s, i) => ({ stepIndex: i, workerId: s.workerId, output: s.output }));\n            previousOutputs = fromStore.concat([\n              { stepIndex, workerId: params.ctx.workerId ?? '', output },\n            ]);\n          }\n        } catch (e: any) {\n          if (process.env.AI_WORKER_QUEUES_DEBUG === '1') {\n            console.warn('[Worker] getQueueJob failed, mapping without previousOutputs:', e?.message ?? e);\n          }\n        }\n      }\n      nextInput = await queueRuntime.invokeChain(queueId, stepIndex + 1, {\n        initialInput,\n        previousOutputs,\n      });\n    }\n\n    const nextInputWithQueue = {\n      ...(nextInput !== null && typeof nextInput === 'object' ? (nextInput as Record<string, unknown>) : { value: nextInput }),\n      [WORKER_QUEUE_KEY]: {\n        id: queueId,\n        stepIndex: stepIndex + 1,\n        initialInput,\n        queueJobId,\n      },\n    };\n\n    const debug = process.env.AI_WORKER_QUEUES_DEBUG === '1';\n    if (debug) {\n      console.log('[Worker] Queue chain dispatching next:', {\n        queueId,\n        fromStep: stepIndex,\n        nextWorkerId: next.workerId,\n        delaySeconds: next.delaySeconds,\n      });\n    }\n\n    if (next.requiresApproval && queueJobId && typeof stepIndex === 'number') {\n      const hitlUiSpec =\n        next.hitl && typeof next.hitl === 'object' && 'ui' in (next.hitl as Record<string, unknown>)\n          ? (next.hitl as Record<string, unknown>).ui\n          : undefined;\n      const pendingInput = {\n        ...nextInputWithQueue,\n        ...(hitlUiSpec !== undefined ? { hitl: { uiSpec: hitlUiSpec } } : {}),\n        __hitlPending: {\n          queueId,\n          queueJobId,\n          stepIndex: stepIndex + 1,\n          workerId: next.workerId,\n          createdAt: new Date().toISOString(),\n        },\n      };\n      await notifyQueueJobStep(queueJobId, 'awaiting_approval', {\n        queueId,\n        stepIndex: stepIndex + 1,\n        workerJobId: childJobId!,\n        workerId: next.workerId,\n        input: pendingInput,\n      });\n      if (debug) {\n        console.log('[Worker] Queue chain paused for HITL approval:', {\n          queueId,\n          queueJobId,\n          nextStep: stepIndex + 1,\n          nextWorkerId: next.workerId,\n          pendingWorkerJobId: childJobId,\n        });\n      }\n      return output;\n    }\n\n    await params.ctx.dispatchWorker(next.workerId, nextInputWithQueue, {\n      await: false,\n      delaySeconds: next.delaySeconds,\n      jobId: childJobId,\n    });\n\n    return output;\n  };\n}\n\nexport interface SQSMessageBody {\n  workerId: string;\n  jobId: string;\n  input: any;\n  context: Record<string, any>;\n  webhookUrl?: string;\n  /** @deprecated Never use. Job updates use MongoDB only. */\n  jobStoreUrl?: string;\n  metadata?: Record<string, any>;\n  timestamp: string;\n  /** ID of the user who triggered this job. Forwarded from dispatch options. */\n  userId?: string;\n  /** Maximum total tokens (input + output) for this job. Forwarded from DispatchOptions.maxTokens. */\n  maxTokens?: number;\n}\n\nexport interface WebhookPayload {\n  jobId: string;\n  workerId: string;\n  status: 'success' | 'error';\n  output?: any;\n  error?: {\n    message: string;\n    stack?: string;\n    name?: string;\n  };\n  metadata?: Record<string, any>;\n}\n\nconst DEFAULT_POLL_INTERVAL_MS = 2000;\nconst DEFAULT_POLL_TIMEOUT_MS = 15 * 60 * 1000; // 15 minutes\n\n/** Job store backend selected by WORKER_DATABASE_TYPE. 'local' must be set explicitly (dev server); it is never a fallback. */\nexport type JobStoreKind = 'mongodb' | 'upstash-redis' | 'local';\n\nexport function getJobStoreKind(): JobStoreKind {\n  const raw = (process.env.WORKER_DATABASE_TYPE || 'upstash-redis').toLowerCase();\n  if (raw === 'mongodb') return 'mongodb';\n  if (raw === 'local') return 'local';\n  return 'upstash-redis';\n}\n\n/**\n * Load any job record via the configured store. Selection mirrors createLambdaHandler:\n * explicit 'local' > redis (when selected AND configured) > mongo (when selected OR configured).\n */\nexport async function loadJobRecordById(jobId: string): Promise<JobRecord | null> {\n  const kind = getJobStoreKind();\n  if (kind === 'local') {\n    return loadLocalJob(jobId);\n  }\n  if (kind === 'upstash-redis' && isRedisJobStoreConfigured()) {\n    return loadRedisJob(jobId);\n  }\n  if (kind === 'mongodb' || isMongoJobStoreConfigured()) {\n    return getMongoJobById(jobId);\n  }\n  return null;\n}\n\nfunction sanitizeWorkerIdForEnv(workerId: string): string {\n  return workerId.replace(/-/g, '_').toUpperCase();\n}\n\nasync function resolveQueueUrlForWorker(calleeWorkerId: string): Promise<string | undefined> {\n  const key = `WORKER_QUEUE_URL_${sanitizeWorkerIdForEnv(calleeWorkerId)}`;\n  const fromEnv = process.env[key]?.trim();\n  if (fromEnv) return fromEnv;\n  const serviceName = process.env.WORKER_SERVICE_NAME;\n  if (!serviceName) return undefined;\n  const stage = process.env.ENVIRONMENT || process.env.STAGE || 'prod';\n  const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1';\n  const queueName = `${serviceName}-${calleeWorkerId}-${stage}`;\n  try {\n    const sqs = new SQSClient({ region });\n    const { QueueUrl } = await sqs.send(new GetQueueUrlCommand({ QueueName: queueName }));\n    return QueueUrl ?? undefined;\n  } catch {\n    return undefined;\n  }\n}\n\n/**\n * Create dispatchWorker for use in handler context (Lambda).\n * Sends message to SQS, appends to parent internalJobs, optionally polls until child completes.\n */\nfunction createDispatchWorker(\n  parentJobId: string,\n  parentWorkerId: string,\n  parentContext: Record<string, any>,\n  jobStore: JobStore | undefined\n): (\n  workerId: string,\n  input: unknown,\n  options?: DispatchWorkerOptions\n) => Promise<{ jobId: string; messageId?: string; output?: unknown }> {\n  return async (\n    calleeWorkerId: string,\n    input: unknown,\n    options?: DispatchWorkerOptions\n  ): Promise<{ jobId: string; messageId?: string; output?: unknown }> => {\n    const childJobId =\n      options?.jobId ||\n      `job-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n    // Provenance stamp (`metadata.__trigger`): records HOW this child run was triggered, persisted\n    // verbatim into the child's job record so observability can always show \"triggered by\" without\n    // walking the parent's internalJobs. Queue chain dispatches (input carries __workerQueue) are\n    // stamped `queue`; plain dispatchWorker calls are stamped `worker`. A caller-supplied\n    // metadata.__trigger wins (e.g. the queue starter or console stamping a more precise origin).\n    const dispatchQueueCtx =\n      input !== null && typeof input === 'object' && WORKER_QUEUE_KEY in input\n        ? ((input as Record<string, unknown>)[WORKER_QUEUE_KEY] as WorkerQueueContext)\n        : undefined;\n    const metadata: Record<string, any> = { ...(options?.metadata ?? {}) };\n    if (metadata.__trigger === undefined) {\n      metadata.__trigger = dispatchQueueCtx?.id\n        ? {\n            type: 'queue',\n            queueId: dispatchQueueCtx.id,\n            queueJobId: dispatchQueueCtx.queueJobId,\n            parentJobId,\n            parentWorkerId,\n          }\n        : {\n            type: 'worker',\n            parentJobId,\n            parentWorkerId,\n            awaited: options?.await === true,\n          };\n    }\n    const serializedContext: Record<string, any> = {};\n    if (parentContext.requestId) serializedContext.requestId = parentContext.requestId;\n    if (parentContext.userId) serializedContext.userId = parentContext.userId;\n\n    const messageBody: SQSMessageBody = {\n      workerId: calleeWorkerId,\n      jobId: childJobId,\n      input: input ?? {},\n      context: serializedContext,\n      webhookUrl: options?.webhookUrl,\n      metadata,\n      timestamp: new Date().toISOString(),\n    };\n\n    // SQS message timer (per-message DelaySeconds): message stays invisible for N seconds.\n    // Calling worker returns immediately; no computation during delay. See:\n    // https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-delay-queues.html\n    // The local bridge honors the same clamped value via setTimeout.\n    const delaySeconds =\n      options?.await !== true && options?.delaySeconds != null\n        ? Math.min(SQS_MAX_DELAY_SECONDS, Math.max(0, Math.floor(options.delaySeconds)))\n        : undefined;\n\n    let messageId: string | undefined;\n    const localBridge = getLocalDispatchBridge();\n    if (localBridge) {\n      // Local dev mode (`ai-worker dev`): hand the message to the in-process queue\n      // instead of SQS. Only reachable when the dev server installed the bridge\n      // global AND set AI_WORKER_LOCAL=1 — never in a deployed Lambda.\n      const result = await localBridge.enqueue(calleeWorkerId, messageBody, delaySeconds);\n      messageId = result?.messageId;\n    } else {\n      const queueUrl = await resolveQueueUrlForWorker(calleeWorkerId);\n      if (!queueUrl) {\n        // No queue URL found — env var missing and WORKER_SERVICE_NAME not set for SQS fallback.\n        throw new Error(\n          `Cannot dispatch to worker \"${calleeWorkerId}\": WORKER_QUEUE_URL_${sanitizeWorkerIdForEnv(calleeWorkerId)} is not set` +\n            ' and WORKER_SERVICE_NAME is not configured for SQS fallback lookup.'\n        );\n      }\n      const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1';\n      const sqs = new SQSClient({ region });\n      const sendResult = await sqs.send(\n        new SendMessageCommand({\n          QueueUrl: queueUrl,\n          MessageBody: JSON.stringify(messageBody),\n          ...(delaySeconds !== undefined && delaySeconds > 0 ? { DelaySeconds: delaySeconds } : {}),\n        })\n      );\n      messageId = sendResult.MessageId ?? undefined;\n    }\n\n    if (jobStore?.appendInternalJob) {\n      await jobStore.appendInternalJob({\n        jobId: childJobId,\n        workerId: calleeWorkerId,\n        awaited: options?.await === true,\n        ...(delaySeconds !== undefined ? { delaySeconds } : {}),\n      });\n    }\n\n    if (options?.await && jobStore?.getJob) {\n      const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n      const pollTimeoutMs = options.pollTimeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;\n      const deadline = Date.now() + pollTimeoutMs;\n      while (Date.now() < deadline) {\n        const child = await jobStore.getJob(childJobId);\n        if (!child) {\n          await new Promise((r) => setTimeout(r, pollIntervalMs));\n          continue;\n        }\n        if (child.status === 'completed') {\n          return { jobId: childJobId, messageId, output: child.output };\n        }\n        if (child.status === 'failed') {\n          const err = child.error;\n          throw new Error(\n            err?.message ?? `Child worker ${calleeWorkerId} failed`\n          );\n        }\n        await new Promise((r) => setTimeout(r, pollIntervalMs));\n      }\n      throw new Error(\n        `Child worker ${calleeWorkerId} (${childJobId}) did not complete within ${pollTimeoutMs}ms`\n      );\n    }\n\n    return { jobId: childJobId, messageId };\n  };\n}\n\n/**\n * Sends a webhook callback to the specified URL.\n */\nasync function sendWebhook(\n  webhookUrl: string,\n  payload: WebhookPayload\n): Promise<void> {\n  try {\n    const headers: Record<string, string> = {\n      'Content-Type': 'application/json',\n      'User-Agent': 'ai-router-worker/1.0',\n    };\n    // Present the internal shared secret so the consumer app can authorize this\n    // Lambda→app callback (the webhook route gates on it). Falls back to WORKERS_API_KEY so a\n    // single shared secret covers both surfaces. No-op when neither is set.\n    const internalSecret = process.env.WORKFLOW_INTERNAL_SECRET || process.env.WORKERS_API_KEY;\n    if (internalSecret && internalSecret.trim()) {\n      headers['x-workflow-secret'] = internalSecret.trim();\n    }\n    const response = await fetch(webhookUrl, {\n      method: 'POST',\n      headers,\n      body: JSON.stringify(payload),\n    });\n\n    if (!response.ok) {\n      const errorText = await response.text().catch(() => '');\n      console.error('[Worker] Webhook callback failed:', {\n        url: webhookUrl,\n        status: response.status,\n        statusText: response.statusText,\n        errorText,\n      });\n      // Don't throw - webhook failures shouldn't fail the Lambda\n    } else {\n      console.log('[Worker] Webhook callback successful:', {\n        url: webhookUrl,\n        status: response.status,\n      });\n    }\n  } catch (error: any) {\n    console.error('[Worker] Webhook callback error:', {\n      url: webhookUrl,\n      error: error?.message || String(error),\n      stack: error?.stack,\n    });\n    // Don't throw - webhook failures shouldn't fail the Lambda\n  }\n}\n\n/**\n * Creates a Lambda handler function that processes SQS events for workers.\n * Job store: MongoDB only. Never uses HTTP/origin URL for job updates.\n *\n * @param handler - The user's worker handler function\n * @param outputSchema - Optional Zod schema for output validation\n * @returns A Lambda handler function\n */\nexport function createLambdaHandler<INPUT, OUTPUT>(\n  handler: WorkerHandler<INPUT, OUTPUT>,\n  outputSchema?: ZodType<OUTPUT>,\n  options?: { retry?: SmartRetryConfig }\n): (event: SQSEvent, context: LambdaContext) => Promise<void> {\n  return async (event: SQSEvent, lambdaContext: LambdaContext) => {\n    // Unambiguous entry log: confirms the worker Lambda was actually invoked by SQS (vs. the\n    // message never arriving). Pair this with the [workers-trigger] \"message ENQUEUED\" log to\n    // see whether a trigger reached its worker.\n    console.log('[Worker] SQS event received', {\n      records: event.Records?.length ?? 0,\n      awsRequestId: lambdaContext?.awsRequestId,\n    });\n    const promises = event.Records.map(async (record: SQSRecord) => {\n      let messageBody: SQSMessageBody | null = null;\n      try {\n        messageBody = JSON.parse(record.body) as SQSMessageBody;\n\n        const { workerId, jobId, input, context, webhookUrl, metadata = {}, userId: messageUserId, maxTokens } =\n          messageBody;\n        // userId flows from dispatch options → context.userId → messageBody.userId\n        const userId: string | undefined = (context.userId as string | undefined) ?? messageUserId;\n\n        // Authoritative jobId ↔ Lambda requestId marker. A single strict-JSON line on a unique,\n        // greppable token so the console can map our custom jobId to the AWS requestId, then pull\n        // the EXACT CloudWatch invocation batch (START..REPORT for that requestId) — not just the\n        // lines that happen to mention the jobId.\n        console.log(\n          '[AIWORKER_RUN] ' +\n            JSON.stringify({ jobId, workerId, awsRequestId: lambdaContext?.awsRequestId })\n        );\n\n        // Idempotency: skip if this job was already completed or failed (e.g. SQS redelivery or duplicate trigger).\n        // Only the Lambda that processes a message creates/updates that job's key; parent workers only append to internalJobs and poll – they never write child job documents.\n        const jobStoreType = getJobStoreKind();\n        const existing = await loadJobRecordById(jobId);\n        if (existing && (existing.status === 'completed' || existing.status === 'failed')) {\n          console.log('[Worker] Skipping already terminal job (idempotent):', {\n            jobId,\n            workerId,\n            status: existing.status,\n          });\n          return;\n        }\n\n        // Select job store and upsert this message's job only (never write child job documents from parent).\n        let jobStore: JobStore | undefined;\n        if (jobStoreType === 'local') {\n          await upsertLocalJob(jobId, workerId, input, metadata, userId);\n          jobStore = createLocalJobStore(workerId, jobId, input, metadata, userId);\n        } else if (\n          jobStoreType === 'upstash-redis' &&\n          isRedisJobStoreConfigured()\n        ) {\n          await upsertRedisJob(jobId, workerId, input, metadata, userId);\n          jobStore = createRedisJobStore(workerId, jobId, input, metadata, userId);\n        } else if (\n          jobStoreType === 'mongodb' ||\n          isMongoJobStoreConfigured()\n        ) {\n          await upsertJob(jobId, workerId, input, metadata, userId);\n          jobStore = createMongoJobStore(workerId, jobId, input, metadata, userId);\n        }\n\n        // Emit a parseable audit log so log queries can find all jobs by user.\n        // Pattern: [WORKER_USER:<userId>] — grep for this to extract caller userId.\n        if (userId) {\n          console.log(`[WORKER_USER:${userId}]`, { jobId, workerId, timestamp: new Date().toISOString() });\n        }\n\n        const baseContext = {\n          jobId,\n          workerId,\n          requestId: context.requestId || lambdaContext.awsRequestId,\n          ...(userId ? { userId } : {}),\n          ...context,\n        };\n\n        // Token budget tracker — enforces maxTokens if set, accumulates otherwise.\n        const tokenTracker = createTokenTracker(maxTokens ?? null);\n        const logger = createWorkerLogger(jobId, workerId);\n\n        const handlerContext: any = {\n          ...baseContext,\n          ...(jobStore ? { jobStore } : {}),\n          logger,\n          dispatchWorker: createDispatchWorker(jobId, workerId, baseContext, jobStore),\n          reportTokenUsage: async (usage: TokenUsage) => {\n            tokenTracker.report(usage); // throws TokenBudgetExceededError if over limit\n            const state = tokenTracker.getState();\n            if (jobStore) {\n              await jobStore.update({ metadata: { tokenUsage: state } }).catch((e: any) => {\n                logger.warn('Failed to persist tokenUsage to job store', { error: e?.message });\n              });\n            }\n          },\n          getTokenBudget: () => tokenTracker.getBudgetInfo(),\n          retryContext: undefined as RetryContext | undefined,\n        };\n\n        if (jobStore) {\n          try {\n            await jobStore.update({ status: 'running' });\n            const queueCtxForLog = getWorkerQueueContext(input, metadata);\n            console.log('[Worker] Job status updated to running:', {\n              jobId,\n              workerId,\n              ...(queueCtxForLog?.id && { queueId: queueCtxForLog.id }),\n              ...(queueCtxForLog?.queueJobId && { queueJobId: queueCtxForLog.queueJobId }),\n            });\n          } catch (error: any) {\n            console.warn('[Worker] Failed to update status to running:', {\n              jobId,\n              workerId,\n              error: error?.message || String(error),\n            });\n          }\n        }\n\n        const queueCtx = getWorkerQueueContext(input, metadata);\n        if (queueCtx?.queueJobId && typeof queueCtx.stepIndex === 'number') {\n          // Ensure initial queue job exists (mainly for cron/queue-starter paths)\n          if (queueCtx.stepIndex === 0) {\n            try {\n              await upsertInitialQueueJob({\n                queueJobId: queueCtx.queueJobId,\n                queueId: queueCtx.id,\n                firstWorkerId: workerId,\n                firstWorkerJobId: jobId,\n                metadata,\n                userId,\n              });\n            } catch (e: any) {\n              console.warn('[Worker] Failed to upsert initial queue job:', {\n                queueJobId: queueCtx.queueJobId,\n                queueId: queueCtx.id,\n                error: e?.message ?? String(e),\n              });\n            }\n          }\n          await notifyQueueJobStep(queueCtx.queueJobId, 'start', {\n            queueId: queueCtx.id,\n            // Use arrayStepIndex when set — it tracks the actual steps[] position for\n            // looping steps where the definition index stays fixed across iterations.\n            stepIndex: queueCtx.arrayStepIndex ?? queueCtx.stepIndex,\n            workerJobId: jobId,\n            workerId,\n            input,\n          });\n        }\n\n        let output: OUTPUT;\n        try {\n          const workerRetryConfig = options?.retry;\n          const executeHandler = async (retryCtx: RetryContext | undefined): Promise<OUTPUT> => {\n            handlerContext.retryContext = retryCtx;\n            const result = await handler({ input: input as INPUT, ctx: handlerContext });\n            return outputSchema ? outputSchema.parse(result) : result;\n          };\n\n          if (workerRetryConfig && workerRetryConfig.on.length > 0) {\n            output = await executeWithRetry(executeHandler, workerRetryConfig, (retryCtx, delayMs) => {\n              logger.warn(\n                `[worker-retry] Retrying handler (attempt ${retryCtx.attempt}/${retryCtx.maxAttempts}): ${retryCtx.lastError.message}`,\n                { delayMs }\n              );\n            });\n          } else {\n            output = await executeHandler(undefined);\n          }\n        } catch (error: any) {\n          const errorPayload: WebhookPayload = {\n            jobId,\n            workerId,\n            status: 'error',\n            error: {\n              message: error.message || 'Unknown error',\n              stack: error.stack,\n              name: error.name || 'Error',\n            },\n            metadata,\n          };\n\n          if (jobStore) {\n            try {\n              await jobStore.update({\n                status: 'failed',\n                error: errorPayload.error,\n              });\n              console.log('[Worker] Job status updated to failed:', {\n                jobId,\n                workerId,\n              });\n            } catch (updateError: any) {\n              console.warn('[Worker] Failed to update job store on error:', {\n                jobId,\n                workerId,\n                error: updateError?.message || String(updateError),\n              });\n            }\n          }\n\n          const queueCtxFail = getWorkerQueueContext(input, metadata);\n          if (queueCtxFail?.queueJobId && typeof queueCtxFail.stepIndex === 'number') {\n            await notifyQueueJobStep(queueCtxFail.queueJobId, 'fail', {\n              queueId: queueCtxFail.id,\n              stepIndex: queueCtxFail.stepIndex,\n              workerJobId: jobId,\n              workerId,\n              error: errorPayload.error,\n            });\n          }\n\n          if (webhookUrl) {\n            await sendWebhook(webhookUrl, errorPayload);\n          }\n          throw error;\n        }\n\n        if (jobStore) {\n          try {\n            await jobStore.update({\n              status: 'completed',\n              output,\n            });\n            console.log('[Worker] Job status updated to completed:', {\n              jobId,\n              workerId,\n            });\n          } catch (updateError: any) {\n            console.warn('[Worker] Failed to update job store on success:', {\n              jobId,\n              workerId,\n              error: updateError?.message || String(updateError),\n            });\n          }\n        }\n\n        // Queue step complete is notified from wrapHandlerForQueue (after append) so one DB update marks step + queue.\n\n        console.log('[Worker] Job completed:', {\n          jobId,\n          workerId,\n          output,\n        });\n\n        const successPayload: WebhookPayload = {\n          jobId,\n          workerId,\n          status: 'success',\n          output,\n          metadata,\n        };\n\n        if (webhookUrl) {\n          await sendWebhook(webhookUrl, successPayload);\n        }\n      } catch (error: any) {\n        console.error('[Worker] Error processing SQS record:', {\n          jobId: messageBody?.jobId ?? '(parse failed)',\n          workerId: messageBody?.workerId ?? '(parse failed)',\n          error: error?.message || String(error),\n          stack: error?.stack,\n        });\n        throw error;\n      }\n    });\n\n    await Promise.all(promises);\n  };\n}\n","/**\n * MongoDB-backed job store for Lambda workers.\n * Updates jobs directly in MongoDB; never uses HTTP/origin URL.\n *\n * Env: MONGODB_WORKER_URI (or MONGODB_URI), MONGODB_WORKER_DB (or MONGODB_DB),\n * MONGODB_WORKER_JOBS_COLLECTION (default: worker_jobs).\n */\n\nimport { MongoClient, type Collection } from 'mongodb';\nimport type { JobStore, JobStoreUpdate } from './handler';\n\nconst uri = process.env.MONGODB_WORKER_URI || process.env.DATABASE_MONGODB_URI || process.env.MONGODB_URI;\nconst dbName =\n  process.env.MONGODB_WORKER_DB ||\n  process.env.MONGODB_DB ||\n  'worker';\nconst collectionName =\n  process.env.MONGODB_WORKER_JOBS_COLLECTION || 'worker_jobs';\n\ntype InternalJobEntry = { jobId: string; workerId: string; awaited?: boolean; delaySeconds?: number };\n\ntype Doc = {\n  _id: string;\n  jobId: string;\n  workerId: string;\n  status: 'queued' | 'running' | 'completed' | 'failed';\n  input: any;\n  output?: any;\n  error?: { message: string; stack?: string; name?: string };\n  metadata?: Record<string, any>;\n  internalJobs?: InternalJobEntry[];\n  userId?: string;\n  createdAt: string;\n  updatedAt: string;\n  completedAt?: string;\n};\n\nlet clientPromise: Promise<MongoClient> | null = null;\n\nfunction getClient(): Promise<MongoClient> {\n  if (!uri) {\n    throw new Error(\n      'MongoDB URI required for job store. Set DATABASE_MONGODB_URI or MONGODB_URI.'\n    );\n  }\n  if (!clientPromise) {\n    clientPromise = new MongoClient(uri, {\n      maxPoolSize: 10,\n      minPoolSize: 0,\n      serverSelectionTimeoutMS: 10_000,\n    }).connect();\n  }\n  return clientPromise;\n}\n\nasync function getCollection(): Promise<Collection<Doc>> {\n  const client = await getClient();\n  return client.db(dbName).collection<Doc>(collectionName);\n}\n\n/**\n * Load a job by id (read-only). Used for idempotency check before processing.\n */\nexport async function getJobById(jobId: string): Promise<{\n  jobId: string;\n  workerId: string;\n  status: 'queued' | 'running' | 'completed' | 'failed';\n  input: any;\n  output?: any;\n  error?: { message: string; stack?: string };\n  metadata?: Record<string, any>;\n  internalJobs?: Array<{ jobId: string; workerId: string }>;\n  createdAt: string;\n  updatedAt: string;\n  completedAt?: string;\n} | null> {\n  try {\n    const coll = await getCollection();\n    const doc = await coll.findOne({ _id: jobId });\n    if (!doc) return null;\n    const { _id, ...r } = doc;\n    return r as any;\n  } catch (e: any) {\n    console.error('[Worker] MongoDB getJobById failed:', {\n      jobId,\n      error: e?.message ?? String(e),\n    });\n    return null;\n  }\n}\n\n/**\n * Create a JobStore that reads/writes directly to MongoDB.\n * Caller must ensure the job exists (upsert on first use).\n */\nexport function createMongoJobStore(\n  workerId: string,\n  jobId: string,\n  input: any,\n  metadata: Record<string, any>,\n  userId?: string\n): JobStore {\n  return {\n    update: async (update: JobStoreUpdate): Promise<void> => {\n      try {\n        const coll = await getCollection();\n        const now = new Date().toISOString();\n        const existing = await coll.findOne({ _id: jobId });\n\n        let metadataUpdate: Record<string, any> = { ...(existing?.metadata ?? {}) };\n        if (update.metadata) {\n          Object.assign(metadataUpdate, update.metadata);\n        }\n        if (update.progress !== undefined || update.progressMessage !== undefined) {\n          metadataUpdate.progress = update.progress;\n          metadataUpdate.progressMessage = update.progressMessage;\n        }\n\n        const set: Partial<Doc> = {\n          updatedAt: now,\n          metadata: metadataUpdate,\n        };\n        if (update.status !== undefined) {\n          set.status = update.status;\n          if (['completed', 'failed'].includes(update.status) && !existing?.completedAt) {\n            set.completedAt = now;\n          }\n        }\n        if (update.output !== undefined) set.output = update.output;\n        if (update.error !== undefined) set.error = update.error;\n\n        if (existing) {\n          await coll.updateOne({ _id: jobId }, { $set: set });\n        } else {\n          const doc: Doc = {\n            _id: jobId,\n            jobId,\n            workerId,\n            status: (update.status as Doc['status']) ?? 'queued',\n            input: input ?? {},\n            output: update.output,\n            error: update.error,\n            metadata: metadataUpdate,\n            ...(userId ? { userId } : {}),\n            createdAt: now,\n            updatedAt: now,\n            completedAt: set.completedAt,\n          };\n          if (doc.status === 'completed' || doc.status === 'failed') {\n            doc.completedAt = doc.completedAt ?? now;\n          }\n          await coll.updateOne({ _id: jobId }, { $set: doc }, { upsert: true });\n        }\n      } catch (e: any) {\n        console.error('[Worker] MongoDB job store update failed:', {\n          jobId,\n          workerId,\n          error: e?.message ?? String(e),\n        });\n      }\n    },\n    get: async () => {\n      try {\n        const coll = await getCollection();\n        const doc = await coll.findOne({ _id: jobId });\n        if (!doc) return null;\n        const { _id, ...r } = doc;\n        return r as any;\n      } catch (e: any) {\n        console.error('[Worker] MongoDB job store get failed:', {\n          jobId,\n          workerId,\n          error: e?.message ?? String(e),\n        });\n        return null;\n      }\n    },\n    appendInternalJob: async (entry: InternalJobEntry): Promise<void> => {\n      try {\n        const coll = await getCollection();\n        await coll.updateOne(\n          { _id: jobId },\n          { $push: { internalJobs: entry } }\n        );\n      } catch (e: any) {\n        console.error('[Worker] MongoDB job store appendInternalJob failed:', {\n          jobId,\n          workerId,\n          error: e?.message ?? String(e),\n        });\n      }\n    },\n    getJob: async (otherJobId: string): Promise<{\n      jobId: string;\n      workerId: string;\n      status: 'queued' | 'running' | 'completed' | 'failed';\n      input: any;\n      output?: any;\n      error?: { message: string; stack?: string };\n      metadata?: Record<string, any>;\n      internalJobs?: Array<{ jobId: string; workerId: string }>;\n      createdAt: string;\n      updatedAt: string;\n      completedAt?: string;\n    } | null> => {\n      try {\n        const coll = await getCollection();\n        const doc = await coll.findOne({ _id: otherJobId });\n        if (!doc) return null;\n        const { _id, ...r } = doc;\n        return r as any;\n      } catch (e: any) {\n        console.error('[Worker] MongoDB job store getJob failed:', {\n          otherJobId,\n          error: e?.message ?? String(e),\n        });\n        return null;\n      }\n    },\n  };\n}\n\n/**\n * Upsert initial job record in MongoDB (queued).\n * Call this when the Lambda starts processing a message.\n */\nexport async function upsertJob(\n  jobId: string,\n  workerId: string,\n  input: any,\n  metadata: Record<string, any>,\n  userId?: string\n): Promise<void> {\n  const coll = await getCollection();\n  const now = new Date().toISOString();\n  await coll.updateOne(\n    { _id: jobId },\n    {\n      $set: {\n        _id: jobId,\n        jobId,\n        workerId,\n        status: 'queued',\n        input: input ?? {},\n        metadata: metadata ?? {},\n        ...(userId ? { userId } : {}),\n        createdAt: now,\n        updatedAt: now,\n      },\n    },\n    { upsert: true }\n  );\n}\n\nexport function isMongoJobStoreConfigured(): boolean {\n  return Boolean(uri?.trim());\n}\n","import { Redis } from '@upstash/redis';\nimport type { JobStore, JobStoreUpdate, JobRecord } from './handler';\n\n// Canonical: WORKER_* first, then UPSTASH_* / REDIS_* / WORKFLOW_* fallbacks\nconst redisUrl =\n  process.env.WORKER_UPSTASH_REDIS_REST_URL ||\n  process.env.UPSTASH_REDIS_REST_URL ||\n  process.env.UPSTASH_REDIS_URL;\nconst redisToken =\n  process.env.WORKER_UPSTASH_REDIS_REST_TOKEN ||\n  process.env.UPSTASH_REDIS_REST_TOKEN ||\n  process.env.UPSTASH_REDIS_TOKEN;\nconst jobKeyPrefix =\n  process.env.WORKER_UPSTASH_REDIS_JOBS_PREFIX ||\n  process.env.UPSTASH_REDIS_KEY_PREFIX ||\n  process.env.REDIS_WORKER_JOB_PREFIX ||\n  'worker:jobs:';\nconst defaultTtlSeconds = 60 * 60 * 24 * 7; // 7 days\nconst jobTtlSeconds =\n  typeof process.env.WORKER_JOBS_TTL_SECONDS === 'string'\n    ? parseInt(process.env.WORKER_JOBS_TTL_SECONDS, 10) || defaultTtlSeconds\n    : typeof process.env.REDIS_WORKER_JOB_TTL_SECONDS === 'string'\n      ? parseInt(process.env.REDIS_WORKER_JOB_TTL_SECONDS, 10) || defaultTtlSeconds\n      : typeof process.env.WORKFLOW_JOBS_TTL_SECONDS === 'string'\n        ? parseInt(process.env.WORKFLOW_JOBS_TTL_SECONDS, 10) || defaultTtlSeconds\n        : defaultTtlSeconds;\n\nlet redisClient: Redis | null = null;\n\nfunction getRedis(): Redis {\n  if (!redisUrl || !redisToken) {\n    throw new Error(\n      'Upstash Redis configuration missing. Set WORKER_UPSTASH_REDIS_REST_URL and WORKER_UPSTASH_REDIS_REST_TOKEN (or UPSTASH_REDIS_REST_URL/UPSTASH_REDIS_REST_TOKEN).'\n    );\n  }\n  if (!redisClient) {\n    redisClient = new Redis({\n      url: redisUrl,\n      token: redisToken,\n    });\n  }\n  return redisClient;\n}\n\nfunction jobKey(jobId: string): string {\n  return `${jobKeyPrefix}${jobId}`;\n}\n\n/** Separate LIST key for internal job refs; each RPUSH is atomic so no race when appending multiple. */\nfunction internalListKey(jobId: string): string {\n  return `${jobKeyPrefix}${jobId}:internal`;\n}\n\nexport function isRedisJobStoreConfigured(): boolean {\n  return Boolean((redisUrl || '').trim() && (redisToken || '').trim());\n}\n\n/** Load a job by id (read-only). Used for idempotency check before processing. */\nexport async function loadJob(jobId: string): Promise<JobRecord | null> {\n  const redis = getRedis();\n  const key = jobKey(jobId);\n  const data = await redis.hgetall<Record<string, string>>(key);\n  if (!data || Object.keys(data).length === 0) return null;\n  const parseJson = <T>(val?: string | null): T | undefined => {\n    if (!val) return undefined;\n    try {\n      return JSON.parse(val) as T;\n    } catch {\n      return undefined;\n    }\n  };\n  // Prefer atomic list key for internal jobs; fallback to hash field for old records\n  const listKey = internalListKey(jobId);\n  const listItems = await redis.lrange<string>(listKey, 0, -1);\n  type InternalRef = { jobId: string; workerId: string; awaited?: boolean; delaySeconds?: number };\n  let internalJobs: Array<InternalRef> | undefined;\n  if (listItems && listItems.length > 0) {\n    internalJobs = listItems.map((s) => {\n      try {\n        return JSON.parse(s) as InternalRef;\n      } catch {\n        return null;\n      }\n    }).filter(Boolean) as Array<InternalRef>;\n  } else {\n    internalJobs = parseJson<Array<InternalRef>>(data.internalJobs);\n  }\n  const record: JobRecord = {\n    jobId: data.jobId,\n    workerId: data.workerId,\n    status: (data.status as JobRecord['status']) || 'queued',\n    input: parseJson<any>(data.input) ?? {},\n    output: parseJson<any>(data.output),\n    error: parseJson<any>(data.error),\n    metadata: parseJson<Record<string, any>>(data.metadata) ?? {},\n    internalJobs,\n    ...(data.userId ? { userId: data.userId } : {}),\n    createdAt: data.createdAt,\n    updatedAt: data.updatedAt,\n    completedAt: data.completedAt,\n  };\n  return record;\n}\n\nexport function createRedisJobStore(\n  workerId: string,\n  jobId: string,\n  input: any,\n  metadata: Record<string, any>,\n  userId?: string\n): JobStore {\n  return {\n    update: async (update: JobStoreUpdate): Promise<void> => {\n      const redis = getRedis();\n      const key = jobKey(jobId);\n      const now = new Date().toISOString();\n\n      // Load existing to merge metadata/progress if needed\n      const existing = await loadJob(jobId);\n      const next: Partial<JobRecord> = {};\n\n      // Start from existing metadata\n      const mergedMeta: Record<string, any> = { ...(existing?.metadata ?? {}) };\n      if (update.metadata) {\n        Object.assign(mergedMeta, update.metadata);\n      }\n      if (update.progress !== undefined || update.progressMessage !== undefined) {\n        mergedMeta.progress = update.progress;\n        mergedMeta.progressMessage = update.progressMessage;\n      }\n\n      next.metadata = mergedMeta;\n      if (update.status !== undefined) {\n        next.status = update.error ? 'failed' : update.status;\n        if ((update.status === 'completed' || update.status === 'failed') && !existing?.completedAt) {\n          next.completedAt = now;\n        }\n      }\n      if (update.output !== undefined) next.output = update.output;\n      if (update.error !== undefined) next.error = update.error;\n\n      const toSet: Record<string, string> = {};\n      if (next.status) toSet['status'] = String(next.status);\n      if (next.output !== undefined) toSet['output'] = JSON.stringify(next.output);\n      if (next.error !== undefined) toSet['error'] = JSON.stringify(next.error);\n      if (next.metadata !== undefined) toSet['metadata'] = JSON.stringify(next.metadata);\n      if (next.completedAt) {\n        toSet['completedAt'] = next.completedAt;\n      }\n      toSet['updatedAt'] = now;\n\n      await redis.hset(key, toSet);\n      if (jobTtlSeconds > 0) {\n        await redis.expire(key, jobTtlSeconds);\n      }\n    },\n    get: async () => {\n      return loadJob(jobId);\n    },\n    appendInternalJob: async (entry) => {\n      const redis = getRedis();\n      const listKey = internalListKey(jobId);\n      await redis.rpush(listKey, JSON.stringify(entry));\n      const mainKey = jobKey(jobId);\n      await redis.hset(mainKey, { updatedAt: new Date().toISOString() });\n      if (jobTtlSeconds > 0) {\n        await redis.expire(listKey, jobTtlSeconds);\n        await redis.expire(mainKey, jobTtlSeconds);\n      }\n    },\n    getJob: async (otherJobId: string) => {\n      return loadJob(otherJobId);\n    },\n  };\n}\n\nexport async function upsertRedisJob(\n  jobId: string,\n  workerId: string,\n  input: any,\n  metadata: Record<string, any>,\n  userId?: string\n): Promise<void> {\n  const redis = getRedis();\n  const key = jobKey(jobId);\n  const now = new Date().toISOString();\n  const toSet: Record<string, string> = {\n    jobId: jobId,\n    workerId: workerId,\n    status: 'queued',\n    input: JSON.stringify(input ?? {}),\n    metadata: JSON.stringify(metadata ?? {}),\n    createdAt: now,\n    updatedAt: now,\n  };\n  if (userId) toSet.userId = userId;\n  await redis.hset(key, toSet);\n  if (jobTtlSeconds > 0) {\n    await redis.expire(key, jobTtlSeconds);\n  }\n}\n\n","/**\n * Local dispatch bridge — the seam the `ai-worker dev` server uses to intercept\n * worker-to-worker dispatch (and queue next-step sends) instead of SQS.\n *\n * Production safety: the bridge is only honored when BOTH conditions hold —\n * `process.env.AI_WORKER_LOCAL === '1'` AND a bridge object was installed on\n * `globalThis`. Nothing in a deployed Lambda sets either, so this path is\n * impossible to trip in production and adds zero dependencies.\n */\n\nimport type { SQSMessageBody } from './handler.js';\n\nexport interface LocalDispatchBridge {\n  /**\n   * Hand a would-be SQS message to the local dev queue.\n   * `delaySeconds` mirrors SQS DelaySeconds semantics (already clamped to 0–900 by the caller).\n   * Must return a message id (used in place of the SQS MessageId).\n   */\n  enqueue(\n    workerId: string,\n    messageBody: SQSMessageBody,\n    delaySeconds?: number\n  ): Promise<{ messageId: string }> | { messageId: string };\n}\n\nconst BRIDGE_GLOBAL_KEY = '__AI_WORKER_LOCAL_BRIDGE__';\n\n/** Install the bridge (called by the dev server before any worker code runs). */\nexport function setLocalDispatchBridge(bridge: LocalDispatchBridge | undefined): void {\n  (globalThis as Record<string, unknown>)[BRIDGE_GLOBAL_KEY] = bridge;\n}\n\n/**\n * Returns the installed bridge, or undefined unless BOTH the env flag and the\n * global are set (see module doc). Checked on every dispatch — cheap (two lookups).\n */\nexport function getLocalDispatchBridge(): LocalDispatchBridge | undefined {\n  if (process.env.AI_WORKER_LOCAL !== '1') return undefined;\n  const bridge = (globalThis as Record<string, unknown>)[BRIDGE_GLOBAL_KEY] as\n    | LocalDispatchBridge\n    | undefined;\n  return bridge && typeof bridge.enqueue === 'function' ? bridge : undefined;\n}\n","/**\n * Smart retry configuration for workers.\n * Retries execute in-process (same Lambda invocation) so error context is preserved\n * between attempts and the job remains in `running` state throughout.\n */\n\nexport interface RetryContext {\n  /** Current attempt number (1-indexed). 2 = first retry, 3 = second retry, etc. */\n  attempt: number;\n  /** Total max attempts configured. */\n  maxAttempts: number;\n  /** Error from the previous attempt — use to self-correct (e.g. inject into prompt). */\n  lastError: {\n    message: string;\n    name: string;\n    stack?: string;\n    /** HTTP status code or error code if present on the error object. */\n    code?: string | number;\n  };\n}\n\nexport type BuiltInRetryPattern =\n  | 'rate-limit'\n  | 'json-parse'\n  | 'overloaded'\n  | 'server-error';\n\nexport interface CustomRetryPattern {\n  /** Regex test against error.message, or a predicate receiving the full error object. */\n  match: RegExp | ((err: Error & Record<string, any>) => boolean);\n  /** Delay in ms before the retry. A function receives the retry attempt number (1 = first retry). */\n  delayMs?: number | ((attempt: number) => number);\n  /** When true, populates ctx.retryContext.lastError so the handler can self-correct. Built-ins set this per pattern. */\n  injectContext?: boolean;\n}\n\nexport type RetryPattern = BuiltInRetryPattern | CustomRetryPattern;\n\nexport interface SmartRetryConfig {\n  /** Maximum total attempts, including the first (default: 3). */\n  maxAttempts?: number;\n  /** Error patterns that trigger a retry. Non-matching errors fail immediately. */\n  on: RetryPattern[];\n}\n\n// ─── Built-in pattern implementations ────────────────────────────────────────\n\ntype PatternImpl = {\n  match: (err: Error & Record<string, any>) => boolean;\n  delayMs: (attempt: number) => number;\n  injectContext: boolean;\n};\n\nconst BUILT_IN_PATTERNS: Record<BuiltInRetryPattern, PatternImpl> = {\n  'rate-limit': {\n    match: (err) =>\n      /rate.?limit|too.?many.?requests/i.test(err.message) ||\n      err.status === 429 ||\n      err.code === 429 ||\n      err.name === 'RateLimitError',\n    delayMs: (attempt) => attempt * 10_000, // 10s, 20s, 30s…\n    injectContext: false,\n  },\n  'json-parse': {\n    match: (err) =>\n      err.name === 'SyntaxError' ||\n      err.name === 'ZodError' ||\n      /json|parse|unexpected.?token|invalid.?format/i.test(err.message),\n    delayMs: (_attempt) => 0, // Immediate — model self-corrects from ctx\n    injectContext: true,\n  },\n  overloaded: {\n    match: (err) =>\n      /overloaded|model.?is.?busy/i.test(err.message) ||\n      err.status === 529 ||\n      err.code === 529,\n    delayMs: (attempt) => attempt * 15_000, // 15s, 30s…\n    injectContext: false,\n  },\n  'server-error': {\n    match: (err) =>\n      /internal.?server.?error|service.?unavailable|bad.?gateway/i.test(err.message) ||\n      (typeof err.status === 'number' && err.status >= 500 && err.status < 600),\n    delayMs: (attempt) => attempt * 5_000, // 5s, 10s…\n    injectContext: false,\n  },\n};\n\n// ─── Pattern matching ─────────────────────────────────────────────────────────\n\ninterface MatchResult {\n  matched: boolean;\n  delayMs: number;\n  injectContext: boolean;\n}\n\nexport function matchesRetryPattern(\n  err: Error,\n  patterns: RetryPattern[],\n  /** 1-indexed retry number (1 = first retry, i.e. second execution). */\n  attempt: number\n): MatchResult {\n  for (const pattern of patterns) {\n    if (typeof pattern === 'string') {\n      const impl = BUILT_IN_PATTERNS[pattern];\n      if (impl.match(err as any)) {\n        return { matched: true, delayMs: impl.delayMs(attempt), injectContext: impl.injectContext };\n      }\n    } else {\n      let matched = false;\n      if (pattern.match instanceof RegExp) {\n        matched = pattern.match.test(err.message);\n      } else {\n        try {\n          matched = pattern.match(err as any);\n        } catch {\n          matched = false;\n        }\n      }\n      if (matched) {\n        const delayMs =\n          typeof pattern.delayMs === 'function'\n            ? pattern.delayMs(attempt)\n            : (pattern.delayMs ?? 0);\n        return { matched: true, delayMs, injectContext: pattern.injectContext ?? false };\n      }\n    }\n  }\n  return { matched: false, delayMs: 0, injectContext: false };\n}\n\n// ─── Retry executor ───────────────────────────────────────────────────────────\n\n/**\n * Executes `fn` with in-process smart retry.\n * `fn` receives `RetryContext | undefined` (undefined on first attempt).\n * `TokenBudgetExceededError` is never retried regardless of config.\n */\nexport async function executeWithRetry<T>(\n  fn: (retryCtx: RetryContext | undefined) => Promise<T>,\n  config: SmartRetryConfig,\n  onRetry?: (retryCtx: RetryContext, delayMs: number) => void\n): Promise<T> {\n  const maxAttempts = config.maxAttempts ?? 3;\n  let lastError: Error | undefined;\n\n  for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n    const retryCtx: RetryContext | undefined =\n      attempt > 1 && lastError\n        ? {\n            attempt,\n            maxAttempts,\n            lastError: {\n              message: lastError.message,\n              name: lastError.name,\n              stack: lastError.stack,\n              code: (lastError as any).code ?? (lastError as any).status,\n            },\n          }\n        : undefined;\n\n    try {\n      return await fn(retryCtx);\n    } catch (err: any) {\n      lastError = err instanceof Error ? err : new Error(String(err));\n\n      // TokenBudgetExceededError must never be retried.\n      if (err?.name === 'TokenBudgetExceededError') throw err;\n\n      if (attempt >= maxAttempts) throw err;\n\n      const retryAttemptNumber = attempt; // 1 = first retry\n      const { matched, delayMs } = matchesRetryPattern(lastError, config.on, retryAttemptNumber);\n      if (!matched) throw err;\n\n      const nextCtx: RetryContext = {\n        attempt: attempt + 1,\n        maxAttempts,\n        lastError: {\n          message: lastError.message,\n          name: lastError.name,\n          stack: lastError.stack,\n          code: (lastError as any).code ?? (lastError as any).status,\n        },\n      };\n      onRetry?.(nextCtx, delayMs);\n\n      if (delayMs > 0) {\n        await new Promise<void>((r) => setTimeout(r, delayMs));\n      }\n    }\n  }\n\n  throw lastError ?? new Error('executeWithRetry: unknown error');\n}\n","/**\n * Token budget tracking for workers.\n * Workers report usage via ctx.reportTokenUsage(); the runtime accumulates\n * and throws TokenBudgetExceededError when the limit is reached.\n */\n\nexport interface TokenUsage {\n  inputTokens: number;\n  outputTokens: number;\n}\n\nexport interface TokenBudgetState {\n  inputTokens: number;\n  outputTokens: number;\n  /** null = no budget configured */\n  budget: number | null;\n}\n\nexport class TokenBudgetExceededError extends Error {\n  public readonly used: number;\n  public readonly budget: number;\n\n  constructor(used: number, budget: number) {\n    super(`Token budget exceeded: used ${used} tokens (budget: ${budget})`);\n    this.name = 'TokenBudgetExceededError';\n    this.used = used;\n    this.budget = budget;\n  }\n}\n\nexport interface TokenTracker {\n  report(usage: TokenUsage): void;\n  getState(): TokenBudgetState;\n  getBudgetInfo(): { used: number; budget: number | null; remaining: number | null };\n}\n\nexport function createTokenTracker(budget: number | null): TokenTracker {\n  let inputTokens = 0;\n  let outputTokens = 0;\n\n  function checkBudget(): void {\n    if (budget !== null) {\n      const total = inputTokens + outputTokens;\n      if (total > budget) {\n        throw new TokenBudgetExceededError(total, budget);\n      }\n    }\n  }\n\n  return {\n    report(usage: TokenUsage): void {\n      inputTokens += usage.inputTokens;\n      outputTokens += usage.outputTokens;\n      checkBudget();\n    },\n    getState(): TokenBudgetState {\n      return { inputTokens, outputTokens, budget };\n    },\n    getBudgetInfo(): { used: number; budget: number | null; remaining: number | null } {\n      const used = inputTokens + outputTokens;\n      return {\n        used,\n        budget,\n        remaining: budget !== null ? Math.max(0, budget - used) : null,\n      };\n    },\n  };\n}\n"],"mappings":"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","names":[]}