mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-30 06:32:24 +00:00
refactor: update documentation, download system and code formatting improvements
- Update Claude rules with improved project overview and command documentation - Enhance download screen with better architecture detection and formatting - Improve device detection utilities with multi-architecture support - Add skills system troubleshooting documentation - Code formatting improvements with better line breaks and spacing - Optimize GitHub release asset parsing for platform-specific downloads 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -18,42 +18,42 @@ This project is a **crypto-focused communication platform** built with Tauri v2,
|
||||
|
||||
## Technology Stack
|
||||
|
||||
| Layer | Technology | Version | Purpose |
|
||||
| --------------------- | --------------- | ------- | ----------------------- |
|
||||
| Layer | Technology | Version | Purpose |
|
||||
| --------------------- | --------------- | ------- | ------------------------ |
|
||||
| **Frontend Core** |
|
||||
| UI Framework | React | 19.1.0 | Component-based UI |
|
||||
| Language | TypeScript | 5.8.3 | Type safety |
|
||||
| Build Tool | Vite | 7.0.4 | Fast development |
|
||||
| UI Framework | React | 19.1.0 | Component-based UI |
|
||||
| Language | TypeScript | 5.8.3 | Type safety |
|
||||
| Build Tool | Vite | 7.0.4 | Fast development |
|
||||
| **UI & Styling** |
|
||||
| Styling | Tailwind CSS | Latest | Utility-first CSS |
|
||||
| Components | Headless UI | Latest | Accessible components |
|
||||
| Animation | Framer Motion | Latest | Smooth animations |
|
||||
| Styling | Tailwind CSS | Latest | Utility-first CSS |
|
||||
| Components | Headless UI | Latest | Accessible components |
|
||||
| Animation | Framer Motion | Latest | Smooth animations |
|
||||
| **State & Data** |
|
||||
| State Management | Redux Toolkit | Latest | Predictable state mgmt |
|
||||
| State Persistence | Redux Persist | Latest | State rehydration |
|
||||
| Data Fetching | TanStack Query | Latest | Server state management |
|
||||
| Form Handling | React Hook Form | Latest | Form validation |
|
||||
| State Management | Redux Toolkit | Latest | Predictable state mgmt |
|
||||
| State Persistence | Redux Persist | Latest | State rehydration |
|
||||
| Data Fetching | TanStack Query | Latest | Server state management |
|
||||
| Form Handling | React Hook Form | Latest | Form validation |
|
||||
| **AI & Intelligence** |
|
||||
| AI Memory | Custom System | Latest | Context & learning |
|
||||
| Entity Graph | Neo4j | Latest | Knowledge relationships |
|
||||
| Embeddings | OpenAI | Latest | Semantic search |
|
||||
| AI Memory | Custom System | Latest | Context & learning |
|
||||
| Entity Graph | Neo4j | Latest | Knowledge relationships |
|
||||
| Embeddings | OpenAI | Latest | Semantic search |
|
||||
| **Communication** |
|
||||
| Real-time | Socket.io | Latest | Live messaging |
|
||||
| Telegram Integration | MTProto | Latest | Deep Telegram access |
|
||||
| MCP Protocol | JSON-RPC 2.0 | Latest | AI tool execution |
|
||||
| Real-time | Socket.io | Latest | Live messaging |
|
||||
| Telegram Integration | MTProto | Latest | Deep Telegram access |
|
||||
| MCP Protocol | JSON-RPC 2.0 | Latest | AI tool execution |
|
||||
| **Team & Skills** |
|
||||
| Skills Platform | GitHub Sync | Latest | Dynamic skill loading |
|
||||
| Team Management | REST API | Latest | Multi-user collaboration|
|
||||
| Skills Platform | GitHub Sync | Latest | Dynamic skill loading |
|
||||
| Team Management | REST API | Latest | Multi-user collaboration |
|
||||
| **Backend Core** |
|
||||
| Language | Rust | 1.93.0 | Performance & safety |
|
||||
| Framework | Tauri | 2.x | Cross-platform apps |
|
||||
| Language | Rust | 1.93.0 | Performance & safety |
|
||||
| Framework | Tauri | 2.x | Cross-platform apps |
|
||||
| **Backend Libraries** |
|
||||
| Async Runtime | Tokio | Latest | Async operations |
|
||||
| JSON Handling | Serde JSON | Latest | Serialization |
|
||||
| Database | SQLx + SQLite | Latest | Local storage |
|
||||
| HTTP Client | Reqwest | Latest | API requests |
|
||||
| WebSocket | WebSocket crate | Latest | Real-time messaging |
|
||||
| Utilities | UUID | Latest | Unique identifiers |
|
||||
| Async Runtime | Tokio | Latest | Async operations |
|
||||
| JSON Handling | Serde JSON | Latest | Serialization |
|
||||
| Database | SQLx + SQLite | Latest | Local storage |
|
||||
| HTTP Client | Reqwest | Latest | API requests |
|
||||
| WebSocket | WebSocket crate | Latest | Real-time messaging |
|
||||
| Utilities | UUID | Latest | Unique identifiers |
|
||||
|
||||
## Project Structure
|
||||
|
||||
|
||||
@@ -178,10 +178,10 @@ Get-Process | Where-Object {$_.ProcessName -match "tauri|vite|cargo|node"} | Sto
|
||||
|
||||
## Build Targets
|
||||
|
||||
| Platform | Command | Output |
|
||||
| -------- | ------------------------------ | ------------------- |
|
||||
| Windows | `yarn tauri build` | `.msi`, `.exe` |
|
||||
| macOS | `yarn tauri build` | `.dmg`, `.app` |
|
||||
| Linux | `yarn tauri build` | `.deb`, `.AppImage` |
|
||||
| Android | `yarn tauri android build` | `.apk`, `.aab` |
|
||||
| iOS | `yarn tauri ios build` | `.ipa` |
|
||||
| Platform | Command | Output |
|
||||
| -------- | -------------------------- | ------------------- |
|
||||
| Windows | `yarn tauri build` | `.msi`, `.exe` |
|
||||
| macOS | `yarn tauri build` | `.dmg`, `.app` |
|
||||
| Linux | `yarn tauri build` | `.deb`, `.AppImage` |
|
||||
| Android | `yarn tauri android build` | `.apk`, `.aab` |
|
||||
| iOS | `yarn tauri ios build` | `.ipa` |
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
# Skills System Troubleshooting Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The Skills System is a Python-based plugin architecture that allows AI agents to have domain-specific knowledge, tools, and automated behaviors. Skills run as isolated Python subprocesses and communicate with the main Tauri application via JSON-RPC.
|
||||
|
||||
## Common Issue: "Setup Failed" with Exit Code 1
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Skills modal shows "Setup Failed" with "Skill process exited with code: 1"
|
||||
- Console shows `ModuleNotFoundError: No module named 'pydantic'`
|
||||
- Error paths like `/Users/cyrus/alphahuman/skills/skills/telegram/`
|
||||
- Python import failures and subprocess stderr messages
|
||||
|
||||
### Root Cause Analysis
|
||||
|
||||
**Primary Issue: Missing Skills Git Submodule**
|
||||
The main cause is that the `skills` Git submodule is not initialized. The system expects skills to be available in the `skills/skills/` directory structure but finds an empty directory.
|
||||
|
||||
**Secondary Issues:**
|
||||
|
||||
1. **Missing Python Virtual Environment**: No `.venv` directory in the skills folder
|
||||
2. **Missing Python Dependencies**: Core packages like `pydantic`, `telethon`, `mcp` not installed
|
||||
3. **Incorrect Python Paths**: PYTHONPATH configuration issues
|
||||
|
||||
### Skills System Architecture
|
||||
|
||||
```
|
||||
skills/ # Git submodule root
|
||||
├── .venv/ # Python virtual environment
|
||||
├── requirements.txt # Shared dependencies
|
||||
├── skills/ # Individual skill packages
|
||||
│ ├── telegram/ # Telegram skill
|
||||
│ │ ├── skill.py # Main skill logic
|
||||
│ │ ├── manifest.json # Skill metadata
|
||||
│ │ ├── requirements.txt # Skill-specific dependencies
|
||||
│ │ └── ...
|
||||
│ ├── browser/ # Browser automation skill
|
||||
│ ├── calendar/ # Calendar integration skill
|
||||
│ └── ... # Other skills
|
||||
└── ...
|
||||
```
|
||||
|
||||
### Solution Steps
|
||||
|
||||
#### 1. Initialize Git Submodule
|
||||
|
||||
```bash
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
This downloads the skills repository from `https://github.com/alphahumanxyz/skills`.
|
||||
|
||||
#### 2. Create Python Virtual Environment
|
||||
|
||||
```bash
|
||||
cd skills
|
||||
python3 -m venv .venv
|
||||
.venv/bin/pip install --upgrade pip
|
||||
```
|
||||
|
||||
#### 3. Install Dependencies
|
||||
|
||||
```bash
|
||||
.venv/bin/pip install -r requirements.txt
|
||||
```
|
||||
|
||||
This installs:
|
||||
|
||||
- **Core Dependencies**: `mcp>=1.0.0`, `pydantic>=2.0`, `aiosqlite>=0.20.0`
|
||||
- **Skill-Specific Dependencies**: Each skill's requirements.txt (telegram, browser, etc.)
|
||||
|
||||
#### 4. Verify Installation
|
||||
|
||||
```bash
|
||||
# Test core imports
|
||||
.venv/bin/python -c "import pydantic, mcp; print('✅ Core dependencies OK')"
|
||||
|
||||
# Test skill import
|
||||
.venv/bin/python -c "import skills.telegram; print('✅ Telegram skill OK')"
|
||||
```
|
||||
|
||||
### How Skills System Works
|
||||
|
||||
#### Development vs Production Paths
|
||||
|
||||
- **Development**: Skills in git submodule at `./skills/skills/`
|
||||
- **Production**: Skills in `~/.alphahuman/skills/`
|
||||
- **Configuration**: `src/lib/skills/paths.ts` handles path resolution
|
||||
|
||||
#### Skill Execution Process
|
||||
|
||||
1. **Discovery**: `SkillProvider` scans for skill manifests
|
||||
2. **Registration**: Skills registered in Redux store
|
||||
3. **Startup**: Python subprocess spawned with proper environment
|
||||
4. **Communication**: JSON-RPC transport over stdin/stdout
|
||||
5. **Setup**: Interactive setup flow if required
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
The system automatically configures:
|
||||
|
||||
- **PYTHONPATH**: Includes skills directory and virtual environment
|
||||
- **Telegram API**: `TELEGRAM_API_ID`, `TELEGRAM_API_HASH`
|
||||
- **Working Directory**: Skills submodule root
|
||||
|
||||
### Verification Commands
|
||||
|
||||
```bash
|
||||
# Check submodule status
|
||||
git submodule status
|
||||
|
||||
# Verify skills directory structure
|
||||
ls -la skills/skills/telegram/
|
||||
|
||||
# Check virtual environment
|
||||
ls -la skills/.venv/
|
||||
|
||||
# Test Python environment
|
||||
cd skills && .venv/bin/python -c "import sys; print('\\n'.join(sys.path))"
|
||||
```
|
||||
|
||||
### Prevention
|
||||
|
||||
To prevent this issue in fresh checkouts:
|
||||
|
||||
1. **Always initialize submodules**:
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules <repo-url>
|
||||
# or after clone:
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
2. **Setup script**: Consider adding to `package.json`:
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"setup": "git submodule update --init && cd skills && python3 -m venv .venv && .venv/bin/pip install -r requirements.txt"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Related Files
|
||||
|
||||
- **Frontend**: `src/lib/skills/` - Skills management system
|
||||
- **Backend**: `src-tauri/src/commands/skills.rs` - Rust skill commands
|
||||
- **Configuration**: `src/utils/config.ts` - Environment variables
|
||||
- **Providers**: `src/providers/SkillProvider.tsx` - Skills lifecycle
|
||||
|
||||
### Expected Behavior After Fix
|
||||
|
||||
1. Skills modal should show "Connect Telegram" instead of error
|
||||
2. No more Python import errors in console
|
||||
3. Skill setup process should work correctly
|
||||
4. Background GitHub sync should function properly
|
||||
|
||||
This fix resolves the fundamental infrastructure issue preventing skills from loading and running properly.
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
type Architecture,
|
||||
type ArchitectureDownloadLink,
|
||||
detectPlatform,
|
||||
fetchLatestRelease,
|
||||
getDownloadLink,
|
||||
getPlatformDisplayName,
|
||||
parseReleaseAssets,
|
||||
parseReleaseAssetsByArchitecture,
|
||||
type Architecture,
|
||||
type ArchitectureDownloadLink,
|
||||
type Platform,
|
||||
type PlatformArchitectureLinks,
|
||||
type PlatformDownloadLinks,
|
||||
@@ -33,7 +33,9 @@ const DownloadScreen = () => {
|
||||
const [selectedPlatform, setSelectedPlatform] = useState<Platform | null>(null);
|
||||
const [selectedArchitecture, setSelectedArchitecture] = useState<Architecture | null>(null);
|
||||
const [releaseLinks, setReleaseLinks] = useState<PlatformDownloadLinks | null>(null);
|
||||
const [architectureLinks, setArchitectureLinks] = useState<PlatformArchitectureLinks | null>(null);
|
||||
const [architectureLinks, setArchitectureLinks] = useState<PlatformArchitectureLinks | null>(
|
||||
null
|
||||
);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
@@ -63,7 +65,9 @@ const DownloadScreen = () => {
|
||||
const platformArchLinks = archLinks[detected.platform as keyof PlatformArchitectureLinks];
|
||||
if (platformArchLinks && platformArchLinks.length > 0) {
|
||||
// Prefer detected architecture, otherwise use first available
|
||||
const preferredLink = platformArchLinks.find(link => link.architecture === detected.architecture) || platformArchLinks[0];
|
||||
const preferredLink =
|
||||
platformArchLinks.find(link => link.architecture === detected.architecture) ||
|
||||
platformArchLinks[0];
|
||||
setSelectedArchitecture(preferredLink.architecture);
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -88,7 +92,8 @@ const DownloadScreen = () => {
|
||||
return getDownloadLink(selectedPlatform || 'unknown', releaseLinks || undefined);
|
||||
}
|
||||
|
||||
const platformArchLinks = architectureLinks[selectedPlatform as keyof PlatformArchitectureLinks];
|
||||
const platformArchLinks =
|
||||
architectureLinks[selectedPlatform as keyof PlatformArchitectureLinks];
|
||||
if (platformArchLinks && selectedArchitecture) {
|
||||
const link = platformArchLinks.find(l => l.architecture === selectedArchitecture);
|
||||
if (link) {
|
||||
@@ -139,9 +144,7 @@ const DownloadScreen = () => {
|
||||
{error && !isLoading && (
|
||||
<div className="mb-6">
|
||||
<div className="bg-red-500/10 border border-red-500/20 rounded-xl p-4">
|
||||
<p className="text-sm text-red-400">
|
||||
{error}. Using fallback download links.
|
||||
</p>
|
||||
<p className="text-sm text-red-400">{error}. Using fallback download links.</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -209,9 +212,12 @@ const DownloadScreen = () => {
|
||||
{downloadOptions
|
||||
.filter(opt => opt.platform !== selectedPlatform)
|
||||
.map(option => {
|
||||
const platformArchLinks = architectureLinks?.[option.platform as keyof PlatformArchitectureLinks];
|
||||
const platformArchLinks =
|
||||
architectureLinks?.[option.platform as keyof PlatformArchitectureLinks];
|
||||
const hasValidLink = platformArchLinks && platformArchLinks.length > 0;
|
||||
const defaultLink = platformArchLinks?.[0]?.url || getDownloadLink(option.platform, releaseLinks || undefined);
|
||||
const defaultLink =
|
||||
platformArchLinks?.[0]?.url ||
|
||||
getDownloadLink(option.platform, releaseLinks || undefined);
|
||||
const hasMultipleArchs = platformArchLinks && platformArchLinks.length > 1;
|
||||
|
||||
return (
|
||||
|
||||
@@ -141,7 +141,9 @@ export function detectPlatform(): PlatformInfo {
|
||||
* Fetch the latest release from GitHub
|
||||
*/
|
||||
export async function fetchLatestRelease(): Promise<GitHubRelease> {
|
||||
const response = await fetch('https://api.github.com/repos/alphahumanxyz/alphahuman/releases/latest');
|
||||
const response = await fetch(
|
||||
'https://api.github.com/repos/alphahumanxyz/alphahuman/releases/latest'
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch release: ${response.statusText}`);
|
||||
}
|
||||
@@ -185,7 +187,9 @@ export function getArchitectureDisplayName(arch: Architecture): string {
|
||||
/**
|
||||
* Parse GitHub release assets and map them to platforms with architecture support
|
||||
*/
|
||||
export function parseReleaseAssetsByArchitecture(assets: GitHubReleaseAsset[]): PlatformArchitectureLinks {
|
||||
export function parseReleaseAssetsByArchitecture(
|
||||
assets: GitHubReleaseAsset[]
|
||||
): PlatformArchitectureLinks {
|
||||
const links: PlatformArchitectureLinks = {};
|
||||
|
||||
// Use Maps to track unique architectures per platform
|
||||
@@ -212,21 +216,39 @@ export function parseReleaseAssetsByArchitecture(assets: GitHubReleaseAsset[]):
|
||||
};
|
||||
|
||||
// Windows: .exe, .msi, .zip (Windows)
|
||||
if (name.includes('windows') || name.includes('.exe') || name.includes('.msi') || (name.includes('.zip') && !name.includes('macos'))) {
|
||||
if (
|
||||
name.includes('windows') ||
|
||||
name.includes('.exe') ||
|
||||
name.includes('.msi') ||
|
||||
(name.includes('.zip') && !name.includes('macos'))
|
||||
) {
|
||||
// Only add if this architecture doesn't exist yet, or prefer more specific filenames
|
||||
if (!windowsMap.has(architecture) || (name.includes('windows') && !windowsMap.get(architecture)?.fileName.toLowerCase().includes('windows'))) {
|
||||
if (
|
||||
!windowsMap.has(architecture) ||
|
||||
(name.includes('windows') &&
|
||||
!windowsMap.get(architecture)?.fileName.toLowerCase().includes('windows'))
|
||||
) {
|
||||
windowsMap.set(architecture, link);
|
||||
}
|
||||
}
|
||||
// macOS: .dmg
|
||||
else if (name.includes('macos') || name.includes('.dmg') || name.includes('darwin')) {
|
||||
// Only add if this architecture doesn't exist yet, or prefer more specific filenames
|
||||
if (!macosMap.has(architecture) || (name.includes('macos') && !macosMap.get(architecture)?.fileName.toLowerCase().includes('macos'))) {
|
||||
if (
|
||||
!macosMap.has(architecture) ||
|
||||
(name.includes('macos') &&
|
||||
!macosMap.get(architecture)?.fileName.toLowerCase().includes('macos'))
|
||||
) {
|
||||
macosMap.set(architecture, link);
|
||||
}
|
||||
}
|
||||
// Linux: .AppImage, .deb, .rpm
|
||||
else if (name.includes('linux') || name.includes('.appimage') || name.includes('.deb') || name.includes('.rpm')) {
|
||||
else if (
|
||||
name.includes('linux') ||
|
||||
name.includes('.appimage') ||
|
||||
name.includes('.deb') ||
|
||||
name.includes('.rpm')
|
||||
) {
|
||||
// Prefer AppImage, then deb, then rpm for the same architecture
|
||||
const existing = linuxMap.get(architecture);
|
||||
if (!existing) {
|
||||
@@ -267,7 +289,10 @@ export function parseReleaseAssetsByArchitecture(assets: GitHubReleaseAsset[]):
|
||||
}
|
||||
|
||||
// Sort architectures: prefer detected architecture, then x64, then aarch64
|
||||
const sortArchitectures = (archLinks: ArchitectureDownloadLink[], preferredArch?: Architecture) => {
|
||||
const sortArchitectures = (
|
||||
archLinks: ArchitectureDownloadLink[],
|
||||
preferredArch?: Architecture
|
||||
) => {
|
||||
return archLinks.sort((a, b) => {
|
||||
if (preferredArch && a.architecture === preferredArch) return -1;
|
||||
if (preferredArch && b.architecture === preferredArch) return 1;
|
||||
|
||||
Reference in New Issue
Block a user