Skip to content

Conversation

@inoribea
Copy link

@inoribea inoribea commented Oct 7, 2025

Overview

This PR introduces a comprehensive memory system to AIRI, enabling both short-term conversation context storage and long-term semantic
memory capabilities.

Key Features

🧠 Memory System Core (packages/memory)

  • Unified Factory Pattern: Single MemorySystemFactory for all provider instantiation
  • Short-term Memory: Conversation context caching with Redis (local/Upstash) and Vercel KV
  • Long-term Memory: Semantic search with PostgreSQL pgvector and Qdrant
  • Hot-swappable Providers: Runtime configuration switching without restart
  • Environment-based Config: Zero-code configuration via environment variables

🎛️ UI Integration (packages/stage-pages, packages/stage-ui)

  • Settings pages at /settings/memory with provider configuration
  • Real-time message preview from short-term cache
  • Per-provider configuration forms (Redis/Upstash/Vercel KV, PostgreSQL/Qdrant)
  • Pinia-based memory store for reactive state management
  • Session management (view/clear/regenerate)

🔌 Server API (packages/server-runtime)

RESTful endpoints for memory operations:

  • GET /api/memory/config - Retrieve current configuration
  • POST /api/memory/config - Update memory configuration
  • POST /api/memory/save - Save conversation messages
  • GET /api/memory/session/:id - Fetch recent messages by session
  • POST /api/memory/search - Semantic similarity search
  • POST /api/memory/clear - Clear session memory
  • GET /api/memory/export - Export user memory data

Architecture

packages/memory/
├── src/
│ ├── memory-factory.ts # Provider factory with configuration
│ ├── providers/
│ │ ├── short-term/
│ │ │ ├── base-short-term.provider.ts
│ │ │ ├── local-redis.provider.ts
│ │ │ ├── upstash-redis.provider.ts
│ │ │ └── vercel-kv.provider.ts
│ │ └── long-term/
│ │ ├── postgres-pgvector.provider.ts
│ │ └── qdrant.provider.ts
│ ├── types/ # TypeScript definitions
│ ├── interfaces/ # Memory interfaces
│ └── migrations/ # SQL migrations

Configuration

Environment Variables:

Short-term (Required):

MEMORY_PROVIDER=local-redis                    # local-redis | upstash-redis | vercel-kv
SHORT_TERM_MEMORY_MAX_MESSAGES=20              # Default: 20
SHORT_TERM_MEMORY_TTL_SECONDS=1800             # Default: 30 minutes
MEMORY_NAMESPACE=memory                        # Redis key prefix

Long-term (Optional):
LONG_TERM_MEMORY_PROVIDER=postgres-pgvector    # postgres-pgvector | qdrant | none
POSTGRES_URL=postgresql://...                  # PostgreSQL connection
QDRANT_URL=http://localhost:6333               # Qdrant endpoint
MEMORY_EMBEDDING_PROVIDER=openai               # openai | cloudflare
MEMORY_EMBEDDING_MODEL=text-embedding-3-small  # Embedding model
MEMORY_EMBEDDING_API_KEY=sk-...                # API key

Use Cases

1. Conversation Context: Maintain recent chat history across sessions
2. Semantic Memory: Store and retrieve relevant past interactions
3. User Profiling: Build long-term user preference models
4. Multi-session Support: Isolated memory per conversation thread

Implementation Details

- Zero Breaking Changes: Purely additive feature, existing functionality unchanged
- Graceful Degradation: Falls back to in-memory if providers unavailable
- Error Handling: Comprehensive error callbacks and logging
- Type Safety: Full TypeScript coverage with interfaces
- Extensible: Easy to add new providers (e.g., MongoDB, Redis Stack)

Testing

- ✅ Build: Passes pnpm build without errors
- ✅ Type Check: No TypeScript errors
- ✅ Local Redis: Tested with local Redis instance
- ✅ UI Rendering: Settings pages render correctly
- ✅ API Endpoints: All endpoints functional and tested

Migration Notes

No migration required. Memory system is opt-in via environment variables.

Dependencies

