[Experiment] Lazy tool discovery: gitea_get_tools(category) loads schemas on demand #50
Labels
No labels
area/dsh
area/forgejo
experiment
priority/later
priority/next
priority/now
type/bug
type/task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
dsh-plugins/dsh-gitea#50
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Origin
Operator's idea draft (
idea.txt, 2026-10-24) after the payload measurement in #48 / #49. Original working title:[Idea/Feature] Toolset Redesign: Remove legacy bloat and implement Lazy-Loading (KISS).The concept: expose only a meta-tool at boot (
gitea_get_tools(category)); when the agent needs Gitea work it asks for a category (issues,wiki,actions,prs,repos,customize) and only those schemas enter the context. Acustomizecategory holdsgitea_favorite(action, tool_name)(always-loaded favourites, a lazy-load blacklist) andgitea_lazy-tools(enable)plus a settings-UI toggle; with lazy mode disabled the plugin behaves exactly as today.Original acceptance criteria from the draft
gitea_get_toolsmeta-tool.gitea_favoritekeeps preferred tools in the always-loaded context.What the harness actually does (DSH 0.2.1-rc.2, from the installed packages)
dsh-tools).tool-additionrecords; the visible set changes and the request prefix changes, so KV cache invalidates "from the first changed schema token" (dsh-tools,dsh-llmprojectToolUpdates).deferLoading: trueexists and is preserved through projection, but the docs are explicit: "declaring a deferred tool does not activate it" and provider enforcement is limited.Item 4 is the crux: lazy loading here is additive, not replacing. A session that loads
issuesthenprscarries base + issues + prs + the meta-tool, and never gets that memory back. The saving exists only for sessions that touch few categories.What the data says (28 sessions, 1,020 unique calls)
So the optimistic case is real but narrow, and the pessimistic case can end up larger than today (meta-tool + favourites + every loaded category). The 12 dead sessions are better served by #49, which is the only lever that removes the payload entirely.
Measurement-first plan (spike, not a shippable design yet)
preset: lazy), default unchanged.usagerecord.fullandcore:UNKNOWN_TOOLrateAcceptance criteria (spike gate)
Impact
If it works, the base footprint drops to a few hundred bytes for sessions that only file one issue — the draft's stretch goal. If it does not, we will have a measured "no" and stop wondering, which is worth the spike on its own.
Boundaries
gitea_favorite, nogitea_lazy-toolsbefore the spike decides.Dependencies
#48 (alias purge) and #49 (presets) are the cheaper levers and should land first. This experiment is only justified if
core+ presets still leave too much on the table. The cache-safe alternative is the dispatcher experiment.Deferred by decision (2026-10-24), not closed: this is a measured no candidate until the dispatcher (#51) reports.
Rationale from the issue's own analysis, which holds up against the implementation now on master:
issuesthenprscarries base + issues + prs + the meta-tool and never gets the memory back. The window where it wins is sessions touching ≤2 categories.preset: none(or a narrow preset) removes the payload at mount with no runtime machinery, notool-additionrecords, and no KV-cache invalidation. That was the strongest argument in this issue, and it is shipped in 0.8.5.tool-addition/deferLoadingbehaviour before DSH 1.0.Plan:
experiment/dispatcheris branched offv0.8.5for #51. If the dispatcher spike wins on prompt tokens and first-try argument accuracy, this issue is moot (the dispatcher is the better cache-safe shape) and closes as won't do. If the dispatcher loses, the remaining case for lazy loading is the narrow ≤2-category window — and then this issue gets a timeboxed prototype behindpreset: lazyto measure that window before anything else (favourites, toggles, settings UI) is built.Keeping it open so the deferred spike is not mistaken for an accepted design.
Closed as won't do — this is now #51's shape, and the operator has chosen the dispatcher.
The deciding argument is the one this issue itself identified: lazy loading is additive. Schemas delivered as results stay in append-only history, the registry changes when categories load (invalidating the prefix), and a session that touches four categories ends up larger than today. #51 keeps the registry stable and delivers schemas as append-only tool results, so it gets the same "don't pay for what you don't use" benefit without betting on
tool-addition/deferLoadingbehaviour before DSH 1.0.Also, the part of this issue that was independently valuable is already shipped:
preset: none(and the narrow presets) in 0.8.5 removes the payload entirely for the 12/28 sessions that never call a Gitea tool, with zero runtime machinery.The analysis in the body stays as the record of why the additive route was rejected; no prototype will be built.
experiment/dispatchercarries the spike.