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

推荐订阅源

Y
Y Combinator Blog
Google DeepMind News
Google DeepMind News
腾讯CDC
V
Visual Studio Blog
Engineering at Meta
Engineering at Meta
博客园 - 司徒正美
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Tailwind CSS Blog
Vercel News
Vercel News
爱范儿
爱范儿
Last Week in AI
Last Week in AI
G
Google Developers Blog
阮一峰的网络日志
阮一峰的网络日志
P
Proofpoint News Feed
有赞技术团队
有赞技术团队
D
DataBreaches.Net
博客园_首页
J
Java Code Geeks
云风的 BLOG
云风的 BLOG
V
V2EX
A
About on SuperTechFans
H
Hackread – Cybersecurity News, Data Breaches, AI and More
人人都是产品经理
人人都是产品经理

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
feat(channels): add directUserId support for per-DM model...
xydigit-zt · 2026-06-23 · via Recent Commits to openclaw:main

@@ -222,4 +222,248 @@ describe("resolveChannelModelOverride", () => {

222222

expect(resolved?.model).toBe("demo-provider/demo-parent-model");

223223

expect(resolved?.matchKey).toBe("-100123");

224224

});

225+226+

it("matches direct-user-specific model override via directUserId", () => {

227+

const resolved = resolveChannelModelOverride({

228+

cfg: {

229+

channels: {

230+

modelByChannel: {

231+

telegram: {

232+

user123: "demo-provider/demo-direct-user-model",

233+

"*": "demo-provider/demo-wildcard-model",

234+

},

235+

},

236+

},

237+

} as unknown as OpenClawConfig,

238+

channel: "telegram",

239+

groupChatType: "direct",

240+

directUserIds: ["user123"],

241+

});

242+243+

expect(resolved?.model).toBe("demo-provider/demo-direct-user-model");

244+

expect(resolved?.matchKey).toBe("user123");

245+

});

246+247+

it("falls back to wildcard when no directUserId match exists", () => {

248+

const resolved = resolveChannelModelOverride({

249+

cfg: {

250+

channels: {

251+

modelByChannel: {

252+

telegram: {

253+

user999: "demo-provider/demo-other-user-model",

254+

"*": "demo-provider/demo-wildcard-model",

255+

},

256+

},

257+

},

258+

} as unknown as OpenClawConfig,

259+

channel: "telegram",

260+

groupChatType: "direct",

261+

directUserIds: ["user123"],

262+

});

263+264+

expect(resolved?.model).toBe("demo-provider/demo-wildcard-model");

265+

expect(resolved?.matchKey).toBe("*");

266+

expect(resolved?.matchSource).toBe("wildcard");

267+

});

268+269+

it("matches direct-user-specific model override via directUserId from origin.from", () => {

270+

const resolved = resolveChannelModelOverride({

271+

cfg: {

272+

channels: {

273+

modelByChannel: {

274+

slack: {

275+

"user:U12345": "demo-provider/demo-slack-dm-model",

276+

},

277+

},

278+

},

279+

} as unknown as OpenClawConfig,

280+

channel: "slack",

281+

groupChatType: "direct",

282+

directUserIds: ["user:U12345"],

283+

});

284+285+

expect(resolved?.model).toBe("demo-provider/demo-slack-dm-model");

286+

expect(resolved?.matchKey).toBe("user:U12345");

287+

});

288+289+

it("ignores directUserId when a groupId is present (group takes precedence)", () => {

290+

const resolved = resolveChannelModelOverride({

291+

cfg: {

292+

channels: {

293+

modelByChannel: {

294+

telegram: {

295+

"-100123": "demo-provider/demo-group-model",

296+

user456: "demo-provider/demo-direct-user-model",

297+

},

298+

},

299+

},

300+

} as unknown as OpenClawConfig,

301+

channel: "telegram",

302+

groupId: "-100123",

303+

directUserIds: ["user456"],

304+

});

305+306+

expect(resolved?.model).toBe("demo-provider/demo-group-model");

307+

expect(resolved?.matchKey).toBe("-100123");

308+

});

309+310+

it("matches slack DM when origin.from is slack:U... but config has user:U... (multi-candidate)", () => {

311+

const resolved = resolveChannelModelOverride({

312+

cfg: {

313+

channels: {

314+

modelByChannel: {

315+

slack: {

316+

"user:U12345": "demo-provider/demo-slack-dm-model",

317+

},

318+

},

319+

},

320+

} as unknown as OpenClawConfig,

321+

channel: "slack",

322+

groupChatType: "direct",

323+

directUserIds: ["slack:U12345", "user:U12345"],

324+

});

325+326+

expect(resolved?.model).toBe("demo-provider/demo-slack-dm-model");

327+

expect(resolved?.matchKey).toBe("user:U12345");

328+

});

