Skip to content

v0.13.0

Latest

Choose a tag to compare

@github-actions github-actions released this 29 Sep 08:48

Borg Agent 0.13.0

Tools

  • The goal, plan, subagent and cross-agent messaging capabilities are their own
    tools, and one capability tool reaches everything else by name or by search.
    Both are on the default surface, not only on the opt-in one. A promoted name is
    refused through the generic tool and points at its own, and an unknown name is
    answered with the closest real capabilities rather than a bare error.
  • query_history is a tool, so which of its retrieval modes answers a question
    arrives with the guidance instead of after a wrong guess.
  • search_files is a tool backed by ripgrep's own engine, so it needs no
    external executable and is the thing to reach for rather than grep. A file with
    undecodable bytes no longer costs you every match inside it.
  • Extension capabilities are advertised with descriptions read from the live
    catalog, so a newly loaded extension is visible without restarting anything.
  • Computer use is a tool of its own. It was always a full capability - native
    desktop and private-display access, and the approval gate that refuses
    consequential controls until you confirm that exact action - but a model had to
    already know the name and invent a JSON body for it before it could take a
    screenshot. A subagent still gets the private headless display rather than
    yours: the spec is surface-aware, so promotion cannot widen a child's reach.

Performance

  • A fast reasoning model no longer makes the interface lag. Every frame was
    re-rendering the whole expanded block, beginning with a fresh copy of every
    byte of reasoning received so far, so a frame cost the length of the block and
    a stream cost the square of it. At 800 lines that was 17.22ms a frame and
    about seven seconds of CPU for one answer; it is now 0.27ms and 113ms, and a
    frame through a real terminal measures 2.02ms with thousands of deltas
    coalesced into it. The lines that have finished are reused, and the line still
    being written is redone, because that is the only one that can still change.
  • BORG_TUI_FPS and BORG_TUI_STREAMING_FPS are documented. They existed and
    were clamped, but appeared nowhere, so the one knob that changes how streamed
    text feels could not be found.

Reliability

  • A compaction that loses its connection is retried instead of failing your turn.
    One empty upstream response on one fold used to abort the whole sequence and
    fail the turn, costing you the context it was there to save. Retries are
    bounded, and a refusal no repeat can fix -- auth, billing, quota, an
    oversized request -- still fails on the first attempt with its real cause.
  • A provider error now names the field it rejected. Only the code and the
    parameter were reported, which say that something is wrong and never what;
    a malformed request was undiagnosable from outside. The provider's own
    wording comes through with the rejected value stripped.

Reliability

  • A history search on a resumed or forked session can no longer report "no
    matches" while having looked at almost none of the history. Those sessions were
    scanned oldest-first under a hard budget, so on a long thread only the oldest
    events were ever reachable and recent work was invisible however the query was
    phrased. The scan now covers the newest window, which is what a resumed thread
    is asking about.

  • Search results say whether they are complete. truncated already conflated
    "your hit list hit the limit" with "the scan never reached the rest of the
    history", and the two were indistinguishable to a caller. A result now carries
    search_incomplete plus the scanned_from_sequence..scanned_to_sequence
    window it covered, so an empty result reads as "not found in what I looked at"
    rather than "does not exist", and the rest can be paged with start_sequence.
    The query_history description says so too.

  • An upstream that answers with an empty response is retried instead of ending
    the turn. Only a refusal is treated as fatal now; everything else is
    retryable, as it was before mid-stream errors were recognised at all.

  • A tool call carrying the presentation field its own schema advertises is
    accepted. The same idea appears as action and as description, and a call
    formed exactly as documented was being refused as malformed - the cause of most
    of that tool's flakiness.

Terminal UI

  • An action group that live work was holding open now folds when that work
    finishes. A group held open by a running process never collapsed, because
    being the newest group kept it open on its own.
  • Pending input reads as an action group rather than a bordered panel: the
    same disclosure, the same summary, the same grey, no frame.
  • A retry no longer re-announces the goal. Every retry re-emits it, and the
    card was taken out and pushed back, so resuming dropped it to the bottom of
    the transcript and reprinted a goal already on screen.

Terminal UI

  • A status line that overflows now ends in a mark. Losing its last column to
    truncation used to drop the tail with nothing to show the text had been cut.
  • The effort and billing segments share one colour instead of being graded per
    value, so the same colour no longer means xhigh in one place and a pro/max
    subscription in another.
  • Dragging the scrollbar moves the transcript one line per row. A scrollbar maps
    proportionally, so on a long thread one row of drag moved hundreds of lines and
    the closer to the middle of the thumb you grabbed, the less each row was
    worth. Clicking the track still jumps - that gesture means "go there" - and
    only the drag changed.
  • The composer's text-entry ground is darker and neutral, so the three rows you
    type in read as a well rather than another band of transcript.
  • The splash says what it is. It now reads "BORG" over "agent" over the version
    with the channel beside it, and all three lines keep one width and one centre
    whatever the version turns out to be - the v prefix yields to the width
    rather than the layout bending around it.

Providers

  • A tool result carrying an image no longer puts the image inside the tool
    result field, which the API reads as text. A valid screenshot came back as
    invalid_value on input -- "the image data you provided does not
    represent a valid image" -- and broke every later turn in the session.
  • An image attachment is typed by what its bytes are, not by what the file is
    called, on every path.
  • A pay-per-use OpenAI key is no longer sent the request shape a ChatGPT
    subscription uses, which the public API rejects outright.

Providers

  • Qwen models that take an effort ladder are sent one. enable_thinking is a
    boolean and is right for Qwen3.5/3.6/3.7, but the Qwen3.8 family takes
    reasoning_effort instead and converts a level into a thinking budget itself
    • so a laddered model was being offered low/medium/high in the picker and then
      having enable_thinking put in the body, and the effort had no effect on the
      request. The choice is now made per model from the catalog entry that already
      exists for it.

Setup

  • The Python library's documented usage is corrected: borg is already in the
    namespace, so import borg is not part of it.
  • HOME can be set for the runtime worker as a user setting, defaulting to off.

Full changelog