fix(skill): type expected skill failures (#28885)

This commit is contained in:
Shoubhit Dash
2026-05-22 23:18:52 +05:30
committed by GitHub
parent 536ee857c6
commit 7265c46af6
5 changed files with 102 additions and 12 deletions

View File

@@ -57,17 +57,26 @@ function isSkillFrontmatter(data: unknown): data is { name: string; description?
)
}
export const InvalidError = NamedError.create("SkillInvalidError", {
export class InvalidError extends Schema.TaggedErrorClass<InvalidError>()("SkillInvalidError", {
path: Schema.String,
message: Schema.optional(Schema.String),
issues: Schema.optional(Schema.Array(Issue)),
})
}) {}
export const NameMismatchError = NamedError.create("SkillNameMismatchError", {
export class NameMismatchError extends Schema.TaggedErrorClass<NameMismatchError>()("SkillNameMismatchError", {
path: Schema.String,
expected: Schema.String,
actual: Schema.String,
})
}) {}
export class NotFoundError extends Schema.TaggedErrorClass<NotFoundError>()("Skill.NotFoundError", {
name: Schema.String,
available: Schema.Array(Schema.String),
}) {
override get message() {
return `Skill "${this.name}" not found. Available skills: ${this.available.join(", ") || "none"}`
}
}
type State = {
skills: Record<string, Info>
@@ -86,6 +95,7 @@ type ScanState = {
export interface Interface {
readonly get: (name: string) => Effect.Effect<Info | undefined>
readonly require: (name: string) => Effect.Effect<Info, NotFoundError>
readonly all: () => Effect.Effect<Info[]>
readonly dirs: () => Effect.Effect<string[]>
readonly available: (agent?: Agent.Info) => Effect.Effect<Info[]>
@@ -277,6 +287,13 @@ export const layer = Layer.effect(
return s.skills[name]
})
const require = Effect.fn("Skill.require")(function* (name: string) {
const s = yield* InstanceState.get(state)
const info = s.skills[name]
if (info) return info
return yield* new NotFoundError({ name, available: Object.keys(s.skills).toSorted() })
})
const all = Effect.fn("Skill.all")(function* () {
const s = yield* InstanceState.get(state)
return Object.values(s.skills)
@@ -293,7 +310,7 @@ export const layer = Layer.effect(
return list.filter((skill) => Permission.evaluate("skill", skill.name, agent.permission).action !== "deny")
})
return Service.of({ get, all, dirs, available })
return Service.of({ get, require, all, dirs, available })
}),
)

View File

@@ -22,12 +22,9 @@ export const SkillTool = Tool.define(
parameters: Parameters,
execute: (params: Schema.Schema.Type<typeof Parameters>, ctx: Tool.Context) =>
Effect.gen(function* () {
const info = yield* skill.get(params.name)
if (!info) {
const all = yield* skill.all()
const available = all.map((item) => item.name).join(", ")
throw new Error(`Skill "${params.name}" not found. Available skills: ${available || "none"}`)
}
const info = yield* skill
.require(params.name)
.pipe(Effect.catchTag("Skill.NotFoundError", (error) => Effect.die(new Error(error.message))))
yield* ctx.ask({
permission: "skill",