feat: LLM-powered model auto-configuration and improved onboarding
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>
This commit is contained in:
81
lib/setup/model-fetcher.ts
Normal file
81
lib/setup/model-fetcher.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
Reference in New Issue
Block a user