@code-yeongyu/senpi-codemode 2026.8.3-3 → 2026.8.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.
package/CHANGELOG.md CHANGED
@@ -12,6 +12,22 @@
12
12
 
13
13
  ### Removed
14
14
 
15
+ ## [2026.8.4] - 2026-08-04
16
+
17
+ ### Breaking Changes
18
+
19
+ - Replaced the eval tool's optional presentation `title` with a required user-language `summary`: every eval call must now describe the cell's purpose in the user's language, callers using `title` must migrate to `summary`, and the generated tool schema, prompt contract, README examples, bridge fixtures, and test corpus all enforce the new argument ([#695](https://github.com/code-yeongyu/senpi/pull/695)).
20
+
21
+ ### Added
22
+
23
+ - Rendered each eval summary inside its transcript cell frame and used the same summary to label detached cells and their completion notices, so concurrent or long-running JavaScript and Python work remains identifiable after detachment and when results arrive asynchronously ([#695](https://github.com/code-yeongyu/senpi/pull/695)).
24
+
25
+ ### Changed
26
+
27
+ ### Fixed
28
+
29
+ ### Removed
30
+
15
31
  ## [2026.8.3-3] - 2026-08-03
16
32
 
17
33
  ### Breaking Changes
package/README.md CHANGED
@@ -14,7 +14,7 @@ task-tool names are known.
14
14
  handle and continue in their existing kernel. Completion is injected with the
15
15
  final value/error and buffered output; use `eval({ action: "peek"|"stop",
16
16
  cell_id })` to inspect or terminate a detached cell. A running peek preserves
17
- the original code and title together with current output, phase, status
17
+ the original code and summary together with current output, phase, status
18
18
  events, tool-call summaries, elapsed duration, and structured display state;
19
19
  a terminal peek preserves the exact final result.
20
20
  - Loopback, bearer-authenticated kernel bridge with bounded JSONL frames.
@@ -127,6 +127,16 @@ updates, and transcripts remain owned by that engine.
127
127
  `isolated`, `apply`, and `merge` are accepted for compatibility but emit a
128
128
  warning because this task-engine integration has no isolation model.
129
129
 
130
+ ## Required summary
131
+
132
+ Every `eval` run call MUST include a `summary` — one line in the user's
133
+ conversational language stating what the cell does and for what purpose (e.g.
134
+ a Korean conversation produces a Korean summary such as "src 전체에서
135
+ legacyClient 사용처 집계"). The summary is shown in the TUI while the cell
136
+ runs and in the finished result, so you can always tell what is running and
137
+ why. Values longer than 80 characters are force-truncated. A run request
138
+ without a `summary` fails with a teaching error.
139
+
130
140
  ## Detached cells
131
141
 
132
142
  `eval` accepts `on_timeout: "detach"|"error"`. The default is `"detach"` in
@@ -137,8 +147,8 @@ a busy error with its cell id and output tail; calls in other languages continue
137
147
  normally. Do not re-run the cell.
138
148
 
139
149
  While any cell is detached, the interactive footer shows a highlighted
140
- `↗ <language> · <title>` status on the extension status line (the cell id when
141
- the call had no title), clearing as soon as the last detached cell settles.
150
+ `↗ <language> · <summary>` status on the extension status line (the cell id
151
+ when the call had no summary), clearing as soon as the last detached cell settles.
142
152
 
143
153
  Use `eval({ action: "peek", cell_id })` for its state and buffered output, or
144
154
  `eval({ action: "stop", cell_id })` to cancel it. Python stop interrupts the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-codemode",
3
- "version": "2026.8.3-3",
3
+ "version": "2026.8.4",
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.3-3",
33
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.8.4",
34
34
  "typebox": "1.3.8"
35
35
  },
36
36
  "peerDependencies": {
37
- "@code-yeongyu/senpi": "2026.8.3-3"
37
+ "@code-yeongyu/senpi": "2026.8.4"
38
38
  },
39
39
  "devDependencies": {
40
- "@code-yeongyu/senpi": "2026.8.3-3"
40
+ "@code-yeongyu/senpi": "2026.8.4"
41
41
  },
42
42
  "keywords": [
43
43
  "senpi",
@@ -28,7 +28,7 @@ function packLabels(labels: readonly string[], budget: number): string {
28
28
  }
29
29
 
30
30
  function labelOf(entry: EvalDetachedCellStatusEntry): string {
31
- return entry.title === undefined || entry.title.length === 0 ? entry.cellId : entry.title;
31
+ return entry.summary === undefined || entry.summary.length === 0 ? entry.cellId : entry.summary;
32
32
  }
33
33
 
34
34
  /**
@@ -59,7 +59,7 @@ type Context = Readonly<Record<string, ContextValue>>;
59
59
  type EvalPromptExample = {
60
60
  readonly caption: string;
61
61
  readonly language: keyof EnabledLanguages;
62
- readonly title: string;
62
+ readonly summary: string;
63
63
  readonly code: string;
64
64
  };
65
65
 
@@ -71,19 +71,19 @@ const REUSE_CHAIN_EXAMPLES = [
71
71
  {
72
72
  caption: "First call — set up once",
73
73
  language: "py",
74
- title: "collect targets",
74
+ summary: "Count all TypeScript source files under src/ excluding tests",
75
75
  code: "from pathlib import Path\nfrom collections import Counter\nfiles = [p for p in Path('src').rglob('*.ts') if 'test' not in p.parts]\nprint(len(files))",
76
76
  },
77
77
  {
78
78
  caption: "Second call — reuse `files`, batch-read in one cell",
79
79
  language: "py",
80
- title: "scan usages",
80
+ summary: "Find which files reference legacyClient so we know what to migrate",
81
81
  code: "hits = Counter()\nfor p in files:\n hits[p.name] = read(p).count('legacyClient')\ndisplay({k: v for k, v in hits.items() if v})",
82
82
  },
83
83
  {
84
84
  caption: "Third call — reuse results, fan out session tools in parallel",
85
85
  language: "py",
86
- title: "confirm callsites",
86
+ summary: "Confirm exact callsite lines in each directory to plan the refactor",
87
87
  code: "dirs = ['src/core', 'src/tools']\ndisplay(parallel([lambda d=d: tool.grep({'pattern': 'legacyClient', 'path': d}) for d in dirs]))",
88
88
  },
89
89
  ] as const satisfies readonly EvalPromptExample[];
@@ -122,7 +122,7 @@ Fields:
122
122
 
123
123
  - \`language\` — {{#if py}}\`"py"\` IPython kernel{{/if}}{{#ifAll py js}}, {{/ifAll}}{{#if js}}\`"js"\` persistent JavaScript VM{{/if}}{{#if rb}}{{#ifAny py js}}, {{/ifAny}}\`"rb"\` persistent Ruby kernel{{/if}}{{#if jl}}{{#ifAny py js rb}}, {{/ifAny}}\`"jl"\` persistent Julia kernel{{/if}}.
124
124
  - \`code\` — cell body, verbatim. Newlines/quotes JSON-encoded; no fences, no headers.
125
- - \`title\` (optional) — short transcript label (e.g. \`"imports"\`).
125
+ - \`summary\` (REQUIRED for run) — ONE line in the USER'S conversational language stating WHAT this cell does and FOR WHAT PURPOSE (e.g. Korean conversation -> "src 전체에서 legacyClient 사용처 집계"); shown in the TUI while the cell runs; >80 chars is force-truncated.
126
126
  - \`timeout\` (optional) — seconds. Raise only for heavy compute or long{{#if spawns}} non-agent{{/if}} tool calls.
127
127
  - \`on_timeout\` (optional) — \`"detach"\` keeps pure computation running in interactive sessions (the default); \`"error"\` interrupts for deadline-sensitive work and is the print/json default.
128
128
  - \`reset\` (optional) — wipe this language's kernel first.{{#ifAll py js}} Per-language: a \`py\` reset never touches the JS VM.{{/ifAll}}
@@ -214,7 +214,7 @@ export function buildEvalPrompt(
214
214
  };
215
215
  const examples = REUSE_CHAIN_EXAMPLES.filter((example) => enabled[example.language])
216
216
  .map((example) => {
217
- const call = { language: example.language, title: example.title, code: example.code };
217
+ const call = { language: example.language, summary: example.summary, code: example.code };
218
218
  return `### ${example.caption}\n\`\`\`json\n${JSON.stringify(call, null, 2)}\n\`\`\``;
219
219
  })
220
220
  .join("\n\n");
@@ -119,7 +119,7 @@ export class CellResultBuilder {
119
119
  return {
120
120
  language: this.#state.input.language,
121
121
  languages: [this.#state.input.language],
122
- ...(this.#state.input.title === undefined ? {} : { title: this.#state.input.title }),
122
+ ...(this.#state.input.summary === undefined ? {} : { summary: this.#state.input.summary }),
123
123
  durationMs: this.#state.durationMs,
124
124
  toolCalls: [...this.#state.toolCalls],
125
125
  truncated: output?.truncated ?? false,
@@ -128,7 +128,7 @@ export class CellResultBuilder {
128
128
  cells: [
129
129
  {
130
130
  index: 0,
131
- ...(this.#state.input.title === undefined ? {} : { title: this.#state.input.title }),
131
+ ...(this.#state.input.summary === undefined ? {} : { summary: this.#state.input.summary }),
132
132
  code: this.#state.input.code,
133
133
  language: this.#state.input.language,
134
134
  output: this.#state.output,
@@ -146,12 +146,12 @@ export class CellResultBuilder {
146
146
  }
147
147
 
148
148
  #liveUpdateText(): string {
149
- const title = this.#state.input.title === undefined ? "" : ` ${this.#state.input.title}`;
149
+ const summary = this.#state.input.summary === undefined ? "" : ` ${this.#state.input.summary}`;
150
150
  const aggregateOutput = this.#output.aggregateText();
151
151
  const outputLines = aggregateOutput.split("\n");
152
152
  const hasTrailingNewline = aggregateOutput.endsWith("\n");
153
153
  if (hasTrailingNewline) outputLines.pop();
154
154
  const output = `${outputLines.slice(-8).join("\n")}${hasTrailingNewline ? "\n" : ""}`;
155
- return `1/1 cells ${this.#state.status}\n[1] ${this.#state.input.language}${title} ${this.#state.status}${output.length === 0 ? "" : `\n${output}`}`;
155
+ return `1/1 cells ${this.#state.status}\n[1] ${this.#state.input.language}${summary} ${this.#state.status}${output.length === 0 ? "" : `\n${output}`}`;
156
156
  }
157
157
  }
@@ -50,7 +50,7 @@ export interface EvalDetachedCellNotifier {
50
50
  export interface EvalDetachedCellStatusEntry {
51
51
  readonly cellId: string;
52
52
  readonly language: EvalLanguage;
53
- readonly title?: string;
53
+ readonly summary?: string;
54
54
  readonly startedAtMs: number;
55
55
  }
56
56
 
@@ -193,7 +193,7 @@ export class EvalDetachedCellManager {
193
193
  cellId: cell.cellId,
194
194
  language: cell.input.language,
195
195
  startedAtMs: cell.startedAtMs,
196
- ...(cell.input.title === undefined ? {} : { title: cell.input.title }),
196
+ ...(cell.input.summary === undefined ? {} : { summary: cell.input.summary }),
197
197
  })),
198
198
  );
199
199
  }
@@ -52,14 +52,14 @@ function fallbackResult(input: EvalToolInput): AgentToolResult<EvalToolDetails>
52
52
  details: {
53
53
  language: input.language,
54
54
  languages: [input.language],
55
- ...(input.title === undefined ? {} : { title: input.title }),
55
+ ...(input.summary === undefined ? {} : { summary: input.summary }),
56
56
  durationMs: 0,
57
57
  toolCalls: [],
58
58
  truncated: false,
59
59
  cells: [
60
60
  {
61
61
  index: 0,
62
- ...(input.title === undefined ? {} : { title: input.title }),
62
+ ...(input.summary === undefined ? {} : { summary: input.summary }),
63
63
  code: input.code,
64
64
  language: input.language,
65
65
  output: "",
@@ -1,8 +1,21 @@
1
1
  import type { ExtensionContext } from "@code-yeongyu/senpi";
2
- import type { EvalControlInput, EvalToolInput, EvalToolRequest } from "./types.ts";
2
+ import { EVAL_SUMMARY_MAX_LENGTH, type EvalControlInput, type EvalToolInput, type EvalToolRequest } from "./types.ts";
3
3
 
4
4
  const NON_INTERACTIVE_MODES = new Set(["print", "json"]);
5
5
 
6
+ const ELLIPSIS = "...";
7
+
8
+ // Harness-side enforcement of the schema maxLength: the tool advertises the limit, but an
9
+ // over-limit value is force-truncated here (prepareArguments runs before schema validation)
10
+ // instead of failing the call.
11
+ export function clampEvalSummary(value: unknown): string | undefined {
12
+ if (typeof value !== "string") return undefined;
13
+ const normalized = value.trim().replace(/\s+/gu, " ");
14
+ if (normalized.length === 0) return undefined;
15
+ if (normalized.length <= EVAL_SUMMARY_MAX_LENGTH) return normalized;
16
+ return `${normalized.slice(0, EVAL_SUMMARY_MAX_LENGTH - ELLIPSIS.length)}${ELLIPSIS}`;
17
+ }
18
+
6
19
  export function parseEvalRequest(params: unknown): EvalToolRequest {
7
20
  if (!isRecord(params)) throw new TypeError("eval parameters must be an object");
8
21
  if (params.action === "peek" || params.action === "stop") {
@@ -14,13 +27,18 @@ export function parseEvalRequest(params: unknown): EvalToolRequest {
14
27
  throw new TypeError(`Unknown eval action "${String(params.action)}"`);
15
28
  if (!isEvalLanguage(params.language)) throw new TypeError("eval run requires language");
16
29
  if (typeof params.code !== "string") throw new TypeError("eval run requires code");
30
+ const summary = clampEvalSummary(params.summary);
31
+ if (summary === undefined)
32
+ throw new TypeError(
33
+ "eval run requires summary — one line in the user's language: what this cell does and for what purpose",
34
+ );
17
35
  if (params.on_timeout !== undefined && params.on_timeout !== "detach" && params.on_timeout !== "error")
18
36
  throw new TypeError(`Unknown eval on_timeout value "${String(params.on_timeout)}"`);
19
37
  return {
20
38
  language: params.language,
21
39
  code: params.code,
40
+ summary,
22
41
  ...(params.action === "run" ? { action: "run" as const } : {}),
23
- ...(typeof params.title === "string" ? { title: params.title } : {}),
24
42
  ...(typeof params.timeout === "number" ? { timeout: params.timeout } : {}),
25
43
  ...(params.on_timeout === "detach" || params.on_timeout === "error" ? { on_timeout: params.on_timeout } : {}),
26
44
  ...(typeof params.reset === "boolean" ? { reset: params.reset } : {}),
@@ -8,10 +8,16 @@ import { abortError, CellExecution, defaultTimeoutFactory } from "./cell-executi
8
8
  import { CellHandler, type CellState } from "./cell-handler.ts";
9
9
  import { EvalDetachedCellManager } from "./detached-cell-manager.ts";
10
10
  import { detachedKernelBusyError, executeEvalControl, resultAfterDetach } from "./detached-eval-result.ts";
11
- import { evalTimeoutBehavior, isEvalControlRequest, parseEvalRequest } from "./eval-request.ts";
11
+ import { clampEvalSummary, evalTimeoutBehavior, isEvalControlRequest, parseEvalRequest } from "./eval-request.ts";
12
12
  import type { CreateEvalToolOptions, EvalCellInvocation } from "./eval-tool-options.ts";
13
13
  import { describeTimeoutState } from "./interrupt-note.ts";
14
- import { createEvalInputSchema, type EvalInputSchema, type EvalToolDetails, enabledLanguageList } from "./types.ts";
14
+ import {
15
+ createEvalInputSchema,
16
+ type EvalInputSchema,
17
+ type EvalToolDetails,
18
+ type EvalToolRequest,
19
+ enabledLanguageList,
20
+ } from "./types.ts";
15
21
 
16
22
  export type { EvalTimeoutFactory } from "./cell-execution.ts";
17
23
  export type { CreateEvalToolOptions } from "./eval-tool-options.ts";
@@ -35,6 +41,15 @@ export function createEvalTool(options: CreateEvalToolOptions): ToolDefinition<E
35
41
  promptGuidelines: [...prompt.promptGuidelines],
36
42
  parameters,
37
43
  executionMode: "sequential",
44
+ prepareArguments: (args) => {
45
+ if (typeof args !== "object" || args === null) return args as EvalToolRequest;
46
+ const record = args as Record<string, unknown>;
47
+ if (record.action === "peek" || record.action === "stop") return args as EvalToolRequest;
48
+ const summary = clampEvalSummary(record.summary);
49
+ if (summary === undefined) delete record.summary;
50
+ else record.summary = summary;
51
+ return args as EvalToolRequest;
52
+ },
38
53
  ...(options.renderers?.renderCall === undefined ? {} : { renderCall: options.renderers.renderCall }),
39
54
  ...(options.renderers?.renderResult === undefined ? {} : { renderResult: options.renderers.renderResult }),
40
55
  async execute(toolCallId, params, signal, onUpdate, ctx) {
@@ -255,8 +255,7 @@ function renderPrefixed(text: string, environment: RenderEnvironment, prefixStyl
255
255
 
256
256
  function cellHeader(cell: EvalCellResult, environment: RenderEnvironment, badges: CellBadges): string {
257
257
  const presentation = cellPresentation(cell.status, environment.spinnerFrame);
258
- const title = cell.title === undefined ? "" : ` ${cell.title}`;
259
- let header = `eval ${cell.language}${title} ${presentation.label} ${presentation.icon}`;
258
+ let header = `eval ${cell.language} ${presentation.label} ${presentation.icon}`;
260
259
  if (cell.durationMs !== undefined) header += ` · ${formatDuration(cell.durationMs)}`;
261
260
  if (badges.reset) header += " · reset";
262
261
  if (badges.timeout !== undefined) header += ` · timeout ${badges.timeout}s`;
@@ -511,6 +510,16 @@ function renderCell(cell: EvalCellResult, environment: RenderEnvironment, badges
511
510
  continuation: "│ ",
512
511
  color: "borderAccent",
513
512
  });
513
+ if (cell.summary !== undefined) {
514
+ appendLines(
515
+ lines,
516
+ renderPrefixed(style(environment.theme, "muted", cell.summary), environment, {
517
+ prefix: "│ ",
518
+ continuation: "│ ",
519
+ color: "muted",
520
+ }),
521
+ );
522
+ }
514
523
  const innerWidth = Math.max(1, environment.width - 2);
515
524
  const codePreview = previewText(
516
525
  highlightedCode(cell.code, cell.language, environment.theme),
@@ -726,7 +735,6 @@ function resultHeader(
726
735
  status: "running" | "done" | "error",
727
736
  theme: Theme | undefined,
728
737
  ): string {
729
- const title = details?.title === undefined ? "" : ` ${details.title}`;
730
738
  let color: ThemeColor;
731
739
  switch (status) {
732
740
  case "running":
@@ -739,7 +747,7 @@ function resultHeader(
739
747
  color = "error";
740
748
  break;
741
749
  }
742
- return style(theme, color, `eval ${details?.language ?? "?"}${title} ${status}`);
750
+ return style(theme, color, `eval ${details?.language ?? "?"} ${status}`);
743
751
  }
744
752
 
745
753
  function resultMetadata(
@@ -771,11 +779,11 @@ export function renderEvalCall(
771
779
  return component;
772
780
  }
773
781
  if (theme === undefined && context.spinnerFrame === undefined) {
774
- const title = args.title === undefined ? "" : ` ${args.title}`;
775
782
  const reset = args.reset === true ? " reset" : "";
776
783
  const timeout = args.timeout === undefined ? "" : ` timeout ${args.timeout}s`;
777
784
  component.setBlocks([
778
- { kind: "text", text: style(theme, "toolTitle", `eval ${args.language}${title}${reset}${timeout}`) },
785
+ { kind: "text", text: style(theme, "toolTitle", `eval ${args.language}${reset}${timeout}`) },
786
+ ...(args.summary === undefined ? [] : [{ kind: "text" as const, text: style(theme, "muted", args.summary) }]),
779
787
  {
780
788
  kind: "text",
781
789
  text: style(theme, "mdCodeBlock", args.code.trim().length > 0 ? args.code : "..."),
@@ -799,7 +807,7 @@ export function renderEvalCall(
799
807
  };
800
808
  const cell: EvalCellResult = {
801
809
  index: 0,
802
- ...(args.title === undefined ? {} : { title: args.title }),
810
+ ...(args.summary === undefined ? {} : { summary: args.summary }),
803
811
  code: args.code,
804
812
  language: args.language,
805
813
  output: "",
@@ -850,6 +858,9 @@ export function renderEvalResult(
850
858
  const status = resultStatus(details, options, context.isError);
851
859
  const blocks: RenderBlock[] = [
852
860
  { kind: "text", text: resultHeader(details, status, theme) },
861
+ ...(details?.summary === undefined
862
+ ? []
863
+ : [{ kind: "text" as const, text: style(theme, "muted", details.summary) }]),
853
864
  ...resultMetadata(details, options, theme),
854
865
  { kind: "blank" },
855
866
  ];
package/src/tool/types.ts CHANGED
@@ -11,11 +11,13 @@ export function enabledLanguageList(enabled: EnabledEvalLanguages): EvalLanguage
11
11
  return evalLanguageOrder.filter((language) => enabled[language]);
12
12
  }
13
13
 
14
+ export const EVAL_SUMMARY_MAX_LENGTH = 80;
15
+
14
16
  export interface EvalToolInput {
15
17
  readonly language: EvalLanguage;
16
18
  readonly code: string;
17
19
  readonly action?: "run";
18
- readonly title?: string;
20
+ readonly summary: string;
19
21
  readonly timeout?: number;
20
22
  readonly on_timeout?: "detach" | "error";
21
23
  readonly reset?: boolean;
@@ -38,7 +40,13 @@ const fullEvalInputSchema = Type.Object({
38
40
  Type.Union([Type.Literal("py"), Type.Literal("js"), Type.Literal("rb"), Type.Literal("jl")]),
39
41
  ),
40
42
  code: Type.Optional(Type.String({ description: "Cell body, verbatim." })),
41
- title: Type.Optional(Type.String({ description: "Short transcript label." })),
43
+ summary: Type.Optional(
44
+ Type.String({
45
+ maxLength: EVAL_SUMMARY_MAX_LENGTH,
46
+ description:
47
+ "REQUIRED for run. ONE line in the USER'S conversational language (Korean conversation -> Korean summary) stating WHAT this cell does and FOR WHAT PURPOSE; shown in the TUI while the cell runs. Longer values are force-truncated to 80 chars.",
48
+ }),
49
+ ),
42
50
  timeout: Type.Optional(Type.Number({ minimum: 1, description: "Timeout in seconds." })),
43
51
  on_timeout: Type.Optional(
44
52
  Type.Union([Type.Literal("detach"), Type.Literal("error")], {
@@ -68,7 +76,13 @@ export function createEvalInputSchema(enabled: EnabledEvalLanguages): EvalInputS
68
76
  ),
69
77
  language: Type.Optional(languageSchema),
70
78
  code: Type.Optional(Type.String({ description: "Cell body, verbatim." })),
71
- title: Type.Optional(Type.String({ description: "Short transcript label." })),
79
+ summary: Type.Optional(
80
+ Type.String({
81
+ maxLength: EVAL_SUMMARY_MAX_LENGTH,
82
+ description:
83
+ "REQUIRED for run. ONE line in the USER'S conversational language (Korean conversation -> Korean summary) stating WHAT this cell does and FOR WHAT PURPOSE; shown in the TUI while the cell runs. Longer values are force-truncated to 80 chars.",
84
+ }),
85
+ ),
72
86
  timeout: Type.Optional(Type.Number({ minimum: 1, description: "Timeout in seconds." })),
73
87
  on_timeout: Type.Optional(
74
88
  Type.Union([Type.Literal("detach"), Type.Literal("error")], {
@@ -134,7 +148,7 @@ export type EvalDisplayOutput =
134
148
 
135
149
  export type EvalCellResult = {
136
150
  readonly index: number;
137
- readonly title?: string;
151
+ readonly summary?: string;
138
152
  readonly code: string;
139
153
  readonly language: EvalLanguage;
140
154
  readonly output: string;
@@ -148,7 +162,7 @@ export type EvalCellResult = {
148
162
  export interface EvalToolDetails {
149
163
  readonly language: EvalLanguage;
150
164
  readonly languages?: readonly EvalLanguage[];
151
- readonly title?: string;
165
+ readonly summary?: string;
152
166
  readonly durationMs: number;
153
167
  readonly toolCalls: readonly EvalToolCallSummary[];
154
168
  readonly truncated: boolean;