-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
feat: Add configurable memory system with short-term and long-term storage #636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- 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>
helper loads
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>
✅ Deploy Preview for airi-vtuber ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for airi-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Summary of ChangesHello @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
Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this 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.
| if (config.provider !== 'postgres-pgvector') { | ||
| throw new Error(`Unsupported long-term memory provider: ${config.provider}`) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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| 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 | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| catch { | ||
| await this.rewriteQueueWithLimit(key) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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)
}
packages/server-runtime/src/index.ts
Outdated
|
|
||
| await saveShortTermMemory({ | ||
| sessionId: body.sessionId, | ||
| message: body.message as any, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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') }}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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') }}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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')"
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>
- 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>
|
Okay, the implementation itself looks good. |
|
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:
Configuration and Deployment:
Project Structure and Tooling:
UI/UX Tweaks:
Most Important Changes: 1. Long-Term Memory Feature and API Endpoints
2. Database Migration for Vector Embeddings
3. Environment and Deployment Configuration
4. Documentation for Database Setup
5. Project Structure and Build Support
These changes lay the groundwork for robust, scalable memory capabilities in AIRI, with clear deployment and configuration paths for both developers and end users. |
…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>
|
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 |
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)MemorySystemFactoryfor all provider instantiation🎛️ UI Integration (
packages/stage-pages,packages/stage-ui)/settings/memorywith provider configuration🔌 Server API (
packages/server-runtime)RESTful endpoints for memory operations:
GET /api/memory/config- Retrieve current configurationPOST /api/memory/config- Update memory configurationPOST /api/memory/save- Save conversation messagesGET /api/memory/session/:id- Fetch recent messages by sessionPOST /api/memory/search- Semantic similarity searchPOST /api/memory/clear- Clear session memoryGET /api/memory/export- Export user memory dataArchitecture
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):