Skip to content

Commit d5fd2bb

Browse files
committed
merge: resolve conflicts after upstream merge
2 parents 58bc329 + f12c342 commit d5fd2bb

34 files changed

+2418
-175
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ roo-cline-*.vsix
1111

1212
# Local prompts and rules
1313
/local-prompts
14+
15+
# Test environment
16+
.test_env

.vscode-test.mjs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
import { defineConfig } from "@vscode/test-cli"
1+
import { defineConfig } from '@vscode/test-cli';
22

33
export default defineConfig({
4-
files: "out/test/**/*.test.js",
5-
})
4+
files: 'src/test/extension.test.ts',
5+
workspaceFolder: '.',
6+
mocha: {
7+
timeout: 60000,
8+
ui: 'tdd'
9+
},
10+
launchArgs: [
11+
'--enable-proposed-api=RooVeterinaryInc.roo-cline',
12+
'--disable-extensions'
13+
]
14+
});

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Roo Cline Changelog
22

3+
## [2.2.45]
4+
5+
- Save different API configurations to quickly switch between providers and settings (thanks @samhvw8!)
6+
7+
## [2.2.44]
8+
9+
- Automatically retry failed API requests with a configurable delay (thanks @RaySinner!)
10+
11+
## [2.2.43]
12+
13+
- Allow deleting single messages or all subsequent messages
14+
315
## [2.2.42]
416

517
- Add a Git section to the context mentions

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ A fork of Cline, an autonomous coding agent, with some additional experimental f
77
- Drag and drop images into chats
88
- Delete messages from chats
99
- @-mention Git commits to include their context in the chat
10+
- Save different API configurations to quickly switch between providers and settings
1011
- "Enhance prompt" button (OpenRouter models only for now)
1112
- Sound effects for feedback
1213
- Option to use browsers of different sizes and adjust screenshot quality
@@ -23,6 +24,7 @@ A fork of Cline, an autonomous coding agent, with some additional experimental f
2324
- Per-tool MCP auto-approval
2425
- Enable/disable individual MCP servers
2526
- Enable/disable the MCP feature overall
27+
- Automatically retry failed API requests with a configurable delay
2628
- Configurable delay after auto-writes to allow diagnostics to detect potential problems
2729
- Control the number of terminal output lines to pass to the model when executing commands
2830
- Runs alongside the original Cline

