fix(cli): allow Ollama apiKey config set without predeclared provider (#29299)

* CLI: seed Ollama provider on apiKey set

* Tests: cover Ollama apiKey config set path
This commit is contained in:
Vincent Koc
2026-02-27 23:35:57 -08:00
committed by GitHub
parent 7968c0f514
commit b297bae027
2 changed files with 47 additions and 0 deletions

View File

@@ -141,6 +141,24 @@ describe("config cli", () => {
expect(written.gateway?.port).toBe(18789);
expect(written.gateway?.auth).toEqual({ mode: "token" });
});
it("auto-seeds a valid Ollama provider when setting only models.providers.ollama.apiKey", async () => {
const resolved: OpenClawConfig = {
gateway: { port: 18789 },
};
setSnapshot(resolved, resolved);
await runConfigCommand(["config", "set", "models.providers.ollama.apiKey", '"ollama-local"']);
expect(mockWriteConfigFile).toHaveBeenCalledTimes(1);
const written = mockWriteConfigFile.mock.calls[0]?.[0];
expect(written.models?.providers?.ollama).toEqual({
baseUrl: "http://127.0.0.1:11434",
api: "ollama",
models: [],
apiKey: "ollama-local",
});
});
});
describe("config get", () => {

View File

@@ -16,6 +16,10 @@ type ConfigSetParseOpts = {
strictJson?: boolean;
};
const OLLAMA_API_KEY_PATH: PathSegment[] = ["models", "providers", "ollama", "apiKey"];
const OLLAMA_PROVIDER_PATH: PathSegment[] = ["models", "providers", "ollama"];
const OLLAMA_DEFAULT_BASE_URL = "http://127.0.0.1:11434";
function isIndexSegment(raw: string): boolean {
return /^[0-9]+$/.test(raw);
}
@@ -242,6 +246,30 @@ function parseRequiredPath(path: string): PathSegment[] {
return parsedPath;
}
function pathEquals(path: PathSegment[], expected: PathSegment[]): boolean {
return (
path.length === expected.length && path.every((segment, index) => segment === expected[index])
);
}
function ensureValidOllamaProviderForApiKeySet(
root: Record<string, unknown>,
path: PathSegment[],
): void {
if (!pathEquals(path, OLLAMA_API_KEY_PATH)) {
return;
}
const existing = getAtPath(root, OLLAMA_PROVIDER_PATH);
if (existing.found) {
return;
}
setAtPath(root, OLLAMA_PROVIDER_PATH, {
baseUrl: OLLAMA_DEFAULT_BASE_URL,
api: "ollama",
models: [],
});
}
export async function runConfigGet(opts: { path: string; json?: boolean; runtime?: RuntimeEnv }) {
const runtime = opts.runtime ?? defaultRuntime;
try {
@@ -345,6 +373,7 @@ export function registerConfigCli(program: Command) {
// instead of snapshot.config (runtime-merged with defaults).
// This prevents runtime defaults from leaking into the written config file (issue #6070)
const next = structuredClone(snapshot.resolved) as Record<string, unknown>;
ensureValidOllamaProviderForApiKeySet(next, parsedPath);
setAtPath(next, parsedPath, parsedValue);
await writeConfigFile(next);
defaultRuntime.log(info(`Updated ${path}. Restart the gateway to apply.`));