refactor(cli): convert debug agent command to effectCmd (#25485)
This commit is contained in:
@@ -7,14 +7,14 @@ import { Session } from "@/session/session"
|
|||||||
import type { MessageV2 } from "../../../session/message-v2"
|
import type { MessageV2 } from "../../../session/message-v2"
|
||||||
import { MessageID, PartID } from "../../../session/schema"
|
import { MessageID, PartID } from "../../../session/schema"
|
||||||
import { ToolRegistry } from "@/tool/registry"
|
import { ToolRegistry } from "@/tool/registry"
|
||||||
import { Instance } from "../../../project/instance"
|
|
||||||
import { Permission } from "../../../permission"
|
import { Permission } from "../../../permission"
|
||||||
import { iife } from "../../../util/iife"
|
import { iife } from "../../../util/iife"
|
||||||
import { bootstrap } from "../../bootstrap"
|
import { effectCmd, fail } from "../../effect-cmd"
|
||||||
import { cmd } from "../cmd"
|
import { InstanceRef } from "@/effect/instance-ref"
|
||||||
import { AppRuntime } from "@/effect/app-runtime"
|
import { InstanceStore } from "@/project/instance-store"
|
||||||
|
import type { InstanceContext } from "@/project/instance"
|
||||||
|
|
||||||
export const AgentCommand = cmd({
|
export const AgentCommand = effectCmd({
|
||||||
command: "agent <name>",
|
command: "agent <name>",
|
||||||
describe: "show agent configuration details",
|
describe: "show agent configuration details",
|
||||||
builder: (yargs) =>
|
builder: (yargs) =>
|
||||||
@@ -32,60 +32,61 @@ export const AgentCommand = cmd({
|
|||||||
type: "string",
|
type: "string",
|
||||||
description: "Tool params as JSON or a JS object literal",
|
description: "Tool params as JSON or a JS object literal",
|
||||||
}),
|
}),
|
||||||
async handler(args) {
|
handler: Effect.fn("Cli.debug.agent")(function* (args) {
|
||||||
await bootstrap(process.cwd(), async () => {
|
const ctx = yield* InstanceRef
|
||||||
const agentName = args.name as string
|
if (!ctx) return
|
||||||
const agent = await AppRuntime.runPromise(Agent.Service.use((svc) => svc.get(agentName)))
|
const store = yield* InstanceStore.Service
|
||||||
if (!agent) {
|
return yield* run(args, ctx).pipe(Effect.ensuring(store.dispose(ctx)))
|
||||||
process.stderr.write(
|
}),
|
||||||
`Agent ${agentName} not found, run '${basename(process.execPath)} agent list' to get an agent list` + EOL,
|
|
||||||
)
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
const availableTools = await getAvailableTools(agent)
|
|
||||||
const resolvedTools = await resolveTools(agent, availableTools)
|
|
||||||
const toolID = args.tool as string | undefined
|
|
||||||
if (toolID) {
|
|
||||||
const tool = availableTools.find((item) => item.id === toolID)
|
|
||||||
if (!tool) {
|
|
||||||
process.stderr.write(`Tool ${toolID} not found for agent ${agentName}` + EOL)
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
if (resolvedTools[toolID] === false) {
|
|
||||||
process.stderr.write(`Tool ${toolID} is disabled for agent ${agentName}` + EOL)
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
const params = parseToolParams(args.params as string | undefined)
|
|
||||||
const ctx = await createToolContext(agent)
|
|
||||||
const result = await tool.execute(params, ctx)
|
|
||||||
process.stdout.write(JSON.stringify({ tool: toolID, input: params, result }, null, 2) + EOL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const output = {
|
|
||||||
...agent,
|
|
||||||
tools: resolvedTools,
|
|
||||||
}
|
|
||||||
process.stdout.write(JSON.stringify(output, null, 2) + EOL)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
async function getAvailableTools(agent: Agent.Info) {
|
const run = Effect.fn("Cli.debug.agent.body")(function* (
|
||||||
return AppRuntime.runPromise(
|
args: { name: string; tool?: string; params?: string },
|
||||||
Effect.gen(function* () {
|
ctx: InstanceContext,
|
||||||
const provider = yield* Provider.Service
|
) {
|
||||||
const registry = yield* ToolRegistry.Service
|
const agentName = args.name
|
||||||
const model = agent.model ?? (yield* provider.defaultModel())
|
const agent = yield* Agent.Service.use((svc) => svc.get(agentName))
|
||||||
return yield* registry.tools({
|
if (!agent) {
|
||||||
...model,
|
process.stderr.write(
|
||||||
agent,
|
`Agent ${agentName} not found, run '${basename(process.execPath)} agent list' to get an agent list` + EOL,
|
||||||
})
|
)
|
||||||
}),
|
return yield* fail("", 1)
|
||||||
)
|
}
|
||||||
}
|
const availableTools = yield* getAvailableTools(agent)
|
||||||
|
const resolvedTools = resolveTools(agent, availableTools)
|
||||||
|
const toolID = args.tool
|
||||||
|
if (toolID) {
|
||||||
|
const tool = availableTools.find((item) => item.id === toolID)
|
||||||
|
if (!tool) {
|
||||||
|
process.stderr.write(`Tool ${toolID} not found for agent ${agentName}` + EOL)
|
||||||
|
return yield* fail("", 1)
|
||||||
|
}
|
||||||
|
if (resolvedTools[toolID] === false) {
|
||||||
|
process.stderr.write(`Tool ${toolID} is disabled for agent ${agentName}` + EOL)
|
||||||
|
return yield* fail("", 1)
|
||||||
|
}
|
||||||
|
const params = parseToolParams(args.params)
|
||||||
|
const toolCtx = yield* createToolContext(agent, ctx)
|
||||||
|
const result = yield* tool.execute(params, toolCtx)
|
||||||
|
process.stdout.write(JSON.stringify({ tool: toolID, input: params, result }, null, 2) + EOL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
async function resolveTools(agent: Agent.Info, availableTools: Awaited<ReturnType<typeof getAvailableTools>>) {
|
const output = {
|
||||||
|
...agent,
|
||||||
|
tools: resolvedTools,
|
||||||
|
}
|
||||||
|
process.stdout.write(JSON.stringify(output, null, 2) + EOL)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getAvailableTools = Effect.fn("Cli.debug.agent.getAvailableTools")(function* (agent: Agent.Info) {
|
||||||
|
const provider = yield* Provider.Service
|
||||||
|
const registry = yield* ToolRegistry.Service
|
||||||
|
const model = agent.model ?? (yield* provider.defaultModel())
|
||||||
|
return yield* registry.tools({ ...model, agent })
|
||||||
|
})
|
||||||
|
|
||||||
|
function resolveTools(agent: Agent.Info, availableTools: { id: string }[]) {
|
||||||
const disabled = Permission.disabled(
|
const disabled = Permission.disabled(
|
||||||
availableTools.map((tool) => tool.id),
|
availableTools.map((tool) => tool.id),
|
||||||
agent.permission,
|
agent.permission,
|
||||||
@@ -123,50 +124,38 @@ function parseToolParams(input?: string) {
|
|||||||
return parsed as Record<string, unknown>
|
return parsed as Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createToolContext(agent: Agent.Info) {
|
const createToolContext = Effect.fn("Cli.debug.agent.createToolContext")(function* (
|
||||||
const { session, messageID } = await AppRuntime.runPromise(
|
agent: Agent.Info,
|
||||||
Effect.gen(function* () {
|
ctx: InstanceContext,
|
||||||
const session = yield* Session.Service
|
) {
|
||||||
const result = yield* session.create({ title: `Debug tool run (${agent.name})` })
|
const sessionSvc = yield* Session.Service
|
||||||
const messageID = MessageID.ascending()
|
const session = yield* sessionSvc.create({ title: `Debug tool run (${agent.name})` })
|
||||||
const model = agent.model
|
const messageID = MessageID.ascending()
|
||||||
? agent.model
|
const model = agent.model
|
||||||
: yield* Effect.gen(function* () {
|
? agent.model
|
||||||
const provider = yield* Provider.Service
|
: yield* Effect.gen(function* () {
|
||||||
return yield* provider.defaultModel()
|
const provider = yield* Provider.Service
|
||||||
})
|
return yield* provider.defaultModel()
|
||||||
const now = Date.now()
|
})
|
||||||
const message: MessageV2.Assistant = {
|
const now = Date.now()
|
||||||
id: messageID,
|
const message: MessageV2.Assistant = {
|
||||||
sessionID: result.id,
|
id: messageID,
|
||||||
role: "assistant",
|
sessionID: session.id,
|
||||||
time: {
|
role: "assistant",
|
||||||
created: now,
|
time: { created: now },
|
||||||
},
|
parentID: messageID,
|
||||||
parentID: messageID,
|
modelID: model.modelID,
|
||||||
modelID: model.modelID,
|
providerID: model.providerID,
|
||||||
providerID: model.providerID,
|
mode: "debug",
|
||||||
mode: "debug",
|
agent: agent.name,
|
||||||
agent: agent.name,
|
path: {
|
||||||
path: {
|
cwd: ctx.directory,
|
||||||
cwd: Instance.directory,
|
root: ctx.worktree,
|
||||||
root: Instance.worktree,
|
},
|
||||||
},
|
cost: 0,
|
||||||
cost: 0,
|
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
||||||
tokens: {
|
}
|
||||||
input: 0,
|
yield* sessionSvc.updateMessage(message)
|
||||||
output: 0,
|
|
||||||
reasoning: 0,
|
|
||||||
cache: {
|
|
||||||
read: 0,
|
|
||||||
write: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
yield* session.updateMessage(message)
|
|
||||||
return { session: result, messageID }
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
const ruleset = Permission.merge(agent.permission, session.permission ?? [])
|
const ruleset = Permission.merge(agent.permission, session.permission ?? [])
|
||||||
|
|
||||||
@@ -189,4 +178,4 @@ async function createToolContext(agent: Agent.Info) {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user