Skip to content

Commit 9619796

Browse files
Himanshu-Singh-Chauhannang-dev
authored andcommitted
add pearai provider
1 parent 9056a59 commit 9619796

File tree

6 files changed

+114
-2
lines changed

6 files changed

+114
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ roo-cline-*.vsix
1515
# Test environment
1616
.test_env
1717
.vscode-test/
18+
.aider*
19+
.env

src/api/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { DeepSeekHandler } from "./providers/deepseek"
1414
import { MistralHandler } from "./providers/mistral"
1515
import { VsCodeLmHandler } from "./providers/vscode-lm"
1616
import { ApiStream } from "./transform/stream"
17+
import { PearAiHandler } from "./providers/pearai"
1718

1819
export interface SingleCompletionHandler {
1920
completePrompt(prompt: string): Promise<string>
@@ -53,6 +54,8 @@ export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
5354
return new VsCodeLmHandler(options)
5455
case "mistral":
5556
return new MistralHandler(options)
57+
case "pearai":
58+
return new PearAiHandler(options)
5659
default:
5760
return new AnthropicHandler(options)
5861
}

src/api/providers/pearai.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { OpenAiHandler } from "./openai"
2+
import { ApiHandlerOptions } from "../../shared/api"
3+
4+
export class PearAiHandler extends OpenAiHandler {
5+
constructor(options: ApiHandlerOptions) {
6+
if (!options.pearaiApiKey) {
7+
throw new Error("PearAI API key is required. Please provide it in the settings.")
8+
}
9+
super({
10+
...options,
11+
// Map PearAI specific options to OpenAI options for compatibility
12+
openAiApiKey: options.pearaiApiKey,
13+
openAiBaseUrl:
14+
options.pearaiBaseUrl ??
15+
"https://stingray-app-gb2an.ondigitalocean.app/pearai-server-api2/integrations/cline",
16+
openAiStreamingEnabled: true,
17+
})
18+
}
19+
}

src/core/webview/ClineProvider.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type SecretKey =
6363
| "openAiNativeApiKey"
6464
| "deepSeekApiKey"
6565
| "mistralApiKey"
66+
| "pearaiApiKey"
6667
type GlobalStateKey =
6768
| "apiProvider"
6869
| "apiModelId"
@@ -97,6 +98,10 @@ type GlobalStateKey =
9798
| "openRouterModelId"
9899
| "openRouterModelInfo"
99100
| "openRouterBaseUrl"
101+
| "pearaiModelId"
102+
| "pearaiModelInfo"
103+
| "pearaiBaseUrl"
104+
| "pearaiApiKey"
100105
| "openRouterUseMiddleOutTransform"
101106
| "allowedCommands"
102107
| "soundEnabled"
@@ -1363,6 +1368,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
13631368
openRouterUseMiddleOutTransform,
13641369
vsCodeLmModelSelector,
13651370
mistralApiKey,
1371+
pearaiApiKey,
1372+
pearaiBaseUrl,
1373+
pearaiModelId,
1374+
pearaiModelInfo,
13661375
} = apiConfiguration
13671376
await this.updateGlobalState("apiProvider", apiProvider)
13681377
await this.updateGlobalState("apiModelId", apiModelId)
@@ -1401,6 +1410,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
14011410
await this.updateGlobalState("openRouterUseMiddleOutTransform", openRouterUseMiddleOutTransform)
14021411
await this.updateGlobalState("vsCodeLmModelSelector", vsCodeLmModelSelector)
14031412
await this.storeSecret("mistralApiKey", mistralApiKey)
1413+
await this.updateGlobalState("pearaiModelId", pearaiModelId)
1414+
await this.updateGlobalState("pearaiModelInfo", pearaiModelInfo)
1415+
await this.storeSecret("pearaiApiKey", pearaiApiKey)
1416+
await this.updateGlobalState("pearaiBaseUrl", pearaiBaseUrl)
14041417
if (this.cline) {
14051418
this.cline.api = buildApiHandler(apiConfiguration)
14061419
}
@@ -2019,6 +2032,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
20192032
openAiNativeApiKey,
20202033
deepSeekApiKey,
20212034
mistralApiKey,
2035+
pearaiApiKey,
2036+
pearaiBaseUrl,
2037+
pearaiModelId,
2038+
pearaiModelInfo,
20222039
azureApiVersion,
20232040
openAiStreamingEnabled,
20242041
openRouterModelId,
@@ -2089,6 +2106,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
20892106
this.getSecret("openAiNativeApiKey") as Promise<string | undefined>,
20902107
this.getSecret("deepSeekApiKey") as Promise<string | undefined>,
20912108
this.getSecret("mistralApiKey") as Promise<string | undefined>,
2109+
this.getSecret("pearaiApiKey") as Promise<string | undefined>,
2110+
this.getGlobalState("pearaiBaseUrl") as Promise<string | undefined>,
2111+
this.getGlobalState("pearaiModelId") as Promise<string | undefined>,
2112+
this.getGlobalState("pearaiModelInfo") as Promise<ModelInfo | undefined>,
20922113
this.getGlobalState("azureApiVersion") as Promise<string | undefined>,
20932114
this.getGlobalState("openAiStreamingEnabled") as Promise<boolean | undefined>,
20942115
this.getGlobalState("openRouterModelId") as Promise<string | undefined>,
@@ -2176,6 +2197,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
21762197
openAiNativeApiKey,
21772198
deepSeekApiKey,
21782199
mistralApiKey,
2200+
pearaiApiKey,
2201+
pearaiBaseUrl,
2202+
pearaiModelId,
2203+
pearaiModelInfo,
21792204
azureApiVersion,
21802205
openAiStreamingEnabled,
21812206
openRouterModelId,

