@oh-my-pi/pi-coding-agent 6.8.4 → 6.8.5
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 +11 -0
- package/package.json +6 -6
- package/src/core/python-executor.ts +6 -10
- package/src/core/streaming-output.ts +10 -19
- package/src/core/tools/python.ts +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [6.8.5] - 2026-01-21
|
|
6
|
+
### Breaking Changes
|
|
7
|
+
|
|
8
|
+
- Changed timeout parameter from seconds to milliseconds in Python tool
|
|
9
|
+
- Updated PythonExecutorOptions interface to use timeoutMs instead of timeout
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Updated default timeout to 30000ms (30 seconds) for Python tool
|
|
14
|
+
- Improved streaming output handling and buffer management
|
|
15
|
+
|
|
5
16
|
## [6.8.4] - 2026-01-21
|
|
6
17
|
### Changed
|
|
7
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "6.8.
|
|
3
|
+
"version": "6.8.5",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"ompConfig": {
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"prepublishOnly": "bun run generate-template && bun run clean && bun run build"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@oh-my-pi/pi-agent-core": "6.8.
|
|
44
|
-
"@oh-my-pi/pi-ai": "6.8.
|
|
45
|
-
"@oh-my-pi/pi-git-tool": "6.8.
|
|
46
|
-
"@oh-my-pi/pi-tui": "6.8.
|
|
47
|
-
"@oh-my-pi/pi-utils": "6.8.
|
|
43
|
+
"@oh-my-pi/pi-agent-core": "6.8.5",
|
|
44
|
+
"@oh-my-pi/pi-ai": "6.8.5",
|
|
45
|
+
"@oh-my-pi/pi-git-tool": "6.8.5",
|
|
46
|
+
"@oh-my-pi/pi-tui": "6.8.5",
|
|
47
|
+
"@oh-my-pi/pi-utils": "6.8.5",
|
|
48
48
|
"@openai/agents": "^0.3.7",
|
|
49
49
|
"@sinclair/typebox": "^0.34.46",
|
|
50
50
|
"ajv": "^8.17.1",
|
|
@@ -14,9 +14,9 @@ export interface PythonExecutorOptions {
|
|
|
14
14
|
/** Working directory for command execution */
|
|
15
15
|
cwd?: string;
|
|
16
16
|
/** Timeout in milliseconds */
|
|
17
|
-
|
|
17
|
+
timeoutMs?: number;
|
|
18
18
|
/** Callback for streaming output chunks (already sanitized) */
|
|
19
|
-
onChunk?: (chunk: string) => void;
|
|
19
|
+
onChunk?: (chunk: string) => Promise<void> | void;
|
|
20
20
|
/** AbortSignal for cancellation */
|
|
21
21
|
signal?: AbortSignal;
|
|
22
22
|
/** Session identifier for kernel reuse */
|
|
@@ -216,17 +216,13 @@ async function executeWithKernel(
|
|
|
216
216
|
try {
|
|
217
217
|
const result = await kernel.execute(code, {
|
|
218
218
|
signal: options?.signal,
|
|
219
|
-
timeoutMs: options?.
|
|
220
|
-
onChunk: (text) =>
|
|
221
|
-
|
|
222
|
-
},
|
|
223
|
-
onDisplay: (output) => {
|
|
224
|
-
displayOutputs.push(output);
|
|
225
|
-
},
|
|
219
|
+
timeoutMs: options?.timeoutMs,
|
|
220
|
+
onChunk: (text) => sink.push(text),
|
|
221
|
+
onDisplay: (output) => void displayOutputs.push(output),
|
|
226
222
|
});
|
|
227
223
|
|
|
228
224
|
if (result.cancelled) {
|
|
229
|
-
const secs = options?.
|
|
225
|
+
const secs = options?.timeoutMs ? Math.round(options.timeoutMs / 1000) : undefined;
|
|
230
226
|
const annotation =
|
|
231
227
|
result.timedOut && secs !== undefined ? `Command timed out after ${secs} seconds` : undefined;
|
|
232
228
|
return {
|
|
@@ -33,8 +33,6 @@ export class OutputSink {
|
|
|
33
33
|
path: string;
|
|
34
34
|
sink: Bun.FileSink;
|
|
35
35
|
};
|
|
36
|
-
#bytesWritten: number = 0;
|
|
37
|
-
#pending: Promise<void> = Promise.resolve();
|
|
38
36
|
|
|
39
37
|
readonly #allocateFilePath: () => string;
|
|
40
38
|
readonly #spillThreshold: number;
|
|
@@ -54,15 +52,16 @@ export class OutputSink {
|
|
|
54
52
|
|
|
55
53
|
async #pushSanitized(data: string): Promise<void> {
|
|
56
54
|
this.#onChunk?.(data);
|
|
57
|
-
|
|
58
|
-
const
|
|
55
|
+
|
|
56
|
+
const bufferOverflow = data.length + this.#buffer.length > this.#spillThreshold;
|
|
57
|
+
const overflow = this.#file || bufferOverflow;
|
|
59
58
|
|
|
60
59
|
const sink = overflow ? await this.#fileSink() : null;
|
|
61
60
|
|
|
62
61
|
this.#buffer += data;
|
|
63
62
|
await sink?.write(data);
|
|
64
63
|
|
|
65
|
-
if (
|
|
64
|
+
if (bufferOverflow) {
|
|
66
65
|
this.#buffer = this.#buffer.slice(-this.#spillThreshold);
|
|
67
66
|
}
|
|
68
67
|
}
|
|
@@ -81,28 +80,21 @@ export class OutputSink {
|
|
|
81
80
|
|
|
82
81
|
async push(chunk: string): Promise<void> {
|
|
83
82
|
chunk = sanitizeText(chunk);
|
|
84
|
-
|
|
85
|
-
this.#pending = op.catch(() => {});
|
|
86
|
-
await op;
|
|
83
|
+
await this.#pushSanitized(chunk);
|
|
87
84
|
}
|
|
88
85
|
|
|
89
86
|
createInput(): WritableStream<Uint8Array | string> {
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
const dec = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
88
|
+
const finalize = async () => {
|
|
89
|
+
await this.push(dec.decode());
|
|
90
|
+
};
|
|
92
91
|
|
|
93
92
|
return new WritableStream<Uint8Array | string>({
|
|
94
93
|
write: async (chunk) => {
|
|
95
94
|
if (typeof chunk === "string") {
|
|
96
95
|
await this.push(chunk);
|
|
97
96
|
} else {
|
|
98
|
-
|
|
99
|
-
const dec = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
100
|
-
decoder = dec;
|
|
101
|
-
finalize = async () => {
|
|
102
|
-
await this.push(dec.decode());
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
await this.push(decoder.decode(chunk, { stream: true }));
|
|
97
|
+
await this.push(dec.decode(chunk, { stream: true }));
|
|
106
98
|
}
|
|
107
99
|
},
|
|
108
100
|
close: finalize,
|
|
@@ -111,7 +103,6 @@ export class OutputSink {
|
|
|
111
103
|
}
|
|
112
104
|
|
|
113
105
|
async dump(notice?: string): Promise<OutputResult> {
|
|
114
|
-
await this.#pending;
|
|
115
106
|
const noticeLine = notice ? `[${notice}]\n` : "";
|
|
116
107
|
|
|
117
108
|
if (this.#file) {
|
package/src/core/tools/python.ts
CHANGED
|
@@ -40,7 +40,7 @@ function groupPreludeHelpers(helpers: PreludeHelper[]): PreludeCategory[] {
|
|
|
40
40
|
|
|
41
41
|
export const pythonSchema = Type.Object({
|
|
42
42
|
code: Type.String({ description: "Python code to execute" }),
|
|
43
|
-
|
|
43
|
+
timeoutMs: Type.Optional(Type.Number({ description: "Timeout in milliseconds (default: 30000)" })),
|
|
44
44
|
workdir: Type.Optional(
|
|
45
45
|
Type.String({ description: "Working directory for the command (default: current directory)" }),
|
|
46
46
|
),
|
|
@@ -151,7 +151,7 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
151
151
|
throw new Error("Python tool requires a session when not using proxy executor");
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
const { code,
|
|
154
|
+
const { code, timeoutMs = 30000, workdir, reset } = params;
|
|
155
155
|
const controller = new AbortController();
|
|
156
156
|
const onAbort = () => controller.abort();
|
|
157
157
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -182,7 +182,7 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
182
182
|
const sessionId = sessionFile ? `session:${sessionFile}:workdir:${commandCwd}` : `cwd:${commandCwd}`;
|
|
183
183
|
const executorOptions: PythonExecutorOptions = {
|
|
184
184
|
cwd: commandCwd,
|
|
185
|
-
|
|
185
|
+
timeoutMs,
|
|
186
186
|
signal: controller.signal,
|
|
187
187
|
sessionId,
|
|
188
188
|
kernelMode: this.session.settings?.getPythonKernelMode?.() ?? "session",
|