mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-02 06:34:54 +00:00
fix(models): preserve source snapshots for SecretRef providers
* fix(models): preserve source snapshots for SecretRef providers * docs: add models SecretRef changelog entry --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -67,6 +67,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Discord/voice: recover stale realtime playback state when Discord stream-close/player-idle events do not arrive, and keep generated runtime plugin aliases available after postbuild rewrites.
|
||||
- Discord/voice: keep realtime playback running when meeting notes attaches to an existing voice session or a realtime consult starts, and route realtime user transcripts into meeting notes.
|
||||
- Config/secrets: preflight active runtime SecretRefs before root and include config writes persist, and roll back unchanged file/env state when post-write refresh fails. Fixes #46531. (#84454) Thanks @samzong.
|
||||
- CLI/models: preserve SecretRef-backed custom provider `apiKey` markers when `models status` regenerates `models.json`, avoiding resolved plaintext secrets on disk. Fixes #84632. (#84658) Thanks @NianJiuZst.
|
||||
- WebChat: keep the run-complete indicator in progress until deferred history replay renders the assistant reply, so Done no longer appears before response text. (#85374) Thanks @neeravmakwana.
|
||||
- Agents/tools: give timed-out or cancelled process trees a bounded SIGTERM cleanup window before SIGKILL while preserving tree-aware cancellation. Fixes #66399. (#85865) Thanks @IWhatsskill.
|
||||
- Agents/compaction: skip agent-harness preflight for provider-owned CLI runtime sessions so over-threshold Claude CLI sessions continue through normal compaction instead of failing on a missing harness. Fixes #84857. (#84878) Thanks @zhangguiping-xydt.
|
||||
|
||||
@@ -100,6 +100,40 @@ function createOpenAiApiKeyRuntimeConfig(): OpenClawConfig {
|
||||
};
|
||||
}
|
||||
|
||||
function createCustomProviderApiKeySourceConfig(): OpenClawConfig {
|
||||
return {
|
||||
models: {
|
||||
providers: {
|
||||
litellm: {
|
||||
baseUrl: "https://litellm.example/v1",
|
||||
apiKey: {
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "OPENCLAW_MODEL_LITELLM_API_KEY", // pragma: allowlist secret
|
||||
},
|
||||
api: "openai-completions" as const,
|
||||
models: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createCustomProviderApiKeyRuntimeConfig(): OpenClawConfig {
|
||||
return {
|
||||
models: {
|
||||
providers: {
|
||||
litellm: {
|
||||
baseUrl: "https://litellm.example/v1",
|
||||
apiKey: "sk-litellm-runtime-secret", // pragma: allowlist secret
|
||||
api: "openai-completions" as const,
|
||||
models: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createOpenAiHeaderSourceConfig(): OpenClawConfig {
|
||||
return {
|
||||
models: {
|
||||
@@ -280,6 +314,24 @@ describe("models-config runtime source snapshot", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves source markers for custom-provider api keys after models status secret resolution", async () => {
|
||||
const agentDir = await fixtureSuite.createCaseDir("agent");
|
||||
await withTempEnv(MODELS_CONFIG_IMPLICIT_ENV_VARS, async () => {
|
||||
unsetEnv(MODELS_CONFIG_IMPLICIT_ENV_VARS);
|
||||
const sourceConfig = createCustomProviderApiKeySourceConfig();
|
||||
const runtimeConfig = createCustomProviderApiKeyRuntimeConfig();
|
||||
|
||||
try {
|
||||
setRuntimeConfigSnapshot(runtimeConfig, sourceConfig);
|
||||
await ensureOpenClawModelsJson(runtimeConfig, agentDir);
|
||||
await expectGeneratedProviderApiKey(agentDir, "litellm", "OPENCLAW_MODEL_LITELLM_API_KEY"); // pragma: allowlist secret
|
||||
} finally {
|
||||
clearRuntimeConfigSnapshot();
|
||||
clearConfigCache();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("invalidates cached readiness when projected config changes under the same runtime snapshot", async () => {
|
||||
const agentDir = await fixtureSuite.createCaseDir("agent");
|
||||
await withTempEnv(MODELS_CONFIG_IMPLICIT_ENV_VARS, async () => {
|
||||
|
||||
@@ -99,6 +99,6 @@ describe("models load-config", () => {
|
||||
const result = await loadModelsConfigWithSource({ commandName: "models list" });
|
||||
|
||||
expect(result.sourceConfig).toBe(runtimeConfig);
|
||||
expect(mocks.setRuntimeConfigSnapshot).toHaveBeenCalledWith(resolvedConfig);
|
||||
expect(mocks.setRuntimeConfigSnapshot).toHaveBeenCalledWith(resolvedConfig, runtimeConfig);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,11 +27,7 @@ export async function loadModelsConfigWithSource(params: {
|
||||
targetIds: getModelsCommandSecretTargetIds(),
|
||||
runtime: params.runtime,
|
||||
});
|
||||
if (pinnedSourceConfig) {
|
||||
setRuntimeConfigSnapshot(resolvedConfig, sourceConfig);
|
||||
} else {
|
||||
setRuntimeConfigSnapshot(resolvedConfig);
|
||||
}
|
||||
setRuntimeConfigSnapshot(resolvedConfig, sourceConfig);
|
||||
return {
|
||||
sourceConfig,
|
||||
resolvedConfig,
|
||||
|
||||
Reference in New Issue
Block a user