惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
B
Blog RSS Feed
Recent Announcements
Recent Announcements
Vercel News
Vercel News
M
MIT News - Artificial intelligence
阮一峰的网络日志
阮一峰的网络日志
L
LangChain Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Security Blog
Microsoft Security Blog
H
Help Net Security
T
The Blog of Author Tim Ferriss
Y
Y Combinator Blog
G
Google Developers Blog
罗磊的独立博客
爱范儿
爱范儿
宝玉的分享
宝玉的分享
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园_首页
S
SegmentFault 最新的问题
WordPress大学
WordPress大学
月光博客
月光博客
人人都是产品经理
人人都是产品经理
Apple Machine Learning Research
Apple Machine Learning Research

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
refactor: centralize model visibility policy · openclaw/o...
steipete · 2026-05-10 · via Recent Commits to openclaw:main

@@ -302,8 +302,8 @@ vi.mock("./model-catalog.js", () => ({

302302

loadManifestModelCatalog: state.loadManifestModelCatalogMock,

303303

}));

304304305-

vi.mock("./model-selection.js", () => ({

306-

buildAllowedModelSet: ({

305+

vi.mock("./model-selection.js", () => {

306+

const buildAllowedModelSet = ({

307307

cfg,

308308

catalog,

309309

defaultProvider,

@@ -369,83 +369,122 @@ vi.mock("./model-selection.js", () => ({

369369

),

370370

allowAny: false,

371371

};

372-

},

373-

buildConfiguredModelCatalog: ({ cfg }: { cfg?: unknown }) => {

374-

const providers = (cfg as { models?: { providers?: Record<string, { models?: unknown[] }> } })

375-

?.models?.providers;

376-

if (!providers) {

377-

return [];

378-

}

379-

return Object.entries(providers).flatMap(([provider, entry]) =>

380-

Array.isArray(entry?.models)

381-

? entry.models

382-

.filter(

383-

(model): model is Record<string, unknown> => !!model && typeof model === "object",

384-

)

385-

.map((model) => {

386-

const id = typeof model.id === "string" ? model.id : "";

387-

return {

388-

provider,

389-

id,

390-

name: typeof model.name === "string" ? model.name : id,

391-

reasoning: typeof model.reasoning === "boolean" ? model.reasoning : undefined,

392-

compat: model.compat,

393-

};

394-

})

395-

.filter((model) => model.id)

396-

: [],

397-

);

398-

},

399-

isModelKeyAllowedBySet: (allowedKeys: ReadonlySet<string>, key: string) => {

400-

if (allowedKeys.has(key)) {

401-

return true;

402-

}

403-

const slash = key.indexOf("/");

404-

return slash > 0 && allowedKeys.has(`${key.slice(0, slash)}/*`);

405-

},

406-

resolveAllowedModelSelection: ({

407-

provider,

408-

model,

409-

allowAny,

410-

allowedKeys,

411-

allowedCatalog,

412-

}: {

413-

provider: string;

414-

model: string;

415-

allowAny: boolean;

416-

allowedKeys: ReadonlySet<string>;

417-

allowedCatalog: Array<{ provider: string; id: string }>;

418-

}) => {

419-

const key = `${provider}/${model}`;

420-

if (

421-

allowAny ||

422-

allowedKeys.has(key) ||

423-

(key.includes("/") && allowedKeys.has(`${key.slice(0, key.indexOf("/"))}/*`))

424-

) {

425-

return { provider, model };

426-

}

427-

const fallback = allowedCatalog[0];

428-

return fallback ? { provider: fallback.provider, model: fallback.id } : null;

429-

},

430-

modelKey: (p: string, m: string) => `${p}/${m}`,

431-

normalizeModelRef: (p: string, m: string) => ({ provider: p, model: m }),

432-

parseModelRef: (m: string, p: string) => ({ provider: p, model: m }),

433-

resolveConfiguredModelRef: ({ cfg }: { cfg?: unknown }) => {

434-

const raw = (cfg as { agents?: { defaults?: { model?: string | { primary?: string } } } })

435-

?.agents?.defaults?.model;

436-

const primary = typeof raw === "string" ? raw : raw?.primary;

437-

const [provider, ...modelParts] = (primary ?? "anthropic/claude").split("/");

438-

return { provider, model: modelParts.join("/") || "claude" };

439-

},

440-

resolveDefaultModelForAgent: ({ cfg }: { cfg?: unknown }) => {

441-

const raw = (cfg as { agents?: { defaults?: { model?: string | { primary?: string } } } })

442-

?.agents?.defaults?.model;

443-

const primary = typeof raw === "string" ? raw : raw?.primary;

444-

const [provider, ...modelParts] = (primary ?? "anthropic/claude").split("/");

445-

return { provider, model: modelParts.join("/") || "claude" };

446-

},

447-

resolveThinkingDefault: (args: unknown) => state.resolveThinkingDefaultMock(args),

448-

}));

372+

};

373+374+

return {

375+

buildAllowedModelSet,

376+

createModelVisibilityPolicy: (params: {

377+

cfg?: unknown;

378+

catalog?: Array<{ provider: string; id: string }>;

379+

defaultProvider: string;

380+

defaultModel?: string;

381+

}) => {

382+

const allowed = buildAllowedModelSet(params);

383+

const allowsKey = (key: string) => {

384+

if (allowed.allowAny || allowed.allowedKeys.has(key)) {

385+

return true;

386+

}

387+

const slash = key.indexOf("/");

388+

return slash > 0 && allowed.allowedKeys.has(`${key.slice(0, slash)}/*`);

389+

};

390+

return {

391+

...allowed,

392+

exactModelRefs: [],

393+

providerWildcards: new Set<string>(),

394+

hasConfiguredEntries: !allowed.allowAny,

395+

hasProviderWildcards: [...allowed.allowedKeys].some((key) => key.endsWith("/*")),

396+

allowsKey,

397+

allows: ({ provider, model }: { provider: string; model: string }) =>

398+

allowsKey(`${provider}/${model}`),

399+

resolveSelection: ({ provider, model }: { provider: string; model: string }) => {

400+

const key = `${provider}/${model}`;

401+

if (allowsKey(key)) {

402+

return { provider, model };

403+

}

404+

const fallback = allowed.allowedCatalog[0];

405+

return fallback ? { provider: fallback.provider, model: fallback.id } : null;

406+

},

407+

visibleCatalog: ({ catalog }: { catalog: Array<{ provider: string; id: string }> }) =>

408+

catalog,

409+

};

410+

},

411+

buildConfiguredModelCatalog: ({ cfg }: { cfg?: unknown }) => {

412+

const providers = (cfg as { models?: { providers?: Record<string, { models?: unknown[] }> } })

413+

?.models?.providers;

414+

if (!providers) {

415+

return [];

416+

}

417+

return Object.entries(providers).flatMap(([provider, entry]) =>

418+

Array.isArray(entry?.models)

419+

? entry.models

420+

.filter(

421+

(model): model is Record<string, unknown> => !!model && typeof model === "object",

422+

)

423+

.map((model) => {

424+

const id = typeof model.id === "string" ? model.id : "";

425+

return {

426+

provider,

427+

id,

428+

name: typeof model.name === "string" ? model.name : id,

429+

reasoning: typeof model.reasoning === "boolean" ? model.reasoning : undefined,

430+

compat: model.compat,

431+

};

432+

})

433+

.filter((model) => model.id)

434+

: [],

435+

);

436+

},

437+

isModelKeyAllowedBySet: (allowedKeys: ReadonlySet<string>, key: string) => {

438+

if (allowedKeys.has(key)) {

439+

return true;

440+

}

441+

const slash = key.indexOf("/");

442+

return slash > 0 && allowedKeys.has(`${key.slice(0, slash)}/*`);

443+

},

444+

resolveAllowedModelSelection: ({

445+

provider,

446+

model,

447+

allowAny,

448+

allowedKeys,

449+

allowedCatalog,

450+

}: {

451+

provider: string;

452+

model: string;

453+

allowAny: boolean;

454+

allowedKeys: ReadonlySet<string>;

455+

allowedCatalog: Array<{ provider: string; id: string }>;

456+

}) => {

457+

const key = `${provider}/${model}`;

458+

if (

459+

allowAny ||

460+

allowedKeys.has(key) ||

461+

(key.includes("/") && allowedKeys.has(`${key.slice(0, key.indexOf("/"))}/*`))

462+

) {

463+

return { provider, model };

464+

}

465+

const fallback = allowedCatalog[0];

466+

return fallback ? { provider: fallback.provider, model: fallback.id } : null;

467+

},

468+

modelKey: (p: string, m: string) => `${p}/${m}`,

469+

normalizeModelRef: (p: string, m: string) => ({ provider: p, model: m }),

470+

parseModelRef: (m: string, p: string) => ({ provider: p, model: m }),

471+

resolveConfiguredModelRef: ({ cfg }: { cfg?: unknown }) => {

472+

const raw = (cfg as { agents?: { defaults?: { model?: string | { primary?: string } } } })

473+

?.agents?.defaults?.model;

474+

const primary = typeof raw === "string" ? raw : raw?.primary;

475+

const [provider, ...modelParts] = (primary ?? "anthropic/claude").split("/");

476+

return { provider, model: modelParts.join("/") || "claude" };

477+

},

478+

resolveDefaultModelForAgent: ({ cfg }: { cfg?: unknown }) => {

479+

const raw = (cfg as { agents?: { defaults?: { model?: string | { primary?: string } } } })

480+

?.agents?.defaults?.model;

481+

const primary = typeof raw === "string" ? raw : raw?.primary;

482+

const [provider, ...modelParts] = (primary ?? "anthropic/claude").split("/");

483+

return { provider, model: modelParts.join("/") || "claude" };

484+

},

485+

resolveThinkingDefault: (args: unknown) => state.resolveThinkingDefaultMock(args),

486+

};

487+

});

449488450489

vi.mock("./provider-auth-aliases.js", () => ({

451490

resolveProviderAuthAliasMap: () => ({}),