Skip to content

agent-wire 0.2.3

Choose a tag to compare

@uncoalesced uncoalesced released this 30 Oct 11:05
· 30 commits to main since this release

agent-wire 0.2.3

Agents burn context calling tools one at a time. Every search, read and feed result lands in the conversation, even the parts the agent throws away a step later. This release adds Code Mode: the agent writes one short script, agent-wire runs it, and only the answer comes back. It also closes off private addresses and adds a lot more CI.

uvx agent-wire-cli install --client auto

Code Mode: wire_run

The idea comes from Cloudflare's Code Mode. Instead of several tool calls, the agent writes one async JavaScript script against wire.read, wire.search, wire.feed, wire.research and wire.cite. Those return plain data, not formatted pages. The script filters and joins it, and only its return value and console.log output reach the model.

const hits = await wire.search('rust async', {platforms: 'hn', limit: 4});
const docs = await wire.read(hits.map(h => h.url));
return docs.map(d => ({title: d.title, points: d.score,
  top: d.comments.sort((a, b) => b.score - a.score).slice(0, 3).map(c => c.text.slice(0, 90))}));

On an offline benchmark (HN top 4 threads with 3 best comments each), classic tools used 3,394 context tokens over 2 round trips. Code Mode used 468 tokens in 1 round trip, 86% fewer. A live run over Reddit and HN fetched 41,005 tokens and returned 61.

  • The sandbox is QuickJS (quickjs-ng). Scripts get no filesystem, network, timers or modules. Limits: 64 MB memory, 5 s CPU per step, 60 s wall clock, 40 calls, 16 in flight.
  • Promise.all runs calls in parallel.
  • Scrubbing, the prompt-injection shield and citation provenance all still apply. wire_me is left out of scripts on purpose.
  • wire serve --code-mode exposes only wire_run and wire_status. The normal profile lists 8 tools. From a shell: wire run script.js or wire run -e "...".
  • The bundled skill, the wire-worker sub-agent and the Cursor, Windsurf and Hermes rules explain when to reach for wire_run.

Private addresses are refused

wire_read, Code Mode reads and the citation checker now refuse localhost, private-network and cloud-metadata addresses, plus anything that isn't http(s). Redirects are followed by hand and every hop is checked again, so a public page can't bounce a request onto your network. The browser stage blocks those requests too. Citation links to private addresses come back as BLOCKED without being opened.

Things you configure yourself, like a self-hosted SearXNG, a transcription endpoint or a watch webhook, are always allowed on a private address. Set WIRE_ALLOW_PRIVATE=1 only if you want reads to reach your own intranet.

Fixes

  • Saved cookies are never attached to anonymous fetches, even after a login wall, and citation checks always go out without your session.
  • Code Mode: a for (;;) await 0 loop can't hang the server, scripts can't reach or replace the host's hooks, and lone surrogates in strings no longer crash Python.
  • wire_run error text is capped and stays inside the untrusted block.
  • wire run and wire cite read piped stdin as UTF-8, which matters on Windows.
  • RSS, Google News, Reddit search and arXiv feeds are parsed with defusedxml.
  • rookiepy is skipped on Python 3.13+, which has no wheel for it.
  • Dependencies: fastmcp 4.1.4 (GHSA-7xgj-8392-5q4r, GHSA-vqqp-x5qm-5qp4), plus newer certifi and filelock.

Security and CI

  • New SECURITY.md: how to report privately, what's in scope, and known limitations.
  • CI now has a lint job (ruff, format and lock checks), tests on Python 3.11 to 3.14, and a wheel install plus real stdio MCP smoke test on Linux, macOS and Windows.
  • A new security workflow runs pip-audit, bandit, zizmor and dependency review, alongside CodeQL for Python and Actions. Dependabot opens weekly grouped updates.
  • Every action is pinned by SHA. The release build uses no cache and keeps no credentials.

378 offline tests pass on Linux, macOS and Windows.

Full changes: #6, #7