Added packages:
- @upstash/redis - Upstash Redis client
- @vercel/kv - Vercel KV client
- @vercel/postgres - Vercel Postgres client
- @qdrant/js-client-rest - Qdrant client
- ioredis - Local Redis client
- pg - PostgreSQL client
- openai - Embedding generation

Related

This implements the memory functionality discussed in recent conversations and addresses the need for persistent conversation state
across sessions.

Checklist

- Code follows project style guidelines
- No breaking changes
- Build passes successfully
- TypeScript types are complete
- Environment variables documented
- Based on latest main branch

---
Questions or feedback welcome! Happy to make any adjustments.

---

inoribea and others added 22 commits October 6, 2025 08:31
- Add URL import dialog for VRM and Live2D models
- Support VPM JSON format parsing
- Implement model caching with IndexedDB
- Auto-detect model format from URL extension
- Support direct .vrm, .zip, and .json URLs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Fix CORS font loading from jsdelivr.net by using local Kiwi Maru
- Add smart WebSocket URL detection (disabled in production)
- Add CORS headers to Vercel configuration
- Support auto-switching between ws:// and wss:// protocols

Fixes font loading errors and WebSocket connection failures on deployed instances.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Auto-select default chat provider when configured
- Auto-select default speech provider when configured
- Auto-select default transcription provider when configured
- Add watcher to set active provider from env variables

Improves onboarding UX by pre-selecting providers based on deployment configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add provider API keys to Vite define config
- Add default provider selection environment variables
- Update .gitignore for build artifacts
- Update stage-web README and type definitions

Enables deploying with pre-configured provider credentials via environment variables.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add comprehensive Vercel deployment section to README
- Document all LLM provider environment variables
- Add default provider selection variables
- Include configuration examples
- Support multiple languages (EN, ZH-CN, JA-JP, FR)

This helps users deploy AIRI to Vercel with pre-configured providers, improving the deployment experience.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add globalEnv variables to turbo.json to pass environment to build
- Add dependsOn to build task to ensure proper dependency order
- Fix vercel.json buildCommand to use 'pnpm run build:web'

Fixes:
- Turborepo warning about missing environment variables
- Build command execution issues on Vercel

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Change buildCommand to use 'pnpm -w run build:web'
- Ensures build script runs at workspace root level
- Fixes 'ERR_PNPM_NO_SCRIPT Missing script: build:web' error
- Add all provider env vars to turbo.json globalEnv
- Add build task dependencies to turbo.json

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…nings

- Change globalEnv to globalPassThroughEnv in turbo.json
- Prevents warnings for optional provider environment variables
- These variables are not required and warnings are unnecessary

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Disable Turbo remote cache to fix 400 error with Vercel artifacts API
- Update build command to use turbo filter syntax for better integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Set vite output directory to project root dist folder for Vercel
- Add empty env array to turbo build task to suppress unnecessary environment variable warnings
- Update vercel.json outputDirectory to match new build output location

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add empty passThroughEnv array to build task to override globalPassThroughEnv,
preventing unnecessary environment variable warnings for packages that don't need them.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Revert to original output directory setup where Vite outputs to apps/stage-web/dist
to match Turbo's outputs configuration and ensure proper build artifact tracking.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fix build error where @proj-airi/memory-system was imported but not
declared as a dependency in server-runtime/package.json. This caused
unresolved import warnings during build:

[UNRESOLVED_IMPORT] Could not resolve '@proj-airi/memory-system' in src/services/memory.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Merged latest changes from moeru-ai/airi upstream including:
- feat(injecta): new dependency injection package
- refactor(stage-tamagotchi): improved structure
- Various fixes and improvements

Preserved local changes:
- Memory system (@proj-airi/memory-system)
- Memory UI components and configuration
- All memory-related functionality

Resolved conflicts by regenerating pnpm-lock.yaml

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@netlify
Copy link

netlify bot commented Oct 7, 2025

Deploy Preview for airi-vtuber ready!

Name Link
🔨 Latest commit a4d4e84
🔍 Latest deploy log https://app.netlify.com/projects/airi-vtuber/deploys/69001e71b8cc840008e0a1a8
😎 Deploy Preview https://deploy-preview-636--airi-vtuber.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Oct 7, 2025

