openAgent
gitlabThe open source UNIVERSAL agent.
clone
https://gitlab.com/bitzzdev/openAgent.gitAIagentautomationopen-sourceuniversal-agent
import { PermissionV1 } from "@opencode-ai/core/v1/permission"import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"import { LayerNode } from "@opencode-ai/core/effect/layer-node"import { Ripgrep } from "@opencode-ai/core/ripgrep"import { Cause, Effect, Exit, Layer } from "effect"import { afterEach, describe, expect } from "bun:test"import path from "path"import type { Permission } from "../../src/permission"import type { Tool } from "@/tool/tool"import { SkillTool } from "../../src/tool/skill"import { ToolRegistry } from "@/tool/registry"import { disposeAllInstances, TestInstance } from "../fixture/fixture"import { SessionID, MessageID } from "../../src/session/schema"import { testEffect } from "../lib/effect"const baseCtx: Omit<Tool.Context, "ask"> = {sessionID: SessionID.make("ses_test"),messageID: MessageID.make("msg_test"),callID: "",agent: "build",abort: AbortSignal.any([]),messages: [],metadata: () => Effect.void,}afterEach(async () => {await disposeAllInstances()})const it = testEffect(LayerNode.compile(LayerNode.group([ToolRegistry.node, CrossSpawnSpawner.node, Ripgrep.node])))describe("tool.skill", () => {it.instance("execute returns skill content block with files", () =>Effect.gen(function* () {const dir = (yield* TestInstance).directoryconst skill = path.join(dir, ".opencode", "skill", "tool-skill")yield* Effect.promise(() =>Bun.write(path.join(skill, "SKILL.md"),`---name: tool-skilldescription: Skill for tool tests.---# Tool SkillUse this skill.`,),)yield* Effect.promise(() => Bun.write(path.join(skill, "scripts", "demo.txt"), "demo"))const home = process.env.OPENCODE_TEST_HOMEprocess.env.OPENCODE_TEST_HOME = diryield* Effect.addFinalizer(() =>Effect.sync(() => {process.env.OPENCODE_TEST_HOME = home}),)const registry = yield* ToolRegistry.Serviceconst agent = { name: "build", mode: "primary" as const, permission: [], options: {} }const tool = (yield* registry.tools({providerID: "opencode" as any,modelID: "gpt-5" as any,agent,})).find((tool) => tool.id === SkillTool.id)if (!tool) throw new Error("Skill tool not found")expect(tool.description).not.toContain("tool-skill")expect(tool.description).not.toContain("Skill for tool tests.")const requests: Array<Omit<PermissionV1.Request, "id" | "sessionID" | "tool">> = []const ctx: Tool.Context = {...baseCtx,ask: (req) =>Effect.sync(() => {requests.push(req)}),}const result = yield* tool.execute({ name: "tool-skill" }, ctx)const file = path.resolve(skill, "scripts", "demo.txt")expect(requests.length).toBe(1)expect(requests[0].permission).toBe("skill")expect(requests[0].patterns).toContain("tool-skill")expect(requests[0].always).toContain("tool-skill")expect(result.metadata.dir).toBe(skill)expect(result.output).toContain(`<skill_content name="tool-skill">`)expect(result.output).toContain(`Base directory for this skill: ${skill}`)expect(result.output).toContain(`<file>${file}</file>`)}),)it.instance("execute preserves not found message", () =>Effect.gen(function* () {const dir = (yield* TestInstance).directoryconst home = process.env.OPENCODE_TEST_HOMEprocess.env.OPENCODE_TEST_HOME = diryield* Effect.addFinalizer(() =>Effect.sync(() => {process.env.OPENCODE_TEST_HOME = home}),)const registry = yield* ToolRegistry.Serviceconst agent = { name: "build", mode: "primary" as const, permission: [], options: {} }const tool = (yield* registry.tools({providerID: "opencode" as any,modelID: "gpt-5" as any,agent,})).find((tool) => tool.id === SkillTool.id)if (!tool) throw new Error("Skill tool not found")const exit = yield* tool.execute({ name: "missing-skill" },{...baseCtx,ask: () => Effect.void,},).pipe(Effect.exit)expect(Exit.isFailure(exit)).toBe(true)if (Exit.isFailure(exit)) {const error = Cause.squash(exit.cause)expect(error).toBeInstanceOf(Error)if (error instanceof Error) expect(error.message).toContain('Skill "missing-skill" not found.')}}),)})