@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/README.md +59 -16
- package/dist/cli.js +338 -116
- package/dist/cli.js.map +1 -1
- package/docs/background-agents.md +4 -0
- package/package.json +1 -1
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.
|
|
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 =
|
|
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
|
|
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
|
-
|
|
10934
|
-
|
|
10935
|
-
reportedValues.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
10956
|
-
`clamping ${UPSTREAM_MAX_RETRIES_ENV}=${
|
|
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
|
|
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 =
|
|
10967
|
-
if (explicit !== void 0)
|
|
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
|
|
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
|
-
|
|
11577
|
-
|
|
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(
|
|
11582
|
-
|
|
11734
|
+
() => idleAbort.abort(attempts.deadlineError(
|
|
11735
|
+
new Error(`provider stream exceeded ${Math.round(totalTimeoutMs / 1e3)}s`)
|
|
11736
|
+
)),
|
|
11737
|
+
totalTimeoutMs
|
|
11583
11738
|
);
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11595
|
-
|
|
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
|
-
}
|
|
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
|
|
11627
|
-
|
|
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(
|
|
11633
|
-
|
|
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(
|
|
11690
|
-
|
|
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
|
|
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
|
-
|
|
16676
|
-
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
|
|
16680
|
-
|
|
16681
|
-
|
|
16682
|
-
|
|
16683
|
-
|
|
16684
|
-
|
|
16685
|
-
|
|
16686
|
-
|
|
16687
|
-
|
|
16688
|
-
|
|
16689
|
-
|
|
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
|
|
16716
|
-
|
|
16717
|
-
|
|
16718
|
-
|
|
16719
|
-
|
|
16720
|
-
|
|
16721
|
-
|
|
16722
|
-
|
|
16723
|
-
|
|
16724
|
-
|
|
16725
|
-
|
|
16726
|
-
|
|
16727
|
-
|
|
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
|
-
|
|
16731
|
-
|
|
16732
|
-
|
|
16733
|
-
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
|
|
16737
|
-
|
|
16738
|
-
|
|
16739
|
-
|
|
16740
|
-
|
|
16741
|
-
|
|
16742
|
-
|
|
16743
|
-
|
|
16744
|
-
|
|
16745
|
-
|
|
16746
|
-
|
|
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
|