Commit Graph
788 Commits
Author SHA1 Message Date
Dark-Alex-17 0bef0f2c39 fix(graph): retire the teammate identity before structured extraction
PR #24 follow-up 10. The identity was only retired by the frontier and
chain-exit safety nets, so a peer stayed messageable during
structured::extract after its agent had already stopped. Mark it
finished the moment the agent future resolves, on success and on both
error paths.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 874ef7f6ec fix(graph): reject a literal max_concurrency of 0 instead of clamping it
Copilot review on PR #24. The validator already rejects 0 and the
template path errors on it, but a literal 0 loaded with
validate_before_run off was silently clamped to 1. Fail with the same
error shape as the template path; only the absent-cap default clamps.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 e746ca1f87 fix(graph): clear peer identity fields after every map chain step
Copilot review on PR #24. The fields were only ever cleared by
run_agent_for_graph taking them, so a failure between arming and that
take (e.g. prompt interpolation) left them set on the item's ctx.
Reset both unconditionally once the step returns.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 dc5e3201da refactor(graph): move the cfg(test) OUTPUT_KEY import into llm's test module
PR #24 follow-up 7.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 cdbff88b4f fix(graph): pick the map teammate identity name by BFS from the branch entry
PR #24 follow-up 6. The identity used to fall back to YAML declaration
order after the entry, so the name depended on how the author ordered
the nodes map. Walk next/fallback edges from the entry instead.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 62122fc698 refactor(graph): drop the duplicated locator prefix from map chain step errors
PR #24 follow-ups 3 and 4. run_chain_steps already wraps every step
error with the map/item/node/step locator, so the inner messages
repeated it. Make them prefix-free and turn the unreachable End arm
into an honest internal-invariant message.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 31c33b5a23 fix(graph): name the offending node type when a map branch reaches a disallowed node
PR #24 follow-up 2. With validate_before_run off, a user-authored
approval/input/end/map node inside a branch reached a message that
called itself an internal error. Name the node type and point at the
validator setting instead.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 2f839b332d fix(function): build bundled bash tools without writing back to the source tree
PR #24 follow-up 1. The bundled-tools test called the writing
generate_bash_declarations on the repo's assets/functions/tools/*.sh,
so cargo test could rewrite tracked files. Split the build+export step
into a pure build_bash_tool so the test never touches the source tree.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 b65aa76d2d docs: updated the formatting of a few comments 2026-09-11 10:56:27 -06:00
Dark-Alex-17 c10965cd71 test(graph): pin the per-item retry chain and bundled validator warning parity
Add the motivating map-chain integration test: draft -> check, where check
re-routes to draft via script `_next` until an item-local attempts counter
reaches 2, run with validate_before_run on. A sibling test drives the same
map node against a parent state to pin that only collect_into lands on the
parent and that no chain visit touches the parent's loop counts.

Extend bundled_graph_agents_parse_and_validate: the sorted (node, warning)
set of every bundled graph must equal the set the pre-subgraph validator
produced, and graph.example.yaml must load through GraphParser, validate
without errors, and declare a writer for its map's output_key.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 b4a73aae7f test(graph): pin teammate retirement on agent timeout and frontier completion 2026-09-11 10:56:27 -06:00
Dark-Alex-17 846bc39263 test(graph): run a validated two-step map chain end to end
Same two-script chain as `map_chain_two_script_steps_route_via_next`,
with `validate_before_run: true`, proving the validator admits the
chains the runtime executes.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 824edf587b feat(graph): validate map branch subgraphs instead of single branch nodes
`validate_map_branches` checked only the entry node and forbade `next`,
non-`output_key` `state_updates` and `output_schema` on it. The runtime
now executes the whole subgraph reachable from `branch`, so the validator
follows suit as `validate_map_subgraphs`, at the same position in
`validate()`:

- approval/input/end/map nodes are rejected anywhere in the subgraph,
  attributed to the map node; when the offending node is a `fallback`
  target the message says why a previously accepted `fallback` now fails
- a fan-out `next` inside the subgraph is rejected
- a subgraph that shares nodes with the main flow (reachable from
  `start` without entering any map branch, via the new
  `main_flow_reachable`) is rejected, naming the shared nodes
- a new warning fires when no subgraph node declares a write to
  `output_key` via `state_updates` or `output_schema`; any script in the
  subgraph suppresses it, since scripts may write any key
- the `next`, `state_updates` and `output_schema` restrictions are gone:
  intra-branch writes are fork-local scratch

Two maps may share a subgraph. `find_reachable_nodes` and
`compute_parallel_groups` are unchanged.

