185 lines
7.2 KiB
Markdown
185 lines
7.2 KiB
Markdown
# M6a task 01: `subagent` in the M5c registry, not core
|
|
|
|
**Branch:** `m6a`. Check it: `git branch --show-current` prints `m6a` and `git status --short`
|
|
is empty; otherwise stop. Never switch branch.
|
|
**Commit subject:** `loopd: subagent in the M5c registry, not core`
|
|
**Log row:** the Task cell is `M6a/01-loopd-subagent-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/M6a/files/crates/loopd/tests/subagent_registry.rs crates/loopd/tests/
|
|
```
|
|
|
|
## Goal
|
|
|
|
`subagent` 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 3.2). `loopd` does not answer the call yet (task 02).
|
|
|
|
## Every place that changes
|
|
|
|
| Place | What happens there |
|
|
|---|---|
|
|
| `crates/loopd/src/subagent.rs` | new: `SUBAGENT`, `schema()` |
|
|
| `crates/loopd/src/lib.rs` | `pub mod subagent;` |
|
|
| `crates/loopd/src/tools.rs` | `m5c()` pushes the non-core entry |
|
|
| `crates/loopd/tests/subagent_registry.rs` | new, given |
|
|
| everything else | **no change**: not `dispatch`, not `turn.rs` |
|
|
|
|
## Files
|
|
|
|
- Copy, from `docs/plans/M6a/files/` (the same path under it): the new test
|
|
`crates/loopd/tests/subagent_registry.rs`.
|
|
- Create: `crates/loopd/src/subagent.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`, not `insert`.** `ask_memory` stays at index 3. `subagent` is last among the
|
|
non-core names, after `http_fetch`.
|
|
- rustfmt `mod` order: `subagent` after `sse` / before `summarise` 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/subagent.rs`
|
|
|
|
Write this module. Do not add `parse_task`, `dispatch_args`, or `run` (task 02 / 03).
|
|
|
|
```rust
|
|
//! The `subagent` tool: loopd answers it itself (M6 spec, section 3).
|
|
//! It is not core; the parent finds it with `find_tool` and calls it through `call_tool`.
|
|
|
|
pub const SUBAGENT: &str = "subagent";
|
|
|
|
pub fn schema() -> crate::llama::ToolSchema {
|
|
crate::llama::ToolSchema {
|
|
name: SUBAGENT.to_string(),
|
|
description: "Run a short task in an isolated child session on the background slot."
|
|
.to_string(),
|
|
parameters: serde_json::json!({
|
|
"type": "object",
|
|
"properties": {
|
|
"task": {
|
|
"type": "string",
|
|
"description": "What the child should do."
|
|
}
|
|
},
|
|
"required": ["task"]
|
|
}),
|
|
}
|
|
}
|
|
```
|
|
|
|
### `crates/loopd/src/lib.rs`
|
|
|
|
**L1.** After `pub mod sse;` add `pub mod subagent;`. rustfmt decides the final order.
|
|
|
|
### `crates/loopd/src/tools.rs`
|
|
|
|
**R1.** The lines (exactly once, inside `m5c`)
|
|
|
|
```rust
|
|
entries.insert(
|
|
3,
|
|
Entry {
|
|
schema: crate::memory::ask_memory_schema(),
|
|
core: true,
|
|
},
|
|
);
|
|
Registry::new(entries)
|
|
```
|
|
|
|
become
|
|
|
|
```rust
|
|
entries.insert(
|
|
3,
|
|
Entry {
|
|
schema: crate::memory::ask_memory_schema(),
|
|
core: true,
|
|
},
|
|
);
|
|
entries.push(Entry {
|
|
schema: crate::subagent::schema(),
|
|
core: false,
|
|
});
|
|
Registry::new(entries)
|
|
```
|
|
|
|
## Steps
|
|
|
|
- [ ] **1. Copy the given test.**
|
|
|
|
```sh
|
|
cp docs/plans/M6a/files/crates/loopd/tests/subagent_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 `subagent_registry` does not compile (`E0432` unresolved
|
|
`loopd::subagent`). Every other target compiles.
|
|
- [ ] **3. The edits.** Write `subagent.rs`, L1, R1. `cargo check -p loopd` prints no error
|
|
and no warning. `wc -l crates/loopd/src/subagent.rs` and `wc -l crates/loopd/src/tools.rs`
|
|
each ≤ 500.
|
|
- [ ] **4. The tests.** `cargo test -p loopd --test subagent_registry --test ask_memory_tool
|
|
--test tools --test baseline`: every test passes, 2 in `subagent_registry`.
|
|
- [ ] **5. Check.** `git diff --stat` lists exactly `crates/loopd/src/subagent.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: **1577** (1575 before,
|
|
plus the 2 of `subagent_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
|
|
`M6a/01-loopd-subagent-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 1577 tests.
|
|
- `git diff HEAD~1 --stat` lists only `crates/loopd/src/subagent.rs`,
|
|
`crates/loopd/src/lib.rs`, `crates/loopd/src/tools.rs`,
|
|
`crates/loopd/tests/subagent_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 `subagent_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
|
|
|
|
`subagent` is in `m5c()`, `core` is false, `schema()` matches the entry, `find("subagent")`
|
|
and `find("isolated")` both hit it, and a baseline assembled from `m5c()` still lists only
|
|
the six core names in `tools`.
|