@jaypie/llm 1.2.10 → 1.2.12
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/cjs/index.cjs +98 -37
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/operate/adapters/AnthropicAdapter.d.ts +2 -2
- package/dist/cjs/operate/adapters/GeminiAdapter.d.ts +2 -2
- package/dist/cjs/operate/adapters/OpenAiAdapter.d.ts +2 -2
- package/dist/cjs/operate/adapters/OpenRouterAdapter.d.ts +2 -2
- package/dist/cjs/operate/adapters/ProviderAdapter.interface.d.ts +5 -3
- package/dist/cjs/operate/retry/RetryExecutor.d.ts +6 -3
- package/dist/esm/index.js +98 -37
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/operate/adapters/AnthropicAdapter.d.ts +2 -2
- package/dist/esm/operate/adapters/GeminiAdapter.d.ts +2 -2
- package/dist/esm/operate/adapters/OpenAiAdapter.d.ts +2 -2
- package/dist/esm/operate/adapters/OpenRouterAdapter.d.ts +2 -2
- package/dist/esm/operate/adapters/ProviderAdapter.interface.d.ts +5 -3
- package/dist/esm/operate/retry/RetryExecutor.d.ts +6 -3
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -1128,17 +1128,24 @@ class AnthropicAdapter extends BaseProviderAdapter {
|
|
|
1128
1128
|
//
|
|
1129
1129
|
// API Execution
|
|
1130
1130
|
//
|
|
1131
|
-
async executeRequest(client, request) {
|
|
1131
|
+
async executeRequest(client, request, signal) {
|
|
1132
1132
|
const anthropic = client;
|
|
1133
|
-
|
|
1133
|
+
try {
|
|
1134
|
+
return (await anthropic.messages.create(request, signal ? { signal } : undefined));
|
|
1135
|
+
}
|
|
1136
|
+
catch (error) {
|
|
1137
|
+
if (signal?.aborted)
|
|
1138
|
+
return undefined;
|
|
1139
|
+
throw error;
|
|
1140
|
+
}
|
|
1134
1141
|
}
|
|
1135
|
-
async *executeStreamRequest(client, request) {
|
|
1142
|
+
async *executeStreamRequest(client, request, signal) {
|
|
1136
1143
|
const anthropic = client;
|
|
1137
1144
|
const streamRequest = {
|
|
1138
1145
|
...request,
|
|
1139
1146
|
stream: true,
|
|
1140
1147
|
};
|
|
1141
|
-
const stream = await anthropic.messages.create(streamRequest);
|
|
1148
|
+
const stream = await anthropic.messages.create(streamRequest, signal ? { signal } : undefined);
|
|
1142
1149
|
// Track current tool call being built
|
|
1143
1150
|
let currentToolCall = null;
|
|
1144
1151
|
// Track usage for final chunk
|
|
@@ -1568,19 +1575,26 @@ class GeminiAdapter extends BaseProviderAdapter {
|
|
|
1568
1575
|
//
|
|
1569
1576
|
// API Execution
|
|
1570
1577
|
//
|
|
1571
|
-
async executeRequest(client, request) {
|
|
1578
|
+
async executeRequest(client, request, signal) {
|
|
1572
1579
|
const genAI = client;
|
|
1573
1580
|
const geminiRequest = request;
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1581
|
+
try {
|
|
1582
|
+
// Cast config to any to bypass strict type checking between our internal types
|
|
1583
|
+
// and the SDK's types. The SDK will validate at runtime.
|
|
1584
|
+
const response = await genAI.models.generateContent({
|
|
1585
|
+
model: geminiRequest.model,
|
|
1586
|
+
contents: geminiRequest.contents,
|
|
1587
|
+
config: geminiRequest.config,
|
|
1588
|
+
});
|
|
1589
|
+
return response;
|
|
1590
|
+
}
|
|
1591
|
+
catch (error) {
|
|
1592
|
+
if (signal?.aborted)
|
|
1593
|
+
return undefined;
|
|
1594
|
+
throw error;
|
|
1595
|
+
}
|
|
1582
1596
|
}
|
|
1583
|
-
async *executeStreamRequest(client, request) {
|
|
1597
|
+
async *executeStreamRequest(client, request, signal) {
|
|
1584
1598
|
const genAI = client;
|
|
1585
1599
|
const geminiRequest = request;
|
|
1586
1600
|
// Use generateContentStream for streaming
|
|
@@ -2230,19 +2244,26 @@ class OpenAiAdapter extends BaseProviderAdapter {
|
|
|
2230
2244
|
//
|
|
2231
2245
|
// API Execution
|
|
2232
2246
|
//
|
|
2233
|
-
async executeRequest(client, request) {
|
|
2247
|
+
async executeRequest(client, request, signal) {
|
|
2234
2248
|
const openai = client;
|
|
2235
|
-
|
|
2236
|
-
|
|
2249
|
+
try {
|
|
2250
|
+
// @ts-expect-error OpenAI SDK types don't match our request format exactly
|
|
2251
|
+
return await openai.responses.create(request, signal ? { signal } : undefined);
|
|
2252
|
+
}
|
|
2253
|
+
catch (error) {
|
|
2254
|
+
if (signal?.aborted)
|
|
2255
|
+
return undefined;
|
|
2256
|
+
throw error;
|
|
2257
|
+
}
|
|
2237
2258
|
}
|
|
2238
|
-
async *executeStreamRequest(client, request) {
|
|
2259
|
+
async *executeStreamRequest(client, request, signal) {
|
|
2239
2260
|
const openai = client;
|
|
2240
2261
|
const baseRequest = request;
|
|
2241
2262
|
const streamRequest = {
|
|
2242
2263
|
...baseRequest,
|
|
2243
2264
|
stream: true,
|
|
2244
2265
|
};
|
|
2245
|
-
const stream = await openai.responses.create(streamRequest);
|
|
2266
|
+
const stream = await openai.responses.create(streamRequest, signal ? { signal } : undefined);
|
|
2246
2267
|
// Track current function call being built
|
|
2247
2268
|
let currentFunctionCall = null;
|
|
2248
2269
|
// Track usage for final chunk
|
|
@@ -2673,19 +2694,26 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
2673
2694
|
//
|
|
2674
2695
|
// API Execution
|
|
2675
2696
|
//
|
|
2676
|
-
async executeRequest(client, request) {
|
|
2697
|
+
async executeRequest(client, request, signal) {
|
|
2677
2698
|
const openRouter = client;
|
|
2678
2699
|
const openRouterRequest = request;
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2700
|
+
try {
|
|
2701
|
+
const response = await openRouter.chat.send({
|
|
2702
|
+
model: openRouterRequest.model,
|
|
2703
|
+
messages: openRouterRequest.messages,
|
|
2704
|
+
tools: openRouterRequest.tools,
|
|
2705
|
+
toolChoice: openRouterRequest.tool_choice,
|
|
2706
|
+
user: openRouterRequest.user,
|
|
2707
|
+
}, signal ? { signal } : undefined);
|
|
2708
|
+
return response;
|
|
2709
|
+
}
|
|
2710
|
+
catch (error) {
|
|
2711
|
+
if (signal?.aborted)
|
|
2712
|
+
return undefined;
|
|
2713
|
+
throw error;
|
|
2714
|
+
}
|
|
2687
2715
|
}
|
|
2688
|
-
async *executeStreamRequest(client, request) {
|
|
2716
|
+
async *executeStreamRequest(client, request, signal) {
|
|
2689
2717
|
const openRouter = client;
|
|
2690
2718
|
const openRouterRequest = request;
|
|
2691
2719
|
// Use chat.send with stream: true for streaming responses
|
|
@@ -2696,7 +2724,7 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
2696
2724
|
toolChoice: openRouterRequest.tool_choice,
|
|
2697
2725
|
user: openRouterRequest.user,
|
|
2698
2726
|
stream: true,
|
|
2699
|
-
});
|
|
2727
|
+
}, signal ? { signal } : undefined);
|
|
2700
2728
|
// Track current tool call being built
|
|
2701
2729
|
let currentToolCall = null;
|
|
2702
2730
|
// Track usage for final chunk
|
|
@@ -3907,9 +3935,12 @@ class RetryExecutor {
|
|
|
3907
3935
|
this.errorClassifier = config.errorClassifier;
|
|
3908
3936
|
}
|
|
3909
3937
|
/**
|
|
3910
|
-
* Execute an operation with retry logic
|
|
3938
|
+
* Execute an operation with retry logic.
|
|
3939
|
+
* Each attempt receives an AbortSignal. On failure, the signal is aborted
|
|
3940
|
+
* before sleeping — this kills lingering socket callbacks from the previous
|
|
3941
|
+
* request and prevents stale async errors from escaping the retry loop.
|
|
3911
3942
|
*
|
|
3912
|
-
* @param operation - The async operation to execute
|
|
3943
|
+
* @param operation - The async operation to execute (receives AbortSignal)
|
|
3913
3944
|
* @param options - Execution options including context and hooks
|
|
3914
3945
|
* @returns The result of the operation
|
|
3915
3946
|
* @throws BadGatewayError if all retries are exhausted or error is not retryable
|
|
@@ -3917,14 +3948,17 @@ class RetryExecutor {
|
|
|
3917
3948
|
async execute(operation, options) {
|
|
3918
3949
|
let attempt = 0;
|
|
3919
3950
|
while (true) {
|
|
3951
|
+
const controller = new AbortController();
|
|
3920
3952
|
try {
|
|
3921
|
-
const result = await operation();
|
|
3953
|
+
const result = await operation(controller.signal);
|
|
3922
3954
|
if (attempt > 0) {
|
|
3923
3955
|
log$1.debug(`API call succeeded after ${attempt} retries`);
|
|
3924
3956
|
}
|
|
3925
3957
|
return result;
|
|
3926
3958
|
}
|
|
3927
3959
|
catch (error) {
|
|
3960
|
+
// Abort the previous request to kill lingering socket callbacks
|
|
3961
|
+
controller.abort("retry");
|
|
3928
3962
|
// Check if we've exhausted retries
|
|
3929
3963
|
if (!this.policy.shouldRetry(attempt)) {
|
|
3930
3964
|
log$1.error(`API call failed after ${this.policy.maxRetries} retries`);
|
|
@@ -3964,7 +3998,19 @@ class RetryExecutor {
|
|
|
3964
3998
|
providerRequest: options.context.providerRequest,
|
|
3965
3999
|
error,
|
|
3966
4000
|
});
|
|
3967
|
-
|
|
4001
|
+
// Guard against stale socket errors that fire during sleep
|
|
4002
|
+
const staleHandler = (reason) => {
|
|
4003
|
+
if (isTransientNetworkError(reason)) {
|
|
4004
|
+
log$1.trace("Suppressed stale socket error during retry sleep");
|
|
4005
|
+
}
|
|
4006
|
+
};
|
|
4007
|
+
process.on("unhandledRejection", staleHandler);
|
|
4008
|
+
try {
|
|
4009
|
+
await kit.sleep(delay);
|
|
4010
|
+
}
|
|
4011
|
+
finally {
|
|
4012
|
+
process.removeListener("unhandledRejection", staleHandler);
|
|
4013
|
+
}
|
|
3968
4014
|
attempt++;
|
|
3969
4015
|
}
|
|
3970
4016
|
}
|
|
@@ -4149,7 +4195,7 @@ class OperateLoop {
|
|
|
4149
4195
|
providerRequest,
|
|
4150
4196
|
});
|
|
4151
4197
|
// Execute with retry (RetryExecutor handles error hooks and throws appropriate errors)
|
|
4152
|
-
const response = await retryExecutor.execute(() => this.adapter.executeRequest(this.client, providerRequest), {
|
|
4198
|
+
const response = await retryExecutor.execute((signal) => this.adapter.executeRequest(this.client, providerRequest, signal), {
|
|
4153
4199
|
context: {
|
|
4154
4200
|
input: state.currentInput,
|
|
4155
4201
|
options,
|
|
@@ -4542,9 +4588,10 @@ class StreamLoop {
|
|
|
4542
4588
|
let attempt = 0;
|
|
4543
4589
|
let chunksYielded = false;
|
|
4544
4590
|
while (true) {
|
|
4591
|
+
const controller = new AbortController();
|
|
4545
4592
|
try {
|
|
4546
4593
|
// Execute streaming request
|
|
4547
|
-
const streamGenerator = this.adapter.executeStreamRequest(this.client, providerRequest);
|
|
4594
|
+
const streamGenerator = this.adapter.executeStreamRequest(this.client, providerRequest, controller.signal);
|
|
4548
4595
|
for await (const chunk of streamGenerator) {
|
|
4549
4596
|
// Pass through text chunks
|
|
4550
4597
|
if (chunk.type === exports.LlmStreamChunkType.Text) {
|
|
@@ -4579,6 +4626,8 @@ class StreamLoop {
|
|
|
4579
4626
|
break;
|
|
4580
4627
|
}
|
|
4581
4628
|
catch (error) {
|
|
4629
|
+
// Abort the previous request to kill lingering socket callbacks
|
|
4630
|
+
controller.abort("retry");
|
|
4582
4631
|
// If chunks were already yielded, we can't transparently retry
|
|
4583
4632
|
if (chunksYielded) {
|
|
4584
4633
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -4605,7 +4654,19 @@ class StreamLoop {
|
|
|
4605
4654
|
const delay = this.retryPolicy.getDelayForAttempt(attempt);
|
|
4606
4655
|
log$1.warn(`Stream request failed. Retrying in ${delay}ms...`);
|
|
4607
4656
|
log$1.var({ error });
|
|
4608
|
-
|
|
4657
|
+
// Guard against stale socket errors that fire during sleep
|
|
4658
|
+
const staleHandler = (reason) => {
|
|
4659
|
+
if (isTransientNetworkError(reason)) {
|
|
4660
|
+
log$1.trace("Suppressed stale socket error during retry sleep");
|
|
4661
|
+
}
|
|
4662
|
+
};
|
|
4663
|
+
process.on("unhandledRejection", staleHandler);
|
|
4664
|
+
try {
|
|
4665
|
+
await kit.sleep(delay);
|
|
4666
|
+
}
|
|
4667
|
+
finally {
|
|
4668
|
+
process.removeListener("unhandledRejection", staleHandler);
|
|
4669
|
+
}
|
|
4609
4670
|
attempt++;
|
|
4610
4671
|
}
|
|
4611
4672
|
}
|