Relax provider profiles schema and log parse error to PostHog (#2139)

* Relax provider profiles schema and log parse error to PostHog

* Create wise-moose-shop.md

---------

Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com>
This commit is contained in:
Chris Estreich 2025-03-30 23:07:34 -07:00 committed by GitHub
parent f25812d722
commit 3322e08cb7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 56 additions and 24 deletions

View file

@ -0,0 +1,5 @@
---
"roo-cline": patch
---
Relax provider profiles schema and add telemetry

View file

@ -88,7 +88,7 @@ export class GlamaHandler extends BaseProvider implements SingleCompletionHandle
let maxTokens: number | undefined
if (this.getModel().id.startsWith("anthropic/")) {
maxTokens = this.getModel().info.maxTokens
maxTokens = this.getModel().info.maxTokens ?? undefined
}
const requestOptions: OpenAI.Chat.ChatCompletionCreateParams = {

View file

@ -79,7 +79,7 @@ export class UnboundHandler extends BaseProvider implements SingleCompletionHand
let maxTokens: number | undefined
if (this.getModel().id.startsWith("anthropic/")) {
maxTokens = this.getModel().info.maxTokens
maxTokens = this.getModel().info.maxTokens ?? undefined
}
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {

View file

@ -230,7 +230,7 @@ export class VertexHandler extends BaseProvider implements SingleCompletionHandl
const result = await model.generateContentStream({
contents: messages.map(convertAnthropicMessageToVertexGemini),
generationConfig: {
maxOutputTokens: this.getModel().info.maxTokens,
maxOutputTokens: this.getModel().info.maxTokens ?? undefined,
temperature: this.options.modelTemperature ?? 0,
},
})

View file

@ -1,4 +1,5 @@
import * as vscode from "vscode"
import { ZodError } from "zod"
import {
PROVIDER_SETTINGS_KEYS,
@ -15,6 +16,7 @@ import {
isSecretStateKey,
} from "../../schemas"
import { logger } from "../../utils/logging"
import { telemetryService } from "../../services/telemetry/TelemetryService"
type GlobalStateKey = keyof GlobalState
type SecretStateKey = keyof SecretState
@ -157,8 +159,10 @@ export class ContextProxy {
try {
return globalSettingsSchema.parse(values)
} catch (error) {
// Log to Posthog?
// We'll want to know about bad type assumptions or bad ExtensionState data.
if (error instanceof ZodError) {
telemetryService.captureSchemaValidationError({ schemaName: "GlobalSettings", error })
}
return GLOBAL_SETTINGS_KEYS.reduce((acc, key) => ({ ...acc, [key]: values[key] }), {} as GlobalSettings)
}
}
@ -173,8 +177,10 @@ export class ContextProxy {
try {
return providerSettingsSchema.parse(values)
} catch (error) {
// Log to Posthog?
// We'll want to know about bad type assumptions or bad ExtensionState data.
if (error instanceof ZodError) {
telemetryService.captureSchemaValidationError({ schemaName: "ProviderSettings", error })
}
return PROVIDER_SETTINGS_KEYS.reduce((acc, key) => ({ ...acc, [key]: values[key] }), {} as ProviderSettings)
}
}
@ -225,7 +231,10 @@ export class ContextProxy {
const globalSettings = globalSettingsExportSchema.parse(this.getValues())
return Object.fromEntries(Object.entries(globalSettings).filter(([_, value]) => value !== undefined))
} catch (error) {
console.log(error.message)
if (error instanceof ZodError) {
telemetryService.captureSchemaValidationError({ schemaName: "GlobalSettings", error })
}
return undefined
}
}

View file

@ -1,8 +1,9 @@
import { ExtensionContext } from "vscode"
import { z } from "zod"
import { z, ZodError } from "zod"
import { providerSettingsSchema, ApiConfigMeta } from "../../schemas"
import { Mode, modes } from "../../shared/modes"
import { telemetryService } from "../../services/telemetry/TelemetryService"
const providerSettingsWithIdSchema = providerSettingsSchema.extend({ id: z.string().optional() })
@ -272,6 +273,10 @@ export class ProviderSettingsManager {
const content = await this.context.secrets.get(this.secretsKey)
return content ? providerProfilesSchema.parse(JSON.parse(content)) : this.defaultProviderProfiles
} catch (error) {
if (error instanceof ZodError) {
telemetryService.captureSchemaValidationError({ schemaName: "ProviderProfiles", error })
}
throw new Error(`Failed to read provider profiles from secrets: ${error}`)
}
}

View file

@ -60,7 +60,7 @@ type TruncateOptions = {
messages: Anthropic.Messages.MessageParam[]
totalTokens: number
contextWindow: number
maxTokens?: number
maxTokens?: number | null
apiHandler: ApiHandler
}

View file

@ -28,7 +28,7 @@ type ProviderSettings = {
glamaModelId?: string | undefined
glamaModelInfo?:
| ({
maxTokens?: number | undefined
maxTokens?: (number | null) | undefined
contextWindow: number
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
@ -47,7 +47,7 @@ type ProviderSettings = {
openRouterModelId?: string | undefined
openRouterModelInfo?:
| ({
maxTokens?: number | undefined
maxTokens?: (number | null) | undefined
contextWindow: number
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
@ -84,7 +84,7 @@ type ProviderSettings = {
openAiModelId?: string | undefined
openAiCustomModelInfo?:
| ({
maxTokens?: number | undefined
maxTokens?: (number | null) | undefined
contextWindow: number
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
@ -126,7 +126,7 @@ type ProviderSettings = {
unboundModelId?: string | undefined
unboundModelInfo?:
| ({
maxTokens?: number | undefined
maxTokens?: (number | null) | undefined
contextWindow: number
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
@ -144,7 +144,7 @@ type ProviderSettings = {
requestyModelId?: string | undefined
requestyModelInfo?:
| ({
maxTokens?: number | undefined
maxTokens?: (number | null) | undefined
contextWindow: number
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined

View file

@ -29,7 +29,7 @@ type ProviderSettings = {
glamaModelId?: string | undefined
glamaModelInfo?:
| ({
maxTokens?: number | undefined
maxTokens?: (number | null) | undefined
contextWindow: number
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
@ -48,7 +48,7 @@ type ProviderSettings = {
openRouterModelId?: string | undefined
openRouterModelInfo?:
| ({
maxTokens?: number | undefined
maxTokens?: (number | null) | undefined
contextWindow: number
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
@ -85,7 +85,7 @@ type ProviderSettings = {
openAiModelId?: string | undefined
openAiCustomModelInfo?:
| ({
maxTokens?: number | undefined
maxTokens?: (number | null) | undefined
contextWindow: number
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
@ -127,7 +127,7 @@ type ProviderSettings = {
unboundModelId?: string | undefined
unboundModelInfo?:
| ({
maxTokens?: number | undefined
maxTokens?: (number | null) | undefined
contextWindow: number
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined
@ -145,7 +145,7 @@ type ProviderSettings = {
requestyModelId?: string | undefined
requestyModelInfo?:
| ({
maxTokens?: number | undefined
maxTokens?: (number | null) | undefined
contextWindow: number
supportsImages?: boolean | undefined
supportsComputerUse?: boolean | undefined

View file

@ -100,7 +100,7 @@ export type TelemetrySetting = z.infer<typeof telemetrySettingsSchema>
*/
export const modelInfoSchema = z.object({
maxTokens: z.number().optional(),
maxTokens: z.number().nullish(),
contextWindow: z.number(),
supportsImages: z.boolean().optional(),
supportsComputerUse: z.boolean().optional(),

View file

@ -1,5 +1,7 @@
import { PostHog } from "posthog-node"
import * as vscode from "vscode"
import { ZodError } from "zod"
import { logger } from "../../utils/logging"
// This forward declaration is needed to avoid circular dependencies
@ -26,6 +28,9 @@ class PostHogClient {
CHECKPOINT_RESTORED: "Checkpoint Restored",
CHECKPOINT_DIFFED: "Checkpoint Diffed",
},
ERRORS: {
SCHEMA_VALIDATION_ERROR: "Schema Validation Error",
},
}
private static instance: PostHogClient
@ -261,6 +266,14 @@ class TelemetryService {
this.captureEvent(PostHogClient.EVENTS.TASK.CHECKPOINT_RESTORED, { taskId })
}
public captureSchemaValidationError({ schemaName, error }: { schemaName: string; error: ZodError }): void {
this.captureEvent(PostHogClient.EVENTS.ERRORS.SCHEMA_VALIDATION_ERROR, {
schemaName,
// https://zod.dev/ERROR_HANDLING?id=formatting-errors
error: error.format(),
})
}
/**
* Checks if telemetry is currently enabled
* @returns Whether telemetry is enabled

View file

@ -43,7 +43,7 @@ export const ModelInfoView = ({
doesNotSupportLabel={t("settings:modelInfo.noPromptCache")}
/>
),
modelInfo.maxTokens !== undefined && modelInfo.maxTokens > 0 && (
typeof modelInfo.maxTokens === "number" && modelInfo.maxTokens > 0 && (
<>
<span className="font-medium">{t("settings:modelInfo.maxOutput")}:</span>{" "}
{modelInfo.maxTokens?.toLocaleString()} tokens

View file

@ -14,7 +14,7 @@ export interface ModelInfo {
/**
* Maximum number of tokens the model can process
*/
maxTokens?: number
maxTokens?: number | null
/**
* Whether the model supports thinking/reasoning capabilities
@ -77,7 +77,7 @@ export const getMaxTokensForModel = (
if (modelInfo?.thinking) {
return apiConfig?.modelMaxTokens || DEFAULT_THINKING_MODEL_MAX_TOKENS
}
return modelInfo?.maxTokens
return modelInfo?.maxTokens ?? undefined
}
/**