feat(tools/background-task): resolve background_output task_id title
This commit is contained in:
parent
83a05630cd
commit
23bca2b4d5
@ -4,6 +4,37 @@ import type { BackgroundOutputArgs } from "../types"
|
|||||||
import { BACKGROUND_OUTPUT_DESCRIPTION } from "../constants"
|
import { BACKGROUND_OUTPUT_DESCRIPTION } from "../constants"
|
||||||
import { formatTaskStatus, formatTaskResult, formatFullSession } from "./formatters"
|
import { formatTaskStatus, formatTaskResult, formatFullSession } from "./formatters"
|
||||||
import { delay } from "./utils"
|
import { delay } from "./utils"
|
||||||
|
import { storeToolMetadata } from "../../../features/tool-metadata-store"
|
||||||
|
import type { BackgroundTask } from "../../../features/background-agent"
|
||||||
|
import type { ToolContextWithMetadata } from "./utils"
|
||||||
|
|
||||||
|
const SISYPHUS_JUNIOR_AGENT = "sisyphus-junior"
|
||||||
|
|
||||||
|
type ToolContextWithCallId = ToolContextWithMetadata & {
|
||||||
|
callID?: string
|
||||||
|
callId?: string
|
||||||
|
call_id?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveToolCallID(ctx: ToolContextWithCallId): string | undefined {
|
||||||
|
if (typeof ctx.callID === "string" && ctx.callID.trim() !== "") {
|
||||||
|
return ctx.callID
|
||||||
|
}
|
||||||
|
if (typeof ctx.callId === "string" && ctx.callId.trim() !== "") {
|
||||||
|
return ctx.callId
|
||||||
|
}
|
||||||
|
if (typeof ctx.call_id === "string" && ctx.call_id.trim() !== "") {
|
||||||
|
return ctx.call_id
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatResolvedTitle(task: BackgroundTask): string {
|
||||||
|
const label = task.agent === SISYPHUS_JUNIOR_AGENT && task.category
|
||||||
|
? task.category
|
||||||
|
: task.agent
|
||||||
|
return `${label} - ${task.description}`
|
||||||
|
}
|
||||||
|
|
||||||
export function createBackgroundOutput(manager: BackgroundOutputManager, client: BackgroundOutputClient): ToolDefinition {
|
export function createBackgroundOutput(manager: BackgroundOutputManager, client: BackgroundOutputClient): ToolDefinition {
|
||||||
return tool({
|
return tool({
|
||||||
@ -19,13 +50,31 @@ export function createBackgroundOutput(manager: BackgroundOutputManager, client:
|
|||||||
include_tool_results: tool.schema.boolean().optional().describe("Include tool results in full_session output (default: false)"),
|
include_tool_results: tool.schema.boolean().optional().describe("Include tool results in full_session output (default: false)"),
|
||||||
thinking_max_chars: tool.schema.number().optional().describe("Max characters for thinking content (default: 2000)"),
|
thinking_max_chars: tool.schema.number().optional().describe("Max characters for thinking content (default: 2000)"),
|
||||||
},
|
},
|
||||||
async execute(args: BackgroundOutputArgs) {
|
async execute(args: BackgroundOutputArgs, toolContext) {
|
||||||
try {
|
try {
|
||||||
|
const ctx = toolContext as ToolContextWithCallId
|
||||||
const task = manager.getTask(args.task_id)
|
const task = manager.getTask(args.task_id)
|
||||||
if (!task) {
|
if (!task) {
|
||||||
return `Task not found: ${args.task_id}`
|
return `Task not found: ${args.task_id}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resolvedTitle = formatResolvedTitle(task)
|
||||||
|
const meta = {
|
||||||
|
title: resolvedTitle,
|
||||||
|
metadata: {
|
||||||
|
task_id: task.id,
|
||||||
|
agent: task.agent,
|
||||||
|
category: task.category,
|
||||||
|
description: task.description,
|
||||||
|
sessionId: task.sessionID ?? "pending",
|
||||||
|
} as Record<string, unknown>,
|
||||||
|
}
|
||||||
|
await ctx.metadata?.(meta)
|
||||||
|
const callID = resolveToolCallID(ctx)
|
||||||
|
if (callID) {
|
||||||
|
storeToolMetadata(ctx.sessionID, callID, meta)
|
||||||
|
}
|
||||||
|
|
||||||
if (args.full_session === true) {
|
if (args.full_session === true) {
|
||||||
return await formatFullSession(task, client, {
|
return await formatFullSession(task, client, {
|
||||||
includeThinking: args.include_thinking === true,
|
includeThinking: args.include_thinking === true,
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
|
/// <reference types="bun-types" />
|
||||||
|
|
||||||
|
import { describe, test, expect } from "bun:test"
|
||||||
import { createBackgroundCancel, createBackgroundOutput } from "./tools"
|
import { createBackgroundCancel, createBackgroundOutput } from "./tools"
|
||||||
import type { BackgroundManager, BackgroundTask } from "../../features/background-agent"
|
import type { BackgroundManager, BackgroundTask } from "../../features/background-agent"
|
||||||
import type { ToolContext } from "@opencode-ai/plugin/tool"
|
import type { ToolContext } from "@opencode-ai/plugin/tool"
|
||||||
import type { BackgroundCancelClient, BackgroundOutputManager, BackgroundOutputClient } from "./tools"
|
import type { BackgroundCancelClient, BackgroundOutputManager, BackgroundOutputClient } from "./tools"
|
||||||
|
import { consumeToolMetadata, clearPendingStore } from "../../features/tool-metadata-store"
|
||||||
|
|
||||||
const projectDir = "/Users/yeongyu/local-workspaces/oh-my-opencode"
|
const projectDir = "/Users/yeongyu/local-workspaces/oh-my-opencode"
|
||||||
|
|
||||||
@ -49,6 +53,59 @@ function createTask(overrides: Partial<BackgroundTask> = {}): BackgroundTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("background_output full_session", () => {
|
describe("background_output full_session", () => {
|
||||||
|
test("resolves task_id into title metadata", async () => {
|
||||||
|
// #given
|
||||||
|
clearPendingStore()
|
||||||
|
|
||||||
|
const task = createTask({
|
||||||
|
id: "task-1",
|
||||||
|
agent: "explore",
|
||||||
|
description: "Find how task output is rendered",
|
||||||
|
status: "running",
|
||||||
|
})
|
||||||
|
const manager = createMockManager(task)
|
||||||
|
const client = createMockClient({})
|
||||||
|
const tool = createBackgroundOutput(manager, client)
|
||||||
|
const ctxWithCallId = {
|
||||||
|
...mockContext,
|
||||||
|
callID: "call-1",
|
||||||
|
} as unknown as ToolContext
|
||||||
|
|
||||||
|
// #when
|
||||||
|
await tool.execute({ task_id: "task-1" }, ctxWithCallId)
|
||||||
|
|
||||||
|
// #then
|
||||||
|
const restored = consumeToolMetadata("test-session", "call-1")
|
||||||
|
expect(restored?.title).toBe("explore - Find how task output is rendered")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("shows category instead of agent for sisyphus-junior", async () => {
|
||||||
|
// #given
|
||||||
|
clearPendingStore()
|
||||||
|
|
||||||
|
const task = createTask({
|
||||||
|
id: "task-1",
|
||||||
|
agent: "sisyphus-junior",
|
||||||
|
category: "quick",
|
||||||
|
description: "Fix flaky test",
|
||||||
|
status: "running",
|
||||||
|
})
|
||||||
|
const manager = createMockManager(task)
|
||||||
|
const client = createMockClient({})
|
||||||
|
const tool = createBackgroundOutput(manager, client)
|
||||||
|
const ctxWithCallId = {
|
||||||
|
...mockContext,
|
||||||
|
callID: "call-1",
|
||||||
|
} as unknown as ToolContext
|
||||||
|
|
||||||
|
// #when
|
||||||
|
await tool.execute({ task_id: "task-1" }, ctxWithCallId)
|
||||||
|
|
||||||
|
// #then
|
||||||
|
const restored = consumeToolMetadata("test-session", "call-1")
|
||||||
|
expect(restored?.title).toBe("quick - Fix flaky test")
|
||||||
|
})
|
||||||
|
|
||||||
test("includes thinking and tool results when enabled", async () => {
|
test("includes thinking and tool results when enabled", async () => {
|
||||||
// #given
|
// #given
|
||||||
const task = createTask()
|
const task = createTask()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user