Skip to content

Commit 60d7246

Browse files
committed
Merge remote-tracking branch 'upstream/main' into roo-to-main
1 parent 65eb730 commit 60d7246

File tree

17 files changed

+556
-110
lines changed

17 files changed

+556
-110
lines changed

apps/web-roo-code/src/app/privacy/page.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default function Privacy() {
4646
<h1 className="text-3xl font-bold tracking-tight sm:text-4xl md:text-5xl">
4747
Costrict Cloud Privacy Policy
4848
</h1>
49-
<p className="text-muted-foreground">Last Updated: August 20, 2025</p>
49+
<p className="text-muted-foreground">Last Updated: September 19, 2025</p>
5050

5151
<p className="lead">
5252
This Privacy Policy explains how Costrict, Inc. (&quot;Costrict,&quot; &quot;we,&quot;
@@ -184,6 +184,13 @@ export default function Privacy() {
184184
<li>
185185
<strong>Send product updates and roadmap communications</strong> (opt‑out available)
186186
</li>
187+
<li>
188+
<strong>Send onboarding, educational, and promotional communications</strong>. We may use
189+
your account information (such as your name and email address) to send you onboarding
190+
messages, product tutorials, feature announcements, newsletters, and other marketing
191+
communications. You can opt out of non‑transactional emails at any time (see “Your Choices”
192+
below).
193+
</li>
187194
</ul>
188195

189196
<h2 className="mt-12 text-2xl font-bold">3. Where Your Data Goes (And Doesn&apos;t)</h2>
@@ -277,6 +284,12 @@ export default function Privacy() {
277284
<strong>Delete your Cloud account</strong> at any time from{" "}
278285
<strong>Security Settings</strong> inside Costrict Cloud.
279286
</li>
287+
<li>
288+
<strong>Marketing communications:</strong> You can unsubscribe from marketing and
289+
promotional emails by clicking the unsubscribe link in those emails. Transactional or
290+
service‑related emails (such as password resets, billing notices, or security alerts) will
291+
continue even if you opt out.
292+
</li>
280293
</ul>
281294

282295
<h2 className="mt-12 text-2xl font-bold">6. Security Practices</h2>

packages/types/src/providers/sambanova.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ export type SambaNovaModelId =
66
| "Meta-Llama-3.3-70B-Instruct"
77
| "DeepSeek-R1"
88
| "DeepSeek-V3-0324"
9+
| "DeepSeek-V3.1"
910
| "DeepSeek-R1-Distill-Llama-70B"
1011
| "Llama-4-Maverick-17B-128E-Instruct"
1112
| "Llama-3.3-Swallow-70B-Instruct-v0.4"
1213
| "Qwen3-32B"
14+
| "gpt-oss-120b"
1315

1416
export const sambaNovaDefaultModelId: SambaNovaModelId = "Meta-Llama-3.3-70B-Instruct"
1517

@@ -51,6 +53,15 @@ export const sambaNovaModels = {
5153
outputPrice: 4.5,
5254
description: "DeepSeek V3 model with 32K context window.",
5355
},
56+
"DeepSeek-V3.1": {
57+
maxTokens: 8192,
58+
contextWindow: 32768,
59+
supportsImages: false,
60+
supportsPromptCache: false,
61+
inputPrice: 3.0,
62+
outputPrice: 4.5,
63+
description: "DeepSeek V3.1 model with 32K context window.",
64+
},
5465
"DeepSeek-R1-Distill-Llama-70B": {
5566
maxTokens: 8192,
5667
contextWindow: 131072,
@@ -87,4 +98,13 @@ export const sambaNovaModels = {
8798
outputPrice: 0.8,
8899
description: "Alibaba Qwen 3 32B model with 8K context window.",
89100
},
101+
"gpt-oss-120b": {
102+
maxTokens: 8192,
103+
contextWindow: 131072,
104+
supportsImages: false,
105+
supportsPromptCache: false,
106+
inputPrice: 0.22,
107+
outputPrice: 0.59,
108+
description: "OpenAI gpt oss 120b model with 128k context window.",
109+
},
90110
} as const satisfies Record<string, ModelInfo>

src/api/providers/gemini.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,7 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
286286
outputTokens: number
287287
cacheReadTokens?: number
288288
}) {
289-
if (!info.inputPrice || !info.outputPrice || !info.cacheReadsPrice) {
290-
return undefined
291-
}
292-
289+
// For models with tiered pricing, prices might only be defined in tiers
293290
let inputPrice = info.inputPrice
294291
let outputPrice = info.outputPrice
295292
let cacheReadsPrice = info.cacheReadsPrice
@@ -306,6 +303,16 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
306303
}
307304
}
308305

306+
// Check if we have the required prices after considering tiers
307+
if (!inputPrice || !outputPrice) {
308+
return undefined
309+
}
310+
311+
// cacheReadsPrice is optional - if not defined, treat as 0
312+
if (!cacheReadsPrice) {
313+
cacheReadsPrice = 0
314+
}
315+
309316
// Subtract the cached input tokens from the total input tokens.
310317
const uncachedInputTokens = inputTokens - cacheReadTokens
311318

src/core/task/Task.ts

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
218218

219219
didFinishAbortingStream = false
220220
abandoned = false
221+
abortReason?: ClineApiReqCancelReason
221222
isInitialized = false
222223
isPaused: boolean = false
223224
pausedModeSlug: string = defaultModeSlug
@@ -1282,6 +1283,16 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
12821283
modifiedClineMessages.splice(lastRelevantMessageIndex + 1)
12831284
}
12841285