jest.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ module.exports = {
3232
modulePathIgnorePatterns: [
3333
'.vscode-test'
3434
],
35+
reporters: [
36+
["jest-simple-dot-reporter", {}]
37+
],
3538
setupFiles: [],
3639
globals: {
3740
'ts-jest': {

package-lock.json

Lines changed: 23 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "Roo Cline",
44
"description": "A fork of Cline, an autonomous coding agent, with some added experimental configuration and automation features.",
55
"publisher": "RooVeterinaryInc",
6-
"version": "2.2.42",
6+
"version": "2.2.45",
77
"icon": "assets/icons/rocket.png",
88
"galleryBanner": {
99
"color": "#617A91",
@@ -176,6 +176,7 @@
176176
"start:webview": "cd webview-ui && npm run start",
177177
"test": "jest && npm run test:webview",
178178
"test:webview": "cd webview-ui && npm run test",
179+
"test:extension": "vscode-test",
179180
"prepare": "husky",
180181
"publish:marketplace": "vsce publish",
181182
"publish": "npm run build && changeset publish && npm install --package-lock-only",
@@ -198,20 +199,22 @@
198199
"@typescript-eslint/parser": "^7.11.0",
199200
"@vscode/test-cli": "^0.0.9",
200201
"@vscode/test-electron": "^2.4.0",
202+
"dotenv": "^16.4.7",
201203
"esbuild": "^0.24.0",
202204
"eslint": "^8.57.0",
203205
"husky": "^9.1.7",
204206
"jest": "^29.7.0",
207+
"jest-simple-dot-reporter": "^1.0.5",
205208
"lint-staged": "^15.2.11",
206209
"npm-run-all": "^4.1.5",
207210
"ts-jest": "^29.2.5",
208211
"typescript": "^5.4.5"
209212
},
210213
"dependencies": {
211214
"@anthropic-ai/bedrock-sdk": "^0.10.2",
212-
"@aws-sdk/client-bedrock-runtime": "^3.706.0",
213215
"@anthropic-ai/sdk": "^0.26.0",
214216
"@anthropic-ai/vertex-sdk": "^0.4.1",
217+
"@aws-sdk/client-bedrock-runtime": "^3.706.0",
215218
"@google/generative-ai": "^0.18.0",
216219
"@modelcontextprotocol/sdk": "^1.0.1",
217220
"@types/clone-deep": "^4.0.4",

src/api/providers/openai-native.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export class OpenAiNativeHandler implements ApiHandler {
2424

2525
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
2626
switch (this.getModel().id) {
27+
case "o1":
2728
case "o1-preview":
2829
case "o1-mini": {
2930
// o1 doesnt support streaming, non-1 temp, or system prompt

src/core/Cline.ts

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ export class Cline {
766766
async *attemptApiRequest(previousApiReqIndex: number): ApiStream {
767767
let mcpHub: McpHub | undefined
768768

769-
const { mcpEnabled } = await this.providerRef.deref()?.getState() ?? {}
769+
const { mcpEnabled, alwaysApproveResubmit, requestDelaySeconds } = await this.providerRef.deref()?.getState() ?? {}
770770

771771
if (mcpEnabled ?? true) {
772772
mcpHub = this.providerRef.deref()?.mcpHub
@@ -799,8 +799,30 @@ export class Cline {
799799
}
800800
}
801801

802-
// Convert to Anthropic.MessageParam by spreading only the API-required properties
803-
const cleanConversationHistory = this.apiConversationHistory.map(({ role, content }) => ({ role, content }))
802+
// Clean conversation history by:
803+
// 1. Converting to Anthropic.MessageParam by spreading only the API-required properties
804+
// 2. Converting image blocks to text descriptions if model doesn't support images
805+
const cleanConversationHistory = this.apiConversationHistory.map(({ role, content }) => {
806+
// Handle array content (could contain image blocks)
807+
if (Array.isArray(content)) {
808+
if (!this.api.getModel().info.supportsImages) {
809+
// Convert image blocks to text descriptions
810+
content = content.map(block => {
811+
if (block.type === 'image') {
812+
// Convert image blocks to text descriptions
813+
// Note: We can't access the actual image content/url due to API limitations,
814+
// but we can indicate that an image was present in the conversation
815+
return {
816+
type: 'text',
817+
text: '[Referenced image in conversation]'
818+
};
819+
}
820+
return block;
821+
});
822+
}
823+
}
824+
return { role, content }
825+
})
804826
const stream = this.api.createMessage(systemPrompt, cleanConversationHistory)
805827
const iterator = stream[Symbol.asyncIterator]()
806828

@@ -810,18 +832,33 @@ export class Cline {
810832
yield firstChunk.value
811833
} catch (error) {
812834
// note that this api_req_failed ask is unique in that we only present this option if the api hasn't streamed any content yet (ie it fails on the first chunk due), as it would allow them to hit a retry button. However if the api failed mid-stream, it could be in any arbitrary state where some tools may have executed, so that error is handled differently and requires cancelling the task entirely.
813-
const { response } = await this.ask(
814-
"api_req_failed",
815-
error.message ?? JSON.stringify(serializeError(error), null, 2),
816-
)
817-
if (response !== "yesButtonClicked") {
818-
// this will never happen since if noButtonClicked, we will clear current task, aborting this instance
819-
throw new Error("API request failed")
835+
if (alwaysApproveResubmit) {
836+
const requestDelay = requestDelaySeconds || 5
837+
// Automatically retry with delay
838+
await this.say(
839+
"error",
840+
`${error.message ?? "Unknown error"} ↺ Retrying in ${requestDelay} seconds...`,
841+
)
842+
await this.say("api_req_retry_delayed")
843+
await delay(requestDelay * 1000)
844+
await this.say("api_req_retried")
845+
// delegate generator output from the recursive call
846+
yield* this.attemptApiRequest(previousApiReqIndex)
847+
return
848+
} else {
849+
const { response } = await this.ask(
850+
"api_req_failed",
851+
error.message ?? JSON.stringify(serializeError(error), null, 2),
852+
)
853+
if (response !== "yesButtonClicked") {
854+
// this will never happen since if noButtonClicked, we will clear current task, aborting this instance
855+
throw new Error("API request failed")
856+
}
857+
await this.say("api_req_retried")
858+
// delegate generator output from the recursive call
859+
yield* this.attemptApiRequest(previousApiReqIndex)
860+
return
820861
}
821-
await this.say("api_req_retried")
822-
// delegate generator output from the recursive call
823-
yield* this.attemptApiRequest(previousApiReqIndex)
824-
return
825862
}
826863

827864
// no error, so we can continue to yield all remaining chunks

0 commit comments

Comments
 (0)