src/shared/api.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export type ApiProvider =
1414
| "deepseek"
1515
| "vscode-lm"
1616
| "mistral"
17+
| "pearai"
1718

1819
export interface ApiHandlerOptions {
1920
apiModelId?: string
@@ -57,6 +58,10 @@ export interface ApiHandlerOptions {
5758
deepSeekBaseUrl?: string
5859
deepSeekApiKey?: string
5960
includeMaxTokens?: boolean
61+
pearaiApiKey?: string
62+
pearaiBaseUrl?: string
63+
pearaiModelId?: string
64+
pearaiModelInfo?: ModelInfo
6065
}
6166

6267
export type ApiConfiguration = ApiHandlerOptions & {

webview-ui/src/components/settings/ApiOptions.tsx

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { Checkbox, Dropdown, Pane } from "vscrui"
22
import type { DropdownOption } from "vscrui"
3-
import { VSCodeLink, VSCodeRadio, VSCodeRadioGroup, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
3+
import {
4+
VSCodeButton,
5+
VSCodeLink,
6+
VSCodeRadio,
7+
VSCodeRadioGroup,
8+
VSCodeTextField,
9+
} from "@vscode/webview-ui-toolkit/react"
410
import { Fragment, memo, useCallback, useEffect, useMemo, useState } from "react"
511
import { useEvent, useInterval } from "react-use"
612
import {
@@ -39,6 +45,8 @@ import OpenRouterModelPicker, {
3945
import OpenAiModelPicker from "./OpenAiModelPicker"
4046
import GlamaModelPicker from "./GlamaModelPicker"
4147

48+
const PEARAI_DEFAULT_URL = "https://stingray-app-gb2an.ondigitalocean.app/pearai-server-api2/integrations/cline"
49+
4250
interface ApiOptionsProps {
4351
apiErrorMessage?: string
4452
modelIdErrorMessage?: string
@@ -52,6 +60,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
5260
const [anthropicBaseUrlSelected, setAnthropicBaseUrlSelected] = useState(!!apiConfiguration?.anthropicBaseUrl)
5361
const [azureApiVersionSelected, setAzureApiVersionSelected] = useState(!!apiConfiguration?.azureApiVersion)
5462
const [openRouterBaseUrlSelected, setOpenRouterBaseUrlSelected] = useState(!!apiConfiguration?.openRouterBaseUrl)
63+
const [pearaiBaseUrlSelected, setPearaiBaseUrlSelected] = useState(!!apiConfiguration?.pearaiBaseUrl)
5564
const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false)
5665

5766
const { selectedProvider, selectedModelId, selectedModelInfo } = useMemo(() => {
@@ -134,6 +143,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
134143
}}
135144
style={{ minWidth: 130, position: "relative", zIndex: OPENROUTER_MODEL_PICKER_Z_INDEX + 1 }}
136145
options={[
146+
{ value: "pearai", label: "PearAI" },
137147
{ value: "openrouter", label: "OpenRouter" },
138148
{ value: "anthropic", label: "Anthropic" },
139149
{ value: "gemini", label: "Google Gemini" },
@@ -151,6 +161,47 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
151161
/>
152162
</div>
153163

164+
{selectedProvider === "pearai" && (
165+
<div>
166+
<VSCodeTextField
167+
value={apiConfiguration?.pearaiApiKey || ""}
168+
style={{ width: "100%" }}
169+
type="password"
170+
onInput={handleInputChange("pearaiApiKey")}
171+
placeholder="Enter API Key...">
172+
<span style={{ fontWeight: 500 }}>PearAI API Key</span>
173+
</VSCodeTextField>
174+
<VSCodeTextField
175+
value={apiConfiguration?.pearaiBaseUrl || PEARAI_DEFAULT_URL}
176+
style={{ width: "100%" }}
177+
type="url"
178+
onInput={handleInputChange("pearaiBaseUrl")}
179+
placeholder={PEARAI_DEFAULT_URL}>
180+
<span style={{ fontWeight: 500 }}>Base URL</span>
181+
</VSCodeTextField>
182+
{apiConfiguration?.pearaiBaseUrl && apiConfiguration.pearaiBaseUrl !== PEARAI_DEFAULT_URL && (
183+
<VSCodeButton
184+
onClick={() => {
185+
handleInputChange("pearaiBaseUrl")({
186+
target: {
187+
value: PEARAI_DEFAULT_URL,
188+
},
189+
})
190+
}}>
191+
Reset to default URL
192+
</VSCodeButton>
193+
)}
194+
<p
195+
style={{
196+
fontSize: "12px",
197+
marginTop: "5px",
198+
color: "var(--vscode-descriptionForeground)",
199+
}}>
200+
This key is stored locally and only used to make API requests from this extension.
201+
</p>
202+
</div>
203+
)}
204+
154205
{selectedProvider === "anthropic" && (
155206
<div>
156207
<VSCodeTextField
@@ -1302,7 +1353,8 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
13021353
selectedProvider !== "openrouter" &&
13031354
selectedProvider !== "openai" &&
13041355
selectedProvider !== "ollama" &&
1305-
selectedProvider !== "lmstudio" && (
1356+
selectedProvider !== "lmstudio" &&
1357+
selectedProvider !== "pearai" && (
13061358
<>
13071359
<div className="dropdown-container">
13081360
<label htmlFor="model-id">
@@ -1552,6 +1604,12 @@ export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration) {
15521604
supportsImages: false, // VSCode LM API currently doesn't support images
15531605
},
15541606
}
1607+
case "pearai":
1608+
return {
1609+
selectedProvider: provider,
1610+
selectedModelId: apiConfiguration?.pearaiModelId || "",
1611+
selectedModelInfo: apiConfiguration?.pearaiModelInfo || openAiModelInfoSaneDefaults,
1612+
}
15551613
default:
15561614
return getProviderData(anthropicModels, anthropicDefaultModelId)
15571615
}

0 commit comments

Comments
 (0)