refactor: remove ToolRegistry runtime facade (#22307)
This commit is contained in:
@@ -18,6 +18,7 @@ const seed = async () => {
|
|||||||
const { Project } = await import("../src/project/project")
|
const { Project } = await import("../src/project/project")
|
||||||
const { ModelID, ProviderID } = await import("../src/provider/schema")
|
const { ModelID, ProviderID } = await import("../src/provider/schema")
|
||||||
const { ToolRegistry } = await import("../src/tool/registry")
|
const { ToolRegistry } = await import("../src/tool/registry")
|
||||||
|
const { Effect } = await import("effect")
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await Instance.provide({
|
await Instance.provide({
|
||||||
@@ -25,7 +26,12 @@ const seed = async () => {
|
|||||||
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||||
fn: async () => {
|
fn: async () => {
|
||||||
await Config.waitForDependencies()
|
await Config.waitForDependencies()
|
||||||
await ToolRegistry.ids()
|
await AppRuntime.runPromise(
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const registry = yield* ToolRegistry.Service
|
||||||
|
yield* registry.ids()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
const session = await Session.create({ title })
|
const session = await Session.create({ title })
|
||||||
const messageID = MessageID.ascending()
|
const messageID = MessageID.ascending()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { Permission } from "../../../permission"
|
|||||||
import { iife } from "../../../util/iife"
|
import { iife } from "../../../util/iife"
|
||||||
import { bootstrap } from "../../bootstrap"
|
import { bootstrap } from "../../bootstrap"
|
||||||
import { cmd } from "../cmd"
|
import { cmd } from "../cmd"
|
||||||
|
import { AppRuntime } from "@/effect/app-runtime"
|
||||||
|
|
||||||
export const AgentCommand = cmd({
|
export const AgentCommand = cmd({
|
||||||
command: "agent <name>",
|
command: "agent <name>",
|
||||||
@@ -71,11 +72,17 @@ export const AgentCommand = cmd({
|
|||||||
})
|
})
|
||||||
|
|
||||||
async function getAvailableTools(agent: Agent.Info) {
|
async function getAvailableTools(agent: Agent.Info) {
|
||||||
const model = agent.model ?? (await Provider.defaultModel())
|
return AppRuntime.runPromise(
|
||||||
return ToolRegistry.tools({
|
Effect.gen(function* () {
|
||||||
...model,
|
const provider = yield* Provider.Service
|
||||||
agent,
|
const registry = yield* ToolRegistry.Service
|
||||||
})
|
const model = agent.model ?? (yield* provider.defaultModel())
|
||||||
|
return yield* registry.tools({
|
||||||
|
...model,
|
||||||
|
agent,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveTools(agent: Agent.Info, availableTools: Awaited<ReturnType<typeof getAvailableTools>>) {
|
async function resolveTools(agent: Agent.Info, availableTools: Awaited<ReturnType<typeof getAvailableTools>>) {
|
||||||
|
|||||||
@@ -162,7 +162,13 @@ export const ExperimentalRoutes = lazy(() =>
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
return c.json(await ToolRegistry.ids())
|
const ids = await AppRuntime.runPromise(
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const registry = yield* ToolRegistry.Service
|
||||||
|
return yield* registry.ids()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
return c.json(ids)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.get(
|
.get(
|
||||||
@@ -205,11 +211,17 @@ export const ExperimentalRoutes = lazy(() =>
|
|||||||
),
|
),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const { provider, model } = c.req.valid("query")
|
const { provider, model } = c.req.valid("query")
|
||||||
const tools = await ToolRegistry.tools({
|
const tools = await AppRuntime.runPromise(
|
||||||
providerID: ProviderID.make(provider),
|
Effect.gen(function* () {
|
||||||
modelID: ModelID.make(model),
|
const agents = yield* Agent.Service
|
||||||
agent: await Agent.get(await Agent.defaultAgent()),
|
const registry = yield* ToolRegistry.Service
|
||||||
})
|
return yield* registry.tools({
|
||||||
|
providerID: ProviderID.make(provider),
|
||||||
|
modelID: ModelID.make(model),
|
||||||
|
agent: yield* agents.get(yield* agents.defaultAgent()),
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
return c.json(
|
return c.json(
|
||||||
tools.map((t) => ({
|
tools.map((t) => ({
|
||||||
id: t.id,
|
id: t.id,
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
|
|||||||
import { Ripgrep } from "../file/ripgrep"
|
import { Ripgrep } from "../file/ripgrep"
|
||||||
import { Format } from "../format"
|
import { Format } from "../format"
|
||||||
import { InstanceState } from "@/effect/instance-state"
|
import { InstanceState } from "@/effect/instance-state"
|
||||||
import { makeRuntime } from "@/effect/run-service"
|
|
||||||
import { Env } from "../env"
|
import { Env } from "../env"
|
||||||
import { Question } from "../question"
|
import { Question } from "../question"
|
||||||
import { Todo } from "../session/todo"
|
import { Todo } from "../session/todo"
|
||||||
@@ -344,18 +343,4 @@ export namespace ToolRegistry {
|
|||||||
Layer.provide(Truncate.defaultLayer),
|
Layer.provide(Truncate.defaultLayer),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
const { runPromise } = makeRuntime(Service, defaultLayer)
|
|
||||||
|
|
||||||
export async function ids() {
|
|
||||||
return runPromise((svc) => svc.ids())
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function tools(input: {
|
|
||||||
providerID: ProviderID
|
|
||||||
modelID: ModelID
|
|
||||||
agent: Agent.Info
|
|
||||||
}): Promise<(Tool.Def & { id: string })[]> {
|
|
||||||
return runPromise((svc) => svc.tools(input))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,157 +1,154 @@
|
|||||||
import { afterEach, describe, expect, test } from "bun:test"
|
import { NodeChildProcessSpawner, NodeFileSystem, NodePath } from "@effect/platform-node"
|
||||||
|
import { afterEach, describe, expect } from "bun:test"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { Effect, Layer } from "effect"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { ToolRegistry } from "../../src/tool/registry"
|
import { ToolRegistry } from "../../src/tool/registry"
|
||||||
|
import { provideTmpdirInstance } from "../fixture/fixture"
|
||||||
|
import { testEffect } from "../lib/effect"
|
||||||
|
|
||||||
|
const node = NodeChildProcessSpawner.layer.pipe(
|
||||||
|
Layer.provideMerge(Layer.mergeAll(NodeFileSystem.layer, NodePath.layer)),
|
||||||
|
)
|
||||||
|
|
||||||
|
const it = testEffect(Layer.mergeAll(ToolRegistry.defaultLayer, node))
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await Instance.disposeAll()
|
await Instance.disposeAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("tool.registry", () => {
|
describe("tool.registry", () => {
|
||||||
test("loads tools from .opencode/tool (singular)", async () => {
|
it.live("loads tools from .opencode/tool (singular)", () =>
|
||||||
await using tmp = await tmpdir({
|
provideTmpdirInstance((dir) =>
|
||||||
init: async (dir) => {
|
Effect.gen(function* () {
|
||||||
const opencodeDir = path.join(dir, ".opencode")
|
const opencode = path.join(dir, ".opencode")
|
||||||
await fs.mkdir(opencodeDir, { recursive: true })
|
const tool = path.join(opencode, "tool")
|
||||||
|
yield* Effect.promise(() => fs.mkdir(tool, { recursive: true }))
|
||||||
const toolDir = path.join(opencodeDir, "tool")
|
yield* Effect.promise(() =>
|
||||||
await fs.mkdir(toolDir, { recursive: true })
|
Bun.write(
|
||||||
|
path.join(tool, "hello.ts"),
|
||||||
await Bun.write(
|
[
|
||||||
path.join(toolDir, "hello.ts"),
|
"export default {",
|
||||||
[
|
" description: 'hello tool',",
|
||||||
"export default {",
|
" args: {},",
|
||||||
" description: 'hello tool',",
|
" execute: async () => {",
|
||||||
" args: {},",
|
" return 'hello world'",
|
||||||
" execute: async () => {",
|
" },",
|
||||||
" return 'hello world'",
|
"}",
|
||||||
" },",
|
"",
|
||||||
"}",
|
].join("\n"),
|
||||||
"",
|
),
|
||||||
].join("\n"),
|
|
||||||
)
|
)
|
||||||
},
|
const registry = yield* ToolRegistry.Service
|
||||||
})
|
const ids = yield* registry.ids()
|
||||||
|
|
||||||
await Instance.provide({
|
|
||||||
directory: tmp.path,
|
|
||||||
fn: async () => {
|
|
||||||
const ids = await ToolRegistry.ids()
|
|
||||||
expect(ids).toContain("hello")
|
expect(ids).toContain("hello")
|
||||||
},
|
}),
|
||||||
})
|
),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("loads tools from .opencode/tools (plural)", async () => {
|
it.live("loads tools from .opencode/tools (plural)", () =>
|
||||||
await using tmp = await tmpdir({
|
provideTmpdirInstance((dir) =>
|
||||||
init: async (dir) => {
|
Effect.gen(function* () {
|
||||||
const opencodeDir = path.join(dir, ".opencode")
|
const opencode = path.join(dir, ".opencode")
|
||||||
await fs.mkdir(opencodeDir, { recursive: true })
|
const tools = path.join(opencode, "tools")
|
||||||
|
yield* Effect.promise(() => fs.mkdir(tools, { recursive: true }))
|
||||||
const toolsDir = path.join(opencodeDir, "tools")
|
yield* Effect.promise(() =>
|
||||||
await fs.mkdir(toolsDir, { recursive: true })
|
Bun.write(
|
||||||
|
path.join(tools, "hello.ts"),
|
||||||
await Bun.write(
|
[
|
||||||
path.join(toolsDir, "hello.ts"),
|
"export default {",
|
||||||
[
|
" description: 'hello tool',",
|
||||||
"export default {",
|
" args: {},",
|
||||||
" description: 'hello tool',",
|
" execute: async () => {",
|
||||||
" args: {},",
|
" return 'hello world'",
|
||||||
" execute: async () => {",
|
" },",
|
||||||
" return 'hello world'",
|
"}",
|
||||||
" },",
|
"",
|
||||||
"}",
|
].join("\n"),
|
||||||
"",
|
),
|
||||||
].join("\n"),
|
|
||||||
)
|
)
|
||||||
},
|
const registry = yield* ToolRegistry.Service
|
||||||
})
|
const ids = yield* registry.ids()
|
||||||
|
|
||||||
await Instance.provide({
|
|
||||||
directory: tmp.path,
|
|
||||||
fn: async () => {
|
|
||||||
const ids = await ToolRegistry.ids()
|
|
||||||
expect(ids).toContain("hello")
|
expect(ids).toContain("hello")
|
||||||
},
|
}),
|
||||||
})
|
),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("loads tools with external dependencies without crashing", async () => {
|
it.live("loads tools with external dependencies without crashing", () =>
|
||||||
await using tmp = await tmpdir({
|
provideTmpdirInstance((dir) =>
|
||||||
init: async (dir) => {
|
Effect.gen(function* () {
|
||||||
const opencodeDir = path.join(dir, ".opencode")
|
const opencode = path.join(dir, ".opencode")
|
||||||
await fs.mkdir(opencodeDir, { recursive: true })
|
const tools = path.join(opencode, "tools")
|
||||||
|
yield* Effect.promise(() => fs.mkdir(tools, { recursive: true }))
|
||||||
const toolsDir = path.join(opencodeDir, "tools")
|
yield* Effect.promise(() =>
|
||||||
await fs.mkdir(toolsDir, { recursive: true })
|
Bun.write(
|
||||||
|
path.join(opencode, "package.json"),
|
||||||
await Bun.write(
|
JSON.stringify({
|
||||||
path.join(opencodeDir, "package.json"),
|
name: "custom-tools",
|
||||||
JSON.stringify({
|
dependencies: {
|
||||||
name: "custom-tools",
|
"@opencode-ai/plugin": "^0.0.0",
|
||||||
dependencies: {
|
cowsay: "^1.6.0",
|
||||||
"@opencode-ai/plugin": "^0.0.0",
|
},
|
||||||
cowsay: "^1.6.0",
|
}),
|
||||||
},
|
),
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
yield* Effect.promise(() =>
|
||||||
await Bun.write(
|
Bun.write(
|
||||||
path.join(opencodeDir, "package-lock.json"),
|
path.join(opencode, "package-lock.json"),
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
name: "custom-tools",
|
name: "custom-tools",
|
||||||
lockfileVersion: 3,
|
lockfileVersion: 3,
|
||||||
packages: {
|
packages: {
|
||||||
"": {
|
"": {
|
||||||
dependencies: {
|
dependencies: {
|
||||||
"@opencode-ai/plugin": "^0.0.0",
|
"@opencode-ai/plugin": "^0.0.0",
|
||||||
cowsay: "^1.6.0",
|
cowsay: "^1.6.0",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
const cowsayDir = path.join(opencodeDir, "node_modules", "cowsay")
|
const cowsay = path.join(opencode, "node_modules", "cowsay")
|
||||||
await fs.mkdir(cowsayDir, { recursive: true })
|
yield* Effect.promise(() => fs.mkdir(cowsay, { recursive: true }))
|
||||||
await Bun.write(
|
yield* Effect.promise(() =>
|
||||||
path.join(cowsayDir, "package.json"),
|
Bun.write(
|
||||||
JSON.stringify({
|
path.join(cowsay, "package.json"),
|
||||||
name: "cowsay",
|
JSON.stringify({
|
||||||
type: "module",
|
name: "cowsay",
|
||||||
exports: "./index.js",
|
type: "module",
|
||||||
}),
|
exports: "./index.js",
|
||||||
|
}),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
await Bun.write(
|
yield* Effect.promise(() =>
|
||||||
path.join(cowsayDir, "index.js"),
|
Bun.write(
|
||||||
["export function say({ text }) {", " return `moo ${text}`", "}", ""].join("\n"),
|
path.join(cowsay, "index.js"),
|
||||||
|
["export function say({ text }) {", " return `moo ${text}`", "}", ""].join("\n"),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
yield* Effect.promise(() =>
|
||||||
await Bun.write(
|
Bun.write(
|
||||||
path.join(toolsDir, "cowsay.ts"),
|
path.join(tools, "cowsay.ts"),
|
||||||
[
|
[
|
||||||
"import { say } from 'cowsay'",
|
"import { say } from 'cowsay'",
|
||||||
"export default {",
|
"export default {",
|
||||||
" description: 'tool that imports cowsay at top level',",
|
" description: 'tool that imports cowsay at top level',",
|
||||||
" args: { text: { type: 'string' } },",
|
" args: { text: { type: 'string' } },",
|
||||||
" execute: async ({ text }: { text: string }) => {",
|
" execute: async ({ text }: { text: string }) => {",
|
||||||
" return say({ text })",
|
" return say({ text })",
|
||||||
" },",
|
" },",
|
||||||
"}",
|
"}",
|
||||||
"",
|
"",
|
||||||
].join("\n"),
|
].join("\n"),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
},
|
const registry = yield* ToolRegistry.Service
|
||||||
})
|
const ids = yield* registry.ids()
|
||||||
|
|
||||||
await Instance.provide({
|
|
||||||
directory: tmp.path,
|
|
||||||
fn: async () => {
|
|
||||||
const ids = await ToolRegistry.ids()
|
|
||||||
expect(ids).toContain("cowsay")
|
expect(ids).toContain("cowsay")
|
||||||
},
|
}),
|
||||||
})
|
),
|
||||||
})
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { NodeChildProcessSpawner, NodeFileSystem, NodePath } from "@effect/platform-node"
|
||||||
import { Effect, Layer, ManagedRuntime } from "effect"
|
import { Effect, Layer, ManagedRuntime } from "effect"
|
||||||
import { Agent } from "../../src/agent/agent"
|
import { Agent } from "../../src/agent/agent"
|
||||||
import { Skill } from "../../src/skill"
|
import { Skill } from "../../src/skill"
|
||||||
@@ -11,8 +12,9 @@ import type { Tool } from "../../src/tool/tool"
|
|||||||
import { Instance } from "../../src/project/instance"
|
import { Instance } from "../../src/project/instance"
|
||||||
import { SkillTool } from "../../src/tool/skill"
|
import { SkillTool } from "../../src/tool/skill"
|
||||||
import { ToolRegistry } from "../../src/tool/registry"
|
import { ToolRegistry } from "../../src/tool/registry"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { provideTmpdirInstance, tmpdir } from "../fixture/fixture"
|
||||||
import { SessionID, MessageID } from "../../src/session/schema"
|
import { SessionID, MessageID } from "../../src/session/schema"
|
||||||
|
import { testEffect } from "../lib/effect"
|
||||||
|
|
||||||
const baseCtx: Omit<Tool.Context, "ask"> = {
|
const baseCtx: Omit<Tool.Context, "ask"> = {
|
||||||
sessionID: SessionID.make("ses_test"),
|
sessionID: SessionID.make("ses_test"),
|
||||||
@@ -28,85 +30,94 @@ afterEach(async () => {
|
|||||||
await Instance.disposeAll()
|
await Instance.disposeAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const node = NodeChildProcessSpawner.layer.pipe(
|
||||||
|
Layer.provideMerge(Layer.mergeAll(NodeFileSystem.layer, NodePath.layer)),
|
||||||
|
)
|
||||||
|
|
||||||
|
const it = testEffect(Layer.mergeAll(ToolRegistry.defaultLayer, node))
|
||||||
|
|
||||||
describe("tool.skill", () => {
|
describe("tool.skill", () => {
|
||||||
test("description lists skill location URL", async () => {
|
it.live("description lists skill location URL", () =>
|
||||||
await using tmp = await tmpdir({
|
provideTmpdirInstance(
|
||||||
git: true,
|
(dir) =>
|
||||||
init: async (dir) => {
|
Effect.gen(function* () {
|
||||||
const skillDir = path.join(dir, ".opencode", "skill", "tool-skill")
|
const skill = path.join(dir, ".opencode", "skill", "tool-skill")
|
||||||
await Bun.write(
|
yield* Effect.promise(() =>
|
||||||
path.join(skillDir, "SKILL.md"),
|
Bun.write(
|
||||||
`---
|
path.join(skill, "SKILL.md"),
|
||||||
|
`---
|
||||||
name: tool-skill
|
name: tool-skill
|
||||||
description: Skill for tool tests.
|
description: Skill for tool tests.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Tool Skill
|
# Tool Skill
|
||||||
`,
|
`,
|
||||||
)
|
),
|
||||||
},
|
)
|
||||||
})
|
const home = process.env.OPENCODE_TEST_HOME
|
||||||
|
process.env.OPENCODE_TEST_HOME = dir
|
||||||
|
yield* Effect.addFinalizer(() =>
|
||||||
|
Effect.sync(() => {
|
||||||
|
process.env.OPENCODE_TEST_HOME = home
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
const registry = yield* ToolRegistry.Service
|
||||||
|
const desc =
|
||||||
|
(yield* registry.tools({
|
||||||
|
providerID: "opencode" as any,
|
||||||
|
modelID: "gpt-5" as any,
|
||||||
|
agent: { name: "build", mode: "primary", permission: [], options: {} },
|
||||||
|
})).find((tool) => tool.id === SkillTool.id)?.description ?? ""
|
||||||
|
expect(desc).toContain("**tool-skill**: Skill for tool tests.")
|
||||||
|
}),
|
||||||
|
{ git: true },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
const home = process.env.OPENCODE_TEST_HOME
|
it.live("description sorts skills by name and is stable across calls", () =>
|
||||||
process.env.OPENCODE_TEST_HOME = tmp.path
|
provideTmpdirInstance(
|
||||||
|
(dir) =>
|
||||||
try {
|
Effect.gen(function* () {
|
||||||
await Instance.provide({
|
for (const [name, description] of [
|
||||||
directory: tmp.path,
|
["zeta-skill", "Zeta skill."],
|
||||||
fn: async () => {
|
["alpha-skill", "Alpha skill."],
|
||||||
const desc = await ToolRegistry.tools({
|
["middle-skill", "Middle skill."],
|
||||||
providerID: "opencode" as any,
|
]) {
|
||||||
modelID: "gpt-5" as any,
|
const skill = path.join(dir, ".opencode", "skill", name)
|
||||||
agent: { name: "build", mode: "primary" as const, permission: [], options: {} },
|
yield* Effect.promise(() =>
|
||||||
}).then((tools) => tools.find((tool) => tool.id === SkillTool.id)?.description ?? "")
|
Bun.write(
|
||||||
expect(desc).toContain(`**tool-skill**: Skill for tool tests.`)
|
path.join(skill, "SKILL.md"),
|
||||||
},
|
`---
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
process.env.OPENCODE_TEST_HOME = home
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
test("description sorts skills by name and is stable across calls", async () => {
|
|
||||||
await using tmp = await tmpdir({
|
|
||||||
git: true,
|
|
||||||
init: async (dir) => {
|
|
||||||
for (const [name, description] of [
|
|
||||||
["zeta-skill", "Zeta skill."],
|
|
||||||
["alpha-skill", "Alpha skill."],
|
|
||||||
["middle-skill", "Middle skill."],
|
|
||||||
]) {
|
|
||||||
const skillDir = path.join(dir, ".opencode", "skill", name)
|
|
||||||
await Bun.write(
|
|
||||||
path.join(skillDir, "SKILL.md"),
|
|
||||||
`---
|
|
||||||
name: ${name}
|
name: ${name}
|
||||||
description: ${description}
|
description: ${description}
|
||||||
---
|
---
|
||||||
|
|
||||||
# ${name}
|
# ${name}
|
||||||
`,
|
`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const home = process.env.OPENCODE_TEST_HOME
|
||||||
|
process.env.OPENCODE_TEST_HOME = dir
|
||||||
|
yield* Effect.addFinalizer(() =>
|
||||||
|
Effect.sync(() => {
|
||||||
|
process.env.OPENCODE_TEST_HOME = home
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const home = process.env.OPENCODE_TEST_HOME
|
|
||||||
process.env.OPENCODE_TEST_HOME = tmp.path
|
|
||||||
|
|
||||||
try {
|
|
||||||
await Instance.provide({
|
|
||||||
directory: tmp.path,
|
|
||||||
fn: async () => {
|
|
||||||
const agent = { name: "build", mode: "primary" as const, permission: [], options: {} }
|
const agent = { name: "build", mode: "primary" as const, permission: [], options: {} }
|
||||||
const load = () =>
|
const registry = yield* ToolRegistry.Service
|
||||||
ToolRegistry.tools({
|
const load = Effect.fnUntraced(function* () {
|
||||||
providerID: "opencode" as any,
|
return (
|
||||||
modelID: "gpt-5" as any,
|
(yield* registry.tools({
|
||||||
agent,
|
providerID: "opencode" as any,
|
||||||
}).then((tools) => tools.find((tool) => tool.id === SkillTool.id)?.description ?? "")
|
modelID: "gpt-5" as any,
|
||||||
const first = await load()
|
agent,
|
||||||
const second = await load()
|
})).find((tool) => tool.id === SkillTool.id)?.description ?? ""
|
||||||
|
)
|
||||||
|
})
|
||||||
|
const first = yield* load()
|
||||||
|
const second = yield* load()
|
||||||
|
|
||||||
expect(first).toBe(second)
|
expect(first).toBe(second)
|
||||||
|
|
||||||
@@ -117,12 +128,10 @@ description: ${description}
|
|||||||
expect(alpha).toBeGreaterThan(-1)
|
expect(alpha).toBeGreaterThan(-1)
|
||||||
expect(middle).toBeGreaterThan(alpha)
|
expect(middle).toBeGreaterThan(alpha)
|
||||||
expect(zeta).toBeGreaterThan(middle)
|
expect(zeta).toBeGreaterThan(middle)
|
||||||
},
|
}),
|
||||||
})
|
{ git: true },
|
||||||
} finally {
|
),
|
||||||
process.env.OPENCODE_TEST_HOME = home
|
)
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
test("execute returns skill content block with files", async () => {
|
test("execute returns skill content block with files", async () => {
|
||||||
await using tmp = await tmpdir({
|
await using tmp = await tmpdir({
|
||||||
|
|||||||
Reference in New Issue
Block a user