Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
244f134 to
14ac685
Compare
The composer is no longer disabled mid-turn. Submissions go into a pending queue; run_turn is the sole consumer and loops until drained, popping one queued message per turn so user/assistant alternation stays clean.
All interaction with the `ai` library now lives in `chat_loop(app)` at the top of the file. TauApp owns public state (model, agent, messages, pending) that chat_loop reads. run_turn shrinks to a thin worker wrapper around the busy flag.
Streaming deltas only call scroll_end when the transcript was already at the bottom — scroll up to read earlier output and the stream keeps writing offscreen. The scrollbar itself is hidden (scrollbar-size: 0 0) because its per-chunk thumb motion was visually noisy; arrow keys, pageup/pagedown, and mouse wheel still scroll.
tools.py mirrors pi's built-in surface: read, write, edit, bash, grep, find, ls. Same schema shapes and continuation/truncation behavior: - read: 1-indexed offset/limit; head truncation at 2000 lines or 50KB with a 'use offset=N to continue' hint; first-line-too-big escape pointing at sed | head -c. - write/edit/bash: require_approval=True so the agent's default loop gates them behind a ToolApproval hook. - edit: exact-match, must-be-unique str_replace; multiple disjoint edits per call, applied right-to-left against the original file. - bash: tail truncation (errors live at the end), exit-code footer. - grep/find: skip .git/node_modules/etc; respect limit/byte caps. chat_loop now handles ToolEnd, ToolCallResult, and HookEvent — tool calls and their results render as 'tool' bubbles below the streaming text, and pending approvals turn the composer placeholder into a [y/n] prompt. Non-y/n input during an approval falls through to the message queue without resolving the hook.
Replaces the y/n-in-the-composer approval flow with a HookPrompt widget that mounts above the composer when a tool fires its approval hook. Yellow rounded border, shows the tool name + args; single-key shortcuts (y/a approve, n/d deny) resolve the hook. Focus shifts to the prompt automatically and returns to the composer on resolution. Tab cycles between prompt and composer if the user wants to look something up before deciding \u2014 the hook stays pending until y/n. Drops the parallel y/n branch from on_composer_submitted; the prompt owns the decision now.
Only bash still requires approval. File mutations through write/edit are fine — they're targeted, reversible, and the approval prompt became friction more than safety once both fired several times per turn.
… messages When TAU_ADVERTISE=1 is set, appends an instruction to the system prompt asking the model to include a Co-authored-by trailer in any commit messages it writes or suggests. Co-authored-by: anthropic/claude-sonnet-4.6, via tau
Co-authored-by: anthropic/claude-opus-4.6, via tau
Detect image files (jpg, png, gif, webp) via magic bytes and return them as base64-encoded image content parts instead of dumping binary as garbled text. Uses the Vercel AI SDK multi-part content format (text + image) so the gateway can pass images through to vision models. Co-authored-by: anthropic/claude-opus-4.6, via tau
The hand-rolled follow_scroll / at_bottom approach had a stale-state bug:
after an async gap (e.g. between stream end and error handler), Textual's
layout would update and at_bottom would become False even though the user
never scrolled.
Textual's built-in Widget.anchor() handles all of this correctly:
- New content auto-scrolls to the bottom
- User scrolls up → anchor releases, no forced scrolling
- User scrolls back to bottom → anchor restores
Removed: follow_scroll(), at_bottom property, auto_scroll parameter,
_following flag, and all manual scroll_end calls.
Added: single transcript.anchor() call at mount time.
Co-authored-by: anthropic/claude-opus-4.6, via tau
Co-authored-by: anthropic/claude-opus-4.6, via tau
Switch from Textual's default dark theme (which forces #121212 background and #1e1e1e surface) to ansi-dark, which uses the terminal's own background color. Removes explicit background overrides from composer and hook prompt widgets. Co-authored-by: anthropic/claude-opus-4.6, via tau
Ctrl+J inserts a newline (works on all terminals). Trailing backslash before Enter also inserts a newline. Shift/Alt+Enter work on terminals with Kitty keyboard protocol support. Co-authored-by: anthropic/claude-opus-4.6, via tau
Detect the underlying provider from MODEL_ID and add the appropriate server-side web search tool: - anthropic -> anthropic.tools.web_search() - openai/xai -> openai.tools.web_search() Also adds Ctrl+J and backslash newline shortcuts to the composer, and fixes a docstring escape warning. Co-authored-by: anthropic/claude-opus-4.6, via tau
The model wasn't using web_search because the system prompt explicitly listed only the coding tools. Now it includes a mention of web_search when provider tools are configured. Co-authored-by: anthropic/claude-opus-4.6, via tau
Display BuiltinToolEnd and BuiltinToolResult events (from provider-executed tools like web_search) in the transcript alongside regular tool call/result output. Also updates system prompt on session resume so new tools and AGENTS.md changes take effect without a fresh session. Co-authored-by: anthropic/claude-opus-4.6, via tau
MODEL_ID includes the 'gateway:' prefix, which shouldn't appear in commit trailers. Use _raw_model instead to get the user-provided value. Co-authored-by: anthropic/claude-opus-4.6, via tau
- Import detect_image_media_type from ai.types.media instead of ai.messages.media (not an explicit export). - Rename shadowed variable to avoid ToolCallPart/BuiltinToolCallPart type conflict. - Guard against None tool_call_id in PartialToolCallResult. - Add mypy to dev dependencies. Co-authored-by: anthropic/claude-opus-4.6, via tau
Add a tool-result CSS class with ansi_bright_black background to visually distinguish tool output from tool call lines and assistant text. Co-authored-by: anthropic/claude-opus-4.6, via tau
Show edit tool calls as a colored unified diff instead of the raw → edit(path=..., edits=[...]) one-liner. Uses difflib.SequenceMatcher on lines to collapse unchanged regions and show only actual changes with context. - Extract edit_string() from the edit tool so the diff renderer can apply edits to the pre-edit file content in memory. - Diff rendering happens at ToolEnd time (before execution) using the file's current content. - On session restore, falls back to the plain one-liner since the file may have changed. Proper restore support will require persisting the old content in the tool result (see TODO below). - Bubble/Transcript gain a renderable kwarg for Rich renderables. - Tool result bubbles use a darker background (#262626). - Add mypy to dev dependencies. HACK: To support diff rendering on session restore and over the wire, we are using an Aggregator to report it out, because only that supports things. Co-authored-by: anthropic/claude-opus-4.6, via tau
Calls _reset_turn_bubbles() before processing each queued message so that a new turn's response doesn't append into the previous turn's assistant bubble. Co-authored-by: anthropic/claude-opus-4.6, via tau
Documents project layout, how to run linting/type-checking with uv, the .tau/TODO task list, and project conventions. Co-authored-by: anthropic/claude-opus-4.6, via tau
Old sessions store edit tool results as plain strings rather than EditResult dicts. Add an isinstance(str) guard so resuming those sessions doesn't crash with 'str has no attribute message'. Co-authored-by: anthropic/claude-opus-4.6, via tau
Co-authored-by: anthropic/claude-opus-4.6, via tau
The other providers don't support the code execution tool that we are using!
The named provider is the maker only for anthropic and openai, so pin gateway routing to ''only'' that provider for those two. Open-weight models are served by many backends where the slug provider isn't the maker, so leave their routing unrestricted.
The file-part-tool rebase routes non-str, non-ToolResultOutput tool returns through JsonOutput, which can't serialize a FilePart. Wrap image reads in ai.messages.ContentOutput([TextPart, FilePart]) so providers emit a real image content block. Co-authored-by: anthropic/claude-opus-4.8, via tau
_format_tool_result JSON-dumped non-str results, splattering the base-64 blob from a read's ContentOutput into the transcript. Add a ContentOutput branch that shows only its text parts (the tool already includes a human-readable label), keeping image data out of the bubble. Co-authored-by: anthropic/claude-opus-4.8, via tau
Contributor
Author
|
Closing in favor of having opened its own repo: https://github.com/vercel-labs/tau-agent |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
tau, a crappy coding agent using Textual.
(Even though I don't really like alternate screen coding agents, but.)