329+330+

it("matches discord DM when multiple candidate forms are present", () => {

331+

const resolved = resolveChannelModelOverride({

332+

cfg: {

333+

channels: {

334+

modelByChannel: {

335+

discord: {

336+

"12345": "demo-provider/demo-discord-dm-model",

337+

},

338+

},

339+

},

340+

} as unknown as OpenClawConfig,

341+

channel: "discord",

342+

groupChatType: "direct",

343+

directUserIds: ["discord:12345", "user:12345", "12345"],

344+

});

345+346+

expect(resolved?.model).toBe("demo-provider/demo-discord-dm-model");

347+

expect(resolved?.matchKey).toBe("12345");

348+

});

349+350+

it("matches telegram DM when raw SenderId is in candidates alongside prefixed forms", () => {

351+

const resolved = resolveChannelModelOverride({

352+

cfg: {

353+

channels: {

354+

modelByChannel: {

355+

telegram: {

356+

"67890": "demo-provider/demo-telegram-dm-model",

357+

},

358+

},

359+

},

360+

} as unknown as OpenClawConfig,

361+

channel: "telegram",

362+

groupChatType: "direct",

363+

directUserIds: ["telegram:67890", "user:67890", "67890"],

364+

});

365+366+

expect(resolved?.model).toBe("demo-provider/demo-telegram-dm-model");

367+

expect(resolved?.matchKey).toBe("67890");

368+

});

369+370+

it("prefers first matching candidate over later candidates", () => {

371+

const resolved = resolveChannelModelOverride({

372+

cfg: {

373+

channels: {

374+

modelByChannel: {

375+

slack: {

376+

"slack:U12345": "demo-provider/demo-prefixed-model",

377+

"user:U12345": "demo-provider/demo-user-model",

378+

},

379+

},

380+

},

381+

} as unknown as OpenClawConfig,

382+

channel: "slack",

383+

groupChatType: "direct",

384+

directUserIds: ["slack:U12345", "user:U12345"],

385+

});

386+387+

expect(resolved?.model).toBe("demo-provider/demo-prefixed-model");

388+

expect(resolved?.matchKey).toBe("slack:U12345");

389+

});

390+391+

it("derives raw peer ID from channel-prefixed origin.from for telegram DM", () => {

392+

const resolved = resolveChannelModelOverride({

393+

cfg: {

394+

channels: {

395+

modelByChannel: {

396+

telegram: {

397+

"12345": "demo-provider/demo-telegram-dm-model",

398+

},

399+

},

400+

},

401+

} as unknown as OpenClawConfig,

402+

channel: "telegram",

403+

groupChatType: "direct",

404+

directUserIds: ["telegram:12345"],

405+

});

406+407+

expect(resolved?.model).toBe("demo-provider/demo-telegram-dm-model");

408+

expect(resolved?.matchKey).toBe("12345");

409+

});

410+411+

it("derives raw peer ID from channel-prefixed origin.from for discord DM", () => {

412+

const resolved = resolveChannelModelOverride({

413+

cfg: {

414+

channels: {

415+

modelByChannel: {

416+

discord: {

417+

"67890": "demo-provider/demo-discord-dm-model",

418+

},

419+

},

420+

},

421+

} as unknown as OpenClawConfig,

422+

channel: "discord",

423+

groupChatType: "direct",

424+

directUserIds: ["discord:67890"],

425+

});

426+427+

expect(resolved?.model).toBe("demo-provider/demo-discord-dm-model");

428+

expect(resolved?.matchKey).toBe("67890");

429+

});

430+431+

it("does not strip prefix for a different channel", () => {

432+

const resolved = resolveChannelModelOverride({

433+

cfg: {

434+

channels: {

435+

modelByChannel: {

436+

telegram: {

437+

"12345": "demo-provider/demo-telegram-dm-model",

438+

},

439+

},

440+

},

441+

} as unknown as OpenClawConfig,

442+

channel: "telegram",

443+

groupChatType: "direct",

444+

directUserIds: ["discord:12345"],

445+

});

446+447+

expect(resolved).toBeNull();

448+

});

449+450+

it("does not leak directUserId match into non-direct conversations", () => {

451+

const resolved = resolveChannelModelOverride({

452+

cfg: {

453+

channels: {

454+

modelByChannel: {

455+

telegram: {

456+

user123: "demo-provider/demo-dm-model",

457+

},

458+

},

459+

},

460+

} as unknown as OpenClawConfig,

461+

channel: "telegram",

462+

groupChatType: "group",

463+

groupId: "some-group",

464+

directUserIds: ["user123"],

465+

});

466+467+

expect(resolved).toBeNull();

468+

});

225469

});