fix margins and text

This commit is contained in:
Prasang Prajapati 2025-09-11 18:19:27 -04:00
parent a4c9b732f3
commit 13c8137d0b
4 changed files with 94 additions and 152 deletions

View file

@ -5,93 +5,21 @@ export const watsonxAiDefaultModelId = ""
// Common model properties
export const baseModelInfo: ModelInfo = {
maxTokens: 4096,
contextWindow: 128000,
maxTokens: 131072,
contextWindow: 131072,
supportsImages: false,
supportsPromptCache: true,
supportsReasoningEffort: false,
supportsPromptCache: false,
supportsReasoningEffort: true,
supportsReasoningBudget: false,
requiredReasoningBudget: false,
inputPrice: 0,
outputPrice: 0,
inputPrice: 5.22,
outputPrice: 5.22,
}
export const watsonxAiModels = {
// IBM Granite model
"ibm/granite-3-3-8b-instruct": {
...baseModelInfo,
description: "Granite 3.3 8b Instruct - IBM-trained, dense decoder-only model",
},
"ibm/granite-3-2-8b-instruct": {
...baseModelInfo,
description: "Granite 3.2 8b Instruct - Text-only model capable of reasoning",
},
"ibm/granite-3-2b-instruct": {
...baseModelInfo,
description: "Granite 3 2b Instruct - IBM-trained, dense decoder-only model",
},
"ibm/granite-3-8b-instruct": {
...baseModelInfo,
description: "Granite 3 8b Instruct - IBM-trained, dense decoder-only model",
},
"ibm/granite-guardian-3-2b": {
...baseModelInfo,
description: "Granite Guardian 3 2b - IBM-trained, dense decoder-only model",
},
"ibm/granite-guardian-3-8b": {
...baseModelInfo,
description: "Granite Guardian 3 8b - IBM-trained, dense decoder-only model",
},
"ibm/granite-vision-3-2-2b": {
...baseModelInfo,
supportsImages: true,
description: "Granite 3 Vision - Image-text, text-out model capable of understanding images",
},
// Meta Llama models
"meta-llama/llama-3-2-11b-vision-instruct": {
...baseModelInfo,
supportsImages: true,
description: "Llama 3 2 11b Vision Instruct - Auto-regressive language model with transformer architecture",
},
"meta-llama/llama-3-2-1b-instruct": {
...baseModelInfo,
description: "Llama 3 2 1b Instruct - Auto-regressive language model with transformer architecture",
},
"meta-llama/llama-3-2-3b-instruct": {
...baseModelInfo,
description: "Llama 3 2 3b Instruct - Auto-regressive language model with transformer architecture",
},
"meta-llama/llama-3-2-90b-vision-instruct": {
...baseModelInfo,
supportsImages: true,
description: "Llama 3 2 90b Vision Instruct - Auto-regressive language model with transformer architecture",
},
"meta-llama/llama-3-3-70b-instruct": {
...baseModelInfo,
description: "Llama 3 3 70b Instruct - FP8 quantized version of the original FP16 weights",
},
"meta-llama/llama-3-405b-instruct": {
...baseModelInfo,
contextWindow: 128000,
description: "Llama 3 405b Instruct - Meta's largest open-source foundation model with 405 billion parameters",
},
"meta-llama/llama-4-maverick-17b-1-0": {
...baseModelInfo,
contextWindow: 128000,
description: "Llama 4 Maverick - 17 billion active parameter model with 128 experts",
},
"meta-llama/llama-guard-3-11b-vision": {
...baseModelInfo,
supportsImages: true,
description: "Llama Guard 3 11b Vision - Auto-regressive language model with transformer architecture",
},
// Mistral AI models
"mistralai/mistral-medium-2505": {
...baseModelInfo,
description: "Mistral Medium - Latest iteration of the Mistral Medium model family",
},
"mistralai/mistral-small-3-1-24b-instruct-2503": {
...baseModelInfo,
description: "Mistral Small 3.1 24B Base 2503 - Instruction-finetuned version of Mistral Small",
description: "",
},
} as const satisfies Record<string, ModelInfo>

View file