Tests: the three rules that inverted are renamed to say what they now
assert (`map_branch_with_in_subgraph_next_passes`,
`map_branch_state_updates_scratch_key_passes`,
`map_branch_with_output_schema_passes`); the four
`map_branch_cannot_be_*` tests pass unmodified. Thirteen new tests cover
each rule, the fallback hint, the missing-writer warning and its three
suppressions, a three-node chain, and `main_flow_reachable`.
2026-09-11 10:56:27 -06:00
Dark-Alex-17 0083cf0c42 test(graph): cover map subgraph chains, output contract and teammate lifetime 2026-09-11 10:56:26 -06:00
Dark-Alex-17 f1cf9a6ae7 feat(graph): run map branches as per-item subgraph chains
A map item no longer runs a single branch node; it walks the subgraph
reachable from `branch` over `next`/`fallback` edges (branch_subgraph),
one chain per item, holding one semaphore permit for the whole chain.
Chain steps go through the shared `step()` so llm retries, fallbacks,
script `_next` and agent timeouts keep their existing semantics. A node
without `next` ends the chain (StepContext.branch_mode), a route outside
the subgraph, a fan-out, an end node or a loop past
max_loop_iterations fails the item, and every item error carries
`map node 'X': sub-branch [i] failed at node 'Y' (step n)`.

`output_key` is removed from each item's fork before the chain runs, so
the collected value must be written by the chain rather than inherited
from the parent.

Teammate identities are now per item for the whole chain: provisioned
when any flagged agent is in the subgraph, armed only before
`teammates: true` agent steps, and retired at chain exit. mark_finished
moves out of run_agent_for_graph to the two provisioning sites (frontier
task and chain exit), so timed-out and early-failing agents are also
marked finished.
2026-09-11 10:56:26 -06:00
Dark-Alex-17 2049316364 feat(graph): accept a {{template}} for a map node's max_concurrency
`MapNode.max_concurrency` becomes `Option<ConcurrencyCap>`, where
`ConcurrencyCap` is `Fixed(usize) | Template(String)`. Integers parse
exactly as before (`4` -> `Fixed(4)`, `0` -> `Fixed(0)`, absent -> `None`);
a string parses as a template that the map executor resolves against the
parent state right before the fan-out via `StateManager::interpolate_raw`,
mirroring `over:`. A template must resolve to an integer >= 1 or a numeric
string (scripts often emit numbers as strings); anything else, including 0,
is an error naming the map node, the template, and the resolved value/type.
The fixed path keeps its `.max(1)` clamp for byte-compatibility.

`Deserialize` is hand-written so a malformed value (`-1`, `4.5`, `true`,
a list, a map) reports the offending value and the accepted forms rather
than serde's opaque untagged-enum "did not match any variant".

Validator: a string cap that contains no `{{ ... }}` pair is a load-time
error (catches `"4"` typed for `4`); a templated cap joins the map node's
read set so `validate_parallel_reads` flags a read of a sibling branch's
write. The existing `Fixed(0)` rule and every other rule keep their order.

Design: plans/map-subgraph-branches-design.md §3.5, §3.11 (C3, I3).
2026-09-11 10:56:26 -06:00
Dark-Alex-17 24088a48a1 fix(graph): honor an explicit output key in state_updates
Hoist the three copies of apply_state_updates (llm, agent, rag) into
graph::state_updates::apply(state, output, has_schema, updates). The
helper computes every state_updates value first, restores the transient
`output` binding, and only then writes the computed updates, so a
`state_updates: { output: "{{output}}" }` entry is no longer clobbered
by the restore step.

The per-file wrappers stay as one-line calls so their existing tests are
unchanged; new direct helper tests live in state_updates.rs, including
the regression test for the clobber.

