@falai/agent 2.4.3 → 2.6.0

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 (121) hide show
  1. package/dist/cjs/core/FlowRouter.d.ts.map +1 -1
  2. package/dist/cjs/core/FlowRouter.js +0 -11
  3. package/dist/cjs/core/FlowRouter.js.map +1 -1
  4. package/dist/cjs/core/ResponseModal.d.ts +51 -2
  5. package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
  6. package/dist/cjs/core/ResponseModal.js +272 -269
  7. package/dist/cjs/core/ResponseModal.js.map +1 -1
  8. package/dist/cjs/core/ToolLoopExecutor.d.ts +11 -0
  9. package/dist/cjs/core/ToolLoopExecutor.d.ts.map +1 -1
  10. package/dist/cjs/core/ToolLoopExecutor.js +75 -51
  11. package/dist/cjs/core/ToolLoopExecutor.js.map +1 -1
  12. package/dist/cjs/index.d.ts +3 -0
  13. package/dist/cjs/index.d.ts.map +1 -1
  14. package/dist/cjs/index.js +4 -2
  15. package/dist/cjs/index.js.map +1 -1
  16. package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
  17. package/dist/cjs/providers/AnthropicProvider.js +18 -35
  18. package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
  19. package/dist/cjs/providers/DeepSeekProvider.d.ts +1 -12
  20. package/dist/cjs/providers/DeepSeekProvider.d.ts.map +1 -1
  21. package/dist/cjs/providers/DeepSeekProvider.js +3 -20
  22. package/dist/cjs/providers/DeepSeekProvider.js.map +1 -1
  23. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  24. package/dist/cjs/providers/GeminiProvider.js +22 -37
  25. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  26. package/dist/cjs/providers/GenericOpenAICompatibleProvider.d.ts +69 -0
  27. package/dist/cjs/providers/GenericOpenAICompatibleProvider.d.ts.map +1 -0
  28. package/dist/cjs/providers/GenericOpenAICompatibleProvider.js +93 -0
  29. package/dist/cjs/providers/GenericOpenAICompatibleProvider.js.map +1 -0
  30. package/dist/cjs/providers/OpenAICompatibleProvider.d.ts +23 -5
  31. package/dist/cjs/providers/OpenAICompatibleProvider.d.ts.map +1 -1
  32. package/dist/cjs/providers/OpenAICompatibleProvider.js +46 -44
  33. package/dist/cjs/providers/OpenAICompatibleProvider.js.map +1 -1
  34. package/dist/cjs/providers/index.d.ts +3 -1
  35. package/dist/cjs/providers/index.d.ts.map +1 -1
  36. package/dist/cjs/providers/index.js +3 -1
  37. package/dist/cjs/providers/index.js.map +1 -1
  38. package/dist/cjs/utils/completion.d.ts +20 -0
  39. package/dist/cjs/utils/completion.d.ts.map +1 -0
  40. package/dist/cjs/utils/completion.js +33 -0
  41. package/dist/cjs/utils/completion.js.map +1 -0
  42. package/dist/cjs/utils/index.d.ts +3 -2
  43. package/dist/cjs/utils/index.d.ts.map +1 -1
  44. package/dist/cjs/utils/index.js +7 -1
  45. package/dist/cjs/utils/index.js.map +1 -1
  46. package/dist/cjs/utils/retry.d.ts +43 -7
  47. package/dist/cjs/utils/retry.d.ts.map +1 -1
  48. package/dist/cjs/utils/retry.js +100 -12
  49. package/dist/cjs/utils/retry.js.map +1 -1
  50. package/dist/cjs/utils/streamingMessage.d.ts +48 -0
  51. package/dist/cjs/utils/streamingMessage.d.ts.map +1 -0
  52. package/dist/cjs/utils/streamingMessage.js +210 -0
  53. package/dist/cjs/utils/streamingMessage.js.map +1 -0
  54. package/dist/core/FlowRouter.d.ts.map +1 -1
  55. package/dist/core/FlowRouter.js +0 -11
  56. package/dist/core/FlowRouter.js.map +1 -1
  57. package/dist/core/ResponseModal.d.ts +51 -2
  58. package/dist/core/ResponseModal.d.ts.map +1 -1
  59. package/dist/core/ResponseModal.js +272 -269
  60. package/dist/core/ResponseModal.js.map +1 -1
  61. package/dist/core/ToolLoopExecutor.d.ts +11 -0
  62. package/dist/core/ToolLoopExecutor.d.ts.map +1 -1
  63. package/dist/core/ToolLoopExecutor.js +76 -52
  64. package/dist/core/ToolLoopExecutor.js.map +1 -1
  65. package/dist/index.d.ts +3 -0
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +1 -0
  68. package/dist/index.js.map +1 -1
  69. package/dist/providers/AnthropicProvider.d.ts.map +1 -1
  70. package/dist/providers/AnthropicProvider.js +19 -36
  71. package/dist/providers/AnthropicProvider.js.map +1 -1
  72. package/dist/providers/DeepSeekProvider.d.ts +1 -12
  73. package/dist/providers/DeepSeekProvider.d.ts.map +1 -1
  74. package/dist/providers/DeepSeekProvider.js +3 -20
  75. package/dist/providers/DeepSeekProvider.js.map +1 -1
  76. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  77. package/dist/providers/GeminiProvider.js +23 -38
  78. package/dist/providers/GeminiProvider.js.map +1 -1
  79. package/dist/providers/GenericOpenAICompatibleProvider.d.ts +69 -0
  80. package/dist/providers/GenericOpenAICompatibleProvider.d.ts.map +1 -0
  81. package/dist/providers/GenericOpenAICompatibleProvider.js +87 -0
  82. package/dist/providers/GenericOpenAICompatibleProvider.js.map +1 -0
  83. package/dist/providers/OpenAICompatibleProvider.d.ts +23 -5
  84. package/dist/providers/OpenAICompatibleProvider.d.ts.map +1 -1
  85. package/dist/providers/OpenAICompatibleProvider.js +47 -45
  86. package/dist/providers/OpenAICompatibleProvider.js.map +1 -1
  87. package/dist/providers/index.d.ts +3 -1
  88. package/dist/providers/index.d.ts.map +1 -1
  89. package/dist/providers/index.js +1 -0
  90. package/dist/providers/index.js.map +1 -1
  91. package/dist/utils/completion.d.ts +20 -0
  92. package/dist/utils/completion.d.ts.map +1 -0
  93. package/dist/utils/completion.js +29 -0
  94. package/dist/utils/completion.js.map +1 -0
  95. package/dist/utils/index.d.ts +3 -2
  96. package/dist/utils/index.d.ts.map +1 -1
  97. package/dist/utils/index.js +3 -1
  98. package/dist/utils/index.js.map +1 -1
  99. package/dist/utils/retry.d.ts +43 -7
  100. package/dist/utils/retry.d.ts.map +1 -1
  101. package/dist/utils/retry.js +98 -12
  102. package/dist/utils/retry.js.map +1 -1
  103. package/dist/utils/streamingMessage.d.ts +48 -0
  104. package/dist/utils/streamingMessage.d.ts.map +1 -0
  105. package/dist/utils/streamingMessage.js +205 -0
  106. package/dist/utils/streamingMessage.js.map +1 -0
  107. package/package.json +1 -1
  108. package/src/core/FlowRouter.ts +0 -14
  109. package/src/core/ResponseModal.ts +332 -299
  110. package/src/core/ToolLoopExecutor.ts +108 -52
  111. package/src/index.ts +3 -0
  112. package/src/providers/AnthropicProvider.ts +22 -43
  113. package/src/providers/DeepSeekProvider.ts +3 -35
  114. package/src/providers/GeminiProvider.ts +27 -46
  115. package/src/providers/GenericOpenAICompatibleProvider.ts +138 -0
  116. package/src/providers/OpenAICompatibleProvider.ts +87 -67
  117. package/src/providers/index.ts +4 -0
  118. package/src/utils/completion.ts +38 -0
  119. package/src/utils/index.ts +5 -2
  120. package/src/utils/retry.ts +136 -14
  121. package/src/utils/streamingMessage.ts +220 -0
