mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Add advisor model to anthropic
This commit is contained in:
parent
43bf383784
commit
7aeab15ecf
4 changed files with 85 additions and 29 deletions
|
|
@ -1,6 +1,14 @@
|
|||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { Stream as AnthropicStream } from "@anthropic-ai/sdk/streaming"
|
||||
import { anthropicDefaultModelId, AnthropicModelId, anthropicModels, ApiHandlerOptions, ModelInfo } from "../../shared/api"
|
||||
import {
|
||||
anthropicDefaultAdvisorModelId,
|
||||
anthropicDefaultModelId,
|
||||
AnthropicModelId,
|
||||
anthropicModels,
|
||||
ApiHandlerOptions,
|
||||
ModelInfo,
|
||||
ModelType,
|
||||
} from "../../shared/api"
|
||||
import { ApiHandler } from "../index"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
|
|
@ -16,9 +24,10 @@ export class AnthropicHandler implements ApiHandler {
|
|||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[], modelType: ModelType): ApiStream {
|
||||
const model = modelType === "advisor" ? this.getAdvisorModel() : this.getModel()
|
||||
let stream: AnthropicStream<Anthropic.Beta.PromptCaching.Messages.RawPromptCachingBetaMessageStreamEvent>
|
||||
const modelId = this.getModel().id
|
||||
const modelId = model.id
|
||||
switch (modelId) {
|
||||
// 'latest' alias does not support cache_control
|
||||
case "claude-3-5-sonnet-20241022":
|
||||
|
|
@ -37,7 +46,7 @@ export class AnthropicHandler implements ApiHandler {
|
|||
stream = await this.client.beta.promptCaching.messages.create(
|
||||
{
|
||||
model: modelId,
|
||||
max_tokens: this.getModel().info.maxTokens || 8192,
|
||||
max_tokens: model.info.maxTokens || 8192,
|
||||
temperature: 0,
|
||||
system: [
|
||||
{
|
||||
|
|
@ -104,7 +113,7 @@ export class AnthropicHandler implements ApiHandler {
|
|||
default: {
|
||||
stream = (await this.client.messages.create({
|
||||
model: modelId,
|
||||
max_tokens: this.getModel().info.maxTokens || 8192,
|
||||
max_tokens: model.info.maxTokens || 8192,
|
||||
temperature: 0,
|
||||
system: [{ text: systemPrompt, type: "text" }],
|
||||
messages,
|
||||
|
|
@ -185,4 +194,16 @@ export class AnthropicHandler implements ApiHandler {
|
|||
info: anthropicModels[anthropicDefaultModelId],
|
||||
}
|
||||
}
|
||||
|
||||
getAdvisorModel(): { id: string; info: ModelInfo } {
|
||||
const modelId = this.options.anthropicAdvisorModelId
|
||||
if (modelId && modelId in anthropicModels) {
|
||||
const id = modelId as AnthropicModelId
|
||||
return { id, info: anthropicModels[id] }
|
||||
}
|
||||
return {
|
||||
id: anthropicDefaultAdvisorModelId,
|
||||
info: anthropicModels[anthropicDefaultAdvisorModelId],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ type SecretKey =
|
|||
type GlobalStateKey =
|
||||
| "apiProvider"
|
||||
| "apiModelId"
|
||||
| "anthropicAdvisorModelId"
|
||||
| "awsRegion"
|
||||
| "awsUseCrossRegionInference"
|
||||
| "vertexProjectId"
|
||||
|
|
@ -382,6 +383,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
const {
|
||||
apiProvider,
|
||||
apiModelId,
|
||||
anthropicAdvisorModelId,
|
||||
apiKey,
|
||||
openRouterApiKey,
|
||||
awsAccessKey,
|
||||
|
|
@ -411,6 +413,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
} = message.apiConfiguration
|
||||
await this.updateGlobalState("apiProvider", apiProvider)
|
||||
await this.updateGlobalState("apiModelId", apiModelId)
|
||||
await this.updateGlobalState("anthropicAdvisorModelId", anthropicAdvisorModelId)
|
||||
await this.storeSecret("apiKey", apiKey)
|
||||
await this.storeSecret("openRouterApiKey", openRouterApiKey)
|
||||
await this.storeSecret("awsAccessKey", awsAccessKey)
|
||||
|
|
@ -1019,6 +1022,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
const [
|
||||
storedApiProvider,
|
||||
apiModelId,
|
||||
anthropicAdvisorModelId,
|
||||
apiKey,
|
||||
openRouterApiKey,
|
||||
awsAccessKey,
|
||||
|
|
@ -1053,6 +1057,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
] = await Promise.all([
|
||||
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
|
||||
this.getGlobalState("apiModelId") as Promise<string | undefined>,
|
||||
this.getGlobalState("anthropicAdvisorModelId") as Promise<string | undefined>,
|
||||
this.getSecret("apiKey") as Promise<string | undefined>,
|
||||
this.getSecret("openRouterApiKey") as Promise<string | undefined>,
|
||||
this.getSecret("awsAccessKey") as Promise<string | undefined>,
|
||||
|
|
@ -1104,6 +1109,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
apiConfiguration: {
|
||||
apiProvider,
|
||||
apiModelId,
|
||||
anthropicAdvisorModelId,
|
||||
apiKey,
|
||||
openRouterApiKey,
|
||||
awsAccessKey,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export type ApiProvider =
|
|||
export interface ApiHandlerOptions {
|
||||
apiModelId?: string
|
||||
apiKey?: string // anthropic
|
||||
anthropicAdvisorModelId?: string
|
||||
anthropicBaseUrl?: string
|
||||
openRouterApiKey?: string
|
||||
openRouterModelId?: string
|
||||
|
|
@ -60,10 +61,13 @@ export interface ModelInfo {
|
|||
description?: string
|
||||
}
|
||||
|
||||
export type ModelType = "base" | "advisor"
|
||||
|
||||
// Anthropic
|
||||
// https://docs.anthropic.com/en/docs/about-claude/models // prices updated 2025-01-02
|
||||
export type AnthropicModelId = keyof typeof anthropicModels
|
||||
export const anthropicDefaultModelId: AnthropicModelId = "claude-3-5-sonnet-20241022"
|
||||
export const anthropicDefaultAdvisorModelId: AnthropicModelId = "claude-3-opus-20240229"
|
||||
export const anthropicModels = {
|
||||
"claude-3-5-sonnet-20241022": {
|
||||
maxTokens: 8192,
|
||||
|
|
@ -192,7 +196,6 @@ export const openRouterDefaultAdvisorModelInfo: ModelInfo = {
|
|||
description:
|
||||
"The latest and strongest model family from OpenAI, o1 is designed to spend more time thinking before responding.\n\nThe o1 models are optimized for math, science, programming, and other STEM-related tasks. They consistently exhibit PhD-level accuracy on benchmarks in physics, chemistry, and biology. Learn more in the [launch announcement](https://openai.com/o1).\n\nNote: This model is currently experimental and not suitable for production use-cases, and may be heavily rate-limited.",
|
||||
}
|
||||
export type ModelType = "base" | "advisor"
|
||||
|
||||
// Vertex AI
|
||||
// https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import {
|
|||
ApiConfiguration,
|
||||
ApiProvider,
|
||||
ModelInfo,
|
||||
ModelType,
|
||||
anthropicDefaultAdvisorModelId,
|
||||
anthropicDefaultModelId,
|
||||
anthropicModels,
|
||||
azureOpenAiDefaultApiVersion,
|
||||
|
|
@ -39,6 +41,7 @@ import { useExtensionState } from "../../context/ExtensionStateContext"
|
|||
import { vscode } from "../../utils/vscode"
|
||||
import VSCodeButtonLink from "../common/VSCodeButtonLink"
|
||||
import OpenRouterModelPicker, { ModelDescriptionMarkdown, OPENROUTER_MODEL_PICKER_Z_INDEX } from "./OpenRouterModelPicker"
|
||||
import styled from "styled-components"
|
||||
|
||||
interface ApiOptionsProps {
|
||||
showModelOptions: boolean
|
||||
|
|
@ -52,6 +55,21 @@ const TabPanel = ({ children, isSelected }: { children: React.ReactNode; isSelec
|
|||
return <div style={{ marginTop: 10 }}>{children}</div>
|
||||
}
|
||||
|
||||
const StyledTabButton = styled.button<{ isSelected: boolean }>`
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
color: ${(props) => (props.isSelected ? "var(--vscode-tab-activeForeground)" : "var(--vscode-tab-inactiveForeground)")};
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid ${(props) => (props.isSelected ? "var(--vscode-foreground)" : "transparent")};
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover {
|
||||
color: var(--vscode-tab-activeForeground);
|
||||
}
|
||||
`
|
||||
|
||||
const TabButton = ({
|
||||
isSelected,
|
||||
onClick,
|
||||
|
|
@ -62,20 +80,9 @@ const TabButton = ({
|
|||
children: React.ReactNode
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
style={{
|
||||
background: "var(--vscode-tab-inactiveBackground)",
|
||||
border: "none",
|
||||
padding: "8px 16px",
|
||||
color: isSelected ? "var(--vscode-tab-activeForeground)" : "var(--vscode-tab-inactiveForeground)",
|
||||
cursor: "pointer",
|
||||
borderBottom: `2px solid ${isSelected ? "var(--vscode-foreground)" : "transparent"}`,
|
||||
fontSize: "12px",
|
||||
fontWeight: 500,
|
||||
}}>
|
||||
<StyledTabButton isSelected={isSelected} onClick={onClick}>
|
||||
{children}
|
||||
</button>
|
||||
</StyledTabButton>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +102,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, ad
|
|||
})
|
||||
}
|
||||
|
||||
const { selectedProvider, selectedModelId, selectedModelInfo } = useMemo(() => {
|
||||
const { selectedProvider, selectedModelId, selectedModelInfo, selectedAdvisorModelId } = useMemo(() => {
|
||||
return normalizeApiConfiguration(apiConfiguration)
|
||||
}, [apiConfiguration])
|
||||
|
||||
|
|
@ -138,12 +145,16 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, ad
|
|||
|
||||
As a workaround, we create separate instances of the dropdown for each provider, and then conditionally render the one that matches the current provider.
|
||||
*/
|
||||
const createDropdown = (models: Record<string, ModelInfo>) => {
|
||||
const createDropdown = (models: Record<string, ModelInfo>, modelType?: ModelType) => {
|
||||
return (
|
||||
<VSCodeDropdown
|
||||
id="model-id"
|
||||
value={selectedModelId}
|
||||
onChange={handleInputChange("apiModelId")}
|
||||
// right now anthropic is the only non-openrouter provider that supports advisor models.
|
||||
// if anthropic then selectedAdvisorId will always have value
|
||||
value={modelType === "advisor" ? selectedAdvisorModelId || selectedModelId : selectedModelId}
|
||||
onChange={
|
||||
modelType === "advisor" ? handleInputChange("anthropicAdvisorModelId") : handleInputChange("apiModelId")
|
||||
}
|
||||
style={{ width: "100%" }}>
|
||||
<VSCodeOption value="">Select a model...</VSCodeOption>
|
||||
{Object.keys(models).map((modelId) => (
|
||||
|
|
@ -751,6 +762,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, ad
|
|||
)}
|
||||
|
||||
{selectedProvider !== "openrouter" &&
|
||||
selectedProvider !== "anthropic" &&
|
||||
selectedProvider !== "openai" &&
|
||||
selectedProvider !== "ollama" &&
|
||||
selectedProvider !== "lmstudio" &&
|
||||
|
|
@ -760,7 +772,6 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, ad
|
|||
<label htmlFor="model-id">
|
||||
<span style={{ fontWeight: 500 }}>Model</span>
|
||||
</label>
|
||||
{selectedProvider === "anthropic" && createDropdown(anthropicModels)}
|
||||
{selectedProvider === "bedrock" && createDropdown(bedrockModels)}
|
||||
{selectedProvider === "vertex" && createDropdown(vertexModels)}
|
||||
{selectedProvider === "gemini" && createDropdown(geminiModels)}
|
||||
|
|
@ -778,7 +789,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, ad
|
|||
</>
|
||||
)}
|
||||
|
||||
{selectedProvider !== "openrouter" && modelIdErrorMessage && (
|
||||
{selectedProvider !== "openrouter" && selectedProvider !== "anthropic" && modelIdErrorMessage && (
|
||||
<p
|
||||
style={{
|
||||
margin: "-10px 0 4px 0",
|
||||
|
|
@ -789,7 +800,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, ad
|
|||
</p>
|
||||
)}
|
||||
|
||||
{selectedProvider === "openrouter" && showModelOptions && (
|
||||
{(selectedProvider === "openrouter" || selectedProvider === "anthropic") && showModelOptions && (
|
||||
<div style={{ marginTop: -5 }}>
|
||||
<div style={{ display: "flex", borderBottom: "1px solid var(--vscode-panel-border)" }}>
|
||||
<TabButton isSelected={selectedTab === "base"} onClick={() => setSelectedTab("base")}>
|
||||
|
|
@ -810,7 +821,12 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, ad
|
|||
This is the default driver model for Cline. It will read and edit files, run commands, and more, with
|
||||
your permission at each step.
|
||||
</p>
|
||||
<OpenRouterModelPicker modelType="base" key="base-model-picker" />
|
||||
{selectedProvider === "anthropic" && (
|
||||
<div className="dropdown-container" style={{ marginBottom: 15 }}>
|
||||
{createDropdown(anthropicModels, "base")}
|
||||
</div>
|
||||
)}
|
||||
{selectedProvider === "openrouter" && <OpenRouterModelPicker modelType="base" key="base-model-picker" />}
|
||||
{modelIdErrorMessage && (
|
||||
<p
|
||||
style={{
|
||||
|
|
@ -833,7 +849,14 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, ad
|
|||
The Cline model can call this smarter, more powerful model to ask for help on planning out a task,
|
||||
fixing a hard bug, and other complex problems.
|
||||
</p>
|
||||
<OpenRouterModelPicker modelType="advisor" key="advisor-model-picker" />
|
||||
{selectedProvider === "anthropic" && (
|
||||
<div className="dropdown-container" style={{ marginBottom: 15 }}>
|
||||
{createDropdown(anthropicModels, "advisor")}
|
||||
</div>
|
||||
)}
|
||||
{selectedProvider === "openrouter" && (
|
||||
<OpenRouterModelPicker modelType="advisor" key="advisor-model-picker" />
|
||||
)}
|
||||
{advisorModelIdErrorMessage && (
|
||||
<p
|
||||
style={{
|
||||
|
|
@ -1017,7 +1040,10 @@ export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration):
|
|||
}
|
||||
switch (provider) {
|
||||
case "anthropic":
|
||||
return getProviderData(anthropicModels, anthropicDefaultModelId)
|
||||
return {
|
||||
...getProviderData(anthropicModels, anthropicDefaultModelId),
|
||||
selectedAdvisorModelId: apiConfiguration?.anthropicAdvisorModelId || anthropicDefaultAdvisorModelId,
|
||||
}
|
||||
case "bedrock":
|
||||
return getProviderData(bedrockModels, bedrockDefaultModelId)
|
||||
case "vertex":
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue