@bman654/clodex 2.8.5 → 2.9.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.
package/dist/cli.js CHANGED
@@ -382,7 +382,7 @@ import { join } from "path";
382
382
  // package.json
383
383
  var package_default = {
384
384
  name: "@bman654/clodex",
385
- version: "2.8.5",
385
+ version: "2.9.0",
386
386
  publishConfig: {
387
387
  access: "public"
388
388
  },
@@ -3423,7 +3423,7 @@ function savedStopsAfter(current, assignments) {
3423
3423
  }
3424
3424
 
3425
3425
  // src/patch-transforms.ts
3426
- var PATCH_TRANSFORMS_VERSION = 11;
3426
+ var PATCH_TRANSFORMS_VERSION = 12;
3427
3427
  var NATIVE_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
3428
3428
  var BASE_EFFORT_LEVELS = ["low", "medium", "high"];
3429
3429
  function projectNativeEffort(effort) {
@@ -3812,7 +3812,7 @@ function applyClodexPatches(source, config) {
3812
3812
  }
3813
3813
  applyOnce(
3814
3814
  patchName,
3815
- /(function [\w$]+\(\)\{)(let (?:[^;{}]|\{[^;{}]*\})*?[\w$]+\(process\.env\.CLAUDE_CODE_REMOTE\)\?(?:(?!\}\s*function )[\s\S])*?\)return process\.env;let ([\w$]+)=\{(?:(?!\}\s*function )[\s\S])*?return \3)(\})/,
3815
+ /(function [\w$]+\(\)\{)(let[ {[](?:[^;{}]|\{[^;{}]*\})*?(?:\{[^;{}]*)?(?:getAgentProxyEnv|[\w$]+\(process\.env\.CLAUDE_CODE_REMOTE\)\?)(?:(?!\}\s*function )[\s\S])*?\)return process\.env;let ([\w$]+)=\{(?:(?!\}\s*function )[\s\S])*?return \3)(\})/,
3816
3816
  (match, head, body, _copyVar, tail) => {
3817
3817
  const at = js.indexOf(match);
3818
3818
  const closingBrace = at < 0 ? -1 : blockEndIndex(js, at + head.length - 1);
@@ -10928,43 +10928,152 @@ function resolveUpstreamTools(tools, messages) {
10928
10928
 
10929
10929
  // src/upstream-retry.ts
10930
10930
  var UPSTREAM_MAX_RETRIES_ENV = "CLODEX_UPSTREAM_MAX_RETRIES";
10931
- var MAX_UPSTREAM_MAX_RETRIES = 5;
10931
+ var UPSTREAM_IDLE_TIMEOUT_ENV = "CLODEX_UPSTREAM_IDLE_TIMEOUT_MS";
10932
+ var UPSTREAM_TOTAL_TIMEOUT_ENV = "CLODEX_UPSTREAM_TOTAL_TIMEOUT_MS";
10933
+ var DEFAULT_UPSTREAM_IDLE_TIMEOUT_MS = 12e4;
10934
+ var DEFAULT_UPSTREAM_TOTAL_TIMEOUT_MS = 10 * 6e4;
10935
+ var MIN_UPSTREAM_IDLE_TIMEOUT_MS = 1e4;
10936
+ var MAX_UPSTREAM_IDLE_TIMEOUT_MS = 60 * 6e4;
10937
+ var MIN_UPSTREAM_TOTAL_TIMEOUT_MS = 6e4;
10938
+ var MAX_UPSTREAM_TOTAL_TIMEOUT_MS = 6 * 60 * 6e4;
10939
+ var SDK_INITIAL_RETRY_DELAY_MS = 2e3;
10932
10940
  var reportedValues = /* @__PURE__ */ new Set();
10933
- function reportOnce(raw, message, warn) {
10934
- if (reportedValues.has(raw)) return;
10935
- reportedValues.add(raw);
10941
+ var defaultWarn = (message) => emitParentNotice(`clodex: ${message}`);
10942
+ function reportOnce(key, message, warn) {
10943
+ if (reportedValues.has(key)) return;
10944
+ reportedValues.add(key);
10936
10945
  try {
10937
10946
  warn(message);
10938
10947
  } catch {
10939
10948
  }
10940
10949
  }
10941
- function upstreamMaxRetries(env = process.env, warn = (message) => emitParentNotice(`clodex: ${message}`)) {
10950
+ function timeoutSetting(env, envName, fallback, min, max, warn) {
10951
+ const raw = env[envName]?.trim();
10952
+ if (raw === void 0 || raw === "") return { value: fallback, explicit: false };
10953
+ const value = Number(raw);
10954
+ if (!Number.isInteger(value) || value <= 0) {
10955
+ reportOnce(
10956
+ `${envName}=${raw}`,
10957
+ `ignoring ${envName}=${raw} (expected a positive integer number of milliseconds)`,
10958
+ warn
10959
+ );
10960
+ return { value: fallback, explicit: false };
10961
+ }
10962
+ if (value < min || value > max) {
10963
+ const clamped = Math.min(max, Math.max(min, value));
10964
+ reportOnce(
10965
+ `${envName}=${raw}`,
10966
+ `clamping ${envName}=${raw} to ${clamped}ms (supported range is ${min}-${max}ms)`,
10967
+ warn
10968
+ );
10969
+ return { value: clamped, explicit: true };
10970
+ }
10971
+ return { value, explicit: true };
10972
+ }
10973
+ function maxRetriesForIdleTimeout(idleTimeoutMs) {
10974
+ let retries = 0;
10975
+ let elapsedMs = 0;
10976
+ let delayMs = SDK_INITIAL_RETRY_DELAY_MS;
10977
+ while (elapsedMs + delayMs < idleTimeoutMs) {
10978
+ elapsedMs += delayMs;
10979
+ delayMs *= 2;
10980
+ retries += 1;
10981
+ }
10982
+ return retries;
10983
+ }
10984
+ var MAX_UPSTREAM_MAX_RETRIES = maxRetriesForIdleTimeout(
10985
+ DEFAULT_UPSTREAM_IDLE_TIMEOUT_MS
10986
+ );
10987
+ var DEFAULT_UPSTREAM_MAX_RETRIES = MAX_UPSTREAM_MAX_RETRIES;
10988
+ function configuredUpstreamMaxRetries(env, warn) {
10942
10989
  const raw = env[UPSTREAM_MAX_RETRIES_ENV]?.trim();
10943
10990
  if (raw === void 0 || raw === "") return void 0;
10944
10991
  const value = Number(raw);
10945
10992
  if (!Number.isInteger(value) || value < 0) {
10946
10993
  reportOnce(
10947
- raw,
10994
+ `${UPSTREAM_MAX_RETRIES_ENV}=${raw}`,
10948
10995
  `ignoring ${UPSTREAM_MAX_RETRIES_ENV}=${raw} (expected a non-negative integer)`,
10949
10996
  warn
10950
10997
  );
10951
10998
  return void 0;
10952
10999
  }
10953
- if (value > MAX_UPSTREAM_MAX_RETRIES) {
11000
+ return value;
11001
+ }
11002
+ function resolveUpstreamMaxRetries(env, warn, idleTimeoutMs) {
11003
+ const ceiling = maxRetriesForIdleTimeout(idleTimeoutMs);
11004
+ const defaultRetries = Math.min(DEFAULT_UPSTREAM_MAX_RETRIES, ceiling);
11005
+ const value = configuredUpstreamMaxRetries(env, warn);
11006
+ if (value === void 0) return defaultRetries;
11007
+ if (value > ceiling) {
10954
11008
  reportOnce(
10955
- raw,
10956
- `clamping ${UPSTREAM_MAX_RETRIES_ENV}=${raw} to ${MAX_UPSTREAM_MAX_RETRIES} (higher values exceed the 120s streaming idle budget)`,
11009
+ `${UPSTREAM_MAX_RETRIES_ENV}=${value}:idle=${idleTimeoutMs}`,
11010
+ `clamping ${UPSTREAM_MAX_RETRIES_ENV}=${value} to ${ceiling} (estimated from the SDK fallback backoff and resolved ${idleTimeoutMs}ms idle timeout; provider delays may allow fewer retries)`,
10957
11011
  warn
10958
11012
  );
10959
- return MAX_UPSTREAM_MAX_RETRIES;
11013
+ return ceiling;
10960
11014
  }
10961
11015
  return value;
10962
11016
  }
11017
+ function upstreamRequestBudget(options = {}) {
11018
+ const env = options.env ?? process.env;
11019
+ const warn = options.warn ?? defaultWarn;
11020
+ const hasIdleOverride = options.idleTimeoutMs !== void 0;
11021
+ const configuredIdle = options.idleTimeoutMs !== void 0 ? { value: options.idleTimeoutMs, explicit: false } : timeoutSetting(
11022
+ env,
11023
+ UPSTREAM_IDLE_TIMEOUT_ENV,
11024
+ DEFAULT_UPSTREAM_IDLE_TIMEOUT_MS,
11025
+ MIN_UPSTREAM_IDLE_TIMEOUT_MS,
11026
+ MAX_UPSTREAM_IDLE_TIMEOUT_MS,
11027
+ warn
11028
+ );
11029
+ const configuredTotal = timeoutSetting(
11030
+ env,
11031
+ UPSTREAM_TOTAL_TIMEOUT_ENV,
11032
+ DEFAULT_UPSTREAM_TOTAL_TIMEOUT_MS,
11033
+ MIN_UPSTREAM_TOTAL_TIMEOUT_MS,
11034
+ MAX_UPSTREAM_TOTAL_TIMEOUT_MS,
11035
+ warn
11036
+ );
11037
+ let idleTimeoutMs = configuredIdle.value;
11038
+ let totalTimeoutMs = configuredTotal.value;
11039
+ if (totalTimeoutMs < idleTimeoutMs) {
11040
+ if (hasIdleOverride) {
11041
+ idleTimeoutMs = totalTimeoutMs;
11042
+ } else if (configuredIdle.explicit && !configuredTotal.explicit) {
11043
+ reportOnce(
11044
+ `timeout-pair:raise-total:${idleTimeoutMs}:${totalTimeoutMs}`,
11045
+ `raising the resolved total timeout from ${totalTimeoutMs}ms to ${idleTimeoutMs}ms so it is not shorter than ${UPSTREAM_IDLE_TIMEOUT_ENV}`,
11046
+ warn
11047
+ );
11048
+ totalTimeoutMs = idleTimeoutMs;
11049
+ } else {
11050
+ reportOnce(
11051
+ `timeout-pair:lower-idle:${idleTimeoutMs}:${totalTimeoutMs}`,
11052
+ `lowering the resolved idle timeout from ${idleTimeoutMs}ms to ${totalTimeoutMs}ms because it cannot exceed ${UPSTREAM_TOTAL_TIMEOUT_ENV}`,
11053
+ warn
11054
+ );
11055
+ idleTimeoutMs = totalTimeoutMs;
11056
+ }
11057
+ }
11058
+ return {
11059
+ idleTimeoutMs,
11060
+ totalTimeoutMs,
11061
+ maxRetries: resolveUpstreamMaxRetries(env, warn, idleTimeoutMs)
11062
+ };
11063
+ }
10963
11064
  var CLIENT_MAX_RETRIES_ENV = "CLAUDE_CODE_MAX_RETRIES";
10964
11065
  var DEFAULT_PASSTHROUGH_RETRIES = 1;
10965
- function passthroughUpstreamRetries(env = process.env) {
10966
- const explicit = upstreamMaxRetries(env);
10967
- if (explicit !== void 0) return explicit;
11066
+ function passthroughUpstreamRetries(env = process.env, warn = defaultWarn) {
11067
+ const explicit = configuredUpstreamMaxRetries(env, warn);
11068
+ if (explicit !== void 0) {
11069
+ if (explicit <= MAX_UPSTREAM_MAX_RETRIES) return explicit;
11070
+ reportOnce(
11071
+ `${UPSTREAM_MAX_RETRIES_ENV}=${explicit}:passthrough`,
11072
+ `clamping ${UPSTREAM_MAX_RETRIES_ENV}=${explicit} to ${MAX_UPSTREAM_MAX_RETRIES} (the raw HTTP MITM path supports at most this many replays)`,
11073
+ warn
11074
+ );
11075
+ return MAX_UPSTREAM_MAX_RETRIES;
11076
+ }
10968
11077
  const raw = env[CLIENT_MAX_RETRIES_ENV]?.trim();
10969
11078
  if (raw !== void 0 && raw !== "") {
10970
11079
  const clientRetries = Number(raw);
@@ -10973,6 +11082,49 @@ function passthroughUpstreamRetries(env = process.env) {
10973
11082
  return DEFAULT_PASSTHROUGH_RETRIES;
10974
11083
  }
10975
11084
 
11085
+ // src/upstream-attempts.ts
11086
+ import { RetryError as RetryError2, wrapLanguageModel as wrapLanguageModel2 } from "ai";
11087
+ function trackUpstreamAttempts(model) {
11088
+ if (typeof model === "string") {
11089
+ return { model, deadlineError: (timeoutError) => timeoutError };
11090
+ }
11091
+ const failedAttempts = [];
11092
+ let waitingToRetry = false;
11093
+ const track = async (call) => {
11094
+ waitingToRetry = false;
11095
+ try {
11096
+ const result = await call();
11097
+ failedAttempts.length = 0;
11098
+ return result;
11099
+ } catch (error) {
11100
+ failedAttempts.push(error);
11101
+ waitingToRetry = true;
11102
+ throw error;
11103
+ }
11104
+ };
11105
+ const middleware = {
11106
+ specificationVersion: "v4",
11107
+ wrapGenerate: ({ doGenerate }) => track(doGenerate),
11108
+ wrapStream: ({ doStream }) => track(doStream)
11109
+ };
11110
+ return {
11111
+ model: wrapLanguageModel2({ model, middleware }),
11112
+ deadlineError: (timeoutError) => {
11113
+ if (!waitingToRetry || failedAttempts.length === 0) return timeoutError;
11114
+ const count = failedAttempts.length;
11115
+ return new RetryError2({
11116
+ message: [
11117
+ "Provider retry interrupted by a request deadline after",
11118
+ count,
11119
+ `failed ${count === 1 ? "attempt" : "attempts"}`
11120
+ ].join(" "),
11121
+ reason: "abort",
11122
+ errors: [...failedAttempts]
11123
+ });
11124
+ }
11125
+ };
11126
+ }
11127
+
10976
11128
  // src/sdk-adapter.ts
10977
11129
  function sdkTranslationErrorSignature(error) {
10978
11130
  const message = error instanceof Error ? error.message : typeof error === "string" ? error : void 0;
@@ -11347,8 +11499,6 @@ function toAnthropicUsage(u) {
11347
11499
  cache_read_input_tokens: cacheRead
11348
11500
  };
11349
11501
  }
11350
- var SDK_STREAM_IDLE_TIMEOUT_MS = 12e4;
11351
- var SDK_TOTAL_TIMEOUT_MS = 10 * 6e4;
11352
11502
  function streamAbortError(signal) {
11353
11503
  if (signal?.reason instanceof Error) return signal.reason;
11354
11504
  const error = new Error(
@@ -11569,42 +11719,44 @@ async function writeAnthropicStream(stream, modelId, write, log12, observer, too
11569
11719
  emit("message_stop", { type: "message_stop" });
11570
11720
  }
11571
11721
  async function streamAnthropicResponse(model, params, modelId, write, log12, observer) {
11572
- const idleTimeoutMs = observer?.idleTimeoutMs ?? SDK_STREAM_IDLE_TIMEOUT_MS;
11722
+ const { idleTimeoutMs, totalTimeoutMs, maxRetries } = upstreamRequestBudget({
11723
+ idleTimeoutMs: observer?.idleTimeoutMs
11724
+ });
11725
+ const attempts = trackUpstreamAttempts(model);
11573
11726
  const idleAbort = new AbortController();
11574
11727
  const stopForwardingAbort = forwardAbortSignal(observer?.abortSignal, idleAbort);
11575
11728
  const abortSignal = idleAbort.signal;
11576
- let idleTimer = setTimeout(
11577
- () => idleAbort.abort(new Error(`no data received from provider for ${Math.round(idleTimeoutMs / 1e3)}s`)),
11578
- idleTimeoutMs
11729
+ const idleError = () => attempts.deadlineError(
11730
+ new Error(`no data received from provider for ${Math.round(idleTimeoutMs / 1e3)}s`)
11579
11731
  );
11732
+ let idleTimer = setTimeout(() => idleAbort.abort(idleError()), idleTimeoutMs);
11580
11733
  const totalTimer = setTimeout(
11581
- () => idleAbort.abort(new Error(`provider stream exceeded ${Math.round(SDK_TOTAL_TIMEOUT_MS / 1e3)}s`)),
11582
- SDK_TOTAL_TIMEOUT_MS
11734
+ () => idleAbort.abort(attempts.deadlineError(
11735
+ new Error(`provider stream exceeded ${Math.round(totalTimeoutMs / 1e3)}s`)
11736
+ )),
11737
+ totalTimeoutMs
11583
11738
  );
11584
- const result = streamText({
11585
- model,
11586
- ...params,
11587
- maxRetries: upstreamMaxRetries(),
11588
- abortSignal,
11589
- onError: () => {
11590
- },
11591
- onStepFinish: (step) => reportUnsupportedServiceTier(params, step.warnings)
11592
- });
11593
- const watchedStream = (async function* () {
11594
- try {
11595
- for await (const part of result.stream) {
11739
+ try {
11740
+ const result = streamText({
11741
+ model: attempts.model,
11742
+ ...params,
11743
+ maxRetries,
11744
+ abortSignal,
11745
+ onError: () => {
11746
+ },
11747
+ onStepFinish: (step) => reportUnsupportedServiceTier(params, step.warnings)
11748
+ });
11749
+ const watchedStream = (async function* () {
11750
+ try {
11751
+ for await (const part of result.stream) {
11752
+ clearTimeout(idleTimer);
11753
+ idleTimer = setTimeout(() => idleAbort.abort(idleError()), idleTimeoutMs);
11754
+ yield part;
11755
+ }
11756
+ } finally {
11596
11757
  clearTimeout(idleTimer);
11597
- idleTimer = setTimeout(
11598
- () => idleAbort.abort(new Error(`no data received from provider for ${Math.round(idleTimeoutMs / 1e3)}s`)),
11599
- idleTimeoutMs
11600
- );
11601
- yield part;
11602
11758
  }
11603
- } finally {
11604
- clearTimeout(idleTimer);
11605
- }
11606
- })();
11607
- try {
11759
+ })();
11608
11760
  await writeAnthropicStream(watchedStream, modelId, write, log12, { ...observer, abortSignal }, params.tools);
11609
11761
  } finally {
11610
11762
  stopForwardingAbort();
@@ -11619,39 +11771,41 @@ async function generateAnthropicResponse(model, params, modelId, options) {
11619
11771
  let finishReason;
11620
11772
  let usage;
11621
11773
  let warnings;
11774
+ const { idleTimeoutMs, totalTimeoutMs, maxRetries } = upstreamRequestBudget({
11775
+ idleTimeoutMs: options?.forceStream ? options.idleTimeoutMs : void 0
11776
+ });
11777
+ const attempts = trackUpstreamAttempts(model);
11622
11778
  if (options?.forceStream) {
11623
11779
  const forceAbort = new AbortController();
11624
11780
  const stopForwardingAbort = forwardAbortSignal(options.abortSignal, forceAbort);
11625
11781
  const abortSignal = forceAbort.signal;
11626
- const idleTimeoutMs = options.idleTimeoutMs ?? SDK_STREAM_IDLE_TIMEOUT_MS;
11627
- let idleTimer = setTimeout(
11628
- () => forceAbort.abort(new Error(`no data received from provider for ${Math.round(idleTimeoutMs / 1e3)}s`)),
11629
- idleTimeoutMs
11782
+ const idleError = () => attempts.deadlineError(
11783
+ new Error(`no data received from provider for ${Math.round(idleTimeoutMs / 1e3)}s`)
11630
11784
  );
11785
+ let idleTimer = setTimeout(() => forceAbort.abort(idleError()), idleTimeoutMs);
11631
11786
  const totalTimer = setTimeout(
11632
- () => forceAbort.abort(new Error(`provider stream exceeded ${Math.round(SDK_TOTAL_TIMEOUT_MS / 1e3)}s`)),
11633
- SDK_TOTAL_TIMEOUT_MS
11787
+ () => forceAbort.abort(attempts.deadlineError(
11788
+ new Error(`provider stream exceeded ${Math.round(totalTimeoutMs / 1e3)}s`)
11789
+ )),
11790
+ totalTimeoutMs
11634
11791
  );
11635
- const r = streamText({
11636
- model,
11637
- ...params,
11638
- maxRetries: upstreamMaxRetries(),
11639
- abortSignal,
11640
- onError: () => {
11641
- },
11642
- onStepFinish: (step) => reportUnsupportedServiceTier(params, step.warnings)
11643
- });
11644
11792
  const streamedText = [];
11645
11793
  const streamedToolCalls = [];
11646
11794
  let streamedFinishReason = "stop";
11647
11795
  let streamedUsage;
11648
11796
  try {
11797
+ const r = streamText({
11798
+ model: attempts.model,
11799
+ ...params,
11800
+ maxRetries,
11801
+ abortSignal,
11802
+ onError: () => {
11803
+ },
11804
+ onStepFinish: (step) => reportUnsupportedServiceTier(params, step.warnings)
11805
+ });
11649
11806
  for await (const part of r.stream) {
11650
11807
  clearTimeout(idleTimer);
11651
- idleTimer = setTimeout(
11652
- () => forceAbort.abort(new Error(`no data received from provider for ${Math.round(idleTimeoutMs / 1e3)}s`)),
11653
- idleTimeoutMs
11654
- );
11808
+ idleTimer = setTimeout(() => forceAbort.abort(idleError()), idleTimeoutMs);
11655
11809
  options.onPart?.(part.type);
11656
11810
  if (abortSignal.aborted || part.type === "abort") {
11657
11811
  throw streamAbortError(abortSignal);
@@ -11686,17 +11840,22 @@ async function generateAnthropicResponse(model, params, modelId, options) {
11686
11840
  const generateAbort = new AbortController();
11687
11841
  const stopForwardingAbort = forwardAbortSignal(options?.abortSignal, generateAbort);
11688
11842
  const totalTimer = setTimeout(
11689
- () => generateAbort.abort(new Error(`provider request exceeded ${Math.round(SDK_TOTAL_TIMEOUT_MS / 1e3)}s`)),
11690
- SDK_TOTAL_TIMEOUT_MS
11843
+ () => generateAbort.abort(attempts.deadlineError(
11844
+ new Error(`provider request exceeded ${Math.round(totalTimeoutMs / 1e3)}s`)
11845
+ )),
11846
+ totalTimeoutMs
11691
11847
  );
11692
11848
  try {
11693
11849
  const r = await generateText({
11694
- model,
11850
+ model: attempts.model,
11695
11851
  ...params,
11696
- maxRetries: upstreamMaxRetries(),
11852
+ maxRetries,
11697
11853
  abortSignal: generateAbort.signal
11698
11854
  });
11699
11855
  ({ text: text5, toolCalls, finishReason, usage, warnings } = r);
11856
+ } catch (error) {
11857
+ if (generateAbort.signal.aborted) throw streamAbortError(generateAbort.signal);
11858
+ throw error;
11700
11859
  } finally {
11701
11860
  stopForwardingAbort();
11702
11861
  clearTimeout(totalTimer);
@@ -16670,24 +16829,81 @@ async function collectOpenAiStream(stream) {
16670
16829
  }
16671
16830
  return collected;
16672
16831
  }
16832
+ function startUpstreamBudget(model, streaming) {
16833
+ const { idleTimeoutMs, totalTimeoutMs, maxRetries } = upstreamRequestBudget();
16834
+ const attempts = trackUpstreamAttempts(model);
16835
+ const abort = new AbortController();
16836
+ const idleError = () => attempts.deadlineError(new Error(
16837
+ `no data received from provider for ${Math.round(idleTimeoutMs / 1e3)}s`
16838
+ ));
16839
+ let idleTimer = streaming ? setTimeout(() => abort.abort(idleError()), idleTimeoutMs) : void 0;
16840
+ const totalTimer = setTimeout(
16841
+ () => abort.abort(attempts.deadlineError(new Error(
16842
+ `provider ${streaming ? "stream" : "request"} exceeded ${Math.round(totalTimeoutMs / 1e3)}s`
16843
+ ))),
16844
+ totalTimeoutMs
16845
+ );
16846
+ return {
16847
+ model: attempts.model,
16848
+ maxRetries,
16849
+ abortSignal: abort.signal,
16850
+ onStreamPart: () => {
16851
+ if (idleTimer === void 0) return;
16852
+ clearTimeout(idleTimer);
16853
+ idleTimer = setTimeout(() => abort.abort(idleError()), idleTimeoutMs);
16854
+ },
16855
+ close: () => {
16856
+ if (idleTimer !== void 0) clearTimeout(idleTimer);
16857
+ clearTimeout(totalTimer);
16858
+ if (!abort.signal.aborted) abort.abort();
16859
+ }
16860
+ };
16861
+ }
16862
+ async function* watchOpenAiStream(stream, budget) {
16863
+ for await (const part of stream) {
16864
+ if (budget.abortSignal.aborted || part.type === "abort") {
16865
+ throw budget.abortSignal.reason instanceof Error ? budget.abortSignal.reason : new Error("SDK stream aborted");
16866
+ }
16867
+ budget.onStreamPart();
16868
+ yield part;
16869
+ }
16870
+ if (budget.abortSignal.aborted) {
16871
+ throw budget.abortSignal.reason instanceof Error ? budget.abortSignal.reason : new Error("SDK stream aborted");
16872
+ }
16873
+ }
16673
16874
  async function generateOpenAiResponse(model, params, responseModelId, options) {
16674
16875
  let result;
16675
- if (options?.forceStream) {
16676
- const { stream } = streamText2({
16677
- model,
16678
- ...params,
16679
- maxRetries: upstreamMaxRetries(),
16680
- onError: () => {
16681
- },
16682
- onStepFinish: (step) => reportUnsupportedServiceTier(params, step.warnings)
16683
- });
16684
- result = await collectOpenAiStream(stream);
16685
- } else {
16686
- result = await generateText2({
16687
- model,
16688
- ...params,
16689
- maxRetries: upstreamMaxRetries()
16690
- });
16876
+ const streaming = options?.forceStream === true;
16877
+ const budget = startUpstreamBudget(model, streaming);
16878
+ try {
16879
+ if (streaming) {
16880
+ const { stream } = streamText2({
16881
+ model: budget.model,
16882
+ ...params,
16883
+ maxRetries: budget.maxRetries,
16884
+ abortSignal: budget.abortSignal,
16885
+ onError: () => {
16886
+ },
16887
+ onStepFinish: (step) => reportUnsupportedServiceTier(params, step.warnings)
16888
+ });
16889
+ result = await collectOpenAiStream(watchOpenAiStream(stream, budget));
16890
+ } else {
16891
+ try {
16892
+ result = await generateText2({
16893
+ model: budget.model,
16894
+ ...params,
16895
+ maxRetries: budget.maxRetries,
16896
+ abortSignal: budget.abortSignal
16897
+ });
16898
+ } catch (error) {
16899
+ if (budget.abortSignal.aborted && budget.abortSignal.reason instanceof Error) {
16900
+ throw budget.abortSignal.reason;
16901
+ }
16902
+ throw error;
16903
+ }
16904
+ }
16905
+ } finally {
16906
+ budget.close();
16691
16907
  }
16692
16908
  reportUnsupportedServiceTier(params, result.warnings);
16693
16909
  const message = { role: "assistant", content: result.text || null };
@@ -16712,41 +16928,47 @@ async function generateOpenAiResponse(model, params, responseModelId, options) {
16712
16928
  };
16713
16929
  }
16714
16930
  async function streamOpenAiResponse(model, params, responseModelId, onChunk) {
16715
- const { stream } = streamText2({
16716
- model,
16717
- ...params,
16718
- maxRetries: upstreamMaxRetries(),
16719
- onStepFinish: (step) => reportUnsupportedServiceTier(params, step.warnings)
16720
- });
16721
- const baseData = {
16722
- id: `chatcmpl-${Date.now()}`,
16723
- object: "chat.completion.chunk",
16724
- created: Math.floor(Date.now() / 1e3),
16725
- model: responseModelId
16726
- };
16727
- const send = (delta, finish_reason = null) => onChunk(`data: ${JSON.stringify({ ...baseData, choices: [{ index: 0, delta, finish_reason }] })}
16931
+ const budget = startUpstreamBudget(model, true);
16932
+ try {
16933
+ const { stream } = streamText2({
16934
+ model: budget.model,
16935
+ ...params,
16936
+ maxRetries: budget.maxRetries,
16937
+ abortSignal: budget.abortSignal,
16938
+ onStepFinish: (step) => reportUnsupportedServiceTier(params, step.warnings)
16939
+ });
16940
+ const baseData = {
16941
+ id: `chatcmpl-${Date.now()}`,
16942
+ object: "chat.completion.chunk",
16943
+ created: Math.floor(Date.now() / 1e3),
16944
+ model: responseModelId
16945
+ };
16946
+ const send = (delta, finish_reason = null) => onChunk(`data: ${JSON.stringify({ ...baseData, choices: [{ index: 0, delta, finish_reason }] })}
16728
16947
 
16729
16948
  `);
16730
- for await (const part of stream) {
16731
- const p13 = part;
16732
- switch (p13.type) {
16733
- case "text-delta":
16734
- send({ role: "assistant", content: p13.textDelta ?? p13.text ?? "" });
16735
- break;
16736
- case "tool-input-start":
16737
- send({ role: "assistant", tool_calls: [{ index: 0, id: p13.id ?? p13.toolCallId, type: "function", function: { name: p13.toolName, arguments: "" } }] });
16738
- break;
16739
- case "tool-input-delta":
16740
- send({ tool_calls: [{ index: 0, function: { arguments: p13.delta ?? p13.text ?? p13.argsTextDelta ?? "" } }] });
16741
- break;
16742
- case "finish":
16743
- send({}, p13.finishReason || "stop");
16744
- break;
16745
- case "error":
16746
- throw p13.error instanceof Error || p13.error && typeof p13.error === "object" ? p13.error : new Error(typeof p13.error === "string" ? p13.error : "Upstream stream failed");
16949
+ for await (const part of watchOpenAiStream(stream, budget)) {
16950
+ const p13 = part;
16951
+ switch (p13.type) {
16952
+ case "text-delta":
16953
+ send({ role: "assistant", content: p13.textDelta ?? p13.text ?? "" });
16954
+ break;
16955
+ case "tool-input-start":
16956
+ send({ role: "assistant", tool_calls: [{ index: 0, id: p13.id ?? p13.toolCallId, type: "function", function: { name: p13.toolName, arguments: "" } }] });
16957
+ break;
16958
+ case "tool-input-delta":
16959
+ send({ tool_calls: [{ index: 0, function: { arguments: p13.delta ?? p13.text ?? p13.argsTextDelta ?? "" } }] });
16960
+ break;
16961
+ case "finish":
16962
+ send({}, p13.finishReason || "stop");
16963
+ break;
16964
+ case "error":
16965
+ throw p13.error instanceof Error || p13.error && typeof p13.error === "object" ? p13.error : new Error(typeof p13.error === "string" ? p13.error : "Upstream stream failed");
16966
+ }
16747
16967
  }
16968
+ onChunk("data: [DONE]\n\n");
16969
+ } finally {
16970
+ budget.close();
16748
16971
  }
16749
- onChunk("data: [DONE]\n\n");
16750
16972
  }
16751
16973
 
16752
16974
  // src/server/router.ts