@microfox/ai-worker 1.0.4 → 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.
Files changed (69) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +22 -0
  3. package/dist/chainMapDefaults.d.mts +21 -0
  4. package/dist/chainMapDefaults.d.ts +21 -0
  5. package/dist/chainMapDefaults.js +59 -0
  6. package/dist/chainMapDefaults.js.map +1 -0
  7. package/dist/chainMapDefaults.mjs +10 -0
  8. package/dist/chainMapDefaults.mjs.map +1 -0
  9. package/dist/chunk-BCRJIFKB.mjs +9 -0
  10. package/dist/chunk-BCRJIFKB.mjs.map +1 -0
  11. package/dist/{chunk-72XGFZCE.mjs → chunk-CILTGUUQ.mjs} +14 -3
  12. package/dist/chunk-CILTGUUQ.mjs.map +1 -0
  13. package/dist/{chunk-7LQNS2SG.mjs → chunk-QHX55IML.mjs} +442 -56
  14. package/dist/chunk-QHX55IML.mjs.map +1 -0
  15. package/dist/chunk-SQB5FQCZ.mjs +21 -0
  16. package/dist/chunk-SQB5FQCZ.mjs.map +1 -0
  17. package/dist/{chunk-AOXGONGI.mjs → chunk-T7DRPKR6.mjs} +7 -5
  18. package/dist/chunk-T7DRPKR6.mjs.map +1 -0
  19. package/dist/chunk-XCKWV2WZ.mjs +34 -0
  20. package/dist/chunk-XCKWV2WZ.mjs.map +1 -0
  21. package/dist/chunk-ZW4PNCDH.mjs +17 -0
  22. package/dist/chunk-ZW4PNCDH.mjs.map +1 -0
  23. package/dist/client.d.mts +148 -2
  24. package/dist/client.d.ts +148 -2
  25. package/dist/client.js +13 -2
  26. package/dist/client.js.map +1 -1
  27. package/dist/client.mjs +1 -1
  28. package/dist/handler.d.mts +121 -23
  29. package/dist/handler.d.ts +121 -23
  30. package/dist/handler.js +450 -58
  31. package/dist/handler.js.map +1 -1
  32. package/dist/handler.mjs +5 -2
  33. package/dist/hitlConfig.d.mts +46 -0
  34. package/dist/hitlConfig.d.ts +46 -0
  35. package/dist/hitlConfig.js +33 -0
  36. package/dist/hitlConfig.js.map +1 -0
  37. package/dist/hitlConfig.mjs +8 -0
  38. package/dist/hitlConfig.mjs.map +1 -0
  39. package/dist/index.d.mts +23 -4
  40. package/dist/index.d.ts +23 -4
  41. package/dist/index.js +575 -74
  42. package/dist/index.js.map +1 -1
  43. package/dist/index.mjs +78 -20
  44. package/dist/index.mjs.map +1 -1
  45. package/dist/queue-B5n6YVQV.d.ts +306 -0
  46. package/dist/queue-DaR2UuZi.d.mts +306 -0
  47. package/dist/queue.d.mts +3 -0
  48. package/dist/queue.d.ts +3 -0
  49. package/dist/queue.js +47 -0
  50. package/dist/queue.js.map +1 -0
  51. package/dist/queue.mjs +12 -0
  52. package/dist/queue.mjs.map +1 -0
  53. package/dist/queueInputEnvelope.d.mts +31 -0
  54. package/dist/queueInputEnvelope.d.ts +31 -0
  55. package/dist/queueInputEnvelope.js +42 -0
  56. package/dist/queueInputEnvelope.js.map +1 -0
  57. package/dist/queueInputEnvelope.mjs +10 -0
  58. package/dist/queueInputEnvelope.mjs.map +1 -0
  59. package/dist/queueJobStore.d.mts +3 -2
  60. package/dist/queueJobStore.d.ts +3 -2
  61. package/dist/queueJobStore.js +6 -4
  62. package/dist/queueJobStore.js.map +1 -1
  63. package/dist/queueJobStore.mjs +1 -1
  64. package/package.json +7 -2
  65. package/dist/chunk-72XGFZCE.mjs.map +0 -1
  66. package/dist/chunk-7LQNS2SG.mjs.map +0 -1
  67. package/dist/chunk-AOXGONGI.mjs.map +0 -1
  68. package/dist/client-BqSJQ9mZ.d.mts +0 -183
  69. package/dist/client-BqSJQ9mZ.d.ts +0 -183
package/dist/index.js CHANGED
@@ -20,21 +20,31 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ QUEUE_ORCHESTRATION_KEYS: () => QUEUE_ORCHESTRATION_KEYS,
23
24
  SQS_MAX_DELAY_SECONDS: () => SQS_MAX_DELAY_SECONDS,
25
+ TokenBudgetExceededError: () => TokenBudgetExceededError,
24
26
  clearWorkersConfigCache: () => clearWorkersConfigCache,
25
27
  createLambdaEntrypoint: () => createLambdaEntrypoint,
26
28
  createLambdaHandler: () => createLambdaHandler,
27
29
  createWorker: () => createWorker,
28
30
  createWorkerLogger: () => createWorkerLogger,
31
+ defaultMapChainContinueFromPrevious: () => defaultMapChainContinueFromPrevious,
32
+ defaultMapChainPassthrough: () => defaultMapChainPassthrough,
33
+ defineHitlConfig: () => defineHitlConfig,
29
34
  defineWorkerQueue: () => defineWorkerQueue,
30
35
  dispatch: () => dispatch,
31
36
  dispatchLocal: () => dispatchLocal,
32
37
  dispatchQueue: () => dispatchQueue,
33
38
  dispatchWorker: () => dispatchWorker,
39
+ executeWithRetry: () => executeWithRetry,
34
40
  getQueueStartUrl: () => getQueueStartUrl,
35
41
  getWorkersConfig: () => getWorkersConfig,
36
42
  getWorkersTriggerUrl: () => getWorkersTriggerUrl,
43
+ matchesRetryPattern: () => matchesRetryPattern,
44
+ queueOrchestrationFieldsSchema: () => queueOrchestrationFieldsSchema,
45
+ repeatStep: () => repeatStep,
37
46
  resolveQueueUrl: () => resolveQueueUrl,
47
+ withQueueOrchestrationEnvelope: () => withQueueOrchestrationEnvelope,
38
48
  wrapHandlerForQueue: () => wrapHandlerForQueue
39
49
  });
40
50
  module.exports = __toCommonJS(index_exports);