@ -63,35 +63,42 @@ export async function getWatsonxModels(
let knownModels: Record<string, ModelInfo> = {}
try {
const response = await service.listFoundationModelSpecs()
let response
if (embedded) {
response = await service.listFoundationModelSpecs({ filters: "function_embedding" })
} else {
response = await service.listFoundationModelSpecs({ filters: "!function_embedding" })
}
if (response && response.result) {
const result = response.result as any
const modelsList = result.models || result.resources || result.foundation_models || []
if (Array.isArray(modelsList)) {
const modelsList = result.resources
if (Array.isArray(modelsList) && modelsList.length > 0) {
for (const model of modelsList) {
const modelId = model.id || model.name || model.model_id
const modelInfo = JSON.stringify(model).toLowerCase()
if (modelId && !embedded && !modelInfo.includes("embed") && !modelInfo.includes("rtrvr")) {
const contextWindow = model.context_length || model.max_input_tokens || 8192
const maxTokens = model.max_output_tokens || Math.floor(contextWindow / 2)
const contextWindow = model.context_length || model.max_input_tokens || 8192
const maxTokens = model.max_output_tokens || Math.floor(contextWindow / 2)
knownModels[modelId] = {
contextWindow,
maxTokens,
supportsPromptCache: false,
}
} else {
if (modelId && embedded && modelInfo.includes("embed") && modelInfo.includes("rtrvr")) {
const contextWindow = model.context_length || model.max_input_tokens || 8192
const maxTokens = model.max_output_tokens || Math.floor(contextWindow / 2)
knownModels[modelId] = {
contextWindow,
maxTokens,
supportsPromptCache: false,
}
}
let description = ""
if (model.long_description) {
description = model.long_description
} else if (model.short_description) {
description = model.short_description
}
const supportsImages = model.modality === "multimodal" || model.modality === "vision" || false
const inputPrice = model.pricing?.input_price || 0
const outputPrice = model.pricing?.output_price || 0
knownModels[modelId] = {
contextWindow,
maxTokens,
supportsPromptCache: false,
supportsImages,
supportsReasoningEffort: false,
supportsReasoningBudget: false,
requiredReasoningBudget: false,
inputPrice,
outputPrice,
description,
}
}
}

View file

@ -8,6 +8,7 @@ import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { WatsonXAI } from "@ibm-cloud/watsonx-ai"
import { convertToWatsonxAiMessages } from "../transform/watsonxai-format"
import { calculateApiCostOpenAI } from "../../shared/cost"
export class WatsonxAIHandler extends BaseProvider implements SingleCompletionHandler {
private options: ApiHandlerOptions
@ -145,11 +146,15 @@ export class WatsonxAIHandler extends BaseProvider implements SingleCompletionHa
usageInfo = response.result.usage || {}
const outputTokens = usageInfo.completion_tokens
const inputTokens = usageInfo?.prompt_tokens || 0
const modelInfo = this.getModel().info
const totalCost = calculateApiCostOpenAI(modelInfo, inputTokens, outputTokens)
yield {
type: "usage",
inputTokens: usageInfo?.prompt_tokens,
inputTokens: inputTokens,
outputTokens,
totalCost: 0, // Actual cost calculation could be added if available
totalCost: totalCost,
}
} catch (error) {
await vscode.window.showErrorMessage(error.message)

View file

@ -248,7 +248,7 @@ export const WatsonxAI = ({
return (
<>
{/* Platform Selection */}
<div className="w-full mb-4">
<div className="w-full mb-1">
<label className="block font-medium mb-1">Platform</label>
<Select
value={apiConfiguration.watsonxPlatform}
@ -265,31 +265,29 @@ export const WatsonxAI = ({
{/* IBM Cloud specific fields */}
{apiConfiguration.watsonxPlatform === "ibmCloud" && (
<>
<div className="w-full mb-4">
<label className="block font-medium mb-1">Region</label>
<Select value={selectedRegion} onValueChange={handleRegionSelect}>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select a region" />
</SelectTrigger>
<SelectContent>
{Object.entries(WATSONX_REGIONS).map(([regionCode, regionName]) => (
<SelectItem key={regionCode} value={regionCode}>
{regionName}
</SelectItem>
))}
</SelectContent>
</Select>
<div className="text-sm text-vscode-descriptionForeground mt-1">
Selected endpoint: {REGION_TO_URL[selectedRegion as keyof typeof REGION_TO_URL]}
</div>
<div className="w-full mb-1">
<label className="block font-medium mb-1">Region</label>
<Select value={selectedRegion} onValueChange={handleRegionSelect}>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select a region" />
</SelectTrigger>
<SelectContent>
{Object.entries(WATSONX_REGIONS).map(([regionCode, regionName]) => (
<SelectItem key={regionCode} value={regionCode}>
{regionName}
</SelectItem>
))}
</SelectContent>
</Select>
<div className="text-sm text-vscode-descriptionForeground mt-1">
Selected endpoint: {REGION_TO_URL[selectedRegion as keyof typeof REGION_TO_URL]}
</div>
</>
</div>
)}
{/* IBM Cloud Pak for Data specific fields */}
{apiConfiguration.watsonxPlatform === "cloudPak" && (
<>
<div className="w-full mb-1">
<VSCodeTextField
value={apiConfiguration.watsonxBaseUrl}
onInput={handleInputChange("watsonxBaseUrl")}
@ -297,13 +295,13 @@ export const WatsonxAI = ({
className="w-full">
<label className="block font-medium mb-1">URL</label>
</VSCodeTextField>
<div className="text-sm text-vscode-descriptionForeground -mt-2 mb-4">
<div className="text-sm text-vscode-descriptionForeground mt-1">
Enter the full URL of your IBM Cloud Pak for Data instance
</div>
</>
</div>
)}
<div className="w-full mb-4">
<div className="w-full mb-1">
<VSCodeTextField
value={apiConfiguration?.watsonxProjectId || ""}
onInput={handleInputChange("watsonxProjectId")}
@ -314,7 +312,7 @@ export const WatsonxAI = ({
</div>
{apiConfiguration.watsonxPlatform === "ibmCloud" && (
<>
<div className="w-full mb-1">
<VSCodeTextField
value={apiConfiguration?.watsonxApiKey || ""}
type="password"
@ -323,23 +321,25 @@ export const WatsonxAI = ({
className="w-full">
<label className="block font-medium mb-1">API Key</label>
</VSCodeTextField>
<div className="text-sm text-vscode-descriptionForeground -mt-2">
<div className="text-sm text-vscode-descriptionForeground mt-1">
{t("settings:providers.apiKeyStorageNotice")}
</div>
</>
</div>
)}
{apiConfiguration.watsonxPlatform === "cloudPak" && (
<>
<VSCodeTextField
value={apiConfiguration.watsonxUsername ? apiConfiguration.watsonxUsername : ""}
onInput={handleInputChange("watsonxUsername")}
placeholder="Username"
className="w-full">
<label className="block font-medium mb-1">Username</label>
</VSCodeTextField>
<div className="w-full mb-1">
<VSCodeTextField
value={apiConfiguration.watsonxUsername ? apiConfiguration.watsonxUsername : ""}
onInput={handleInputChange("watsonxUsername")}
placeholder="Username"
className="w-full">
<label className="block font-medium mb-1">Username</label>
</VSCodeTextField>
</div>
<div className="w-full mt-4">
<div className="w-full mb-1">
<label className="block font-medium mb-1">Authentication Type</label>
<Select
value={apiConfiguration.watsonxAuthType}
@ -355,38 +355,38 @@ export const WatsonxAI = ({
</div>
{apiConfiguration.watsonxAuthType === "apiKey" ? (
<>
<div className="w-full mb-1">
<VSCodeTextField
value={apiConfiguration?.watsonxApiKey || ""}
type="password"
onInput={handleInputChange("watsonxApiKey")}
placeholder="API Key"
className="w-full mt-4">
className="w-full">
<label className="block font-medium mb-1">API Key</label>
</VSCodeTextField>
<div className="text-sm text-vscode-descriptionForeground -mt-2">
<div className="text-sm text-vscode-descriptionForeground mt-1">
{t("settings:providers.apiKeyStorageNotice")}
</div>
</>
</div>
) : (
<>
<div className="w-full mb-1">
<VSCodeTextField
value={apiConfiguration.watsonxPassword}
type="password"
onInput={handleInputChange("watsonxPassword")}
placeholder="Password"
className="w-full mt-4">
className="w-full">
<label className="block font-medium mb-1">Password</label>
</VSCodeTextField>
<div className="text-sm text-vscode-descriptionForeground -mt-2">
<div className="text-sm text-vscode-descriptionForeground mt-1">
{t("settings:providers.passwordStorageNotice")}
</div>
</>
</div>
)}
</>
)}
<div className="w-full mb-4">
<div className="w-full mb-">
<Button
variant="outline"
onClick={() => {
@ -402,7 +402,7 @@ export const WatsonxAI = ({
(apiConfiguration.watsonxAuthType === "apiKey" && !apiConfiguration.watsonxApiKey) ||
(apiConfiguration.watsonxAuthType === "password" && !apiConfiguration.watsonxPassword)))
}
className="w-full mt-4"
className="w-full md-1"
title={"Retrieve available models"}>
<div className="flex items-center gap-2">
{refreshStatus === "loading" ? (
@ -416,15 +416,17 @@ export const WatsonxAI = ({
</div>
{refreshStatus === "loading" && (
<div className="text-sm text-vscode-descriptionForeground">
<div className="text-sm text-vscode-descriptionForeground mb-1">
{t("settings:providers.refreshModels.loading")}
</div>
)}
{refreshStatus === "success" && (
<div className="text-sm text-vscode-foreground">{"Models retrieved successfully"}</div>
<div className="text-sm text-vscode-foreground mb-1">{"Models retrieved successfully"}</div>
)}
{refreshStatus === "error" && (
<div className="text-sm text-vscode-errorForeground">{refreshError || "Failed to retrieve models"}</div>
<div className="text-sm text-vscode-errorForeground mb-1">
{refreshError || "Failed to retrieve models"}
</div>
)}
<ModelPicker