@trigger.dev/sdk 4.5.1 → 4.5.2

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 (61) hide show
  1. package/dist/commonjs/v3/ai.js +66 -22
  2. package/dist/commonjs/v3/ai.js.map +1 -1
  3. package/dist/commonjs/v3/chat-react.d.ts +1 -0
  4. package/dist/commonjs/v3/chat-react.js +4 -1
  5. package/dist/commonjs/v3/chat-react.js.map +1 -1
  6. package/dist/commonjs/v3/chat.d.ts +100 -0
  7. package/dist/commonjs/v3/chat.js +203 -19
  8. package/dist/commonjs/v3/chat.js.map +1 -1
  9. package/dist/commonjs/v3/index.d.ts +1 -1
  10. package/dist/commonjs/v3/index.js.map +1 -1
  11. package/dist/commonjs/v3/runs-bulk.test.d.ts +1 -0
  12. package/dist/commonjs/v3/runs-bulk.test.js +141 -0
  13. package/dist/commonjs/v3/runs-bulk.test.js.map +1 -0
  14. package/dist/commonjs/v3/runs.d.ts +19 -2
  15. package/dist/commonjs/v3/runs.js +87 -0
  16. package/dist/commonjs/v3/runs.js.map +1 -1
  17. package/dist/commonjs/v3/sessions.js +5 -2
  18. package/dist/commonjs/v3/sessions.js.map +1 -1
  19. package/dist/commonjs/v3/shared.d.ts +2 -2
  20. package/dist/commonjs/v3/shared.js +79 -4
  21. package/dist/commonjs/v3/shared.js.map +1 -1
  22. package/dist/commonjs/v3/shared.test.js +37 -0
  23. package/dist/commonjs/v3/shared.test.js.map +1 -1
  24. package/dist/commonjs/version.js +1 -1
  25. package/dist/esm/v3/ai.js +66 -22
  26. package/dist/esm/v3/ai.js.map +1 -1
  27. package/dist/esm/v3/chat-react.d.ts +1 -0
  28. package/dist/esm/v3/chat-react.js +4 -1
  29. package/dist/esm/v3/chat-react.js.map +1 -1
  30. package/dist/esm/v3/chat.d.ts +100 -0
  31. package/dist/esm/v3/chat.js +204 -20
  32. package/dist/esm/v3/chat.js.map +1 -1
  33. package/dist/esm/v3/index.d.ts +1 -1
  34. package/dist/esm/v3/index.js.map +1 -1
  35. package/dist/esm/v3/runs-bulk.test.d.ts +1 -0
  36. package/dist/esm/v3/runs-bulk.test.js +139 -0
  37. package/dist/esm/v3/runs-bulk.test.js.map +1 -0
  38. package/dist/esm/v3/runs.d.ts +18 -1
  39. package/dist/esm/v3/runs.js +87 -0
  40. package/dist/esm/v3/runs.js.map +1 -1
  41. package/dist/esm/v3/sessions.js +5 -2
  42. package/dist/esm/v3/sessions.js.map +1 -1
  43. package/dist/esm/v3/shared.d.ts +2 -2
  44. package/dist/esm/v3/shared.js +79 -5
  45. package/dist/esm/v3/shared.js.map +1 -1
  46. package/dist/esm/v3/shared.test.js +38 -1
  47. package/dist/esm/v3/shared.test.js.map +1 -1
  48. package/dist/esm/version.js +1 -1
  49. package/docs/ai-chat/frontend.mdx +46 -0
  50. package/docs/ai-chat/pending-messages.mdx +3 -1
  51. package/docs/ai-chat/reference.mdx +20 -0
  52. package/docs/billing-limits.mdx +73 -0
  53. package/docs/how-to-reduce-your-spend.mdx +1 -14
  54. package/docs/limits.mdx +5 -0
  55. package/docs/self-hosting/docker.mdx +24 -1
  56. package/docs/self-hosting/env/webapp.mdx +6 -1
  57. package/docs/self-hosting/kubernetes.mdx +26 -0
  58. package/docs/self-hosting/overview.mdx +4 -1
  59. package/docs/self-hosting/security.mdx +50 -0
  60. package/docs/troubleshooting.mdx +4 -0
  61. package/package.json +2 -2
@@ -2922,6 +2922,11 @@ function chatAgent(options) {
2922
2922
  // default, `inFlightUsers`). The turn-loop checks this queue ahead of
2923
2923
  // `messagesInput.waitWithIdleTimeout` so recovered turns fire first.
2924
2924
  const bootInjectedQueue = [];
2925
+ // Messages consumed by a turn's `messagesInput.on` handler, dispatched
2926
+ // one per turn by the end-of-turn pickup. Loop-level on purpose:
2927
+ // consuming a record advances the committed `.in` cursor, so entries
2928
+ // dropped with a turn-local buffer are lost permanently.
2929
+ const pendingWireMessages = [];
2925
2930
  const couldHavePriorState = payload.continuation === true || ctx.attempt.number > 1;
2926
2931
  // `.in` resume cursor, computed at most once per boot. The boot
2927
2932
  // block below resolves it (snapshot field or records scan) and the
@@ -3628,6 +3633,9 @@ function chatAgent(options) {
3628
3633
  } // end else (no boot-injected first turn)
3629
3634
  }