1286+
// Remove any trailing reasoning-only UI messages that were not part of the persisted API conversation
1287+
while (modifiedClineMessages.length > 0) {
1288+
const last = modifiedClineMessages[modifiedClineMessages.length - 1]
1289+
if (last.type === "say" && last.say === "reasoning") {
1290+
modifiedClineMessages.pop()
1291+
} else {
1292+
break
1293+
}
1294+
}
1295+
12851296
// Since we don't use `api_req_finished` anymore, we need to check if the
12861297
// last `api_req_started` has a cost value, if it doesn't and no
12871298
// cancellation reason to present, then we remove it since it indicates
@@ -1904,28 +1915,10 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
19041915
lastMessage.partial = false
19051916
// instead of streaming partialMessage events, we do a save and post like normal to persist to disk
19061917
console.log("updating partial message", lastMessage)
1907-
// await this.saveClineMessages()
19081918
}
19091919

1910-
// Let assistant know their response was interrupted for when task is resumed
1911-
await this.addToApiConversationHistory({
1912-
role: "assistant",
1913-
content: [
1914-
{
1915-
type: "text",
1916-
text:
1917-
assistantMessage +
1918-
`\n\n[${
1919-
cancelReason === "streaming_failed"
1920-
? "Response interrupted by API Error"
1921-
: "Response interrupted by user"
1922-
}]`,
1923-
},
1924-
],
1925-
})
1926-
19271920
// Update `api_req_started` to have cancelled and cost, so that
1928-
// we can display the cost of the partial stream.
1921+
// we can display the cost of the partial stream and the cancellation reason
19291922
updateApiReqMsg(cancelReason, streamingFailedMessage)
19301923
await this.saveClineMessages()
19311924

@@ -2209,24 +2202,23 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
22092202
// may have executed), so we just resort to replicating a
22102203
// cancel task.
22112204

2212-
// Check if this was a user-initiated cancellation BEFORE calling abortTask
2213-
// If this.abort is already true, it means the user clicked cancel, so we should
2214-
// treat this as "user_cancelled" rather than "streaming_failed"
2215-
const cancelReason = this.abort ? "user_cancelled" : "streaming_failed"
2205+
// Determine cancellation reason BEFORE aborting to ensure correct persistence
2206+
const cancelReason: ClineApiReqCancelReason = this.abort ? "user_cancelled" : "streaming_failed"
22162207

22172208
const streamingFailedMessage = this.abort
22182209
? undefined
22192210
: (error.message ?? JSON.stringify(serializeError(error), null, 2))
22202211

2221-
// Now call abortTask after determining the cancel reason.
2222-
await this.abortTask()
2212+
// Persist interruption details first to both UI and API histories
22232213
await abortStream(cancelReason, streamingFailedMessage)
22242214

2225-
const history = await provider?.getTaskWithId(this.taskId)
2215+
// Record reason for provider to decide rehydration path
2216+
this.abortReason = cancelReason
22262217

2227-
if (history) {
2228-
await provider?.createTaskWithHistoryItem(history.historyItem)
2229-
}
2218+
// Now abort (emits TaskAborted which provider listens to)
2219+
await this.abortTask()
2220+
2221+
// Do not rehydrate here; provider owns rehydration to avoid duplication races
22302222
}
22312223
} finally {
22322224
this.isStreaming = false

0 commit comments

Comments
 (0)