Deploy Preview for airi-docs ready!

Name Link
🔨 Latest commit a4d4e84
🔍 Latest deploy log https://app.netlify.com/projects/airi-docs/deploys/69001e71beed8c000816129a
😎 Deploy Preview https://deploy-preview-636--airi-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @inoribea, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers a foundational memory system for AIRI, enabling it to retain conversation context and semantic understanding across sessions. It provides robust backend services, a user-friendly interface for configuration, and a comprehensive API, alongside updates to deployment and environment variable handling to streamline integration and customization.

Highlights

  • Configurable Memory System: Introduced a new memory system (packages/memory) supporting both short-term conversation context (Redis, Vercel KV) and long-term semantic memory (PostgreSQL pgvector, Qdrant). This system is hot-swappable and configurable via environment variables.
  • UI Integration: Added dedicated settings pages (/settings/memory) in the UI (packages/stage-pages, packages/stage-ui) for configuring memory providers, previewing short-term messages, and managing sessions. This includes per-provider configuration forms and Pinia-based state management.
  • Server API Endpoints: Implemented new RESTful API endpoints (packages/server-runtime) for memory operations, including retrieving/updating configuration, saving messages, fetching recent messages, performing semantic searches, clearing sessions, and exporting user memory data.
  • Environment Variable Management: Significantly expanded environment variable support across the application (apps/stage-web, packages/stage-ui, turbo.json, vercel.json) to preconfigure LLM providers and the new memory system, simplifying deployment and initial setup.
  • Model Import from URL: Added functionality to import display models (VRM, Live2D) directly from a URL, with caching for offline use, enhancing model management flexibility.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive and well-architected memory system, which is a fantastic addition. The separation of short-term and long-term memory with multiple provider support is excellent. The code is generally of high quality. I've found a few issues, including a critical logic bug in the memory factory and some code duplication that could be refactored. There are also some minor bugs in the new Vue components and some type-safety improvements that could be made in the server runtime. Overall, great work on this significant feature.

Comment on lines +292 to +294
if (config.provider !== 'postgres-pgvector') {
throw new Error(`Unsupported long-term memory provider: ${config.provider}`)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

There's a logic error in createLongTermFromConfig that prevents the qdrant provider from being used when creating from a configuration object. The check if (config.provider !== 'postgres-pgvector') throws an error for any provider other than postgres-pgvector, making the qdrant configuration block unreachable. This should be changed to allow for all supported long-term providers. A switch statement might be more suitable here for better extensibility.

Suggested change
if (config.provider !== 'postgres-pgvector') {
throw new Error(`Unsupported long-term memory provider: ${config.provider}`)
}
if (config.provider !== 'postgres-pgvector' && config.provider !== 'qdrant') {
throw new Error(`Unsupported long-term memory provider: ${config.provider}`)
}

accountId: embeddingAccountId.value || undefined,
model: embeddingModel.value,
},
} satisfies QdrantLongTermPayload
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The type QdrantLongTermPayload is not defined in this file, which will cause a TypeScript compilation error. The same issue exists for PostgresLongTermPayload on subsequent lines. You should import the corresponding configuration types from @proj-airi/memory-system (likely QdrantLongTermConfiguration and PostgresLongTermConfiguration) and use them with the satisfies keyword.

For example:

import type { QdrantLongTermConfiguration, PostgresLongTermConfiguration } from '@proj-airi/memory-system';

// ...

} satisfies QdrantLongTermConfiguration

Comment on lines +205 to +348
private async generateEmbedding(input: string): Promise<number[]> {
const trimmed = input.trim()
if (trimmed.length === 0) {
return Array.from({ length: this.vectorSize }, () => 0)
}

let embedding: number[] = []

if (this.embeddingConfig.provider === 'cloudflare') {
embedding = await this.generateCloudflareEmbedding(trimmed)
}
else {
if (!this.openai) {
throw new Error('OpenAI-compatible client is not configured for embeddings.')
}

const response = await this.openai.embeddings.create({
model: this.embeddingConfig.model ?? DEFAULT_EMBEDDING_MODEL,
input: trimmed,
})

embedding = response.data?.[0]?.embedding ?? []
}

if (!embedding.length) {
throw new Error('Failed to generate embedding for memory content.')
}

if (embedding.length !== this.vectorSize) {
throw new Error(`Embedding dimension mismatch. Expected ${this.vectorSize}, received ${embedding.length}.`)
}

return embedding.map((value: number | string) => Number(value))
}

