# AI SDK

{% hint style="warning" %}
注意：此功能需要 Eagle 4.0 Build20 或更高版本。
{% endhint %}

***

## AI SDK 依赖插件简介 <a href="#introduction" id="introduction"></a>

「AI SDK 依赖插件」是一款面向插件开发者的开发工具包，提供统一的 AI 模型配置中心，支持各大主流 AI 模型，一次配置，处处可用。通过整合 AI SDK，开发者可在自身的插件中轻松实现文字生成、结构化对象生成以及流式处理等 AI 功能。

### 统一配置中心：一次设置，处处可用

AI SDK 插件支持以下 8 个 Provider：

**商业模型**：

* OpenAI（GPT-5.2、GPT-5、o3 等）
* Anthropic Claude（Claude Sonnet 4.6、Claude Opus 4.6 等）
* Google Gemini（Gemini 3 Pro、Gemini 3 Flash 等）
* DeepSeek（DeepSeek V3、DeepSeek R1 等）
* 通义千问（Qwen3 系列）

**OpenAI 兼容协议**（连接任何兼容 OpenAI API 的服务）：

* OpenAI Compatible（支持 Groq、Together AI、Fireworks、vLLM 等）

**本地模型**（完全离线运行）：

* Ollama（支持 Llama 4、Qwen3、Gemma 3 等）
* LM Studio（图形化界面，新手友好）

后续版本将陆续增加更多主流模型服务提供商的支持。

配置一次后，所有 AI 相关插件都能直接使用，无需重复设置。例如：你安装了「AI 翻译」与「AI 重新命名」插件，它们都会自动共用你在 AI SDK 里填好的配置，甚至可以各自选择不同的模型，而不需要再次输入 API Key。

### 开放的开发环境

