Six closed tasks for consult: registry, CONSULT_WAIT, [consult]/[secrets], ToolName and grants, Decision body, loopback HTTP. Reference is the git bundle ~/boxmaker-refs/m6b-ref.bundle at 5fb05f0. Gate after task 06 is 1611. Co-Authored-By: Grok 4.6 <noreply@x.ai>
180 lines
7.2 KiB
Markdown
180 lines
7.2 KiB
Markdown
# M6b task 01: `consult` in the M5c registry, not core
|
|
|
|
**Branch:** `m6b`. Check it: `git branch --show-current` prints `m6b` and `git status --short`
|
|
is empty; otherwise stop. Never switch branch.
|
|
**Commit subject:** `loopd: consult in the M5c registry, not core`
|
|
**Log row:** the Task cell is `M6b/01-loopd-consult-registry`.
|
|
|
|
**First action.** Run this before any Read of crate source. Do not `ls` `crates/loopd/tests/`.
|
|
Do not Read `tests/support/`, `turn.rs`, `session.rs`, `docs/implementer-log.md` (except the
|
|
first 12 lines at the log step). The signatures below are complete.
|
|
|
|
```sh
|
|
cp docs/plans/M6b/files/crates/loopd/tests/consult_registry.rs crates/loopd/tests/
|
|
```
|
|
|
|
## Goal
|
|
|
|
`consult` is in `Registry::m5c()`, not core. `find_tool` finds it. A new session's epoch
|
|
`tools` array stays `clock`, `recall`, `memory`, `ask_memory`, `find_tool`, `call_tool`
|
|
(spec 4). `loopd` does not answer the call: `dispatch` already Ports every non-core name
|
|
other than `subagent` to `brokerd`.
|
|
|
|
## Every place that changes
|
|
|
|
| Place | What happens there |
|
|
|---|---|
|
|
| `crates/loopd/src/consult.rs` | new: `CONSULT`, `schema()` |
|
|
| `crates/loopd/src/lib.rs` | `pub mod consult;` |
|
|
| `crates/loopd/src/tools.rs` | `m5c()` pushes the non-core entry after `subagent` |
|
|
| `crates/loopd/tests/consult_registry.rs` | new, given |
|
|
| everything else | **no change**: not `dispatch`, not `broker_port.rs` |
|
|
|
|
## Files
|
|
|
|
- Copy, from `docs/plans/M6b/files/` (the same path under it): the new test
|
|
`crates/loopd/tests/consult_registry.rs`.
|
|
- Create: `crates/loopd/src/consult.rs` (the module below).
|
|
- Modify: `crates/loopd/src/lib.rs`, `crates/loopd/src/tools.rs`,
|
|
`docs/implementer-log.md`.
|
|
- Do not touch: any other file.
|
|
|
|
At the log-and-commit step, read only the first 12 lines of `docs/implementer-log.md`.
|
|
|
|
## Facts you need
|
|
|
|
- **Not core.** `core_schemas()` already filters `e.core`. A non-core `Entry` is found by
|
|
`find` and by `get`, and is absent from `Baseline.tools`.
|
|
- **`m5c()` only.** Do not add the entry to `m2b`, `m3a`, or `m5a`. `loopd serve` uses `m5c`.
|
|
- **`push`, after `subagent`.** `ask_memory` stays at index 3. `consult` is last among the
|
|
non-core names.
|
|
- rustfmt `mod` order: `consult` after `config` / before `cron` as rustfmt decides.
|
|
- Same-crate modules may import each other. This task's module imports nothing from
|
|
`turn` or `tools`.
|
|
- The items the edits use. This table is complete.
|
|
|
|
| Item | Signature |
|
|
|---|---|
|
|
| `ToolSchema` | `{ name: String, description: String, parameters: serde_json::Value }` in `crate::llama` |
|
|
| `Entry` | `{ schema: ToolSchema, core: bool }` |
|
|
| `Registry::m5c` | `m5c() -> Registry` |
|
|
| `Registry::get` | `get(&self, name: &str) -> Option<&Entry>` |
|
|
| `Registry::find` | `find(&self, query: &str) -> Vec<&ToolSchema>` |
|
|
| `Registry::core_schemas` | `core_schemas(&self) -> Vec<ToolSchema>` |
|
|
|
|
## The edits, exactly
|
|
|
|
### `crates/loopd/src/consult.rs`
|
|
|
|
Write this module. Do not add a wait constant, a parse, or a runtime (later tasks).
|
|
|
|
```rust
|
|
//! The `consult` tool: `brokerd` decides it and POSTs an allowlisted body (M6 spec, section 4).
|
|
//! It is not core; the parent finds it with `find_tool` and calls it through `call_tool`.
|
|
|
|
pub const CONSULT: &str = "consult";
|
|
|
|
pub fn schema() -> crate::llama::ToolSchema {
|
|
crate::llama::ToolSchema {
|
|
name: CONSULT.to_string(),
|
|
description: "Ask a remote model a question. The session history is not sent. Needs a grant from the owner.".to_string(),
|
|
parameters: serde_json::json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"question": {
|
|
"type": "string",
|
|
"description": "The question to send. Nothing else of the session is included."
|
|
}
|
|
},
|
|
"required": ["question"]
|
|
}),
|
|
}
|
|
}
|
|
```
|
|
|
|
### `crates/loopd/src/lib.rs`
|
|
|
|
**L1.** After `pub mod config;` add `pub mod consult;`. rustfmt decides the final order.
|
|
|
|
### `crates/loopd/src/tools.rs`
|
|
|
|
**R1.** The lines (exactly once, inside `m5c`)
|
|
|
|
```rust
|
|
entries.push(Entry {
|
|
schema: crate::subagent::schema(),
|
|
core: false,
|
|
});
|
|
Registry::new(entries)
|
|
```
|
|
|
|
become
|
|
|
|
```rust
|
|
entries.push(Entry {
|
|
schema: crate::subagent::schema(),
|
|
core: false,
|
|
});
|
|
entries.push(Entry {
|
|
schema: crate::consult::schema(),
|
|
core: false,
|
|
});
|
|
Registry::new(entries)
|
|
```
|
|
|
|
## Steps
|
|
|
|
- [ ] **1. Copy the given test.**
|
|
|
|
```sh
|
|
cp docs/plans/M6b/files/crates/loopd/tests/consult_registry.rs crates/loopd/tests/
|
|
```
|
|
|
|
- [ ] **2. See it fail.** `cargo build --tests --keep-going -p loopd`, with a shell timeout of
|
|
600000 ms: test target `consult_registry` does not compile (`E0432` unresolved
|
|
`loopd::consult`). Every other target compiles.
|
|
- [ ] **3. The edits.** Write `consult.rs`, L1, R1. `cargo check -p loopd` prints no error
|
|
and no warning. `wc -l crates/loopd/src/consult.rs` and `wc -l crates/loopd/src/tools.rs`
|
|
each ≤ 500.
|
|
- [ ] **4. The tests.** `cargo test -p loopd --test consult_registry --test subagent_registry
|
|
--test ask_memory_tool --test tools --test baseline`: every test passes, 2 in
|
|
`consult_registry`.
|
|
- [ ] **5. Check.** `git diff --stat` lists exactly `crates/loopd/src/consult.rs`,
|
|
`crates/loopd/src/lib.rs`, `crates/loopd/src/tools.rs`. `git status --short` also shows
|
|
the new test as untracked.
|
|
- [ ] **6. Run the gate.** `cargo fmt --all`, then `make gate`, with a shell timeout of
|
|
600000 ms. Expected last line: `gate: ok`. That is done counting: **1592** (1590 before,
|
|
plus the 2 of `consult_registry.rs`). After `gate: ok`, do not add up `test result:`
|
|
lines and do not run `cargo test --workspace`.
|
|
- [ ] **7. Log and commit.** Add your row to `docs/implementer-log.md`; its Task cell is
|
|
`M6b/01-loopd-consult-registry`. Read only the first 12 lines of that file; insert the
|
|
row under the header. Stage with
|
|
`git add crates/loopd docs/implementer-log.md Cargo.lock`, then commit as `AGENTS.md`
|
|
says. `Cargo.lock` does not change in this task; the `git add` is harmless.
|
|
|
|
## Done when
|
|
|
|
- `make gate` prints `gate: ok` with 1592 tests.
|
|
- `git diff HEAD~1 --stat` lists only `crates/loopd/src/consult.rs`,
|
|
`crates/loopd/src/lib.rs`, `crates/loopd/src/tools.rs`,
|
|
`crates/loopd/tests/consult_registry.rs` and `docs/implementer-log.md`.
|
|
|
|
## Stop and report if
|
|
|
|
- The branch check at the top fails.
|
|
- A "before" block is not in its file exactly as shown, or is there more than once.
|
|
- Step 2 shows a different result: the tests compile, or a different crate fails.
|
|
- `cargo check` in step 3 prints an error or a warning. Quote it, and stop.
|
|
- A test fails in step 4. Do not change the test: stop, and give the failing tests' names
|
|
and their messages.
|
|
- The fix seems to need a change anywhere else. It does not; stop and say why you think so.
|
|
- A test outside `consult_registry.rs` fails in the gate: check once whether it fails
|
|
without your change (`git stash -u`, run it, `git stash pop`), then stop and report both
|
|
results.
|
|
|
|
## What the given tests pin
|
|
|
|
`consult` is in `m5c()`, `core` is false, `schema()` matches the entry, `find("consult")`
|
|
and `find("remote")` both hit it, `subagent` is still present, and a baseline assembled
|
|
from `m5c()` still lists only the six core names in `tools`.
|