Merge pull request #2476 from code-yeongyu/fix/issue-2441-session-id-pending

fix: omit sessionId from metadata when not yet assigned
This commit is contained in:
YeonGyu-Kim
2026-03-12 01:32:30 +09:00
committed by GitHub
4 changed files with 158 additions and 4 deletions

View File

@@ -0,0 +1,68 @@
/// <reference types="bun-types" />
import type { ToolContext } from "@opencode-ai/plugin/tool"
import { describe, expect, test } from "bun:test"
import type { BackgroundTask } from "../../features/background-agent"
import { clearPendingStore, consumeToolMetadata } from "../../features/tool-metadata-store"
import type { BackgroundOutputClient, BackgroundOutputManager } from "./clients"
import { createBackgroundOutput } from "./create-background-output"
const projectDir = "/Users/yeongyu/local-workspaces/oh-my-opencode"
type ToolContextWithCallID = ToolContext & {
callID: string
}
describe("createBackgroundOutput metadata", () => {
test("omits sessionId metadata when task session is not yet assigned", async () => {
// #given
clearPendingStore()
const task: BackgroundTask = {
id: "task-1",
sessionID: undefined,
parentSessionID: "main-1",
parentMessageID: "msg-1",
description: "background task",
prompt: "do work",
agent: "test-agent",
status: "running",
}
const manager: BackgroundOutputManager = {
getTask: id => (id === task.id ? task : undefined),
}
const client: BackgroundOutputClient = {
session: {
messages: async () => ({ data: [] }),
},
}
const tool = createBackgroundOutput(manager, client)
const context = {
sessionID: "test-session",
messageID: "test-message",
agent: "test-agent",
directory: projectDir,
worktree: projectDir,
abort: new AbortController().signal,
metadata: () => {},
ask: async () => {},
callID: "call-1",
} as ToolContextWithCallID
// #when
await tool.execute({ task_id: task.id }, context)
// #then
expect(consumeToolMetadata("test-session", "call-1")).toEqual({
title: "test-agent - background task",
metadata: {
agent: "test-agent",
category: undefined,
description: "background task",
task_id: "task-1",
},
})
clearPendingStore()
})
})

View File

@@ -75,7 +75,7 @@ export function createBackgroundOutput(manager: BackgroundOutputManager, client:
agent: task.agent,
category: task.category,
description: task.description,
sessionId: task.sessionID ?? "pending",
...(task.sessionID ? { sessionId: task.sessionID } : {}),
} as Record<string, unknown>,
}
ctx.metadata?.(meta)

View File

@@ -0,0 +1,84 @@
/// <reference types="bun-types" />
import type { PluginInput } from "@opencode-ai/plugin"
import type { ToolContext } from "@opencode-ai/plugin/tool"
import { describe, expect, mock, test } from "bun:test"
import type { BackgroundManager } from "../../features/background-agent"
import { clearPendingStore, consumeToolMetadata } from "../../features/tool-metadata-store"
import { createBackgroundTask } from "./create-background-task"
const projectDir = "/Users/yeongyu/local-workspaces/oh-my-opencode"
type ToolContextWithCallID = ToolContext & {
callID: string
}
describe("createBackgroundTask metadata", () => {
test("omits sessionId metadata when session is not yet assigned", async () => {
// #given
clearPendingStore()
const manager = {
launch: mock(() => Promise.resolve({
id: "task-1",
sessionID: null,
description: "Test task",
agent: "test-agent",
status: "pending",
})),
getTask: mock(() => undefined),
} as unknown as BackgroundManager
const client = {
session: {
messages: mock(() => Promise.resolve({ data: [] })),
},
} as unknown as PluginInput["client"]
let capturedMetadata: { title?: string; metadata?: Record<string, unknown> } | undefined
const tool = createBackgroundTask(manager, client)
const originalDateNow = Date.now
let dateNowCallCount = 0
Date.now = () => {
dateNowCallCount += 1
return dateNowCallCount === 1 ? 0 : 30001
}
try {
// #when
const context: ToolContextWithCallID = {
sessionID: "test-session",
messageID: "test-message",
agent: "test-agent",
directory: projectDir,
worktree: projectDir,
abort: new AbortController().signal,
ask: async () => {},
callID: "call-1",
metadata: input => {
capturedMetadata = input
},
}
const output = await tool.execute(
{
description: "Test background task",
prompt: "Test prompt",
agent: "test-agent",
},
context
)
// #then
expect(output).toContain("Session ID: (not yet assigned)")
expect(output).not.toContain('Session ID: pending')
expect(capturedMetadata?.metadata).toEqual({})
expect(consumeToolMetadata("test-session", "call-1")).toEqual({
title: "Test background task",
metadata: {},
})
} finally {
Date.now = originalDateNow
clearPendingStore()
}
})
})

View File

@@ -94,9 +94,11 @@ export function createBackgroundTask(
const bgMeta = {
title: args.description,
metadata: { sessionId: sessionId ?? "pending" },
metadata: {
...(sessionId ? { sessionId } : {}),
},
}
await ctx.metadata?.(bgMeta)
ctx.metadata?.(bgMeta)
if (ctx.callID) {
storeToolMetadata(ctx.sessionID, ctx.callID, bgMeta)
@@ -105,7 +107,7 @@ export function createBackgroundTask(
return `Background task launched successfully.
Task ID: ${task.id}
Session ID: ${sessionId ?? "pending"}
Session ID: ${sessionId ?? "(not yet assigned)"}
Description: ${task.description}
Agent: ${task.agent}
Status: ${task.status}