Skip to content

Dial v0.2.11

Choose a tag to compare

@github-actions github-actions released this 03 Nov 20:13
· 40 commits to main since this release

Security

  • Refuse unquoted shell expansion in inspection exemptions, native writes into Git metadata,
    and host Git reads with executable filters or text-conversion drivers. Git history inspection
    cannot invoke repository-configured signature verifiers. Remote SSH wrappers no longer depend
    on the login shell's path-quoting grammar.
  • Authenticate collaboration hosts and writable guest actions without transmitting the write
    token. Protocol 1004 requires newly generated links and updated clients (docs/collab.md).
  • Restrict text-recovered tool calls to offered tools on local/private endpoints and require
    one-shot human approval throughout parent and worker execution. Saved grants, speculative
    reads and batch shortcuts cannot authorize recovered calls (docs/llm-transport.md).
  • Allowlist inherited child environments, redact secret debug output, zeroize tokens, and
    warn about the account-policy risk of Anthropic subscription client identity. Existing
    subscription sign-in remains available without an additional opt-in.
  • The release signing job also removes its private-key file in an if: always() step, so the
    key is shredded even when the signing step is killed before its exit trap runs. The publish
    job checks every artifact against SHA256SUMS and the signature against the public key before
    creating the release (docs/release-and-install.md).

