feat(core): adjust bg shell completion msg (include output file) (#45461)

This commit is contained in:
Aiden Cline
2026-08-26 23:04:11 -05:00
committed by GitHub
parent 1c66cd7832
commit fcc6568fcb
2 changed files with 25 additions and 14 deletions
+5 -6
View File
@@ -19,9 +19,8 @@ import { ToolOutput } from "../../tool-output.js"
export const name = "shell"
export const DEFAULT_TIMEOUT_MS = 2 * 60 * 1_000
const BACKGROUND_STARTED = "The command was moved to the background."
const BACKGROUND_INSTRUCTION =
"You will be notified automatically when the command finishes. DO NOT sleep, poll, or proactively check on its progress."
"You will be notified automatically when the command finishes. Avoid sleep commands or polling for completion; if you need the output before then, read the file directly."
const OS =
process.platform === "darwin"
? "macOS"
@@ -95,8 +94,8 @@ const toolResult = (output: Output) => {
}
}
const backgroundResult = (shellID: string) => ({
output: BACKGROUND_STARTED,
const backgroundResult = (shellID: string, file: string) => ({
output: `Command moved to the background (shell ID: ${shellID}).\nOutput is streaming to: ${file}`,
shellID,
truncated: false,
status: "running" as const,
@@ -295,7 +294,7 @@ export const Plugin = {
if (input.background === true) {
yield* runtime.job.background(job.id)
yield* notifyWhenDone(context.sessionID, context.id, info.id, info.command, settled)
return backgroundResult(info.id)
return backgroundResult(info.id, info.file)
}
const result = yield* runtime.job
@@ -304,7 +303,7 @@ export const Plugin = {
if (result?.type === "backgrounded") {
yield* shell.timeout(info.id, 0)
yield* notifyWhenDone(context.sessionID, context.id, info.id, info.command, settled)
return backgroundResult(info.id)
return backgroundResult(info.id, info.file)
}
if (result?.info.status === "error")
return yield* Effect.fail(new Error(result.info.error ?? "Command failed"))
+20 -8
View File
@@ -1298,6 +1298,17 @@ describe("ShellTool", () => {
const shell = yield* Shell.Service
if (!shellID) return
const id = ShellSchema.ID.make(shellID)
const info = yield* shell.get(id)
expect(settled.content).toEqual([
{
type: "text",
text: `Command moved to the background (shell ID: ${shellID}).\nOutput is streaming to: ${info.file}`,
},
{
type: "text",
text: "You will be notified automatically when the command finishes. Avoid sleep commands or polling for completion; if you need the output before then, read the file directly.",
},
])
expect((yield* shell.list()).map((info) => info.id)).toContain(id)
expect((yield* shell.wait(id)).status).toBe("timeout")
expect((yield* Fiber.join(admitted)).valueOrUndefined?.data.item.payload).toMatchObject({
@@ -1523,19 +1534,20 @@ describe("ShellTool", () => {
const settled = yield* Fiber.join(waiting)
const shellID = typeof settled.metadata?.shellID === "string" ? settled.metadata.shellID : undefined
expect(settled.metadata).toMatchObject({ truncated: false })
expect(settled.content?.[0]).toEqual({
type: "text",
text: "The command was moved to the background.",
})
expect(settled.content?.[1]).toMatchObject({
type: "text",
text: expect.stringContaining("DO NOT sleep, poll"),
})
expect(shellID).toStartWith("sh_")
const shell = yield* Shell.Service
if (!shellID) return
const id = ShellSchema.ID.make(shellID)
const info = yield* shell.get(id)
expect(settled.content?.[0]).toEqual({
type: "text",
text: `Command moved to the background (shell ID: ${shellID}).\nOutput is streaming to: ${info.file}`,
})
expect(settled.content?.[1]).toEqual({
type: "text",
text: "You will be notified automatically when the command finishes. Avoid sleep commands or polling for completion; if you need the output before then, read the file directly.",
})
yield* Effect.sleep(Duration.millis(100))
expect((yield* shell.get(id)).status).toBe("running")
expect((yield* shell.list()).map((info) => info.id)).toContain(id)