diff --git a/src/tools/background-task/create-background-output.ts b/src/tools/background-task/create-background-output.ts index 925db344a..7e8ac8f3d 100644 --- a/src/tools/background-task/create-background-output.ts +++ b/src/tools/background-task/create-background-output.ts @@ -1,6 +1,6 @@ import { tool, type ToolDefinition } from "@opencode-ai/plugin" import type { BackgroundTask } from "../../features/background-agent" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import type { BackgroundOutputArgs } from "./types" import type { BackgroundOutputClient, BackgroundOutputManager } from "./clients" import { BACKGROUND_OUTPUT_DESCRIPTION } from "./constants" @@ -23,13 +23,6 @@ type ToolContextWithMetadata = { call_id?: string } -function resolveToolCallID(ctx: ToolContextWithMetadata): 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}` @@ -80,12 +73,7 @@ export function createBackgroundOutput(manager: BackgroundOutputManager, client: ...(task.sessionID ? { sessionId: task.sessionID } : {}), } as Record, } - ctx.metadata?.(meta) - - const callID = resolveToolCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, meta) - } + await publishToolMetadata(ctx, meta) const shouldBlock = args.block === true const timeoutMs = Math.min(args.timeout ?? 60000, 600000) diff --git a/src/tools/background-task/create-background-task.ts b/src/tools/background-task/create-background-task.ts index 0d2c38f0f..cd892e6a3 100644 --- a/src/tools/background-task/create-background-task.ts +++ b/src/tools/background-task/create-background-task.ts @@ -4,7 +4,7 @@ import type { BackgroundTaskArgs } from "./types" import { BACKGROUND_TASK_DESCRIPTION } from "./constants" import { resolveMessageContext } from "../../features/hook-message-injector" import { getSessionAgent } from "../../features/claude-code-session-state" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { log } from "../../shared/logger" import { delay } from "./delay" import { getMessageDir } from "./message-dir" @@ -100,11 +100,7 @@ export function createBackgroundTask( ...(sessionId ? { sessionId } : {}), }, } - ctx.metadata?.(bgMeta) - - if (ctx.callID) { - storeToolMetadata(ctx.sessionID, ctx.callID, bgMeta) - } + await publishToolMetadata(ctx, bgMeta) return `Background task launched successfully. diff --git a/src/tools/delegate-task/background-continuation.ts b/src/tools/delegate-task/background-continuation.ts index 0d365d964..dd0850439 100644 --- a/src/tools/delegate-task/background-continuation.ts +++ b/src/tools/delegate-task/background-continuation.ts @@ -1,9 +1,8 @@ import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" import type { ExecutorContext, ParentContext } from "./executor-types" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" -import { resolveCallID } from "./resolve-call-id" export async function executeBackgroundContinuation( args: DelegateTaskArgs, @@ -37,11 +36,7 @@ export async function executeBackgroundContinuation( model: task.model ? { providerID: task.model.providerID, modelID: task.model.modelID } : undefined, }, } - await ctx.metadata?.(bgContMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, bgContMeta) - } + await publishToolMetadata(ctx, bgContMeta) return `Background task continued. diff --git a/src/tools/delegate-task/background-task.ts b/src/tools/delegate-task/background-task.ts index 184325ec9..73d43ad02 100644 --- a/src/tools/delegate-task/background-task.ts +++ b/src/tools/delegate-task/background-task.ts @@ -3,8 +3,7 @@ import type { ExecutorContext, ParentContext } from "./executor-types" import type { FallbackEntry } from "../../shared/model-requirements" import { getTimingConfig } from "./timing" import { buildTaskPrompt } from "./prompt-builder" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" import { SessionCategoryRegistry } from "../../shared/session-category-registry" @@ -134,11 +133,7 @@ export async function executeBackgroundTask( title: args.description, metadata, } - await ctx.metadata?.(unstableMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, unstableMeta) - } + await publishToolMetadata(ctx, unstableMeta) const taskMetadataBlock = sessionId ? `\n\n\nsession_id: ${sessionId}\ntask_id: ${task.id}\nbackground_task_id: ${task.id}\n` diff --git a/src/tools/delegate-task/resolve-call-id.test.ts b/src/tools/delegate-task/resolve-call-id.test.ts deleted file mode 100644 index 7b4da140e..000000000 --- a/src/tools/delegate-task/resolve-call-id.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { describe, test, expect } from "bun:test" -import { resolveCallID } from "./resolve-call-id" -import type { ToolContextWithMetadata } from "./types" - -describe("resolveCallID", () => { - function makeCtx(overrides: Partial = {}): ToolContextWithMetadata { - return { - sessionID: "ses_test", - messageID: "msg_test", - agent: "sisyphus", - abort: new AbortController().signal, - ...overrides, - } - } - - test("#given callID is set #then returns callID", () => { - const ctx = makeCtx({ callID: "call_abc" }) - expect(resolveCallID(ctx)).toBe("call_abc") - }) - - test("#given only callId is set #then returns callId", () => { - const ctx = makeCtx({ callId: "call_def" }) - expect(resolveCallID(ctx)).toBe("call_def") - }) - - test("#given only call_id is set #then returns call_id", () => { - const ctx = makeCtx({ call_id: "call_ghi" }) - expect(resolveCallID(ctx)).toBe("call_ghi") - }) - - test("#given callID and callId are both set #then prefers callID", () => { - const ctx = makeCtx({ callID: "preferred", callId: "fallback" }) - expect(resolveCallID(ctx)).toBe("preferred") - }) - - test("#given no call ID variants are set #then returns undefined", () => { - const ctx = makeCtx() - expect(resolveCallID(ctx)).toBeUndefined() - }) -}) diff --git a/src/tools/delegate-task/resolve-call-id.ts b/src/tools/delegate-task/resolve-call-id.ts deleted file mode 100644 index cfa3b747e..000000000 --- a/src/tools/delegate-task/resolve-call-id.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { ToolContextWithMetadata } from "./types" - -export function resolveCallID(ctx: ToolContextWithMetadata): string | undefined { - return ctx.callID ?? ctx.callId ?? ctx.call_id -} diff --git a/src/tools/delegate-task/sync-continuation.ts b/src/tools/delegate-task/sync-continuation.ts index fa6f9f022..a8e412ece 100644 --- a/src/tools/delegate-task/sync-continuation.ts +++ b/src/tools/delegate-task/sync-continuation.ts @@ -1,8 +1,7 @@ import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types" import type { ExecutorContext, SessionMessage } from "./executor-types" import { isPlanFamily } from "./constants" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { getTaskToastManager } from "../../features/task-toast-manager" import { getAgentToolRestrictions } from "../../shared/agent-tool-restrictions" import { getMessageDir } from "../../shared" @@ -78,11 +77,7 @@ export async function executeSyncContinuation( model: resumeModel, }, } - await ctx.metadata?.(syncContMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, syncContMeta) - } + await publishToolMetadata(ctx, syncContMeta) const allowTask = isPlanFamily(resumeAgent) const tddEnabled = sisyphusAgentConfig?.tdd diff --git a/src/tools/delegate-task/sync-task.ts b/src/tools/delegate-task/sync-task.ts index 18d99e500..7675fa0de 100644 --- a/src/tools/delegate-task/sync-task.ts +++ b/src/tools/delegate-task/sync-task.ts @@ -2,8 +2,7 @@ import type { ModelFallbackInfo } from "../../features/task-toast-manager/types" import type { DelegateTaskArgs, ToolContextWithMetadata, DelegatedModelConfig } from "./types" import type { ExecutorContext, ParentContext } from "./executor-types" import { getTaskToastManager } from "../../features/task-toast-manager" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { subagentSessions, syncSubagentSessions, setSessionAgent } from "../../features/claude-code-session-state" import { log } from "../../shared/logger" import { SessionCategoryRegistry } from "../../shared/session-category-registry" @@ -130,11 +129,7 @@ export async function executeSyncTask( model: categoryModel ? { providerID: categoryModel.providerID, modelID: categoryModel.modelID } : undefined, }, } - await ctx.metadata?.(syncTaskMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, syncTaskMeta) - } + await publishToolMetadata(ctx, syncTaskMeta) let effectiveCategoryModel = categoryModel let promptError = await deps.sendSyncPrompt(client, { diff --git a/src/tools/delegate-task/unstable-agent-task.ts b/src/tools/delegate-task/unstable-agent-task.ts index 7d10780cb..7a6d46e0d 100644 --- a/src/tools/delegate-task/unstable-agent-task.ts +++ b/src/tools/delegate-task/unstable-agent-task.ts @@ -3,8 +3,7 @@ import type { ExecutorContext, ParentContext, SessionMessage } from "./executor- import { DEFAULT_SYNC_POLL_TIMEOUT_MS, getTimingConfig } from "./timing" import { buildTaskPrompt } from "./prompt-builder" import { cancelUnstableAgentTask } from "./cancel-unstable-agent-task" -import { storeToolMetadata } from "../../features/tool-metadata-store" -import { resolveCallID } from "./resolve-call-id" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { formatDuration } from "./time-formatter" import { formatDetailedError } from "./error-formatting" import { getSessionTools } from "../../shared/session-tools-store" @@ -81,11 +80,7 @@ export async function executeUnstableAgentTask( model: categoryModel ? { providerID: categoryModel.providerID, modelID: categoryModel.modelID } : undefined, }, } - await ctx.metadata?.(bgTaskMeta) - const callID = resolveCallID(ctx) - if (callID) { - storeToolMetadata(ctx.sessionID, callID, bgTaskMeta) - } + await publishToolMetadata(ctx, bgTaskMeta) const startTime = new Date() const timingCfg = getTimingConfig() diff --git a/src/tools/hashline-edit/hashline-edit-executor.ts b/src/tools/hashline-edit/hashline-edit-executor.ts index b9412d89e..54509ab6c 100644 --- a/src/tools/hashline-edit/hashline-edit-executor.ts +++ b/src/tools/hashline-edit/hashline-edit-executor.ts @@ -1,5 +1,5 @@ import type { ToolContext } from "@opencode-ai/plugin/tool" -import { storeToolMetadata } from "../../features/tool-metadata-store" +import { publishToolMetadata } from "../../features/tool-metadata-store" import { applyHashlineEditsWithReport } from "./edit-operations" import { countLineDiffs, generateUnifiedDiff } from "./diff-utils" import { canonicalizeFileText, restoreFileText } from "./file-text-canonicalization" @@ -26,13 +26,6 @@ type ToolContextWithMetadata = ToolContextWithCallID & { metadata?: (value: unknown) => void } -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 canCreateFromMissingFile(edits: HashlineEdit[]): boolean { if (edits.length === 0) return false return edits.every((edit) => (edit.op === "append" || edit.op === "prepend") && !edit.pos) @@ -143,13 +136,7 @@ export async function executeHashlineEditTool(args: HashlineEditArgs, context: T applyResult.noopEdits, applyResult.deduplicatedEdits ) - if (typeof metadataContext.metadata === "function") { - metadataContext.metadata(formattedMeta) - } - const callID = resolveToolCallID(metadataContext) - if (callID) { - storeToolMetadata(context.sessionID, callID, formattedMeta) - } + await publishToolMetadata(metadataContext, formattedMeta) if (rename && rename !== filePath) { await Bun.write(rename, formattedContent) await Bun.file(filePath).delete() @@ -173,14 +160,7 @@ export async function executeHashlineEditTool(args: HashlineEditArgs, context: T applyResult.deduplicatedEdits ) - if (typeof metadataContext.metadata === "function") { - metadataContext.metadata(meta) - } - - const callID = resolveToolCallID(metadataContext) - if (callID) { - storeToolMetadata(context.sessionID, callID, meta) - } + await publishToolMetadata(metadataContext, meta) if (rename && rename !== filePath) { return `Moved ${filePath} to ${rename}`