mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-25 07:50:19 -06:00
Compare commits
1 Commits
release/4.
...
feautre/ai
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a141171c5 |
@@ -124,6 +124,7 @@
|
||||
"add_action": "Aktion hinzufügen",
|
||||
"add_filter": "Filter hinzufügen",
|
||||
"add_logo": "Logo hinzufügen",
|
||||
"add_member": "Mitglied hinzufügen",
|
||||
"add_project": "Projekt hinzufügen",
|
||||
"add_to_team": "Zum Team hinzufügen",
|
||||
"all": "Alle",
|
||||
@@ -280,6 +281,7 @@
|
||||
"only_one_file_allowed": "Es ist nur eine Datei erlaubt",
|
||||
"only_owners_managers_and_manage_access_members_can_perform_this_action": "Nur Eigentümer, Manager und Mitglieder mit Zugriff auf das Management können diese Aktion ausführen.",
|
||||
"option_id": "Option-ID",
|
||||
"option_ids": "Option-IDs",
|
||||
"or": "oder",
|
||||
"organization": "Organisation",
|
||||
"organization_id": "Organisations-ID",
|
||||
@@ -1314,7 +1316,7 @@
|
||||
"columns": "Spalten",
|
||||
"company": "Firma",
|
||||
"company_logo": "Firmenlogo",
|
||||
"completed_responses": "abgeschlossene Antworten",
|
||||
"completed_responses": "unvollständige oder vollständige Antworten.",
|
||||
"concat": "Verketten +",
|
||||
"conditional_logic": "Bedingte Logik",
|
||||
"confirm_default_language": "Standardsprache bestätigen",
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
"add_action": "Add action",
|
||||
"add_filter": "Add filter",
|
||||
"add_logo": "Add logo",
|
||||
"add_member": "Add member",
|
||||
"add_project": "Add project",
|
||||
"add_to_team": "Add to team",
|
||||
"all": "All",
|
||||
@@ -280,6 +281,7 @@
|
||||
"only_one_file_allowed": "Only one file is allowed",
|
||||
"only_owners_managers_and_manage_access_members_can_perform_this_action": "Only owners and managers can perform this action.",
|
||||
"option_id": "Option ID",
|
||||
"option_ids": "Option IDs",
|
||||
"or": "or",
|
||||
"organization": "Organization",
|
||||
"organization_id": "Organization ID",
|
||||
@@ -1314,7 +1316,7 @@
|
||||
"columns": "Columns",
|
||||
"company": "Company",
|
||||
"company_logo": "Company logo",
|
||||
"completed_responses": "completed responses.",
|
||||
"completed_responses": "partial or completed responses.",
|
||||
"concat": "Concat +",
|
||||
"conditional_logic": "Conditional Logic",
|
||||
"confirm_default_language": "Confirm default language",
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
"add_action": "Ajouter une action",
|
||||
"add_filter": "Ajouter un filtre",
|
||||
"add_logo": "Ajouter un logo",
|
||||
"add_member": "Ajouter un membre",
|
||||
"add_project": "Ajouter un projet",
|
||||
"add_to_team": "Ajouter à l'équipe",
|
||||
"all": "Tout",
|
||||
@@ -280,6 +281,7 @@
|
||||
"only_one_file_allowed": "Un seul fichier est autorisé",
|
||||
"only_owners_managers_and_manage_access_members_can_perform_this_action": "Seules les propriétaires, les gestionnaires et les membres ayant accès à la gestion peuvent effectuer cette action.",
|
||||
"option_id": "Identifiant de l'option",
|
||||
"option_ids": "Identifiants des options",
|
||||
"or": "ou",
|
||||
"organization": "Organisation",
|
||||
"organization_id": "ID de l'organisation",
|
||||
@@ -1205,7 +1207,7 @@
|
||||
"delete_survey_and_responses_warning": "Êtes-vous sûr de vouloir supprimer cette enquête et toutes ses réponses?",
|
||||
"edit": {
|
||||
"1_choose_the_default_language_for_this_survey": "1. Choisissez la langue par défaut pour ce sondage :",
|
||||
"2_activate_translation_for_specific_languages": "2. Activer la traduction pour des langues spécifiques :",
|
||||
"2_activate_translation_for_specific_languages": "2. Activer la traduction pour des langues spécifiques:",
|
||||
"add": "Ajouter +",
|
||||
"add_a_delay_or_auto_close_the_survey": "Ajouter un délai ou fermer automatiquement l'enquête",
|
||||
"add_a_four_digit_pin": "Ajoutez un code PIN à quatre chiffres.",
|
||||
@@ -1314,7 +1316,7 @@
|
||||
"columns": "Colonnes",
|
||||
"company": "Société",
|
||||
"company_logo": "Logo de l'entreprise",
|
||||
"completed_responses": "réponses complètes.",
|
||||
"completed_responses": "des réponses partielles ou complètes.",
|
||||
"concat": "Concat +",
|
||||
"conditional_logic": "Logique conditionnelle",
|
||||
"confirm_default_language": "Confirmer la langue par défaut",
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
"add_action": "Adicionar ação",
|
||||
"add_filter": "Adicionar filtro",
|
||||
"add_logo": "Adicionar logo",
|
||||
"add_member": "Adicionar membro",
|
||||
"add_project": "Adicionar projeto",
|
||||
"add_to_team": "Adicionar à equipe",
|
||||
"all": "Todos",
|
||||
@@ -280,6 +281,7 @@
|
||||
"only_one_file_allowed": "É permitido apenas um arquivo",
|
||||
"only_owners_managers_and_manage_access_members_can_perform_this_action": "Apenas proprietários, gerentes e membros com acesso de gerenciamento podem realizar essa ação.",
|
||||
"option_id": "ID da opção",
|
||||
"option_ids": "IDs da Opção",
|
||||
"or": "ou",
|
||||
"organization": "organização",
|
||||
"organization_id": "ID da Organização",
|
||||
@@ -1314,7 +1316,7 @@
|
||||
"columns": "colunas",
|
||||
"company": "empresa",
|
||||
"company_logo": "Logo da empresa",
|
||||
"completed_responses": "respostas completas",
|
||||
"completed_responses": "respostas parciais ou completas.",
|
||||
"concat": "Concatenar +",
|
||||
"conditional_logic": "Lógica Condicional",
|
||||
"confirm_default_language": "Confirmar idioma padrão",
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
"add_action": "Adicionar ação",
|
||||
"add_filter": "Adicionar filtro",
|
||||
"add_logo": "Adicionar logótipo",
|
||||
"add_member": "Adicionar membro",
|
||||
"add_project": "Adicionar projeto",
|
||||
"add_to_team": "Adicionar à equipa",
|
||||
"all": "Todos",
|
||||
@@ -280,6 +281,7 @@
|
||||
"only_one_file_allowed": "Apenas um ficheiro é permitido",
|
||||
"only_owners_managers_and_manage_access_members_can_perform_this_action": "Apenas proprietários e gestores podem realizar esta ação.",
|
||||
"option_id": "ID de Opção",
|
||||
"option_ids": "IDs de Opção",
|
||||
"or": "ou",
|
||||
"organization": "Organização",
|
||||
"organization_id": "ID da Organização",
|
||||
@@ -1314,7 +1316,7 @@
|
||||
"columns": "Colunas",
|
||||
"company": "Empresa",
|
||||
"company_logo": "Logotipo da empresa",
|
||||
"completed_responses": "respostas concluídas",
|
||||
"completed_responses": "respostas parciais ou completas",
|
||||
"concat": "Concatenar +",
|
||||
"conditional_logic": "Lógica Condicional",
|
||||
"confirm_default_language": "Confirmar idioma padrão",
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
"add_action": "新增操作",
|
||||
"add_filter": "新增篩選器",
|
||||
"add_logo": "新增標誌",
|
||||
"add_member": "新增成員",
|
||||
"add_project": "新增專案",
|
||||
"add_to_team": "新增至團隊",
|
||||
"all": "全部",
|
||||
@@ -280,6 +281,7 @@
|
||||
"only_one_file_allowed": "僅允許一個檔案",
|
||||
"only_owners_managers_and_manage_access_members_can_perform_this_action": "只有擁有者、管理員和管理存取權限的成員才能執行此操作。",
|
||||
"option_id": "選項 ID",
|
||||
"option_ids": "選項 IDs",
|
||||
"or": "或",
|
||||
"organization": "組織",
|
||||
"organization_id": "組織 ID",
|
||||
@@ -1314,7 +1316,7 @@
|
||||
"columns": "欄位",
|
||||
"company": "公司",
|
||||
"company_logo": "公司標誌",
|
||||
"completed_responses": "完成的回應。",
|
||||
"completed_responses": "部分或完整答复。",
|
||||
"concat": "串連 +",
|
||||
"conditional_logic": "條件邏輯",
|
||||
"confirm_default_language": "確認預設語言",
|
||||
|
||||
10
packages/ai/.eslintrc.cjs
Normal file
10
packages/ai/.eslintrc.cjs
Normal file
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
extends: ["@formbricks/eslint-config/library.js"],
|
||||
parserOptions: {
|
||||
project: "tsconfig.json",
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
rules: {
|
||||
"no-console": "off",
|
||||
},
|
||||
};
|
||||
198
packages/ai/README.md
Normal file
198
packages/ai/README.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# @formbricks/ai
|
||||
|
||||
A model-agnostic AI package for Formbricks, providing a unified interface for LLM operations across different providers.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-Provider Support**: OpenAI and Anthropic models with easy switching
|
||||
- **Type-Safe**: Full TypeScript support with schema validation
|
||||
- **Environment-Based Configuration**: Automatic provider selection via environment variables
|
||||
- **Structured Output**: Generate validated JSON objects from prompts using schemas
|
||||
- **Helper Functions**: Built-in summarization and translation utilities
|
||||
|
||||
## Installation
|
||||
|
||||
This package is part of the Formbricks monorepo and is intended for internal use.
|
||||
|
||||
```bash
|
||||
pnpm install @formbricks/ai
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Environment Configuration
|
||||
|
||||
Set up your environment variables:
|
||||
|
||||
```bash
|
||||
# Provider selection (defaults to "openai")
|
||||
AI_PROVIDER=openai # or "anthropic"
|
||||
|
||||
# Model selection (uses sensible defaults if not specified)
|
||||
AI_MODEL=gpt-4 # or "claude-3-sonnet-20240229"
|
||||
|
||||
# API Keys
|
||||
OPENAI_API_KEY=your_openai_key
|
||||
ANTHROPIC_API_KEY=your_anthropic_key
|
||||
|
||||
# Optional: Custom base URL
|
||||
AI_BASE_URL=https://your-custom-endpoint.com
|
||||
```
|
||||
|
||||
### Basic Usage
|
||||
|
||||
#### Text Generation
|
||||
|
||||
```typescript
|
||||
import { generateText } from "@formbricks/ai";
|
||||
|
||||
const result = await generateText({
|
||||
prompt: "Explain quantum computing in simple terms",
|
||||
system: "You are a helpful science teacher",
|
||||
temperature: 0.7,
|
||||
maxTokens: 200,
|
||||
});
|
||||
|
||||
console.log(result.text);
|
||||
```
|
||||
|
||||
#### Structured Object Generation
|
||||
|
||||
```typescript
|
||||
import { z } from "zod";
|
||||
import { generateObject } from "@formbricks/ai";
|
||||
|
||||
const analysisSchema = z.object({
|
||||
sentiment: z.enum(["positive", "negative", "neutral"]),
|
||||
summary: z.string(),
|
||||
keyTopics: z.array(z.string()),
|
||||
confidence: z.number().min(0).max(1),
|
||||
});
|
||||
|
||||
const result = await generateObject({
|
||||
prompt: "Analyze this customer feedback: 'The product is amazing but delivery was slow'",
|
||||
schema: analysisSchema,
|
||||
temperature: 0.3,
|
||||
});
|
||||
|
||||
console.log(result.object.sentiment); // Type-safe access
|
||||
console.log(result.object.keyTopics);
|
||||
```
|
||||
|
||||
#### Helper Functions
|
||||
|
||||
```typescript
|
||||
import { summarizeText, translateText } from "@formbricks/ai";
|
||||
|
||||
// Summarization
|
||||
const summary = await summarizeText(longText, 150);
|
||||
|
||||
// Translation
|
||||
const translated = await translateText("Hello, how are you?", "Spanish", "English");
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Programmatic Configuration
|
||||
|
||||
You can override environment configuration programmatically:
|
||||
|
||||
```typescript
|
||||
import { createAIModel, generateText } from "@formbricks/ai";
|
||||
|
||||
const customConfig = {
|
||||
provider: "anthropic" as const,
|
||||
model: "claude-3-haiku-20240307",
|
||||
apiKey: "your-api-key",
|
||||
};
|
||||
|
||||
// Use custom config for specific calls
|
||||
const result = await generateText(
|
||||
{
|
||||
prompt: "Hello world",
|
||||
},
|
||||
customConfig
|
||||
);
|
||||
|
||||
// Or create a reusable model instance
|
||||
const aiModel = createAIModel(customConfig);
|
||||
```
|
||||
|
||||
### Supported Models
|
||||
|
||||
#### OpenAI
|
||||
|
||||
- `gpt-4` (default)
|
||||
- `gpt-4-turbo`
|
||||
- `gpt-3.5-turbo`
|
||||
|
||||
#### Anthropic
|
||||
|
||||
- `claude-3-sonnet-20240229` (default)
|
||||
- `claude-3-haiku-20240307`
|
||||
- `claude-3-opus-20240229`
|
||||
|
||||
## Error Handling
|
||||
|
||||
The package provides clear error messages for common issues:
|
||||
|
||||
```typescript
|
||||
import { generateText, isAIConfigured } from "@formbricks/ai";
|
||||
|
||||
// Check if AI is properly configured
|
||||
if (!isAIConfigured()) {
|
||||
throw new Error("AI is not properly configured. Please check your environment variables.");
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await generateText({
|
||||
prompt: "Your prompt here",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("AI generation failed:", error.message);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage in Formbricks
|
||||
|
||||
This package is designed to be used across the Formbricks ecosystem:
|
||||
|
||||
- **NextJS API Routes**: For server-side AI operations
|
||||
- **Background Jobs**: For processing surveys and responses
|
||||
- **Future NestJS Backend**: Modular design allows easy integration
|
||||
|
||||
## Development
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
|
||||
### Development Mode
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
|
||||
```bash
|
||||
pnpm lint
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
The package follows a layered architecture:
|
||||
|
||||
1. **Types Layer** (`types.ts`): TypeScript definitions and interfaces
|
||||
2. **Configuration Layer** (`config.ts`): Provider setup and validation
|
||||
3. **Abstraction Layer** (`ai.ts`): Main API functions
|
||||
4. **Export Layer** (`index.ts`): Public API exports
|
||||
|
||||
This design ensures:
|
||||
|
||||
- Easy testing and mocking
|
||||
- Provider-agnostic implementation
|
||||
- Type safety throughout
|
||||
- Consistent error handling
|
||||
39
packages/ai/package.json
Normal file
39
packages/ai/package.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "@formbricks/ai",
|
||||
"packageManager": "pnpm@9.15.9",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"main": "./dist/index.cjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.cjs"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf .turbo node_modules dist",
|
||||
"build": "vite build",
|
||||
"dev": "vite build --watch",
|
||||
"lint": "eslint ./src --fix",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "^1.0.6",
|
||||
"@ai-sdk/openai": "^1.0.20",
|
||||
"ai": "^5.0.2",
|
||||
"zod": "^3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formbricks/config-typescript": "workspace:*",
|
||||
"@formbricks/eslint-config": "workspace:*",
|
||||
"typescript": "5.8.3",
|
||||
"vite": "6.3.5",
|
||||
"vite-plugin-dts": "4.5.3"
|
||||
}
|
||||
}
|
||||
196
packages/ai/src/ai.ts
Normal file
196
packages/ai/src/ai.ts
Normal file
@@ -0,0 +1,196 @@
|
||||
import { generateObject as aiGenerateObject, generateText as aiGenerateText } from "ai";
|
||||
import type { z } from "zod";
|
||||
import { createAIModel } from "./config";
|
||||
import type {
|
||||
GenerateObjectOptions,
|
||||
GenerateObjectResult,
|
||||
GenerateTextOptions,
|
||||
GenerateTextResult,
|
||||
ProviderConfig,
|
||||
} from "./types";
|
||||
|
||||
/**
|
||||
* Singleton AI model instance for reuse across calls
|
||||
*/
|
||||
let aiModelInstance: ReturnType<typeof createAIModel> | null = null;
|
||||
|
||||
/**
|
||||
* Get or create the AI model instance
|
||||
*/
|
||||
function getAIModel(customConfig?: ProviderConfig) {
|
||||
if (!aiModelInstance || customConfig) {
|
||||
aiModelInstance = createAIModel(customConfig);
|
||||
}
|
||||
return aiModelInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate text using the configured AI model
|
||||
*
|
||||
* @param options - Text generation options
|
||||
* @returns Promise resolving to generated text and usage information
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const result = await generateText({
|
||||
* prompt: "Summarize the following text: Lorem ipsum...",
|
||||
* system: "You are a helpful assistant that provides concise summaries.",
|
||||
* temperature: 0.7,
|
||||
* maxTokens: 150
|
||||
* });
|
||||
*
|
||||
* console.log(result.text);
|
||||
* ```
|
||||
*/
|
||||
export async function generateText(
|
||||
options: GenerateTextOptions,
|
||||
customConfig?: ProviderConfig
|
||||
): Promise<GenerateTextResult> {
|
||||
const { model } = getAIModel(customConfig);
|
||||
|
||||
try {
|
||||
const result = await aiGenerateText({
|
||||
model,
|
||||
prompt: options.prompt,
|
||||
system: options.system,
|
||||
temperature: options.temperature,
|
||||
...(options.maxTokens && { maxTokens: options.maxTokens }),
|
||||
});
|
||||
|
||||
return {
|
||||
text: result.text,
|
||||
usage: result.usage
|
||||
? {
|
||||
inputTokens: result.usage.inputTokens,
|
||||
outputTokens: result.usage.outputTokens,
|
||||
totalTokens: result.usage.totalTokens,
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to generate text: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a structured object using the configured AI model
|
||||
*
|
||||
* @param options - Object generation options including Zod schema
|
||||
* @returns Promise resolving to generated object and usage information
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { z } from "zod";
|
||||
*
|
||||
* const summarySchema = z.object({
|
||||
* title: z.string(),
|
||||
* summary: z.string(),
|
||||
* keyPoints: z.array(z.string()),
|
||||
* sentiment: z.enum(['positive', 'negative', 'neutral'])
|
||||
* });
|
||||
*
|
||||
* const result = await generateObject({
|
||||
* prompt: "Analyze the following article: Lorem ipsum...",
|
||||
* schema: summarySchema,
|
||||
* system: "You are an expert content analyzer.",
|
||||
* temperature: 0.3
|
||||
* });
|
||||
*
|
||||
* console.log(result.object.title);
|
||||
* console.log(result.object.keyPoints);
|
||||
* ```
|
||||
*/
|
||||
export async function generateObject<T extends z.ZodSchema>(
|
||||
options: GenerateObjectOptions<T>,
|
||||
customConfig?: ProviderConfig
|
||||
): Promise<GenerateObjectResult<z.infer<T>>> {
|
||||
const { model } = getAIModel(customConfig);
|
||||
|
||||
try {
|
||||
const result = await aiGenerateObject({
|
||||
model,
|
||||
prompt: options.prompt,
|
||||
schema: options.schema,
|
||||
system: options.system,
|
||||
temperature: options.temperature,
|
||||
...(options.maxTokens && { maxTokens: options.maxTokens }),
|
||||
});
|
||||
|
||||
return {
|
||||
object: result.object,
|
||||
usage: result.usage
|
||||
? {
|
||||
inputTokens: result.usage.inputTokens,
|
||||
outputTokens: result.usage.outputTokens,
|
||||
totalTokens: result.usage.totalTokens,
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to generate object: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for text summarization
|
||||
*
|
||||
* @param text - Text to summarize
|
||||
* @param maxLength - Optional maximum length for the summary
|
||||
* @returns Promise resolving to the summary
|
||||
*/
|
||||
export async function summarizeText(
|
||||
text: string,
|
||||
maxLength?: number,
|
||||
customConfig?: ProviderConfig
|
||||
): Promise<string> {
|
||||
const prompt = `Summarize the following text${maxLength ? ` in approximately ${maxLength} characters` : ""}:\n\n${text}`;
|
||||
|
||||
const result = await generateText(
|
||||
{
|
||||
prompt,
|
||||
system:
|
||||
"You are a helpful assistant that creates clear, concise summaries. Focus on the key points and main ideas.",
|
||||
temperature: 0.3,
|
||||
maxTokens: maxLength ? Math.ceil(maxLength / 3) : undefined, // Rough token estimate
|
||||
},
|
||||
customConfig
|
||||
);
|
||||
|
||||
return result.text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for text translation
|
||||
*
|
||||
* @param text - Text to translate
|
||||
* @param targetLanguage - Target language for translation
|
||||
* @param sourceLanguage - Optional source language (auto-detected if not provided)
|
||||
* @returns Promise resolving to the translated text
|
||||
*/
|
||||
export async function translateText(
|
||||
text: string,
|
||||
targetLanguage: string,
|
||||
sourceLanguage?: string,
|
||||
customConfig?: ProviderConfig
|
||||
): Promise<string> {
|
||||
const sourceText = sourceLanguage ? `from ${sourceLanguage} ` : "";
|
||||
const prompt = `Translate the following text ${sourceText}to ${targetLanguage}:\n\n${text}`;
|
||||
|
||||
const result = await generateText(
|
||||
{
|
||||
prompt,
|
||||
system: `You are a professional translator. Provide only the translated text without any additional commentary or explanations. Maintain the original tone and style.`,
|
||||
temperature: 0.1, // Low temperature for consistency
|
||||
},
|
||||
customConfig
|
||||
);
|
||||
|
||||
return result.text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the AI model instance (useful for testing or when configuration changes)
|
||||
*/
|
||||
export function resetAIModel(): void {
|
||||
aiModelInstance = null;
|
||||
}
|
||||
168
packages/ai/src/config.ts
Normal file
168
packages/ai/src/config.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
import { anthropic } from "@ai-sdk/anthropic";
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
import type { LanguageModelV1 } from "ai";
|
||||
import type {
|
||||
AIEnvironmentConfig,
|
||||
AIModelInstance,
|
||||
AIProvider,
|
||||
AnthropicConfig,
|
||||
OpenAIConfig,
|
||||
ProviderConfig,
|
||||
} from "./types";
|
||||
|
||||
/**
|
||||
* Default models for each provider
|
||||
*/
|
||||
const DEFAULT_MODELS: Record<AIProvider, string> = {
|
||||
openai: "gpt-4",
|
||||
anthropic: "claude-3-sonnet-20240229",
|
||||
};
|
||||
|
||||
/**
|
||||
* Get environment configuration from process.env
|
||||
*/
|
||||
function getEnvironmentConfig(): AIEnvironmentConfig {
|
||||
return {
|
||||
AI_PROVIDER: process.env.AI_PROVIDER,
|
||||
AI_MODEL: process.env.AI_MODEL,
|
||||
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
|
||||
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
|
||||
AI_BASE_URL: process.env.AI_BASE_URL,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create provider configuration from environment variables
|
||||
*/
|
||||
function createProviderConfigFromEnv(): ProviderConfig {
|
||||
const env = getEnvironmentConfig();
|
||||
|
||||
// Determine provider (default to openai if not specified)
|
||||
const provider = (env.AI_PROVIDER as AIProvider) || "openai";
|
||||
|
||||
// Get model for the provider
|
||||
const model = env.AI_MODEL || DEFAULT_MODELS[provider];
|
||||
|
||||
// Create configuration based on provider
|
||||
switch (provider) {
|
||||
case "openai": {
|
||||
const config: OpenAIConfig = {
|
||||
provider: "openai",
|
||||
model,
|
||||
apiKey: env.OPENAI_API_KEY,
|
||||
baseURL: env.AI_BASE_URL,
|
||||
};
|
||||
return config;
|
||||
}
|
||||
case "anthropic": {
|
||||
const config: AnthropicConfig = {
|
||||
provider: "anthropic",
|
||||
model,
|
||||
apiKey: env.ANTHROPIC_API_KEY,
|
||||
baseURL: env.AI_BASE_URL,
|
||||
};
|
||||
return config;
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unsupported AI provider: ${provider}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a language model instance from provider configuration
|
||||
*/
|
||||
function createModelFromConfig(config: ProviderConfig): LanguageModelV1 {
|
||||
switch (config.provider) {
|
||||
case "openai": {
|
||||
const options: any = {};
|
||||
|
||||
if (config.apiKey) {
|
||||
options.apiKey = config.apiKey;
|
||||
}
|
||||
|
||||
if (config.baseURL) {
|
||||
options.baseURL = config.baseURL;
|
||||
}
|
||||
|
||||
return openai(config.model, options);
|
||||
}
|
||||
case "anthropic": {
|
||||
const options: any = {};
|
||||
|
||||
if (config.apiKey) {
|
||||
options.apiKey = config.apiKey;
|
||||
}
|
||||
|
||||
if (config.baseURL) {
|
||||
options.baseURL = config.baseURL;
|
||||
}
|
||||
|
||||
return anthropic(config.model, options);
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unsupported provider: ${(config as ProviderConfig).provider}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that required API keys are present for the configured provider
|
||||
*/
|
||||
function validateConfiguration(config: ProviderConfig): void {
|
||||
switch (config.provider) {
|
||||
case "openai":
|
||||
if (!config.apiKey && !process.env.OPENAI_API_KEY) {
|
||||
throw new Error(
|
||||
"OpenAI API key is required. Set OPENAI_API_KEY environment variable or provide apiKey in configuration."
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "anthropic":
|
||||
if (!config.apiKey && !process.env.ANTHROPIC_API_KEY) {
|
||||
throw new Error(
|
||||
"Anthropic API key is required. Set ANTHROPIC_API_KEY environment variable or provide apiKey in configuration."
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported provider: ${(config as ProviderConfig).provider}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure the AI model instance
|
||||
*/
|
||||
export function createAIModel(customConfig?: ProviderConfig): AIModelInstance {
|
||||
// Use custom config or create from environment
|
||||
const config = customConfig || createProviderConfigFromEnv();
|
||||
|
||||
// Validate the configuration
|
||||
validateConfiguration(config);
|
||||
|
||||
// Create the model instance
|
||||
const model = createModelFromConfig(config);
|
||||
|
||||
return {
|
||||
model,
|
||||
config,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current provider configuration without creating a model
|
||||
*/
|
||||
export function getProviderConfig(): ProviderConfig {
|
||||
return createProviderConfigFromEnv();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if AI is properly configured
|
||||
*/
|
||||
export function isAIConfigured(): boolean {
|
||||
try {
|
||||
const config = createProviderConfigFromEnv();
|
||||
validateConfiguration(config);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
20
packages/ai/src/index.ts
Normal file
20
packages/ai/src/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// Main AI functions
|
||||
export { generateText, generateObject, summarizeText, translateText, resetAIModel } from "./ai";
|
||||
|
||||
// Configuration functions
|
||||
export { createAIModel, getProviderConfig, isAIConfigured } from "./config";
|
||||
|
||||
// Types
|
||||
export type {
|
||||
AIProvider,
|
||||
AIProviderConfig,
|
||||
OpenAIConfig,
|
||||
AnthropicConfig,
|
||||
ProviderConfig,
|
||||
AIEnvironmentConfig,
|
||||
GenerateTextOptions,
|
||||
GenerateObjectOptions,
|
||||
GenerateTextResult,
|
||||
GenerateObjectResult,
|
||||
AIModelInstance,
|
||||
} from "./types";
|
||||
102
packages/ai/src/types.ts
Normal file
102
packages/ai/src/types.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import type { LanguageModelV1 } from "ai";
|
||||
import type { z } from "zod";
|
||||
|
||||
/**
|
||||
* Supported AI providers
|
||||
*/
|
||||
export type AIProvider = "openai" | "anthropic";
|
||||
|
||||
/**
|
||||
* Configuration for different AI providers
|
||||
*/
|
||||
export interface AIProviderConfig {
|
||||
provider: AIProvider;
|
||||
model: string;
|
||||
apiKey?: string;
|
||||
baseURL?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenAI specific configuration
|
||||
*/
|
||||
export interface OpenAIConfig extends AIProviderConfig {
|
||||
provider: "openai";
|
||||
model: string; // e.g., "gpt-4", "gpt-3.5-turbo"
|
||||
}
|
||||
|
||||
/**
|
||||
* Anthropic specific configuration
|
||||
*/
|
||||
export interface AnthropicConfig extends AIProviderConfig {
|
||||
provider: "anthropic";
|
||||
model: string; // e.g., "claude-3-sonnet-20240229", "claude-3-haiku-20240307"
|
||||
}
|
||||
|
||||
/**
|
||||
* Union type for all provider configurations
|
||||
*/
|
||||
export type ProviderConfig = OpenAIConfig | AnthropicConfig;
|
||||
|
||||
/**
|
||||
* Environment variables for AI configuration
|
||||
*/
|
||||
export interface AIEnvironmentConfig {
|
||||
AI_PROVIDER?: string;
|
||||
AI_MODEL?: string;
|
||||
OPENAI_API_KEY?: string;
|
||||
ANTHROPIC_API_KEY?: string;
|
||||
AI_BASE_URL?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for text generation
|
||||
*/
|
||||
export interface GenerateTextOptions {
|
||||
prompt: string;
|
||||
system?: string;
|
||||
temperature?: number;
|
||||
maxTokens?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for object generation
|
||||
*/
|
||||
export interface GenerateObjectOptions<T extends z.ZodSchema> {
|
||||
prompt: string;
|
||||
schema: T;
|
||||
system?: string;
|
||||
temperature?: number;
|
||||
maxTokens?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result from text generation
|
||||
*/
|
||||
export interface GenerateTextResult {
|
||||
text: string;
|
||||
usage?: {
|
||||
inputTokens?: number;
|
||||
outputTokens?: number;
|
||||
totalTokens?: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Result from object generation
|
||||
*/
|
||||
export interface GenerateObjectResult<T> {
|
||||
object: T;
|
||||
usage?: {
|
||||
inputTokens?: number;
|
||||
outputTokens?: number;
|
||||
totalTokens?: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal type for the language model instance
|
||||
*/
|
||||
export interface AIModelInstance {
|
||||
model: LanguageModelV1;
|
||||
config: ProviderConfig;
|
||||
}
|
||||
12
packages/ai/tsconfig.json
Normal file
12
packages/ai/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "dist",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"],
|
||||
"extends": "@formbricks/config-typescript/js-library.json",
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
49
packages/ai/vite.config.ts
Normal file
49
packages/ai/vite.config.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { resolve } from "path";
|
||||
import { UserConfig, defineConfig } from "vite";
|
||||
import dts from "vite-plugin-dts";
|
||||
|
||||
export default defineConfig((): UserConfig => {
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": resolve(__dirname, "src"),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: {
|
||||
index: resolve(__dirname, "src/index.ts"),
|
||||
},
|
||||
output: [
|
||||
{
|
||||
format: "esm",
|
||||
entryFileNames: "[name].js",
|
||||
chunkFileNames: "[name].js",
|
||||
},
|
||||
{
|
||||
format: "cjs",
|
||||
entryFileNames: "[name].cjs",
|
||||
chunkFileNames: "[name].cjs",
|
||||
},
|
||||
],
|
||||
external: [
|
||||
// External dependencies that should not be bundled
|
||||
"@ai-sdk/anthropic",
|
||||
"@ai-sdk/openai",
|
||||
"ai",
|
||||
"zod",
|
||||
],
|
||||
},
|
||||
emptyOutDir: true,
|
||||
ssr: true, // Server-side rendering mode for Node.js
|
||||
},
|
||||
plugins: [
|
||||
dts({
|
||||
rollupTypes: false,
|
||||
include: ["src/**/*"],
|
||||
exclude: ["src/**/*.test.ts", "src/**/*.spec.ts"],
|
||||
insertTypesEntry: true,
|
||||
}),
|
||||
],
|
||||
};
|
||||
});
|
||||
149
pnpm-lock.yaml
generated
149
pnpm-lock.yaml
generated
@@ -536,6 +536,37 @@ importers:
|
||||
specifier: 3.1.0
|
||||
version: 3.1.0(typescript@5.8.3)(vitest@3.1.3(@types/node@22.15.18)(jiti@2.4.2)(jsdom@26.1.0)(terser@5.39.1)(tsx@4.19.4)(yaml@2.8.0))
|
||||
|
||||
packages/ai:
|
||||
dependencies:
|
||||
'@ai-sdk/anthropic':
|
||||
specifier: ^1.0.6
|
||||
version: 1.2.12(zod@3.24.4)
|
||||
'@ai-sdk/openai':
|
||||
specifier: ^1.0.20
|
||||
version: 1.3.23(zod@3.24.4)
|
||||
ai:
|
||||
specifier: ^5.0.2
|
||||
version: 5.0.2(zod@3.24.4)
|
||||
zod:
|
||||
specifier: 3.24.4
|
||||
version: 3.24.4
|
||||
devDependencies:
|
||||
'@formbricks/config-typescript':
|
||||
specifier: workspace:*
|
||||
version: link:../config-typescript
|
||||
'@formbricks/eslint-config':
|
||||
specifier: workspace:*
|
||||
version: link:../config-eslint
|
||||
typescript:
|
||||
specifier: 5.8.3
|
||||
version: 5.8.3
|
||||
vite:
|
||||
specifier: 6.3.5
|
||||
version: 6.3.5(@types/node@22.15.18)(jiti@2.4.2)(terser@5.39.1)(tsx@4.19.4)(yaml@2.8.0)
|
||||
vite-plugin-dts:
|
||||
specifier: 4.5.3
|
||||
version: 4.5.3(@types/node@22.15.18)(rollup@4.46.1)(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.18)(jiti@2.4.2)(terser@5.39.1)(tsx@4.19.4)(yaml@2.8.0))
|
||||
|
||||
packages/config-eslint:
|
||||
devDependencies:
|
||||
'@next/eslint-plugin-next':
|
||||
@@ -824,6 +855,44 @@ packages:
|
||||
'@adobe/css-tools@4.4.3':
|
||||
resolution: {integrity: sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==}
|
||||
|
||||
'@ai-sdk/anthropic@1.2.12':
|
||||
resolution: {integrity: sha512-YSzjlko7JvuiyQFmI9RN1tNZdEiZxc+6xld/0tq/VkJaHpEzGAb1yiNxxvmYVcjvfu/PcvCxAAYXmTYQQ63IHQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.0.0
|
||||
|
||||
'@ai-sdk/gateway@1.0.0':
|
||||
resolution: {integrity: sha512-VEm87DyRx1yIPywbTy8ntoyh4jEDv1rJ88m+2I7zOm08jJI5BhFtAWh0OF6YzZu1Vu4NxhOWO4ssGdsqydDQ3A==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4
|
||||
|
||||
'@ai-sdk/openai@1.3.23':
|
||||
resolution: {integrity: sha512-86U7rFp8yacUAOE/Jz8WbGcwMCqWvjK33wk5DXkfnAOEn3mx2r7tNSJdjukQFZbAK97VMXGPPHxF+aEARDXRXQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.0.0
|
||||
|
||||
'@ai-sdk/provider-utils@2.2.8':
|
||||
resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.23.8
|
||||
|
||||
'@ai-sdk/provider-utils@3.0.0':
|
||||
resolution: {integrity: sha512-BoQZtGcBxkeSH1zK+SRYNDtJPIPpacTeiMZqnG4Rv6xXjEwM0FH4MGs9c+PlhyEWmQCzjRM2HAotEydFhD4dYw==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4
|
||||
|
||||
'@ai-sdk/provider@1.1.3':
|
||||
resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@ai-sdk/provider@2.0.0':
|
||||
resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@alloc/quick-lru@5.2.0':
|
||||
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -3734,6 +3803,9 @@ packages:
|
||||
'@sqltools/formatter@1.2.5':
|
||||
resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==}
|
||||
|
||||
'@standard-schema/spec@1.0.0':
|
||||
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
|
||||
|
||||
'@standard-schema/utils@0.3.0':
|
||||
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
|
||||
|
||||
@@ -4677,6 +4749,12 @@ packages:
|
||||
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ai@5.0.2:
|
||||
resolution: {integrity: sha512-Uk4lmwlr2b/4G9DUYCWYKcWz93xQ6p6AEeRZN+/AO9NbOyCm9axrDru26c83Ax8OB8IHUvoseA3CqaZkg9Z0Kg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4
|
||||
|
||||
ajv-draft-04@1.0.0:
|
||||
resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
|
||||
peerDependencies:
|
||||
@@ -5887,6 +5965,10 @@ packages:
|
||||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||
engines: {node: '>=0.8.x'}
|
||||
|
||||
eventsource-parser@3.0.3:
|
||||
resolution: {integrity: sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
expand-template@2.0.3:
|
||||
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -6723,6 +6805,9 @@ packages:
|
||||
json-schema-traverse@1.0.0:
|
||||
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
|
||||
|
||||
json-schema@0.4.0:
|
||||
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
|
||||
|
||||
json-stable-stringify-without-jsonify@1.0.1:
|
||||
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
|
||||
|
||||
@@ -9490,6 +9575,11 @@ packages:
|
||||
peerDependencies:
|
||||
zod: ^3.21.4
|
||||
|
||||
zod-to-json-schema@3.24.6:
|
||||
resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==}
|
||||
peerDependencies:
|
||||
zod: ^3.24.1
|
||||
|
||||
zod@3.24.4:
|
||||
resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==}
|
||||
|
||||
@@ -9497,6 +9587,47 @@ snapshots:
|
||||
|
||||
'@adobe/css-tools@4.4.3': {}
|
||||
|
||||
'@ai-sdk/anthropic@1.2.12(zod@3.24.4)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 1.1.3
|
||||
'@ai-sdk/provider-utils': 2.2.8(zod@3.24.4)
|
||||
zod: 3.24.4
|
||||
|
||||
'@ai-sdk/gateway@1.0.0(zod@3.24.4)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 2.0.0
|
||||
'@ai-sdk/provider-utils': 3.0.0(zod@3.24.4)
|
||||
zod: 3.24.4
|
||||
|
||||
'@ai-sdk/openai@1.3.23(zod@3.24.4)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 1.1.3
|
||||
'@ai-sdk/provider-utils': 2.2.8(zod@3.24.4)
|
||||
zod: 3.24.4
|
||||
|
||||
'@ai-sdk/provider-utils@2.2.8(zod@3.24.4)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 1.1.3
|
||||
nanoid: 3.3.11
|
||||
secure-json-parse: 2.7.0
|
||||
zod: 3.24.4
|
||||
|
||||
'@ai-sdk/provider-utils@3.0.0(zod@3.24.4)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 2.0.0
|
||||
'@standard-schema/spec': 1.0.0
|
||||
eventsource-parser: 3.0.3
|
||||
zod: 3.24.4
|
||||
zod-to-json-schema: 3.24.6(zod@3.24.4)
|
||||
|
||||
'@ai-sdk/provider@1.1.3':
|
||||
dependencies:
|
||||
json-schema: 0.4.0
|
||||
|
||||
'@ai-sdk/provider@2.0.0':
|
||||
dependencies:
|
||||
json-schema: 0.4.0
|
||||
|
||||
'@alloc/quick-lru@5.2.0': {}
|
||||
|
||||
'@ampproject/remapping@2.3.0':
|
||||
@@ -13506,6 +13637,8 @@ snapshots:
|
||||
|
||||
'@sqltools/formatter@1.2.5': {}
|
||||
|
||||
'@standard-schema/spec@1.0.0': {}
|
||||
|
||||
'@standard-schema/utils@0.3.0': {}
|
||||
|
||||
'@storybook/addon-a11y@9.0.15(storybook@9.0.15(@testing-library/dom@8.20.1)(prettier@3.5.3))':
|
||||
@@ -14624,6 +14757,14 @@ snapshots:
|
||||
indent-string: 4.0.0
|
||||
optional: true
|
||||
|
||||
ai@5.0.2(zod@3.24.4):
|
||||
dependencies:
|
||||
'@ai-sdk/gateway': 1.0.0(zod@3.24.4)
|
||||
'@ai-sdk/provider': 2.0.0
|
||||
'@ai-sdk/provider-utils': 3.0.0(zod@3.24.4)
|
||||
'@opentelemetry/api': 1.9.0
|
||||
zod: 3.24.4
|
||||
|
||||
ajv-draft-04@1.0.0(ajv@8.13.0):
|
||||
optionalDependencies:
|
||||
ajv: 8.13.0
|
||||
@@ -16043,6 +16184,8 @@ snapshots:
|
||||
|
||||
events@3.3.0: {}
|
||||
|
||||
eventsource-parser@3.0.3: {}
|
||||
|
||||
expand-template@2.0.3: {}
|
||||
|
||||
expect-type@1.2.2: {}
|
||||
@@ -16926,6 +17069,8 @@ snapshots:
|
||||
|
||||
json-schema-traverse@1.0.0: {}
|
||||
|
||||
json-schema@0.4.0: {}
|
||||
|
||||
json-stable-stringify-without-jsonify@1.0.1: {}
|
||||
|
||||
json5@1.0.2:
|
||||
@@ -19879,4 +20024,8 @@ snapshots:
|
||||
dependencies:
|
||||
zod: 3.24.4
|
||||
|
||||
zod-to-json-schema@3.24.6(zod@3.24.4):
|
||||
dependencies:
|
||||
zod: 3.24.4
|
||||
|
||||
zod@3.24.4: {}
|
||||
|
||||
Reference in New Issue
Block a user