private extractUserId(message: Message): string | null {
const metadata = message.metadata ?? {}
const candidate = (metadata as Record<string, unknown>).userId
?? (metadata as Record<string, unknown>).userID
?? (metadata as Record<string, unknown>).user_id

return typeof candidate === 'string' && candidate.length > 0 ? candidate : null
}

private extractSessionId(message: Message): string | null {
const metadata = message.metadata ?? {}
const candidate = (metadata as Record<string, unknown>).sessionId
?? (metadata as Record<string, unknown>).sessionID
?? (metadata as Record<string, unknown>).session_id

return typeof candidate === 'string' && candidate.length > 0 ? candidate : null
}

private resolveEmbeddingConfiguration(
config?: EmbeddingProviderConfiguration,
): EmbeddingProviderConfiguration {
const provider = config?.provider
?? (env.MEMORY_EMBEDDING_PROVIDER as EmbeddingProviderConfiguration['provider'] | undefined)
?? 'openai'

const apiKey = config?.apiKey
?? env.MEMORY_EMBEDDING_API_KEY
?? env.OPENAI_API_KEY

if (!apiKey) {
throw new Error('An embedding API key is required.')
}

const model = config?.model
?? env.MEMORY_EMBEDDING_MODEL
?? DEFAULT_EMBEDDING_MODEL

const baseUrl = config?.baseUrl ?? env.MEMORY_EMBEDDING_BASE_URL
const accountId = config?.accountId ?? env.CLOUDFLARE_ACCOUNT_ID

if (provider === 'cloudflare' && !accountId) {
throw new Error('Cloudflare embedding provider requires an account ID.')
}

return {
provider,
apiKey,
model,
baseUrl,
accountId,
} satisfies EmbeddingProviderConfiguration
}

private async generateCloudflareEmbedding(input: string): Promise<number[]> {
const accountId = this.embeddingConfig.accountId
if (!accountId) {
throw new Error('Cloudflare account ID is not configured.')
}

const url = `${this.embeddingConfig.baseUrl ?? 'https://api.cloudflare.com/client/v4'}/accounts/${accountId}/ai/run/${this.embeddingConfig.model ?? DEFAULT_EMBEDDING_MODEL}`

const response = await fetch(url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.embeddingConfig.apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: input }),
})

if (!response.ok) {
const body = await response.text()
throw new Error(`Cloudflare embedding request failed: ${response.status} ${body}`)
}

const payload = await response.json() as Record<string, any>
const embedding = this.extractCloudflareEmbedding(payload)

if (!embedding || !Array.isArray(embedding) || embedding.length === 0) {
throw new Error('Cloudflare embedding response did not include an embedding vector.')
}

return embedding.map((value: number | string) => Number(value))
}

