@microfox/ai-worker 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +22 -0
- package/dist/chainMapDefaults.d.mts +21 -0
- package/dist/chainMapDefaults.d.ts +21 -0
- package/dist/chainMapDefaults.js +59 -0
- package/dist/chainMapDefaults.js.map +1 -0
- package/dist/chainMapDefaults.mjs +10 -0
- package/dist/chainMapDefaults.mjs.map +1 -0
- package/dist/chunk-BCRJIFKB.mjs +9 -0
- package/dist/chunk-BCRJIFKB.mjs.map +1 -0
- package/dist/{chunk-72XGFZCE.mjs → chunk-CILTGUUQ.mjs} +14 -3
- package/dist/chunk-CILTGUUQ.mjs.map +1 -0
- package/dist/{chunk-7LQNS2SG.mjs → chunk-QHX55IML.mjs} +442 -56
- package/dist/chunk-QHX55IML.mjs.map +1 -0
- package/dist/chunk-SQB5FQCZ.mjs +21 -0
- package/dist/chunk-SQB5FQCZ.mjs.map +1 -0
- package/dist/{chunk-AOXGONGI.mjs → chunk-T7DRPKR6.mjs} +7 -5
- package/dist/chunk-T7DRPKR6.mjs.map +1 -0
- package/dist/chunk-XCKWV2WZ.mjs +34 -0
- package/dist/chunk-XCKWV2WZ.mjs.map +1 -0
- package/dist/chunk-ZW4PNCDH.mjs +17 -0
- package/dist/chunk-ZW4PNCDH.mjs.map +1 -0
- package/dist/client.d.mts +148 -2
- package/dist/client.d.ts +148 -2
- package/dist/client.js +13 -2
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +1 -1
- package/dist/handler.d.mts +121 -23
- package/dist/handler.d.ts +121 -23
- package/dist/handler.js +450 -58
- package/dist/handler.js.map +1 -1
- package/dist/handler.mjs +5 -2
- package/dist/hitlConfig.d.mts +46 -0
- package/dist/hitlConfig.d.ts +46 -0
- package/dist/hitlConfig.js +33 -0
- package/dist/hitlConfig.js.map +1 -0
- package/dist/hitlConfig.mjs +8 -0
- package/dist/hitlConfig.mjs.map +1 -0
- package/dist/index.d.mts +28 -4
- package/dist/index.d.ts +28 -4
- package/dist/index.js +575 -74
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +78 -20
- package/dist/index.mjs.map +1 -1
- package/dist/queue-B5n6YVQV.d.ts +306 -0
- package/dist/queue-DaR2UuZi.d.mts +306 -0
- package/dist/queue.d.mts +3 -0
- package/dist/queue.d.ts +3 -0
- package/dist/queue.js +47 -0
- package/dist/queue.js.map +1 -0
- package/dist/queue.mjs +12 -0
- package/dist/queue.mjs.map +1 -0
- package/dist/queueInputEnvelope.d.mts +31 -0
- package/dist/queueInputEnvelope.d.ts +31 -0
- package/dist/queueInputEnvelope.js +42 -0
- package/dist/queueInputEnvelope.js.map +1 -0
- package/dist/queueInputEnvelope.mjs +10 -0
- package/dist/queueInputEnvelope.mjs.map +1 -0
- package/dist/queueJobStore.d.mts +3 -2
- package/dist/queueJobStore.d.ts +3 -2
- package/dist/queueJobStore.js +6 -4
- package/dist/queueJobStore.js.map +1 -1
- package/dist/queueJobStore.mjs +1 -1
- package/package.json +7 -2
- package/dist/chunk-72XGFZCE.mjs.map +0 -1
- package/dist/chunk-7LQNS2SG.mjs.map +0 -1
- package/dist/chunk-AOXGONGI.mjs.map +0 -1
- package/dist/client-BqSJQ9mZ.d.mts +0 -183
- package/dist/client-BqSJQ9mZ.d.ts +0 -183
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/handler.ts","../src/mongoJobStore.ts","../src/redisJobStore.ts","../src/queueJobStore.ts","../src/config.ts","../src/queue.ts"],"sourcesContent":["/**\n * @microfox/ai-worker\n * Worker runtime for ai-router - SQS-based async agent execution\n */\n\nimport { dispatch, dispatchLocal, getWorkersTriggerUrl, type DispatchOptions, type DispatchResult } from './client.js';\nimport { createLambdaHandler, createWorkerLogger, type WorkerHandler, type JobStore, type DispatchWorkerOptions, SQS_MAX_DELAY_SECONDS } from './handler.js';\nimport type { ZodType, z } from 'zod';\n\nexport * from './client.js';\nexport * from './handler.js';\nexport * from './config.js';\nexport * from './queue.js';\n\n/**\n * Schedule event configuration for a worker.\n * Supports both simple rate/cron strings and full configuration objects.\n * \n * @example Simple rate/cron\n * ```typescript\n * schedule: 'rate(2 hours)'\n * // or\n * schedule: 'cron(0 12 * * ? *)'\n * ```\n * \n * @example Full configuration\n * ```typescript\n * schedule: {\n * rate: 'rate(10 minutes)',\n * enabled: true,\n * input: { key1: 'value1' }\n * }\n * ```\n * \n * @example Multiple schedules\n * ```typescript\n * schedule: [\n * 'rate(2 hours)',\n * { rate: 'cron(0 12 * * ? *)', enabled: false }\n * ]\n * ```\n */\nexport interface ScheduleEventConfig {\n /**\n * Schedule rate using either rate() or cron() syntax.\n * Can be a string or array of strings for multiple schedules.\n * \n * @example 'rate(2 hours)' or 'cron(0 12 * * ? *)'\n * @example ['cron(0 0/4 ? * MON-FRI *)', 'cron(0 2 ? * SAT-SUN *)']\n */\n rate: string | string[];\n /**\n * Whether the schedule is enabled (default: true).\n */\n enabled?: boolean;\n /**\n * Input payload to pass to the function.\n */\n input?: Record<string, any>;\n /**\n * JSONPath expression to select part of the event data as input.\n */\n inputPath?: string;\n /**\n * Input transformer configuration for custom input mapping.\n */\n inputTransformer?: {\n inputPathsMap?: Record<string, string>;\n inputTemplate?: string;\n };\n /**\n * Name of the schedule event.\n */\n name?: string;\n /**\n * Description of the schedule event.\n */\n description?: string;\n /**\n * Method to use: 'eventBus' (default) or 'scheduler'.\n * Use 'scheduler' for higher limits (1M events vs 300).\n */\n method?: 'eventBus' | 'scheduler';\n /**\n * Timezone for the schedule (only used with method: 'scheduler').\n * @example 'America/New_York'\n */\n timezone?: string;\n}\n\nexport type ScheduleConfig = \n | string \n | ScheduleEventConfig \n | (string | ScheduleEventConfig)[];\n\n/**\n * Configuration for a worker's Lambda function deployment.\n * \n * **Best Practice**: Export this as a separate const from your worker file:\n * ```typescript\n * export const workerConfig: WorkerConfig = {\n * timeout: 900,\n * memorySize: 2048,\n * layers: ['arn:aws:lambda:${aws:region}:${aws:accountId}:layer:ffmpeg:1'],\n * schedule: 'rate(2 hours)',\n * };\n * ```\n * \n * The CLI will automatically extract it from the export. You do not need to pass it to `createWorker()`.\n */\nexport interface WorkerConfig {\n /**\n * Lambda function timeout in seconds (max 900).\n */\n timeout?: number;\n /**\n * Lambda function memory size in MB (128-10240).\n */\n memorySize?: number;\n /**\n * Optional Lambda layers ARNs to attach to this worker function.\n *\n * This is primarily used by @microfox/ai-worker-cli when generating serverless.yml.\n * Supports CloudFormation pseudo-parameters like ${aws:region} and ${aws:accountId}.\n *\n * Example:\n * layers: ['arn:aws:lambda:${aws:region}:${aws:accountId}:layer:ffmpeg:1']\n */\n layers?: string[];\n /**\n * Schedule events configuration for this worker.\n * Allows multiple schedule events to be attached to the same function.\n * \n * @example Simple rate\n * ```typescript\n * schedule: 'rate(2 hours)'\n * ```\n * \n * @example Multiple schedules\n * ```typescript\n * schedule: [\n * 'rate(2 hours)',\n * { rate: 'cron(0 12 * * ? *)', enabled: true, input: { key: 'value' } }\n * ]\n * ```\n * \n * @example Using scheduler method with timezone\n * ```typescript\n * schedule: {\n * method: 'scheduler',\n * rate: 'cron(0 0/4 ? * MON-FRI *)',\n * timezone: 'America/New_York',\n * input: { key1: 'value1' }\n * }\n * ```\n */\n schedule?: ScheduleConfig;\n\n /**\n * SQS queue settings for this worker (used by @microfox/ai-worker-cli when generating serverless.yml).\n *\n * Notes:\n * - To effectively disable retries, set `maxReceiveCount: 1` (requires DLQ; the CLI will create one).\n * - SQS does not support `maxReceiveCount: 0`.\n * - `messageRetentionPeriod` is in seconds (max 1209600 = 14 days).\n */\n sqs?: {\n /**\n * How many receives before sending to DLQ.\n * Use 1 to avoid retries.\n */\n maxReceiveCount?: number;\n /**\n * How long messages are retained in the main queue (seconds).\n */\n messageRetentionPeriod?: number;\n /**\n * Visibility timeout for the main queue (seconds).\n * If not set, CLI defaults to (worker timeout + 60s).\n */\n visibilityTimeout?: number;\n /**\n * DLQ message retention period (seconds).\n * Defaults to `messageRetentionPeriod` (or 14 days).\n */\n deadLetterMessageRetentionPeriod?: number;\n };\n}\n\nexport interface WorkerAgentConfig<INPUT_SCHEMA extends ZodType<any>, OUTPUT> {\n id: string;\n inputSchema: INPUT_SCHEMA;\n outputSchema: ZodType<OUTPUT>;\n handler: WorkerHandler<z.infer<INPUT_SCHEMA>, OUTPUT>;\n /**\n * @deprecated Prefer exporting `workerConfig` as a separate const from your worker file.\n * The CLI will automatically extract it from the export. This parameter is kept for backward compatibility.\n */\n workerConfig?: WorkerConfig;\n}\n\nexport interface WorkerAgent<INPUT_SCHEMA extends ZodType<any>, OUTPUT> {\n id: string;\n dispatch: (\n input: z.input<INPUT_SCHEMA>,\n options: DispatchOptions\n ) => Promise<DispatchResult>;\n handler: WorkerHandler<z.infer<INPUT_SCHEMA>, OUTPUT>;\n inputSchema: INPUT_SCHEMA;\n outputSchema: ZodType<OUTPUT>;\n workerConfig?: WorkerConfig;\n}\n\n/**\n * Creates a worker agent that can be dispatched to SQS/Lambda.\n *\n * In development mode (NODE_ENV === 'development' and WORKERS_LOCAL_MODE !== 'false'),\n * dispatch() will run the handler immediately in the same process.\n *\n * In production, dispatch() sends a message to SQS which triggers a Lambda function.\n *\n * @template INPUT_SCHEMA - The Zod schema type (e.g., `typeof InputSchema`).\n * Used to derive both:\n * - Pre-parse input type via `z.input<INPUT_SCHEMA>` for `dispatch()` (preserves optional fields)\n * - Parsed input type via `z.infer<INPUT_SCHEMA>` for handler (defaults applied)\n * @template OUTPUT - The output type returned by the handler. Use `z.infer<typeof OutputSchema>`.\n *\n * @param config - Worker agent configuration\n * @returns A worker agent object with a dispatch method\n *\n * @example\n * ```typescript\n * const InputSchema = z.object({\n * url: z.string().url(),\n * timeout: z.number().optional().default(5000), // optional with default\n * });\n *\n * export const worker = createWorker<typeof InputSchema, Output>({\n * // dispatch() accepts { url: string, timeout?: number } (pre-parse, optional preserved)\n * // handler receives { url: string, timeout: number } (parsed, default applied)\n * });\n * ```\n */\nexport function createWorker<INPUT_SCHEMA extends ZodType<any>, OUTPUT>(\n config: WorkerAgentConfig<INPUT_SCHEMA, OUTPUT>\n): WorkerAgent<INPUT_SCHEMA, OUTPUT> {\n const { id, inputSchema, outputSchema, handler } = config;\n\n const agent: WorkerAgent<INPUT_SCHEMA, OUTPUT> = {\n id,\n handler,\n inputSchema,\n outputSchema,\n\n async dispatch(input: z.input<INPUT_SCHEMA>, options: DispatchOptions): Promise<DispatchResult> {\n const mode = options.mode ?? 'auto';\n const envWantsLocal =\n process.env.NODE_ENV === 'development' &&\n process.env.WORKERS_LOCAL_MODE !== 'false';\n // Check if we're in local development mode\n const isLocal = mode === 'local' || (mode === 'auto' && envWantsLocal);\n\n if (isLocal) {\n // Local mode: run handler immediately\n // Parse input to apply defaults and get the final parsed type\n const parsedInput = inputSchema.parse(input);\n const localJobId = options.jobId || `local-${Date.now()}`;\n \n // Try to get direct job store access in local mode (same process as Next.js app)\n // This allows direct DB updates without needing HTTP/webhook URLs\n let directJobStore: {\n updateJob: (jobId: string, data: any) => Promise<void>;\n setJob?: (jobId: string, data: any) => Promise<void>;\n } | null = null;\n\n // Path constants for job store imports\n const nextJsPathAlias = '@/app/api/workflows/stores/jobStore';\n const explicitPath = process.env.WORKER_JOB_STORE_MODULE_PATH;\n\n // Reliable approach: try Next.js path alias first, then explicit env var\n // The @/ alias works at runtime in Next.js context\n const resolveJobStore = async () => {\n // Option 1: Try Next.js path alias (works in Next.js runtime context)\n try {\n const module = await import(nextJsPathAlias);\n if (module?.updateJob) {\n return { updateJob: module.updateJob, setJob: module.setJob };\n }\n } catch {\n // Path alias not available (not in Next.js context or alias not configured)\n }\n\n // Option 2: Use explicit env var if provided (for custom setups)\n if (explicitPath) {\n try {\n const module = await import(explicitPath).catch(() => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(explicitPath);\n });\n if (module?.updateJob) {\n return { updateJob: module.updateJob, setJob: module.setJob };\n }\n } catch {\n // Explicit path failed\n }\n }\n\n return null;\n };\n\n directJobStore = await resolveJobStore();\n if (directJobStore) {\n console.log('[Worker] Using direct job store in local mode (no HTTP needed)');\n }\n\n // Derive job store URL from webhook URL or environment (fallback for HTTP mode)\n let jobStoreUrl: string | undefined;\n if (options.webhookUrl) {\n try {\n const webhookUrlObj = new URL(options.webhookUrl);\n jobStoreUrl = webhookUrlObj.pathname.replace(/\\/webhook$/, '');\n jobStoreUrl = `${webhookUrlObj.origin}${jobStoreUrl}`;\n } catch {\n // Invalid URL, skip job store URL\n }\n }\n jobStoreUrl = jobStoreUrl || process.env.WORKER_JOB_STORE_URL;\n\n // Create job store interface for local mode\n // Prefer direct DB access, fallback to HTTP calls if needed\n const createLocalJobStore = (\n directStore: typeof directJobStore,\n httpUrl?: string\n ): JobStore | undefined => {\n // If we have direct job store access, use it (no HTTP needed)\n if (directStore) {\n return {\n update: async (update) => {\n try {\n // Build update payload\n const updatePayload: any = {};\n \n if (update.status !== undefined) {\n updatePayload.status = update.status;\n }\n if (update.metadata !== undefined) {\n updatePayload.metadata = update.metadata;\n }\n if (update.progress !== undefined) {\n // Merge progress into metadata\n updatePayload.metadata = {\n ...updatePayload.metadata,\n progress: update.progress,\n progressMessage: update.progressMessage,\n };\n }\n if (update.output !== undefined) {\n updatePayload.output = update.output;\n }\n if (update.error !== undefined) {\n updatePayload.error = update.error;\n }\n\n await directStore.updateJob(localJobId, updatePayload);\n console.log('[Worker] Local job updated (direct DB):', {\n jobId: localJobId,\n workerId: id,\n updates: Object.keys(updatePayload),\n });\n } catch (error: any) {\n console.warn('[Worker] Failed to update local job (direct DB):', {\n jobId: localJobId,\n workerId: id,\n error: error?.message || String(error),\n });\n }\n },\n get: async () => {\n try {\n // Use the same direct store that has updateJob - it should also have getJob\n if (directStore) {\n // Try to import getJob from the same module\n const nextJsPath = '@/app/api/workflows/stores/jobStore';\n const explicitPath = process.env.WORKER_JOB_STORE_MODULE_PATH;\n \n for (const importPath of [nextJsPath, explicitPath].filter(Boolean)) {\n try {\n const module = await import(importPath!);\n if (module?.getJob) {\n return await module.getJob(localJobId);\n }\n } catch {\n // Continue\n }\n }\n }\n return null;\n } catch (error: any) {\n console.warn('[Worker] Failed to get local job (direct DB):', {\n jobId: localJobId,\n workerId: id,\n error: error?.message || String(error),\n });\n return null;\n }\n },\n appendInternalJob: async (entry: { jobId: string; workerId: string }) => {\n try {\n const nextJsPath = '@/app/api/workflows/stores/jobStore';\n const explicitPath = process.env.WORKER_JOB_STORE_MODULE_PATH;\n for (const importPath of [nextJsPath, explicitPath].filter(Boolean)) {\n try {\n const module = await import(importPath!);\n if (typeof module?.appendInternalJob === 'function') {\n await module.appendInternalJob(localJobId, entry);\n return;\n }\n } catch {\n // Continue\n }\n }\n } catch (error: any) {\n console.warn('[Worker] Failed to appendInternalJob (direct DB):', { localJobId, error: error?.message || String(error) });\n }\n },\n getJob: async (otherJobId: string) => {\n try {\n const nextJsPath = '@/app/api/workflows/stores/jobStore';\n const explicitPath = process.env.WORKER_JOB_STORE_MODULE_PATH;\n for (const importPath of [nextJsPath, explicitPath].filter(Boolean)) {\n try {\n const module = await import(importPath!);\n if (typeof module?.getJob === 'function') {\n return await module.getJob(otherJobId);\n }\n } catch {\n // Continue\n }\n }\n } catch (error: any) {\n console.warn('[Worker] Failed to getJob (direct DB):', { otherJobId, error: error?.message || String(error) });\n }\n return null;\n },\n };\n }\n\n // Fallback to HTTP calls if no direct access\n if (!httpUrl) {\n return undefined;\n }\n\n // Use HTTP calls to update job store\n return {\n update: async (update) => {\n try {\n // Build update payload\n const updatePayload: any = { jobId: localJobId, workerId: id };\n \n if (update.status !== undefined) {\n updatePayload.status = update.status;\n }\n if (update.metadata !== undefined) {\n updatePayload.metadata = update.metadata;\n }\n if (update.progress !== undefined) {\n // Merge progress into metadata\n updatePayload.metadata = {\n ...updatePayload.metadata,\n progress: update.progress,\n progressMessage: update.progressMessage,\n };\n }\n if (update.output !== undefined) {\n updatePayload.output = update.output;\n }\n if (update.error !== undefined) {\n updatePayload.error = update.error;\n }\n\n const response = await fetch(`${httpUrl}/update`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(updatePayload),\n });\n if (!response.ok) {\n throw new Error(`Job store update failed: ${response.status} ${response.statusText}`);\n }\n console.log('[Worker] Local job updated (HTTP):', {\n jobId: localJobId,\n workerId: id,\n updates: Object.keys(updatePayload),\n });\n } catch (error: any) {\n console.warn('[Worker] Failed to update local job (HTTP):', {\n jobId: localJobId,\n workerId: id,\n error: error?.message || String(error),\n });\n }\n },\n get: async () => {\n try {\n // GET /api/workflows/workers/:workerId/:jobId\n const response = await fetch(`${httpUrl}/${id}/${localJobId}`, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`Job store get failed: ${response.status} ${response.statusText}`);\n }\n\n return await response.json();\n } catch (error: any) {\n console.warn('[Worker] Failed to get local job (HTTP):', {\n jobId: localJobId,\n workerId: id,\n error: error?.message || String(error),\n });\n return null;\n }\n },\n };\n };\n\n const jobStore = createLocalJobStore(directJobStore, jobStoreUrl);\n\n const DEFAULT_POLL_INTERVAL_MS = 2000;\n const DEFAULT_POLL_TIMEOUT_MS = 15 * 60 * 1000;\n\n const createLocalDispatchWorker = (\n parentJobId: string,\n parentWorkerId: string,\n parentContext: Record<string, any>,\n store: 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 const metadata = options?.metadata ?? {};\n const serializedContext: Record<string, any> = {};\n if (parentContext.requestId) serializedContext.requestId = parentContext.requestId;\n const messageBody = {\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 let triggerUrl: string;\n try {\n triggerUrl = getWorkersTriggerUrl();\n } catch (e: any) {\n throw new Error(\n `Local dispatchWorker requires WORKER_BASE_URL (or similar) for worker \"${calleeWorkerId}\": ${e?.message ?? e}`\n );\n }\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) headers['x-workers-trigger-key'] = triggerKey;\n\n // Fire-and-forget with delay: schedule trigger after delay, return immediately (no computation/wait in caller).\n if (options?.await !== true && options?.delaySeconds != null && options.delaySeconds > 0) {\n const sec = Math.min(SQS_MAX_DELAY_SECONDS, Math.max(0, Math.floor(options.delaySeconds)));\n const storeRef = store;\n setTimeout(() => {\n fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({ workerId: calleeWorkerId, body: messageBody }),\n })\n .then(async (response) => {\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n console.error(\n `[Worker] Delayed trigger failed for \"${calleeWorkerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n return;\n }\n if (storeRef?.appendInternalJob) {\n await storeRef.appendInternalJob({ jobId: childJobId, workerId: calleeWorkerId });\n }\n })\n .catch((err) => {\n console.error('[Worker] Delayed trigger error:', { calleeWorkerId, jobId: childJobId, error: err?.message ?? err });\n });\n }, sec * 1000);\n return { jobId: childJobId, messageId: undefined };\n }\n\n const response = await fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({ workerId: calleeWorkerId, body: messageBody }),\n });\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to trigger worker \"${calleeWorkerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ? String(data.messageId) : `trigger-${childJobId}`;\n\n if (store?.appendInternalJob) {\n await store.appendInternalJob({ jobId: childJobId, workerId: calleeWorkerId });\n }\n\n if (options?.await && store?.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 store.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(err?.message ?? `Child worker ${calleeWorkerId} failed`);\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 // Create initial job record if we have job store access\n if (directJobStore?.setJob) {\n try {\n await directJobStore.setJob(localJobId, {\n jobId: localJobId,\n workerId: id,\n status: 'queued',\n input: parsedInput,\n metadata: options.metadata || {},\n });\n } catch (error: any) {\n console.warn('[Worker] Failed to create initial job record:', {\n jobId: localJobId,\n workerId: id,\n error: error?.message || String(error),\n });\n // Continue - job will still be created when status is updated\n }\n }\n\n const baseContext = { jobId: localJobId, workerId: id };\n const handlerContext = {\n ...baseContext,\n ...(jobStore ? { jobStore } : {}),\n logger: createWorkerLogger(localJobId, id),\n dispatchWorker: createLocalDispatchWorker(\n localJobId,\n id,\n baseContext,\n jobStore\n ),\n };\n\n try {\n // Update status to running before execution\n if (jobStore) {\n await jobStore.update({ status: 'running' });\n }\n\n const output = await dispatchLocal(handler, parsedInput, handlerContext);\n\n // Update status to completed before webhook\n if (jobStore) {\n await jobStore.update({ status: 'completed', output });\n }\n\n // Only send webhook if webhookUrl is provided\n if (options.webhookUrl) {\n try {\n await fetch(options.webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jobId: localJobId,\n workerId: id,\n status: 'success',\n output,\n metadata: options.metadata,\n }),\n });\n } catch (error) {\n console.warn('[Worker] Local webhook call failed:', error);\n }\n }\n\n return {\n messageId: `local-${Date.now()}`,\n status: 'queued',\n jobId: localJobId,\n };\n } catch (error: any) {\n // Update status to failed before webhook\n if (jobStore) {\n await jobStore.update({\n status: 'failed',\n error: {\n message: error.message || 'Unknown error',\n stack: error.stack,\n name: error.name || 'Error',\n },\n });\n }\n\n // Only send error webhook if webhookUrl is provided\n if (options.webhookUrl) {\n try {\n await fetch(options.webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jobId: localJobId,\n workerId: id,\n status: 'error',\n error: {\n message: error.message || 'Unknown error',\n stack: error.stack,\n name: error.name || 'Error',\n },\n metadata: options.metadata,\n }),\n });\n } catch (webhookError) {\n console.warn('[Worker] Local error webhook call failed:', webhookError);\n }\n }\n throw error;\n }\n }\n\n // Production mode: dispatch to SQS\n return dispatch(id, input, inputSchema, options);\n },\n };\n\n return agent;\n}\n\n/**\n * Creates a Lambda handler entrypoint for a worker agent.\n * This is used by the deployment script to generate Lambda entrypoints.\n *\n * @param agent - The worker agent\n * @returns A Lambda handler function\n */\nexport function createLambdaEntrypoint<INPUT_SCHEMA extends ZodType<any>, OUTPUT>(\n agent: WorkerAgent<INPUT_SCHEMA, OUTPUT>\n) {\n return createLambdaHandler(agent.handler, agent.outputSchema);\n}\n","/**\n * Client for dispatching background worker jobs.\n *\n * In production, dispatching happens via the workers HTTP API:\n * POST /workers/trigger -> enqueues message to SQS on the workers service side\n *\n * This avoids requiring AWS credentials in your Next.js app.\n */\n\nimport type { ZodType, z } from 'zod';\nimport type { WorkerQueueConfig } from './queue.js';\n\nexport interface WorkerQueueRegistry {\n getQueueById(queueId: string): WorkerQueueConfig | undefined;\n /** (initialInput, previousOutputs) for best DX: derive next input from original request and all prior step outputs. */\n invokeMapInput?: (\n queueId: string,\n stepIndex: number,\n initialInput: unknown,\n previousOutputs: Array<{ stepIndex: number; workerId: string; output: unknown }>\n ) => Promise<unknown> | unknown;\n}\n\nexport interface DispatchOptions {\n /**\n * Optional webhook callback URL to notify when the job finishes.\n * Only called when provided. Default: no webhook (use job store / MongoDB only).\n */\n webhookUrl?: string;\n /**\n * Controls how dispatch executes.\n * - \"auto\" (default): local inline execution in development unless WORKERS_LOCAL_MODE=false.\n * - \"local\": force inline execution (no SQS).\n * - \"remote\": force SQS/Lambda dispatch even in development.\n */\n mode?: 'auto' | 'local' | 'remote';\n jobId?: string;\n metadata?: Record<string, any>;\n /**\n * In-memory queue registry for dispatchQueue. Required when using dispatchQueue.\n * Pass a registry that imports from your .queue.ts definitions (works on Vercel/serverless).\n */\n registry?: WorkerQueueRegistry;\n /**\n * Optional callback to create a queue job record before dispatching.\n * Called with queueJobId (= first worker's jobId), queueId, and firstStep.\n */\n onCreateQueueJob?: (params: {\n queueJobId: string;\n queueId: string;\n firstStep: { workerId: string; workerJobId: string };\n metadata?: Record<string, unknown>;\n }) => Promise<void>;\n}\n\nexport interface DispatchResult {\n messageId: string;\n status: 'queued';\n jobId: string;\n}\n\nexport interface DispatchQueueResult extends DispatchResult {\n queueId: string;\n}\n\nexport interface SerializedContext {\n requestId?: string;\n userId?: string;\n traceId?: string;\n [key: string]: any;\n}\n\n/**\n * Derives the full /workers/trigger URL from env.\n * Exported for use by local dispatchWorker (worker-to-worker in dev).\n * Server-side only; clients should use useWorkflowJob with your app's /api/workflows routes.\n *\n * Env vars:\n * - WORKER_BASE_URL: base URL of the workers service (e.g. https://.../prod)\n * - WORKERS_TRIGGER_API_URL / WORKERS_CONFIG_API_URL: legacy, still supported\n */\nexport function getWorkersTriggerUrl(): string {\n const raw =\n process.env.WORKER_BASE_URL ||\n process.env.WORKERS_TRIGGER_API_URL ||\n process.env.WORKERS_CONFIG_API_URL;\n\n if (!raw) {\n throw new Error(\n 'WORKER_BASE_URL is required for background workers. Set it server-side only.'\n );\n }\n\n const url = new URL(raw);\n url.search = '';\n url.hash = '';\n\n const path = url.pathname || '';\n\n // If the user pointed at a specific endpoint, normalize back to the service root.\n url.pathname = path.replace(/\\/?workers\\/(trigger|config)\\/?$/, '');\n\n const basePath = url.pathname.replace(/\\/+$/, '');\n url.pathname = `${basePath}/workers/trigger`.replace(/\\/+$/, '');\n\n return url.toString();\n}\n\n/**\n * URL for the queue start endpoint (dispatch proxy). Use this so queue starts\n * go through the queue handler Lambda for easier debugging (one log stream per queue).\n */\nexport function getQueueStartUrl(queueId: string): string {\n const raw =\n process.env.WORKER_BASE_URL ||\n process.env.WORKERS_TRIGGER_API_URL ||\n process.env.WORKERS_CONFIG_API_URL;\n\n if (!raw) {\n throw new Error(\n 'WORKER_BASE_URL is required for background workers. Set it server-side only.'\n );\n }\n\n const url = new URL(raw);\n url.search = '';\n url.hash = '';\n\n const path = url.pathname || '';\n url.pathname = path.replace(/\\/?workers\\/(trigger|config)\\/?$/, '');\n const basePath = url.pathname.replace(/\\/+$/, '');\n const safeSegment = encodeURIComponent(queueId);\n url.pathname = `${basePath}/queues/${safeSegment}/start`.replace(/\\/+$/, '');\n\n return url.toString();\n}\n\n/**\n * Serializes context data for transmission to Lambda.\n * Only serializes safe, JSON-compatible properties.\n */\nfunction serializeContext(ctx: any): SerializedContext {\n const serialized: SerializedContext = {};\n\n if (ctx.requestId) {\n serialized.requestId = ctx.requestId;\n }\n\n // Extract any additional serializable metadata\n if (ctx.metadata && typeof ctx.metadata === 'object') {\n Object.assign(serialized, ctx.metadata);\n }\n\n // Allow custom context serialization via a helper property\n if (ctx._serializeContext && typeof ctx._serializeContext === 'function') {\n const custom = ctx._serializeContext();\n Object.assign(serialized, custom);\n }\n\n return serialized;\n}\n\n\n/**\n * Dispatches a background worker job to SQS.\n *\n * @param workerId - The ID of the worker to dispatch\n * @param input - The input data for the worker (will be validated against inputSchema)\n * @param inputSchema - Zod schema for input validation\n * @param options - Dispatch options including webhook URL\n * @param ctx - Optional context object (only serializable parts will be sent)\n * @returns Promise resolving to dispatch result with messageId and jobId\n */\nexport async function dispatch<INPUT_SCHEMA extends ZodType<any>>(\n workerId: string,\n input: z.input<INPUT_SCHEMA>,\n inputSchema: INPUT_SCHEMA,\n options: DispatchOptions,\n ctx?: any\n): Promise<DispatchResult> {\n // Validate input against schema\n const validatedInput = inputSchema.parse(input);\n\n // Generate job ID if not provided\n const jobId =\n options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n // Resolve /workers/trigger endpoint URL\n const triggerUrl = getWorkersTriggerUrl();\n\n // Serialize context (only safe, JSON-compatible parts)\n const serializedContext = ctx ? serializeContext(ctx) : {};\n\n // Job updates use MongoDB only; never pass jobStoreUrl/origin URL.\n const messageBody = {\n workerId,\n jobId,\n input: validatedInput,\n context: serializedContext,\n webhookUrl: options.webhookUrl,\n metadata: options.metadata || {},\n timestamp: new Date().toISOString(),\n };\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) {\n headers['x-workers-trigger-key'] = triggerKey;\n }\n\n const response = await fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n workerId,\n body: messageBody,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to trigger worker \"${workerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ? String(data.messageId) : `trigger-${jobId}`;\n\n return {\n messageId,\n status: 'queued',\n jobId,\n };\n}\n\n/**\n * Dispatch a worker by ID without importing the worker module.\n * Sends to the workers trigger API (WORKER_BASE_URL). No input schema validation at call site.\n *\n * @param workerId - The worker ID (e.g. 'echo', 'data-processor')\n * @param input - Input payload (object or undefined)\n * @param options - Optional jobId, webhookUrl, metadata\n * @param ctx - Optional context (serializable parts sent in the request)\n * @returns Promise resolving to { messageId, status: 'queued', jobId }\n */\nexport async function dispatchWorker(\n workerId: string,\n input?: Record<string, unknown>,\n options: DispatchOptions = {},\n ctx?: any\n): Promise<DispatchResult> {\n const jobId =\n options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const triggerUrl = getWorkersTriggerUrl();\n const serializedContext = ctx ? serializeContext(ctx) : {};\n const messageBody = {\n workerId,\n jobId,\n input: input ?? {},\n context: serializedContext,\n webhookUrl: options.webhookUrl,\n metadata: options.metadata || {},\n timestamp: new Date().toISOString(),\n };\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) headers['x-workers-trigger-key'] = triggerKey;\n const response = await fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({ workerId, body: messageBody }),\n });\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to trigger worker \"${workerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ? String(data.messageId) : `trigger-${jobId}`;\n return { messageId, status: 'queued', jobId };\n}\n\n/**\n * Local development mode: runs the handler immediately in the same process.\n * This bypasses SQS and Lambda for faster iteration during development.\n *\n * @param handler - The worker handler function\n * @param input - The input data\n * @param ctx - The context object\n * @returns The handler result\n */\nexport async function dispatchLocal<INPUT, OUTPUT>(\n handler: (params: { input: INPUT; ctx: any }) => Promise<OUTPUT>,\n input: INPUT,\n ctx?: any\n): Promise<OUTPUT> {\n return handler({ input, ctx: ctx || {} });\n}\n\n/**\n * Dispatches a queue by ID. POSTs to the queue-start API; the queue-start handler creates the queue job.\n * Pass the first worker's input directly (no registry required).\n */\nexport async function dispatchQueue<InitialInput = any>(\n queueId: string,\n initialInput?: InitialInput,\n options: DispatchOptions = {},\n _ctx?: any\n): Promise<DispatchQueueResult> {\n const jobId =\n options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const queueStartUrl = getQueueStartUrl(queueId);\n const normalizedInput =\n initialInput !== null && typeof initialInput === 'object'\n ? (initialInput as Record<string, unknown>)\n : { value: initialInput };\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) headers['x-workers-trigger-key'] = triggerKey;\n const response = await fetch(queueStartUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n input: normalizedInput,\n initialInput: normalizedInput,\n metadata: options.metadata ?? {},\n jobId,\n ...(options.webhookUrl ? { webhookUrl: options.webhookUrl } : {}),\n }),\n });\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to start queue \"${queueId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ?? data?.jobId ?? `queue-${jobId}`;\n return { queueId, messageId, status: 'queued', jobId };\n}\n\n","/**\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 } 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';\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 }>;\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 (fire-and-forget or await).\n */\n appendInternalJob?(entry: { jobId: string; workerId: string }): 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 /**\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 [key: string]: any;\n };\n}\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 mapInputFromPrev?: string;\n}\n\n/** One previous step's output (for mapInputFromPrev context). */\nexport interface QueueStepOutput {\n stepIndex: number;\n workerId: string;\n output: unknown;\n}\n\n/** Runtime helpers for queue-aware wrappers (provided by generated registry). */\nexport interface QueueRuntime {\n getNextStep(queueId: string, stepIndex: number): QueueNextStep | undefined;\n /** Optional: when provided, mapping can use outputs from any previous step. */\n getQueueJob?(queueJobId: string): Promise<{ steps: Array<{ workerId: string; output?: unknown }> } | null>;\n /** (initialInput, previousOutputs) – previousOutputs includes outputs for steps 0..stepIndex-1 and current step. */\n invokeMapInput?(\n queueId: string,\n stepIndex: number,\n initialInput: unknown,\n previousOutputs: QueueStepOutput[]\n ): Promise<unknown> | unknown;\n}\n\nconst WORKER_QUEUE_KEY = '__workerQueue';\nasync function notifyQueueJobStep(\n queueJobId: string,\n action: 'start' | '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 === '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 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. Uses literal worker IDs so the CLI env injection\n * picks up WORKER_QUEUE_URL_* for next-step workers.\n */\nexport function wrapHandlerForQueue<INPUT, OUTPUT>(\n handler: WorkerHandler<INPUT, OUTPUT>,\n queueRuntime: QueueRuntime\n): WorkerHandler<INPUT & { __workerQueue?: { id: string; stepIndex: number; initialInput: unknown; queueJobId?: string } }, OUTPUT> {\n return async (params) => {\n const queueContext = (params.input as any)?.[WORKER_QUEUE_KEY];\n const output = await handler(params);\n\n if (!queueContext || typeof queueContext !== 'object' || !queueContext.id) {\n return output;\n }\n\n const { id: queueId, stepIndex, initialInput, queueJobId } = queueContext;\n const jobId = (params.ctx as any)?.jobId;\n const workerId = (params.ctx as any)?.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 if (next && queueJobId) {\n // Append next step first so updateQueueJobStepInStore(complete) sees steps.length > 1\n await notifyQueueJobStep(queueJobId, 'append', {\n workerJobId: childJobId!,\n workerId: next.workerId,\n });\n }\n\n // Notify current step complete (after append when there's next, so queue isn't marked completed yet)\n if (queueJobId && typeof stepIndex === 'number') {\n await notifyQueueJobStep(queueJobId, 'complete', {\n queueId,\n stepIndex,\n workerJobId: jobId,\n workerId,\n output,\n });\n }\n\n if (!next) {\n return output;\n }\n\n let nextInput: unknown = output;\n if (next.mapInputFromPrev && typeof queueRuntime.invokeMapInput === '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 as any)?.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.invokeMapInput(\n queueId,\n 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 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}\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\nfunction sanitizeWorkerIdForEnv(workerId: string): string {\n return workerId.replace(/-/g, '_').toUpperCase();\n}\n\nfunction getQueueUrlForWorker(calleeWorkerId: string): string | undefined {\n const key = `WORKER_QUEUE_URL_${sanitizeWorkerIdForEnv(calleeWorkerId)}`;\n return process.env[key]?.trim() || undefined;\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 const metadata = options?.metadata ?? {};\n const serializedContext: Record<string, any> = {};\n if (parentContext.requestId) serializedContext.requestId = parentContext.requestId;\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 const queueUrl = getQueueUrlForWorker(calleeWorkerId);\n\n if (queueUrl) {\n const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1';\n const sqs = new SQSClient({ region });\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 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 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 const messageId = sendResult.MessageId ?? undefined;\n\n if (jobStore?.appendInternalJob) {\n await jobStore.appendInternalJob({ jobId: childJobId, workerId: calleeWorkerId });\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 // Fallback: no queue URL (e.g. local dev). Caller (index.ts) should provide in-process dispatch.\n throw new Error(\n `WORKER_QUEUE_URL_${sanitizeWorkerIdForEnv(calleeWorkerId)} is not set. ` +\n 'Configure queue URL for worker-to-worker dispatch, or run in local mode.'\n );\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 response = await fetch(webhookUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': 'ai-router-worker/1.0',\n },\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): (event: SQSEvent, context: LambdaContext) => Promise<void> {\n return async (event: SQSEvent, lambdaContext: LambdaContext) => {\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 = {} } =\n messageBody;\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 raw = (process.env.WORKER_DATABASE_TYPE || 'upstash-redis').toLowerCase();\n const jobStoreType: 'mongodb' | 'upstash-redis' =\n raw === 'mongodb' ? 'mongodb' : 'upstash-redis';\n if (jobStoreType === 'upstash-redis' && isRedisJobStoreConfigured()) {\n const existing = await loadRedisJob(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 } else if (jobStoreType === 'mongodb' || isMongoJobStoreConfigured()) {\n const existing = await getMongoJobById(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\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 (\n jobStoreType === 'upstash-redis' &&\n isRedisJobStoreConfigured()\n ) {\n await upsertRedisJob(jobId, workerId, input, metadata);\n jobStore = createRedisJobStore(workerId, jobId, input, metadata);\n } else if (\n jobStoreType === 'mongodb' ||\n isMongoJobStoreConfigured()\n ) {\n await upsertJob(jobId, workerId, input, metadata);\n jobStore = createMongoJobStore(workerId, jobId, input, metadata);\n }\n\n const baseContext = {\n jobId,\n workerId,\n requestId: context.requestId || lambdaContext.awsRequestId,\n ...context,\n };\n const handlerContext = {\n ...baseContext,\n ...(jobStore ? { jobStore } : {}),\n logger: createWorkerLogger(jobId, workerId),\n dispatchWorker: createDispatchWorker(\n jobId,\n workerId,\n baseContext,\n jobStore\n ),\n };\n\n if (jobStore) {\n try {\n await jobStore.update({ status: 'running' });\n const queueCtxForLog = (input as any)?.__workerQueue ?? metadata?.__workerQueue;\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 = (input as any)?.__workerQueue ?? metadata?.__workerQueue;\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 });\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 stepIndex: queueCtx.stepIndex,\n workerJobId: jobId,\n workerId,\n input,\n });\n }\n\n let output: OUTPUT;\n try {\n output = await handler({\n input: input as INPUT,\n ctx: handlerContext,\n });\n\n if (outputSchema) {\n output = outputSchema.parse(output);\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 = (input as any)?.__workerQueue ?? metadata?.__workerQueue;\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 };\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 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): 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 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: { jobId: string; workerId: string }): 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): 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 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 let internalJobs: Array<{ jobId: string; workerId: string }> | undefined;\n if (listItems && listItems.length > 0) {\n internalJobs = listItems.map((s) => {\n try {\n return JSON.parse(s) as { jobId: string; workerId: string };\n } catch {\n return null;\n }\n }).filter(Boolean) as Array<{ jobId: string; workerId: string }>;\n } else {\n internalJobs = parseJson<Array<{ jobId: string; workerId: string }>>(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 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): 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): Promise<void> {\n const redis = getRedis();\n const key = jobKey(jobId);\n const now = new Date().toISOString();\n const doc: Partial<JobRecord> = {\n jobId,\n workerId,\n status: 'queued',\n input,\n metadata,\n createdAt: now,\n updatedAt: now,\n };\n const toSet: Record<string, string> = {\n jobId: jobId,\n workerId: workerId,\n status: doc.status!,\n input: JSON.stringify(doc.input ?? {}),\n metadata: JSON.stringify(doc.metadata ?? {}),\n createdAt: now,\n updatedAt: now,\n };\n await redis.hset(key, toSet);\n if (jobTtlSeconds > 0) {\n await redis.expire(key, jobTtlSeconds);\n }\n}\n\n","/**\n * Queue job store for worker queues (MongoDB or Upstash Redis).\n *\n * Mirrors the worker_jobs pattern but optimized for queues:\n * - MongoDB: collection `queue_jobs` (configurable via MONGODB_QUEUE_JOBS_COLLECTION)\n * - Upstash Redis: JSON blob per queue job with compact step entries\n *\n * This module is runtime-only (used by Lambda workers). Next.js APIs can read\n * the same collections/keys to show queue progress.\n */\n\nimport type { Redis } from '@upstash/redis';\nimport { Redis as UpstashRedis } from '@upstash/redis';\nimport { MongoClient, type Collection } from 'mongodb';\n\ntype QueueJobStep = {\n workerId: string;\n workerJobId: string;\n status: 'queued' | 'running' | 'completed' | 'failed';\n input?: unknown;\n output?: unknown;\n error?: { message: string };\n startedAt?: string;\n completedAt?: string;\n};\n\ntype QueueJobDoc = {\n _id: string; // queueJobId\n id: string;\n queueId: string;\n status: 'running' | 'completed' | 'failed' | 'partial';\n steps: QueueJobStep[];\n metadata?: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n completedAt?: string;\n};\n\n\n// === Mongo backend (shares connection pattern with mongoJobStore) ===\n\nconst mongoUri = process.env.DATABASE_MONGODB_URI || process.env.MONGODB_URI;\nconst mongoDbName =\n process.env.DATABASE_MONGODB_DB ||\n process.env.MONGODB_DB ||\n 'mediamake';\nconst mongoQueueCollectionName =\n process.env.MONGODB_QUEUE_JOBS_COLLECTION || 'queue_jobs';\n\nlet mongoClientPromise: Promise<MongoClient> | null = null;\n\nasync function getMongoClient(): Promise<MongoClient> {\n if (!mongoUri) {\n throw new Error(\n 'MongoDB URI required for queue job store. Set DATABASE_MONGODB_URI or MONGODB_URI.'\n );\n }\n if (!mongoClientPromise) {\n mongoClientPromise = new MongoClient(mongoUri, {\n maxPoolSize: 10,\n minPoolSize: 0,\n serverSelectionTimeoutMS: 10_000,\n }).connect();\n }\n return mongoClientPromise;\n}\n\nasync function getMongoQueueCollection(): Promise<Collection<QueueJobDoc>> {\n const client = await getMongoClient();\n return client.db(mongoDbName).collection<QueueJobDoc>(mongoQueueCollectionName);\n}\n\n// === Redis backend (Upstash) ===\n\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 queueKeyPrefix =\n process.env.WORKER_UPSTASH_REDIS_QUEUE_PREFIX ||\n process.env.UPSTASH_REDIS_QUEUE_PREFIX ||\n 'worker:queue-jobs:';\n\nconst defaultTtlSeconds = 60 * 60 * 24 * 7; // 7 days\nconst queueJobTtlSeconds =\n typeof process.env.WORKER_QUEUE_JOBS_TTL_SECONDS === 'string'\n ? parseInt(process.env.WORKER_QUEUE_JOBS_TTL_SECONDS, 10) || defaultTtlSeconds\n : typeof process.env.WORKER_JOBS_TTL_SECONDS === 'string'\n ? parseInt(process.env.WORKER_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 for queue job store. 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 UpstashRedis({\n url: redisUrl,\n token: redisToken,\n });\n }\n return redisClient;\n}\n\nfunction queueKey(id: string): string {\n return `${queueKeyPrefix}${id}`;\n}\n\ntype QueueJobRecord = Omit<QueueJobDoc, '_id'>;\n\n/** Hash values from Upstash hgetall may be auto-parsed (array/object) or raw strings. */\nfunction stepsFromHash(val: unknown): QueueJobStep[] {\n if (Array.isArray(val)) return val as QueueJobStep[];\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val) as QueueJobStep[];\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n return [];\n}\n\nfunction metadataFromHash(val: unknown): Record<string, unknown> {\n if (val && typeof val === 'object' && !Array.isArray(val)) return val as Record<string, unknown>;\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val) as Record<string, unknown>;\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n }\n return {};\n}\n\nasync function loadQueueJobRedis(queueJobId: string): Promise<QueueJobRecord | null> {\n const redis = getRedis();\n const key = queueKey(queueJobId);\n const data = await redis.hgetall(key);\n if (!data || typeof data !== 'object' || Object.keys(data).length === 0) return null;\n const d = data as Record<string, unknown>;\n const record: QueueJobRecord = {\n id: (d.id === undefined ? queueJobId : String(d.id)) as string,\n queueId: String(d.queueId ?? ''),\n status: (String(d.status ?? 'running') as QueueJobRecord['status']),\n steps: stepsFromHash(d.steps),\n metadata: metadataFromHash(d.metadata),\n createdAt: String(d.createdAt ?? new Date().toISOString()),\n updatedAt: String(d.updatedAt ?? new Date().toISOString()),\n completedAt: d.completedAt != null ? String(d.completedAt) : undefined,\n };\n return record;\n}\n\nasync function saveQueueJobRedis(record: QueueJobRecord): Promise<void> {\n const redis = getRedis();\n const key = queueKey(record.id);\n const now = new Date().toISOString();\n const toSet: Record<string, string> = {\n id: record.id,\n queueId: record.queueId,\n status: record.status,\n steps: JSON.stringify(record.steps || []),\n metadata: JSON.stringify(record.metadata || {}),\n createdAt: record.createdAt || now,\n updatedAt: record.updatedAt || now,\n };\n if (record.completedAt) {\n toSet.completedAt = record.completedAt;\n }\n await redis.hset(key, toSet);\n if (queueJobTtlSeconds > 0) {\n await redis.expire(key, queueJobTtlSeconds);\n }\n}\n\n// === Backend selection ===\n\nfunction getStoreType(): 'mongodb' | 'upstash-redis' {\n const t = (process.env.WORKER_DATABASE_TYPE || 'upstash-redis').toLowerCase();\n return t === 'mongodb' ? 'mongodb' : 'upstash-redis';\n}\n\nfunction preferMongo(): boolean {\n return getStoreType() === 'mongodb' && Boolean(mongoUri?.trim());\n}\n\nfunction preferRedis(): boolean {\n return getStoreType() !== 'mongodb' && Boolean((redisUrl || '').trim() && (redisToken || '').trim());\n}\n\n// === Public API used from handler.ts ===\n\nexport async function upsertInitialQueueJob(options: {\n queueJobId: string;\n queueId: string;\n firstWorkerId: string;\n firstWorkerJobId: string;\n metadata?: Record<string, any>;\n}): Promise<void> {\n const { queueJobId, queueId, firstWorkerId, firstWorkerJobId, metadata } = options;\n const now = new Date().toISOString();\n\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n const existing = await coll.findOne({ _id: queueJobId });\n if (existing) {\n const steps = existing.steps ?? [];\n if (steps.length === 0) {\n steps.push({\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n });\n }\n await coll.updateOne(\n { _id: queueJobId },\n {\n $set: {\n steps,\n updatedAt: now,\n },\n }\n );\n } else {\n const doc: QueueJobDoc = {\n _id: queueJobId,\n id: queueJobId,\n queueId,\n status: 'running',\n steps: [\n {\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n },\n ],\n metadata: metadata ?? {},\n createdAt: now,\n updatedAt: now,\n };\n await coll.updateOne(\n { _id: queueJobId },\n { $set: doc },\n { upsert: true }\n );\n }\n return;\n }\n\n if (preferRedis()) {\n const existing = await loadQueueJobRedis(queueJobId);\n if (existing) {\n // Ensure we have at least one step\n if (!existing.steps || existing.steps.length === 0) {\n existing.steps = [\n {\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n },\n ];\n }\n existing.updatedAt = now;\n await saveQueueJobRedis(existing);\n } else {\n const record: QueueJobRecord = {\n id: queueJobId,\n queueId,\n status: 'running',\n steps: [\n {\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n },\n ],\n metadata: metadata ?? {},\n createdAt: now,\n updatedAt: now,\n };\n await saveQueueJobRedis(record);\n }\n }\n}\n\nexport async function updateQueueJobStepInStore(options: {\n queueJobId: string;\n queueId?: string;\n stepIndex: number;\n workerId: string;\n workerJobId: string;\n status: 'running' | 'completed' | 'failed';\n input?: unknown;\n output?: unknown;\n error?: { message: string };\n}): Promise<void> {\n const { queueJobId, stepIndex, status, input, output, error } = options;\n const now = new Date().toISOString();\n\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n const existing = await coll.findOne({ _id: queueJobId });\n if (!existing) return;\n const step = existing.steps[stepIndex];\n if (!step) return;\n\n const mergedStep: QueueJobStep = {\n ...step,\n status,\n ...(input !== undefined && { input }),\n ...(output !== undefined && { output }),\n ...(error !== undefined && { error }),\n startedAt: step.startedAt ?? (status === 'running' ? now : step.startedAt),\n completedAt:\n step.completedAt ??\n (status === 'completed' || status === 'failed' ? now : step.completedAt),\n };\n\n const setDoc: Partial<QueueJobDoc> & { steps: QueueJobStep[] } = {\n steps: existing.steps,\n updatedAt: now,\n };\n setDoc.steps[stepIndex] = mergedStep;\n if (status === 'failed') {\n setDoc.status = 'failed';\n if (!existing.completedAt) setDoc.completedAt = now;\n } else if (status === 'completed' && stepIndex === existing.steps.length - 1) {\n setDoc.status = 'completed';\n if (!existing.completedAt) setDoc.completedAt = now;\n }\n\n await coll.updateOne(\n { _id: queueJobId },\n {\n $set: setDoc,\n }\n );\n return;\n }\n\n if (preferRedis()) {\n const existing = await loadQueueJobRedis(queueJobId);\n if (!existing) {\n // No queue job; nothing to update\n return;\n }\n const steps = existing.steps || [];\n const step = steps[stepIndex];\n if (!step) {\n return;\n }\n step.status = status;\n if (input !== undefined) step.input = input;\n if (output !== undefined) step.output = output;\n if (error !== undefined) step.error = error;\n if (status === 'running') {\n step.startedAt = step.startedAt ?? now;\n }\n if (status === 'completed' || status === 'failed') {\n step.completedAt = step.completedAt ?? now;\n }\n\n existing.steps = steps;\n existing.updatedAt = now;\n if (status === 'failed') {\n existing.status = 'failed';\n existing.completedAt = existing.completedAt ?? now;\n } else if (status === 'completed' && stepIndex === steps.length - 1) {\n existing.status = 'completed';\n existing.completedAt = existing.completedAt ?? now;\n }\n await saveQueueJobRedis(existing);\n }\n}\n\nexport async function appendQueueJobStepInStore(options: {\n queueJobId: string;\n queueId?: string;\n workerId: string;\n workerJobId: string;\n}): Promise<void> {\n const { queueJobId, workerId, workerJobId } = options;\n const now = new Date().toISOString();\n\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n await coll.updateOne(\n { _id: queueJobId },\n {\n $push: {\n steps: {\n workerId,\n workerJobId,\n status: 'queued',\n } as QueueJobStep,\n },\n $set: { updatedAt: now },\n }\n );\n return;\n }\n\n if (preferRedis()) {\n const existing = await loadQueueJobRedis(queueJobId);\n if (!existing) return;\n const steps = existing.steps || [];\n steps.push({\n workerId,\n workerJobId,\n status: 'queued',\n });\n existing.steps = steps;\n existing.updatedAt = now;\n await saveQueueJobRedis(existing);\n }\n}\n\n/**\n * Load a queue job by ID (for mapping context: previous step outputs).\n * Used by wrapHandlerForQueue when invoking mapInputFromPrev with previousOutputs.\n */\nexport async function getQueueJob(queueJobId: string): Promise<{\n id: string;\n queueId: string;\n status: string;\n steps: Array<{ workerId: string; workerJobId: string; status: string; output?: unknown }>;\n} | null> {\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n const doc = await coll.findOne({ _id: queueJobId });\n if (!doc) return null;\n return {\n id: doc.id ?? queueJobId,\n queueId: doc.queueId,\n status: doc.status,\n steps: (doc.steps ?? []).map((s: QueueJobStep) => ({\n workerId: s.workerId,\n workerJobId: s.workerJobId,\n status: s.status,\n output: s.output,\n })),\n };\n }\n if (preferRedis()) {\n const record = await loadQueueJobRedis(queueJobId);\n if (!record) return null;\n return {\n id: record.id,\n queueId: record.queueId,\n status: record.status,\n steps: (record.steps ?? []).map((s) => ({\n workerId: s.workerId,\n workerJobId: s.workerJobId,\n status: s.status,\n output: s.output,\n })),\n };\n }\n return null;\n}\n\n","/**\n * Workers-config client for resolving queue URLs from the workers-config API Lambda.\n */\n\nexport interface WorkersConfig {\n version: string;\n stage: string;\n region: string;\n workers: Record<\n string,\n {\n queueUrl: string;\n region: string;\n }\n >;\n}\n\nlet cachedConfig: WorkersConfig | null = null;\nlet cacheExpiry: number = 0;\nconst CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Fetches the workers configuration from the workers-config API.\n * Results are cached for 5 minutes to reduce API calls.\n *\n * @param apiUrl - The URL of the workers-config API endpoint\n * @param apiKey - Optional API key for authentication (sent as x-workers-config-key header)\n * @returns The workers configuration mapping worker IDs to queue URLs\n */\nexport async function getWorkersConfig(\n apiUrl: string,\n apiKey?: string\n): Promise<WorkersConfig> {\n const now = Date.now();\n\n // Return cached config if still valid\n if (cachedConfig && now < cacheExpiry) {\n return cachedConfig;\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (apiKey) {\n headers['x-workers-config-key'] = apiKey;\n }\n\n const response = await fetch(apiUrl, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch workers config: ${response.status} ${response.statusText}`\n );\n }\n\n const config = (await response.json()) as WorkersConfig;\n cachedConfig = config;\n cacheExpiry = now + CACHE_TTL_MS;\n\n return config;\n}\n\n/**\n * Resolves the queue URL for a specific worker ID.\n * Throws an error if the worker ID is not found in the configuration.\n *\n * @param workerId - The ID of the worker\n * @param apiUrl - The URL of the workers-config API endpoint\n * @param apiKey - Optional API key for authentication\n * @returns The queue URL for the worker\n */\nexport async function resolveQueueUrl(\n workerId: string,\n apiUrl: string,\n apiKey?: string\n): Promise<string> {\n const config = await getWorkersConfig(apiUrl, apiKey);\n const worker = config.workers[workerId];\n\n if (!worker) {\n throw new Error(\n `Worker \"${workerId}\" not found in workers config. Available workers: ${Object.keys(config.workers).join(', ')}`\n );\n }\n\n return worker.queueUrl;\n}\n\n/**\n * Clears the cached workers configuration.\n * Useful for testing or when you need to force a refresh.\n */\nexport function clearWorkersConfigCache(): void {\n cachedConfig = null;\n cacheExpiry = 0;\n}\n","/**\n * Queue definition and context types for worker queues.\n *\n * These types are used at code-time by .queue.ts files and at runtime\n * by the client and generated registry/queue wrappers.\n */\n\nexport interface WorkerQueueStep {\n /** Worker ID for this step. Must match an existing worker id. */\n workerId: string;\n /**\n * Optional delay (in seconds) before this step is executed.\n * Implemented via SQS DelaySeconds (0–900).\n */\n delaySeconds?: number;\n /**\n * Optional name of a mapping function exported from the .queue.ts file.\n * The function is called with (initialInput, previousOutputs):\n * - initialInput: original input passed to dispatchQueue (always first, for best DX).\n * - previousOutputs: array of { stepIndex, workerId, output } for steps 0..current-1.\n * Use any prior step's output; the immediate previous step is previousOutputs[previousOutputs.length - 1]?.output.\n */\n mapInputFromPrev?: string;\n}\n\nexport interface WorkerQueueConfig<InitialInput = any, StepOutput = any> {\n /** Stable queue identifier, e.g. \"cost-usage\". */\n id: string;\n /** Ordered list of workers forming the queue. */\n steps: WorkerQueueStep[];\n /**\n * Optional schedule for the queue (cron or rate).\n * When set, the CLI generates a queue-starter Lambda triggered by this schedule.\n * Example: 'cron(0 3 * * ? *)' for daily at 03:00 UTC.\n */\n schedule?: string | { rate: string; enabled?: boolean; input?: Record<string, any> };\n // The generic parameters are reserved for future typing improvements and\n // are intentionally unused here (config is structural at runtime).\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _initialInputType?: InitialInput;\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _stepOutputType?: StepOutput;\n}\n\n/**\n * Queue execution context that is embedded into job input/metadata so\n * queue-aware wrappers can determine where they are in the queue.\n */\nexport interface WorkerQueueContext<InitialInput = any> {\n id: string;\n stepIndex: number;\n initialInput: InitialInput;\n /** Queue job ID (same as first worker's jobId) for tracking progress. */\n queueJobId?: string;\n}\n\n/**\n * Identity helper for defining worker queues in .queue.ts files.\n * This is primarily for type safety and CLI discovery.\n */\nexport function defineWorkerQueue<T extends WorkerQueueConfig>(config: T): T {\n return config;\n}\n\n"],"mappings":"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","names":["import_redis","import_mongodb","redisUrl","redisToken","defaultTtlSeconds","redisClient","getRedis","UpstashRedis","module","explicitPath","DEFAULT_POLL_INTERVAL_MS","DEFAULT_POLL_TIMEOUT_MS","input","options","response"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/handler.ts","../src/mongoJobStore.ts","../src/redisJobStore.ts","../src/queueJobStore.ts","../src/queue.ts","../src/retryConfig.ts","../src/tokenBudget.ts","../src/config.ts","../src/queueInputEnvelope.ts","../src/chainMapDefaults.ts","../src/hitlConfig.ts"],"sourcesContent":["/**\n * @microfox/ai-worker\n * Worker runtime for ai-router - SQS-based async agent execution\n */\n\nimport { dispatch, dispatchLocal, getWorkersTriggerUrl, type DispatchOptions, type DispatchResult } from './client.js';\nimport { createLambdaHandler, createWorkerLogger, type WorkerHandler, type JobStore, type DispatchWorkerOptions, SQS_MAX_DELAY_SECONDS } from './handler.js';\nimport { QUEUE_ORCHESTRATION_KEYS } from './queue.js';\nimport { type SmartRetryConfig, type RetryContext, executeWithRetry } from './retryConfig.js';\nimport { type TokenUsage, createTokenTracker } from './tokenBudget.js';\nimport type { ZodType, z } from 'zod';\n\nexport * from './client.js';\nexport * from './handler.js';\nexport * from './config.js';\nexport * from './queue.js';\nexport * from './queueInputEnvelope.js';\nexport * from './chainMapDefaults.js';\nexport * from './hitlConfig.js';\nexport * from './retryConfig.js';\nexport { TokenBudgetExceededError } from './tokenBudget.js';\nexport type { TokenUsage, TokenBudgetState } from './tokenBudget.js';\n\n/**\n * Schedule event configuration for a worker.\n * Supports both simple rate/cron strings and full configuration objects.\n * \n * @example Simple rate/cron\n * ```typescript\n * schedule: 'rate(2 hours)'\n * // or\n * schedule: 'cron(0 12 * * ? *)'\n * ```\n * \n * @example Full configuration\n * ```typescript\n * schedule: {\n * rate: 'rate(10 minutes)',\n * enabled: true,\n * input: { key1: 'value1' }\n * }\n * ```\n * \n * @example Multiple schedules\n * ```typescript\n * schedule: [\n * 'rate(2 hours)',\n * { rate: 'cron(0 12 * * ? *)', enabled: false }\n * ]\n * ```\n */\nexport interface ScheduleEventConfig {\n /**\n * Schedule rate using either rate() or cron() syntax.\n * Can be a string or array of strings for multiple schedules.\n * \n * @example 'rate(2 hours)' or 'cron(0 12 * * ? *)'\n * @example ['cron(0 0/4 ? * MON-FRI *)', 'cron(0 2 ? * SAT-SUN *)']\n */\n rate: string | string[];\n /**\n * Whether the schedule is enabled (default: true).\n */\n enabled?: boolean;\n /**\n * Input payload to pass to the function.\n */\n input?: Record<string, any>;\n /**\n * JSONPath expression to select part of the event data as input.\n */\n inputPath?: string;\n /**\n * Input transformer configuration for custom input mapping.\n */\n inputTransformer?: {\n inputPathsMap?: Record<string, string>;\n inputTemplate?: string;\n };\n /**\n * Name of the schedule event.\n */\n name?: string;\n /**\n * Description of the schedule event.\n */\n description?: string;\n /**\n * Method to use: 'eventBus' (default) or 'scheduler'.\n * Use 'scheduler' for higher limits (1M events vs 300).\n */\n method?: 'eventBus' | 'scheduler';\n /**\n * Timezone for the schedule (only used with method: 'scheduler').\n * @example 'America/New_York'\n */\n timezone?: string;\n}\n\nexport type ScheduleConfig = \n | string \n | ScheduleEventConfig \n | (string | ScheduleEventConfig)[];\n\n/**\n * Configuration for a worker's Lambda function deployment.\n * \n * **Best Practice**: Export this as a separate const from your worker file:\n * ```typescript\n * export const workerConfig: WorkerConfig = {\n * timeout: 900,\n * memorySize: 2048,\n * layers: ['arn:aws:lambda:${aws:region}:${aws:accountId}:layer:ffmpeg:1'],\n * schedule: 'rate(2 hours)',\n * };\n * ```\n * \n * The CLI will automatically extract it from the export. You do not need to pass it to `createWorker()`.\n */\nexport interface WorkerConfig {\n /**\n * Lambda function timeout in seconds (max 900).\n */\n timeout?: number;\n /**\n * Lambda function memory size in MB (128-10240).\n */\n memorySize?: number;\n /**\n * Optional Lambda layers ARNs to attach to this worker function.\n *\n * This is primarily used by @microfox/ai-worker-cli when generating serverless.yml.\n * Supports CloudFormation pseudo-parameters like ${aws:region} and ${aws:accountId}.\n *\n * Example:\n * layers: ['arn:aws:lambda:${aws:region}:${aws:accountId}:layer:ffmpeg:1']\n */\n layers?: string[];\n /**\n * Schedule events configuration for this worker.\n * Allows multiple schedule events to be attached to the same function.\n * \n * @example Simple rate\n * ```typescript\n * schedule: 'rate(2 hours)'\n * ```\n * \n * @example Multiple schedules\n * ```typescript\n * schedule: [\n * 'rate(2 hours)',\n * { rate: 'cron(0 12 * * ? *)', enabled: true, input: { key: 'value' } }\n * ]\n * ```\n * \n * @example Using scheduler method with timezone\n * ```typescript\n * schedule: {\n * method: 'scheduler',\n * rate: 'cron(0 0/4 ? * MON-FRI *)',\n * timezone: 'America/New_York',\n * input: { key1: 'value1' }\n * }\n * ```\n */\n schedule?: ScheduleConfig;\n\n /**\n * If set, this worker is deployed to the serverless project for this group.\n * Do not use 'core' (reserved). Max 12 characters (serverless service name limits).\n */\n group?: string;\n\n /**\n * SQS queue settings for this worker (used by @microfox/ai-worker-cli when generating serverless.yml).\n *\n * Notes:\n * - To effectively disable retries, set `maxReceiveCount: 1` (requires DLQ; the CLI will create one).\n * - SQS does not support `maxReceiveCount: 0`.\n * - `messageRetentionPeriod` is in seconds (max 1209600 = 14 days).\n */\n sqs?: {\n /**\n * How many receives before sending to DLQ.\n * Use 1 to avoid retries.\n */\n maxReceiveCount?: number;\n /**\n * How long messages are retained in the main queue (seconds).\n */\n messageRetentionPeriod?: number;\n /**\n * Visibility timeout for the main queue (seconds).\n * If not set, CLI defaults to (worker timeout + 60s).\n */\n visibilityTimeout?: number;\n /**\n * DLQ message retention period (seconds).\n * Defaults to `messageRetentionPeriod` (or 14 days).\n */\n deadLetterMessageRetentionPeriod?: number;\n };\n}\n\nexport interface WorkerAgentConfig<INPUT_SCHEMA extends ZodType<any>, OUTPUT> {\n id: string;\n inputSchema: INPUT_SCHEMA;\n outputSchema: ZodType<OUTPUT>;\n handler: WorkerHandler<z.infer<INPUT_SCHEMA>, OUTPUT>;\n /**\n * Smart retry configuration for this worker.\n * Applies whenever this worker runs (Lambda or local mode).\n * Can be overridden per queue step via WorkerQueueStep.retry.\n * Retries are in-process so ctx.retryContext is populated on each retry attempt.\n *\n * @example\n * ```ts\n * retry: { maxAttempts: 3, on: ['rate-limit', 'json-parse'] }\n * ```\n */\n retry?: SmartRetryConfig;\n /**\n * @deprecated Prefer exporting `workerConfig` as a separate const from your worker file.\n * The CLI will automatically extract it from the export. This parameter is kept for backward compatibility.\n */\n workerConfig?: WorkerConfig;\n}\n\nexport interface WorkerAgent<INPUT_SCHEMA extends ZodType<any>, OUTPUT> {\n id: string;\n dispatch: (\n input: z.input<INPUT_SCHEMA>,\n options: DispatchOptions\n ) => Promise<DispatchResult>;\n handler: WorkerHandler<z.infer<INPUT_SCHEMA>, OUTPUT>;\n inputSchema: INPUT_SCHEMA;\n outputSchema: ZodType<OUTPUT>;\n workerConfig?: WorkerConfig;\n /** Smart retry config set on this worker via createWorker({ retry }). */\n retry?: SmartRetryConfig;\n}\n\n/**\n * Creates a worker agent that can be dispatched to SQS/Lambda.\n *\n * In development mode (NODE_ENV === 'development' and WORKERS_LOCAL_MODE !== 'false'),\n * dispatch() will run the handler immediately in the same process.\n *\n * In production, dispatch() sends a message to SQS which triggers a Lambda function.\n *\n * @template INPUT_SCHEMA - The Zod schema type (e.g., `typeof InputSchema`).\n * Used to derive both:\n * - Pre-parse input type via `z.input<INPUT_SCHEMA>` for `dispatch()` (preserves optional fields)\n * - Parsed input type via `z.infer<INPUT_SCHEMA>` for handler (defaults applied)\n * @template OUTPUT - The output type returned by the handler. Use `z.infer<typeof OutputSchema>`.\n *\n * @param config - Worker agent configuration\n * @returns A worker agent object with a dispatch method\n *\n * @example\n * ```typescript\n * const InputSchema = z.object({\n * url: z.string().url(),\n * timeout: z.number().optional().default(5000), // optional with default\n * });\n *\n * export const worker = createWorker<typeof InputSchema, Output>({\n * // dispatch() accepts { url: string, timeout?: number } (pre-parse, optional preserved)\n * // handler receives { url: string, timeout: number } (parsed, default applied)\n * });\n * ```\n */\nexport function createWorker<INPUT_SCHEMA extends ZodType<any>, OUTPUT>(\n config: WorkerAgentConfig<INPUT_SCHEMA, OUTPUT>\n): WorkerAgent<INPUT_SCHEMA, OUTPUT> {\n const { id, inputSchema, outputSchema, handler, retry: retryConfig } = config;\n\n const agent: WorkerAgent<INPUT_SCHEMA, OUTPUT> = {\n id,\n handler,\n inputSchema,\n outputSchema,\n retry: retryConfig,\n\n async dispatch(input: z.input<INPUT_SCHEMA>, options: DispatchOptions): Promise<DispatchResult> {\n const mode = options.mode ?? 'auto';\n const envWantsLocal =\n process.env.NODE_ENV === 'development' &&\n process.env.WORKERS_LOCAL_MODE !== 'false';\n // Check if we're in local development mode\n const isLocal = mode === 'local' || (mode === 'auto' && envWantsLocal);\n\n if (isLocal) {\n // Local mode: run handler immediately.\n // Strip queue/HITL orchestration keys before parsing so workers don't need\n // queueOrchestrationFieldsSchema in their Zod schemas.\n const rawInputObj =\n input !== null && typeof input === 'object' ? (input as Record<string, unknown>) : null;\n const domainInput = rawInputObj\n ? Object.fromEntries(\n Object.entries(rawInputObj).filter(\n ([k]) => k !== '__workerQueue' && !(QUEUE_ORCHESTRATION_KEYS as readonly string[]).includes(k)\n )\n )\n : input;\n const parsedInput = inputSchema.parse(domainInput);\n const localJobId = options.jobId || `local-${Date.now()}`;\n \n // Try to get direct job store access in local mode (same process as Next.js app)\n // This allows direct DB updates without needing HTTP/webhook URLs\n let directJobStore: {\n updateJob: (jobId: string, data: any) => Promise<void>;\n setJob?: (jobId: string, data: any) => Promise<void>;\n } | null = null;\n\n // Path constants for job store imports\n const nextJsPathAlias = '@/app/api/workflows/stores/jobStore';\n const explicitPath = process.env.WORKER_JOB_STORE_MODULE_PATH;\n\n // Reliable approach: try Next.js path alias first, then explicit env var\n // The @/ alias works at runtime in Next.js context\n const resolveJobStore = async () => {\n // Option 1: Try Next.js path alias (works in Next.js runtime context)\n try {\n const module = await import(nextJsPathAlias);\n if (module?.updateJob) {\n return { updateJob: module.updateJob, setJob: module.setJob };\n }\n } catch {\n // Path alias not available (not in Next.js context or alias not configured)\n }\n\n // Option 2: Use explicit env var if provided (for custom setups)\n if (explicitPath) {\n try {\n const module = await import(explicitPath).catch(() => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require(explicitPath);\n });\n if (module?.updateJob) {\n return { updateJob: module.updateJob, setJob: module.setJob };\n }\n } catch {\n // Explicit path failed\n }\n }\n\n return null;\n };\n\n directJobStore = await resolveJobStore();\n if (directJobStore) {\n console.log('[Worker] Using direct job store in local mode (no HTTP needed)');\n }\n\n // Derive job store URL from webhook URL or environment (fallback for HTTP mode)\n let jobStoreUrl: string | undefined;\n if (options.webhookUrl) {\n try {\n const webhookUrlObj = new URL(options.webhookUrl);\n jobStoreUrl = webhookUrlObj.pathname.replace(/\\/webhook$/, '');\n jobStoreUrl = `${webhookUrlObj.origin}${jobStoreUrl}`;\n } catch {\n // Invalid URL, skip job store URL\n }\n }\n jobStoreUrl = jobStoreUrl || process.env.WORKER_JOB_STORE_URL;\n\n // Create job store interface for local mode\n // Prefer direct DB access, fallback to HTTP calls if needed\n const createLocalJobStore = (\n directStore: typeof directJobStore,\n httpUrl?: string\n ): JobStore | undefined => {\n // If we have direct job store access, use it (no HTTP needed)\n if (directStore) {\n return {\n update: async (update) => {\n try {\n // Build update payload\n const updatePayload: any = {};\n \n if (update.status !== undefined) {\n updatePayload.status = update.status;\n }\n if (update.metadata !== undefined) {\n updatePayload.metadata = update.metadata;\n }\n if (update.progress !== undefined) {\n // Merge progress into metadata\n updatePayload.metadata = {\n ...updatePayload.metadata,\n progress: update.progress,\n progressMessage: update.progressMessage,\n };\n }\n if (update.output !== undefined) {\n updatePayload.output = update.output;\n }\n if (update.error !== undefined) {\n updatePayload.error = update.error;\n }\n\n await directStore.updateJob(localJobId, updatePayload);\n console.log('[Worker] Local job updated (direct DB):', {\n jobId: localJobId,\n workerId: id,\n updates: Object.keys(updatePayload),\n });\n } catch (error: any) {\n console.warn('[Worker] Failed to update local job (direct DB):', {\n jobId: localJobId,\n workerId: id,\n error: error?.message || String(error),\n });\n }\n },\n get: async () => {\n try {\n // Use the same direct store that has updateJob - it should also have getJob\n if (directStore) {\n // Try to import getJob from the same module\n const nextJsPath = '@/app/api/workflows/stores/jobStore';\n const explicitPath = process.env.WORKER_JOB_STORE_MODULE_PATH;\n \n for (const importPath of [nextJsPath, explicitPath].filter(Boolean)) {\n try {\n const module = await import(importPath!);\n if (module?.getJob) {\n return await module.getJob(localJobId);\n }\n } catch {\n // Continue\n }\n }\n }\n return null;\n } catch (error: any) {\n console.warn('[Worker] Failed to get local job (direct DB):', {\n jobId: localJobId,\n workerId: id,\n error: error?.message || String(error),\n });\n return null;\n }\n },\n appendInternalJob: async (entry: { jobId: string; workerId: string }) => {\n try {\n const nextJsPath = '@/app/api/workflows/stores/jobStore';\n const explicitPath = process.env.WORKER_JOB_STORE_MODULE_PATH;\n for (const importPath of [nextJsPath, explicitPath].filter(Boolean)) {\n try {\n const module = await import(importPath!);\n if (typeof module?.appendInternalJob === 'function') {\n await module.appendInternalJob(localJobId, entry);\n return;\n }\n } catch {\n // Continue\n }\n }\n } catch (error: any) {\n console.warn('[Worker] Failed to appendInternalJob (direct DB):', { localJobId, error: error?.message || String(error) });\n }\n },\n getJob: async (otherJobId: string) => {\n try {\n const nextJsPath = '@/app/api/workflows/stores/jobStore';\n const explicitPath = process.env.WORKER_JOB_STORE_MODULE_PATH;\n for (const importPath of [nextJsPath, explicitPath].filter(Boolean)) {\n try {\n const module = await import(importPath!);\n if (typeof module?.getJob === 'function') {\n return await module.getJob(otherJobId);\n }\n } catch {\n // Continue\n }\n }\n } catch (error: any) {\n console.warn('[Worker] Failed to getJob (direct DB):', { otherJobId, error: error?.message || String(error) });\n }\n return null;\n },\n };\n }\n\n // Fallback to HTTP calls if no direct access\n if (!httpUrl) {\n return undefined;\n }\n\n // Use HTTP calls to update job store\n return {\n update: async (update) => {\n try {\n // Build update payload\n const updatePayload: any = { jobId: localJobId, workerId: id };\n \n if (update.status !== undefined) {\n updatePayload.status = update.status;\n }\n if (update.metadata !== undefined) {\n updatePayload.metadata = update.metadata;\n }\n if (update.progress !== undefined) {\n // Merge progress into metadata\n updatePayload.metadata = {\n ...updatePayload.metadata,\n progress: update.progress,\n progressMessage: update.progressMessage,\n };\n }\n if (update.output !== undefined) {\n updatePayload.output = update.output;\n }\n if (update.error !== undefined) {\n updatePayload.error = update.error;\n }\n\n const response = await fetch(`${httpUrl}/update`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(updatePayload),\n });\n if (!response.ok) {\n throw new Error(`Job store update failed: ${response.status} ${response.statusText}`);\n }\n console.log('[Worker] Local job updated (HTTP):', {\n jobId: localJobId,\n workerId: id,\n updates: Object.keys(updatePayload),\n });\n } catch (error: any) {\n console.warn('[Worker] Failed to update local job (HTTP):', {\n jobId: localJobId,\n workerId: id,\n error: error?.message || String(error),\n });\n }\n },\n get: async () => {\n try {\n // GET /api/workflows/workers/:workerId/:jobId\n const response = await fetch(`${httpUrl}/${id}/${localJobId}`, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`Job store get failed: ${response.status} ${response.statusText}`);\n }\n\n return await response.json();\n } catch (error: any) {\n console.warn('[Worker] Failed to get local job (HTTP):', {\n jobId: localJobId,\n workerId: id,\n error: error?.message || String(error),\n });\n return null;\n }\n },\n };\n };\n\n const jobStore = createLocalJobStore(directJobStore, jobStoreUrl);\n\n const DEFAULT_POLL_INTERVAL_MS = 2000;\n const DEFAULT_POLL_TIMEOUT_MS = 15 * 60 * 1000;\n\n const createLocalDispatchWorker = (\n parentJobId: string,\n parentWorkerId: string,\n parentContext: Record<string, any>,\n store: 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 const metadata = options?.metadata ?? {};\n const serializedContext: Record<string, any> = {};\n if (parentContext.requestId) serializedContext.requestId = parentContext.requestId;\n if (parentContext.userId) serializedContext.userId = parentContext.userId;\n const messageBody = {\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 let triggerUrl: string;\n try {\n triggerUrl = getWorkersTriggerUrl();\n } catch (e: any) {\n throw new Error(\n `Local dispatchWorker requires WORKER_BASE_URL (or similar) for worker \"${calleeWorkerId}\": ${e?.message ?? e}`\n );\n }\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) headers['x-workers-trigger-key'] = triggerKey;\n\n // Fire-and-forget with delay: schedule trigger after delay, return immediately (no computation/wait in caller).\n if (options?.await !== true && options?.delaySeconds != null && options.delaySeconds > 0) {\n const sec = Math.min(SQS_MAX_DELAY_SECONDS, Math.max(0, Math.floor(options.delaySeconds)));\n const storeRef = store;\n setTimeout(() => {\n fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({ workerId: calleeWorkerId, body: messageBody }),\n })\n .then(async (response) => {\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n console.error(\n `[Worker] Delayed trigger failed for \"${calleeWorkerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n return;\n }\n if (storeRef?.appendInternalJob) {\n await storeRef.appendInternalJob({ jobId: childJobId, workerId: calleeWorkerId });\n }\n })\n .catch((err) => {\n console.error('[Worker] Delayed trigger error:', { calleeWorkerId, jobId: childJobId, error: err?.message ?? err });\n });\n }, sec * 1000);\n return { jobId: childJobId, messageId: undefined };\n }\n\n const response = await fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({ workerId: calleeWorkerId, body: messageBody }),\n });\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to trigger worker \"${calleeWorkerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ? String(data.messageId) : `trigger-${childJobId}`;\n\n if (store?.appendInternalJob) {\n await store.appendInternalJob({ jobId: childJobId, workerId: calleeWorkerId });\n }\n\n if (options?.await && store?.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 store.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(err?.message ?? `Child worker ${calleeWorkerId} failed`);\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 // Create initial job record if we have job store access\n if (directJobStore?.setJob) {\n try {\n await directJobStore.setJob(localJobId, {\n jobId: localJobId,\n workerId: id,\n status: 'queued',\n input: parsedInput,\n metadata: options.metadata || {},\n });\n } catch (error: any) {\n console.warn('[Worker] Failed to create initial job record:', {\n jobId: localJobId,\n workerId: id,\n error: error?.message || String(error),\n });\n // Continue - job will still be created when status is updated\n }\n }\n\n const localUserId = options.userId;\n const baseContext = {\n jobId: localJobId,\n workerId: id,\n ...(localUserId ? { userId: localUserId } : {}),\n };\n if (localUserId) {\n // Parseable audit log matching Lambda pattern for consistent log parsing.\n console.log(`[WORKER_USER:${localUserId}]`, { jobId: localJobId, workerId: id, mode: 'local', timestamp: new Date().toISOString() });\n }\n\n const localLogger = createWorkerLogger(localJobId, id);\n const tokenTracker = createTokenTracker(options.maxTokens ?? null);\n\n const handlerContext: any = {\n ...baseContext,\n ...(jobStore ? { jobStore } : {}),\n logger: localLogger,\n dispatchWorker: createLocalDispatchWorker(localJobId, id, baseContext, jobStore),\n reportTokenUsage: async (usage: TokenUsage) => {\n tokenTracker.report(usage);\n const state = tokenTracker.getState();\n if (jobStore) {\n await jobStore.update({ metadata: { tokenUsage: state } }).catch((e: any) => {\n localLogger.warn('Failed to persist tokenUsage', { error: e?.message });\n });\n }\n },\n getTokenBudget: () => tokenTracker.getBudgetInfo(),\n retryContext: undefined as RetryContext | undefined,\n };\n\n try {\n // Update status to running before execution\n if (jobStore) {\n await jobStore.update({ status: 'running' });\n }\n\n const executeLocal = async (retryCtx: RetryContext | undefined) => {\n handlerContext.retryContext = retryCtx;\n return dispatchLocal(handler, parsedInput, handlerContext);\n };\n\n const output = retryConfig && retryConfig.on.length > 0\n ? await executeWithRetry(executeLocal, retryConfig, (retryCtx, delayMs) => {\n localLogger.warn(\n `[worker-retry] Local retry (attempt ${retryCtx.attempt}/${retryCtx.maxAttempts}): ${retryCtx.lastError.message}`,\n { delayMs }\n );\n })\n : await executeLocal(undefined);\n\n // Update status to completed before webhook\n if (jobStore) {\n await jobStore.update({ status: 'completed', output });\n }\n\n // Only send webhook if webhookUrl is provided\n if (options.webhookUrl) {\n try {\n await fetch(options.webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jobId: localJobId,\n workerId: id,\n status: 'success',\n output,\n metadata: options.metadata,\n }),\n });\n } catch (error) {\n console.warn('[Worker] Local webhook call failed:', error);\n }\n }\n\n return {\n messageId: `local-${Date.now()}`,\n status: 'queued',\n jobId: localJobId,\n };\n } catch (error: any) {\n // Update status to failed before webhook\n if (jobStore) {\n await jobStore.update({\n status: 'failed',\n error: {\n message: error.message || 'Unknown error',\n stack: error.stack,\n name: error.name || 'Error',\n },\n });\n }\n\n // Only send error webhook if webhookUrl is provided\n if (options.webhookUrl) {\n try {\n await fetch(options.webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jobId: localJobId,\n workerId: id,\n status: 'error',\n error: {\n message: error.message || 'Unknown error',\n stack: error.stack,\n name: error.name || 'Error',\n },\n metadata: options.metadata,\n }),\n });\n } catch (webhookError) {\n console.warn('[Worker] Local error webhook call failed:', webhookError);\n }\n }\n throw error;\n }\n }\n\n // Production mode: dispatch to SQS\n return dispatch(id, input, inputSchema, options);\n },\n };\n\n return agent;\n}\n\n/**\n * Creates a Lambda handler entrypoint for a worker agent.\n * This is used by the deployment script to generate Lambda entrypoints.\n *\n * @param agent - The worker agent\n * @returns A Lambda handler function\n */\nexport function createLambdaEntrypoint<INPUT_SCHEMA extends ZodType<any>, OUTPUT>(\n agent: WorkerAgent<INPUT_SCHEMA, OUTPUT>\n) {\n return createLambdaHandler(agent.handler, agent.outputSchema, { retry: agent.retry });\n}\n","/**\n * Client for dispatching background worker jobs.\n *\n * In production, dispatching happens via the workers HTTP API:\n * POST /workers/trigger -> enqueues message to SQS on the workers service side\n *\n * This avoids requiring AWS credentials in your Next.js app.\n */\n\nimport type { ZodType, z } from 'zod';\nimport type { WorkerQueueConfig } from './queue.js';\n\nimport type { ChainContext, HitlResumeContext, LoopContext } from './queue.js';\n\nexport interface WorkerQueueRegistry {\n getQueueById(queueId: string): WorkerQueueConfig | undefined;\n getStepAt?(queueId: string, stepIndex: number): {\n workerId?: string;\n requiresApproval?: boolean;\n hasChain?: boolean;\n hasResume?: boolean;\n hasLoop?: boolean;\n hitl?: unknown;\n } | undefined;\n /** Build next-step input during normal chain advancement (no HITL). */\n invokeChain?: (\n queueId: string,\n stepIndex: number,\n ctx: ChainContext\n ) => Promise<unknown> | unknown;\n /** Build domain input when a HITL step resumes after human approval. */\n invokeResume?: (\n queueId: string,\n stepIndex: number,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ctx: HitlResumeContext<any>\n ) => Promise<unknown> | unknown;\n /** Evaluate whether a looping step should run again after its output. */\n invokeLoop?: (\n queueId: string,\n stepIndex: number,\n ctx: LoopContext\n ) => Promise<boolean> | boolean;\n}\n\nexport interface DispatchOptions {\n /**\n * Optional webhook callback URL to notify when the job finishes.\n * Only called when provided. Default: no webhook (use job store / MongoDB only).\n */\n webhookUrl?: string;\n /**\n * Controls how dispatch executes.\n * - \"auto\" (default): local inline execution in development unless WORKERS_LOCAL_MODE=false.\n * - \"local\": force inline execution (no SQS).\n * - \"remote\": force SQS/Lambda dispatch even in development.\n */\n mode?: 'auto' | 'local' | 'remote';\n jobId?: string;\n /**\n * The ID of the user who triggered this job.\n * Call getClientId() in your API route and pass the result here.\n * If omitted, userId is not stored and not logged.\n */\n userId?: string;\n metadata?: Record<string, any>;\n /**\n * In-memory queue registry for dispatchQueue. Required when using dispatchQueue.\n * Pass a registry that imports from your .queue.ts definitions (works on Vercel/serverless).\n */\n registry?: WorkerQueueRegistry;\n /**\n * Optional callback to create a queue job record before dispatching.\n * Called with queueJobId (= first worker's jobId), queueId, and firstStep.\n */\n onCreateQueueJob?: (params: {\n queueJobId: string;\n queueId: string;\n firstStep: { workerId: string; workerJobId: string };\n metadata?: Record<string, unknown>;\n }) => Promise<void>;\n /**\n * Maximum total tokens (input + output) allowed for this job.\n * The worker must call ctx.reportTokenUsage() after each LLM call.\n * Throws TokenBudgetExceededError when the limit is reached.\n * For queues, applies per-step unless overridden on the queue step config.\n */\n maxTokens?: number;\n}\n\nexport interface DispatchResult {\n messageId: string;\n status: 'queued';\n jobId: string;\n}\n\nexport interface DispatchQueueResult extends DispatchResult {\n queueId: string;\n}\n\nexport interface SerializedContext {\n requestId?: string;\n userId?: string;\n traceId?: string;\n [key: string]: any;\n}\n\n\n/**\n * Derives the full /workers/trigger URL from env.\n * Exported for use by local dispatchWorker (worker-to-worker in dev).\n * Server-side only; clients should use useWorkflowJob with your app's /api/workflows routes.\n *\n * Env vars:\n * - WORKER_BASE_URL: base URL of the workers service (e.g. https://.../prod)\n * - WORKERS_TRIGGER_API_URL / WORKERS_CONFIG_API_URL: legacy, still supported\n */\nexport function getWorkersTriggerUrl(): string {\n const raw =\n process.env.WORKER_BASE_URL ||\n process.env.WORKERS_TRIGGER_API_URL ||\n process.env.WORKERS_CONFIG_API_URL;\n\n if (!raw) {\n throw new Error(\n 'WORKER_BASE_URL is required for background workers. Set it server-side only.'\n );\n }\n\n const url = new URL(raw);\n url.search = '';\n url.hash = '';\n\n const path = url.pathname || '';\n\n // If the user pointed at a specific endpoint, normalize back to the service root.\n url.pathname = path.replace(/\\/?workers\\/(trigger|config)\\/?$/, '');\n\n const basePath = url.pathname.replace(/\\/+$/, '');\n url.pathname = `${basePath}/workers/trigger`.replace(/\\/+$/, '');\n\n return url.toString();\n}\n\n/**\n * URL for the queue start endpoint (dispatch proxy). Use this so queue starts\n * go through the queue handler Lambda for easier debugging (one log stream per queue).\n */\nexport function getQueueStartUrl(queueId: string): string {\n const raw =\n process.env.WORKER_BASE_URL ||\n process.env.WORKERS_TRIGGER_API_URL ||\n process.env.WORKERS_CONFIG_API_URL;\n\n if (!raw) {\n throw new Error(\n 'WORKER_BASE_URL is required for background workers. Set it server-side only.'\n );\n }\n\n const url = new URL(raw);\n url.search = '';\n url.hash = '';\n\n const path = url.pathname || '';\n url.pathname = path.replace(/\\/?workers\\/(trigger|config)\\/?$/, '');\n const basePath = url.pathname.replace(/\\/+$/, '');\n const safeSegment = encodeURIComponent(queueId);\n url.pathname = `${basePath}/queues/${safeSegment}/start`.replace(/\\/+$/, '');\n\n return url.toString();\n}\n\n/**\n * Serializes context data for transmission to Lambda.\n * Only serializes safe, JSON-compatible properties.\n */\nfunction serializeContext(ctx: any): SerializedContext {\n const serialized: SerializedContext = {};\n\n if (ctx.requestId) {\n serialized.requestId = ctx.requestId;\n }\n\n if (ctx.userId) {\n serialized.userId = ctx.userId;\n }\n\n // Extract any additional serializable metadata\n if (ctx.metadata && typeof ctx.metadata === 'object') {\n Object.assign(serialized, ctx.metadata);\n }\n\n // Allow custom context serialization via a helper property\n if (ctx._serializeContext && typeof ctx._serializeContext === 'function') {\n const custom = ctx._serializeContext();\n Object.assign(serialized, custom);\n }\n\n return serialized;\n}\n\n\n/**\n * Dispatches a background worker job to SQS.\n *\n * @param workerId - The ID of the worker to dispatch\n * @param input - The input data for the worker (will be validated against inputSchema)\n * @param inputSchema - Zod schema for input validation\n * @param options - Dispatch options including webhook URL\n * @param ctx - Optional context object (only serializable parts will be sent)\n * @returns Promise resolving to dispatch result with messageId and jobId\n */\nexport async function dispatch<INPUT_SCHEMA extends ZodType<any>>(\n workerId: string,\n input: z.input<INPUT_SCHEMA>,\n inputSchema: INPUT_SCHEMA,\n options: DispatchOptions,\n ctx?: any\n): Promise<DispatchResult> {\n // Validate input against schema\n const validatedInput = inputSchema.parse(input);\n\n // Generate job ID if not provided\n const jobId =\n options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n // Resolve /workers/trigger endpoint URL\n const triggerUrl = getWorkersTriggerUrl();\n\n // Serialize context (only safe, JSON-compatible parts)\n const serializedContext = ctx ? serializeContext(ctx) : {};\n\n // Attach userId if explicitly provided in options or context.\n const userId = options.userId ?? (ctx?.userId as string | undefined);\n if (userId) serializedContext.userId = userId;\n\n // Job updates use MongoDB only; never pass jobStoreUrl/origin URL.\n const messageBody = {\n workerId,\n jobId,\n input: validatedInput,\n context: serializedContext,\n webhookUrl: options.webhookUrl,\n metadata: options.metadata || {},\n timestamp: new Date().toISOString(),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n };\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) {\n headers['x-workers-trigger-key'] = triggerKey;\n }\n\n const response = await fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n workerId,\n body: messageBody,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to trigger worker \"${workerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ? String(data.messageId) : `trigger-${jobId}`;\n\n return {\n messageId,\n status: 'queued',\n jobId,\n };\n}\n\n/**\n * Dispatch a worker by ID without importing the worker module.\n * Sends to the workers trigger API (WORKER_BASE_URL). No input schema validation at call site.\n *\n * @param workerId - The worker ID (e.g. 'echo', 'data-processor')\n * @param input - Input payload (object or undefined)\n * @param options - Optional jobId, webhookUrl, metadata\n * @param ctx - Optional context (serializable parts sent in the request)\n * @returns Promise resolving to { messageId, status: 'queued', jobId }\n */\nexport async function dispatchWorker(\n workerId: string,\n input?: Record<string, unknown>,\n options: DispatchOptions = {},\n ctx?: any\n): Promise<DispatchResult> {\n const jobId =\n options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const triggerUrl = getWorkersTriggerUrl();\n const serializedContext = ctx ? serializeContext(ctx) : {};\n const userId = options.userId ?? (ctx?.userId as string | undefined);\n if (userId) serializedContext.userId = userId;\n const messageBody = {\n workerId,\n jobId,\n input: input ?? {},\n context: serializedContext,\n webhookUrl: options.webhookUrl,\n metadata: options.metadata || {},\n timestamp: new Date().toISOString(),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n };\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) headers['x-workers-trigger-key'] = triggerKey;\n const response = await fetch(triggerUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({ workerId, body: messageBody }),\n });\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to trigger worker \"${workerId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ? String(data.messageId) : `trigger-${jobId}`;\n return { messageId, status: 'queued', jobId };\n}\n\n/**\n * Local development mode: runs the handler immediately in the same process.\n * This bypasses SQS and Lambda for faster iteration during development.\n *\n * @param handler - The worker handler function\n * @param input - The input data\n * @param ctx - The context object\n * @returns The handler result\n */\nexport async function dispatchLocal<INPUT, OUTPUT>(\n handler: (params: { input: INPUT; ctx: any }) => Promise<OUTPUT>,\n input: INPUT,\n ctx?: any\n): Promise<OUTPUT> {\n return handler({ input, ctx: ctx || {} });\n}\n\n/**\n * Dispatches a queue by ID. POSTs to the queue-start API; the queue-start handler creates the queue job.\n * Pass the first worker's input directly (no registry required).\n */\nexport async function dispatchQueue<InitialInput = any>(\n queueId: string,\n initialInput?: InitialInput,\n options: DispatchOptions = {},\n _ctx?: any\n): Promise<DispatchQueueResult> {\n const jobId =\n options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const queueStartUrl = getQueueStartUrl(queueId);\n const normalizedInput =\n initialInput !== null && typeof initialInput === 'object'\n ? (initialInput as Record<string, unknown>)\n : { value: initialInput };\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;\n if (triggerKey) headers['x-workers-trigger-key'] = triggerKey;\n const userId = options.userId ?? (_ctx?.userId as string | undefined);\n const response = await fetch(queueStartUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n input: normalizedInput,\n initialInput: normalizedInput,\n metadata: options.metadata ?? {},\n jobId,\n ...(userId ? { userId } : {}),\n ...(options.webhookUrl ? { webhookUrl: options.webhookUrl } : {}),\n }),\n });\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(\n `Failed to start queue \"${queueId}\": ${response.status} ${response.statusText}${text ? ` - ${text}` : ''}`\n );\n }\n const data = (await response.json().catch(() => ({}))) as any;\n const messageId = data?.messageId ?? data?.jobId ?? `queue-${jobId}`;\n return { queueId, messageId, status: 'queued', jobId };\n}\n\n","/**\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 } 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 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 }>;\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 (fire-and-forget or await).\n */\n appendInternalJob?(entry: { jobId: string; workerId: string }): 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\nfunction sanitizeWorkerIdForEnv(workerId: string): string {\n return workerId.replace(/-/g, '_').toUpperCase();\n}\n\nfunction getQueueUrlForWorker(calleeWorkerId: string): string | undefined {\n const key = `WORKER_QUEUE_URL_${sanitizeWorkerIdForEnv(calleeWorkerId)}`;\n return process.env[key]?.trim() || undefined;\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 const metadata = options?.metadata ?? {};\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 const queueUrl = getQueueUrlForWorker(calleeWorkerId);\n\n if (queueUrl) {\n const region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1';\n const sqs = new SQSClient({ region });\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 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 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 const messageId = sendResult.MessageId ?? undefined;\n\n if (jobStore?.appendInternalJob) {\n await jobStore.appendInternalJob({ jobId: childJobId, workerId: calleeWorkerId });\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 // Fallback: no queue URL (e.g. local dev). Caller (index.ts) should provide in-process dispatch.\n throw new Error(\n `WORKER_QUEUE_URL_${sanitizeWorkerIdForEnv(calleeWorkerId)} is not set. ` +\n 'Configure queue URL for worker-to-worker dispatch, or run in local mode.'\n );\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 response = await fetch(webhookUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': 'ai-router-worker/1.0',\n },\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 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 // 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 raw = (process.env.WORKER_DATABASE_TYPE || 'upstash-redis').toLowerCase();\n const jobStoreType: 'mongodb' | 'upstash-redis' =\n raw === 'mongodb' ? 'mongodb' : 'upstash-redis';\n if (jobStoreType === 'upstash-redis' && isRedisJobStoreConfigured()) {\n const existing = await loadRedisJob(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 } else if (jobStoreType === 'mongodb' || isMongoJobStoreConfigured()) {\n const existing = await getMongoJobById(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\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 (\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 };\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: { jobId: string; workerId: string }): 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 let internalJobs: Array<{ jobId: string; workerId: string }> | undefined;\n if (listItems && listItems.length > 0) {\n internalJobs = listItems.map((s) => {\n try {\n return JSON.parse(s) as { jobId: string; workerId: string };\n } catch {\n return null;\n }\n }).filter(Boolean) as Array<{ jobId: string; workerId: string }>;\n } else {\n internalJobs = parseJson<Array<{ jobId: string; workerId: string }>>(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 * Queue job store for worker queues (MongoDB or Upstash Redis).\n *\n * Mirrors the worker_jobs pattern but optimized for queues:\n * - MongoDB: collection `queue_jobs` (configurable via MONGODB_QUEUE_JOBS_COLLECTION)\n * - Upstash Redis: JSON blob per queue job with compact step entries\n *\n * This module is runtime-only (used by Lambda workers). Next.js APIs can read\n * the same collections/keys to show queue progress.\n */\n\nimport type { Redis } from '@upstash/redis';\nimport { Redis as UpstashRedis } from '@upstash/redis';\nimport { MongoClient, type Collection } from 'mongodb';\n\ntype QueueJobStep = {\n workerId: string;\n workerJobId: string;\n status: 'queued' | 'running' | 'awaiting_approval' | 'completed' | 'failed';\n input?: unknown;\n output?: unknown;\n error?: { message: string };\n startedAt?: string;\n completedAt?: string;\n};\n\ntype QueueJobDoc = {\n _id: string; // queueJobId\n id: string;\n queueId: string;\n status: 'running' | 'completed' | 'failed' | 'partial';\n steps: QueueJobStep[];\n metadata?: Record<string, unknown>;\n userId?: string;\n createdAt: string;\n updatedAt: string;\n completedAt?: string;\n};\n\n\n// === Mongo backend (shares connection pattern with mongoJobStore) ===\n\nconst mongoUri = process.env.DATABASE_MONGODB_URI || process.env.MONGODB_URI;\nconst mongoDbName =\n process.env.DATABASE_MONGODB_DB ||\n process.env.MONGODB_DB ||\n 'mediamake';\nconst mongoQueueCollectionName =\n process.env.MONGODB_QUEUE_JOBS_COLLECTION || 'queue_jobs';\n\nlet mongoClientPromise: Promise<MongoClient> | null = null;\n\nasync function getMongoClient(): Promise<MongoClient> {\n if (!mongoUri) {\n throw new Error(\n 'MongoDB URI required for queue job store. Set DATABASE_MONGODB_URI or MONGODB_URI.'\n );\n }\n if (!mongoClientPromise) {\n mongoClientPromise = new MongoClient(mongoUri, {\n maxPoolSize: 10,\n minPoolSize: 0,\n serverSelectionTimeoutMS: 10_000,\n }).connect();\n }\n return mongoClientPromise;\n}\n\nasync function getMongoQueueCollection(): Promise<Collection<QueueJobDoc>> {\n const client = await getMongoClient();\n return client.db(mongoDbName).collection<QueueJobDoc>(mongoQueueCollectionName);\n}\n\n// === Redis backend (Upstash) ===\n\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 queueKeyPrefix =\n process.env.WORKER_UPSTASH_REDIS_QUEUE_PREFIX ||\n process.env.UPSTASH_REDIS_QUEUE_PREFIX ||\n 'worker:queue-jobs:';\n\nconst defaultTtlSeconds = 60 * 60 * 24 * 7; // 7 days\nconst queueJobTtlSeconds =\n typeof process.env.WORKER_QUEUE_JOBS_TTL_SECONDS === 'string'\n ? parseInt(process.env.WORKER_QUEUE_JOBS_TTL_SECONDS, 10) || defaultTtlSeconds\n : typeof process.env.WORKER_JOBS_TTL_SECONDS === 'string'\n ? parseInt(process.env.WORKER_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 for queue job store. 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 UpstashRedis({\n url: redisUrl,\n token: redisToken,\n });\n }\n return redisClient;\n}\n\nfunction queueKey(id: string): string {\n return `${queueKeyPrefix}${id}`;\n}\n\ntype QueueJobRecord = Omit<QueueJobDoc, '_id'> & { userId?: string };\n\n/** Hash values from Upstash hgetall may be auto-parsed (array/object) or raw strings. */\nfunction stepsFromHash(val: unknown): QueueJobStep[] {\n if (Array.isArray(val)) return val as QueueJobStep[];\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val) as QueueJobStep[];\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n return [];\n}\n\nfunction metadataFromHash(val: unknown): Record<string, unknown> {\n if (val && typeof val === 'object' && !Array.isArray(val)) return val as Record<string, unknown>;\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val) as Record<string, unknown>;\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n }\n return {};\n}\n\nasync function loadQueueJobRedis(queueJobId: string): Promise<QueueJobRecord | null> {\n const redis = getRedis();\n const key = queueKey(queueJobId);\n const data = await redis.hgetall(key);\n if (!data || typeof data !== 'object' || Object.keys(data).length === 0) return null;\n const d = data as Record<string, unknown>;\n const record: QueueJobRecord = {\n id: (d.id === undefined ? queueJobId : String(d.id)) as string,\n queueId: String(d.queueId ?? ''),\n status: (String(d.status ?? 'running') as QueueJobRecord['status']),\n steps: stepsFromHash(d.steps),\n metadata: metadataFromHash(d.metadata),\n ...(d.userId ? { userId: String(d.userId) } : {}),\n createdAt: String(d.createdAt ?? new Date().toISOString()),\n updatedAt: String(d.updatedAt ?? new Date().toISOString()),\n completedAt: d.completedAt != null ? String(d.completedAt) : undefined,\n };\n return record;\n}\n\nasync function saveQueueJobRedis(record: QueueJobRecord): Promise<void> {\n const redis = getRedis();\n const key = queueKey(record.id);\n const now = new Date().toISOString();\n const toSet: Record<string, string> = {\n id: record.id,\n queueId: record.queueId,\n status: record.status,\n steps: JSON.stringify(record.steps || []),\n metadata: JSON.stringify(record.metadata || {}),\n createdAt: record.createdAt || now,\n updatedAt: record.updatedAt || now,\n };\n if (record.completedAt) toSet.completedAt = record.completedAt;\n if (record.userId) toSet.userId = record.userId;\n await redis.hset(key, toSet);\n if (queueJobTtlSeconds > 0) {\n await redis.expire(key, queueJobTtlSeconds);\n }\n}\n\n// === Backend selection ===\n\nfunction getStoreType(): 'mongodb' | 'upstash-redis' {\n const t = (process.env.WORKER_DATABASE_TYPE || 'upstash-redis').toLowerCase();\n return t === 'mongodb' ? 'mongodb' : 'upstash-redis';\n}\n\nfunction preferMongo(): boolean {\n return getStoreType() === 'mongodb' && Boolean(mongoUri?.trim());\n}\n\nfunction preferRedis(): boolean {\n return getStoreType() !== 'mongodb' && Boolean((redisUrl || '').trim() && (redisToken || '').trim());\n}\n\n// === Public API used from handler.ts ===\n\nexport async function upsertInitialQueueJob(options: {\n queueJobId: string;\n queueId: string;\n firstWorkerId: string;\n firstWorkerJobId: string;\n metadata?: Record<string, any>;\n userId?: string;\n}): Promise<void> {\n const { queueJobId, queueId, firstWorkerId, firstWorkerJobId, metadata, userId } = options;\n const now = new Date().toISOString();\n\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n const existing = await coll.findOne({ _id: queueJobId });\n if (existing) {\n const steps = existing.steps ?? [];\n if (steps.length === 0) {\n steps.push({\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n });\n }\n await coll.updateOne(\n { _id: queueJobId },\n {\n $set: {\n steps,\n updatedAt: now,\n },\n }\n );\n } else {\n const doc: QueueJobDoc = {\n _id: queueJobId,\n id: queueJobId,\n queueId,\n status: 'running',\n steps: [\n {\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n },\n ],\n metadata: metadata ?? {},\n ...(userId ? { userId } : {}),\n createdAt: now,\n updatedAt: now,\n };\n await coll.updateOne(\n { _id: queueJobId },\n { $set: doc },\n { upsert: true }\n );\n }\n return;\n }\n\n if (preferRedis()) {\n const existing = await loadQueueJobRedis(queueJobId);\n if (existing) {\n // Ensure we have at least one step\n if (!existing.steps || existing.steps.length === 0) {\n existing.steps = [\n {\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n },\n ];\n }\n existing.updatedAt = now;\n await saveQueueJobRedis(existing);\n } else {\n const record: QueueJobRecord = {\n id: queueJobId,\n queueId,\n status: 'running',\n steps: [\n {\n workerId: firstWorkerId,\n workerJobId: firstWorkerJobId,\n status: 'queued',\n },\n ],\n metadata: metadata ?? {},\n ...(userId ? { userId } : {}),\n createdAt: now,\n updatedAt: now,\n };\n await saveQueueJobRedis(record);\n }\n }\n}\n\nexport async function updateQueueJobStepInStore(options: {\n queueJobId: string;\n queueId?: string;\n stepIndex: number;\n workerId: string;\n workerJobId: string;\n status: 'running' | 'awaiting_approval' | 'completed' | 'failed';\n input?: unknown;\n output?: unknown;\n error?: { message: string };\n}): Promise<void> {\n const { queueJobId, stepIndex, status, input, output, error } = options;\n const now = new Date().toISOString();\n\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n const existing = await coll.findOne({ _id: queueJobId });\n if (!existing) return;\n const step = existing.steps[stepIndex];\n if (!step) return;\n\n const mergedStep: QueueJobStep = {\n ...step,\n status,\n ...(input !== undefined && { input }),\n ...(output !== undefined && { output }),\n ...(error !== undefined && { error }),\n startedAt: step.startedAt ?? (status === 'running' ? now : step.startedAt),\n completedAt:\n step.completedAt ??\n (status === 'completed' || status === 'failed' ? now : step.completedAt),\n };\n\n const setDoc: Partial<QueueJobDoc> & { steps: QueueJobStep[] } = {\n steps: existing.steps,\n updatedAt: now,\n };\n setDoc.steps[stepIndex] = mergedStep;\n if (status === 'failed') {\n setDoc.status = 'failed';\n if (!existing.completedAt) setDoc.completedAt = now;\n } else if (status === 'completed' && stepIndex === existing.steps.length - 1) {\n setDoc.status = 'completed';\n if (!existing.completedAt) setDoc.completedAt = now;\n }\n\n await coll.updateOne(\n { _id: queueJobId },\n {\n $set: setDoc,\n }\n );\n return;\n }\n\n if (preferRedis()) {\n const existing = await loadQueueJobRedis(queueJobId);\n if (!existing) {\n // No queue job; nothing to update\n return;\n }\n const steps = existing.steps || [];\n const step = steps[stepIndex];\n if (!step) {\n return;\n }\n step.status = status;\n if (input !== undefined) step.input = input;\n if (output !== undefined) step.output = output;\n if (error !== undefined) step.error = error;\n if (status === 'running') {\n step.startedAt = step.startedAt ?? now;\n }\n if (status === 'completed' || status === 'failed') {\n step.completedAt = step.completedAt ?? now;\n }\n\n existing.steps = steps;\n existing.updatedAt = now;\n if (status === 'failed') {\n existing.status = 'failed';\n existing.completedAt = existing.completedAt ?? now;\n } else if (status === 'completed' && stepIndex === steps.length - 1) {\n existing.status = 'completed';\n existing.completedAt = existing.completedAt ?? now;\n }\n await saveQueueJobRedis(existing);\n }\n}\n\nexport async function appendQueueJobStepInStore(options: {\n queueJobId: string;\n queueId?: string;\n workerId: string;\n workerJobId: string;\n}): Promise<void> {\n const { queueJobId, workerId, workerJobId } = options;\n const now = new Date().toISOString();\n\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n await coll.updateOne(\n { _id: queueJobId },\n {\n $push: {\n steps: {\n workerId,\n workerJobId,\n status: 'queued',\n } as QueueJobStep,\n },\n $set: { updatedAt: now },\n }\n );\n return;\n }\n\n if (preferRedis()) {\n const existing = await loadQueueJobRedis(queueJobId);\n if (!existing) return;\n const steps = existing.steps || [];\n steps.push({\n workerId,\n workerJobId,\n status: 'queued',\n });\n existing.steps = steps;\n existing.updatedAt = now;\n await saveQueueJobRedis(existing);\n }\n}\n\n/**\n * Load a queue job by ID (for mapping context: previous step outputs).\n * Used by wrapHandlerForQueue for chain mapping and HITL resume (`previousOutputs`).\n */\nexport async function getQueueJob(queueJobId: string): Promise<{\n id: string;\n queueId: string;\n status: string;\n steps: Array<{ workerId: string; workerJobId: string; status: string; output?: unknown }>;\n} | null> {\n if (preferMongo()) {\n const coll = await getMongoQueueCollection();\n const doc = await coll.findOne({ _id: queueJobId });\n if (!doc) return null;\n return {\n id: doc.id ?? queueJobId,\n queueId: doc.queueId,\n status: doc.status,\n steps: (doc.steps ?? []).map((s: QueueJobStep) => ({\n workerId: s.workerId,\n workerJobId: s.workerJobId,\n status: s.status,\n output: s.output,\n })),\n };\n }\n if (preferRedis()) {\n const record = await loadQueueJobRedis(queueJobId);\n if (!record) return null;\n return {\n id: record.id,\n queueId: record.queueId,\n status: record.status,\n steps: (record.steps ?? []).map((s) => ({\n workerId: s.workerId,\n workerJobId: s.workerJobId,\n status: s.status,\n output: s.output,\n })),\n };\n }\n return null;\n}\n\n","import type { HitlStepConfig } from './hitlConfig.js';\nimport type { SmartRetryConfig } from './retryConfig.js';\n\n/**\n * Queue definition and context types for worker queues.\n *\n * ## Human-in-the-loop (HITL) pause / resume\n *\n * **Pause (`awaiting_approval`)** — After a step completes, if the **next** step has\n * `requiresApproval: true`, the runtime calls the step's `chain` function (if any),\n * stores the result as the pending input for that step, marks it `awaiting_approval`,\n * and does **not** dispatch the worker until a human approves.\n *\n * **Resume (`POST .../approve`)** — The app route calls `dispatchWorker` for that step\n * with `__hitlInput` (reviewer form payload) attached. The `wrapHandlerForQueue` runtime\n * calls the step's `resume` function (or merges inputs by default) to produce the final\n * domain input, then strips all envelope keys before the user handler receives it.\n *\n * Workers **do not** need to accept any `__workerQueue` / `__hitlPending` / `__hitlInput`\n * keys in their Zod schemas — the runtime strips them automatically.\n */\n\n/** Output from one completed step, available to subsequent steps via ChainContext / HitlResumeContext. */\nexport interface QueueStepOutput {\n stepIndex: number;\n workerId: string;\n output: unknown;\n}\n\n/**\n * Context passed to a step's {@link WorkerQueueStep.chain} function when the queue\n * advances normally (previous step completed without HITL).\n */\nexport interface ChainContext {\n /** Original input passed to `dispatchQueue` (the first step's input). */\n initialInput: unknown;\n /**\n * Outputs from all previous steps in order.\n * `previousOutputs[0]` = step 0 output; last entry = most recent.\n */\n previousOutputs: QueueStepOutput[];\n}\n\n/**\n * Context passed to a step's {@link WorkerQueueStep.resume} function when a human has\n * approved the HITL pause and the step is being re-dispatched.\n *\n * @template T - Shape of the reviewer / UI form payload.\n * Derive it from your `hitl.inputSchema` if defined:\n * `HitlResumeContext<z.infer<typeof reviewerSchema>>`.\n */\nexport interface HitlResumeContext<T = unknown> {\n /** Original input passed to `dispatchQueue` (the first step's input). */\n initialInput: unknown;\n /**\n * Outputs from all previous steps in order.\n * `previousOutputs[0]` = step 0 output; last entry = most recent.\n */\n previousOutputs: QueueStepOutput[];\n /** Reviewer / UI form payload submitted via `POST .../approve` (`input` body field). */\n reviewerInput: T;\n /**\n * The computed next-step input that was stored pending approval (domain fields only;\n * all `__workerQueue` / `__hitlPending` / `hitl` envelope keys are stripped).\n * This is what the `chain` function produced before the step was paused.\n */\n pendingInput: Record<string, unknown>;\n}\n\n/** Internal envelope keys injected by the queue runtime. Never passed to user handlers. */\nexport const QUEUE_ORCHESTRATION_KEYS = [\n '__workerQueue',\n '__hitlInput',\n '__hitlDecision',\n '__hitlPending',\n 'hitl',\n] as const;\n\nexport interface WorkerQueueStep {\n /** Worker ID for this step. Must match an existing registered worker. */\n workerId: string;\n /**\n * Optional delay (in seconds) before this step is executed.\n * Implemented via SQS DelaySeconds (max 900).\n */\n delaySeconds?: number;\n /**\n * Called when the queue advances to this step after the previous step completes\n * normally (no HITL). Receives a {@link ChainContext} and must return the input\n * object for this worker.\n *\n * **Built-in shortcuts** (use a string instead of a function):\n * - `'passthrough'` — pass the previous step's output directly as this step's input.\n * - `'continueFromPrevious'` — extract `{ current, history }` from the previous\n * output and build a `{ mode: 'continue', ... }` payload (useful for multi-round sessions).\n *\n * When omitted, the previous step's output is used as-is (equivalent to `'passthrough'`).\n *\n * @example\n * ```ts\n * chain: (ctx) => ({\n * mode: 'review' as const,\n * data: ctx.previousOutputs[ctx.previousOutputs.length - 1]?.output,\n * }),\n * ```\n */\n chain?: ((ctx: ChainContext) => unknown) | 'passthrough' | 'continueFromPrevious';\n /**\n * Called when this step resumes after a human approves a HITL pause.\n * Receives a {@link HitlResumeContext} with the reviewer's form payload and the\n * stored pending input, and must return the final domain input for this worker.\n *\n * When omitted, a shallow merge of `pendingInput` + `reviewerInput` is used as the\n * default (suitable for simple cases where reviewer fields override pending fields).\n *\n * @example\n * ```ts\n * resume: (ctx: HitlResumeContext<ReviewerSchema>) => ({\n * ...ctx.pendingInput,\n * overriddenField: ctx.reviewerInput.overriddenField,\n * }),\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n resume?: (ctx: HitlResumeContext<any>) => unknown;\n /**\n * When `true`, queue execution pauses before dispatching this step.\n * The step waits until a human calls `POST .../approve` (or `POST .../reject`).\n * Define a `resume` function to control how the reviewer's payload is merged with\n * the pending input.\n */\n requiresApproval?: boolean;\n /**\n * Optional HITL UI/metadata for this step (consumed by app UI and tooling).\n * Use {@link defineHitlConfig} for type-safe authoring.\n * The worker runtime uses only `requiresApproval` — this field is UI-only.\n */\n hitl?: HitlStepConfig;\n /**\n * Smart retry configuration for this queue step.\n * Overrides any retry config on the worker definition for this step only.\n * Retries run in-process (same Lambda invocation); ctx.retryContext is populated\n * on each retry so the handler can self-correct (e.g. inject error into prompt).\n *\n * @example\n * ```ts\n * retry: { maxAttempts: 3, on: ['rate-limit', 'json-parse'] }\n * ```\n */\n retry?: SmartRetryConfig;\n /**\n * When defined, evaluated after each run of this step to decide whether to\n * re-run it (another iteration) instead of advancing to the next step.\n *\n * Combine with `requiresApproval: true` for HITL-gated loops where the\n * reviewer's decision (e.g. a `continueLoop` field in their payload)\n * controls whether another round starts.\n *\n * @example\n * ```ts\n * // Loop continues until the worker returns { finalized: true }\n * loop: {\n * shouldContinue: ({ output }) => !(output as { finalized?: boolean }).finalized,\n * maxIterations: 20,\n * }\n * ```\n */\n loop?: {\n /** Return true to run this step again; false to advance to the next step. */\n shouldContinue: (ctx: LoopContext) => boolean | Promise<boolean>;\n /**\n * Hard cap on total iterations (including the first run).\n * Prevents runaway loops. Default: 50.\n */\n maxIterations?: number;\n };\n}\n\nexport interface WorkerQueueConfig<InitialInput = any, StepOutput = any> {\n /** Stable queue identifier, e.g. `\"cost-review\"`. */\n id: string;\n /** Ordered list of steps forming the queue pipeline. */\n steps: WorkerQueueStep[];\n /**\n * Optional schedule for the queue (cron or rate expression).\n * When set, the CLI generates a queue-starter Lambda triggered by this schedule.\n * @example `'cron(0 3 * * ? *)'` — daily at 03:00 UTC.\n */\n schedule?: string | { rate: string; enabled?: boolean; input?: Record<string, any> };\n // Reserved phantom types for IDE hints — do not affect runtime.\n _initialInputType?: InitialInput;\n _stepOutputType?: StepOutput;\n}\n\n/**\n * Context passed to a step's {@link WorkerQueueStep.loop | loop.shouldContinue} function\n * after each iteration of a looping step.\n */\nexport interface LoopContext {\n /** Output returned by the worker for this iteration. */\n output: unknown;\n /** Step definition index (stable; does not change across iterations). */\n stepIndex: number;\n /** 0-based count of how many times this step has already run (0 = first run). */\n iterationCount: number;\n /** Original input passed to `dispatchQueue`. */\n initialInput: unknown;\n /** Outputs from all previous steps (and previous iterations of this step). */\n previousOutputs: QueueStepOutput[];\n}\n\n/**\n * Queue execution context embedded into job input so queue-aware wrappers\n * know their position in the pipeline. Injected automatically by the runtime.\n */\nexport interface WorkerQueueContext<InitialInput = any> {\n id: string;\n /** Queue definition step index — used to look up chain/resume/loop config. Stays fixed across loop iterations. */\n stepIndex: number;\n /**\n * Actual array position of this step in the job's steps[] store.\n * Differs from stepIndex when the same step has looped multiple times\n * (each iteration is appended as a new entry). Defaults to stepIndex when absent.\n */\n arrayStepIndex?: number;\n initialInput: InitialInput;\n /** Queue job ID for progress tracking (same as first worker's jobId). */\n queueJobId?: string;\n /** How many times this step has already run (used by looping steps). */\n iterationCount?: number;\n}\n\n/**\n * Repeat a step definition `count` times, calling `factory(index)` for each repetition.\n * Eliminates copy-paste for multi-round HITL workflows.\n *\n * @example\n * ```ts\n * const queue = defineWorkerQueue({\n * id: 'multi-review',\n * steps: [\n * { workerId: 'ingest' },\n * ...repeatStep(3, (i) => ({\n * workerId: 'review',\n * chain: chainFromPrev,\n * resume: resumeFromHitl,\n * requiresApproval: true,\n * hitl: defineHitlConfig({ taskKey: `review-r${i + 1}`, ui: { type: 'schema-form', title: `Round ${i + 1}` } }),\n * })),\n * ],\n * });\n * ```\n */\nexport function repeatStep(\n count: number,\n factory: (index: number) => WorkerQueueStep\n): WorkerQueueStep[] {\n return Array.from({ length: count }, (_, i) => factory(i));\n}\n\n/**\n * Identity helper for defining worker queues in `.queue.ts` files.\n * Use `satisfies WorkerQueueConfig<InitialInput, StepOutput>` for phantom-type docs.\n *\n * @example\n * ```ts\n * const q = defineWorkerQueue({\n * id: 'my-queue',\n * steps: [ ... ],\n * }) satisfies WorkerQueueConfig<MyInit, MyOutput>;\n * export default q;\n * ```\n */\nexport function defineWorkerQueue<T extends WorkerQueueConfig>(config: T): T {\n return config;\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","/**\n * Workers-config client for resolving queue URLs from the workers-config API Lambda.\n */\n\nexport interface WorkersConfig {\n version: string;\n stage: string;\n region: string;\n workers: Record<\n string,\n {\n queueUrl: string;\n region: string;\n }\n >;\n}\n\nlet cachedConfig: WorkersConfig | null = null;\nlet cacheExpiry: number = 0;\nconst CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Fetches the workers configuration from the workers-config API.\n * Results are cached for 5 minutes to reduce API calls.\n *\n * @param apiUrl - The URL of the workers-config API endpoint\n * @param apiKey - Optional API key for authentication (sent as x-workers-config-key header)\n * @returns The workers configuration mapping worker IDs to queue URLs\n */\nexport async function getWorkersConfig(\n apiUrl: string,\n apiKey?: string\n): Promise<WorkersConfig> {\n const now = Date.now();\n\n // Return cached config if still valid\n if (cachedConfig && now < cacheExpiry) {\n return cachedConfig;\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (apiKey) {\n headers['x-workers-config-key'] = apiKey;\n }\n\n const response = await fetch(apiUrl, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch workers config: ${response.status} ${response.statusText}`\n );\n }\n\n const config = (await response.json()) as WorkersConfig;\n cachedConfig = config;\n cacheExpiry = now + CACHE_TTL_MS;\n\n return config;\n}\n\n/**\n * Resolves the queue URL for a specific worker ID.\n * Throws an error if the worker ID is not found in the configuration.\n *\n * @param workerId - The ID of the worker\n * @param apiUrl - The URL of the workers-config API endpoint\n * @param apiKey - Optional API key for authentication\n * @returns The queue URL for the worker\n */\nexport async function resolveQueueUrl(\n workerId: string,\n apiUrl: string,\n apiKey?: string\n): Promise<string> {\n const config = await getWorkersConfig(apiUrl, apiKey);\n const worker = config.workers[workerId];\n\n if (!worker) {\n throw new Error(\n `Worker \"${workerId}\" not found in workers config. Available workers: ${Object.keys(config.workers).join(', ')}`\n );\n }\n\n return worker.queueUrl;\n}\n\n/**\n * Clears the cached workers configuration.\n * Useful for testing or when you need to force a refresh.\n */\nexport function clearWorkersConfigCache(): void {\n cachedConfig = null;\n cacheExpiry = 0;\n}\n","/**\n * @deprecated Workers no longer need to accept queue orchestration keys in their Zod schemas.\n * The runtime strips `__workerQueue`, `__hitlInput`, `__hitlDecision`, `__hitlPending`, and `hitl`\n * automatically before calling the user handler. Remove `queueOrchestrationFieldsSchema`\n * and `withQueueOrchestrationEnvelope` from your worker schemas and use plain `z.object({...})`.\n */\n\nimport { z } from 'zod';\n\n/**\n * @deprecated No longer needed. The queue runtime strips all envelope keys before the user handler runs.\n */\nexport const queueOrchestrationFieldsSchema = z.object({\n __workerQueue: z.record(z.string(), z.unknown()).optional(),\n __hitlPending: z.unknown().optional(),\n __hitlInput: z.unknown().optional(),\n __hitlDecision: z.unknown().optional(),\n});\n\nexport type QueueOrchestrationFields = z.infer<typeof queueOrchestrationFieldsSchema>;\n\n/**\n * @deprecated No longer needed. The queue runtime strips all envelope keys before the user handler runs.\n */\nexport function withQueueOrchestrationEnvelope<D extends z.ZodObject<z.ZodRawShape>>(domain: D) {\n return domain.merge(queueOrchestrationFieldsSchema);\n}\n","import type { ChainContext } from './queue.js';\n\n/**\n * Built-in chain mapping: pass the previous step's output directly as the next step's input.\n * Falls back to `initialInput` if there are no previous outputs.\n *\n * Use via `chain: 'passthrough'` on a queue step — no need to reference this directly.\n */\nexport function defaultMapChainPassthrough(ctx: ChainContext): unknown {\n const { initialInput, previousOutputs } = ctx;\n if (previousOutputs.length > 0) {\n return previousOutputs[previousOutputs.length - 1]?.output;\n }\n return initialInput;\n}\n\n/**\n * Built-in chain mapping for same-worker \"continue\" rounds.\n * Maps `{ current, history, ... }` from the last step output into\n * `{ mode: 'continue', current, history, nextNumber: 0, operator: 'add' }`.\n *\n * Use via `chain: 'continueFromPrevious'` on a queue step.\n */\nexport function defaultMapChainContinueFromPrevious(ctx: ChainContext): unknown {\n const { previousOutputs } = ctx;\n const prev = previousOutputs[previousOutputs.length - 1]?.output as {\n current?: number;\n history?: string[];\n } | null;\n if (!prev || typeof prev.current !== 'number') {\n return {\n mode: 'continue' as const,\n current: 0,\n history: [] as string[],\n nextNumber: 0,\n operator: 'add' as const,\n };\n }\n return {\n mode: 'continue' as const,\n current: prev.current,\n history: prev.history ?? [],\n nextNumber: 0,\n operator: 'add' as const,\n };\n}\n","import type { ZodType } from 'zod';\n\n/**\n * UI rendering hint for a HITL step.\n *\n * - `'custom'` — render using a registered view component (by `viewId`).\n * - `'schema-form'` — auto-render a form for the step (no custom view needed).\n * The panel falls back to a raw-JSON textarea if no schema-form renderer is available.\n */\nexport type HitlUiSpec =\n | {\n type: 'custom';\n /** View ID used to look up the renderer in the app's HITL view registry. */\n viewId: string;\n title?: string;\n sections?: Array<Record<string, unknown>>;\n [key: string]: unknown;\n }\n | {\n type: 'schema-form';\n title?: string;\n description?: string;\n };\n\n/** Metadata for a human-in-the-loop step on `WorkerQueueStep.hitl`. */\nexport type HitlStepConfig = {\n taskKey: string;\n timeoutSeconds?: number;\n onTimeout?: 'reject' | 'auto-approve';\n assignees?: string[];\n ui: HitlUiSpec;\n /** Reviewer form schema — single source of truth; use `z.infer<typeof schema>` for types. */\n inputSchema?: ZodType;\n};\n\n/**\n * DX helper for queue authors: keeps HITL config typed/readable.\n *\n * @example\n * ```ts\n * const hitl = defineHitlConfig({\n * taskKey: 'review-step',\n * ui: { type: 'schema-form', title: 'Review the output' },\n * inputSchema: z.object({ approved: z.boolean(), comment: z.string().optional() }),\n * });\n * ```\n */\nexport function defineHitlConfig<T extends HitlStepConfig>(config: T): T {\n return config;\n}\n"],"mappings":"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","names":["import_redis","import_mongodb","redisUrl","redisToken","defaultTtlSeconds","redisClient","getRedis","UpstashRedis","module","explicitPath","DEFAULT_POLL_INTERVAL_MS","DEFAULT_POLL_TIMEOUT_MS","input","options","response"]}
|