基于 [ai-sdk.dev](https://ai-sdk.dev/) 标准（AI SDK v6），AI SDK 插件为开发者提供了一组干净、稳定的基础设施。开发者不用再花心力处理 API Key 存储、模型切换、错误处理等基础配置，可以专注于插件的功能创新。唯一的区别在于 Provider 的获取方式——我们使用自行开发的 Provider 来确保更好的稳定性和用户体验。

{% hint style="info" %}
**版本说明**：此插件基于 AI SDK v6 构建，与 [ai-sdk.dev](https://ai-sdk.dev/) 官方文档保持同步。
{% endhint %}

***

## 安装与设置 <a href="#installation" id="installation"></a>

### 安装步骤

1. 进入 Eagle 插件中心
2. 搜索并找到「AI SDK」插件
3. 点击安装
4. 安装完成后，打开 **偏好设置**，在左侧栏找到「**AI 模型**」
5. 在右侧设置区块中配置模型服务提供商，并设置**默认模型**（语言模型、视觉模型）

{% hint style="info" %}
当用户安装具有 AI SDK 依赖的插件时，Eagle 会自动提示用户安装「AI SDK 依赖插件」。因此，开发者无需专门编写代码让用户进行安装，系统会自动确保相关依赖已安装后才允许插件运行。
{% endhint %}

### 在 manifest.json 中声明依赖

在插件的 `manifest.json` 中加入 `dependencies` 字段：

```json
{
    "id": "YOUR_PLUGIN_ID",
    "version": "1.0.0",
    "platform": "all",
    "arch": "all",
    "name": "我的 AI 插件",
    "logo": "/logo.png",
    "keywords": [],
    "dependencies": ["ai-sdk"],
    "devTools": false,
    "main": {
        "url": "index.html",
        "width": 640,
        "height": 480
    }
}
```

关键设置为 `"dependencies": ["ai-sdk"]`，这会让 Eagle 知道此插件需要 AI SDK 才能运作。

***

## 快速开始 <a href="#quickstart" id="quickstart"></a>

获取 AI SDK 模块：

```javascript
const ai = eagle.extraModule.ai;
```

### 推荐做法：使用默认模型

用户通常会在偏好设置的「AI 模型」中，事先选好偏好的语言模型与视觉模型。通过 `getDefaultModel()` 直接继承用户的选择，是最简单也最推荐的做法：

```javascript
eagle.onPluginCreate(async (plugin) => {
    const ai = eagle.extraModule.ai;
    const { generateText } = ai;

    // 获取用户设置的默认语言模型（同步，无需 await）
    // 另有 getDefaultModel("image") 可获取用户的默认视觉模型
    const defaultLLM = ai.getDefaultModel("chat");

    if (!defaultLLM) {
        console.log("请先在 AI SDK 设置中选择默认语言模型");
        ai.open(); // 自动打开偏好设置中的模型设置面板
        return;
    }

    // 直接用 provider::model 字符串获取模型
    const model = ai.getModel(defaultLLM);

    // 生成文字
    const result = await generateText({
        model,
        prompt: "请用一句话介绍数字艺术",
    });

    console.log(result.text);
});
```

{% hint style="success" %}
**🦄 最佳实践：** 优先使用 `getDefaultModel("chat")` 获取用户的偏好模型，而非在代码中写死特定的 Provider 与模型名称。这样做有两大好处：

1. **开发更轻松**——不需要自己实现模型选择器，直接继承用户在 AI SDK 中的偏好设置。
2. **避免配置问题**——如果你在代码中指定 `openai("gpt-5")`，但用户没有配置 OpenAI，就会出错。使用默认模型则能保证用户已经配置并验证过。
   {% endhint %}

### 指定特定 Provider

如果你的插件确实需要使用特定的 Provider（例如只有 OpenAI 支持的功能），也可以直接指定：

```javascript
eagle.onPluginCreate(async (plugin) => {
    const ai = eagle.extraModule.ai;
    const { generateText } = ai;

    // 获取特定 Provider（同步，无需 await）
    const openai = ai.getProvider("openai");

    const result = await generateText({
        model: openai("gpt-5"),
        prompt: "请用一句话介绍数字艺术",
    });

    console.log(result.text);
});
```

***

## 核心概念 <a href="#core-concepts" id="core-concepts"></a>

### Provider 与 Model 的关系

AI SDK 采用双层结构：**Provider**（提供者）负责管理 API 连接与认证，**Model**（模型）则是实际执行 AI 任务的单位。

```
Provider（如 openai）
  └── Model（如 gpt-5）
  └── Model（如 gpt-5.2）
```

### provider::model 格式

{% hint style="danger" %}
**重要：** Provider 与 Model 之间使用**双冒号** `::` 分隔，而非单冒号或斜线。
{% endhint %}

```javascript
// ✅ 正确
"openai::gpt-5"
"anthropic::claude-sonnet-4-6-20250514"
"google::gemini-3-flash"

// ❌ 错误
"openai/gpt-5"
"openai:gpt-5"
```

此格式用于 `getModel()` 和 `getDefaultModel()` 等方法。

### 同步 vs 异步方法

AI SDK 中的方法明确区分为同步与异步两类：

**同步方法**（无需 `await`）：

* `getProviders()`、`getProvider()`、`getAvailableProviders()`、`getModel()`
* `getDefaultModel()`

**异步方法**（需要 `await`）：

* `generateText()`、`generateObject()`、`streamText()`、`streamObject()`
* Provider 实例的 `verify()`、`getModels()`、`hasModel()`

### 获取 Model 的三种方式

```javascript
const ai = eagle.extraModule.ai;

// ⭐ 推荐：使用默认模型，直接继承用户偏好
const defaultLLM = ai.getModel(ai.getDefaultModel("chat"));   // 默认语言模型
const defaultVLM = ai.getModel(ai.getDefaultModel("image"));  // 默认视觉模型

// 方式二：直接用 provider::model 格式获取
const model = ai.getModel("openai::gpt-5");

// 方式三：先获取 Provider，再指定 Model
const openai = ai.getProvider("openai");
const model = openai("gpt-5");
```

{% hint style="success" %}
**🦄 最佳实践：** 除非你的插件有特殊需求（例如仅支持特定 Provider 的功能），否则应优先使用 `getDefaultModel()` 来获取用户的偏好模型。
{% endhint %}

***

## generateText() — 基本文字生成 <a href="#generate-text" id="generate-text"></a>

使用指定模型生成文字回应。

### 基本用法（prompt）

```javascript
const ai = eagle.extraModule.ai;
const { generateText } = ai;

// 使用默认语言模型
const model = ai.getModel(ai.getDefaultModel("chat"));

const result = await generateText({
    model,
    prompt: "请帮我写一个关于数字艺术的创意简介",
});

console.log(result.text);
```

### 使用 messages 数组

通过 `messages` 可以设置系统提示词与多轮对话：

```javascript
const model = ai.getModel(ai.getDefaultModel("chat"));

const result = await generateText({
    model,
    messages: [
        {
            role: "system",
            content: "你是一位专业的艺术评论家。",
        },
        {
            role: "user",
            content: "请分析印象派的色彩运用特点。",
        },
    ],
});

console.log(result.text);
```

### 多模态（文字 + 图片）

```javascript
// 使用默认视觉模型（支持图片理解）
const model = ai.getModel(ai.getDefaultModel("image"));

const result = await generateText({
    model,
    messages: [
        {
            role: "user",
            content: [
                {
                    type: "text",
                    text: "请描述这张图片的内容",
                },
                {
                    type: "image",
                    image: "https://example.com/sample-image.jpg",
                },
            ],
        },
    ],
});

console.log(result.text);
```

{% hint style="info" %}
更多 `generateText` 的进阶用法（如 `maxTokens`、`temperature` 等参数），请参考 [AI SDK 官方文档](https://ai-sdk.dev/docs/ai-sdk-core/generating-text)。
{% endhint %}

***

## generateObject() — 结构化对象生成 <a href="#generate-object" id="generate-object"></a>

让 AI 依照指定的 Schema 返回结构化 JSON 对象。

### 使用 Zod Schema

```javascript
const ai = eagle.extraModule.ai;
const { generateObject } = ai;
const { z } = require("zod");

// 纯文字任务使用默认语言模型
const model = ai.getModel(ai.getDefaultModel("chat"));

const result = await generateObject({
    model,
    schema: z.object({
        tags: z.array(z.object({
            name: z.string(),
            reason: z.string(),
        })),
        description: z.string(),
    }),
    prompt: "请为一张日落海滩的照片生成 5 个标签和描述",
});

console.log(result.object.tags);
console.log(result.object.description);
```

### 使用 JSON Schema

```javascript
const model = ai.getModel(ai.getDefaultModel("chat"));

const result = await generateObject({
    model,
    schema: {
        type: "object",
        properties: {
            tags: {
                type: "array",
                items: {
                    type: "object",
                    properties: {
                        name: { type: "string" },
                        reason: { type: "string" },
                    },
                },
            },
            description: { type: "string" },
        },
    },
    prompt: "请为一张日落海滩的照片生成 5 个标签和描述",
});

console.log(result.object.tags);
console.log(result.object.description);
```

### 图片分析示例

```javascript
// 涉及图片理解，使用默认视觉模型
const model = ai.getModel(ai.getDefaultModel("image"));

const result = await generateObject({
    model,
    schema: {
        type: "object",
        properties: {
            colors: { type: "array", items: { type: "string" } },
            style: { type: "string" },
            mood: { type: "string" },
        },
    },
    messages: [
        {
            role: "system",
            content: "你是一个专业的图像分析专家。",
        },
        {
            role: "user",
            content: [
                { type: "text", text: "请分析这张图片的色彩、风格和情感。" },
                { type: "image", image: "https://example.com/artwork.jpg" },
            ],
        },
    ],
});

console.log(result.object);
```

{% hint style="info" %}
更多 `generateObject` 的进阶用法，请参考 [AI SDK 官方文档](https://ai-sdk.dev/docs/ai-sdk-core/generating-structured-data)。
{% endhint %}

***

## streamText() — 流式文字生成 <a href="#stream-text" id="stream-text"></a>

以流式方式逐步接收 AI 回应，适合需要即时显示结果的场景。

```javascript
const ai = eagle.extraModule.ai;
const { streamText } = ai;
const model = ai.getModel(ai.getDefaultModel("chat"));

const { textStream } = streamText({
    model,
    prompt: "请详细介绍数字艺术的发展历程",
});

// 使用异步迭代器逐步接收文字
for await (const textPart of textStream) {
    console.log(textPart); // 即时显示
}
```

### 即时显示在 UI 中

```javascript
let fullText = "";

const { textStream } = streamText({
    model,
    prompt: "请撰写一篇短文",
});

for await (const textPart of textStream) {
    fullText += textPart;
    // 更新 UI 元素
    document.getElementById("output").textContent = fullText;
}
```

{% hint style="info" %}
更多 `streamText` 的进阶用法，请参考 [AI SDK 官方文档](https://ai-sdk.dev/docs/ai-sdk-core/generating-text#streamtext)。
{% endhint %}

***

## streamObject() — 流式对象生成 <a href="#stream-object" id="stream-object"></a>

以流式方式逐步接收结构化对象，每次迭代会收到目前已解析的部分对象。

```javascript
const ai = eagle.extraModule.ai;
const { streamObject } = ai;
const model = ai.getModel(ai.getDefaultModel("chat"));

const { partialObjectStream } = streamObject({
    model,
    schema: {
        type: "object",
        properties: {
            analysis: {
                type: "object",
                properties: {
                    colors: { type: "array", items: { type: "string" } },
                    style: { type: "string" },
                    mood: { type: "string" },
                    suggestions: { type: "array", items: { type: "string" } },
                },
            },
        },
    },
    prompt: "请分析这件艺术作品的色彩、风格、情感，并提供改进建议。",
});

for await (const partialObject of partialObjectStream) {
    console.log("当前结果:", partialObject);
    // partialObject 会逐步增加字段，例如：
    // { analysis: { colors: ["红"] } }
    // { analysis: { colors: ["红", "蓝"], style: "印象派" } }
    // { analysis: { colors: ["红", "蓝"], style: "印象派", mood: "宁静" } }
}
```

{% hint style="success" %}
**🦄 最佳实践：** `streamObject` 适合需要在 UI 上渐进式显示分析结果的场景，让用户能在 AI 尚未完成时就看到部分结果。
{% endhint %}

{% hint style="info" %}
更多 `streamObject` 的进阶用法，请参考 [AI SDK 官方文档](https://ai-sdk.dev/docs/ai-sdk-core/generating-structured-data#streamobject)。
{% endhint %}

***

## Provider 管理方法 <a href="#provider-management" id="provider-management"></a>

以下方法皆为**同步方法**，无需使用 `await`。

***

### getProviders() <a href="#get-providers" id="get-providers"></a>

获取所有已注册的 Provider 数组。

* 返回 `ProviderFunction[]` — 所有 Provider 的数组

```javascript
const ai = eagle.extraModule.ai;

// ✅ 正确：返回数组
const providers = ai.getProviders();
console.log(providers.length); // 8

providers.forEach(provider => {
    console.log(provider.name); // "openai", "anthropic", "google", ...
});
```

{% hint style="danger" %}
**注意：** `getProviders()` 返回的是**数组**，不是对象。以下写法是错误的：

```javascript
// ❌ 错误：不可以解构为对象
const { openai, anthropic } = ai.getProviders();

// ❌ 错误：不需要 await
const providers = await ai.getProviders();
```

{% endhint %}

***

### getProvider(providerName) <a href="#get-provider" id="get-provider"></a>

获取指定名称的 Provider。

* `providerName` string — Provider 名称（如 `"openai"`、`"google"`）
* 返回 `ProviderFunction | undefined` — 找到的 Provider，若不存在则返回 `undefined`

```javascript
const openai = ai.getProvider("openai");
const google = ai.getProvider("google");

if (openai) {
    const model = openai("gpt-5");
}
```

{% hint style="info" %}
如果需要获取特定 Provider，建议使用 `getProvider()` 而非 `getProviders()`，代码更简洁清晰。但在多数情况下，直接使用 `getDefaultModel()` 是更好的选择。
{% endhint %}

***

### getAvailableProviders() <a href="#get-available-providers" id="get-available-providers"></a>

获取所有已配置（用户已完成设置）的 Provider。

* 返回 `ProviderFunction[]` — 已配置的 Provider 数组

```javascript
const available = ai.getAvailableProviders();

if (available.length === 0) {
    console.log("尚未配置任何 AI 提供者，请先在 AI SDK 设置中配置。");
} else {
    console.log(`已配置 ${available.length} 个提供者：`);
    available.forEach(p => console.log(`- ${p.name}`));
}
```

{% hint style="info" %}
此方法与 `getProviders()` 的差异在于：`getProviders()` 返回所有 8 个 Provider（含未配置的），`getAvailableProviders()` 仅返回用户已完成设置的 Provider。
{% endhint %}

***

### getModel(providerAndModel) <a href="#get-model" id="get-model"></a>

通过 `provider::model` 格式直接获取模型实例。

* `providerAndModel` string — 格式为 `"provider::model"`
* 返回 `Model` — 可直接传入 `generateText()` 等方法的模型对象

```javascript
// 直接获取模型
const model = ai.getModel("openai::gpt-5");

const result = await generateText({
    model: model,
    prompt: "Hello!",
});
```

{% hint style="danger" %}
**注意：** 必须使用 `::` 双冒号分隔 Provider 与 Model 名称，否则会抛出错误。
{% endhint %}

***

## 设置与刷新 <a href="#settings" id="settings"></a>

***

### open() <a href="#open" id="open"></a>

打开偏好设置中的「AI 模型」设置面板。适合在插件界面中提供「模型设置」按钮，让用户快速配置模型服务提供商与默认模型。

* 返回 `void`

```javascript
const ai = eagle.extraModule.ai;

// 例如：在插件界面中放置「模型设置」按钮
document.getElementById("settings-btn").addEventListener("click", () => {
    ai.open(); // 系统会自动弹出偏好设置中的模型设置区块
});
```

{% hint style="success" %}
**🦄 最佳实践：** 当 `getDefaultModel()` 返回 `undefined`（用户尚未设置默认模型）时，可以在插件界面中显示提示并提供按钮调用 `open()`，引导用户完成设置。
{% endhint %}

***

### reload() <a href="#reload" id="reload"></a>

重新加载 AI SDK 配置。当用户通过 `open()` 打开设置面板并调整配置后，调用此方法即可读取到最新的配置。

* 返回 `void`

```javascript
const ai = eagle.extraModule.ai;

// 引导用户设置后，刷新配置
ai.open();

// 用户完成设置后，刷新以获取最新配置
ai.reload();

const defaultLLM = ai.getDefaultModel("chat"); // 获取用户刚设置的模型
```

{% hint style="info" %}
`open()` 不会阻塞程序执行，系统无法得知用户何时完成设置。建议在需要使用模型时调用 `reload()` 确保读取到最新配置。
{% endhint %}

***

## 默认模型方法 <a href="#default-model" id="default-model"></a>

AI SDK 支持设置和读取默认模型，让用户可以在偏好设置的「AI 模型」中统一指定偏好的模型。

***

### getDefaultModel(type) <a href="#get-default-model" id="get-default-model"></a>

获取指定类型的默认模型。此为**同步方法**。

* `type` string — 模型类型，可选值：`"chat"`（语言模型）或 `"image"`（视觉模型）
* 返回 `string | undefined` — 默认模型的 `"provider::model"` 字符串，若未设置则返回 `undefined`

```javascript
// 获取用户的默认语言模型
const defaultLLM = ai.getDefaultModel("chat");

if (defaultLLM) {
    console.log(`默认语言模型：${defaultLLM}`); // "openai::gpt-5"
    const model = ai.getModel(defaultLLM);
    const result = await generateText({ model, prompt: "Hello!" });
}

// 获取用户的默认视觉模型
const defaultVLM = ai.getDefaultModel("image");

if (defaultVLM) {
    console.log(`默认视觉模型：${defaultVLM}`); // "openai::dall-e-3"
}
```

{% hint style="info" %}
用户可以在偏好设置的「AI 模型」中分别选择偏好的**语言模型**（`"chat"`）和**视觉模型**（`"image"`），插件可各取所需。
{% endhint %}

***

## Provider 实例方法 <a href="#provider-instance-methods" id="provider-instance-methods"></a>

通过 `getProvider()` 获取的 Provider 实例，除了可作为函数调用来获取 Model 之外，还提供以下方法。

***

### verify() <a href="#verify" id="verify"></a>

验证 Provider 的连接与认证是否有效。用来检查用户目前的配置是否能正常连接。

* 返回 `Promise<VerifyResult>` — 验证结果对象
  * `ok` boolean — 验证是否成功
  * `error` APIError（可选） — 失败时的错误详情

```javascript
const openai = ai.getProvider("openai");

const result = await openai.verify();

if (result.ok) {
    console.log("连接成功！");
} else {
    console.error("连接失败：", result.error.message);
    console.error("HTTP 状态码：", result.error.status);
}
```

{% hint style="danger" %}
**注意：** `verify()` 返回的不是 `boolean`，而是包含 `ok` 和 `error` 的对象。

```javascript
// ❌ 错误
const isValid = await openai.verify();
if (isValid) { ... }

// ✅ 正确
const result = await openai.verify();
if (result.ok) { ... }
```

{% endhint %}

***

### getModels() <a href="#get-models" id="get-models"></a>

获取此 Provider 所有可用的模型列表。

* 返回 `Promise<string[]>` — 模型 ID 数组

```javascript
const openai = ai.getProvider("openai");
const models = await openai.getModels();

console.log(models);
// ["gpt-5.2", "gpt-5", "o3", ...]
```

{% hint style="info" %}
此方法会向 Provider 的 API 发送请求，请确保用户已完成该 Provider 的配置。若未配置，会抛出 `APIError`。
{% endhint %}

***

### hasModel(modelId) <a href="#has-model" id="has-model"></a>

检查此 Provider 是否包含指定模型。

* `modelId` string — 模型 ID（如 `"gpt-5"`）
* 返回 `Promise<boolean>` — 是否存在

```javascript
const openai = ai.getProvider("openai");
const exists = await openai.hasModel("gpt-5");

if (exists) {
    console.log("此模型可用");
}
```

***

## Provider 实例属性 <a href="#provider-instance-properties" id="provider-instance-properties"></a>

以下为 Provider 实例的只读属性：

***

### `name` string

Provider 的名称。

```javascript
const openai = ai.getProvider("openai");
console.log(openai.name); // "openai"
```

***

### `baseURL` string | undefined

目前设置的 API 端点。

```javascript
const openai = ai.getProvider("openai");
console.log(openai.baseURL); // "https://api.openai.com" 或 undefined
```

***

## 支持的 Provider 一览表 <a href="#supported-providers" id="supported-providers"></a>

| Provider          | 名称                    | 类型     | 默认 Base URL                                         |
| ----------------- | --------------------- | ------ | --------------------------------------------------- |
| OpenAI            | `"openai"`            | 商业（云端） | 需手动设置                                               |
| Anthropic         | `"anthropic"`         | 商业（云端） | 需手动设置                                               |
| Google Gemini     | `"google"`            | 商业（云端） | 需手动设置                                               |
| DeepSeek          | `"deepseek"`          | 商业（云端） | 需手动设置                                               |
| 通义千问              | `"tongyi"`            | 商业（云端） | `https://dashscope.aliyuncs.com/compatible-mode/v1` |
| OpenAI Compatible | `"openai-compatible"` | 兼容协议   | 用户自行设置                                              |
| Ollama            | `"ollama"`            | 本地     | `http://localhost:11434/v1`                         |
| LM Studio         | `"lmstudio"`          | 本地     | `http://localhost:1234/v1`                          |

{% hint style="info" %}
**OpenAI Compatible** 可连接任何兼容 OpenAI API 的服务（如 Groq、Together AI、Fireworks、vLLM 等）。API Key 为选填——云端服务通常需要，本地服务则不需要。使用时需自行提供 Base URL。
{% endhint %}

{% hint style="danger" %}
**注意：** Google Gemini 的 Provider 名称是 `"google"`，**不是** `"gemini"`。

```javascript
// ✅ 正确
const google = ai.getProvider("google");
ai.getModel("google::gemini-3-flash");

// ❌ 错误
const gemini = ai.getProvider("gemini");
ai.getModel("gemini::gemini-3-flash");
```

{% endhint %}

***

## 错误处理 <a href="#error-handling" id="error-handling"></a>

### APIError 类

AI SDK 在 API 请求失败时会抛出 `APIError`，包含完整的错误信息。

#### 属性

| 属性             | 类型                    | 说明                          |
| -------------- | --------------------- | --------------------------- |
| `message`      | `string`              | 错误消息                        |
| `status`       | `number \| undefined` | HTTP 状态码（如 401、403、500）     |
| `statusText`   | `string \| undefined` | HTTP 状态文字（如 "Unauthorized"） |
| `code`         | `string \| undefined` | 错误码（从响应内容中提取）               |
| `provider`     | `string \| undefined` | Provider 名称                 |
| `url`          | `string \| undefined` | 请求的 URL                     |
| `responseBody` | `unknown`             | 服务器返回的原始错误内容                |

#### 方法

| 方法           | 说明                 |
| ------------ | ------------------ |
| `toJSON()`   | 返回完整错误详情对象（适合记录日志） |
| `toString()` | 返回错误消息字符串          |

### 错误处理示例

```javascript
const ai = eagle.extraModule.ai;
const { generateText, APIError } = ai;

try {
    const model = ai.getModel(ai.getDefaultModel("chat"));
    const result = await generateText({
        model,
        prompt: "Hello!",
    });
    console.log(result.text);
} catch (error) {
    if (error instanceof APIError) {
        console.error("API 错误：", error.message);
        console.error("状态码：", error.status);       // 401, 429, 500...
        console.error("Provider：", error.provider);    // "openai"

        // 根据状态码处理
        switch (error.status) {
            case 401:
                console.error("API Key 无效，请检查 AI SDK 设置");
                break;
            case 429:
                console.error("请求频率过高，请稍后再试");
                break;
            case 500:
                console.error("服务器内部错误");
                break;
        }

        // 记录完整日志
        console.log(JSON.stringify(error.toJSON(), null, 2));
    } else {
        console.error("非预期错误：", error);
    }
}
```

### 网络错误

当无法连接到 Provider 时（如本地 Ollama 未启动），也会收到 `APIError`：

```javascript
const ollama = ai.getProvider("ollama");
const result = await ollama.verify();

if (!result.ok) {
    console.error(result.error.message);
    // "[ollama] Network error: fetch failed"
}
```

***

## 最佳实践 <a href="#best-practices" id="best-practices"></a>

### 1. 优先使用默认模型

这是最重要的建议。使用 `getDefaultModel()` 直接继承用户在 AI SDK 设置界面中的偏好，而非在代码中写死特定的 Provider 和模型：

```javascript
const ai = eagle.extraModule.ai;
const { generateText } = ai;

// ⭐ 推荐：用户已在 AI SDK 中设置好偏好模型
const defaultLLM = ai.getDefaultModel("chat");

if (!defaultLLM) {
    console.log("请先在 AI SDK 设置中选择默认语言模型");
    return;
}

const model = ai.getModel(defaultLLM);
const result = await generateText({ model, prompt: "..." });
```

**为什么不要写死模型？** 如果你在代码中指定 `ai.getProvider("openai")("gpt-5")`，但用户没有配置 OpenAI，就会出错。你需要额外处理「Provider 未配置」的边界情况，这很麻烦。使用默认模型则能保证用户已经配置并验证过，省去大量防御性代码。

### 2. 正确处理 verify() 结果

```javascript
// ✅ 正确：检查 result.ok
const result = await openai.verify();
if (result.ok) {
    // 连接成功
} else {
    console.error(result.error.message);
}

// ❌ 错误：不要直接当 boolean 使用
if (await openai.verify()) { ... }
```

### 3. 流式适用于长文本生成

当预期回应较长时，使用 `streamText()` 提供更好的用户体验：

```javascript
const { textStream } = streamText({
    model: ai.getModel(ai.getDefaultModel("chat")),
    prompt: longPrompt,
});

for await (const chunk of textStream) {
    appendToUI(chunk);
}
```

***

## 完整示例 <a href="#full-example" id="full-example"></a>

以下为一个综合性的插件示例，展示如何正确使用 AI SDK 的主要功能：

```javascript
eagle.onPluginCreate(async (plugin) => {
    const ai = eagle.extraModule.ai;
    const { generateText, generateObject, streamText, APIError } = ai;

    // 1. 获取用户在偏好设置中选择的默认语言模型
    const defaultLLM = ai.getDefaultModel("chat");

    if (!defaultLLM) {
        console.log("请先在 AI SDK 设置中选择默认语言模型");
        return;
    }

    const model = ai.getModel(defaultLLM);
    console.log(`使用默认模型：${defaultLLM}`);

    // 2. 基本文字生成
    try {
        const result = await generateText({
            model,
            prompt: "请用一句话描述这个插件的功能",
        });
        console.log("生成结果：", result.text);
    } catch (error) {
        if (error instanceof APIError) {
            console.error(`API 错误 [${error.status}]：${error.message}`);
        }
    }

    // 3. 结构化对象生成
    try {
        const result = await generateObject({
            model,
            schema: {
                type: "object",
                properties: {
                    tags: { type: "array", items: { type: "string" } },
                    category: { type: "string" },
                },
            },
            prompt: "请为一张猫咪照片生成 3 个标签和分类",
        });
        console.log("标签：", result.object.tags);
        console.log("分类：", result.object.category);
    } catch (error) {
        console.error("对象生成失败：", error.message);
    }

    // 4. 流式文字生成
    try {
        const { textStream } = streamText({
            model,
            prompt: "请列出 5 个数字艺术的创作技巧",
        });

        let fullText = "";
        for await (const chunk of textStream) {
            fullText += chunk;
        }
        console.log("流式结果：", fullText);
    } catch (error) {
        console.error("流式生成失败：", error.message);
    }
});
```

***

## API 速查表 <a href="#api-cheatsheet" id="api-cheatsheet"></a>

### AI SDK 顶层方法

| 方法                          | 同步/异步 | 返回类型                            | 说明              |
| --------------------------- | ----- | ------------------------------- | --------------- |
| `getProviders()`            | 同步    | `ProviderFunction[]`            | 获取所有 Provider   |
| `getProvider(name)`         | 同步    | `ProviderFunction \| undefined` | 获取指定 Provider   |
| `getAvailableProviders()`   | 同步    | `ProviderFunction[]`            | 获取已配置的 Provider |
| `getModel(provider::model)` | 同步    | `Model`                         | 获取模型实例          |
| `getDefaultModel(type)`     | 同步    | `string \| undefined`           | 获取默认模型          |
| `open()`                    | 同步    | `void`                          | 打开偏好设置的模型设置面板   |
| `reload()`                  | 同步    | `void`                          | 重新加载最新配置        |
| `generateText(options)`     | 异步    | `Promise<GenerateTextResult>`   | 生成文字            |
| `generateObject(options)`   | 异步    | `Promise<GenerateObjectResult>` | 生成结构化对象         |
| `streamText(options)`       | 异步    | `StreamTextResult`              | 流式文字生成          |
| `streamObject(options)`     | 异步    | `StreamObjectResult`            | 流式对象生成          |

### Provider 实例方法

| 方法                  | 同步/异步 | 返回类型                    | 说明         |
| ------------------- | ----- | ----------------------- | ---------- |
| `provider(modelId)` | 同步    | `Model`                 | 获取模型（函数调用） |
| `verify()`          | 异步    | `Promise<VerifyResult>` | 验证连接与认证    |
| `getModels()`       | 异步    | `Promise<string[]>`     | 获取模型列表     |
| `hasModel(modelId)` | 异步    | `Promise<boolean>`      | 检查模型是否存在   |

### Provider 实例属性

| 属性        | 类型                    | 说明              |
| --------- | --------------------- | --------------- |
| `name`    | `string`              | Provider 名称（只读） |
| `baseURL` | `string \| undefined` | API 端点（只读）      |

### VerifyResult

| 属性      | 类型                      | 说明       |
| ------- | ----------------------- | -------- |
| `ok`    | `boolean`               | 验证是否成功   |
| `error` | `APIError \| undefined` | 失败时的错误对象 |