@@ -5,8 +5,37 @@ export interface RetryOptions<T> {
5
5
  onRetry?: (attempt: number, error: unknown) => void;
6
6
  onFailure?: (error: unknown) => boolean;
7
7
  }
8
+ /** Provider timeout (ms) + retry count, after defaults are applied. */
9
+ export interface RetryConfig {
10
+ timeout: number;
11
+ retries: number;
12
+ }
13
+ /**
14
+ * Normalize a provider's optional retry config against the defaults. `timeout`
15
+ * uses `||` (a 0ms timeout is degenerate — it aborts every call immediately — so
16
+ * fall back to the default), while `retries` uses `??` so an explicit
17
+ * `retries: 0` (disable retries) is honored rather than treated as unset. Single
18
+ * definition so this distinction can't drift between providers.
19
+ */
20
+ export declare function resolveRetryConfig(input?: {
21
+ timeout?: number;
22
+ retries?: number;
23
+ }): RetryConfig;
8
24
  export declare function retry<T>(options: RetryOptions<T>): Promise<T>;
9
- export declare const withTimeoutAndRetry: <T>(operation: () => Promise<T>, timeoutMs?: number, maxRetries?: number, operationName?: string) => Promise<T>;
25
+ /**
26
+ * Combine abort signals into one that aborts as soon as any input aborts.
27
+ * `undefined` inputs are skipped, so a caller can pass an optional caller-signal
28
+ * alongside a required per-attempt one. Returns the sole signal when only one is
29
+ * present (no wrapper), or `undefined` when none are.
30
+ *
31
+ * Prefers the platform `AbortSignal.any`, which cleans up its listeners via weak
32
+ * refs — so merging onto a long-lived caller signal that's reused across many
33
+ * calls can't accumulate listeners. Falls back to a manual controller on older
34
+ * runtimes (< Node 20.3); there the listeners live until a source aborts or is
35
+ * garbage-collected, which is fine for the usual per-request signal.
36
+ */
37
+ export declare function combineAbortSignals(...signals: Array<AbortSignal | undefined>): AbortSignal | undefined;
38
+ export declare const withTimeoutAndRetry: <T>(operation: (signal: AbortSignal) => Promise<T>, timeoutMs?: number, maxRetries?: number, operationName?: string) => Promise<T>;
10
39
  export interface StreamRetryOptions {
11
40
  /** Maximum number of retries after the first attempt. Defaults to 3. */
12
41
  maxRetries?: number;
@@ -14,18 +43,25 @@ export interface StreamRetryOptions {
14
43
  delay?: (attempt: number) => number;
15
44
  /** Label used in retry logs. */
16
45
  operationName?: string;
46
+ /**
47
+ * Max ms to wait for the *first* chunk (time-to-first-token) before treating
48
+ * the attempt as failed. Guards a provider that opens a stream and then
49
+ * stalls. Only the first chunk is bounded — later chunks are unbounded so a
50
+ * long but healthy stream is never cut off. `0`/omitted disables the deadline.
51
+ */
52
+ firstChunkTimeoutMs?: number;
17
53
  }
18
54
  /**
19
55
  * Streaming analog of {@link withTimeoutAndRetry}. Re-runs an async-generator
20
- * factory as long as it fails *before yielding its first chunk* — e.g. an
21
- * empty completion that throws "No response", or an error while establishing
22
- * the stream. Once any chunk has been yielded the stream is committed and
23
- * further errors propagate, so a retry can never double-emit deltas that the
24
- * consumer has already received.
56
+ * factory as long as it fails *before yielding its first chunk* — an empty
57
+ * completion that throws "No response", an error while establishing the stream,
58
+ * or (with `firstChunkTimeoutMs`) a stall before the first token. Once any chunk
59
+ * has been yielded the stream is committed and further errors propagate, so a
60
+ * retry can never double-emit deltas the consumer has already received.
25
61
  *
26
62
  * This mirrors the non-streaming path, where the provider throws on an empty
27
63
  * completion inside `withTimeoutAndRetry` and is retried on the same model
28
64
  * before the caller falls through to backup models.
29
65
  */
30
- export declare function withStreamRetry<T>(factory: () => AsyncGenerator<T>, options?: StreamRetryOptions): AsyncGenerator<T>;
66
+ export declare function withStreamRetry<T>(factory: (signal: AbortSignal) => AsyncGenerator<T>, options?: StreamRetryOptions): AsyncGenerator<T>;
31
67
  //# sourceMappingURL=retry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../src/utils/retry.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACpD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;CACzC;AAED,wBAAsB,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA8BnE;AAED,eAAO,MAAM,mBAAmB,GAAU,CAAC,EACzC,WAAW,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,YAAW,MAAc,EACzB,aAAY,MAAU,EACtB,gBAAe,MAAuB,KACrC,OAAO,CAAC,CAAC,CA8CX,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAuB,eAAe,CAAC,CAAC,EACtC,OAAO,EAAE,MAAM,cAAc,CAAC,CAAC,CAAC,EAChC,OAAO,GAAE,kBAAuB,GAC/B,cAAc,CAAC,CAAC,CAAC,CA6BnB"}
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../src/utils/retry.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACpD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;CACzC;AAED,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,WAAW,CAKd;AAED,wBAAsB,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA8BnE;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC,GACzC,WAAW,GAAG,SAAS,CAgBzB;AAED,eAAO,MAAM,mBAAmB,GAAU,CAAC,EACzC,WAAW,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EAC9C,YAAW,MAAc,EACzB,aAAY,MAAU,EACtB,gBAAe,MAAuB,KACrC,OAAO,CAAC,CAAC,CAiDX,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAuBD;;;;;;;;;;;GAWG;AACH,wBAAuB,eAAe,CAAC,CAAC,EACtC,OAAO,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,cAAc,CAAC,CAAC,CAAC,EACnD,OAAO,GAAE,kBAAuB,GAC/B,cAAc,CAAC,CAAC,CAAC,CAwDnB"}
@@ -1,12 +1,31 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.withTimeoutAndRetry = void 0;
4
+ exports.resolveRetryConfig = resolveRetryConfig;
4
5
  exports.retry = retry;
6
+ exports.combineAbortSignals = combineAbortSignals;
5
7
  exports.withStreamRetry = withStreamRetry;
6
8
  /**
7
9
  * Retry utility with exponential backoff
8
10
  */
9
11
  const logger_1 = require("./logger");
12
+ const DEFAULT_RETRY_CONFIG = {
13
+ timeout: 60000,
14
+ retries: 3,
15
+ };
16
+ /**
17
+ * Normalize a provider's optional retry config against the defaults. `timeout`
18
+ * uses `||` (a 0ms timeout is degenerate — it aborts every call immediately — so
19
+ * fall back to the default), while `retries` uses `??` so an explicit
20
+ * `retries: 0` (disable retries) is honored rather than treated as unset. Single
21
+ * definition so this distinction can't drift between providers.
22
+ */
23
+ function resolveRetryConfig(input) {
24
+ return {
25
+ timeout: input?.timeout || DEFAULT_RETRY_CONFIG.timeout,
26
+ retries: input?.retries ?? DEFAULT_RETRY_CONFIG.retries,
27
+ };
28
+ }
10
29
  async function retry(options) {
11
30
  const { operation, maxRetries, delay, onRetry, onFailure } = options;
12
31
  let lastError;
@@ -33,6 +52,38 @@ async function retry(options) {
33
52
  // eslint-disable-next-line @typescript-eslint/only-throw-error
34
53
  throw lastError ?? new Error("Operation failed");
35
54
  }
55
+ /** Capped exponential backoff (1s, 2s, 4s, … max 5s) shared by the retry helpers. */
56
+ const defaultBackoff = (attempt) => Math.min(1000 * Math.pow(2, attempt), 5000);
57
+ /**
58
+ * Combine abort signals into one that aborts as soon as any input aborts.
59
+ * `undefined` inputs are skipped, so a caller can pass an optional caller-signal
60
+ * alongside a required per-attempt one. Returns the sole signal when only one is
61
+ * present (no wrapper), or `undefined` when none are.
62
+ *
63
+ * Prefers the platform `AbortSignal.any`, which cleans up its listeners via weak
64
+ * refs — so merging onto a long-lived caller signal that's reused across many
65
+ * calls can't accumulate listeners. Falls back to a manual controller on older
66
+ * runtimes (< Node 20.3); there the listeners live until a source aborts or is
67
+ * garbage-collected, which is fine for the usual per-request signal.
68
+ */
69
+ function combineAbortSignals(...signals) {
70
+ const present = signals.filter((s) => s != null);
71
+ if (present.length <= 1)
72
+ return present[0];
73
+ if (typeof AbortSignal.any === "function")
74
+ return AbortSignal.any(present);
75
+ const controller = new AbortController();
76
+ for (const signal of present) {
77
+ if (signal.aborted) {
78
+ controller.abort(signal.reason);
79
+ break;
80
+ }
81
+ signal.addEventListener("abort", () => controller.abort(signal.reason), {
82
+ once: true,
83
+ });
84
+ }
85
+ return controller.signal;
86
+ }
36
87
  const withTimeoutAndRetry = async (operation, timeoutMs = 60000, maxRetries = 3, operationName = "AI operation") => {
37
88
  const createTimeoutOperation = () => async () => {
38
89
  const controller = new AbortController();
@@ -40,8 +91,11 @@ const withTimeoutAndRetry = async (operation, timeoutMs = 60000, maxRetries = 3,
40
91
  controller.abort();
41
92
  }, timeoutMs);
42
93
  try {
94
+ // Hand the operation the timeout signal so the in-flight upstream call is
95
+ // actually cancelled when the deadline fires — otherwise the abandoned
96
+ // attempt keeps running while the retry stacks a second concurrent call.
43
97
  const result = await Promise.race([
44
- operation(),
98
+ operation(controller.signal),
45
99
  new Promise((_, reject) => {
46
100
  controller.signal.addEventListener("abort", () => {
47
101
  reject(new Error(`Operation timed out after ${timeoutMs}ms`));
@@ -59,11 +113,11 @@ const withTimeoutAndRetry = async (operation, timeoutMs = 60000, maxRetries = 3,
59
113
  return retry({
60
114
  operation: createTimeoutOperation(),
61
115
  maxRetries,
62
- delay: (attempt) => Math.min(1000 * Math.pow(2, attempt), 5000),
116
+ delay: defaultBackoff,
63
117
  onRetry: (attempt, error) => {
64
118
  const message = error instanceof Error ? error.message : String(error);
65
119
  logger_1.logger.error(`[${operationName}] Failed attempt ${attempt + 1}:`, message);
66
- const delay = Math.min(1000 * Math.pow(2, attempt), 5000);
120
+ const delay = defaultBackoff(attempt);
67
121
  logger_1.logger.debug(`[${operationName}] Retrying in ${delay}ms...`);
68
122
  logger_1.logger.debug(`[${operationName}] Attempt ${attempt + 2}/${maxRetries + 1}`);
69
123
  },
@@ -74,28 +128,49 @@ const withTimeoutAndRetry = async (operation, timeoutMs = 60000, maxRetries = 3,
74
128
  });
75
129
  };
76
130
  exports.withTimeoutAndRetry = withTimeoutAndRetry;
131
+ /** Reject if `next` hasn't settled within `timeoutMs`; always clears its timer. */
132
+ function raceFirstChunk(next, timeoutMs, operationName) {
133
+ let timer;
134
+ const timeout = new Promise((_, reject) => {
135
+ timer = setTimeout(() => reject(new Error(`[${operationName}] Stream timed out: no first chunk within ${timeoutMs}ms`)), timeoutMs);
136
+ });
137
+ return Promise.race([next, timeout]).finally(() => clearTimeout(timer));
138
+ }
77
139
  /**
78
140
  * Streaming analog of {@link withTimeoutAndRetry}. Re-runs an async-generator
79
- * factory as long as it fails *before yielding its first chunk* — e.g. an
80
- * empty completion that throws "No response", or an error while establishing
81
- * the stream. Once any chunk has been yielded the stream is committed and
82
- * further errors propagate, so a retry can never double-emit deltas that the
83
- * consumer has already received.
141
+ * factory as long as it fails *before yielding its first chunk* — an empty
142
+ * completion that throws "No response", an error while establishing the stream,
143
+ * or (with `firstChunkTimeoutMs`) a stall before the first token. Once any chunk
144
+ * has been yielded the stream is committed and further errors propagate, so a
145
+ * retry can never double-emit deltas the consumer has already received.
84
146
  *
85
147
  * This mirrors the non-streaming path, where the provider throws on an empty
86
148
  * completion inside `withTimeoutAndRetry` and is retried on the same model
87
149
  * before the caller falls through to backup models.
88
150
  */
89
151
  async function* withStreamRetry(factory, options = {}) {
90
- const { maxRetries = 3, delay = (attempt) => Math.min(1000 * Math.pow(2, attempt), 5000), operationName = "AI stream", } = options;
152
+ const { maxRetries = 3, delay = defaultBackoff, operationName = "AI stream", firstChunkTimeoutMs, } = options;
91
153
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
154
+ // One controller per attempt: aborting it on abandon cancels the upstream
155
+ // SDK call so a retry can't stack a second concurrent stream.
156
+ const controller = new AbortController();
157
+ const iterator = factory(controller.signal);
92
158
  let yielded = false;
159
+ let completed = false;
93
160
  try {
94
- for await (const chunk of factory()) {
161
+ // Drive the iterator by hand so the first chunk can be raced against a
162
+ // deadline; for-await would give no hook for that.
163
+ for (;;) {
164
+ const result = !yielded && firstChunkTimeoutMs
165
+ ? await raceFirstChunk(iterator.next(), firstChunkTimeoutMs, operationName)
166
+ : await iterator.next();
167
+ if (result.done) {
168
+ completed = true;
169
+ return;
170
+ }
95
171
  yielded = true;
96
- yield chunk;
172
+ yield result.value;
97
173
  }
98
- return;
99
174
  }
100
175
  catch (error) {
101
176
  // Can't retry once deltas are out, and don't retry past the budget.
@@ -108,6 +183,19 @@ async function* withStreamRetry(factory, options = {}) {
108
183
  logger_1.logger.debug(`[${operationName}] Retrying in ${delayMs}ms... (attempt ${attempt + 2}/${maxRetries + 1})`);
109
184
  await new Promise((resolve) => setTimeout(resolve, delayMs));
110
185
  }
186
+ finally {
187
+ // Abandoning an attempt (first-chunk timeout, pre-yield error before a
188
+ // retry, or a consumer that breaks early): abort the upstream SDK call
189
+ // first so it's actually torn down — not left running while we retry —
190
+ // then dispose the iterator. Aborting also unblocks a stalled
191
+ // iterator.next() so return() can run the generator's cleanup. Both are
192
+ // fire-and-forget: a wedged generator's return() may never settle, so we
193
+ // must not await it.
194
+ if (!completed) {
195
+ controller.abort();
196
+ void iterator.return?.(undefined)?.catch(() => undefined);
197
+ }
198
+ }
111
199
  }
112
200
  }
113
201
  //# sourceMappingURL=retry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../src/utils/retry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../src/utils/retry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Incremental extraction of the `message` field from a streamed structured
3
+ * JSON response.
4
+ *
5
+ * Providers that enforce a JSON schema stream the raw wrapper object
6
+ * (`{"message":"Hel` → `{"message":"Hello"}`), not the message text. Without
7
+ * this, every streaming consumer has to re-implement partial-JSON unwrapping to
8
+ * recover the user-facing tokens. These helpers do it once, at the framework
9
+ * boundary, so `delta`/`accumulated` carry clean message text and the parsed
10
+ * object is surfaced only when complete.
11
+ *
12
+ * The extractor targets the top-level `message` string field specifically
13
+ * (tracking object depth and string context, so a nested decoy `"message"` key
14
+ * or a `"message"` substring inside another value is never mistaken for it),
15
+ * and is tolerant of truncation at any byte — a dangling escape sequence is
16
+ * held back rather than emitted half-decoded. Input that is not a JSON object
17
+ * (e.g. a provider streaming plain text) is passed through verbatim.
18
+ */
19
+ /**
20
+ * Extract the decoded value of the top-level `message` string field from a
21
+ * (possibly partial) JSON object string, returning the text available so far.
22
+ *
23
+ * Returns `""` while the `message` value has not begun streaming, and passes
24
+ * `accumulated` through unchanged when it is not a JSON object.
25
+ */
26
+ export declare function extractMessageSoFar(accumulated: string): string;
27
+ /**
28
+ * Stateful wrapper over {@link extractMessageSoFar} for a single stream: feed
29
+ * each chunk's accumulated JSON and get back the clean message-so-far plus the
30
+ * newly revealed delta.
31
+ *
32
+ * Each push re-scans the full accumulated buffer (O(n) per chunk, O(n²) over a
33
+ * stream) — deliberately kept simple and stateless: at LLM response sizes (KBs)
34
+ * the cost is negligible, and it avoids carrying cross-chunk parser/escape state.
35
+ */
36
+ export declare class StreamingMessageDecoder {
37
+ private previous;
38
+ /**
39
+ * @param accumulated The provider chunk's full accumulated output so far.
40
+ * @returns `message` (clean text so far) and `delta` (the new text since the
41
+ * previous push).
42
+ */
43
+ push(accumulated: string): {
44
+ message: string;
45
+ delta: string;
46
+ };
47
+ }
48
+ //# sourceMappingURL=streamingMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamingMessage.d.ts","sourceRoot":"","sources":["../../../src/utils/streamingMessage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA6HH;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAyC/D;AAED;;;;;;;;GAQG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAM;IAEtB;;;;OAIG;IACH,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;CAU9D"}
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ /**
3
+ * Incremental extraction of the `message` field from a streamed structured
4
+ * JSON response.
5
+ *
6
+ * Providers that enforce a JSON schema stream the raw wrapper object
7
+ * (`{"message":"Hel` → `{"message":"Hello"}`), not the message text. Without
8
+ * this, every streaming consumer has to re-implement partial-JSON unwrapping to
9
+ * recover the user-facing tokens. These helpers do it once, at the framework
10
+ * boundary, so `delta`/`accumulated` carry clean message text and the parsed
11
+ * object is surfaced only when complete.
12
+ *
13
+ * The extractor targets the top-level `message` string field specifically
14
+ * (tracking object depth and string context, so a nested decoy `"message"` key
15
+ * or a `"message"` substring inside another value is never mistaken for it),
16
+ * and is tolerant of truncation at any byte — a dangling escape sequence is
17
+ * held back rather than emitted half-decoded. Input that is not a JSON object
18
+ * (e.g. a provider streaming plain text) is passed through verbatim.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.StreamingMessageDecoder = void 0;
22
+ exports.extractMessageSoFar = extractMessageSoFar;
23
+ const WHITESPACE = " \t\n\r";
24
+ const ESCAPE_CHARS = {
25
+ '"': '"',
26
+ "\\": "\\",
27
+ "/": "/",
28
+ b: "\b",
29
+ f: "\f",
30
+ n: "\n",
31
+ r: "\r",
32
+ t: "\t",
33
+ };
34
+ /**
35
+ * Read a JSON string token whose opening quote is at `s[start]`. Decodes
36
+ * escapes. When the closing quote has not arrived, returns the decoded prefix
37
+ * with any trailing incomplete escape (`\` or a partial `\uXXXX`) held back, so
38
+ * a half-decoded character is never produced.
39
+ */
40
+ function readJsonString(s, start) {
41
+ let out = "";
42
+ const n = s.length;
43
+ let i = start + 1; // skip opening quote
44
+ while (i < n) {
45
+ const ch = s[i];
46
+ if (ch === '"') {
47
+ return { value: out, end: i + 1, complete: true };
48
+ }
49
+ if (ch === "\\") {
50
+ const esc = s[i + 1];
51
+ if (esc === undefined) {
52
+ // Dangling backslash — wait for the rest of the escape.
53
+ return { value: out, end: n, complete: false };
54
+ }
55
+ if (esc === "u") {
56
+ if (i + 6 > n) {
57
+ // Incomplete \uXXXX — hold it back.
58
+ return { value: out, end: n, complete: false };
59
+ }
60
+ const code = parseInt(s.slice(i + 2, i + 6), 16);
61
+ if (Number.isNaN(code)) {
62
+ return { value: out, end: n, complete: false };
63
+ }
64
+ out += String.fromCharCode(code);
65
+ i += 6;
66
+ }
67
+ else if (esc in ESCAPE_CHARS) {
68
+ out += ESCAPE_CHARS[esc];
69
+ i += 2;
70
+ }
71
+ else {
72
+ // Not a valid JSON escape; pass the character through leniently.
73
+ out += esc;
74
+ i += 2;
75
+ }
76
+ continue;
77
+ }
78
+ out += ch;
79
+ i++;
80
+ }
81
+ return { value: out, end: n, complete: false };
82
+ }
83
+ /**
84
+ * Skip one JSON value (string, object, array, or primitive) starting at `s[i]`.
85
+ * Tolerant of truncation: an unfinished value reports `complete: false`.
86
+ */
87
+ function skipJsonValue(s, i) {
88
+ const n = s.length;
89
+ if (i >= n)
90
+ return { end: n, complete: false };
91
+ const ch = s[i];
92
+ if (ch === '"') {
93
+ const r = readJsonString(s, i);
94
+ return { end: r.end, complete: r.complete };
95
+ }
96
+ if (ch === "{" || ch === "[") {
97
+ let depth = 0;
98
+ let j = i;
99
+ while (j < n) {
100
+ const c = s[j];
101
+ if (c === '"') {
102
+ const r = readJsonString(s, j);
103
+ if (!r.complete)
104
+ return { end: n, complete: false };
105
+ j = r.end;
106
+ continue;
107
+ }
108
+ if (c === "{" || c === "[")
109
+ depth++;
110
+ else if (c === "}" || c === "]") {
111
+ depth--;
112
+ if (depth === 0)
113
+ return { end: j + 1, complete: true };
114
+ }
115
+ j++;
116
+ }
117
+ return { end: n, complete: false };
118
+ }
119
+ // Primitive (number, true, false, null): runs until a structural delimiter.
120
+ // Hitting end-of-input first means it may still be streaming.
121
+ let j = i;
122
+ while (j < n && !`,}]${WHITESPACE}`.includes(s[j]))
123
+ j++;
124
+ return j < n ? { end: j, complete: true } : { end: n, complete: false };
125
+ }
126
+ /**
127
+ * Extract the decoded value of the top-level `message` string field from a
128
+ * (possibly partial) JSON object string, returning the text available so far.
129
+ *
130
+ * Returns `""` while the `message` value has not begun streaming, and passes
131
+ * `accumulated` through unchanged when it is not a JSON object.
132
+ */
133
+ function extractMessageSoFar(accumulated) {
134
+ const s = accumulated;
135
+ const n = s.length;
136
+ let i = 0;
137
+ while (i < n && WHITESPACE.includes(s[i]))
138
+ i++;
139
+ // Not a JSON object — a plain-text stream; emit verbatim.
140
+ if (i >= n || s[i] !== "{")
141
+ return accumulated;
142
+ i++; // skip '{'
143
+ while (i < n) {
144
+ while (i < n && (WHITESPACE.includes(s[i]) || s[i] === ","))
145
+ i++;
146
+ if (i >= n)
147
+ return "";
148
+ if (s[i] === "}")
149
+ return ""; // object closed without a message
150
+ if (s[i] !== '"')
151
+ return ""; // key not (fully) arrived
152
+ const key = readJsonString(s, i);
153
+ if (!key.complete)
154
+ return ""; // key still streaming
155
+ i = key.end;
156
+ while (i < n && WHITESPACE.includes(s[i]))
157
+ i++;
158
+ if (i >= n || s[i] !== ":")
159
+ return ""; // colon not arrived
160
+ i++;
161
+ while (i < n && WHITESPACE.includes(s[i]))
162
+ i++;
163
+ if (i >= n)
164
+ return "";
165
+ if (key.value === "message") {
166
+ // Found it. Only a string value yields text; null/other → no message yet.
167
+ if (s[i] !== '"')
168
+ return "";
169
+ return readJsonString(s, i).value;
170
+ }
171
+ // A field before `message`: skip its value. If it is still streaming we
172
+ // cannot have reached `message` yet.
173
+ const skipped = skipJsonValue(s, i);
174
+ if (!skipped.complete)
175
+ return "";
176
+ i = skipped.end;
177
+ }
178
+ return "";
179
+ }
180
+ /**
181
+ * Stateful wrapper over {@link extractMessageSoFar} for a single stream: feed
182
+ * each chunk's accumulated JSON and get back the clean message-so-far plus the
183
+ * newly revealed delta.
184
+ *
185
+ * Each push re-scans the full accumulated buffer (O(n) per chunk, O(n²) over a
186
+ * stream) — deliberately kept simple and stateless: at LLM response sizes (KBs)
187
+ * the cost is negligible, and it avoids carrying cross-chunk parser/escape state.
188
+ */
189
+ class StreamingMessageDecoder {
190
+ constructor() {
191
+ this.previous = "";
192
+ }
193
+ /**
194
+ * @param accumulated The provider chunk's full accumulated output so far.
195
+ * @returns `message` (clean text so far) and `delta` (the new text since the
196
+ * previous push).
197
+ */
198
+ push(accumulated) {
199
+ const message = extractMessageSoFar(accumulated);
200
+ // Decoding is monotonic (each push extends the prefix); the guard is a
201
+ // belt-and-braces reset for any non-prefix anomaly.
202
+ const delta = message.startsWith(this.previous)
203
+ ? message.slice(this.previous.length)
204
+ : message;
205
+ this.previous = message;
206
+ return { message, delta };
207
+ }
208
+ }
209
+ exports.StreamingMessageDecoder = StreamingMessageDecoder;
210
+ //# sourceMappingURL=streamingMessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamingMessage.js","sourceRoot":"","sources":["../../../src/utils/streamingMessage.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FlowRouter.d.ts","sourceRoot":"","sources":["../../src/core/FlowRouter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FlowRouter.d.ts","sourceRoot":"","sources":["../../src/core/FlowRouter.ts"],"names":[],"mappings":"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"}
@@ -198,17 +198,6 @@ export class FlowRouter {
198
198
  };
199
199
  }
200
200
  }
201
- // No candidates means flow has no valid next steps (edge case)
202
- if (candidates.length === 0) {
203
- logger.debug(`[FlowRouter] Single-flow: No valid candidate steps found`);
204
- return {
205
- selectedFlow,
206
- selectedStep: undefined,
207
- session: updatedSession,
208
- isFlowComplete: false,
209
- completedFlows,
210
- };
211
- }
212
201
  // Multiple candidates - use AI to select best step
213
202
  const lastUserMessage = getLastMessageFromHistory(history);
214
203
  // Collect AI context strings from step conditions