refactor(copy): 术语统一——收录版本、模型服务、智能体等(DEAI-2)

- 版本目标 → 收录版本(前后端用户可见字符串、能力描述、给模型的提示)
- Agent 上游 / 上游 → 模型服务;界面上的 Agent / Agent 会话 → 智能体 / 智能体会话
- 身份歧义 / 识别有歧义 / 无法确定作品 → 没识别出作品;待识别(池) → 未识别
- 建档 → 加入媒体库;资产 → 文件;库根 → 媒体库目录;纳管 → 本工具 / 外部任务;
  哨兵 → 标记文件 / 检查目录;站点快照 → 抓取;Feed / RSS 订阅 / 来源健康 → RSS
- 代码标识符、API 字段名、迁移文件不改;glossary.md 同步;smoke 选择器跟随

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-29 20:35:43 +08:00
1 parent d282212a6b
commit 4480fc346d
212 files changed
+741 -715

No files matched your search

+2 -2
View File
@@ -73,8 +73,8 @@ export function createPiModule(
registerScheduledJob(ctx, {
key: "pi.token_refresh",
defaults: {
name: "上游登录刷新",
description: "订阅登录即将过期的 Agent 上游,提前刷新 token",
name: "模型服务登录刷新",
description: "订阅登录即将过期的模型服务,提前刷新 token",
group: "maintain",
schedule: { type: "interval", everyMs: interval },
},
+4 -4
View File
@@ -92,12 +92,12 @@ function keyOf(cred: UpstreamCredential | undefined): string | null {
/** 按 provider / 认证方式挑模型列表接口 */
function planFor(spec: UpstreamSpec, cred: UpstreamCredential | undefined): Plan {
const extra = spec.extra ?? {};
if (spec.provider === "fake") return { kind: "unsupported", reason: "Fake 上游没有远程模型列表" };
if (spec.provider === "fake") return { kind: "unsupported", reason: "Fake 模型服务没有远程模型列表" };
if (spec.provider === "radius") return { kind: "pi" };
const custom = spec.provider === "openai-compatible";
// 订阅登录只有 OpenRouter 换到的是普通 API Key,其它订阅 token 不能调公开的模型列表接口
if (spec.authKind === "oauth" && spec.provider !== "openrouter")
return { kind: "unsupported", reason: "订阅登录的上游没有公开的模型列表接口,用内置模型表" };
return { kind: "unsupported", reason: "订阅登录的模型服务没有公开的模型列表接口,用内置模型表" };
const key = keyOf(cred);
if (spec.authKind !== "none" && !key && !custom) throw new FetchError("auth", "还没有配置 API Key");
@@ -232,7 +232,7 @@ function normalizeGoogle(item: Record<string, unknown>): Remote | null {
function parseList(shape: Shape, body: unknown): Remote[] {
const b = obj(body);
const raw = Array.isArray(body) ? body : Array.isArray(b.data) ? b.data : Array.isArray(b.models) ? b.models : null;
if (!raw) throw new FetchError("other", "上游返回的不是模型列表");
if (!raw) throw new FetchError("other", "模型服务返回的不是模型列表");
const norm = shape === "anthropic" ? normalizeAnthropic : shape === "google" ? normalizeGoogle : normalizeOpenAI;
const out: Remote[] = [];
const seen = new Set<string>();
@@ -376,7 +376,7 @@ async function fetchRemote(
if (plan.kind === "unsupported") throw new FetchError("unsupported", plan.reason);
if (plan.kind === "http") return await fetchList(plan.endpoint);
// Radius:pi-ai 自带的动态刷新
if (!client) throw new FetchError("config", "上游配置不完整");
if (!client) throw new FetchError("config", "模型服务配置不完整");
const r = await client.listModels({ refresh: true });
if (!r.refreshed) throw toFetchError(new Error(r.refreshError ?? "刷新失败"));
return r.items.map(fromInfo);
+3 -3
View File
@@ -105,8 +105,8 @@ export class OAuthSessions {
async start(row: PiUpstreamRow, req: { mode?: PiOAuthMode; enterpriseDomain?: string }): Promise<PiOAuthStartResult> {
const info = providerInfo(row.provider);
if (row.auth_kind !== "oauth" || !info?.oauth)
throw new ApiException("precondition_failed", "这个上游不是订阅登录类型");
if (!row.enabled) throw new ApiException("precondition_failed", "上游已停用");
throw new ApiException("precondition_failed", "这个模型服务不是订阅登录类型");
if (!row.enabled) throw new ApiException("precondition_failed", "模型服务已停用");
const mode = req.mode ?? info.oauth.modes[0]!;
if (!info.oauth.modes.includes(mode))
throw new ApiException(
@@ -270,6 +270,6 @@ export class OAuthSessions {
export async function requireRow(ctx: ServerContext, id: string): Promise<PiUpstreamRow> {
const row = await getRow(ctx, id);
if (!row) throw new ApiException("not_found", "上游不存在");
if (!row) throw new ApiException("not_found", "模型服务不存在");
return row;
}
+3 -3
View File
@@ -24,13 +24,13 @@ const DECISION_KEY = (id: string) => `pi_upstream_expired:${id}`;
/** 与其它模块的 upsertDecision 同一写法(跨模块不 import):同键未关闭时只累加 attempts */
async function upsertExpiredDecision(ctx: ServerContext, row: PiUpstreamRow, message: string) {
const title = `Agent 上游「${row.name}」登录已失效,需要重新登录`;
const title = `模型服务「${row.name}」登录已失效,需要重新登录`;
await ctx.db.transaction().execute(async (trx) => {
const r = await sql<{ id: string; inserted: boolean }>`
insert into decision (kind, severity, title, summary, subject_type, subject_id, dedupe_key, evidence, options)
values ('other', 'warning', ${title}, ${message}, 'pi_upstream', ${row.id}, ${DECISION_KEY(row.id)},
${JSON.stringify({ provider: row.provider, upstreamId: row.id, error: message })}::jsonb,
${JSON.stringify([{ key: "relogin", label: "重新登录", description: "设置 → Agent → 上游" }])}::jsonb)
${JSON.stringify([{ key: "relogin", label: "重新登录", description: "设置 → 智能体 → 模型服务" }])}::jsonb)
on conflict (dedupe_key) where status in ('open', 'investigating', 'awaiting_user')
do update set attempts = decision.attempts + 1, evidence = excluded.evidence, summary = excluded.summary,
updated_at = now()
@@ -102,7 +102,7 @@ export async function refreshPiTokens(ctx: ServerContext, opts: RefreshOptions =
if (r.ok) report.refreshed += 1;
else {
report.failed.push({ upstreamId: row.id, message: r.message });
ctx.logger.warn({ upstreamId: row.id, provider: row.provider, message: r.message }, "Agent 上游 token 刷新失败");
ctx.logger.warn({ upstreamId: row.id, provider: row.provider, message: r.message }, "模型服务 token 刷新失败");
}
}
return report;
+8 -7
View File
@@ -116,7 +116,7 @@ export async function createUpstream(
.execute();
} catch (err) {
if (secretRef) await ctx.secrets.remove(secretRef).catch(() => {});
if (isUnique(err)) throw new ApiException("conflict", `上游名称「${body.name}」已存在`);
if (isUnique(err)) throw new ApiException("conflict", `模型服务名称「${body.name}」已存在`);
throw err;
}
if (body.makeDefault || !(await defaultUpstreamId(ctx))) await setDefaultUpstream(ctx, id);
@@ -140,7 +140,7 @@ export async function updateUpstream(
const defaultModel = body.defaultModel !== undefined ? body.defaultModel : row.default_model;
validateShape({ provider: row.provider, authKind, baseUrl, defaultModel });
if (body.apiKey && authKind !== "api_key")
throw new ApiException("validation_failed", "只有 api_key 型上游可以填 apiKey");
throw new ApiException("validation_failed", "只有 api_key 型模型服务可以填 apiKey");
const kindChanged = authKind !== row.auth_kind;
const store = dbCredentialStore(ctx, row.id);
@@ -167,7 +167,7 @@ export async function updateUpstream(
.where("id", "=", row.id)
.execute()
.catch((err) => {
if (isUnique(err)) throw new ApiException("conflict", `上游名称「${body.name}」已存在`);
if (isUnique(err)) throw new ApiException("conflict", `模型服务名称「${body.name}」已存在`);
throw err;
});
if (typeof body.apiKey === "string") {
@@ -217,10 +217,11 @@ export async function resolveRunUpstream(ctx: ServerContext, upstreamId?: string
const id = upstreamId ?? (await defaultUpstreamId(ctx));
if (!id) return null;
const row = await getRow(ctx, id);
if (!row) throw new Error(upstreamId ? `指定的上游 ${upstreamId} 不存在` : "默认上游已不存在,在设置里重新选择");
if (!row.enabled) throw new Error(`上游「${row.name}」已停用`);
if (row.status === "expired") throw new Error(`上游「${row.name}」登录已失效,在设置里重新登录`);
if (!row)
throw new Error(upstreamId ? `指定的模型服务 ${upstreamId} 不存在` : "默认模型服务已不存在,在设置里重新选择");
if (!row.enabled) throw new Error(`模型服务「${row.name}」已停用`);
if (row.status === "expired") throw new Error(`模型服务「${row.name}」登录已失效,在设置里重新登录`);
if (row.status === "auth_required")
throw new Error(`上游「${row.name}」${row.auth_kind === "oauth" ? "未登录" : "未配置 API Key"}`);
throw new Error(`模型服务「${row.name}」${row.auth_kind === "oauth" ? "未登录" : "未配置 API Key"}`);
return { row, spec: { ...specOf(row), extra: parseExtra(row.extra) }, credentials: dbCredentialStore(ctx, row.id) };
}
+2 -2
View File
@@ -59,7 +59,7 @@ async function readSecret(ctx: Ctx, row: Pick<PiUpstreamRow, "auth_kind" | "secr
try {
return decode(row.auth_kind, await ctx.secrets.resolve(row.secret_ref));
} catch (err) {
ctx.logger.warn({ secretRef: row.secret_ref, err: { message: (err as Error).message } }, "上游凭证读取失败");
ctx.logger.warn({ secretRef: row.secret_ref, err: { message: (err as Error).message } }, "模型服务凭证读取失败");
return undefined;
}
}
@@ -85,7 +85,7 @@ export function dbCredentialStore(ctx: Ctx, upstreamId: string): UpstreamCredent
.where("id", "=", upstreamId)
.forUpdate()
.executeTakeFirst();
if (!row) throw new Error("上游不存在或已删除");
if (!row) throw new Error("模型服务不存在或已删除");
const cur = await readSecret(ctx, row);
const next = await fn(cur);
if (next === undefined) return cur;