Repository navigation
Bug: ctx.skills.register() does not default source, so plugin-registered skills fail to load
#9550
Replies: 1 comment 1 reply
|
Good catch, and you have the right three call sites. Two refinements that decide what the fix should be. 1. The asymmetry is real and asymmetric in both directions of the type.
But note where the type stands today: The README sentence for embedded skills ("the registry fills in a default invocation policy and the 2. That makes "default it" and "reject it" two different fixes, and I'd let the maintainers choose — but the fail-fast one is the more faithful reading.
Either way the invariant that is missing today is the one worth writing down: the write path must validate the shape the read path requires — Two smaller observations from reading the tree: the same incomplete definition is also what I have no stake in which of the two fixes lands — but if it is useful, I can hold a plugin-side shim in the meantime (a registered-source default applied on the registry instance, so untyped callers on already-released versions get a loadable skill plus a warning that names the omission). Say the word and I'll publish it; otherwise I'll leave this as a pure upstream fix. |
Uh oh!
There was an error while loading. Please reload this page.
Bug:
ctx.skills.register()does not defaultsource, so any plugin-registered skill fails to loadSummary
A plugin that registers a skill with
ctx.skills.register({ name, description, content, invocation })gets a skill that appears in the skill list but cannot be loaded. Loading it fails with:There is no error at registration time, so the failure is only discovered when the skill is actually used — which makes this hard to attribute.
Root cause
Two internal inconsistencies in the skills registry:
1.
register()defaultsinvocationandprovider, but notsource.2.
runtimeCandidate()passessourcestraight through.3.
validateDefinition()then requires it to be a string.So
provideris always fine (it has a default) whilesourceis alwaysundefined(it does not). The registration path validates a different shape than the read-back path, so an incomplete definition is accepted at registration and rejected on use.Impact
Any plugin using
ctx.skills.register()is affected unless it happens to passsourceexplicitly. The skill is listed (so it looks installed) but is unusable, and the error message points at the skill rather than at the registry, which makes it look like the plugin is at fault.Reproduction
Register a skill exactly as documented, without
source:Then load it (
skill(name: "my-plugin-skill")). Result:Adding
source: 'runtime'makes it load correctly.Suggested fix
Default
sourceinregister()alongside the existingproviderdefault, e.g.:Given
RUNTIME_PROVIDER === "runtime"is already the reserved name for this registration kind, reusing it forsourcekeeps the two fields consistent.Alternatively, if
sourceis genuinely meant to be caller-supplied,validateRuntimeSkill()should require it at registration so the mistake fails immediately and locally instead of at load time. Either way, the two validation paths should agree on which fields are mandatory.Note
This is easy to work around from the plugin side (pass
source: 'runtime'explicitly), and that is what I have done. But the defaulting asymmetry betweenproviderandsourcelooks unintentional, and the delayed/indirect error makes it a costly trap for plugin authors.All reactions