Render opencode Edit tool calls as diffs

opencode's Edit tool sends camelCase input keys (filePath, oldString,
newString) and a plain-string success ack on output. The shared edit
schemas expect snake_case input and an object output, so calls fell
through to the generic "unknown" renderer (raw JSON Input/Output).

Normalize both at the opencode boundary so the quirk does not leak into
the cross-provider schema.
This commit is contained in:
Mohamed Boudra
2026-05-27 22:43:08 +07:00
parent a025f17a73
commit e3eb333ddc
2 changed files with 52 additions and 5 deletions

View File

@@ -219,6 +219,25 @@ function deriveOpencodeTaskDetail(
};
}
const OpencodeEditInputSchema = z.union([
z
.object({
filePath: z.string(),
oldString: z.string().optional(),
newString: z.string().optional(),
})
.passthrough()
.transform((value) => ({
filePath: value.filePath,
oldString: nonEmptyString(value.oldString),
newString: nonEmptyString(value.newString),
unifiedDiff: undefined,
})),
ToolEditInputSchema,
]);
const OpencodeEditOutputSchema = z.union([z.string().transform(() => null), ToolEditOutputSchema]);
const OpencodeKnownToolDetailSchema = z.union([
toolDetailBranchByToolName(
"shell",
@@ -264,11 +283,16 @@ const OpencodeKnownToolDetailSchema = z.union([
ToolWriteOutputSchema,
toWriteToolDetail,
),
toolDetailBranchByToolName("edit", ToolEditInputSchema, ToolEditOutputSchema, toEditToolDetail),
toolDetailBranchByToolName(
"edit",
OpencodeEditInputSchema,
OpencodeEditOutputSchema,
toEditToolDetail,
),
toolDetailBranchByToolName(
"apply_patch",
ToolEditInputSchema,
ToolEditOutputSchema,
OpencodeEditInputSchema,
OpencodeEditOutputSchema,
toEditToolDetail,
),
toolDetailBranchByToolName(
@@ -279,8 +303,8 @@ const OpencodeKnownToolDetailSchema = z.union([
),
toolDetailBranchByToolName(
"apply_diff",
ToolEditInputSchema,
ToolEditOutputSchema,
OpencodeEditInputSchema,
OpencodeEditOutputSchema,
toEditToolDetail,
),
toolDetailBranchByToolName("search", ToolSearchInputSchema, z.unknown(), (input) =>

View File

@@ -296,6 +296,29 @@ describe("opencode tool-call mapper", () => {
});
});
it("maps completed edit calls with OpenCode camelCase input and success text", () => {
const item = expectMapped(
mapOpencodeToolCall({
toolName: "edit",
callId: "opencode-edit-camel",
status: "completed",
input: {
filePath: "/Users/moboudra/dev/paseo/packages/website/src/data/agent-pages.ts",
oldString: 'metaTitle: "Junie agent Mobile and Desktop App, Open Source"',
newString: 'metaTitle: "Junie Agent Mobile and Desktop App, Open Source"',
},
output: "Edit applied successfully.",
}),
);
expect(item.detail).toEqual({
type: "edit",
filePath: "/Users/moboudra/dev/paseo/packages/website/src/data/agent-pages.ts",
oldString: 'metaTitle: "Junie agent Mobile and Desktop App, Open Source"',
newString: 'metaTitle: "Junie Agent Mobile and Desktop App, Open Source"',
});
});
it("maps skill calls to plain text detail with the loaded skill name", () => {
const item = expectMapped(
mapOpencodeToolCall({