private extractCloudflareEmbedding(payload: Record<string, any>): number[] | undefined {
const result = payload.result ?? payload

if (Array.isArray(result?.data) && result.data.length > 0) {
const candidate = result.data[0]
if (Array.isArray(candidate?.embedding)) {
return candidate.embedding as number[]
}
if (Array.isArray(candidate?.vector)) {
return candidate.vector as number[]
}
}

if (Array.isArray(result?.embedding)) {
return result.embedding as number[]
}

if (Array.isArray(result?.data?.embedding)) {
return result.data.embedding as number[]
}

return undefined
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The methods generateEmbedding, extractUserId, extractSessionId, resolveEmbeddingConfiguration, generateCloudflareEmbedding, and extractCloudflareEmbedding are nearly identical to the ones in postgres-pgvector.provider.ts. This code duplication makes maintenance harder and increases the risk of bugs. These utility functions should be extracted into a shared service or utility module, for example, an EmbeddingService that could be instantiated and passed to the providers. This would centralize the embedding logic and improve maintainability.

Comment on lines +80 to +82
catch {
await this.rewriteQueueWithLimit(key)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The catch block in trimQueue is empty. This practice, known as error swallowing, is dangerous because it hides potential issues. If ltrim fails, rewriteQueueWithLimit is called, but if that also fails (its own catch is also empty), the error is silently ignored, and the memory queue could grow indefinitely. At a minimum, these errors should be logged to aid in debugging. The same issue exists in ensureTtl.

    catch (trimError) {
      console.error('[memory] Failed to ltrim queue, attempting rewrite', { key, error: trimError });
      await this.rewriteQueueWithLimit(key)
    }


await saveShortTermMemory({
sessionId: body.sessionId,
message: body.message as any,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The message from the request body is cast to any (body.message as any). This bypasses TypeScript's type checking and can lead to runtime errors if the message payload is not in the expected format. It's better to use a type guard or a validation library (like Zod, which seems to be used elsewhere in the project) to ensure the message conforms to the Message interface before processing it.

Suggested change
message: body.message as any,
message: body.message as import('@proj-airi/memory-system').Message,

const apiKey = env.MEMORY_EMBEDDING_API_KEY ?? env.OPENAI_API_KEY ?? ''

return {
provider: (env.MEMORY_EMBEDDING_PROVIDER as any) ?? 'openai',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using as any to cast env.MEMORY_EMBEDDING_PROVIDER bypasses type safety. This can hide potential issues if an unsupported provider name is used. It's safer to cast to the specific EmbeddingProviderType and ideally include a validation step to ensure the value is one of the allowed enum members.

Suggested change
provider: (env.MEMORY_EMBEDDING_PROVIDER as any) ?? 'openai',
provider: (env.MEMORY_EMBEDDING_PROVIDER as import('@proj-airi/memory-system').EmbeddingProviderType) ?? 'openai',

v-model="longTermQdrantApiKey"
type="password"
class="w-full border border-neutral-200 rounded-md bg-white px-3 py-2 text-sm dark:border-neutral-700 dark:bg-neutral-900"
placeholder="{{ t('settings.memory.long_term.qdrantApiKeyPlaceholder', 'Optional if public instance') }}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The placeholder attribute is using mustache syntax {{ ... }}. This is incorrect for Vue attributes and will result in the literal string being displayed as the placeholder. You should use v-bind: or its shorthand : to bind the result of the t() function. This issue is also present on lines 353 and 400.

              :placeholder="t('settings.memory.long_term.qdrantApiKeyPlaceholder', 'Optional if public instance')"

id="memory-long-term-embedding-account"
v-model="embeddingAccountId"
type="text"
class="w-full border border-neutral-200 rounded-md bg-white px-3 py-2 text-sm dark-border-neutral-700 dark:bg-neutral-900"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The class dark-border-neutral-700 is not a valid UnoCSS class. The dark mode variant should be prefixed, like dark:border-neutral-700. This typo also appears on lines 352 and 398.

              class="w-full border border-neutral-200 rounded-md bg-white px-3 py-2 text-sm dark:border-neutral-700 dark:bg-neutral-900"

{{ t('settings.memory.long_term.promoteAssistant', 'Persist assistant messages automatically') }}
</span>
</label>
<label class="items中心 flex gap-3 border border-neutral-200 rounded-lg bg-neutral-50 px-3 py-3 dark:border-neutral-800 dark:bg-neutral-900/70">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's a typo in the class attribute: items中心. This should be items-center.

          <label class="items-center flex gap-3 border border-neutral-200 rounded-lg bg-neutral-50 px-3 py-3 dark:border-neutral-800 dark:bg-neutral-900/70">

v-model="shortTermRedisPassword"
type="password"
class="w-full border border-neutral-200 rounded-md bg-white px-3 py-2 text-sm dark:border-neutral-700 dark:bg-neutral-900"
placeholder="{{ t('settings.memory.short_term.redisPasswordPlaceholder', 'Optional password') }}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The placeholder attribute is using mustache syntax {{ ... }}. This is incorrect for Vue attributes and will result in the literal string being displayed as the placeholder. You should use v-bind: or its shorthand : to bind the result of the t() function.

              :placeholder="t('settings.memory.short_term.redisPasswordPlaceholder', 'Optional password')"

inoribea and others added 4 commits October 7, 2025 20:51
Add comprehensive Chinese (Simplified) translations for memory-related
settings pages, including:
- Short-term memory configuration (providers, TTL, namespace, etc.)
- Long-term memory configuration (database, embeddings, search, etc.)
- All labels, descriptions, hints, and error messages

Translations follow the existing i18n patterns and terminology used
throughout the project.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
… fetching

Add comprehensive support for loading Live2D models directly from
model3.json URLs (including GitHub blob URLs):

Features:
- Auto-convert GitHub blob URLs to raw URLs
- Parse model3.json and collect all referenced resources
  (textures, motions, physics, expressions, sounds, etc.)
- Batch download all resources from the same base directory
- Package everything into a zip file using JSZip
- Cache the packaged model for offline use
- Generate preview images for imported models

This enables users to load Live2D models directly from GitHub or other
hosting services by simply pasting the model3.json URL, without needing
to manually download and package all the files.

Example URL support:
https://github.com/user/repo/blob/main/model/model.model3.json

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive Chinese (Simplified) documentation for deploying
AIRI Stage Web on Vercel, including:

- Step-by-step deployment instructions
- Environment variable configuration guide
- Memory system configuration (Redis/Postgres/Qdrant)
- Embedding provider setup
- Local verification steps
- Common troubleshooting tips

This mirrors the existing English guide and provides Chinese users
with complete deployment documentation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
inoribea and others added 8 commits October 11, 2025 02:51
- Fix 'can't access property timestamp' error
- API returns flat objects, not nested {message: ...} structure
- Map search/export results to expected MemoryMessage format
- Extract role from metadata with fallback to 'user'

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Added environment variable configuration support for:
- ElevenLabs (ELEVENLABS_API_KEY, ELEVENLABS_BASE_URL, ELEVENLABS_MODEL)
- Alibaba Cloud Model Studio/阿里百炼 (ALIBABA_CLOUD_*)
- Volcengine/火山引擎 (VOLCENGINE_*, including APP_ID)
- Microsoft/Azure Speech (MICROSOFT_SPEECH_*, including REGION/ENDPOINT)
- Index-TTS/Bilibili (INDEX_TTS_*)
- Player2 Speech (PLAYER2_BASE_URL, PLAYER2_SPEECH_MODEL)

Updated documentation in both English and Chinese for Vercel deployment.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Vision Module:
- Add complete vision recognition capabilities with AI-powered image analysis
- Implement camera capture functionality with real-time preview
- Create vision test platform for service validation and testing
- Add provider configuration and model selection interface
- Support multiple capture methods: camera, file upload, analysis prompts
- Include responsive design optimized for desktop and mobile screens

Messaging Module:
- Merge Discord and Telegram into unified messaging interface
- Add Telegram bot support with sticker and photo interaction
- Create separate configuration components for each messaging platform
- Implement unified provider selection and centralized management
- Add comprehensive internationalization support (EN/ZH)
- Update routing to consolidate messaging settings with improved UX

Audio Improvements:
- Fix audio device enumeration with automatic permission requests
- Add device refresh functionality with detailed user feedback
- Enhance permission handling flow with better error recovery
- Improve error messages and add debugging information

Chat Integration Foundation:
- Add image upload components for conversation interface integration
- Implement drag-and-drop image upload functionality with validation
- Create image preview and management system with multiple view modes
- Add pipeline framework for image analysis in chat context
- Support multiple image formats and comprehensive validation

Technical Enhancements:
- Add comprehensive TypeScript type definitions throughout codebase
- Implement proper error handling and retry mechanisms
- Create reusable composables for vision functionality
- Add performance optimizations for image processing
- Include detailed documentation and comprehensive usage guides

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Fix Button import in ImagePreview component
- Add @xsai/generate-image dependency to stage-ui
- Update vision store to use correct generateImage API
- Export useVision from composables index
- Successfully resolve module resolution issues

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Add supportsVision flag to ProviderMetadata interface
- Update buildOpenAICompatibleProvider to support vision capability
- Add supportsVision: true to OpenAI, Anthropic, Google Generative AI, OpenAI Compatible
- Fix vision store to use ChatProvider instead of VisionProvider
- Fix TypeScript type issues in vision composables and components
- Fix ImageUpload mobile detection and Messaging v-model bindings
- Restore proper Button export from misc directory

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Add useHearingStore import to use-modules-list composable
- Update hearing module configured status to use hearingStore.configured
- Fix hearing module visibility in main body module list

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Create dedicated messaging store that manages both Discord and Telegram
- Update messaging module configured status to check either Discord or Telegram
- Add dynamic icon logic: Discord icon when Discord is configured,
  Telegram icon when Telegram is configured, default chat icon otherwise
- Create missing index files for stores and modules exports
- Fix messaging module visibility and status in main module list

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Export useAiriCardStore from modules/index.ts
- Fixes build error for missing export in chat.ts

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@gg582
Copy link
Collaborator

gg582 commented Oct 11, 2025

Okay, the implementation itself looks good.
But could you attach some form of summary?

@gg582
Copy link
Collaborator

gg582 commented Oct 11, 2025

This pull request introduces a comprehensive long-term memory feature for AIRI, including serverless API endpoints, database migrations, and configuration for various providers and deployment environments. The changes set up the infrastructure for storing, searching, and managing user memory embeddings, with detailed documentation and environment variable templates to support local and Vercel deployments.

Backend API and Memory Functionality:

  • Added new serverless API endpoints in the api/memory/ directory for saving messages, searching similar messages, clearing sessions, retrieving recent session messages, and managing memory configuration, all with CORS support and robust error handling. [1] [2] [3] api/memory/session/[sessionId].tsR1-R40, [4]

  • Introduced a new memory_embeddings table migration with vector support (pgvector extension) for semantic search, including performance indexes and guidance for dimension selection based on embedding models.

Configuration and Deployment:

  • Added a detailed .env.example file covering all necessary environment variables for providers, database, memory settings, and deployment notes for Vercel and local environments.

  • Added a README.md for database migrations with step-by-step setup, embedding dimension notes, and alternative manual table creation instructions.

  • Updated the main README.md to reference the new Vercel deployment guide.

Project Structure and Tooling:

  • Added api/package.json and api/tsconfig.json to define dependencies (including pg, @vercel/kv, @qdrant/js-client-rest, etc.) and TypeScript configuration for the API functions. [1] [2]

  • Added .vercel-force-rebuild-1760120844 to trigger a clean rebuild on Vercel deployments.

UI/UX Tweaks:

  • Updated route metadata in the settings UI to improve navigation labels for vision and messaging modules.

Most Important Changes:

1. Long-Term Memory Feature and API Endpoints

2. Database Migration for Vector Embeddings

  • Added SQL migration to create the memory_embeddings table with pgvector extension, vector indexes for similarity search, and detailed comments for embedding dimension configuration.

3. Environment and Deployment Configuration

  • Introduced a comprehensive .env.example covering all providers, memory options, and deployment notes, and referenced new deployment documentation in the main README. [1] [2]

4. Documentation for Database Setup

  • Added a migration README with clear instructions for setting up the memory_embeddings table, adjusting vector dimensions, and configuring environment variables for different providers.

5. Project Structure and Build Support

  • Added API-specific package.json and tsconfig.json for dependency and TypeScript management, and a file to force clean Vercel rebuilds. [1] [2] [3]

These changes lay the groundwork for robust, scalable memory capabilities in AIRI, with clear deployment and configuration paths for both developers and end users.

inoribea and others added 18 commits October 12, 2025 01:00
…ucture

- Add error handling for generateImage API return values
- Ensure return object always has content property
- Handle case where API returns string or undefined
- Prevent access errors when vision analysis fails

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Add desktop toggle buttons in InteractiveArea.vue between clear messages and theme toggle
- Add mobile toggle buttons in MobileInteractiveArea.vue between theme toggle and settings
- Add speech toggle with green highlight when enabled
- Add hearing toggle with green highlight when enabled
- Add vision/image input toggle with blue highlight when enabled
- Add image upload button (shows when image input is enabled)
- Add file input handling for image upload functionality
- Conditionally show vision buttons only when vision store is configured
- Include proper icons, tooltips, and visual feedback for all toggles

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Fix button visibility to only show when corresponding modules are configured
- Add configured-based conditional rendering for speech and hearing buttons
- Keep vision buttons only shown when vision module is configured
- Add smart microphone permission handling - only request when enabling hearing
- Set hearing and speech buttons to default off state for user control
- Replace simple toggle with handleHearingToggle function for permission logic
- Apply consistent behavior across both desktop and mobile versions

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Fix VAD auto-start on page load causing unwanted microphone permission requests
- Remove invalid characters causing parsing errors
- Improve VAD initialization flow
- Maintain updated function definitions

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Add iconColor property for Factorio gaming module in use-modules-list
- Factorio gaming module now displays using proper i-lobe-icons:factorio icon
- Maintains same icon references as Discord (i-simple-icons:discord) and Telegram (i-simple-icons:telegram)
- Factorio joins other gaming modules with proper visual representation

Co-authored-by: factory-droid[fix: resolve VAD auto-start and syntax errors
<138933559+factory-droid[bot]@users.noreply.github.com>
- Fix Factorio and Minecraft module icons (iconColor → icon)
- Fix messaging module icon display (computed → IIFE)
- Add icon/iconColor support to RadioCardSimple component
- Fix vision model selection UI not showing properly
- Add watch listener for vision provider changes
- Fix vision store async provider instance calls
- Improve IconStatusItem hover effects for colored icons

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Revert IconStatusItem.vue icon color changes to original style
- Remove invalid Button variant='primary' in Messaging component
- Adjust Vision page layout: left side 60%, right side 40% for better display

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Reverts the vision analysis functions back to the original implementation that uses providerId and model in providerOptions instead of calling providerInstance.vision()

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…tions

Improves initializeProvider logic to properly detect empty values:
- Adds isEffectivelyEmpty helper function for deep empty checking
- Handles nested objects (e.g., volcengine's app: { appId })
- Treats empty strings, empty objects, and objects with all empty values as effectively empty
- Allows environment variables to override these empty configurations

This fixes the issue where users who previously saved empty configs
couldn't have them automatically filled from environment variables.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Changed from 'icon' to 'iconColor' for gaming module icons because:
- i-vscode-icons:file-type-minecraft is a colorful icon
- i-lobe-icons:factorio is a colorful icon
- iconColor property is specifically for colored icons in IconStatusItem

This fixes the issue where these icons were not displaying properly.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Changes to IconStatusItem component:
- Removed grayscale-100 and text color classes from iconColor template
- Changed iconColor styling to use opacity and brightness filters instead
- Non-hover: opacity 0.6, brightness 0.8 (slightly dimmed but keeps color)
- Hover: opacity 1, brightness 1/1.2 (brightens up without changing color)
- Separated icon and iconColor hover styles for different effects

This fixes Factorio and Minecraft icons not displaying because they
were being converted to grayscale, making colored icons invisible.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Moved messaging implementation from Messaging component to messaging.vue page
- Matches the structure of other module pages like consciousness and speech
- Uses neutral color scheme consistent with other pages
- Fixed dark mode styling for success messages

This should fix the blank messaging page issue.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Reverted messaging.vue to use Messaging component (原来的实现)
- Changed Minecraft and Factorio to use monochrome gameboy icon instead of colorful icons
- This keeps consistency with other module icons

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Minecraft uses i-vscode-icons:file-type-minecraft (colorful)
- Factorio uses i-lobe-icons:factorio (colorful)
- iconColor should now work properly after previous IconStatusItem fixes

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Fixed matchesEnvCredentials logic to handle nested objects like volcengine's app: { appId }.
Uses JSON.stringify for deep object comparison instead of reference equality.

This fixes the issue where providers with nested env variables (VOLCENGINE_APP_ID)
were not being recognized as configured even when environment variables were set.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@gg582
Copy link
Collaborator

gg582 commented Oct 13, 2025

113 files changed....At least you can write a comment in Chinese if you are not good at writing info in English..but you write your commit messages well, so I guess you are speaking English fluently. When things go well, you can write an explanation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants