wip: bash commands

This commit is contained in:
Dax Raad
2025-08-13 13:28:51 -04:00
parent 77bb5af092
commit 7505fa61b9
2 changed files with 122 additions and 0 deletions

View File

@@ -592,6 +592,36 @@ export namespace Server {
return c.json(msg)
},
)
.post(
"/session/:id/command",
describeRoute({
description: "Run a bash command",
operationId: "session.chat",
responses: {
200: {
description: "Created message",
content: {
"application/json": {
schema: resolver(MessageV2.Assistant),
},
},
},
},
}),
zValidator(
"param",
z.object({
id: z.string().openapi({ description: "Session ID" }),
}),
),
zValidator("json", Session.CommandInput.omit({ sessionID: true })),
async (c) => {
const sessionID = c.req.valid("param").id
const body = c.req.valid("json")
const msg = await Session.command({ ...body, sessionID })
return c.json(msg)
},
)
.post(
"/session/:id/revert",
describeRoute({

View File

@@ -43,6 +43,8 @@ import { Plugin } from "../plugin"
import { Agent } from "../agent/agent"
import { Permission } from "../permission"
import { Wildcard } from "../util/wildcard"
import { BashTool } from "../tool/bash"
import { ulid } from "ulid"
export namespace Session {
const log = Log.create({ service: "session" })
@@ -997,6 +999,96 @@ export namespace Session {
return result
}
export const CommandInput = z.object({
sessionID: Identifier.schema("session"),
agent: z.string(),
command: z.string(),
})
export type CommandInput = z.infer<typeof CommandInput>
export async function command(input: CommandInput) {
using abort = lock(input.sessionID)
const msg: MessageV2.Assistant = {
id: Identifier.ascending("message"),
sessionID: input.sessionID,
system: [],
mode: input.agent,
cost: 0,
path: {
cwd: App.info().path.cwd,
root: App.info().path.root,
},
time: {
created: Date.now(),
},
role: "assistant",
tokens: {
input: 0,
output: 0,
reasoning: 0,
cache: { read: 0, write: 0 },
},
modelID: "",
providerID: "",
}
await updateMessage(msg)
const part: MessageV2.Part = {
type: "tool",
id: Identifier.ascending("part"),
messageID: msg.id,
sessionID: input.sessionID,
tool: "bash",
callID: ulid(),
state: {
status: "running",
time: {
start: Date.now(),
},
input: {
command: input.command,
},
},
}
await updatePart(part)
const tool = await BashTool.init()
const result = await tool.execute(
{
command: input.command,
description: "User command",
},
{
messageID: msg.id,
sessionID: input.sessionID,
abort: abort.signal,
callID: part.callID,
agent: input.agent,
metadata: async (e) => {
if (part.state.status === "running") {
part.state.title = e.title
part.state.metadata = e.metadata
await updatePart(part)
}
},
},
)
msg.time.completed = Date.now()
await updateMessage(msg)
if (part.state.status === "running") {
part.state = {
status: "completed",
time: {
...part.state.time,
end: Date.now(),
},
input: part.state.input,
title: result.title,
metadata: result.metadata,
output: result.output,
}
await updatePart(part)
}
return { info: msg, parts: [part] }
}
function createProcessor(assistantMsg: MessageV2.Assistant, model: ModelsDev.Model) {
const toolcalls: Record<string, MessageV2.ToolPart> = {}
let snapshot: string | undefined