Commit Graph
1341 Commits
Author SHA1 Message Date
Alex Clarke 73cf4a625b Merge pull request #29 from Dark-Alex-17/feat/PLAN-hooks
PLAN-hooks: external fire-and-forget lifecycle hook system
2026-09-16 13:59:45 -06:00
Dark-Alex-17 4087f3b3d0 style: applied improved styling to the whole of the hooks integration 2026-09-16 13:44:35 -06:00
Dark-Alex-17 0defc61bec test(TASK-035): run deep compress tests on a big-stack thread
The .compress-session success test polls through the whole summarization
call chain; those nested poll frames overflow the default test-thread
stack on Windows debug builds even with the outer future boxed. Drive
all four deep-compress tests through the same big-stack run_async
harness the macro tests already use.
2026-09-16 13:44:35 -06:00
Dark-Alex-17 7155b1b4fb docs(TASK-040): add hooks block to config.example.yaml 2026-09-16 13:44:35 -06:00
Dark-Alex-17 42380d4b82 feat(TASK-039): wire hooks into bundle installs and reconcile builtin hook dirs
Bundles: RemoteLayout.hooks + scan/is_empty/plan routing into hooks_dir,
a functional --filter hooks arm replacing the inert interim arm,
TopCategory::Hooks provenance rows, and per-file 'bundle defines hook
script' summary lines (visibility only, no approval prompt).

Reconciliation: new builtin_manifest module — a hidden per-directory
.builtin-manifest records the files the builtin installer actually owns
(written this run, previously owned, or pending failed deletions);
deletion is strictly manifest-minus-embed so user-created files in the
same directory are never touched. Wired into install_builtin_agents for
agents/<name>/hooks/ and a greenfield minimal Role::install_builtin_role_hooks
for roles/hooks/.

Hardening: bundles are barred from shipping any path component that
aliases .builtin-manifest (Unicode case fold + trailing dot/space,
directories included); manifest entries reuse the bundle store's
is_safe_component rules; malformed manifests fail safe toward keeping
files; role-side reconcile failures degrade to a warning like the
agent side.
2026-09-16 13:44:35 -06:00
Dark-Alex-17 e62502c862 test(TASK-038): adopt hook usage-probe regression script
Black-box scenarios against a built binary with dry_run configs: hook
cadence + env scoping, runtime inertness of failing hooks, --info firing
zero agent.* events, --install-builtins hooks install/force/cold-start
semantics, and end-to-end firing of the installed log-events.sh via the
documented relative-path wiring.
2026-09-16 13:44:35 -06:00
Dark-Alex-17 fc3bb259cb feat(TASK-038): add hooks builtin-asset category with example scripts and roles mixin scanning
- AssetCategory::Hooks + InstallFilter::Hooks (NAMES/parse/clap), reserving
  the 'hooks' bundle name via the existing AssetCategory::parse check
- HookAssets embed + install_builtin_hooks(force): installs the bundled
  example scripts 0755 into paths::hooks_dir() via write_file_atomic, wired
  into install_builtins() and install_assets(); warns once when
  COYOTE_HOOKS_DIR diverges from the config-dir default
- assets/hooks/notify.sh: notify-send -> osascript -> terminal fallback,
  with AppleScript-literal sanitization of model-influenced values
- assets/hooks/log-events.sh: appends a COYOTE_* env snapshot (secrets
  excluded, 0600 log, symlink-refusing) to ${COYOTE_HOOK_LOG:-/tmp/coyote-hooks.log}
- sbx-mixin discovery now scans roles/*.sbx-mixin.yaml and
  roles/hooks/*.sbx-mixin.yaml (mirroring the role-hook cwd)
- tests: install+0755+force, install_assets(Hooks) end-to-end, discover()
  roles scanning, reserved bundle name, no-ARGC-BUILD embed content, script
  content order + real execution (secret exclusion, tty-less fallback),
  CLI parser round-trips; hooks_dir env test made #[serial]
2026-09-16 13:44:35 -06:00
Dark-Alex-17 0c6b7c8594 fix(TASK-035): close agent-bracket leaks and prove compression/role-hook seams
- Open the top-level agent bracket only at committed dispatch sites so
  inspection-flag early returns (--list-sessions, --info, --macro,
  --rebuild-rag, --init-*, --build-tools) never leak agent.started
- Close the agent bracket ahead of process::exit in shell_execute's
  execute branch, where the dispatch wrapper's close is unreachable
- Extract the ask-loop auto-compression seam and cover the
  session.compressed success path at both call sites with sink tests
- Prove Session.role_hooks never serializes and that injected
  role_hooks YAML is ignored on deserialization
2026-09-16 13:44:35 -06:00
Dark-Alex-17 8710737964 feat(TASK-035): wire turn/session/compression seams + top-level agent bracket
Turn bracket (repl::TurnBracket): turn.started on entry and exactly one of
turn.{completed,interrupted,failed} on exit, with the interrupted-vs-failed
discrimination (abort_signal.aborted_ctrlc()) in one place. Wired at the
three outer boundaries: ask(), start_directive, and shell_execute — never at
the per-LLM-round before/after_chat_completion seams.

Session seams: session.started fires for newly created sessions only
(use_session's new_from_ctx paths; resume fires nothing), session.ended in
exit_session while the session is still attached, session.compressed on the
success path of both compress_session call sites (auto-compression and the
.compress command).

Session-held role hooks: Session snapshots the role's HooksMap on set_role,
clears it on clear_role/sync_agent, and re-reads it from the role file on
load; resolved_hooks gains a session leg so role hooks keep firing when the
role lives in the session (fresh set_role and resumed sessions alike).

Top-level agent bracket: agent.started/completed/failed once per agent RUN —
headless --agent dispatch and the interactive agent-context lifetime (enter
via .agent or startup; exit via switch-away or REPL teardown), never per
message. COYOTE_AGENT_ID is synthesized as top-<agent-name>-<nonce>.

Exit-path seams call hooks::drain_pending with a 2s bound so exit hooks
finish spawning before process teardown; interactive mid-session events
never drain.
2026-09-16 13:44:35 -06:00
Dark-Alex-17 363104fe77 fix(TASK-036): reuse hooks::base_envs_parts in job terminal hook firing 2026-09-16 13:44:35 -06:00
Dark-Alex-17 8f775dc2d9 fix(TASK-036): pin exact user__-prefixed COYOTE_TOOL_NAME on tool hook events 2026-09-16 13:44:35 -06:00
Dark-Alex-17 2731e98ed1 feat(TASK-036): fire tool, LLM, and job hook events at their seams
Wire the hook engine into the three runtime seams:

- tool.*: ToolCall::eval fires tool.started once the name and arguments
  are resolved, then exactly one of tool.completed/tool.failed,
  discriminated on both the Err path and tool_call_error-shaped outputs.
  The arguments JSON is handed to the engine as the payload; eval itself
  performs no payload-file I/O.
- llm.request.*: the three transport free functions
  (call_chat_completions, call_chat_completions_streaming, and the quiet
  graph-node variant) fire started/completed/failed for every provider
  and caller, classifying failures as aborted, api_error (with
  COYOTE_LLM_STATUS), or other.
- job.*: handle_job_tool fires job.started before either spawn and the
  terminal event inside the detached closures via a pre-resolved
  fire_resolved snapshot, so job__start's return is never delayed.

The test sink now captures the payload and cwd of each dispatch
(sink-only change), and seam tests pin event cadence, env contracts, and
byte-identical tool results and errors.
2026-09-16 13:44:35 -06:00
Dark-Alex-17 0c2a68ecc4 fix(TASK-037): cover genuine node failure payload and malformed graph.yaml hook degradation
Two test gaps: no test fired a genuine graph.node.failed and inspected
its payload (the only node-failure test asserted the hook's absence
because a fallback absorbed the error), and no test drove a malformed
hook definition through the new graph seams. The first test fails an
agent node with no fallback and asserts the captured envs carry the
node id, node type, a numeric duration, and a non-empty error while
the failure still propagates out of the executor. The second routes a
blank-command hook from graph.yaml's top level through the executor
seam and proves it degrades safely: the node completes, the malformed
hook is skipped with a debug log, and a well-formed sibling on the
same event still fires.
2026-09-16 13:44:35 -06:00
Dark-Alex-17 bd7cad21e2 feat(TASK-037): wire supervisor-agent and graph hook seams
Fire agent.started before the supervisor spawn and agent.completed/failed
from the spawn task's result arms, resolved against the child context so
global hooks stay gated by the child's own whitelist. Graph AgentNode
failures fire agent.failed at the point of failure, before a declared
fallback converts them into a successful route. The graph executor fires
graph.node.started before each branch spawn and graph.node.completed/failed
beside the narrate calls, with per-branch pre-resolved snapshots and
metadata so parallel super-step branches never cross-contaminate. Base
envs for detached dispatches are rebuilt at fire time via a shared
hook_base_envs helper.
2026-09-16 13:44:34 -06:00
Dark-Alex-17 0c4d0d777c feat(TASK-034): hook dispatch engine in src/hooks.rs
- HookEvent (22 dotted variants) + owned ResolvedHook snapshots
- RequestContext::resolved_hooks: global (gated by agent global_hooks)
  -> role (additive) -> agent precedence; per-scope cwds; unknown
  whitelist entries inert + debug-logged with agent name
- fire/fire_resolved: fire-and-forget detached dispatch via platform
  shell (sh -c / cmd /C raw_arg), null stdio, fresh unix process group,
  reap-only await, no-runtime guard (skip + debug, never panic)
- tool.* payload files: crypto-random nonce, create_new + 0600, verbatim
  JSON, best-effort delete after reap, hook still runs on write failure
- base env (COYOTE_EVENT/HOOK_NAME/CONFIG_DIR/EVENT_TIMESTAMP RFC3339
  UTC, SESSION_ID/AGENT_NAME when present) + per-event extras; every
  value truncated engine-side to 2048 bytes (UTF-8-safe; payload path
  documented exempt)
- drain_pending(timeout): opt-in exit-path seam with spawn-ack
  semantics (Drop-guard counter; never waits for child completion)
- #[cfg(test)] synchronous capture sink (records instead of spawning)
  + hooks-scoped debug capture in src/testing.rs (poison-proof,
  boundary-aware target prefix)
- Agent::hooks()/global_hooks() accessors; Role::hooks() dead_code
  marker removed

Engine compiles unused by design; call sites land in TASK-035/036/037.
2026-09-16 13:44:34 -06:00
Dark-Alex-17 b020e1b75e fix(TASK-033): cover hooks env overrides with tests and debug-log malformed hook config 2026-09-16 13:44:34 -06:00
Dark-Alex-17 9693cdd4ac feat(TASK-033): add hook config schema across all scopes
Introduce src/hooks.rs as a types-only module (HookDef, HooksMap) and
plumb hooks:/global_hooks: config fields through every scope:

- Config + AppConfig hooks field, both Default impls, the manual
  from_config copy, and a COYOTE_HOOKS env override
- Role frontmatter: hand-parsed hooks arm, private field, getter, and
  JSON-inline re-serialization in Role::export (malformed maps degrade
  to None)
- AgentConfig + Graph: hooks + global_hooks on both structs, copied in
  AgentConfig::from_graph, with a per-agent global_hooks env override
- paths::hooks_dir() = <config_dir>/hooks with COYOTE_HOOKS_DIR override
- Commented hooks: block in the global config template (global scope
  only; no global_hooks key)

No engine or dispatch logic yet; existing configs parse unchanged.
2026-09-16 13:44:34 -06:00
Dark-Alex-17 e4dfbe906c feat: updated sisyphus and architect agents so that when reviewing a PR, they add review round summaries as new comments rather than updating the PR description 2026-09-16 11:36:34 -06:00
Dark-Alex-17 fa7f96e9e8 Merge remote-tracking branch 'refs/remotes/origin/main' 2026-09-16 10:18:21 -06:00
Dark-Alex-17 5046aebca3 feat: support config-driven OAuth endpoints on the openai and gemini clients 2026-09-16 10:17:05 -06:00
github-actions[bot] 1d6823ca0c chore: refresh generated model catalog [skip ci] 2026-09-16 12:33:39 +00:00
Dark-Alex-17 9fb90be851 fix: added additional constraints around parallelization bugs in verification tasks 2026-09-16 00:36:33 -06:00
Dark-Alex-17 4cc5563ba8 feat: support config-driven OAuth endpoints on the claude client
- ClaudeConfig gains an oauth: block (custom endpoints, e.g. a private
  gateway); without it, auth: oauth keeps the stock Claude Pro/Max provider
- Claude-Code system-prefix spoof + anthropic-beta header are only sent on
  the stock provider path
- OAuth tokens are stamped with an issuer fingerprint (token_url|client_id)
  so switching endpoints never replays a token against the wrong issuer
- All auth flows refresh the in-memory access-token cache on save, so
  .authenticate mid-session takes effect immediately
- A custom oauth: block now requires api_base: refusing to silently fall
  back to api.anthropic.com prevents sending a gateway token to the wrong
  host
2026-09-15 23:51:51 -06:00
Dark-Alex-17 fcc0049ab2 feat: further increased budgets for adversary and code reviewer agents 2026-09-15 23:09:59 -06:00
Dark-Alex-17 dca9b1553e test: bumped the adversary's holistic max iterations from 20 to 30 in the tests 2026-09-15 21:41:13 -06:00
Dark-Alex-17 ea31236d29 Merge branch 'main' of github.com:Dark-Alex-17/coyote 2026-09-15 20:06:16 -06:00
Dark-Alex-17 d16db663df feat: increased resource budgets for review suite 2026-09-15 20:06:07 -06:00
github-actions[bot] 94d48fb76e chore: refresh generated model catalog [skip ci] 2026-09-16 00:52:03 +00:00
Dark-Alex-17 6c50c60c22 feat: improve the code review suite to support larger PRs 2026-09-15 15:14:25 -06:00
Dark-Alex-17 f31885ba07 test: fixed tests for the new finding-verifier agent changes 2026-09-15 15:04:48 -06:00
Dark-Alex-17 fd26f43b84 feat: Improved the code-reviewer suite so it doesn't need to loop as frequently for failed reviews based on the finding-verifier (which may need many round trips to verify large PRs) 2026-09-15 14:50:39 -06:00
Dark-Alex-17 e240be8bda feat: improved the adversary agent to look for facts and not criteria. 2026-09-15 12:02:16 -06:00
Dark-Alex-17 9e2f3c0f12 feat: auto continuation is unavailable in llm nodes; continuation driven loops should be in agent nodes only
CI / All (ubuntu-latest) (push) Failing after 28s
CI / All (macos-latest) (push) Canceled after 0s
CI / All (windows-latest) (push) Canceled after 0s
2026-09-15 11:42:39 -06:00
Dark-Alex-17 8746e3e29a Merge branch 'main' of github.com:Dark-Alex-17/coyote 2026-09-15 11:14:24 -06:00
Dark-Alex-17 5b9852d80e fix: Require injection of user interaction functions for LLM nodes to be explicit 2026-09-15 11:13:12 -06:00
github-actions[bot] 99d4b20ac3 chore: refresh generated model catalog [skip ci] 2026-09-15 12:32:39 +00:00
github-actions[bot] 17864c8864 chore: refresh generated model catalog [skip ci] 2026-09-15 01:14:26 +00:00
github-actions[bot] 2a04c4f5e1 chore: bump Cargo.toml and sandbox image to 0.10.3 2026-09-15 00:00:52 +00:00
github-actions[bot] ca58176ef9 bump: version 0.10.2 → 0.10.3 [skip ci] 2026-09-15 00:00:48 +00:00
Dark-Alex-17 cfb83a629e feat: create a config alias for default_reasoning_level (to match some wording and make the config flexible)
CI / All (ubuntu-latest) (push) Failing after 30s
CI / All (macos-latest) (push) Canceled after 0s
CI / All (windows-latest) (push) Canceled after 0s
2026-09-14 17:47:01 -06:00
Dark-Alex-17 8377f8287b feat: support custom resource definitions for openai-compatible Oauth customization 2026-09-14 17:46:44 -06:00
Dark-Alex-17 ffb75cb168 feat: Support specifying the compression model to use when compressing a session for greater cost controls 2026-09-14 15:49:44 -06:00
Dark-Alex-17 58b0dbd812 feat: Added full cost tracking to Coyote and added it to the default right prompt 2026-09-14 15:24:48 -06:00
Dark-Alex-17 bd5c0a7cdd chore: updated the models.yaml to incorporate cached read/write prices pulled from models.dev and openrouter 2026-09-14 14:47:22 -06:00
Dark-Alex-17 d84dea21b6 feat: added support for input/output token cache cost tracking 2026-09-14 14:47:01 -06:00
Dark-Alex-17 755b25f9b2 fix: empty tool results can't cause errors in bedrock, claude, openai, or vertexai clients anymore 2026-09-14 14:46:46 -06:00
Dark-Alex-17 23f941b09f fix: proper support for reasoning/thinking in bedrock models 2026-09-14 14:46:15 -06:00
Dark-Alex-17 77da48a40f feat: Support persisting paused todo lists to sessions so users can exit and resume paused todo sessions; Also fixed a bug so todo list pausing is only supported when being used in a session since it typically requires multi-turn communication 2026-09-14 13:57:08 -06:00
Dark-Alex-17 5d59adadbc feat: Support token caching to reduce LLM costs in Anthropic models (not typically handled automatically by APIs) 2026-09-14 13:56:13 -06:00
Alex Clarke 9a6ffcb8ca Merge pull request #28 from Dark-Alex-17/feat/PLAN-review-retry
PLAN-review-retry: self-healing review gate (fault-only lane retries) + untimed approvals
2026-09-14 11:46:15 -06:00