Design: plans/map-subgraph-branches-design.md §2.6, §3.7 (C5, D3).
2026-09-11 10:56:26 -06:00
Dark-Alex-17 71c3283b87 test: updated macro test 2026-09-09 16:44:23 -06:00
Dark-Alex-17 47edaa35ff feat: teammates flag enabling peer messaging between concurrent graph agent nodes
Agent nodes marked teammates: true whose sub-agents run concurrently (map fan-out branches or multiple flagged agent nodes in one super-step) now form a team: each member gets a pre-provisioned inbox in a messaging-only PeerRegistry before any branch starts, a teammate roster injected into its prompt, peer resolution in agent__send_message, and a peers section in agent__list_running. Registries are scoped to a single fan-out and carry no lifecycle semantics: outputs still flow exclusively through collect_into/state reducers, finished peers reject new messages, and nothing registers in a supervisor. Also hardens the agent-recursion depth guard to work without a supervisor and adds validator warnings for zero-valued orchestration limits.
2026-09-09 16:44:23 -06:00
Dark-Alex-17 7e84804ed1 feat: support explicit can_spawn_agents, max_concurrent_agents, and max_agent_depth keys in graph.yaml
Graph agents previously derived can_spawn_agents from the presence of an agent node, so a pure-LLM-node graph could never spawn dynamic sub-agents. The three optional graph-level keys now override the derivation/defaults in AgentConfig::from_graph, enabling orchestrator graphs (can_spawn_agents: true with only llm nodes). Explicit false on a graph with agent nodes still runs those nodes; only dynamic spawning from llm nodes is disabled.
2026-09-09 16:44:23 -06:00
Dark-Alex-17 7f5b75dbdf fix: properly anchored the role frontmatter regex so it doesn't catch in-instruction separators 2026-09-09 13:23:33 -06:00
Dark-Alex-17 dbec2f77d1 fix: support non-object tool result outputs for bedrock 2026-09-09 12:32:54 -06:00
Dark-Alex-17 13ebe04472 feat: support setting the tool_timeout in the main config file instead of only via an environment variable 2026-09-08 17:22:21 -06:00
Dark-Alex-17 695153f88e feat: Added new environment variable to force showing tool call logging when not in a tty 2026-09-08 16:47:40 -06:00
Dark-Alex-17 4651658b34 fix: suppress subagent error and warning output to stderr/stdout 2026-09-08 11:24:43 -06:00
Dark-Alex-17 a0dc4550b1 feat: added a clear line separator for the end of LLM turns to make it more clear where they are 2026-09-03 22:01:54 -06:00
Dark-Alex-17 f66036e9d8 feat: sort models by release date 2026-09-03 21:48:10 -06:00
Dark-Alex-17 eaab57375e fix: --generate-models parsed before vault initialization 2026-09-03 19:55:03 -06:00
Dark-Alex-17 206f36d826 fix: drive tool rounds iteratively instead of recursively to prevent stack overflow on long agentic turns to fix latent stack overflow recursion bug 2026-09-03 16:09:41 -06:00
Dark-Alex-17 cb5b46800f feat: support auto continuation in subagents and prevent them from calling todo__pause 2026-09-03 15:50:00 -06:00
Dark-Alex-17 101b706be5 fix: session replays now include mid-turn messages so the full session gets replayed 2026-09-03 15:12:49 -06:00
Dark-Alex-17 9a5f587e74 test: deflake windows graph script tests
python3 first-start on fresh Windows runners (AV interpreter scans) blew
the 5s/10s/30s script timeouts. Drop the incidental python3 spawns from
the bash fixtures (pure-bash JSON extraction) and give the genuinely
python tests 60s headroom.
2026-09-03 14:09:14 -06:00
Dark-Alex-17 74b8c17392 perf: probe models-override staleness in the background refresh task 2026-09-03 13:48:02 -06:00
Dark-Alex-17 67cf8e42d9 docs: removed trailing whitespace in models.yaml generated header 2026-09-03 13:38:10 -06:00
Dark-Alex-17 154330c5a0 fix: resolve duplicate model ids by requested type 2026-09-03 13:25:37 -06:00
Dark-Alex-17 b50b033520 style: Removed redundant comments 2026-09-03 13:09:42 -06:00
Dark-Alex-17 3b01ae8f18 fix: let ctrl-c interrupt blocking job and agent collects 2026-09-03 13:03:10 -06:00
Dark-Alex-17 dc41e9d5df style: Cleaned up comments and organization of quirks.yaml file 2026-09-03 12:40:08 -06:00
Dark-Alex-17 49bd5d86b4 fix: skip terminal color-scheme queries in test builds 2026-09-03 12:35:12 -06:00
Dark-Alex-17 41d5fa9800 fix: memoize quirk glob patterns and isolate concurrent override writes 2026-09-03 11:17:58 -06:00
Dark-Alex-17 012212a998 feat: apply provider quirks to models created from a name
Unknown chat/reranker models resolved through the create-from-name
fallback now inherit their provider's family rules (require_max_tokens,
reasoning defaults, etc.) from the quirks overlay, and the model
completion table marks reasoning-capable models with a brain glyph.
2026-09-03 11:17:58 -06:00
Dark-Alex-17 f1cb6589bc feat: refresh the model catalog from live API data at runtime 2026-09-03 11:17:58 -06:00
Dark-Alex-17 539b57aded feat: generate the model catalog from live API data
Add a hidden --generate-models flag that rebuilds models.yaml from
models.dev and OpenRouter merged with the hand-owned quirks overlay,
regenerate the committed catalog with it (393 -> 1090 models), and
retire the Python updater. GitHub becomes fully quirks-owned since
upstream only tracks Copilot ids, legacy ids upstream dropped are
preserved as hand-owned quirks entries, and non-chat model families
(image/tts/audio/realtime) are excluded from generation.
2026-09-03 11:17:58 -06:00
Dark-Alex-17 2d7a759fc0 feat: add model catalog source adapters and merge engine 2026-09-03 11:17:58 -06:00
Dark-Alex-17 078e5c757d feat: add hand-owned model quirks overlay 2026-09-03 11:17:58 -06:00
Dark-Alex-17 af7d37890c fix: children subagents couldn't properly send messages to parent inboxes 2026-09-02 14:18:16 -06:00
Dark-Alex-17 c0a17031c5 feat: added tab completions to --update-bundle flag 2026-09-01 12:53:24 -06:00
Dark-Alex-17 affa5e7cef feat: added a dedicated config_dir output to coyote --info/.info 2026-09-01 10:51:41 -06:00
Dark-Alex-17 016f2654e4 fix: make binary shims for custom tools cross-device compatible so users can't accidentally break sandboxes via sbx cp ~/.config/coyote <sbx-name>:/home/agent/.config 2026-08-31 13:48:56 -06:00
Dark-Alex-17 f0661b4ea4 feat: Support Linux ARM64 GNU 2026-08-28 22:49:58 -06:00