3630
3635
  for (let turn = 0; turn < maxTurns; turn++) {
3636
+ // Declared here so the finally can detach it — a handler leaked past
3637
+ // its turn duplicates every mid-stream message into the shared buffer.
3638
+ let turnMsgSub;
3631
3639
  try {
3632
3640
  // Extract turn-level context before entering the span. Slim
3633
3641
  // wire: at most one delta message per record. `headStartMessages`
@@ -3703,8 +3711,6 @@ function chatAgent(options) {
3703
3711
  const stopSignal = stopController.signal;
3704
3712
  const cancelSignal = runSignal;
3705
3713
  const combinedSignal = AbortSignal.any([runSignal, stopController.signal]);
3706
- // Buffer messages that arrive during streaming
3707
- const pendingMessages = [];
3708
3714
  const pmConfig = locals_js_1.locals.get(chatPendingMessagesKey);
3709
3715
  const msgSub = messagesInput.on(async (msg) => {
3710
3716
  // If pendingMessages is configured, route to the steering queue
@@ -3751,8 +3757,9 @@ function chatAgent(options) {
3751
3757
  return; // Don't add to wire buffer — frontend handles non-injected case
3752
3758
  }
3753
3759
  // No pendingMessages config — standard wire buffer for next turn
3754
- pendingMessages.push(msg);
3760
+ pendingWireMessages.push(msg);
3755
3761
  });
3762
+ turnMsgSub = msgSub;
3756
3763
  // Track new messages for this turn (user input + assistant response).
3757
3764
  const turnNewModelMessages = [];
3758
3765
  const turnNewUIMessages = [];
@@ -4807,9 +4814,10 @@ function chatAgent(options) {
4807
4814
  return "continue";
4808
4815
  }
4809
4816
  // If messages arrived during streaming (without pendingMessages config),
4810
- // use the first one immediately as the next turn.
4811
- if (pendingMessages.length > 0) {
4812
- currentWirePayload = pendingMessages[0];
4817
+ // dispatch the oldest as the next turn. The rest stay queued
4818
+ // and drain one per turn.
4819
+ if (pendingWireMessages.length > 0) {
4820
+ currentWirePayload = pendingWireMessages.shift();
4813
4821
  return "continue";
4814
4822
  }
4815
4823
  // chat.requestUpgrade() was called — exit the loop so the
@@ -4895,6 +4903,9 @@ function chatAgent(options) {
4895
4903
  // Turn error handler: write an error chunk + turn-complete to the stream
4896
4904
  // so the client sees the error, then wait for the next message instead
4897
4905
  // of killing the entire run. This keeps the conversation alive.
4906
+ // Detach the turn's message handler first — left attached it would
4907
+ // eat the very message the wait below is waiting for.
4908
+ turnMsgSub?.off();
4898
4909
  if (turnError instanceof Error &&
4899
4910
  turnError.name === "AbortError" &&
4900
4911
  runSignal.aborted) {
@@ -5014,6 +5025,11 @@ function chatAgent(options) {
5014
5025
  currentWirePayload = bootInjectedQueue.shift();
5015
5026
  continue;
5016
5027
  }
5028
+ // Same for messages buffered during the errored turn — already consumed, idling strands them.
5029
+ if (pendingWireMessages.length > 0) {
5030
+ currentWirePayload = pendingWireMessages.shift();
5031
+ continue;
5032
+ }
5017
5033
  // Wait for the next message — same as after a successful turn
5018
5034
  const effectiveIdleTimeout = metadata_js_1.metadata.get(IDLE_TIMEOUT_METADATA_KEY) ??
5019
5035
  idleTimeoutInSeconds;
@@ -5029,6 +5045,9 @@ function chatAgent(options) {
5029
5045
  currentWirePayload = next.output;
5030
5046
  // Continue to next iteration of the for loop
5031
5047
  }
5048
+ finally {
5049
+ turnMsgSub?.off();
5050
+ }
5032
5051
  }
5033
5052
  }
5034
5053
  finally {
@@ -5939,8 +5958,17 @@ function createChatSession(payload, options) {
5939
5958
  const accumulator = new ChatMessageAccumulator();
5940
5959
  let previousTurnUsage;
5941
5960
  let cumulativeUsage = emptyUsage();
5961
+ // Messages consumed mid-turn, dispatched one per next(). Iterator-level
5962
+ // for the same reason as the agent loop's `pendingWireMessages`:
5963
+ // consumed records never replay, so a turn-local buffer loses them.
5964
+ const sessionPendingWire = [];
5965
+ // The current turn's message subscription — detached defensively at the
5966
+ // top of next() in case user code threw without complete()/done().
5967
+ let activeMsgSub;
5942
5968
  return {
5943
5969
  async next() {
5970
+ activeMsgSub?.off();
5971
+ activeMsgSub = undefined;
5944
5972
  if (!booted) {
5945
5973
  booted = true;
5946
5974
  await seedSessionInResumeCursorForCustomLoop(currentPayload);
@@ -6000,23 +6028,29 @@ function createChatSession(payload, options) {
6000
6028
  currentPayload = { ...currentPayload, continuation: true };
6001
6029
  }
6002
6030
  }
6003
- // Subsequent turns: wait for the next message
6031
+ // Subsequent turns: drain buffered mid-turn messages first (they
6032
+ // were consumed and won't be re-delivered), then wait.
6004
6033
  if (turn > 0) {
6005
- // chat.requestUpgrade() / chat.endRun() — exit before waiting
6006
- if (locals_js_1.locals.get(chatUpgradeRequestedKey) || locals_js_1.locals.get(chatEndRunRequestedKey)) {
6007
- stop.cleanup();
6008
- return { done: true, value: undefined };
6034
+ if (sessionPendingWire.length > 0) {
6035
+ currentPayload = sessionPendingWire.shift();
6009
6036
  }
6010
- const next = await messagesInput.waitWithIdleTimeout({
6011
- idleTimeoutInSeconds,
6012
- timeout,
6013
- spanName: "waiting for next message",
6014
- });
6015
- if (!next.ok || runSignal.aborted) {
6016
- stop.cleanup();
6017
- return { done: true, value: undefined };
6037
+ else {
6038
+ // chat.requestUpgrade() / chat.endRun() — exit before waiting
6039
+ if (locals_js_1.locals.get(chatUpgradeRequestedKey) || locals_js_1.locals.get(chatEndRunRequestedKey)) {
6040
+ stop.cleanup();
6041
+ return { done: true, value: undefined };
6042
+ }
6043
+ const next = await messagesInput.waitWithIdleTimeout({
6044
+ idleTimeoutInSeconds,
6045
+ timeout,
6046
+ spanName: "waiting for next message",
6047
+ });
6048
+ if (!next.ok || runSignal.aborted) {
6049
+ stop.cleanup();
6050
+ return { done: true, value: undefined };
6051
+ }
6052
+ currentPayload = next.output;
6018
6053
  }
6019
- currentPayload = next.output;
6020
6054
  }
6021
6055
  // Check limits
6022
6056
  if (turn >= maxTurns || runSignal.aborted) {
@@ -6041,10 +6075,10 @@ function createChatSession(payload, options) {
6041
6075
  clientData: currentPayload.metadata,
6042
6076
  });
6043
6077
  // Listen for messages during streaming (steering + next-turn buffer)
6044
- const sessionPendingWire = [];
6045
6078
  const sessionMsgSub = messagesInput.on(async (msg) => {
6046
- sessionPendingWire.push(msg);
6047
6079
  if (sessionPendingMessages) {
6080
+ // Steering route — the frontend re-sends non-injected
6081
+ // messages on turn complete, so don't also buffer the wire.
6048
6082
  // Slim wire: at most one delta message per record. Read
6049
6083
  // `msg.message` directly — no array slicing needed.
6050
6084
  const lastUIMessage = msg.message;
@@ -6069,8 +6103,11 @@ function createChatSession(payload, options) {
6069
6103
  /* non-fatal */
6070
6104
  }
6071
6105
  }
6106
+ return;
6072
6107
  }
6108
+ sessionPendingWire.push(msg);
6073
6109
  });
6110
+ activeMsgSub = sessionMsgSub;
6074
6111
  // Accumulate messages. Slim wire: pass the single delta message as
6075
6112
  // a 0-or-1-length array. The accumulator's behavior is unchanged —
6076
6113
  // it still appends user messages and reconverts on regenerate.
@@ -6161,6 +6198,11 @@ function createChatSession(payload, options) {
6161
6198
  throw error;
6162
6199
  }
6163
6200
  }
6201
+ finally {
6202
+ // Detach at stream end (like the agent loop): the steering queue
6203
+ // can't inject anymore, so later arrivals must buffer for the next turn.
6204
+ sessionMsgSub.off();
6205
+ }
6164
6206
  if (response) {
6165
6207
  const cleaned = stop.signal.aborted && !runSignal.aborted
6166
6208
  ? cleanupAbortedParts(response)
@@ -6304,6 +6346,8 @@ function createChatSession(payload, options) {
6304
6346
  return { done: false, value: turnObj };
6305
6347
  },
6306
6348
  async return() {
6349
+ activeMsgSub?.off();
6350
+ activeMsgSub = undefined;
6307
6351
  // `stop` only exists once next() has booted the iterator.
6308
6352
  stop?.cleanup();
6309
6353
  return { done: true, value: undefined };