Files
devclaw-gitea/lib/tools/autoconfigure-models.ts
Lauren ten Hoor b2fc94db9e 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>
2026-02-12 20:37:15 +08:00

137 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* autoconfigure-models.ts — Tool for automatically configuring model assignments.
*
* Queries available authenticated models and intelligently assigns them to DevClaw roles.
*/
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
import { jsonResult } from "openclaw/plugin-sdk";
import type { ToolContext } from "../types.js";
import {
assignModels,
formatAssignment,
generateSetupInstructions,
type ModelAssignment,
} from "../setup/smart-model-selector.js";
import { fetchAuthenticatedModels } from "../setup/model-fetcher.js";
/**
* Get available authenticated models from OpenClaw.
*/
async function getAuthenticatedModels(
api: OpenClawPluginApi,
): Promise<Array<{ model: string; provider: string; authenticated: boolean }>> {
try {
const models = fetchAuthenticatedModels();
// Map to the format expected by assignModels()
return models.map((m) => {
// Extract provider from key (format: provider/model-name)
const provider = m.key.split("/")[0] || "unknown";
return {
model: m.key,
provider,
authenticated: true,
};
});
} catch (err) {
throw new Error(`Failed to get authenticated models: ${(err as Error).message}`);
}
}
/**
* Create the autoconfigure_models tool.
*/
export function createAutoConfigureModelsTool(api: OpenClawPluginApi) {
return (ctx: ToolContext) => ({
name: "autoconfigure_models",
label: "Auto-Configure Models",
description:
"Automatically discover authenticated models and intelligently assign them to DevClaw roles based on capability tiers",
parameters: {
type: "object",
properties: {
preferProvider: {
type: "string",
description:
"Optional: Prefer models from this provider (e.g., 'anthropic', 'openai')",
},
},
},
async execute(_id: string, params: Record<string, unknown>) {
try {
// Get all authenticated models
let authenticatedModels = await getAuthenticatedModels(api);
// Filter by preferred provider if specified
const preferProvider = params?.preferProvider as string | undefined;
if (preferProvider) {
const filtered = authenticatedModels.filter(
(m) => m.provider.toLowerCase() === preferProvider.toLowerCase(),
);
if (filtered.length === 0) {
return jsonResult({
success: false,
error: `No authenticated models found for provider: ${preferProvider}`,
message: `❌ No authenticated models found for provider "${preferProvider}".\n\nAvailable providers: ${[...new Set(authenticatedModels.map((m) => m.provider))].join(", ")}`,
});
}
authenticatedModels = filtered;
}
// Intelligently assign models using current session context
const assignment = await assignModels(authenticatedModels, ctx.sessionKey);
if (!assignment) {
// No models available
const instructions = generateSetupInstructions();
return jsonResult({
success: false,
modelCount: 0,
message: instructions,
});
}
// Format the assignment
const table = formatAssignment(assignment);
const modelCount = authenticatedModels.length;
let message = `✅ Auto-configured models based on ${modelCount} authenticated model${modelCount === 1 ? "" : "s"}:\n\n`;
message += table;
message += "\n\n";
if (modelCount === 1) {
message += " Only one authenticated model found — assigned to all roles.";
} else {
message += " Models assigned by capability tier (Tier 1 → senior, Tier 2 → medior/reviewer, Tier 3 → junior/tester).";
}
if (preferProvider) {
message += `\n📌 Filtered to provider: ${preferProvider}`;
}
message += "\n\n**Next step:** Pass this configuration to `setup` tool:\n";
message += "```javascript\n";
message += "setup({ models: <this-configuration> })\n";
message += "```";
return jsonResult({
success: true,
modelCount,
assignment,
models: assignment,
provider: preferProvider || "auto",
message,
});
} catch (err) {
const errorMsg = (err as Error).message;
api.logger.error(`Auto-configure models error: ${errorMsg}`);
return jsonResult({
success: false,
error: errorMsg,
message: `❌ Failed to auto-configure models: ${errorMsg}`,
});
}
},
});
}