traderclaw-cli 1.0.51 → 1.0.52
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/bin/installer-step-engine.mjs +16 -3
- package/bin/llm-model-preference.mjs +10 -3
- package/bin/openclaw-trader.mjs +66 -29
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execSync, spawn } from "child_process";
|
|
1
|
+
import { execFileSync, execSync, spawn } from "child_process";
|
|
2
2
|
import { randomBytes } from "crypto";
|
|
3
3
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, statSync, writeFileSync } from "fs";
|
|
4
4
|
import { homedir, tmpdir } from "os";
|
|
@@ -1214,8 +1214,21 @@ function persistXProfileIdentities(configPath, modeConfig, identities) {
|
|
|
1214
1214
|
}
|
|
1215
1215
|
|
|
1216
1216
|
function listProviderModels(provider) {
|
|
1217
|
-
|
|
1218
|
-
|
|
1217
|
+
let raw;
|
|
1218
|
+
try {
|
|
1219
|
+
raw = execFileSync(
|
|
1220
|
+
"openclaw",
|
|
1221
|
+
["models", "list", "--all", "--provider", provider, "--json"],
|
|
1222
|
+
{
|
|
1223
|
+
encoding: "utf-8",
|
|
1224
|
+
maxBuffer: 25 * 1024 * 1024,
|
|
1225
|
+
timeout: 20_000,
|
|
1226
|
+
env: NO_COLOR_ENV,
|
|
1227
|
+
},
|
|
1228
|
+
).trim();
|
|
1229
|
+
} catch {
|
|
1230
|
+
return [];
|
|
1231
|
+
}
|
|
1219
1232
|
if (!raw) return [];
|
|
1220
1233
|
const parsed = extractJson(raw);
|
|
1221
1234
|
if (!parsed) return [];
|
|
@@ -211,14 +211,21 @@ export function modelPreferenceScore(provider, modelId) {
|
|
|
211
211
|
return score;
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
/** Cap list size after scoring so huge catalogs stay fast for sort + JSON payloads. */
|
|
215
|
+
export const MAX_MODELS_PER_PROVIDER_SORT = 1500;
|
|
216
|
+
|
|
214
217
|
/**
|
|
215
218
|
* Best-first order for dropdowns and validation.
|
|
219
|
+
* Uses a score cache because sort() may compare the same ids many times.
|
|
216
220
|
*/
|
|
217
221
|
export function sortModelsByPreference(provider, modelIds) {
|
|
218
222
|
const items = [...new Set((modelIds || []).filter(Boolean))];
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
223
|
+
const cache = new Map();
|
|
224
|
+
const score = (id) => {
|
|
225
|
+
if (!cache.has(id)) cache.set(id, modelPreferenceScore(provider, id));
|
|
226
|
+
return cache.get(id);
|
|
227
|
+
};
|
|
228
|
+
return items.sort((a, b) => score(b) - score(a) || String(a).localeCompare(String(b)));
|
|
222
229
|
}
|
|
223
230
|
|
|
224
231
|
export function choosePreferredProviderModel(provider, models = []) {
|
package/bin/openclaw-trader.mjs
CHANGED
|
@@ -5,11 +5,17 @@ import { readFileSync, writeFileSync, mkdirSync, appendFileSync, existsSync } fr
|
|
|
5
5
|
import { join } from "path";
|
|
6
6
|
import { homedir } from "os";
|
|
7
7
|
import { randomUUID, createPrivateKey, sign as cryptoSign } from "crypto";
|
|
8
|
-
import { execSync } from "child_process";
|
|
8
|
+
import { execFile, execSync } from "child_process";
|
|
9
|
+
import { promisify } from "util";
|
|
9
10
|
import { createServer } from "http";
|
|
10
|
-
import { sortModelsByPreference } from "./llm-model-preference.mjs";
|
|
11
|
+
import { sortModelsByPreference, MAX_MODELS_PER_PROVIDER_SORT } from "./llm-model-preference.mjs";
|
|
11
12
|
import { resolvePluginPackageRoot } from "./resolve-plugin-root.mjs";
|
|
12
13
|
|
|
14
|
+
const execFileAsync = promisify(execFile);
|
|
15
|
+
|
|
16
|
+
/** Parallel per-provider `openclaw models list` — wall time ~max(single), not sum of all providers. */
|
|
17
|
+
const OPENCLAW_MODELS_PER_PROVIDER_TIMEOUT_MS = 16_000;
|
|
18
|
+
|
|
13
19
|
const PLUGIN_ROOT = resolvePluginPackageRoot(import.meta.url);
|
|
14
20
|
const PACKAGE_JSON = JSON.parse(readFileSync(join(PLUGIN_ROOT, "package.json"), "utf-8"));
|
|
15
21
|
const VERSION = PACKAGE_JSON.version;
|
|
@@ -1766,7 +1772,7 @@ function parseJsonBody(req) {
|
|
|
1766
1772
|
});
|
|
1767
1773
|
}
|
|
1768
1774
|
|
|
1769
|
-
function
|
|
1775
|
+
async function loadWizardLlmCatalogAsync() {
|
|
1770
1776
|
const supportedProviders = new Set([
|
|
1771
1777
|
"anthropic",
|
|
1772
1778
|
"openai",
|
|
@@ -1830,34 +1836,54 @@ function loadWizardLlmCatalog() {
|
|
|
1830
1836
|
return { ...fallback, warning: "openclaw_not_found" };
|
|
1831
1837
|
}
|
|
1832
1838
|
|
|
1839
|
+
const providerIds = [...supportedProviders].sort((a, b) => a.localeCompare(b));
|
|
1840
|
+
|
|
1841
|
+
async function fetchModelsForProvider(provider) {
|
|
1842
|
+
try {
|
|
1843
|
+
const { stdout } = await execFileAsync(
|
|
1844
|
+
"openclaw",
|
|
1845
|
+
["models", "list", "--all", "--provider", provider, "--json"],
|
|
1846
|
+
{
|
|
1847
|
+
encoding: "utf-8",
|
|
1848
|
+
maxBuffer: 25 * 1024 * 1024,
|
|
1849
|
+
timeout: OPENCLAW_MODELS_PER_PROVIDER_TIMEOUT_MS,
|
|
1850
|
+
env: NO_COLOR_ENV,
|
|
1851
|
+
},
|
|
1852
|
+
);
|
|
1853
|
+
return { provider, stdout };
|
|
1854
|
+
} catch (err) {
|
|
1855
|
+
return { provider, error: err };
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1833
1859
|
try {
|
|
1834
|
-
const
|
|
1835
|
-
|
|
1836
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
1837
|
-
maxBuffer: 50 * 1024 * 1024,
|
|
1838
|
-
timeout: 30_000,
|
|
1839
|
-
env: NO_COLOR_ENV,
|
|
1840
|
-
});
|
|
1841
|
-
const parsed = extractJson(raw);
|
|
1842
|
-
if (!parsed) throw new Error(`Could not extract JSON from openclaw models list output (first 200 chars): ${stripAnsi(raw).slice(0, 200)}`);
|
|
1843
|
-
const models = Array.isArray(parsed?.models) ? parsed.models : [];
|
|
1860
|
+
const t0 = Date.now();
|
|
1861
|
+
const batches = await Promise.all(providerIds.map((p) => fetchModelsForProvider(p)));
|
|
1844
1862
|
const providerMap = new Map();
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
const
|
|
1849
|
-
if (
|
|
1850
|
-
const
|
|
1851
|
-
const
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1863
|
+
|
|
1864
|
+
for (const batch of batches) {
|
|
1865
|
+
if (batch.error || !batch.stdout) continue;
|
|
1866
|
+
const parsed = extractJson(batch.stdout);
|
|
1867
|
+
if (!parsed) continue;
|
|
1868
|
+
const models = Array.isArray(parsed?.models) ? parsed.models : [];
|
|
1869
|
+
const want = batch.provider;
|
|
1870
|
+
for (const entry of models) {
|
|
1871
|
+
if (!entry || typeof entry.key !== "string") continue;
|
|
1872
|
+
const modelId = String(entry.key);
|
|
1873
|
+
const slash = modelId.indexOf("/");
|
|
1874
|
+
if (slash <= 0 || slash === modelId.length - 1) continue;
|
|
1875
|
+
const provider = modelId.slice(0, slash);
|
|
1876
|
+
if (provider !== want) continue;
|
|
1877
|
+
const existing = providerMap.get(provider) || [];
|
|
1878
|
+
existing.push({
|
|
1879
|
+
id: modelId,
|
|
1880
|
+
name: typeof entry.name === "string" && entry.name.trim() ? entry.name : modelId,
|
|
1881
|
+
});
|
|
1882
|
+
providerMap.set(provider, existing);
|
|
1883
|
+
}
|
|
1857
1884
|
}
|
|
1858
1885
|
|
|
1859
|
-
const providers =
|
|
1860
|
-
.sort((a, b) => a.localeCompare(b))
|
|
1886
|
+
const providers = providerIds
|
|
1861
1887
|
.map((id) => {
|
|
1862
1888
|
const rawModels = providerMap.get(id) || [];
|
|
1863
1889
|
const sortedIds = sortModelsByPreference(
|
|
@@ -1865,7 +1891,8 @@ function loadWizardLlmCatalog() {
|
|
|
1865
1891
|
rawModels.map((m) => m.id),
|
|
1866
1892
|
);
|
|
1867
1893
|
const byId = new Map(rawModels.map((m) => [m.id, m]));
|
|
1868
|
-
const
|
|
1894
|
+
const limitedIds = sortedIds.slice(0, MAX_MODELS_PER_PROVIDER_SORT);
|
|
1895
|
+
const models = limitedIds.map((mid) => byId.get(mid)).filter(Boolean);
|
|
1869
1896
|
return { id, models };
|
|
1870
1897
|
})
|
|
1871
1898
|
.filter((entry) => supportedProviders.has(entry.id))
|
|
@@ -1875,10 +1902,12 @@ function loadWizardLlmCatalog() {
|
|
|
1875
1902
|
return { ...fallback, warning: "openclaw_model_catalog_empty" };
|
|
1876
1903
|
}
|
|
1877
1904
|
|
|
1905
|
+
const elapsedMs = Date.now() - t0;
|
|
1878
1906
|
return {
|
|
1879
1907
|
source: "openclaw",
|
|
1880
1908
|
providers,
|
|
1881
1909
|
generatedAt: new Date().toISOString(),
|
|
1910
|
+
catalogFetchMs: elapsedMs,
|
|
1882
1911
|
};
|
|
1883
1912
|
} catch (err) {
|
|
1884
1913
|
const detail = err?.message || String(err);
|
|
@@ -2629,7 +2658,15 @@ async function cmdInstall(args) {
|
|
|
2629
2658
|
}
|
|
2630
2659
|
|
|
2631
2660
|
if (req.method === "GET" && req.url === "/api/llm/options") {
|
|
2632
|
-
|
|
2661
|
+
try {
|
|
2662
|
+
const payload = await loadWizardLlmCatalogAsync();
|
|
2663
|
+
respondJson(200, payload);
|
|
2664
|
+
} catch (err) {
|
|
2665
|
+
respondJson(500, {
|
|
2666
|
+
source: "error",
|
|
2667
|
+
message: err instanceof Error ? err.message : String(err),
|
|
2668
|
+
});
|
|
2669
|
+
}
|
|
2633
2670
|
return;
|
|
2634
2671
|
}
|
|
2635
2672
|
|
package/package.json
CHANGED