-
Notifications
You must be signed in to change notification settings - Fork 17.8k
refactor(cli): convert debug agent command to effectCmd #25485
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,14 +7,14 @@ import { Session } from "@/session/session" | |
| import type { MessageV2 } from "../../../session/message-v2" | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. testing
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ay |
||
| import { MessageID, PartID } from "../../../session/schema" | ||
| import { ToolRegistry } from "@/tool/registry" | ||
| import { Instance } from "../../../project/instance" | ||
| import { Permission } from "../../../permission" | ||
| import { iife } from "../../../util/iife" | ||
| import { bootstrap } from "../../bootstrap" | ||
| import { cmd } from "../cmd" | ||
| import { AppRuntime } from "@/effect/app-runtime" | ||
| import { effectCmd, fail } from "../../effect-cmd" | ||
| import { InstanceRef } from "@/effect/instance-ref" | ||
| import { InstanceStore } from "@/project/instance-store" | ||
| import type { InstanceContext } from "@/project/instance" | ||
|
|
||
| export const AgentCommand = cmd({ | ||
| export const AgentCommand = effectCmd({ | ||
| command: "agent <name>", | ||
| describe: "show agent configuration details", | ||
| builder: (yargs) => | ||
|
|
@@ -32,60 +32,61 @@ export const AgentCommand = cmd({ | |
| type: "string", | ||
| description: "Tool params as JSON or a JS object literal", | ||
| }), | ||
| async handler(args) { | ||
| await bootstrap(process.cwd(), async () => { | ||
| const agentName = args.name as string | ||
| const agent = await AppRuntime.runPromise(Agent.Service.use((svc) => svc.get(agentName))) | ||
| if (!agent) { | ||
| 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 | ||
| } | ||
| handler: Effect.fn("Cli.debug.agent")(function* (args) { | ||
| const ctx = yield* InstanceRef | ||
| if (!ctx) return | ||
| const store = yield* InstanceStore.Service | ||
| return yield* run(args, ctx).pipe(Effect.ensuring(store.dispose(ctx))) | ||
| }), | ||
| }) | ||
|
|
||
| const output = { | ||
| ...agent, | ||
| tools: resolvedTools, | ||
| } | ||
| process.stdout.write(JSON.stringify(output, null, 2) + EOL) | ||
| }) | ||
| }, | ||
| const run = Effect.fn("Cli.debug.agent.body")(function* ( | ||
| args: { name: string; tool?: string; params?: string }, | ||
| ctx: InstanceContext, | ||
| ) { | ||
| const agentName = args.name | ||
| const agent = yield* Agent.Service.use((svc) => svc.get(agentName)) | ||
| if (!agent) { | ||
| process.stderr.write( | ||
| `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 | ||
| } | ||
|
|
||
| const output = { | ||
| ...agent, | ||
| tools: resolvedTools, | ||
| } | ||
| process.stdout.write(JSON.stringify(output, null, 2) + EOL) | ||
| }) | ||
|
|
||
| async function getAvailableTools(agent: Agent.Info) { | ||
| return AppRuntime.runPromise( | ||
| Effect.gen(function* () { | ||
| const provider = yield* Provider.Service | ||
| const registry = yield* ToolRegistry.Service | ||
| const model = agent.model ?? (yield* provider.defaultModel()) | ||
| return yield* registry.tools({ | ||
| ...model, | ||
| agent, | ||
| }) | ||
| }), | ||
| ) | ||
| } | ||
| const getAvailableTools = Effect.fn("Cli.debug.agent.getAvailableTools")(function* (agent: Agent.Info) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hello
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. testing
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. funky. fukny |
||
| const provider = yield* Provider.Service | ||
| 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>>) { | ||
| function resolveTools(agent: Agent.Info, availableTools: { id: string }[]) { | ||
| const disabled = Permission.disabled( | ||
| availableTools.map((tool) => tool.id), | ||
| agent.permission, | ||
|
|
@@ -123,50 +124,38 @@ function parseToolParams(input?: string) { | |
| return parsed as Record<string, unknown> | ||
| } | ||
|
|
||
| async function createToolContext(agent: Agent.Info) { | ||
| const { session, messageID } = await AppRuntime.runPromise( | ||
| Effect.gen(function* () { | ||
| const session = yield* Session.Service | ||
| const result = yield* session.create({ title: `Debug tool run (${agent.name})` }) | ||
| const messageID = MessageID.ascending() | ||
| const model = agent.model | ||
| ? agent.model | ||
| : yield* Effect.gen(function* () { | ||
| const provider = yield* Provider.Service | ||
| return yield* provider.defaultModel() | ||
| }) | ||
| const now = Date.now() | ||
| const message: MessageV2.Assistant = { | ||
| id: messageID, | ||
| sessionID: result.id, | ||
| role: "assistant", | ||
| time: { | ||
| created: now, | ||
| }, | ||
| parentID: messageID, | ||
| modelID: model.modelID, | ||
| providerID: model.providerID, | ||
| mode: "debug", | ||
| agent: agent.name, | ||
| path: { | ||
| cwd: Instance.directory, | ||
| root: Instance.worktree, | ||
| }, | ||
| cost: 0, | ||
| tokens: { | ||
| input: 0, | ||
| output: 0, | ||
| reasoning: 0, | ||
| cache: { | ||
| read: 0, | ||
| write: 0, | ||
| }, | ||
| }, | ||
| } | ||
| yield* session.updateMessage(message) | ||
| return { session: result, messageID } | ||
| }), | ||
| ) | ||
| const createToolContext = Effect.fn("Cli.debug.agent.createToolContext")(function* ( | ||
| agent: Agent.Info, | ||
| ctx: InstanceContext, | ||
| ) { | ||
| const sessionSvc = yield* Session.Service | ||
| const session = yield* sessionSvc.create({ title: `Debug tool run (${agent.name})` }) | ||
| const messageID = MessageID.ascending() | ||
| const model = agent.model | ||
| ? agent.model | ||
| : yield* Effect.gen(function* () { | ||
| const provider = yield* Provider.Service | ||
| return yield* provider.defaultModel() | ||
| }) | ||
| const now = Date.now() | ||
| const message: MessageV2.Assistant = { | ||
| id: messageID, | ||
| sessionID: session.id, | ||
| role: "assistant", | ||
| time: { created: now }, | ||
| parentID: messageID, | ||
| modelID: model.modelID, | ||
| providerID: model.providerID, | ||
| mode: "debug", | ||
| agent: agent.name, | ||
| path: { | ||
| cwd: ctx.directory, | ||
| root: ctx.worktree, | ||
| }, | ||
| cost: 0, | ||
| tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, | ||
| } | ||
| yield* sessionSvc.updateMessage(message) | ||
|
|
||
| const ruleset = Permission.merge(agent.permission, session.permission ?? []) | ||
|
|
||
|
|
@@ -189,4 +178,4 @@ async function createToolContext(agent: Agent.Info) { | |
| }) | ||
| }, | ||
| } | ||
| } | ||
| }) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test