Bootstrap rein-openweights: minimal agentic loop over OpenRouter (REIN-OW-WP-0001)
Implements T01-T04: - tools.py: green-commit-only-equivalent tool surface (read/write/edit/ glob/grep + git status/diff/log/add+commit), path-traversal guarded. - openrouter_client.py: own minimal chat-completions client — llm-connect's OpenRouterAdapter takes a single prompt string and never surfaces tool_calls, so it can't drive a multi-turn tool-calling loop without a breaking change to its frozen Core ABC. llm-connect stays an optional dependency (pyproject.toml), not load-bearing. - loop.py: plan -> tool call -> observe -> repeat, budget- and turn-bounded, tool errors reported back to the model instead of crashing the loop. - credentials.py: own OpenBao AppRole/ambient-token acquisition, per glas-harness ADR-002 (Option B) — glas-harness does not broker this. - runner.py/hub.py: commit-verified success criterion + State Hub progress/token reporting, mirroring rein-aharness's model. 26 tests, all mocked at the httpx/subprocess boundary — no real OpenRouter or OpenBao calls made. T05 (Forgejo repo creation) stays open, deferred to the operator. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
ac5407a83e
commit
4ee612140b
21 changed files with 1207 additions and 36 deletions
|
|
@ -12,54 +12,72 @@ to implement the glas-harness rein contract once
|
|||
|
||||
## Task: Pick the starter open-weight model + OpenRouter path
|
||||
|
||||
Confirm `llm-connect` already supports the intended model class (check
|
||||
its existing OpenRouter integration, used today by rein-aharness's
|
||||
mail-triage/brief-daily paths for structured JSON — but not for a
|
||||
multi-turn tool-use loop). Identify gaps: streaming tool-call support,
|
||||
function-calling schema compatibility for the chosen open-weight model.
|
||||
Checked `llm-connect`'s existing OpenRouter integration
|
||||
(`OpenRouterAdapter.execute_prompt`): it takes a single prompt string,
|
||||
builds a fixed `[system, user]` message pair itself, and never surfaces
|
||||
`message.tool_calls` in its response — it cannot drive a multi-turn
|
||||
tool-calling loop without a breaking change to llm-connect's frozen
|
||||
Core `LLMAdapter` ABC. Decision: rein-openweights uses its own minimal
|
||||
OpenRouter client (`openrouter_client.py`) for the agentic loop instead;
|
||||
`tools`/`tool_choice` already pass through llm-connect's own
|
||||
`OPENAI_CHAT_PASSTHROUGH_FIELDS` allow-list, confirming the request
|
||||
shape is standard OpenAI-compatible function-calling, just not
|
||||
round-tripped by that adapter today. Starter model is a `--model`-configurable
|
||||
default (`meta-llama/llama-3.1-70b-instruct`), not hardcoded.
|
||||
|
||||
```task
|
||||
id: REIN-OW-WP-0001-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
## Task: Minimal agentic loop
|
||||
|
||||
Implement plan → tool call → observe → repeat with a hard tool allow-list
|
||||
matching rein-aharness's `green-commit-only` (Read/Write/Edit/Glob/Grep +
|
||||
local git add/commit/status/log/diff, no push/network/shell), bounded by
|
||||
a turn/token budget (reuse `llm-connect`'s `BudgetTracker` the way
|
||||
rein-aharness's runner does).
|
||||
Implemented in `loop.py` + `tools.py`: plan → tool call → observe →
|
||||
repeat with a hard tool allow-list matching rein-aharness's
|
||||
`green-commit-only` (`read_file`/`write_file`/`edit_file`/`glob_files`/
|
||||
`grep_files` + `git_status`/`git_diff`/`git_log`/`git_add_commit`, no
|
||||
push/network/shell), bounded by `max_turns` and a token budget. Budget
|
||||
tracker is vendored locally (`budget.py`), not `llm-connect`'s —
|
||||
consistent with T01/ADR-002 keeping llm-connect optional. Path-traversal
|
||||
guarded (`_resolve`); tool errors are reported back to the model as a
|
||||
`role: tool` message rather than crashing the loop. 26 tests, all
|
||||
mocked at the `httpx`/subprocess boundary.
|
||||
|
||||
```task
|
||||
id: REIN-OW-WP-0001-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
## Task: Success criterion + reporting
|
||||
|
||||
Mirror rein-aharness's model: a local git commit is the sole success
|
||||
signal, State Hub progress/token event on completion, metrics written in
|
||||
a comparable format so the two reins are measurable side by side.
|
||||
Implemented in `runner.py`/`hub.py`: a local git commit is the sole
|
||||
success signal (`RunResult.ok == committed`), State Hub progress event
|
||||
(`executor_run`) and token event posted on completion via a hub module
|
||||
mirroring rein-aharness's, `--no-hub` to skip. Not yet exercised against
|
||||
a live State Hub call in this pass (mocked in tests) — same caveat as
|
||||
rein-aharness/glas-harness's own not-yet-live-run notes elsewhere in
|
||||
this rein family.
|
||||
|
||||
```task
|
||||
id: REIN-OW-WP-0001-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
```
|
||||
|
||||
## Task: Credential brokering
|
||||
|
||||
Resolve per glas-harness `GLAS-WP-0001-T06`: OpenRouter/llm-connect
|
||||
credential acquisition either brokered by glas-harness or done directly
|
||||
here via OpenBao/ops-warden. Do not hardcode a choice before that ADR
|
||||
addendum lands.
|
||||
Resolved by glas-harness `docs/adr/ADR-002-credential-brokering-and-composable-reins.md`
|
||||
(Option B): rein-openweights acquires its own OpenRouter credential.
|
||||
Implemented in `credentials.py`, mirroring rein-aharness's mailscan.py
|
||||
OpenBao AppRole/ambient-token pattern (explicit env var → AppRole
|
||||
exchange → ambient token → single `kv get`). glas-harness does not
|
||||
broker this.
|
||||
|
||||
```task
|
||||
id: REIN-OW-WP-0001-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
```
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue