mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-16 13:18:29 +00:00
66 lines
2.7 KiB
TypeScript
66 lines
2.7 KiB
TypeScript
import { AgentV2 } from "@opencode-ai/core/agent"
|
|
import type { PermissionV2 } from "@opencode-ai/core/permission"
|
|
import { SessionMessage } from "@opencode-ai/core/session/message"
|
|
import { ToolRegistry } from "@opencode-ai/core/tool/registry"
|
|
import { Tools } from "@opencode-ai/core/tool/tools"
|
|
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
|
import { Effect, type Scope } from "effect"
|
|
|
|
export const toolIdentity = {
|
|
agent: AgentV2.ID.make("build"),
|
|
assistantMessageID: SessionMessage.ID.make("msg_tool_test"),
|
|
}
|
|
|
|
// Default fixture model: a non-OpenAI provider, so edit and write are the materialized edit tools.
|
|
export const testModel: ToolRegistry.MaterializeInput["model"] = { id: "claude-test", provider: "anthropic" }
|
|
|
|
export const toolDefinitions = (
|
|
registry: ToolRegistry.Interface,
|
|
permissions?: PermissionV2.Ruleset,
|
|
model = testModel,
|
|
) => registry.materialize({ permissions, model }).pipe(Effect.map((materialized) => materialized.definitions))
|
|
|
|
export function waitForTool(
|
|
registry: ToolRegistry.Interface,
|
|
name: string,
|
|
remaining = 1000,
|
|
): Effect.Effect<void, Error> {
|
|
return Effect.gen(function* () {
|
|
if ((yield* toolDefinitions(registry)).some((tool) => tool.name === name)) return
|
|
if (remaining === 0) {
|
|
yield* Effect.fail(new Error(`Timed out waiting for tool: ${name}`))
|
|
return
|
|
}
|
|
yield* Effect.promise(() => Bun.sleep(1))
|
|
yield* waitForTool(registry, name, remaining - 1)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Registers a core tool plugin's tools against the real registry without booting the
|
|
* full plugin host. Only the tool domain is live; focused tool tests exercise
|
|
* registration, materialization, and settlement through the same path production uses.
|
|
*/
|
|
export const registerToolPlugin = <R>(plugin: {
|
|
readonly id: string
|
|
readonly effect: (context: PluginContext) => Effect.Effect<void, never, R>
|
|
}): Effect.Effect<void, never, R | Tools.Service | Scope.Scope> =>
|
|
Effect.gen(function* () {
|
|
const tools = yield* Tools.Service
|
|
const context: Pick<PluginContext, "tool"> = {
|
|
tool: {
|
|
register: tools.register,
|
|
execute: {
|
|
before: () => Effect.die("registerToolPlugin does not support tool hooks"),
|
|
after: () => Effect.die("registerToolPlugin does not support tool hooks"),
|
|
},
|
|
},
|
|
}
|
|
yield* plugin.effect(context as PluginContext)
|
|
})
|
|
|
|
export const settleTool = (registry: ToolRegistry.Interface, input: ToolRegistry.ExecuteInput, model = testModel) =>
|
|
registry.materialize({ model }).pipe(Effect.flatMap((materialized) => materialized.settle(input)))
|
|
|
|
export const executeTool = (registry: ToolRegistry.Interface, input: ToolRegistry.ExecuteInput, model = testModel) =>
|
|
settleTool(registry, input, model).pipe(Effect.map((settlement) => settlement.result))
|