Commit graph

733 commits

Author SHA1 Message Date
Bryan Helmkamp
ae1f13402b Add 5-minute stream read timeout and increase retry backoff to 5s
A stalled Anthropic SSE stream caused a run to hang for 10 minutes
until the stall watchdog killed it. The HTTP connection succeeded but
no SSE events arrived, and with stream_read_timeout defaulting to None
the read blocked indefinitely.

- Set AdapterTimeout default stream_read to 300s (5 min), matching
  the idle timeout used by OpenAI Codex
- Increase BackoffConfig default initial_delay_ms from 200ms to 5s
  so transient LLM failures get meaningful recovery time before retry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 10:03:50 -04:00
Bryan Helmkamp
a019082dfc Print only first line of goal in arc run start output
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 10:01:36 -04:00
Bryan Helmkamp
2b8da8f15b Add tests for Daytona execute_command timeout and cancellation
Adds two new tests to the Daytona integration suite:
1. `daytona_exec_command_cancelled`: verifies that an active token cancellation properly aborts a running command and yields a correct exit code/message.
2. `daytona_exec_command_local_timeout`: tests the recent fix that prevents commands from hanging indefinitely by enforcing a local timeout fallback.
2026-03-08 10:01:06 -04:00
Bryan Helmkamp
6280a822eb Fix subagent/system prompt empty handling with TDD 2026-03-08 09:59:56 -04:00
Bryan Helmkamp
59634a3936 Increase default stall watchdog timeout from 10 minutes to 30 minutes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 09:52:07 -04:00
Bryan Helmkamp
3dce68d664 cargo fmt 2026-03-08 09:51:10 -04:00
Bryan Helmkamp
445050dc57 Enforce local timeout and cancellation for Daytona execute_command
The Daytona SDK HTTP client can sometimes hang indefinitely if the connection
drops or the server stops responding. Since `daytona_sandbox.rs` was awaiting
the `execute_command` call directly, this could cause the entire workflow engine
to stall, eventually triggering the stall watchdog.

This wraps the `execute_command` call in a `tokio::select!` block, enforcing
the requested `timeout_ms` locally (with a 5s grace period) and respecting
the `cancel_token`.

Co-Authored-By: Gemini CLI <noreply@google.com>
2026-03-08 09:49:51 -04:00
Bryan Helmkamp
5967c3783e Fix v4a patch parser/applier to match canonical OpenAI codex spec
- Forward-order hunk application with cursor tracking (fixes duplicate line matching)
- Accept `@@ context` without trailing ` @@` (backward compat preserved)
- Stacked `@@` anchors collapse to single hunk using last context
- `*** End of File` marker for backward search from end of file
- `*** Move to:` for file renames during update
- 4-pass fuzzy matching: exact → trim_end → trim → unicode normalization
- Heredoc wrapper stripping (<<EOF / <<'EOF' / <<"EOF")
- Update system prompt to use canonical `@@ context` format

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 09:45:14 -04:00
Bryan Helmkamp
58e08bec60 Cache start node ID before main loop to avoid repeated O(n) lookup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 03:09:39 -04:00
Bryan Helmkamp
a3abbaf191 Skip git checkpoint commit for start node
The start node is a no-op (StartHandler returns success immediately), so its
git checkpoint commit is always empty. Skipping it reduces noise in git history
without losing any data — the checkpoint JSON is still saved to disk, and the
next node's diff falls back to base_sha correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 03:02:57 -04:00
Bryan Helmkamp
77fd3134c3 Use format_lines_numbered in format_patch_error to avoid duplicating line numbering logic
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 01:16:11 -05:00
Bryan Helmkamp
225a383690 Include file contents in apply_patch error responses
When apply_patch fails because a context anchor line doesn't match, the
model had no visibility into what the file actually contained and would
retry blindly. Now the error includes numbered file contents (truncated
to 9K chars via HeadTail mode) so the model can self-correct in one try.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 01:11:19 -05:00
Bryan Helmkamp
3e1185d19b Extract ActiveStage::last_bar() and clean up compaction bar handling
- Extract repeated `tool_calls.back().map_or(&spinner, |e| &e.bar)` into
  `ActiveStage::last_bar()` (used in 4 places)
