dsh-agentic-router 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dsh/index.js +26 -11
  2. package/package.json +2 -2
package/dsh/index.js CHANGED
@@ -38,6 +38,22 @@ const KNN_GRADUATION = 30 // k-NN 毕业经验线
38
38
  const SETTLE_DELAY_MS = 45000 // 反馈结算窗口:回合结束 45s 后查询 messageFeedback
39
39
  const SWEEP_MS = 15000 // 结算轮询周期
40
40
 
41
+ // 同步兜底档位表:从 DEFAULT_PRICES 已知的 provider→model 推导档位,
42
+ // 让插件在 llm.listModels 异步加载完成之前也能立即决策与切换(不 await、不延期)。
43
+ // 加载完成后由 refreshModelTiers 用权威目录覆盖。
44
+ function fallbackTiers() {
45
+ const tiers = { fast: [], mid: [], strong: [] }
46
+ const providers = []
47
+ for (const provider of Object.keys(DEFAULT_PRICES)) {
48
+ if (provider === '*') continue
49
+ const models = Object.keys(DEFAULT_PRICES[provider] || {})
50
+ if (!models.length) continue
51
+ providers.push({ provider, models })
52
+ for (const n of models) tiers[tierOf(n)].push(provider + '/' + n)
53
+ }
54
+ return { providers, tiers }
55
+ }
56
+
41
57
  function freshState() {
42
58
  return {
43
59
  mode: 'shadow',
@@ -45,7 +61,7 @@ function freshState() {
45
61
  decisions: [],
46
62
  forced: null,
47
63
  pending: new Map(),
48
- modelTiers: null,
64
+ modelTiers: fallbackTiers(),
49
65
  turnDecision: {},
50
66
  openTurns: new Map(),
51
67
  pendingFeedback: [],
@@ -287,11 +303,9 @@ export function apply(ctx, config = {}) {
287
303
 
288
304
  // ---- 决策流水线(inbox 与 request 兜底共用) ----
289
305
  // 返回 { key, td, record, target };已决策过本回合则返回 null。
290
- // 档位表异步加载;决策前等待就绪(tiers-not-ready 会拿不到 target)。
291
- async function decideAndRecord(payload, text, current, provider, source) {
292
- if (!state.modelTiers) {
293
- try { await tiersReady } catch (e) { /* keep null */ }
294
- }
306
+ // 必须同步执行:档位表用 fallbackTiers() 兜底(见 freshState),
307
+ // 不 await、不延期——否则追加 header 会落到 prompt 组装之后,被 loop 覆盖。
308
+ function decideAndRecord(payload, text, current, provider, source) {
295
309
  const key = fullKey(payload)
296
310
  if (state.turnDecision[key]) return null
297
311
  const cls = classify(text)
@@ -377,14 +391,14 @@ export function apply(ctx, config = {}) {
377
391
  // ---- 事件挂载 ----
378
392
  // 回合开始(prompt 组装之前):捕获用户消息并决策,active 模式立即应用切换。
379
393
  // 这是主路径——零延迟,回合第一步就按目标模型执行。
380
- ctx.on('agent/inbox/claimed', async (payload) => {
394
+ ctx.on('agent/inbox/claimed', (payload) => {
381
395
  try {
382
396
  const session = sessionOf(payload)
383
397
  const text = extractText(payload && payload.message)
384
398
  if (!text) return
385
399
  const current = session ? currentModel(session) : null
386
400
  const provider = session ? currentProvider(session) : ''
387
- const r = await decideAndRecord(payload, text, current, provider, 'inbox')
401
+ const r = decideAndRecord(payload, text, current, provider, 'inbox')
388
402
  if (!r) return
389
403
  applyDecision(session, r.key, r.td, r.record, r.target)
390
404
  commitRecord(r.record)
@@ -428,7 +442,7 @@ export function apply(ctx, config = {}) {
428
442
  const text = state.pending.get(pkey) || ''
429
443
  state.pending.delete(pkey)
430
444
  const provider = typeof cfg.provider === 'string' ? cfg.provider : ''
431
- const r = await decideAndRecord(payload, text, model, provider, 'request')
445
+ const r = decideAndRecord(payload, text, model, provider, 'request')
432
446
  if (r) {
433
447
  r.td.needsApply = state.mode === 'active' && r.target && r.target !== r.td.currentModel
434
448
  commitRecord(r.record)
@@ -571,10 +585,11 @@ export function apply(ctx, config = {}) {
571
585
  ctx.on('agent/turn-stopping', (payload) => finalize(payload, 'clean-close'))
572
586
  ctx.on('agent/error', (payload) => finalize(payload, 'error'))
573
587
 
574
- // 档位表异步加载;decideAndRecord 在决策前 await 此 promise
588
+ // 权威档位表异步加载,就绪后覆盖同步兜底表(fallbackTiers 保证首回合即可决策)。
589
+ // 仅在刷新成功时覆盖,避免把兜底表清成 null。
575
590
  const tiersReady = refreshModelTiers(llm)
576
591
  tiersReady.then((t) => {
577
- state.modelTiers = t
592
+ if (t) state.modelTiers = t
578
593
  log('model tiers: ' + JSON.stringify(t))
579
594
  }).catch((e) => log('model tiers refresh failed: ' + String(e)))
580
595
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-agentic-router",
3
- "version": "1.4.0",
4
- "description": "DeepSeek Harness plugin: learning agentic router — rule + UCB + LinUCB + k-NN experts under an EXP3 meta-selector, with a durable quality-reward flywheel and REAL model switching via the session request-header precedence chain (v1.4.0)",
3
+ "version": "1.4.1",
4
+ "description": "DeepSeek Harness plugin: learning agentic router — rule + UCB + LinUCB + k-NN experts under an EXP3 meta-selector, with a durable quality-reward flywheel and REAL model switching via the session request-header precedence chain (v1.4.1, cold-start fix)",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": "lhl",