dsh-plugin-litellm-bridge 2.0.3 → 2.0.4

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.
@@ -279,7 +279,7 @@ window.__ModuleLoader__.load({
279
279
  },
280
280
  }),
281
281
  h('span', { style: { fontWeight: 600 } }, 'LiteLLM 网关'),
282
- h('span', { style: S.badge(tone === 'ok' ? T.success : tone === 'error' ? T.error : T.warn) }, label),
282
+ h('span', { style: S.badge(tone === 'ok' ? T.success : tone === 'error' ? T.error : T.warn) }, safeText(label)),
283
283
  st?.owned && h('span', { style: S.badge(T.brand, tint(T.brand, 14)) }, '本插件托管'),
284
284
  !st?.owned && st?.alive && h('span', { style: S.badge() }, '外部运行 · 不接管'),
285
285
  h('span', { style: { marginLeft: 'auto', display: 'flex', gap: 6 } },
@@ -290,11 +290,18 @@ window.__ModuleLoader__.load({
290
290
  ),
291
291
  ),
292
292
  h('div', { style: { padding: '0 12px 10px', ...S.mono, fontSize: 11, color: T.labelSecondary, lineHeight: 1.7 } },
293
- h('div', null, `地址:${st?.url || '—'}`),
294
- h('div', null, `托管策略:${st?.ownership || '—'}${st?.autoStart === false ? '(autoStartGateway 已关闭)' : ''}`),
295
- st?.lastError && h('div', { style: { color: T.error } }, `最近错误:${st.lastError}`),
293
+ // 【必须 safeText】这些值来自宿主 RPC,可能是对象 / undefined / Error。
294
+ // 直接插进子节点会触发 React #62(Objects are not valid as a React child),
295
+ // 整个设置页白屏 —— 实测「点测试连通性后白屏」就是这个原因之一。
296
+ h('div', null, `地址:${safeText(st?.url, '—')}`),
297
+ h('div', null,
298
+ `托管策略:${safeText(st?.ownership, '—')}` +
299
+ (st?.autoStart === false ? '(autoStartGateway 已关闭)' : '')),
300
+ st?.lastError && h('div', { style: { color: T.error } },
301
+ `最近错误:${safeText(st.lastError)}`),
296
302
  !st?.lastError && st?.lastExit?.abnormal &&
297
- h('div', { style: { color: T.error } }, `异常退出记录:code=${st.lastExit.code}`),
303
+ h('div', { style: { color: T.error } },
304
+ `异常退出记录:code=${safeText(st.lastExit.code, '?')}`),
298
305
  ),
299
306
  );
300
307
  }
