mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-07 02:58:11 +00:00
Add AI SDK Utilities (#375)
### TL;DR
Upgraded Biome to v2.2.0 and added a new AI SDK package for supermemory integration.
### What changed?
- Updated Biome configuration with enhanced linting rules and formatting options
- Upgraded `@biomejs/biome` from v2.1.3 to v2.2.0
- Added a new `@supermemory/ai-sdk` package with:
- Infinite Chat Provider for connecting to various LLM providers with unlimited context
- Memory Tools for searching, adding, and fetching memories from supermemory
- Comprehensive test suite for both features
- Detailed README with usage examples and configuration options
- Removed unused ESLint and TypeScript configuration packages
### How to test?
1. Run `bun install` to update dependencies
2. Test the new AI SDK:
3. Verify Biome works with the updated configuration:
### Why make this change?
The new AI SDK package provides integration with Vercel's AI SDK, allowing developers to use supermemory's context management with various LLM providers. This enables unlimited context support and memory tools for AI agents. The Biome upgrade brings improved linting and formatting capabilities, enhancing code quality across the project.
This commit is contained in:
parent
9e1e392a2b
commit
8ff3c75847
20 changed files with 1183 additions and 250 deletions
140
biome.json
140
biome.json
|
|
@ -1,75 +1,105 @@
|
|||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
|
||||
"assist": {
|
||||
"actions": {
|
||||
"source": {
|
||||
"organizeImports": "on",
|
||||
"useSortedAttributes": "on",
|
||||
"useSortedKeys": "off"
|
||||
}
|
||||
},
|
||||
"enabled": true
|
||||
},
|
||||
"files": {
|
||||
"includes": [
|
||||
"**/*.js",
|
||||
"**/*.jsx",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.json",
|
||||
"**/*.jsonc",
|
||||
"**",
|
||||
"!**/node_modules",
|
||||
"!**/.next/",
|
||||
"!**/.contentlayer",
|
||||
"!**/.vercel",
|
||||
"!**/.react-router",
|
||||
"!**/.wrangler",
|
||||
"!**/package.json",
|
||||
"!**/worker-configuration.d.ts",
|
||||
"!**/.turbo/",
|
||||
"!**/.vercel",
|
||||
"!**/dist",
|
||||
"!**/.astro",
|
||||
"!**/build",
|
||||
"!**/.next",
|
||||
"!**/.turbo",
|
||||
"!**/*.d.ts"
|
||||
"!**/.alchemy",
|
||||
"!**/.build",
|
||||
"!**/.open-next",
|
||||
"!**/*.astro"
|
||||
]
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "tab",
|
||||
"indentWidth": 2,
|
||||
"lineEnding": "lf",
|
||||
"lineWidth": 80,
|
||||
"attributePosition": "auto",
|
||||
"includes": ["**", "!**/*.md"]
|
||||
},
|
||||
"assist": { "actions": { "source": { "organizeImports": "on" } } },
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"a11y": {
|
||||
"recommended": true
|
||||
},
|
||||
"complexity": {
|
||||
"recommended": true
|
||||
},
|
||||
"correctness": {
|
||||
"recommended": true
|
||||
},
|
||||
"performance": {
|
||||
"recommended": true
|
||||
},
|
||||
"security": {
|
||||
"recommended": true
|
||||
},
|
||||
"style": {
|
||||
"recommended": true
|
||||
},
|
||||
"suspicious": {
|
||||
"recommended": true
|
||||
}
|
||||
}
|
||||
"indentStyle": "tab"
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "double",
|
||||
"jsxQuoteStyle": "double",
|
||||
"trailingCommas": "all",
|
||||
"semicolons": "asNeeded",
|
||||
"arrowParentheses": "always",
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": false,
|
||||
"quoteProperties": "asNeeded",
|
||||
"attributePosition": "auto"
|
||||
"semicolons": "asNeeded"
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"formatter": {
|
||||
"trailingCommas": "none"
|
||||
"linter": {
|
||||
"domains": {
|
||||
"project": "none"
|
||||
},
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"a11y": {
|
||||
"useValidAnchor": "warn"
|
||||
},
|
||||
"correctness": {
|
||||
"noUnusedVariables": {
|
||||
"level": "warn",
|
||||
"options": {
|
||||
"ignoreRestSiblings": true
|
||||
}
|
||||
},
|
||||
"useExhaustiveDependencies": "warn",
|
||||
"noUnusedImports": "warn"
|
||||
},
|
||||
"recommended": true,
|
||||
"style": {
|
||||
"noDefaultExport": "off",
|
||||
"noInferrableTypes": "error",
|
||||
"noNonNullAssertion": "warn",
|
||||
"noParameterAssign": "error",
|
||||
"noUnusedTemplateLiteral": "error",
|
||||
"noUselessElse": "error",
|
||||
"useAsConstAssertion": "error",
|
||||
"useDefaultParameterLast": "error",
|
||||
"useEnumInitializers": "error",
|
||||
"useNamingConvention": {
|
||||
"level": "off",
|
||||
"options": {
|
||||
"strictCase": false
|
||||
}
|
||||
},
|
||||
"useNumberNamespace": "error",
|
||||
"useSelfClosingElements": "error",
|
||||
"useSingleVarDeclarator": "error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"includes": ["**/*.astro"],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"correctness": {
|
||||
"noUnusedVariables": "off",
|
||||
"noUnusedImports": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"vcs": {
|
||||
"clientKind": "git",
|
||||
"enabled": true,
|
||||
"useIgnoreFile": true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
|
@ -50,7 +50,7 @@
|
|||
"zod-openapi": "^4.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.1.3",
|
||||
"@biomejs/biome": "^2.2.0",
|
||||
"@total-typescript/tsconfig": "^1.0.4",
|
||||
"@types/pg": "^8.15.4",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
|
|
|
|||
313
packages/ai-sdk/README.md
Normal file
313
packages/ai-sdk/README.md
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
# supermemory AI SDK Utilities
|
||||
|
||||
Vercel AI SDK utilities for supermemory
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @supermemory/ai-sdk
|
||||
# or
|
||||
bun add @supermemory/ai-sdk
|
||||
# or
|
||||
pnpm add @supermemory/ai-sdk
|
||||
# or
|
||||
yarn add @supermemory/ai-sdk
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
Choose **one** of the following approaches (they cannot be used together):
|
||||
|
||||
- **Infinite Chat Provider**: Connect to various LLM providers with unlimited context support
|
||||
- **Memory Tools**: Search, add, and fetch memories from supermemory using AI agents
|
||||
|
||||
## Infinite Chat Provider
|
||||
|
||||
The infinite chat provider allows you to connect to various LLM providers with supermemory's context management.
|
||||
|
||||
```typescript
|
||||
import { createSupermemoryInfiniteChat } from '@supermemory/ai-sdk'
|
||||
import { generateText } from 'ai'
|
||||
|
||||
// Using a named provider
|
||||
const supermemory = createSupermemoryInfiniteChat('your-supermemory-api-key', {
|
||||
providerName: 'openai',
|
||||
providerApiKey: 'your-openai-api-key',
|
||||
headers: {
|
||||
// Optional additional headers
|
||||
}
|
||||
})
|
||||
|
||||
// Using a custom provider URL
|
||||
const supermemory = createSupermemoryInfiniteChat('your-supermemory-api-key', {
|
||||
providerUrl: 'https://your-custom-provider.com/v1/chat/completions',
|
||||
providerApiKey: 'your-provider-api-key',
|
||||
headers: {
|
||||
// Optional additional headers
|
||||
}
|
||||
})
|
||||
|
||||
const result = await generateText({
|
||||
model: supermemory('gpt-4-turbo'),
|
||||
messages: [
|
||||
{ role: 'user', content: 'Hello, how are you?' }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
### Complete Infinite Chat Example
|
||||
|
||||
```typescript
|
||||
import { createSupermemoryInfiniteChat } from '@supermemory/ai-sdk'
|
||||
import { generateText } from 'ai'
|
||||
|
||||
const supermemoryApiKey = process.env.SUPERMEMORY_API_KEY!
|
||||
const openaiApiKey = process.env.OPENAI_API_KEY!
|
||||
|
||||
// Initialize infinite chat provider
|
||||
const supermemory = createSupermemoryInfiniteChat(supermemoryApiKey, {
|
||||
providerName: 'openai',
|
||||
providerApiKey: openaiApiKey,
|
||||
headers: {}
|
||||
})
|
||||
|
||||
async function chat(userMessage: string) {
|
||||
const result = await generateText({
|
||||
model: supermemory('gpt-4-turbo'),
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: 'You are a helpful assistant with unlimited context.'
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: userMessage
|
||||
}
|
||||
]
|
||||
// No tools - infinite chat handles context automatically
|
||||
})
|
||||
|
||||
return result.text
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```typescript
|
||||
// Option 1: Use a named provider
|
||||
interface ConfigWithProviderName {
|
||||
providerName: 'openai' | 'anthropic' | 'openrouter' | 'deepinfra' | 'groq' | 'google' | 'cloudflare'
|
||||
providerApiKey: string
|
||||
headers?: Record<string, string>
|
||||
}
|
||||
|
||||
// Option 2: Use a custom provider URL
|
||||
interface ConfigWithProviderUrl {
|
||||
providerUrl: string
|
||||
providerApiKey: string
|
||||
headers?: Record<string, string>
|
||||
}
|
||||
```
|
||||
|
||||
## Memory Tools
|
||||
|
||||
supermemory tools allow AI agents to interact with user memories for enhanced context and personalization.
|
||||
|
||||
```typescript
|
||||
import { supermemoryTools } from '@supermemory/ai-sdk'
|
||||
import { generateText } from 'ai'
|
||||
|
||||
const result = await generateText({
|
||||
model: openai('gpt-4-turbo'),
|
||||
messages: [
|
||||
{ role: 'user', content: 'What do you remember about my preferences?' }
|
||||
],
|
||||
tools: {
|
||||
...supermemoryTools('your-supermemory-api-key', {
|
||||
// Optional: specify a base URL for self-hosted instances
|
||||
baseUrl: 'https://api.supermemory.com',
|
||||
|
||||
// Use either projectId OR containerTags, not both
|
||||
projectId: 'your-project-id',
|
||||
// OR
|
||||
containerTags: ['tag1', 'tag2']
|
||||
}),
|
||||
// Your other tools go here
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Complete Memory Tools Example
|
||||
|
||||
```typescript
|
||||
import { supermemoryTools } from '@supermemory/ai-sdk'
|
||||
import { generateText } from 'ai'
|
||||
import { openai } from '@ai-sdk/openai'
|
||||
|
||||
const supermemoryApiKey = process.env.SUPERMEMORY_API_KEY!
|
||||
|
||||
async function chatWithTools(userMessage: string) {
|
||||
const result = await generateText({
|
||||
model: openai('gpt-4-turbo'), // Use standard provider
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: 'You are a helpful assistant with access to user memories.'
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: userMessage
|
||||
}
|
||||
],
|
||||
tools: {
|
||||
...supermemoryTools(supermemoryApiKey, {
|
||||
projectId: 'my-project'
|
||||
})
|
||||
},
|
||||
maxToolRoundtrips: 5
|
||||
})
|
||||
|
||||
return result.text
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```typescript
|
||||
interface SupermemoryConfig {
|
||||
// Optional: Base URL for API calls (default: https://api.supermemory.com)
|
||||
baseUrl?: string
|
||||
|
||||
// Container tags for organizing memories (cannot be used with projectId)
|
||||
containerTags?: string[]
|
||||
|
||||
// Project ID for scoping memories (cannot be used with containerTags)
|
||||
projectId?: string
|
||||
}
|
||||
```
|
||||
|
||||
### Self-Hosted supermemory
|
||||
|
||||
If you're running a self-hosted supermemory instance:
|
||||
|
||||
```typescript
|
||||
const tools = supermemoryTools('your-api-key', {
|
||||
baseUrl: 'https://your-supermemory-instance.com',
|
||||
containerTags: ['production', 'user-memories']
|
||||
})
|
||||
```
|
||||
|
||||
### Available Tools
|
||||
|
||||
##### Search Memories
|
||||
|
||||
Search through user memories using semantic matching.
|
||||
|
||||
```typescript
|
||||
const searchResult = await tools.searchMemories.execute({
|
||||
informationToGet: 'user preferences about coffee'
|
||||
})
|
||||
```
|
||||
|
||||
##### Add Memory
|
||||
|
||||
Add new memories to the user's memory store.
|
||||
|
||||
```typescript
|
||||
const addResult = await tools.addMemory.execute({
|
||||
memory: 'User prefers dark roast coffee in the morning'
|
||||
})
|
||||
```
|
||||
|
||||
##### Fetch Memory
|
||||
|
||||
Retrieve a specific memory by its ID.
|
||||
|
||||
```typescript
|
||||
const fetchResult = await tools.fetchMemory.execute({
|
||||
memoryId: 'memory-id-123'
|
||||
})
|
||||
```
|
||||
|
||||
### Using Individual Tools
|
||||
|
||||
For more flexibility, you can import and use individual tools:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
searchMemoriesTool,
|
||||
addMemoryTool,
|
||||
fetchMemoryTool
|
||||
} from '@supermemory/ai-sdk'
|
||||
|
||||
const searchTool = searchMemoriesTool('your-api-key', {
|
||||
projectId: 'your-project-id'
|
||||
})
|
||||
|
||||
// Use only the search tool
|
||||
const result = await generateText({
|
||||
model: openai('gpt-4-turbo'),
|
||||
messages: [...],
|
||||
tools: {
|
||||
searchMemories: searchTool
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
All tool executions return a result object with a `success` field:
|
||||
|
||||
```typescript
|
||||
const result = await tools.searchMemories.execute({
|
||||
informationToGet: 'user preferences'
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
console.log('Found memories:', result.results)
|
||||
console.log('Total count:', result.count)
|
||||
} else {
|
||||
console.error('Error searching memories:', result.error)
|
||||
}
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
bun test
|
||||
|
||||
# Run tests in watch mode
|
||||
bun test --watch
|
||||
```
|
||||
|
||||
#### Environment Variables for Tests
|
||||
|
||||
All tests require API keys to run. Copy `.env.example` to `.env` and set the required values:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
**Required:**
|
||||
- `SUPERMEMORY_API_KEY`: Your Supermemory API key
|
||||
- `PROVIDER_API_KEY`: Your AI provider API key (OpenAI, Anthropic, etc.)
|
||||
- `OPENAI_API_KEY`: Your OpenAI API key for tool integration tests
|
||||
|
||||
**Optional:**
|
||||
- `SUPERMEMORY_BASE_URL`: Custom Supermemory base URL (defaults to `https://api.supermemory.ai`)
|
||||
- `PROVIDER_NAME`: Provider name (defaults to `openai`) - one of: `openai`, `anthropic`, `openrouter`, `deepinfra`, `groq`, `google`, `cloudflare`
|
||||
- `PROVIDER_URL`: Custom provider URL (use instead of `PROVIDER_NAME`)
|
||||
- `MODEL_NAME`: Model to use in tests (defaults to `gpt-3.5-turbo`)
|
||||
|
||||
Tests will fail if required API keys are not provided.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Support
|
||||
|
||||
Email our [24/7 Founder/CEO/Support Executive](dhravya@supermemory.com)
|
||||
26
packages/ai-sdk/package.json
Normal file
26
packages/ai-sdk/package.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "@supermemory/ai-sdk",
|
||||
"version": "0.0.1",
|
||||
"main": "dist/index.mjs",
|
||||
"types": "dist/index.d.mts",
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"dev": "tsdown --watch",
|
||||
"check-types": "tsc --noEmit",
|
||||
"test": "vitest",
|
||||
"test:watch": "vitest --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/openai": "^2.0.15",
|
||||
"ai": "^5.0.17",
|
||||
"supermemory": "^3.0.0-alpha.22",
|
||||
"zod": "^4.0.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@total-typescript/tsconfig": "^1.0.4",
|
||||
"@types/bun": "^1.2.20",
|
||||
"tsdown": "^0.14.1",
|
||||
"typescript": "^5.9.2",
|
||||
"vitest": "^3.2.4"
|
||||
}
|
||||
}
|
||||
2
packages/ai-sdk/src/index.ts
Normal file
2
packages/ai-sdk/src/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./infinite-chat"
|
||||
export * from "./tools"
|
||||
365
packages/ai-sdk/src/infinite-chat.test.ts
Normal file
365
packages/ai-sdk/src/infinite-chat.test.ts
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
import { generateText } from "ai"
|
||||
import { describe, expect, it } from "vitest"
|
||||
import z from "zod"
|
||||
import {
|
||||
createSupermemoryInfiniteChat,
|
||||
type SupermemoryInfiniteChatConfig,
|
||||
} from "./infinite-chat"
|
||||
|
||||
import "dotenv/config"
|
||||
|
||||
const providers = z.enum([
|
||||
"openai",
|
||||
"anthropic",
|
||||
"openrouter",
|
||||
"deepinfra",
|
||||
"groq",
|
||||
"google",
|
||||
"cloudflare",
|
||||
] satisfies SupermemoryInfiniteChatConfig["providerName"][])
|
||||
|
||||
describe("createSupermemoryInfiniteChat", () => {
|
||||
// Required API keys - tests will fail if not provided
|
||||
const testApiKey = process.env.SUPERMEMORY_API_KEY
|
||||
const testProviderApiKey = process.env.PROVIDER_API_KEY
|
||||
|
||||
if (!testApiKey) {
|
||||
throw new Error(
|
||||
"SUPERMEMORY_API_KEY environment variable is required for tests",
|
||||
)
|
||||
}
|
||||
if (!testProviderApiKey) {
|
||||
throw new Error(
|
||||
"PROVIDER_API_KEY environment variable is required for tests",
|
||||
)
|
||||
}
|
||||
|
||||
// Optional configuration with defaults
|
||||
const testProviderName = providers.parse(
|
||||
process.env.PROVIDER_NAME ?? "openai",
|
||||
)
|
||||
const testProviderUrl = process.env.PROVIDER_URL
|
||||
const testModelName = process.env.MODEL_NAME || "gpt-5-mini"
|
||||
const testHeaders = { "custom-header": "test-value" }
|
||||
|
||||
// Validate provider configuration - either name OR URL, not both
|
||||
if (testProviderUrl && process.env.PROVIDER_NAME) {
|
||||
throw new Error(
|
||||
"Cannot specify both PROVIDER_NAME and PROVIDER_URL - use one or the other",
|
||||
)
|
||||
}
|
||||
|
||||
// Test prompts and inputs
|
||||
const testPrompts = [
|
||||
"Hello, how are you?",
|
||||
"What is 2 + 2?",
|
||||
"Write a short poem about AI",
|
||||
"Explain quantum computing in simple terms",
|
||||
"What can you help me with today?",
|
||||
]
|
||||
|
||||
const testMessages = [
|
||||
[{ role: "user" as const, content: "Hello!" }],
|
||||
[
|
||||
{ role: "system" as const, content: "You are a helpful assistant." },
|
||||
{ role: "user" as const, content: "What is AI?" },
|
||||
],
|
||||
[
|
||||
{ role: "user" as const, content: "Tell me a joke" },
|
||||
{
|
||||
role: "assistant" as const,
|
||||
content:
|
||||
"Why don't scientists trust atoms? Because they make up everything!",
|
||||
},
|
||||
{ role: "user" as const, content: "Tell me another one" },
|
||||
],
|
||||
]
|
||||
|
||||
describe("client creation", () => {
|
||||
it("should create client with configured provider", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: testHeaders,
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: testHeaders,
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
expect(typeof client).toBe("function")
|
||||
})
|
||||
|
||||
it("should create client with openai provider configuration", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = {
|
||||
providerName: "openai",
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: testHeaders,
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
expect(typeof client).toBe("function")
|
||||
})
|
||||
|
||||
it("should create client with anthropic provider configuration", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = {
|
||||
providerName: "anthropic",
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: testHeaders,
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
expect(typeof client).toBe("function")
|
||||
})
|
||||
|
||||
it("should create client with custom provider URL", () => {
|
||||
const customUrl = "https://custom-provider.com/v1/chat"
|
||||
const config: SupermemoryInfiniteChatConfig = {
|
||||
providerUrl: customUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: testHeaders,
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
expect(typeof client).toBe("function")
|
||||
})
|
||||
})
|
||||
|
||||
describe("AI SDK integration", () => {
|
||||
it("should generate text with simple prompt", async () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
console.log(client(testModelName))
|
||||
|
||||
const result = await generateText({
|
||||
model: client(testModelName),
|
||||
prompt: testPrompts[0], // "Hello, how are you?"
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.text).toBeDefined()
|
||||
expect(typeof result.text).toBe("string")
|
||||
expect(result.text.length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it("should generate text with messages array", async () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
const result = await generateText({
|
||||
model: client(testModelName),
|
||||
messages: testMessages[1], // System + user messages
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.text).toBeDefined()
|
||||
expect(typeof result.text).toBe("string")
|
||||
expect(result.text.length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it("should handle conversation history", async () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
const result = await generateText({
|
||||
model: client(testModelName),
|
||||
messages: testMessages[2], // Multi-turn conversation
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.text).toBeDefined()
|
||||
expect(typeof result.text).toBe("string")
|
||||
expect(result.text.length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it("should work with different prompt variations", async () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
// Test multiple prompts
|
||||
for (const prompt of testPrompts.slice(0, 3)) {
|
||||
const result = await generateText({
|
||||
model: client(testModelName),
|
||||
prompt,
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.text).toBeDefined()
|
||||
expect(typeof result.text).toBe("string")
|
||||
expect(result.text.length).toBeGreaterThan(0)
|
||||
}
|
||||
})
|
||||
|
||||
it("should work with configured and alternate models", async () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
const modelsToTest = [testModelName]
|
||||
// Add alternate model for OpenAI
|
||||
if (testProviderName === "openai" && !testProviderUrl) {
|
||||
modelsToTest.push("gpt-4o-mini")
|
||||
}
|
||||
|
||||
for (const modelName of modelsToTest) {
|
||||
const result = await generateText({
|
||||
model: client(modelName),
|
||||
prompt: "Say hello in one word",
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.text).toBeDefined()
|
||||
expect(typeof result.text).toBe("string")
|
||||
}
|
||||
})
|
||||
|
||||
it("should work with custom headers", async () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {
|
||||
"x-custom-header": "test-value",
|
||||
},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {
|
||||
"x-custom-header": "test-value",
|
||||
},
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
const result = await generateText({
|
||||
model: client(testModelName),
|
||||
prompt: "Hello",
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.text).toBeDefined()
|
||||
expect(typeof result.text).toBe("string")
|
||||
})
|
||||
})
|
||||
|
||||
describe("configuration validation", () => {
|
||||
it("should handle empty headers object", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
})
|
||||
|
||||
it("should handle configuration with custom headers", () => {
|
||||
const customHeaders = {
|
||||
authorization: "Bearer custom-token",
|
||||
"x-custom": "custom-value",
|
||||
}
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: customHeaders,
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: customHeaders,
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
})
|
||||
|
||||
it("should handle different API keys", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = {
|
||||
providerName: "openai",
|
||||
providerApiKey: "different-provider-key",
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = createSupermemoryInfiniteChat("different-sm-key", config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
49
packages/ai-sdk/src/infinite-chat.ts
Normal file
49
packages/ai-sdk/src/infinite-chat.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { createOpenAI } from "@ai-sdk/openai"
|
||||
|
||||
interface SupermemoryInfiniteChatConfigBase {
|
||||
providerApiKey: string
|
||||
headers: Record<string, string>
|
||||
}
|
||||
|
||||
interface SupermemoryInfiniteChatConfigWithProviderName
|
||||
extends SupermemoryInfiniteChatConfigBase {
|
||||
providerName: keyof typeof providerMap
|
||||
providerUrl?: never
|
||||
}
|
||||
|
||||
interface SupermemoryInfiniteChatConfigWithProviderUrl
|
||||
extends SupermemoryInfiniteChatConfigBase {
|
||||
providerUrl: string
|
||||
providerName?: never
|
||||
}
|
||||
|
||||
export type SupermemoryInfiniteChatConfig =
|
||||
| SupermemoryInfiniteChatConfigWithProviderName
|
||||
| SupermemoryInfiniteChatConfigWithProviderUrl
|
||||
|
||||
type SupermemoryApiKey = string
|
||||
|
||||
const providerMap = {
|
||||
openai: "https://api.openai.com/v1",
|
||||
anthropic: "https://api.anthropic.com/v1",
|
||||
openrouter: "https://openrouter.ai/api/v1",
|
||||
deepinfra: "https://api.deepinfra.com/v1/openai",
|
||||
groq: "https://api.groq.com/openai/v1",
|
||||
google: "https://generativelanguage.googleapis.com/v1beta/openai",
|
||||
cloudflare: "https://gateway.ai.cloudflare.com/v1/*/unlimited-context/openai",
|
||||
} as const
|
||||
|
||||
export const createSupermemoryInfiniteChat = (
|
||||
apiKey: SupermemoryApiKey,
|
||||
config: SupermemoryInfiniteChatConfig,
|
||||
) =>
|
||||
createOpenAI({
|
||||
apiKey: config.providerApiKey,
|
||||
baseURL: config.providerName
|
||||
? providerMap[config.providerName]
|
||||
: config.providerUrl,
|
||||
headers: {
|
||||
"x-api-key": apiKey,
|
||||
...config.headers,
|
||||
},
|
||||
}).chat
|
||||
185
packages/ai-sdk/src/tools.test.ts
Normal file
185
packages/ai-sdk/src/tools.test.ts
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
import { createOpenAI } from "@ai-sdk/openai"
|
||||
import { generateText } from "ai"
|
||||
import { describe, expect, it } from "vitest"
|
||||
import { type SupermemoryToolsConfig, supermemoryTools } from "./tools"
|
||||
|
||||
import "dotenv/config"
|
||||
|
||||
describe("supermemoryTools", () => {
|
||||
// Required API keys - tests will fail if not provided
|
||||
const testApiKey = process.env.SUPERMEMORY_API_KEY
|
||||
const testOpenAIKey = process.env.OPENAI_API_KEY
|
||||
|
||||
if (!testApiKey) {
|
||||
throw new Error(
|
||||
"SUPERMEMORY_API_KEY environment variable is required for tests",
|
||||
)
|
||||
}
|
||||
if (!testOpenAIKey) {
|
||||
throw new Error("OPENAI_API_KEY environment variable is required for tests")
|
||||
}
|
||||
|
||||
// Optional configuration with defaults
|
||||
const testBaseUrl = process.env.SUPERMEMORY_BASE_URL ?? undefined
|
||||
const testModelName = process.env.MODEL_NAME || "gpt-5-mini"
|
||||
|
||||
const testPrompts = [
|
||||
"What do you remember about my preferences?",
|
||||
"Help me plan my day based on what you know about me",
|
||||
"What are my current projects?",
|
||||
"Remind me of my interests and hobbies",
|
||||
"What should I focus on today?",
|
||||
]
|
||||
|
||||
describe("client initialization", () => {
|
||||
it("should create tools with default configuration", () => {
|
||||
const config: SupermemoryToolsConfig = {}
|
||||
const tools = supermemoryTools(testApiKey, config)
|
||||
|
||||
expect(tools).toBeDefined()
|
||||
expect(tools.searchMemories).toBeDefined()
|
||||
expect(tools.addMemory).toBeDefined()
|
||||
expect(tools.fetchMemory).toBeDefined()
|
||||
})
|
||||
|
||||
it("should create tools with custom baseUrl", () => {
|
||||
const config: SupermemoryToolsConfig = {
|
||||
baseUrl: testBaseUrl,
|
||||
}
|
||||
const tools = supermemoryTools(testApiKey, config)
|
||||
|
||||
expect(tools).toBeDefined()
|
||||
expect(tools.searchMemories).toBeDefined()
|
||||
expect(tools.addMemory).toBeDefined()
|
||||
expect(tools.fetchMemory).toBeDefined()
|
||||
})
|
||||
|
||||
it("should create tools with projectId configuration", () => {
|
||||
const config: SupermemoryToolsConfig = {
|
||||
projectId: "test-project-123",
|
||||
}
|
||||
const tools = supermemoryTools(testApiKey, config)
|
||||
|
||||
expect(tools).toBeDefined()
|
||||
expect(tools.searchMemories).toBeDefined()
|
||||
expect(tools.addMemory).toBeDefined()
|
||||
expect(tools.fetchMemory).toBeDefined()
|
||||
})
|
||||
|
||||
it("should create tools with custom container tags", () => {
|
||||
const config: SupermemoryToolsConfig = {
|
||||
containerTags: ["custom-tag-1", "custom-tag-2"],
|
||||
}
|
||||
const tools = supermemoryTools(testApiKey, config)
|
||||
|
||||
expect(tools).toBeDefined()
|
||||
expect(tools.searchMemories).toBeDefined()
|
||||
expect(tools.addMemory).toBeDefined()
|
||||
expect(tools.fetchMemory).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("AI SDK integration", () => {
|
||||
it("should work with AI SDK generateText", async () => {
|
||||
const openai = createOpenAI({
|
||||
apiKey: testOpenAIKey,
|
||||
})
|
||||
|
||||
const result = await generateText({
|
||||
model: openai(testModelName),
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are a helpful assistant with access to user memories. Use the search tool when the user asks about preferences or past information.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: testPrompts[0]!,
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
...supermemoryTools(testApiKey, {
|
||||
projectId: "test-ai-integration",
|
||||
baseUrl: testBaseUrl,
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.text).toBeDefined()
|
||||
expect(typeof result.text).toBe("string")
|
||||
})
|
||||
|
||||
it("should use tools when prompted", async () => {
|
||||
const openai = createOpenAI({
|
||||
apiKey: testOpenAIKey,
|
||||
})
|
||||
|
||||
const tools = supermemoryTools(testApiKey, {
|
||||
projectId: "test-tool-usage",
|
||||
baseUrl: testBaseUrl,
|
||||
})
|
||||
|
||||
const result = await generateText({
|
||||
model: openai(testModelName),
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are a helpful assistant. When the user asks you to remember something, use the addMemory tool.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: "Please remember that I prefer dark roast coffee",
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
addMemory: tools.addMemory,
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.text).toBeDefined()
|
||||
expect(result.toolCalls).toBeDefined()
|
||||
|
||||
if (result.toolCalls && result.toolCalls.length > 0) {
|
||||
const addMemoryCall = result.toolCalls.find(
|
||||
(call) => call.toolName === "addMemory",
|
||||
)
|
||||
expect(addMemoryCall).toBeDefined()
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle multiple tool types", async () => {
|
||||
const openai = createOpenAI({
|
||||
apiKey: testOpenAIKey,
|
||||
})
|
||||
|
||||
const result = await generateText({
|
||||
model: openai(testModelName),
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are a helpful assistant with access to user memories. Use search when asked about preferences, and addMemory when told to remember something.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content:
|
||||
"Search for my preferences and then remember that I also like green tea",
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
...supermemoryTools(testApiKey, {
|
||||
containerTags: ["test-multi-tools"],
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.text).toBeDefined()
|
||||
expect(typeof result.text).toBe("string")
|
||||
})
|
||||
})
|
||||
})
|
||||
147
packages/ai-sdk/src/tools.ts
Normal file
147
packages/ai-sdk/src/tools.ts
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
import { tool } from "ai"
|
||||
import Supermemory from "supermemory"
|
||||
import { z } from "zod"
|
||||
|
||||
/**
|
||||
* Supermemory configuration
|
||||
* Only one of `projectId` or `containerTags` can be provided.
|
||||
*/
|
||||
export interface SupermemoryToolsConfig {
|
||||
baseUrl?: string
|
||||
containerTags?: string[]
|
||||
projectId?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Supermemory tools for AI SDK
|
||||
*/
|
||||
export function supermemoryTools(
|
||||
apiKey: string,
|
||||
config: SupermemoryToolsConfig,
|
||||
) {
|
||||
const client = new Supermemory({
|
||||
apiKey,
|
||||
...(config.baseUrl && { baseURL: config.baseUrl }),
|
||||
})
|
||||
|
||||
const containerTags = config.projectId
|
||||
? [`sm_project_${config.projectId}`]
|
||||
: (config.containerTags ?? ["sm_project_default"])
|
||||
|
||||
const searchMemories = tool({
|
||||
description:
|
||||
"Search user memories and patterns. Run when explicitly asked or when context about user's past choices would be helpful. Uses semantic matching to find relevant details across related experiences.",
|
||||
inputSchema: z.object({
|
||||
informationToGet: z
|
||||
.string()
|
||||
.describe("Terms to search for in the user's memories"),
|
||||
}),
|
||||
execute: async ({ informationToGet }) => {
|
||||
try {
|
||||
const response = await client.search.execute({
|
||||
q: informationToGet,
|
||||
containerTags,
|
||||
limit: 10,
|
||||
chunkThreshold: 0.6,
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
results: response.results,
|
||||
count: response.results?.length || 0,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const addMemory = tool({
|
||||
description:
|
||||
"Add a new memory to the user's memories. Run when explicitly asked or when the user mentions any information generalizable beyond the context of the current conversation.",
|
||||
inputSchema: z.object({
|
||||
memory: z
|
||||
.string()
|
||||
.describe(
|
||||
"The text content of the memory to add. This should be a single sentence or a short paragraph.",
|
||||
),
|
||||
}),
|
||||
execute: async ({ memory }) => {
|
||||
try {
|
||||
const metadata: Record<string, string | number | boolean> = {}
|
||||
|
||||
const response = await client.memories.add({
|
||||
content: memory,
|
||||
containerTags,
|
||||
...(Object.keys(metadata).length > 0 && { metadata }),
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
memory: response,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const fetchMemory = tool({
|
||||
description: "Fetch a specific memory by ID to get its full details",
|
||||
inputSchema: z.object({
|
||||
memoryId: z.string().describe("The ID of the memory to fetch"),
|
||||
}),
|
||||
execute: async ({ memoryId }) => {
|
||||
try {
|
||||
const response = await client.memories.get(memoryId)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
memory: response,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
searchMemories,
|
||||
addMemory,
|
||||
fetchMemory,
|
||||
}
|
||||
}
|
||||
|
||||
// Export individual tool creators for more flexibility
|
||||
export const searchMemoriesTool = (
|
||||
apiKey: string,
|
||||
config: SupermemoryToolsConfig,
|
||||
) => {
|
||||
const { searchMemories } = supermemoryTools(apiKey, config)
|
||||
return searchMemories
|
||||
}
|
||||
|
||||
export const addMemoryTool = (
|
||||
apiKey: string,
|
||||
config: SupermemoryToolsConfig,
|
||||
) => {
|
||||
const { addMemory } = supermemoryTools(apiKey, config)
|
||||
return addMemory
|
||||
}
|
||||
|
||||
export const fetchMemoryTool = (
|
||||
apiKey: string,
|
||||
config: SupermemoryToolsConfig,
|
||||
) => {
|
||||
const { fetchMemory } = supermemoryTools(apiKey, config)
|
||||
return fetchMemory
|
||||
}
|
||||
10
packages/ai-sdk/tsconfig.json
Normal file
10
packages/ai-sdk/tsconfig.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "@total-typescript/tsconfig/bundler/dom/library-monorepo",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./*"],
|
||||
"@lib/*": ["../lib/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# `@turbo/eslint-config`
|
||||
|
||||
Collection of internal eslint configurations.
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
import js from "@eslint/js"
|
||||
import eslintConfigPrettier from "eslint-config-prettier"
|
||||
import onlyWarn from "eslint-plugin-only-warn"
|
||||
import turboPlugin from "eslint-plugin-turbo"
|
||||
import tseslint from "typescript-eslint"
|
||||
|
||||
/**
|
||||
* A shared ESLint configuration for the repository.
|
||||
*
|
||||
* @type {import("eslint").Linter.Config[]}
|
||||
* */
|
||||
export const config = [
|
||||
js.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
plugins: {
|
||||
turbo: turboPlugin,
|
||||
},
|
||||
rules: {
|
||||
"turbo/no-undeclared-env-vars": "warn",
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
onlyWarn,
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ["dist/**"],
|
||||
},
|
||||
]
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
import js from "@eslint/js"
|
||||
import pluginNext from "@next/eslint-plugin-next"
|
||||
import eslintConfigPrettier from "eslint-config-prettier"
|
||||
import pluginReact from "eslint-plugin-react"
|
||||
import pluginReactHooks from "eslint-plugin-react-hooks"
|
||||
import globals from "globals"
|
||||
import tseslint from "typescript-eslint"
|
||||
import { config as baseConfig } from "./base.js"
|
||||
|
||||
/**
|
||||
* A custom ESLint configuration for libraries that use Next.js.
|
||||
*
|
||||
* @type {import("eslint").Linter.Config[]}
|
||||
* */
|
||||
export const nextJsConfig = [
|
||||
...baseConfig,
|
||||
js.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
...pluginReact.configs.flat.recommended,
|
||||
languageOptions: {
|
||||
...pluginReact.configs.flat.recommended.languageOptions,
|
||||
globals: {
|
||||
...globals.serviceworker,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
"@next/next": pluginNext,
|
||||
},
|
||||
rules: {
|
||||
...pluginNext.configs.recommended.rules,
|
||||
...pluginNext.configs["core-web-vitals"].rules,
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
"react-hooks": pluginReactHooks,
|
||||
},
|
||||
settings: { react: { version: "detect" } },
|
||||
rules: {
|
||||
...pluginReactHooks.configs.recommended.rules,
|
||||
// React scope no longer necessary with new JSX transform.
|
||||
"react/react-in-jsx-scope": "off",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"name": "@repo/eslint-config",
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"exports": {
|
||||
"./base": "./base.js",
|
||||
"./next-js": "./next.js",
|
||||
"./react-internal": "./react-internal.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.33.0",
|
||||
"@next/eslint-plugin-next": "^15.4.2",
|
||||
"eslint": "^9.33.0",
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-only-warn": "^1.1.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-turbo": "^2.5.0",
|
||||
"globals": "^16.3.0",
|
||||
"typescript": "^5.9.2",
|
||||
"typescript-eslint": "^8.39.0"
|
||||
}
|
||||
}
|
||||
39
packages/eslint-config/react-internal.js
vendored
39
packages/eslint-config/react-internal.js
vendored
|
|
@ -1,39 +0,0 @@
|
|||
import js from "@eslint/js"
|
||||
import eslintConfigPrettier from "eslint-config-prettier"
|
||||
import pluginReact from "eslint-plugin-react"
|
||||
import pluginReactHooks from "eslint-plugin-react-hooks"
|
||||
import globals from "globals"
|
||||
import tseslint from "typescript-eslint"
|
||||
import { config as baseConfig } from "./base.js"
|
||||
|
||||
/**
|
||||
* A custom ESLint configuration for libraries that use React.
|
||||
*
|
||||
* @type {import("eslint").Linter.Config[]} */
|
||||
export const config = [
|
||||
...baseConfig,
|
||||
js.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
...tseslint.configs.recommended,
|
||||
pluginReact.configs.flat.recommended,
|
||||
{
|
||||
languageOptions: {
|
||||
...pluginReact.configs.flat.recommended.languageOptions,
|
||||
globals: {
|
||||
...globals.serviceworker,
|
||||
...globals.browser,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
"react-hooks": pluginReactHooks,
|
||||
},
|
||||
settings: { react: { version: "detect" } },
|
||||
rules: {
|
||||
...pluginReactHooks.configs.recommended.rules,
|
||||
// React scope no longer necessary with new JSX transform.
|
||||
"react/react-in-jsx-scope": "off",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"esModuleInterop": true,
|
||||
"incremental": false,
|
||||
"isolatedModules": true,
|
||||
"lib": ["es2022", "DOM", "DOM.Iterable"],
|
||||
"module": "NodeNext",
|
||||
"moduleDetection": "force",
|
||||
"moduleResolution": "NodeNext",
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "ES2022"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"plugins": [{ "name": "next" }],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"allowJs": true,
|
||||
"jsx": "preserve",
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "@repo/typescript-config",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue