feat: add custom model selection to all agents (#2659)

Move "Custom model" from OpenClaw-specific to common setup steps so
every agent shows it in the setup menu. Add modelEnvVar to agents that
support model override via environment variable:

- Kilo Code: KILOCODE_MODEL
- ZeroClaw: ZEROCLAW_MODEL
- Hermes: LLM_MODEL
- Junie: JUNIE_MODEL

When a custom model is selected, the env var is injected into .spawnrc
alongside the other agent env vars. OpenClaw continues to use its
existing configure() path. Claude and Codex don't have modelEnvVar
since they handle model routing differently.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ahmed Abushagur 2026-03-15 12:44:48 -07:00 committed by GitHub
parent bc2aa89002
commit 0a7a95ec3c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 18 additions and 7 deletions

View file

@ -1,6 +1,6 @@
{
"name": "@openrouter/spawn",
"version": "0.18.10",
"version": "0.19.0",
"type": "module",
"bin": {
"spawn": "cli.js"

View file

@ -726,6 +726,7 @@ function createAgents(runner: CloudRunner): Record<string, AgentConfig> {
kilocode: {
name: "Kilo Code",
cloudInitTier: "node",
modelEnvVar: "KILOCODE_MODEL",
preProvision: detectGithubAuth,
install: () =>
installAgent(
@ -744,6 +745,7 @@ function createAgents(runner: CloudRunner): Record<string, AgentConfig> {
zeroclaw: {
name: "ZeroClaw",
cloudInitTier: "minimal",
modelEnvVar: "ZEROCLAW_MODEL",
preProvision: detectGithubAuth,
install: async () => {
// Direct binary install from pinned release (v0.1.9a "latest" has no assets,
@ -774,6 +776,7 @@ function createAgents(runner: CloudRunner): Record<string, AgentConfig> {
hermes: {
name: "Hermes Agent",
cloudInitTier: "minimal",
modelEnvVar: "LLM_MODEL",
preProvision: detectGithubAuth,
install: () =>
installAgent(
@ -794,6 +797,7 @@ function createAgents(runner: CloudRunner): Record<string, AgentConfig> {
junie: {
name: "Junie",
cloudInitTier: "node",
modelEnvVar: "JUNIE_MODEL",
preProvision: detectGithubAuth,
install: () =>
installAgent(

View file

@ -22,6 +22,8 @@ export interface AgentConfig {
name: string;
/** Default model ID passed to configure() (no interactive prompt — override via MODEL_ID env var). */
modelDefault?: string;
/** Env var name for setting the model on the remote (e.g. ZEROCLAW_MODEL, LLM_MODEL). */
modelEnvVar?: string;
/** Pre-provision hook (runs before server creation, e.g., prompt for GitHub auth). */
preProvision?: () => Promise<void>;
/** Install the agent on the remote machine. */
@ -66,11 +68,6 @@ const AGENT_EXTRA_STEPS: Record<string, OptionalStep[]> = {
hint: "connect via bot token from @BotFather",
dataEnvVar: "TELEGRAM_BOT_TOKEN",
},
{
value: "custom-model",
label: "Custom model",
hint: "enter an OpenRouter model ID manually",
},
],
};
@ -86,6 +83,11 @@ const COMMON_STEPS: OptionalStep[] = [
label: "Reuse saved OpenRouter key",
hint: "off = create a fresh key via OAuth",
},
{
value: "custom-model",
label: "Custom model",
hint: "enter an OpenRouter model ID manually",
},
];
/** Get the optional setup steps for a given agent (no CloudRunner required). */

View file

@ -174,7 +174,12 @@ export async function runOrchestration(
// 7. Wait for readiness
await cloud.waitForReady();
const envContent = generateEnvConfig(agent.envVars(apiKey));
const envPairs = agent.envVars(apiKey);
// Inject agent-specific model env var when a custom model is selected
if (modelId && agent.modelEnvVar) {
envPairs.push(`${agent.modelEnvVar}=${modelId}`);
}
const envContent = generateEnvConfig(envPairs);
// 8. Install agent (skip entirely for snapshot boots, try tarball first on cloud VMs)
if (cloud.skipAgentInstall) {