mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-21 03:15:11 +00:00
refactor(effect): simplify task tool registry bridge
This commit is contained in:
@@ -47,6 +47,7 @@ import { Process } from "@/util/process"
|
||||
import { Cause, Effect, Exit, Layer, Option, Scope, ServiceMap } from "effect"
|
||||
import { InstanceState } from "@/effect/instance-state"
|
||||
import { makeRuntime } from "@/effect/run-service"
|
||||
import { TaskTool } from "@/tool/task"
|
||||
|
||||
// @ts-ignore
|
||||
globalThis.AI_SDK_LOG_WARNINGS = false
|
||||
@@ -558,7 +559,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
||||
}) {
|
||||
const { task, model, lastUser, sessionID, session, msgs } = input
|
||||
const ctx = yield* InstanceState.context
|
||||
const taskTool = yield* registry.fromID("task")
|
||||
const taskTool = yield* registry.fromID(TaskTool.id)
|
||||
const taskModel = task.model ? yield* getModel(task.model.providerID, task.model.modelID, sessionID) : model
|
||||
const assistantMessage: MessageV2.Assistant = yield* sessions.updateMessage({
|
||||
id: MessageID.ascending(),
|
||||
@@ -581,7 +582,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
||||
sessionID: assistantMessage.sessionID,
|
||||
type: "tool",
|
||||
callID: ulid(),
|
||||
tool: "task",
|
||||
tool: TaskTool.id,
|
||||
state: {
|
||||
status: "running",
|
||||
input: {
|
||||
|
||||
@@ -82,18 +82,10 @@ export namespace ToolRegistry {
|
||||
const config = yield* Config.Service
|
||||
const plugin = yield* Plugin.Service
|
||||
|
||||
const info = <T extends Tool.Info, R = never>(
|
||||
tool: T | Effect.Effect<T, never, R>,
|
||||
): Effect.Effect<T, never, R> => (Effect.isEffect(tool) ? tool : Effect.succeed(tool))
|
||||
|
||||
const build = <T extends Tool.Info, R = never>(
|
||||
tool: T | Effect.Effect<T, never, R>,
|
||||
): Effect.Effect<Tool.Def, never, R> => info(tool).pipe(Effect.flatMap(Tool.init))
|
||||
|
||||
const task = yield* info(TaskTool)
|
||||
const read = yield* info(ReadTool)
|
||||
const askInfo = yield* info(QuestionTool)
|
||||
const todoInfo = yield* info(TodoWriteTool)
|
||||
const task = yield* TaskTool
|
||||
const read = yield* ReadTool
|
||||
const question = yield* QuestionTool
|
||||
const todo = yield* TodoWriteTool
|
||||
|
||||
const state = yield* InstanceState.make<State>(
|
||||
Effect.fn("ToolRegistry.state")(function* (ctx) {
|
||||
@@ -147,47 +139,49 @@ export namespace ToolRegistry {
|
||||
}
|
||||
|
||||
const cfg = yield* config.get()
|
||||
const question =
|
||||
const questionEnabled =
|
||||
["app", "cli", "desktop"].includes(Flag.OPENCODE_CLIENT) || Flag.OPENCODE_ENABLE_QUESTION_TOOL
|
||||
|
||||
const invalid = yield* build(InvalidTool)
|
||||
const bash = yield* build(BashTool)
|
||||
const readDef = yield* build(read)
|
||||
const glob = yield* build(GlobTool)
|
||||
const grep = yield* build(GrepTool)
|
||||
const edit = yield* build(EditTool)
|
||||
const write = yield* build(WriteTool)
|
||||
const taskDef = yield* build(task)
|
||||
const fetch = yield* build(WebFetchTool)
|
||||
const todo = yield* build(todoInfo)
|
||||
const search = yield* build(WebSearchTool)
|
||||
const code = yield* build(CodeSearchTool)
|
||||
const skill = yield* build(SkillTool)
|
||||
const patch = yield* build(ApplyPatchTool)
|
||||
const ask = yield* build(askInfo)
|
||||
const lsp = yield* build(LspTool)
|
||||
const plan = yield* build(PlanExitTool)
|
||||
const tool = yield* Effect.all({
|
||||
invalid: Tool.init(InvalidTool),
|
||||
bash: Tool.init(BashTool),
|
||||
read: Tool.init(read),
|
||||
glob: Tool.init(GlobTool),
|
||||
grep: Tool.init(GrepTool),
|
||||
edit: Tool.init(EditTool),
|
||||
write: Tool.init(WriteTool),
|
||||
task: Tool.init(task),
|
||||
fetch: Tool.init(WebFetchTool),
|
||||
todo: Tool.init(todo),
|
||||
search: Tool.init(WebSearchTool),
|
||||
code: Tool.init(CodeSearchTool),
|
||||
skill: Tool.init(SkillTool),
|
||||
patch: Tool.init(ApplyPatchTool),
|
||||
question: Tool.init(question),
|
||||
lsp: Tool.init(LspTool),
|
||||
plan: Tool.init(PlanExitTool),
|
||||
})
|
||||
|
||||
return {
|
||||
custom,
|
||||
builtin: [
|
||||
invalid,
|
||||
...(question ? [ask] : []),
|
||||
bash,
|
||||
readDef,
|
||||
glob,
|
||||
grep,
|
||||
edit,
|
||||
write,
|
||||
taskDef,
|
||||
fetch,
|
||||
todo,
|
||||
search,
|
||||
code,
|
||||
skill,
|
||||
patch,
|
||||
...(Flag.OPENCODE_EXPERIMENTAL_LSP_TOOL ? [lsp] : []),
|
||||
...(Flag.OPENCODE_EXPERIMENTAL_PLAN_MODE && Flag.OPENCODE_CLIENT === "cli" ? [plan] : []),
|
||||
tool.invalid,
|
||||
...(questionEnabled ? [tool.question] : []),
|
||||
tool.bash,
|
||||
tool.read,
|
||||
tool.glob,
|
||||
tool.grep,
|
||||
tool.edit,
|
||||
tool.write,
|
||||
tool.task,
|
||||
tool.fetch,
|
||||
tool.todo,
|
||||
tool.search,
|
||||
tool.code,
|
||||
tool.skill,
|
||||
tool.patch,
|
||||
...(Flag.OPENCODE_EXPERIMENTAL_LSP_TOOL ? [tool.lsp] : []),
|
||||
...(Flag.OPENCODE_EXPERIMENTAL_PLAN_MODE && Flag.OPENCODE_CLIENT === "cli" ? [tool.plan] : []),
|
||||
],
|
||||
}
|
||||
}),
|
||||
@@ -237,7 +231,7 @@ export namespace ToolRegistry {
|
||||
id: tool.id,
|
||||
description: [
|
||||
output.description,
|
||||
tool.id === "task" ? yield* TaskDescription(input.agent) : undefined,
|
||||
tool.id === TaskTool.id ? yield* TaskDescription(input.agent) : undefined,
|
||||
tool.id === SkillTool.id ? yield* SkillDescription(input.agent) : undefined,
|
||||
]
|
||||
.filter(Boolean)
|
||||
|
||||
@@ -10,6 +10,8 @@ import { Config } from "../config/config"
|
||||
import { Permission } from "@/permission"
|
||||
import { Effect } from "effect"
|
||||
|
||||
const id = "task"
|
||||
|
||||
const parameters = z.object({
|
||||
description: z.string().describe("A short (3-5 words) description of the task"),
|
||||
prompt: z.string().describe("The task for the agent to perform"),
|
||||
@@ -24,7 +26,7 @@ const parameters = z.object({
|
||||
})
|
||||
|
||||
export const TaskTool = Tool.defineEffect(
|
||||
"task",
|
||||
id,
|
||||
Effect.gen(function* () {
|
||||
const agent = yield* Agent.Service
|
||||
const config = yield* Config.Service
|
||||
@@ -35,7 +37,7 @@ export const TaskTool = Tool.defineEffect(
|
||||
if (!ctx.extra?.bypassAgentCheck) {
|
||||
yield* Effect.promise(() =>
|
||||
ctx.ask({
|
||||
permission: "task",
|
||||
permission: id,
|
||||
patterns: [params.subagent_type],
|
||||
always: ["*"],
|
||||
metadata: {
|
||||
@@ -51,7 +53,7 @@ export const TaskTool = Tool.defineEffect(
|
||||
return yield* Effect.fail(new Error(`Unknown agent type: ${params.subagent_type} is not a valid agent type`))
|
||||
}
|
||||
|
||||
const canTask = next.permission.some((rule) => rule.permission === "task")
|
||||
const canTask = next.permission.some((rule) => rule.permission === id)
|
||||
const canTodo = next.permission.some((rule) => rule.permission === "todowrite")
|
||||
|
||||
const taskID = params.task_id
|
||||
@@ -81,7 +83,7 @@ export const TaskTool = Tool.defineEffect(
|
||||
? []
|
||||
: [
|
||||
{
|
||||
permission: "task" as const,
|
||||
permission: id,
|
||||
pattern: "*" as const,
|
||||
action: "deny" as const,
|
||||
},
|
||||
|
||||
@@ -98,24 +98,27 @@ export namespace Tool {
|
||||
}
|
||||
}
|
||||
|
||||
export function define<Parameters extends z.ZodType, Result extends Metadata>(
|
||||
id: string,
|
||||
export function define<Parameters extends z.ZodType, Result extends Metadata, ID extends string = string>(
|
||||
id: ID,
|
||||
init: (() => Promise<DefWithoutID<Parameters, Result>>) | DefWithoutID<Parameters, Result>,
|
||||
): Info<Parameters, Result> {
|
||||
): Info<Parameters, Result> & { id: ID } {
|
||||
return {
|
||||
id,
|
||||
init: wrap(id, init),
|
||||
}
|
||||
}
|
||||
|
||||
export function defineEffect<Parameters extends z.ZodType, Result extends Metadata, R>(
|
||||
id: string,
|
||||
export function defineEffect<Parameters extends z.ZodType, Result extends Metadata, R, ID extends string = string>(
|
||||
id: ID,
|
||||
init: Effect.Effect<(() => Promise<DefWithoutID<Parameters, Result>>) | DefWithoutID<Parameters, Result>, never, R>,
|
||||
): Effect.Effect<Info<Parameters, Result>, never, R> {
|
||||
return Effect.map(init, (next) => ({ id, init: wrap(id, next) }))
|
||||
): Effect.Effect<Info<Parameters, Result>, never, R> & { id: ID } {
|
||||
return Object.assign(
|
||||
Effect.map(init, (next) => ({ id, init: wrap(id, next) })),
|
||||
{ id },
|
||||
)
|
||||
}
|
||||
|
||||
export function init(info: Info): Effect.Effect<Def, never, any> {
|
||||
export function init(info: Info): Effect.Effect<Def> {
|
||||
return Effect.gen(function* () {
|
||||
const init = yield* Effect.promise(() => info.init())
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user