From eb5a8e94c6907d214d72827fcb42fed54de84f28 Mon Sep 17 00:00:00 2001 From: bebiksior Date: Tue, 27 Oct 2026 16:50:25 +0100 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=93=9D=20Update=20AI=20integration=20?= =?UTF-8?q?docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/guides/ai.md | 275 +++++++-- src/plugins/reference/sdks/frontend/ai.md | 692 +++++++++++++++++++++- 2 files changed, 883 insertions(+), 84 deletions(-) diff --git a/src/plugins/guides/ai.md b/src/plugins/guides/ai.md index 7e09f5a..c0d5bed 100644 --- a/src/plugins/guides/ai.md +++ b/src/plugins/guides/ai.md @@ -1,93 +1,172 @@ # Use AI in Your Plugin -You can integrate AI capabilities into your plugin using Caido's AI provider, which is compatible with the [ai](https://ai-sdk.dev/) library. +Frontend plugins can call the AI providers the user configured in Caido through `sdk.ai`. Requests go through the Caido backend with the user's credentials, so your plugin never handles API keys. -## Creating an AI Provider +## Installing the AI SDK -To create an AI provider instance: +`sdk.ai.createProvider()` returns a provider for the [AI SDK](https://ai-sdk.dev/) v6. Install `ai` to call it, and `@ai-sdk/provider`, which the `@caido/sdk-frontend` types depend on: + +```bash +pnpm add ai @ai-sdk/provider +``` + +## Checking That AI Is Configured + +`sdk.ai.getUpstreamProviders()` only returns the providers the user has configured, so an empty array means AI is not set up: ```ts -const provider = sdk.ai.createProvider(); +if (sdk.ai.getUpstreamProviders().length === 0) { + sdk.window.showToast("Configure an AI provider in Caido's settings first.", { + variant: "warning", + }); +} ``` -This returns an `AIProvider` instance that can be used with the `ai` library. +Caido's built-in providers have a fixed `id`: `"openai"`, `"anthropic"`, `"google"`, `"xai"`, `"openrouter"` and `"bedrock"`, plus `"chatgpt"` and `"grok"` when signed in with OAuth. Users can also add custom providers, such as a self-hosted gateway or a local model, whose `id` is the alias the user chose. `authentication` reports whether the stored credentials work. See [AIUpstreamProvider](/plugins/reference/sdks/frontend/ai.md#aiupstreamprovider) for all properties. -## Getting Upstream Providers +## Choosing a Model -To get information about available AI upstream providers and their configuration status: +`sdk.ai.getUpstreamModels()` returns the models listed in **Settings → AI → Models**. Pass `providerId` to only get the models of one provider: ```ts -const providers = sdk.ai.getUpstreamProviders(); +const models = sdk.ai.getUpstreamModels({ providerId: "openai" }); ``` -This returns an array of `AIUpstreamProvider` objects, each containing: +A model's `modelId` has the form `"/"`. -- `id` - The provider ID (`"openai"`, `"anthropic"`, `"google"`, or `"openrouter"`) -- `status` - The configuration status (`"Ready"` or `"Missing"`) +A model's `support` object reports `toolCalling`, `reasoning`, `structuredOutput`, `temperature` and `compaction` as `"SUPPORTED"`, `"UNSUPPORTED"` or `"UNKNOWN"`. `reasoningEfforts` lists the accepted reasoning efforts. See [AIUpstreamModel](/plugins/reference/sdks/frontend/ai.md#aiupstreammodel) for all properties. -This is useful for checking which AI providers are configured before attempting to use them: +To get notified when models change, subscribe with `sdk.ai.onUpstreamModelsChange()`: ```ts -const providers = sdk.ai.getUpstreamProviders(); -const openaiProvider = providers.find((p) => p.id === "openai"); +const handle = sdk.ai.onUpstreamModelsChange((models) => { + renderModelPicker(models); +}); -if (openaiProvider?.status === "Ready") { - // OpenAI is configured and ready to use - const provider = sdk.ai.createProvider(); - // Use the provider... -} else { - sdk.window.showToast("OpenAI is not configured", { variant: "warning" }); -} +handle.stop(); ``` -::: tip -The AI provider is compatible with all features of the `ai` library, including text generation, streaming, tool calling, and more. Refer to the [ai SDK documentation](https://ai-sdk.dev/) for advanced usage. -::: +## Generating Text -::: info -The AI provider uses Caido's configured AI settings. Users can configure their AI provider preferences in Caido's settings. -::: +Call the provider with a model ID to get an AI SDK language model, then pass it to `generateText` or `streamText`: -::: warning -AI operations can be resource-intensive and may have rate limits. Consider implementing error handling and user feedback for long-running AI operations. -::: +```ts +import { generateText } from "ai"; -## Examples +const provider = sdk.ai.createProvider(); + +const { text } = await generateText({ + model: provider("openai/gpt-5.5"), + prompt: "Explain what HTTP is in one sentence.", +}); +``` -### Basic AI Integration +Only language models are supported. To cancel a request or stream, pass an `abortSignal`. -This example demonstrates the basic setup for using AI in your plugin. It creates an AI provider, uses it with the `ai` library to generate text from a prompt, and logs the response. +## Configuring Reasoning and Structured Output -First, install the `ai` package: +Pass model settings as the second argument: -```bash -npm install ai +```ts +const model = provider("anthropic/claude-sonnet-4-6", { + reasoning: { kind: "effort", effort: "high", output: "include" }, + parallelToolCalls: true, + structuredOutput: { strict: true }, +}); ``` -Then use the provider in your plugin: +`reasoning` can also be `{ kind: "budget", tokens }` or `{ kind: "disabled" }`, and `output: "omit"` leaves the reasoning text out of the response. + +Strict structured output requires every property to be listed in `required` and `additionalProperties: false` on every object. + +See [AILanguageModelSettings](/plugins/reference/sdks/frontend/ai.md#ailanguagemodelsettings) for all options. + +## Compacting Long Conversations + +OpenAI, ChatGPT and Anthropic models, including Anthropic models on Amazon Bedrock, support native compaction: once the input passes `triggerInputTokens`, the provider summarizes the conversation so far and continues from the summary. Check `support.compaction` on the model first, since a request with `compaction` fails on models that do not support it. + +The summary is returned as a reasoning part with `providerMetadata.caido.compaction`. Send it back with the rest of the conversation on the next request, and the provider skips everything before it: ```ts -import type { Caido } from "@caido/sdk-frontend"; +import type { ModelMessage } from "ai"; import { generateText } from "ai"; -export type CaidoSDK = Caido; +const messages: ModelMessage[] = []; -export const init = async (sdk: CaidoSDK) => { - const provider = sdk.ai.createProvider(); +const ask = async (prompt: string) => { + messages.push({ role: "user", content: prompt }); - // Use with the ai library - const { text } = await generateText({ - model: provider, - prompt: "Explain what HTTP is in one sentence.", + const result = await generateText({ + model: provider("anthropic/claude-sonnet-4-6", { + compaction: { triggerInputTokens: 100_000 }, + }), + messages, }); - sdk.log.info("AI Response:", text); + messages.push(...result.response.messages); + return result.text; }; ``` -### AI-Powered Code Generation +On Anthropic, `instructions` replaces the default summary prompt, and `pauseAfterCompaction` ends the turn right after compacting, with `providerMetadata.caido.finishReason` set to `"paused"`. OpenAI ignores both. + +## Passing Provider-Specific Options + +Call-level `providerOptions` are forwarded to the Caido backend, keyed by the names of the provider's own API: + +```ts +await generateText({ + model: provider("openai/gpt-5.5"), + prompt: "Summarize this request.", + providerOptions: { + openai: { service_tier: "priority" }, + }, +}); +``` + +`providerOptions` on user text parts, tool result parts and assistant content are also forwarded, so an Anthropic cache breakpoint is `{ anthropic: { cache_control: { type: "ephemeral" } } }`. + +## Avoiding Unsupported Features + +The following throw an `UnsupportedFunctionalityError` before any request is sent: -This example registers a command that uses AI to generate Caido plugin code based on a user's description. The command prompts for a description, generates code using AI, and logs the result. +- File parts in user or assistant messages. +- Provider-defined tools, tool input examples and provider-executed tool calls. +- Tool results in assistant messages, multipart (`content`) tool results, `execution-denied` tool results and tool approval responses. +- JSON responses without a schema (`responseFormat: { type: "json" }`). + +## Handling Errors + +By default, Caido shows an error toast when an AI request fails. Pass `notifyErrors: false` if your plugin reports failures itself: + +```ts +const provider = sdk.ai.createProvider({ notifyErrors: false }); +``` + +A failed request throws an AI SDK `APICallError`, or a `RetryError` wrapping it once retries are exhausted. If the request reached the Caido backend, the error's `data` is an [AIError](/plugins/reference/sdks/frontend/ai.md#aierror) with a `kind` and a `message`. Upstream failures have `kind: "provider"` and a `providerError` such as `{ kind: "rate-limited" }`. + +`getAIError(error)` reads the `AIError` from either error type, and returns `undefined` for failures that never reached the backend: + +```ts +import { getAIError } from "@caido/sdk-frontend"; + +try { + await generateText({ model: provider(modelId), prompt }); +} catch (error) { + const aiError = getAIError(error); + if (aiError?.providerError?.kind === "rate-limited") { + sdk.window.showToast("Rate limited, try again later.", { variant: "warning" }); + } else { + sdk.window.showToast(aiError?.message ?? String(error), { variant: "error" }); + } +} +``` + +## Examples + +### Summarizing a Request With the First Available Model + +This example registers a command that picks the first configured model and asks it to summarize a request, showing a toast when no AI provider is configured. ```ts import type { Caido } from "@caido/sdk-frontend"; @@ -95,30 +174,102 @@ import { generateText } from "ai"; export type CaidoSDK = Caido; -const generateCode = async (sdk: CaidoSDK, description: string): Promise => { - const provider = sdk.ai.createProvider(); +const summarize = async (sdk: CaidoSDK, raw: string) => { + const [model] = sdk.ai.getUpstreamModels(); + if (model === undefined) { + sdk.window.showToast("Configure an AI provider in Caido's settings first.", { + variant: "warning", + }); + return; + } + const provider = sdk.ai.createProvider(); const { text } = await generateText({ - model: provider, - prompt: `Generate a Caido plugin code snippet that: ${description}`, + model: provider(model.modelId), + system: "You are a web security assistant. Be concise.", + prompt: `Summarize what this HTTP request does:\n\n${raw}`, }); - return text; + sdk.log.info(text); }; export const init = (sdk: CaidoSDK) => { - sdk.commands.register("ai-generate-code", { - name: "AI: Generate Code", - run: async () => { - const description = prompt("What should the code do?"); - if (description) { - const code = await generateCode(sdk, description); - sdk.window.showToast("Code generated! Check console.", { variant: "success" }); - sdk.log.info("Generated code:", code); + sdk.commands.register("ai-summarize-request", { + name: "AI: Summarize Request", + run: async (context) => { + if (context.type === "RequestContext") { + await summarize(sdk, context.request.raw); } }, }); - sdk.commandPalette.register("ai-generate-code"); + sdk.commandPalette.register("ai-summarize-request"); +}; +``` + +### Streaming a Response + +This example streams a response token by token and cancels it after 30 seconds. Errors are reported by the `onError` callback instead of the default toast. + +```ts +import type { AIModelId, Caido } from "@caido/sdk-frontend"; +import { streamText } from "ai"; + +export type CaidoSDK = Caido; + +export const streamAnswer = async (sdk: CaidoSDK, modelId: AIModelId, prompt: string) => { + const provider = sdk.ai.createProvider({ notifyErrors: false }); + + const result = streamText({ + model: provider(modelId), + prompt, + abortSignal: AbortSignal.timeout(30_000), + onError: ({ error }) => { + sdk.log.error("AI request failed", error); + }, + }); + + let answer = ""; + for await (const chunk of result.textStream) { + answer += chunk; + } + return answer; +}; +``` + +### Generating Structured Output + +This example asks a model for a JSON object that matches a schema, using the AI SDK's `Output.object()`. It enables strict mode only when the model reports structured output support. + +```ts +import type { AIUpstreamModel, Caido } from "@caido/sdk-frontend"; +import { generateText, jsonSchema, Output } from "ai"; + +export type CaidoSDK = Caido; + +type Classification = { category: string; risky: boolean }; + +export const classify = async (sdk: CaidoSDK, model: AIUpstreamModel, raw: string) => { + const provider = sdk.ai.createProvider(); + + const { output } = await generateText({ + model: provider(model.modelId, { + structuredOutput: { strict: model.support.structuredOutput === "SUPPORTED" }, + }), + output: Output.object({ + schema: jsonSchema({ + type: "object", + properties: { + category: { type: "string" }, + risky: { type: "boolean" }, + }, + required: ["category", "risky"], + additionalProperties: false, + }), + }), + prompt: `Classify this HTTP request:\n\n${raw}`, + }); + + return output; }; ``` diff --git a/src/plugins/reference/sdks/frontend/ai.md b/src/plugins/reference/sdks/frontend/ai.md index fe6de89..03a9b69 100644 --- a/src/plugins/reference/sdks/frontend/ai.md +++ b/src/plugins/reference/sdks/frontend/ai.md @@ -1,5 +1,157 @@ # AI +### AICompactionSettings + +> **AICompactionSettings** = `object` + +Settings for native context compaction. + +The summary is returned as a reasoning part with +`providerMetadata.caido.compaction`. + +#### Properties + +##### instructions? + +> `optional` **instructions**: `string` + +Custom summarization instructions. Ignored by OpenAI. + +##### pauseAfterCompaction? + +> `optional` **pauseAfterCompaction**: `boolean` + +End the turn after compacting. Ignored by OpenAI. + +###### Default + +```ts +false +``` + +##### triggerInputTokens? + +> `optional` **triggerInputTokens**: `number` + +Input-token threshold that triggers compaction. Defaults to the provider threshold. + +*** + +### AICreateProviderOptions + +> **AICreateProviderOptions** = `object` + +Options for [AiSDK.createProvider](#createprovider). + +#### Properties + +##### notifyErrors? + +> `optional` **notifyErrors**: `boolean` + +Whether Caido shows a toast when a request fails. + +Set to `false` when the plugin reports failures itself, for example with +[getAIError](#getaierror). + +###### Default + +```ts +true +``` + +*** + +### AIError + +> **AIError** = `object` + +Normalized details of a failed AI request. + +Attached as `data` to the AI SDK `APICallError` of a failed request, for +both `/ai/completion` and `/ai/stream`. Use [getAIError](#getaierror) to read it +from an unknown error. + +#### Properties + +##### code? + +> `optional` **code**: `string` + +The provider-specific error code, when the provider reported one. + +##### kind + +> **kind**: [`AIErrorKind`](#aierrorkind) + +The kind of failure. + +##### message + +> **message**: `string` + +The failure message. + +##### providerError? + +> `optional` **providerError**: [`AIProviderError`](#aiprovidererror) + +The upstream provider failure, present when `kind` is `provider`. + +##### retryable? + +> `optional` **retryable**: `boolean` + +Whether retrying the same request may succeed. + +##### retryAfterMs? + +> `optional` **retryAfterMs**: `number` + +The delay suggested by the provider before retrying, in milliseconds. + +##### status? + +> `optional` **status**: `number` + +The HTTP status of the failure: the provider status when the provider +reported one, otherwise the Caido backend response status. + +*** + +### AIErrorKind + +> **AIErrorKind** = `"provider-not-configured"` \| `"invalid-request"` \| `"authorization"` \| `"provider"` \| `"internal"` + +The kind of a failed AI request, as reported by the Caido backend. + +- `provider-not-configured`: the alias of the model id matches no + configured provider. +- `invalid-request`: the backend rejected the request payload. +- `authorization`: the Caido session is not allowed to use AI. +- `provider`: the upstream provider request failed, see + [AIError.providerError](#providererror). +- `internal`: the backend failed unexpectedly. + +*** + +### AIGetUpstreamModelsOptions + +> **AIGetUpstreamModelsOptions** = `object` + +Options for [AiSDK.getUpstreamModels](#getupstreammodels). + +#### Properties + +##### providerId? + +> `optional` **providerId**: [`AIUpstreamProviderId`](#aiupstreamproviderid) + +Only return models of this provider (the provider alias, see +[AIUpstreamProvider.id](#id-1)). + +*** + ### AILanguageModelSettings > **AILanguageModelSettings** = `object` @@ -8,44 +160,230 @@ Settings for AI language model. #### Properties -##### capabilities? - -> `optional` **capabilities**: `object` +##### compaction? -###### reasoning +> `optional` **compaction**: [`AICompactionSettings`](#aicompactionsettings) -> **reasoning**: `boolean` +##### parallelToolCalls? -###### structured\_output - -> **structured\_output**: `boolean` +> `optional` **parallelToolCalls**: `boolean` ##### reasoning? > `optional` **reasoning**: [`AIReasoningSettings`](#aireasoningsettings) +##### structuredOutput? + +> `optional` **structuredOutput**: [`AIStructuredOutputSettings`](#aistructuredoutputsettings) + +*** + +### AIModelId + +> **AIModelId** = `` `${string}/${string}` `` + +AI model identifier in the form `"/"`. + +The alias is everything before the first `/` and must match the `id` of a +configured upstream provider (see [AIUpstreamProvider](#aiupstreamprovider)). Everything +after it is sent to that provider as the model name, so ids with their own +slashes such as `openrouter/anthropic/claude-sonnet-4.6` work as expected. + *** ### AIProvider -> **AIProvider** = `ProviderV3` & (`modelId`: `string`, `settings?`: [`AILanguageModelSettings`](#ailanguagemodelsettings)) => `LanguageModelV3` +> **AIProvider** = `Omit`\<`ProviderV3`, `"languageModel"`\> & `object` & (`modelId`: [`AIModelId`](#aimodelid), `settings?`: [`AILanguageModelSettings`](#ailanguagemodelsettings)) => `LanguageModelV3` Official AI Provider to be used by the [ai](https://ai-sdk.dev/) library. +Only language models are supported: `imageModel` and `embeddingModel` +throw an AI SDK `NoSuchModelError`. + +The following AI SDK features are not supported by language models and +throw an `UnsupportedFunctionalityError` before any request is sent: +- file parts in user or assistant messages +- provider-defined tools, tool input examples, and provider-executed tool + calls +- tool results in assistant messages, multipart (`content`) tool results, + `execution-denied` tool results, and tool approval responses +- `responseFormat: { type: "json" }` without a schema +- the reserved `caido` namespace in call-level `providerOptions` + +`providerOptions` on user text parts, tool result parts, and assistant +content are sent to the backend unchanged, apart from the reserved `caido` +namespace. Keys use the backend names, so an Anthropic cache breakpoint is +`{ anthropic: { cache_control: { type: "ephemeral" } } }`. + +`providerOptions` on system, user, and tool messages, on tool definitions, +and on tool result outputs are dropped with a warning because the backend +has no slot for them. Provider tool results returned by the provider are +dropped from the response (and surfaced as `raw` stream parts when +`includeRawChunks` is set). + +A paused turn (for example after [AICompactionSettings.pauseAfterCompaction](#pauseaftercompaction)) +finishes with the `other` finish reason and +`providerMetadata.caido.finishReason` set to `"paused"`. + +`abortSignal` cancels the request or the running stream; the resulting +`AbortError` is rethrown unchanged and never reported as a failure. +Tool input streaming (`tool-input-start`, `tool-input-delta`, +`tool-input-end`) is supported. + +#### Type Declaration + +##### languageModel() + +> **languageModel**: (`modelId`: [`AIModelId`](#aimodelid), `settings?`: [`AILanguageModelSettings`](#ailanguagemodelsettings)) => `LanguageModelV3` + +###### Parameters + +| Parameter | Type | +| ------ | ------ | +| `modelId` | [`AIModelId`](#aimodelid) | +| `settings?` | [`AILanguageModelSettings`](#ailanguagemodelsettings) | + +###### Returns + +`LanguageModelV3` + +*** + +### AIProviderError + +> **AIProviderError** = `object` + +Details of an upstream provider failure. + +#### Properties + +##### code? + +> `optional` **code**: `string` + +The provider-specific error code. + +##### kind + +> **kind**: [`AIProviderErrorKind`](#aiprovidererrorkind) + +The kind of failure. + +##### message + +> **message**: `string` + +The failure message. + +##### model? + +> `optional` **model**: `string` + +The model that was requested. + +##### origin? + +> `optional` **origin**: `string` + +The provider API profile that produced the failure. + +##### requestId? + +> `optional` **requestId**: `string` + +The provider request id, useful when contacting provider support. + +##### retryable + +> **retryable**: `boolean` + +Whether retrying the same request may succeed. + +##### retryAfterMs? + +> `optional` **retryAfterMs**: `number` + +The delay suggested by the provider before retrying, in milliseconds. + +##### status? + +> `optional` **status**: `number` + +The HTTP status returned by the provider. + +*** + +### AIProviderErrorKind + +> **AIProviderErrorKind** = `"configuration"` \| `"invalid-request"` \| `"unsupported-capability"` \| `"unsupported-content"` \| `"authentication"` \| `"permission"` \| `"content-policy"` \| `"not-found"` \| `"rate-limited"` \| `"overloaded"` \| `"context-length"` \| `"transport"` \| `"timeout"` \| `"malformed-response"` \| `"truncated-stream"` \| `"provider"` + +The kind of an upstream provider failure. + +*** + +### AIReasoningOutput + +> **AIReasoningOutput** = `"include"` \| `"omit"` + +Controls whether reasoning content is included in the response. + *** ### AIReasoningSettings -> **AIReasoningSettings** = `object` +> **AIReasoningSettings** = \{ `kind`: `"disabled"`; \} \| \{ `effort`: [`AIUpstreamModelReasoningEffort`](#aiupstreammodelreasoningeffort); `kind`: `"effort"`; `output?`: [`AIReasoningOutput`](#aireasoningoutput); \} \| \{ `kind`: `"budget"`; `output?`: [`AIReasoningOutput`](#aireasoningoutput); `tokens`: `number`; \} \| \{ `effort`: `"low"` \| `"medium"` \| `"high"`; `kind?`: `undefined`; \} Settings for AI reasoning. -#### Properties +The legacy untagged shape `{ effort }` is still accepted and treated as +`{ kind: "effort", effort }`. + +#### Type Declaration + +\{ `kind`: `"disabled"`; \} + +##### kind + +> **kind**: `"disabled"` + +\{ `effort`: [`AIUpstreamModelReasoningEffort`](#aiupstreammodelreasoningeffort); `kind`: `"effort"`; `output?`: [`AIReasoningOutput`](#aireasoningoutput); \} + +##### effort + +> **effort**: [`AIUpstreamModelReasoningEffort`](#aiupstreammodelreasoningeffort) + +##### kind + +> **kind**: `"effort"` + +##### output? + +> `optional` **output**: [`AIReasoningOutput`](#aireasoningoutput) + +\{ `kind`: `"budget"`; `output?`: [`AIReasoningOutput`](#aireasoningoutput); `tokens`: `number`; \} + +##### kind + +> **kind**: `"budget"` + +##### output? + +> `optional` **output**: [`AIReasoningOutput`](#aireasoningoutput) + +##### tokens + +> **tokens**: `number` + +\{ `effort`: `"low"` \| `"medium"` \| `"high"`; `kind?`: `undefined`; \} ##### effort > **effort**: `"low"` \| `"medium"` \| `"high"` +##### kind? + +> `optional` **kind**: `undefined` + *** ### AiSDK @@ -58,27 +396,232 @@ Utilities to interact with AI. ##### createProvider() -> **createProvider**: () => [`AIProvider`](#aiprovider) +> **createProvider**: (`options?`: [`AICreateProviderOptions`](#aicreateprovideroptions)) => [`AIProvider`](#aiprovider) Creates a new AI provider instance that can be used with the [ai](https://ai-sdk.dev/) library. +Models are addressed as `"/"`, see [AIModelId](#aimodelid). +Failed requests surface as an AI SDK `APICallError`, wrapped in a +`RetryError` when the AI SDK retried it; use [getAIError](#getaierror) to read +the normalized [AIError](#aierror) details from either. + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`AICreateProviderOptions`](#aicreateprovideroptions) | Provider options. | + ###### Returns [`AIProvider`](#aiprovider) A provider instance compatible with the [ai](https://ai-sdk.dev/) library. +##### getUpstreamModels() + +> **getUpstreamModels**: (`options?`: [`AIGetUpstreamModelsOptions`](#aigetupstreammodelsoptions)) => [`AIUpstreamModel`](#aiupstreammodel)[] + +Gets the models of the configured upstream AI providers, as managed in +Settings → AI → Models (catalog models plus user-defined ones). + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `options?` | [`AIGetUpstreamModelsOptions`](#aigetupstreammodelsoptions) | Optional provider filter. | + +###### Returns + +[`AIUpstreamModel`](#aiupstreammodel)[] + +An array of upstream models. + ##### getUpstreamProviders() > **getUpstreamProviders**: () => [`AIUpstreamProvider`](#aiupstreamprovider)[] -Gets the list of upstream AI providers with their configuration status. +Gets the list of configured upstream AI providers. ###### Returns [`AIUpstreamProvider`](#aiupstreamprovider)[] -An array of AI upstream providers with their configuration status. +An array of configured AI upstream providers. + +##### onUpstreamModelsChange() + +> **onUpstreamModelsChange**: (`callback`: (`models`: [`AIUpstreamModel`](#aiupstreammodel)[]) => `void`) => [`ListenerHandle`](utils.md#listenerhandle) + +Registers a callback invoked whenever the upstream model list changes +(user edits, provider added or removed). + +###### Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `callback` | (`models`: [`AIUpstreamModel`](#aiupstreammodel)[]) => `void` | Receives the current list of upstream models. | + +###### Returns + +[`ListenerHandle`](utils.md#listenerhandle) + +A handle to stop listening. + +*** + +### AIStructuredOutputSettings + +> **AIStructuredOutputSettings** = `object` + +Settings for structured output (`responseFormat: { type: "json" }`). + +#### Properties + +##### strict? + +> `optional` **strict**: `boolean` + +Whether the provider must follow the response schema exactly. + +Strict mode requires a schema compatible with the provider's strict +subset: every property listed in `required` and +`additionalProperties: false` on every object. + +###### Default + +```ts +false +``` + +*** + +### AIUpstreamModel + +> **AIUpstreamModel** = `object` + +A model available on a configured upstream AI provider, as managed in +Settings → AI → Models. + +#### Properties + +##### capabilities + +> **capabilities**: [`AIUpstreamModelCapability`](#aiupstreammodelcapability)[] + +The capabilities known to be supported. + +Absence means unsupported OR unknown; check [support](#support) to tell the +two apart. + +##### contextWindow? + +> `optional` **contextWindow**: `number` + +The context window in tokens, when known. + +##### displayName + +> **displayName**: `string` + +##### id + +> **id**: `string` + +The model name without the provider prefix. May itself contain `/`, for +example OpenRouter ids such as `anthropic/claude-sonnet-4.6`. + +##### modelId + +> **modelId**: [`AIModelId`](#aimodelid) + +Ready-made id for [AIProvider.languageModel](#aiprovider): `` `${providerId}/${id}` ``. + +##### outputTokenLimit? + +> `optional` **outputTokenLimit**: `number` + +The maximum output tokens, when known. + +##### providerId + +> **providerId**: [`AIUpstreamProviderId`](#aiupstreamproviderid) + +The alias of the provider serving this model; matches [AIUpstreamProvider.id](#id-1). + +##### reasoningEfforts + +> **reasoningEfforts**: [`AIUpstreamModelReasoningEffort`](#aiupstreammodelreasoningeffort)[] + +The accepted reasoning efforts. Empty when the model declares no constraint. + +##### source + +> **source**: [`AIUpstreamModelSource`](#aiupstreammodelsource) + +##### support + +> **support**: `object` + +Tri-state knowledge for every capability. + +###### compaction + +> **compaction**: [`AIUpstreamModelCapabilitySupport`](#aiupstreammodelcapabilitysupport) + +###### reasoning + +> **reasoning**: [`AIUpstreamModelCapabilitySupport`](#aiupstreammodelcapabilitysupport) + +###### structuredOutput + +> **structuredOutput**: [`AIUpstreamModelCapabilitySupport`](#aiupstreammodelcapabilitysupport) + +###### temperature + +> **temperature**: [`AIUpstreamModelCapabilitySupport`](#aiupstreammodelcapabilitysupport) + +###### toolCalling + +> **toolCalling**: [`AIUpstreamModelCapabilitySupport`](#aiupstreammodelcapabilitysupport) + +*** + +### AIUpstreamModelCapability + +> **AIUpstreamModelCapability** = `"TOOL_CALLING"` \| `"REASONING"` \| `"STRUCTURED_OUTPUT"` \| `"TEMPERATURE"` \| `"COMPACTION"` + +A capability an upstream model is known to support. + +*** + +### AIUpstreamModelCapabilitySupport + +> **AIUpstreamModelCapabilitySupport** = `"SUPPORTED"` \| `"UNSUPPORTED"` \| `"UNKNOWN"` + +Tri-state capability knowledge for an upstream model. + +Caido is permissive: `UNKNOWN` capabilities are still sent to the provider, +only `UNSUPPORTED` ones are constrained. + +*** + +### AIUpstreamModelReasoningEffort + +> **AIUpstreamModelReasoningEffort** = `"minimal"` \| `"low"` \| `"medium"` \| `"high"` \| `"xhigh"` \| `"max"` + +A reasoning effort accepted by an upstream model, from least to most. + +*** + +### AIUpstreamModelSource + +> **AIUpstreamModelSource** = `"CATALOG"` \| `"CUSTOM"` + +Where an upstream model comes from. + +- `CATALOG`: from Caido's model catalog. +- `CUSTOM`: user-defined in Settings → AI → Models, replacing the catalog + model of the same id. *** @@ -87,31 +630,136 @@ An array of AI upstream providers with their configuration status. > **AIUpstreamProvider** = `object` AI upstream provider information. +Only configured providers are returned. #### Properties +##### api + +> **api**: [`AIUpstreamProviderApi`](#aiupstreamproviderapi) + +The response API the provider speaks. + +##### auth + +> **auth**: [`AIUpstreamProviderAuth`](#aiupstreamproviderauth) + +How the provider authenticates. + +##### authentication + +> **authentication**: [`AIUpstreamProviderAuthentication`](#aiupstreamproviderauthentication) + +Whether the stored credentials are currently usable. + ##### id > **id**: [`AIUpstreamProviderId`](#aiupstreamproviderid) -##### status +The provider alias, used before the first `/` of an [AIModelId](#aimodelid). -> **status**: [`AIUpstreamProviderStatus`](#aiupstreamproviderstatus) +##### kind + +> **kind**: [`AIUpstreamProviderKind`](#aiupstreamproviderkind) + +The provider kind. + +*** + +### AIUpstreamProviderApi + +> **AIUpstreamProviderApi** = `"ANTHROPIC"` \| `"BEDROCK"` \| `"CHATGPT_RESPONSE"` \| `"GEMINI"` \| `"OPENAI_COMPLETION"` \| `"OPENAI_RESPONSE"` \| `"OPENROUTER"` \| `"XAI_COMPLETION"` \| `"XAI_RESPONSE"` + +The response API a provider speaks. + +*** + +### AIUpstreamProviderAuth + +> **AIUpstreamProviderAuth** = `"API_KEY"` \| `"OAUTH"` \| `"AWS"` \| `"NONE"` + +How a configured upstream provider authenticates. + +- `API_KEY`: the user stored an API key. +- `OAUTH`: the user signed in with a subscription account. +- `AWS`: requests are signed with AWS credentials, from a stored key pair + or an AWS profile on the machine running Caido. +- `NONE`: no credentials are stored (for example a local endpoint). + +*** + +### AIUpstreamProviderAuthentication + +> **AIUpstreamProviderAuthentication** = `"VALID"` \| `"UNVERIFIED"` \| `"INVALID"` + +Whether the stored credentials of a configured upstream provider are +currently usable. + +- `VALID`: the last request or sign-in succeeded. +- `UNVERIFIED`: the credentials have not been used yet. +- `INVALID`: the backend saw the credentials rejected. It flips back to + `VALID` after the next successful request or sign-in. *** ### AIUpstreamProviderId -> **AIUpstreamProviderId** = `"anthropic"` \| `"google"` \| `"openai"` \| `"openrouter"` +> **AIUpstreamProviderId** = `string` AI upstream provider ID. *** -### AIUpstreamProviderStatus +### AIUpstreamProviderKind + +> **AIUpstreamProviderKind** = `"ANTHROPIC"` \| `"BEDROCK"` \| `"CHATGPT"` \| `"CUSTOM"` \| `"GEMINI"` \| `"OPENAI"` \| `"OPENROUTER"` \| `"XAI"` + +The kind of a configured upstream provider. + +`CUSTOM` providers are user-defined endpoints; every other kind is one of +the providers Caido offers directly. + +*** + +### createAIModelId() + +> `const` **createAIModelId**: (`providerId`: [`AIUpstreamProviderId`](#aiupstreamproviderid), `modelId`: `string`) => [`AIModelId`](#aimodelid) + +Builds an [AIModelId](#aimodelid) from a provider alias and a model name. + +#### Parameters + +| Parameter | Type | +| ------ | ------ | +| `providerId` | [`AIUpstreamProviderId`](#aiupstreamproviderid) | +| `modelId` | `string` | + +#### Returns + +[`AIModelId`](#aimodelid) + +*** + +### getAIError() + +> `const` **getAIError**: (`error`: `unknown`) => [`AIError`](#aierror) \| `undefined` + +Reads the normalized [AIError](#aierror) of a failed AI request. + +Accepts the error thrown by `generateText` or passed to the `onError` +callback / `error` stream part of `streamText`: an AI SDK `APICallError`, or +the `RetryError` wrapping it once retries are exhausted, in which case the +last attempt's error is read. + +Failures that never reached the Caido backend (for example a network +error) carry no `data`, so this returns `undefined` for them. + +#### Parameters + +| Parameter | Type | +| ------ | ------ | +| `error` | `unknown` | -> **AIUpstreamProviderStatus** = `"Ready"` \| `"Missing"` +#### Returns -AI upstream provider status. -Ready: The upstream provider is ready to use. -Missing: The upstream provider is not configured. +[`AIError`](#aierror) \| `undefined` From 2e0be83f8b9ee7815eabfeaa42f3427a75ed7d11 Mon Sep 17 00:00:00 2001 From: bebiksior Date: Thu, 29 Oct 2026 00:17:28 +0100 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20missing=20model?= =?UTF-8?q?=20toast=20in=20AI=20guide?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/guides/ai.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/guides/ai.md b/src/plugins/guides/ai.md index c0d5bed..c50811a 100644 --- a/src/plugins/guides/ai.md +++ b/src/plugins/guides/ai.md @@ -177,7 +177,7 @@ export type CaidoSDK = Caido; const summarize = async (sdk: CaidoSDK, raw: string) => { const [model] = sdk.ai.getUpstreamModels(); if (model === undefined) { - sdk.window.showToast("Configure an AI provider in Caido's settings first.", { + sdk.window.showToast("Configure an AI provider and model in Caido's settings first.", { variant: "warning", }); return;