Skip to content

feat: agent loop, tool layer, and skills runner on rig - #74

Merged
aksOps merged 1 commit into
mainfrom
feat-ai-skills-runner
Aug 16, 2026
Merged

feat: agent loop, tool layer, and skills runner on rig#74
aksOps merged 1 commit into
mainfrom
feat-ai-skills-runner

Conversation

@aksOps

@aksOps aksOps commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

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

  • Tool layer (internal/server/tools.go): propose_card (validated via the existing validateDraft path; the cap is enforced by a collector whose limit the model can see), find_similar (FTS via SearchSimilar), fetch_link (dedicated SSRF-guarded client with its own KB_LINK_ALLOW_PRIVATE policy, 64 KiB cap, text/json only), and list_tasks / get_task / update_task mirrors of the MCP tools.
  • Skills (internal/server/skills.go): embedded defaults under internal/server/skills/*.md, overridable per name from KB_DATA/skills. Names and descriptions are advertised in the system prompt; bodies load on demand via load_skill or 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 via http.NewResponseController past the 90s server write timeout (required a statusWriter.Unwrap).
  • ADR split is the first skill: /api/ai/stories keeps its exact response contract but internally drives the loop; the model calls propose_card once 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.
  • Tool scoping: paths that ingest third-party-authored text (the forge-issue ADR variant) run with a read-only tool scope — no update_task, no fetch_link — bounding prompt-injection blast radius. /api/ai/run-skill (user-authored input) gets the full set.
  • gpt-5/o-series models get max_tokens renamed to max_completion_tokens at the transport on the runner path, matching the single-shot path's usesMaxCompletionTokens behavior.

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), and fetch_link inheriting the forge private-address opt-in.

Testing

  • go build / go vet / gofmt clean; full suite go test ./...: 1247 tests, 6 packages, 0 failed (also race-clean).
  • Go coverage 97.1% (gate 96.4%); per-package all above the 95% floor.
  • Runner covered end-to-end against a scripted multi-turn fake OpenAI backend: tool rounds, card cap, partial results, tool scoping, budget-field rename, deadline plumbing (mutation-tested: reverting each fix fails its test).
  • Not verified: live gpt-5/o-series upstream (no key in this environment); real-model behavior of the adr-split skill against Ollama Cloud — worth a manual pass before release.

Closes #68.

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).
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedgolang/​github.com/​RandomCodeSpace/​rig@​v0.1.0100100100100100

View full report

@sonarqubecloud

Copy link
Copy Markdown

@aksOps

aksOps commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

Live validation against Ollama Cloud (qwen3.5:397b — no qwen3.6 exists on this account; closest available flagship):

  • POST /api/ai/test: ok:true (tool-calling probe), 1.7s
  • POST /api/ai/stories, 2 KiB ADR with 9 deliverables, max=10: 9 stories in 32.0s — content-driven count, no anchoring to the cap; all cards carried prio/effort/tags/checks
  • POST /api/ai/run-skill (skill=adr-split, same input): 10 cards + markdown commentary in 31.9s
  • POST /api/ai/stories with max=3: exactly 3 stories in 34.2s — server-side cap holds

All four requests HTTP 200, no retries needed. gpt-5/o-series budget-field rename remains unverified against a live upstream.

@aksOps

aksOps commented Aug 16, 2026

Copy link
Copy Markdown
Contributor Author

Second live validation, gemma4:31b (Ollama Cloud):

  • POST /api/ai/test: ok:true, 0.7s
  • POST /api/ai/stories, same 9-deliverable ADR, max=10: 9 stories in 7.3s
  • POST /api/ai/run-skill (adr-split): 9 cards + commentary in 7.2s
  • POST /api/ai/stories, max=3: exactly 3 in 10.0s

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.

@aksOps
aksOps marked this pull request as ready for review August 16, 2026 06:52
@aksOps
aksOps merged commit 005ba08 into main Aug 16, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AI: agent loop, tool layer, and skills runner

1 participant