Skip to content

Commit abff598

Browse files
committed
feat: implement automatic temperature reduction on tool failure
- Add temperature tracking properties to Task class - Implement temperature reduction logic with configurable factor (0.5) - Add retry mechanism when tools fail, reducing temperature up to 3 times - Include temperature information in error messages - Add comprehensive test coverage for temperature reduction functionality Fixes #6156
1 parent 1e17b3b commit abff598

File tree

4 files changed

+466
-605
lines changed

4 files changed

+466
-605
lines changed

src/core/assistant-message/presentAssistantMessage.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,9 +307,13 @@ export async function presentAssistantMessage(cline: Task) {
307307
const handleError = async (action: string, error: Error) => {
308308
const errorString = `Error ${action}: ${JSON.stringify(serializeError(error))}`
309309

310+
// Include temperature information in error message
311+
const currentTemp = (cline as any).currentTemperature ?? (cline as any).originalTemperature ?? "default"
312+
const tempInfo = currentTemp !== "default" ? ` (temperature: ${currentTemp})` : ""
313+
310314
await cline.say(
311315
"error",
312-
`Error ${action}:\n${error.message ?? JSON.stringify(serializeError(error), null, 2)}`,
316+
`Error ${action}${tempInfo}:\n${error.message ?? JSON.stringify(serializeError(error), null, 2)}`,
313317
)
314318

315319
pushToolResult(formatResponse.toolError(errorString))

src/core/task/Task.ts

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,13 @@ export class Task extends EventEmitter<ClineEvents> {
213213
didAlreadyUseTool = false
214214
didCompleteReadingStream = false
215215

216+
// Temperature management for tool failure retries
217+
private currentTemperature?: number
218+
private originalTemperature?: number
219+
private temperatureReductionAttempts = 0
220+
private readonly maxTemperatureReductions = 3
221+
private readonly temperatureReductionFactor = 0.5
222+
216223
constructor({
217224
provider,
218225
apiConfiguration,
@@ -1361,7 +1368,7 @@ export class Task extends EventEmitter<ClineEvents> {
13611368
// Yields only if the first chunk is successful, otherwise will
13621369
// allow the user to retry the request (most likely due to rate
13631370
// limit error, which gets thrown on the first chunk).
1364-
const stream = this.attemptApiRequest()
1371+
const stream = this.attemptApiRequest(0, this.currentTemperature)
13651372
let assistantMessage = ""
13661373
let reasoningMessage = ""
13671374
this.isStreaming = true
@@ -1565,8 +1572,29 @@ export class Task extends EventEmitter<ClineEvents> {
15651572
this.consecutiveMistakeCount++
15661573
}
15671574

1568-
const recDidEndLoop = await this.recursivelyMakeClineRequests(this.userMessageContent)
1569-
didEndLoop = recDidEndLoop
1575+
// Check if we should retry with reduced temperature due to tool failure
1576+
if (this.shouldReduceTemperature) {
1577+
const canRetry = await this.retryWithReducedTemperature()
1578+
if (canRetry) {
1579+
// Retry the request with reduced temperature
1580+
const retryUserContent = [
1581+
...this.userMessageContent,
1582+
{
1583+
type: "text" as const,
1584+
text: "I've reduced the temperature to help avoid tool errors. Please try again with the same approach.",
1585+
},
1586+
]
1587+
const recDidEndLoop = await this.recursivelyMakeClineRequests(retryUserContent)
1588+
didEndLoop = recDidEndLoop
1589+
} else {
1590+
// Can't reduce temperature further, proceed normally
1591+
const recDidEndLoop = await this.recursivelyMakeClineRequests(this.userMessageContent)
1592+
didEndLoop = recDidEndLoop
1593+
}
1594+
} else {
1595+
const recDidEndLoop = await this.recursivelyMakeClineRequests(this.userMessageContent)
1596+
didEndLoop = recDidEndLoop
1597+
}
15701598
} else {
15711599
// If there's no assistant_responses, that means we got no text
15721600
// or tool_use content blocks from API which we should assume is
@@ -1669,7 +1697,7 @@ export class Task extends EventEmitter<ClineEvents> {
16691697
})()
16701698
}
16711699

1672-
public async *attemptApiRequest(retryAttempt: number = 0): ApiStream {
1700+
public async *attemptApiRequest(retryAttempt: number = 0, temperatureOverride?: number): ApiStream {
16731701
const state = await this.providerRef.deref()?.getState()
16741702
const {
16751703
apiConfiguration,
@@ -1682,6 +1710,22 @@ export class Task extends EventEmitter<ClineEvents> {
16821710
profileThresholds = {},
16831711
} = state ?? {}
16841712

1713+
// Store original temperature on first attempt
1714+
if (this.originalTemperature === undefined && apiConfiguration) {
1715+
this.originalTemperature = apiConfiguration.modelTemperature ?? undefined
1716+
}
1717+
1718+
// Apply temperature override if provided
1719+
if (temperatureOverride !== undefined && apiConfiguration) {
1720+
this.currentTemperature = temperatureOverride
1721+
// Create a modified API configuration with the new temperature
1722+
const modifiedApiConfig = { ...apiConfiguration, modelTemperature: temperatureOverride }
1723+
// Rebuild the API handler with the modified configuration
1724+
this.api = buildApiHandler(modifiedApiConfig)
1725+
} else {
1726+
this.currentTemperature = this.originalTemperature
1727+
}
1728+
16851729
// Get condensing configuration for automatic triggers
16861730
const customCondensingPrompt = state?.customCondensingPrompt
16871731
const condensingApiConfigId = state?.condensingApiConfigId
@@ -1947,6 +1991,43 @@ export class Task extends EventEmitter<ClineEvents> {
19471991
if (error) {
19481992
this.emit("taskToolFailed", this.taskId, toolName, error)
19491993
}
1994+
1995+
// Trigger temperature reduction for retry
1996+
this.shouldReduceTemperature = true
1997+
}
1998+
1999+
private shouldReduceTemperature = false
2000+
2001+
public async retryWithReducedTemperature(): Promise<boolean> {
2002+
// Check if we've exceeded max temperature reductions
2003+
if (this.temperatureReductionAttempts >= this.maxTemperatureReductions) {
2004+
await this.say(
2005+
"error",
2006+
`Maximum temperature reduction attempts (${this.maxTemperatureReductions}) reached. Cannot reduce temperature further.`,
2007+
)
2008+
return false
2009+
}
2010+
2011+
// Calculate new temperature
2012+
const currentTemp = this.currentTemperature ?? this.originalTemperature ?? 1.0
2013+
const newTemperature = Math.max(0, currentTemp * this.temperatureReductionFactor)
2014+
2015+
// Increment attempt counter
2016+
this.temperatureReductionAttempts++
2017+
2018+
// Log the temperature reduction
2019+
await this.say(
2020+
"text",
2021+
`Reducing temperature from ${currentTemp.toFixed(2)} to ${newTemperature.toFixed(2)} due to tool failure (attempt ${this.temperatureReductionAttempts}/${this.maxTemperatureReductions})`,
2022+
)
2023+
2024+
// Store the new temperature for the next API request
2025+
this.currentTemperature = newTemperature
2026+
2027+
// Reset the flag
2028+
this.shouldReduceTemperature = false
2029+
2030+
return true
19502031
}
19512032

19522033
// Getters

0 commit comments

Comments
 (0)