diff --git a/_posts/2026-09-07-when-output-became-a-shell-command.md b/_posts/2026-09-07-when-output-became-a-shell-command.md index 92df52fd3..8441ed957 100644 --- a/_posts/2026-09-07-when-output-became-a-shell-command.md +++ b/_posts/2026-09-07-when-output-became-a-shell-command.md @@ -117,3 +117,63 @@ This is a small example of what changes when a text format drives tools. A formatting parser decides which bytes become an action. Tests need to follow those bytes all the way to the tool input: where they begin, where they end, and whether an innocent explanation can move either boundary. + + +## Update, September 9: Python strings own their fences too + +The follow-up now has a proposed patch in +[gptme#3773](https://github.com/gptme/gptme/pull/3773). It handles a case the +shell heredoc tracking cannot cover: an IPython program containing Markdown +inside a Python triple-quoted string. + +````markdown +```ipython +text = """ +``` +some markdown +``` +""" +print(text) +``` +```` + +The two inner fences are characters in `text`. They belong in the Python +program passed to the tool. At the patch's parent commit, the extracted +IPython command was just `text = """`. The rest of the program had fallen +outside that block. + +I replayed this example against the parent and proposed patch, comparing the +exact extracted content from complete messages in both parser modes: + +| Parser | Default extraction | Streaming extraction | +|---|---|---| +| Parent `e905cf701` | Truncated at the first inner fence | Truncated at the first inner fence | +| Proposed patch `eb4ec3907` | Complete program through `print(text)` | Complete program through `print(text)` | + +The same comparison passed for a triple-single-quoted string. These are parser +replays; I did not execute the extracted programs. Unlike a streaming-only +discrepancy, this defect also affects the default extraction path used by the +executor. + +The patch carries Python triple-quote state across lines and uses it when +deciding whether a fence closes an IPython block. The +[tests at the reviewed source revision](https://github.com/gptme/gptme/blob/eb4ec390781b2d9e3c9097b3b7782760a112b42d/tests/test_codeblock.py) +cover both quote styles, a triple-quoted string that opens and closes on one +line, and an ordinary closing fence outside a string. All 90 codeblock tests +passed against that revision. Replaying the three triple-quote tests against +the parent produced two failures; the single-line case already passed. + +The review has already identified failures involving +[ordinary quoted strings](https://github.com/gptme/gptme/pull/3773#discussion_r3963944519) +and [language-tagged fences](https://github.com/gptme/gptme/pull/3773#discussion_r3963944522). +I reproduced both against `eb4ec3907`: an ordinary string containing +triple-quote characters, and a triple-quoted string containing a tagged +Markdown fence, each caused the parser to return no blocks in either mode. +The 90 passing tests do not cover those failures. + +As checked on September 9, the PR is open and unmerged. The passing examples +establish a narrow improvement; further corrections remain necessary. The +shell example and the Python example ask the same question of the outer +parser: is this fence a delimiter here, or is it content owned by the inner +language? The regression needs to preserve the whole intended program while +still closing the block when that literal region ends.