mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
feat: show LLM request and response data in API request items
- Added request and response fields to ClineApiReqInfo interface - Store request data when initiating API calls in Task.ts - Accumulate and store response data during streaming in Task.ts - Updated ChatRow component to display request/response in expandable UI - Added click handler to API request items to toggle visibility - Display request as formatted JSON and response as markdown Fixes #9119
This commit is contained in:
parent
e98f4b9057
commit
f77f4b4ac7
3 changed files with 64 additions and 2 deletions
|
|
@ -1859,8 +1859,19 @@ export class Task extends EventEmitter<TaskEvents> 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<TaskEvents> 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<TaskEvents> implements TaskLike {
|
|||
cost: totalCost ?? costResult.totalCost,
|
||||
cancelReason,
|
||||
streamingFailedMessage,
|
||||
response: accumulatedResponse || undefined,
|
||||
} satisfies ClineApiReqInfo)
|
||||
}
|
||||
|
||||
|
|
@ -2014,6 +2029,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
break
|
||||
case "text": {
|
||||
assistantMessage += chunk.text
|
||||
accumulatedResponse += chunk.text
|
||||
|
||||
// Parse raw assistant message chunk into content blocks.
|
||||
const prevLength = this.assistantMessageContent.length
|
||||
|
|
|
|||
|
|
@ -464,6 +464,7 @@ export interface ClineAskUseMcpServer {
|
|||
|
||||
export interface ClineApiReqInfo {
|
||||
request?: string
|
||||
response?: string
|
||||
tokensIn?: number
|
||||
tokensOut?: number
|
||||
cacheWrites?: number
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ export const ChatRowContent = ({
|
|||
const [editedContent, setEditedContent] = useState("")
|
||||
const [editMode, setEditMode] = useState<Mode>(mode || "code")
|
||||
const [editImages, setEditImages] = useState<string[]>([])
|
||||
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<ClineApiReqInfo>(message.text)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`group text-sm transition-opacity ${
|
||||
isApiRequestInProgress ? "opacity-100" : "opacity-40 hover:opacity-100"
|
||||
}`}
|
||||
apiReqInfo?.request || apiReqInfo?.response ? "cursor-pointer" : ""
|
||||
} ${isApiRequestInProgress ? "opacity-100" : "opacity-40 hover:opacity-100"}`}
|
||||
style={{
|
||||
...headerStyle,
|
||||
marginBottom:
|
||||
|
|
@ -1084,10 +1088,21 @@ export const ChatRowContent = ({
|
|||
? 10
|
||||
: 0,
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
onClick={() => {
|
||||
if (apiReqInfo?.request || apiReqInfo?.response) {
|
||||
setShowRequestResponse(!showRequestResponse)
|
||||
}
|
||||
}}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "10px", flexGrow: 1 }}>
|
||||
{icon}
|
||||
{title}
|
||||
{(apiReqInfo?.request || apiReqInfo?.response) && (
|
||||
<span
|
||||
className={`codicon codicon-chevron-${showRequestResponse ? "up" : "down"}`}
|
||||
style={{ fontSize: "12px", opacity: 0.7 }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="text-xs text-vscode-dropdown-foreground border-vscode-dropdown-border/50 border px-1.5 py-0.5 rounded-lg"
|
||||
|
|
@ -1095,6 +1110,36 @@ export const ChatRowContent = ({
|
|||
${Number(cost || 0)?.toFixed(4)}
|
||||
</div>
|
||||
</div>
|
||||
{showRequestResponse && (apiReqInfo?.request || apiReqInfo?.response) && (
|
||||
<div className="ml-6 mt-2 mb-4">
|
||||
{apiReqInfo?.request && (
|
||||
<div className="mb-3">
|
||||
<div className="text-xs font-semibold mb-1 text-vscode-descriptionForeground">
|
||||
Request to LLM:
|
||||
</div>
|
||||
<CodeAccordian
|
||||
code={apiReqInfo.request}
|
||||
language="json"
|
||||
isExpanded={true}
|
||||
onToggleExpand={() => {}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{apiReqInfo?.response && (
|
||||
<div>
|
||||
<div className="text-xs font-semibold mb-1 text-vscode-descriptionForeground">
|
||||
Response from LLM:
|
||||
</div>
|
||||
<CodeAccordian
|
||||
code={apiReqInfo.response}
|
||||
language="markdown"
|
||||
isExpanded={true}
|
||||
onToggleExpand={() => {}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{(((cost === null || cost === undefined) && apiRequestFailedMessage) ||
|
||||
apiReqStreamingFailedMessage) && (
|
||||
<ErrorRow
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue