@oh-my-pi/pi-coding-agent 6.8.5 → 6.9.69
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 +51 -0
- package/package.json +6 -6
- package/src/cli/stats-cli.ts +191 -0
- package/src/core/agent-session.ts +103 -1
- package/src/core/extensions/index.ts +2 -0
- package/src/core/extensions/runner.ts +31 -0
- package/src/core/extensions/types.ts +24 -0
- package/src/core/messages.ts +48 -0
- package/src/core/sdk.ts +0 -2
- package/src/core/session-manager.ts +10 -1
- package/src/core/settings-manager.ts +0 -105
- package/src/core/tools/bash.ts +5 -7
- package/src/core/tools/index.ts +1 -5
- package/src/core/tools/patch/applicator.ts +115 -17
- package/src/core/tools/patch/index.ts +1 -1
- package/src/core/tools/patch/normalize.ts +185 -10
- package/src/core/tools/python.ts +444 -86
- package/src/core/tools/task/executor.ts +2 -6
- package/src/core/tools/task/index.ts +30 -12
- package/src/core/tools/task/render.ts +163 -30
- package/src/core/tools/task/template.ts +37 -0
- package/src/core/tools/task/types.ts +6 -2
- package/src/core/tools/task/worker.ts +1 -1
- package/src/index.ts +2 -2
- package/src/main.ts +12 -0
- package/src/modes/interactive/components/python-execution.ts +180 -0
- package/src/modes/interactive/components/settings-defs.ts +0 -70
- package/src/modes/interactive/components/settings-selector.ts +0 -1
- package/src/modes/interactive/components/welcome.ts +1 -0
- package/src/modes/interactive/controllers/command-controller.ts +46 -0
- package/src/modes/interactive/controllers/event-controller.ts +0 -11
- package/src/modes/interactive/controllers/input-controller.ts +28 -1
- package/src/modes/interactive/controllers/selector-controller.ts +0 -9
- package/src/modes/interactive/interactive-mode.ts +10 -58
- package/src/modes/interactive/theme/dark.json +2 -9
- package/src/modes/interactive/theme/defaults/alabaster.json +2 -8
- package/src/modes/interactive/theme/defaults/amethyst.json +2 -9
- package/src/modes/interactive/theme/defaults/anthracite.json +2 -9
- package/src/modes/interactive/theme/defaults/basalt.json +89 -88
- package/src/modes/interactive/theme/defaults/birch.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-abyss.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-arctic.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-aurora.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-catppuccin.json +2 -1
- package/src/modes/interactive/theme/defaults/dark-cavern.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-copper.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-cosmos.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-cyberpunk.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-dracula.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-eclipse.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-ember.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-equinox.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-forest.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-github.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-gruvbox.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-lavender.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-lunar.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-midnight.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-monochrome.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-monokai.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-nebula.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-nord.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-ocean.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-one.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-rainforest.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-reef.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-retro.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-rose-pine.json +2 -1
- package/src/modes/interactive/theme/defaults/dark-sakura.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-slate.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-solarized.json +2 -1
- package/src/modes/interactive/theme/defaults/dark-solstice.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-starfall.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-sunset.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-swamp.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-synthwave.json +2 -1
- package/src/modes/interactive/theme/defaults/dark-taiga.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-terminal.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-tokyo-night.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-tundra.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-twilight.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-volcanic.json +2 -8
- package/src/modes/interactive/theme/defaults/graphite.json +2 -9
- package/src/modes/interactive/theme/defaults/light-arctic.json +2 -1
- package/src/modes/interactive/theme/defaults/light-aurora-day.json +2 -8
- package/src/modes/interactive/theme/defaults/light-canyon.json +2 -8
- package/src/modes/interactive/theme/defaults/light-catppuccin.json +2 -1
- package/src/modes/interactive/theme/defaults/light-cirrus.json +2 -8
- package/src/modes/interactive/theme/defaults/light-coral.json +3 -2
- package/src/modes/interactive/theme/defaults/light-cyberpunk.json +2 -9
- package/src/modes/interactive/theme/defaults/light-dawn.json +2 -8
- package/src/modes/interactive/theme/defaults/light-dunes.json +2 -8
- package/src/modes/interactive/theme/defaults/light-eucalyptus.json +3 -2
- package/src/modes/interactive/theme/defaults/light-forest.json +2 -9
- package/src/modes/interactive/theme/defaults/light-frost.json +3 -2
- package/src/modes/interactive/theme/defaults/light-github.json +2 -1
- package/src/modes/interactive/theme/defaults/light-glacier.json +2 -8
- package/src/modes/interactive/theme/defaults/light-gruvbox.json +2 -9
- package/src/modes/interactive/theme/defaults/light-haze.json +2 -8
- package/src/modes/interactive/theme/defaults/light-honeycomb.json +3 -2
- package/src/modes/interactive/theme/defaults/light-lagoon.json +2 -8
- package/src/modes/interactive/theme/defaults/light-lavender.json +3 -2
- package/src/modes/interactive/theme/defaults/light-meadow.json +2 -8
- package/src/modes/interactive/theme/defaults/light-mint.json +3 -2
- package/src/modes/interactive/theme/defaults/light-monochrome.json +2 -1
- package/src/modes/interactive/theme/defaults/light-ocean.json +2 -9
- package/src/modes/interactive/theme/defaults/light-one.json +2 -8
- package/src/modes/interactive/theme/defaults/light-opal.json +2 -8
- package/src/modes/interactive/theme/defaults/light-orchard.json +2 -8
- package/src/modes/interactive/theme/defaults/light-paper.json +3 -2
- package/src/modes/interactive/theme/defaults/light-prism.json +2 -8
- package/src/modes/interactive/theme/defaults/light-retro.json +2 -9
- package/src/modes/interactive/theme/defaults/light-sand.json +3 -2
- package/src/modes/interactive/theme/defaults/light-savanna.json +2 -8
- package/src/modes/interactive/theme/defaults/light-solarized.json +2 -1
- package/src/modes/interactive/theme/defaults/light-soleil.json +2 -8
- package/src/modes/interactive/theme/defaults/light-sunset.json +2 -9
- package/src/modes/interactive/theme/defaults/light-synthwave.json +2 -9
- package/src/modes/interactive/theme/defaults/light-tokyo-night.json +2 -9
- package/src/modes/interactive/theme/defaults/light-wetland.json +2 -8
- package/src/modes/interactive/theme/defaults/light-zenith.json +2 -8
- package/src/modes/interactive/theme/defaults/limestone.json +2 -8
- package/src/modes/interactive/theme/defaults/mahogany.json +2 -9
- package/src/modes/interactive/theme/defaults/marble.json +2 -8
- package/src/modes/interactive/theme/defaults/obsidian.json +89 -88
- package/src/modes/interactive/theme/defaults/onyx.json +89 -88
- package/src/modes/interactive/theme/defaults/pearl.json +2 -8
- package/src/modes/interactive/theme/defaults/porcelain.json +89 -88
- package/src/modes/interactive/theme/defaults/quartz.json +2 -8
- package/src/modes/interactive/theme/defaults/sandstone.json +2 -8
- package/src/modes/interactive/theme/defaults/titanium.json +88 -87
- package/src/modes/interactive/theme/light.json +2 -8
- package/src/modes/interactive/theme/theme-schema.json +5 -0
- package/src/modes/interactive/theme/theme.ts +7 -0
- package/src/modes/interactive/types.ts +5 -15
- package/src/modes/interactive/utils/ui-helpers.ts +20 -0
- package/src/prompts/system/system-prompt.md +8 -0
- package/src/prompts/tools/python.md +40 -2
- package/src/prompts/tools/task.md +8 -13
- package/src/core/custom-commands/bundled/wt/index.ts +0 -435
- package/src/core/tools/git.ts +0 -213
- package/src/core/voice-controller.ts +0 -135
- package/src/core/voice-supervisor.ts +0 -976
- package/src/core/voice.ts +0 -314
- package/src/lib/worktree/collapse.ts +0 -180
- package/src/lib/worktree/constants.ts +0 -14
- package/src/lib/worktree/errors.ts +0 -23
- package/src/lib/worktree/git.ts +0 -60
- package/src/lib/worktree/index.ts +0 -15
- package/src/lib/worktree/operations.ts +0 -216
- package/src/lib/worktree/session.ts +0 -114
- package/src/lib/worktree/stats.ts +0 -67
- package/src/modes/interactive/utils/voice-manager.ts +0 -96
- package/src/prompts/tools/git.md +0 -9
- package/src/prompts/voice-summary.md +0 -12
package/src/core/tools/python.ts
CHANGED
|
@@ -2,10 +2,10 @@ import { relative, resolve, sep } from "node:path";
|
|
|
2
2
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
3
3
|
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
5
|
-
import { Text, truncateToWidth } from "@oh-my-pi/pi-tui";
|
|
5
|
+
import { Text, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
6
6
|
import { type Static, Type } from "@sinclair/typebox";
|
|
7
7
|
import { truncateToVisualLines } from "../../modes/interactive/components/visual-truncate";
|
|
8
|
-
import type
|
|
8
|
+
import { highlightCode, type Theme } from "../../modes/interactive/theme/theme";
|
|
9
9
|
import pythonDescription from "../../prompts/tools/python.md" with { type: "text" };
|
|
10
10
|
import type { RenderResultOptions } from "../custom-tools/types";
|
|
11
11
|
import { renderPromptTemplate } from "../prompt-templates";
|
|
@@ -39,15 +39,26 @@ function groupPreludeHelpers(helpers: PreludeHelper[]): PreludeCategory[] {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export const pythonSchema = Type.Object({
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
cells: Type.Array(
|
|
43
|
+
Type.Object({
|
|
44
|
+
code: Type.String({
|
|
45
|
+
description:
|
|
46
|
+
"Python code for this cell. Keep it focused (imports, helper, test, use). No narrative text—put explanations in the assistant message or in the cell title.",
|
|
47
|
+
}),
|
|
48
|
+
title: Type.Optional(
|
|
49
|
+
Type.String({ description: "Short label for the cell (e.g., 'imports', 'parse helper')." }),
|
|
50
|
+
),
|
|
51
|
+
}),
|
|
52
|
+
{
|
|
53
|
+
description:
|
|
54
|
+
"Python cells to execute sequentially. Each cell runs in the same kernel—imports and variables persist. Keep cells small: one logical step each (import, define, test, use). If a cell fails, fix only that cell; earlier cells' state remains.",
|
|
55
|
+
},
|
|
46
56
|
),
|
|
57
|
+
timeoutMs: Type.Optional(Type.Number({ description: "Timeout in milliseconds (default: 30000)" })),
|
|
58
|
+
cwd: Type.Optional(Type.String({ description: "Working directory for the command (default: current directory)" })),
|
|
47
59
|
reset: Type.Optional(Type.Boolean({ description: "Restart the kernel before executing this code" })),
|
|
48
60
|
});
|
|
49
|
-
|
|
50
|
-
export type PythonToolParams = { code: string; timeout?: number; workdir?: string; reset?: boolean };
|
|
61
|
+
export type PythonToolParams = Static<typeof pythonSchema>;
|
|
51
62
|
|
|
52
63
|
export type PythonToolResult = {
|
|
53
64
|
content: Array<{ type: "text"; text: string }>;
|
|
@@ -56,7 +67,19 @@ export type PythonToolResult = {
|
|
|
56
67
|
|
|
57
68
|
export type PythonProxyExecutor = (params: PythonToolParams, signal?: AbortSignal) => Promise<PythonToolResult>;
|
|
58
69
|
|
|
70
|
+
export interface PythonCellResult {
|
|
71
|
+
index: number;
|
|
72
|
+
title?: string;
|
|
73
|
+
code: string;
|
|
74
|
+
output: string;
|
|
75
|
+
status: "pending" | "running" | "complete" | "error";
|
|
76
|
+
durationMs?: number;
|
|
77
|
+
exitCode?: number;
|
|
78
|
+
statusEvents?: PythonStatusEvent[];
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
export interface PythonToolDetails {
|
|
82
|
+
cells?: PythonCellResult[];
|
|
60
83
|
truncation?: TruncationResult;
|
|
61
84
|
fullOutputPath?: string;
|
|
62
85
|
fullOutput?: string;
|
|
@@ -151,7 +174,7 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
151
174
|
throw new Error("Python tool requires a session when not using proxy executor");
|
|
152
175
|
}
|
|
153
176
|
|
|
154
|
-
const {
|
|
177
|
+
const { cells, timeoutMs = 30000, cwd, reset } = params;
|
|
155
178
|
const controller = new AbortController();
|
|
156
179
|
const onAbort = () => controller.abort();
|
|
157
180
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -161,7 +184,7 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
161
184
|
throw new Error("Aborted");
|
|
162
185
|
}
|
|
163
186
|
|
|
164
|
-
const commandCwd =
|
|
187
|
+
const commandCwd = cwd ? resolveToCwd(cwd, this.session.cwd) : this.session.cwd;
|
|
165
188
|
let cwdStat: Awaited<ReturnType<Bun.BunFile["stat"]>>;
|
|
166
189
|
try {
|
|
167
190
|
cwdStat = await Bun.file(commandCwd).stat();
|
|
@@ -177,89 +200,184 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
177
200
|
let tailBytes = 0;
|
|
178
201
|
const jsonOutputs: unknown[] = [];
|
|
179
202
|
const images: ImageContent[] = [];
|
|
203
|
+
const statusEvents: PythonStatusEvent[] = [];
|
|
204
|
+
|
|
205
|
+
const cellResults: PythonCellResult[] = cells.map((cell, index) => ({
|
|
206
|
+
index,
|
|
207
|
+
title: cell.title,
|
|
208
|
+
code: cell.code,
|
|
209
|
+
output: "",
|
|
210
|
+
status: "pending",
|
|
211
|
+
}));
|
|
212
|
+
const cellOutputs: string[] = [];
|
|
213
|
+
let lastFullOutputPath: string | undefined;
|
|
214
|
+
|
|
215
|
+
const appendTail = (text: string) => {
|
|
216
|
+
if (!text) return;
|
|
217
|
+
const chunkBytes = Buffer.byteLength(text, "utf-8");
|
|
218
|
+
tailChunks.push({ text, bytes: chunkBytes });
|
|
219
|
+
tailBytes += chunkBytes;
|
|
220
|
+
while (tailBytes > maxTailBytes && tailChunks.length > 1) {
|
|
221
|
+
const removed = tailChunks.shift();
|
|
222
|
+
if (removed) {
|
|
223
|
+
tailBytes -= removed.bytes;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const buildUpdateDetails = (truncation?: TruncationResult): PythonToolDetails => {
|
|
229
|
+
const details: PythonToolDetails = {
|
|
230
|
+
cells: cellResults.map((cell) => ({
|
|
231
|
+
...cell,
|
|
232
|
+
statusEvents: cell.statusEvents ? [...cell.statusEvents] : undefined,
|
|
233
|
+
})),
|
|
234
|
+
};
|
|
235
|
+
if (truncation) {
|
|
236
|
+
details.truncation = truncation;
|
|
237
|
+
}
|
|
238
|
+
if (lastFullOutputPath) {
|
|
239
|
+
details.fullOutputPath = lastFullOutputPath;
|
|
240
|
+
}
|
|
241
|
+
if (jsonOutputs.length > 0) {
|
|
242
|
+
details.jsonOutputs = jsonOutputs;
|
|
243
|
+
}
|
|
244
|
+
if (images.length > 0) {
|
|
245
|
+
details.images = images;
|
|
246
|
+
}
|
|
247
|
+
if (statusEvents.length > 0) {
|
|
248
|
+
details.statusEvents = statusEvents;
|
|
249
|
+
}
|
|
250
|
+
return details;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const pushUpdate = () => {
|
|
254
|
+
if (!onUpdate) return;
|
|
255
|
+
const tailText = tailChunks.map((entry) => entry.text).join("");
|
|
256
|
+
const truncation = truncateTail(tailText);
|
|
257
|
+
onUpdate({
|
|
258
|
+
content: [{ type: "text", text: truncation.content || "" }],
|
|
259
|
+
details: buildUpdateDetails(truncation.truncated ? truncation : undefined),
|
|
260
|
+
});
|
|
261
|
+
};
|
|
180
262
|
|
|
181
263
|
const sessionFile = this.session.getSessionFile?.() ?? undefined;
|
|
182
|
-
const sessionId = sessionFile ? `session:${sessionFile}:
|
|
183
|
-
const
|
|
264
|
+
const sessionId = sessionFile ? `session:${sessionFile}:cwd:${commandCwd}` : `cwd:${commandCwd}`;
|
|
265
|
+
const baseExecutorOptions: Omit<PythonExecutorOptions, "reset"> = {
|
|
184
266
|
cwd: commandCwd,
|
|
185
267
|
timeoutMs,
|
|
186
268
|
signal: controller.signal,
|
|
187
269
|
sessionId,
|
|
188
270
|
kernelMode: this.session.settings?.getPythonKernelMode?.() ?? "session",
|
|
189
271
|
useSharedGateway: this.session.settings?.getPythonSharedGateway?.() ?? true,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
for (let i = 0; i < cells.length; i++) {
|
|
275
|
+
const cell = cells[i];
|
|
276
|
+
const isFirstCell = i === 0;
|
|
277
|
+
const cellResult = cellResults[i];
|
|
278
|
+
cellResult.status = "running";
|
|
279
|
+
cellResult.output = "";
|
|
280
|
+
cellResult.statusEvents = undefined;
|
|
281
|
+
cellResult.exitCode = undefined;
|
|
282
|
+
cellResult.durationMs = undefined;
|
|
283
|
+
pushUpdate();
|
|
284
|
+
|
|
285
|
+
const executorOptions: PythonExecutorOptions = {
|
|
286
|
+
...baseExecutorOptions,
|
|
287
|
+
reset: isFirstCell ? reset : false,
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const startTime = Date.now();
|
|
291
|
+
const result = await executePython(cell.code, executorOptions);
|
|
292
|
+
const durationMs = Date.now() - startTime;
|
|
293
|
+
|
|
294
|
+
const cellStatusEvents: PythonStatusEvent[] = [];
|
|
295
|
+
for (const output of result.displayOutputs) {
|
|
296
|
+
if (output.type === "json") {
|
|
297
|
+
jsonOutputs.push(output.data);
|
|
200
298
|
}
|
|
201
|
-
if (
|
|
202
|
-
|
|
203
|
-
const truncation = truncateTail(tailText);
|
|
204
|
-
onUpdate({
|
|
205
|
-
content: [{ type: "text", text: truncation.content || "" }],
|
|
206
|
-
details: truncation.truncated ? { truncation } : undefined,
|
|
207
|
-
});
|
|
299
|
+
if (output.type === "image") {
|
|
300
|
+
images.push({ type: "image", data: output.data, mimeType: output.mimeType });
|
|
208
301
|
}
|
|
209
|
-
|
|
210
|
-
|
|
302
|
+
if (output.type === "status") {
|
|
303
|
+
statusEvents.push(output.event);
|
|
304
|
+
cellStatusEvents.push(output.event);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
211
307
|
|
|
212
|
-
|
|
308
|
+
if (result.fullOutputPath) {
|
|
309
|
+
lastFullOutputPath = result.fullOutputPath;
|
|
310
|
+
}
|
|
213
311
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
312
|
+
const cellOutput = result.output.trim();
|
|
313
|
+
cellResult.output = cellOutput;
|
|
314
|
+
cellResult.exitCode = result.exitCode;
|
|
315
|
+
cellResult.durationMs = durationMs;
|
|
316
|
+
cellResult.statusEvents = cellStatusEvents.length > 0 ? cellStatusEvents : undefined;
|
|
317
|
+
|
|
318
|
+
let combinedCellOutput = "";
|
|
319
|
+
if (cells.length > 1) {
|
|
320
|
+
const cellHeader = `[${i + 1}/${cells.length}]`;
|
|
321
|
+
const cellTitle = cell.title ? ` ${cell.title}` : "";
|
|
322
|
+
if (cellOutput) {
|
|
323
|
+
combinedCellOutput = `${cellHeader}${cellTitle}\n${cellOutput}`;
|
|
324
|
+
} else {
|
|
325
|
+
combinedCellOutput = `${cellHeader}${cellTitle} (ok)`;
|
|
326
|
+
}
|
|
327
|
+
cellOutputs.push(combinedCellOutput);
|
|
328
|
+
} else if (cellOutput) {
|
|
329
|
+
combinedCellOutput = cellOutput;
|
|
330
|
+
cellOutputs.push(combinedCellOutput);
|
|
218
331
|
}
|
|
219
|
-
|
|
220
|
-
|
|
332
|
+
|
|
333
|
+
if (combinedCellOutput) {
|
|
334
|
+
const prefix = cellOutputs.length > 1 ? "\n\n" : "";
|
|
335
|
+
appendTail(`${prefix}${combinedCellOutput}`);
|
|
221
336
|
}
|
|
222
|
-
|
|
223
|
-
|
|
337
|
+
|
|
338
|
+
if (result.cancelled) {
|
|
339
|
+
cellResult.status = "error";
|
|
340
|
+
pushUpdate();
|
|
341
|
+
const errorMsg = result.output || "Command aborted";
|
|
342
|
+
throw new Error(cells.length > 1 ? `Cell ${i + 1} aborted: ${errorMsg}` : errorMsg);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (result.exitCode !== 0 && result.exitCode !== undefined) {
|
|
346
|
+
cellResult.status = "error";
|
|
347
|
+
pushUpdate();
|
|
348
|
+
const combinedOutput = cellOutputs.join("\n\n");
|
|
349
|
+
throw new Error(
|
|
350
|
+
cells.length > 1
|
|
351
|
+
? `${combinedOutput}\n\nCell ${i + 1} failed (exit code ${result.exitCode}). Earlier cells succeeded—their state persists. Fix only cell ${i + 1}.`
|
|
352
|
+
: `${combinedOutput}\n\nCommand exited with code ${result.exitCode}`,
|
|
353
|
+
);
|
|
224
354
|
}
|
|
225
|
-
}
|
|
226
355
|
|
|
227
|
-
|
|
228
|
-
|
|
356
|
+
cellResult.status = "complete";
|
|
357
|
+
pushUpdate();
|
|
229
358
|
}
|
|
230
359
|
|
|
231
|
-
const
|
|
360
|
+
const combinedOutput = cellOutputs.join("\n\n");
|
|
361
|
+
const truncation = truncateTail(combinedOutput);
|
|
232
362
|
let outputText =
|
|
233
363
|
truncation.content || (jsonOutputs.length > 0 || images.length > 0 ? "(no text output)" : "(no output)");
|
|
234
|
-
|
|
364
|
+
|
|
365
|
+
const details: PythonToolDetails = {
|
|
366
|
+
cells: cellResults,
|
|
367
|
+
fullOutputPath: lastFullOutputPath,
|
|
368
|
+
jsonOutputs: jsonOutputs.length > 0 ? jsonOutputs : undefined,
|
|
369
|
+
images: images.length > 0 ? images : undefined,
|
|
370
|
+
statusEvents: statusEvents.length > 0 ? statusEvents : undefined,
|
|
371
|
+
};
|
|
235
372
|
|
|
236
373
|
if (truncation.truncated) {
|
|
237
|
-
details =
|
|
238
|
-
truncation,
|
|
239
|
-
fullOutputPath: result.fullOutputPath,
|
|
240
|
-
jsonOutputs: jsonOutputs,
|
|
241
|
-
images,
|
|
242
|
-
statusEvents: statusEvents.length > 0 ? statusEvents : undefined,
|
|
243
|
-
};
|
|
374
|
+
details.truncation = truncation;
|
|
244
375
|
outputText += formatTailTruncationNotice(truncation, {
|
|
245
|
-
fullOutputPath:
|
|
246
|
-
originalContent:
|
|
376
|
+
fullOutputPath: lastFullOutputPath,
|
|
377
|
+
originalContent: combinedOutput,
|
|
247
378
|
});
|
|
248
379
|
}
|
|
249
380
|
|
|
250
|
-
if (!details && (jsonOutputs.length > 0 || images.length > 0 || statusEvents.length > 0)) {
|
|
251
|
-
details = {
|
|
252
|
-
jsonOutputs: jsonOutputs.length > 0 ? jsonOutputs : undefined,
|
|
253
|
-
images: images.length > 0 ? images : undefined,
|
|
254
|
-
statusEvents: statusEvents.length > 0 ? statusEvents : undefined,
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if (result.exitCode !== 0 && result.exitCode !== undefined) {
|
|
259
|
-
outputText += `\n\nCommand exited with code ${result.exitCode}`;
|
|
260
|
-
throw new Error(outputText);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
381
|
return { content: [{ type: "text", text: outputText }], details };
|
|
264
382
|
} finally {
|
|
265
383
|
signal?.removeEventListener("abort", onAbort);
|
|
@@ -268,9 +386,9 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
268
386
|
}
|
|
269
387
|
|
|
270
388
|
interface PythonRenderArgs {
|
|
271
|
-
code?: string
|
|
389
|
+
cells?: Array<{ code: string; title?: string }>;
|
|
272
390
|
timeout?: number;
|
|
273
|
-
|
|
391
|
+
cwd?: string;
|
|
274
392
|
}
|
|
275
393
|
|
|
276
394
|
interface PythonRenderContext {
|
|
@@ -600,13 +718,175 @@ function renderStatusEvents(events: PythonStatusEvent[], theme: Theme, expanded:
|
|
|
600
718
|
return lines;
|
|
601
719
|
}
|
|
602
720
|
|
|
721
|
+
function applyCellBackground(line: string, width: number, bgFn?: (text: string) => string): string {
|
|
722
|
+
if (!bgFn) return line;
|
|
723
|
+
if (width <= 0) return bgFn(line);
|
|
724
|
+
const paddingNeeded = Math.max(0, width - visibleWidth(line));
|
|
725
|
+
const padded = line + " ".repeat(paddingNeeded);
|
|
726
|
+
return bgFn(padded);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
function highlightPythonCode(code?: string): string[] {
|
|
730
|
+
return highlightCode(code ?? "", "python");
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function formatCellStatus(cell: PythonCellResult, ui: ToolUIKit, spinnerFrame?: number): string | undefined {
|
|
734
|
+
switch (cell.status) {
|
|
735
|
+
case "pending":
|
|
736
|
+
return `${ui.statusIcon("pending")} ${ui.theme.fg("muted", "pending")}`;
|
|
737
|
+
case "running":
|
|
738
|
+
return `${ui.statusIcon("running", spinnerFrame)} ${ui.theme.fg("muted", "running")}`;
|
|
739
|
+
case "complete":
|
|
740
|
+
return ui.statusIcon("success");
|
|
741
|
+
case "error":
|
|
742
|
+
return ui.statusIcon("error");
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function formatCellHeader(
|
|
747
|
+
cell: PythonCellResult,
|
|
748
|
+
index: number,
|
|
749
|
+
total: number,
|
|
750
|
+
ui: ToolUIKit,
|
|
751
|
+
spinnerFrame?: number,
|
|
752
|
+
workdirLabel?: string,
|
|
753
|
+
): string {
|
|
754
|
+
const indexLabel = ui.theme.fg("accent", `[${index + 1}/${total}]`);
|
|
755
|
+
const title = cell.title ? ` ${cell.title}` : "";
|
|
756
|
+
const metaParts: string[] = [];
|
|
757
|
+
if (workdirLabel) {
|
|
758
|
+
metaParts.push(ui.theme.fg("dim", workdirLabel));
|
|
759
|
+
}
|
|
760
|
+
if (cell.durationMs !== undefined) {
|
|
761
|
+
metaParts.push(ui.theme.fg("dim", `(${ui.formatDuration(cell.durationMs)})`));
|
|
762
|
+
}
|
|
763
|
+
const statusLabel = formatCellStatus(cell, ui, spinnerFrame);
|
|
764
|
+
if (statusLabel) {
|
|
765
|
+
metaParts.push(statusLabel);
|
|
766
|
+
}
|
|
767
|
+
const meta = metaParts.length > 0 ? ` ${metaParts.join(ui.theme.fg("dim", ui.theme.sep.dot))}` : "";
|
|
768
|
+
return `${indexLabel}${title}${meta}`;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
function formatCellOutputLines(
|
|
772
|
+
cell: PythonCellResult,
|
|
773
|
+
expanded: boolean,
|
|
774
|
+
previewLines: number,
|
|
775
|
+
theme: Theme,
|
|
776
|
+
): { lines: string[]; hiddenCount: number } {
|
|
777
|
+
const rawLines = cell.output ? cell.output.split("\n") : [];
|
|
778
|
+
const displayLines = expanded ? rawLines : rawLines.slice(-previewLines);
|
|
779
|
+
const hiddenCount = rawLines.length - displayLines.length;
|
|
780
|
+
const outputLines = displayLines.map((line) => theme.fg("toolOutput", line));
|
|
781
|
+
|
|
782
|
+
if (outputLines.length === 0) {
|
|
783
|
+
return { lines: [], hiddenCount: 0 };
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
return { lines: outputLines, hiddenCount };
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
function renderCellBlock(
|
|
790
|
+
cell: PythonCellResult,
|
|
791
|
+
index: number,
|
|
792
|
+
total: number,
|
|
793
|
+
ui: ToolUIKit,
|
|
794
|
+
options: {
|
|
795
|
+
expanded: boolean;
|
|
796
|
+
previewLines: number;
|
|
797
|
+
spinnerFrame?: number;
|
|
798
|
+
showOutput: boolean;
|
|
799
|
+
workdirLabel?: string;
|
|
800
|
+
width: number;
|
|
801
|
+
bgFn?: (text: string) => string;
|
|
802
|
+
},
|
|
803
|
+
): string[] {
|
|
804
|
+
const { expanded, previewLines, spinnerFrame, showOutput, workdirLabel, width, bgFn } = options;
|
|
805
|
+
const h = ui.theme.boxSharp.horizontal;
|
|
806
|
+
const v = ui.theme.boxSharp.vertical;
|
|
807
|
+
const cap = h.repeat(3);
|
|
808
|
+
const border = (text: string) => ui.theme.fg("dim", text);
|
|
809
|
+
const lineWidth = Math.max(0, width);
|
|
810
|
+
|
|
811
|
+
const buildBarLine = (leftChar: string, label?: string): string => {
|
|
812
|
+
const left = border(`${leftChar}${cap}`);
|
|
813
|
+
if (lineWidth <= 0) return left;
|
|
814
|
+
const rawLabel = label ? ` ${label} ` : " ";
|
|
815
|
+
const maxLabelWidth = Math.max(0, lineWidth - visibleWidth(left));
|
|
816
|
+
const trimmedLabel = truncateToWidth(rawLabel, maxLabelWidth, ui.theme.format.ellipsis);
|
|
817
|
+
const fillCount = Math.max(0, lineWidth - visibleWidth(left + trimmedLabel));
|
|
818
|
+
return `${left}${trimmedLabel}${border(h.repeat(fillCount))}`;
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
const lines: string[] = [];
|
|
822
|
+
lines.push(
|
|
823
|
+
applyCellBackground(
|
|
824
|
+
buildBarLine(ui.theme.boxSharp.topLeft, formatCellHeader(cell, index, total, ui, spinnerFrame, workdirLabel)),
|
|
825
|
+
lineWidth,
|
|
826
|
+
bgFn,
|
|
827
|
+
),
|
|
828
|
+
);
|
|
829
|
+
|
|
830
|
+
const codePrefix = border(`${v} `);
|
|
831
|
+
const codeWidth = Math.max(0, lineWidth - visibleWidth(codePrefix));
|
|
832
|
+
const codeLines = highlightPythonCode(cell.code);
|
|
833
|
+
for (const line of codeLines) {
|
|
834
|
+
const text = truncateToWidth(line, codeWidth, ui.theme.format.ellipsis);
|
|
835
|
+
lines.push(applyCellBackground(`${codePrefix}${text}`, lineWidth, bgFn));
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
const statusLines = renderStatusEvents(cell.statusEvents ?? [], ui.theme, expanded);
|
|
839
|
+
const outputContent = formatCellOutputLines(cell, expanded, previewLines, ui.theme);
|
|
840
|
+
const hasOutput = outputContent.lines.length > 0;
|
|
841
|
+
const hasStatus = statusLines.length > 0;
|
|
842
|
+
const showOutputSection = showOutput && (hasOutput || hasStatus);
|
|
843
|
+
|
|
844
|
+
if (showOutputSection) {
|
|
845
|
+
lines.push(
|
|
846
|
+
applyCellBackground(
|
|
847
|
+
buildBarLine(ui.theme.boxSharp.teeRight, ui.theme.fg("toolTitle", "Output")),
|
|
848
|
+
lineWidth,
|
|
849
|
+
bgFn,
|
|
850
|
+
),
|
|
851
|
+
);
|
|
852
|
+
|
|
853
|
+
for (const line of outputContent.lines) {
|
|
854
|
+
const text = truncateToWidth(line, codeWidth, ui.theme.format.ellipsis);
|
|
855
|
+
lines.push(applyCellBackground(`${codePrefix}${text}`, lineWidth, bgFn));
|
|
856
|
+
}
|
|
857
|
+
if (!expanded && outputContent.hiddenCount > 0) {
|
|
858
|
+
const hint = ui.theme.fg(
|
|
859
|
+
"dim",
|
|
860
|
+
`${ui.theme.format.ellipsis} ${outputContent.hiddenCount} more lines (ctrl+o to expand)`,
|
|
861
|
+
);
|
|
862
|
+
lines.push(
|
|
863
|
+
applyCellBackground(
|
|
864
|
+
`${codePrefix}${truncateToWidth(hint, codeWidth, ui.theme.format.ellipsis)}`,
|
|
865
|
+
lineWidth,
|
|
866
|
+
bgFn,
|
|
867
|
+
),
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
for (const line of statusLines) {
|
|
872
|
+
const text = truncateToWidth(line, codeWidth, ui.theme.format.ellipsis);
|
|
873
|
+
lines.push(applyCellBackground(`${codePrefix}${text}`, lineWidth, bgFn));
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const bottomLeft = border(`${ui.theme.boxSharp.bottomLeft}${cap}`);
|
|
878
|
+
const bottomFillCount = Math.max(0, lineWidth - visibleWidth(bottomLeft));
|
|
879
|
+
const bottomLine = `${bottomLeft}${border(h.repeat(bottomFillCount))}`;
|
|
880
|
+
lines.push(applyCellBackground(bottomLine, lineWidth, bgFn));
|
|
881
|
+
return lines;
|
|
882
|
+
}
|
|
883
|
+
|
|
603
884
|
export const pythonToolRenderer = {
|
|
604
885
|
renderCall(args: PythonRenderArgs, uiTheme: Theme): Component {
|
|
605
886
|
const ui = new ToolUIKit(uiTheme);
|
|
606
|
-
const
|
|
607
|
-
const prompt = uiTheme.fg("accent", ">>>");
|
|
887
|
+
const cells = args.cells ?? [];
|
|
608
888
|
const cwd = process.cwd();
|
|
609
|
-
let displayWorkdir = args.
|
|
889
|
+
let displayWorkdir = args.cwd;
|
|
610
890
|
|
|
611
891
|
if (displayWorkdir) {
|
|
612
892
|
const resolvedCwd = resolve(cwd);
|
|
@@ -622,11 +902,44 @@ export const pythonToolRenderer = {
|
|
|
622
902
|
}
|
|
623
903
|
}
|
|
624
904
|
|
|
625
|
-
const
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
905
|
+
const workdirLabel = displayWorkdir ? `cd ${displayWorkdir}` : undefined;
|
|
906
|
+
if (cells.length === 0) {
|
|
907
|
+
const prompt = uiTheme.fg("accent", ">>>");
|
|
908
|
+
const prefix = workdirLabel ? `${uiTheme.fg("dim", `${workdirLabel} && `)}` : "";
|
|
909
|
+
const text = ui.title(`${prompt} ${prefix}${uiTheme.format.ellipsis}`);
|
|
910
|
+
return new Text(text, 0, 0);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
return {
|
|
914
|
+
render: (width: number): string[] => {
|
|
915
|
+
const lines: string[] = [];
|
|
916
|
+
for (let i = 0; i < cells.length; i++) {
|
|
917
|
+
const cell = cells[i];
|
|
918
|
+
const cellResult: PythonCellResult = {
|
|
919
|
+
index: i,
|
|
920
|
+
title: cell.title,
|
|
921
|
+
code: cell.code,
|
|
922
|
+
output: "",
|
|
923
|
+
status: "pending",
|
|
924
|
+
};
|
|
925
|
+
lines.push(
|
|
926
|
+
...renderCellBlock(cellResult, i, cells.length, ui, {
|
|
927
|
+
expanded: true,
|
|
928
|
+
previewLines: PYTHON_DEFAULT_PREVIEW_LINES,
|
|
929
|
+
showOutput: false,
|
|
930
|
+
workdirLabel: i === 0 ? workdirLabel : undefined,
|
|
931
|
+
width,
|
|
932
|
+
bgFn: (text: string) => uiTheme.bg("toolPendingBg", text),
|
|
933
|
+
}),
|
|
934
|
+
);
|
|
935
|
+
if (i < cells.length - 1) {
|
|
936
|
+
lines.push("");
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
return lines;
|
|
940
|
+
},
|
|
941
|
+
invalidate: () => {},
|
|
942
|
+
};
|
|
630
943
|
},
|
|
631
944
|
|
|
632
945
|
renderResult(
|
|
@@ -642,7 +955,6 @@ export const pythonToolRenderer = {
|
|
|
642
955
|
const previewLines = renderContext?.previewLines ?? PYTHON_DEFAULT_PREVIEW_LINES;
|
|
643
956
|
const output = renderContext?.output ?? (result.content?.find((c) => c.type === "text")?.text ?? "").trim();
|
|
644
957
|
const fullOutput = details?.fullOutput;
|
|
645
|
-
const displayOutput = expanded ? (fullOutput ?? output) : output;
|
|
646
958
|
const showingFullOutput = expanded && fullOutput !== undefined;
|
|
647
959
|
|
|
648
960
|
const jsonOutputs = details?.jsonOutputs ?? [];
|
|
@@ -652,12 +964,6 @@ export const pythonToolRenderer = {
|
|
|
652
964
|
return [header, ...treeLines];
|
|
653
965
|
});
|
|
654
966
|
|
|
655
|
-
// Render status events
|
|
656
|
-
const statusEvents = details?.statusEvents ?? [];
|
|
657
|
-
const statusLines = renderStatusEvents(statusEvents, uiTheme, expanded);
|
|
658
|
-
|
|
659
|
-
const combinedOutput = [displayOutput, ...jsonLines].filter(Boolean).join("\n");
|
|
660
|
-
|
|
661
967
|
const truncation = details?.truncation;
|
|
662
968
|
const fullOutputPath = details?.fullOutputPath;
|
|
663
969
|
const timeoutSeconds = renderContext?.timeout;
|
|
@@ -685,12 +991,63 @@ export const pythonToolRenderer = {
|
|
|
685
991
|
}
|
|
686
992
|
}
|
|
687
993
|
|
|
994
|
+
const cellResults = details?.cells;
|
|
995
|
+
if (cellResults && cellResults.length > 0) {
|
|
996
|
+
return {
|
|
997
|
+
render: (width: number): string[] => {
|
|
998
|
+
const lines: string[] = [];
|
|
999
|
+
for (let i = 0; i < cellResults.length; i++) {
|
|
1000
|
+
const cell = cellResults[i];
|
|
1001
|
+
const showOutput = cell.status !== "pending";
|
|
1002
|
+
const bgColor =
|
|
1003
|
+
cell.status === "error"
|
|
1004
|
+
? "toolErrorBg"
|
|
1005
|
+
: cell.status === "complete"
|
|
1006
|
+
? "toolSuccessBg"
|
|
1007
|
+
: "toolPendingBg";
|
|
1008
|
+
lines.push(
|
|
1009
|
+
...renderCellBlock(cell, i, cellResults.length, ui, {
|
|
1010
|
+
expanded,
|
|
1011
|
+
previewLines,
|
|
1012
|
+
spinnerFrame: options.spinnerFrame,
|
|
1013
|
+
showOutput,
|
|
1014
|
+
width,
|
|
1015
|
+
bgFn: (text: string) => uiTheme.bg(bgColor, text),
|
|
1016
|
+
}),
|
|
1017
|
+
);
|
|
1018
|
+
if (i < cellResults.length - 1) {
|
|
1019
|
+
lines.push("");
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
if (jsonLines.length > 0) {
|
|
1023
|
+
if (lines.length > 0) {
|
|
1024
|
+
lines.push("");
|
|
1025
|
+
}
|
|
1026
|
+
lines.push(...jsonLines);
|
|
1027
|
+
}
|
|
1028
|
+
if (timeoutLine) {
|
|
1029
|
+
lines.push(timeoutLine);
|
|
1030
|
+
}
|
|
1031
|
+
if (warningLine) {
|
|
1032
|
+
lines.push(warningLine);
|
|
1033
|
+
}
|
|
1034
|
+
return lines;
|
|
1035
|
+
},
|
|
1036
|
+
invalidate: () => {},
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
const displayOutput = expanded ? (fullOutput ?? output) : output;
|
|
1041
|
+
const combinedOutput = [displayOutput, ...jsonLines].filter(Boolean).join("\n");
|
|
1042
|
+
|
|
1043
|
+
const statusEvents = details?.statusEvents ?? [];
|
|
1044
|
+
const statusLines = renderStatusEvents(statusEvents, uiTheme, expanded);
|
|
1045
|
+
|
|
688
1046
|
if (!combinedOutput && statusLines.length === 0) {
|
|
689
1047
|
const lines = [timeoutLine, warningLine].filter(Boolean) as string[];
|
|
690
1048
|
return new Text(lines.join("\n"), 0, 0);
|
|
691
1049
|
}
|
|
692
1050
|
|
|
693
|
-
// If only status events (no text output), show them directly
|
|
694
1051
|
if (!combinedOutput && statusLines.length > 0) {
|
|
695
1052
|
const lines = [...statusLines, timeoutLine, warningLine].filter(Boolean) as string[];
|
|
696
1053
|
return new Text(lines.join("\n"), 0, 0);
|
|
@@ -733,7 +1090,6 @@ export const pythonToolRenderer = {
|
|
|
733
1090
|
outputLines.push(truncateToWidth(skippedLine, width, uiTheme.fg("dim", uiTheme.format.ellipsis)));
|
|
734
1091
|
}
|
|
735
1092
|
outputLines.push(...cachedLines);
|
|
736
|
-
// Add status events below the output
|
|
737
1093
|
for (const statusLine of statusLines) {
|
|
738
1094
|
outputLines.push(truncateToWidth(statusLine, width, uiTheme.fg("dim", uiTheme.format.ellipsis)));
|
|
739
1095
|
}
|
|
@@ -752,4 +1108,6 @@ export const pythonToolRenderer = {
|
|
|
752
1108
|
},
|
|
753
1109
|
};
|
|
754
1110
|
},
|
|
1111
|
+
mergeCallAndResult: true,
|
|
1112
|
+
inline: true,
|
|
755
1113
|
};
|
|
@@ -16,7 +16,7 @@ import { checkPythonKernelAvailability } from "../../python-kernel";
|
|
|
16
16
|
import type { ToolSession } from "..";
|
|
17
17
|
import { LspTool } from "../lsp/index";
|
|
18
18
|
import type { LspParams } from "../lsp/types";
|
|
19
|
-
import { PythonTool } from "../python";
|
|
19
|
+
import { PythonTool, type PythonToolParams } from "../python";
|
|
20
20
|
import { subprocessToolRegistry } from "./subprocess-tool-registry";
|
|
21
21
|
import {
|
|
22
22
|
type AgentDefinition,
|
|
@@ -789,11 +789,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
|
|
789
789
|
const timeoutSignal = createTimeoutSignal(timeoutMs);
|
|
790
790
|
const combinedSignal = combineSignals([signal, callController.signal, timeoutSignal]);
|
|
791
791
|
try {
|
|
792
|
-
const result = await pythonTool.execute(
|
|
793
|
-
request.callId,
|
|
794
|
-
request.params as { code: string; timeout?: number; workdir?: string; reset?: boolean },
|
|
795
|
-
combinedSignal,
|
|
796
|
-
);
|
|
792
|
+
const result = await pythonTool.execute(request.callId, request.params as PythonToolParams, combinedSignal);
|
|
797
793
|
postMessageSafe({
|
|
798
794
|
type: "python_tool_result",
|
|
799
795
|
callId: request.callId,
|