Fixed

  • scripts/release.sh and the release workflow's CI gate list every failed job of the latest CI run (with links) when they refuse to release, instead of only reporting that no successful run exists.
  • Windows native edits no longer fail Git-metadata protection on \\?\C:\… paths (the macOS profile's backslash refusal now applies only where a quoted sandbox profile is generated), the collaboration relay treats a peer that drops its socket (broken pipe or reset) as a normal disconnect rather than a relay error, and CI compiles the Wayland/PipeWire feature combinations on Ubuntu 24.04, whose PipeWire headers match libspa 0.9.
  • Closing the terminal Dial runs in (a killed tmux server, a closed SSH session) no longer leaves Dial spinning at full CPU: the input reader treats a hung-up terminal as closed and exits instead of retrying its end-of-file forever.
  • Ctrl+O and Ctrl+L on a long, tool-heavy session no longer end it with "terminal frame exceeds the byte limit": replayed scrollback is painted in bounded slices across frames. Leaving the terminal writes its mode resets (bracketed paste, keyboard protocol, cursor, autowrap) as a separate frame that is always attempted, so a refused scrollback write can no longer leave the shell in those modes.
  • auto worker isolation falls back to the next backend when one passes its probe but fails to set up (an unprivileged or containerized kernel overlay mount without fuse-overlayfs), instead of failing every isolated task; the setup error is shown as that backend's skip reason. The worktree backend now gets the dependency copy, so workers there can run tests that need node_modules, virtual environments or vendor.
  • A worker's private git snapshot excludes every build-output and dependency directory the copy backends exclude (target, build, dist, .cache, __pycache__, …); overlay isolation previously added a project's whole target/ (tens of gigabytes) to a temp-dir repository for every isolated worker.
  • Background workers stopped because their owner went away (quitting, or a settings change that rebuilds the agent) are recorded as interrupted, so --restore resumes them; only an explicit cancel records cancelled.
  • One-shot notes (background job finished, monitor deliveries, hook context, the 80% wrap-up notice) are no longer lost when a reply is discarded after it arrives: a reply that never reaches history (truncation raise, rejected edit preview, repair, guidance regeneration) leaves its notes queued for the retry.
  • A model that keeps answering in text while an investigation checkpoint is open gets two "call rewind" reminders, then the turn stops as incomplete; previously the reminder repeated without limit (each one a paid request, with the default unlimited step budget).
  • Goal mode counts batched and streamed-reuse tool calls as activity; a continuation turn made of parallel reads is no longer treated as stalled.
  • The prewalk and plan-yolo model handoffs install the new model through the shared route installer (authentication config, context cap, cache identity, role caches) and resize the turn's output budget, so a handoff to a smaller model no longer keeps the planner's context window and compaction thresholds.
  • The patch engine no longer edits the first of several identical blocks when the hunk meant another: exact and whitespace-tolerant passes report how many places match, so a hunk's line number selects the right occurrence and a context-stripped fallback that matches more than one place is refused instead of applied.
  • Patch re-indentation keeps a line the model deliberately re-indented (a dedent, or wrapping lines in a new block) instead of snapping it back to the file's previous indentation when the hunk was matched with different whitespace.
  • A shell command that reaches the automatic background threshold keeps running in the foreground under its own timeout when no background owner can take it (bg not enabled, or all eight slots in use); previously the refused hand-off stopped the command and discarded its output.
  • Captured shell output never splits a multi-byte character at the head/tail cut (box-drawing tree output no longer shows replacement characters when nothing was omitted).
  • A line ending in \r\r\n keeps its own carriage return when an edit changes a different line.
  • grep and glob scoped to a subdirectory honour the .gitignore files of its parent directories (build output such as dist/ no longer consumes the page budget), while an explicitly requested ignored directory is still searched.
  • A wide grep page no longer evicts the edit witnesses of files the model read or edited: new search-only witnesses enter at the old end of the store, and superseded snapshots are trimmed before whole files are evicted.
  • A session whose last append was torn by a crash or full disk no longer reports corruption on every later resume: the writer removes the unloaded partial line when it claims the journal, instead of sealing it into a malformed interior line with the next append. A complete final entry that only lost its newline is kept.
  • Checkpoint review diffs are bounded to 500 ms of edit-script search (a coarser but correct diff past that), and compare-before-restore checks the review token without rebuilding the diff while holding the checkpoint lock.
  • Recheck session-writer identity after locking, retain locks through removal, version SQLite
    schemas transactionally, and preserve process-group ownership when waiting for child exit.
  • Load Git-overlay status/diffs off the input thread, reject stale replies and unsafe hunk
    fallbacks, and route Unix termination signals through normal terminal cleanup without
    erasing scrollback. Bound relay admission and report actor panics to RPC clients.
  • Honour bounded provider retry hints with exponential backoff/jitter; handle CR-only SSE
    framing and checked configuration deadlines. Clarify Linux test prerequisites before running
    the Rust suite, while continuing independent test binaries after failures.
  • A refreshed OAuth token, a rotated pooled API key, an account or model switch no longer breaks Responses, Codex WebSocket and native-compaction sessions with "start a clean chat": native items owned by another account, endpoint, credential or model are never replayed, and those turns are sent in portable form instead. Gemini tool history from another model, route or credential is replayed as plain text rather than refused, without inventing function-call signatures.
  • Anthropic signed blocks (thinking, server tool results) are recorded with the host that produced them (dial_provider_origin) and replay only there; a turn from another Anthropic-protocol provider (z.ai, MiniMax, Vercel, Cloudflare) is sent as portable text and tool calls. Claude subscription tokens are re-read on every retry attempt, so a retry that outlives the token no longer fails with an authentication error.
  • A streamed Responses context_length_exceeded failure is classified as a context overflow (compaction) instead of a transient failure retried with the same prompt; usage_not_included and usage_limit_reached are quota exhaustion. The Anthropic "input length and max_tokens exceed context limit" refusal is recognized as an overflow.
  • Chat-completions finish reasons are normalized: max_tokens, model_length, model_context_window_exceeded and max_output_tokens mean length, and error/network_error are incomplete streams, so truncated or aborted replies are no longer accepted as complete answers. A tool call cut off by the output limit on Gemini, Responses or Ollama is dropped and reported as length (raising the budget) instead of failing the turn.
  • Idle cache warming stops once the combined cost of its replays would exceed the single cache miss they prevent (previously each replay was judged alone, so long idle windows cost more than the miss).
  • A tool-call delta whose index is reused by a different call id starts a new call instead of concatenating two calls.
  • The steering runtime probe no longer routes loopback requests through an environment proxy.
  • Oversized images are resized once and reused on later requests (bounded cache) instead of being decoded, Lanczos-resized and re-encoded on every request; the saved model catalog is parsed once per file version; and request fingerprinting reuses the built request body instead of re-parsing the serialized request.
  • A running tool's live output no longer grows its runtime body without bound: the body keeps the first 1 MiB (prefix-stable, so RPC byte deltas stay valid) and marks the cut once. A single runtime update too large for the stream journal's replay row limit is now published in a bounded form instead of latching the journal, which previously stopped all session persistence until restart; copying a journal refuses rather than silently dropping such a node.
  • Stream-journal reclamation no longer rescans and rewrites the whole stream on every flush once retained live baselines exceed 4 MiB; it waits for another 4 MiB of growth, as after a deferred attempt.
  • Editing one workspace crate no longer recompiles unrelated crates beneath it: dial-tools and dial-agent read the executable's build identity registered at startup (dial_core::build_identity) instead of linking dial-build-info, whose revision/dirty/time values change on every source edit. Touching a dial-ui file rebuilt in 27 s before and 11 s after on a 4-core dev build.

Changed

  • A streaming /btw side answer is saved (and shown) at most every 500 ms or 8 KiB after its first text, instead of rewriting and fsyncing the side-thread file on every refresh tick of the UI thread; only text the private store accepted is ever displayed. The periodic 30 s project rescan no longer hands an unchanged listing to the composer (which restarted a scan of up to 32 MB of source and repeated the "File completion is partial" notice), and the vocabulary scan is skipped when word completion is off. RPC republishes its query projection for runtime-only (worker) changes at most every 500 ms instead of copying the whole execution tree on every idle tick.
  • Streaming markdown keeps its incremental cache for replies containing [ or < (links, generics, comparisons, inline HTML) by cutting only at the parser's own top-level block boundaries; previously any such character made every later frame re-render the whole remaining reply. A 20 KB reply with one `Vec<T>` early rendered in 96 ms instead of 2.57 s across its deltas (debug build). The task card no longer re-renders every frame while a worker runs (live elapsed time is compared at the one-second resolution it is shown in).
  • Request preparation validates the tool offer without rebuilding every tool's contract identity (previously about 12% of CPU in a tool-heavy local turn), checks for Snapcompact layers and user-supplied image references without copying the whole session history, compiles each cleanse parser pattern once, and keeps only the newest 256 truncated-artifact URIs (written only when one is added) instead of re-journaling an ever-growing list.
  • find reuses its parsed-source evidence across calls on repositories larger than its cache: entries are indexed by path, the cache holds up to 4096 files (within the existing 32 MiB bound), and eviction never displaces an entry the current retrieval already used, so repeated sweeps hit instead of re-tokenizing every file. Fuzzy edit matching skips windows whose length-based upper bound cannot affect the result and normalizes each file line once instead of once per window. Idle background-job readers back off from 10 ms to 100 ms polling.
  • Isolate release signing behind a protected environment, require exact-SHA push-to-main CI,
    publish curated version-specific changelog notes, and broaden platform lint/feature coverage.
    Container digest signing uses pinned Cosign with GitHub OIDC. Repository-owner protection
    settings and outstanding verification/platform limits are tracked in
    docs/audit-2026-11-01-follow-up.md.
  • Replace direct fs2 locking with standard file locks, consolidate filesystem/HTTP/OAuth
    and UTF-8 boundary owners, extract orchestration phases, and enforce documented unsafe
    invariants through the workspace Clippy lint. See the audit follow-up for item dispositions.
  • verification.review.enabled is now unset by default: completion review runs when a coach
    model role is assigned and its route passes the escalation privacy gate (local, or
    escalation.allow_remote). Explicit true/false keep their meaning; strict_requirements
    stays off (docs/requirement-verification.md).
  • Dependency updates: ratatui 0.30 (on crossterm 0.29, so one crossterm version is built),
    quick-xml 0.42 (document XML is read as UTF-8 text; DTD refusal and entity rules unchanged),
    ast-grep 0.51, fontdue 0.9.5, unicode-normalization 0.1.26, and the release workflow's
    checkout v7, upload-artifact v7, download-artifact v8 (digest mismatches now fail), and
    Docker build-push v7 / login v4 actions.
  • CI's Linux feature-powerset jobs share one Rust cache per runner image instead of one per
    combination (32 entries, ~6.5 GB of the 10 GB quota), so the macOS test caches are no longer
    evicted and the macos-15-intel job stops rebuilding every dependency from scratch. The Intel
    job now runs format, build and the full test suite only; installed-binary smoke, terminal
    lifecycle, slim build and runtime-overhead steps run on macos-15 and Ubuntu.

Added

  • GPT-, Claude-, Gemini- and DeepSeek-inspired reasoning workflow presets, adapted from public
    guidance/research. Existing strategies and the unchanged default remain available; presets do
    not select models or change provider thinking/effort controls (docs/agent-loop.md).
  • Advisory edit-churn note: six committed edits to one file without a passing check prompt the
    model to verify or re-plan. It never stops the turn (docs/agent-loop.md).
  • /contract <task> starts a turn that records goal, constraints and checkable "done when"
    deliverables in working_state first, and stops with a recorded blocked state when stuck. It
    reuses the existing completion gates (docs/agent-loop.md).