@@ -338,7 +345,7 @@ window.__ModuleLoader__.load({
338
345
  h('select', {
339
346
  style: { ...S.inputAuto, minWidth: 110 },
340
347
  value: pid, onChange: (e) => setPid(e.target.value),
341
- }, ...(profileIds || []).map((p) => h('option', { key: p, value: p }, p))),
348
+ }, ...(profileIds || []).map((p) => h('option', { key: p, value: p }, safeText(p)))),
342
349
  h('select', {
343
350
  style: { ...S.inputAuto, minWidth: 110 },
344
351
  value: agentType, onChange: (e) => setAgentType(e.target.value),
@@ -373,7 +380,7 @@ window.__ModuleLoader__.load({
373
380
  },
374
381
  h('span', { style: S.badge() }, String(i + 1)),
375
382
  i === 0 && h('span', { style: S.badge(T.brand, tint(T.brand, 14)) }, '首选'),
376
- h('span', { style: { ...S.mono, flex: 1, wordBreak: 'break-all' } }, m),
383
+ h('span', { style: { ...S.mono, flex: 1, wordBreak: 'break-all' } }, safeText(m)),
377
384
  row && h('span', { style: { ...S.mono, fontSize: 11, color: row.ok ? T.success : T.error } },
378
385
  row.ok ? '✓' : '✗'),
379
386
  row && row.latencyMs != null && h('span', {
@@ -386,7 +393,7 @@ window.__ModuleLoader__.load({
386
393
  }),
387
394
  ),
388
395
 
389
- err && h('div', { style: S.notice('error') }, err),
396
+ err && h('div', { style: S.notice('error') }, safeText(err)),
390
397
 
391
398
  result && h('div', null,
392
399
  h('div', { style: { ...S.row, marginBottom: 8 } },
@@ -740,7 +747,7 @@ window.__ModuleLoader__.load({
740
747
 
741
748
  return h('div', { key: at },
742
749
  h('div', { style: S.h2Row },
743
- h('h2', { style: S.h2 }, groupLabel),
750
+ h('h2', { style: S.h2 }, safeText(groupLabel)),
744
751
  isSub && h('span', { style: S.badge() }, '仅子 Agent 使用'),
745
752
  h('span', { style: { ...S.mono, fontSize: 11, color: T.labelSecondary } },
746
753
  chainLen ? `链长 ${chainLen}` : '未配置'),
@@ -931,11 +938,11 @@ window.__ModuleLoader__.load({
931
938
  h('div', { style: { ...S.row, marginBottom: 10 } },
932
939
  h('select', { style: { ...S.input, width: 'auto' }, value: fAgent, onChange: (e) => setFAgent(e.target.value) },
933
940
  h('option', { value: '' }, '全部 agent-type'),
934
- agents.map((a) => h('option', { key: a, value: a }, a)),
941
+ agents.map((a) => h('option', { key: a, value: a }, safeText(a))),
935
942
  ),
936
943
  h('select', { style: { ...S.input, width: 'auto' }, value: fProfile, onChange: (e) => setFProfile(e.target.value) },
937
944
  h('option', { value: '' }, '全部 profile'),
938
- profiles.map((p) => h('option', { key: p, value: p }, p)),
945
+ profiles.map((p) => h('option', { key: p, value: p }, safeText(p))),
939
946
  ),
940
947
  h('span', { style: { marginLeft: 'auto', ...S.mono, fontSize: 11, color: T.labelSecondary } },
941
948
  `显示 ${shown.length} / 最多 ${limit} 条`),
@@ -964,9 +971,9 @@ window.__ModuleLoader__.load({
964
971
  l.time ? String(l.time).replace('T', ' ').slice(0, 19) : '—'),
965
972
  isGwEvent
966
973
  ? h('span', { style: S.badge(T.brand, tint(T.brand, 14)) }, 'gateway')
967
- : h('span', { style: S.badge() }, l.agentType),
968
- !isGwEvent && h('span', { style: S.badge() }, l.profile),
969
- h('span', { style: { ...S.mono, fontWeight: 600 } }, l.model),
974
+ : h('span', { style: S.badge() }, safeText(l.agentType, '-')),
975
+ !isGwEvent && h('span', { style: S.badge() }, safeText(l.profile, '-')),
976
+ h('span', { style: { ...S.mono, fontWeight: 600 } }, safeText(l.model)),
970
977
  l.source === 'local' && !isGwEvent && h('span', { style: S.badge(T.brand, tint(T.brand, 14)) }, 'local'),
971
978
  k === 'fallback' && h('span', { style: S.badge(T.warn, tint(T.warn, 14)) }, 'FALLBACK'),
972
979
  k === 'failed' && h('span', { style: S.badge(T.error, tint(T.error, 14)) }, '失败'),
@@ -1054,7 +1061,7 @@ window.__ModuleLoader__.load({
1054
1061
  style: S.input, value: profile, onChange: (e) => setProfile(e.target.value),
1055
1062
  },
1056
1063
  h('option', { value: '' }, '(不绑定)'),
1057
- profileIds.map((p) => h('option', { key: p, value: p }, p)),
1064
+ profileIds.map((p) => h('option', { key: p, value: p }, safeText(p))),
1058
1065
  ),
1059
1066
  h('div', { style: S.hint },
1060
1067
  '绑定后:本会话的 root 请求按该 profile 的 root 链走;spawn 的子 Agent 按同 profile 的 coder/research 链走。'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-litellm-bridge",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "LiteLLM gateway bridge for DSH: assemble root / coder / research fallback chains from the DSH model pool and hand the order to a LiteLLM gateway that executes retries and fallbacks. The plugin performs no routing itself.",
5
5
  "keywords": [
6
6
  "dsh",