Update system prompt to tool call more reliably

This commit is contained in:
Saoud Rizwan
2024-09-27 19:47:16 -04:00
parent b1dcff8f64
commit 36ba28d347
3 changed files with 105 additions and 72 deletions

View File

@@ -227,21 +227,24 @@ export class ClaudeDev {
}
let askTs: number
if (partial !== undefined) {
const lastMessage = this.claudeMessages.at(-1)
const lastMessageOfType = findLast(this.claudeMessages, (m) => m.ask === type)
const isUpdatingPreviousPartial =
lastMessage && lastMessage.partial && lastMessage.type === "ask" && lastMessage.ask === type
lastMessageOfType &&
lastMessageOfType.partial &&
lastMessageOfType.type === "ask" &&
lastMessageOfType.ask === type
if (partial) {
if (isUpdatingPreviousPartial) {
// existing partial message, so update it
lastMessage.text = text
lastMessage.partial = partial
lastMessageOfType.text = text
lastMessageOfType.partial = partial
// todo be more efficient about saving and posting only new data or one whole message at a time so ignore partial for saves, and only post parts of partial message instead of whole array in new listener
// await this.saveClaudeMessages()
// await this.providerRef.deref()?.postStateToWebview()
await this.providerRef
.deref()
?.postMessageToWebview({ type: "partialMessage", partialMessage: lastMessage })
throw new Error("Current ask promise was ignored")
?.postMessageToWebview({ type: "partialMessage", partialMessage: lastMessageOfType })
throw new Error("Current ask promise was ignored 1")
} else {
// this is a new partial message, so add it with partial state
// this.askResponse = undefined
@@ -251,7 +254,7 @@ export class ClaudeDev {
// this.lastMessageTs = askTs
await this.addToClaudeMessages({ ts: Date.now(), type: "ask", ask: type, text, partial })
await this.providerRef.deref()?.postStateToWebview()
throw new Error("Current ask promise was ignored")
throw new Error("Current ask promise was ignored 2")
}
} else {
// partial=false means its a complete version of a previously partial message
@@ -262,9 +265,9 @@ export class ClaudeDev {
this.askResponseImages = undefined
askTs = Date.now()
this.lastMessageTs = askTs
lastMessage.ts = askTs
lastMessage.text = text
lastMessage.partial = false
lastMessageOfType.ts = askTs
lastMessageOfType.text = text
lastMessageOfType.partial = false
await this.saveClaudeMessages()
await this.providerRef.deref()?.postStateToWebview()
} else {
@@ -319,20 +322,23 @@ export class ClaudeDev {
}
if (partial !== undefined) {
const lastMessage = this.claudeMessages.at(-1)
const lastMessageOfType = findLast(this.claudeMessages, (m) => m.say === type)
const isUpdatingPreviousPartial =
lastMessage && lastMessage.partial && lastMessage.type === "say" && lastMessage.say === type
lastMessageOfType &&
lastMessageOfType.partial &&
lastMessageOfType.type === "say" &&
lastMessageOfType.say === type
if (partial) {
if (isUpdatingPreviousPartial) {
// existing partial message, so update it
lastMessage.text = text
lastMessage.images = images
lastMessage.partial = partial
lastMessageOfType.text = text
lastMessageOfType.images = images
lastMessageOfType.partial = partial
// await this.saveClaudeMessages()
// await this.providerRef.deref()?.postStateToWebview()
await this.providerRef
.deref()
?.postMessageToWebview({ type: "partialMessage", partialMessage: lastMessage })
?.postMessageToWebview({ type: "partialMessage", partialMessage: lastMessageOfType })
} else {
// this is a new partial message, so add it with partial state
@@ -345,10 +351,10 @@ export class ClaudeDev {
// this is the complete version of a previously partial message, so replace the partial with the complete version
const sayTs = Date.now()
this.lastMessageTs = sayTs
lastMessage.ts = sayTs
lastMessage.text = text
lastMessage.images = images
lastMessage.partial = false
lastMessageOfType.ts = sayTs
lastMessageOfType.text = text
lastMessageOfType.images = images
lastMessageOfType.partial = false
// instead of streaming partialMessage events, we do a save and post like normal to persist to disk
await this.saveClaudeMessages()
@@ -1673,16 +1679,22 @@ ${this.customInstructions.trim()}
}
// If the last API request's total token usage is close to the context window, truncate the conversation history to free up space for the new request
const lastApiReqFinished = findLast(this.claudeMessages, (m) => m.say === "api_req_finished")
if (lastApiReqFinished && lastApiReqFinished.text) {
const lastApiReqStarted = findLast(this.claudeMessages, (m) => m.say === "api_req_started")
if (lastApiReqStarted && lastApiReqStarted.text) {
const {
tokensIn,
tokensOut,
cacheWrites,
cacheReads,
}: { tokensIn?: number; tokensOut?: number; cacheWrites?: number; cacheReads?: number } = JSON.parse(
lastApiReqFinished.text
lastApiReqStarted.text
)
console.log("lastApiReqStarted", lastApiReqStarted.text, {
tokensIn,
tokensOut,
cacheWrites,
cacheReads,
})
const totalTokens = (tokensIn || 0) + (tokensOut || 0) + (cacheWrites || 0) + (cacheReads || 0)
const contextWindow = this.api.getModel().info.contextWindow
const maxAllowedSize = Math.max(contextWindow - 40_000, contextWindow * 0.8)
@@ -2494,9 +2506,6 @@ ${this.customInstructions.trim()}
textContent.content = textContentLines.join("\n")
this.assistantMessageContent = [textContent, ...toolCalls]
// Present the updated content
this.presentAssistantMessage()
}
async recursivelyMakeClaudeRequests(
@@ -2692,23 +2701,31 @@ ${this.customInstructions.trim()}
let totalCost: string | undefined
await this.say(
"api_req_finished",
JSON.stringify({
tokensIn: inputTokens,
tokensOut: outputTokens,
cacheWrites: cacheCreationInputTokens,
cacheReads: cacheReadInputTokens,
cost:
totalCost ||
this.calculateApiCost(
inputTokens,
outputTokens,
cacheCreationInputTokens,
cacheReadInputTokens
),
})
)
// update api_req_started. we can't use api_req_finished anymore since it's a unique case where it could come after a streaming message (ie in the middle of being updated or executed)
// fortunately api_req_finished was always parsed out for the gui 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)
this.claudeMessages[lastApiReqIndex].text = JSON.stringify({
...JSON.parse(this.claudeMessages[lastApiReqIndex].text),
tokensIn: inputTokens,
tokensOut: outputTokens,
cacheWrites: cacheCreationInputTokens,
cacheReads: cacheReadInputTokens,
cost:
totalCost ||
this.calculateApiCost(inputTokens, outputTokens, cacheCreationInputTokens, cacheReadInputTokens),
})
await this.saveClaudeMessages()
await this.providerRef.deref()?.postStateToWebview()
// await this.say(
// "api_req_finished",
// JSON.stringify({
// })
// )
// console.log("apiContentBlocks", apiContentBlocks)
// throw new Error("ClaudeDev fail")
// now add to apiconversationhistory
// need to save assistant responses to file before proceeding to tool use since user can exit at any moment and we wouldn't be able to save the assistant's response
@@ -2725,6 +2742,10 @@ ${this.customInstructions.trim()}
await pWaitFor(() => this.userMessageContentReady)
console.log("attempted to send new request")
// throw new Error("ClaudeDev fail")
const recDidEndLoop = await this.recursivelyMakeClaudeRequests(this.userMessageContent)
didEndLoop = recDidEndLoop
} else {