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

推荐订阅源

L
LangChain Blog
Recent Announcements
Recent Announcements
GbyAI
GbyAI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Microsoft Azure Blog
Microsoft Azure Blog
N
Netflix TechBlog - Medium
人人都是产品经理
人人都是产品经理
MongoDB | Blog
MongoDB | Blog
D
DataBreaches.Net
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
WordPress大学
WordPress大学
U
Unit 42
腾讯CDC
D
Docker
The GitHub Blog
The GitHub Blog
阮一峰的网络日志
阮一峰的网络日志
Vercel News
Vercel News
I
InfoQ
Jina AI
Jina AI
爱范儿
爱范儿
宝玉的分享
宝玉的分享
博客园 - Franky
G
Google Developers Blog
P
Proofpoint News Feed

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
fix(agents): cancel model scan error bodies · openclaw/op...
vincentkoc · 2026-06-19 · via Recent Commits to openclaw:main

@@ -188,73 +188,81 @@ async function fetchOpenRouterModels(

188188

fetchImpl: typeof fetch,

189189

timeoutMs: number,

190190

): Promise<OpenRouterModelMeta[]> {

191-

const res = await withTimeout(timeoutMs, (signal) =>

192-

fetchImpl(OPENROUTER_MODELS_URL, {

193-

headers: { Accept: "application/json" },

194-

signal,

195-

}),

196-

);

197-

if (!res.ok) {

198-

throw new Error(`OpenRouter /models failed: HTTP ${res.status}`);

199-

}

200-

const payload = (await res.json()) as { data?: unknown };

201-

const entries = Array.isArray(payload.data) ? payload.data : [];

202-203-

return entries

204-

.map((entry) => {

205-

if (!entry || typeof entry !== "object") {

206-

return null;

207-

}

208-

const obj = entry as Record<string, unknown>;

209-

const id = normalizeOptionalString(obj.id) ?? "";

210-

if (!id) {

211-

return null;

212-

}

213-

const name = typeof obj.name === "string" && obj.name.trim() ? obj.name.trim() : id;

214-215-

const contextLength =

216-

typeof obj.context_length === "number" && Number.isFinite(obj.context_length)

217-

? obj.context_length

218-

: null;

219-220-

const maxCompletionTokens =

221-

typeof obj.max_completion_tokens === "number" && Number.isFinite(obj.max_completion_tokens)

222-

? obj.max_completion_tokens

223-

: typeof obj.max_output_tokens === "number" && Number.isFinite(obj.max_output_tokens)

224-

? obj.max_output_tokens

191+

let res: Response | undefined;

192+

try {

193+

res = await withTimeout(timeoutMs, (signal) =>

194+

fetchImpl(OPENROUTER_MODELS_URL, {

195+

headers: { Accept: "application/json" },

196+

signal,

197+

}),

198+

);

199+

if (!res.ok) {

200+

throw new Error(`OpenRouter /models failed: HTTP ${res.status}`);

201+

}

202+

const payload = (await res.json()) as { data?: unknown };

203+

const entries = Array.isArray(payload.data) ? payload.data : [];

204+205+

return entries

206+

.map((entry) => {

207+

if (!entry || typeof entry !== "object") {

208+

return null;

209+

}

210+

const obj = entry as Record<string, unknown>;

211+

const id = normalizeOptionalString(obj.id) ?? "";

212+

if (!id) {

213+

return null;

214+

}

215+

const name = typeof obj.name === "string" && obj.name.trim() ? obj.name.trim() : id;

216+217+

const contextLength =

218+

typeof obj.context_length === "number" && Number.isFinite(obj.context_length)

219+

? obj.context_length

225220

: null;

226221227-

const supportedParameters = Array.isArray(obj.supported_parameters)

228-

? normalizeStringEntries(

229-

obj.supported_parameters.filter((value) => typeof value === "string"),

230-

)

231-

: [];

232-233-

const supportedParametersCount = supportedParameters.length;

234-

const supportsToolsMeta = supportedParameters.includes("tools");

235-236-

const modality =

237-

typeof obj.modality === "string" && obj.modality.trim() ? obj.modality.trim() : null;

238-239-

const inferredParamB = inferParamBFromIdOrName(`${id} ${name}`);

240-

const createdAtMs = normalizeCreatedAtMs(obj.created_at);

241-

const pricing = parseOpenRouterPricing(obj.pricing);

242-243-

return {

244-

id,

245-

name,

246-

contextLength,

247-

maxCompletionTokens,

248-

supportedParameters,

249-

supportedParametersCount,

250-

supportsToolsMeta,

251-

modality,

252-

inferredParamB,

253-

createdAtMs,

254-

pricing,

255-

} satisfies OpenRouterModelMeta;

256-

})

257-

.filter((entry): entry is OpenRouterModelMeta => Boolean(entry));

222+

const maxCompletionTokens =

223+

typeof obj.max_completion_tokens === "number" &&

224+

Number.isFinite(obj.max_completion_tokens)

225+

? obj.max_completion_tokens

226+

: typeof obj.max_output_tokens === "number" && Number.isFinite(obj.max_output_tokens)

227+

? obj.max_output_tokens

228+

: null;

229+230+

const supportedParameters = Array.isArray(obj.supported_parameters)

231+

? normalizeStringEntries(

232+

obj.supported_parameters.filter((value) => typeof value === "string"),

233+

)

234+

: [];

235+236+

const supportedParametersCount = supportedParameters.length;

237+

const supportsToolsMeta = supportedParameters.includes("tools");

238+239+

const modality =

240+

typeof obj.modality === "string" && obj.modality.trim() ? obj.modality.trim() : null;

241+242+

const inferredParamB = inferParamBFromIdOrName(`${id} ${name}`);

243+

const createdAtMs = normalizeCreatedAtMs(obj.created_at);

244+

const pricing = parseOpenRouterPricing(obj.pricing);

245+246+

return {

247+

id,

248+

name,

249+

contextLength,

250+

maxCompletionTokens,

251+

supportedParameters,

252+

supportedParametersCount,

253+

supportsToolsMeta,

254+

modality,

255+

inferredParamB,

256+

createdAtMs,

257+

pricing,

258+

} satisfies OpenRouterModelMeta;

259+

})

260+

.filter((entry): entry is OpenRouterModelMeta => Boolean(entry));

261+

} finally {

262+

if (res && !res.bodyUsed) {

263+

await res.body?.cancel().catch(() => undefined);

264+

}

265+

}

258266

}

259267260268

async function probeTool(