export * as SkillGuidance from "./guidance" import { Context, Effect, Layer, Schema } from "effect" import { AgentV2 } from "../agent" import { PermissionV2 } from "../permission" import { PluginBoot } from "../plugin/boot" import { SkillV2 } from "../skill" import { SystemContext } from "../system-context/index" const Summary = Schema.Struct({ name: Schema.String, description: Schema.String, }) type Summary = typeof Summary.Type const render = (skills: ReadonlyArray) => [ "Skills provide specialized instructions and workflows for specific tasks.", "Use the skill tool to load a skill when a task matches its description.", ...(skills.length === 0 ? ["No skills are currently available."] : [ "", ...skills.flatMap((skill) => [ " ", ` ${skill.name}`, ` ${skill.description}`, " ", ]), "", ]), ].join("\n") export interface Interface { readonly load: (agent: AgentV2.Selection) => Effect.Effect } export class Service extends Context.Service()("@opencode/v2/SkillGuidance") {} export const layer = Layer.effect( Service, Effect.gen(function* () { const boot = yield* PluginBoot.Service const skills = yield* SkillV2.Service return Service.of({ load: Effect.fn("SkillGuidance.load")(function* (selection) { yield* boot.wait() const agent = selection.info if (!agent) return SystemContext.empty const permitted = SkillV2.available(yield* skills.list(), agent) if (permitted.length === 0 && PermissionV2.evaluate("skill", "*", agent.permissions).effect === "deny") return SystemContext.empty const available = permitted .flatMap((skill) => skill.description === undefined ? [] : [{ name: skill.name, description: skill.description }], ) .toSorted((a, b) => a.name.localeCompare(b.name)) return SystemContext.make({ key: SystemContext.Key.make("core/skill-guidance"), codec: Schema.toCodecJson(Schema.Array(Summary)), load: Effect.succeed(available), baseline: render, update: (_previous, current) => [ "The available skills have changed. This list supersedes the previous available skills list.", render(current), ].join("\n"), removed: () => "Skill guidance is no longer available. Do not use any previously listed skill.", }) }), }) }), ) export const locationLayer = layer