@tradejs/node 3.0.0 → 3.1.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/dist/registry.js CHANGED
@@ -36,6 +36,7 @@ __export(registry_exports, {
36
36
  getRegisteredManifests: () => getRegisteredManifests,
37
37
  getRegisteredStrategies: () => getRegisteredStrategies,
38
38
  getStrategyCreator: () => getStrategyCreator,
39
+ getStrategyDefaults: () => getStrategyDefaults,
39
40
  getStrategyManifest: () => getStrategyManifest,
40
41
  isKnownStrategy: () => isKnownStrategy,
41
42
  registerStrategyEntries: () => registerStrategyEntries,
@@ -55,11 +56,8 @@ var import_constants3 = require("@tradejs/core/constants");
55
56
  var import_ml2 = require("@tradejs/infra/ml");
56
57
 
57
58
  // src/ai.ts
58
- var import_aiLanguages = require("@tradejs/core/aiLanguages");
59
- var import_aiEndpoints = require("@tradejs/core/aiEndpoints");
60
- var import_aiModels = require("@tradejs/core/aiModels");
59
+ var import_aiLanguages2 = require("@tradejs/core/aiLanguages");
61
60
  var import_redis = require("@tradejs/infra/redis");
62
- var import_userSettings = require("@tradejs/infra/userSettings");
63
61
 
64
62
  // src/aiShared.ts
65
63
  var MAX_AI_SERIES_POINTS = 5;
@@ -1119,6 +1117,11 @@ var getStrategyCreator = async (name, cwd = getTradejsProjectCwd()) => {
1119
1117
  const { state } = getStrategyRegistryState(cwd);
1120
1118
  return state.strategyCreators.get(name);
1121
1119
  };
1120
+ var getStrategyDefaults = async (name, cwd = getTradejsProjectCwd()) => {
1121
+ await ensureStrategyPluginsLoaded(cwd);
1122
+ const { state } = getStrategyRegistryState(cwd);
1123
+ return state.strategyEntriesMap.get(name)?.defaults;
1124
+ };
1122
1125
  var getAvailableStrategyNames = async (cwd = getTradejsProjectCwd()) => {
1123
1126
  await ensureStrategyPluginsLoaded(cwd);
1124
1127
  const { state } = getStrategyRegistryState(cwd);
@@ -1301,6 +1304,139 @@ var postProcessLocalAiAnalysisByStrategy = (signal, analysis, payload = buildAiP
1301
1304
  }) ?? strategyAnalysis;
1302
1305
  };
1303
1306
 
1307
+ // src/aiProvider.ts
1308
+ var import_aiEndpoints = require("@tradejs/core/aiEndpoints");
1309
+ var import_aiModels = require("@tradejs/core/aiModels");
1310
+ var import_aiLanguages = require("@tradejs/core/aiLanguages");
1311
+ var import_userSettings = require("@tradejs/infra/userSettings");
1312
+ var DEFAULT_AI_MODEL = "openai/gpt-5-mini";
1313
+ var userSettingsCache = /* @__PURE__ */ new Map();
1314
+ var aiModelCache = /* @__PURE__ */ new Map();
1315
+ var normalizeResponseContent = (content) => {
1316
+ if (typeof content === "string") return content;
1317
+ if (content && typeof content === "object" && !Array.isArray(content)) {
1318
+ return content;
1319
+ }
1320
+ if (Array.isArray(content)) {
1321
+ return content.map(
1322
+ (part) => typeof part?.text === "string" ? part.text : ""
1323
+ ).join("\n").trim();
1324
+ }
1325
+ return String(content ?? "");
1326
+ };
1327
+ var getAiInvocationError = (error) => {
1328
+ const details = error instanceof Error && error.message.trim() ? error.message.trim() : String(error);
1329
+ const isEmptyCompletion = error instanceof TypeError && /Cannot read properties of undefined \(reading ['"]message['"]\)/.test(
1330
+ details
1331
+ );
1332
+ const wrapped = new Error(
1333
+ isEmptyCompletion ? "AI provider returned an empty chat completion" : `AI model invocation failed: ${details}`
1334
+ );
1335
+ wrapped.cause = error;
1336
+ return wrapped;
1337
+ };
1338
+ var isEmptyResponseContent = (content) => typeof content === "string" ? content.trim().length === 0 : Object.keys(content).length === 0;
1339
+ var getAiModelCacheKey = (userName, modelName, temperature) => `${userName}::${modelName}::${temperature}`;
1340
+ var resolveAiModelName = (settings, requestedModelName) => {
1341
+ const explicitModelName = requestedModelName?.trim() ?? "";
1342
+ if (explicitModelName) return explicitModelName;
1343
+ return settings.AI_MODEL?.trim() || DEFAULT_AI_MODEL;
1344
+ };
1345
+ var getOpenRouterModelKwargs = (apiEndpoint) => {
1346
+ const endpoint = String(apiEndpoint ?? "").trim();
1347
+ if (!endpoint) return {};
1348
+ let hostname = "";
1349
+ try {
1350
+ hostname = new URL(endpoint).hostname;
1351
+ } catch {
1352
+ hostname = endpoint;
1353
+ }
1354
+ return hostname.toLowerCase().includes("openrouter") ? { provider: { ignore: ["azure"] } } : {};
1355
+ };
1356
+ var getAiUserSettings = async (userName = "root") => {
1357
+ let settingsPromise = userSettingsCache.get(userName);
1358
+ if (!settingsPromise) {
1359
+ settingsPromise = (0, import_userSettings.getUserSettings)(userName).then((settings2) => {
1360
+ const endpoint = (0, import_aiEndpoints.normalizeAiEndpoint)(settings2.AI_API_ENDPOINT);
1361
+ return {
1362
+ ...settings2,
1363
+ AI_API_ENDPOINT: endpoint,
1364
+ AI_MODEL: (0, import_aiModels.normalizeAiModel)(settings2.AI_MODEL, endpoint),
1365
+ AI_RESPONSE_LANGUAGE: (0, import_aiLanguages.normalizeAiResponseLanguage)(
1366
+ settings2.AI_RESPONSE_LANGUAGE
1367
+ )
1368
+ };
1369
+ });
1370
+ settingsPromise.catch(() => userSettingsCache.delete(userName));
1371
+ userSettingsCache.set(userName, settingsPromise);
1372
+ }
1373
+ const settings = await settingsPromise;
1374
+ if (!settings.AI_API_KEY || !settings.AI_API_ENDPOINT) {
1375
+ throw new Error(`AI settings are incomplete for user ${userName}`);
1376
+ }
1377
+ return settings;
1378
+ };
1379
+ var getAiModel = async (userName = "root", requestedModelName, temperature = 0.2) => {
1380
+ const settings = await getAiUserSettings(userName);
1381
+ const modelName = resolveAiModelName(settings, requestedModelName);
1382
+ const cacheKey = getAiModelCacheKey(userName, modelName, temperature);
1383
+ let modelPromise = aiModelCache.get(cacheKey);
1384
+ if (!modelPromise) {
1385
+ modelPromise = import("@langchain/openai").then(({ ChatOpenAI }) => {
1386
+ const modelKwargs = getOpenRouterModelKwargs(settings.AI_API_ENDPOINT);
1387
+ return new ChatOpenAI({
1388
+ temperature,
1389
+ modelName,
1390
+ apiKey: settings.AI_API_KEY,
1391
+ ...Object.keys(modelKwargs).length ? { modelKwargs } : {},
1392
+ configuration: {
1393
+ baseURL: settings.AI_API_ENDPOINT,
1394
+ defaultHeaders: {
1395
+ "HTTP-Referer": "https://tradejs.dev",
1396
+ "X-Title": "Inv"
1397
+ }
1398
+ }
1399
+ });
1400
+ });
1401
+ modelPromise.catch(() => aiModelCache.delete(cacheKey));
1402
+ aiModelCache.set(cacheKey, modelPromise);
1403
+ }
1404
+ try {
1405
+ return await modelPromise;
1406
+ } catch (error) {
1407
+ aiModelCache.delete(cacheKey);
1408
+ userSettingsCache.delete(userName);
1409
+ throw error;
1410
+ }
1411
+ };
1412
+ var invokeAiChatWithUserMessageEncoding = async ({
1413
+ messages,
1414
+ userName = "root",
1415
+ model,
1416
+ temperature = 0.2
1417
+ }, resolveUserMessageEncoding) => {
1418
+ const [{ HumanMessage, SystemMessage }, aiModel] = await Promise.all([
1419
+ import("@langchain/core/messages"),
1420
+ getAiModel(userName, model, temperature)
1421
+ ]);
1422
+ const providerMessages = messages.map(
1423
+ (message) => message.role === "system" ? new SystemMessage(message.content) : new HumanMessage(
1424
+ resolveUserMessageEncoding(message) === "text-block" ? { content: [{ type: "text", text: message.content }] } : message.content
1425
+ )
1426
+ );
1427
+ try {
1428
+ const response = await aiModel.invoke(providerMessages);
1429
+ const content = normalizeResponseContent(response?.content);
1430
+ if (isEmptyResponseContent(content)) {
1431
+ throw new Error("AI provider returned an empty chat completion");
1432
+ }
1433
+ return { content };
1434
+ } catch (error) {
1435
+ throw getAiInvocationError(error);
1436
+ }
1437
+ };
1438
+ var invokeAiPromptChat = (options) => invokeAiChatWithUserMessageEncoding(options, () => "text-block");
1439
+
1304
1440
  // src/ai.ts
1305
1441
  var parseAIResponse = (input) => {
1306
1442
  try {
@@ -1314,18 +1450,6 @@ var parseAIResponse = (input) => {
1314
1450
  return {};
1315
1451
  }
1316
1452
  };
1317
- var normalizeResponseContent = (content) => {
1318
- if (typeof content === "string" || content && typeof content === "object") {
1319
- if (typeof content !== "object" || !Array.isArray(content)) {
1320
- return content;
1321
- }
1322
- }
1323
- if (Array.isArray(content)) {
1324
- const text = content.map((part) => typeof part?.text === "string" ? part.text : "").join("\n").trim();
1325
- return text;
1326
- }
1327
- return String(content ?? "");
1328
- };
1329
1453
  var normalizeAnalysis = (raw) => {
1330
1454
  const direction = raw?.direction === "LONG" || raw?.direction === "SHORT" ? raw.direction : null;
1331
1455
  const qualityNum = typeof raw?.quality === "number" ? Math.max(1, Math.min(5, Math.round(raw.quality))) : void 0;
@@ -1559,153 +1683,24 @@ Trade payload:
1559
1683
  ${JSON.stringify(payload)}
1560
1684
  ${buildAiHumanPromptAddonByStrategy(signal, payload)}
1561
1685
  `;
1562
- var getAiInvocationError = (error) => {
1563
- const details = error instanceof Error && error.message.trim() ? error.message.trim() : String(error);
1564
- const isEmptyCompletion = error instanceof TypeError && /Cannot read properties of undefined \(reading ['"]message['"]\)/.test(
1565
- details
1566
- );
1567
- const wrapped = new Error(
1568
- isEmptyCompletion ? "AI provider returned an empty chat completion" : `AI model invocation failed: ${details}`
1569
- );
1570
- wrapped.cause = error;
1571
- return wrapped;
1572
- };
1573
- var isEmptyResponseContent = (content) => typeof content === "string" ? content.trim().length === 0 : Object.keys(content).length === 0;
1574
- var DEFAULT_AI_MODEL = "openai/gpt-5-mini";
1575
- var userSettingsCache = /* @__PURE__ */ new Map();
1576
- var aiModelCache = /* @__PURE__ */ new Map();
1577
- var getAiModelCacheKey = (userName, modelName) => `${userName}::${modelName}`;
1578
- var resolveAiModelName = (settings, requestedModelName) => {
1579
- const explicitModelName = typeof requestedModelName === "string" ? requestedModelName.trim() : "";
1580
- if (explicitModelName) {
1581
- return explicitModelName;
1582
- }
1583
- const settingsModelName = typeof settings.AI_MODEL === "string" ? settings.AI_MODEL.trim() : "";
1584
- return settingsModelName || DEFAULT_AI_MODEL;
1585
- };
1586
- var getOpenRouterModelKwargs = (apiEndpoint) => {
1587
- const endpoint = String(apiEndpoint ?? "").trim();
1588
- if (!endpoint) {
1589
- return {};
1590
- }
1591
- let hostname = "";
1592
- try {
1593
- hostname = new URL(endpoint).hostname;
1594
- } catch {
1595
- hostname = endpoint;
1596
- }
1597
- if (!hostname.toLowerCase().includes("openrouter")) {
1598
- return {};
1599
- }
1600
- return {
1601
- provider: {
1602
- ignore: ["azure"]
1603
- }
1604
- };
1605
- };
1606
- var getAiSettings = async (userName = "root") => {
1607
- let settingsPromise = userSettingsCache.get(userName);
1608
- if (!settingsPromise) {
1609
- settingsPromise = (0, import_userSettings.getUserSettings)(userName).then((settings2) => {
1610
- const endpoint = (0, import_aiEndpoints.normalizeAiEndpoint)(settings2.AI_API_ENDPOINT);
1611
- return {
1612
- ...settings2,
1613
- AI_API_ENDPOINT: endpoint,
1614
- AI_MODEL: (0, import_aiModels.normalizeAiModel)(settings2.AI_MODEL, endpoint),
1615
- AI_RESPONSE_LANGUAGE: (0, import_aiLanguages.normalizeAiResponseLanguage)(
1616
- settings2.AI_RESPONSE_LANGUAGE
1617
- )
1618
- };
1619
- });
1620
- settingsPromise.catch(() => {
1621
- userSettingsCache.delete(userName);
1622
- });
1623
- userSettingsCache.set(userName, settingsPromise);
1624
- }
1625
- const settings = await settingsPromise;
1626
- if (!settings.AI_API_KEY || !settings.AI_API_ENDPOINT) {
1627
- throw new Error(`AI settings are incomplete for user ${userName}`);
1628
- }
1629
- return settings;
1630
- };
1631
- var createAiModel = async (userName = "root", requestedModelName) => {
1632
- const settings = await getAiSettings(userName);
1633
- const modelName = resolveAiModelName(settings, requestedModelName);
1634
- const cacheKey = getAiModelCacheKey(userName, modelName);
1635
- let modelPromise = aiModelCache.get(cacheKey);
1636
- if (!modelPromise) {
1637
- modelPromise = (async () => {
1638
- const { ChatOpenAI } = await import("@langchain/openai");
1639
- const modelKwargs = getOpenRouterModelKwargs(settings.AI_API_ENDPOINT);
1640
- return new ChatOpenAI({
1641
- temperature: 0.2,
1642
- modelName,
1643
- apiKey: settings.AI_API_KEY,
1644
- ...Object.keys(modelKwargs).length ? { modelKwargs } : {},
1645
- configuration: {
1646
- baseURL: settings.AI_API_ENDPOINT,
1647
- defaultHeaders: {
1648
- "HTTP-Referer": "https://tradejs.dev",
1649
- "X-Title": "Inv"
1650
- }
1651
- }
1652
- });
1653
- })();
1654
- modelPromise.catch(() => {
1655
- aiModelCache.delete(cacheKey);
1656
- });
1657
- aiModelCache.set(cacheKey, modelPromise);
1658
- }
1659
- return modelPromise;
1660
- };
1661
- var getAiModel = async (userName = "root", requestedModelName) => {
1662
- const settings = await getAiSettings(userName);
1663
- const resolvedModelName = resolveAiModelName(settings, requestedModelName);
1664
- try {
1665
- return await createAiModel(userName, resolvedModelName);
1666
- } catch (error) {
1667
- aiModelCache.delete(getAiModelCacheKey(userName, resolvedModelName));
1668
- userSettingsCache.delete(userName);
1669
- throw error;
1670
- }
1671
- };
1672
1686
  var runAiPrompt = async ({ systemPrompt, humanPrompt }, options = {}) => {
1673
- const [{ HumanMessage, SystemMessage }, model, settings] = await Promise.all([
1674
- import("@langchain/core/messages"),
1675
- getAiModel(options.userName, options.model),
1676
- getAiSettings(options.userName)
1677
- ]);
1678
- const messages = [];
1679
- const responseLanguage = (0, import_aiLanguages.getAiResponseLanguagePromptName)(
1680
- settings.AI_RESPONSE_LANGUAGE || import_aiLanguages.DEFAULT_AI_RESPONSE_LANGUAGE
1687
+ const settings = await getAiUserSettings(options.userName);
1688
+ const responseLanguage = (0, import_aiLanguages2.getAiResponseLanguagePromptName)(
1689
+ settings.AI_RESPONSE_LANGUAGE || import_aiLanguages2.DEFAULT_AI_RESPONSE_LANGUAGE
1681
1690
  );
1682
- messages.push(new SystemMessage(systemPrompt));
1683
- messages.push(
1684
- new SystemMessage(
1685
- `Write all user-visible text fields in ${responseLanguage}. Keep field names and JSON syntax unchanged.`
1686
- )
1687
- );
1688
- messages.push(
1689
- new HumanMessage({
1690
- content: [
1691
- {
1692
- type: "text",
1693
- text: humanPrompt
1694
- }
1695
- ]
1696
- })
1697
- );
1698
- let response;
1699
- try {
1700
- response = await model.invoke(messages);
1701
- } catch (error) {
1702
- throw getAiInvocationError(error);
1703
- }
1704
- const responseContent = normalizeResponseContent(response?.content);
1705
- if (isEmptyResponseContent(responseContent)) {
1706
- throw new Error("AI provider returned an empty chat completion");
1707
- }
1708
- const parsed = parseAIResponse(responseContent);
1691
+ const response = await invokeAiPromptChat({
1692
+ userName: options.userName,
1693
+ model: options.model,
1694
+ messages: [
1695
+ { role: "system", content: systemPrompt },
1696
+ {
1697
+ role: "system",
1698
+ content: `Write all user-visible text fields in ${responseLanguage}. Keep field names and JSON syntax unchanged.`
1699
+ },
1700
+ { role: "user", content: humanPrompt }
1701
+ ]
1702
+ });
1703
+ const parsed = parseAIResponse(response.content);
1709
1704
  const normalized = normalizeAnalysis(parsed);
1710
1705
  if (!options.signal) {
1711
1706
  return normalized;
@@ -6275,6 +6270,7 @@ setStrategyRuntimeFactory(createStrategyRuntime);
6275
6270
  getRegisteredManifests,
6276
6271
  getRegisteredStrategies,
6277
6272
  getStrategyCreator,
6273
+ getStrategyDefaults,
6278
6274
  getStrategyManifest,
6279
6275
  isKnownStrategy,
6280
6276
  registerStrategyEntries,
package/dist/registry.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import "./chunk-OGAWBO3Z.mjs";
1
+ import "./chunk-MKLTJQLY.mjs";
2
2
  import {
3
3
  ensureIndicatorPluginsLoaded,
4
4
  ensureStrategyPluginsLoaded,
@@ -6,12 +6,13 @@ import {
6
6
  getRegisteredManifests,
7
7
  getRegisteredStrategies,
8
8
  getStrategyCreator,
9
+ getStrategyDefaults,
9
10
  getStrategyManifest,
10
11
  isKnownStrategy,
11
12
  registerStrategyEntries,
12
13
  resetStrategyRegistryCache,
13
14
  strategies
14
- } from "./chunk-VRXU4E4O.mjs";
15
+ } from "./chunk-KOQSLFT2.mjs";
15
16
  import "./chunk-WS5DYEVZ.mjs";
16
17
  import "./chunk-Y6FXYEAI.mjs";
17
18
  export {
@@ -21,6 +22,7 @@ export {
21
22
  getRegisteredManifests,
22
23
  getRegisteredStrategies,
23
24
  getStrategyCreator,
25
+ getStrategyDefaults,
24
26
  getStrategyManifest,
25
27
  isKnownStrategy,
26
28
  registerStrategyEntries,
@@ -0,0 +1,12 @@
1
+ import { RuntimeStrategiesResponse } from '@tradejs/types';
2
+
3
+ interface RuntimeDashboardQuery {
4
+ userName: string;
5
+ provider?: string | null;
6
+ hours?: string | number | null;
7
+ now?: number;
8
+ projectRoot?: string;
9
+ }
10
+ declare const loadRuntimeDashboard: ({ userName, provider: requestedProvider, hours: requestedHours, now, projectRoot: requestedProjectRoot, }: RuntimeDashboardQuery) => Promise<RuntimeStrategiesResponse>;
11
+
12
+ export { type RuntimeDashboardQuery, loadRuntimeDashboard };
@@ -0,0 +1,12 @@
1
+ import { RuntimeStrategiesResponse } from '@tradejs/types';
2
+
3
+ interface RuntimeDashboardQuery {
4
+ userName: string;
5
+ provider?: string | null;
6
+ hours?: string | number | null;
7
+ now?: number;
8
+ projectRoot?: string;
9
+ }
10
+ declare const loadRuntimeDashboard: ({ userName, provider: requestedProvider, hours: requestedHours, now, projectRoot: requestedProjectRoot, }: RuntimeDashboardQuery) => Promise<RuntimeStrategiesResponse>;
11
+
12
+ export { type RuntimeDashboardQuery, loadRuntimeDashboard };