refactor(agent): runAgent uses Agent upstreams only; deprecate legacy settings.pi fields
pi.provider / baseUrl / model / thinkingLevel / apiKeySecretRef are now DEPRECATED_SETTINGS_FIELDS: kept in the schema for stored JSON, dropped from PATCH /settings and from the settings sections, never read by the server. runAgent fails with a clear message when no upstream is set. The agent demo gate checks the default upstream provider; e2e seeds a fake upstream as default. OpenAPI summaries say Agent upstream. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
fb7727cf66
commit
3e37ac8ae7
15 files changed
+122
-115
No files matched your search
@@ -5,7 +5,8 @@ import { audit, endpoint } from "./endpoint.ts";
|
||||
import { type CachedSettingsReader, SETTINGS_CHANGED_EVENT } from "./provided.ts";
|
||||
|
||||
// GET/PATCH /settings:按分组部分更新 → mergeSettings → GlobalSettings 整体校验 → 逐组 upsert;
|
||||
// Pi 上游密钥(pi.apiKey 只写)存为 secret,设置里只留 apiKeySecretRef;变更经 SSE 总线广播 settings.changed,
|
||||
// TMDB 密钥(metadata.tmdbApiKey 只写)存为 secret,设置里只留 tmdbApiKeySecretRef(Agent 上游密钥在 pi_upstream,
|
||||
// 旧 pi.apiKey 已弃用,PATCH 里会被 schema 丢弃);变更经 SSE 总线广播 settings.changed,
|
||||
// 各进程的 ctx.settings 缓存随之失效。自动化总开关 automation.enabled / 只读对账 automation.readOnlyReconcile 也走这里。
|
||||
|
||||
const isCached = (s: unknown): s is CachedSettingsReader =>
|
||||
@@ -21,15 +22,7 @@ export function registerSettingsRoutes(app: ModuleApp, ctx: ServerContext) {
|
||||
const patch = body as GlobalSettingsUpdate;
|
||||
const current = isCached(ctx.settings) ? await ctx.settings.fresh() : await ctx.settings.all();
|
||||
const merged = mergeSettings(current, patch);
|
||||
const oldRef = current.pi.apiKeySecretRef;
|
||||
let dropRef: string | null = null;
|
||||
let newRef: string | null = null;
|
||||
const apiKey = patch.pi?.apiKey;
|
||||
if (apiKey === null) {
|
||||
merged.pi.apiKeySecretRef = null;
|
||||
dropRef = oldRef;
|
||||
}
|
||||
// TMDB 密钥同样只写:存 secret(metadata_api_key),设置里只留 tmdbApiKeySecretRef
|
||||
// TMDB 密钥只写:存 secret(metadata_api_key),设置里只留 tmdbApiKeySecretRef
|
||||
const oldTmdbRef = current.metadata.tmdbApiKeySecretRef;
|
||||
const tmdbKey = patch.metadata?.tmdbApiKey;
|
||||
let dropTmdbRef: string | null = null;
|
||||
@@ -44,15 +37,6 @@ export function registerSettingsRoutes(app: ModuleApp, ctx: ServerContext) {
|
||||
throw new ApiException("validation_failed", msg);
|
||||
}
|
||||
const next = parsed.data;
|
||||
if (typeof apiKey === "string") {
|
||||
if (oldRef) {
|
||||
await ctx.secrets.replace(oldRef, apiKey);
|
||||
next.pi.apiKeySecretRef = oldRef;
|
||||
} else {
|
||||
newRef = await ctx.secrets.create({ purpose: "llm_api_key", plaintext: apiKey });
|
||||
next.pi.apiKeySecretRef = newRef;
|
||||
}
|
||||
}
|
||||
if (typeof tmdbKey === "string") {
|
||||
if (oldTmdbRef) {
|
||||
await ctx.secrets.replace(oldTmdbRef, tmdbKey);
|
||||
@@ -76,17 +60,14 @@ export function registerSettingsRoutes(app: ModuleApp, ctx: ServerContext) {
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
if (newRef) await ctx.secrets.remove(newRef).catch(() => {});
|
||||
if (newTmdbRef) await ctx.secrets.remove(newTmdbRef).catch(() => {});
|
||||
throw err;
|
||||
}
|
||||
if (dropRef) await ctx.secrets.remove(dropRef).catch(() => {});
|
||||
if (dropTmdbRef) await ctx.secrets.remove(dropTmdbRef).catch(() => {});
|
||||
if (isCached(ctx.settings)) ctx.settings.invalidate();
|
||||
void ctx.events.publish(SETTINGS_CHANGED_EVENT, { keys });
|
||||
// 审计里不留明文密钥
|
||||
const logged: Record<string, unknown> = { ...patch };
|
||||
if (patch.pi && "apiKey" in patch.pi) logged.pi = { ...patch.pi, apiKey: apiKey === null ? "(cleared)" : "(set)" };
|
||||
if (patch.metadata && "tmdbApiKey" in patch.metadata)
|
||||
logged.metadata = { ...patch.metadata, tmdbApiKey: tmdbKey === null ? "(cleared)" : "(set)" };
|
||||
await audit(ctx, actor, "settings.update", { type: "settings", id: keys.join(",") }, { patch: logged });
|
||||
|
||||
Reference in new issue
Block a user