dsh-xray 0.8.0 → 0.8.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.
- package/lib/client.js +90 -25
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -47,6 +47,7 @@ window.__ModuleLoader__.load({
|
|
|
47
47
|
'.xray-entry-stats{color:var(--dsw-alias-label-tertiary);font-size:12px}',
|
|
48
48
|
'.xray-entry-close{margin-left:auto;font:inherit;font-size:12px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:2px 10px;cursor:pointer}',
|
|
49
49
|
'.xray-entry-text{flex:1;min-height:0;overflow:auto;margin:0;padding:12px;background:var(--dsw-alias-bg-layer-3);border-radius:8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-word}',
|
|
50
|
+
'.xray-owner-entry{display:inline-block;padding-left:22px}',
|
|
50
51
|
'.xray-num{text-align:right}',
|
|
51
52
|
'.xray-warn{color:var(--dsw-alias-state-error-primary,#f85149)}',
|
|
52
53
|
'.xray-ok{color:var(--dsw-alias-state-success-primary,#3fb950)}',
|
|
@@ -72,6 +73,7 @@ window.__ModuleLoader__.load({
|
|
|
72
73
|
|
|
73
74
|
/** English messages (also the key vocabulary; zh mirrors every key). */
|
|
74
75
|
const en = {
|
|
76
|
+
'view.xray': 'X-Ray',
|
|
75
77
|
'panel.sub': 'composition X-ray — live from this harness',
|
|
76
78
|
'panel.loading': 'loading {view}…',
|
|
77
79
|
'panel.renderFailed': 'render failed: {message}',
|
|
@@ -152,12 +154,15 @@ window.__ModuleLoader__.load({
|
|
|
152
154
|
'entry.stats': '{chars} chars · ~{tokens} tokens ({estimator})',
|
|
153
155
|
'entry.close': 'close',
|
|
154
156
|
'tip.clickEntry': 'Click to view the exact text this entry puts into every request',
|
|
157
|
+
'tip.expandPlugin':
|
|
158
|
+
'A plugin has no single text — its cost is the sum of the entries it registered; click to unfold them',
|
|
155
159
|
'tip.contextTokens':
|
|
156
160
|
'Estimated tokens every request carries before your message — see the cost view for the full breakdown',
|
|
157
161
|
};
|
|
158
162
|
|
|
159
163
|
/** Simplified Chinese mirror of every en key. */
|
|
160
164
|
const zh = {
|
|
165
|
+
'view.xray': 'X 光',
|
|
161
166
|
'panel.sub': '组合 X 光——实时来自当前 harness',
|
|
162
167
|
'panel.loading': '正在加载 {view}…',
|
|
163
168
|
'panel.renderFailed': '渲染失败:{message}',
|
|
@@ -229,6 +234,7 @@ window.__ModuleLoader__.load({
|
|
|
229
234
|
'entry.stats': '{chars} 字符 · 约 {tokens} tokens({estimator})',
|
|
230
235
|
'entry.close': '关闭',
|
|
231
236
|
'tip.clickEntry': '点击查看该条目每次请求实际注入的完整文本',
|
|
237
|
+
'tip.expandPlugin': '插件本身没有单一文本——它的成本是其注册的全部条目之和;点击展开这些条目',
|
|
232
238
|
'tip.contextTokens': '每次请求在你的消息之前携带的估算 tokens——完整明细见 cost 视图',
|
|
233
239
|
};
|
|
234
240
|
|
|
@@ -290,6 +296,69 @@ window.__ModuleLoader__.load({
|
|
|
290
296
|
);
|
|
291
297
|
}
|
|
292
298
|
|
|
299
|
+
/** By-plugin rollup with expandable rows: a plugin has no single text —
|
|
300
|
+
* its cost is the SUM of the entries it registered, so clicking a row
|
|
301
|
+
* unfolds those entries (each linking to its raw text). */
|
|
302
|
+
function OwnersTable({ owners, onInspect, t }) {
|
|
303
|
+
const [open, setOpen] = react.useState(() => new Set());
|
|
304
|
+
const toggle = (plugin) =>
|
|
305
|
+
setOpen((current) => {
|
|
306
|
+
const next = new Set(current);
|
|
307
|
+
if (next.has(plugin)) next.delete(plugin);
|
|
308
|
+
else next.add(plugin);
|
|
309
|
+
return next;
|
|
310
|
+
});
|
|
311
|
+
const rows = [];
|
|
312
|
+
for (const o of owners) {
|
|
313
|
+
const expanded = open.has(o.plugin);
|
|
314
|
+
rows.push(
|
|
315
|
+
Row(o.plugin, [
|
|
316
|
+
h(
|
|
317
|
+
'button',
|
|
318
|
+
{
|
|
319
|
+
className: 'xray-entry-link',
|
|
320
|
+
title: t('tip.expandPlugin'),
|
|
321
|
+
onClick: () => toggle(o.plugin),
|
|
322
|
+
},
|
|
323
|
+
`${expanded ? '▾' : '▸'} `,
|
|
324
|
+
o.plugin === 'unattributed'
|
|
325
|
+
? h(
|
|
326
|
+
'span',
|
|
327
|
+
{ className: 'xray-muted', title: t('tip.unattributed') },
|
|
328
|
+
t('cost.unattributed'),
|
|
329
|
+
)
|
|
330
|
+
: o.plugin,
|
|
331
|
+
),
|
|
332
|
+
{ cls: 'xray-num', text: String(o.sections) },
|
|
333
|
+
{ cls: 'xray-num', text: String(o.tools) },
|
|
334
|
+
{ cls: 'xray-num', text: `~${o.tokens}` },
|
|
335
|
+
{ cls: 'xray-num', text: `${o.share}%` },
|
|
336
|
+
h(Bar, { share: o.share }),
|
|
337
|
+
]),
|
|
338
|
+
);
|
|
339
|
+
if (expanded) {
|
|
340
|
+
for (const entry of o.entries) {
|
|
341
|
+
rows.push(
|
|
342
|
+
Row(`${o.plugin}/${entry.kind}/${entry.name}`, [
|
|
343
|
+
h(
|
|
344
|
+
'span',
|
|
345
|
+
{ className: 'xray-owner-entry' },
|
|
346
|
+
h('span', { className: 'xray-muted' }, `${entry.kind} · `),
|
|
347
|
+
h(EntryLink, { kind: entry.kind, name: entry.name, onInspect, t }),
|
|
348
|
+
),
|
|
349
|
+
'',
|
|
350
|
+
'',
|
|
351
|
+
{ cls: 'xray-num', text: `~${entry.tokens}` },
|
|
352
|
+
'',
|
|
353
|
+
'',
|
|
354
|
+
]),
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return h(Table, { t, headers: ['plugin', 'sections', 'tools', 'tokens', 'share', ''], rows });
|
|
360
|
+
}
|
|
361
|
+
|
|
293
362
|
/** Raw-text inspector: fetches one entry's live text on open. Fetched per
|
|
294
363
|
* view, never cached — the text IS the audit artifact. */
|
|
295
364
|
function EntryModal({ target, onClose, t }) {
|
|
@@ -354,7 +423,7 @@ window.__ModuleLoader__.load({
|
|
|
354
423
|
|
|
355
424
|
//#region per-view renderers (mirror lib/panel.js, as components; all copy through t)
|
|
356
425
|
const renderers = {
|
|
357
|
-
summary: (d, t) =>
|
|
426
|
+
summary: (d, t, _onInspect, goToView) =>
|
|
358
427
|
h(
|
|
359
428
|
react.Fragment,
|
|
360
429
|
null,
|
|
@@ -372,7 +441,15 @@ window.__ModuleLoader__.load({
|
|
|
372
441
|
]),
|
|
373
442
|
Row('s', [t('row.services'), { cls: 'xray-num', text: String(d.services) }]),
|
|
374
443
|
Row('t', [
|
|
375
|
-
h(
|
|
444
|
+
h(
|
|
445
|
+
'button',
|
|
446
|
+
{
|
|
447
|
+
className: 'xray-entry-link',
|
|
448
|
+
title: t('tip.contextTokens'),
|
|
449
|
+
onClick: () => goToView('cost'),
|
|
450
|
+
},
|
|
451
|
+
t('row.contextTokens'),
|
|
452
|
+
),
|
|
376
453
|
{ cls: 'xray-num', text: `~${d.toolSchemaTokens}` },
|
|
377
454
|
]),
|
|
378
455
|
],
|
|
@@ -486,26 +563,7 @@ window.__ModuleLoader__.load({
|
|
|
486
563
|
react.Fragment,
|
|
487
564
|
null,
|
|
488
565
|
h('div', { className: 'xray-h3' }, t('h3.byPlugin')),
|
|
489
|
-
h(
|
|
490
|
-
t,
|
|
491
|
-
headers: ['plugin', 'sections', 'tools', 'tokens', 'share', ''],
|
|
492
|
-
rows: d.owners.map((o) =>
|
|
493
|
-
Row(o.plugin, [
|
|
494
|
-
o.plugin === 'unattributed'
|
|
495
|
-
? h(
|
|
496
|
-
'span',
|
|
497
|
-
{ className: 'xray-muted', title: t('tip.unattributed') },
|
|
498
|
-
t('cost.unattributed'),
|
|
499
|
-
)
|
|
500
|
-
: o.plugin,
|
|
501
|
-
{ cls: 'xray-num', text: String(o.sections) },
|
|
502
|
-
{ cls: 'xray-num', text: String(o.tools) },
|
|
503
|
-
{ cls: 'xray-num', text: `~${o.tokens}` },
|
|
504
|
-
{ cls: 'xray-num', text: `${o.share}%` },
|
|
505
|
-
h(Bar, { share: o.share }),
|
|
506
|
-
]),
|
|
507
|
-
),
|
|
508
|
-
}),
|
|
566
|
+
h(OwnersTable, { owners: d.owners, onInspect, t }),
|
|
509
567
|
)
|
|
510
568
|
: null,
|
|
511
569
|
d.sections.length
|
|
@@ -624,7 +682,7 @@ window.__ModuleLoader__.load({
|
|
|
624
682
|
// A diagnostic surface must never take itself down on one bad
|
|
625
683
|
// payload: render the failure, keep the tab and its nav alive.
|
|
626
684
|
try {
|
|
627
|
-
body = renderers[state.for](state.data, t, setInspecting);
|
|
685
|
+
body = renderers[state.for](state.data, t, setInspecting, setView);
|
|
628
686
|
} catch (err) {
|
|
629
687
|
body = h(
|
|
630
688
|
'p',
|
|
@@ -661,12 +719,19 @@ window.__ModuleLoader__.load({
|
|
|
661
719
|
//#endregion
|
|
662
720
|
|
|
663
721
|
const inject = ['slots', 'locale'];
|
|
664
|
-
/** Mount the X-
|
|
722
|
+
/** Mount the X-Ray tab into the conversation view ring (beside Chat / Trajectory). */
|
|
665
723
|
function apply(ctx) {
|
|
666
724
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'xray: dictionaries');
|
|
725
|
+
const t = ctx.locale.bind(NS);
|
|
667
726
|
ctx.slots.inject('conversation.view', () =>
|
|
668
727
|
ctx.slots.register(
|
|
669
|
-
{
|
|
728
|
+
{
|
|
729
|
+
name: 'conversation.view',
|
|
730
|
+
id: 'xray',
|
|
731
|
+
order: 20,
|
|
732
|
+
label: () => t('view.xray'),
|
|
733
|
+
locale: NS,
|
|
734
|
+
},
|
|
670
735
|
XrayPanel,
|
|
671
736
|
),
|
|
672
737
|
);
|