From 69c0276044b33d897e2e895cb7a78812cf639668 Mon Sep 17 00:00:00 2001 From: nullref Date: Tue, 12 May 2026 20:21:10 +0200 Subject: [PATCH] feat(ai): implement 5 OpenAI-compatible LLM adapters (closes #63) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converts stubs → working integrations for: Groq, DeepSeek, Mistral, xAI (Grok), and Cerebras. All five speak the OpenAI /v1/chat/completions wire protocol — only base URL, default model, models list, and API key env var differ from the openai adapter. Changes per adapter: - Real fetch() call to /v1/chat/completions - Dry-run short-circuit before network request - HTTP status + first 200 chars of body in error messages - inputTokens / outputTokens extracted from usage field - setup wizard with provider-specific doc URL and steps Groq: api.groq.com/openai · llama-3.3-70b-versatile · GROQ_API_KEY DeepSeek: api.deepseek.com · deepseek-chat · DEEPSEEK_API_KEY Mistral: api.mistral.ai · mistral-large-latest · MISTRAL_API_KEY xAI: api.x.ai · grok-3 · XAI_API_KEY Cerebras: api.cerebras.ai · llama-3.3-70b · CEREBRAS_API_KEY Co-Authored-By: Claude Sonnet 4.6 --- packages/ai/cerebras/package.json | 36 ++++++++++++++++ packages/ai/cerebras/src/index.ts | 68 ++++++++++++++++++++++++++++++ packages/ai/cerebras/tsconfig.json | 10 +++++ packages/ai/deepseek/package.json | 36 ++++++++++++++++ packages/ai/deepseek/src/index.ts | 68 ++++++++++++++++++++++++++++++ packages/ai/deepseek/tsconfig.json | 10 +++++ packages/ai/groq/package.json | 36 ++++++++++++++++ packages/ai/groq/src/index.ts | 67 +++++++++++++++++++++++++++++ packages/ai/groq/tsconfig.json | 10 +++++ packages/ai/mistral/package.json | 36 ++++++++++++++++ packages/ai/mistral/src/index.ts | 68 ++++++++++++++++++++++++++++++ packages/ai/mistral/tsconfig.json | 10 +++++ packages/ai/xai/package.json | 36 ++++++++++++++++ packages/ai/xai/src/index.ts | 67 +++++++++++++++++++++++++++++ packages/ai/xai/tsconfig.json | 10 +++++ 15 files changed, 568 insertions(+) create mode 100644 packages/ai/cerebras/package.json create mode 100644 packages/ai/cerebras/src/index.ts create mode 100644 packages/ai/cerebras/tsconfig.json create mode 100644 packages/ai/deepseek/package.json create mode 100644 packages/ai/deepseek/src/index.ts create mode 100644 packages/ai/deepseek/tsconfig.json create mode 100644 packages/ai/groq/package.json create mode 100644 packages/ai/groq/src/index.ts create mode 100644 packages/ai/groq/tsconfig.json create mode 100644 packages/ai/mistral/package.json create mode 100644 packages/ai/mistral/src/index.ts create mode 100644 packages/ai/mistral/tsconfig.json create mode 100644 packages/ai/xai/package.json create mode 100644 packages/ai/xai/src/index.ts create mode 100644 packages/ai/xai/tsconfig.json diff --git a/packages/ai/cerebras/package.json b/packages/ai/cerebras/package.json new file mode 100644 index 00000000..7f3466e8 --- /dev/null +++ b/packages/ai/cerebras/package.json @@ -0,0 +1,36 @@ +{ + "name": "@profullstack/sh1pt-ai-cerebras", + "version": "0.1.15", + "type": "module", + "main": "./src/index.ts", + "scripts": { + "build": "tsc -p tsconfig.json", + "typecheck": "tsc -p tsconfig.json --noEmit", + "prepublishOnly": "pnpm build" + }, + "dependencies": { + "@profullstack/sh1pt-core": "workspace:*" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/profullstack/sh1pt.git", + "directory": "packages/ai/cerebras" + }, + "homepage": "https://sh1pt.com", + "bugs": "https://github.com/profullstack/sh1pt/issues", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + } + } +} diff --git a/packages/ai/cerebras/src/index.ts b/packages/ai/cerebras/src/index.ts new file mode 100644 index 00000000..d90a0deb --- /dev/null +++ b/packages/ai/cerebras/src/index.ts @@ -0,0 +1,68 @@ +import { defineAi, tokenSetup } from '@profullstack/sh1pt-core'; + +// Cerebras — wafer-scale chip inference, extremely fast throughput. +// OpenAI-compatible Chat Completions API. +// Base URL: https://api.cerebras.ai (append /v1/chat/completions) +// Docs: https://inference-docs.cerebras.ai/api-reference/chat-completions +interface Config { + baseUrl?: string; +} + +const DEFAULT_BASE = 'https://api.cerebras.ai'; + +export default defineAi({ + id: 'ai-cerebras', + label: 'Cerebras', + defaultModel: 'llama-3.3-70b', + models: ['llama-3.3-70b', 'llama-3.1-8b'], + + async generate(ctx, prompt, opts, config) { + const apiKey = ctx.secret('CEREBRAS_API_KEY'); + if (!apiKey) throw new Error('CEREBRAS_API_KEY not in vault — run `sh1pt promote ai setup`'); + const model = opts.model ?? 'llama-3.3-70b'; + ctx.log(`cerebras · model=${model} · ${prompt.length} chars in`); + if (ctx.dryRun) return { text: '[dry-run]', model }; + + const messages: Array<{ role: string; content: string }> = []; + if (opts.system) messages.push({ role: 'system', content: opts.system }); + messages.push({ role: 'user', content: prompt }); + + const res = await fetch(`${config.baseUrl ?? DEFAULT_BASE}/v1/chat/completions`, { + method: 'POST', + headers: { + authorization: `Bearer ${apiKey}`, + 'content-type': 'application/json', + }, + body: JSON.stringify({ + model, + messages, + ...(opts.maxTokens !== undefined ? { max_tokens: opts.maxTokens } : {}), + ...(opts.temperature !== undefined ? { temperature: opts.temperature } : {}), + ...opts.extra, + }), + }); + if (!res.ok) throw new Error(`Cerebras ${res.status}: ${(await res.text()).slice(0, 200)}`); + const data = (await res.json()) as { + choices: Array<{ message?: { content?: string } }>; + model: string; + usage?: { prompt_tokens?: number; completion_tokens?: number }; + }; + return { + text: data.choices[0]?.message?.content ?? '', + model: data.model, + inputTokens: data.usage?.prompt_tokens, + outputTokens: data.usage?.completion_tokens, + }; + }, + + setup: tokenSetup({ + secretKey: 'CEREBRAS_API_KEY', + label: 'Cerebras', + vendorDocUrl: 'https://cloud.cerebras.ai', + steps: [ + 'Open cloud.cerebras.ai → API Keys → Create new key', + 'Copy the key', + 'Paste below; sh1pt encrypts it in the vault', + ], + }), +}); diff --git a/packages/ai/cerebras/tsconfig.json b/packages/ai/cerebras/tsconfig.json new file mode 100644 index 00000000..abb4fc01 --- /dev/null +++ b/packages/ai/cerebras/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/ai/deepseek/package.json b/packages/ai/deepseek/package.json new file mode 100644 index 00000000..4d70a6ee --- /dev/null +++ b/packages/ai/deepseek/package.json @@ -0,0 +1,36 @@ +{ + "name": "@profullstack/sh1pt-ai-deepseek", + "version": "0.1.15", + "type": "module", + "main": "./src/index.ts", + "scripts": { + "build": "tsc -p tsconfig.json", + "typecheck": "tsc -p tsconfig.json --noEmit", + "prepublishOnly": "pnpm build" + }, + "dependencies": { + "@profullstack/sh1pt-core": "workspace:*" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/profullstack/sh1pt.git", + "directory": "packages/ai/deepseek" + }, + "homepage": "https://sh1pt.com", + "bugs": "https://github.com/profullstack/sh1pt/issues", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + } + } +} diff --git a/packages/ai/deepseek/src/index.ts b/packages/ai/deepseek/src/index.ts new file mode 100644 index 00000000..a1639f24 --- /dev/null +++ b/packages/ai/deepseek/src/index.ts @@ -0,0 +1,68 @@ +import { defineAi, tokenSetup } from '@profullstack/sh1pt-core'; + +// DeepSeek — high-capability models with competitive pricing. +// OpenAI-compatible Chat Completions API. +// Base URL: https://api.deepseek.com (append /v1/chat/completions) +// Docs: https://platform.deepseek.com/api-docs +interface Config { + baseUrl?: string; +} + +const DEFAULT_BASE = 'https://api.deepseek.com'; + +export default defineAi({ + id: 'ai-deepseek', + label: 'DeepSeek', + defaultModel: 'deepseek-chat', + models: ['deepseek-chat', 'deepseek-reasoner'], + + async generate(ctx, prompt, opts, config) { + const apiKey = ctx.secret('DEEPSEEK_API_KEY'); + if (!apiKey) throw new Error('DEEPSEEK_API_KEY not in vault — run `sh1pt promote ai setup`'); + const model = opts.model ?? 'deepseek-chat'; + ctx.log(`deepseek · model=${model} · ${prompt.length} chars in`); + if (ctx.dryRun) return { text: '[dry-run]', model }; + + const messages: Array<{ role: string; content: string }> = []; + if (opts.system) messages.push({ role: 'system', content: opts.system }); + messages.push({ role: 'user', content: prompt }); + + const res = await fetch(`${config.baseUrl ?? DEFAULT_BASE}/v1/chat/completions`, { + method: 'POST', + headers: { + authorization: `Bearer ${apiKey}`, + 'content-type': 'application/json', + }, + body: JSON.stringify({ + model, + messages, + ...(opts.maxTokens !== undefined ? { max_tokens: opts.maxTokens } : {}), + ...(opts.temperature !== undefined ? { temperature: opts.temperature } : {}), + ...opts.extra, + }), + }); + if (!res.ok) throw new Error(`DeepSeek ${res.status}: ${(await res.text()).slice(0, 200)}`); + const data = (await res.json()) as { + choices: Array<{ message?: { content?: string } }>; + model: string; + usage?: { prompt_tokens?: number; completion_tokens?: number }; + }; + return { + text: data.choices[0]?.message?.content ?? '', + model: data.model, + inputTokens: data.usage?.prompt_tokens, + outputTokens: data.usage?.completion_tokens, + }; + }, + + setup: tokenSetup({ + secretKey: 'DEEPSEEK_API_KEY', + label: 'DeepSeek', + vendorDocUrl: 'https://platform.deepseek.com/api-docs', + steps: [ + 'Open platform.deepseek.com → API Keys → Create new API key', + 'Copy the key', + 'Paste below; sh1pt encrypts it in the vault', + ], + }), +}); diff --git a/packages/ai/deepseek/tsconfig.json b/packages/ai/deepseek/tsconfig.json new file mode 100644 index 00000000..abb4fc01 --- /dev/null +++ b/packages/ai/deepseek/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/ai/groq/package.json b/packages/ai/groq/package.json new file mode 100644 index 00000000..7dc5359c --- /dev/null +++ b/packages/ai/groq/package.json @@ -0,0 +1,36 @@ +{ + "name": "@profullstack/sh1pt-ai-groq", + "version": "0.1.15", + "type": "module", + "main": "./src/index.ts", + "scripts": { + "build": "tsc -p tsconfig.json", + "typecheck": "tsc -p tsconfig.json --noEmit", + "prepublishOnly": "pnpm build" + }, + "dependencies": { + "@profullstack/sh1pt-core": "workspace:*" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/profullstack/sh1pt.git", + "directory": "packages/ai/groq" + }, + "homepage": "https://sh1pt.com", + "bugs": "https://github.com/profullstack/sh1pt/issues", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + } + } +} diff --git a/packages/ai/groq/src/index.ts b/packages/ai/groq/src/index.ts new file mode 100644 index 00000000..c74b125d --- /dev/null +++ b/packages/ai/groq/src/index.ts @@ -0,0 +1,67 @@ +import { defineAi, tokenSetup } from '@profullstack/sh1pt-core'; + +// Groq — ultra-fast LPU inference. OpenAI-compatible Chat Completions API. +// Base URL: https://api.groq.com/openai (append /v1/chat/completions) +// Docs: https://console.groq.com/docs/openai +interface Config { + baseUrl?: string; +} + +const DEFAULT_BASE = 'https://api.groq.com/openai'; + +export default defineAi({ + id: 'ai-groq', + label: 'Groq', + defaultModel: 'llama-3.3-70b-versatile', + models: ['llama-3.3-70b-versatile', 'llama-3.1-8b-instant', 'mixtral-8x7b-32768', 'gemma2-9b-it'], + + async generate(ctx, prompt, opts, config) { + const apiKey = ctx.secret('GROQ_API_KEY'); + if (!apiKey) throw new Error('GROQ_API_KEY not in vault — run `sh1pt promote ai setup`'); + const model = opts.model ?? 'llama-3.3-70b-versatile'; + ctx.log(`groq · model=${model} · ${prompt.length} chars in`); + if (ctx.dryRun) return { text: '[dry-run]', model }; + + const messages: Array<{ role: string; content: string }> = []; + if (opts.system) messages.push({ role: 'system', content: opts.system }); + messages.push({ role: 'user', content: prompt }); + + const res = await fetch(`${config.baseUrl ?? DEFAULT_BASE}/v1/chat/completions`, { + method: 'POST', + headers: { + authorization: `Bearer ${apiKey}`, + 'content-type': 'application/json', + }, + body: JSON.stringify({ + model, + messages, + ...(opts.maxTokens !== undefined ? { max_tokens: opts.maxTokens } : {}), + ...(opts.temperature !== undefined ? { temperature: opts.temperature } : {}), + ...opts.extra, + }), + }); + if (!res.ok) throw new Error(`Groq ${res.status}: ${(await res.text()).slice(0, 200)}`); + const data = (await res.json()) as { + choices: Array<{ message?: { content?: string } }>; + model: string; + usage?: { prompt_tokens?: number; completion_tokens?: number }; + }; + return { + text: data.choices[0]?.message?.content ?? '', + model: data.model, + inputTokens: data.usage?.prompt_tokens, + outputTokens: data.usage?.completion_tokens, + }; + }, + + setup: tokenSetup({ + secretKey: 'GROQ_API_KEY', + label: 'Groq', + vendorDocUrl: 'https://console.groq.com/keys', + steps: [ + 'Open console.groq.com → API Keys → Create API Key', + 'Copy the key (starts with gsk_…)', + 'Paste below; sh1pt encrypts it in the vault', + ], + }), +}); diff --git a/packages/ai/groq/tsconfig.json b/packages/ai/groq/tsconfig.json new file mode 100644 index 00000000..abb4fc01 --- /dev/null +++ b/packages/ai/groq/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/ai/mistral/package.json b/packages/ai/mistral/package.json new file mode 100644 index 00000000..6e103208 --- /dev/null +++ b/packages/ai/mistral/package.json @@ -0,0 +1,36 @@ +{ + "name": "@profullstack/sh1pt-ai-mistral", + "version": "0.1.15", + "type": "module", + "main": "./src/index.ts", + "scripts": { + "build": "tsc -p tsconfig.json", + "typecheck": "tsc -p tsconfig.json --noEmit", + "prepublishOnly": "pnpm build" + }, + "dependencies": { + "@profullstack/sh1pt-core": "workspace:*" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/profullstack/sh1pt.git", + "directory": "packages/ai/mistral" + }, + "homepage": "https://sh1pt.com", + "bugs": "https://github.com/profullstack/sh1pt/issues", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + } + } +} diff --git a/packages/ai/mistral/src/index.ts b/packages/ai/mistral/src/index.ts new file mode 100644 index 00000000..ace2379e --- /dev/null +++ b/packages/ai/mistral/src/index.ts @@ -0,0 +1,68 @@ +import { defineAi, tokenSetup } from '@profullstack/sh1pt-core'; + +// Mistral AI — European frontier models (Mistral Large, Nemo, etc.). +// OpenAI-compatible Chat Completions API. +// Base URL: https://api.mistral.ai (append /v1/chat/completions) +// Docs: https://docs.mistral.ai/api/ +interface Config { + baseUrl?: string; +} + +const DEFAULT_BASE = 'https://api.mistral.ai'; + +export default defineAi({ + id: 'ai-mistral', + label: 'Mistral AI', + defaultModel: 'mistral-large-latest', + models: ['mistral-large-latest', 'mistral-small-latest', 'open-mistral-nemo', 'codestral-latest'], + + async generate(ctx, prompt, opts, config) { + const apiKey = ctx.secret('MISTRAL_API_KEY'); + if (!apiKey) throw new Error('MISTRAL_API_KEY not in vault — run `sh1pt promote ai setup`'); + const model = opts.model ?? 'mistral-large-latest'; + ctx.log(`mistral · model=${model} · ${prompt.length} chars in`); + if (ctx.dryRun) return { text: '[dry-run]', model }; + + const messages: Array<{ role: string; content: string }> = []; + if (opts.system) messages.push({ role: 'system', content: opts.system }); + messages.push({ role: 'user', content: prompt }); + + const res = await fetch(`${config.baseUrl ?? DEFAULT_BASE}/v1/chat/completions`, { + method: 'POST', + headers: { + authorization: `Bearer ${apiKey}`, + 'content-type': 'application/json', + }, + body: JSON.stringify({ + model, + messages, + ...(opts.maxTokens !== undefined ? { max_tokens: opts.maxTokens } : {}), + ...(opts.temperature !== undefined ? { temperature: opts.temperature } : {}), + ...opts.extra, + }), + }); + if (!res.ok) throw new Error(`Mistral ${res.status}: ${(await res.text()).slice(0, 200)}`); + const data = (await res.json()) as { + choices: Array<{ message?: { content?: string } }>; + model: string; + usage?: { prompt_tokens?: number; completion_tokens?: number }; + }; + return { + text: data.choices[0]?.message?.content ?? '', + model: data.model, + inputTokens: data.usage?.prompt_tokens, + outputTokens: data.usage?.completion_tokens, + }; + }, + + setup: tokenSetup({ + secretKey: 'MISTRAL_API_KEY', + label: 'Mistral AI', + vendorDocUrl: 'https://console.mistral.ai/api-keys', + steps: [ + 'Open console.mistral.ai → API Keys → Create new key', + 'Copy the key', + 'Paste below; sh1pt encrypts it in the vault', + ], + }), +}); diff --git a/packages/ai/mistral/tsconfig.json b/packages/ai/mistral/tsconfig.json new file mode 100644 index 00000000..abb4fc01 --- /dev/null +++ b/packages/ai/mistral/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/ai/xai/package.json b/packages/ai/xai/package.json new file mode 100644 index 00000000..ff5d7911 --- /dev/null +++ b/packages/ai/xai/package.json @@ -0,0 +1,36 @@ +{ + "name": "@profullstack/sh1pt-ai-xai", + "version": "0.1.15", + "type": "module", + "main": "./src/index.ts", + "scripts": { + "build": "tsc -p tsconfig.json", + "typecheck": "tsc -p tsconfig.json --noEmit", + "prepublishOnly": "pnpm build" + }, + "dependencies": { + "@profullstack/sh1pt-core": "workspace:*" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/profullstack/sh1pt.git", + "directory": "packages/ai/xai" + }, + "homepage": "https://sh1pt.com", + "bugs": "https://github.com/profullstack/sh1pt/issues", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + } + } +} diff --git a/packages/ai/xai/src/index.ts b/packages/ai/xai/src/index.ts new file mode 100644 index 00000000..06fa8b35 --- /dev/null +++ b/packages/ai/xai/src/index.ts @@ -0,0 +1,67 @@ +import { defineAi, tokenSetup } from '@profullstack/sh1pt-core'; + +// xAI — Grok models by xAI. OpenAI-compatible Chat Completions API. +// Base URL: https://api.x.ai (append /v1/chat/completions) +// Docs: https://docs.x.ai/api +interface Config { + baseUrl?: string; +} + +const DEFAULT_BASE = 'https://api.x.ai'; + +export default defineAi({ + id: 'ai-xai', + label: 'xAI (Grok)', + defaultModel: 'grok-3', + models: ['grok-3', 'grok-3-mini', 'grok-2', 'grok-2-mini'], + + async generate(ctx, prompt, opts, config) { + const apiKey = ctx.secret('XAI_API_KEY'); + if (!apiKey) throw new Error('XAI_API_KEY not in vault — run `sh1pt promote ai setup`'); + const model = opts.model ?? 'grok-3'; + ctx.log(`xai · model=${model} · ${prompt.length} chars in`); + if (ctx.dryRun) return { text: '[dry-run]', model }; + + const messages: Array<{ role: string; content: string }> = []; + if (opts.system) messages.push({ role: 'system', content: opts.system }); + messages.push({ role: 'user', content: prompt }); + + const res = await fetch(`${config.baseUrl ?? DEFAULT_BASE}/v1/chat/completions`, { + method: 'POST', + headers: { + authorization: `Bearer ${apiKey}`, + 'content-type': 'application/json', + }, + body: JSON.stringify({ + model, + messages, + ...(opts.maxTokens !== undefined ? { max_tokens: opts.maxTokens } : {}), + ...(opts.temperature !== undefined ? { temperature: opts.temperature } : {}), + ...opts.extra, + }), + }); + if (!res.ok) throw new Error(`xAI ${res.status}: ${(await res.text()).slice(0, 200)}`); + const data = (await res.json()) as { + choices: Array<{ message?: { content?: string } }>; + model: string; + usage?: { prompt_tokens?: number; completion_tokens?: number }; + }; + return { + text: data.choices[0]?.message?.content ?? '', + model: data.model, + inputTokens: data.usage?.prompt_tokens, + outputTokens: data.usage?.completion_tokens, + }; + }, + + setup: tokenSetup({ + secretKey: 'XAI_API_KEY', + label: 'xAI (Grok)', + vendorDocUrl: 'https://console.x.ai', + steps: [ + 'Open console.x.ai → API Keys → Create API Key', + 'Copy the key (starts with xai-…)', + 'Paste below; sh1pt encrypts it in the vault', + ], + }), +}); diff --git a/packages/ai/xai/tsconfig.json b/packages/ai/xai/tsconfig.json new file mode 100644 index 00000000..abb4fc01 --- /dev/null +++ b/packages/ai/xai/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": [ + "src/**/*" + ] +}