refactor(core): consolidate tool architecture

This commit is contained in:
Dax Raad 2026-07-26 20:08:55 -04:00
commit 8db7487c89
466 changed files with 9405 additions and 11071 deletions

View file

@ -1,53 +1,53 @@
import path from "path"
import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import { AgentV2 } from "@opencode-ai/core/agent"
import { Agent } from "@opencode-ai/core/agent"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { AbsolutePath } from "@opencode-ai/core/schema"
import { SkillV2 } from "@opencode-ai/core/skill"
import { Skill } from "@opencode-ai/core/skill"
import { SkillInstructions } from "@opencode-ai/core/skill/instructions"
import { it } from "../lib/effect"
import { readInitial, readUpdate } from "../lib/instructions"
const build = AgentV2.ID.make("build")
const effect = SkillV2.Info.make({
id: SkillV2.ID.make("effect"),
name: SkillV2.Name.make("Effect"),
const build = Agent.ID.make("build")
const effect = Skill.Info.make({
id: Skill.ID.make("effect"),
name: Skill.Name.make("Effect"),
description: "Build applications with Effect",
location: AbsolutePath.make(path.resolve("/skills/effect/SKILL.md")),
content: "Effect guidance",
})
const hidden = SkillV2.Info.make({
id: SkillV2.ID.make("hidden"),
name: SkillV2.Name.make("Hidden"),
const hidden = Skill.Info.make({
id: Skill.ID.make("hidden"),
name: Skill.Name.make("Hidden"),
location: AbsolutePath.make(path.resolve("/skills/hidden/SKILL.md")),
content: "Undescribed guidance",
})
const denied = SkillV2.Info.make({
id: SkillV2.ID.make("denied"),
name: SkillV2.Name.make("Denied"),
const denied = Skill.Info.make({
id: Skill.ID.make("denied"),
name: Skill.Name.make("Denied"),
description: "Must not be advertised",
location: AbsolutePath.make(path.resolve("/skills/denied/SKILL.md")),
content: "Denied guidance",
})
const manual = SkillV2.Info.make({
id: SkillV2.ID.make("manual"),
name: SkillV2.Name.make("Manual"),
const manual = Skill.Info.make({
id: Skill.ID.make("manual"),
name: Skill.Name.make("Manual"),
description: "Load only when explicitly selected",
autoinvoke: false,
location: AbsolutePath.make(path.resolve("/skills/manual/SKILL.md")),
content: "Manual guidance",
})
const layer = (list: () => SkillV2.Info[]) =>
const layer = (list: () => Skill.Info[]) =>
AppNodeBuilder.build(SkillInstructions.node, [
[SkillV2.node, Layer.mock(SkillV2.Service, { list: () => Effect.succeed(list()) })],
[Skill.node, Layer.mock(Skill.Service, { list: () => Effect.succeed(list()) })],
])
describe("SkillInstructions", () => {
it.effect("renders described agent skills and updates the complete available list", () => {
const agent = AgentV2.Info.make({
...AgentV2.Info.empty(build),
const agent = Agent.Info.make({
...Agent.Info.empty(build),
permissions: [{ action: "skill", resource: "denied", effect: "deny" }],
})
let skills = [hidden, denied, manual, effect]
@ -80,10 +80,10 @@ describe("SkillInstructions", () => {
})
it.effect("announces added and removed skills as deltas without restating the list", () => {
const agent = AgentV2.Info.make(AgentV2.Info.empty(build))
const debugging = SkillV2.Info.make({
id: SkillV2.ID.make("debugging"),
name: SkillV2.Name.make("Debugging"),
const agent = Agent.Info.make(Agent.Info.empty(build))
const debugging = Skill.Info.make({
id: Skill.ID.make("debugging"),
name: Skill.Name.make("Debugging"),
description: "Diagnose hard bugs",
location: AbsolutePath.make(path.resolve("/skills/debugging/SKILL.md")),
content: "Debugging guidance",
@ -117,13 +117,13 @@ describe("SkillInstructions", () => {
})
it.effect("restates the full skill list when a description changes", () => {
const agent = AgentV2.Info.make(AgentV2.Info.empty(build))
const agent = Agent.Info.make(Agent.Info.empty(build))
let skills = [effect]
return Effect.gen(function* () {
const instructions = yield* SkillInstructions.Service
const initialized = yield* instructions.load({ id: agent.id, info: agent }).pipe(Effect.flatMap(readInitial))
skills = [SkillV2.Info.make({ ...effect, description: "Build applications with Effect v4" })]
skills = [Skill.Info.make({ ...effect, description: "Build applications with Effect v4" })]
expect(
yield* instructions
.load({ id: agent.id, info: agent })
@ -137,8 +137,8 @@ describe("SkillInstructions", () => {
})
it.effect("omits instructions when the selected agent denies all skills", () => {
const agent = AgentV2.Info.make({
...AgentV2.Info.empty(build),
const agent = Agent.Info.make({
...Agent.Info.empty(build),
permissions: [{ action: "skill", resource: "*", effect: "deny" }],
})
return Effect.gen(function* () {
@ -148,8 +148,8 @@ describe("SkillInstructions", () => {
})
it.effect("omits instructions when a resource-specific denial follows the global denial", () => {
const agent = AgentV2.Info.make({
...AgentV2.Info.empty(build),
const agent = Agent.Info.make({
...Agent.Info.empty(build),
permissions: [
{ action: "skill", resource: "*", effect: "deny" },
{ action: "skill", resource: "hidden", effect: "deny" },
@ -162,8 +162,8 @@ describe("SkillInstructions", () => {
})
it.effect("retains specifically allowed skills after a global denial", () => {
const agent = AgentV2.Info.make({
...AgentV2.Info.empty(build),
const agent = Agent.Info.make({
...Agent.Info.empty(build),
permissions: [
{ action: "skill", resource: "*", effect: "deny" },
{ action: "skill", resource: "effect", effect: "allow" },
@ -178,8 +178,8 @@ describe("SkillInstructions", () => {
})
it.effect("omits instructions when a specifically allowed skill is denied again", () => {
const agent = AgentV2.Info.make({
...AgentV2.Info.empty(build),
const agent = Agent.Info.make({
...Agent.Info.empty(build),
permissions: [
{ action: "skill", resource: "*", effect: "deny" },
{ action: "skill", resource: "effect", effect: "allow" },