@@ -78,6 +88,9 @@ function serializeContext(ctx) {
78
88
  if (ctx.requestId) {
79
89
  serialized.requestId = ctx.requestId;
80
90
  }
91
+ if (ctx.userId) {
92
+ serialized.userId = ctx.userId;
93
+ }
81
94
  if (ctx.metadata && typeof ctx.metadata === "object") {
82
95
  Object.assign(serialized, ctx.metadata);
83
96
  }
@@ -92,6 +105,8 @@ async function dispatch(workerId, input, inputSchema, options, ctx) {
92
105
  const jobId = options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
93
106
  const triggerUrl = getWorkersTriggerUrl();
94
107
  const serializedContext = ctx ? serializeContext(ctx) : {};
108
+ const userId = options.userId ?? ctx?.userId;
109
+ if (userId) serializedContext.userId = userId;
95
110
  const messageBody = {
96
111
  workerId,
97
112
  jobId,
@@ -99,7 +114,8 @@ async function dispatch(workerId, input, inputSchema, options, ctx) {
99
114
  context: serializedContext,
100
115
  webhookUrl: options.webhookUrl,
101
116
  metadata: options.metadata || {},
102
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
117
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
118
+ ...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {}
103
119
  };
104
120
  const headers = {
105
121
  "Content-Type": "application/json"
@@ -134,6 +150,8 @@ async function dispatchWorker(workerId, input, options = {}, ctx) {
134
150
  const jobId = options.jobId || `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
135
151
  const triggerUrl = getWorkersTriggerUrl();
136
152
  const serializedContext = ctx ? serializeContext(ctx) : {};
153
+ const userId = options.userId ?? ctx?.userId;
154
+ if (userId) serializedContext.userId = userId;
137
155
  const messageBody = {
138
156
  workerId,
139
157
  jobId,
@@ -141,7 +159,8 @@ async function dispatchWorker(workerId, input, options = {}, ctx) {
141
159
  context: serializedContext,
142
160
  webhookUrl: options.webhookUrl,
143
161
  metadata: options.metadata || {},
144
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
162
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
163
+ ...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {}
145
164
  };
146
165
  const headers = { "Content-Type": "application/json" };
147
166
  const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;
@@ -171,6 +190,7 @@ async function dispatchQueue(queueId, initialInput, options = {}, _ctx) {
171
190
  const headers = { "Content-Type": "application/json" };
172
191
  const triggerKey = process.env.WORKERS_TRIGGER_API_KEY;
173
192
  if (triggerKey) headers["x-workers-trigger-key"] = triggerKey;
193
+ const userId = options.userId ?? _ctx?.userId;
174
194
  const response = await fetch(queueStartUrl, {
175
195
  method: "POST",
176
196
  headers,
@@ -179,6 +199,7 @@ async function dispatchQueue(queueId, initialInput, options = {}, _ctx) {
179
199
  initialInput: normalizedInput,
180
200
  metadata: options.metadata ?? {},
181
201
  jobId,
202
+ ...userId ? { userId } : {},
182
203
  ...options.webhookUrl ? { webhookUrl: options.webhookUrl } : {}
183
204
  })
184
205
  });
@@ -236,7 +257,7 @@ async function getJobById(jobId) {
236
257
  return null;
237
258
  }
238
259
  }
239
- function createMongoJobStore(workerId, jobId, input, metadata) {
260
+ function createMongoJobStore(workerId, jobId, input, metadata, userId) {
240
261
  return {
241
262
  update: async (update) => {
242
263
  try {
@@ -275,6 +296,7 @@ function createMongoJobStore(workerId, jobId, input, metadata) {
275
296
  output: update.output,
276
297
  error: update.error,
277
298
  metadata: metadataUpdate,
299
+ ...userId ? { userId } : {},
278
300
  createdAt: now,
279
301
  updatedAt: now,
280
302
  completedAt: set.completedAt
@@ -340,7 +362,7 @@ function createMongoJobStore(workerId, jobId, input, metadata) {
340
362
  }
341
363
  };
342
364
  }
343
- async function upsertJob(jobId, workerId, input, metadata) {
365
+ async function upsertJob(jobId, workerId, input, metadata, userId) {
344
366
  const coll = await getCollection();
345
367
  const now = (/* @__PURE__ */ new Date()).toISOString();
346
368
  await coll.updateOne(
@@ -353,6 +375,7 @@ async function upsertJob(jobId, workerId, input, metadata) {
353
375
  status: "queued",
354
376
  input: input ?? {},
355
377
  metadata: metadata ?? {},
378
+ ...userId ? { userId } : {},
356
379
  createdAt: now,
357
380
  updatedAt: now
358
381
  }
@@ -431,13 +454,14 @@ async function loadJob(jobId) {
431
454
  error: parseJson(data.error),
432
455
  metadata: parseJson(data.metadata) ?? {},
433
456
  internalJobs,
457
+ ...data.userId ? { userId: data.userId } : {},
434
458
  createdAt: data.createdAt,
435
459
  updatedAt: data.updatedAt,
436
460
  completedAt: data.completedAt
437
461
  };
438
462
  return record;
439
463
  }
440
- function createRedisJobStore(workerId, jobId, input, metadata) {
464
+ function createRedisJobStore(workerId, jobId, input, metadata, userId) {
441
465
  return {
442
466
  update: async (update) => {
443
467
  const redis = getRedis();
@@ -495,28 +519,20 @@ function createRedisJobStore(workerId, jobId, input, metadata) {
495
519
  }
496
520
  };
497
521
  }
498
- async function upsertRedisJob(jobId, workerId, input, metadata) {
522
+ async function upsertRedisJob(jobId, workerId, input, metadata, userId) {
499
523
  const redis = getRedis();
500
524
  const key = jobKey(jobId);
501
525
  const now = (/* @__PURE__ */ new Date()).toISOString();
502
- const doc = {
503
- jobId,
504
- workerId,
505
- status: "queued",
506
- input,
507
- metadata,
508
- createdAt: now,
509
- updatedAt: now
510
- };
511
526
  const toSet = {
512
527
  jobId,
513
528
  workerId,
514
- status: doc.status,
515
- input: JSON.stringify(doc.input ?? {}),
516
- metadata: JSON.stringify(doc.metadata ?? {}),
529
+ status: "queued",
530
+ input: JSON.stringify(input ?? {}),
531
+ metadata: JSON.stringify(metadata ?? {}),
517
532
  createdAt: now,
518
533
  updatedAt: now
519
534
  };
535
+ if (userId) toSet.userId = userId;
520
536
  await redis.hset(key, toSet);
521
537
  if (jobTtlSeconds > 0) {
522
538
  await redis.expire(key, jobTtlSeconds);
@@ -608,6 +624,7 @@ async function loadQueueJobRedis(queueJobId) {
608
624
  status: String(d.status ?? "running"),
609
625
  steps: stepsFromHash(d.steps),
610
626
  metadata: metadataFromHash(d.metadata),
627
+ ...d.userId ? { userId: String(d.userId) } : {},
611
628
  createdAt: String(d.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()),
612
629
  updatedAt: String(d.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()),
613
630
  completedAt: d.completedAt != null ? String(d.completedAt) : void 0
@@ -627,9 +644,8 @@ async function saveQueueJobRedis(record) {
627
644
  createdAt: record.createdAt || now,
628
645
  updatedAt: record.updatedAt || now
629
646
  };
630
- if (record.completedAt) {
631
- toSet.completedAt = record.completedAt;
632
- }
647
+ if (record.completedAt) toSet.completedAt = record.completedAt;
648
+ if (record.userId) toSet.userId = record.userId;
633
649
  await redis.hset(key, toSet);
634
650
  if (queueJobTtlSeconds > 0) {
635
651
  await redis.expire(key, queueJobTtlSeconds);
@@ -646,7 +662,7 @@ function preferRedis() {
646
662
  return getStoreType() !== "mongodb" && Boolean((redisUrl2 || "").trim() && (redisToken2 || "").trim());
647
663
  }
648
664
  async function upsertInitialQueueJob(options) {
649
- const { queueJobId, queueId, firstWorkerId, firstWorkerJobId, metadata } = options;
665
+ const { queueJobId, queueId, firstWorkerId, firstWorkerJobId, metadata, userId } = options;
650
666
  const now = (/* @__PURE__ */ new Date()).toISOString();
651
667
  if (preferMongo()) {
652
668
  const coll = await getMongoQueueCollection();
@@ -683,6 +699,7 @@ async function upsertInitialQueueJob(options) {
683
699
  }
684
700
  ],
685
701
  metadata: metadata ?? {},
702
+ ...userId ? { userId } : {},
686
703
  createdAt: now,
687
704
  updatedAt: now
688
705
  };
@@ -721,6 +738,7 @@ async function upsertInitialQueueJob(options) {
721
738
  }
722
739
  ],
723
740
  metadata: metadata ?? {},
741
+ ...userId ? { userId } : {},
724
742
  createdAt: now,
725
743
  updatedAt: now
726
744
  };
@@ -833,6 +851,156 @@ async function appendQueueJobStepInStore(options) {
833
851
  }
834
852
  }
835
853
 
854
+ // src/queue.ts
855
+ var QUEUE_ORCHESTRATION_KEYS = [
856
+ "__workerQueue",
857
+ "__hitlInput",
858
+ "__hitlDecision",
859
+ "__hitlPending",
860
+ "hitl"
861
+ ];
862
+ function repeatStep(count, factory) {
863
+ return Array.from({ length: count }, (_, i) => factory(i));
864
+ }
865
+ function defineWorkerQueue(config) {
866
+ return config;
867
+ }
868
+
869
+ // src/retryConfig.ts
870
+ var BUILT_IN_PATTERNS = {
871
+ "rate-limit": {
872
+ match: (err) => /rate.?limit|too.?many.?requests/i.test(err.message) || err.status === 429 || err.code === 429 || err.name === "RateLimitError",
873
+ delayMs: (attempt) => attempt * 1e4,
874
+ // 10s, 20s, 30s…
875
+ injectContext: false
876
+ },
877
+ "json-parse": {
878
+ match: (err) => err.name === "SyntaxError" || err.name === "ZodError" || /json|parse|unexpected.?token|invalid.?format/i.test(err.message),
879
+ delayMs: (_attempt) => 0,
880
+ // Immediate — model self-corrects from ctx
881
+ injectContext: true
882
+ },
883
+ overloaded: {
884
+ match: (err) => /overloaded|model.?is.?busy/i.test(err.message) || err.status === 529 || err.code === 529,
885
+ delayMs: (attempt) => attempt * 15e3,
886
+ // 15s, 30s…
887
+ injectContext: false
888
+ },
889
+ "server-error": {
890
+ match: (err) => /internal.?server.?error|service.?unavailable|bad.?gateway/i.test(err.message) || typeof err.status === "number" && err.status >= 500 && err.status < 600,
891
+ delayMs: (attempt) => attempt * 5e3,
892
+ // 5s, 10s…
893
+ injectContext: false
894
+ }
895
+ };
896
+ function matchesRetryPattern(err, patterns, attempt) {
897
+ for (const pattern of patterns) {
898
+ if (typeof pattern === "string") {
899
+ const impl = BUILT_IN_PATTERNS[pattern];
900
+ if (impl.match(err)) {
901
+ return { matched: true, delayMs: impl.delayMs(attempt), injectContext: impl.injectContext };
902
+ }
903
+ } else {
904
+ let matched = false;
905
+ if (pattern.match instanceof RegExp) {
906
+ matched = pattern.match.test(err.message);
907
+ } else {
908
+ try {
909
+ matched = pattern.match(err);
910
+ } catch {
911
+ matched = false;
912
+ }
913
+ }
914
+ if (matched) {
915
+ const delayMs = typeof pattern.delayMs === "function" ? pattern.delayMs(attempt) : pattern.delayMs ?? 0;
916
+ return { matched: true, delayMs, injectContext: pattern.injectContext ?? false };
917
+ }
918
+ }
919
+ }
920
+ return { matched: false, delayMs: 0, injectContext: false };
921
+ }
922
+ async function executeWithRetry(fn, config, onRetry) {
923
+ const maxAttempts = config.maxAttempts ?? 3;
924
+ let lastError;
925
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
926
+ const retryCtx = attempt > 1 && lastError ? {
927
+ attempt,
928
+ maxAttempts,
929
+ lastError: {
930
+ message: lastError.message,
931
+ name: lastError.name,
932
+ stack: lastError.stack,
933
+ code: lastError.code ?? lastError.status
934
+ }
935
+ } : void 0;
936
+ try {
937
+ return await fn(retryCtx);
938
+ } catch (err) {
939
+ lastError = err instanceof Error ? err : new Error(String(err));
940
+ if (err?.name === "TokenBudgetExceededError") throw err;
941
+ if (attempt >= maxAttempts) throw err;
942
+ const retryAttemptNumber = attempt;
943
+ const { matched, delayMs } = matchesRetryPattern(lastError, config.on, retryAttemptNumber);
944
+ if (!matched) throw err;
945
+ const nextCtx = {
946
+ attempt: attempt + 1,
947
+ maxAttempts,
948
+ lastError: {
949
+ message: lastError.message,
950
+ name: lastError.name,
951
+ stack: lastError.stack,
952
+ code: lastError.code ?? lastError.status
953
+ }
954
+ };
955
+ onRetry?.(nextCtx, delayMs);
956
+ if (delayMs > 0) {
957
+ await new Promise((r) => setTimeout(r, delayMs));
958
+ }
959
+ }
960
+ }
961
+ throw lastError ?? new Error("executeWithRetry: unknown error");
962
+ }
963
+
964
+ // src/tokenBudget.ts
965
+ var TokenBudgetExceededError = class extends Error {
966
+ constructor(used, budget) {
967
+ super(`Token budget exceeded: used ${used} tokens (budget: ${budget})`);
968
+ this.name = "TokenBudgetExceededError";
969
+ this.used = used;
970
+ this.budget = budget;
971
+ }
972
+ };
973
+ function createTokenTracker(budget) {
974
+ let inputTokens = 0;
975
+ let outputTokens = 0;
976
+ function checkBudget() {
977
+ if (budget !== null) {
978
+ const total = inputTokens + outputTokens;
979
+ if (total > budget) {
980
+ throw new TokenBudgetExceededError(total, budget);
981
+ }
982
+ }
983
+ }
984
+ return {
985
+ report(usage) {
986
+ inputTokens += usage.inputTokens;
987
+ outputTokens += usage.outputTokens;
988
+ checkBudget();
989
+ },
990
+ getState() {
991
+ return { inputTokens, outputTokens, budget };
992
+ },
993
+ getBudgetInfo() {
994
+ const used = inputTokens + outputTokens;
995
+ return {
996
+ used,
997
+ budget,
998
+ remaining: budget !== null ? Math.max(0, budget - used) : null
999
+ };
1000
+ }
1001
+ };
1002
+ }
1003
+
836
1004
  // src/handler.ts
837
1005
  var SQS_MAX_DELAY_SECONDS = 900;
838
1006
  function createWorkerLogger(jobId, workerId) {
@@ -855,6 +1023,67 @@ function createWorkerLogger(jobId, workerId) {
855
1023
  };
856
1024
  }
857
1025
  var WORKER_QUEUE_KEY = "__workerQueue";
1026
+ async function loadPreviousOutputsBeforeStep(queueRuntime, queueJobId, beforeStepIndex) {
1027
+ if (!queueJobId || typeof queueRuntime.getQueueJob !== "function") {
1028
+ return [];
1029
+ }
1030
+ try {
1031
+ const job = await queueRuntime.getQueueJob(queueJobId);
1032
+ if (!job?.steps) return [];
1033
+ return job.steps.slice(0, beforeStepIndex).map((s, i) => ({ stepIndex: i, workerId: s.workerId, output: s.output }));
1034
+ } catch (e) {
1035
+ if (process.env.AI_WORKER_QUEUES_DEBUG === "1") {
1036
+ console.warn("[Worker] getQueueJob failed (resume mapping):", e?.message ?? e);
1037
+ }
1038
+ return [];
1039
+ }
1040
+ }
1041
+ async function maybeApplyHitlResumeMapper(params, queueRuntime) {
1042
+ const inputObj = params.input;
1043
+ if (!inputObj || typeof inputObj !== "object") return;
1044
+ if (!("__hitlInput" in inputObj)) return;
1045
+ const wq = inputObj[WORKER_QUEUE_KEY];
1046
+ if (!wq?.id || typeof wq.stepIndex !== "number") return;
1047
+ const queueId = wq.id;
1048
+ const stepIndex = wq.stepIndex;
1049
+ const initialInput = wq.initialInput;
1050
+ const queueJobId = wq.queueJobId;
1051
+ const previousOutputs = await loadPreviousOutputsBeforeStep(queueRuntime, queueJobId, stepIndex);
1052
+ const pendingInput = { ...inputObj };
1053
+ for (const key of QUEUE_ORCHESTRATION_KEYS) {
1054
+ delete pendingInput[key];
1055
+ }
1056
+ delete pendingInput[WORKER_QUEUE_KEY];
1057
+ const reviewerInput = inputObj.__hitlInput;
1058
+ const decision = inputObj.__hitlDecision;
1059
+ let merged;
1060
+ if (typeof queueRuntime.invokeResume === "function") {
1061
+ merged = await queueRuntime.invokeResume(queueId, stepIndex, {
1062
+ initialInput,
1063
+ previousOutputs,
1064
+ reviewerInput,
1065
+ pendingInput
1066
+ });
1067
+ } else {
1068
+ merged = {
1069
+ ...pendingInput,
1070
+ ...reviewerInput !== null && typeof reviewerInput === "object" ? reviewerInput : {}
1071
+ };
1072
+ }
1073
+ const mergedObj = merged !== null && typeof merged === "object" ? merged : { value: merged };
1074
+ params.input = {
1075
+ ...mergedObj,
1076
+ [WORKER_QUEUE_KEY]: wq,
1077
+ ...decision !== void 0 ? { __hitlDecision: decision } : {}
1078
+ };
1079
+ }
1080
+ function getWorkerQueueContext(input, metadata) {
1081
+ const fromInput = input !== null && typeof input === "object" && WORKER_QUEUE_KEY in input ? input[WORKER_QUEUE_KEY] : void 0;
1082
+ const fromMeta = metadata !== void 0 && typeof metadata === "object" && WORKER_QUEUE_KEY in metadata ? metadata[WORKER_QUEUE_KEY] : void 0;
1083
+ const q = fromInput ?? fromMeta;
1084
+ if (q === null || typeof q !== "object") return void 0;
1085
+ return q;
1086
+ }
858
1087
  async function notifyQueueJobStep(queueJobId, action, params) {
859
1088
  try {
860
1089
  if (action === "append") {
@@ -874,7 +1103,7 @@ async function notifyQueueJobStep(queueJobId, action, params) {
874
1103
  return;
875
1104
  }
876
1105
  if (params.stepIndex === void 0) return;
877
- const status = action === "start" ? "running" : action === "complete" ? "completed" : action === "fail" ? "failed" : void 0;
1106
+ const status = action === "start" ? "running" : action === "awaiting_approval" ? "awaiting_approval" : action === "complete" ? "completed" : action === "fail" ? "failed" : void 0;
878
1107
  if (!status) return;
879
1108
  await updateQueueJobStepInStore({
880
1109
  queueJobId,
@@ -894,6 +1123,13 @@ async function notifyQueueJobStep(queueJobId, action, params) {
894
1123
  status
895
1124
  });
896
1125
  } catch (err) {
1126
+ if (action === "append") {
1127
+ console.error("[Worker] Queue append failed (rethrowing):", {
1128
+ queueJobId,
1129
+ error: err?.message ?? String(err)
1130
+ });
1131
+ throw err;
1132
+ }
897
1133
  console.warn("[Worker] Queue job update error:", {
898
1134
  queueJobId,
899
1135
  action,
@@ -903,26 +1139,152 @@ async function notifyQueueJobStep(queueJobId, action, params) {
903
1139
  }
904
1140
  function wrapHandlerForQueue(handler, queueRuntime) {
905
1141
  return async (params) => {
906
- const queueContext = params.input?.[WORKER_QUEUE_KEY];
907
- const output = await handler(params);
908
- if (!queueContext || typeof queueContext !== "object" || !queueContext.id) {
1142
+ await maybeApplyHitlResumeMapper(params, queueRuntime);
1143
+ const inputObj = params.input !== null && typeof params.input === "object" ? params.input : {};
1144
+ const queueContextRaw = inputObj[WORKER_QUEUE_KEY];
1145
+ const queueCtxForRetry = queueContextRaw && typeof queueContextRaw === "object" ? queueContextRaw : void 0;
1146
+ const stepRetryConfig = queueCtxForRetry?.id && typeof queueCtxForRetry.stepIndex === "number" && typeof queueRuntime.getStepAt === "function" ? queueRuntime.getStepAt(queueCtxForRetry.id, queueCtxForRetry.stepIndex)?.retry : void 0;
1147
+ const domainInput = { ...inputObj };
1148
+ for (const key of QUEUE_ORCHESTRATION_KEYS) {
1149
+ delete domainInput[key];
1150
+ }
1151
+ delete domainInput[WORKER_QUEUE_KEY];
1152
+ params.input = domainInput;
1153
+ let output;
1154
+ if (stepRetryConfig && stepRetryConfig.on.length > 0) {
1155
+ output = await executeWithRetry(
1156
+ async (retryCtx) => {
1157
+ params.ctx.retryContext = retryCtx;
1158
+ return handler(params);
1159
+ },
1160
+ stepRetryConfig,
1161
+ (retryCtx, delayMs) => {
1162
+ const logger = params.ctx.logger;
1163
+ if (logger?.warn) {
1164
+ logger.warn(
1165
+ `[queue-retry] Retrying step (attempt ${retryCtx.attempt}/${retryCtx.maxAttempts}): ${retryCtx.lastError.message}`,
1166
+ { delayMs }
1167
+ );
1168
+ } else {
1169
+ console.warn("[queue-retry] Step retry", { attempt: retryCtx.attempt, error: retryCtx.lastError.message, delayMs });
1170
+ }
1171
+ }
1172
+ );
1173
+ } else {
1174
+ output = await handler(params);
1175
+ }
1176
+ if (!queueContextRaw || typeof queueContextRaw !== "object") {
1177
+ return output;
1178
+ }
1179
+ const queueContext = queueContextRaw;
1180
+ if (!queueContext.id) {
909
1181
  return output;
910
1182
  }
911
1183
  const { id: queueId, stepIndex, initialInput, queueJobId } = queueContext;
912
- const jobId = params.ctx?.jobId;
913
- const workerId = params.ctx?.workerId ?? "";
1184
+ const arrayStepIndex = queueContext.arrayStepIndex ?? stepIndex;
1185
+ const jobId = params.ctx.jobId;
1186
+ const workerId = params.ctx.workerId ?? "";
914
1187
  const next = queueRuntime.getNextStep(queueId, stepIndex);
915
1188
  const childJobId = next ? `job-${Date.now()}-${Math.random().toString(36).slice(2, 11)}` : void 0;
1189
+ const iterationCount = queueContext.iterationCount ?? 0;
1190
+ if (typeof queueRuntime.invokeLoop === "function") {
1191
+ const currentStep = typeof queueRuntime.getStepAt === "function" ? queueRuntime.getStepAt(queueId, stepIndex) : void 0;
1192
+ const maxIterations = currentStep?.loop?.maxIterations ?? 50;
1193
+ if (iterationCount < maxIterations - 1) {
1194
+ let previousOutputsForLoop = [];
1195
+ let stepsLengthBeforeAppend = arrayStepIndex + 1;
1196
+ if (queueJobId && typeof queueRuntime.getQueueJob === "function") {
1197
+ try {
1198
+ const job = await queueRuntime.getQueueJob(queueJobId);
1199
+ if (job?.steps) {
1200
+ previousOutputsForLoop = job.steps.slice(0, stepIndex).map((s, i) => ({ stepIndex: i, workerId: s.workerId, output: s.output }));
1201
+ stepsLengthBeforeAppend = job.steps.length;
1202
+ }
1203
+ } catch {
1204
+ }
1205
+ }
1206
+ previousOutputsForLoop = previousOutputsForLoop.concat([{ stepIndex, workerId, output }]);
1207
+ const shouldLoop = await queueRuntime.invokeLoop(queueId, stepIndex, {
1208
+ output,
1209
+ stepIndex,
1210
+ iterationCount,
1211
+ initialInput,
1212
+ previousOutputs: previousOutputsForLoop
1213
+ });
1214
+ if (shouldLoop) {
1215
+ const loopJobId = `job-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
1216
+ let loopInput = output;
1217
+ if (typeof queueRuntime.invokeChain === "function") {
1218
+ loopInput = await queueRuntime.invokeChain(queueId, stepIndex, {
1219
+ initialInput,
1220
+ previousOutputs: previousOutputsForLoop
1221
+ });
1222
+ }
1223
+ const loopInputWithQueue = {
1224
+ ...loopInput !== null && typeof loopInput === "object" ? loopInput : { value: loopInput },
1225
+ [WORKER_QUEUE_KEY]: {
1226
+ id: queueId,
1227
+ stepIndex,
1228
+ // definition index stays fixed
1229
+ arrayStepIndex: stepsLengthBeforeAppend,
1230
+ // actual index for next iteration
1231
+ initialInput,
1232
+ queueJobId,
1233
+ iterationCount: iterationCount + 1
1234
+ }
1235
+ };
1236
+ if (queueJobId) {
1237
+ await notifyQueueJobStep(queueJobId, "append", { workerJobId: loopJobId, workerId });
1238
+ }
1239
+ if (queueJobId && typeof arrayStepIndex === "number") {
1240
+ await notifyQueueJobStep(queueJobId, "complete", {
1241
+ queueId,
1242
+ stepIndex: arrayStepIndex,
1243
+ workerJobId: jobId,
1244
+ workerId,
1245
+ output
1246
+ });
1247
+ }
1248
+ if (currentStep?.requiresApproval && queueJobId) {
1249
+ const hitlUiSpec = currentStep.hitl && typeof currentStep.hitl === "object" && "ui" in currentStep.hitl ? currentStep.hitl.ui : void 0;
1250
+ const pendingInput = {
1251
+ ...loopInputWithQueue,
1252
+ ...hitlUiSpec !== void 0 ? { hitl: { uiSpec: hitlUiSpec } } : {},
1253
+ __hitlPending: {
1254
+ queueId,
1255
+ queueJobId,
1256
+ stepIndex,
1257
+ workerId,
1258
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1259
+ }
1260
+ };
1261
+ await notifyQueueJobStep(queueJobId, "awaiting_approval", {
1262
+ queueId,
1263
+ stepIndex: stepsLengthBeforeAppend,
1264
+ workerJobId: loopJobId,
1265
+ workerId,
1266
+ input: pendingInput
1267
+ });
1268
+ return output;
1269
+ }
1270
+ await params.ctx.dispatchWorker(workerId, loopInputWithQueue, {
1271
+ await: false,
1272
+ jobId: loopJobId
1273
+ });
1274
+ return output;
1275
+ }
1276
+ }
1277
+ }
916
1278
  if (next && queueJobId) {
917
1279
  await notifyQueueJobStep(queueJobId, "append", {
918
1280
  workerJobId: childJobId,
919
1281
  workerId: next.workerId
920
1282
  });
921
1283
  }
922
- if (queueJobId && typeof stepIndex === "number") {
1284
+ if (queueJobId && typeof arrayStepIndex === "number") {
923
1285
  await notifyQueueJobStep(queueJobId, "complete", {
924
1286
  queueId,
925
- stepIndex,
1287
+ stepIndex: arrayStepIndex,
926
1288
  workerJobId: jobId,
927
1289
  workerId,
928
1290
  output
@@ -932,7 +1294,7 @@ function wrapHandlerForQueue(handler, queueRuntime) {
932
1294
  return output;
933
1295
  }
934
1296
  let nextInput = output;
935
- if (next.mapInputFromPrev && typeof queueRuntime.invokeMapInput === "function") {
1297
+ if (typeof queueRuntime.invokeChain === "function") {
936
1298
  let previousOutputs = [];
937
1299
  if (queueJobId && typeof queueRuntime.getQueueJob === "function") {
938
1300
  try {
@@ -940,7 +1302,7 @@ function wrapHandlerForQueue(handler, queueRuntime) {
940
1302
  if (job?.steps) {
941
1303
  const fromStore = job.steps.slice(0, stepIndex).map((s, i) => ({ stepIndex: i, workerId: s.workerId, output: s.output }));
942
1304
  previousOutputs = fromStore.concat([
943
- { stepIndex, workerId: params.ctx?.workerId ?? "", output }
1305
+ { stepIndex, workerId: params.ctx.workerId ?? "", output }
944
1306
  ]);
945
1307
  }
946
1308
  } catch (e) {
@@ -949,12 +1311,10 @@ function wrapHandlerForQueue(handler, queueRuntime) {
949
1311
  }
950
1312
  }
951
1313
  }
952
- nextInput = await queueRuntime.invokeMapInput(
953
- queueId,
954
- stepIndex + 1,
1314
+ nextInput = await queueRuntime.invokeChain(queueId, stepIndex + 1, {
955
1315
  initialInput,
956
1316
  previousOutputs
957
- );
1317
+ });
958
1318
  }
959
1319
  const nextInputWithQueue = {
960
1320
  ...nextInput !== null && typeof nextInput === "object" ? nextInput : { value: nextInput },
@@ -974,6 +1334,37 @@ function wrapHandlerForQueue(handler, queueRuntime) {
974
1334
  delaySeconds: next.delaySeconds
975
1335
  });
976
1336
  }
1337
+ if (next.requiresApproval && queueJobId && typeof stepIndex === "number") {
1338
+ const hitlUiSpec = next.hitl && typeof next.hitl === "object" && "ui" in next.hitl ? next.hitl.ui : void 0;
1339
+ const pendingInput = {
1340
+ ...nextInputWithQueue,
1341
+ ...hitlUiSpec !== void 0 ? { hitl: { uiSpec: hitlUiSpec } } : {},
1342
+ __hitlPending: {
1343
+ queueId,
1344
+ queueJobId,
1345
+ stepIndex: stepIndex + 1,
1346
+ workerId: next.workerId,
1347
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1348
+ }
1349
+ };
1350
+ await notifyQueueJobStep(queueJobId, "awaiting_approval", {
1351
+ queueId,
1352
+ stepIndex: stepIndex + 1,
1353
+ workerJobId: childJobId,
1354
+ workerId: next.workerId,
1355
+ input: pendingInput
1356
+ });
1357
+ if (debug) {
1358
+ console.log("[Worker] Queue chain paused for HITL approval:", {
1359
+ queueId,
1360
+ queueJobId,
1361
+ nextStep: stepIndex + 1,
1362
+ nextWorkerId: next.workerId,
1363
+ pendingWorkerJobId: childJobId
1364
+ });
1365
+ }
1366
+ return output;
1367
+ }
977
1368
  await params.ctx.dispatchWorker(next.workerId, nextInputWithQueue, {
978
1369
  await: false,
979
1370
  delaySeconds: next.delaySeconds,
@@ -997,6 +1388,7 @@ function createDispatchWorker(parentJobId, parentWorkerId, parentContext, jobSto
997
1388
  const metadata = options?.metadata ?? {};
998
1389
  const serializedContext = {};
999
1390
  if (parentContext.requestId) serializedContext.requestId = parentContext.requestId;
1391
+ if (parentContext.userId) serializedContext.userId = parentContext.userId;
1000
1392
  const messageBody = {
1001
1393
  workerId: calleeWorkerId,
1002
1394
  jobId: childJobId,
@@ -1086,13 +1478,14 @@ async function sendWebhook(webhookUrl, payload) {
1086
1478
  });
1087
1479
  }
1088
1480
  }
1089
- function createLambdaHandler(handler, outputSchema) {
1481
+ function createLambdaHandler(handler, outputSchema, options) {
1090
1482
  return async (event, lambdaContext) => {
1091
1483
  const promises = event.Records.map(async (record) => {
1092
1484
  let messageBody = null;
1093
1485
  try {
1094
1486
  messageBody = JSON.parse(record.body);
1095
- const { workerId, jobId, input, context, webhookUrl, metadata = {} } = messageBody;
1487
+ const { workerId, jobId, input, context, webhookUrl, metadata = {}, userId: messageUserId, maxTokens } = messageBody;
1488
+ const userId = context.userId ?? messageUserId;
1096
1489
  const raw = (process.env.WORKER_DATABASE_TYPE || "upstash-redis").toLowerCase();
1097
1490
  const jobStoreType = raw === "mongodb" ? "mongodb" : "upstash-redis";
1098
1491
  if (jobStoreType === "upstash-redis" && isRedisJobStoreConfigured()) {
@@ -1118,33 +1511,45 @@ function createLambdaHandler(handler, outputSchema) {
1118
1511
  }
1119
1512
  let jobStore;
1120
1513
  if (jobStoreType === "upstash-redis" && isRedisJobStoreConfigured()) {
1121
- await upsertRedisJob(jobId, workerId, input, metadata);
1122
- jobStore = createRedisJobStore(workerId, jobId, input, metadata);
1514
+ await upsertRedisJob(jobId, workerId, input, metadata, userId);
1515
+ jobStore = createRedisJobStore(workerId, jobId, input, metadata, userId);
1123
1516
  } else if (jobStoreType === "mongodb" || isMongoJobStoreConfigured()) {
1124
- await upsertJob(jobId, workerId, input, metadata);
1125
- jobStore = createMongoJobStore(workerId, jobId, input, metadata);
1517
+ await upsertJob(jobId, workerId, input, metadata, userId);
1518
+ jobStore = createMongoJobStore(workerId, jobId, input, metadata, userId);
1519
+ }
1520
+ if (userId) {
1521
+ console.log(`[WORKER_USER:${userId}]`, { jobId, workerId, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1126
1522
  }
1127
1523
  const baseContext = {
1128
1524
  jobId,
1129
1525
  workerId,
1130
1526
  requestId: context.requestId || lambdaContext.awsRequestId,
1527
+ ...userId ? { userId } : {},
1131
1528
  ...context
1132
1529
  };
1530
+ const tokenTracker = createTokenTracker(maxTokens ?? null);
1531
+ const logger = createWorkerLogger(jobId, workerId);
1133
1532
  const handlerContext = {
1134
1533
  ...baseContext,
1135
1534
  ...jobStore ? { jobStore } : {},
1136
- logger: createWorkerLogger(jobId, workerId),
1137
- dispatchWorker: createDispatchWorker(
1138
- jobId,
1139
- workerId,
1140
- baseContext,
1141
- jobStore
1142
- )
1535
+ logger,
1536
+ dispatchWorker: createDispatchWorker(jobId, workerId, baseContext, jobStore),
1537
+ reportTokenUsage: async (usage) => {
1538
+ tokenTracker.report(usage);
1539
+ const state = tokenTracker.getState();
1540
+ if (jobStore) {
1541
+ await jobStore.update({ metadata: { tokenUsage: state } }).catch((e) => {
1542
+ logger.warn("Failed to persist tokenUsage to job store", { error: e?.message });
1543
+ });
1544
+ }
1545
+ },
1546
+ getTokenBudget: () => tokenTracker.getBudgetInfo(),
1547
+ retryContext: void 0
1143
1548
  };
1144
1549
  if (jobStore) {
1145
1550
  try {
1146
1551
  await jobStore.update({ status: "running" });
1147
- const queueCtxForLog = input?.__workerQueue ?? metadata?.__workerQueue;
1552
+ const queueCtxForLog = getWorkerQueueContext(input, metadata);
1148
1553
  console.log("[Worker] Job status updated to running:", {
1149
1554
  jobId,
1150
1555
  workerId,
@@ -1159,7 +1564,7 @@ function createLambdaHandler(handler, outputSchema) {
1159
1564
  });
1160
1565
  }
1161
1566
  }
1162
- const queueCtx = input?.__workerQueue ?? metadata?.__workerQueue;
1567
+ const queueCtx = getWorkerQueueContext(input, metadata);
1163
1568
  if (queueCtx?.queueJobId && typeof queueCtx.stepIndex === "number") {
1164
1569
  if (queueCtx.stepIndex === 0) {
1165
1570
  try {
@@ -1168,7 +1573,8 @@ function createLambdaHandler(handler, outputSchema) {
1168
1573
  queueId: queueCtx.id,
1169
1574
  firstWorkerId: workerId,
1170
1575
  firstWorkerJobId: jobId,
1171
- metadata
1576
+ metadata,
1577
+ userId
1172
1578
  });
1173
1579
  } catch (e) {
1174
1580
  console.warn("[Worker] Failed to upsert initial queue job:", {
@@ -1180,7 +1586,9 @@ function createLambdaHandler(handler, outputSchema) {
1180
1586
  }
1181
1587
  await notifyQueueJobStep(queueCtx.queueJobId, "start", {
1182
1588
  queueId: queueCtx.id,
1183
- stepIndex: queueCtx.stepIndex,
1589
+ // Use arrayStepIndex when set — it tracks the actual steps[] position for
1590
+ // looping steps where the definition index stays fixed across iterations.
1591
+ stepIndex: queueCtx.arrayStepIndex ?? queueCtx.stepIndex,
1184
1592
  workerJobId: jobId,
1185
1593
  workerId,
1186
1594
  input
@@ -1188,12 +1596,21 @@ function createLambdaHandler(handler, outputSchema) {
1188
1596
  }
1189
1597
  let output;
1190
1598
  try {
1191
- output = await handler({
1192
- input,
1193
- ctx: handlerContext
1194
- });
1195
- if (outputSchema) {
1196
- output = outputSchema.parse(output);
1599
+ const workerRetryConfig = options?.retry;
1600
+ const executeHandler = async (retryCtx) => {
1601
+ handlerContext.retryContext = retryCtx;
1602
+ const result = await handler({ input, ctx: handlerContext });
1603
+ return outputSchema ? outputSchema.parse(result) : result;
1604
+ };
1605
+ if (workerRetryConfig && workerRetryConfig.on.length > 0) {
1606
+ output = await executeWithRetry(executeHandler, workerRetryConfig, (retryCtx, delayMs) => {
1607
+ logger.warn(
1608
+ `[worker-retry] Retrying handler (attempt ${retryCtx.attempt}/${retryCtx.maxAttempts}): ${retryCtx.lastError.message}`,
1609
+ { delayMs }
1610
+ );
1611
+ });
1612
+ } else {
1613
+ output = await executeHandler(void 0);
1197
1614
  }
1198
1615
  } catch (error) {
1199
1616
  const errorPayload = {
@@ -1225,7 +1642,7 @@ function createLambdaHandler(handler, outputSchema) {
1225
1642
  });
1226
1643
  }
1227
1644
  }
1228
- const queueCtxFail = input?.__workerQueue ?? metadata?.__workerQueue;
1645
+ const queueCtxFail = getWorkerQueueContext(input, metadata);
1229
1646
  if (queueCtxFail?.queueJobId && typeof queueCtxFail.stepIndex === "number") {
1230
1647
  await notifyQueueJobStep(queueCtxFail.queueJobId, "fail", {
1231
1648
  queueId: queueCtxFail.id,
@@ -1331,25 +1748,73 @@ function clearWorkersConfigCache() {
1331
1748
  cacheExpiry = 0;
1332
1749
  }
1333
1750
 
1334
- // src/queue.ts
1335
- function defineWorkerQueue(config) {
1751
+ // src/queueInputEnvelope.ts
1752
+ var import_zod = require("zod");
1753
+ var queueOrchestrationFieldsSchema = import_zod.z.object({
1754
+ __workerQueue: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
1755
+ __hitlPending: import_zod.z.unknown().optional(),
1756
+ __hitlInput: import_zod.z.unknown().optional(),
1757
+ __hitlDecision: import_zod.z.unknown().optional()
1758
+ });
1759
+ function withQueueOrchestrationEnvelope(domain) {
1760
+ return domain.merge(queueOrchestrationFieldsSchema);
1761
+ }
1762
+
1763
+ // src/chainMapDefaults.ts
1764
+ function defaultMapChainPassthrough(ctx) {
1765
+ const { initialInput, previousOutputs } = ctx;
1766
+ if (previousOutputs.length > 0) {
1767
+ return previousOutputs[previousOutputs.length - 1]?.output;
1768
+ }
1769
+ return initialInput;
1770
+ }
1771
+ function defaultMapChainContinueFromPrevious(ctx) {
1772
+ const { previousOutputs } = ctx;
1773
+ const prev = previousOutputs[previousOutputs.length - 1]?.output;
1774
+ if (!prev || typeof prev.current !== "number") {
1775
+ return {
1776
+ mode: "continue",
1777
+ current: 0,
1778
+ history: [],
1779
+ nextNumber: 0,
1780
+ operator: "add"
1781
+ };
1782
+ }
1783
+ return {
1784
+ mode: "continue",
1785
+ current: prev.current,
1786
+ history: prev.history ?? [],
1787
+ nextNumber: 0,
1788
+ operator: "add"
1789
+ };
1790
+ }
1791
+
1792
+ // src/hitlConfig.ts
1793
+ function defineHitlConfig(config) {
1336
1794
  return config;
1337
1795
  }
1338
1796
 
1339
1797
  // src/index.ts
1340
1798
  function createWorker(config) {
1341
- const { id, inputSchema, outputSchema, handler } = config;
1799
+ const { id, inputSchema, outputSchema, handler, retry: retryConfig } = config;
1342
1800
  const agent = {
1343
1801
  id,
1344
1802
  handler,
1345
1803
  inputSchema,
1346
1804
  outputSchema,
1805
+ retry: retryConfig,
1347
1806
  async dispatch(input, options) {
1348
1807
  const mode = options.mode ?? "auto";
1349
1808
  const envWantsLocal = process.env.NODE_ENV === "development" && process.env.WORKERS_LOCAL_MODE !== "false";
1350
1809
  const isLocal = mode === "local" || mode === "auto" && envWantsLocal;
1351
1810
  if (isLocal) {
1352
- const parsedInput = inputSchema.parse(input);
1811
+ const rawInputObj = input !== null && typeof input === "object" ? input : null;
1812
+ const domainInput = rawInputObj ? Object.fromEntries(
1813
+ Object.entries(rawInputObj).filter(
1814
+ ([k]) => k !== "__workerQueue" && !QUEUE_ORCHESTRATION_KEYS.includes(k)
1815
+ )
1816
+ ) : input;
1817
+ const parsedInput = inputSchema.parse(domainInput);
1353
1818
  const localJobId = options.jobId || `local-${Date.now()}`;
1354
1819
  let directJobStore = null;
1355
1820
  const nextJsPathAlias = "@/app/api/workflows/stores/jobStore";
@@ -1571,6 +2036,7 @@ function createWorker(config) {
1571
2036
  const metadata = options2?.metadata ?? {};
1572
2037
  const serializedContext = {};
1573
2038
  if (parentContext.requestId) serializedContext.requestId = parentContext.requestId;
2039
+ if (parentContext.userId) serializedContext.userId = parentContext.userId;
1574
2040
  const messageBody = {
1575
2041
  workerId: calleeWorkerId,
1576
2042
  jobId: childJobId,
@@ -1675,23 +2141,48 @@ function createWorker(config) {
1675
2141
  });
1676
2142
  }
1677
2143
  }
1678
- const baseContext = { jobId: localJobId, workerId: id };
2144
+ const localUserId = options.userId;
2145
+ const baseContext = {
2146
+ jobId: localJobId,
2147
+ workerId: id,
2148
+ ...localUserId ? { userId: localUserId } : {}
2149
+ };
2150
+ if (localUserId) {
2151
+ console.log(`[WORKER_USER:${localUserId}]`, { jobId: localJobId, workerId: id, mode: "local", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
2152
+ }
2153
+ const localLogger = createWorkerLogger(localJobId, id);
2154
+ const tokenTracker = createTokenTracker(options.maxTokens ?? null);
1679
2155
  const handlerContext = {
1680
2156
  ...baseContext,
1681
2157
  ...jobStore ? { jobStore } : {},
1682
- logger: createWorkerLogger(localJobId, id),
1683
- dispatchWorker: createLocalDispatchWorker(
1684
- localJobId,
1685
- id,
1686
- baseContext,
1687
- jobStore
1688
- )
2158
+ logger: localLogger,
2159
+ dispatchWorker: createLocalDispatchWorker(localJobId, id, baseContext, jobStore),
2160
+ reportTokenUsage: async (usage) => {
2161
+ tokenTracker.report(usage);
2162
+ const state = tokenTracker.getState();
2163
+ if (jobStore) {
2164
+ await jobStore.update({ metadata: { tokenUsage: state } }).catch((e) => {
2165
+ localLogger.warn("Failed to persist tokenUsage", { error: e?.message });
2166
+ });
2167
+ }
2168
+ },
2169
+ getTokenBudget: () => tokenTracker.getBudgetInfo(),
2170
+ retryContext: void 0
1689
2171
  };
1690
2172
  try {
1691
2173
  if (jobStore) {
1692
2174
  await jobStore.update({ status: "running" });
1693
2175
  }
1694
- const output = await dispatchLocal(handler, parsedInput, handlerContext);
2176
+ const executeLocal = async (retryCtx) => {
2177
+ handlerContext.retryContext = retryCtx;
2178
+ return dispatchLocal(handler, parsedInput, handlerContext);
2179
+ };
2180
+ const output = retryConfig && retryConfig.on.length > 0 ? await executeWithRetry(executeLocal, retryConfig, (retryCtx, delayMs) => {
2181
+ localLogger.warn(
2182
+ `[worker-retry] Local retry (attempt ${retryCtx.attempt}/${retryCtx.maxAttempts}): ${retryCtx.lastError.message}`,
2183
+ { delayMs }
2184
+ );
2185
+ }) : await executeLocal(void 0);
1695
2186
  if (jobStore) {
1696
2187
  await jobStore.update({ status: "completed", output });
1697
2188
  }
@@ -1758,25 +2249,35 @@ function createWorker(config) {
1758
2249
  return agent;
1759
2250
  }
1760
2251
  function createLambdaEntrypoint(agent) {
1761
- return createLambdaHandler(agent.handler, agent.outputSchema);
2252
+ return createLambdaHandler(agent.handler, agent.outputSchema, { retry: agent.retry });
1762
2253
  }
1763
2254
  // Annotate the CommonJS export names for ESM import in node:
1764
2255
  0 && (module.exports = {
2256
+ QUEUE_ORCHESTRATION_KEYS,
1765
2257
  SQS_MAX_DELAY_SECONDS,
2258
+ TokenBudgetExceededError,
1766
2259
  clearWorkersConfigCache,
1767
2260
  createLambdaEntrypoint,
1768
2261
  createLambdaHandler,
1769
2262
  createWorker,
1770
2263
  createWorkerLogger,
2264
+ defaultMapChainContinueFromPrevious,
2265
+ defaultMapChainPassthrough,
2266
+ defineHitlConfig,
1771
2267
  defineWorkerQueue,
1772
2268
  dispatch,
1773
2269
  dispatchLocal,
1774
2270
  dispatchQueue,
1775
2271
  dispatchWorker,
2272
+ executeWithRetry,
1776
2273
  getQueueStartUrl,
1777
2274
  getWorkersConfig,
1778
2275
  getWorkersTriggerUrl,
2276
+ matchesRetryPattern,
2277
+ queueOrchestrationFieldsSchema,
2278
+ repeatStep,
1779
2279
  resolveQueueUrl,
2280
+ withQueueOrchestrationEnvelope,
1780
2281
  wrapHandlerForQueue
1781
2282
  });
1782
2283
  //# sourceMappingURL=index.js.map