- Clean up existing compaction_bar before overwriting in CompactionStarted
- Tidy CompactionCompleted handler to inline the if-let chain

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 01:08:51 -05:00
Bryan Helmkamp
e33d3f02fb Add validation error for unresolved @file references in DOT workflows
Unresolved @file references in node prompts or graph goals silently
passed through as literal text. Now caught at validation time with
a clear error and fix hint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 01:05:37 -05:00
Bryan Helmkamp
3d4de58be2 Print run ID at start of arc run start and on resume
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 01:04:46 -05:00
Bryan Helmkamp
030dc7fb89 Move compaction_bar to per-stage state to fix parallel stage bug
The compaction progress bar was stored as a single global field on
ProgressUI, which meant parallel stages could clobber each other's
compaction bar. Move it into ActiveStage so each stage tracks its own.
Also clean up compaction_bar in finish_stage to prevent stale spinners.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 01:03:12 -05:00
Bryan Helmkamp
2864a6b1d1 Fix @file references with ~ and .. paths
resolve_file_ref now expands tilde via dirs::home_dir() and uses
canonicalize() to resolve .., symlinks, and verify existence in one step.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 00:55:30 -05:00
Bryan Helmkamp
6803b9ad9a Show compaction progress in non-verbose arc run output
Compaction events were previously only shown with `-v`. Since compaction
takes time and changes agent behavior, display a spinning progress bar
on CompactionStarted and a summary line on CompactionCompleted regardless
of verbose mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 00:39:30 -05:00
Bryan Helmkamp
15a8eed5dc Reuse server_config::LogConfig in CLI instead of duplicate struct
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 00:37:46 -05:00
Bryan Helmkamp
a1fb96c08a Add [log] config section to server.toml and cli.toml
Allow persistent log level configuration without environment variables.
Precedence: ARC_LOG env > --debug flag > config [log] level > "info".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-08 00:33:51 -05:00
Bryan Helmkamp
916e95764c Bump daytona-sdk-rust to 03b7c06 (revert envs field)
The toolbox API does not support envs in /process/execute, so the
SDK now matches the Go SDK: accepts env in options but does not send
it. Arc uses export prepending as the workaround.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 00:25:35 -05:00
Bryan Helmkamp
23cff7db70 Restore Daytona env export workaround alongside SDK fix
The Daytona toolbox's /process/execute endpoint does not yet process
the envs field (not in its OpenAPI spec), so prepend export statements
as a fallback. The SDK also sends envs for forward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 00:20:09 -05:00
Bryan Helmkamp
8dffe80527 Bump daytona-sdk-rust and remove exec_command env workaround
The upstream SDK now passes env vars through ExecuteRequest.envs,
so we no longer need to prepend export statements to commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 00:12:50 -05:00
Bryan Helmkamp
3748fea9d5 Work around Daytona SDK missing env support in exec_command
The Daytona toolbox API's ExecuteRequest struct has no env field,
so ExecuteCommandOptions.env is silently dropped. Prepend export
statements to the command string to inject env vars into the shell.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 23:59:40 -05:00
Bryan Helmkamp
95854936e8 Remove imagegen-api test files from git tracking
These are local test files like imagegen.dot/imagegen.toml.
They live in gitignored tmp/ and don't need to be tracked.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 23:58:01 -05:00
Bryan Helmkamp
3eb15dab4e Fix imagegen-api.dot to avoid double variable expansion
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 23:38:47 -05:00
Bryan Helmkamp
6ea5cc8f38 Add API-backend imagegen test workflow for sandbox.env e2e testing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 23:36:32 -05:00
Bryan Helmkamp
9a823447fa Pass [sandbox.env] through API backend tool execution
Previously sandbox env vars only reached CLI backend agents but not
API backend tool calls. Thread tool_env through ToolContext so shell
and web_fetch tools pass env vars to exec_command for all backends.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 23:13:51 -05:00
Bryan Helmkamp
13ee1735c0 Consolidate duplicate test backends in prompt handler tests
Hoist OneShotCapturingBackend to module scope and remove two identical
CapturingBackend definitions that duplicated its functionality.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-07 23:01:15 -05:00
Bryan Helmkamp
eb2ff9dd5c Add project_memory attribute for prompt nodes
Prompt nodes now discover project docs (AGENTS.md, CLAUDE.md, etc.)
and pass them as a system prompt to one_shot LLM calls. The
project_memory attribute defaults to true and can be set to false
to disable this behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-07 22:56:26 -05:00
Bryan Helmkamp
521732fc74 Add /update-docs skill for keeping docs in sync with code
Watermark-based skill that detects code changes since the last run,
maps them to affected doc pages via a code-to-doc mapping table, and
makes surgical edits. Watermark file created on first run.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:47:17 -05:00
Bryan Helmkamp
5d6691df22 Add [sandbox.env] support to workflow configs
Allow passing environment variables into sandbox command execution via
`[sandbox.env]` in TOML configs. Supports literal values and host env
passthrough via `${env.VARNAME}` syntax (whole-value only, missing vars
are hard errors). Env vars are injected into command nodes via
`cmd.envs()` and into CLI backend agents via the sandbox env file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:43:16 -05:00
Bryan Helmkamp
36d35d07fe Consolidate changelog writing guide into /changelog skill
Move docs/naming/changelog-guide.md into the skill's references/
directory and de-duplicate SKILL.md against guide.md and format.md.
Each file now has a single responsibility: SKILL.md (workflow steps),
guide.md (writing conventions), format.md (MDX template).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:42:39 -05:00
Bryan Helmkamp
006f198014 Rename stale agent variable to exec in cli_config tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:42:15 -05:00
Bryan Helmkamp
1825b61b0e Rename arc agent CLI subcommand to arc exec
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:38:03 -05:00
Bryan Helmkamp
b7c0af09c3 Fix /changelog skill to handle same-day re-runs
The skill previously used the most recent entry date as an exclusive
cutoff, so re-running on the same day would skip commits that landed
after the first run. Make the date range inclusive and regenerate
existing files with the full set of commits for that day.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:09:02 -05:00
Bryan Helmkamp
6cee3e1926 DRY up telemetry ID loading and Telemetry construction
Extract read_existing_id() helper to deduplicate file-read-trim-check
pattern, and extract private Telemetry::new() to consolidate for_server/for_cli.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:03:58 -05:00
Bryan Helmkamp
f4b530c691 Split anonymous ID into server (UUID-on-disk) and CLI (MAC-based hash) strategies
Server is long-lived on a fixed host, so a persisted UUID at ~/.arc/.id is
appropriate. CLI runs ephemerally, so an MD5 of the MAC address avoids file
I/O and is stable per-machine. CLI falls back to ~/.arc/.id if it exists
for migration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:00:44 -05:00
Bryan Helmkamp
2b8d6a40a1 Add Segment-based telemetry module to arc-util
Adds a telemetry library for product analytics with Segment integration.
Includes Track/User wire types, persistent anonymous ID (~/.arc/anonymous_id),
OS/arch/locale context, fire-and-forget sender via tokio::spawn, and
ARC_TELEMETRY env var control (off/errors/all). No CLI or server integration yet.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:47:03 -05:00
Bryan Helmkamp
f0dd4f5053 Document --no-retro flag for faster workflow testing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:40:31 -05:00
Bryan Helmkamp
d56ed52490 Inline untracked @file references in DOT prompts at prepare time
Cloud sandboxes clone the repo, so untracked local files referenced via
prompt="@path/to/file.md" won't exist. This inlines those file contents
at prepare time while leaving git-tracked @references for the agent to
read from the sandbox.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:32:53 -05:00
Bryan Helmkamp
ecd5d0ae9a Document dockerfile path syntax in run configuration docs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:23:56 -05:00
Bryan Helmkamp
c62d9b68d9 Simplify opaque OpenAI item handling and DockerfileSource serde
- Extract ContentPart::is_opaque_openai() to deduplicate matches! patterns
- Use std::mem::take to avoid cloning reasoning/message items
- Replace hand-rolled DockerfileSource serde with derive + untagged enum
- Add --fail-with-body to imagegen curl for better error reporting
- Add tmp to .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:16:27 -05:00
Bryan Helmkamp
22a1bba192 Add --goal CLI arg to arc run start
Allows overriding the workflow goal from the command line, which is
exposed as $goal in node prompts via VariableExpansionTransform.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 21:11:34 -05:00
Bryan Helmkamp
6f1bd9cff6 Support dockerfile = { path = "..." } in snapshot config
Add DockerfileSource enum (Inline/Path) with custom serde to allow
referencing a Dockerfile by path instead of embedding content inline.
Paths are resolved relative to the config file directory during loading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 20:54:55 -05:00
Bryan Helmkamp
25e74054c8 Support --help and -h flags in imagegen tool
Move API key check after argument parsing so help works without
GEMINI_API_KEY set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 20:35:06 -05:00
Bryan Helmkamp
df903379fe Add imagegen tool for Gemini-based image generation
Bash script that calls the Gemini API (gemini-2.5-flash-image) to generate
images from text prompts. Reads GEMINI_API_KEY from .env.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 20:19:38 -05:00
Bryan Helmkamp
e73803039c Extract ContentPart::OPENAI_REASONING and OPENAI_MESSAGE constants
Replace 16 raw string literal usages of "openai_reasoning" and
"openai_message" across openai.rs and history.rs with constants
defined on ContentPart, eliminating typo risk and centralizing
the kind identifiers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:43:39 -05:00
Bryan Helmkamp
ca71b2895d Preserve OpenAI message output items for Responses API round-tripping
When an assistant turn has reasoning + text + tool calls, the message
output item was reconstructed without its original `id` and `status`
fields. The Responses API requires reasoning items to be followed by
a valid output item identified by `id`, so the reconstructed message
was not recognized, causing "Item 'rs_...' was provided without its
required following item" errors.

Preserve the full message output item as an opaque `openai_message`
provider part (like we already do for `openai_reasoning`), and use it
in translate_input instead of constructing a new message from text.
Also strip `openai_message` items during compaction alongside reasoning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:35:06 -05:00
Bryan Helmkamp
f0c97a2739 Add server-mode support for arc llm chat via session endpoints
Implement the server-side session handlers (create, retrieve, send message,
stream events, list) with in-memory storage and LLM generation, wire them
into the router replacing not_implemented stubs, add run_chat_via_server
CLI function with SSE streaming, and add mode dispatch so `arc llm chat
--mode server` delegates to the API server.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:34:15 -05:00