diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 7ed317da10..05b146a32c 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -1859,8 +1859,19 @@ export class Task extends EventEmitter implements TaskLike { // message. const lastApiReqIndex = findLastIndex(this.clineMessages, (m) => m.say === "api_req_started") + // Store the request content as a formatted string + const requestContent = JSON.stringify( + { + role: "user", + content: finalUserContent, + }, + null, + 2, + ) + this.clineMessages[lastApiReqIndex].text = JSON.stringify({ apiProtocol, + request: requestContent, } satisfies ClineApiReqInfo) await this.saveClineMessages() @@ -1880,6 +1891,9 @@ export class Task extends EventEmitter implements TaskLike { // anyways, so it remains solely for legacy purposes to keep track // of prices in tasks from history (it's worth removing a few months // from now). + // Store accumulated response text for the API request + let accumulatedResponse = "" + const updateApiReqMsg = (cancelReason?: ClineApiReqCancelReason, streamingFailedMessage?: string) => { if (lastApiReqIndex < 0 || !this.clineMessages[lastApiReqIndex]) { return @@ -1917,6 +1931,7 @@ export class Task extends EventEmitter implements TaskLike { cost: totalCost ?? costResult.totalCost, cancelReason, streamingFailedMessage, + response: accumulatedResponse || undefined, } satisfies ClineApiReqInfo) } @@ -2014,6 +2029,7 @@ export class Task extends EventEmitter implements TaskLike { break case "text": { assistantMessage += chunk.text + accumulatedResponse += chunk.text // Parse raw assistant message chunk into content blocks. const prevLength = this.assistantMessageContent.length diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index c3926d5073..9ffd1e2f7c 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -464,6 +464,7 @@ export interface ClineAskUseMcpServer { export interface ClineApiReqInfo { request?: string + response?: string tokensIn?: number tokensOut?: number cacheWrites?: number diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 4d446daeaa..aa806c5c45 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -170,6 +170,7 @@ export const ChatRowContent = ({ const [editedContent, setEditedContent] = useState("") const [editMode, setEditMode] = useState(mode || "code") const [editImages, setEditImages] = useState([]) + const [showRequestResponse, setShowRequestResponse] = useState(false) // Handle message events for image selection during edit mode useEffect(() => { @@ -1070,12 +1071,15 @@ export const ChatRowContent = ({ const isApiRequestInProgress = apiReqCancelReason === undefined && apiRequestFailedMessage === undefined && cost === undefined + // Parse the API request info to get request and response data + const apiReqInfo = safeJsonParse(message.text) + return ( <>
{ + if (apiReqInfo?.request || apiReqInfo?.response) { + setShowRequestResponse(!showRequestResponse) + } }}>
{icon} {title} + {(apiReqInfo?.request || apiReqInfo?.response) && ( + + )}
+ {showRequestResponse && (apiReqInfo?.request || apiReqInfo?.response) && ( +
+ {apiReqInfo?.request && ( +
+
+ Request to LLM: +
+ {}} + /> +
+ )} + {apiReqInfo?.response && ( +
+
+ Response from LLM: +
+ {}} + /> +
+ )} +
+ )} {(((cost === null || cost === undefined) && apiRequestFailedMessage) || apiReqStreamingFailedMessage) && (