@backtest-kit/ollama 14.1.0 → 15.0.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 +287 -287
- package/build/index.cjs +224 -160
- package/build/index.mjs +226 -162
- package/package.json +114 -112
- package/types.d.ts +16 -14
package/build/index.cjs
CHANGED
|
@@ -297,7 +297,9 @@ const TYPES = {
|
|
|
297
297
|
...publicServices$1,
|
|
298
298
|
};
|
|
299
299
|
|
|
300
|
-
|
|
300
|
+
// Symbol.for keeps the brand check working when CJS and ESM copies of the
|
|
301
|
+
// package end up in the same process (dual-package hazard).
|
|
302
|
+
const PROMPT_TYPE_SYMBOL = Symbol.for("backtest-kit.ollama.prompt-type");
|
|
301
303
|
class Prompt {
|
|
302
304
|
constructor(source) {
|
|
303
305
|
this.source = source;
|
|
@@ -317,7 +319,7 @@ Prompt.isPrompt = (value) => {
|
|
|
317
319
|
};
|
|
318
320
|
|
|
319
321
|
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
320
|
-
const REQUIRE_MODULE_FN = functoolsKit.memoize(([module]) => module, (module) => {
|
|
322
|
+
const REQUIRE_MODULE_FN = functoolsKit.memoize(([module]) => path.join(module.baseDir, module.path), (module) => {
|
|
321
323
|
const modulePath = require$1.resolve(path.join(module.baseDir, module.path));
|
|
322
324
|
return require$1(modulePath);
|
|
323
325
|
});
|
|
@@ -337,7 +339,8 @@ class PromptCacheService {
|
|
|
337
339
|
module,
|
|
338
340
|
});
|
|
339
341
|
if (module) {
|
|
340
|
-
REQUIRE_MODULE_FN.clear(module);
|
|
342
|
+
REQUIRE_MODULE_FN.clear(path.join(module.baseDir, module.path));
|
|
343
|
+
return;
|
|
341
344
|
}
|
|
342
345
|
REQUIRE_MODULE_FN.clear();
|
|
343
346
|
};
|
|
@@ -898,6 +901,13 @@ const toPlainString = async (content) => {
|
|
|
898
901
|
typographer: true,
|
|
899
902
|
});
|
|
900
903
|
let telegramHtml = md.render(markdown);
|
|
904
|
+
// sanitize-html transformTags cannot insert text content, so list markers
|
|
905
|
+
// are injected into the HTML as text before sanitizing.
|
|
906
|
+
telegramHtml = telegramHtml.replace(/<ol[^>]*>[\s\S]*?<\/ol>/g, (block) => {
|
|
907
|
+
let counter = 0;
|
|
908
|
+
return block.replace(/<li>/g, () => `<li>${++counter}. `);
|
|
909
|
+
});
|
|
910
|
+
telegramHtml = telegramHtml.replace(/<li>(?!\d+\. )/g, "<li>• ");
|
|
901
911
|
telegramHtml = sanitizeHtml(telegramHtml, {
|
|
902
912
|
allowedTags: [
|
|
903
913
|
"b",
|
|
@@ -926,7 +936,7 @@ const toPlainString = async (content) => {
|
|
|
926
936
|
em: "",
|
|
927
937
|
p: () => "",
|
|
928
938
|
ul: () => "",
|
|
929
|
-
li: () => "
|
|
939
|
+
li: () => "",
|
|
930
940
|
ol: () => "",
|
|
931
941
|
hr: () => "\n",
|
|
932
942
|
br: () => "\n",
|
|
@@ -1195,6 +1205,10 @@ class OptimizerTemplateService {
|
|
|
1195
1205
|
``,
|
|
1196
1206
|
` await dumpJson(resultId, messages, result);`,
|
|
1197
1207
|
``,
|
|
1208
|
+
` if (result.position === "wait") {`,
|
|
1209
|
+
` return null;`,
|
|
1210
|
+
` }`,
|
|
1211
|
+
``,
|
|
1198
1212
|
` result.id = resultId;`,
|
|
1199
1213
|
``,
|
|
1200
1214
|
` return result;`,
|
|
@@ -1881,8 +1895,9 @@ const GET_STRATEGY_DATA_FN = async (symbol, self) => {
|
|
|
1881
1895
|
const strategyList = [];
|
|
1882
1896
|
const totalSources = self.params.rangeTrain.length * self.params.source.length;
|
|
1883
1897
|
let processedSources = 0;
|
|
1884
|
-
for (const { startDate, endDate } of self.params.rangeTrain) {
|
|
1898
|
+
for (const { note, startDate, endDate } of self.params.rangeTrain) {
|
|
1885
1899
|
const messageList = [];
|
|
1900
|
+
const sourceNames = [];
|
|
1886
1901
|
for (const source of self.params.source) {
|
|
1887
1902
|
// Emit progress event at the start of processing each source
|
|
1888
1903
|
await self.onProgress({
|
|
@@ -1910,6 +1925,7 @@ const GET_STRATEGY_DATA_FN = async (symbol, self) => {
|
|
|
1910
1925
|
role: "assistant",
|
|
1911
1926
|
content: assistantContent,
|
|
1912
1927
|
});
|
|
1928
|
+
sourceNames.push(DEFAULT_SOURCE_NAME);
|
|
1913
1929
|
processedSources++;
|
|
1914
1930
|
}
|
|
1915
1931
|
else {
|
|
@@ -1931,18 +1947,19 @@ const GET_STRATEGY_DATA_FN = async (symbol, self) => {
|
|
|
1931
1947
|
role: "assistant",
|
|
1932
1948
|
content: assistantContent,
|
|
1933
1949
|
});
|
|
1950
|
+
sourceNames.push(name || DEFAULT_SOURCE_NAME);
|
|
1934
1951
|
processedSources++;
|
|
1935
1952
|
}
|
|
1936
|
-
const name = "name" in source
|
|
1937
|
-
? source.name || DEFAULT_SOURCE_NAME
|
|
1938
|
-
: DEFAULT_SOURCE_NAME;
|
|
1939
|
-
strategyList.push({
|
|
1940
|
-
symbol,
|
|
1941
|
-
name,
|
|
1942
|
-
messages: messageList,
|
|
1943
|
-
strategy: await self.params.getPrompt(symbol, messageList),
|
|
1944
|
-
});
|
|
1945
1953
|
}
|
|
1954
|
+
// One strategy per training range: getPrompt receives the complete
|
|
1955
|
+
// conversation history with all sources (see IOptimizerSchema.getPrompt).
|
|
1956
|
+
// Messages are snapshotted so later ranges cannot mutate this strategy.
|
|
1957
|
+
strategyList.push({
|
|
1958
|
+
symbol,
|
|
1959
|
+
name: note || sourceNames.join("+") || DEFAULT_SOURCE_NAME,
|
|
1960
|
+
messages: [...messageList],
|
|
1961
|
+
strategy: await self.params.getPrompt(symbol, messageList),
|
|
1962
|
+
});
|
|
1946
1963
|
}
|
|
1947
1964
|
// Emit final progress event (100%)
|
|
1948
1965
|
await self.onProgress({
|
|
@@ -2048,7 +2065,7 @@ const GET_STRATEGY_CODE_FN = async (symbol, self) => {
|
|
|
2048
2065
|
const GET_STRATEGY_DUMP_FN = async (symbol, path$1, self) => {
|
|
2049
2066
|
const report = await self.getCode(symbol);
|
|
2050
2067
|
try {
|
|
2051
|
-
const dir = path.join(process.cwd(), path$1);
|
|
2068
|
+
const dir = path.isAbsolute(path$1) ? path$1 : path.join(process.cwd(), path$1);
|
|
2052
2069
|
await fs.mkdir(dir, { recursive: true });
|
|
2053
2070
|
const filename = `${self.params.optimizerName}_${symbol}.mjs`;
|
|
2054
2071
|
const filepath = path.join(dir, filename);
|
|
@@ -2438,17 +2455,17 @@ var InferenceName$1 = InferenceName;
|
|
|
2438
2455
|
* });
|
|
2439
2456
|
* ```
|
|
2440
2457
|
*/
|
|
2441
|
-
const
|
|
2458
|
+
const GET_CLIENT_FN$9 = functoolsKit.memoize(([apiKey]) => `${apiKey}`, (apiKey) => new OpenAI({
|
|
2459
|
+
baseURL: "https://api.x.ai/v1",
|
|
2460
|
+
apiKey,
|
|
2461
|
+
}));
|
|
2462
|
+
const getGrok = () => {
|
|
2442
2463
|
const apiKey = engine$1.contextService.context.apiKey;
|
|
2443
2464
|
if (Array.isArray(apiKey)) {
|
|
2444
|
-
getGrok.clear();
|
|
2445
2465
|
throw new Error("Grok provider does not support token rotation");
|
|
2446
2466
|
}
|
|
2447
|
-
return
|
|
2448
|
-
|
|
2449
|
-
apiKey: apiKey,
|
|
2450
|
-
});
|
|
2451
|
-
});
|
|
2467
|
+
return GET_CLIENT_FN$9(apiKey);
|
|
2468
|
+
};
|
|
2452
2469
|
|
|
2453
2470
|
/**
|
|
2454
2471
|
* Global configuration parameters for the Ollama package.
|
|
@@ -2584,7 +2601,7 @@ class GrokProvider {
|
|
|
2584
2601
|
},
|
|
2585
2602
|
});
|
|
2586
2603
|
const result = {
|
|
2587
|
-
content: content,
|
|
2604
|
+
content: content ?? "",
|
|
2588
2605
|
mode,
|
|
2589
2606
|
agentName,
|
|
2590
2607
|
role,
|
|
@@ -2744,8 +2761,8 @@ class GrokProvider {
|
|
|
2744
2761
|
Authorization: `Bearer ${this.contextService.context.apiKey}`,
|
|
2745
2762
|
},
|
|
2746
2763
|
body: JSON.stringify({
|
|
2764
|
+
model: this.contextService.context.model,
|
|
2747
2765
|
messages,
|
|
2748
|
-
context: this.contextService.context,
|
|
2749
2766
|
max_tokens: 5000,
|
|
2750
2767
|
response_format: format,
|
|
2751
2768
|
}),
|
|
@@ -3131,7 +3148,12 @@ class HfProvider {
|
|
|
3131
3148
|
continue;
|
|
3132
3149
|
}
|
|
3133
3150
|
lodashEs.set(validation.data, "_thinking", reasoning_content);
|
|
3134
|
-
|
|
3151
|
+
{
|
|
3152
|
+
// apiKey must never reach the outline result: it gets dumped to
|
|
3153
|
+
// markdown files and forwarded to downstream consumers.
|
|
3154
|
+
const { inference, model } = this.contextService.context;
|
|
3155
|
+
lodashEs.set(validation.data, "_context", { inference, model });
|
|
3156
|
+
}
|
|
3135
3157
|
const result = {
|
|
3136
3158
|
role: "assistant",
|
|
3137
3159
|
content: JSON.stringify(validation.data),
|
|
@@ -3166,10 +3188,12 @@ class HfProvider {
|
|
|
3166
3188
|
* @throws Error if no API keys are provided in context
|
|
3167
3189
|
*/
|
|
3168
3190
|
class OllamaWrapper {
|
|
3169
|
-
constructor(_config) {
|
|
3191
|
+
constructor(_config, apiKeys) {
|
|
3170
3192
|
this._config = _config;
|
|
3171
|
-
|
|
3172
|
-
|
|
3193
|
+
if (!apiKeys?.length) {
|
|
3194
|
+
throw new Error("OllamaRotate required apiKey[] to process token rotation");
|
|
3195
|
+
}
|
|
3196
|
+
this._chatFn = agentSwarmKit.RoundRobin.create(apiKeys, (token) => {
|
|
3173
3197
|
const ollama = new ollama$1.Ollama({
|
|
3174
3198
|
...this._config,
|
|
3175
3199
|
headers: {
|
|
@@ -3185,9 +3209,6 @@ class OllamaWrapper {
|
|
|
3185
3209
|
}
|
|
3186
3210
|
};
|
|
3187
3211
|
});
|
|
3188
|
-
if (!engine$1.contextService.context.apiKey) {
|
|
3189
|
-
throw new Error("OllamaRotate required apiKey[] to process token rotation");
|
|
3190
|
-
}
|
|
3191
3212
|
}
|
|
3192
3213
|
/**
|
|
3193
3214
|
* Executes a chat request with automatic token rotation.
|
|
@@ -3220,10 +3241,28 @@ class OllamaWrapper {
|
|
|
3220
3241
|
* // Next request will use a different API key
|
|
3221
3242
|
* ```
|
|
3222
3243
|
*/
|
|
3223
|
-
const
|
|
3244
|
+
const GET_WRAPPER_FN = functoolsKit.memoize(([apiKeys]) => apiKeys.join(","), (apiKeys) => new OllamaWrapper({
|
|
3224
3245
|
host: "https://ollama.com",
|
|
3225
|
-
}));
|
|
3246
|
+
}, apiKeys));
|
|
3247
|
+
const getOllamaRotate = () => {
|
|
3248
|
+
const apiKey = engine$1.contextService.context.apiKey;
|
|
3249
|
+
if (!Array.isArray(apiKey)) {
|
|
3250
|
+
throw new Error("OllamaRotate required apiKey[] to process token rotation");
|
|
3251
|
+
}
|
|
3252
|
+
return GET_WRAPPER_FN(apiKey);
|
|
3253
|
+
};
|
|
3226
3254
|
|
|
3255
|
+
const GET_CLIENT_FN$8 = functoolsKit.memoize(([apiKey]) => `${apiKey ?? ""}`, (apiKey) => {
|
|
3256
|
+
if (!apiKey) {
|
|
3257
|
+
return new ollama$1.Ollama();
|
|
3258
|
+
}
|
|
3259
|
+
return new ollama$1.Ollama({
|
|
3260
|
+
host: "https://ollama.com",
|
|
3261
|
+
headers: {
|
|
3262
|
+
Authorization: `Bearer ${apiKey}`,
|
|
3263
|
+
},
|
|
3264
|
+
});
|
|
3265
|
+
});
|
|
3227
3266
|
/**
|
|
3228
3267
|
* Creates and caches an Ollama client with flexible configuration.
|
|
3229
3268
|
*
|
|
@@ -3269,21 +3308,13 @@ const getOllamaRotate = functoolsKit.singleshot(() => new OllamaWrapper({
|
|
|
3269
3308
|
* });
|
|
3270
3309
|
* ```
|
|
3271
3310
|
*/
|
|
3272
|
-
const getOllama =
|
|
3311
|
+
const getOllama = () => {
|
|
3273
3312
|
const apiKey = engine$1.contextService.context.apiKey;
|
|
3274
3313
|
if (Array.isArray(apiKey)) {
|
|
3275
3314
|
return getOllamaRotate();
|
|
3276
3315
|
}
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
}
|
|
3280
|
-
return new ollama$1.Ollama({
|
|
3281
|
-
host: "https://ollama.com",
|
|
3282
|
-
headers: {
|
|
3283
|
-
Authorization: `Bearer ${apiKey}`,
|
|
3284
|
-
},
|
|
3285
|
-
});
|
|
3286
|
-
});
|
|
3316
|
+
return GET_CLIENT_FN$8(apiKey);
|
|
3317
|
+
};
|
|
3287
3318
|
|
|
3288
3319
|
/**
|
|
3289
3320
|
* Maximum number of retry attempts for outline completion when model fails to use tools correctly.
|
|
@@ -3617,7 +3648,12 @@ class OllamaProvider {
|
|
|
3617
3648
|
attempt++;
|
|
3618
3649
|
continue;
|
|
3619
3650
|
}
|
|
3620
|
-
|
|
3651
|
+
{
|
|
3652
|
+
// apiKey must never reach the outline result: it gets dumped to
|
|
3653
|
+
// markdown files and forwarded to downstream consumers.
|
|
3654
|
+
const { inference, model } = this.contextService.context;
|
|
3655
|
+
lodashEs.set(validation.data, "_context", { inference, model });
|
|
3656
|
+
}
|
|
3621
3657
|
const result = {
|
|
3622
3658
|
role: "assistant",
|
|
3623
3659
|
content: JSON.stringify(validation.data),
|
|
@@ -3636,6 +3672,10 @@ class OllamaProvider {
|
|
|
3636
3672
|
}
|
|
3637
3673
|
}
|
|
3638
3674
|
|
|
3675
|
+
const GET_CLIENT_FN$7 = functoolsKit.memoize(([apiKey]) => `${apiKey}`, (apiKey) => new OpenAI({
|
|
3676
|
+
baseURL: "https://api.anthropic.com/v1/",
|
|
3677
|
+
apiKey,
|
|
3678
|
+
}));
|
|
3639
3679
|
/**
|
|
3640
3680
|
* Creates and caches an OpenAI-compatible client for Claude (Anthropic) API.
|
|
3641
3681
|
*
|
|
@@ -3663,17 +3703,13 @@ class OllamaProvider {
|
|
|
3663
3703
|
* });
|
|
3664
3704
|
* ```
|
|
3665
3705
|
*/
|
|
3666
|
-
const getClaude =
|
|
3706
|
+
const getClaude = () => {
|
|
3667
3707
|
const apiKey = engine$1.contextService.context.apiKey;
|
|
3668
3708
|
if (Array.isArray(apiKey)) {
|
|
3669
|
-
getClaude.clear();
|
|
3670
3709
|
throw new Error("Claude provider does not support token rotation");
|
|
3671
3710
|
}
|
|
3672
|
-
return
|
|
3673
|
-
|
|
3674
|
-
apiKey,
|
|
3675
|
-
});
|
|
3676
|
-
});
|
|
3711
|
+
return GET_CLIENT_FN$7(apiKey);
|
|
3712
|
+
};
|
|
3677
3713
|
|
|
3678
3714
|
/**
|
|
3679
3715
|
* Maximum number of retry attempts for outline completion when model fails to use tools correctly.
|
|
@@ -3776,7 +3812,7 @@ class ClaudeProvider {
|
|
|
3776
3812
|
}
|
|
3777
3813
|
const { choices: [{ message: { content, role, tool_calls }, },], } = await claude.chat.completions.create(requestOptions);
|
|
3778
3814
|
const result = {
|
|
3779
|
-
content: content,
|
|
3815
|
+
content: content ?? "",
|
|
3780
3816
|
mode,
|
|
3781
3817
|
agentName,
|
|
3782
3818
|
role,
|
|
@@ -3857,7 +3893,7 @@ class ClaudeProvider {
|
|
|
3857
3893
|
};
|
|
3858
3894
|
// Debug logging
|
|
3859
3895
|
if (GLOBAL_CONFIG.CC_ENABLE_DEBUG) {
|
|
3860
|
-
await fs.appendFile("./
|
|
3896
|
+
await fs.appendFile("./debug_claude_provider_stream.txt", JSON.stringify({ params, answer: result }, null, 2) + "\n\n");
|
|
3861
3897
|
}
|
|
3862
3898
|
return result;
|
|
3863
3899
|
}
|
|
@@ -3960,7 +3996,12 @@ class ClaudeProvider {
|
|
|
3960
3996
|
attempt++;
|
|
3961
3997
|
continue;
|
|
3962
3998
|
}
|
|
3963
|
-
|
|
3999
|
+
{
|
|
4000
|
+
// apiKey must never reach the outline result: it gets dumped to
|
|
4001
|
+
// markdown files and forwarded to downstream consumers.
|
|
4002
|
+
const { inference, model } = this.contextService.context;
|
|
4003
|
+
lodashEs.set(validation.data, "_context", { inference, model });
|
|
4004
|
+
}
|
|
3964
4005
|
const result = {
|
|
3965
4006
|
role: "assistant",
|
|
3966
4007
|
content: JSON.stringify(validation.data),
|
|
@@ -3979,6 +4020,9 @@ class ClaudeProvider {
|
|
|
3979
4020
|
}
|
|
3980
4021
|
}
|
|
3981
4022
|
|
|
4023
|
+
const GET_CLIENT_FN$6 = functoolsKit.memoize(([apiKey]) => `${apiKey}`, (apiKey) => new OpenAI({
|
|
4024
|
+
apiKey,
|
|
4025
|
+
}));
|
|
3982
4026
|
/**
|
|
3983
4027
|
* Creates and caches an OpenAI client for OpenAI API.
|
|
3984
4028
|
*
|
|
@@ -4006,16 +4050,13 @@ class ClaudeProvider {
|
|
|
4006
4050
|
* });
|
|
4007
4051
|
* ```
|
|
4008
4052
|
*/
|
|
4009
|
-
const getOpenAi =
|
|
4053
|
+
const getOpenAi = () => {
|
|
4010
4054
|
const apiKey = engine$1.contextService.context.apiKey;
|
|
4011
4055
|
if (Array.isArray(apiKey)) {
|
|
4012
|
-
getOpenAi.clear();
|
|
4013
4056
|
throw new Error("OpenAI provider does not support token rotation");
|
|
4014
4057
|
}
|
|
4015
|
-
return
|
|
4016
|
-
|
|
4017
|
-
});
|
|
4018
|
-
});
|
|
4058
|
+
return GET_CLIENT_FN$6(apiKey);
|
|
4059
|
+
};
|
|
4019
4060
|
|
|
4020
4061
|
/**
|
|
4021
4062
|
* Provider for OpenAI GPT models (GPT-4, GPT-4 Turbo, GPT-3.5, etc.).
|
|
@@ -4132,7 +4173,7 @@ class GPT5Provider {
|
|
|
4132
4173
|
tools: tools,
|
|
4133
4174
|
});
|
|
4134
4175
|
const result = {
|
|
4135
|
-
content: content,
|
|
4176
|
+
content: content ?? "",
|
|
4136
4177
|
mode,
|
|
4137
4178
|
agentName,
|
|
4138
4179
|
role,
|
|
@@ -4357,17 +4398,17 @@ class GPT5Provider {
|
|
|
4357
4398
|
* });
|
|
4358
4399
|
* ```
|
|
4359
4400
|
*/
|
|
4360
|
-
const
|
|
4401
|
+
const GET_CLIENT_FN$5 = functoolsKit.memoize(([apiKey]) => `${apiKey}`, (apiKey) => new OpenAI({
|
|
4402
|
+
baseURL: "https://api.deepseek.com",
|
|
4403
|
+
apiKey,
|
|
4404
|
+
}));
|
|
4405
|
+
const getDeepseek = () => {
|
|
4361
4406
|
const apiKey = engine$1.contextService.context.apiKey;
|
|
4362
4407
|
if (Array.isArray(apiKey)) {
|
|
4363
|
-
getDeepseek.clear();
|
|
4364
4408
|
throw new Error("Deepseek provider does not support token rotation");
|
|
4365
4409
|
}
|
|
4366
|
-
return
|
|
4367
|
-
|
|
4368
|
-
apiKey: apiKey,
|
|
4369
|
-
});
|
|
4370
|
-
});
|
|
4410
|
+
return GET_CLIENT_FN$5(apiKey);
|
|
4411
|
+
};
|
|
4371
4412
|
|
|
4372
4413
|
/**
|
|
4373
4414
|
* Maximum number of retry attempts for outline completion.
|
|
@@ -4450,7 +4491,7 @@ class DeepseekProvider {
|
|
|
4450
4491
|
tools: formattedTools?.length ? formattedTools : undefined,
|
|
4451
4492
|
});
|
|
4452
4493
|
const result = {
|
|
4453
|
-
content: content,
|
|
4494
|
+
content: content ?? "",
|
|
4454
4495
|
mode,
|
|
4455
4496
|
agentName,
|
|
4456
4497
|
role,
|
|
@@ -4633,7 +4674,12 @@ class DeepseekProvider {
|
|
|
4633
4674
|
attempt++;
|
|
4634
4675
|
continue;
|
|
4635
4676
|
}
|
|
4636
|
-
|
|
4677
|
+
{
|
|
4678
|
+
// apiKey must never reach the outline result: it gets dumped to
|
|
4679
|
+
// markdown files and forwarded to downstream consumers.
|
|
4680
|
+
const { inference, model } = this.contextService.context;
|
|
4681
|
+
lodashEs.set(validation.data, "_context", { inference, model });
|
|
4682
|
+
}
|
|
4637
4683
|
const result = {
|
|
4638
4684
|
role: "assistant",
|
|
4639
4685
|
content: JSON.stringify(validation.data),
|
|
@@ -4679,17 +4725,17 @@ class DeepseekProvider {
|
|
|
4679
4725
|
* });
|
|
4680
4726
|
* ```
|
|
4681
4727
|
*/
|
|
4682
|
-
const
|
|
4728
|
+
const GET_CLIENT_FN$4 = functoolsKit.memoize(([apiKey]) => `${apiKey}`, (apiKey) => new OpenAI({
|
|
4729
|
+
baseURL: "https://api.mistral.ai/v1",
|
|
4730
|
+
apiKey,
|
|
4731
|
+
}));
|
|
4732
|
+
const getMistral = () => {
|
|
4683
4733
|
const apiKey = engine$1.contextService.context.apiKey;
|
|
4684
4734
|
if (Array.isArray(apiKey)) {
|
|
4685
|
-
getMistral.clear();
|
|
4686
4735
|
throw new Error("Mistral provider does not support token rotation");
|
|
4687
4736
|
}
|
|
4688
|
-
return
|
|
4689
|
-
|
|
4690
|
-
apiKey: apiKey,
|
|
4691
|
-
});
|
|
4692
|
-
});
|
|
4737
|
+
return GET_CLIENT_FN$4(apiKey);
|
|
4738
|
+
};
|
|
4693
4739
|
|
|
4694
4740
|
/**
|
|
4695
4741
|
* Maximum number of retry attempts for outline completion.
|
|
@@ -4772,7 +4818,7 @@ class MistralProvider {
|
|
|
4772
4818
|
tools: formattedTools?.length ? formattedTools : undefined,
|
|
4773
4819
|
});
|
|
4774
4820
|
const result = {
|
|
4775
|
-
content: content,
|
|
4821
|
+
content: content ?? "",
|
|
4776
4822
|
mode,
|
|
4777
4823
|
agentName,
|
|
4778
4824
|
role,
|
|
@@ -4955,7 +5001,12 @@ class MistralProvider {
|
|
|
4955
5001
|
attempt++;
|
|
4956
5002
|
continue;
|
|
4957
5003
|
}
|
|
4958
|
-
|
|
5004
|
+
{
|
|
5005
|
+
// apiKey must never reach the outline result: it gets dumped to
|
|
5006
|
+
// markdown files and forwarded to downstream consumers.
|
|
5007
|
+
const { inference, model } = this.contextService.context;
|
|
5008
|
+
lodashEs.set(validation.data, "_context", { inference, model });
|
|
5009
|
+
}
|
|
4959
5010
|
const result = {
|
|
4960
5011
|
role: "assistant",
|
|
4961
5012
|
content: JSON.stringify(validation.data),
|
|
@@ -5001,17 +5052,17 @@ class MistralProvider {
|
|
|
5001
5052
|
* });
|
|
5002
5053
|
* ```
|
|
5003
5054
|
*/
|
|
5004
|
-
const
|
|
5055
|
+
const GET_CLIENT_FN$3 = functoolsKit.memoize(([apiKey]) => `${apiKey}`, (apiKey) => new OpenAI({
|
|
5056
|
+
baseURL: "https://api.perplexity.ai",
|
|
5057
|
+
apiKey,
|
|
5058
|
+
}));
|
|
5059
|
+
const getPerplexity = () => {
|
|
5005
5060
|
const apiKey = engine$1.contextService.context.apiKey;
|
|
5006
5061
|
if (Array.isArray(apiKey)) {
|
|
5007
|
-
getPerplexity.clear();
|
|
5008
5062
|
throw new Error("Perplexity provider does not support token rotation");
|
|
5009
5063
|
}
|
|
5010
|
-
return
|
|
5011
|
-
|
|
5012
|
-
apiKey: apiKey,
|
|
5013
|
-
});
|
|
5014
|
-
});
|
|
5064
|
+
return GET_CLIENT_FN$3(apiKey);
|
|
5065
|
+
};
|
|
5015
5066
|
|
|
5016
5067
|
/**
|
|
5017
5068
|
* Provider for Perplexity AI models via OpenAI-compatible API.
|
|
@@ -5127,7 +5178,7 @@ class PerplexityProvider {
|
|
|
5127
5178
|
});
|
|
5128
5179
|
const { choices: [{ message: { content, role, tool_calls }, },], } = result;
|
|
5129
5180
|
const finalResult = {
|
|
5130
|
-
content: content,
|
|
5181
|
+
content: content ?? "",
|
|
5131
5182
|
mode,
|
|
5132
5183
|
agentName,
|
|
5133
5184
|
role,
|
|
@@ -5254,6 +5305,10 @@ class PerplexityProvider {
|
|
|
5254
5305
|
}
|
|
5255
5306
|
}
|
|
5256
5307
|
|
|
5308
|
+
const GET_CLIENT_FN$2 = functoolsKit.memoize(([apiKey]) => `${apiKey}`, (apiKey) => new OpenAI({
|
|
5309
|
+
baseURL: "https://api.cohere.ai/compatibility/v1",
|
|
5310
|
+
apiKey,
|
|
5311
|
+
}));
|
|
5257
5312
|
/**
|
|
5258
5313
|
* Creates and caches an OpenAI-compatible client for Cohere API.
|
|
5259
5314
|
*
|
|
@@ -5281,17 +5336,13 @@ class PerplexityProvider {
|
|
|
5281
5336
|
* });
|
|
5282
5337
|
* ```
|
|
5283
5338
|
*/
|
|
5284
|
-
const getCohere =
|
|
5339
|
+
const getCohere = () => {
|
|
5285
5340
|
const apiKey = engine$1.contextService.context.apiKey;
|
|
5286
5341
|
if (Array.isArray(apiKey)) {
|
|
5287
|
-
getCohere.clear();
|
|
5288
5342
|
throw new Error("Cohere provider does not support token rotation");
|
|
5289
5343
|
}
|
|
5290
|
-
return
|
|
5291
|
-
|
|
5292
|
-
apiKey: apiKey,
|
|
5293
|
-
});
|
|
5294
|
-
});
|
|
5344
|
+
return GET_CLIENT_FN$2(apiKey);
|
|
5345
|
+
};
|
|
5295
5346
|
|
|
5296
5347
|
/**
|
|
5297
5348
|
* Provider for Cohere AI models via OpenAI-compatible API.
|
|
@@ -5401,7 +5452,7 @@ class CohereProvider {
|
|
|
5401
5452
|
});
|
|
5402
5453
|
const { choices: [{ message: { content, role, tool_calls }, },], } = result;
|
|
5403
5454
|
const finalResult = {
|
|
5404
|
-
content: content,
|
|
5455
|
+
content: content ?? "",
|
|
5405
5456
|
mode,
|
|
5406
5457
|
agentName,
|
|
5407
5458
|
role,
|
|
@@ -5681,7 +5732,7 @@ class AlibabaProvider {
|
|
|
5681
5732
|
});
|
|
5682
5733
|
const { choices: [{ message: { content, role, tool_calls }, },], } = responseData;
|
|
5683
5734
|
const result = {
|
|
5684
|
-
content: content,
|
|
5735
|
+
content: content ?? "",
|
|
5685
5736
|
mode,
|
|
5686
5737
|
agentName,
|
|
5687
5738
|
role,
|
|
@@ -5762,7 +5813,7 @@ class AlibabaProvider {
|
|
|
5762
5813
|
});
|
|
5763
5814
|
}
|
|
5764
5815
|
const result = {
|
|
5765
|
-
content: content,
|
|
5816
|
+
content: content ?? "",
|
|
5766
5817
|
mode,
|
|
5767
5818
|
agentName,
|
|
5768
5819
|
role,
|
|
@@ -5890,7 +5941,12 @@ class AlibabaProvider {
|
|
|
5890
5941
|
attempt++;
|
|
5891
5942
|
continue;
|
|
5892
5943
|
}
|
|
5893
|
-
|
|
5944
|
+
{
|
|
5945
|
+
// apiKey must never reach the outline result: it gets dumped to
|
|
5946
|
+
// markdown files and forwarded to downstream consumers.
|
|
5947
|
+
const { inference, model } = this.contextService.context;
|
|
5948
|
+
lodashEs.set(validation.data, "_context", { inference, model });
|
|
5949
|
+
}
|
|
5894
5950
|
const result = {
|
|
5895
5951
|
role: "assistant",
|
|
5896
5952
|
content: JSON.stringify(validation.data),
|
|
@@ -5909,6 +5965,10 @@ class AlibabaProvider {
|
|
|
5909
5965
|
}
|
|
5910
5966
|
}
|
|
5911
5967
|
|
|
5968
|
+
const GET_CLIENT_FN$1 = functoolsKit.memoize(([apiKey]) => `${apiKey}`, (apiKey) => new OpenAI({
|
|
5969
|
+
apiKey,
|
|
5970
|
+
baseURL: "https://api.z.ai/api/paas/v4/",
|
|
5971
|
+
}));
|
|
5912
5972
|
/**
|
|
5913
5973
|
* Creates and caches an OpenAI-compatible client for Z.ai GLM-4 API.
|
|
5914
5974
|
*
|
|
@@ -5951,17 +6011,13 @@ class AlibabaProvider {
|
|
|
5951
6011
|
* });
|
|
5952
6012
|
* ```
|
|
5953
6013
|
*/
|
|
5954
|
-
const getZAi =
|
|
6014
|
+
const getZAi = () => {
|
|
5955
6015
|
const apiKey = engine$1.contextService.context.apiKey;
|
|
5956
6016
|
if (Array.isArray(apiKey)) {
|
|
5957
|
-
getZAi.clear();
|
|
5958
6017
|
throw new Error("Z.ai provider does not support token rotation");
|
|
5959
6018
|
}
|
|
5960
|
-
return
|
|
5961
|
-
|
|
5962
|
-
baseURL: "https://api.z.ai/api/paas/v4/"
|
|
5963
|
-
});
|
|
5964
|
-
});
|
|
6019
|
+
return GET_CLIENT_FN$1(apiKey);
|
|
6020
|
+
};
|
|
5965
6021
|
|
|
5966
6022
|
/**
|
|
5967
6023
|
* GLM-4 provider implementation for Z.ai API integration.
|
|
@@ -6093,7 +6149,7 @@ class GLM4Provider {
|
|
|
6093
6149
|
tools: tools,
|
|
6094
6150
|
});
|
|
6095
6151
|
const result = {
|
|
6096
|
-
content: content,
|
|
6152
|
+
content: content ?? "",
|
|
6097
6153
|
mode,
|
|
6098
6154
|
agentName,
|
|
6099
6155
|
role,
|
|
@@ -6327,16 +6383,16 @@ class GLM4Provider {
|
|
|
6327
6383
|
* });
|
|
6328
6384
|
* ```
|
|
6329
6385
|
*/
|
|
6330
|
-
const
|
|
6386
|
+
const GET_CLIENT_FN = functoolsKit.memoize(([apiKey]) => `${apiKey}`, (apiKey) => new Groq({
|
|
6387
|
+
apiKey,
|
|
6388
|
+
}));
|
|
6389
|
+
const getGroq = () => {
|
|
6331
6390
|
const apiKey = engine$1.contextService.context.apiKey;
|
|
6332
6391
|
if (Array.isArray(apiKey)) {
|
|
6333
|
-
getGroq.clear();
|
|
6334
6392
|
throw new Error("Groq provider does not support token rotation");
|
|
6335
6393
|
}
|
|
6336
|
-
return
|
|
6337
|
-
|
|
6338
|
-
});
|
|
6339
|
-
});
|
|
6394
|
+
return GET_CLIENT_FN(apiKey);
|
|
6395
|
+
};
|
|
6340
6396
|
|
|
6341
6397
|
/**
|
|
6342
6398
|
* Maximum number of retry attempts for outline completion.
|
|
@@ -6419,7 +6475,7 @@ class GroqProvider {
|
|
|
6419
6475
|
tools: formattedTools?.length ? formattedTools : undefined,
|
|
6420
6476
|
});
|
|
6421
6477
|
const result = {
|
|
6422
|
-
content: content,
|
|
6478
|
+
content: content ?? "",
|
|
6423
6479
|
mode,
|
|
6424
6480
|
agentName,
|
|
6425
6481
|
role,
|
|
@@ -6597,7 +6653,12 @@ class GroqProvider {
|
|
|
6597
6653
|
attempt++;
|
|
6598
6654
|
continue;
|
|
6599
6655
|
}
|
|
6600
|
-
|
|
6656
|
+
{
|
|
6657
|
+
// apiKey must never reach the outline result: it gets dumped to
|
|
6658
|
+
// markdown files and forwarded to downstream consumers.
|
|
6659
|
+
const { inference, model } = this.contextService.context;
|
|
6660
|
+
lodashEs.set(validation.data, "_context", { inference, model });
|
|
6661
|
+
}
|
|
6601
6662
|
const result = {
|
|
6602
6663
|
role: "assistant",
|
|
6603
6664
|
content: JSON.stringify(validation.data),
|
|
@@ -6817,7 +6878,7 @@ agentSwarmKit.addCompletion({
|
|
|
6817
6878
|
getCompletion: async (params) => {
|
|
6818
6879
|
const result = await LOCAL_RUNNER_FN$1(params);
|
|
6819
6880
|
if (typeof result === "symbol") {
|
|
6820
|
-
throw new Error(`${exports.CompletionName.
|
|
6881
|
+
throw new Error(`${exports.CompletionName.RunnerStreamCompletion} inference timeout`);
|
|
6821
6882
|
}
|
|
6822
6883
|
return result;
|
|
6823
6884
|
},
|
|
@@ -6885,7 +6946,7 @@ agentSwarmKit.addCompletion({
|
|
|
6885
6946
|
* ```
|
|
6886
6947
|
*/
|
|
6887
6948
|
const ollama = (fn, model, apiKey) => {
|
|
6888
|
-
const wrappedFn = async (args) => {
|
|
6949
|
+
const wrappedFn = async (...args) => {
|
|
6889
6950
|
return await ContextService.runInContext(async () => {
|
|
6890
6951
|
return await fn(...args);
|
|
6891
6952
|
}, {
|
|
@@ -6917,7 +6978,7 @@ const ollama = (fn, model, apiKey) => {
|
|
|
6917
6978
|
* ```
|
|
6918
6979
|
*/
|
|
6919
6980
|
const grok = (fn, model, apiKey) => {
|
|
6920
|
-
const wrappedFn = async (args) => {
|
|
6981
|
+
const wrappedFn = async (...args) => {
|
|
6921
6982
|
return await ContextService.runInContext(async () => {
|
|
6922
6983
|
return await fn(...args);
|
|
6923
6984
|
}, {
|
|
@@ -6949,7 +7010,7 @@ const grok = (fn, model, apiKey) => {
|
|
|
6949
7010
|
* ```
|
|
6950
7011
|
*/
|
|
6951
7012
|
const hf = (fn, model, apiKey) => {
|
|
6952
|
-
const wrappedFn = async (args) => {
|
|
7013
|
+
const wrappedFn = async (...args) => {
|
|
6953
7014
|
return await ContextService.runInContext(async () => {
|
|
6954
7015
|
return await fn(...args);
|
|
6955
7016
|
}, {
|
|
@@ -6981,7 +7042,7 @@ const hf = (fn, model, apiKey) => {
|
|
|
6981
7042
|
* ```
|
|
6982
7043
|
*/
|
|
6983
7044
|
const claude = (fn, model, apiKey) => {
|
|
6984
|
-
const wrappedFn = async (args) => {
|
|
7045
|
+
const wrappedFn = async (...args) => {
|
|
6985
7046
|
return await ContextService.runInContext(async () => {
|
|
6986
7047
|
return await fn(...args);
|
|
6987
7048
|
}, {
|
|
@@ -7013,7 +7074,7 @@ const claude = (fn, model, apiKey) => {
|
|
|
7013
7074
|
* ```
|
|
7014
7075
|
*/
|
|
7015
7076
|
const gpt5 = (fn, model, apiKey) => {
|
|
7016
|
-
const wrappedFn = async (args) => {
|
|
7077
|
+
const wrappedFn = async (...args) => {
|
|
7017
7078
|
return await ContextService.runInContext(async () => {
|
|
7018
7079
|
return await fn(...args);
|
|
7019
7080
|
}, {
|
|
@@ -7045,7 +7106,7 @@ const gpt5 = (fn, model, apiKey) => {
|
|
|
7045
7106
|
* ```
|
|
7046
7107
|
*/
|
|
7047
7108
|
const deepseek = (fn, model, apiKey) => {
|
|
7048
|
-
const wrappedFn = async (args) => {
|
|
7109
|
+
const wrappedFn = async (...args) => {
|
|
7049
7110
|
return await ContextService.runInContext(async () => {
|
|
7050
7111
|
return await fn(...args);
|
|
7051
7112
|
}, {
|
|
@@ -7077,7 +7138,7 @@ const deepseek = (fn, model, apiKey) => {
|
|
|
7077
7138
|
* ```
|
|
7078
7139
|
*/
|
|
7079
7140
|
const mistral = (fn, model, apiKey) => {
|
|
7080
|
-
const wrappedFn = async (args) => {
|
|
7141
|
+
const wrappedFn = async (...args) => {
|
|
7081
7142
|
return await ContextService.runInContext(async () => {
|
|
7082
7143
|
return await fn(...args);
|
|
7083
7144
|
}, {
|
|
@@ -7109,7 +7170,7 @@ const mistral = (fn, model, apiKey) => {
|
|
|
7109
7170
|
* ```
|
|
7110
7171
|
*/
|
|
7111
7172
|
const perplexity = (fn, model, apiKey) => {
|
|
7112
|
-
const wrappedFn = async (args) => {
|
|
7173
|
+
const wrappedFn = async (...args) => {
|
|
7113
7174
|
return await ContextService.runInContext(async () => {
|
|
7114
7175
|
return await fn(...args);
|
|
7115
7176
|
}, {
|
|
@@ -7141,7 +7202,7 @@ const perplexity = (fn, model, apiKey) => {
|
|
|
7141
7202
|
* ```
|
|
7142
7203
|
*/
|
|
7143
7204
|
const cohere = (fn, model, apiKey) => {
|
|
7144
|
-
const wrappedFn = async (args) => {
|
|
7205
|
+
const wrappedFn = async (...args) => {
|
|
7145
7206
|
return await ContextService.runInContext(async () => {
|
|
7146
7207
|
return await fn(...args);
|
|
7147
7208
|
}, {
|
|
@@ -7173,7 +7234,7 @@ const cohere = (fn, model, apiKey) => {
|
|
|
7173
7234
|
* ```
|
|
7174
7235
|
*/
|
|
7175
7236
|
const alibaba = (fn, model, apiKey) => {
|
|
7176
|
-
const wrappedFn = async (args) => {
|
|
7237
|
+
const wrappedFn = async (...args) => {
|
|
7177
7238
|
return await ContextService.runInContext(async () => {
|
|
7178
7239
|
return await fn(...args);
|
|
7179
7240
|
}, {
|
|
@@ -7184,26 +7245,6 @@ const alibaba = (fn, model, apiKey) => {
|
|
|
7184
7245
|
};
|
|
7185
7246
|
return wrappedFn;
|
|
7186
7247
|
};
|
|
7187
|
-
/**
|
|
7188
|
-
* Wrap async function with Zhipu AI GLM-4 inference context.
|
|
7189
|
-
*
|
|
7190
|
-
* Creates a higher-order function that executes the provided async function
|
|
7191
|
-
* within a Zhipu AI GLM-4 inference context via OpenAI-compatible Z.ai API.
|
|
7192
|
-
*
|
|
7193
|
-
* @template T - Async function type
|
|
7194
|
-
* @param fn - Async function to wrap
|
|
7195
|
-
* @param model - GLM-4 model name (e.g., "glm-4-plus", "glm-4-air")
|
|
7196
|
-
* @param apiKey - Single API key or array of keys
|
|
7197
|
-
* @returns Wrapped function with same signature as input
|
|
7198
|
-
*
|
|
7199
|
-
* @example
|
|
7200
|
-
* ```typescript
|
|
7201
|
-
* import { glm4 } from '@backtest-kit/ollama';
|
|
7202
|
-
*
|
|
7203
|
-
* const wrappedFn = glm4(myAsyncFn, 'glm-4-plus', process.env.ZAI_API_KEY);
|
|
7204
|
-
* const result = await wrappedFn(args);
|
|
7205
|
-
* ```
|
|
7206
|
-
*/
|
|
7207
7248
|
/**
|
|
7208
7249
|
* Wrap async function with Groq inference context.
|
|
7209
7250
|
*
|
|
@@ -7225,7 +7266,7 @@ const alibaba = (fn, model, apiKey) => {
|
|
|
7225
7266
|
* ```
|
|
7226
7267
|
*/
|
|
7227
7268
|
const groq = (fn, model, apiKey) => {
|
|
7228
|
-
const wrappedFn = async (args) => {
|
|
7269
|
+
const wrappedFn = async (...args) => {
|
|
7229
7270
|
return await ContextService.runInContext(async () => {
|
|
7230
7271
|
return await fn(...args);
|
|
7231
7272
|
}, {
|
|
@@ -7236,8 +7277,28 @@ const groq = (fn, model, apiKey) => {
|
|
|
7236
7277
|
};
|
|
7237
7278
|
return wrappedFn;
|
|
7238
7279
|
};
|
|
7280
|
+
/**
|
|
7281
|
+
* Wrap async function with Zhipu AI GLM-4 inference context.
|
|
7282
|
+
*
|
|
7283
|
+
* Creates a higher-order function that executes the provided async function
|
|
7284
|
+
* within a Zhipu AI GLM-4 inference context via OpenAI-compatible Z.ai API.
|
|
7285
|
+
*
|
|
7286
|
+
* @template T - Async function type
|
|
7287
|
+
* @param fn - Async function to wrap
|
|
7288
|
+
* @param model - GLM-4 model name (e.g., "glm-4-plus", "glm-4-air")
|
|
7289
|
+
* @param apiKey - Single API key or array of keys
|
|
7290
|
+
* @returns Wrapped function with same signature as input
|
|
7291
|
+
*
|
|
7292
|
+
* @example
|
|
7293
|
+
* ```typescript
|
|
7294
|
+
* import { glm4 } from '@backtest-kit/ollama';
|
|
7295
|
+
*
|
|
7296
|
+
* const wrappedFn = glm4(myAsyncFn, 'glm-4-plus', process.env.ZAI_API_KEY);
|
|
7297
|
+
* const result = await wrappedFn(args);
|
|
7298
|
+
* ```
|
|
7299
|
+
*/
|
|
7239
7300
|
const glm4 = (fn, model, apiKey) => {
|
|
7240
|
-
const wrappedFn = async (args) => {
|
|
7301
|
+
const wrappedFn = async (...args) => {
|
|
7241
7302
|
return await ContextService.runInContext(async () => {
|
|
7242
7303
|
return await fn(...args);
|
|
7243
7304
|
}, {
|
|
@@ -7290,7 +7351,8 @@ const DUMP_SIGNAL_METHOD_NAME = "dump.dumpSignal";
|
|
|
7290
7351
|
*
|
|
7291
7352
|
* @example
|
|
7292
7353
|
* ```typescript
|
|
7293
|
-
* import {
|
|
7354
|
+
* import { getCandles } from "backtest-kit";
|
|
7355
|
+
* import { dumpSignal } from "@backtest-kit/ollama";
|
|
7294
7356
|
* import { v4 as uuid } from "uuid";
|
|
7295
7357
|
*
|
|
7296
7358
|
* addStrategy({
|
|
@@ -7437,7 +7499,9 @@ async function validate(args = {}) {
|
|
|
7437
7499
|
return await validateInternal(args);
|
|
7438
7500
|
}
|
|
7439
7501
|
|
|
7440
|
-
|
|
7502
|
+
// Symbol.for keeps the brand check working when CJS and ESM copies of the
|
|
7503
|
+
// package end up in the same process (dual-package hazard).
|
|
7504
|
+
const MODULE_TYPE_SYMBOL = Symbol.for("backtest-kit.ollama.module-type");
|
|
7441
7505
|
class Module {
|
|
7442
7506
|
constructor(path, baseDir) {
|
|
7443
7507
|
this.path = path;
|
|
@@ -7498,15 +7562,15 @@ async function commitPrompt(source, history) {
|
|
|
7498
7562
|
const systemPrompts = await engine$1.resolvePromptService.getSystemPrompt(prompt, symbol, strategyName, exchangeName, frameName, isBacktest);
|
|
7499
7563
|
const userPrompt = await engine$1.resolvePromptService.getUserPrompt(prompt, symbol, strategyName, exchangeName, frameName, isBacktest);
|
|
7500
7564
|
if (systemPrompts.length > 0) {
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7565
|
+
// Single unshift with spread: per-item unshift in a loop would REVERSE
|
|
7566
|
+
// the system prompt order at the head of the history.
|
|
7567
|
+
const systemMessages = systemPrompts
|
|
7568
|
+
.filter((content) => content.trim())
|
|
7569
|
+
.map((content) => ({
|
|
7570
|
+
role: "system",
|
|
7571
|
+
content,
|
|
7572
|
+
}));
|
|
7573
|
+
history.unshift(...systemMessages);
|
|
7510
7574
|
}
|
|
7511
7575
|
if (userPrompt && userPrompt.trim()) {
|
|
7512
7576
|
history.push({
|
|
@@ -7686,7 +7750,7 @@ const LIST_OPTIMIZERS_METHOD_NAME = "list.listOptimizerSchema";
|
|
|
7686
7750
|
*
|
|
7687
7751
|
* @example
|
|
7688
7752
|
* ```typescript
|
|
7689
|
-
* import { listOptimizers, addOptimizer } from "backtest-kit";
|
|
7753
|
+
* import { listOptimizers, addOptimizer } from "@backtest-kit/ollama";
|
|
7690
7754
|
*
|
|
7691
7755
|
* addOptimizer({
|
|
7692
7756
|
* optimizerName: "llm-strategy-generator",
|