dsh-better-display 0.3.4 → 0.3.6
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/CHANGELOG.md +10 -0
- package/README.en.md +3 -3
- package/README.md +3 -3
- package/lib/client.js +477 -341
- package/lib/client.js.map +1 -1
- package/lib/types/client/ChoreographedFlow.d.ts.map +1 -1
- package/lib/types/client/ChoreographedFlow.js +6 -0
- package/lib/types/client/ChoreographedFlow.js.map +1 -1
- package/lib/types/client/ToolActivity.js +8 -8
- package/lib/types/client/ToolActivity.js.map +1 -1
- package/lib/types/client/tool-activity.d.ts +15 -0
- package/lib/types/client/tool-activity.d.ts.map +1 -1
- package/lib/types/client/tool-activity.js +42 -0
- package/lib/types/client/tool-activity.js.map +1 -1
- package/package.json +4 -3
- package/scripts/build-motion-fixture.mjs +12 -0
- package/scripts/verify-flowcell.mjs +87 -0
- package/src/client/ChoreographedFlow.tsx +5 -0
- package/src/client/ToolActivity.tsx +8 -8
- package/src/client/tool-activity.ts +42 -0
- package/tests/tool-clock.test.ts +45 -0
|
@@ -264,6 +264,48 @@ export function activityPhase(entry: Pick<ToolActivityEntry, 'block' | 'draft'>,
|
|
|
264
264
|
return 'returned';
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
/**
|
|
268
|
+
* First-seen time for calls the host has not stamped yet. A draft that
|
|
269
|
+
* precedes a landed call carries no timestamp, so without this memory the
|
|
270
|
+
* running clock would restart at zero on every remount — e.g. switching to
|
|
271
|
+
* another conversation and back while the call is still preparing. Keyed by
|
|
272
|
+
* call id, dropped when the call leaves the running phases.
|
|
273
|
+
*/
|
|
274
|
+
const clockFirstSeen = new Map<string, number>();
|
|
275
|
+
const CLOCK_FIRST_SEEN_LIMIT = 512;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Session-stamped start of a call, or null while only a draft exists.
|
|
279
|
+
* A settled result carries `callTime`, the paired tool/call event's time; a
|
|
280
|
+
* still-running call head stamps the same instant in its own `time` field.
|
|
281
|
+
*/
|
|
282
|
+
export function callStartTime(entry: Pick<ToolActivityEntry, 'block'>): number | null {
|
|
283
|
+
const block = entry.block;
|
|
284
|
+
if (!block) return null;
|
|
285
|
+
return 'kind' in block ? block.callTime : block.time;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* The instant a still-running call's elapsed clock counts from. The stamped
|
|
290
|
+
* time wins so a remounted view keeps counting from the real start; an
|
|
291
|
+
* un-stamped draft falls back to when this view first saw that call id, which
|
|
292
|
+
* survives remounts for the same reason.
|
|
293
|
+
*/
|
|
294
|
+
export function runningClockBase(callId: string, block: ToolCallBlock | undefined, now = Date.now()): number {
|
|
295
|
+
const stamped = callStartTime({ block });
|
|
296
|
+
if (stamped != null) return stamped;
|
|
297
|
+
const seen = clockFirstSeen.get(callId);
|
|
298
|
+
if (seen !== undefined) return seen;
|
|
299
|
+
if (clockFirstSeen.size >= CLOCK_FIRST_SEEN_LIMIT) clockFirstSeen.delete(clockFirstSeen.keys().next().value!);
|
|
300
|
+
clockFirstSeen.set(callId, now);
|
|
301
|
+
return now;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Forget a call's first-seen time once its clock is no longer live. */
|
|
305
|
+
export function forgetCallClock(callId: string): void {
|
|
306
|
+
clockFirstSeen.delete(callId);
|
|
307
|
+
}
|
|
308
|
+
|
|
267
309
|
export function activitySummary(entry: Pick<ToolActivityEntry, 'block' | 'draft'>) {
|
|
268
310
|
const { name, raw } = toolIdentity(entry);
|
|
269
311
|
const args = inputFields(raw);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { callStartTime, forgetCallClock, runningClockBase } from '../src/client/tool-activity.ts';
|
|
4
|
+
import type { RunningToolCall, ToolResultNode } from '@deepseek-ai/dsh-client-ui-conversation/client';
|
|
5
|
+
|
|
6
|
+
const startedCall = (callId: string, time: number): RunningToolCall => ({
|
|
7
|
+
phase: 'start', callId, name: 'bash', turn: 1, step: 0, time, argsRaw: '{"command":"sleep 60"}', subCalls: [],
|
|
8
|
+
});
|
|
9
|
+
const resultOf = (callId: string, callTime: number | null, time: number): ToolResultNode => ({
|
|
10
|
+
kind: 'tool-result', seq: 1, callId, time, callTime,
|
|
11
|
+
call: { name: 'bash', argsRaw: '{"command":"sleep 60"}' },
|
|
12
|
+
content: [], isError: false, subCalls: [],
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('a dispatched call counts from its stamped start, not the mount time', () => {
|
|
16
|
+
// The view remounts long after the tool/call event: base must stay the
|
|
17
|
+
// session-stamped time, so the clock shows the real elapsed seconds.
|
|
18
|
+
const block = startedCall('c1', 1_000);
|
|
19
|
+
assert.equal(callStartTime({ block }), 1_000);
|
|
20
|
+
assert.equal(runningClockBase('c1', block, 60_000), 1_000);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('a draft-only call keeps the same base across remounts', () => {
|
|
24
|
+
// A draft carries no timestamp; first-seen is remembered per call id so
|
|
25
|
+
// remounting the view does not zero the clock.
|
|
26
|
+
assert.equal(runningClockBase('c2', undefined, 10_000), 10_000);
|
|
27
|
+
assert.equal(runningClockBase('c2', undefined, 30_000), 10_000);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('a landed call head wins over the remembered draft time', () => {
|
|
31
|
+
runningClockBase('c3', undefined, 10_000);
|
|
32
|
+
assert.equal(runningClockBase('c3', startedCall('c3', 8_000), 20_000), 8_000);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('settling forgets the first-seen time so the id can be reused safely', () => {
|
|
36
|
+
runningClockBase('c4', undefined, 10_000);
|
|
37
|
+
forgetCallClock('c4');
|
|
38
|
+
assert.equal(runningClockBase('c4', undefined, 40_000), 40_000);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('a settled result still reports its paired call time', () => {
|
|
42
|
+
assert.equal(callStartTime({ block: resultOf('c5', 1_000, 5_000) }), 1_000);
|
|
43
|
+
// A result whose call fell outside the window stamps nothing.
|
|
44
|
+
assert.equal(callStartTime({ block: resultOf('c6', null, 5_000) }), null);
|
|
45
|
+
});
|