@geenius/ai
v0.17.0
Published
Geenius AI — Reusable AI packages for Convex apps (React + SolidJS)
Maintainers
Readme
@geenius/ai
Reusable AI contracts, provider adapters, framework bindings, and launch persistence providers for Geenius apps.
@geenius/ai is the free FSL lite package for low-level runtime and UI integration. The commercial siblings are @geenius/ai-magic for high-level AI Magic wizard surfaces and @geenius/ai-workflow for hosted workflow orchestration.
Install
pnpm add @geenius/aiImport Surface
import { DEFAULT_MODELS, DEFAULT_PROVIDERS, defineAIConfig } from '@geenius/ai'
import { DEFAULT_VOICES, buildSkillPrompt, createSkillRegistry } from '@geenius/ai'
import { ChatPage, GenerationCard, ModelTestRunner, useAI } from '@geenius/ai/react'
import { ChatPage as ChatPageCss, GenerationCard as GenerationCardCss } from '@geenius/ai/react-css'
import { ChatPage as SolidChatPage, GenerationCard as SolidGenerationCard, createAI } from '@geenius/ai/solidjs'
import { ChatPage as SolidChatPageCss, GenerationCard as SolidGenerationCardCss } from '@geenius/ai/solidjs-css'
import { ChatPage as ChatPageNative, ModelSelector as ModelSelectorNative } from '@geenius/ai/react-native'
import { aiTables, generateTextArgs, performAICall } from '@geenius/ai/convex'
import { createNeonAIStore, runAIMigrations } from '@geenius/ai/neon'
import { createCloudflareKVAIStore, createMemoryKVNamespace } from '@geenius/ai/cloudflareKV'
import { createMemoryAIStore } from '@geenius/ai/memory'@geenius/ai resolves to the shared framework-agnostic contract. Framework-specific code is exported only from the framework subpaths.
Quick Start
Shared configuration
import { defineAIConfig } from '@geenius/ai'
export const aiConfig = defineAIConfig({
defaultProvider: 'openai',
defaultModel: 'gpt-4o-mini',
providers: [
{
type: 'openai',
name: 'OpenAI',
baseUrl: 'https://api.openai.com/v1',
apiKeyEnvVar: 'OPENAI_API_KEY',
isActive: true,
models: ['gpt-4o-mini'],
},
],
})React usage
import { ChatPage } from '@geenius/ai/react'
export function SupportAssistant() {
return (
<ChatPage
model="gpt-4o-mini"
systemPrompt="You are a concise support copilot."
callGenerateText={async ({ model, messages }) => {
return {
content: `Generated ${messages.length} message(s) with ${model}.`,
model,
provider: 'openai',
type: 'text',
durationMs: 42,
finishReason: 'stop',
}
}}
/>
)
}React CSS usage
import { AILogsPage, ChatPage, ModelTestPage, useChat } from '@geenius/ai/react-css'
import '@geenius/ai/react-css/styles.css'
export function EmbeddedAssistant() {
const callGenerateText = async ({ model, messages }) => ({
content: `Generated ${messages.length} message(s) with ${model}.`,
model,
provider: 'openai',
type: 'text',
durationMs: 42,
finishReason: 'stop',
})
const chat = useChat({
model: 'gpt-4o-mini',
callGenerateText,
})
return (
<>
<button type="button" onClick={() => void chat.sendMessage('Summarize today')}>
Send sample prompt
</button>
<ChatPage model="gpt-4o-mini" callGenerateText={callGenerateText} />
<AILogsPage callListLogs={async () => []} />
<ModelTestPage availableModels={['gpt-4o-mini']} />
</>
)
}SolidJS usage
import { createAI } from '@geenius/ai/solidjs'
const ai = createAI({
callGenerateText: async ({ model, messages }) => {
return {
content: `Generated ${messages.length} message(s) with ${model}.`,
model,
provider: 'openai',
type: 'text',
durationMs: 42,
finishReason: 'stop',
}
},
})The @geenius/ai/react, @geenius/ai/react-css, @geenius/ai/solidjs, @geenius/ai/solidjs-css,
and @geenius/ai/react-native entrypoints all use the same portable call* callback contract so
UI variants can stay backend-agnostic.
React Native usage
import { AIProvider, ChatPage } from '@geenius/ai/react-native'
export function App() {
return (
<AIProvider
defaults={{
ai: {
callGenerateText: async ({ model, messages }) => ({
content: `Generated ${messages.length} message(s) with ${model}.`,
model,
provider: 'openai',
type: 'text',
durationMs: 42,
finishReason: 'stop',
}),
},
}}
>
<ChatPage />
</AIProvider>
)
}Convex usage
import { defineSchema } from 'convex/server'
import { aiTables } from '@geenius/ai/convex'
export default defineSchema({
...aiTables,
})Neon usage
import { createNeonAIStore, runAIMigrations } from '@geenius/ai/neon'
const store = createNeonAIStore({ execute: sql })
await runAIMigrations(sql)
const conversation = await store.createConversation({
userId: 'user_1',
title: 'Support assistant',
model: 'gpt-4o-mini',
})
await store.addMessage({
conversationId: conversation.id,
userId: 'user_1',
role: 'user',
content: 'Summarize today',
})
await store.saveLog({
requestId: 'req_1',
model: 'gpt-4o-mini',
provider: 'openai',
caller: 'support-assistant',
type: 'text',
timestamp: Date.now(),
durationMs: 42,
systemPrompt: '',
userPrompt: 'Summarize today',
hasImage: false,
requestBodySize: 128,
status: 'success',
httpStatus: 200,
responseContent: 'Summary generated.',
responseSize: 18,
})Cloudflare KV usage
import { createCloudflareKVAIStore, createMemoryKVNamespace } from '@geenius/ai/cloudflareKV'
const namespace = createMemoryKVNamespace()
const store = createCloudflareKVAIStore({ namespace, keyPrefix: 'ai', ttlSeconds: 3600 })
type CachedCompletion = {
content: string
model: string
}
await store.putCache<CachedCompletion>(
'prompt:launch-recap',
{ content: 'Launch recap generated.', model: 'gpt-4o-mini' },
{ scope: 'user_1', ttlSeconds: 300 },
)
const cachedCompletion = await store.getCache<CachedCompletion>('prompt:launch-recap', {
scope: 'user_1',
})
await store.putSession(
'session_realtime_1',
{ conversationId: 'conv_1', status: 'streaming' },
{ ttlSeconds: 900 },
)
const realtimeSession = await store.getSession<{
conversationId: string
status: string
}>('session_realtime_1')
await store.putRateLimit(
'user_1:gpt-4o-mini',
{ count: 4, limit: 20, resetAt: Date.now() + 60_000 },
{ scope: 'provider:openai', ttlSeconds: 60 },
)
const rateLimit = await store.getRateLimit('user_1:gpt-4o-mini', {
scope: 'provider:openai',
})Cloudflare KV short-lived helpers share the store key prefix, accept an optional scope, and apply TTLs for cache, session, and rate-limit state. TTL values must satisfy Cloudflare KV's 60-second minimum.
Memory usage
import { createMemoryAIStore, createMemoryStore } from '@geenius/ai/memory'
let now = Date.UTC(2026, 0, 1)
const memory = createMemoryStore({
maxPerNamespace: 2,
autoExpireDays: 30,
now: () => now,
})
await memory.set({
namespace: 'user',
scopeId: 'user_1',
type: 'preference',
importance: 'high',
key: 'tone',
value: 'concise and technical',
})
await memory.set({
namespace: 'user',
scopeId: 'user_1',
type: 'preference',
importance: 'medium',
key: 'currency',
value: 'EUR',
})
const tone = await memory.get('user', 'tone', 'user_1')
const matches = await memory.search({
namespace: 'user',
scopeId: 'user_1',
query: 'technical',
limit: 5,
})
now += 31 * 24 * 60 * 60 * 1000
const expiredTone = await memory.get('user', 'tone', 'user_1') // null after auto expiry
const store = createMemoryAIStore()
await store.saveLog({ model: 'gpt-4o-mini', provider: 'openai' })
await store.clear()createMemoryStore() implements the shared MemoryStore contract for prompt memory. maxPerNamespace evicts the lowest-priority, least-recently-accessed entries when a namespace exceeds the configured limit; autoExpireDays assigns an expiry timestamp to entries that do not provide one.
API Reference
The complete architecture and launch criteria live in .docs/DOCS/PACKAGES/AI.md. The package README stays focused on the public import surface.
Root: @geenius/ai
The root entrypoint is framework-agnostic. It exports shared contracts and helpers only; there is no @geenius/ai/shared subpath.
| Area | Key exports | Use when |
| --- | --- | --- |
| Configuration | defineAIConfig, mergeAIConfig, findModelConfig, findProviderConfig, getModelsByCapability, getProviderForModel, DEFAULT_MODELS, DEFAULT_PROVIDERS, DEFAULT_VOICES | Building provider/model registries that UI and adapters can share. |
| Generation | getAIGenerationContent, getAIImageAssetSource, getAIMediaAssetSource, isAIGenerationResponse, generateStructuredOutputWithValidation, parseAndValidateStructuredOutput, withStructuredOutputSchemaInstruction | Normalizing provider responses and validating structured output. |
| Conversations | createAIConversation, listAIConversations, filterAIConversations, searchAIConversations, patchAIConversation, archiveAIConversation, renameAIConversation, setAIConversationFavorite, updateAIConversationTags, moveAIConversationToFolder, createDbAIConversationPersistence | Managing portable conversation state before it reaches a UI or DB adapter. |
| Content | BUILT_IN_TEMPLATES, buildActionSystemPrompt, buildContentPrompt plus Content* types | Creating rewrite, summarize, translate, tone, and extraction prompts. |
| Memory | DEFAULT_MEMORY_CONFIG, buildMemoryContext, extractPreferenceHints plus MemoryStore, MemoryEntry, and memory query types | Injecting user/org memory into prompts without coupling to a storage backend. |
| Skills | BUILT_IN_SKILLS, buildSkillPrompt, createSkillRegistry plus Skill* types | Registering tool-like skills and building skill execution prompts. |
| Providers and errors | createProvider, createAdapterAIProvider, generateTextWithRetries, resolveProviderForModel, clearProviderCache, AIError, AIConfigurationError, AIProviderRequestError, AIProviderTimeoutError, AIStateError, AIUnsupportedOperationError, toAIError, requireAIValue | Bridging provider adapters and surfacing normalized errors. |
| Shared types | AIMessage, AIChatMessage, AIConversation, AILogEntry, AIModel, AIProviderConfig, AIGenerationResult, AITranscriptionResult, AIVoiceOption, ChatWindowProps, ImageGeneratorProps, VoiceSelectorProps, and related option/result types | Typing callbacks, UI props, adapter payloads, and persistence records across variants. |
UI Variants
All UI variants consume the same portable call* callback contract and keep persistence outside the component layer.
| Subpath | Key exports | Notes |
| --- | --- | --- |
| @geenius/ai/react | AIProvider, useAIProviderContext, useAI, useChat, useAILogs, useAIModels, useContentManager, useImageGeneration, useMemory, useModelTest, useRealtimeAudio, useSkills, useTextToSpeech, useTranscription, useVideoGeneration, ModelSelector, VoiceSelector, AILogTable, ChatWindow, GenerationCard, ImageGenerator, ModelTestRunner, AILogsPage, ChatPage, ModelTestPage | React + Tailwind 4 utility classes. |
| @geenius/ai/react-css | Same provider, hook, component, and page surface as React | React + Vanilla CSS BEM classes. Import @geenius/ai/react-css/styles.css. |
| @geenius/ai/solidjs | AIProvider, useAIProviderContext, createAI, createChat, createAILogs, createAIModels, createContentManager, createImageGeneration, createMemory, createModelTest, createRealtimeAudio, createSkills, createTextToSpeech, createTranscription, createVideoGeneration, matching components, and pages | SolidJS + Tailwind 4 utility classes. |
| @geenius/ai/solidjs-css | Same SolidJS provider, primitive, component, and page surface as SolidJS | SolidJS + Vanilla CSS BEM classes. Import @geenius/ai/solidjs-css/styles.css. |
| @geenius/ai/react-native | AIProvider, useAIProviderContext, native hooks, nativeTokens, FlatList, Pressable, ScrollView, StyleSheet, Text, TextInput, View, native components, and native pages | React Native StyleSheet primitives backed by shared tokens. |
Persistence Providers
These subpaths are launch DB/storage adapters. UI variants do not import them directly; app code passes callbacks or store methods into UI hooks and pages.
| Subpath | Key exports | Use when |
| --- | --- | --- |
| @geenius/ai/convex | aiTables, generateTextArgs, performAICall, createLogEntry, validators and query/mutation helpers | Wiring Convex schema, queries, mutations, and action arguments for AI logs and calls. |
| @geenius/ai/neon | createNeonAIStore, runAIMigrations, aiMigrations, createNeonAIRlsPolicyStatements, createNeonAITenantContextStatement, Neon store/input/filter types | Storing logs, conversations, messages, model costs, providers, and tenant-aware policy metadata in native Neon SQL. |
| @geenius/ai/cloudflareKV | createCloudflareKVAIStore, createMemoryKVNamespace, buildCloudflareKVAIKey, createCloudflareKVAIKeys, CLOUDFLARE_KV_AI_CAPABILITIES, KV option/store types | Running edge-friendly key/value storage with TTL-backed cache, session, and rate-limit helpers. |
| @geenius/ai/memory | createMemoryAIStore, createMemoryStore, memory AI store/input/filter/snapshot types | Running deterministic in-process stores for tests, demos, Storybook fixtures, and local development. |
Stylesheet Subpaths
| Subpath | Exports |
| --- | --- |
| @geenius/ai/react-css/styles.css | The React Vanilla CSS stylesheet and its ambient CSS module typing. |
| @geenius/ai/solidjs-css/styles.css | The SolidJS Vanilla CSS stylesheet and its ambient CSS module typing. |
Package Layout
@geenius/ai: provider configuration, model registry, typed errors, content helpers, skills, memory, and framework-agnostic runtime helpers.@geenius/ai/react: headless React hooks, components, and page compositions.@geenius/ai/react-css: React hooks and plain-CSS component/page surfaces.@geenius/ai/solidjs: SolidJS primitives, components, and page compositions.@geenius/ai/solidjs-css: SolidJS primitives and plain-CSS component/page surfaces.@geenius/ai/react-native: React Native hooks, components, and page compositions for native AI surfaces.@geenius/ai/convex: schema tables, argument validators, and backend helper exports.@geenius/ai/neon: Postgres/Neon logs, conversations, messages, model costs, and append-only migration runner.@geenius/ai/cloudflareKV: edge KV log, conversation, message, and model store.@geenius/ai/memory: deterministic in-process store for tests, demos, and Storybook fixtures.
Storybook
Development-only review surfaces are stock Storybook v10 apps wired through @geenius/storybook. Each implemented UI variant has its own app so provider/theme/runtime differences are exercised independently.
Build them locally with:
pnpm --filter ./apps/storybook-react build
pnpm --filter ./apps/storybook-react-css build
pnpm --filter ./apps/storybook-solidjs build
pnpm --filter ./apps/storybook-solidjs-css buildRun them locally with:
pnpm --filter ./apps/storybook-react dev
pnpm --filter ./apps/storybook-react-css dev
pnpm --filter ./apps/storybook-solidjs dev
pnpm --filter ./apps/storybook-solidjs-css devContributing tests
The test matrix is driven from variants.json. Add a variant or provider there first, then add the matching package directory, Storybook/review app, Playwright harness coverage, bundle budget, and coverage target. Scripts and configs read the manifest through @geenius/release-toolkit; do not hardcode variant lists in package.json, Playwright config, or smoke gates.
Useful gates:
pnpm test:gauntletruns the PR-blocking lint, type, unit, packed-smoke, size, supply-chain, and license checks.pnpm test:allruns the extended pre-release stack: gauntlet, DB conformance, migrations, Storybook, e2e, a11y, visual, perf, and coverage.pnpm run test:a11yruns axe/keyboard/focus coverage across implemented web variants.pnpm run test:visualruns default-on chromium visual regression; update local baselines withpnpm run test:visual -- --update-snapshots.pnpm run test:storybook:buildbuilds every implemented per-variant Storybook app.pnpm run test:coverageaggregates Vitest coverage. Current legacy package-wide coverage is below the v1 target and must be raised before strict release gating.
License
FSL-1.1-Apache-2.0 for the free tier, with proprietary commercial licensing for paid Geenius distributions.
