@code-yeongyu/senpi-codemode 2026.8.16 → 2026.8.18
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 +26 -0
- package/package.json +4 -4
- package/src/tool/cell-runtime.ts +2 -0
- package/src/tool/render.ts +43 -6
- package/src/tool/types.ts +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,32 @@
|
|
|
12
12
|
|
|
13
13
|
### Removed
|
|
14
14
|
|
|
15
|
+
## [2026.8.18] - 2026-08-18
|
|
16
|
+
|
|
17
|
+
### Breaking Changes
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
### Removed
|
|
26
|
+
|
|
27
|
+
## [2026.8.17] - 2026-08-17
|
|
28
|
+
|
|
29
|
+
### Breaking Changes
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- Show exact nested tool-call count and calls-per-second in completed eval TUI headers, using true wall-clock elapsed time for both the visible duration and throughput denominator while preserving kernel-reported timing separately ([#916](https://github.com/code-yeongyu/senpi/pull/916)).
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
### Removed
|
|
40
|
+
|
|
15
41
|
## [2026.8.16] - 2026-08-16
|
|
16
42
|
|
|
17
43
|
### Breaking Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/senpi-codemode",
|
|
3
|
-
"version": "2026.8.
|
|
3
|
+
"version": "2026.8.18",
|
|
4
4
|
"description": "Source-only senpi extension package for codemode evaluation tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@babel/parser": "8.0.4",
|
|
33
|
-
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.
|
|
33
|
+
"@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.18",
|
|
34
34
|
"typebox": "1.3.8"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@code-yeongyu/senpi": "2026.8.
|
|
37
|
+
"@code-yeongyu/senpi": "2026.8.18"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@code-yeongyu/senpi": "2026.8.
|
|
40
|
+
"@code-yeongyu/senpi": "2026.8.18"
|
|
41
41
|
},
|
|
42
42
|
"keywords": [
|
|
43
43
|
"senpi",
|
package/src/tool/cell-runtime.ts
CHANGED
|
@@ -127,6 +127,8 @@ export class CellResultBuilder {
|
|
|
127
127
|
languages: [this.#state.input.language],
|
|
128
128
|
...(this.#state.input.summary === undefined ? {} : { summary: this.#state.input.summary }),
|
|
129
129
|
durationMs: this.#state.durationMs,
|
|
130
|
+
wallDurationMs: Math.max(0, Date.now() - this.#state.startedAt),
|
|
131
|
+
toolCallCount: this.#state.toolCallMetrics.length,
|
|
130
132
|
toolCalls: [...this.#state.toolCalls],
|
|
131
133
|
truncated: output?.truncated ?? false,
|
|
132
134
|
...(isError ? { isError: true } : {}),
|
package/src/tool/render.ts
CHANGED
|
@@ -188,12 +188,18 @@ type RenderEnvironment = {
|
|
|
188
188
|
readonly width: number;
|
|
189
189
|
readonly meta: TruncationMeta | undefined;
|
|
190
190
|
};
|
|
191
|
-
type CellBadges = {
|
|
191
|
+
type CellBadges = {
|
|
192
|
+
readonly reset: boolean;
|
|
193
|
+
readonly timeout: number | undefined;
|
|
194
|
+
readonly throughput: CellThroughput | undefined;
|
|
195
|
+
};
|
|
196
|
+
type CellThroughput = { readonly calls: number; readonly wallDurationMs: number | undefined };
|
|
192
197
|
type PrefixStyle = { readonly prefix: string; readonly continuation: string; readonly color: ThemeColor };
|
|
193
198
|
type DetailedRenderContext = {
|
|
194
199
|
readonly environment: RenderEnvironment;
|
|
195
200
|
readonly args: EvalToolRequest;
|
|
196
201
|
readonly showImageFallback: boolean;
|
|
202
|
+
readonly isFinal: boolean;
|
|
197
203
|
};
|
|
198
204
|
|
|
199
205
|
function assertNever(value: never): never {
|
|
@@ -256,7 +262,9 @@ function renderPrefixed(text: string, environment: RenderEnvironment, prefixStyl
|
|
|
256
262
|
function cellHeader(cell: EvalCellResult, environment: RenderEnvironment, badges: CellBadges): string {
|
|
257
263
|
const presentation = cellPresentation(cell.status, environment.spinnerFrame);
|
|
258
264
|
let header = `eval ${cell.language} ${presentation.label} ${presentation.icon}`;
|
|
259
|
-
if (
|
|
265
|
+
if (badges.throughput !== undefined) header += ` · ${formatThroughputBadge(badges.throughput)}`;
|
|
266
|
+
const elapsedMs = badges.throughput?.wallDurationMs ?? cell.durationMs;
|
|
267
|
+
if (elapsedMs !== undefined) header += ` · ${formatDuration(elapsedMs)}`;
|
|
260
268
|
if (badges.reset) header += " · reset";
|
|
261
269
|
if (badges.timeout !== undefined) header += ` · timeout ${badges.timeout}s`;
|
|
262
270
|
return style(environment.theme, presentation.color, header);
|
|
@@ -283,6 +291,19 @@ function plural(count: number, singular: string, pluralNoun: string): string {
|
|
|
283
291
|
return `${count} ${count === 1 ? singular : pluralNoun}`;
|
|
284
292
|
}
|
|
285
293
|
|
|
294
|
+
function formatCallsPerSecond(calls: number, wallDurationMs: number | undefined): string {
|
|
295
|
+
const seconds = typeof wallDurationMs === "number" && Number.isFinite(wallDurationMs) ? wallDurationMs / 1_000 : 0;
|
|
296
|
+
if (seconds <= 0) return calls === 0 ? "0.00 calls/s" : "n/a calls/s";
|
|
297
|
+
return `${(calls / seconds).toFixed(2)} calls/s`;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function formatThroughputBadge(throughput: CellThroughput): string {
|
|
301
|
+
return `${plural(throughput.calls, "call", "calls")} · ${formatCallsPerSecond(
|
|
302
|
+
throughput.calls,
|
|
303
|
+
throughput.wallDurationMs,
|
|
304
|
+
)}`;
|
|
305
|
+
}
|
|
306
|
+
|
|
286
307
|
function statusIcon(op: string): string {
|
|
287
308
|
if (op.startsWith("git_")) return "⌁";
|
|
288
309
|
switch (op) {
|
|
@@ -613,9 +634,17 @@ function renderDetailedLines(
|
|
|
613
634
|
const cells = details.cells ?? [];
|
|
614
635
|
for (const [index, cell] of cells.entries()) {
|
|
615
636
|
const run = isEvalRunInput(context.args) ? context.args : undefined;
|
|
637
|
+
const throughput =
|
|
638
|
+
context.isFinal &&
|
|
639
|
+
cells.length === 1 &&
|
|
640
|
+
cell.status === "complete" &&
|
|
641
|
+
typeof details.toolCallCount === "number"
|
|
642
|
+
? { calls: details.toolCallCount, wallDurationMs: details.wallDurationMs }
|
|
643
|
+
: undefined;
|
|
616
644
|
const badges = {
|
|
617
645
|
reset: index === 0 && run?.reset === true,
|
|
618
646
|
timeout: index === 0 ? run?.timeout : undefined,
|
|
647
|
+
throughput,
|
|
619
648
|
};
|
|
620
649
|
appendLines(lines, renderCell(cell, context.environment, badges));
|
|
621
650
|
if (index < cells.length - 1) lines.push("");
|
|
@@ -754,11 +783,14 @@ function resultMetadata(
|
|
|
754
783
|
details: EvalToolDetails | undefined,
|
|
755
784
|
options: ToolRenderResultOptions,
|
|
756
785
|
theme: Theme | undefined,
|
|
786
|
+
status: "running" | "done" | "error",
|
|
757
787
|
): RenderBlock[] {
|
|
758
788
|
const metadata: string[] = [];
|
|
759
789
|
if (details?.phase) metadata.push(`phase ${details.phase}`);
|
|
760
|
-
|
|
761
|
-
|
|
790
|
+
const elapsedMs = details?.wallDurationMs ?? details?.durationMs;
|
|
791
|
+
if (!options.isPartial && typeof elapsedMs === "number") metadata.push(`took ${formatDuration(elapsedMs)}`);
|
|
792
|
+
if (status === "done" && typeof details?.toolCallCount === "number")
|
|
793
|
+
metadata.push(formatThroughputBadge({ calls: details.toolCallCount, wallDurationMs: details.wallDurationMs }));
|
|
762
794
|
if (metadata.length === 0) return [];
|
|
763
795
|
return [{ kind: "text", text: style(theme, "muted", metadata.join(" | ")) }];
|
|
764
796
|
}
|
|
@@ -814,7 +846,11 @@ export function renderEvalCall(
|
|
|
814
846
|
output: "",
|
|
815
847
|
status: context.spinnerFrame === undefined ? "pending" : "running",
|
|
816
848
|
};
|
|
817
|
-
return renderCell(cell, environment, {
|
|
849
|
+
return renderCell(cell, environment, {
|
|
850
|
+
reset: args.reset === true,
|
|
851
|
+
timeout: args.timeout,
|
|
852
|
+
throughput: undefined,
|
|
853
|
+
});
|
|
818
854
|
},
|
|
819
855
|
},
|
|
820
856
|
]);
|
|
@@ -846,6 +882,7 @@ export function renderEvalResult(
|
|
|
846
882
|
},
|
|
847
883
|
args: context.args,
|
|
848
884
|
showImageFallback: context.showImages && imageProtocol === null,
|
|
885
|
+
isFinal: !options.isPartial,
|
|
849
886
|
}),
|
|
850
887
|
},
|
|
851
888
|
];
|
|
@@ -862,7 +899,7 @@ export function renderEvalResult(
|
|
|
862
899
|
...(details?.summary === undefined
|
|
863
900
|
? []
|
|
864
901
|
: [{ kind: "text" as const, text: style(theme, "muted", details.summary) }]),
|
|
865
|
-
...resultMetadata(details, options, theme),
|
|
902
|
+
...resultMetadata(details, options, theme, status),
|
|
866
903
|
{ kind: "blank" },
|
|
867
904
|
];
|
|
868
905
|
const rawOutput = textOutput(result, context.showImages && imageProtocol === null);
|
package/src/tool/types.ts
CHANGED
|
@@ -164,6 +164,10 @@ export interface EvalToolDetails {
|
|
|
164
164
|
readonly languages?: readonly EvalLanguage[];
|
|
165
165
|
readonly summary?: string;
|
|
166
166
|
readonly durationMs: number;
|
|
167
|
+
/** True wall-clock elapsed time since the cell started; `durationMs` stays kernel-reported. */
|
|
168
|
+
readonly wallDurationMs?: number;
|
|
169
|
+
/** Exact count of initiated nested tool calls, including calls still pending at settlement. */
|
|
170
|
+
readonly toolCallCount?: number;
|
|
167
171
|
readonly toolCalls: readonly EvalToolCallSummary[];
|
|
168
172
|
readonly truncated: boolean;
|
|
169
173
|
readonly isError?: boolean;
|