Skip to content

v0.9.0

Choose a tag to compare

@devoidfury devoidfury released this 15 Sep 10:13
· 171 commits to main since this release
  • [BRK] llm-client / config: the tool-result seam split into two independently-selected seams.

    • WireFormat owns the model-facing markup shape of harness wrappers (tool results, attached-file includes, system notices): modelToolFormat/--model-tool-format became modelWireFormat/--model-wire-format (default still "xml", but the shape -- and the file-include/system-notice marker protection -- now come from the autoloaded wire-format-xml extension).
    • RoleMapping owns where the internal harness role rides on the wire: the provider/model entry wireFormat: "system-first" | "developer" moved to roleMapping with the same two ids, registered by the new autoloaded role-mapping-default.
    • Tool results now travel as structured parts (tool/status/meta/error/hint/output) through context, session logs, hooks, and UI events instead of pre-rendered text. Rendering is up to each UI. The wire serializer is the only render point for the wire format. Fields are mangled before the format sees them.
    • Wire breaks for extension authors: the turn:end hook payload's result is content, same for the TOOL_RESULT output event; ToolResult.outputTag removed; EXTENSION_PROVIDES.TOOL_FORMATS replaced by WIRE_FORMATS + ROLE_MAPPINGS. A seam name configured but not registered by a handler throws Unknown wire format/role mapping "<name>"
    • Config Migration: a stale wireFormat: "developer" config fails on the first request with Unknown wire format "developer" -- rename the key to roleMapping/role-mapping.
  • added visual display protection from zero-width characters / bidi spoofing (which a malicious llm could use to hide a dangerous command in an innocent-looking ask prompt) by escaping these characters prior to rendering.

  • ui-interactive-cli: bracketed pastes whose content is a single line once surrounding newlines are trimmed no longer become a [Paste #N] marker -- the trimmed content is inserted inline (a pasted line with a trailing Enter behaves like typing it).

  • added experimental sysbox layer for bash-tool -- kernel enforced resource limits, syscall-level sandboxing (seccomp launcher C, Landlock fence, capability probes, cgroup DoS limits).

  • removed sysbox layer. Fun experiment but I was not confident enough shipping it. For real isolation run hotdog in a container or VM. More info at docs/postmortems/sysbox.md

  • approvals - user-gate, a tool-call approval layer, above the spawn boundary.

    • Opt-in (userGate.enabled defaults false -- with default: "ask" an on-by-default gate would prompt every user on every call).
    • Grammar is tool or tool.param=glob -- bash.cmd=git, edit.paths=src, fetch.url=https://docs.example.com/* -- and path values reuse Workspace rule matcher (same as workspace.deny), matched against the absolute AND the workspace-relative path.
    • Precedence deny > allow > default. deny never prompts and cannot be overridden mid-run. default can be set to ask (interactive), allow or deny -- allowlist-only, nothing prompts, unrecognized tools and unanalyzable bash deny too. default deny recommended in non-interactive mode, like on CI or with -p.
    • Bash commands are segmented on ;/&&/||/|/newline with cd retargeting later segments, and the analysis bails to an ask on anything that could hide an effect: $(...), backticks, ${}/$VAR, parens, brace expansion, unquoted globs, here-documents, xargs, eval, env, find -exec/-delete, and inline-code interpreters (sh -c, python -c, node -e, awk...).
    • Fails closed -- no seam, non-interactive UI, throwing prompt, aborted run or empty answer all block, with the reason; malformed rule is a startup error and keeps every call blocked until fixed.
    • What it does NOT stop: the command is not executed and the final operation isn't checked; nothing enforced at system level once the command is started.
    • Nothing is written to config from a prompt; a session allow is in-memory only, keyed on the tool plus every extracted value.
  • added /show-prompt command to see the active system prompt, as an interactive slash command and the show-prompt subcommand.

  • cli - token usage line reworked; now also shows the context window size.

  • workspace - now warns and continues when some configured roots are missing; errors only when all roots are missing. Also fix workspace handling when a root is /.

  • extensions - an invalid extension.json now throws at load instead of being silently skipped. Fix nested extension import.

  • sessions - resuming with an invalid session id now throws instead of silently starting a fresh session.

  • sessions - interrupted or missing tool results are healed on load, so a session killed mid tool-call no longer produces API errors on resume.

  • agent - fix per-model context-limit lookup; non-default models were falling back to the base limit.

  • compaction - an unrecognized model now resolves the default context limit instead of erroring and skipping compaction.

  • llm-client - connection errors now report the url being connected to.

  • question tool - more robust Ctrl-C handling; clearer error in one-shot mode when no user is connected to answer.

  • info - fix skills display.

  • internals

    • tool-executor - toolCtx is now built (and AGENT_TOOL_CONTEXT fires) BEFORE the TOOL_CALL gate pipeline, and the gate payload carries toolCtx
    • bash-tool - add truncated="true" result metadata info when output is truncated, same as find/grep/etc
    • hooks - unrecognized hook name now logs a warning instead of being silently ignored.

Full Changelog: v0.8.0...v0.9.0