@oh-my-pi/pi-coding-agent 11.6.1 → 11.7.0
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
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [11.7.0] - 2026-02-07
|
|
6
|
+
### Changed
|
|
7
|
+
|
|
8
|
+
- Enhanced error messages for failed Python cells to include full combined output context instead of just the error message
|
|
9
|
+
- Updated error cell output styling to use error color theme instead of standard tool output color for better visual distinction
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Improved error handling in Python cell execution to preserve and display combined output from previous cells when an error occurs
|
|
14
|
+
- Fixed tab character rendering in Python tool output display to properly format whitespace in cell output and status events
|
|
15
|
+
|
|
5
16
|
## [11.6.1] - 2026-02-07
|
|
6
17
|
### Fixed
|
|
7
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.7.0",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"ompConfig": {
|
|
@@ -90,12 +90,12 @@
|
|
|
90
90
|
"@mozilla/readability": "0.6.0",
|
|
91
91
|
"@oclif/core": "^4.8.0",
|
|
92
92
|
"@oclif/plugin-autocomplete": "^3.2.40",
|
|
93
|
-
"@oh-my-pi/omp-stats": "11.
|
|
94
|
-
"@oh-my-pi/pi-agent-core": "11.
|
|
95
|
-
"@oh-my-pi/pi-ai": "11.
|
|
96
|
-
"@oh-my-pi/pi-natives": "11.
|
|
97
|
-
"@oh-my-pi/pi-tui": "11.
|
|
98
|
-
"@oh-my-pi/pi-utils": "11.
|
|
93
|
+
"@oh-my-pi/omp-stats": "11.7.0",
|
|
94
|
+
"@oh-my-pi/pi-agent-core": "11.7.0",
|
|
95
|
+
"@oh-my-pi/pi-ai": "11.7.0",
|
|
96
|
+
"@oh-my-pi/pi-natives": "11.7.0",
|
|
97
|
+
"@oh-my-pi/pi-tui": "11.7.0",
|
|
98
|
+
"@oh-my-pi/pi-utils": "11.7.0",
|
|
99
99
|
"@sinclair/typebox": "^0.34.48",
|
|
100
100
|
"ajv": "^8.17.1",
|
|
101
101
|
"chalk": "^5.6.2",
|
|
@@ -454,6 +454,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
454
454
|
private async loadTodoList(): Promise<void> {
|
|
455
455
|
const sessionFile = this.sessionManager.getSessionFile() ?? null;
|
|
456
456
|
if (!sessionFile) {
|
|
457
|
+
this.todoItems = [];
|
|
457
458
|
this.renderTodoList();
|
|
458
459
|
return;
|
|
459
460
|
}
|
|
@@ -463,9 +464,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
463
464
|
const data = (await Bun.file(todoPath).json()) as { todos?: TodoItem[] };
|
|
464
465
|
if (data?.todos && Array.isArray(data.todos)) {
|
|
465
466
|
this.todoItems = data.todos;
|
|
467
|
+
} else {
|
|
468
|
+
this.todoItems = [];
|
|
466
469
|
}
|
|
467
470
|
} catch (error) {
|
|
468
471
|
if (isEnoent(error)) {
|
|
472
|
+
this.todoItems = [];
|
|
469
473
|
this.renderTodoList();
|
|
470
474
|
return;
|
|
471
475
|
}
|
package/src/modes/theme/theme.ts
CHANGED
|
@@ -184,242 +184,149 @@ export type SymbolKey =
|
|
|
184
184
|
type SymbolMap = Record<SymbolKey, string>;
|
|
185
185
|
|
|
186
186
|
const UNICODE_SYMBOLS: SymbolMap = {
|
|
187
|
-
// Status
|
|
188
|
-
|
|
189
|
-
"status.
|
|
190
|
-
// pick: ✗ | alt: ✘ ✖ ❌ ⨯
|
|
191
|
-
"status.error": "✗",
|
|
192
|
-
// pick: ⚠ | alt: ‼ ⁉ ▲ △
|
|
187
|
+
// Status
|
|
188
|
+
"status.success": "✔",
|
|
189
|
+
"status.error": "✘",
|
|
193
190
|
"status.warning": "⚠",
|
|
194
|
-
|
|
195
|
-
"status.
|
|
196
|
-
|
|
197
|
-
"status.pending": "◔",
|
|
198
|
-
// pick: ○ | alt: ◌ ◯ ⃠
|
|
199
|
-
"status.disabled": "○",
|
|
200
|
-
// pick: ● | alt: ◉ ◎ ⬤
|
|
191
|
+
"status.info": "ⓘ",
|
|
192
|
+
"status.pending": "⏳",
|
|
193
|
+
"status.disabled": "⦸",
|
|
201
194
|
"status.enabled": "●",
|
|
202
|
-
|
|
203
|
-
"status.
|
|
204
|
-
|
|
205
|
-
"status.shadowed": "◐",
|
|
206
|
-
// pick: ⊗ | alt: ⊘ ⛔ ⏹ ⨂
|
|
207
|
-
"status.aborted": "⊗",
|
|
195
|
+
"status.running": "⟳",
|
|
196
|
+
"status.shadowed": "◌",
|
|
197
|
+
"status.aborted": "⏹",
|
|
208
198
|
// Navigation
|
|
209
|
-
// pick: ❯ | alt: › ▸ ▹
|
|
210
199
|
"nav.cursor": "❯",
|
|
211
|
-
|
|
212
|
-
"nav.selected": "➜",
|
|
213
|
-
// pick: ▸ | alt: ▶ ▹ ⯈
|
|
200
|
+
"nav.selected": "➤",
|
|
214
201
|
"nav.expand": "▸",
|
|
215
|
-
// pick: ▾ | alt: ▼ ▽ ⯆
|
|
216
202
|
"nav.collapse": "▾",
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// Tree Connectors
|
|
220
|
-
// pick: ├─ | alt: ├╴ ├╌ ├┄ ╠═
|
|
203
|
+
"nav.back": "⟵",
|
|
204
|
+
// Tree
|
|
221
205
|
"tree.branch": "├─",
|
|
222
|
-
// pick: └─ | alt: └╴ └╌ └┄ ╚═
|
|
223
206
|
"tree.last": "└─",
|
|
224
|
-
// pick: │ | alt: ┃ ║ ▏ ▕
|
|
225
207
|
"tree.vertical": "│",
|
|
226
|
-
// pick: ─ | alt: ━ ═ ╌ ┄
|
|
227
208
|
"tree.horizontal": "─",
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// Box Drawing - Rounded
|
|
231
|
-
// pick: ╭ | alt: ┌ ┏ ╔
|
|
209
|
+
"tree.hook": "└",
|
|
210
|
+
// Box (rounded)
|
|
232
211
|
"boxRound.topLeft": "╭",
|
|
233
|
-
// pick: ╮ | alt: ┐ ┓ ╗
|
|
234
212
|
"boxRound.topRight": "╮",
|
|
235
|
-
// pick: ╰ | alt: └ ┗ ╚
|
|
236
213
|
"boxRound.bottomLeft": "╰",
|
|
237
|
-
// pick: ╯ | alt: ┘ ┛ ╝
|
|
238
214
|
"boxRound.bottomRight": "╯",
|
|
239
|
-
// pick: ─ | alt: ━ ═ ╌
|
|
240
215
|
"boxRound.horizontal": "─",
|
|
241
|
-
// pick: │ | alt: ┃ ║ ▏
|
|
242
216
|
"boxRound.vertical": "│",
|
|
243
|
-
// Box
|
|
244
|
-
// pick: ┌ | alt: ┏ ╭ ╔
|
|
217
|
+
// Box (sharp)
|
|
245
218
|
"boxSharp.topLeft": "┌",
|
|
246
|
-
// pick: ┐ | alt: ┓ ╮ ╗
|
|
247
219
|
"boxSharp.topRight": "┐",
|
|
248
|
-
// pick: └ | alt: ┗ ╰ ╚
|
|
249
220
|
"boxSharp.bottomLeft": "└",
|
|
250
|
-
// pick: ┘ | alt: ┛ ╯ ╝
|
|
251
221
|
"boxSharp.bottomRight": "┘",
|
|
252
|
-
// pick: ─ | alt: ━ ═ ╌
|
|
253
222
|
"boxSharp.horizontal": "─",
|
|
254
|
-
// pick: │ | alt: ┃ ║ ▏
|
|
255
223
|
"boxSharp.vertical": "│",
|
|
256
|
-
// pick: ┼ | alt: ╋ ╬ ┿
|
|
257
224
|
"boxSharp.cross": "┼",
|
|
258
|
-
// pick: ┬ | alt: ╦ ┯ ┳
|
|
259
225
|
"boxSharp.teeDown": "┬",
|
|
260
|
-
// pick: ┴ | alt: ╩ ┷ ┻
|
|
261
226
|
"boxSharp.teeUp": "┴",
|
|
262
|
-
// pick: ├ | alt: ╠ ┝ ┣
|
|
263
227
|
"boxSharp.teeRight": "├",
|
|
264
|
-
// pick: ┤ | alt: ╣ ┥ ┫
|
|
265
228
|
"boxSharp.teeLeft": "┤",
|
|
266
|
-
// Separators
|
|
267
|
-
|
|
268
|
-
"sep.
|
|
269
|
-
|
|
270
|
-
"sep.
|
|
271
|
-
// pick: > | alt: › ▸ »
|
|
272
|
-
"sep.powerlineLeft": ">",
|
|
273
|
-
// pick: < | alt: ‹ ◂ «
|
|
274
|
-
"sep.powerlineRight": "<",
|
|
275
|
-
// pick: > | alt: › ▸
|
|
229
|
+
// Separators (powerline-ish, but pure Unicode)
|
|
230
|
+
"sep.powerline": "▕",
|
|
231
|
+
"sep.powerlineThin": "┆",
|
|
232
|
+
"sep.powerlineLeft": "▶",
|
|
233
|
+
"sep.powerlineRight": "◀",
|
|
276
234
|
"sep.powerlineThinLeft": ">",
|
|
277
|
-
// pick: < | alt: ‹ ◂
|
|
278
235
|
"sep.powerlineThinRight": "<",
|
|
279
|
-
|
|
280
|
-
"sep.block": "█",
|
|
281
|
-
// pick: space | alt: ␠ ·
|
|
236
|
+
"sep.block": "▌",
|
|
282
237
|
"sep.space": " ",
|
|
283
|
-
// pick: > | alt: › » ▸
|
|
284
238
|
"sep.asciiLeft": ">",
|
|
285
|
-
// pick: < | alt: ‹ « ◂
|
|
286
239
|
"sep.asciiRight": "<",
|
|
287
|
-
// pick: · | alt: • ⋅
|
|
288
240
|
"sep.dot": " · ",
|
|
289
|
-
// pick: / | alt: / ∕ ⁄
|
|
290
241
|
"sep.slash": " / ",
|
|
291
|
-
|
|
292
|
-
"sep.pipe": " | ",
|
|
242
|
+
"sep.pipe": " │ ",
|
|
293
243
|
// Icons
|
|
294
|
-
|
|
295
|
-
"icon.
|
|
296
|
-
// pick: 📋 | alt: 🗒 📝
|
|
297
|
-
"icon.plan": "📋",
|
|
298
|
-
// pick: 📁 | alt: 📂 🗂 🗃
|
|
244
|
+
"icon.model": "⬢",
|
|
245
|
+
"icon.plan": "🗺",
|
|
299
246
|
"icon.folder": "📁",
|
|
300
|
-
// pick: 📄 | alt: 📃 📝
|
|
301
247
|
"icon.file": "📄",
|
|
302
|
-
// pick: ⎇ | alt: 🔀 ⑂
|
|
303
248
|
"icon.git": "⎇",
|
|
304
|
-
|
|
305
|
-
"icon.
|
|
306
|
-
// pick: ⊛ | alt: ◎ ◍ ⊙
|
|
307
|
-
"icon.tokens": "⊛",
|
|
308
|
-
// pick: ◫ | alt: ◧ ▣ ▦
|
|
249
|
+
"icon.branch": "⑂",
|
|
250
|
+
"icon.tokens": "🪙",
|
|
309
251
|
"icon.context": "◫",
|
|
310
|
-
|
|
311
|
-
"icon.
|
|
312
|
-
// pick: ◷ | alt: ⏱ ⏲ ⌛
|
|
313
|
-
"icon.time": "◷",
|
|
314
|
-
// pick: π | alt: ∏ ∑
|
|
252
|
+
"icon.cost": "💲",
|
|
253
|
+
"icon.time": "⏱",
|
|
315
254
|
"icon.pi": "π",
|
|
316
|
-
|
|
317
|
-
"icon.
|
|
318
|
-
|
|
319
|
-
"icon.
|
|
320
|
-
|
|
321
|
-
"icon.
|
|
322
|
-
// pick: out: | alt: ⤴ ↱
|
|
323
|
-
"icon.output": "out:",
|
|
324
|
-
// pick: host | alt: 🖥 💻
|
|
325
|
-
"icon.host": "host",
|
|
326
|
-
// pick: id | alt: 🧭 🧩
|
|
327
|
-
"icon.session": "id",
|
|
328
|
-
// pick: 📦 | alt: 🧰
|
|
255
|
+
"icon.agents": "👥",
|
|
256
|
+
"icon.cache": "💾",
|
|
257
|
+
"icon.input": "⤵",
|
|
258
|
+
"icon.output": "⤴",
|
|
259
|
+
"icon.host": "🖥",
|
|
260
|
+
"icon.session": "🆔",
|
|
329
261
|
"icon.package": "📦",
|
|
330
|
-
// pick: ⚠ | alt: ❗
|
|
331
262
|
"icon.warning": "⚠",
|
|
332
|
-
|
|
333
|
-
"icon.
|
|
334
|
-
|
|
335
|
-
"icon.
|
|
336
|
-
|
|
337
|
-
"icon.
|
|
338
|
-
|
|
339
|
-
"icon.
|
|
340
|
-
|
|
341
|
-
"icon.
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
"
|
|
346
|
-
|
|
347
|
-
"
|
|
348
|
-
|
|
349
|
-
"icon.extensionPrompt": "PR",
|
|
350
|
-
// pick: CF | alt: 📄 📎
|
|
351
|
-
"icon.extensionContextFile": "CF",
|
|
352
|
-
// pick: IN | alt: 📘 ℹ
|
|
353
|
-
"icon.extensionInstruction": "IN",
|
|
354
|
-
// Thinking Levels
|
|
355
|
-
// pick: [min] | alt: · ◔ min
|
|
356
|
-
"thinking.minimal": "[min]",
|
|
357
|
-
// pick: [low] | alt: ◑ low ▪ low
|
|
358
|
-
"thinking.low": "[low]",
|
|
359
|
-
// pick: [med] | alt: ◒ med ▪ med
|
|
360
|
-
"thinking.medium": "[med]",
|
|
361
|
-
// pick: [high] | alt: ◕ high ▪ high
|
|
362
|
-
"thinking.high": "[high]",
|
|
363
|
-
// pick: [xhi] | alt: ◉ xhi ▪ xhi
|
|
364
|
-
"thinking.xhigh": "[xhi]",
|
|
263
|
+
"icon.rewind": "↶",
|
|
264
|
+
"icon.auto": "⟲",
|
|
265
|
+
"icon.extensionSkill": "✦",
|
|
266
|
+
"icon.extensionTool": "🛠",
|
|
267
|
+
"icon.extensionSlashCommand": "⌘",
|
|
268
|
+
"icon.extensionMcp": "🔌",
|
|
269
|
+
"icon.extensionRule": "⚖",
|
|
270
|
+
"icon.extensionHook": "🪝",
|
|
271
|
+
"icon.extensionPrompt": "✎",
|
|
272
|
+
"icon.extensionContextFile": "📎",
|
|
273
|
+
"icon.extensionInstruction": "📘",
|
|
274
|
+
// Thinking levels
|
|
275
|
+
"thinking.minimal": "◔ min",
|
|
276
|
+
"thinking.low": "◑ low",
|
|
277
|
+
"thinking.medium": "◒ med",
|
|
278
|
+
"thinking.high": "◕ high",
|
|
279
|
+
"thinking.xhigh": "◉ xhi",
|
|
365
280
|
// Checkboxes
|
|
366
|
-
// pick: ☑ | alt: ✓ ✔ ✅
|
|
367
281
|
"checkbox.checked": "☑",
|
|
368
|
-
// pick: ☐ | alt: □ ▢
|
|
369
282
|
"checkbox.unchecked": "☐",
|
|
370
|
-
//
|
|
283
|
+
// Formatting
|
|
371
284
|
"format.bullet": "•",
|
|
372
|
-
|
|
373
|
-
"format.
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
"format.bracketRight": "⟩",
|
|
378
|
-
// Markdown-specific
|
|
379
|
-
// pick: │ | alt: ┃ ║
|
|
380
|
-
"md.quoteBorder": "│",
|
|
381
|
-
// pick: ─ | alt: ━ ═
|
|
285
|
+
"format.dash": "—",
|
|
286
|
+
"format.bracketLeft": "⟦",
|
|
287
|
+
"format.bracketRight": "⟧",
|
|
288
|
+
// Markdown
|
|
289
|
+
"md.quoteBorder": "▏",
|
|
382
290
|
"md.hrChar": "─",
|
|
383
|
-
// pick: • | alt: · ▪ ◦
|
|
384
291
|
"md.bullet": "•",
|
|
385
|
-
// Language icons (
|
|
386
|
-
"lang.default": "
|
|
387
|
-
"lang.typescript": "
|
|
388
|
-
"lang.javascript": "
|
|
389
|
-
"lang.python": "
|
|
390
|
-
"lang.rust": "
|
|
391
|
-
"lang.go": "
|
|
392
|
-
"lang.java": "
|
|
393
|
-
"lang.c": "
|
|
394
|
-
"lang.cpp": "
|
|
395
|
-
"lang.csharp": "
|
|
396
|
-
"lang.ruby": "
|
|
397
|
-
"lang.php": "
|
|
398
|
-
"lang.swift": "
|
|
399
|
-
"lang.kotlin": "
|
|
400
|
-
"lang.shell": "
|
|
401
|
-
"lang.html": "
|
|
402
|
-
"lang.css": "
|
|
403
|
-
"lang.json": "
|
|
404
|
-
"lang.yaml": "
|
|
405
|
-
"lang.markdown": "
|
|
406
|
-
"lang.sql": "
|
|
407
|
-
"lang.docker": "
|
|
408
|
-
"lang.lua": "
|
|
409
|
-
"lang.text": "
|
|
410
|
-
"lang.env": "
|
|
411
|
-
"lang.toml": "
|
|
412
|
-
"lang.xml": "
|
|
413
|
-
"lang.ini": "
|
|
414
|
-
"lang.conf": "
|
|
415
|
-
"lang.log": "
|
|
416
|
-
"lang.csv": "
|
|
417
|
-
"lang.tsv": "
|
|
418
|
-
"lang.image": "
|
|
419
|
-
"lang.pdf": "
|
|
420
|
-
"lang.archive": "
|
|
421
|
-
"lang.binary": "
|
|
422
|
-
// Settings
|
|
292
|
+
// Language/file icons (emoji-centric, no Nerd Font required)
|
|
293
|
+
"lang.default": "⌘",
|
|
294
|
+
"lang.typescript": "🟦",
|
|
295
|
+
"lang.javascript": "🟨",
|
|
296
|
+
"lang.python": "🐍",
|
|
297
|
+
"lang.rust": "🦀",
|
|
298
|
+
"lang.go": "🐹",
|
|
299
|
+
"lang.java": "☕",
|
|
300
|
+
"lang.c": "Ⓒ",
|
|
301
|
+
"lang.cpp": "➕",
|
|
302
|
+
"lang.csharp": "♯",
|
|
303
|
+
"lang.ruby": "💎",
|
|
304
|
+
"lang.php": "🐘",
|
|
305
|
+
"lang.swift": "🕊",
|
|
306
|
+
"lang.kotlin": "🅺",
|
|
307
|
+
"lang.shell": "💻",
|
|
308
|
+
"lang.html": "🌐",
|
|
309
|
+
"lang.css": "🎨",
|
|
310
|
+
"lang.json": "🧾",
|
|
311
|
+
"lang.yaml": "📋",
|
|
312
|
+
"lang.markdown": "📝",
|
|
313
|
+
"lang.sql": "🗄",
|
|
314
|
+
"lang.docker": "🐳",
|
|
315
|
+
"lang.lua": "🌙",
|
|
316
|
+
"lang.text": "🗒",
|
|
317
|
+
"lang.env": "🔧",
|
|
318
|
+
"lang.toml": "🧾",
|
|
319
|
+
"lang.xml": "⟨⟩",
|
|
320
|
+
"lang.ini": "⚙",
|
|
321
|
+
"lang.conf": "⚙",
|
|
322
|
+
"lang.log": "📜",
|
|
323
|
+
"lang.csv": "📑",
|
|
324
|
+
"lang.tsv": "📑",
|
|
325
|
+
"lang.image": "🖼",
|
|
326
|
+
"lang.pdf": "📕",
|
|
327
|
+
"lang.archive": "🗜",
|
|
328
|
+
"lang.binary": "⚙",
|
|
329
|
+
// Settings tabs
|
|
423
330
|
"tab.display": "🎨",
|
|
424
331
|
"tab.agent": "🤖",
|
|
425
332
|
"tab.input": "⌨",
|
|
@@ -846,7 +753,7 @@ export type SpinnerType = "status" | "activity";
|
|
|
846
753
|
|
|
847
754
|
const SPINNER_FRAMES: Record<SymbolPreset, Record<SpinnerType, string[]>> = {
|
|
848
755
|
unicode: {
|
|
849
|
-
status: ["
|
|
756
|
+
status: ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"],
|
|
850
757
|
activity: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
|
|
851
758
|
},
|
|
852
759
|
nerd: {
|
|
@@ -179,6 +179,7 @@ Continue non-destructively; someone's work may live there.
|
|
|
179
179
|
- Ask for parameters only when required; otherwise choose safe defaults, state them.
|
|
180
180
|
- Non-trivial logic: define test first when feasible.
|
|
181
181
|
- Algorithmic work: start naive correct version before optimizing.
|
|
182
|
+
- **Formatting is a batch operation, not per-edit cleanup.** Never fix indentation or style issues one edit at a time. Make all semantic changes first, then run the project's formatter once at the end. One command beats twenty whitespace edits.
|
|
182
183
|
|
|
183
184
|
## Integration
|
|
184
185
|
- AGENTS.md defines local law; nearest wins, deeper overrides higher.
|
|
@@ -48,7 +48,7 @@ Returns success/failure; on failure, error message indicates:
|
|
|
48
48
|
- Never use anchors as comments (no line numbers, location labels, placeholders like `@@ @@`)
|
|
49
49
|
- Do not place new lines outside intended block
|
|
50
50
|
- If edit fails or breaks structure, re-read file and produce new patch from current content—do not retry same diff
|
|
51
|
-
- **NEVER** use edit to fix indentation or reformat code
|
|
51
|
+
- **NEVER** use edit to fix indentation, whitespace, or reformat code. Formatting is a single command run once at the end (`bun fmt`, `cargo fmt`, `prettier --write`, etc.)—not N individual edits. If you see inconsistent indentation after an edit, leave it; the formatter will fix all of it in one pass.
|
|
52
52
|
</critical>
|
|
53
53
|
|
|
54
54
|
<example name="create">
|
package/src/tools/python.ts
CHANGED
|
@@ -17,7 +17,7 @@ import type { ToolSession } from ".";
|
|
|
17
17
|
import type { OutputMeta } from "./output-meta";
|
|
18
18
|
import { allocateOutputArtifact, createTailBuffer } from "./output-utils";
|
|
19
19
|
import { resolveToCwd } from "./path-utils";
|
|
20
|
-
import { shortenPath, ToolUIKit, truncateToWidth } from "./render-utils";
|
|
20
|
+
import { replaceTabs, shortenPath, ToolUIKit, truncateToWidth } from "./render-utils";
|
|
21
21
|
import { ToolAbortError, ToolError } from "./tool-errors";
|
|
22
22
|
import { toolResult } from "./tool-result";
|
|
23
23
|
import { DEFAULT_MAX_BYTES } from "./truncate";
|
|
@@ -341,18 +341,93 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
|
|
|
341
341
|
cellResult.status = "error";
|
|
342
342
|
pushUpdate();
|
|
343
343
|
const errorMsg = result.output || "Command aborted";
|
|
344
|
-
|
|
344
|
+
const combinedOutput = cellOutputs.join("\n\n");
|
|
345
|
+
const outputText =
|
|
346
|
+
cells.length > 1
|
|
347
|
+
? `${combinedOutput}\n\nCell ${i + 1} aborted: ${errorMsg}`
|
|
348
|
+
: combinedOutput || errorMsg;
|
|
349
|
+
|
|
350
|
+
const rawSummary = (await finalizeOutput()) ?? {
|
|
351
|
+
output: "",
|
|
352
|
+
truncated: false,
|
|
353
|
+
totalLines: 0,
|
|
354
|
+
totalBytes: 0,
|
|
355
|
+
outputLines: 0,
|
|
356
|
+
outputBytes: 0,
|
|
357
|
+
};
|
|
358
|
+
const outputLines = combinedOutput.length > 0 ? combinedOutput.split("\n").length : 0;
|
|
359
|
+
const outputBytes = Buffer.byteLength(combinedOutput, "utf-8");
|
|
360
|
+
const missingLines = Math.max(0, rawSummary.totalLines - rawSummary.outputLines);
|
|
361
|
+
const missingBytes = Math.max(0, rawSummary.totalBytes - rawSummary.outputBytes);
|
|
362
|
+
const summaryForMeta: OutputSummary = {
|
|
363
|
+
output: combinedOutput,
|
|
364
|
+
truncated: rawSummary.truncated,
|
|
365
|
+
totalLines: outputLines + missingLines,
|
|
366
|
+
totalBytes: outputBytes + missingBytes,
|
|
367
|
+
outputLines,
|
|
368
|
+
outputBytes,
|
|
369
|
+
artifactId: rawSummary.artifactId,
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
const details: PythonToolDetails = {
|
|
373
|
+
cells: cellResults,
|
|
374
|
+
jsonOutputs: jsonOutputs.length > 0 ? jsonOutputs : undefined,
|
|
375
|
+
images: images.length > 0 ? images : undefined,
|
|
376
|
+
statusEvents: statusEvents.length > 0 ? statusEvents : undefined,
|
|
377
|
+
isError: true,
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
return toolResult(details)
|
|
381
|
+
.text(outputText)
|
|
382
|
+
.truncationFromSummary(summaryForMeta, { direction: "tail" })
|
|
383
|
+
.done();
|
|
345
384
|
}
|
|
346
385
|
|
|
347
386
|
if (result.exitCode !== 0 && result.exitCode !== undefined) {
|
|
348
387
|
cellResult.status = "error";
|
|
349
388
|
pushUpdate();
|
|
350
389
|
const combinedOutput = cellOutputs.join("\n\n");
|
|
351
|
-
|
|
390
|
+
const outputText =
|
|
352
391
|
cells.length > 1
|
|
353
392
|
? `${combinedOutput}\n\nCell ${i + 1} failed (exit code ${result.exitCode}). Earlier cells succeeded—their state persists. Fix only cell ${i + 1}.`
|
|
354
|
-
:
|
|
355
|
-
|
|
393
|
+
: combinedOutput
|
|
394
|
+
? `${combinedOutput}\n\nCommand exited with code ${result.exitCode}`
|
|
395
|
+
: `Command exited with code ${result.exitCode}`;
|
|
396
|
+
|
|
397
|
+
const rawSummary = (await finalizeOutput()) ?? {
|
|
398
|
+
output: "",
|
|
399
|
+
truncated: false,
|
|
400
|
+
totalLines: 0,
|
|
401
|
+
totalBytes: 0,
|
|
402
|
+
outputLines: 0,
|
|
403
|
+
outputBytes: 0,
|
|
404
|
+
};
|
|
405
|
+
const outputLines = combinedOutput.length > 0 ? combinedOutput.split("\n").length : 0;
|
|
406
|
+
const outputBytes = Buffer.byteLength(combinedOutput, "utf-8");
|
|
407
|
+
const missingLines = Math.max(0, rawSummary.totalLines - rawSummary.outputLines);
|
|
408
|
+
const missingBytes = Math.max(0, rawSummary.totalBytes - rawSummary.outputBytes);
|
|
409
|
+
const summaryForMeta: OutputSummary = {
|
|
410
|
+
output: combinedOutput,
|
|
411
|
+
truncated: rawSummary.truncated,
|
|
412
|
+
totalLines: outputLines + missingLines,
|
|
413
|
+
totalBytes: outputBytes + missingBytes,
|
|
414
|
+
outputLines,
|
|
415
|
+
outputBytes,
|
|
416
|
+
artifactId: rawSummary.artifactId,
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
const details: PythonToolDetails = {
|
|
420
|
+
cells: cellResults,
|
|
421
|
+
jsonOutputs: jsonOutputs.length > 0 ? jsonOutputs : undefined,
|
|
422
|
+
images: images.length > 0 ? images : undefined,
|
|
423
|
+
statusEvents: statusEvents.length > 0 ? statusEvents : undefined,
|
|
424
|
+
isError: true,
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
return toolResult(details)
|
|
428
|
+
.text(outputText)
|
|
429
|
+
.truncationFromSummary(summaryForMeta, { direction: "tail" })
|
|
430
|
+
.done();
|
|
356
431
|
}
|
|
357
432
|
|
|
358
433
|
cellResult.status = "complete";
|
|
@@ -627,7 +702,7 @@ function formatStatusEventExpanded(event: PythonStatusEvent, theme: Theme): stri
|
|
|
627
702
|
const addPreview = (preview: string, maxLines = 3) => {
|
|
628
703
|
const previewLines = String(preview).split("\n").slice(0, maxLines);
|
|
629
704
|
for (const line of previewLines) {
|
|
630
|
-
lines.push(` ${theme.fg("toolOutput", truncateToWidth(line, 80))}`);
|
|
705
|
+
lines.push(` ${theme.fg("toolOutput", truncateToWidth(replaceTabs(line), 80))}`);
|
|
631
706
|
}
|
|
632
707
|
const totalLines = String(preview).split("\n").length;
|
|
633
708
|
if (totalLines > maxLines) {
|
|
@@ -744,7 +819,10 @@ function formatCellOutputLines(
|
|
|
744
819
|
const rawLines = cell.output ? cell.output.split("\n") : [];
|
|
745
820
|
const displayLines = expanded ? rawLines : rawLines.slice(-previewLines);
|
|
746
821
|
const hiddenCount = rawLines.length - displayLines.length;
|
|
747
|
-
const outputLines = displayLines.map(line =>
|
|
822
|
+
const outputLines = displayLines.map(line => {
|
|
823
|
+
const cleaned = replaceTabs(line);
|
|
824
|
+
return cell.status === "error" ? theme.fg("error", cleaned) : theme.fg("toolOutput", cleaned);
|
|
825
|
+
});
|
|
748
826
|
|
|
749
827
|
if (outputLines.length === 0) {
|
|
750
828
|
return { lines: [], hiddenCount: 0 };
|