@meistrari/chat-nuxt 3.13.1 → 3.14.0-rc.0
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/dist/module.json +1 -1
- package/dist/runtime/messages/components/chat-debug-workbench.d.vue.ts +3 -0
- package/dist/runtime/messages/components/chat-debug-workbench.vue +428 -0
- package/dist/runtime/messages/components/chat-debug-workbench.vue.d.ts +3 -0
- package/dist/runtime/messages/debug/chat-debug-scenarios.d.ts +38 -0
- package/dist/runtime/messages/debug/chat-debug-scenarios.js +712 -0
- package/dist/runtime/messages/debug/use-chat-debug-diagnostics.d.ts +44 -0
- package/dist/runtime/messages/debug/use-chat-debug-diagnostics.js +157 -0
- package/dist/runtime/messages/debug/use-chat-debug-playback.d.ts +31 -0
- package/dist/runtime/messages/debug/use-chat-debug-playback.js +135 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import ChatMessageList from "./chat-message-list.vue";
|
|
3
|
+
import { provideEmbedConfig } from "../../embed/composables/embed-config";
|
|
4
|
+
import { createChatDebugScenarios } from "../debug/chat-debug-scenarios";
|
|
5
|
+
import { useChatDebugDiagnostics } from "../debug/use-chat-debug-diagnostics";
|
|
6
|
+
import { formatChatDebugTime as formatTime, useChatDebugPlayback } from "../debug/use-chat-debug-playback";
|
|
7
|
+
const scenarios = createChatDebugScenarios();
|
|
8
|
+
const viewportWidth = ref("default");
|
|
9
|
+
const showBounds = ref(false);
|
|
10
|
+
const rootRef = ref(null);
|
|
11
|
+
const stageRef = ref(null);
|
|
12
|
+
provideEmbedConfig({
|
|
13
|
+
workspaceId: "chat-debug-workbench",
|
|
14
|
+
hideSidebar: true
|
|
15
|
+
}, { syncGlobal: false });
|
|
16
|
+
const {
|
|
17
|
+
selectedScenario,
|
|
18
|
+
elapsedMs,
|
|
19
|
+
playing,
|
|
20
|
+
speed,
|
|
21
|
+
seekRevision,
|
|
22
|
+
playbackState,
|
|
23
|
+
appliedEventCount,
|
|
24
|
+
currentEvent,
|
|
25
|
+
progress,
|
|
26
|
+
seek,
|
|
27
|
+
restart,
|
|
28
|
+
selectScenario,
|
|
29
|
+
togglePlayback,
|
|
30
|
+
jumpToEnd,
|
|
31
|
+
stepEvent,
|
|
32
|
+
selectSpeed
|
|
33
|
+
} = useChatDebugPlayback(scenarios, {
|
|
34
|
+
onFrame: handlePlaybackFrame,
|
|
35
|
+
onReset: handlePlaybackReset
|
|
36
|
+
});
|
|
37
|
+
const { diagnostics, reset: resetDiagnostics, recordFrame } = useChatDebugDiagnostics({
|
|
38
|
+
stageRef,
|
|
39
|
+
scenario: selectedScenario,
|
|
40
|
+
playbackState,
|
|
41
|
+
appliedEventCount,
|
|
42
|
+
elapsedMs,
|
|
43
|
+
playing,
|
|
44
|
+
speed,
|
|
45
|
+
seekRevision
|
|
46
|
+
});
|
|
47
|
+
function handlePlaybackFrame(frameDeltaMs) {
|
|
48
|
+
recordFrame(frameDeltaMs);
|
|
49
|
+
}
|
|
50
|
+
function handlePlaybackReset() {
|
|
51
|
+
resetDiagnostics();
|
|
52
|
+
}
|
|
53
|
+
const messageCharacters = computed(() => playbackState.value.messages.reduce(
|
|
54
|
+
(total, message) => total + message.content.length,
|
|
55
|
+
0
|
|
56
|
+
));
|
|
57
|
+
const estimatedTokens = computed(() => Math.ceil(messageCharacters.value / 4));
|
|
58
|
+
const pendingMessages = computed(() => playbackState.value.messages.filter((message) => message.status === "pending").length);
|
|
59
|
+
const speedOptions = [
|
|
60
|
+
{ id: "1x", label: "1\xD7", title: "Real time" },
|
|
61
|
+
{ id: "4x", label: "4\xD7", title: "Four times faster" },
|
|
62
|
+
{ id: "gap", label: "Gaps", title: "Keep event cadence and compress idle gaps" }
|
|
63
|
+
];
|
|
64
|
+
const viewportOptions = [
|
|
65
|
+
{ id: "narrow", label: "Narrow" },
|
|
66
|
+
{ id: "default", label: "Default" },
|
|
67
|
+
{ id: "wide", label: "Wide" }
|
|
68
|
+
];
|
|
69
|
+
function eventToneClass(tone) {
|
|
70
|
+
return {
|
|
71
|
+
neutral: "bg-gray-400",
|
|
72
|
+
user: "bg-blue-500",
|
|
73
|
+
assistant: "bg-violet-500",
|
|
74
|
+
reasoning: "bg-amber-500",
|
|
75
|
+
tool: "bg-emerald-500",
|
|
76
|
+
error: "bg-red-500"
|
|
77
|
+
}[tone];
|
|
78
|
+
}
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<template>
|
|
82
|
+
<section
|
|
83
|
+
ref="rootRef"
|
|
84
|
+
class="chat-debug-workbench"
|
|
85
|
+
w-full
|
|
86
|
+
h-full
|
|
87
|
+
bg
|
|
88
|
+
text-primary
|
|
89
|
+
>
|
|
90
|
+
<aside class="scenario-rail" px-20px py-22px overflow-y-auto>
|
|
91
|
+
<div body-caption-9-medium text-tertiary mb-10px>
|
|
92
|
+
Scenarios
|
|
93
|
+
</div>
|
|
94
|
+
<div flex="~ col" gap-4px>
|
|
95
|
+
<button
|
|
96
|
+
v-for="scenario in scenarios"
|
|
97
|
+
:key="scenario.id"
|
|
98
|
+
type="button"
|
|
99
|
+
:title="scenario.intent"
|
|
100
|
+
py-5px
|
|
101
|
+
text-left
|
|
102
|
+
group
|
|
103
|
+
@click="selectScenario(scenario.id)"
|
|
104
|
+
>
|
|
105
|
+
<div flex items-center gap-7px>
|
|
106
|
+
<span
|
|
107
|
+
w-4px h-4px rounded-full shrink-0
|
|
108
|
+
:class="scenario.id === selectedScenario.id ? 'bg-gray-900' : 'bg-gray-300 group-hover:bg-gray-500'"
|
|
109
|
+
transition-colors
|
|
110
|
+
/>
|
|
111
|
+
<span
|
|
112
|
+
body-12-medium
|
|
113
|
+
truncate
|
|
114
|
+
:class="scenario.id === selectedScenario.id ? 'text-primary' : 'text-secondary group-hover:text-primary'"
|
|
115
|
+
transition-colors
|
|
116
|
+
>
|
|
117
|
+
{{ scenario.name }}
|
|
118
|
+
</span>
|
|
119
|
+
<span ml-auto shrink-0 body-caption-9-medium text-tertiary tabular-nums>
|
|
120
|
+
{{ formatTime(scenario.durationMs) }}
|
|
121
|
+
</span>
|
|
122
|
+
</div>
|
|
123
|
+
</button>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div mt-24px>
|
|
127
|
+
<div body-caption-9-medium text-tertiary mb-10px>
|
|
128
|
+
Shortcuts
|
|
129
|
+
</div>
|
|
130
|
+
<dl class="shortcut-list" body-11-regular text-secondary>
|
|
131
|
+
<dt>Play / pause</dt><dd><TelaKbd>Space</TelaKbd></dd>
|
|
132
|
+
<dt>Previous event</dt><dd><TelaKbd>,</TelaKbd></dd>
|
|
133
|
+
<dt>Next event</dt><dd><TelaKbd>.</TelaKbd></dd>
|
|
134
|
+
<dt>Restart</dt><dd><TelaKbd>R</TelaKbd></dd>
|
|
135
|
+
</dl>
|
|
136
|
+
</div>
|
|
137
|
+
</aside>
|
|
138
|
+
|
|
139
|
+
<main class="stage-column" min-w-0 min-h-0 flex="~ col">
|
|
140
|
+
<div h-48px px-24px flex items-center justify-between shrink-0>
|
|
141
|
+
<div flex items-center gap-8px body-11-regular text-tertiary>
|
|
142
|
+
<span>{{ selectedScenario.name }}</span>
|
|
143
|
+
<TelaDotSeparator />
|
|
144
|
+
<span>{{ playbackState.messages.length }} messages</span>
|
|
145
|
+
</div>
|
|
146
|
+
<div flex items-center gap-12px>
|
|
147
|
+
<div flex items-center gap-10px>
|
|
148
|
+
<button
|
|
149
|
+
v-for="option in viewportOptions"
|
|
150
|
+
:key="option.id"
|
|
151
|
+
type="button"
|
|
152
|
+
body-11-regular
|
|
153
|
+
:class="viewportWidth === option.id ? 'text-primary' : 'text-tertiary hover:text-secondary'"
|
|
154
|
+
transition-colors
|
|
155
|
+
@click="viewportWidth = option.id"
|
|
156
|
+
>
|
|
157
|
+
{{ option.label }}
|
|
158
|
+
</button>
|
|
159
|
+
</div>
|
|
160
|
+
<button
|
|
161
|
+
type="button"
|
|
162
|
+
body-11-regular
|
|
163
|
+
:class="showBounds ? 'text-primary' : 'text-tertiary hover:text-secondary'"
|
|
164
|
+
transition-colors
|
|
165
|
+
@click="showBounds = !showBounds"
|
|
166
|
+
>
|
|
167
|
+
Bounds
|
|
168
|
+
</button>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
<div ref="stageRef" class="stage-viewport" min-h-0 grow flex justify-center px-24px pb-24px>
|
|
173
|
+
<div
|
|
174
|
+
class="chat-under-test"
|
|
175
|
+
:class="[
|
|
176
|
+
`chat-under-test--${viewportWidth}`,
|
|
177
|
+
showBounds && 'chat-under-test--bounded'
|
|
178
|
+
]"
|
|
179
|
+
>
|
|
180
|
+
<TelaChatBody variant="widget" h-full>
|
|
181
|
+
<ChatMessageList
|
|
182
|
+
:messages="playbackState.messages"
|
|
183
|
+
:loading="playbackState.loading"
|
|
184
|
+
:streaming-active-message-id="playbackState.streamingActiveMessageId"
|
|
185
|
+
:preparing-steps="playbackState.preparingSteps"
|
|
186
|
+
variant="widget"
|
|
187
|
+
@retry="stepEvent(-1)"
|
|
188
|
+
/>
|
|
189
|
+
</TelaChatBody>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
</main>
|
|
193
|
+
|
|
194
|
+
<aside class="diagnostics-rail" px-24px py-22px overflow-y-auto>
|
|
195
|
+
<div flex items-start justify-between gap-12px>
|
|
196
|
+
<div>
|
|
197
|
+
<h2 heading-h5-semibold text-wrap-balance>
|
|
198
|
+
Diagnostics
|
|
199
|
+
</h2>
|
|
200
|
+
<p body-11-regular text-tertiary mt-4px>
|
|
201
|
+
Passive probes around the mounted component.
|
|
202
|
+
</p>
|
|
203
|
+
</div>
|
|
204
|
+
<span
|
|
205
|
+
body-10-regular
|
|
206
|
+
:class="speed === '1x' ? 'text-emerald-700' : 'text-amber-700'"
|
|
207
|
+
>
|
|
208
|
+
{{ speed === "1x" ? "representative" : "accelerated" }}
|
|
209
|
+
</span>
|
|
210
|
+
</div>
|
|
211
|
+
|
|
212
|
+
<section mt-28px>
|
|
213
|
+
<div body-10-regular text-tertiary uppercase tracking-0.08em mb-16px>
|
|
214
|
+
Vitals
|
|
215
|
+
</div>
|
|
216
|
+
<dl class="metric-grid">
|
|
217
|
+
<div>
|
|
218
|
+
<dt body-10-regular text-tertiary>
|
|
219
|
+
Event → paint
|
|
220
|
+
</dt>
|
|
221
|
+
<dd heading-h3-semibold tabular-nums>
|
|
222
|
+
{{ diagnostics.paintLatencyMs.toFixed(1) }}<small>ms</small>
|
|
223
|
+
</dd>
|
|
224
|
+
</div>
|
|
225
|
+
<div>
|
|
226
|
+
<dt body-10-regular text-tertiary>
|
|
227
|
+
Dropped frames
|
|
228
|
+
</dt>
|
|
229
|
+
<dd heading-h3-semibold tabular-nums>
|
|
230
|
+
{{ diagnostics.droppedFrames }}
|
|
231
|
+
</dd>
|
|
232
|
+
</div>
|
|
233
|
+
<div>
|
|
234
|
+
<dt body-10-regular text-tertiary>
|
|
235
|
+
DOM nodes
|
|
236
|
+
</dt>
|
|
237
|
+
<dd heading-h3-semibold tabular-nums>
|
|
238
|
+
{{ diagnostics.domNodes }}
|
|
239
|
+
</dd>
|
|
240
|
+
</div>
|
|
241
|
+
<div>
|
|
242
|
+
<dt body-10-regular text-tertiary>
|
|
243
|
+
Layout shift
|
|
244
|
+
</dt>
|
|
245
|
+
<dd heading-h3-semibold tabular-nums>
|
|
246
|
+
{{ diagnostics.cumulativeLayoutShift.toFixed(3) }}
|
|
247
|
+
</dd>
|
|
248
|
+
</div>
|
|
249
|
+
</dl>
|
|
250
|
+
</section>
|
|
251
|
+
|
|
252
|
+
<section mt-28px>
|
|
253
|
+
<div body-10-regular text-tertiary uppercase tracking-0.08em mb-14px>
|
|
254
|
+
Conversation
|
|
255
|
+
</div>
|
|
256
|
+
<dl class="detail-list" body-12-regular>
|
|
257
|
+
<div>
|
|
258
|
+
<dt text-tertiary>
|
|
259
|
+
Messages
|
|
260
|
+
</dt><dd text-primary tabular-nums>
|
|
261
|
+
{{ playbackState.messages.length }}
|
|
262
|
+
</dd>
|
|
263
|
+
</div>
|
|
264
|
+
<div>
|
|
265
|
+
<dt text-tertiary>
|
|
266
|
+
Pending
|
|
267
|
+
</dt><dd text-primary tabular-nums>
|
|
268
|
+
{{ pendingMessages }}
|
|
269
|
+
</dd>
|
|
270
|
+
</div>
|
|
271
|
+
<div>
|
|
272
|
+
<dt text-tertiary>
|
|
273
|
+
Characters
|
|
274
|
+
</dt><dd text-primary tabular-nums>
|
|
275
|
+
{{ messageCharacters }}
|
|
276
|
+
</dd>
|
|
277
|
+
</div>
|
|
278
|
+
<div>
|
|
279
|
+
<dt text-tertiary>
|
|
280
|
+
Est. tokens
|
|
281
|
+
</dt><dd text-primary tabular-nums>
|
|
282
|
+
~{{ estimatedTokens }}
|
|
283
|
+
</dd>
|
|
284
|
+
</div>
|
|
285
|
+
<div>
|
|
286
|
+
<dt text-tertiary>
|
|
287
|
+
Clock drift
|
|
288
|
+
</dt><dd text-primary tabular-nums>
|
|
289
|
+
{{ (diagnostics.clockDriftMs / 1e3).toFixed(1) }} s
|
|
290
|
+
</dd>
|
|
291
|
+
</div>
|
|
292
|
+
</dl>
|
|
293
|
+
</section>
|
|
294
|
+
|
|
295
|
+
<section mt-28px>
|
|
296
|
+
<div body-10-regular text-tertiary uppercase tracking-0.08em mb-14px>
|
|
297
|
+
Scroll & anchoring
|
|
298
|
+
</div>
|
|
299
|
+
<div flex items-center gap-8px body-12-medium>
|
|
300
|
+
<span
|
|
301
|
+
w-6px h-6px rounded-full
|
|
302
|
+
:class="diagnostics.scrollPosition === 'pinned' ? 'bg-emerald-500' : diagnostics.scrollPosition === 'detached' ? 'bg-amber-500' : 'bg-gray-400'"
|
|
303
|
+
/>
|
|
304
|
+
{{ diagnostics.scrollPosition }}
|
|
305
|
+
</div>
|
|
306
|
+
<dl class="detail-list" body-12-regular mt-12px>
|
|
307
|
+
<div>
|
|
308
|
+
<dt text-tertiary>
|
|
309
|
+
Position
|
|
310
|
+
</dt><dd text-primary tabular-nums>
|
|
311
|
+
{{ diagnostics.scrollTop }} px
|
|
312
|
+
</dd>
|
|
313
|
+
</div>
|
|
314
|
+
<div>
|
|
315
|
+
<dt text-tertiary>
|
|
316
|
+
Content height
|
|
317
|
+
</dt><dd text-primary tabular-nums>
|
|
318
|
+
{{ diagnostics.scrollHeight }} px
|
|
319
|
+
</dd>
|
|
320
|
+
</div>
|
|
321
|
+
<div>
|
|
322
|
+
<dt text-tertiary>
|
|
323
|
+
Largest move
|
|
324
|
+
</dt><dd text-primary tabular-nums>
|
|
325
|
+
{{ diagnostics.maxScrollJump.toFixed(0) }} px
|
|
326
|
+
</dd>
|
|
327
|
+
</div>
|
|
328
|
+
</dl>
|
|
329
|
+
</section>
|
|
330
|
+
|
|
331
|
+
<section mt-28px>
|
|
332
|
+
<div flex items-center justify-between gap-12px mb-14px>
|
|
333
|
+
<div body-10-regular text-tertiary uppercase tracking-0.08em>
|
|
334
|
+
Findings
|
|
335
|
+
</div>
|
|
336
|
+
<span body-10-regular text-tertiary>{{ diagnostics.findings.length }}</span>
|
|
337
|
+
</div>
|
|
338
|
+
<p v-if="diagnostics.findings.length === 0" body-11-regular text-tertiary leading-16px>
|
|
339
|
+
No thresholds crossed in this run.
|
|
340
|
+
</p>
|
|
341
|
+
<button
|
|
342
|
+
v-for="finding in diagnostics.findings"
|
|
343
|
+
v-else
|
|
344
|
+
:key="finding.kind"
|
|
345
|
+
type="button"
|
|
346
|
+
w-full
|
|
347
|
+
py-7px
|
|
348
|
+
flex items-start gap-8px
|
|
349
|
+
text-left
|
|
350
|
+
@click="seek(finding.atMs)"
|
|
351
|
+
>
|
|
352
|
+
<span i-ph-warning-circle text-amber-600 mt-1px />
|
|
353
|
+
<span grow body-11-regular text-secondary leading-16px>{{ finding.label }}</span>
|
|
354
|
+
<span body-10-regular text-tertiary tabular-nums>{{ formatTime(finding.atMs) }}</span>
|
|
355
|
+
</button>
|
|
356
|
+
</section>
|
|
357
|
+
</aside>
|
|
358
|
+
|
|
359
|
+
<footer class="transport" px-24px>
|
|
360
|
+
<div flex items-center gap-6px>
|
|
361
|
+
<TelaIconButton
|
|
362
|
+
:icon="playing ? 'i-ph-pause-fill' : 'i-ph-play-fill'"
|
|
363
|
+
size="sm"
|
|
364
|
+
color="primary"
|
|
365
|
+
:aria-label="playing ? 'Pause playback' : 'Play playback'"
|
|
366
|
+
@click="togglePlayback"
|
|
367
|
+
/>
|
|
368
|
+
<TelaIconButton icon="i-ph-arrow-counter-clockwise" size="xs" color="secondary" aria-label="Restart" @click="restart" />
|
|
369
|
+
<TelaIconButton icon="i-ph-caret-left" size="xs" color="secondary" aria-label="Previous event" @click="stepEvent(-1)" />
|
|
370
|
+
<TelaIconButton icon="i-ph-caret-right" size="xs" color="secondary" aria-label="Next event" @click="stepEvent(1)" />
|
|
371
|
+
</div>
|
|
372
|
+
|
|
373
|
+
<div class="timeline" min-w-0>
|
|
374
|
+
<div flex items-center justify-between gap-12px mb-7px body-10-regular text-tertiary tabular-nums>
|
|
375
|
+
<span>{{ formatTime(elapsedMs) }}</span>
|
|
376
|
+
<span v-if="currentEvent" truncate>{{ currentEvent.label }}</span>
|
|
377
|
+
<span>{{ formatTime(selectedScenario.durationMs) }}</span>
|
|
378
|
+
</div>
|
|
379
|
+
<div class="timeline-track">
|
|
380
|
+
<div class="timeline-progress" :style="{ transform: `scaleX(${progress})` }" />
|
|
381
|
+
<button
|
|
382
|
+
v-for="event in selectedScenario.events"
|
|
383
|
+
:key="event.id"
|
|
384
|
+
type="button"
|
|
385
|
+
class="timeline-marker"
|
|
386
|
+
:class="eventToneClass(event.tone)"
|
|
387
|
+
:style="{ left: `${event.atMs / selectedScenario.durationMs * 100}%` }"
|
|
388
|
+
:title="`${formatTime(event.atMs)} \xB7 ${event.label}`"
|
|
389
|
+
@click="seek(event.atMs)"
|
|
390
|
+
/>
|
|
391
|
+
<input
|
|
392
|
+
:value="elapsedMs"
|
|
393
|
+
type="range"
|
|
394
|
+
min="0"
|
|
395
|
+
:max="selectedScenario.durationMs"
|
|
396
|
+
step="1"
|
|
397
|
+
aria-label="Playback timeline"
|
|
398
|
+
@input="seek(Number($event.target.value))"
|
|
399
|
+
>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
|
|
403
|
+
<div flex items-center justify-end gap-14px>
|
|
404
|
+
<div flex items-center gap-10px>
|
|
405
|
+
<button
|
|
406
|
+
v-for="option in speedOptions"
|
|
407
|
+
:key="option.id"
|
|
408
|
+
type="button"
|
|
409
|
+
body-11-medium
|
|
410
|
+
:title="option.title"
|
|
411
|
+
:class="speed === option.id ? 'text-primary' : 'text-tertiary hover:text-secondary'"
|
|
412
|
+
transition-colors
|
|
413
|
+
@click="selectSpeed(option.id)"
|
|
414
|
+
>
|
|
415
|
+
{{ option.label }}
|
|
416
|
+
</button>
|
|
417
|
+
</div>
|
|
418
|
+
<button type="button" body-11-medium text-secondary hover:text-primary transition-colors @click="jumpToEnd">
|
|
419
|
+
End
|
|
420
|
+
</button>
|
|
421
|
+
</div>
|
|
422
|
+
</footer>
|
|
423
|
+
</section>
|
|
424
|
+
</template>
|
|
425
|
+
|
|
426
|
+
<style scoped>
|
|
427
|
+
.chat-debug-workbench{display:grid;grid-template-columns:188px minmax(480px,1fr) 280px;grid-template-rows:minmax(0,1fr) 82px;overflow:hidden}.diagnostics-rail,.scenario-rail,.stage-column{grid-row:1}.scenario-rail{grid-column:1}.stage-column{grid-column:2}.diagnostics-rail{grid-column:3}.transport{align-items:center;display:grid;gap:24px;grid-column:1/-1;grid-row:2;grid-template-columns:190px minmax(280px,1fr) 220px}.detail-list,.shortcut-list{display:flex;flex-direction:column;gap:9px}.detail-list>div,.shortcut-list :deep(div),.shortcut-list>div{display:contents}.shortcut-list{align-items:center;display:grid;grid-template-columns:minmax(0,1fr) auto}.detail-list dd,.shortcut-list dd{margin:0}.detail-list>div{align-items:baseline;display:flex;gap:16px;justify-content:space-between}.stage-viewport{overflow:hidden}.chat-under-test{height:100%;min-height:0;overflow:hidden;width:100%}.chat-under-test--narrow{max-width:520px}.chat-under-test--default{max-width:760px}.chat-under-test--wide{max-width:1040px}.chat-under-test--bounded{outline:1px dashed rgba(156,163,175,.8);outline-offset:-1px}.metric-grid{display:grid;gap:22px 18px;grid-template-columns:1fr 1fr}.metric-grid dd{margin:5px 0 0}.metric-grid small{color:#6b7280;font-size:10px;font-weight:400;margin-left:3px}.timeline-track{height:18px;position:relative}.timeline-progress,.timeline-track:before{content:"";height:2px;left:0;position:absolute;right:0;top:8px}.timeline-track:before{background:#e5e7eb}.timeline-progress{background:#1f2937;transform-origin:left center;z-index:1}.timeline-marker{height:8px;padding:0;position:absolute;top:5px;transform:translateX(-1px);width:2px;z-index:2}.timeline-track input[type=range]{cursor:ew-resize;height:18px;inset:0;margin:0;opacity:0;position:absolute;width:100%;z-index:3}@media (max-width:1180px){.chat-debug-workbench{grid-template-columns:168px minmax(480px,1fr) 260px}.diagnostics-rail,.scenario-rail{padding-left:16px;padding-right:16px}}@media (max-width:900px){.chat-debug-workbench{grid-template-columns:minmax(480px,1fr) 260px}.scenario-rail{display:none}.stage-column{grid-column:1}.diagnostics-rail{grid-column:2}}
|
|
428
|
+
</style>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Message } from '../../types/schemas/chat/conversations.js';
|
|
2
|
+
export type ChatDebugEventTone = 'neutral' | 'user' | 'assistant' | 'reasoning' | 'tool' | 'error';
|
|
3
|
+
type ChatDebugEventBase = {
|
|
4
|
+
id: string;
|
|
5
|
+
atMs: number;
|
|
6
|
+
label: string;
|
|
7
|
+
tone: ChatDebugEventTone;
|
|
8
|
+
};
|
|
9
|
+
export type ChatDebugEvent = ChatDebugEventBase & ({
|
|
10
|
+
type: 'message.upsert';
|
|
11
|
+
message: Message;
|
|
12
|
+
} | {
|
|
13
|
+
type: 'message.patch';
|
|
14
|
+
messageId: string;
|
|
15
|
+
patch: Partial<Message>;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'playback.patch';
|
|
18
|
+
patch: Partial<Omit<ChatDebugPlaybackState, 'messages'>>;
|
|
19
|
+
});
|
|
20
|
+
export type ChatDebugScenario = {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
intent: string;
|
|
24
|
+
durationMs: number;
|
|
25
|
+
events: ChatDebugEvent[];
|
|
26
|
+
};
|
|
27
|
+
export type ChatDebugPlaybackState = {
|
|
28
|
+
messages: Message[];
|
|
29
|
+
loading: boolean;
|
|
30
|
+
streamingActiveMessageId: string | null;
|
|
31
|
+
preparingSteps: string[] | null;
|
|
32
|
+
};
|
|
33
|
+
export declare const EMPTY_CHAT_DEBUG_PLAYBACK_STATE: ChatDebugPlaybackState;
|
|
34
|
+
export declare function applyChatDebugEvent(state: ChatDebugPlaybackState, event: ChatDebugEvent): ChatDebugPlaybackState;
|
|
35
|
+
export declare function resolveChatDebugPlayback(scenario: ChatDebugScenario, elapsedMs: number): ChatDebugPlaybackState;
|
|
36
|
+
export declare function countAppliedChatDebugEvents(scenario: ChatDebugScenario, elapsedMs: number): number;
|
|
37
|
+
export declare function createChatDebugScenarios(baseTime?: number): ChatDebugScenario[];
|
|
38
|
+
export {};
|