Major changes: - Add autoconfigure_models tool for intelligent model assignment - Implement LLM-based model selection using openclaw agent - Improve onboarding flow with better model access checks - Update README with clearer installation and onboarding instructions Technical improvements: - Add model-fetcher utility to query authenticated models - Add smart-model-selector for LLM-driven model assignment - Use session context for LLM calls during onboarding - Suppress logging from openclaw models list calls Documentation: - Add prerequisites section to README - Add conversational onboarding example - Improve quick start flow Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
82 lines
2.3 KiB
TypeScript
82 lines
2.3 KiB
TypeScript
/**
|
|
* model-fetcher.ts — Shared helper for fetching OpenClaw models without logging.
|
|
*
|
|
* Uses execSync to bypass OpenClaw's command logging infrastructure.
|
|
*/
|
|
import { execSync } from "node:child_process";
|
|
|
|
export type OpenClawModelRow = {
|
|
key: string;
|
|
name?: string;
|
|
input: string;
|
|
contextWindow: number | null;
|
|
local: boolean;
|
|
available: boolean;
|
|
tags: string[];
|
|
missing?: boolean;
|
|
};
|
|
|
|
/**
|
|
* Fetch all models from OpenClaw without logging.
|
|
*
|
|
* @param allModels - If true, fetches all models (--all flag). If false, only authenticated models.
|
|
* @returns Array of model objects from OpenClaw's model registry
|
|
*/
|
|
export function fetchModels(allModels = true): OpenClawModelRow[] {
|
|
try {
|
|
const command = allModels
|
|
? "openclaw models list --all --json"
|
|
: "openclaw models list --json";
|
|
|
|
// Use execSync directly to bypass OpenClaw's command logging
|
|
const output = execSync(command, {
|
|
encoding: "utf-8",
|
|
timeout: 10000,
|
|
cwd: process.cwd(),
|
|
// Suppress stderr to avoid any error messages
|
|
stdio: ["pipe", "pipe", "ignore"],
|
|
}).trim();
|
|
|
|
if (!output) {
|
|
throw new Error("Empty output from openclaw models list");
|
|
}
|
|
|
|
// Parse JSON (skip any log lines like "[plugins] ...")
|
|
const lines = output.split("\n");
|
|
|
|
// Find the first line that starts with { (the beginning of JSON)
|
|
const jsonStartIndex = lines.findIndex((line: string) => {
|
|
const trimmed = line.trim();
|
|
return trimmed.startsWith("{");
|
|
});
|
|
|
|
if (jsonStartIndex === -1) {
|
|
throw new Error(
|
|
`No JSON object found in output. Got: ${output.substring(0, 200)}...`,
|
|
);
|
|
}
|
|
|
|
// Join all lines from the JSON start to the end
|
|
const jsonString = lines.slice(jsonStartIndex).join("\n");
|
|
|
|
const data = JSON.parse(jsonString);
|
|
const models = data.models as OpenClawModelRow[];
|
|
|
|
if (!Array.isArray(models)) {
|
|
throw new Error(`Expected array of models, got: ${typeof models}`);
|
|
}
|
|
|
|
return models;
|
|
} catch (err) {
|
|
throw new Error(`Failed to fetch models: ${(err as Error).message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch only authenticated models (available: true).
|
|
*/
|
|
export function fetchAuthenticatedModels(): OpenClawModelRow[] {
|
|
// Use --all flag but suppress logging via stdio in fetchModels()
|
|
return fetchModels(true).filter((m) => m.available === true);
|
|
}
|