Skip to content

Commit 13151d2

Browse files
committed
all helicone models
1 parent 4d37e8c commit 13151d2

File tree

12 files changed

+142
-45
lines changed

12 files changed

+142
-45
lines changed

packages/types/src/provider-settings.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import {
1414
fireworksModels,
1515
geminiModels,
1616
groqModels,
17-
heliconeModels,
1817
ioIntelligenceModels,
1918
mistralModels,
2019
moonshotModels,
@@ -41,6 +40,7 @@ export const DEFAULT_CONSECUTIVE_MISTAKE_LIMIT = 3
4140
*/
4241

4342
export const dynamicProviders = [
43+
"helicone",
4444
"openrouter",
4545
"vercel-ai-gateway",
4646
"huggingface",
@@ -130,7 +130,6 @@ export const providerNames = [
130130
"gemini",
131131
"gemini-cli",
132132
"groq",
133-
"helicone",
134133
"mistral",
135134
"moonshot",
136135
"openai-native",
@@ -219,7 +218,6 @@ const heliconeSchema = baseProviderSettingsSchema.extend({
219218
heliconeApiKey: z.string().optional(),
220219
heliconeModelId: z.string().optional(),
221220
heliconeBaseUrl: z.string().optional(),
222-
heliconeSpecificProvider: z.string().optional(),
223221
})
224222

225223
const bedrockSchema = apiModelIdProviderModelSchema.extend({
@@ -563,7 +561,7 @@ export const modelIdKeysByProvider: Record<TypicalProvider, ModelIdKey> = {
563561
"claude-code": "apiModelId",
564562
glama: "glamaModelId",
565563
openrouter: "openRouterModelId",
566-
helicone: "apiModelId",
564+
helicone: "heliconeModelId",
567565
bedrock: "apiModelId",
568566
vertex: "apiModelId",
569567
"openai-native": "openAiModelId",
@@ -669,7 +667,6 @@ export const MODELS_BY_PROVIDER: Record<
669667
models: Object.keys(geminiModels),
670668
},
671669
groq: { id: "groq", label: "Groq", models: Object.keys(groqModels) },
672-
helicone: { id: "helicone", label: "Helicone", models: Object.keys(heliconeModels) },
673670
"io-intelligence": {
674671
id: "io-intelligence",
675672
label: "IO Intelligence",
@@ -712,6 +709,7 @@ export const MODELS_BY_PROVIDER: Record<
712709

713710
// Dynamic providers; models pulled from remote APIs.
714711
glama: { id: "glama", label: "Glama", models: [] },
712+
helicone: { id: "helicone", label: "Helicone", models: [] },
715713
huggingface: { id: "huggingface", label: "Hugging Face", models: [] },
716714
litellm: { id: "litellm", label: "LiteLLM", models: [] },
717715
openrouter: { id: "openrouter", label: "OpenRouter", models: [] },
Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import type { ModelInfo } from "../model.js"
22

3-
// Helicone is OpenAI-compatible and uses name/provider model IDs.
4-
// TODO [HELICONE]: change this to claude-4.5-sonnet/anthropic as Roo Code is optimized for that
5-
export const heliconeDefaultModelId = "gpt-4o/openai"
3+
// Helicone is OpenAI-compatible
4+
export const heliconeDefaultModelId = "claude-4.5-sonnet"
65

76
export const heliconeDefaultModelInfo: ModelInfo = {
8-
maxTokens: 16_384,
9-
contextWindow: 128_000,
7+
maxTokens: 8192,
8+
contextWindow: 200_000,
109
supportsImages: true,
10+
supportsComputerUse: true,
1111
supportsPromptCache: true,
12-
inputPrice: 5.0,
13-
outputPrice: 20.0,
14-
cacheReadsPrice: 2.5,
15-
description: "GPT-4o via Helicone AI Gateway.",
12+
inputPrice: 3.0,
13+
outputPrice: 15.0,
14+
cacheWritesPrice: 3.75,
15+
cacheReadsPrice: 0.3,
16+
description: "Claude 4.5 Sonnet via Helicone AI Gateway.",
1617
}
17-
18-
export const heliconeModels = {
19-
"gpt-4o/openai": heliconeDefaultModelInfo,
20-
} as const
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import axios from "axios"
2+
import { z } from "zod"
3+
import type { ModelInfo } from "@roo-code/types"
4+
5+
// Helicone Public Model Registry schemas
6+
const heliconePricingSchema = z.object({
7+
prompt: z.number().optional(),
8+
completion: z.number().optional(),
9+
cacheRead: z.number().optional(),
10+
cacheWrite: z.number().optional(),
11+
})
12+
13+
const heliconeEndpointSchema = z.object({
14+
provider: z.string().optional(),
15+
providerSlug: z.string().optional(),
16+
supportsPtb: z.boolean().optional(),
17+
pricing: heliconePricingSchema.optional(),
18+
})
19+
20+
const heliconeModelSchema = z.object({
21+
id: z.string(),
22+
name: z.string().optional(),
23+
author: z.string().optional(),
24+
contextLength: z.number().optional(),
25+
maxOutput: z.number().optional(),
26+
description: z.string().optional(),
27+
inputModalities: z.array(z.string().nullable()).nullable().optional(),
28+
outputModalities: z.array(z.string().nullable()).nullable().optional(),
29+
supportedParameters: z.array(z.string().nullable()).nullable().optional(),
30+
endpoints: z.array(heliconeEndpointSchema).default([]),
31+
})
32+
33+
const heliconeModelsResponseSchema = z.object({
34+
models: z.array(heliconeModelSchema),
35+
total: z.number().optional(),
36+
})
37+
38+
export async function getHeliconeModels(): Promise<Record<string, ModelInfo>> {
39+
const models: Record<string, ModelInfo> = {}
40+
41+
try {
42+
// Public model registry (no auth required)
43+
const url = "https://api.helicone.ai/v1/public/model-registry/models"
44+
const resp = await axios.get(url)
45+
const parsed = heliconeModelsResponseSchema.safeParse(resp.data.data)
46+
const data = parsed.success ? parsed.data?.models : resp.data?.data?.models || []
47+
48+
if (!parsed.success) {
49+
console.error("Helicone models response is invalid", parsed.error.format())
50+
}
51+
52+
for (const m of data) {
53+
const model = heliconeModelSchema.parse(m)
54+
55+
const contextLength = model.contextLength ?? 128_000
56+
const maxTokens = model.maxOutput ?? Math.ceil(contextLength * 0.2)
57+
const inputMods = (model.inputModalities || []).filter((mod): mod is string => typeof mod === "string")
58+
59+
// Find the first PTB-enabled endpoint for pricing
60+
const ptbEndpoint = model.endpoints.find((ep) => ep.supportsPtb === true)
61+
if (!ptbEndpoint) continue
62+
63+
const info: ModelInfo = {
64+
maxTokens,
65+
contextWindow: contextLength,
66+
supportsImages: inputMods.includes("image"),
67+
supportsPromptCache: true,
68+
inputPrice: ptbEndpoint.pricing?.prompt,
69+
outputPrice: ptbEndpoint.pricing?.completion,
70+
cacheWritesPrice: ptbEndpoint.pricing?.cacheWrite,
71+
cacheReadsPrice: ptbEndpoint.pricing?.cacheRead,
72+
description: model.description,
73+
}
74+
75+
models[model.id] = info
76+
}
77+
} catch (error) {
78+
console.error(
79+
`Error fetching Helicone models: ${JSON.stringify(error, Object.getOwnPropertyNames(error as any), 2)}`,
80+
)
81+
}
82+
83+
return models
84+
}

src/api/providers/fetchers/modelCache.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type { RouterName, ModelRecord } from "../../../shared/api"
1313
import { fileExistsAtPath } from "../../../utils/fs"
1414

1515
import { getOpenRouterModels } from "./openrouter"
16+
import { getHeliconeModels } from "./helicone"
1617
import { getVercelAiGatewayModels } from "./vercel-ai-gateway"
1718
import { getRequestyModels } from "./requesty"
1819
import { getGlamaModels } from "./glama"
@@ -63,6 +64,9 @@ export const getModels = async (options: GetModelsOptions): Promise<ModelRecord>
6364

6465
try {
6566
switch (provider) {
67+
case "helicone":
68+
models = await getHeliconeModels()
69+
break
6670
case "openrouter":
6771
models = await getOpenRouterModels()
6872
break

src/api/providers/helicone.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import { Anthropic } from "@anthropic-ai/sdk"
22
import OpenAI from "openai"
33

4-
import {
5-
heliconeDefaultModelId,
6-
heliconeDefaultModelInfo,
7-
heliconeModels,
8-
DEEP_SEEK_DEFAULT_TEMPERATURE,
9-
} from "@roo-code/types"
4+
import { heliconeDefaultModelId, heliconeDefaultModelInfo, DEEP_SEEK_DEFAULT_TEMPERATURE } from "@roo-code/types"
105

116
import type { ApiHandlerOptions, ModelRecord } from "../../shared/api"
127

@@ -15,6 +10,8 @@ import { ApiStreamChunk } from "../transform/stream"
1510
import { convertToR1Format } from "../transform/r1-format"
1611
import { getModelParams } from "../transform/model-params"
1712

13+
import { getModels } from "./fetchers/modelCache"
14+
1815
import { DEFAULT_HEADERS } from "./constants"
1916
import { BaseProvider } from "./base-provider"
2017
import type { SingleCompletionHandler } from "../index"
@@ -109,12 +106,14 @@ export class HeliconeHandler extends BaseProvider implements SingleCompletionHan
109106
}
110107

111108
public async fetchModel() {
112-
this.models = heliconeModels as unknown as ModelRecord
109+
const models = await getModels({ provider: "helicone" })
110+
this.models = models
111+
113112
return this.getModel()
114113
}
115114

116115
override getModel() {
117-
const id = this.options.apiModelId ?? heliconeDefaultModelId
116+
const id = this.options.heliconeModelId ?? heliconeDefaultModelId
118117
const info = this.models[id] ?? heliconeDefaultModelInfo
119118

120119
const params = getModelParams({

src/core/webview/webviewMessageHandler.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ export const webviewMessageHandler = async (
757757
const { apiConfiguration } = await provider.getState()
758758

759759
const routerModels: Record<RouterName, ModelRecord> = {
760+
helicone: {},
760761
openrouter: {},
761762
"vercel-ai-gateway": {},
762763
huggingface: {},
@@ -784,6 +785,7 @@ export const webviewMessageHandler = async (
784785
}
785786

786787
const modelFetchPromises: { key: RouterName; options: GetModelsOptions }[] = [
788+
{ key: "helicone", options: { provider: "helicone" } },
787789
{ key: "openrouter", options: { provider: "openrouter" } },
788790
{
789791
key: "requesty",

src/shared/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ type CommonFetchParams = {
152152
// If a new dynamic provider is added in packages/types, this will fail to compile
153153
// until a corresponding entry is added here.
154154
const dynamicProviderExtras = {
155+
helicone: {} as {}, // eslint-disable-line @typescript-eslint/no-empty-object-type
155156
openrouter: {} as {}, // eslint-disable-line @typescript-eslint/no-empty-object-type
156157
"vercel-ai-gateway": {} as {}, // eslint-disable-line @typescript-eslint/no-empty-object-type
157158
huggingface: {} as {}, // eslint-disable-line @typescript-eslint/no-empty-object-type

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,9 @@ const ApiOptions = ({
477477
<Helicone
478478
apiConfiguration={apiConfiguration}
479479
setApiConfigurationField={setApiConfigurationField}
480-
// TODO [HELICONE]: add router models, selected model id,
481-
// fromWelcomeView
480+
routerModels={routerModels}
481+
organizationAllowList={organizationAllowList}
482+
modelValidationError={modelValidationError}
482483
/>
483484
)}
484485

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type ModelIdKey = keyof Pick<
3030
ProviderSettings,
3131
| "glamaModelId"
3232
| "openRouterModelId"
33+
| "heliconeModelId"
3334
| "unboundModelId"
3435
| "requestyModelId"
3536
| "openAiModelId"

webview-ui/src/components/settings/constants.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
fireworksModels,
2222
rooModels,
2323
featherlessModels,
24-
heliconeModels,
2524
} from "@roo-code/types"
2625

2726
export const MODELS_BY_PROVIDER: Partial<Record<ProviderName, Record<string, ModelInfo>>> = {
@@ -45,7 +44,6 @@ export const MODELS_BY_PROVIDER: Partial<Record<ProviderName, Record<string, Mod
4544
fireworks: fireworksModels,
4645
roo: rooModels,
4746
featherless: featherlessModels,
48-
helicone: heliconeModels,
4947
}
5048

5149
export const PROVIDERS = [

0 commit comments

Comments
 (0)