@jaypie/llm 1.2.14 → 1.2.16
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/constants.d.ts +18 -6
- package/dist/cjs/index.cjs +363 -157
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/operate/adapters/XaiAdapter.d.ts +11 -0
- package/dist/cjs/operate/adapters/index.d.ts +1 -0
- package/dist/cjs/operate/index.d.ts +1 -1
- package/dist/cjs/providers/xai/XaiProvider.class.d.ts +21 -0
- package/dist/cjs/providers/xai/index.d.ts +1 -0
- package/dist/cjs/providers/xai/utils.d.ts +5 -0
- package/dist/esm/constants.d.ts +18 -6
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +363 -158
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/operate/adapters/XaiAdapter.d.ts +11 -0
- package/dist/esm/operate/adapters/index.d.ts +1 -0
- package/dist/esm/operate/index.d.ts +1 -1
- package/dist/esm/providers/xai/XaiProvider.class.d.ts +21 -0
- package/dist/esm/providers/xai/index.d.ts +1 -0
- package/dist/esm/providers/xai/utils.d.ts +5 -0
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -38,6 +38,12 @@ const FIRST_CLASS_PROVIDER = {
|
|
|
38
38
|
SMALL: "z-ai/glm-4.7",
|
|
39
39
|
TINY: "z-ai/glm-4.7",
|
|
40
40
|
},
|
|
41
|
+
XAI: {
|
|
42
|
+
DEFAULT: "grok-4-1-fast-reasoning",
|
|
43
|
+
LARGE: "grok-4-1-fast-reasoning",
|
|
44
|
+
SMALL: "grok-3",
|
|
45
|
+
TINY: "grok-3-mini",
|
|
46
|
+
},
|
|
41
47
|
};
|
|
42
48
|
const PROVIDER = {
|
|
43
49
|
ANTHROPIC: {
|
|
@@ -118,6 +124,19 @@ const PROVIDER = {
|
|
|
118
124
|
USER: "user",
|
|
119
125
|
},
|
|
120
126
|
},
|
|
127
|
+
XAI: {
|
|
128
|
+
// https://docs.x.ai/docs/models
|
|
129
|
+
API_KEY: "XAI_API_KEY",
|
|
130
|
+
BASE_URL: "https://api.x.ai/v1",
|
|
131
|
+
MODEL: {
|
|
132
|
+
DEFAULT: FIRST_CLASS_PROVIDER.XAI.DEFAULT,
|
|
133
|
+
LARGE: FIRST_CLASS_PROVIDER.XAI.LARGE,
|
|
134
|
+
SMALL: FIRST_CLASS_PROVIDER.XAI.SMALL,
|
|
135
|
+
TINY: FIRST_CLASS_PROVIDER.XAI.TINY,
|
|
136
|
+
},
|
|
137
|
+
MODEL_MATCH_WORDS: ["grok", "xai"],
|
|
138
|
+
NAME: "xai",
|
|
139
|
+
},
|
|
121
140
|
};
|
|
122
141
|
// Last: Defaults
|
|
123
142
|
const DEFAULT = {
|
|
@@ -135,6 +154,7 @@ const ALL = {
|
|
|
135
154
|
PROVIDER.ANTHROPIC.MODEL.DEFAULT,
|
|
136
155
|
PROVIDER.GEMINI.MODEL.DEFAULT,
|
|
137
156
|
PROVIDER.OPENAI.MODEL.DEFAULT,
|
|
157
|
+
PROVIDER.XAI.MODEL.DEFAULT,
|
|
138
158
|
],
|
|
139
159
|
COMBINED: [
|
|
140
160
|
PROVIDER.ANTHROPIC.MODEL.DEFAULT,
|
|
@@ -149,21 +169,28 @@ const ALL = {
|
|
|
149
169
|
PROVIDER.OPENAI.MODEL.LARGE,
|
|
150
170
|
PROVIDER.OPENAI.MODEL.SMALL,
|
|
151
171
|
PROVIDER.OPENAI.MODEL.TINY,
|
|
172
|
+
PROVIDER.XAI.MODEL.DEFAULT,
|
|
173
|
+
PROVIDER.XAI.MODEL.LARGE,
|
|
174
|
+
PROVIDER.XAI.MODEL.SMALL,
|
|
175
|
+
PROVIDER.XAI.MODEL.TINY,
|
|
152
176
|
],
|
|
153
177
|
LARGE: [
|
|
154
178
|
PROVIDER.ANTHROPIC.MODEL.LARGE,
|
|
155
179
|
PROVIDER.GEMINI.MODEL.LARGE,
|
|
156
180
|
PROVIDER.OPENAI.MODEL.LARGE,
|
|
181
|
+
PROVIDER.XAI.MODEL.LARGE,
|
|
157
182
|
],
|
|
158
183
|
SMALL: [
|
|
159
184
|
PROVIDER.ANTHROPIC.MODEL.SMALL,
|
|
160
185
|
PROVIDER.GEMINI.MODEL.SMALL,
|
|
161
186
|
PROVIDER.OPENAI.MODEL.SMALL,
|
|
187
|
+
PROVIDER.XAI.MODEL.SMALL,
|
|
162
188
|
],
|
|
163
189
|
TINY: [
|
|
164
190
|
PROVIDER.ANTHROPIC.MODEL.TINY,
|
|
165
191
|
PROVIDER.GEMINI.MODEL.TINY,
|
|
166
192
|
PROVIDER.OPENAI.MODEL.TINY,
|
|
193
|
+
PROVIDER.XAI.MODEL.TINY,
|
|
167
194
|
],
|
|
168
195
|
};
|
|
169
196
|
|
|
@@ -214,6 +241,12 @@ function determineModelProvider(input) {
|
|
|
214
241
|
provider: PROVIDER.OPENROUTER.NAME,
|
|
215
242
|
};
|
|
216
243
|
}
|
|
244
|
+
if (input === PROVIDER.XAI.NAME) {
|
|
245
|
+
return {
|
|
246
|
+
model: PROVIDER.XAI.MODEL.DEFAULT,
|
|
247
|
+
provider: PROVIDER.XAI.NAME,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
217
250
|
// Check if input matches an Anthropic model exactly
|
|
218
251
|
for (const [, modelValue] of Object.entries(PROVIDER.ANTHROPIC.MODEL)) {
|
|
219
252
|
if (input === modelValue) {
|
|
@@ -250,6 +283,15 @@ function determineModelProvider(input) {
|
|
|
250
283
|
};
|
|
251
284
|
}
|
|
252
285
|
}
|
|
286
|
+
// Check if input matches an xAI model exactly
|
|
287
|
+
for (const [, modelValue] of Object.entries(PROVIDER.XAI.MODEL)) {
|
|
288
|
+
if (input === modelValue) {
|
|
289
|
+
return {
|
|
290
|
+
model: input,
|
|
291
|
+
provider: PROVIDER.XAI.NAME,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
253
295
|
// Assume OpenRouter for models containing "/" (e.g., "openai/gpt-4", "anthropic/claude-3-opus")
|
|
254
296
|
// This check must come before match words so that "openai/gpt-4" is not matched by "openai" keyword
|
|
255
297
|
if (input.includes("/")) {
|
|
@@ -296,6 +338,15 @@ function determineModelProvider(input) {
|
|
|
296
338
|
}
|
|
297
339
|
}
|
|
298
340
|
}
|
|
341
|
+
// Check xAI match words
|
|
342
|
+
for (const matchWord of PROVIDER.XAI.MODEL_MATCH_WORDS) {
|
|
343
|
+
if (lowerInput.includes(matchWord)) {
|
|
344
|
+
return {
|
|
345
|
+
model: input,
|
|
346
|
+
provider: PROVIDER.XAI.NAME,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
}
|
|
299
350
|
// Check OpenRouter match words
|
|
300
351
|
for (const matchWord of PROVIDER.OPENROUTER.MODEL_MATCH_WORDS) {
|
|
301
352
|
if (lowerInput.includes(matchWord)) {
|
|
@@ -507,8 +558,8 @@ function formatOperateInput(input, options) {
|
|
|
507
558
|
return [input];
|
|
508
559
|
}
|
|
509
560
|
|
|
510
|
-
const getLogger$
|
|
511
|
-
const log$1 = getLogger$
|
|
561
|
+
const getLogger$5 = () => log$2.log.lib({ lib: kit.JAYPIE.LIB.LLM });
|
|
562
|
+
const log$1 = getLogger$5();
|
|
512
563
|
|
|
513
564
|
// Turn policy constants
|
|
514
565
|
const MAX_TURNS_ABSOLUTE_LIMIT = 72;
|
|
@@ -3149,6 +3200,23 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
3149
3200
|
// Export singleton instance
|
|
3150
3201
|
const openRouterAdapter = new OpenRouterAdapter();
|
|
3151
3202
|
|
|
3203
|
+
/**
|
|
3204
|
+
* XaiAdapter extends OpenAiAdapter since xAI (Grok) uses an OpenAI-compatible API.
|
|
3205
|
+
* Only the name and default model are overridden; all request building, response parsing,
|
|
3206
|
+
* error classification, tool handling, and streaming are inherited.
|
|
3207
|
+
*/
|
|
3208
|
+
class XaiAdapter extends OpenAiAdapter {
|
|
3209
|
+
constructor() {
|
|
3210
|
+
super(...arguments);
|
|
3211
|
+
// @ts-expect-error Narrowing override: xAI name differs from parent's literal "openai"
|
|
3212
|
+
this.name = PROVIDER.XAI.NAME;
|
|
3213
|
+
// @ts-expect-error Narrowing override: xAI default model differs from parent's literal
|
|
3214
|
+
this.defaultModel = PROVIDER.XAI.MODEL.DEFAULT;
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
// Export singleton instance
|
|
3218
|
+
const xaiAdapter = new XaiAdapter();
|
|
3219
|
+
|
|
3152
3220
|
const DEFAULT_TOOL_TYPE = "function";
|
|
3153
3221
|
const log = log$2.log.lib({ lib: kit.JAYPIE.LIB.LLM });
|
|
3154
3222
|
function logToolMessage(message, context) {
|
|
@@ -3957,73 +4025,91 @@ class RetryExecutor {
|
|
|
3957
4025
|
*/
|
|
3958
4026
|
async execute(operation, options) {
|
|
3959
4027
|
let attempt = 0;
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
4028
|
+
// Persistent guard against stale socket errors (TypeError: terminated).
|
|
4029
|
+
// Installed after the first abort and kept alive through subsequent attempts
|
|
4030
|
+
// so that asynchronous undici socket teardown errors that fire between
|
|
4031
|
+
// sleep completion and the next operation's await are caught.
|
|
4032
|
+
let staleGuard;
|
|
4033
|
+
const installGuard = () => {
|
|
4034
|
+
if (staleGuard)
|
|
4035
|
+
return;
|
|
4036
|
+
staleGuard = (reason) => {
|
|
4037
|
+
if (isTransientNetworkError(reason)) {
|
|
4038
|
+
log$1.trace("Suppressed stale socket error during retry");
|
|
3966
4039
|
}
|
|
3967
|
-
|
|
4040
|
+
};
|
|
4041
|
+
process.on("unhandledRejection", staleGuard);
|
|
4042
|
+
};
|
|
4043
|
+
const removeGuard = () => {
|
|
4044
|
+
if (staleGuard) {
|
|
4045
|
+
process.removeListener("unhandledRejection", staleGuard);
|
|
4046
|
+
staleGuard = undefined;
|
|
3968
4047
|
}
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
providerRequest: options.context.providerRequest,
|
|
3980
|
-
error,
|
|
3981
|
-
});
|
|
3982
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3983
|
-
throw new errors.BadGatewayError(errorMessage);
|
|
4048
|
+
};
|
|
4049
|
+
try {
|
|
4050
|
+
while (true) {
|
|
4051
|
+
const controller = new AbortController();
|
|
4052
|
+
try {
|
|
4053
|
+
const result = await operation(controller.signal);
|
|
4054
|
+
if (attempt > 0) {
|
|
4055
|
+
log$1.debug(`API call succeeded after ${attempt} retries`);
|
|
4056
|
+
}
|
|
4057
|
+
return result;
|
|
3984
4058
|
}
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
4059
|
+
catch (error) {
|
|
4060
|
+
// Abort the previous request to kill lingering socket callbacks
|
|
4061
|
+
controller.abort("retry");
|
|
4062
|
+
// Install the guard immediately after abort — stale socket errors
|
|
4063
|
+
// can fire on any subsequent microtask boundary (during hook calls,
|
|
4064
|
+
// sleep, or the next operation attempt)
|
|
4065
|
+
installGuard();
|
|
4066
|
+
// Check if we've exhausted retries
|
|
4067
|
+
if (!this.policy.shouldRetry(attempt)) {
|
|
4068
|
+
log$1.error(`API call failed after ${this.policy.maxRetries} retries`);
|
|
4069
|
+
log$1.var({ error });
|
|
4070
|
+
await this.hookRunner.runOnUnrecoverableError(options.hooks, {
|
|
4071
|
+
input: options.context.input,
|
|
4072
|
+
options: options.context.options,
|
|
4073
|
+
providerRequest: options.context.providerRequest,
|
|
4074
|
+
error,
|
|
4075
|
+
});
|
|
4076
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4077
|
+
throw new errors.BadGatewayError(errorMessage);
|
|
4078
|
+
}
|
|
4079
|
+
// Check if error is not retryable
|
|
4080
|
+
if (!this.errorClassifier.isRetryable(error)) {
|
|
4081
|
+
log$1.error("API call failed with non-retryable error");
|
|
4082
|
+
log$1.var({ error });
|
|
4083
|
+
await this.hookRunner.runOnUnrecoverableError(options.hooks, {
|
|
4084
|
+
input: options.context.input,
|
|
4085
|
+
options: options.context.options,
|
|
4086
|
+
providerRequest: options.context.providerRequest,
|
|
4087
|
+
error,
|
|
4088
|
+
});
|
|
4089
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4090
|
+
throw new errors.BadGatewayError(errorMessage);
|
|
4091
|
+
}
|
|
4092
|
+
// Warn if this is an unknown error type
|
|
4093
|
+
if (!this.errorClassifier.isKnownError(error)) {
|
|
4094
|
+
log$1.warn("API returned unknown error type, will retry");
|
|
4095
|
+
log$1.var({ error });
|
|
4096
|
+
}
|
|
4097
|
+
const delay = this.policy.getDelayForAttempt(attempt);
|
|
4098
|
+
log$1.warn(`API call failed. Retrying in ${delay}ms...`);
|
|
4099
|
+
await this.hookRunner.runOnRetryableError(options.hooks, {
|
|
3990
4100
|
input: options.context.input,
|
|
3991
4101
|
options: options.context.options,
|
|
3992
4102
|
providerRequest: options.context.providerRequest,
|
|
3993
4103
|
error,
|
|
3994
4104
|
});
|
|
3995
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3996
|
-
throw new errors.BadGatewayError(errorMessage);
|
|
3997
|
-
}
|
|
3998
|
-
// Warn if this is an unknown error type
|
|
3999
|
-
if (!this.errorClassifier.isKnownError(error)) {
|
|
4000
|
-
log$1.warn("API returned unknown error type, will retry");
|
|
4001
|
-
log$1.var({ error });
|
|
4002
|
-
}
|
|
4003
|
-
const delay = this.policy.getDelayForAttempt(attempt);
|
|
4004
|
-
log$1.warn(`API call failed. Retrying in ${delay}ms...`);
|
|
4005
|
-
await this.hookRunner.runOnRetryableError(options.hooks, {
|
|
4006
|
-
input: options.context.input,
|
|
4007
|
-
options: options.context.options,
|
|
4008
|
-
providerRequest: options.context.providerRequest,
|
|
4009
|
-
error,
|
|
4010
|
-
});
|
|
4011
|
-
// Guard against stale socket errors that fire during sleep
|
|
4012
|
-
const staleHandler = (reason) => {
|
|
4013
|
-
if (isTransientNetworkError(reason)) {
|
|
4014
|
-
log$1.trace("Suppressed stale socket error during retry sleep");
|
|
4015
|
-
}
|
|
4016
|
-
};
|
|
4017
|
-
process.on("unhandledRejection", staleHandler);
|
|
4018
|
-
try {
|
|
4019
4105
|
await kit.sleep(delay);
|
|
4106
|
+
attempt++;
|
|
4020
4107
|
}
|
|
4021
|
-
finally {
|
|
4022
|
-
process.removeListener("unhandledRejection", staleHandler);
|
|
4023
|
-
}
|
|
4024
|
-
attempt++;
|
|
4025
4108
|
}
|
|
4026
4109
|
}
|
|
4110
|
+
finally {
|
|
4111
|
+
removeGuard();
|
|
4112
|
+
}
|
|
4027
4113
|
}
|
|
4028
4114
|
}
|
|
4029
4115
|
|
|
@@ -4597,89 +4683,103 @@ class StreamLoop {
|
|
|
4597
4683
|
// Retry loop for connection-level failures
|
|
4598
4684
|
let attempt = 0;
|
|
4599
4685
|
let chunksYielded = false;
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4686
|
+
// Persistent guard against stale socket errors (TypeError: terminated).
|
|
4687
|
+
// Installed after the first abort and kept alive through subsequent attempts.
|
|
4688
|
+
let staleGuard;
|
|
4689
|
+
const installGuard = () => {
|
|
4690
|
+
if (staleGuard)
|
|
4691
|
+
return;
|
|
4692
|
+
staleGuard = (reason) => {
|
|
4693
|
+
if (isTransientNetworkError(reason)) {
|
|
4694
|
+
log$1.trace("Suppressed stale socket error during retry");
|
|
4695
|
+
}
|
|
4696
|
+
};
|
|
4697
|
+
process.on("unhandledRejection", staleGuard);
|
|
4698
|
+
};
|
|
4699
|
+
const removeGuard = () => {
|
|
4700
|
+
if (staleGuard) {
|
|
4701
|
+
process.removeListener("unhandledRejection", staleGuard);
|
|
4702
|
+
staleGuard = undefined;
|
|
4703
|
+
}
|
|
4704
|
+
};
|
|
4705
|
+
try {
|
|
4706
|
+
while (true) {
|
|
4707
|
+
const controller = new AbortController();
|
|
4708
|
+
try {
|
|
4709
|
+
// Execute streaming request
|
|
4710
|
+
const streamGenerator = this.adapter.executeStreamRequest(this.client, providerRequest, controller.signal);
|
|
4711
|
+
for await (const chunk of streamGenerator) {
|
|
4712
|
+
// Pass through text chunks
|
|
4713
|
+
if (chunk.type === exports.LlmStreamChunkType.Text) {
|
|
4714
|
+
chunksYielded = true;
|
|
4715
|
+
yield chunk;
|
|
4716
|
+
}
|
|
4717
|
+
// Collect tool calls
|
|
4718
|
+
if (chunk.type === exports.LlmStreamChunkType.ToolCall) {
|
|
4719
|
+
chunksYielded = true;
|
|
4720
|
+
collectedToolCalls.push({
|
|
4721
|
+
callId: chunk.toolCall.id,
|
|
4722
|
+
name: chunk.toolCall.name,
|
|
4723
|
+
arguments: chunk.toolCall.arguments,
|
|
4724
|
+
raw: chunk.toolCall,
|
|
4725
|
+
});
|
|
4726
|
+
yield chunk;
|
|
4727
|
+
}
|
|
4728
|
+
// Track usage from done chunk (but don't yield it yet - we'll emit our own)
|
|
4729
|
+
if (chunk.type === exports.LlmStreamChunkType.Done && chunk.usage) {
|
|
4730
|
+
state.usageItems.push(...chunk.usage);
|
|
4731
|
+
}
|
|
4732
|
+
// Pass through error chunks
|
|
4733
|
+
if (chunk.type === exports.LlmStreamChunkType.Error) {
|
|
4734
|
+
chunksYielded = true;
|
|
4735
|
+
yield chunk;
|
|
4736
|
+
}
|
|
4610
4737
|
}
|
|
4611
|
-
//
|
|
4612
|
-
if (
|
|
4613
|
-
|
|
4614
|
-
collectedToolCalls.push({
|
|
4615
|
-
callId: chunk.toolCall.id,
|
|
4616
|
-
name: chunk.toolCall.name,
|
|
4617
|
-
arguments: chunk.toolCall.arguments,
|
|
4618
|
-
raw: chunk.toolCall,
|
|
4619
|
-
});
|
|
4620
|
-
yield chunk;
|
|
4738
|
+
// Stream completed successfully
|
|
4739
|
+
if (attempt > 0) {
|
|
4740
|
+
log$1.debug(`Stream request succeeded after ${attempt} retries`);
|
|
4621
4741
|
}
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4742
|
+
break;
|
|
4743
|
+
}
|
|
4744
|
+
catch (error) {
|
|
4745
|
+
// Abort the previous request to kill lingering socket callbacks
|
|
4746
|
+
controller.abort("retry");
|
|
4747
|
+
// Install the guard immediately after abort
|
|
4748
|
+
installGuard();
|
|
4749
|
+
// If chunks were already yielded, we can't transparently retry
|
|
4750
|
+
if (chunksYielded) {
|
|
4751
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4752
|
+
log$1.error("Stream failed after partial data was delivered");
|
|
4753
|
+
log$1.var({ error });
|
|
4754
|
+
yield {
|
|
4755
|
+
type: exports.LlmStreamChunkType.Error,
|
|
4756
|
+
error: {
|
|
4757
|
+
detail: errorMessage,
|
|
4758
|
+
status: 502,
|
|
4759
|
+
title: "Stream Error",
|
|
4760
|
+
},
|
|
4761
|
+
};
|
|
4762
|
+
return { shouldContinue: false };
|
|
4625
4763
|
}
|
|
4626
|
-
//
|
|
4627
|
-
if (
|
|
4628
|
-
|
|
4629
|
-
|
|
4764
|
+
// Check if we've exhausted retries or error is not retryable
|
|
4765
|
+
if (!this.retryPolicy.shouldRetry(attempt) ||
|
|
4766
|
+
!this.adapter.isRetryableError(error)) {
|
|
4767
|
+
log$1.error(`Stream request failed after ${this.retryPolicy.maxRetries} retries`);
|
|
4768
|
+
log$1.var({ error });
|
|
4769
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4770
|
+
throw new errors.BadGatewayError(errorMessage);
|
|
4630
4771
|
}
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
if (attempt > 0) {
|
|
4634
|
-
log$1.debug(`Stream request succeeded after ${attempt} retries`);
|
|
4635
|
-
}
|
|
4636
|
-
break;
|
|
4637
|
-
}
|
|
4638
|
-
catch (error) {
|
|
4639
|
-
// Abort the previous request to kill lingering socket callbacks
|
|
4640
|
-
controller.abort("retry");
|
|
4641
|
-
// If chunks were already yielded, we can't transparently retry
|
|
4642
|
-
if (chunksYielded) {
|
|
4643
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4644
|
-
log$1.error("Stream failed after partial data was delivered");
|
|
4645
|
-
log$1.var({ error });
|
|
4646
|
-
yield {
|
|
4647
|
-
type: exports.LlmStreamChunkType.Error,
|
|
4648
|
-
error: {
|
|
4649
|
-
detail: errorMessage,
|
|
4650
|
-
status: 502,
|
|
4651
|
-
title: "Stream Error",
|
|
4652
|
-
},
|
|
4653
|
-
};
|
|
4654
|
-
return { shouldContinue: false };
|
|
4655
|
-
}
|
|
4656
|
-
// Check if we've exhausted retries or error is not retryable
|
|
4657
|
-
if (!this.retryPolicy.shouldRetry(attempt) ||
|
|
4658
|
-
!this.adapter.isRetryableError(error)) {
|
|
4659
|
-
log$1.error(`Stream request failed after ${this.retryPolicy.maxRetries} retries`);
|
|
4772
|
+
const delay = this.retryPolicy.getDelayForAttempt(attempt);
|
|
4773
|
+
log$1.warn(`Stream request failed. Retrying in ${delay}ms...`);
|
|
4660
4774
|
log$1.var({ error });
|
|
4661
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4662
|
-
throw new errors.BadGatewayError(errorMessage);
|
|
4663
|
-
}
|
|
4664
|
-
const delay = this.retryPolicy.getDelayForAttempt(attempt);
|
|
4665
|
-
log$1.warn(`Stream request failed. Retrying in ${delay}ms...`);
|
|
4666
|
-
log$1.var({ error });
|
|
4667
|
-
// Guard against stale socket errors that fire during sleep
|
|
4668
|
-
const staleHandler = (reason) => {
|
|
4669
|
-
if (isTransientNetworkError(reason)) {
|
|
4670
|
-
log$1.trace("Suppressed stale socket error during retry sleep");
|
|
4671
|
-
}
|
|
4672
|
-
};
|
|
4673
|
-
process.on("unhandledRejection", staleHandler);
|
|
4674
|
-
try {
|
|
4675
4775
|
await kit.sleep(delay);
|
|
4776
|
+
attempt++;
|
|
4676
4777
|
}
|
|
4677
|
-
finally {
|
|
4678
|
-
process.removeListener("unhandledRejection", staleHandler);
|
|
4679
|
-
}
|
|
4680
|
-
attempt++;
|
|
4681
4778
|
}
|
|
4682
4779
|
}
|
|
4780
|
+
finally {
|
|
4781
|
+
removeGuard();
|
|
4782
|
+
}
|
|
4683
4783
|
// Execute afterEachModelResponse hook
|
|
4684
4784
|
await this.hookRunnerInstance.runAfterModelResponse(context.hooks, {
|
|
4685
4785
|
content: "",
|
|
@@ -4835,10 +4935,10 @@ async function loadSdk$2() {
|
|
|
4835
4935
|
}
|
|
4836
4936
|
}
|
|
4837
4937
|
// Logger
|
|
4838
|
-
const getLogger$
|
|
4938
|
+
const getLogger$4 = () => log$2.log.lib({ lib: kit.JAYPIE.LIB.LLM });
|
|
4839
4939
|
// Client initialization
|
|
4840
|
-
async function initializeClient$
|
|
4841
|
-
const logger = getLogger$
|
|
4940
|
+
async function initializeClient$4({ apiKey, } = {}) {
|
|
4941
|
+
const logger = getLogger$4();
|
|
4842
4942
|
const resolvedApiKey = apiKey || (await aws.getEnvSecret("ANTHROPIC_API_KEY"));
|
|
4843
4943
|
if (!resolvedApiKey) {
|
|
4844
4944
|
throw new errors.ConfigurationError("The application could not resolve the required API key: ANTHROPIC_API_KEY");
|
|
@@ -4864,7 +4964,7 @@ function formatUserMessage$3(message, { data, placeholders } = {}) {
|
|
|
4864
4964
|
};
|
|
4865
4965
|
}
|
|
4866
4966
|
function prepareMessages$3(message, { data, placeholders } = {}) {
|
|
4867
|
-
const logger = getLogger$
|
|
4967
|
+
const logger = getLogger$4();
|
|
4868
4968
|
const messages = [];
|
|
4869
4969
|
// Add user message (necessary for all requests)
|
|
4870
4970
|
const userMessage = formatUserMessage$3(message, { data, placeholders });
|
|
@@ -4953,7 +5053,7 @@ async function createStructuredCompletion$1(client, messages, model, responseSch
|
|
|
4953
5053
|
// Main class implementation
|
|
4954
5054
|
class AnthropicProvider {
|
|
4955
5055
|
constructor(model = PROVIDER.ANTHROPIC.MODEL.DEFAULT, { apiKey } = {}) {
|
|
4956
|
-
this.log = getLogger$
|
|
5056
|
+
this.log = getLogger$4();
|
|
4957
5057
|
this.conversationHistory = [];
|
|
4958
5058
|
this.model = model;
|
|
4959
5059
|
this.apiKey = apiKey;
|
|
@@ -4962,7 +5062,7 @@ class AnthropicProvider {
|
|
|
4962
5062
|
if (this._client) {
|
|
4963
5063
|
return this._client;
|
|
4964
5064
|
}
|
|
4965
|
-
this._client = await initializeClient$
|
|
5065
|
+
this._client = await initializeClient$4({ apiKey: this.apiKey });
|
|
4966
5066
|
return this._client;
|
|
4967
5067
|
}
|
|
4968
5068
|
async getOperateLoop() {
|
|
@@ -5051,10 +5151,10 @@ async function loadSdk$1() {
|
|
|
5051
5151
|
}
|
|
5052
5152
|
}
|
|
5053
5153
|
// Logger
|
|
5054
|
-
const getLogger$
|
|
5154
|
+
const getLogger$3 = () => log$2.log.lib({ lib: kit.JAYPIE.LIB.LLM });
|
|
5055
5155
|
// Client initialization
|
|
5056
|
-
async function initializeClient$
|
|
5057
|
-
const logger = getLogger$
|
|
5156
|
+
async function initializeClient$3({ apiKey, } = {}) {
|
|
5157
|
+
const logger = getLogger$3();
|
|
5058
5158
|
const resolvedApiKey = apiKey || (await aws.getEnvSecret("GEMINI_API_KEY"));
|
|
5059
5159
|
if (!resolvedApiKey) {
|
|
5060
5160
|
throw new errors.ConfigurationError("The application could not resolve the requested keys");
|
|
@@ -5074,7 +5174,7 @@ function formatUserMessage$2(message, { data, placeholders } = {}) {
|
|
|
5074
5174
|
};
|
|
5075
5175
|
}
|
|
5076
5176
|
function prepareMessages$2(message, { data, placeholders } = {}) {
|
|
5077
|
-
const logger = getLogger$
|
|
5177
|
+
const logger = getLogger$3();
|
|
5078
5178
|
const messages = [];
|
|
5079
5179
|
let systemInstruction;
|
|
5080
5180
|
// Note: Gemini handles system prompts differently via systemInstruction config
|
|
@@ -5088,7 +5188,7 @@ function prepareMessages$2(message, { data, placeholders } = {}) {
|
|
|
5088
5188
|
|
|
5089
5189
|
class GeminiProvider {
|
|
5090
5190
|
constructor(model = PROVIDER.GEMINI.MODEL.DEFAULT, { apiKey } = {}) {
|
|
5091
|
-
this.log = getLogger$
|
|
5191
|
+
this.log = getLogger$3();
|
|
5092
5192
|
this.conversationHistory = [];
|
|
5093
5193
|
this.model = model;
|
|
5094
5194
|
this.apiKey = apiKey;
|
|
@@ -5097,7 +5197,7 @@ class GeminiProvider {
|
|
|
5097
5197
|
if (this._client) {
|
|
5098
5198
|
return this._client;
|
|
5099
5199
|
}
|
|
5100
|
-
this._client = await initializeClient$
|
|
5200
|
+
this._client = await initializeClient$3({ apiKey: this.apiKey });
|
|
5101
5201
|
return this._client;
|
|
5102
5202
|
}
|
|
5103
5203
|
async getOperateLoop() {
|
|
@@ -5202,10 +5302,10 @@ class GeminiProvider {
|
|
|
5202
5302
|
}
|
|
5203
5303
|
|
|
5204
5304
|
// Logger
|
|
5205
|
-
const getLogger$
|
|
5305
|
+
const getLogger$2 = () => log$2.log.lib({ lib: kit.JAYPIE.LIB.LLM });
|
|
5206
5306
|
// Client initialization
|
|
5207
|
-
async function initializeClient$
|
|
5208
|
-
const logger = getLogger$
|
|
5307
|
+
async function initializeClient$2({ apiKey, } = {}) {
|
|
5308
|
+
const logger = getLogger$2();
|
|
5209
5309
|
const resolvedApiKey = apiKey || (await aws.getEnvSecret("OPENAI_API_KEY"));
|
|
5210
5310
|
if (!resolvedApiKey) {
|
|
5211
5311
|
throw new errors.ConfigurationError("The application could not resolve the requested keys");
|
|
@@ -5233,7 +5333,7 @@ function formatUserMessage$1(message, { data, placeholders } = {}) {
|
|
|
5233
5333
|
};
|
|
5234
5334
|
}
|
|
5235
5335
|
function prepareMessages$1(message, { system, data, placeholders } = {}) {
|
|
5236
|
-
const logger = getLogger$
|
|
5336
|
+
const logger = getLogger$2();
|
|
5237
5337
|
const messages = [];
|
|
5238
5338
|
if (system) {
|
|
5239
5339
|
const systemMessage = formatSystemMessage$1(system, { data, placeholders });
|
|
@@ -5247,7 +5347,7 @@ function prepareMessages$1(message, { system, data, placeholders } = {}) {
|
|
|
5247
5347
|
}
|
|
5248
5348
|
// Completion requests
|
|
5249
5349
|
async function createStructuredCompletion(client, { messages, responseSchema, model, }) {
|
|
5250
|
-
const logger = getLogger$
|
|
5350
|
+
const logger = getLogger$2();
|
|
5251
5351
|
logger.trace("Using structured output");
|
|
5252
5352
|
const zodSchema = responseSchema instanceof v4.z.ZodType
|
|
5253
5353
|
? responseSchema
|
|
@@ -5278,7 +5378,7 @@ async function createStructuredCompletion(client, { messages, responseSchema, mo
|
|
|
5278
5378
|
return completion.choices[0].message.parsed;
|
|
5279
5379
|
}
|
|
5280
5380
|
async function createTextCompletion(client, { messages, model, }) {
|
|
5281
|
-
const logger = getLogger$
|
|
5381
|
+
const logger = getLogger$2();
|
|
5282
5382
|
logger.trace("Using text output (unstructured)");
|
|
5283
5383
|
const completion = await client.chat.completions.create({
|
|
5284
5384
|
messages,
|
|
@@ -5290,7 +5390,7 @@ async function createTextCompletion(client, { messages, model, }) {
|
|
|
5290
5390
|
|
|
5291
5391
|
class OpenAiProvider {
|
|
5292
5392
|
constructor(model = PROVIDER.OPENAI.MODEL.DEFAULT, { apiKey } = {}) {
|
|
5293
|
-
this.log = getLogger$
|
|
5393
|
+
this.log = getLogger$2();
|
|
5294
5394
|
this.conversationHistory = [];
|
|
5295
5395
|
this.model = model;
|
|
5296
5396
|
this.apiKey = apiKey;
|
|
@@ -5299,7 +5399,7 @@ class OpenAiProvider {
|
|
|
5299
5399
|
if (this._client) {
|
|
5300
5400
|
return this._client;
|
|
5301
5401
|
}
|
|
5302
|
-
this._client = await initializeClient$
|
|
5402
|
+
this._client = await initializeClient$2({ apiKey: this.apiKey });
|
|
5303
5403
|
return this._client;
|
|
5304
5404
|
}
|
|
5305
5405
|
async getOperateLoop() {
|
|
@@ -5386,10 +5486,10 @@ async function loadSdk() {
|
|
|
5386
5486
|
}
|
|
5387
5487
|
}
|
|
5388
5488
|
// Logger
|
|
5389
|
-
const getLogger = () => log$2.log.lib({ lib: kit.JAYPIE.LIB.LLM });
|
|
5489
|
+
const getLogger$1 = () => log$2.log.lib({ lib: kit.JAYPIE.LIB.LLM });
|
|
5390
5490
|
// Client initialization
|
|
5391
|
-
async function initializeClient({ apiKey, } = {}) {
|
|
5392
|
-
const logger = getLogger();
|
|
5491
|
+
async function initializeClient$1({ apiKey, } = {}) {
|
|
5492
|
+
const logger = getLogger$1();
|
|
5393
5493
|
const resolvedApiKey = apiKey || (await aws.getEnvSecret("OPENROUTER_API_KEY"));
|
|
5394
5494
|
if (!resolvedApiKey) {
|
|
5395
5495
|
throw new errors.ConfigurationError("The application could not resolve the requested keys");
|
|
@@ -5422,7 +5522,7 @@ function formatUserMessage(message, { data, placeholders } = {}) {
|
|
|
5422
5522
|
};
|
|
5423
5523
|
}
|
|
5424
5524
|
function prepareMessages(message, { system, data, placeholders } = {}) {
|
|
5425
|
-
const logger = getLogger();
|
|
5525
|
+
const logger = getLogger$1();
|
|
5426
5526
|
const messages = [];
|
|
5427
5527
|
if (system) {
|
|
5428
5528
|
const systemMessage = formatSystemMessage(system, { data, placeholders });
|
|
@@ -5437,7 +5537,7 @@ function prepareMessages(message, { system, data, placeholders } = {}) {
|
|
|
5437
5537
|
|
|
5438
5538
|
class OpenRouterProvider {
|
|
5439
5539
|
constructor(model = getDefaultModel(), { apiKey } = {}) {
|
|
5440
|
-
this.log = getLogger();
|
|
5540
|
+
this.log = getLogger$1();
|
|
5441
5541
|
this.conversationHistory = [];
|
|
5442
5542
|
this.model = model;
|
|
5443
5543
|
this.apiKey = apiKey;
|
|
@@ -5446,7 +5546,7 @@ class OpenRouterProvider {
|
|
|
5446
5546
|
if (this._client) {
|
|
5447
5547
|
return this._client;
|
|
5448
5548
|
}
|
|
5449
|
-
this._client = await initializeClient({ apiKey: this.apiKey });
|
|
5549
|
+
this._client = await initializeClient$1({ apiKey: this.apiKey });
|
|
5450
5550
|
return this._client;
|
|
5451
5551
|
}
|
|
5452
5552
|
async getOperateLoop() {
|
|
@@ -5534,6 +5634,107 @@ class OpenRouterProvider {
|
|
|
5534
5634
|
}
|
|
5535
5635
|
}
|
|
5536
5636
|
|
|
5637
|
+
// Logger
|
|
5638
|
+
const getLogger = () => log$2.log.lib({ lib: kit.JAYPIE.LIB.LLM });
|
|
5639
|
+
// Client initialization
|
|
5640
|
+
async function initializeClient({ apiKey, } = {}) {
|
|
5641
|
+
const logger = getLogger();
|
|
5642
|
+
const resolvedApiKey = apiKey || (await aws.getEnvSecret(PROVIDER.XAI.API_KEY));
|
|
5643
|
+
if (!resolvedApiKey) {
|
|
5644
|
+
throw new errors.ConfigurationError("The application could not resolve the requested keys");
|
|
5645
|
+
}
|
|
5646
|
+
const client = new openai.OpenAI({
|
|
5647
|
+
apiKey: resolvedApiKey,
|
|
5648
|
+
baseURL: PROVIDER.XAI.BASE_URL,
|
|
5649
|
+
});
|
|
5650
|
+
logger.trace("Initialized xAI client");
|
|
5651
|
+
return client;
|
|
5652
|
+
}
|
|
5653
|
+
|
|
5654
|
+
class XaiProvider {
|
|
5655
|
+
constructor(model = PROVIDER.XAI.MODEL.DEFAULT, { apiKey } = {}) {
|
|
5656
|
+
this.log = getLogger$2();
|
|
5657
|
+
this.conversationHistory = [];
|
|
5658
|
+
this.model = model;
|
|
5659
|
+
this.apiKey = apiKey;
|
|
5660
|
+
}
|
|
5661
|
+
async getClient() {
|
|
5662
|
+
if (this._client) {
|
|
5663
|
+
return this._client;
|
|
5664
|
+
}
|
|
5665
|
+
this._client = await initializeClient({ apiKey: this.apiKey });
|
|
5666
|
+
return this._client;
|
|
5667
|
+
}
|
|
5668
|
+
async getOperateLoop() {
|
|
5669
|
+
if (this._operateLoop) {
|
|
5670
|
+
return this._operateLoop;
|
|
5671
|
+
}
|
|
5672
|
+
const client = await this.getClient();
|
|
5673
|
+
this._operateLoop = createOperateLoop({
|
|
5674
|
+
adapter: xaiAdapter,
|
|
5675
|
+
client,
|
|
5676
|
+
});
|
|
5677
|
+
return this._operateLoop;
|
|
5678
|
+
}
|
|
5679
|
+
async getStreamLoop() {
|
|
5680
|
+
if (this._streamLoop) {
|
|
5681
|
+
return this._streamLoop;
|
|
5682
|
+
}
|
|
5683
|
+
const client = await this.getClient();
|
|
5684
|
+
this._streamLoop = createStreamLoop({
|
|
5685
|
+
adapter: xaiAdapter,
|
|
5686
|
+
client,
|
|
5687
|
+
});
|
|
5688
|
+
return this._streamLoop;
|
|
5689
|
+
}
|
|
5690
|
+
async send(message, options) {
|
|
5691
|
+
const client = await this.getClient();
|
|
5692
|
+
const messages = prepareMessages$1(message, options || {});
|
|
5693
|
+
const modelToUse = options?.model || this.model;
|
|
5694
|
+
if (options?.response) {
|
|
5695
|
+
return createStructuredCompletion(client, {
|
|
5696
|
+
messages,
|
|
5697
|
+
responseSchema: options.response,
|
|
5698
|
+
model: modelToUse,
|
|
5699
|
+
});
|
|
5700
|
+
}
|
|
5701
|
+
return createTextCompletion(client, {
|
|
5702
|
+
messages,
|
|
5703
|
+
model: modelToUse,
|
|
5704
|
+
});
|
|
5705
|
+
}
|
|
5706
|
+
async operate(input, options = {}) {
|
|
5707
|
+
const operateLoop = await this.getOperateLoop();
|
|
5708
|
+
const mergedOptions = { ...options, model: options.model ?? this.model };
|
|
5709
|
+
// Create a merged history including both the tracked history and any explicitly provided history
|
|
5710
|
+
if (this.conversationHistory.length > 0) {
|
|
5711
|
+
// If options.history exists, merge with instance history, otherwise use instance history
|
|
5712
|
+
mergedOptions.history = options.history
|
|
5713
|
+
? [...this.conversationHistory, ...options.history]
|
|
5714
|
+
: [...this.conversationHistory];
|
|
5715
|
+
}
|
|
5716
|
+
// Execute operate loop
|
|
5717
|
+
const response = await operateLoop.execute(input, mergedOptions);
|
|
5718
|
+
// Update conversation history with the new history from the response
|
|
5719
|
+
if (response.history && response.history.length > 0) {
|
|
5720
|
+
this.conversationHistory = response.history;
|
|
5721
|
+
}
|
|
5722
|
+
return response;
|
|
5723
|
+
}
|
|
5724
|
+
async *stream(input, options = {}) {
|
|
5725
|
+
const streamLoop = await this.getStreamLoop();
|
|
5726
|
+
const mergedOptions = { ...options, model: options.model ?? this.model };
|
|
5727
|
+
// Create a merged history including both the tracked history and any explicitly provided history
|
|
5728
|
+
if (this.conversationHistory.length > 0) {
|
|
5729
|
+
mergedOptions.history = options.history
|
|
5730
|
+
? [...this.conversationHistory, ...options.history]
|
|
5731
|
+
: [...this.conversationHistory];
|
|
5732
|
+
}
|
|
5733
|
+
// Execute stream loop
|
|
5734
|
+
yield* streamLoop.execute(input, mergedOptions);
|
|
5735
|
+
}
|
|
5736
|
+
}
|
|
5737
|
+
|
|
5537
5738
|
class Llm {
|
|
5538
5739
|
constructor(providerName = DEFAULT.PROVIDER.NAME, options = {}) {
|
|
5539
5740
|
const { fallback, model } = options;
|
|
@@ -5595,6 +5796,10 @@ class Llm {
|
|
|
5595
5796
|
return new OpenRouterProvider(model || PROVIDER.OPENROUTER.MODEL.DEFAULT, {
|
|
5596
5797
|
apiKey,
|
|
5597
5798
|
});
|
|
5799
|
+
case PROVIDER.XAI.NAME:
|
|
5800
|
+
return new XaiProvider(model || PROVIDER.XAI.MODEL.DEFAULT, {
|
|
5801
|
+
apiKey,
|
|
5802
|
+
});
|
|
5598
5803
|
default:
|
|
5599
5804
|
throw new errors.ConfigurationError(`Unsupported provider: ${providerName}`);
|
|
5600
5805
|
}
|
|
@@ -6039,6 +6244,7 @@ exports.LLM = constants;
|
|
|
6039
6244
|
exports.Llm = Llm;
|
|
6040
6245
|
exports.OpenRouterProvider = OpenRouterProvider;
|
|
6041
6246
|
exports.Toolkit = Toolkit;
|
|
6247
|
+
exports.XaiProvider = XaiProvider;
|
|
6042
6248
|
exports.extractReasoning = extractReasoning;
|
|
6043
6249
|
exports.isLlmOperateInput = isLlmOperateInput;
|
|
6044
6250
|
exports.isLlmOperateInputContent = isLlmOperateInputContent;
|