feat: agent loop, tool layer, and skills runner on rig - #74
Conversation
Adopt github.com/RandomCodeSpace/rig v0.1.0 for the bounded tool-call loop and skills infrastructure; kb contributes tools, skills, config, and HTTP. - tools: propose_card (validated, cap enforced by a visible collector), find_similar (FTS), fetch_link (SSRF-guarded client with its own KB_LINK_ALLOW_PRIVATE policy, 64 KiB / text-or-json only), plus list_tasks, get_task, update_task mirrors of the MCP tools - skills: embedded defaults under internal/server/skills with KB_DATA/skills overrides, advertised in the system prompt, bodies via load_skill or force-injected on explicit invocation - POST /api/ai/run-skill: generic runner endpoint returning proposed cards and markdown commentary; 12-round / 4-minute bound with the response write deadline extended past the server write timeout - ADR split reworked as the adr-split skill on the runner: the model proposes one card per story it finds, removing the story-count anchor; /api/ai/stories keeps its exact response contract and runs with a read-only tool scope (no update_task/fetch_link on paths that ingest third-party issue text) - max_tokens renamed to max_completion_tokens for gpt-5/o-series models at the transport, preserving the single-shot path's behavior Story draft and import remain on the legacy single-shot pipeline (#69).
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
|
Live validation against Ollama Cloud (qwen3.5:397b — no qwen3.6 exists on this account; closest available flagship):
All four requests HTTP 200, no retries needed. gpt-5/o-series budget-field rename remains unverified against a live upstream. |
|
Second live validation, gemma4:31b (Ollama Cloud):
All HTTP 200 first try. Both validated backends (qwen3.5:397b, gemma4:31b) independently produced 9 stories from the 9-deliverable document under a cap of 10 — the count now tracks content, not the cap. Gemma omits emoji and writes leaner checklists; all cards still pass validation. |



Implements the agent loop, tool layer, and skills runner from #68, built on the new rig library (v0.1.0) extracted from kb's AI substrate.
What changed
internal/server/tools.go):propose_card(validated via the existingvalidateDraftpath; the cap is enforced by a collector whose limit the model can see),find_similar(FTS viaSearchSimilar),fetch_link(dedicated SSRF-guarded client with its ownKB_LINK_ALLOW_PRIVATEpolicy, 64 KiB cap, text/json only), andlist_tasks/get_task/update_taskmirrors of the MCP tools.internal/server/skills.go): embedded defaults underinternal/server/skills/*.md, overridable per name fromKB_DATA/skills. Names and descriptions are advertised in the system prompt; bodies load on demand viaload_skillor are force-injected on explicit invocation.POST /api/ai/run-skill(internal/server/runner.go): generic runner endpoint returning{cards, commentary}so new skills need no new endpoints. 12-round / 4-minute bound; the response write deadline is extended viahttp.NewResponseControllerpast the 90s server write timeout (required astatusWriter.Unwrap)./api/ai/storieskeeps its exact response contract but internally drives the loop; the model callspropose_cardonce per story it actually finds. The "at most N stories" prompt is gone — the count anchor with it; the cap is now purely server-side.update_task, nofetch_link— bounding prompt-injection blast radius./api/ai/run-skill(user-authored input) gets the full set.max_tokensrenamed tomax_completion_tokensat the transport on the runner path, matching the single-shot path'susesMaxCompletionTokensbehavior.Story draft and import stay on the legacy single-shot pipeline; migrating them and deleting that pipeline is #69.
Review findings already addressed
Built via a multi-agent workflow with adversarial review; fixes landed before this PR: the write-deadline no-op through
withLogging, side-effect tools reachable from third-party text, partial results discarded on budget errors (cards proposed before an iteration/output limit now return 200 with the failure noted in commentary), andfetch_linkinheriting the forge private-address opt-in.Testing
go build/go vet/gofmtclean; full suitego test ./...: 1247 tests, 6 packages, 0 failed (also race-clean).Closes #68.