Skip to content

Agentao 0.4.22

Latest

Choose a tag to compare

@jin-bo jin-bo released this 07 Sep 03:34
· 1 commit to main since this release
26a4b81

Agentao 0.4.22

A Windows release. This repository had never run a test on Windows. It does
now, on Python 3.10 and 3.12. The first run to reach the whole suite failed 155
tests on 3.10 and 162 on 3.12, and refused to collect 13 modules at all — six
product defects and a long tail of tests written by someone who had only ever
seen a POSIX path separator. None of the six is a "Windows bug": each is
something POSIX absorbs quietly and Windows bills for.

On top of that, run_shell_command can use PowerShell, and the reference CLI no
longer lets a model choose how its own commands are rendered to the human
approving them.

The headline:

  • PowerShell on Windows, opt-in. "shell": {"dialect": "powershell"} in the
    user-level permissions.json finds pwsh.exe, else powershell.exe, and
    launches it directly. The Windows default is unchanged — nothing
    configured still means %COMSPEC% /c, the same environment and the same
    command floor.
  • The tool-confirmation prompt is inert. Model-authored text went straight
    into a Rich console.print. A raw escape could erase the line just printed
    and reprint something else; [black on black] needs no control byte at all
    and renders the tail of a command invisible. That prompt is where a human
    arbitrates every shell command in the default posture.
  • Six Windows defects, none of them cosmetic. Every edit of a CRLF file
    doubled its carriage returns. Two session saves in one clock tick destroyed
    the first. Every memory read and write leaked a SQLite connection, which on
    Windows means a host could not delete its own workspace.
  • The slow clean-install tier now runs. Nine tests that build a wheel and
    install it into fresh environments had been selected by a marker no CI job
    ever passed. One of them had been failing since June.

PowerShell

The Windows shell has always been %COMSPEC% /c with a command floor written
for POSIX syntax. Now the dialect is a configuration, and four things about the
launch are worth knowing:

  • The interpreter is found by walking known install locations and the absolute
    directories of PATH, never shutil.which.
    On Windows that function
    prepends the current directory to the search and cannot be told not to, so a
    checkout containing a file named pwsh.exe would be what agentao starts.
  • The command travels as -EncodedCommand, base64 of UTF-16LE, so quotes,
    backslashes, percent signs and newlines survive with no layer in between
    having to agree about escaping.
  • A fixed trailer turns the last statement's outcome into an exit code. A
    native command's own non-zero code is preserved; a cmdlet that only wrote an
    error gives 1. A bare exit $LASTEXITCODE reports a stale 0 for that second
    case, which is a failing command reported as success.
  • Windows PowerShell 5.1 wraps a redirected error stream in CLIXML, unwrapped
    here by bounded text extraction rather than by an XML parser: the stream
    carries the output of model-written code, and the standard library's parser
    expands internal entities.

The command floor's dialect-independent half runs on every dialect, always, so
nothing it refuses today is allowed on the PowerShell path. A table of Windows
irrecoverable classes runs in addition — formatting a volume, clearing a disk,
deleting shadow copies, disabling BitLocker, a recursive Remove-Item on a
drive root — reading PowerShell's built-in aliases and abbreviated parameters,
because a table written in canonical names alone refuses one spelling of six
while reading as coverage.

This replaces a much larger design that was never released. That one
resolved the interpreter by identity: attested images, a trusted-root chain over
every ancestor directory, a closed child environment. The measurement that ended
it is that on an elevated Windows token the trust predicate is true of
everything, so the trusted set is empty, the ladder runs empty, and every shell
call is denied. Running elevated is common on Windows. Nothing about it was ever
in a release, so there is no migration; if you were tracking main, the
changelog lists what moved.

Two PowerShell 5.1 behaviours documented rather than worked around

Both were measured on a Windows runner, and neither is reachable from anything
agentao writes:

  • What 5.1 pipes into a native command begins with a UTF-8 byte order mark.
    Five prelude variants were tried, including no prelude at all; 5.1 emitted the
    mark in every one and PowerShell 7 in none.
  • Cmdlets that write files default to the system ANSI code page there, so
    Set-Content -Value '中文' writes ??. The prelude sets the two stream
    encodings and stops, because changing a cmdlet's default changes what a user's
    command means — and 5.1's own utf8 is UTF-8 with a BOM.

What the Windows job found

Six product defects on the first run, and a seventh on a later one:

  • Every edit of a CRLF file doubled its carriage returns.
  • The state directory moved on every run when there was no home directory,
    because the privacy check tested POSIX mode bits that Windows never sets.
  • Every memory read and write leaked a SQLite connection. with self._connect() as conn reads like a resource scope and is not.
  • Two session saves inside one clock tick destroyed the first. Windows' clock is
    far coarser than six digits of microseconds suggest.
  • An atomic write could fail because someone else had the file open.
  • A healthy ACP server was reported as an immediate exit, because the startup
    check waited a flat 50 ms and Windows process creation routinely takes longer.
  • A background PowerShell command returned a process id and ran nothing. Under
    DETACHED_PROCESS both interpreters exit 0 with empty output without
    executing a statement; PowerShell hosts itself in a console and that flag
    leaves it none.

Also in this release

  • run_shell_command promised the model bash -c and delivered /bin/sh -c.
    It is bash now, resolved rather than assumed, so an image with no bash still
    works.
  • A configured shell.path named an interpreter that never ran: the value
    reached the resolved spec and stopped there.
  • The shell tool's description names the interpreter that will read the command
    instead of saying cmd /c on Windows unconditionally.
  • The [full] dependency baseline compares distribution names rather than
    pinned versions. The churn hid a real change: distro and tqdm left the
    closure when openai went 2.x to 3.x.

Full detail, including the API surface that moved, is in the changelog under
0.4.22.