Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions src/core/tools/__tests__/generateImageTool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,60 @@ describe("generateImageTool", () => {
expect(mockGenerateImage).toHaveBeenCalled()
expect(mockPushToolResult).toHaveBeenCalled()
})

it("should add cache-busting parameter to image URI", async () => {
const completeBlock: ToolUse = {
type: "tool_use",
name: "generate_image",
params: {
prompt: "Generate a test image",
path: "test-image.png",
},
partial: false,
}

// Mock convertToWebviewUri to return a test URI
const mockWebviewUri = "https://file+.vscode-resource.vscode-cdn.net/test/workspace/test-image.png"
mockCline.providerRef.deref().convertToWebviewUri = vi.fn().mockReturnValue(mockWebviewUri)

// Mock the OpenRouterHandler generateImage method
const mockGenerateImage = vi.fn().mockResolvedValue({
success: true,
imageData: "data:image/png;base64,fakebase64data",
})

vi.mocked(OpenRouterHandler).mockImplementation(
() =>
({
generateImage: mockGenerateImage,
}) as any,
)

await generateImageTool(
mockCline as Task,
completeBlock,
mockAskApproval,
mockHandleError,
mockPushToolResult,
mockRemoveClosingTag,
)

// Check that cline.say was called with image data containing cache-busting parameter
expect(mockCline.say).toHaveBeenCalledWith("image", expect.stringMatching(/"imageUri":"[^"]+\?t=\d+"/))

// Verify the imageUri contains the cache-busting parameter
const sayCall = mockCline.say.mock.calls.find((call: any[]) => call[0] === "image")
if (sayCall) {
const imageData = JSON.parse(sayCall[1])
expect(imageData.imageUri).toMatch(/\?t=\d+$/)
// Handle both Unix and Windows path separators
const expectedPath =
process.platform === "win32"
? "\\test\\workspace\\test-image.png"
: "/test/workspace/test-image.png"
expect(imageData.imagePath).toBe(expectedPath)
}
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great test coverage! Consider adding an additional test case to verify the behavior when the URI already contains query parameters (testing the includes("?") branch). This would ensure both code paths are covered:

it("should append cache-busting parameter to URI with existing query params", async () => {
  const mockWebviewUri = "https://file+.vscode-resource.vscode-cdn.net/test/workspace/test-image.png?existing=param"
  // ... rest of test
  expect(imageData.imageUri).toMatch(/\?existing=param&t=\d+$/)
})

})

describe("missing parameters", () => {
Expand Down
6 changes: 5 additions & 1 deletion src/core/tools/generateImageTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,11 @@ export async function generateImageTool(
const fullImagePath = path.join(cline.cwd, finalPath)

// Convert to webview URI if provider is available
const imageUri = provider?.convertToWebviewUri?.(fullImagePath) ?? vscode.Uri.file(fullImagePath).toString()
let imageUri = provider?.convertToWebviewUri?.(fullImagePath) ?? vscode.Uri.file(fullImagePath).toString()

// Add cache-busting parameter to prevent browser caching issues
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be helpful to add a brief comment explaining why cache-busting is needed? This could help future maintainers understand the context, something like:

Suggested change
// Add cache-busting parameter to prevent browser caching issues
// Add cache-busting parameter to prevent browser caching issues
// This ensures the webview always displays the newly generated image instead of a cached version
const cacheBuster = Date.now()

const cacheBuster = Date.now()
imageUri = imageUri.includes("?") ? `${imageUri}&t=${cacheBuster}` : `${imageUri}?t=${cacheBuster}`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using a more descriptive parameter name for clarity. Instead of t, perhaps cache or cb (cache-buster) would make the purpose more obvious?

Suggested change
imageUri = imageUri.includes("?") ? `${imageUri}&t=${cacheBuster}` : `${imageUri}?t=${cacheBuster}`
// Add cache-busting parameter to prevent browser caching issues
const cacheBuster = Date.now()
imageUri = imageUri.includes("?") ? `${imageUri}&cache=${cacheBuster}` : `${imageUri}?cache=${cacheBuster}`


// Send the image with the webview URI
await cline.say("image", JSON.stringify({ imageUri, imagePath: fullImagePath }))
Expand Down
Loading