@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
|
@@ -17,8 +17,8 @@ export declare class AnthropicAdapter extends BaseProviderAdapter {
|
|
|
17
17
|
buildRequest(request: OperateRequest): Anthropic.MessageCreateParams;
|
|
18
18
|
formatTools(toolkit: Toolkit, outputSchema?: JsonObject): ProviderToolDefinition[];
|
|
19
19
|
formatOutputSchema(schema: JsonObject | NaturalSchema | z.ZodType): JsonObject;
|
|
20
|
-
executeRequest(client: unknown, request: unknown): Promise<Anthropic.Message>;
|
|
21
|
-
executeStreamRequest(client: unknown, request: unknown): AsyncIterable<LlmStreamChunk>;
|
|
20
|
+
executeRequest(client: unknown, request: unknown, signal?: AbortSignal): Promise<Anthropic.Message>;
|
|
21
|
+
executeStreamRequest(client: unknown, request: unknown, signal?: AbortSignal): AsyncIterable<LlmStreamChunk>;
|
|
22
22
|
parseResponse(response: unknown, _options?: LlmOperateOptions): ParsedResponse;
|
|
23
23
|
extractToolCalls(response: unknown): StandardToolCall[];
|
|
24
24
|
extractUsage(response: unknown, model: string): LlmUsageItem;
|
|
@@ -17,8 +17,8 @@ export declare class GeminiAdapter extends BaseProviderAdapter {
|
|
|
17
17
|
buildRequest(request: OperateRequest): GeminiRequest;
|
|
18
18
|
formatTools(toolkit: Toolkit, outputSchema?: JsonObject): ProviderToolDefinition[];
|
|
19
19
|
formatOutputSchema(schema: JsonObject | NaturalSchema | z.ZodType): JsonObject;
|
|
20
|
-
executeRequest(client: unknown, request: unknown): Promise<GeminiRawResponse>;
|
|
21
|
-
executeStreamRequest(client: unknown, request: unknown): AsyncIterable<LlmStreamChunk>;
|
|
20
|
+
executeRequest(client: unknown, request: unknown, signal?: AbortSignal): Promise<GeminiRawResponse>;
|
|
21
|
+
executeStreamRequest(client: unknown, request: unknown, signal?: AbortSignal): AsyncIterable<LlmStreamChunk>;
|
|
22
22
|
parseResponse(response: unknown, options?: LlmOperateOptions): ParsedResponse;
|
|
23
23
|
extractToolCalls(response: unknown): StandardToolCall[];
|
|
24
24
|
extractUsage(response: unknown, model: string): LlmUsageItem;
|
|
@@ -16,8 +16,8 @@ export declare class OpenAiAdapter extends BaseProviderAdapter {
|
|
|
16
16
|
buildRequest(request: OperateRequest): unknown;
|
|
17
17
|
formatTools(toolkit: Toolkit, _outputSchema?: JsonObject): ProviderToolDefinition[];
|
|
18
18
|
formatOutputSchema(schema: JsonObject | NaturalSchema | z.ZodType): JsonObject;
|
|
19
|
-
executeRequest(client: unknown, request: unknown): Promise<unknown>;
|
|
20
|
-
executeStreamRequest(client: unknown, request: unknown): AsyncIterable<LlmStreamChunk>;
|
|
19
|
+
executeRequest(client: unknown, request: unknown, signal?: AbortSignal): Promise<unknown>;
|
|
20
|
+
executeStreamRequest(client: unknown, request: unknown, signal?: AbortSignal): AsyncIterable<LlmStreamChunk>;
|
|
21
21
|
parseResponse(response: unknown, options?: LlmOperateOptions): ParsedResponse;
|
|
22
22
|
extractToolCalls(response: unknown): StandardToolCall[];
|
|
23
23
|
extractUsage(response: unknown, model: string): LlmUsageItem;
|
|
@@ -88,8 +88,8 @@ export declare class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
88
88
|
buildRequest(request: OperateRequest): OpenRouterRequest;
|
|
89
89
|
formatTools(toolkit: Toolkit, outputSchema?: JsonObject): ProviderToolDefinition[];
|
|
90
90
|
formatOutputSchema(schema: JsonObject | NaturalSchema | z.ZodType): JsonObject;
|
|
91
|
-
executeRequest(client: unknown, request: unknown): Promise<OpenRouterResponse>;
|
|
92
|
-
executeStreamRequest(client: unknown, request: unknown): AsyncIterable<LlmStreamChunk>;
|
|
91
|
+
executeRequest(client: unknown, request: unknown, signal?: AbortSignal): Promise<OpenRouterResponse>;
|
|
92
|
+
executeStreamRequest(client: unknown, request: unknown, signal?: AbortSignal): AsyncIterable<LlmStreamChunk>;
|
|
93
93
|
parseResponse(response: unknown, _options?: LlmOperateOptions): ParsedResponse;
|
|
94
94
|
extractToolCalls(response: unknown): StandardToolCall[];
|
|
95
95
|
extractUsage(response: unknown, model: string): LlmUsageItem;
|
|
@@ -47,17 +47,19 @@ export interface ProviderAdapter {
|
|
|
47
47
|
*
|
|
48
48
|
* @param client - The provider's SDK client instance
|
|
49
49
|
* @param request - Provider-specific request object (from buildRequest)
|
|
50
|
+
* @param signal - Optional AbortSignal to cancel the request on retry
|
|
50
51
|
* @returns Raw provider response
|
|
51
52
|
*/
|
|
52
|
-
executeRequest(client: unknown, request: unknown): Promise<unknown>;
|
|
53
|
+
executeRequest(client: unknown, request: unknown, signal?: AbortSignal): Promise<unknown>;
|
|
53
54
|
/**
|
|
54
55
|
* Execute a streaming API request to the provider
|
|
55
56
|
*
|
|
56
57
|
* @param client - The provider's SDK client instance
|
|
57
58
|
* @param request - Provider-specific request object (from buildRequest)
|
|
59
|
+
* @param signal - Optional AbortSignal to cancel the request on retry
|
|
58
60
|
* @returns AsyncIterable of stream chunks
|
|
59
61
|
*/
|
|
60
|
-
executeStreamRequest?(client: unknown, request: unknown): AsyncIterable<LlmStreamChunk>;
|
|
62
|
+
executeStreamRequest?(client: unknown, request: unknown, signal?: AbortSignal): AsyncIterable<LlmStreamChunk>;
|
|
61
63
|
/**
|
|
62
64
|
* Parse a provider response into standardized format
|
|
63
65
|
*
|
|
@@ -158,7 +160,7 @@ export declare abstract class BaseProviderAdapter implements ProviderAdapter {
|
|
|
158
160
|
abstract buildRequest(request: OperateRequest): unknown;
|
|
159
161
|
abstract formatTools(toolkit: Toolkit, outputSchema?: JsonObject): ProviderToolDefinition[];
|
|
160
162
|
abstract formatOutputSchema(schema: JsonObject | NaturalSchema | z.ZodType): JsonObject;
|
|
161
|
-
abstract executeRequest(client: unknown, request: unknown): Promise<unknown>;
|
|
163
|
+
abstract executeRequest(client: unknown, request: unknown, signal?: AbortSignal): Promise<unknown>;
|
|
162
164
|
abstract parseResponse(response: unknown, options?: LlmOperateOptions): ParsedResponse;
|
|
163
165
|
abstract extractToolCalls(response: unknown): StandardToolCall[];
|
|
164
166
|
abstract extractUsage(response: unknown, model: string): LlmUsageItem;
|
|
@@ -28,12 +28,15 @@ export declare class RetryExecutor {
|
|
|
28
28
|
private readonly errorClassifier;
|
|
29
29
|
constructor(config: RetryExecutorConfig);
|
|
30
30
|
/**
|
|
31
|
-
* Execute an operation with retry logic
|
|
31
|
+
* Execute an operation with retry logic.
|
|
32
|
+
* Each attempt receives an AbortSignal. On failure, the signal is aborted
|
|
33
|
+
* before sleeping — this kills lingering socket callbacks from the previous
|
|
34
|
+
* request and prevents stale async errors from escaping the retry loop.
|
|
32
35
|
*
|
|
33
|
-
* @param operation - The async operation to execute
|
|
36
|
+
* @param operation - The async operation to execute (receives AbortSignal)
|
|
34
37
|
* @param options - Execution options including context and hooks
|
|
35
38
|
* @returns The result of the operation
|
|
36
39
|
* @throws BadGatewayError if all retries are exhausted or error is not retryable
|
|
37
40
|
*/
|
|
38
|
-
execute<T>(operation: () => Promise<T
|
|
41
|
+
execute<T>(operation: ((signal: AbortSignal) => Promise<T>) | (() => Promise<T>), options: ExecuteOptions): Promise<T>;
|
|
39
42
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1126,17 +1126,24 @@ class AnthropicAdapter extends BaseProviderAdapter {
|
|
|
1126
1126
|
//
|
|
1127
1127
|
// API Execution
|
|
1128
1128
|
//
|
|
1129
|
-
async executeRequest(client, request) {
|
|
1129
|
+
async executeRequest(client, request, signal) {
|
|
1130
1130
|
const anthropic = client;
|
|
1131
|
-
|
|
1131
|
+
try {
|
|
1132
|
+
return (await anthropic.messages.create(request, signal ? { signal } : undefined));
|
|
1133
|
+
}
|
|
1134
|
+
catch (error) {
|
|
1135
|
+
if (signal?.aborted)
|
|
1136
|
+
return undefined;
|
|
1137
|
+
throw error;
|
|
1138
|
+
}
|
|
1132
1139
|
}
|
|
1133
|
-
async *executeStreamRequest(client, request) {
|
|
1140
|
+
async *executeStreamRequest(client, request, signal) {
|
|
1134
1141
|
const anthropic = client;
|
|
1135
1142
|
const streamRequest = {
|
|
1136
1143
|
...request,
|
|
1137
1144
|
stream: true,
|
|
1138
1145
|
};
|
|
1139
|
-
const stream = await anthropic.messages.create(streamRequest);
|
|
1146
|
+
const stream = await anthropic.messages.create(streamRequest, signal ? { signal } : undefined);
|
|
1140
1147
|
// Track current tool call being built
|
|
1141
1148
|
let currentToolCall = null;
|
|
1142
1149
|
// Track usage for final chunk
|
|
@@ -1566,19 +1573,26 @@ class GeminiAdapter extends BaseProviderAdapter {
|
|
|
1566
1573
|
//
|
|
1567
1574
|
// API Execution
|
|
1568
1575
|
//
|
|
1569
|
-
async executeRequest(client, request) {
|
|
1576
|
+
async executeRequest(client, request, signal) {
|
|
1570
1577
|
const genAI = client;
|
|
1571
1578
|
const geminiRequest = request;
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1579
|
+
try {
|
|
1580
|
+
// Cast config to any to bypass strict type checking between our internal types
|
|
1581
|
+
// and the SDK's types. The SDK will validate at runtime.
|
|
1582
|
+
const response = await genAI.models.generateContent({
|
|
1583
|
+
model: geminiRequest.model,
|
|
1584
|
+
contents: geminiRequest.contents,
|
|
1585
|
+
config: geminiRequest.config,
|
|
1586
|
+
});
|
|
1587
|
+
return response;
|
|
1588
|
+
}
|
|
1589
|
+
catch (error) {
|
|
1590
|
+
if (signal?.aborted)
|
|
1591
|
+
return undefined;
|
|
1592
|
+
throw error;
|
|
1593
|
+
}
|
|
1580
1594
|
}
|
|
1581
|
-
async *executeStreamRequest(client, request) {
|
|
1595
|
+
async *executeStreamRequest(client, request, signal) {
|
|
1582
1596
|
const genAI = client;
|
|
1583
1597
|
const geminiRequest = request;
|
|
1584
1598
|
// Use generateContentStream for streaming
|
|
@@ -2228,19 +2242,26 @@ class OpenAiAdapter extends BaseProviderAdapter {
|
|
|
2228
2242
|
//
|
|
2229
2243
|
// API Execution
|
|
2230
2244
|
//
|
|
2231
|
-
async executeRequest(client, request) {
|
|
2245
|
+
async executeRequest(client, request, signal) {
|
|
2232
2246
|
const openai = client;
|
|
2233
|
-
|
|
2234
|
-
|
|
2247
|
+
try {
|
|
2248
|
+
// @ts-expect-error OpenAI SDK types don't match our request format exactly
|
|
2249
|
+
return await openai.responses.create(request, signal ? { signal } : undefined);
|
|
2250
|
+
}
|
|
2251
|
+
catch (error) {
|
|
2252
|
+
if (signal?.aborted)
|
|
2253
|
+
return undefined;
|
|
2254
|
+
throw error;
|
|
2255
|
+
}
|
|
2235
2256
|
}
|
|
2236
|
-
async *executeStreamRequest(client, request) {
|
|
2257
|
+
async *executeStreamRequest(client, request, signal) {
|
|
2237
2258
|
const openai = client;
|
|
2238
2259
|
const baseRequest = request;
|
|
2239
2260
|
const streamRequest = {
|
|
2240
2261
|
...baseRequest,
|
|
2241
2262
|
stream: true,
|
|
2242
2263
|
};
|
|
2243
|
-
const stream = await openai.responses.create(streamRequest);
|
|
2264
|
+
const stream = await openai.responses.create(streamRequest, signal ? { signal } : undefined);
|
|
2244
2265
|
// Track current function call being built
|
|
2245
2266
|
let currentFunctionCall = null;
|
|
2246
2267
|
// Track usage for final chunk
|
|
@@ -2671,19 +2692,26 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
2671
2692
|
//
|
|
2672
2693
|
// API Execution
|
|
2673
2694
|
//
|
|
2674
|
-
async executeRequest(client, request) {
|
|
2695
|
+
async executeRequest(client, request, signal) {
|
|
2675
2696
|
const openRouter = client;
|
|
2676
2697
|
const openRouterRequest = request;
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2698
|
+
try {
|
|
2699
|
+
const response = await openRouter.chat.send({
|
|
2700
|
+
model: openRouterRequest.model,
|
|
2701
|
+
messages: openRouterRequest.messages,
|
|
2702
|
+
tools: openRouterRequest.tools,
|
|
2703
|
+
toolChoice: openRouterRequest.tool_choice,
|
|
2704
|
+
user: openRouterRequest.user,
|
|
2705
|
+
}, signal ? { signal } : undefined);
|
|
2706
|
+
return response;
|
|
2707
|
+
}
|
|
2708
|
+
catch (error) {
|
|
2709
|
+
if (signal?.aborted)
|
|
2710
|
+
return undefined;
|
|
2711
|
+
throw error;
|
|
2712
|
+
}
|
|
2685
2713
|
}
|
|
2686
|
-
async *executeStreamRequest(client, request) {
|
|
2714
|
+
async *executeStreamRequest(client, request, signal) {
|
|
2687
2715
|
const openRouter = client;
|
|
2688
2716
|
const openRouterRequest = request;
|
|
2689
2717
|
// Use chat.send with stream: true for streaming responses
|
|
@@ -2694,7 +2722,7 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
2694
2722
|
toolChoice: openRouterRequest.tool_choice,
|
|
2695
2723
|
user: openRouterRequest.user,
|
|
2696
2724
|
stream: true,
|
|
2697
|
-
});
|
|
2725
|
+
}, signal ? { signal } : undefined);
|
|
2698
2726
|
// Track current tool call being built
|
|
2699
2727
|
let currentToolCall = null;
|
|
2700
2728
|
// Track usage for final chunk
|
|
@@ -3905,9 +3933,12 @@ class RetryExecutor {
|
|
|
3905
3933
|
this.errorClassifier = config.errorClassifier;
|
|
3906
3934
|
}
|
|
3907
3935
|
/**
|
|
3908
|
-
* Execute an operation with retry logic
|
|
3936
|
+
* Execute an operation with retry logic.
|
|
3937
|
+
* Each attempt receives an AbortSignal. On failure, the signal is aborted
|
|
3938
|
+
* before sleeping — this kills lingering socket callbacks from the previous
|
|
3939
|
+
* request and prevents stale async errors from escaping the retry loop.
|
|
3909
3940
|
*
|
|
3910
|
-
* @param operation - The async operation to execute
|
|
3941
|
+
* @param operation - The async operation to execute (receives AbortSignal)
|
|
3911
3942
|
* @param options - Execution options including context and hooks
|
|
3912
3943
|
* @returns The result of the operation
|
|
3913
3944
|
* @throws BadGatewayError if all retries are exhausted or error is not retryable
|
|
@@ -3915,14 +3946,17 @@ class RetryExecutor {
|
|
|
3915
3946
|
async execute(operation, options) {
|
|
3916
3947
|
let attempt = 0;
|
|
3917
3948
|
while (true) {
|
|
3949
|
+
const controller = new AbortController();
|
|
3918
3950
|
try {
|
|
3919
|
-
const result = await operation();
|
|
3951
|
+
const result = await operation(controller.signal);
|
|
3920
3952
|
if (attempt > 0) {
|
|
3921
3953
|
log$1.debug(`API call succeeded after ${attempt} retries`);
|
|
3922
3954
|
}
|
|
3923
3955
|
return result;
|
|
3924
3956
|
}
|
|
3925
3957
|
catch (error) {
|
|
3958
|
+
// Abort the previous request to kill lingering socket callbacks
|
|
3959
|
+
controller.abort("retry");
|
|
3926
3960
|
// Check if we've exhausted retries
|
|
3927
3961
|
if (!this.policy.shouldRetry(attempt)) {
|
|
3928
3962
|
log$1.error(`API call failed after ${this.policy.maxRetries} retries`);
|
|
@@ -3962,7 +3996,19 @@ class RetryExecutor {
|
|
|
3962
3996
|
providerRequest: options.context.providerRequest,
|
|
3963
3997
|
error,
|
|
3964
3998
|
});
|
|
3965
|
-
|
|
3999
|
+
// Guard against stale socket errors that fire during sleep
|
|
4000
|
+
const staleHandler = (reason) => {
|
|
4001
|
+
if (isTransientNetworkError(reason)) {
|
|
4002
|
+
log$1.trace("Suppressed stale socket error during retry sleep");
|
|
4003
|
+
}
|
|
4004
|
+
};
|
|
4005
|
+
process.on("unhandledRejection", staleHandler);
|
|
4006
|
+
try {
|
|
4007
|
+
await sleep(delay);
|
|
4008
|
+
}
|
|
4009
|
+
finally {
|
|
4010
|
+
process.removeListener("unhandledRejection", staleHandler);
|
|
4011
|
+
}
|
|
3966
4012
|
attempt++;
|
|
3967
4013
|
}
|
|
3968
4014
|
}
|
|
@@ -4147,7 +4193,7 @@ class OperateLoop {
|
|
|
4147
4193
|
providerRequest,
|
|
4148
4194
|
});
|
|
4149
4195
|
// Execute with retry (RetryExecutor handles error hooks and throws appropriate errors)
|
|
4150
|
-
const response = await retryExecutor.execute(() => this.adapter.executeRequest(this.client, providerRequest), {
|
|
4196
|
+
const response = await retryExecutor.execute((signal) => this.adapter.executeRequest(this.client, providerRequest, signal), {
|
|
4151
4197
|
context: {
|
|
4152
4198
|
input: state.currentInput,
|
|
4153
4199
|
options,
|
|
@@ -4540,9 +4586,10 @@ class StreamLoop {
|
|
|
4540
4586
|
let attempt = 0;
|
|
4541
4587
|
let chunksYielded = false;
|
|
4542
4588
|
while (true) {
|
|
4589
|
+
const controller = new AbortController();
|
|
4543
4590
|
try {
|
|
4544
4591
|
// Execute streaming request
|
|
4545
|
-
const streamGenerator = this.adapter.executeStreamRequest(this.client, providerRequest);
|
|
4592
|
+
const streamGenerator = this.adapter.executeStreamRequest(this.client, providerRequest, controller.signal);
|
|
4546
4593
|
for await (const chunk of streamGenerator) {
|
|
4547
4594
|
// Pass through text chunks
|
|
4548
4595
|
if (chunk.type === LlmStreamChunkType.Text) {
|
|
@@ -4577,6 +4624,8 @@ class StreamLoop {
|
|
|
4577
4624
|
break;
|
|
4578
4625
|
}
|
|
4579
4626
|
catch (error) {
|
|
4627
|
+
// Abort the previous request to kill lingering socket callbacks
|
|
4628
|
+
controller.abort("retry");
|
|
4580
4629
|
// If chunks were already yielded, we can't transparently retry
|
|
4581
4630
|
if (chunksYielded) {
|
|
4582
4631
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -4603,7 +4652,19 @@ class StreamLoop {
|
|
|
4603
4652
|
const delay = this.retryPolicy.getDelayForAttempt(attempt);
|
|
4604
4653
|
log$1.warn(`Stream request failed. Retrying in ${delay}ms...`);
|
|
4605
4654
|
log$1.var({ error });
|
|
4606
|
-
|
|
4655
|
+
// Guard against stale socket errors that fire during sleep
|
|
4656
|
+
const staleHandler = (reason) => {
|
|
4657
|
+
if (isTransientNetworkError(reason)) {
|
|
4658
|
+
log$1.trace("Suppressed stale socket error during retry sleep");
|
|
4659
|
+
}
|
|
4660
|
+
};
|
|
4661
|
+
process.on("unhandledRejection", staleHandler);
|
|
4662
|
+
try {
|
|
4663
|
+
await sleep(delay);
|
|
4664
|
+
}
|
|
4665
|
+
finally {
|
|
4666
|
+
process.removeListener("unhandledRejection", staleHandler);
|
|
4667
|
+
}
|
|
4607
4668
|
attempt++;
|
|
4608
4669
|
}
|
|
4609
4670
|
}
|