You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Pick the entries of the model-visible skill catalog per request by relevance to the user's message, using the classification provider from #16180, the same way #16181 selects deferred tools.
Today resolveSkillCatalog (packages/api/src/agents/skills.ts) fills the catalog with the first SKILL_CATALOG_LIMIT = 100 active skills in listing order. endpoints.agents.skills.maxCatalogSkills can lower that number but not change which skills are picked, and skills past the cap also leave activeSkills, so the model cannot invoke them even by exact name. With a synced library of ~1,100 skills (K-Dense scientific-agent-skills, academic-research-skills and Auto-Empirical-Research-Skills via skillSync) this means:
roughly 9 in 10 skills are never visible to the model, and which 100 are visible is arbitrary, so the relevant skill is usually missing;
a greeting gets the whole catalog too; we saw a skill whose description says "ALWAYS activate this skill" loaded for a plain "hi".
This is a concrete form of suggestions 3 and 4 in #13127 (dynamic preselection / cheap router model), now that a classification interface exists.
Proposed behavior:
When classification is enabled and the visible catalog is larger than the cap, score every visible skill against the latest user message and list the top N.
Skills below a probability threshold are not listed; if nothing clears it, the turn gets no catalog (and no skill tool).
A skill the user names in the message is always listed.
activeSkills stays the full active set: ranking changes only the catalog text, and every active skill stays invocable by exact name.
Catalogs that already fit under the cap skip the classifier (no cost for agents with a few selected skills).
Any classifier failure (timeout, 429, auth, billing) falls back to today's behavior with a logged warning; the turn never blocks.
Possible config, next to the existing key:
endpoints:
agents:
skills:
maxCatalogSkills: 20# existing: entries in the catalogselection:
enabled: true # uses the `classification` provider from #16180minProbability: 0.6batchSize: 300timeoutMs: 5000
More details
We run this as a patch on v0.8.8-rc2 with TypeSafe's Jev (/v1/systemone). What we learned:
One boolean question per skill ("an agent about to work on this task would do it better if it first loaded skill X: <description, first 300 chars>"), with only the user message as state. Following TypeSafe's guidance, the candidate list stays out of the state, since unrelated text there lowers accuracy.
Jev answers each question independently of the others in the request, so the catalog can be split into batches that run in parallel, followed by one global sort. The same skill scored alone, in two 200-question batches and in one 400-question batch differed by at most 0.04, so no tournament rounds or keyword prefilter are needed.
Ranking needs a scan of the whole accessible catalog, so the page budget (MAX_CATALOG_PAGES = 10) needs its own limit in that mode (we use 50).
Measured with jev-1.13.0 on 1,048 skills (2026-09-29):
requests per turn
4 (300 questions each, at most 8 in flight)
wall time
0.7–1.2 s
classifier input
~105k tokens/turn ≈ $0.0044 at $0.042/M (output is free)
"staggered DiD"
top 4 all econometrics / DiD skills at 0.98
"hierarchical Bayesian model in PyMC"
pymc, bayesian-estimation at 0.98
off-topic ("a name for my cat")
best 0.51, all others ≤ 0.15, so no catalog that turn
With 20 entries the catalog fits the SDK budget without further cuts (up to ~26 entries keep the full 250 characters at a 200k window, per #15590).
Cost grows linearly with the catalog (~100 input tokens per skill per turn); a wide/narrow two-pass or a per-conversation cache could help for larger libraries.
What features would you like to see added?
Pick the entries of the model-visible skill catalog per request by relevance to the user's message, using the classification provider from #16180, the same way #16181 selects deferred tools.
Today
resolveSkillCatalog(packages/api/src/agents/skills.ts) fills the catalog with the firstSKILL_CATALOG_LIMIT = 100active skills in listing order.endpoints.agents.skills.maxCatalogSkillscan lower that number but not change which skills are picked, and skills past the cap also leaveactiveSkills, so the model cannot invoke them even by exact name. With a synced library of ~1,100 skills (K-Dense scientific-agent-skills, academic-research-skills and Auto-Empirical-Research-Skills via skillSync) this means:formatSkillCatalogcuts each description to ~61 characters (🔎 fix: Report Measured Skill Catalog Truncation #15590), too short to choose from;This is a concrete form of suggestions 3 and 4 in #13127 (dynamic preselection / cheap router model), now that a classification interface exists.
Proposed behavior:
skilltool).activeSkillsstays the full active set: ranking changes only the catalog text, and every active skill stays invocable by exact name.Possible config, next to the existing key:
More details
We run this as a patch on v0.8.8-rc2 with TypeSafe's Jev (
/v1/systemone). What we learned:state. Following TypeSafe's guidance, the candidate list stays out of the state, since unrelated text there lowers accuracy.MAX_CATALOG_PAGES = 10) needs its own limit in that mode (we use 50).Measured with jev-1.13.0 on 1,048 skills (2026-09-29):
With 20 entries the catalog fits the SDK budget without further cuts (up to ~26 entries keep the full 250 characters at a 200k window, per #15590).
Open questions:
Happy to open a PR on top of #16180 if this direction is welcome.
Which components are impacted by your request?
Endpoints
Pictures
No response
Code of Conduct