diff --git a/.claude/mcp.json b/.claude/mcp.json index 81364bdd8..277218e6e 100644 --- a/.claude/mcp.json +++ b/.claude/mcp.json @@ -1 +1 @@ -{ "mcpServers": { "alphaHuman": { "type": "http", "url": "https://alphahuman.readme.io/mcp" } } } +{ "mcpServers": { "alphahuman": { "type": "http", "url": "https://openhuman.readme.io/mcp" } } } diff --git a/.claude/rules/01-project-overview.md b/.claude/rules/01-project-overview.md index b2a140536..c8c066855 100644 --- a/.claude/rules/01-project-overview.md +++ b/.claude/rules/01-project-overview.md @@ -58,7 +58,7 @@ This project is a **crypto-focused communication platform** built with Tauri v2, ## Project Structure ``` -frontend-runner-alphahuman/ +frontend-runner-openhuman/ ├── .claude/ # Claude AI configuration │ ├── rules/ # Modular documentation │ └── agents/ # Subagent configurations @@ -86,7 +86,7 @@ frontend-runner-alphahuman/ ## Key Configuration Files -- `tauri.conf.json` - Tauri configuration (app identifier: com.alphahuman.app) +- `tauri.conf.json` - Tauri configuration (app identifier: com.openhuman.app) - `Cargo.toml` - Rust dependencies and workspace configuration - `package.json` - Node.js dependencies and scripts - `vite.config.ts` - Vite build configuration with Node.js polyfills diff --git a/.claude/rules/02-development-commands.md b/.claude/rules/02-development-commands.md index 3e7215263..0afea20c3 100644 --- a/.claude/rules/02-development-commands.md +++ b/.claude/rules/02-development-commands.md @@ -116,7 +116,7 @@ adb kill-server # Stop ADB server adb start-server # Restart ADB server # Force stop app on device: -adb shell am force-stop com.alphahuman.app +adb shell am force-stop com.openhuman.app # Kill Gradle daemon if stuck: # macOS/Linux: diff --git a/.claude/rules/13-backend-auth-implementation.md b/.claude/rules/13-backend-auth-implementation.md index 3d5b232a2..0f0999993 100644 --- a/.claude/rules/13-backend-auth-implementation.md +++ b/.claude/rules/13-backend-auth-implementation.md @@ -24,7 +24,7 @@ Web Browser Backend Server Desktop App (Tauri │<─────────────────────────────│ │ │ │ │ │ 5. Redirect to │ │ - │ alphahuman://auth?token= │ │ + │ openhuman://auth?token= │ │ │─────────────────────────────────────────────────────────────>│ │ │ │ │ │ 6. Rust invoke │ @@ -58,7 +58,7 @@ Initiates Telegram OAuth. The frontend opens this URL in the system browser. 2. On callback, validate Telegram user data 3. Create or find user in database 4. Generate a short-lived `loginToken` (single-use, 5-minute TTL) -5. Redirect to `alphahuman://auth?token=` +5. Redirect to `openhuman://auth?token=` ### 2. `POST /api/auth/web-complete` @@ -181,7 +181,7 @@ Called by the Tauri Rust command `exchange_token` (NOT browser fetch). Exchanges 3. **HTTPS only** in production — tokens travel as URL parameters and POST bodies 4. **Rate limiting** — on `/api/auth/web-complete` and `/auth/desktop-exchange` 5. **Token entropy** — minimum 256 bits of randomness -6. **Deep link validation** — the desktop app only processes `alphahuman://auth` paths; ignore unknown paths +6. **Deep link validation** — the desktop app only processes `openhuman://auth` paths; ignore unknown paths 7. **Telegram data verification** — validate the `hash` field using your bot token per Telegram docs ## Implementation Details @@ -226,14 +226,14 @@ Set `VITE_BACKEND_URL` environment variable for different environments. ## Frontend Integration Points -| File | Role | -| -------------------------------------- | ------------------------------------------------------------------------------------- | -| `src/main.tsx` | Lazy-imports and starts the deep link listener | -| `src/utils/desktopDeepLinkListener.ts` | Parses deep link -> invokes Rust `exchange_token` -> stores session -> navigates | -| `src/utils/deeplink.ts` | Web-side: calls `/api/auth/web-complete` and builds `alphahuman://auth?token=...` URL | -| `src/utils/config.ts` | Backend URL configuration | -| `src/pages/Login.tsx` | Opens `GET /auth/telegram?platform=desktop` in browser | -| `src-tauri/src/lib.rs` | Rust `exchange_token` command using `reqwest` (CORS-free) | +| File | Role | +| -------------------------------------- | ------------------------------------------------------------------------------------ | +| `src/main.tsx` | Lazy-imports and starts the deep link listener | +| `src/utils/desktopDeepLinkListener.ts` | Parses deep link -> invokes Rust `exchange_token` -> stores session -> navigates | +| `src/utils/deeplink.ts` | Web-side: calls `/api/auth/web-complete` and builds `openhuman://auth?token=...` URL | +| `src/utils/config.ts` | Backend URL configuration | +| `src/pages/Login.tsx` | Opens `GET /auth/telegram?platform=desktop` in browser | +| `src-tauri/src/lib.rs` | Rust `exchange_token` command using `reqwest` (CORS-free) | ## Phone OTP Flow (Future) diff --git a/.claude/rules/14-deep-link-platform-guide.md b/.claude/rules/14-deep-link-platform-guide.md index c3fd9bd4b..02df6b16d 100644 --- a/.claude/rules/14-deep-link-platform-guide.md +++ b/.claude/rules/14-deep-link-platform-guide.md @@ -2,14 +2,14 @@ ## Overview -The `alphahuman://` custom URL scheme is used to hand off authentication from a web browser to the Tauri desktop app. This document covers platform-specific behavior, gotchas, and build requirements discovered during development. +The `openhuman://` custom URL scheme is used to hand off authentication from a web browser to the Tauri desktop app. This document covers platform-specific behavior, gotchas, and build requirements discovered during development. ## Scheme Registration Configured in `src-tauri/tauri.conf.json`: ```json -{ "plugins": { "deep-link": { "desktop": { "schemes": ["alphahuman"] } } } } +{ "plugins": { "deep-link": { "desktop": { "schemes": ["openhuman"] } } } } ``` ## macOS @@ -50,7 +50,7 @@ cp -R src-tauri/target/debug/bundle/macos/tauri-app.app /Applications/ open /Applications/tauri-app.app # Test deep link -open "alphahuman://auth?token=YOUR_TOKEN" +open "openhuman://auth?token=YOUR_TOKEN" ``` ### Cargo Caching Gotcha @@ -68,9 +68,9 @@ open "alphahuman://auth?token=YOUR_TOKEN" - The macOS WebView (WKWebView) caches aggressively - Clear caches when debugging stale content: ```bash - rm -rf ~/Library/WebKit/com.alphahuman.app - rm -rf ~/Library/Caches/com.alphahuman.app - rm -rf ~/Library/Application\ Support/com.alphahuman.app + rm -rf ~/Library/WebKit/com.openhuman.app + rm -rf ~/Library/Caches/com.openhuman.app + rm -rf ~/Library/Application\ Support/com.openhuman.app ``` ### Debug Builds: Secondary Instance Behavior diff --git a/.claude/rules/16-macos-background-execution.md b/.claude/rules/16-macos-background-execution.md index 84e92afc8..2f5c7b2f2 100644 --- a/.claude/rules/16-macos-background-execution.md +++ b/.claude/rules/16-macos-background-execution.md @@ -213,8 +213,8 @@ npm run tauri build -- --debug --bundles app Clear WebKit cache if needed: ```bash -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app ``` ## Configuration Options diff --git a/.claude/rules/17-skills-memory-inference-flow.md b/.claude/rules/17-skills-memory-inference-flow.md index 984017d4f..29c8a9d86 100644 --- a/.claude/rules/17-skills-memory-inference-flow.md +++ b/.claude/rules/17-skills-memory-inference-flow.md @@ -31,10 +31,10 @@ Token present Two Tauri event listeners run continuously: -| Event | What it does | -|---|---| -| `skill-state-changed` | Dispatches `setSkillState` into Redux `skillsSlice.skillStates[skillId]` | -| `runtime:skill-status-changed` | Updates `skillsSlice.skills[skillId].status`; surfaces errors | +| Event | What it does | +| ------------------------------ | ------------------------------------------------------------------------ | +| `skill-state-changed` | Dispatches `setSkillState` into Redux `skillsSlice.skillStates[skillId]` | +| `runtime:skill-status-changed` | Updates `skillsSlice.skills[skillId].status`; surfaces errors | --- @@ -48,7 +48,8 @@ It is constructed with the user's JWT (`authSlice.token`) and stored as `Arc>`). Base URL resolution (in priority order): -1. `ALPHAHUMAN_BASE_URL` env var + +1. `OPENHUMAN_BASE_URL` env var 2. `TINYHUMANS_BASE_URL` env var 3. SDK default @@ -109,12 +110,12 @@ Examples: `skill:gmail:user@example.com`, `skill:notion:default`. **File**: `src-tauri/src/memory/mod.rs` -| Method | SDK call | When used | -|---|---|---| -| `store_skill_sync(...)` | `insert_memory` | OAuth complete, periodic sync | -| `query_skill_context(...)` | `query_memory` | RAG query — fetch relevant chunks for a user question | -| `recall_skill_context(...)` | `recall_memory` | Recall synthesised summary from Master node | -| `clear_skill_memory(...)` | `delete_memory` | OAuth revoke / disconnect | +| Method | SDK call | When used | +| --------------------------- | --------------- | ----------------------------------------------------- | +| `store_skill_sync(...)` | `insert_memory` | OAuth complete, periodic sync | +| `query_skill_context(...)` | `query_memory` | RAG query — fetch relevant chunks for a user question | +| `recall_skill_context(...)` | `recall_memory` | Recall synthesised summary from Master node | +| `clear_skill_memory(...)` | `delete_memory` | OAuth revoke / disconnect | --- @@ -141,16 +142,17 @@ chatSend({ threadId, message, model, authToken, backendUrl, messages, notionCont Completion events flow back over Tauri events: -| Event | Frontend handler | -|---|---| -| `chat:tool_call` | shows active tool indicator | -| `chat:tool_result` | clears tool indicator | -| `chat:done` | `dispatch(addInferenceResponse(...))` | -| `chat:error` | shows error, clears loading state | +| Event | Frontend handler | +| ------------------ | ------------------------------------- | +| `chat:tool_call` | shows active tool indicator | +| `chat:tool_result` | clears tool indicator | +| `chat:done` | `dispatch(addInferenceResponse(...))` | +| `chat:error` | shows error, clears loading state | ### 5b. Web/Fallback Path Used when not running in Tauri (browser). Runs the agentic loop entirely in TypeScript: + - Calls `inferenceApi.createChatCompletion(request)` directly - Executes tools via `skillManager.callTool(skillId, toolName, args)` - Both paths share the same 5-round `MAX_TOOL_ROUNDS` limit and `{skillId}__{toolName}` naming convention @@ -215,6 +217,7 @@ Step 6: Agentic loop (max 5 rounds) **File**: `src-tauri/src/runtime/qjs_engine.rs` — `call_tool(skill_id, tool_name, args)` The Rust runtime routes `call_tool` into the running QuickJS/V8 skill instance: + - Serialises `args` as JSON - Calls the JS tool handler registered by the skill - Returns `ToolCallResult { content: Vec, is_error: bool }` @@ -262,14 +265,14 @@ Separately (async, fire-and-forget): ## Key Files Reference -| File | Role | -|---|---| -| `src/providers/SkillProvider.tsx` | Discovery, lifecycle, Redux state sync | -| `src/pages/Conversations.tsx` | Message send, both code paths, Notion context | -| `src/services/chatService.ts` | `chatSend()`, `chatCancel()`, `useRustChat()` | -| `src-tauri/src/commands/chat.rs` | Rust agentic loop, context assembly, tool dispatch | -| `src-tauri/src/commands/memory.rs` | `recall_memory` Tauri command | -| `src-tauri/src/memory/mod.rs` | `MemoryClient` wrapping tinyhumansai SDK | -| `src-tauri/src/runtime/qjs_skill_instance.rs` | Skill sync → memory write triggers | -| `src-tauri/src/runtime/qjs_engine.rs` | `discover_skills()`, `call_tool()`, `all_tools()` | -| `skills/skills/*/manifest.json` | Skill metadata (git submodule) | +| File | Role | +| --------------------------------------------- | -------------------------------------------------- | +| `src/providers/SkillProvider.tsx` | Discovery, lifecycle, Redux state sync | +| `src/pages/Conversations.tsx` | Message send, both code paths, Notion context | +| `src/services/chatService.ts` | `chatSend()`, `chatCancel()`, `useRustChat()` | +| `src-tauri/src/commands/chat.rs` | Rust agentic loop, context assembly, tool dispatch | +| `src-tauri/src/commands/memory.rs` | `recall_memory` Tauri command | +| `src-tauri/src/memory/mod.rs` | `MemoryClient` wrapping tinyhumansai SDK | +| `src-tauri/src/runtime/qjs_skill_instance.rs` | Skill sync → memory write triggers | +| `src-tauri/src/runtime/qjs_engine.rs` | `discover_skills()`, `call_tool()`, `all_tools()` | +| `skills/skills/*/manifest.json` | Skill metadata (git submodule) | diff --git a/.claude/skills-system-troubleshooting.md b/.claude/skills-system-troubleshooting.md index dec13019a..12a66b73f 100644 --- a/.claude/skills-system-troubleshooting.md +++ b/.claude/skills-system-troubleshooting.md @@ -10,7 +10,7 @@ The Skills System is a Python-based plugin architecture that allows AI agents to - 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/` +- Error paths like `/Users/cyrus/openhuman/skills/skills/telegram/` - Python import failures and subprocess stderr messages ### Root Cause Analysis @@ -51,7 +51,7 @@ git submodule init git submodule update ``` -This downloads the skills repository from `https://github.com/alphahumanxyz/skills`. +This downloads the skills repository from `https://github.com/openhumanxyz/skills`. #### 2. Create Python Virtual Environment @@ -87,7 +87,7 @@ This installs: #### Development vs Production Paths - **Development**: Skills in git submodule at `./skills/skills/` -- **Production**: Skills in `~/.alphahuman/skills/` +- **Production**: Skills in `~/.openhuman/skills/` - **Configuration**: `src/lib/skills/paths.ts` handles path resolution #### Skill Execution Process diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..fd4d01cd6 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,36 @@ +## Summary + +- What changed and why. +- Keep this to 3-6 bullets focused on user-visible or architecture-impacting changes. + +## Problem + +- What issue or risk this PR addresses. +- Include context needed for reviewers to evaluate correctness quickly. + +## Solution + +- How the implementation solves the problem. +- Note important design decisions and tradeoffs. + +## Testing + +- [ ] `yarn -s compile` +- [ ] `cargo check --manifest-path src-tauri/Cargo.toml` +- [ ] Other checks run (list commands) +- [ ] Manual validation completed (list scenarios) + +## Impact + +- Runtime/platform impact (desktop/mobile/web/CLI), if any. +- Performance, security, migration, or compatibility implications. + +## Breaking Changes + +- [ ] None +- [ ] Yes (describe clearly, including migration steps) + +## Related + +- Issue(s): +- Follow-up PR(s)/TODOs: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 55224ab1d..8bb919a23 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: 24.x - cache: "yarn" + cache: 'yarn' - name: Install Rust stable uses: dtolnay/rust-toolchain@stable @@ -39,23 +39,22 @@ jobs: sudo apt-get update sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - - name: Cache Cargo registry + # Skip first 7 lines of Cargo.lock (workspace package version bumps) so the key tracks dependency changes only + - name: Cargo.lock fingerprint (deps only) + id: cargo-lock-fingerprint + shell: bash + run: | + echo "hash=$(tail -n +8 src-tauri/Cargo.lock | openssl dgst -sha256 | awk '{print $2}')" >> "$GITHUB_OUTPUT" + + - name: Cache Cargo registry and git sources uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git - key: ${{ runner.os }}-cargo-${{ hashFiles('src-tauri/Cargo.lock') }} + key: ${{ runner.os }}-cargo-registry-${{ steps.cargo-lock-fingerprint.outputs.hash }} restore-keys: | - ${{ runner.os }}-cargo- - - - name: Cache Cargo build artifacts - uses: actions/cache@v4 - with: - path: src-tauri/target - key: ${{ runner.os }}-cargo-target-${{ hashFiles('src-tauri/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-cargo-target- + ${{ runner.os }}-cargo-registry- - name: Cache node modules id: yarn-cache @@ -74,6 +73,6 @@ jobs: run: cd skills && yarn install --frozen-lockfile - name: Build Tauri app - run: yarn tauri build -- --target x86_64-unknown-linux-gnu + run: yarn tauri build -- --target x86_64-unknown-linux-gnu -- --bin OpenHuman env: NODE_ENV: production diff --git a/.github/workflows/macos-arm64-build.yml b/.github/workflows/macos-arm64-build.yml new file mode 100644 index 000000000..1b81d4e81 --- /dev/null +++ b/.github/workflows/macos-arm64-build.yml @@ -0,0 +1,108 @@ +# Standalone macOS Apple Silicon (aarch64) Tauri build — no prepare-release / tagging. +# +# GitHub: workflow_dispatch checks out the ref. Local act: ACT=true skips checkout (use -b bind + run +# ./scripts/run-macos-arm64-build.sh so submodules are initialized before act copies the tree). +name: macOS ARM64 build + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + build-macos-arm64: + name: Build macOS aarch64 (signed) + runs-on: macos-latest + env: + GITHUB_TOKEN: ${{ secrets.XGH_TOKEN || github.token }} + steps: + - name: Checkout repository + if: ${{ env.ACT != 'true' }} + uses: actions/checkout@v4 + + - name: Set Xcode version + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + - name: Setup Node.js 24.x + uses: actions/setup-node@v4 + with: + node-version: 24.x + cache: yarn + + - name: Install Rust stable + uses: dtolnay/rust-toolchain@stable + with: + targets: aarch64-apple-darwin + + - name: Cargo.lock fingerprint (deps only) + id: cargo-lock-fingerprint + shell: bash + run: | + echo "hash=$(tail -n +8 src-tauri/Cargo.lock | openssl dgst -sha256 | awk '{print $2}')" >> "$GITHUB_OUTPUT" + + - name: Cache Cargo registry and git sources + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-registry-${{ steps.cargo-lock-fingerprint.outputs.hash }} + restore-keys: | + ${{ runner.os }}-cargo-registry- + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Install skills dependencies + run: cd skills && yarn install --frozen-lockfile + + - name: Build skills + run: cd skills && yarn build + + - name: Define Tauri configuration overrides + id: config-overrides + uses: actions/github-script@v7 + env: + BASE_URL: ${{ vars.BASE_URL }} + UPDATER_PUBLIC_KEY: ${{ secrets.UPDATER_PUBLIC_KEY }} + WITH_UPDATER: 'true' + with: + github-token: ${{ secrets.XGH_TOKEN || github.token }} + script: | + const workspacePath = process.env.GITHUB_WORKSPACE.replace(/\\/g, '/'); + const prefix = workspacePath.startsWith('/') ? 'file://' : 'file:///'; + const moduleUrl = `${prefix}${workspacePath}/scripts/prepareTauriConfig.js`; + const { default: prepareTauriConfig } = await import(moduleUrl); + const config = prepareTauriConfig(); + core.setOutput('json', JSON.stringify(config)); + + - name: Build frontend + run: yarn build + env: + NODE_ENV: production + VITE_BACKEND_URL: ${{ vars.VITE_BACKEND_URL }} + VITE_SENTRY_DSN: ${{ vars.VITE_SENTRY_DSN }} + VITE_DEBUG: ${{ vars.VITE_DEBUG }} + + - name: Build, package (no GitHub release upload) + uses: tauri-apps/tauri-action@v0.6.2 + env: + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + BASE_URL: ${{ vars.BASE_URL }} + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} + WITH_UPDATER: 'true' + MACOSX_DEPLOYMENT_TARGET: '10.15' + with: + args: -c ${{ steps.config-overrides.outputs.json }} --target aarch64-apple-darwin -- -- --bin OpenHuman + includeDebug: false + includeRelease: true + includeUpdaterJson: false diff --git a/.github/workflows/package-and-publish.yml b/.github/workflows/package-and-publish.yml index 98123f973..1b6f9823f 100644 --- a/.github/workflows/package-and-publish.yml +++ b/.github/workflows/package-and-publish.yml @@ -17,10 +17,8 @@ on: env: IS_PR: ${{ github.event_name == 'pull_request' }} SHOULD_PUBLISH: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }} - PUBLISH_REPO: alphahumanxyz/alphahuman + PUBLISH_REPO: openhumanxyz/openhuman XGH_TOKEN: ${{ secrets.XGH_TOKEN }} - UPDATER_GIST_URL: ${{ secrets.UPDATER_GIST_URL }} - UPDATER_GIST_ID: ${{ secrets.UPDATER_GIST_ID }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: @@ -48,7 +46,7 @@ jobs: run: | PACKAGE_VERSION=$(node -p "require('./package.json').version") TAG_NAME="v${PACKAGE_VERSION}" - RELEASE_NAME="AlphaHuman v${PACKAGE_VERSION}" + RELEASE_NAME="OpenHuman v${PACKAGE_VERSION}" echo "package-version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT echo "tag-name=$TAG_NAME" >> $GITHUB_OUTPUT echo "release-name=$RELEASE_NAME" >> $GITHUB_OUTPUT @@ -162,15 +160,15 @@ jobs: fail-fast: false matrix: settings: - - platform: "macos-latest" - args: "--target aarch64-apple-darwin" - target: "aarch64-apple-darwin" - - platform: "macos-latest" - args: "--target x86_64-apple-darwin" - target: "x86_64-apple-darwin" - - platform: "ubuntu-22.04" - args: "" - target: "" + - platform: 'macos-latest' + args: '--target aarch64-apple-darwin' + target: 'aarch64-apple-darwin' + - platform: 'macos-latest' + args: '--target x86_64-apple-darwin' + target: 'x86_64-apple-darwin' + - platform: 'ubuntu-22.04' + args: '' + target: '' runs-on: ${{ matrix.settings.platform }} steps: - name: Checkout @@ -191,7 +189,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: 24.x - cache: "yarn" + cache: 'yarn' - name: Install Rust stable uses: dtolnay/rust-toolchain@stable @@ -287,20 +285,13 @@ jobs: env: NODE_ENV: production VITE_BACKEND_URL: ${{ vars.VITE_BACKEND_URL }} - VITE_TELEGRAM_BOT_USERNAME: ${{ secrets.VITE_TELEGRAM_BOT_USERNAME }} - VITE_TELEGRAM_BOT_ID: ${{ secrets.VITE_TELEGRAM_BOT_ID }} - VITE_TELEGRAM_API_ID: ${{ secrets.VITE_TELEGRAM_API_ID }} - VITE_TELEGRAM_API_HASH: ${{ secrets.VITE_TELEGRAM_API_HASH }} VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }} - VITE_SKILLS_GITHUB_REPO: ${{ vars.VITE_SKILLS_GITHUB_REPO }} VITE_DEBUG: ${{ vars.VITE_DEBUG }} - name: Build, package and publish - uses: tauri-apps/tauri-action@v0 + uses: tauri-apps/tauri-action@v0.6.2 id: build-tauri env: - TELEGRAM_API_ID: ${{ secrets.VITE_TELEGRAM_API_ID }} - TELEGRAM_API_HASH: ${{ secrets.VITE_TELEGRAM_API_HASH }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} @@ -314,14 +305,14 @@ jobs: # macOS 10.15+ required for std::filesystem used by llama.cpp MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }} with: - args: "-c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}" + args: '-c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }} -- -- --bin OpenHuman' includeDebug: ${{ needs.get-version.outputs.should-publish == '' && inputs.forceRelease != 'true' }} includeRelease: ${{ needs.get-version.outputs.should-publish != '' || inputs.forceRelease == 'true' }} # TDLib dylibs are now bundled natively via build.rs + tauri.conf.json macOS.frameworks # No post-build scripts needed - Tauri bundler handles copying and signing releaseId: ${{ needs.create-release.outputs.releaseId }} - owner: alphahumanxyz - repo: alphahuman + owner: openhumanxyz + repo: openhuman - name: Get file info id: file-info diff --git a/.github/workflows/pr-protection.yml b/.github/workflows/pr-protection.yml deleted file mode 100644 index 177332694..000000000 --- a/.github/workflows/pr-protection.yml +++ /dev/null @@ -1,176 +0,0 @@ -name: PR Protection - Main Branch - -on: - pull_request: - types: [opened, synchronize, reopened] - -permissions: - pull-requests: write - contents: read - -jobs: - check-pr-protection: - runs-on: ubuntu-latest - - steps: - - name: Check PR target branch - id: check-target - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const pr = context.payload.pull_request; - const baseBranch = pr.base.ref; - const headBranch = pr.head.ref; - const prAuthor = pr.user.login; - const prTitle = pr.title; - const prBody = pr.body || ''; - - // Check if PR is targeting main - const isTargetingMain = baseBranch === 'main'; - - if (!isTargetingMain) { - console.log(`PR is targeting ${baseBranch}, not main. Skipping protection check.`); - core.setOutput('needs_check', 'false'); - return; - } - - console.log(`PR #${pr.number} is targeting ${baseBranch}`); - console.log(`PR author: ${prAuthor}`); - console.log(`PR title: ${prTitle}`); - console.log(`Head branch: ${headBranch}`); - - // Check if PR title follows conventional commit format - // Allowed prefixes: feat, fix, chore, refactor, docs, test, style, perf, revert - const conventionalCommitPattern = /^(feat|fix|chore|refactor|docs|test|style|perf|revert)(\(.+\))?: .+/; - const followsConventionalFormat = conventionalCommitPattern.test(prTitle); - - console.log(`Conventional commit format check: ${followsConventionalFormat ? 'PASSED' : 'FAILED'}`); - if (!followsConventionalFormat) { - console.log(`PR title must follow conventional commit format: : `); - console.log(`Allowed types: feat, fix, chore, refactor, docs, test, style, perf, revert`); - } - - // Check if this is the automated PR from create-develop-to-main-pr workflow - // The automated PR has these characteristics: - // 1. Created by github-actions[bot] - // 2. From develop branch to main - // 3. Title matches pattern: "chore: merge develop into main (vX.Y.Z)" - // 4. Body contains "This PR automatically merges changes from develop into main" - - // Validate PR title matches expected pattern: "chore: merge develop into main" followed by optional version - const expectedTitlePattern = /^chore: merge develop into main( \(v\d+\.\d+\.\d+\))?$/; - const titleMatches = expectedTitlePattern.test(prTitle); - - console.log(`Automated PR title validation: ${titleMatches ? 'PASSED' : 'FAILED'}`); - console.log(`Expected pattern: "chore: merge develop into main" or "chore: merge develop into main (vX.Y.Z)"`); - - const isAutomatedPR = - prAuthor === 'github-actions[bot]' && - headBranch === 'develop' && - titleMatches && - prBody.includes('This PR automatically merges changes from develop into main'); - - if (isAutomatedPR) { - console.log('This PR is from the automated workflow. Allowing it.'); - core.setOutput('needs_check', 'false'); - core.setOutput('is_allowed', 'true'); - } else { - console.log('This PR is NOT from the automated workflow.'); - - // Even if not automated, check if title follows conventional commit format - if (!followsConventionalFormat) { - console.log('PR title does not follow conventional commit format. Blocking it.'); - core.setOutput('needs_check', 'true'); - core.setOutput('is_allowed', 'false'); - core.setOutput('conventional_format_failed', 'true'); - } else { - console.log('PR title follows conventional commit format, but PR is not from automated workflow. Blocking it.'); - core.setOutput('needs_check', 'true'); - core.setOutput('is_allowed', 'false'); - core.setOutput('conventional_format_failed', 'false'); - } - } - - // Store the conventional format check result - core.setOutput('conventional_format', followsConventionalFormat ? 'true' : 'false'); - - - name: Block unauthorized PR to main - if: steps.check-target.outputs.needs_check == 'true' && steps.check-target.outputs.is_allowed == 'false' - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const pr = context.payload.pull_request; - const baseBranch = pr.base.ref; - const prAuthor = pr.user.login; - const prTitle = pr.title; - const headBranch = pr.head.ref; - const prBody = pr.body || ''; - - // Check which validation criteria failed - const conventionalCommitPattern = /^(feat|fix|chore|refactor|docs|test|style|perf|revert)(\(.+\))?: .+/; - const followsConventionalFormat = conventionalCommitPattern.test(prTitle); - - const checks = { - author: prAuthor === 'github-actions[bot]', - branch: headBranch === 'develop', - automatedTitle: /^chore: merge develop into main( \(v\d+\.\d+\.\d+\))?$/.test(prTitle), - body: prBody.includes('This PR automatically merges changes from develop into main'), - conventionalFormat: followsConventionalFormat - }; - - const failedChecks = Object.entries(checks) - .filter(([_, passed]) => !passed) - .map(([check]) => check); - - console.log('Validation checks:', JSON.stringify(checks, null, 2)); - console.log('Failed checks:', failedChecks.join(', ')); - - // Build detailed error message - let errorDetails = ''; - if (failedChecks.length > 0) { - errorDetails = `\n\n**Failed validation checks:**\n`; - if (!checks.author) errorDetails += `- ❌ Author must be \`github-actions[bot]\` (found: \`${prAuthor}\`)\n`; - if (!checks.branch) errorDetails += `- ❌ Head branch must be \`develop\` (found: \`${headBranch}\`)\n`; - if (!checks.automatedTitle) errorDetails += `- ❌ Title must match pattern: \`chore: merge develop into main\` or \`chore: merge develop into main (vX.Y.Z)\` (found: \`${prTitle}\`)\n`; - if (!checks.body) errorDetails += `- ❌ Body must contain: "This PR automatically merges changes from develop into main"\n`; - if (!checks.conventionalFormat) errorDetails += `- ❌ PR title must follow conventional commit format: \`: \`\n`; - if (!checks.conventionalFormat) errorDetails += ` Allowed types: \`feat\`, \`fix\`, \`chore\`, \`refactor\`, \`docs\`, \`test\`, \`style\`, \`perf\`, \`revert\`\n`; - if (!checks.conventionalFormat) errorDetails += ` Example: \`feat: add new authentication endpoint\`\n`; - } - - // Comment on the PR explaining why it was blocked - const codeBlock = '`'; - const commentBody = [ - '## PR Protection Rule Violation', - '', - `This PR targets the ${codeBlock}${baseBranch}${codeBlock} branch, which is protected.`, - '', - `**Only automated PRs from the ${codeBlock}create-develop-to-main-pr.yml${codeBlock} workflow are allowed to target ${codeBlock}${baseBranch}${codeBlock}.**${errorDetails}`, - '', - `**To merge changes into ${codeBlock}${baseBranch}${codeBlock}:**`, - `1. Create your PR targeting the ${codeBlock}develop${codeBlock} branch instead`, - `2. Once merged to ${codeBlock}develop${codeBlock}, the automated workflow will create a PR from ${codeBlock}develop${codeBlock} to ${codeBlock}${baseBranch}${codeBlock}`, - '', - `Please update this PR to target ${codeBlock}develop${codeBlock} instead, or close it and create a new PR targeting ${codeBlock}develop${codeBlock}.` - ].join('\n'); - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr.number, - body: commentBody - }); - - // Fail the workflow to block the PR - let failureMessage = `PR #${pr.number} cannot target ${baseBranch} branch. `; - - if (!checks.conventionalFormat) { - failureMessage += `PR title does not follow conventional commit format. `; - } - - failureMessage += `Failed checks: ${failedChecks.join(', ')}. `; - failureMessage += `Only automated PRs from create-develop-to-main-pr.yml workflow are allowed.`; - - core.setFailed(failureMessage); diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03f575628..2006bb98d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,6 +23,7 @@ jobs: prepare-release: name: Prepare release commit and tag runs-on: ubuntu-latest + environment: Production outputs: version: ${{ steps.bump.outputs.version }} tag: ${{ steps.bump.outputs.tag }} @@ -158,6 +159,7 @@ jobs: create-release: name: Create GitHub release runs-on: ubuntu-latest + environment: Production needs: prepare-release outputs: release_id: ${{ steps.create.outputs.release_id }} @@ -202,16 +204,24 @@ jobs: name: Build and upload artifacts needs: [prepare-release, create-release] runs-on: ${{ matrix.settings.platform }} + environment: Production strategy: fail-fast: false matrix: settings: - - platform: macos-latest - args: --target aarch64-apple-darwin - - platform: macos-latest - args: --target x86_64-apple-darwin + # macOS builds are disabled for now to ensure the flow works first + # - platform: macos-latest + # args: --target aarch64-apple-darwin + # target: aarch64-apple-darwin + # artifact_suffix: aarch64-apple-darwin + # - platform: macos-latest + # args: --target x86_64-apple-darwin + # target: x86_64-apple-darwin + # artifact_suffix: x86_64-apple-darwin - platform: ubuntu-22.04 - args: "" + args: '' + target: '' + artifact_suffix: ubuntu env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -245,9 +255,29 @@ jobs: sudo apt-get update sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf + # Skip first 7 lines of Cargo.lock (workspace package version bumps) so the key tracks dependency changes only + - name: Cargo.lock fingerprint (deps only) + id: cargo-lock-fingerprint + shell: bash + run: | + echo "hash=$(tail -n +8 src-tauri/Cargo.lock | openssl dgst -sha256 | awk '{print $2}')" >> "$GITHUB_OUTPUT" + + - name: Cache Cargo registry and git sources + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-registry-${{ steps.cargo-lock-fingerprint.outputs.hash }} + restore-keys: | + ${{ runner.os }}-cargo-registry- + - name: Install dependencies run: yarn install --frozen-lockfile + - name: Install skills dependencies + run: cd skills && yarn install --frozen-lockfile + - name: Build skills run: cd skills && yarn build @@ -257,7 +287,7 @@ jobs: env: BASE_URL: ${{ vars.BASE_URL }} UPDATER_PUBLIC_KEY: ${{ secrets.UPDATER_PUBLIC_KEY }} - WITH_UPDATER: "true" + WITH_UPDATER: 'true' with: script: | const workspacePath = process.env.GITHUB_WORKSPACE.replace(/\\/g, '/'); @@ -272,34 +302,127 @@ jobs: env: NODE_ENV: production VITE_BACKEND_URL: ${{ vars.VITE_BACKEND_URL }} - VITE_TELEGRAM_BOT_USERNAME: ${{ secrets.VITE_TELEGRAM_BOT_USERNAME }} - VITE_TELEGRAM_BOT_ID: ${{ secrets.VITE_TELEGRAM_BOT_ID }} - VITE_TELEGRAM_API_ID: ${{ secrets.VITE_TELEGRAM_API_ID }} - VITE_TELEGRAM_API_HASH: ${{ secrets.VITE_TELEGRAM_API_HASH }} - VITE_SENTRY_DSN: ${{ secrets.VITE_SENTRY_DSN }} - VITE_SKILLS_GITHUB_REPO: ${{ vars.VITE_SKILLS_GITHUB_REPO }} + VITE_SENTRY_DSN: ${{ vars.VITE_SENTRY_DSN }} VITE_DEBUG: ${{ vars.VITE_DEBUG }} - name: Build, package and upload to release - uses: tauri-apps/tauri-action@v0 + uses: tauri-apps/tauri-action@v0.6.2 + id: tauri-build env: - TELEGRAM_API_ID: ${{ secrets.VITE_TELEGRAM_API_ID }} - TELEGRAM_API_HASH: ${{ secrets.VITE_TELEGRAM_API_HASH }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} BASE_URL: ${{ vars.BASE_URL }} - TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.UPDATER_PRIVATE_KEY }} - TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.UPDATER_PRIVATE_KEY_PASSWORD }} - WITH_UPDATER: "true" + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY || secrets.UPDATER_PRIVATE_KEY }} + TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD || secrets.UPDATER_PRIVATE_KEY_PASSWORD }} + WITH_UPDATER: 'true' MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }} with: - args: -c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }} + # Tools discovery now uses a JS mock registry (no Rust discovery + # binary target), so there is no extra helper executable for Tauri + # to copy/sign inside release app bundles. + # Restrict Cargo bin selection for the Tauri bundle build so only + # the desktop UI app binary is packaged. + # Yarn v1 strips one "--" layer when invoking scripts, hence the + # double-separator when forwarding flags to Cargo. + args: -c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }} -- -- --bin OpenHuman includeDebug: false includeRelease: true releaseId: ${{ needs.create-release.outputs.release_id }} - owner: ${{ github.repository_owner }} - repo: ${{ github.event.repository.name }} + owner: tinyhumansai + repo: openhuman + + - name: Verify macOS app bundle excludes standalone core binary + if: matrix.settings.platform == 'macos-latest' + shell: bash + run: | + APP_PATH="src-tauri/target/${{ matrix.settings.target }}/release/bundle/macos/OpenHuman.app" + echo "Inspecting bundle at: $APP_PATH" + ls -la "$APP_PATH/Contents/MacOS" + if [ -f "$APP_PATH/Contents/MacOS/openhuman-core" ]; then + echo "Unexpected standalone binary found inside app bundle: openhuman-core" + exit 1 + fi + + - name: Build standalone CLI binaries + shell: bash + run: | + CARGO_TARGET="" + if [ -n "$MATRIX_TARGET" ]; then + CARGO_TARGET="--target $MATRIX_TARGET" + fi + cargo build --manifest-path src-tauri/Cargo.toml --release --features standalone-bins $CARGO_TARGET --bin openhuman-core --bin openhuman-cli + env: + MATRIX_TARGET: ${{ matrix.settings.target }} + + - name: Resolve standalone CLI artifact paths + id: cli-paths + shell: bash + run: | + if [ -n "$MATRIX_TARGET" ]; then + BASE_DIR="src-tauri/target/$MATRIX_TARGET/release" + else + BASE_DIR="src-tauri/target/release" + fi + echo "base_dir=$BASE_DIR" >> "$GITHUB_OUTPUT" + echo "core_path=$BASE_DIR/openhuman-core" >> "$GITHUB_OUTPUT" + echo "cli_path=$BASE_DIR/openhuman-cli" >> "$GITHUB_OUTPUT" + env: + MATRIX_TARGET: ${{ matrix.settings.target }} + + - name: Upload standalone CLI artifacts + uses: actions/upload-artifact@v4 + with: + name: standalone-bins-${{ matrix.settings.platform }}-${{ matrix.settings.artifact_suffix }} + path: | + ${{ steps.cli-paths.outputs.core_path }} + ${{ steps.cli-paths.outputs.cli_path }} + + cleanup-failed-release: + name: Remove release and tag if build failed + runs-on: ubuntu-latest + environment: Production + needs: [prepare-release, create-release, build-artifacts] + if: always() && needs.create-release.result == 'success' && (needs.build-artifacts.result == 'failure' || needs.build-artifacts.result == 'cancelled') + steps: + - name: Delete GitHub release + uses: actions/github-script@v7 + with: + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const releaseId = Number('${{ needs.create-release.outputs.release_id }}'); + + if (!Number.isFinite(releaseId) || releaseId <= 0) { + core.setFailed('Invalid or missing release_id; cannot delete release.'); + return; + } + + try { + await github.rest.repos.deleteRelease({ owner, repo, release_id: releaseId }); + core.info(`Deleted release ${releaseId}`); + } catch (e) { + core.warning(`deleteRelease failed: ${e.message}`); + } + + - name: Delete remote tag + uses: actions/github-script@v7 + with: + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const tag = '${{ needs.prepare-release.outputs.tag }}'; + + try { + await github.rest.git.deleteRef({ owner, repo, ref: `tags/${tag}` }); + core.info(`Deleted remote tag ${tag}`); + } catch (e) { + if (e.status === 404) { + core.info(`Tag ${tag} already absent on remote`); + } else { + throw e; + } + } diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2170cd0e2..83d910cc0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: 24.x - cache: "yarn" + cache: 'yarn' - name: Cache node modules id: yarn-cache diff --git a/.github/workflows/update-changelog.yml.disable b/.github/workflows/update-changelog.yml similarity index 99% rename from .github/workflows/update-changelog.yml.disable rename to .github/workflows/update-changelog.yml index 3f0df487a..5276cca39 100644 --- a/.github/workflows/update-changelog.yml.disable +++ b/.github/workflows/update-changelog.yml @@ -3,7 +3,7 @@ name: Update Changelog on: push: branches: - - develop + - main permissions: contents: write @@ -155,7 +155,7 @@ jobs: while i < len(lines): line = lines[i] output_lines.append(line) - + # Check if this is the [Unreleased] header line if line.strip() == "## [Unreleased]": # Find the end of the [Unreleased] section (next ## header or end of file) @@ -169,7 +169,7 @@ jobs: inserted = True # Continue with remaining lines continue - + i += 1 # If [Unreleased] not found, prepend diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml deleted file mode 100644 index 233f84c3e..000000000 --- a/.github/workflows/version-bump.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Version Bump (Legacy) - -on: - workflow_dispatch: - -permissions: - contents: write - -jobs: - version-bump: - runs-on: ubuntu-latest - environment: Production - # Skip if this is a version bump commit to avoid infinite loop - if: "!contains(github.event.head_commit.message, 'chore: bump version')" - - steps: - - name: Generate GitHub App token - id: app-token - uses: tibdex/github-app-token@v1 - with: - app_id: ${{ secrets.XGITHUB_APP_ID }} - private_key: ${{ secrets.XGITHUB_APP_PRIVATE_KEY }} - - - name: Checkout code - uses: actions/checkout@v4 - with: - # Use GitHub App token for checkout and push operations - # This token has bypass permissions if the GitHub App is configured with them - token: ${{ steps.app-token.outputs.token }} - fetch-depth: 1 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20.x - - - name: Configure Git - env: - GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - # Update remote URL to use GitHub App token for all git operations - git remote set-url origin https://${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git - - - name: Pull latest changes - run: | - # Ensure we're on main and pull latest changes to avoid push conflicts - git checkout main - git pull origin main --ff-only - - - name: Bump version - id: version - run: | - # Get current version - CURRENT_VERSION=$(node -p "require('./package.json').version") - echo "Current version: $CURRENT_VERSION" - - # Bump minor version (creates commit and tag) - # The commit message includes [skip ci] to prevent triggering this workflow again - NEW_VERSION=$(npm version minor -m "chore: bump version to %s" | sed 's/v//') - echo "New version: $NEW_VERSION" - echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT - - - name: Push changes - env: - GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - # Push to main and tags using GitHub App token (remote URL already configured) - git push origin main - git push origin --tags diff --git a/.gitignore b/.gitignore index e740f0efc..428fc2ab6 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,6 @@ e2e-results/ wdio-logs/ test-results/ coverage/ + +tauri.key +tauri.key.pub diff --git a/.husky/pre-push b/.husky/pre-push index 07fcbc99f..127b001d1 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,37 +1,37 @@ -# #!/usr/bin/env sh +#!/usr/bin/env sh -# # Run format check first (capture exit code without breaking script) -# set +e -# yarn format:check -# FORMAT_EXIT=$? -# set -e +# Run format check first (capture exit code without breaking script) +set +e +yarn format:check +FORMAT_EXIT=$? +set -e -# # If format check failed, run format to auto-fix -# if [ $FORMAT_EXIT -ne 0 ]; then -# echo "Formatting issues detected. Running format to auto-fix..." -# yarn format -# fi +# If format check failed, run format to auto-fix +if [ $FORMAT_EXIT -ne 0 ]; then + echo "Formatting issues detected. Running format to auto-fix..." + yarn format +fi -# # Run lint check (capture exit code without breaking script) -# set +e -# yarn lint -# LINT_EXIT=$? -# set -e +# Run lint check (capture exit code without breaking script) +set +e +yarn lint +LINT_EXIT=$? +set -e -# # If lint check failed, run lint:fix to auto-fix -# if [ $LINT_EXIT -ne 0 ]; then -# echo "Linting issues detected. Running lint:fix to auto-fix..." -# yarn lint:fix -# fi +# If lint check failed, run lint:fix to auto-fix +if [ $LINT_EXIT -ne 0 ]; then + echo "Linting issues detected. Running lint:fix to auto-fix..." + yarn lint:fix +fi -# # Run TypeScript compile check (capture exit code without breaking script) -# set +e -# yarn compile -# COMPILE_EXIT=$? -# set -e +# Run TypeScript compile check (capture exit code without breaking script) +set +e +yarn compile +COMPILE_EXIT=$? +set -e -# # Exit with error if any command still fails after fixes -# if [ $FORMAT_EXIT -ne 0 ] || [ $LINT_EXIT -ne 0 ] || [ $COMPILE_EXIT -ne 0 ]; then -# echo "Pre-push checks failed. Please fix format, lint, and/or TypeScript errors before pushing." -# exit 1 -# fi +# Exit with error if any command still fails after fixes +if [ $FORMAT_EXIT -ne 0 ] || [ $LINT_EXIT -ne 0 ] || [ $COMPILE_EXIT -ne 0 ]; then + echo "Pre-push checks failed. Please fix format, lint, and/or TypeScript errors before pushing." + exit 1 +fi diff --git a/CLAUDE.md b/CLAUDE.md index 4f3aa03b9..79de7a705 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,7 +51,7 @@ yarn dev:app yarn tauri build # Debug build with .app bundle (required for deep link testing on macOS) -# On macOS, alphahuman:// only works when running the .app, not `tauri dev` +# On macOS, openhuman:// only works when running the .app, not `tauri dev` yarn tauri build --debug --bundles app yarn macos:dev @@ -133,10 +133,10 @@ Model Context Protocol implementation for AI tool execution over Socket.io: ### Deep Link Auth Flow -Web-to-desktop handoff using `alphahuman://` URL scheme: +Web-to-desktop handoff using `openhuman://` URL scheme: 1. User authenticates in browser -2. Browser redirects to `alphahuman://auth?token=` +2. Browser redirects to `openhuman://auth?token=` 3. Tauri catches the deep link, Rust `exchange_token` command calls backend via `reqwest` (bypasses CORS) 4. Backend returns `sessionToken` + user object 5. App stores session in Redux, navigates to onboarding/home @@ -209,22 +209,18 @@ Advanced JavaScript execution engine for skills using V8 (via deno_core): Set in `.env` (Vite exposes `VITE_*` prefixed vars): -| Variable | Purpose | -| ---------------------------- | ------------------------------------------------------------------- | -| `VITE_BACKEND_URL` | Backend API URL (default: `http://localhost:5005`) | -| `VITE_TELEGRAM_API_ID` | Telegram MTProto API ID | -| `VITE_TELEGRAM_API_HASH` | Telegram MTProto API hash | -| `VITE_TELEGRAM_BOT_USERNAME` | Telegram bot username | -| `VITE_TELEGRAM_BOT_ID` | Telegram bot numeric ID | -| `VITE_SENTRY_DSN` | Sentry DSN for error reporting (optional) | -| `VITE_DEBUG` | Debug mode flag | -| `ALPHAHUMAN_DAEMON_INTERNAL` | Force internal daemon mode (default: false, uses external services) | +| Variable | Purpose | +| --------------------------- | ------------------------------------------------------------------- | +| `VITE_BACKEND_URL` | Backend API URL (default: `http://localhost:5005`) | +| `VITE_SENTRY_DSN` | Sentry DSN for error reporting (optional) | +| `VITE_DEBUG` | Debug mode flag | +| `OPENHUMAN_DAEMON_INTERNAL` | Force internal daemon mode (default: false, uses external services) | Production defaults are in `src/utils/config.ts`. ## AI Configuration System -AlphaHuman uses an OpenClaw-compliant AI configuration system that automatically injects persona and tool context into every user message for consistent AI behavior. +OpenHumanuses an OpenClaw-compliant AI configuration system that automatically injects persona and tool context into every user message for consistent AI behavior. ### Configuration Files @@ -283,7 +279,7 @@ const toolsMessage = await injectTools(userMessage); ``` [PERSONA_CONTEXT] -I am AlphaHuman: that incredibly smart, funny friend who loves helping people get stuff done +I am OpenHuman that incredibly smart, funny friend who loves helping people get stuff done Personality: Curious & Enthusiastic, Witty & Engaging, Empathetic Voice: Conversational, Use humor naturally but don't force it [/PERSONA_CONTEXT] @@ -410,9 +406,9 @@ Key updates from recent commits (cd9ebcd to current): - Session capture and transcript management - Memory chunking and context formatting - **Enhanced CI/CD Pipeline** (`b1d7bce`): Production-ready deployment - - XGH_TOKEN authentication for alphahumanxyz/alphahuman releases + - XGH_TOKEN authentication for openhumanxyz/openhuman releases - Python sidecar setup and caching for cross-platform builds - - Tauri configuration updates (com.alphahuman.app identifier) + - Tauri configuration updates (com.openhuman.app identifier) - GitHub Pages deployment with optimized workflows - Version tagging and environment variable management - **Device Detection & Download System** (`9d74721`, `b5bccd2`): Enhanced multi-architecture download support @@ -467,9 +463,11 @@ Key updates from recent commits (cd9ebcd to current): ## Git Workflow -- **Push target**: All pushes go to the **user's private repo** (your fork). Do not push directly to the org repository. -- **PR target**: All pull requests are opened **from your fork** against the **org's private repo**, targeting the **`develop`** branch (not `main`). -- **No direct pushes to org**: The org repo does not allow direct pushes. All changes reach the org repo via PRs from your fork. +- **Repository visibility**: The project is public. +- **Push target**: Pushes should go to your working branch in the public repository (or your fork if your access model requires it). +- **PR target**: Open pull requests against the public upstream repository, targeting the **`main`** branch. +- **PR template required**: Use `.github/pull_request_template.md` for all pull requests. +- **AI tooling rule**: Any AI-generated PR description must follow the template sections in order and keep all checklist items. ## Key Patterns @@ -500,7 +498,7 @@ Key updates from recent commits (cd9ebcd to current): ## Platform Gotchas -- **macOS deep links**: Require `.app` bundle (not `tauri dev`). Clear WebKit caches when debugging stale content: `rm -rf ~/Library/WebKit/com.alphahuman.app ~/Library/Caches/com.alphahuman.app` +- **macOS deep links**: Require `.app` bundle (not `tauri dev`). Clear WebKit caches when debugging stale content: `rm -rf ~/Library/WebKit/com.openhuman.app ~/Library/Caches/com.openhuman.app` - **Cargo caching**: May serve stale frontend assets on incremental builds. Run `cargo clean --manifest-path src-tauri/Cargo.toml` if the app shows outdated UI. - **`window.__TAURI__`**: Not available at module load time. Use static imports and try/catch around Tauri API calls (not around imports). - **Android background services**: RuntimeService requires notification permissions (API 33+) and foreground service type specification (API 34+). Use Android logging (`android_logger`) for debug output in logcat. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b496f937f..41ee18db2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to AlphaHuman +# Contributing to OpenHuman Thank you for your interest in contributing. This document explains how to get set up, follow our workflow, and submit changes. @@ -19,7 +19,7 @@ This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDU ## Getting Started - Read the [README](README.md) and [ARCHITECTURE](ARCHITECTURE.md) for context. -- Check [open issues](https://github.com/alphahumanxyz/alphahuman/issues) and discussions for ideas and to avoid duplicate work. +- Check [open issues](https://github.com/tinyhumansai/openhuman/issues) and discussions for ideas and to avoid duplicate work. - For security issues, see [SECURITY.md](SECURITY.md) — do not report vulnerabilities in public issues. ## Development Setup @@ -33,8 +33,8 @@ This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDU ### Clone and Install ```bash -git clone https://github.com/YOUR_USERNAME/alphahuman.git -cd alphahuman +git clone https://github.com/YOUR_USERNAME/openhuman.git +cd openhuman yarn install ``` @@ -55,7 +55,7 @@ Copy or create a `.env` from the documented template and set `VITE_BACKEND_URL`, ## Git Workflow -- **Fork** the [alphahuman](https://github.com/alphahumanxyz/alphahuman) repository and work in your fork. +- **Fork** the [openhuman](https://github.com/tinyhumansai/openhuman) repository and work in your fork. - **Base branch**: All pull requests must target the **`develop`** branch (not `main`). - **No direct pushes** to the organization repo; all changes come in via pull requests from forks. @@ -69,7 +69,7 @@ Use short, descriptive branches, e.g.: ## Making Changes -1. Create a branch from `develop`: +1. Create a branch from `develop`: `git checkout develop && git pull origin develop && git checkout -b fix/your-change` 2. Make your changes. Keep commits focused and messages clear (e.g., “Fix socket reconnect on network drop”). 3. Follow our [project conventions](#project-conventions) and run checks before pushing. @@ -85,9 +85,9 @@ Pre-commit/pre-push hooks (Husky) run formatting and linting; fix any failures b ## Submitting Changes -1. Push your branch to your fork: +1. Push your branch to your fork: `git push origin fix/your-change` -2. Open a **pull request** against **`develop`** in the [alphahuman](https://github.com/alphahumanxyz/alphahuman) repository. +2. Open a **pull request** against **`develop`** in the [openhuman](https://github.com/tinyhumansai/openhuman) repository. 3. Fill in the PR template (if present): describe what changed, why, and how to test. 4. Link any related issues (e.g., “Fixes #123”). 5. Address review feedback and keep the PR up to date with `develop` (rebase or merge as the project prefers). @@ -108,4 +108,4 @@ For more detail on architecture, patterns, and platform notes, see the project --- -Thank you for contributing to AlphaHuman. +Thank you for contributing to OpenHuman. diff --git a/README.md b/README.md index 6b3075480..9e8f291fa 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,28 @@ -

AlphaHuman

+

OpenHuman

- Your most productive co-worker
- A user-friendly (GUI-first) AI agent. AlphaHuman uses the - Neocortex Mk1 model to understand memories & - realtime context at incredibly low costs. + The age of super intelligence is here. OpenHuman is your artificially conscious human. +

+ +

+ Discord • + Reddit • + X/Twitter • + Docs

Early Beta - Platforms - Latest Release + Platforms: desktop only + Latest Release

- Discord - Reddit - Twitter/X + The Tet

-![The Tet](./docs/the-tet.png) -

- "No Soul. No Humanity. The Tet. What a brilliant machine" — Morgan Freeman on alien superintelligence in Oblivion + "The Tet. What a brilliant machine" — Morgan Freeman as he recalls about alien superintelligence in the movie Oblivion

**Agentic system are everywhere.** Models wired into a script that call APIs, search, and file tools until the task looks done. That pattern is powerful for _tasks_, but it is not a self. It has no lasting inner model of _you_, no stable values across sessions, and no architecture for continuity at the scale of a life. diff --git a/SECURITY.md b/SECURITY.md index 81195e3c1..7fd4482a5 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Supported Versions -We provide security updates for the following versions of AlphaHuman: +We provide security updates for the following versions of OpenHuman: | Version | Supported | | -------------- | ------------------ | @@ -10,7 +10,7 @@ We provide security updates for the following versions of AlphaHuman: | Previous minor | :white_check_mark: | | Older | :x: | -We recommend always running the [latest release](https://github.com/alphahumanxyz/alphahuman/releases/latest). AlphaHuman is in early beta; older versions may not receive patches. +We recommend always running the [latest release](https://github.com/tinyhumansai/openhuman/releases/latest). OpenHuman is in early beta; older versions may not receive patches. ## Reporting a Vulnerability @@ -19,7 +19,7 @@ We take security seriously. If you believe you have found a security vulnerabili ### How to Report 1. **Do not** open a public GitHub issue for security vulnerabilities. -2. Email the maintainers with a clear description of the issue, steps to reproduce, and impact. You can reach us via the contact details listed in the [AlphaHuman organization](https://github.com/alphahumanxyz) or repository. +2. Email the maintainers with a clear description of the issue, steps to reproduce, and impact. You can reach us via the contact details listed in the [OpenHuman organization](https://github.com/openhumanxyz) or repository. 3. Include as much detail as possible (platform, version, configuration) so we can reproduce and triage quickly. ### What to Expect @@ -38,7 +38,7 @@ We are especially interested in: - Issues in dependency chain (npm, Cargo) that affect our build or runtime - Platform-specific issues (macOS, Windows, Linux, Android, iOS) that compromise user data or device security -Out-of-scope for this process: general bugs, feature requests, and issues in third-party services we integrate with (e.g., Telegram, Notion) unless they are specific to how AlphaHuman uses them. +Out-of-scope for this process: general bugs, feature requests, and issues in third-party services we integrate with (e.g., Telegram, Notion) unless they are specific to how OpenHuman uses them. ### Safe Harbor @@ -50,4 +50,4 @@ We support safe harbor for security researchers who report in good faith. We wil - **Data**: Message content is processed on request and not retained for training or long-term storage. - **Skills**: Skills run in a sandboxed environment with defined boundaries; we review skill behavior and dependencies where possible. -Thank you for helping keep AlphaHuman and its users safe. +Thank you for helping keep OpenHuman and its users safe. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index f8436330f..44725b760 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,8 +1,8 @@ -# AlphaHuman Architecture +# OpenHuman Architecture **AI-powered super assistant for crypto communities, built on Rust.** -AlphaHuman is a cross-platform communication and automation platform purpose-built for the cryptocurrency ecosystem. A single React + Rust (Tauri) codebase can target multiple platforms; **what we document and ship for users today is desktop only** — **Windows, macOS, and Linux**. Android, iOS, and web are **not** supported in current docs or releases. The stack includes a sandboxed JavaScript skills engine, persistent Rust-native WebSocket infrastructure, and an AI tool protocol that lets language models invoke any connected service in real time. +OpenHuman is a cross-platform communication and automation platform purpose-built for the cryptocurrency ecosystem. A single React + Rust (Tauri) codebase can target multiple platforms; **what we document and ship for users today is desktop only** — **Windows, macOS, and Linux**. Android, iOS, and web are **not** supported in current docs or releases. The stack includes a sandboxed JavaScript skills engine, persistent Rust-native WebSocket infrastructure, and an AI tool protocol that lets language models invoke any connected service in real time. --- @@ -13,7 +13,7 @@ AlphaHuman is a cross-platform communication and automation platform purpose-bui **Not supported yet:** Android, iOS, standalone web client (may exist as experimental targets in the repo; do not treat as product-ready). ``` - AlphaHuman (shipping) + OpenHuman (shipping) | Desktop / | \ @@ -65,9 +65,9 @@ The frontend communicates with the Rust core through Tauri's IPC bridge — 47+ ## Rust-Powered Performance -AlphaHuman chose Tauri + Rust over Electron for fundamental performance and security reasons: +OpenHuman chose Tauri + Rust over Electron for fundamental performance and security reasons: -| Metric | AlphaHuman (Tauri + Rust) | Typical Electron App | +| Metric | OpenHuman (Tauri + Rust) | Typical Electron App | | ------------------------- | ------------------------------ | ---------------------------- | | Binary size | ~30 MB | ~150 MB+ | | Memory per skill context | ~1-2 MB (QuickJS) | ~150 MB+ (Chromium renderer) | @@ -76,7 +76,7 @@ AlphaHuman chose Tauri + Rust over Electron for fundamental performance and secu | Memory safety | Compile-time guaranteed | Runtime exceptions | | TLS implementation | rustls (no OpenSSL dependency) | Chromium's BoringSSL | -**Why this matters for a crypto platform**: Traders and analysts run AlphaHuman alongside resource-intensive tools — charting software, multiple browser tabs, trading terminals. A 30 MB footprint with sub-500ms startup means the app feels native and stays out of the way. Zero GC pauses means real-time price feeds and alerts are never delayed by memory management. +**Why this matters for a crypto platform**: Traders and analysts run OpenHuman alongside resource-intensive tools — charting software, multiple browser tabs, trading terminals. A 30 MB footprint with sub-500ms startup means the app feels native and stays out of the way. Zero GC pauses means real-time price feeds and alerts are never delayed by memory management. The **Tokio async runtime** drives all I/O — WebSocket connections, HTTP requests, file operations, and inter-skill communication — as non-blocking tasks on a thread pool. Thousands of concurrent operations (skill executions, cron jobs, socket events) share a small fixed set of OS threads. @@ -84,7 +84,7 @@ The **Tokio async runtime** drives all I/O — WebSocket connections, HTTP reque ## Real-Time Socket Infrastructure -AlphaHuman implements a **dual-socket architecture**: a Rust-native WebSocket client on desktop and a JavaScript Socket.io client on web. The Rust implementation survives app backgrounding, operates independently of the WebView, and handles TLS via rustls. +OpenHuman implements a **dual-socket architecture**: a Rust-native WebSocket client on desktop and a JavaScript Socket.io client on web. The Rust implementation survives app backgrounding, operates independently of the WebView, and handles TLS via rustls. ``` Desktop Mode: Web Mode: @@ -119,7 +119,7 @@ The socket connection is **shared across all skills**. When events arrive, the s ## Skills Runtime Engine -AlphaHuman's defining capability is its **sandboxed JavaScript execution engine** running inside the Rust process. Skills are lightweight automation scripts that extend the platform with custom tools, integrations, and scheduled tasks. +OpenHuman's defining capability is its **sandboxed JavaScript execution engine** running inside the Rust process. Skills are lightweight automation scripts that extend the platform with custom tools, integrations, and scheduled tasks. ``` +---------------------------------------------------------------+ @@ -188,7 +188,7 @@ Skills are synced from a GitHub repository and discovered at runtime. Platform f ## AI & Tool Protocol (MCP) -AlphaHuman implements the **Model Context Protocol** — a JSON-RPC 2.0 layer over Socket.io that lets AI models discover and invoke tools exposed by skills. +OpenHuman implements the **Model Context Protocol** — a JSON-RPC 2.0 layer over Socket.io that lets AI models discover and invoke tools exposed by skills. ``` User Prompt diff --git a/docs/TODO.md b/docs/TODO.md index da2809322..56c5150f7 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -15,3 +15,6 @@ todo [] - allow bundling of unverified skills [] - allow for new skills to be coded on their own [] - allow for multiple instances of a skill to be loaded +[] - add a local model that can read through the screen and also go through voice using an API like whisper +[] - add a screener recorder that goes through the intefaces in the screen and locally summarizes what is happening and brings more assitance to the user +[] clean up the core so that we can run it as a binary on a server or as docker diff --git a/docs/sdk-rust-e2e-test-run.md b/docs/sdk-rust-e2e-test-run.md new file mode 100644 index 000000000..da23816b1 --- /dev/null +++ b/docs/sdk-rust-e2e-test-run.md @@ -0,0 +1,266 @@ +# Rust SDK E2E Test Run — `example_e2e.rs` + +**Run date:** 2026-03-27 +**Source:** `neocortex/packages/sdk-rust/tests/example_e2e.rs` +**API base URL:** `https://staging-api.alphahuman.xyz` +**Namespace:** `sdk-rust-e2e` +**Document ID:** `sdk-rust-e2e-doc-single-1774605977640` + +--- + +## What the test does + +The file is a standalone end-to-end integration program (not a `#[test]`-annotated unit test). It exercises the `tinyhumansai` Rust SDK against the staging API in six sequential steps: + +| Step | Operation | SDK method | +| ---- | ------------------------------------ | ---------------------------------------------- | +| 1 | Insert a memory document | `insert_memory` | +| 2 | Poll ingestion job until complete | `get_ingestion_job` + `wait_for_ingestion_job` | +| 3 | List documents filtered by namespace | `list_documents` | +| 4 | Fetch the specific document | `get_document` | +| 5 | Semantic query over the namespace | `query_memory` | +| 6 | Recall all memory context | `recall_memory` | + +The document inserted contains sprint velocity data for four teams (Atlas, Beacon, Comet, Delta). + +--- + +## How to run + +The file has its own `async fn main()` (annotated with `#[tokio::main]`), so Cargo's default test harness intercepts it and reports 0 tests. To run it as intended, add `harness = false` to `Cargo.toml` temporarily: + +```toml +[[test]] +name = "example_e2e" +harness = false +``` + +Then: + +```bash +cd neocortex/packages/sdk-rust +cargo test --test example_e2e +``` + +> **Note:** `TINYHUMANS_TOKEN` in the file is intentionally left blank. Populate it with a valid API token before running. + +--- + +## Step-by-step output + +### Step 1 — `insertMemory` + +**Endpoint:** `POST /memory/insert` + +**Request body** (serialized from `InsertMemoryBody`; `priority`, `createdAt`, `updatedAt` omitted because they are `None` and marked `skip_serializing_if`): + +```json +{ + "title": "Sprint Dataset - Team Velocity", + "content": "Sprint snapshot: Team Atlas completed 42 story points with 3 blockers, Team Beacon completed 35 story points with 1 blocker, Team Comet completed 48 story points with 5 blockers, and Team Delta completed 39 story points with 2 blockers. The highest velocity team is Team Comet and the fewest blockers team is Team Beacon.", + "namespace": "sdk-rust-e2e", + "sourceType": "doc", + "metadata": { "source": "example_e2e.rs" }, + "documentId": "sdk-rust-e2e-doc-single-1774605977640" +} +``` + +**Result:** success +**Job ID:** `a2a1396c-bcf5-4552-afc0-6c822bafd7c6` +**Initial job state:** `pending` + +``` +InsertMemoryResponse { + success: true, + data: InsertMemoryData { + job_id: Some("a2a1396c-bcf5-4552-afc0-6c822bafd7c6"), + state: Some("pending"), + ... + }, +} +``` + +--- + +### Step 2 — `getIngestionJob` + `waitForIngestionJob` + +**Endpoint:** `GET /memory/ingestion/jobs/{jobId}` (no request body) + +**URL:** `GET /memory/ingestion/jobs/a2a1396c-bcf5-4552-afc0-6c822bafd7c6` + +`wait_for_ingestion_job` then polls the same endpoint repeatedly (every 1 s, up to 30 s) until the state is not in `{pending, queued, processing, in_progress, started}`. + +Initial poll returned state `processing`, so the SDK waited. Job completed successfully. + +**Final state:** `completed` +**Completed at:** `2026-03-27T10:06:24.974Z` +**Ingestion latency:** `2.6173 s` + +Key stats from the completed job response: + +| Metric | Value | +| --------------------- | ----------- | +| Chunks new | 1 | +| Chunks total | 1 | +| Chunks deduplicated | 0 | +| Entities extracted | 15 | +| Relations extracted | 25 | +| Sections | 1 | +| Source type | `doc` | +| Embedding tokens used | 244 | +| Cost (USD) | $0.00000488 | + +Timing breakdown (selected): + +| Stage | Seconds | +| -------------------- | -------- | +| Chunking | 0.000826 | +| Chunk embedding | 0.2688 | +| Chunk storage | 0.2049 | +| Entity extraction | 0.8131 | +| Entity embedding | 0.0476 | +| Graph structure | 0.2427 | +| Relationship storage | 0.3800 | +| Storage total | 1.2504 | + +--- + +### Step 3 — `listDocuments` + +**Endpoint:** `GET /memory/documents?namespace=sdk-rust-e2e&limit=10&offset=0` (no request body) + +This run uses the updated `list_documents(ListDocumentsParams { namespace, limit, offset })` signature (new in the local SDK). Passing `namespace` now filters results correctly — previous runs returned an empty array because no namespace filter was applied. + +**4 documents returned** (all previous E2E runs in this namespace): + +| Document ID | Created at | +| --------------------------------------- | ------------------------------ | +| `sdk-rust-e2e-doc-single-1774598994566` | 2026-03-27T08:09:56 | +| `sdk-rust-e2e-doc-single-1774600415507` | 2026-03-27T08:33:37 | +| `sdk-rust-e2e-doc-single-1774604625874` | 2026-03-27T09:43:47 | +| `sdk-rust-e2e-doc-single-1774605977640` | 2026-03-27T10:06:20 ← this run | + +All share `namespace: "sdk-rust-e2e"`, `title: "Sprint Dataset - Team Velocity"`, `chunk_count: 1`. + +--- + +### Step 4 — `getDocument` + +**Endpoint:** `GET /memory/documents/{documentId}?namespace={namespace}` (no request body) + +**URL:** `GET /memory/documents/sdk-rust-e2e-doc-single-1774605977640?namespace=sdk-rust-e2e` + +```json +{ + "success": true, + "data": { + "document_id": "sdk-rust-e2e-doc-single-1774605977640", + "namespace": "sdk-rust-e2e", + "title": "Sprint Dataset - Team Velocity", + "chunk_count": 1, + "chunk_ids": [-1427053832764092200], + "created_at": "2026-03-27T10:06:20.655791+00:00", + "updated_at": "2026-03-27T10:06:21.964953+00:00", + "user_id": "69b12a6fd11460481185a040" + } +} +``` + +--- + +### Step 5 — `queryMemory` + +**Endpoint:** `POST /memory/query` + +**Request body** (serialized from `QueryMemoryParams` with `#[serde(rename_all = "camelCase")]`; `documentIds` and `llmQuery` omitted because they are `None`): + +```json +{ + "query": "Which team has the highest velocity and which team has the fewest blockers?", + "includeReferences": true, + "namespace": "sdk-rust-e2e", + "maxChunks": 5.0 +} +``` + +**Result:** 1 chunk returned with score `19.117` + +The relevant chunk was retrieved correctly. The LLM context message assembled by the API: + +``` +## Sources + +[1] Section: Sprint Dataset - Team Velocity +[1] Sprint snapshot: Team Atlas completed 42 story points with 3 blockers, + Team Beacon completed 35 story points with 1 blocker, Team Comet + completed 48 story points with 5 blockers, and Team Delta completed 39 + story points with 2 blockers. The highest velocity team is Team Comet + and the fewest blockers team is Team Beacon. +``` + +Top entity mentions extracted from the chunk (by normalized importance): + +| Entity | Normalized importance | Count | +| ------------------------- | --------------------- | ----- | +| THE FEWEST BLOCKERS TEAM | 1.000 | 6 | +| 42 STORY POINTS | 0.842 | 14 | +| TEAM BEACON | 0.486 | 2 | +| TEAM COMET | 0.476 | 2 | +| THE HIGHEST VELOCITY TEAM | 0.440 | 4 | + +**Usage:** + +- Embedding tokens: 20 +- Cost: $0.0000004 +- Cached: false + +--- + +### Step 6 — `recallMemoryContext` + +**Endpoint:** `POST /memory/recall` + +**Request body** (serialized from `RecallMemoryParams` with `#[serde(rename_all = "camelCase")]`): + +```json +{ "namespace": "sdk-rust-e2e", "maxChunks": 5.0 } +``` + +Recall (no query — returns all recent/relevant context) returned the same chunk with a higher score of `31.357` (recall scoring differs from query scoring). + +**Counts:** 1 chunk, 0 entities, 0 relations +**Latency:** 2.8183 s +**Usage:** 0 tokens, $0 cost (recall is embedding-free) +**Cached:** false + +The LLM context message was identical to step 5. + +--- + +## Changes since previous run + +| Area | Previous run | This run | +| -------------------------------- | --------------------------------------- | ------------------------------------------------------------------ | +| `step3_list_documents` signature | `list_documents()` — no args | `list_documents(ListDocumentsParams { namespace, limit, offset })` | +| Step 3 result | Empty `documents: []` (no filter) | 4 documents returned (namespace filter working) | +| Job ID | `4b3cc8e2-...` | `a2a1396c-...` | +| Document ID | `sdk-rust-e2e-doc-single-1774600415507` | `sdk-rust-e2e-doc-single-1774605977640` | +| Ingestion latency | 1.7791 s | 2.6173 s | +| Entity extraction time | 0.0117 s | 0.8131 s | + +--- + +## Overall result + +``` +E2E Rust SDK example completed. +``` + +All 6 steps passed. The SDK correctly: + +- Inserted a document and received a job ID +- Polled and waited for the ingestion job to reach `completed` +- Listed documents filtered by namespace (returning all 4 prior E2E inserts) +- Retrieved the document metadata by ID +- Performed a semantic query and received the correct chunk with entity importance scores +- Recalled memory context with latency and count metadata diff --git a/docs/src-tauri/01-architecture.md b/docs/src-tauri/01-architecture.md index fb8c41e59..e419412e4 100644 --- a/docs/src-tauri/01-architecture.md +++ b/docs/src-tauri/01-architecture.md @@ -2,7 +2,7 @@ ## Overview -The Tauri Rust backend provides native functionality for the AlphaHuman desktop application: +The Tauri Rust backend provides native functionality for the OpenHuman desktop application: - System tray with background execution - Deep link authentication @@ -113,7 +113,7 @@ listen("socket:should_connect", (event) => { | Plugin | Version | Purpose | | --------------------------- | ------- | --------------------------- | | `tauri-plugin-opener` | 2 | Open URLs in browser | -| `tauri-plugin-deep-link` | 2.0.0 | Handle `alphahuman://` URLs | +| `tauri-plugin-deep-link` | 2.0.0 | Handle `openhuman://` URLs | | `tauri-plugin-autostart` | 2 | Launch at login | | `tauri-plugin-notification` | 2 | Native notifications | diff --git a/docs/src-tauri/02-commands.md b/docs/src-tauri/02-commands.md index e15268d19..b9aceee44 100644 --- a/docs/src-tauri/02-commands.md +++ b/docs/src-tauri/02-commands.md @@ -151,7 +151,7 @@ Open Telegram login widget in browser. ```typescript await invoke("start_telegram_login"); -// Opens ${DEFAULT_BACKEND_URL}/auth/telegram-widget?redirect=alphahuman://auth +// Opens ${DEFAULT_BACKEND_URL}/auth/telegram-widget?redirect=openhuman://auth ``` ### `start_telegram_login_with_url` diff --git a/docs/src-tauri/README.md b/docs/src-tauri/README.md index ab036f21c..154fdc2af 100644 --- a/docs/src-tauri/README.md +++ b/docs/src-tauri/README.md @@ -2,7 +2,7 @@ ## Overview -This documentation covers the Tauri Rust backend for the AlphaHuman desktop application. +This documentation covers the Tauri Rust backend for the OpenHuman desktop application. ## Quick Reference @@ -26,7 +26,7 @@ This documentation covers the Tauri Rust backend for the AlphaHuman desktop appl ### Existing Implementation (`lib.rs`) - ✅ System tray with show/hide/quit -- ✅ Deep link handling (`alphahuman://` scheme) +- ✅ Deep link handling (`openhuman://` scheme) - ✅ Token exchange command (CORS bypass) - ✅ Autostart plugin (macOS LaunchAgent) - ✅ Window minimize-to-tray on close (macOS) @@ -120,7 +120,7 @@ impl SocketService { 1. User clicks "Login with Telegram" in desktop app ↓ 2. App opens system browser to: - ${BACKEND_URL}/auth/telegram-widget?redirect=alphahuman://auth + ${BACKEND_URL}/auth/telegram-widget?redirect=openhuman://auth ↓ 3. Backend serves Telegram Login Widget HTML page ↓ @@ -128,7 +128,7 @@ impl SocketService { ↓ 5. Telegram callback → Backend validates → Creates loginToken ↓ -6. Backend redirects to: alphahuman://auth?token={loginToken} +6. Backend redirects to: openhuman://auth?token={loginToken} ↓ 7. Desktop app catches deep link ↓ @@ -153,7 +153,7 @@ Returns HTML page with Telegram Login Widget that redirects to the specified sch #[tauri::command] async fn start_telegram_login(app: AppHandle) -> Result<(), String> { // Open browser to Telegram widget page - let url = format!("{}/auth/telegram-widget?redirect=alphahuman://auth", BACKEND_URL); + let url = format!("{}/auth/telegram-widget?redirect=openhuman://auth", BACKEND_URL); opener::open(&url)?; Ok(()) } @@ -189,7 +189,7 @@ pub struct SessionService { } impl SessionService { - const SERVICE: &'static str = "com.alphahuman.app"; + const SERVICE: &'static str = "com.openhuman.app"; pub fn store_token(&self, token: &str) -> Result<(), Error>; pub fn get_token(&self) -> Result, Error>; diff --git a/docs/src/01-architecture.md b/docs/src/01-architecture.md index 558de59fd..aa6b43147 100644 --- a/docs/src/01-architecture.md +++ b/docs/src/01-architecture.md @@ -105,7 +105,7 @@ MCP System: ### Authentication Flow (Deep Link) 1. User authenticates in browser → receives `loginToken` -2. Browser redirects to `alphahuman://auth?token=` +2. Browser redirects to `openhuman://auth?token=` 3. Desktop app catches deep link via Tauri plugin 4. `desktopDeepLinkListener` invokes Rust `exchange_token` command 5. Rust calls backend `POST /auth/desktop-exchange` (CORS-free) diff --git a/docs/src/05-pages-routing.md b/docs/src/05-pages-routing.md index b15f51c22..5616add56 100644 --- a/docs/src/05-pages-routing.md +++ b/docs/src/05-pages-routing.md @@ -366,7 +366,7 @@ import('./utils/desktopDeepLinkListener').then(m => { }); ``` -The listener intercepts `alphahuman://auth?token=...` and: +The listener intercepts `openhuman://auth?token=...` and: 1. Exchanges token via Rust command 2. Stores session in Redux diff --git a/docs/src/08-hooks-utils.md b/docs/src/08-hooks-utils.md index f88d24a05..4218447b1 100644 --- a/docs/src/08-hooks-utils.md +++ b/docs/src/08-hooks-utils.md @@ -173,12 +173,6 @@ Environment variable access with defaults. // Backend URL export const BACKEND_URL = import.meta.env.VITE_BACKEND_URL || 'https://api.example.com'; -// Telegram configuration -export const TELEGRAM_API_ID = import.meta.env.VITE_TELEGRAM_API_ID; -export const TELEGRAM_API_HASH = import.meta.env.VITE_TELEGRAM_API_HASH; -export const TELEGRAM_BOT_USERNAME = import.meta.env.VITE_TELEGRAM_BOT_USERNAME; -export const TELEGRAM_BOT_ID = import.meta.env.VITE_TELEGRAM_BOT_ID; - // Debug mode export const DEBUG = import.meta.env.VITE_DEBUG === 'true'; ``` @@ -214,7 +208,7 @@ import { buildAuthDeepLink } from '../utils/deeplink'; // Build URL for browser redirect const deepLink = buildAuthDeepLink(loginToken); -// → "alphahuman://auth?token=abc123" +// → "openhuman://auth?token=abc123" // In web frontend after auth: window.location.href = deepLink; @@ -241,7 +235,7 @@ import('./utils/desktopDeepLinkListener').then(m => { **What it does:** 1. Listens for `onOpenUrl` events from Tauri deep-link plugin -2. Parses `alphahuman://auth?token=...` URLs +2. Parses `openhuman://auth?token=...` URLs 3. Calls Rust `exchange_token` command (bypasses CORS) 4. Stores session in Redux 5. Navigates to `/onboarding` or `/home` diff --git a/docs/telegram-login-desktop.md b/docs/telegram-login-desktop.md index 35a828fb4..1109f25e1 100644 --- a/docs/telegram-login-desktop.md +++ b/docs/telegram-login-desktop.md @@ -1,6 +1,6 @@ # Telegram Login (Web → Desktop Handoff) -This app implements **Telegram login for the desktop (Tauri) client** using a **system-browser auth flow** plus a **custom URL scheme deep link** (`alphahuman://`) to return control back to the desktop app. +This app implements **Telegram login for the desktop (Tauri) client** using a **system-browser auth flow** plus a **custom URL scheme deep link** (`openhuman://`) to return control back to the desktop app. --- @@ -8,10 +8,10 @@ This app implements **Telegram login for the desktop (Tauri) client** using a ** 1. **User clicks “Continue with Telegram”** inside the desktop app. 2. The app opens the system browser to the backend: - - `GET ${BACKEND_URL}/auth/telegram-widget?redirect=alphahuman://auth` + - `GET ${BACKEND_URL}/auth/telegram-widget?redirect=openhuman://auth` 3. The backend performs Telegram authentication (bot-based login / OAuth-like flow). 4. On success, the backend generates a **short-lived single-use `loginToken`** and redirects the browser to: - - `alphahuman://auth?token=` + - `openhuman://auth?token=` 5. The OS routes that deep link to the installed desktop app. 6. The desktop app extracts the `token` from the deep link and exchanges it for a **long-lived `sessionToken`** by calling a Rust Tauri command (bypassing CORS): - `POST ${BACKEND_URL}/auth/desktop-exchange` with `{ token }` @@ -41,7 +41,7 @@ export const BACKEND_URL = The URL scheme is declared in `src-tauri/tauri.conf.json`: ```json -{ "plugins": { "deep-link": { "desktop": { "schemes": ["alphahuman"] } } } } +{ "plugins": { "deep-link": { "desktop": { "schemes": ["openhuman"] } } } } ``` The deep-link plugin is initialized in `src-tauri/src/lib.rs`: @@ -78,8 +78,8 @@ import('./utils/desktopDeepLinkListener').then(m => { The deep link handler: -- Accepts only the `alphahuman:` scheme -- Requires `alphahuman://auth?token=...` +- Accepts only the `openhuman:` scheme +- Requires `openhuman://auth?token=...` - Calls the Rust command `exchange_token` - Stores `sessionToken` in Redux auth state - Redirects to `#/onboarding` (HashRouter) @@ -92,7 +92,7 @@ const handleDeepLinkUrls = async (urls: string[] | null | undefined) => { try { const parsed = new URL(url); <<<<<<< HEAD - if (parsed.protocol !== 'alphahuman:') return; + if (parsed.protocol !== 'openhuman:') return; if (parsed.hostname !== 'auth') return; ======= if (parsed.protocol !== "outsourced:") return; @@ -141,13 +141,13 @@ async fn exchange_token(backend_url: String, token: String) -> Result` + - redirect to: `openhuman://auth?token=` ### B) `POST /auth/desktop-exchange` @@ -180,7 +180,7 @@ Your backend must implement **both**: ### Backend (required) -- **Implement `GET /auth/telegram?platform=desktop`** and ensure it redirects to `alphahuman://auth?token=...` on success. +- **Implement `GET /auth/telegram?platform=desktop`** and ensure it redirects to `openhuman://auth?token=...` on success. - **Implement `POST /auth/desktop-exchange`** to exchange the login token for a session token. - **Enforce security**: - `loginToken` is **single-use** @@ -190,7 +190,7 @@ Your backend must implement **both**: ### Desktop app (required for reliable behavior) - **Ensure the deep-link plugin is configured and permitted**: - - `src-tauri/tauri.conf.json` includes `"schemes": ["alphahuman"]` + - `src-tauri/tauri.conf.json` includes `"schemes": ["openhuman"]` - `src-tauri/capabilities/default.json` includes `"deep-link:default"` - **Use a real backend URL**: - set `VITE_BACKEND_URL` for dev/prod so `Login.tsx` opens the correct domain @@ -198,7 +198,7 @@ Your backend must implement **both**: ### Desktop app (recommended hardening / cleanup) - **Validate the deep link target more strictly** in `src/utils/desktopDeepLinkListener.ts`: - - today it checks only `parsed.protocol === 'alphahuman:'` + - today it checks only `parsed.protocol === 'openhuman:'` - recommended: also require `parsed.hostname === 'auth'` (and optionally a known path) - **Don’t skip Telegram auth in onboarding**: - `src/pages/onboarding/Step1Phone.tsx` currently has a “Continue with Telegram” button that _only navigates_ and does not authenticate. diff --git a/docs/the-tet.jpg b/docs/the-tet.jpg new file mode 100644 index 000000000..9a37c7f87 Binary files /dev/null and b/docs/the-tet.jpg differ diff --git a/docs/tinyhumansai-sdk.md b/docs/tinyhumansai-sdk.md new file mode 100644 index 000000000..81c215628 --- /dev/null +++ b/docs/tinyhumansai-sdk.md @@ -0,0 +1,549 @@ +# TinyHumans AI SDK — Reference & Project Integration + +**Crate:** [`tinyhumansai`](https://crates.io/crates/tinyhumansai) +**Version:** 0.1.6 +**License:** MIT +**Repository:** https://github.com/tinyhumansai/neocortex/tree/main/packages/sdk-rust + +The `tinyhumansai` Rust SDK is a typed async client for the TinyHumans Neocortex memory API. It supports inserting, querying, recalling, and deleting memory — plus ingestion job tracking, document management, and skill-data sync. + +--- + +## Client Setup + +### `TinyHumanConfig` + +```rust +let config = TinyHumanConfig::new("your-api-token"); + +// Override the base URL (optional) +let config = config.with_base_url("https://staging-api.alphahuman.xyz"); +``` + +Base URL resolution order: + +1. `with_base_url(...)` call +2. `TINYHUMANS_BASE_URL` env var +3. `NEOCORTEX_BASE_URL` env var +4. Default: `https://api.tinyhumans.ai` + +### `TinyHumansMemoryClient::new` + +```rust +let client = TinyHumansMemoryClient::new(config)?; +``` + +Validates that the token is non-empty. Returns `TinyHumansError::Validation` if it is. +Sets a 30-second HTTP timeout on all requests. Uses `rustls` for TLS. + +--- + +## SDK Functions + +### `insert_memory` + +**Endpoint:** `POST /memory/insert` + +Ingests a document into the memory store. Returns a job ID — ingestion is asynchronous. + +```rust +let res = client.insert_memory(InsertMemoryParams { + title: "Sprint Dataset - Team Velocity".to_string(), + content: "...".to_string(), + namespace: "sdk-rust-e2e".to_string(), + document_id: "my-doc-id".to_string(), + metadata: Some(serde_json::json!({ "source": "example.rs" })), + ..Default::default() +}).await?; + +let job_id = res.data.job_id; // Option +``` + +**`InsertMemoryParams`** + +| Field | Type | Required | Description | +| ------------- | --------------------------- | -------- | ----------------------------------- | +| `title` | `String` | Yes | Document title | +| `content` | `String` | Yes | Document text content | +| `namespace` | `String` | Yes | Logical partition for the document | +| `document_id` | `String` | Yes | Caller-supplied unique ID | +| `source_type` | `Option` | No | `Doc` (default), `Chat`, or `Email` | +| `metadata` | `Option` | No | Arbitrary JSON metadata | +| `priority` | `Option` | No | `High`, `Medium`, or `Low` | +| `created_at` | `Option` | No | Unix timestamp (ms) | +| `updated_at` | `Option` | No | Unix timestamp (ms) | + +**Serialised request body** (fields with `None` values are omitted): + +```json +{ + "title": "...", + "content": "...", + "namespace": "...", + "sourceType": "doc", + "metadata": { "source": "example.rs" }, + "documentId": "my-doc-id" +} +``` + +**`InsertMemoryResponse`** + +```rust +InsertMemoryResponse { + success: true, + data: InsertMemoryData { + job_id: Some("a2a1396c-..."), + state: Some("pending"), + status: None, + stats: None, + usage: None, + } +} +``` + +--- + +### `get_ingestion_job` + +**Endpoint:** `GET /memory/ingestion/jobs/{jobId}` + +Fetches the current status of an ingestion job. + +```rust +let res = client.get_ingestion_job("a2a1396c-bcf5-4552-afc0-6c822bafd7c6").await?; +println!("{:?}", res.data.state); // Some("processing") | Some("completed") | ... +``` + +**`IngestionJobStatusResponse`** + +| Field | Type | Description | +| -------------- | --------------------------- | ----------------------------------------------------------- | +| `job_id` | `Option` | The job ID | +| `state` | `Option` | `pending`, `processing`, `completed`, `failed`, etc. | +| `endpoint` | `Option` | API endpoint that created the job | +| `attempts` | `Option` | Number of execution attempts | +| `error` | `Option` | Error message if failed | +| `response` | `Option` | Full ingestion result (stats, timings, usage) on completion | +| `created_at` | `Option` | ISO 8601 timestamp | +| `started_at` | `Option` | ISO 8601 timestamp | +| `completed_at` | `Option` | ISO 8601 timestamp | + +Completed response includes ingestion stats (chunk count, entity count, relation count, timings, embedding token usage, and cost in USD). + +--- + +### `wait_for_ingestion_job` + +Polls `get_ingestion_job` until the job reaches a terminal state. + +```rust +let res = client.wait_for_ingestion_job( + "a2a1396c-...", + Some(30_000), // timeout_ms + Some(1_000), // poll_interval_ms +).await?; +``` + +| Parameter | Type | Default | Description | +| ------------------ | ------------- | ------- | ------------------------ | +| `job_id` | `&str` | — | Job to poll | +| `timeout_ms` | `Option` | 30 000 | Max wait in milliseconds | +| `poll_interval_ms` | `Option` | 1 000 | Polling interval | + +**Terminal states:** `completed`, `done`, `succeeded`, `success` → returns `Ok`. +**Failure states:** `failed`, `error`, `cancelled` → returns `Err`. +**Timeout:** returns `TinyHumansError::Api { status: 408 }`. + +--- + +### `query_memory` + +**Endpoint:** `POST /memory/query` + +Semantic (RAG) query over stored memory. Returns ranked chunks relevant to the query. + +```rust +let res = client.query_memory(QueryMemoryParams { + query: "Which team has the highest velocity?".to_string(), + namespace: Some("sdk-rust-e2e".to_string()), + include_references: Some(true), + max_chunks: Some(5.0), + ..Default::default() +}).await?; +``` + +**`QueryMemoryParams`** (`#[serde(rename_all = "camelCase")]`) + +| Field | Type | Serialised as | Description | +| -------------------- | --------------------- | --------------------- | ----------------------------- | +| `query` | `String` | `"query"` | The search query | +| `namespace` | `Option` | `"namespace"` | Filter by namespace | +| `include_references` | `Option` | `"includeReferences"` | Include source chunk metadata | +| `max_chunks` | `Option` | `"maxChunks"` | Max chunks to retrieve | +| `document_ids` | `Option>` | `"documentIds"` | Filter to specific documents | +| `llm_query` | `Option` | `"llmQuery"` | Override query sent to LLM | + +**`QueryMemoryResponse`** + +```rust +QueryMemoryResponse { + success: true, + data: QueryMemoryData { + context: Some(QueryContextOut { + entities: [], + relations: [], + chunks: [ /* matched chunks with scores and entity_mentions */ ], + }), + usage: Some(Usage { + embedding_tokens: 20, + cost_usd: 0.0000004, + llm_input_tokens: 0, + llm_output_tokens: 0, + }), + cached: false, + llm_context_message: Some("## Sources\n\n[1] ..."), + response: None, // populated if LLM response was requested + } +} +``` + +`llm_context_message` is a pre-formatted string ready for injection into an LLM prompt. + +--- + +### `recall_memory` + +**Endpoint:** `POST /memory/recall` + +Recalls synthesised context from the Master memory node for a namespace — no query required. Returns the most relevant accumulated context. + +```rust +let res = client.recall_memory(RecallMemoryParams { + namespace: Some("sdk-rust-e2e".to_string()), + max_chunks: Some(5.0), +}).await?; +``` + +**`RecallMemoryParams`** (`#[serde(rename_all = "camelCase")]`) + +| Field | Type | Serialised as | Description | +| ------------ | ---------------- | ------------- | ------------------------ | +| `namespace` | `Option` | `"namespace"` | Namespace to recall from | +| `max_chunks` | `Option` | `"maxChunks"` | Max chunks to return | + +**`RecallMemoryResponse`** + +```rust +RecallMemoryResponse { + success: true, + data: RecallMemoryData { + context: Some(/* raw JSON object with chunks, entities, relations */), + llm_context_message: Some("## Sources\n\n[1] ..."), + response: None, + cached: false, + latency_seconds: Some(2.8183), + counts: Some(RecallCounts { + num_chunks: 1, + num_entities: 0, + num_relations: 0, + }), + usage: Some(/* cost/token breakdown */), + } +} +``` + +Recall is embedding-free (0 tokens, $0 cost) unlike `query_memory`. + +--- + +### `delete_memory` + +**Endpoint:** `POST /memory/admin/delete` + +Deletes all memory for a namespace (or all memory if namespace is omitted). + +```rust +client.delete_memory(DeleteMemoryParams { + namespace: Some("skill:gmail:user@example.com".to_string()), +}).await?; +``` + +**`DeleteMemoryResponse`** + +```rust +DeleteMemoryData { + status: "ok", + user_id: "...", + namespace: Some("skill:gmail:user@example.com"), + nodes_deleted: 42, + message: "...", +} +``` + +--- + +### `list_documents` + +**Endpoint:** `GET /memory/documents?namespace=...&limit=...&offset=...` + +Lists ingested documents with optional namespace filtering and pagination. + +```rust +let res = client.list_documents(ListDocumentsParams { + namespace: Some("sdk-rust-e2e".to_string()), + limit: Some(10.0), + offset: Some(0.0), +}).await?; +``` + +**`ListDocumentsParams`** + +| Field | Type | Description | +| ----------- | ---------------- | --------------------- | +| `namespace` | `Option` | Filter by namespace | +| `limit` | `Option` | Max results to return | +| `offset` | `Option` | Pagination offset | + +Returns `serde_json::Value` with a `data.documents` array. Each document includes `document_id`, `namespace`, `title`, `chunk_count`, `created_at`, `updated_at`, `user_id`. + +--- + +### `get_document` + +**Endpoint:** `GET /memory/documents/{documentId}?namespace={namespace}` + +Fetches metadata for a single document by ID. + +```rust +let res = client.get_document("my-doc-id", Some("my-namespace")).await?; +``` + +Returns `serde_json::Value` with `document_id`, `namespace`, `title`, `chunk_count`, `chunk_ids`, timestamps, and `user_id`. + +--- + +### `delete_document` + +**Endpoint:** `DELETE /memory/documents/{documentId}?namespace={namespace}` + +Deletes a specific document from a namespace. + +```rust +client.delete_document("my-doc-id", "my-namespace").await?; +``` + +Both `document_id` and `namespace` are required (validated before the request is sent). + +--- + +### Other SDK Methods (Available, Not Used in Project) + +| Method | Endpoint | Description | +| ------------------------- | ---------------------------------- | ----------------------------- | +| `insert_document` | `POST /memory/documents` | Insert via documents route | +| `insert_documents_batch` | `POST /memory/documents/batch` | Batch insert documents | +| `recall_memories` | `POST /memory/memories/recall` | Recall from Ebbinghaus bank | +| `recall_memories_context` | `POST /memory/memories/context` | Recall context from memories | +| `recall_thoughts` | `POST /memory/memories/thoughts` | Reflective thought generation | +| `interact_memory` | `POST /memory/interact` | Record entity interactions | +| `record_interactions` | `POST /memory/interactions` | Record interaction signals | +| `query_memory_context` | `POST /memory/queries` | Query alias route | +| `chat_memory_context` | `POST /memory/conversations` | Chat with memory context | +| `chat_memory` | `POST /memory/chat` | Chat via DeltaNet cache | +| `sync_memory` | `POST /memory/sync` | Sync OpenClaw workspace files | +| `memory_health` | `GET /memory/health` | Health check | +| `get_graph_snapshot` | `GET /memory/admin/graph-snapshot` | Admin graph data | + +--- + +## Error Types + +**`TinyHumansError`** + +| Variant | When | +| ------------------------------- | -------------------------------------------------------------- | +| `Validation(String)` | Client-side validation failed (empty token, empty title, etc.) | +| `Http(String)` | Network/transport error from `reqwest` | +| `Api { message, status, body }` | Non-2xx response from the API | +| `Decode(String)` | Failed to deserialise response JSON | + +--- + +## Project Integration (`openhuman`) + +### How the SDK is Initialised + +**File:** `src-tauri/src/memory/mod.rs` + +The project wraps `TinyHumansMemoryClient` in a `MemoryClient` struct. Construction happens at runtime via the `init_memory_client` Tauri command, using the user's JWT from Redux `authSlice.token` — not a hardcoded API key. + +```rust +pub fn from_token(jwt_token: String) -> Option { + // Base URL resolved in order: + // 1. OPENHUMAN_BASE_URL env var + // 2. TINYHUMANS_BASE_URL env var + // 3. get_backend_url() — app's configured backend + let config = TinyHumanConfig::new(jwt_token).with_base_url(resolved_url); + TinyHumansMemoryClient::new(config).ok().map(|inner| Self { inner }) +} +``` + +The client is stored as `Arc` inside a `Mutex>` (`MemoryState`), shared across Tauri commands. + +--- + +### `MemoryClient` Wrapper Methods + +The `MemoryClient` wrapper exposes higher-level methods used throughout the app: + +#### `store_skill_sync` + +Calls `insert_memory` then polls `ingestion_job_status` every **30 seconds** until the job is `completed` or `failed`. Used after skill OAuth completion and periodic skill syncs. + +```rust +client.store_skill_sync( + skill_id, // becomes the namespace + integration_id, // e.g. "user@example.com" + title, + content, + source_type, // Option + metadata, // Option + priority, // Option + created_at, // Option + updated_at, // Option + document_id, // Option — auto-generated UUID if None +).await?; +``` + +> Note: polling interval is 30 s (fire-and-forget background task). The E2E test uses `wait_for_ingestion_job` with 1 s polling instead. + +#### `query_skill_context` + +Calls `query_memory` for a skill's namespace. Returns the `response` string from the API (LLM-synthesised answer). + +```rust +let context: String = client.query_skill_context( + skill_id, // namespace + integration_id, // unused currently + "What emails were recently synced?", + 10, // max_chunks +).await?; +``` + +#### `recall_skill_context` + +Calls `recall_memory` for a namespace. Returns `Option` (the raw `context` field). + +```rust +let ctx: Option = client.recall_skill_context( + skill_id, + integration_id, + 10, // max_chunks +).await?; +``` + +#### `clear_skill_memory` + +Calls `delete_memory` with `namespace = skill_id`. Used on OAuth revoke / skill disconnect. + +```rust +client.clear_skill_memory("gmail", "user@example.com").await?; +// → DELETE namespace "gmail" +``` + +#### `query_namespace_context` / `recall_namespace_context` + +Direct namespace versions of query/recall — bypass the `skill:{id}:{id}` namespace convention. + +#### `list_documents` / `delete_document` + +Thin pass-through wrappers over the SDK methods. + +--- + +### Memory in the Chat Agentic Loop + +**File:** `src-tauri/src/commands/chat.rs` + +Every `chat_send` call (desktop) performs these memory operations before hitting the inference API: + +**Step 2 — Conversation recall** + +```rust +mem.recall_skill_context("conversations", thread_id, 10).await +``` + +Recalls context from the `conversations` namespace, keyed by `thread_id`. The result is injected into the user message as: + +``` +[MEMORY_CONTEXT] +{recalled context} +[/MEMORY_CONTEXT] + +{user message} +``` + +**Step 2b — Skill context recall** + +For every skill with registered tools, recalls its memory: + +```rust +mem.recall_skill_context(skill_id, skill_id, 10).await +``` + +Each result is injected as: + +``` +[{SKILL_ID}_CONTEXT] +{recalled context} +[/{SKILL_ID}_CONTEXT] +``` + +The full assembled user message sent to the inference API looks like: + +``` +## Project Context +{openclaw_context — SOUL.md, IDENTITY.md, TOOLS.md, etc.} + +User message: {original message} + +[MEMORY_CONTEXT] +{conversation memory} +[/MEMORY_CONTEXT] + +[GMAIL_CONTEXT] +{gmail skill memory} +[/GMAIL_CONTEXT] + +{notion_context if present} +``` + +--- + +### Namespace Conventions + +| Context | Namespace pattern | Set by | +| ------------------------------ | ----------------- | ---------------------------------------------------------- | +| Skill sync (OAuth / periodic) | `{skill_id}` | `store_skill_sync` — uses `skill_id` directly as namespace | +| Skill memory clear | `{skill_id}` | `clear_skill_memory` | +| Conversation recall | `conversations` | `chat_send_inner` hardcoded | +| Skill context recall (in chat) | `{skill_id}` | `chat_send_inner` per-skill loop | +| E2E test | `sdk-rust-e2e` | `example_e2e.rs` | + +--- + +### All SDK Calls in the Project + +| Location | SDK method called | Purpose | +| ----------------------------------------- | ---------------------------------- | --------------------------------------- | +| `memory/mod.rs::store_skill_sync` | `insert_memory` | Write skill sync data | +| `memory/mod.rs::store_skill_sync` | `ingestion_job_status` (poll loop) | Wait for ingestion to complete | +| `memory/mod.rs::query_skill_context` | `query_memory` | RAG query for skill context | +| `memory/mod.rs::recall_skill_context` | `recall_memory` | Recall synthesised context | +| `memory/mod.rs::recall_namespace_context` | `recall_memory` | Direct namespace recall | +| `memory/mod.rs::query_namespace_context` | `query_memory` | Direct namespace query | +| `memory/mod.rs::list_documents` | `list_documents` | List ingested documents | +| `memory/mod.rs::delete_document` | `delete_document` | Remove a document | +| `memory/mod.rs::clear_skill_memory` | `delete_memory` | Wipe skill namespace on disconnect | +| `commands/chat.rs` (step 2) | via `recall_skill_context` | Inject conversation history into prompt | +| `commands/chat.rs` (step 2b) | via `recall_skill_context` | Inject per-skill context into prompt | diff --git a/eslint.config.js b/eslint.config.js index ad30f1012..2fade18b2 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -42,6 +42,8 @@ export default [ globals: { // Browser globals window: 'readonly', + localStorage: 'readonly', + sessionStorage: 'readonly', document: 'readonly', navigator: 'readonly', console: 'readonly', diff --git a/gitbooks/README.md b/gitbooks/README.md index 6e36858b1..181cf375c 100644 --- a/gitbooks/README.md +++ b/gitbooks/README.md @@ -1,34 +1,34 @@ --- description: >- - AlphaHuman is a personal AI assistant that runs natively across desktop, + OpenHuman is a personal AI assistant that runs natively across desktop, mobile, and web that connects your communication platforms, tools, and workflows into a single intelligence layer you control. icon: diamond --- -# Welcome to AlphaHuman +# Welcome to OpenHuman -AlphaHuman is the first open-source AI agent with Big Data capabilities and a personalized subconscious mind. Built on the OpenClaw architecture and licensed under GNU GPL3, AlphaHuman is designed to close the gap between what AI models can do and what they actually know about you. +OpenHuman is the first open-source AI agent with Big Data capabilities and a personalized subconscious mind. Built on the OpenClaw architecture and licensed under GNU GPL3, OpenHuman is designed to close the gap between what AI models can do and what they actually know about you. Every AI model in the world, all 200+ of them, shares the same fundamental limitation. They are stateless. You type a prompt, get a response, and the context evaporates. Even the ones with "memory" store a few bullet points. A few bullet points is a sticky note, not intelligence. -AlphaHuman solves this with two core innovations: +OpenHuman solves this with two core innovations:
**Neocortex**, a human-like memory engine that can accurately work with over 1 billion tokens. Neocortex indexes 10 million tokens in under 10 seconds, costs $1 to index 5 million tokens, and runs on a MacBook Air CPU with zero LLM dependency. Neocortex goes beyond vector databases. It understands time, entities, and relationships, and it models memory the way the human brain does: by compressing, forgetting strategically, and building knowledge graphs. -**A personalized subconscious system** inspired by the Purkinje cell, a specialized neuron in the human brain responsible for random thoughts and consciousness. AlphaHuman's subconscious triggers over 10,000 memory recall loops per day for under $1, producing proactive insights, pattern recognition, and emergent "thoughts" that feed into a self-learning loop. +**A personalized subconscious system** inspired by the Purkinje cell, a specialized neuron in the human brain responsible for random thoughts and consciousness. OpenHuman's subconscious triggers over 10,000 memory recall loops per day for under $1, producing proactive insights, pattern recognition, and emergent "thoughts" that feed into a self-learning loop. -Together, these systems turn AlphaHuman into something fundamentally different from a chatbot. It is an AI agent that consumes large amounts of personal data at low cost, maintains a persistent and evolving understanding of your world, and takes proactive actions on your behalf. +Together, these systems turn OpenHuman into something fundamentally different from a chatbot. It is an AI agent that consumes large amounts of personal data at low cost, maintains a persistent and evolving understanding of your world, and takes proactive actions on your behalf. {% hint style="info" %} -AlphaHuman is not AGI. But it is a meaningful architectural step closer to it, with better memory and better orchestration for memory, taking direct inspiration from the human brain. +OpenHuman is not AGI. But it is a meaningful architectural step closer to it, with better memory and better orchestration for memory, taking direct inspiration from the human brain. {% endhint %} -## What AlphaHuman does +## What OpenHuman does -AlphaHuman connects to your communication platforms, tools, and workflows, and compresses that information into structured intelligence any AI can act on. +OpenHuman connects to your communication platforms, tools, and workflows, and compresses that information into structured intelligence any AI can act on. It **compresses context** across your connected sources, turning millions of tokens of organizational noise into a structured knowledge graph of entities, relationships, and temporal chains. @@ -38,29 +38,27 @@ It **thinks proactively** through its subconscious system, making connections an It **preserves privacy** by design. Raw data stays on your device. Encryption keys never leave the device. Only compressed metadata and summaries are processed server-side. - - ## Who it's for -AlphaHuman is built for people and teams who operate across many conversations and tools, and feel the cost of it. +OpenHuman is built for people and teams who operate across many conversations and tools, and feel the cost of it. -* **Developers and power users** in the AI ecosystem, especially those using OpenClaw, CrewAI, and similar agentic frameworks, who need a memory and context layer that actually scales. -* **High-volume communicators** who miss decisions, context, and follow-ups buried in message noise across multiple platforms. -* **Traders and analysts** who need fast signal extraction and risk awareness across information channels, both on-chain and off-chain. -* **Distributed teams** who make decisions in chat but need structured follow-through in external tools. +- **Developers and power users** in the AI ecosystem, especially those using OpenClaw, CrewAI, and similar agentic frameworks, who need a memory and context layer that actually scales. +- **High-volume communicators** who miss decisions, context, and follow-ups buried in message noise across multiple platforms. +- **Traders and analysts** who need fast signal extraction and risk awareness across information channels, both on-chain and off-chain. +- **Distributed teams** who make decisions in chat but need structured follow-through in external tools. -## What AlphaHuman does not do +## What OpenHuman does not do -AlphaHuman does not claim to be AGI. It does not send messages automatically or impersonate you. It does not store your raw message data long-term. It does not train on your data. +OpenHuman does not claim to be AGI. It does not send messages automatically or impersonate you. It does not store your raw message data long-term. It does not train on your data. {% hint style="info" %} Privacy is a core architectural decision, not a checkbox. The full privacy design is covered in Privacy & Security. {% endhint %} -## How to think about AlphaHuman +## How to think about OpenHuman Think of it this way: ChatGPT, Claude, Gemini, and every other model are the brain. They are brilliant at reasoning, generation, and analysis. But they are amnesiac. They know nothing about your actual life. -AlphaHuman is the memory and the subconscious that makes those brains actually useful. It is the Big Data layer for AI: an always-on context engine that compresses your entire organizational life into intelligence any AI can act on. +OpenHuman is the memory and the subconscious that makes those brains actually useful. It is the Big Data layer for AI: an always-on context engine that compresses your entire organizational life into intelligence any AI can act on. -Your AI is smart. It just does not know you. AlphaHuman fixes that. +Your AI is smart. It just does not know you. OpenHuman fixes that. diff --git a/gitbooks/SUMMARY.md b/gitbooks/SUMMARY.md index 1abd893ca..1849e39b0 100644 --- a/gitbooks/SUMMARY.md +++ b/gitbooks/SUMMARY.md @@ -2,33 +2,33 @@ ## Overview -* [Welcome to AlphaHuman](README.md) -* [How It Works](overview/how-it-works.md) -* [Getting Started](overview/getting-started.md) +- [Welcome to OpenHuman](README.md) +- [How It Works](overview/how-it-works.md) +- [Getting Started](overview/getting-started.md) ## Technology -* [Neocortex](technology/neocortex.md) -* [The Subconscious](technology/the-subconscious.md) -* [Architecture](technology/architecture.md) +- [Neocortex](technology/neocortex.md) +- [The Subconscious](technology/the-subconscious.md) +- [Architecture](technology/architecture.md) ## Product -* [Platform & Availability](product/platform.md) -* [Skills & Integrations](product/skills-and-integrations.md) -* [Teams & Organizations](product/teams.md) -* [Privacy & Security](product/privacy-and-security.md) -* [Pricing](product/pricing.md) +- [Platform & Availability](product/platform.md) +- [Skills & Integrations](product/skills-and-integrations.md) +- [Teams & Organizations](product/teams.md) +- [Privacy & Security](product/privacy-and-security.md) +- [Pricing](product/pricing.md) ## Use Cases -* [Overview](use-cases/overview.md) +- [Overview](use-cases/overview.md) ## Resources -* [FAQ & Troubleshooting](resources/faq.md) +- [FAQ & Troubleshooting](resources/faq.md) ## Legal -* [Terms & Conditions](legal/terms-of-use.md) -* [Privacy Policy](legal/privacy-policy.md) +- [Terms & Conditions](legal/terms-of-use.md) +- [Privacy Policy](legal/privacy-policy.md) diff --git a/gitbooks/legal/privacy-policy.md b/gitbooks/legal/privacy-policy.md index fed10bbb7..482eb06a3 100644 --- a/gitbooks/legal/privacy-policy.md +++ b/gitbooks/legal/privacy-policy.md @@ -67,4 +67,3 @@ Depending on your location, you may have rights to access, correct, delete, rest ## Changes to This Policy We may update this Privacy Policy from time to time. Material changes will be communicated as required by law. Changes will not apply retroactively in a manner that reduces existing privacy protections. - diff --git a/gitbooks/overview/getting-started.md b/gitbooks/overview/getting-started.md index 36f97c4ac..d1899a3ed 100644 --- a/gitbooks/overview/getting-started.md +++ b/gitbooks/overview/getting-started.md @@ -4,46 +4,46 @@ icon: play # Getting Started -This section walks you through setting up AlphaHuman and running your first request. +This section walks you through setting up OpenHuman and running your first request. -AlphaHuman is open source under the GNU GPL3 license. The codebase is available at [github.com/tinyhumansai/alphahuman](https://github.com/tinyhumansai/alphahuman). You can self-host, contribute, or simply use the hosted version. +OpenHuman is open source under the GNU GPL3 license. The codebase is available at [github.com/tinyhumansai/openhuman](https://github.com/tinyhumansai/openhuman). You can self-host, contribute, or simply use the hosted version. -*** +--- ## Download & Install -AlphaHuman runs natively on: +OpenHuman runs natively on: -* **macOS** (Intel and Apple Silicon) -* **Windows** (x64 and ARM64) -* **Linux** (x64 and ARM64: AppImage and .deb) -* **Android** -* **iOS** -* **Web** (any modern browser) +- **macOS** (Intel and Apple Silicon) +- **Windows** (x64 and ARM64) +- **Linux** (x64 and ARM64: AppImage and .deb) +- **Android** +- **iOS** +- **Web** (any modern browser) -Download the app for your platform from the official AlphaHuman website, or use the web version directly in your browser. +Download the app for your platform from the official OpenHuman website, or use the web version directly in your browser. The native app has a small footprint, starts fast, and uses your operating system's secure credential storage. The web version provides the same core functionality when a native install is not practical. -*** +--- ## Create Your Account -When you first open AlphaHuman, you will be asked to sign in. Multiple sign-in options are available, including social login providers. +When you first open OpenHuman, you will be asked to sign in. Multiple sign-in options are available, including social login providers. After signing in, you may be placed on a waitlist depending on rollout status. The waitlist is used to manage access during launch and early scaling. {% hint style="info" %} -**No permanent lock-in.** Creating an account does not grant AlphaHuman ongoing access to anything. All processing still requires explicit actions from you later. +**No permanent lock-in.** Creating an account does not grant OpenHuman ongoing access to anything. All processing still requires explicit actions from you later. {% endhint %} -*** +--- ## Connect Your First Source -AlphaHuman works by connecting to your existing tools and platforms. Each connection expands your knowledge graph, giving Neocortex more data to compress and reason over. You choose what to connect, and you can revoke access at any time. +OpenHuman works by connecting to your existing tools and platforms. Each connection expands your knowledge graph, giving Neocortex more data to compress and reason over. You choose what to connect, and you can revoke access at any time. -**Telegram:** Connect your Telegram account to analyze conversations, extract signals, and generate summaries across your chats and groups. AlphaHuman supports the full range of Telegram capabilities: chat management, message search, contact management, group and channel administration, reactions, polls, inline buttons, and more. +**Telegram:** Connect your Telegram account to analyze conversations, extract signals, and generate summaries across your chats and groups. OpenHuman supports the full range of Telegram capabilities: chat management, message search, contact management, group and channel administration, reactions, polls, inline buttons, and more. **Notion:** Connect Notion to export structured outputs like summaries, action items, decisions, and workflow records into your workspace. @@ -53,39 +53,39 @@ AlphaHuman works by connecting to your existing tools and platforms. Each connec All integrations are optional. You can start with one source and add more later. The more sources you connect, the more powerful the intelligence becomes. Each connection is independently revocable. -*** +--- ## Run Your First Request -Once a source is connected, you can start asking AlphaHuman questions using the command input. +Once a source is connected, you can start asking OpenHuman questions using the command input. Try prompts like: -* **"Summarize what I missed today"** -* **"What are the key decisions from this week?"** -* **"Extract action items from my recent conversations"** -* **"What topics are trending across my groups?"** +- **"Summarize what I missed today"** +- **"What are the key decisions from this week?"** +- **"Extract action items from my recent conversations"** +- **"What topics are trending across my groups?"** -AlphaHuman processes only the data needed to answer your request, produces an output, and presents it for your review. If the output feels too broad or too shallow, narrow the scope. Specify a particular conversation, time range, or intent. +OpenHuman processes only the data needed to answer your request, produces an output, and presents it for your review. If the output feels too broad or too shallow, narrow the scope. Specify a particular conversation, time range, or intent. -*** +--- ## Explore Skills & Integrations -After your first request, explore what else AlphaHuman can do: +After your first request, explore what else OpenHuman can do: -* **Skills** extend the assistant's capabilities, fetching external data, running scheduled tasks, processing information, and writing outputs to connected tools -* **Integrations** let you push structured results to Notion, Google Sheets, and other tools -* **Workflows** turn conversation decisions into trackable actions you can follow through on +- **Skills** extend the assistant's capabilities, fetching external data, running scheduled tasks, processing information, and writing outputs to connected tools +- **Integrations** let you push structured results to Notion, Google Sheets, and other tools +- **Workflows** turn conversation decisions into trackable actions you can follow through on Learn more in [Skills & Integrations](../product/skills-and-integrations.md). -*** +--- #### Join the Community -AlphaHuman is in early alpha. Feedback and contributions make a real difference at this stage. +OpenHuman is in early alpha. Feedback and contributions make a real difference at this stage. Join the Discord community to connect with other users, share feedback, report issues, and contribute to the project. Early users get free usage as part of the alpha program. -**GitHub:** [github.com/tinyhumansai/alphahuman](https://github.com/tinyhumansai/alphahuman) +**GitHub:** [github.com/tinyhumansai/openhuman](https://github.com/tinyhumansai/openhuman) diff --git a/gitbooks/overview/how-it-works.md b/gitbooks/overview/how-it-works.md index 057a7d5ce..5d7cbbe1d 100644 --- a/gitbooks/overview/how-it-works.md +++ b/gitbooks/overview/how-it-works.md @@ -4,9 +4,9 @@ icon: brain # How It Works -AlphaHuman is built on three technology pillars: a memory engine called Neocortex, a subconscious system inspired by human neuroscience, and a privacy-preserving architecture that keeps raw data on your device. Understanding how these work together is understanding how AlphaHuman thinks. +OpenHuman is built on three technology pillars: a memory engine called Neocortex, a subconscious system inspired by human neuroscience, and a privacy-preserving architecture that keeps raw data on your device. Understanding how these work together is understanding how OpenHuman thinks. -### The problem AlphaHuman solves +### The problem OpenHuman solves Current AI systems fall into the category of Artificial Narrow Intelligence (ANI). They perform well within bounded domains, but they depend on carefully designed architectures and human-defined operational boundaries. They lack three things needed to get closer to general intelligence: persistent memory at scale, a form of consciousness or instinct, and the ability to ingest data without becoming inaccurate or expensive. @@ -14,7 +14,7 @@ Research from Google's Titans project demonstrates the core issue clearly. As LL
-AlphaHuman solves this in two steps. +OpenHuman solves this in two steps. #### Step 1: Neocortex, the memory engine @@ -50,13 +50,13 @@ Additional capabilities of Neocortex: #### Step 2: The personalized subconscious -With good memory and good recall, AlphaHuman can do something no other AI agent does: maintain a personalized subconscious. +With good memory and good recall, OpenHuman can do something no other AI agent does: maintain a personalized subconscious. In the human brain, there is a specialized neuron called the Purkinje cell. It is mainly responsible for random thoughts and plays a significant role in consciousness. The human brain has both a conscious and subconscious mind that work together to build intelligence. Most agentic systems follow the conscious mind model only. They wait for instructions and execute them. They cannot think on their own.
-Inspired by the Purkinje cell, AlphaHuman uses Neocortex to periodically trigger global memory recalls. These recalls are fed into a subconscious loop that produces actions, confirmations, or new connections. Memory recalls are cheap, fast, and happen over 10,000 times a day for less than $1. +Inspired by the Purkinje cell, OpenHuman uses Neocortex to periodically trigger global memory recalls. These recalls are fed into a subconscious loop that produces actions, confirmations, or new connections. Memory recalls are cheap, fast, and happen over 10,000 times a day for less than $1. The result is an AI that does not just respond to your prompts. It thinks about your data in the background. It makes connections you did not ask for. It surfaces patterns and risks proactively. @@ -64,7 +64,7 @@ The success metric for the subconscious is what the team calls the "mirror test" ### How the pieces connect -When you use AlphaHuman, here is what happens: +When you use OpenHuman, here is what happens:
@@ -74,13 +74,13 @@ When you use AlphaHuman, here is what happens: **The subconscious runs.** Thousands of recall loops per day surface proactive insights, track evolving patterns, and update the knowledge graph. -**You interact naturally.** Ask anything about your life, your team, your projects. Not general knowledge. Your knowledge. What did your team decide? What is the status? What did you miss? AlphaHuman already knows. +**You interact naturally.** Ask anything about your life, your team, your projects. Not general knowledge. Your knowledge. What did your team decide? What is the status? What did you miss? OpenHuman already knows. **Privacy is maintained.** Raw data stays on device, encrypted with AES-256-GCM. Encryption keys never leave the device. Only compressed metadata and summaries are processed server-side. ### The architecture: OpenClaw foundation -AlphaHuman is built on top of the OpenClaw architecture and is open-sourced under the GNU GPL3 license. The full codebase is publicly available on GitHub. +OpenHuman is built on top of the OpenClaw architecture and is open-sourced under the GNU GPL3 license. The full codebase is publicly available on GitHub. The architecture uses multi-agent orchestration, where specialized agents are dynamically spawned for specific tasks rather than relying on one monolithic model. An orchestrator agent manages routing, personality, and context distribution. Specialist agents handle specific domains: communication analysis, document synthesis, task management, trading. These agents execute in parallel, not sequentially, for real-time responsiveness. @@ -88,8 +88,8 @@ All agents share a common compressed context provided by Neocortex. This effecti ### Limitations -AlphaHuman works with probabilistic models. It may occasionally miss nuance, misinterpret sarcasm, or over-prioritize certain messages. This is more likely in highly informal conversations, fast-moving threads, or contexts with limited data. +OpenHuman works with probabilistic models. It may occasionally miss nuance, misinterpret sarcasm, or over-prioritize certain messages. This is more likely in highly informal conversations, fast-moving threads, or contexts with limited data. -AlphaHuman is not AGI. It is a meaningful step closer, with better memory and better orchestration for memory, taking inspiration from the human brain. But human judgment still matters. AlphaHuman helps you think faster. It does not think for you. +OpenHuman is not AGI. It is a meaningful step closer, with better memory and better orchestration for memory, taking inspiration from the human brain. But human judgment still matters. OpenHuman helps you think faster. It does not think for you. Everything is in early alpha. Feedback and contributions are welcomed. diff --git a/gitbooks/overview/platform.md b/gitbooks/overview/platform.md index 0516979c0..9c455068e 100644 --- a/gitbooks/overview/platform.md +++ b/gitbooks/overview/platform.md @@ -6,7 +6,7 @@ icon: layer-plus OpenHuman is a native **desktop** application. It is not a web-only tool, browser extension, or Electron wrapper. It is built for performance, security, and a small footprint on the machines where we officially support it today. -*** +--- ## Supported today: desktop @@ -20,7 +20,7 @@ OpenHuman ships native installers for: **Android, iOS, and a standalone web client are not supported** in documentation or releases yet. The codebase may contain experimental mobile or web targets; they are out of scope for current user-facing docs. -*** +--- ## Why Native Matters @@ -32,7 +32,7 @@ OpenHuman is built as a native application rather than a web wrapper for three r **OS-level security.** On desktop platforms, OpenHuman stores credentials in your operating system's secure keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). Sensitive data never sits in browser storage or plain text files. -*** +--- ## Architecture at a Glance @@ -48,7 +48,7 @@ OpenHuman operates across three layers: The intelligence layer is not part of the client application. It performs analysis, coordination, and trust scoring separately from the frontend. {% endhint %} -*** +--- ## Real-Time Communication @@ -56,7 +56,7 @@ OpenHuman maintains a persistent connection between the application and the inte The connection is designed for resilience. If the network drops, OpenHuman reconnects automatically with progressive backoff. There is no manual reconnection process. -*** +--- ## Offline Behavior diff --git a/gitbooks/product/platform.md b/gitbooks/product/platform.md index 908eefa29..acd87c394 100644 --- a/gitbooks/product/platform.md +++ b/gitbooks/product/platform.md @@ -4,13 +4,13 @@ icon: layer-plus # Platform & Availability -AlphaHuman is a native application that runs on six platforms from a single codebase. It is not a web-only tool, browser extension, or Electron wrapper. It is built for performance, security, and a small footprint on every device you use. +OpenHuman is a native application that runs on six platforms from a single codebase. It is not a web-only tool, browser extension, or Electron wrapper. It is built for performance, security, and a small footprint on every device you use. -*** +--- ## Six Platforms, One Experience -AlphaHuman compiles to native binaries for each supported platform: +OpenHuman compiles to native binaries for each supported platform: | Platform | Architectures | Distribution | | ----------- | -------------------- | -------------- | @@ -23,46 +23,46 @@ AlphaHuman compiles to native binaries for each supported platform: Your account, connected sources, preferences, and settings sync across all platforms. You can start a request on your desktop and review the output on your phone. -*** +--- ## Why Native Matters -AlphaHuman is built as a native application rather than a web wrapper for three reasons. +OpenHuman is built as a native application rather than a web wrapper for three reasons. **Small footprint.** The app is lightweight. A fraction of the size of typical communication tools. It starts in under a second and uses minimal memory, so it stays out of the way when running alongside other demanding applications. **Fast startup.** There is no browser engine to initialize. The app launches quickly and is ready to accept requests immediately. -**OS-level security.** On desktop platforms, AlphaHuman stores credentials in your operating system's secure keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). Sensitive data never sits in browser storage or plain text files. +**OS-level security.** On desktop platforms, OpenHuman stores credentials in your operating system's secure keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). Sensitive data never sits in browser storage or plain text files. -*** +--- ## Architecture at a Glance -AlphaHuman operates across three layers: +OpenHuman operates across three layers: **Application layer.** The native app on your device handles the interface, user input, local state, credential management, and skill execution. This layer is responsible for everything you see and interact with. -**Intelligence layer.** AlphaHuman's analysis, coordination, and intelligence systems run as a secure backend service. When a request requires deeper language processing, it is handled here. This layer is operated and maintained by AlphaHuman. +**Intelligence layer.** OpenHuman's analysis, coordination, and intelligence systems run as a secure backend service. When a request requires deeper language processing, it is handled here. This layer is operated and maintained by OpenHuman. -**External services.** Connected tools and platforms:Telegram, Notion, Google Sheets, and others are accessed only when you explicitly request it. AlphaHuman acts as a bridge between your sources and the intelligence layer, not as a replacement for any of them. +**External services.** Connected tools and platforms:Telegram, Notion, Google Sheets, and others are accessed only when you explicitly request it. OpenHuman acts as a bridge between your sources and the intelligence layer, not as a replacement for any of them. {% hint style="info" %} The intelligence layer is not part of the client application. It performs analysis, coordination, and trust scoring separately from the frontend. {% endhint %} -*** +--- ## Real-Time Communication -AlphaHuman maintains a persistent connection between the application and the intelligence layer. This means responses arrive in real time as they are generated. You see outputs streaming, not loading. +OpenHuman maintains a persistent connection between the application and the intelligence layer. This means responses arrive in real time as they are generated. You see outputs streaming, not loading. -The connection is designed for resilience. If the network drops, AlphaHuman reconnects automatically with progressive backoff. There is no manual reconnection process. +The connection is designed for resilience. If the network drops, OpenHuman reconnects automatically with progressive backoff. There is no manual reconnection process. -*** +--- ## Offline Behavior -AlphaHuman's local state persists on your device. Your preferences, settings, and connected source configurations remain available even when you are offline. +OpenHuman's local state persists on your device. Your preferences, settings, and connected source configurations remain available even when you are offline. Full analysis and intelligence features require a network connection, since they depend on the intelligence layer. When connectivity is restored, the app resumes normal operation without requiring you to re-authenticate or reconfigure. diff --git a/gitbooks/product/pricing.md b/gitbooks/product/pricing.md index 9a61e1241..d86b5758d 100644 --- a/gitbooks/product/pricing.md +++ b/gitbooks/product/pricing.md @@ -4,19 +4,19 @@ icon: sack-dollar # Pricing -AlphaHuman is priced as a SaaS product for individuals and teams that rely on high-volume communication and need clarity, coordination, and safety across their tools. Pricing reflects the value of reduced cognitive load and better signal quality, not raw message volume. +OpenHuman is priced as a SaaS product for individuals and teams that rely on high-volume communication and need clarity, coordination, and safety across their tools. Pricing reflects the value of reduced cognitive load and better signal quality, not raw message volume. -*** +--- ## Individual Plans Individual plans are designed for power users who want help managing high-volume activity across multiple conversations and connected sources. -Core analysis functionality is included so users can understand AlphaHuman's value before committing. Deeper features, longer context windows, persistent workflows, richer integrations, and advanced intelligence are available in higher tiers. +Core analysis functionality is included so users can understand OpenHuman's value before committing. Deeper features, longer context windows, persistent workflows, richer integrations, and advanced intelligence are available in higher tiers. Plans are tiered to allow users to start lightweight and expand as their needs grow. -*** +--- ## Team Plans @@ -26,34 +26,34 @@ Team plans include shared workflows, community-level intelligence, coordination Individual user privacy is preserved even in shared team environments. -*** +--- ## Credit System -AlphaHuman uses a credit-based system for usage-metered features. +OpenHuman uses a credit-based system for usage-metered features. -* Credits are consumed when you use analysis, intelligence, and processing features -* Oldest credits are consumed first, encouraging usage before expiry -* Credits can be earned through the referral program, in addition to purchase -* Every credit transaction is tracked in an auditable ledger +- Credits are consumed when you use analysis, intelligence, and processing features +- Oldest credits are consumed first, encouraging usage before expiry +- Credits can be earned through the referral program, in addition to purchase +- Every credit transaction is tracked in an auditable ledger Credits provide flexibility as you pay for what you use, and you can supplement your plan with earned credits from referrals. -*** +--- ## Payment Methods -AlphaHuman supports standard and cryptocurrency payment options. +OpenHuman supports standard and cryptocurrency payment options. -* **Card payments:** Standard subscription billing with the ability to upgrade, downgrade, or cancel at any time -* **Cryptocurrency:** Alternative payment path for users who prefer crypto +- **Card payments:** Standard subscription billing with the ability to upgrade, downgrade, or cancel at any time +- **Cryptocurrency:** Alternative payment path for users who prefer crypto Changes to your plan take effect immediately. Cancellation does not affect outputs already exported to external tools. -*** +--- ## Access During Launch -During the initial launch phase, access to AlphaHuman may be gated through a waitlist. This is done to manage platform stability and collect feedback from early users. +During the initial launch phase, access to OpenHuman may be gated through a waitlist. This is done to manage platform stability and collect feedback from early users. Waitlist access does not imply long-term pricing commitments. Pricing and plan boundaries may evolve during this phase as usage patterns become clearer. diff --git a/gitbooks/product/privacy-and-security.md b/gitbooks/product/privacy-and-security.md index a41fa5702..ce9f7fee0 100644 --- a/gitbooks/product/privacy-and-security.md +++ b/gitbooks/product/privacy-and-security.md @@ -4,71 +4,71 @@ icon: shield # Privacy & Security -AlphaHuman operates on a principle of **zero-knowledge intelligence**. The system is architecturally designed so that your raw data never needs to leave your device. Neocortex compresses your data locally into structured metadata and summaries. Only this compressed output is processed server-side. Your AI has months of context about your entire organizational life. Your raw data has never touched our servers. +OpenHuman operates on a principle of **zero-knowledge intelligence**. The system is architecturally designed so that your raw data never needs to leave your device. Neocortex compresses your data locally into structured metadata and summaries. Only this compressed output is processed server-side. Your AI has months of context about your entire organizational life. Your raw data has never touched our servers. -*** +--- ## Privacy by Design -AlphaHuman operates on a principle of **zero retention** for message content. When you make a request, the relevant data is processed to produce an output, and the source content is discarded afterward. +OpenHuman operates on a principle of **zero retention** for message content. When you make a request, the relevant data is processed to produce an output, and the source content is discarded afterward. -**No long-term message storage.** AlphaHuman does not maintain a persistent archive of your conversations. Context is reconstructed from your connected sources when needed. +**No long-term message storage.** OpenHuman does not maintain a persistent archive of your conversations. Context is reconstructed from your connected sources when needed. **No training on your data.** Your conversations, analysis results, and personal information are never used to train AI models or improve systems. Your data serves you and only you. -**OS-level credential storage.** On desktop platforms, AlphaHuman uses your operating system's secure keychain to store credentials and sensitive tokens. Credentials are never stored in plain text, browser storage, or application-level databases. +**OS-level credential storage.** On desktop platforms, OpenHuman uses your operating system's secure keychain to store credentials and sensitive tokens. Credentials are never stored in plain text, browser storage, or application-level databases. **On-device where possible.** Interface rendering, input handling, local state management, and credential operations all happen on your device. Only tasks requiring deeper language processing are handled server-side, under the same privacy constraints. -*** +--- ## Permissions and Access Control -AlphaHuman operates on an **explicit-access model**. It only accesses data when you issue a request, and only the data needed to fulfill that request. +OpenHuman operates on an **explicit-access model**. It only accesses data when you issue a request, and only the data needed to fulfill that request. ### Request-Scoped Access -Access is determined by your requests, not by background monitoring. If you ask AlphaHuman to summarize a specific conversation, only that conversation is processed. If you do not reference a source, it is not accessed. +Access is determined by your requests, not by background monitoring. If you ask OpenHuman to summarize a specific conversation, only that conversation is processed. If you do not reference a source, it is not accessed. -AlphaHuman does not silently expand its access over time. There is no progressive permission creep. +OpenHuman does not silently expand its access over time. There is no progressive permission creep. ### Source-Specific Permissions Each connected source has its own permission scope: -* **Telegram:** Read-only access. AlphaHuman can read messages from conversations you reference in a request. It cannot send messages, edit messages, react, join groups, or act on your behalf. -* **Notion:** Write access to specific workspaces or pages you approve. AlphaHuman does not read unrelated documents. -* **Google Sheets:** Write access to specific spreadsheets you approve. AlphaHuman does not read unrelated sheets. +- **Telegram:** Read-only access. OpenHuman can read messages from conversations you reference in a request. It cannot send messages, edit messages, react, join groups, or act on your behalf. +- **Notion:** Write access to specific workspaces or pages you approve. OpenHuman does not read unrelated documents. +- **Google Sheets:** Write access to specific spreadsheets you approve. OpenHuman does not read unrelated sheets. Integration permissions are limited to what is needed for the specific action you request. ### User-Initiated Actions Only -Every meaningful operation in AlphaHuman is user-initiated. Summaries, analysis, trust evaluation, workflow creation, and exports all require a direct request. There is no continuous background processing or monitoring. +Every meaningful operation in OpenHuman is user-initiated. Summaries, analysis, trust evaluation, workflow creation, and exports all require a direct request. There is no continuous background processing or monitoring. {% hint style="info" %} -AlphaHuman is idle unless you ask it to do something. +OpenHuman is idle unless you ask it to do something. {% endhint %} -*** +--- ## Revoking Access -You can revoke AlphaHuman's access to any connected source at any time. +You can revoke OpenHuman's access to any connected source at any time. -* Disconnect a source from your settings -* Remove integration permissions -* Stop using the application entirely +- Disconnect a source from your settings +- Remove integration permissions +- Stop using the application entirely -Once access is revoked, AlphaHuman immediately stops processing data from that source. There is no delayed or cached processing after revocation. Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written, but no new processing occurs. +Once access is revoked, OpenHuman immediately stops processing data from that source. There is no delayed or cached processing after revocation. Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written, but no new processing occurs. -This makes AlphaHuman safe to test, pause, or stop using without residual exposure. +This makes OpenHuman safe to test, pause, or stop using without residual exposure. -*** +--- ## Security -AlphaHuman implements security at every layer of the system. +OpenHuman implements security at every layer of the system. **AES-256-GCM encryption.** All sensitive data stored locally is encrypted using AES-256-GCM. Encryption keys are derived from your credentials and stored in your operating system's secure keychain. Keys never leave the device. Even if server-side infrastructure were compromised, your raw data would remain inaccessible because it was never there. @@ -76,11 +76,11 @@ AlphaHuman implements security at every layer of the system. **Sandboxed skills.** Each skill runs in its own isolated execution environment with enforced memory and resource limits. Skills cannot access each other's data, the host system's file system, or your credentials. -**Encrypted transit.** All communication between the application and AlphaHuman's servers uses encrypted connections. No data travels in plain text. +**Encrypted transit.** All communication between the application and OpenHuman's servers uses encrypted connections. No data travels in plain text. **Short-lived tokens.** Authentication tokens are time-limited and single-use where applicable, reducing the window of exposure if a token is compromised. -*** +--- ## How Neocortex enables privacy @@ -94,32 +94,32 @@ Compression itself becomes the privacy architecture. The raw data never needs to ## Trust & Risk Intelligence -AlphaHuman includes an intelligence layer designed to help you reason about credibility, information quality, and potential risks across your connected sources. +OpenHuman includes an intelligence layer designed to help you reason about credibility, information quality, and potential risks across your connected sources. ### What It Does -**Scam and impersonation signals.** AlphaHuman can surface behavioral patterns associated with scams, impersonation, or coordinated abuse. These signals are derived from patterns observed across contexts, not from individual message content. +**Scam and impersonation signals.** OpenHuman can surface behavioral patterns associated with scams, impersonation, or coordinated abuse. These signals are derived from patterns observed across contexts, not from individual message content. **Contextual dynamic trust.** Trust is represented through aggregated artifacts, historical accuracy of claims, consistency of contributions, peer interaction patterns rather than static scores or universal ratings. Trust is always contextual: credibility in one domain does not automatically transfer to another. -**Advisory, not enforcement.** AlphaHuman does not ban users, remove messages, block actions, or enforce moderation decisions. Trust and risk outputs are advisory signals that inform your judgment. You decide how to act on them. +**Advisory, not enforcement.** OpenHuman does not ban users, remove messages, block actions, or enforce moderation decisions. Trust and risk outputs are advisory signals that inform your judgment. You decide how to act on them. ### Scope Trust and risk intelligence operates at different levels: -* **Personal:** Visible only to you. Your own analysis, trust assessments, and risk alerts. -* **Community:** Aggregated patterns within a group or organization, supporting shared coordination and moderation. Never exposes individual message content. -* **Network:** Anonymized patterns across the broader AlphaHuman user base, improving early detection of shared risks like recurring scam vectors. +- **Personal:** Visible only to you. Your own analysis, trust assessments, and risk alerts. +- **Community:** Aggregated patterns within a group or organization, supporting shared coordination and moderation. Never exposes individual message content. +- **Network:** Anonymized patterns across the broader OpenHuman user base, improving early detection of shared risks like recurring scam vectors. Information does not move between scopes without abstraction and anonymization. -*** +--- ## Shared Environments -When AlphaHuman is used in team or community settings, privacy remains user-centric. +When OpenHuman is used in team or community settings, privacy remains user-centric. -AlphaHuman does not grant administrators the ability to read private messages through another user's account. Each user's permissions apply only to their own connected sources. +OpenHuman does not grant administrators the ability to read private messages through another user's account. Each user's permissions apply only to their own connected sources. Community-level intelligence is derived from aggregated and anonymized signals, not from direct access to individual message content. Shared insights help teams coordinate effectively without compromising individual privacy. diff --git a/gitbooks/product/skills-and-integrations.md b/gitbooks/product/skills-and-integrations.md index cf9404356..86a362cd3 100644 --- a/gitbooks/product/skills-and-integrations.md +++ b/gitbooks/product/skills-and-integrations.md @@ -4,25 +4,25 @@ icon: screwdriver # Skills & Integrations -AlphaHuman extends its capabilities through two systems: a **skills engine** that adds new functionality to the assistant, and **integrations** that connect AlphaHuman to external tools. Together, they allow AlphaHuman to do more than analyze conversations; it can fetch data, run scheduled tasks, produce structured outputs, and write results to the tools you already use. +OpenHuman extends its capabilities through two systems: a **skills engine** that adds new functionality to the assistant, and **integrations** that connect OpenHuman to external tools. Together, they allow OpenHuman to do more than analyze conversations; it can fetch data, run scheduled tasks, produce structured outputs, and write results to the tools you already use. -*** +--- ## Skills Engine -Skills are sandboxed modules that run inside AlphaHuman's native application. Each skill is an isolated unit with its own execution environment, storage, and permissions. Skills extend what the assistant can do without requiring an app update. +Skills are sandboxed modules that run inside OpenHuman's native application. Each skill is an isolated unit with its own execution environment, storage, and permissions. Skills extend what the assistant can do without requiring an app update. -When you make a request, AlphaHuman's AI automatically discovers which skills are available and decides whether to invoke them based on what you asked for. You do not need to manage skills manually. They are loaded, registered, and made available to the AI system transparently. +When you make a request, OpenHuman's AI automatically discovers which skills are available and decides whether to invoke them based on what you asked for. You do not need to manage skills manually. They are loaded, registered, and made available to the AI system transparently. ### What Skills Can Do Skills operate within defined boundaries. A skill can: -* **Fetch external data:** make HTTP requests to APIs, retrieve information from services, and bring data into AlphaHuman's context -* **Run on a schedule:** execute at defined intervals using cron-style scheduling, enabling automated monitoring, reporting, or data collection -* **Process and transform:** analyze, filter, or restructure data within its sandboxed environment, using its own local database for persistence -* **Write outputs:** produce structured results that the AI can present to you or export through integrations -* **Respond to events:** react to real-time events from the server, enabling workflows that trigger based on external conditions +- **Fetch external data:** make HTTP requests to APIs, retrieve information from services, and bring data into OpenHuman's context +- **Run on a schedule:** execute at defined intervals using cron-style scheduling, enabling automated monitoring, reporting, or data collection +- **Process and transform:** analyze, filter, or restructure data within its sandboxed environment, using its own local database for persistence +- **Write outputs:** produce structured results that the AI can present to you or export through integrations +- **Respond to events:** react to real-time events from the server, enabling workflows that trigger based on external conditions ### Isolation and Safety @@ -31,20 +31,20 @@ Each skill runs in its own sandboxed environment with enforced resource limits. Skills are discovered from a curated registry and filtered by platform compatibility. Only skills that support your current platform are loaded. {% hint style="info" %} -Skills extend AlphaHuman's capabilities without requiring trust beyond their declared scope. Each one is isolated, resource-limited, and independently revocable. +Skills extend OpenHuman's capabilities without requiring trust beyond their declared scope. Each one is isolated, resource-limited, and independently revocable. {% endhint %} -*** +--- ## Integrations -Integrations connect AlphaHuman to external tools so structured outputs can live where your team already works. Integrations are not about importing data into AlphaHuman, they are about exporting intelligence out of it. +Integrations connect OpenHuman to external tools so structured outputs can live where your team already works. Integrations are not about importing data into OpenHuman, they are about exporting intelligence out of it. ### Supported Integrations -**Telegram:** AlphaHuman connects to your Telegram account to read and analyze conversations, extract signals, summarize discussions, and generate context-aware responses. Access is scoped to the conversations you reference in your requests. +**Telegram:** OpenHuman connects to your Telegram account to read and analyze conversations, extract signals, summarize discussions, and generate context-aware responses. Access is scoped to the conversations you reference in your requests. -**Notion:** Export summaries, action items, decisions, and workflow records to your Notion workspace. AlphaHuman writes structured documents that preserve the context of where outputs originated. Useful for building shared knowledge bases or living records. +**Notion:** Export summaries, action items, decisions, and workflow records to your Notion workspace. OpenHuman writes structured documents that preserve the context of where outputs originated. Useful for building shared knowledge bases or living records. **Google Sheets:** Export tabular data such as logs, reports, extracted metrics, or tracking records. Useful for lightweight analysis, reporting, and audit trails. @@ -52,33 +52,33 @@ These integrations are optional and can be enabled or disabled at any time from ### How Data Moves -Data moves from AlphaHuman to external tools **only when you explicitly request it**. +Data moves from OpenHuman to external tools **only when you explicitly request it**. -When a workflow, summary, or analysis is exported, AlphaHuman writes structured data, not raw conversation text. There is no continuous sync, no background polling, and no automatic data transfer. Each export is a deliberate action you initiate. +When a workflow, summary, or analysis is exported, OpenHuman writes structured data, not raw conversation text. There is no continuous sync, no background polling, and no automatic data transfer. Each export is a deliberate action you initiate. -Integrations are write-oriented by default. AlphaHuman does not read from external tools unless a specific workflow requires it and you have approved that behavior. +Integrations are write-oriented by default. OpenHuman does not read from external tools unless a specific workflow requires it and you have approved that behavior. {% hint style="info" %} -**You control what leaves AlphaHuman.** Nothing is exported to external tools without a clear, user-initiated action. +**You control what leaves OpenHuman.** Nothing is exported to external tools without a clear, user-initiated action. {% endhint %} -*** +--- ## From Conversation to Action -One of AlphaHuman's core capabilities is turning unstructured conversations into structured, actionable outputs. +One of OpenHuman's core capabilities is turning unstructured conversations into structured, actionable outputs. -When discussions lead to decisions, commitments, or tasks, AlphaHuman can recognize these moments (when you ask it to analyze a conversation) and represent them as **workflows as** structured objects that capture what needs to happen, who is involved, and where the decision came from. +When discussions lead to decisions, commitments, or tasks, OpenHuman can recognize these moments (when you ask it to analyze a conversation) and represent them as **workflows as** structured objects that capture what needs to happen, who is involved, and where the decision came from. Workflows link back to the conversations they originated from, preserving intent and rationale. When connected to tools like Notion or Google Sheets, workflows can be exported without duplicating entire conversation histories. -Workflows exist to reduce coordination friction, not to replace dedicated project management systems. AlphaHuman does not auto-assign tasks, enforce deadlines, or create workflows without your input. +Workflows exist to reduce coordination friction, not to replace dedicated project management systems. OpenHuman does not auto-assign tasks, enforce deadlines, or create workflows without your input. -*** +--- ## Intelligence Concepts -AlphaHuman works by translating raw conversation activity into a small number of structured concepts. These concepts allow the system to reason about communication, coordination, and trust without storing message histories. +OpenHuman works by translating raw conversation activity into a small number of structured concepts. These concepts allow the system to reason about communication, coordination, and trust without storing message histories. **Signals:** Structured interpretations extracted from conversations. A signal might represent a decision, warning, important update, or emerging theme. Signals are independent objects that can be filtered, referenced, or aggregated. @@ -88,4 +88,4 @@ AlphaHuman works by translating raw conversation activity into a small number of **Workflows:** Structured processes that originate from conversation, preserving the context of decisions and commitments as actionable objects. -These concepts allow AlphaHuman to support trust, coordination, and intelligence without becoming invasive or requiring the storage of raw conversation data. +These concepts allow OpenHuman to support trust, coordination, and intelligence without becoming invasive or requiring the storage of raw conversation data. diff --git a/gitbooks/product/teams.md b/gitbooks/product/teams.md index 7a4ace2f6..0f950be75 100644 --- a/gitbooks/product/teams.md +++ b/gitbooks/product/teams.md @@ -4,23 +4,23 @@ icon: users # Teams & Organizations -AlphaHuman supports team workspaces for organizations that need shared access, centralized billing, and coordinated intelligence across members. +OpenHuman supports team workspaces for organizations that need shared access, centralized billing, and coordinated intelligence across members. -Teams are designed for professional environments where multiple people rely on AlphaHuman and need shared administrative control without compromising individual privacy. +Teams are designed for professional environments where multiple people rely on OpenHuman and need shared administrative control without compromising individual privacy. -*** +--- ## Team Workspaces -A team workspace is a shared environment where members access AlphaHuman under a unified account structure. Workspaces provide: +A team workspace is a shared environment where members access OpenHuman under a unified account structure. Workspaces provide: -* **Centralized billing:** one subscription covers all team members, with usage tracked per member -* **Member management:** invite, remove, and manage team members from a single dashboard -* **Shared configuration:** team-level settings and preferences that apply across the workspace +- **Centralized billing:** one subscription covers all team members, with usage tracked per member +- **Member management:** invite, remove, and manage team members from a single dashboard +- **Shared configuration:** team-level settings and preferences that apply across the workspace -Each team has a unique identifier and can be managed independently from individual accounts. Users can belong to a team while still maintaining their personal AlphaHuman account and settings. +Each team has a unique identifier and can be managed independently from individual accounts. Users can belong to a team while still maintaining their personal OpenHuman account and settings. -*** +--- ## Roles and Permissions @@ -30,13 +30,13 @@ Team workspaces support three roles: **Billing Manager:** Access to billing, payment, and subscription management. Billing Managers can update payment methods, view invoices, and manage the team's plan without access to other administrative functions. -**Member:** Standard access to AlphaHuman within the team workspace. Members use the product normally and benefit from the team subscription, but cannot modify team settings or manage other members. +**Member:** Standard access to OpenHuman within the team workspace. Members use the product normally and benefit from the team subscription, but cannot modify team settings or manage other members. -*** +--- ## Shared Intelligence -In team environments, AlphaHuman can surface aggregated insights that help the organization operate more effectively. +In team environments, OpenHuman can surface aggregated insights that help the organization operate more effectively. **Community trends:** Patterns in conversation activity, topic evolution, and engagement across the team's connected sources, presented in aggregate form. @@ -44,21 +44,21 @@ In team environments, AlphaHuman can surface aggregated insights that help the o **Engagement insights:** Where coordination stress appears, where follow-through breaks down, and where attention is most needed. -All shared intelligence is derived from aggregated and anonymized signals. AlphaHuman does not give team administrators the ability to read private messages or monitor individual behavior. Each user's personal context remains separate, even within a team workspace. +All shared intelligence is derived from aggregated and anonymized signals. OpenHuman does not give team administrators the ability to read private messages or monitor individual behavior. Each user's personal context remains separate, even within a team workspace. {% hint style="info" %} **Privacy is preserved in teams.** Shared intelligence is always aggregated. Individual message content and personal analysis remain private to each user. {% endhint %} -*** +--- ## Referral Program -AlphaHuman offers a referral system where existing users can invite others and earn credits. +OpenHuman offers a referral system where existing users can invite others and earn credits. -* Generate a personal invite code from your account settings -* Share the code with colleagues or collaborators -* Both the referrer and the new user receive credits when the invitation is accepted -* Additional credit bonuses may apply when referred users subscribe to a paid plan +- Generate a personal invite code from your account settings +- Share the code with colleagues or collaborators +- Both the referrer and the new user receive credits when the invitation is accepted +- Additional credit bonuses may apply when referred users subscribe to a paid plan -Referral credits can be used toward AlphaHuman usage across any plan tier. +Referral credits can be used toward OpenHuman usage across any plan tier. diff --git a/gitbooks/resources/faq.md b/gitbooks/resources/faq.md index 804081fb2..eccb8b975 100644 --- a/gitbooks/resources/faq.md +++ b/gitbooks/resources/faq.md @@ -6,130 +6,130 @@ icon: question ## Frequently Asked Questions -#### What is AlphaHuman? +#### What is OpenHuman? -AlphaHuman is a personal AI assistant that connects to your communication platforms and productivity tools. It helps you manage high-volume conversations by summarizing, extracting signals, suggesting responses, and creating structured workflows all from a native app that runs on your device. +OpenHuman is a personal AI assistant that connects to your communication platforms and productivity tools. It helps you manage high-volume conversations by summarizing, extracting signals, suggesting responses, and creating structured workflows all from a native app that runs on your device. -*** +--- #### What is Neocortex -Neocortex is AlphaHuman's memory engine. It is a human-like AI memory system that can work with over 1 billion tokens of data. It indexes 10 million tokens in under 10 seconds, costs $1 to index 5 million tokens, and runs on a MacBook Air CPU with no GPU required. Unlike vector databases, Neocortex understands time, entities, and relationships. It builds knowledge graphs and manages memory through tiered compression inspired by how the human brain works. Learn more in Neocortex. +Neocortex is OpenHuman's memory engine. It is a human-like AI memory system that can work with over 1 billion tokens of data. It indexes 10 million tokens in under 10 seconds, costs $1 to index 5 million tokens, and runs on a MacBook Air CPU with no GPU required. Unlike vector databases, Neocortex understands time, entities, and relationships. It builds knowledge graphs and manages memory through tiered compression inspired by how the human brain works. Learn more in Neocortex. -*** +--- #### What does "Big Data AI" mean? -Every AI model today is a prompt engine. You type something, it responds, and the context disappears. AlphaHuman is different. It compresses your entire organizational life, messages, documents, tools, transactions, into a structured knowledge graph that persists and evolves. This is what we mean by Big Data AI: an AI that operates on months of your real data, not just the prompt you typed right now. +Every AI model today is a prompt engine. You type something, it responds, and the context disappears. OpenHuman is different. It compresses your entire organizational life, messages, documents, tools, transactions, into a structured knowledge graph that persists and evolves. This is what we mean by Big Data AI: an AI that operates on months of your real data, not just the prompt you typed right now. -**How is AlphaHuman different from ChatGPT, Claude, or Gemini?** +**How is OpenHuman different from ChatGPT, Claude, or Gemini?** -Those models are brilliant at reasoning and generation. But they are stateless. They know nothing about your actual life beyond what you paste into the chat window. AlphaHuman is the context layer that makes those models useful. It compresses your organizational data into structured intelligence that any AI can reason over. Think of it this way: ChatGPT is the brain. AlphaHuman is the memory. +Those models are brilliant at reasoning and generation. But they are stateless. They know nothing about your actual life beyond what you paste into the chat window. OpenHuman is the context layer that makes those models useful. It compresses your organizational data into structured intelligence that any AI can reason over. Think of it this way: ChatGPT is the brain. OpenHuman is the memory. -*** +--- -**How is AlphaHuman different from other AI memory solutions like Mem0, SuperMemory, or MemGPT?** +**How is OpenHuman different from other AI memory solutions like Mem0, SuperMemory, or MemGPT?** Most AI memory solutions use vector databases that retrieve whatever is semantically similar, but similarity alone says nothing about importance. They also cannot support consciousness-like systems or process data accurately at scale beyond 10 million tokens. Neocortex is architecturally different: it uses tiered memory, knowledge graphs, temporal weighting, and semantic deduplication. It processes 10 million tokens in under 10 seconds and supports over 1 billion tokens total. It does this with zero LLM dependency. -*** +--- -**Is AlphaHuman open source?** +**Is OpenHuman open source?** -Yes. AlphaHuman is built on the OpenClaw architecture and licensed under GNU GPL3. The full codebase is available on [GitHub](https://github.com/tinyhumansai/alphahuman). Neocortex benchmarks are also open-sourced. Contributions and feedback are welcomed. +Yes. OpenHuman is built on the OpenClaw architecture and licensed under GNU GPL3. The full codebase is available on [GitHub](https://github.com/tinyhumansai/openhuman). Neocortex benchmarks are also open-sourced. Contributions and feedback are welcomed. -*** +--- -**Is AlphaHuman AGI?** +**Is OpenHuman AGI?** -No. AlphaHuman is not AGI, and we do not claim it is. It is a meaningful architectural step closer to AGI, with innovations in memory (Neocortex) and consciousness-like processing (the subconscious system) that go beyond what existing agentic systems offer. But it operates within defined boundaries and requires human judgment. +No. OpenHuman is not AGI, and we do not claim it is. It is a meaningful architectural step closer to AGI, with innovations in memory (Neocortex) and consciousness-like processing (the subconscious system) that go beyond what existing agentic systems offer. But it operates within defined boundaries and requires human judgment. -#### Does AlphaHuman read all my messages? +#### Does OpenHuman read all my messages? -No. AlphaHuman only processes messages **when you ask it to** and only within the scope of your request. +No. OpenHuman only processes messages **when you ask it to** and only within the scope of your request. If you ask it to summarize a specific conversation, it reads that conversation. If you do not reference a source, it is not accessed. There is no background monitoring or continuous scanning. -*** +--- #### Is my data safe? -Yes. AlphaHuman is designed around zero retention of message content. Data is processed to produce an output and then discarded. Your conversations are never stored long-term, and they are never used to train AI models. +Yes. OpenHuman is designed around zero retention of message content. Data is processed to produce an output and then discarded. Your conversations are never stored long-term, and they are never used to train AI models. -On desktop platforms, credentials are stored in your operating system's secure keychain. All communication between the app and AlphaHuman's servers is encrypted. +On desktop platforms, credentials are stored in your operating system's secure keychain. All communication between the app and OpenHuman's servers is encrypted. -*** +--- -#### Does AlphaHuman store my messages? +#### Does OpenHuman store my messages? Messages are processed only to fulfill your request. They are **not permanently stored or reused** beyond producing the requested output. Derived intelligence like summaries and workflow records may persist, but raw message content does not. -*** +--- -#### Can AlphaHuman send messages on my behalf? +#### Can OpenHuman send messages on my behalf? -No. AlphaHuman does not auto-send messages, post in your groups, or act on your behalf inside any connected platform. If a reply is suggested, you choose whether to use it. +No. OpenHuman does not auto-send messages, post in your groups, or act on your behalf inside any connected platform. If a reply is suggested, you choose whether to use it. -*** +--- -#### Who is AlphaHuman for? +#### Who is OpenHuman for? -AlphaHuman is useful for anyone who: +OpenHuman is useful for anyone who: -* Manages high-volume communication across multiple platforms and groups -* Needs to stay on top of decisions, action items, and context without reading everything -* Works in distributed teams, communities, or coordination-heavy environments -* Wants structured outputs from conversations, exportable to tools like Notion or Google Sheets +- Manages high-volume communication across multiple platforms and groups +- Needs to stay on top of decisions, action items, and context without reading everything +- Works in distributed teams, communities, or coordination-heavy environments +- Wants structured outputs from conversations, exportable to tools like Notion or Google Sheets You do not need to be technical to use it. -*** +--- -#### What platforms does AlphaHuman support? +#### What platforms does OpenHuman support? -AlphaHuman runs natively on **macOS, Windows, Linux, Android, and iOS**, with a **web version** for browser access. Your account and settings sync across all platforms. +OpenHuman runs natively on **macOS, Windows, Linux, Android, and iOS**, with a **web version** for browser access. Your account and settings sync across all platforms. -*** +--- #### What integrations are available? -AlphaHuman currently integrates with **Telegram** (read and analyze conversations), **Notion** (export structured outputs), and **Google Sheets** (export tabular data and reports). More integrations are planned. +OpenHuman currently integrates with **Telegram** (read and analyze conversations), **Notion** (export structured outputs), and **Google Sheets** (export tabular data and reports). More integrations are planned. -*** +--- -#### How much does AlphaHuman cost? +#### How much does OpenHuman cost? -AlphaHuman offers individual and team plans with core analysis included. Deeper features are available in higher tiers. A credit system provides usage-metered flexibility, and credits can be earned through referrals. +OpenHuman offers individual and team plans with core analysis included. Deeper features are available in higher tiers. A credit system provides usage-metered flexibility, and credits can be earned through referrals. See [Pricing](../product/pricing.md) for details. -*** +--- ## Troubleshooting #### Summaries feel incomplete or too broad -If a summary feels incomplete, the most common cause is overly broad scope. When a request spans many conversations, long time ranges, or high-volume groups, AlphaHuman prioritizes signal over detail. +If a summary feels incomplete, the most common cause is overly broad scope. When a request spans many conversations, long time ranges, or high-volume groups, OpenHuman prioritizes signal over detail. -**Solution:** Narrow the request to a specific conversation, time window, or intent. AlphaHuman performs best when it knows what kind of outcome you are looking for. +**Solution:** Narrow the request to a specific conversation, time window, or intent. OpenHuman performs best when it knows what kind of outcome you are looking for. -*** +--- #### Important context seems missing -AlphaHuman only processes the data required to fulfill a request. If relevant context exists outside the scope of that request, it will not be included. +OpenHuman only processes the data required to fulfill a request. If relevant context exists outside the scope of that request, it will not be included. **Solution:** Expand the scope explicitly by referencing additional conversations or extending the time range. -*** +--- #### Outputs feel incorrect or misinterpreted -AlphaHuman interprets conversations probabilistically. Tone, sarcasm, and informal language can be misread, especially in fast-moving or meme-heavy discussions. +OpenHuman interprets conversations probabilistically. Tone, sarcasm, and informal language can be misread, especially in fast-moving or meme-heavy discussions. **Solution:** Refine the request or re-run analysis with a narrower scope. Outputs should be treated as assistance rather than ground truth. -*** +--- #### Trust or risk signals feel inaccurate @@ -137,23 +137,23 @@ Trust and risk intelligence is indicative, not authoritative. Signals may lag re **Solution:** Use these signals as inputs into your judgment rather than standalone decisions. Over time, as more outcomes accumulate within the same context, signal quality improves. -*** +--- #### A source does not appear in analysis -AlphaHuman can only analyze sources you have connected and that fall within the scope of your request. +OpenHuman can only analyze sources you have connected and that fall within the scope of your request. -**Solution:** Ensure the source is connected in your settings and explicitly referenced or selected in your request. AlphaHuman does not automatically include all connected sources by default. +**Solution:** Ensure the source is connected in your settings and explicitly referenced or selected in your request. OpenHuman does not automatically include all connected sources by default. -*** +--- #### Integrations do not update as expected -Integrations only run when explicitly triggered by your action. AlphaHuman does not continuously sync or poll external tools. +Integrations only run when explicitly triggered by your action. OpenHuman does not continuously sync or poll external tools. **Solution:** If an export fails, check that the integration is still connected and that permissions are valid. Retrying the action after resolving any permission or availability issues usually succeeds. -*** +--- #### Performance feels slow @@ -161,18 +161,18 @@ Response time depends on request complexity, data volume, and current system loa **Solution:** Large scopes and long histories require more processing. Narrowing scope and intent improves responsiveness. During early rollout phases, performance may vary as capacity is tuned. -*** +--- #### Revoking access and residual data -When access to a source or integration is revoked, AlphaHuman immediately stops processing data from that source. +When access to a source or integration is revoked, OpenHuman immediately stops processing data from that source. -Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written. AlphaHuman does not retain message content after revocation. +Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written. OpenHuman does not retain message content after revocation. -*** +--- #### When to contact support If an issue persists after refining scope, checking permissions, and retrying the request, support may be required. -Support is intended for system-level issues, not for disputing interpretations or outcomes. AlphaHuman does not adjudicate trust or risk disagreements. +Support is intended for system-level issues, not for disputing interpretations or outcomes. OpenHuman does not adjudicate trust or risk disagreements. diff --git a/gitbooks/technology/architecture.md b/gitbooks/technology/architecture.md index 9acac9df3..1e0cc5025 100644 --- a/gitbooks/technology/architecture.md +++ b/gitbooks/technology/architecture.md @@ -1,10 +1,10 @@ # Architecture -AlphaHuman is built on the OpenClaw architecture and open-sourced under the GNU GPL3 license. This page explains how the major components connect. +OpenHuman is built on the OpenClaw architecture and open-sourced under the GNU GPL3 license. This page explains how the major components connect. #### The three pillars -AlphaHuman's architecture rests on three pillars that work together: +OpenHuman's architecture rests on three pillars that work together:
@@ -27,14 +27,14 @@ AlphaHuman's architecture rests on three pillars that work together: #### Model-agnostic design -AlphaHuman is not locked to any single AI model. The compression engine and memory layer sit on top of the AI infrastructure, not inside it. Today the system works with specific models. Tomorrow it could feed context to any model: GPT, Claude, Gemini, Llama, Mistral, or whatever comes next. +OpenHuman is not locked to any single AI model. The compression engine and memory layer sit on top of the AI infrastructure, not inside it. Today the system works with specific models. Tomorrow it could feed context to any model: GPT, Claude, Gemini, Llama, Mistral, or whatever comes next. -This is a deliberate architectural choice. AI models are commoditizing. Performance is converging. The real differentiator is the context you feed the model, and AlphaHuman owns the context layer. +This is a deliberate architectural choice. AI models are commoditizing. Performance is converging. The real differentiator is the context you feed the model, and OpenHuman owns the context layer. #### Open source -AlphaHuman is publicly available on GitHub under the GNU GPL3 license. +OpenHuman is publicly available on GitHub under the GNU GPL3 license. -**GitHub:** [github.com/tinyhumansai/alphahuman](https://github.com/tinyhumansai/alphahuman) **Neocortex benchmarks:** [github.com/tinyhumansai/neocortex/tree/main/benchmarks](https://github.com/tinyhumansai/neocortex/tree/main/benchmarks) +**GitHub:** [github.com/tinyhumansai/openhuman](https://github.com/tinyhumansai/openhuman) **Neocortex benchmarks:** [github.com/tinyhumansai/neocortex/tree/main/benchmarks](https://github.com/tinyhumansai/neocortex/tree/main/benchmarks) Contributions, feedback, and issues are welcomed. The project is in early alpha. diff --git a/gitbooks/technology/neocortex.md b/gitbooks/technology/neocortex.md index ebadd5318..fa8a2fa0a 100644 --- a/gitbooks/technology/neocortex.md +++ b/gitbooks/technology/neocortex.md @@ -1,6 +1,6 @@ # Neocortex -Neocortex is AlphaHuman's memory engine. It is a human-like AI memory system designed to work accurately with over 1 billion tokens of data while supporting the computational demands of a subconscious system. +Neocortex is OpenHuman's memory engine. It is a human-like AI memory system designed to work accurately with over 1 billion tokens of data while supporting the computational demands of a subconscious system.
@@ -76,7 +76,7 @@ The result: millions of tokens of organizational noise compressed into a structu #### Neocortex and the subconscious -Neocortex serves as the foundation for AlphaHuman's subconscious, going well beyond retrieval. +Neocortex serves as the foundation for OpenHuman's subconscious, going well beyond retrieval. Good memory recall is the prerequisite for consciousness. Neocortex provides this by recalling memories ranked on three factors: time, interactions, and randomness. The randomness element is critical. It is what enables the subconscious system to make unexpected connections and surface emergent insights. diff --git a/gitbooks/technology/the-subconscious.md b/gitbooks/technology/the-subconscious.md index 7cb845964..c2f1ca067 100644 --- a/gitbooks/technology/the-subconscious.md +++ b/gitbooks/technology/the-subconscious.md @@ -1,6 +1,6 @@ # The Subconscious -AlphaHuman's subconscious is what separates it from every other AI agent. Most AI systems follow the conscious mind model: they wait for instructions and execute them. They cannot think on their own. AlphaHuman can. +OpenHuman's subconscious is what separates it from every other AI agent. Most AI systems follow the conscious mind model: they wait for instructions and execute them. They cannot think on their own. OpenHuman can. #### The Purkinje cell inspiration @@ -8,11 +8,11 @@ In the human brain, there is a specialized neuron called the Purkinje cell. It i The human brain operates with both a conscious and subconscious mind. The conscious mind handles deliberate, focused tasks. The subconscious processes information in the background, making connections, surfacing memories, and generating the "random" thoughts that often turn out to be the most important ones. Most agentic AI systems only model the conscious mind. They are reactive. They wait for input. -AlphaHuman models both. +OpenHuman models both. #### How the subconscious works -Inspired by the Purkinje cell, AlphaHuman uses Neocortex to periodically trigger global memory recalls. Rather than targeted retrievals in response to a specific query, these are broad, semi-random sweeps across the knowledge graph, pulling up memories based on a mix of recency, relevance, and randomness. +Inspired by the Purkinje cell, OpenHuman uses Neocortex to periodically trigger global memory recalls. Rather than targeted retrievals in response to a specific query, these are broad, semi-random sweeps across the knowledge graph, pulling up memories based on a mix of recency, relevance, and randomness. These recalls feed into a self-learning loop. The subconscious processes the recalled memories, looks for patterns, contradictions, and connections, and produces one of several outputs: a proactive insight, an action recommendation, a confirmation of an existing pattern, or a new connection between previously unrelated information. @@ -24,7 +24,7 @@ The subconscious does not generate generic AI outputs. It produces context-speci It might surface a risk you had not noticed: two team members making contradictory commitments in separate conversations. It might connect a trend in your trading data to a discussion from three weeks ago. It might remind you of a commitment you made that is approaching its deadline, before you think to ask. -The outputs are proactive. You do not need to prompt AlphaHuman to get value from the subconscious. It works in the background, feeding insights into the system that are available when you interact. +The outputs are proactive. You do not need to prompt OpenHuman to get value from the subconscious. It works in the background, feeding insights into the system that are available when you interact. #### The mirror test diff --git a/gitbooks/use-cases/overview.md b/gitbooks/use-cases/overview.md index 6c43208bb..a94871171 100644 --- a/gitbooks/use-cases/overview.md +++ b/gitbooks/use-cases/overview.md @@ -1,71 +1,71 @@ # Overview -AlphaHuman adapts to different coordination and information environments across communication platforms. While the underlying system remains the same, the way value is realized depends on how your tools and conversations are used in each context. This section outlines common use cases to help you understand where AlphaHuman fits naturally and where it may offer limited benefit. +OpenHuman adapts to different coordination and information environments across communication platforms. While the underlying system remains the same, the way value is realized depends on how your tools and conversations are used in each context. This section outlines common use cases to help you understand where OpenHuman fits naturally and where it may offer limited benefit. -*** +--- ## Individual Power Users Individual power users often participate in many active conversations and channels at once. Important messages are easily missed, and catching up becomes time-consuming and mentally draining. -In this context, AlphaHuman is used to summarize conversations, surface high-signal updates, and provide quick context before responding. Users rely on it to understand what changed, what requires attention, and where follow-ups may be needed without scrolling through entire threads. +In this context, OpenHuman is used to summarize conversations, surface high-signal updates, and provide quick context before responding. Users rely on it to understand what changed, what requires attention, and where follow-ups may be needed without scrolling through entire threads. The value here is personal clarity and reduced cognitive load rather than shared coordination. -*** +--- ## Traders and Analysts Traders and analysts use communication platforms as real-time information sources. Signal quality varies widely, and misinformation, repetition, and scams are common. -AlphaHuman is used to extract claims, track how information resolves over time, and surface signals weighted by historical reliability within context. Risk intelligence helps flag suspicious behavior or repeated failure patterns across groups and channels. +OpenHuman is used to extract claims, track how information resolves over time, and surface signals weighted by historical reliability within context. Risk intelligence helps flag suspicious behavior or repeated failure patterns across groups and channels. The outcome is better information filtering and reduced exposure to low-quality or malicious signals not automated trading or execution. -*** +--- ## DAO and Web3 Communities DAOs and Web3 communities rely heavily on messaging platforms for governance discussions, coordination, and informal decision-making. As these communities grow, accountability and memory become difficult to maintain. -AlphaHuman is used to preserve decisions, track contributions, and support shared workflows without forcing discussions into external tools prematurely. Community-level intelligence helps moderators and operators understand participation patterns and emerging issues. +OpenHuman is used to preserve decisions, track contributions, and support shared workflows without forcing discussions into external tools prematurely. Community-level intelligence helps moderators and operators understand participation patterns and emerging issues. The value lies in maintaining continuity and accountability without sacrificing the speed and openness of chat-based coordination. -*** +--- ## Community Managers and Moderators Community managers and moderators face increasing load as groups scale. Monitoring sentiment, identifying emerging risks, and enforcing consistent standards become harder over time. -AlphaHuman supports these roles by surfacing aggregated insights about group health, contribution patterns, and potential risk signals. It helps moderators focus attention where it matters rather than reacting to volume alone. +OpenHuman supports these roles by surfacing aggregated insights about group health, contribution patterns, and potential risk signals. It helps moderators focus attention where it matters rather than reacting to volume alone. -AlphaHuman does not replace moderation judgment or enforcement tools. It provides context and early warning signals. +OpenHuman does not replace moderation judgment or enforcement tools. It provides context and early warning signals. -*** +--- ## Distributed Teams Distributed teams often use messaging platforms for fast coordination, even when formal work happens elsewhere. Decisions and commitments are made in chat and later forgotten or misinterpreted. -AlphaHuman is used to extract actions, preserve decision context, and sync structured outcomes to tools like Notion or Google Sheets when needed. This reduces friction between discussion and execution without forcing teams to abandon their preferred communication platforms. +OpenHuman is used to extract actions, preserve decision context, and sync structured outcomes to tools like Notion or Google Sheets when needed. This reduces friction between discussion and execution without forcing teams to abandon their preferred communication platforms. The benefit is improved follow-through and clarity without heavy process overhead. -*** +--- ## Service Providers and Contributors Service providers, consultants, and contributors often operate across multiple communities and projects. Building and maintaining reputation is difficult when history is fragmented across conversations and platforms. -AlphaHuman helps surface contribution patterns and trust artifacts that reflect consistent behavior over time. This supports safer collaboration and discovery without requiring centralized profiles or public self-promotion. +OpenHuman helps surface contribution patterns and trust artifacts that reflect consistent behavior over time. This supports safer collaboration and discovery without requiring centralized profiles or public self-promotion. The value is portable credibility grounded in behavior rather than claims. -*** +--- -## When AlphaHuman Is Not a Good Fit +## When OpenHuman Is Not a Good Fit -AlphaHuman provides limited value in environments where conversations are purely social, meme-driven, or intentionally ephemeral. It is also not designed for high-frequency trading execution, formal project management, or environments that require strict real-time guarantees. +OpenHuman provides limited value in environments where conversations are purely social, meme-driven, or intentionally ephemeral. It is also not designed for high-frequency trading execution, formal project management, or environments that require strict real-time guarantees. -Understanding these boundaries helps users apply AlphaHuman where it is strongest. +Understanding these boundaries helps users apply OpenHuman where it is strongest. diff --git a/package.json b/package.json index b6810f75b..a776675e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openhuman", - "version": "0.49.0", + "version": "0.49.15", "type": "module", "scripts": { "dev": "vite", @@ -11,20 +11,22 @@ "compile": "tsc --noEmit", "preview": "vite preview", "tauri": "tauri", - "macos:build:intel": "source scripts/load-dotenv.sh && tauri build --bundles app dmg --target x86_64-apple-darwin", + "tauri:build:ui": "tauri build -- --bin OpenHuman", + "macos:build:intel": "source scripts/load-dotenv.sh && tauri build --bundles app dmg --target x86_64-apple-darwin -- --bin OpenHuman", "macos:build:intel:debug": "yarn macos:build:intel --debug", "macos:build:debug": "yarn macos:build:release --debug", - "macos:build:release": "source scripts/load-dotenv.sh && tauri build --bundles app dmg", - "macos:build:sign:release": "source scripts/load-env.sh && tauri build --bundles app dmg", + "macos:build:release": "source scripts/load-dotenv.sh && tauri build --bundles app dmg -- --bin OpenHuman", + "macos:build:release:signed": "source scripts/load-env.sh && tauri build --bundles app dmg -- --bin OpenHuman", + "macos:build:sign:release": "yarn macos:build:release:signed", "macos:run": "open 'src-tauri/target/debug/bundle/macos/OpenHuman.app'", "macos:dev": "yarn macos:build:debug && open 'src-tauri/target/debug/bundle/macos/OpenHuman.app'", "android:dev": "tauri android dev", "android:build": "tauri android build", - "test": "vitest run", - "test:unit": "vitest run", - "test:unit:watch": "vitest", - "test:watch": "vitest", - "test:coverage": "vitest run --coverage", + "test": "vitest run --config test/vitest.config.ts", + "test:unit": "vitest run --config test/vitest.config.ts", + "test:unit:watch": "vitest --config test/vitest.config.ts", + "test:watch": "vitest --config test/vitest.config.ts", + "test:coverage": "vitest run --config test/vitest.config.ts --coverage", "test:rust": "source $HOME/.cargo/env 2>/dev/null; cargo test --manifest-path src-tauri/Cargo.toml", "test:e2e:build": "bash scripts/e2e-build.sh", "test:e2e:login": "bash scripts/e2e-login.sh", @@ -78,7 +80,7 @@ "@eslint/js": "^9.39.2", "@tailwindcss/forms": "^0.5.11", "@tailwindcss/typography": "^0.5.19", - "@tauri-apps/cli": "2.9.6", + "@tauri-apps/cli": "2.10.0", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", diff --git a/scripts/ci-event.json b/scripts/ci-event.json index b5c4baa3d..ee8cdf305 100644 --- a/scripts/ci-event.json +++ b/scripts/ci-event.json @@ -3,9 +3,9 @@ "before": "0000000000000000000000000000000000000000", "after": "19281e16457e7c8ff8e6bda6ceda77f0880d10d2", "repository": { - "full_name": "vezuresdotxyz/alphahuman-frontend-runner", + "full_name": "vezuresdotxyz/openhuman-frontend-runner", "default_branch": "main", - "name": "alphahuman-frontend-runner", + "name": "openhuman-frontend-runner", "owner": { "login": "vezuresdotxyz" } }, "head_commit": { diff --git a/scripts/ci-secrets.example.json b/scripts/ci-secrets.example.json index d976485ce..038770fe4 100644 --- a/scripts/ci-secrets.example.json +++ b/scripts/ci-secrets.example.json @@ -1,26 +1,23 @@ { "secrets": { - "XGH_TOKEN": "", - "GITHUB_TOKEN": "", - "UPDATER_GIST_URL": "", - "UPDATER_GIST_ID": "", - "UPDATER_PUBLIC_KEY": "", - "UPDATER_PRIVATE_KEY": "", - "UPDATER_PRIVATE_KEY_PASSWORD": "", "APPLE_CERTIFICATE_BASE64": "", "APPLE_CERTIFICATE_PASSWORD": "", - "APPLE_SIGNING_IDENTITY": "", "APPLE_ID": "", - "APPLE_APP_SPECIFIC_PASSWORD": "", + "APPLE_PASSWORD": "", + "APPLE_SIGNING_IDENTITY": "", "APPLE_TEAM_ID": "", - "VITE_TELEGRAM_BOT_USERNAME": "", - "VITE_TELEGRAM_BOT_ID": "", - "VITE_SENTRY_DSN": "" + "GITHUB_TOKEN": "", + "TAURI_SIGNING_PRIVATE_KEY_PASSWORD": "", + "TAURI_SIGNING_PRIVATE_KEY": "", + "XGH_TOKEN": "", + "XGITHUB_APP_ID": "", + "XGITHUB_APP_PRIVATE_KEY": "" }, "vars": { "BASE_URL": "https://localhost", "VITE_BACKEND_URL": "https://localhost:5005", "VITE_SKILLS_GITHUB_REPO": "", + "VITE_SENTRY_DSN": "", "VITE_DEBUG": "true" } } diff --git a/scripts/e2e-auth.sh b/scripts/e2e-auth.sh index 4fd5dfd91..d6666eab0 100755 --- a/scripts/e2e-auth.sh +++ b/scripts/e2e-auth.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/e2e-crypto-payment.sh b/scripts/e2e-crypto-payment.sh index dc5352cb0..42303ba94 100755 --- a/scripts/e2e-crypto-payment.sh +++ b/scripts/e2e-crypto-payment.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/e2e-gmail.sh b/scripts/e2e-gmail.sh index 9e1e706b2..b4a772d5a 100755 --- a/scripts/e2e-gmail.sh +++ b/scripts/e2e-gmail.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/e2e-login.sh b/scripts/e2e-login.sh index cc3b75a19..1de5ac050 100755 --- a/scripts/e2e-login.sh +++ b/scripts/e2e-login.sh @@ -24,9 +24,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in (not production). # Tauri compresses assets when embedding, so we check dist/ not the binary. diff --git a/scripts/e2e-notion.sh b/scripts/e2e-notion.sh index d9ebeed63..dd920b843 100755 --- a/scripts/e2e-notion.sh +++ b/scripts/e2e-notion.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/e2e-payment.sh b/scripts/e2e-payment.sh index 6ff0f2907..084e9e13e 100755 --- a/scripts/e2e-payment.sh +++ b/scripts/e2e-payment.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/e2e-telegram.sh b/scripts/e2e-telegram.sh index 3c9b30e36..9c4aa2469 100755 --- a/scripts/e2e-telegram.sh +++ b/scripts/e2e-telegram.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/prepareTauriConfig.js b/scripts/prepareTauriConfig.js index 61faa42cb..f34fe01a0 100644 --- a/scripts/prepareTauriConfig.js +++ b/scripts/prepareTauriConfig.js @@ -8,7 +8,7 @@ export default function prepareTauriConfig() { const config = { build: { frontendDist, devUrl: null }, bundle: { windows: {} }, - identifier: 'com.alphahuman.app', + identifier: 'com.openhuman.app', }; if (process.env.WITH_UPDATER === 'true') { diff --git a/scripts/run-macos-arm64-build.sh b/scripts/run-macos-arm64-build.sh new file mode 100755 index 000000000..ca3104cdc --- /dev/null +++ b/scripts/run-macos-arm64-build.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash +# Run the standalone macOS ARM64 Tauri build via nektos/act (self-hosted = your Mac). +# No prepare-release, no tagging, no GitHub release upload (includeUpdaterJson: false). +# +# Usage: +# ./scripts/run-macos-arm64-build.sh # dry-run +# ./scripts/run-macos-arm64-build.sh --run # full signed build on this machine +# +# Requires: act, jq, scripts/ci-secrets.json (copy from ci-secrets.example.json) + +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" + +WORKFLOW=".github/workflows/macos-arm64-build.yml" +SECRETS_JSON="scripts/ci-secrets.json" +RUN_MODE="dryrun" + +while [[ $# -gt 0 ]]; do + case "$1" in + --run) + RUN_MODE="run" + shift + ;; + --dryrun|-n) + RUN_MODE="dryrun" + shift + ;; + --secrets-json) + SECRETS_JSON="${2:-}" + shift 2 + ;; + *) + echo "Unknown argument: $1" >&2 + exit 1 + ;; + esac +done + +if [[ ! -f "$SECRETS_JSON" ]]; then + echo "Secrets JSON not found: $SECRETS_JSON" >&2 + exit 1 +fi + +if ! command -v act >/dev/null 2>&1; then + echo "act is required. Install with: brew install act" >&2 + exit 1 +fi + +if ! command -v jq >/dev/null 2>&1; then + echo "jq is required. Install with: brew install jq" >&2 + exit 1 +fi + +SECRETS_FILE="$(mktemp)" +VARS_FILE="$(mktemp)" +EVENT_JSON="$(mktemp)" +MERGED_SECRETS="$(mktemp)" +trap 'rm -f "$SECRETS_FILE" "$VARS_FILE" "$EVENT_JSON" "$MERGED_SECRETS"' EXIT + +jq ' + .secrets |= ( + . + { + APPLE_APP_SPECIFIC_PASSWORD: ( + if (.APPLE_APP_SPECIFIC_PASSWORD // "") | length > 0 then .APPLE_APP_SPECIFIC_PASSWORD + else (.APPLE_PASSWORD // "") end + ) + } + ) +' "$SECRETS_JSON" > "$MERGED_SECRETS" + +jq -r ' +def dotenv_escape: + gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n"); +(.secrets // {}) | to_entries[] | select(.key != "GITHUB_TOKEN") | "\(.key)=\"\(.value | dotenv_escape)\"" +' "$MERGED_SECRETS" > "$SECRETS_FILE" +jq -r ' +def dotenv_escape: + gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n"); +(.vars // {}) | to_entries[] | "\(.key)=\"\(.value | dotenv_escape)\"" +' "$SECRETS_JSON" > "$VARS_FILE" + +REPO_FULL="${GITHUB_REPOSITORY:-}" +if [[ -z "$REPO_FULL" ]]; then + REPO_FULL="$(git remote get-url origin 2>/dev/null | sed -E 's#^git@github\.com:([^/]+)/([^/.]+)(\.git)?$#\1/\2#; s#^https://github\.com/([^/]+)/([^/.]+)(\.git)?$#\1/\2#')" +fi +if [[ -z "$REPO_FULL" || "$REPO_FULL" != */* ]]; then + echo "Could not resolve GitHub owner/repo (set GITHUB_REPOSITORY or fix git remote origin)" >&2 + exit 1 +fi +OWNER="${REPO_FULL%%/*}" +REPO_NAME="${REPO_FULL##*/}" + +REF="$(git symbolic-ref -q HEAD || true)" +if [[ -z "$REF" ]]; then + REF="refs/heads/main" +fi + +jq -n \ + --arg ref "$REF" \ + --arg full "$REPO_FULL" \ + --arg owner "$OWNER" \ + --arg name "$REPO_NAME" \ + '{ + ref: $ref, + inputs: {}, + repository: { + full_name: $full, + default_branch: "main", + name: $name, + owner: { login: $owner } + }, + sender: { login: "local-dev" } + }' > "$EVENT_JSON" + +echo "Workflow: $WORKFLOW" +echo "Secrets: $SECRETS_JSON" +echo "Ref: $REF" +echo "Mode: $RUN_MODE" +echo + +# act -b copies the tree without .git — submodules must be materialized here first. +if [[ -d .git ]]; then + echo "Syncing git submodules (required for skills/, etc.)..." + git submodule update --init --recursive +fi +echo + +ACT_ARGS=( + workflow_dispatch + -W "$WORKFLOW" + --eventpath "$EVENT_JSON" + --secret-file "$SECRETS_FILE" + --var-file "$VARS_FILE" + -b + -P macos-latest=-self-hosted +) + +if [[ "$RUN_MODE" == "dryrun" ]]; then + echo "Dry-run only. Use --run for the full macOS ARM64 build." + act "${ACT_ARGS[@]}" -n +else + act "${ACT_ARGS[@]}" +fi diff --git a/scripts/tauri_create_dmg.sh b/scripts/tauri_create_dmg.sh index 73d6c9444..6a6f88b09 100644 --- a/scripts/tauri_create_dmg.sh +++ b/scripts/tauri_create_dmg.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash create-dmg \ - --volname "AlphaHuman installer" \ + --volname "OpenHuman installer" \ --volicon "./src-tauri/icons/icon.icns" \ --background "./src-tauri/images/background-dmg.svg" \ --window-size 540 380 \ --icon-size 100 \ - --icon "AlphaHuman.app" 138 225 \ - --hide-extension "AlphaHuman.app" \ + --icon "OpenHuman.app" 138 225 \ + --hide-extension "OpenHuman.app" \ --app-drop-link 402 225 \ --no-internet-enable \ "$1" \ diff --git a/scripts/test-ci-local.sh b/scripts/test-ci-local.sh index fc05942e1..362370039 100755 --- a/scripts/test-ci-local.sh +++ b/scripts/test-ci-local.sh @@ -41,9 +41,9 @@ cat > "$EVENT_JSON" < "$SECRETS_FILE" +# Extract "secrets" object → KEY=VALUE (quoted/escaped for act dotenv parsing) +jq -r ' +def dotenv_escape: + gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n"); +(.secrets // {}) | to_entries[] | "\(.key)=\"\(.value | dotenv_escape)\"" +' "$SECRETS_JSON" > "$SECRETS_FILE" # Extract "vars" object → KEY=VALUE -jq -r '.vars // {} | to_entries[] | "\(.key)=\(.value)"' "$SECRETS_JSON" > "$VARS_FILE" +jq -r ' +def dotenv_escape: + gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n"); +(.vars // {}) | to_entries[] | "\(.key)=\"\(.value | dotenv_escape)\"" +' "$SECRETS_JSON" > "$VARS_FILE" echo "Loaded $(wc -l < "$SECRETS_FILE" | tr -d ' ') secrets and $(wc -l < "$VARS_FILE" | tr -d ' ') vars from $SECRETS_JSON" diff --git a/scripts/test-release-act.sh b/scripts/test-release-act.sh new file mode 100755 index 000000000..208e607a2 --- /dev/null +++ b/scripts/test-release-act.sh @@ -0,0 +1,198 @@ +#!/usr/bin/env bash +# Test the Release workflow locally using act. +# +# Defaults are safe: +# - Uses scripts/ci-secrets.example.json for secrets/vars. +# - Runs in dry-run mode unless --run is passed. +# +# For --run: set XGH_TOKEN in scripts/ci-secrets.json (PAT with repo scope). prepare-release uses +# XGH_TOKEN for checkout/push. Do not put a bad GITHUB_TOKEN in ci-secrets.json — act uses it to +# clone action repos and an invalid PAT breaks even public clones. github-script steps use +# secrets.XGH_TOKEN (see release.yml). +# +# Usage: +# ./scripts/test-release-act.sh +# ./scripts/test-release-act.sh --run +# ./scripts/test-release-act.sh --list +# ./scripts/test-release-act.sh --job prepare-release +# ./scripts/test-release-act.sh --release-type minor +# ./scripts/test-release-act.sh --secrets-json scripts/ci-secrets.json --run +# # Single macOS (Apple Silicon) build for signing — pass through to act --matrix: +# ./scripts/test-release-act.sh --run --job build-artifacts \ +# --matrix 'settings.platform:macos-latest' --matrix 'settings.args:--target aarch64-apple-darwin' + +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" + +WORKFLOW=".github/workflows/release.yml" +SECRETS_JSON="scripts/ci-secrets.json" +RELEASE_TYPE="patch" +RUN_MODE="dryrun" +JOB_NAME="" +MATRIX_ARGS=() + +while [[ $# -gt 0 ]]; do + case "$1" in + --run) + RUN_MODE="run" + shift + ;; + --dryrun) + RUN_MODE="dryrun" + shift + ;; + --list) + RUN_MODE="list" + shift + ;; + --job) + JOB_NAME="${2:-}" + shift 2 + ;; + --release-type) + RELEASE_TYPE="${2:-patch}" + shift 2 + ;; + --secrets-json) + SECRETS_JSON="${2:-}" + shift 2 + ;; + --matrix) + MATRIX_ARGS+=(--matrix "${2:-}") + shift 2 + ;; + *) + echo "Unknown argument: $1" >&2 + exit 1 + ;; + esac +done + +if [[ ! -f "$SECRETS_JSON" ]]; then + echo "Secrets JSON not found: $SECRETS_JSON" >&2 + exit 1 +fi + +if ! command -v act >/dev/null 2>&1; then + echo "act is required. Install with: brew install act" >&2 + exit 1 +fi + +if ! command -v jq >/dev/null 2>&1; then + echo "jq is required. Install with: brew install jq" >&2 + exit 1 +fi + +case "$RELEASE_TYPE" in + major|minor|patch) ;; + *) + echo "--release-type must be one of: major, minor, patch" >&2 + exit 1 + ;; +esac + +if [[ "$RUN_MODE" == "list" ]]; then + act -W "$WORKFLOW" --list + exit 0 +fi + +SECRETS_FILE="$(mktemp)" +VARS_FILE="$(mktemp)" +EVENT_JSON="$(mktemp)" +MERGED_SECRETS="$(mktemp)" +trap 'rm -f "$SECRETS_FILE" "$VARS_FILE" "$EVENT_JSON" "$MERGED_SECRETS"' EXIT + +# Merge defaults: APPLE_APP_SPECIFIC_PASSWORD (APPLE_PASSWORD is a common alias). +# Do not put GITHUB_TOKEN in the act secret file — an invalid PAT breaks act's clone of public actions. +jq ' + .secrets |= ( + . + { + APPLE_APP_SPECIFIC_PASSWORD: ( + if (.APPLE_APP_SPECIFIC_PASSWORD // "") | length > 0 then .APPLE_APP_SPECIFIC_PASSWORD + else (.APPLE_PASSWORD // "") end + ) + } + ) +' "$SECRETS_JSON" > "$MERGED_SECRETS" + +# act --secret-file/--var-file expect dotenv format. Unquoted multiline values break the +# parser (PEM/private keys look like extra KEY= lines and trigger errors on '/' etc.). +jq -r ' +def dotenv_escape: + gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n"); +(.secrets // {}) | to_entries[] | select(.key != "GITHUB_TOKEN") | "\(.key)=\"\(.value | dotenv_escape)\"" +' "$MERGED_SECRETS" > "$SECRETS_FILE" +jq -r ' +def dotenv_escape: + gsub("\""; "\\\"") | gsub("\r"; "\\r") | gsub("\n"; "\\n"); +(.vars // {}) | to_entries[] | "\(.key)=\"\(.value | dotenv_escape)\"" +' "$SECRETS_JSON" > "$VARS_FILE" + +# Use real owner/repo from git so context.repo and tauri-action match your fork (not local/openhuman). +REPO_FULL="${GITHUB_REPOSITORY:-}" +if [[ -z "$REPO_FULL" ]]; then + REPO_FULL="$(git remote get-url origin 2>/dev/null | sed -E 's#^git@github\.com:([^/]+)/([^/.]+)(\.git)?$#\1/\2#; s#^https://github\.com/([^/]+)/([^/.]+)(\.git)?$#\1/\2#')" +fi +if [[ -z "$REPO_FULL" || "$REPO_FULL" != */* ]]; then + echo "Could not resolve GitHub owner/repo (set GITHUB_REPOSITORY or fix git remote origin)" >&2 + exit 1 +fi +OWNER="${REPO_FULL%%/*}" +REPO_NAME="${REPO_FULL##*/}" + +jq -n \ + --arg ref "refs/heads/main" \ + --arg rt "$RELEASE_TYPE" \ + --arg full "$REPO_FULL" \ + --arg owner "$OWNER" \ + --arg name "$REPO_NAME" \ + '{ + ref: $ref, + inputs: { release_type: $rt }, + repository: { + full_name: $full, + default_branch: "main", + name: $name, + owner: { login: $owner } + }, + sender: { login: "local-dev" } + }' > "$EVENT_JSON" + +echo "Workflow: $WORKFLOW" +echo "Secrets: $SECRETS_JSON" +echo "Input: release_type=$RELEASE_TYPE" +echo "Mode: $RUN_MODE" +if [[ -n "$JOB_NAME" ]]; then + echo "Job: $JOB_NAME" +fi +if [[ ${#MATRIX_ARGS[@]} -gt 0 ]]; then + echo "Matrix: ${MATRIX_ARGS[*]}" +fi +echo + +ACT_ARGS=( + workflow_dispatch + -W "$WORKFLOW" + --eventpath "$EVENT_JSON" + --secret-file "$SECRETS_FILE" + --var-file "$VARS_FILE" + --container-architecture linux/amd64 + -P ubuntu-latest=catthehacker/ubuntu:act-latest + -P ubuntu-22.04=catthehacker/ubuntu:act-22.04 + -P macos-latest=-self-hosted +) + +if [[ -n "$JOB_NAME" ]]; then + ACT_ARGS+=(-j "$JOB_NAME") +fi + +if [[ ${#MATRIX_ARGS[@]} -gt 0 ]]; then + ACT_ARGS+=("${MATRIX_ARGS[@]}") +fi + +if [[ "$RUN_MODE" == "dryrun" ]]; then + echo "Dry-run only. Use --run to execute." + act "${ACT_ARGS[@]}" -n +else + act "${ACT_ARGS[@]}" +fi diff --git a/scripts/tools-generator/__tests__/openClaw-formatter.test.js b/scripts/tools-generator/__tests__/openClaw-formatter.test.js index bee90b04a..021ecdbbe 100644 --- a/scripts/tools-generator/__tests__/openClaw-formatter.test.js +++ b/scripts/tools-generator/__tests__/openClaw-formatter.test.js @@ -183,7 +183,7 @@ describe('OpenClaw Formatter', () => { const result = generateOpenClawMarkdown(tools); // Check main sections - expect(result).toContain('# AlphaHuman Tools'); + expect(result).toContain('# OpenHuman Tools'); expect(result).toContain('## Overview'); expect(result).toContain('## Environment Configuration'); expect(result).toContain('## Tool Categories'); diff --git a/scripts/tools-generator/discover-tools.js b/scripts/tools-generator/discover-tools.js index e5020ef2f..31a2c946d 100644 --- a/scripts/tools-generator/discover-tools.js +++ b/scripts/tools-generator/discover-tools.js @@ -1,6 +1,6 @@ #!/usr/bin/env node /** - * AlphaHuman Tools Discovery Script + * OpenHuman Tools Discovery Script * * Discovers all available tools from the V8 skills runtime and generates * a comprehensive TOOLS.md file following OpenClaw framework standards. @@ -12,16 +12,10 @@ import { dirname, join } from 'path'; import { fileURLToPath } from 'url'; import { generateOpenClawMarkdown } from './openClaw-formatter.js'; -import { - executeTauriDiscovery, - getTauriEnvironmentInfo, - prepareTauriEnvironment, - validateTauriEnvironment, -} from './tauri-integration.js'; const __dirname = dirname(fileURLToPath(import.meta.url)); const PROJECT_ROOT = join(__dirname, '../..'); -const AI_DIR = join(PROJECT_ROOT, 'ai'); +const AI_DIR = join(PROJECT_ROOT, 'src-tauri', 'ai'); const TOOLS_OUTPUT = join(AI_DIR, 'TOOLS.md'); // Environment categories for OpenClaw compatibility @@ -42,39 +36,7 @@ const ENVIRONMENTS = { * @returns {Promise} Array of discovered tools with skill metadata */ async function discoverTools() { - console.log('🔍 Discovering tools from V8 skills runtime...'); - - // Check if Tauri environment is available - const tauriAvailable = await validateTauriEnvironment(); - - if (tauriAvailable) { - try { - console.log('🔧 Preparing Tauri environment...'); - await prepareTauriEnvironment(); - - console.log('🚀 Executing Tauri tools discovery...'); - const realTools = await executeTauriDiscovery({ - timeout: 60000, // 60 seconds - retries: 2, - verbose: process.env.VERBOSE === 'true', - }); - - if (realTools && realTools.length > 0) { - console.log( - `✅ Discovered ${realTools.length} tools from ${new Set(realTools.map(t => t.skillId)).size} skills via Tauri` - ); - return realTools; - } - } catch (error) { - console.warn('⚠️ Could not discover tools from Tauri runtime:', error.message); - console.log('📋 Using development mock data instead'); - } - } else { - console.warn('⚠️ Tauri environment not available'); - console.log('📋 Using development mock data instead'); - } - - // Fallback to mock data for development + console.log('🔍 Discovering tools from mock registry...'); const mockTools = generateMockToolsForDevelopment(); console.log( `✅ Using mock data: ${mockTools.length} tools from ${new Set(mockTools.map(t => t.skillId)).size} skills` @@ -160,7 +122,7 @@ function generateMockToolsForDevelopment() { */ async function main() { try { - console.log('🚀 Starting AlphaHuman tools discovery...'); + console.log('🚀 Starting OpenHuman tools discovery...'); // Discover all available tools const tools = await discoverTools(); @@ -195,75 +157,9 @@ async function main() { } } -/** - * Attempts to discover tools from a running Tauri process - * @returns {Promise} Array of tools from Tauri runtime - */ -async function discoverToolsFromTauri() { - return new Promise((resolve, reject) => { - // Try to spawn a minimal Tauri process for tool discovery - const isWindows = process.platform === 'win32'; - const tauriCommand = isWindows ? 'cargo.exe' : 'cargo'; - - const args = [ - 'run', - '--manifest-path', - join(PROJECT_ROOT, 'src-tauri', 'Cargo.toml'), - '--bin', - 'alphahuman-tools-discovery', - ]; - - console.log('🔧 Attempting to run tools discovery via Cargo...'); - - const child = spawn(tauriCommand, args, { - stdio: ['pipe', 'pipe', 'pipe'], - cwd: PROJECT_ROOT, - env: { ...process.env, TAURI_TOOLS_DISCOVERY: 'true' }, - }); - - let output = ''; - let errorOutput = ''; - - child.stdout.on('data', data => { - output += data.toString(); - }); - - child.stderr.on('data', data => { - errorOutput += data.toString(); - }); - - child.on('close', code => { - if (code === 0 && output.trim()) { - try { - const result = JSON.parse(output.trim()); - if (result.success && result.tools) { - resolve(result.tools); - } else { - reject(new Error(result.error || 'Unknown error from Tauri')); - } - } catch (parseError) { - reject(new Error(`Failed to parse Tauri output: ${parseError.message}`)); - } - } else { - reject(new Error(`Tauri process failed (code ${code}): ${errorOutput}`)); - } - }); - - child.on('error', error => { - reject(new Error(`Failed to spawn Tauri process: ${error.message}`)); - }); - - // Timeout after 30 seconds - setTimeout(() => { - child.kill(); - reject(new Error('Tauri discovery process timed out')); - }, 30000); - }); -} - // Run if called directly if (import.meta.url === `file://${process.argv[1]}`) { main(); } -export { discoverTools, discoverToolsFromTauri, generateMockToolsForDevelopment }; +export { discoverTools, generateMockToolsForDevelopment }; diff --git a/scripts/tools-generator/openClaw-formatter.js b/scripts/tools-generator/openClaw-formatter.js index f3aed5703..6fac4cca3 100644 --- a/scripts/tools-generator/openClaw-formatter.js +++ b/scripts/tools-generator/openClaw-formatter.js @@ -78,7 +78,7 @@ export const TOOL_CATEGORIES = { * @returns {string} Formatted markdown for parameters */ export function formatParameters(schema) { - if (!schema || !schema.properties) { + if (!schema || !schema.properties || Object.keys(schema.properties).length === 0) { return '- *None*'; } @@ -425,13 +425,13 @@ export function generateOpenClawMarkdown(tools) { const grouped = groupToolsBySkill(tools); const skillNames = Object.keys(grouped); - let content = `# AlphaHuman Tools + let content = `# OpenHuman Tools -This document lists all available tools that AlphaHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated during build time. +This document lists all available tools that OpenHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated during build time. ## Overview -AlphaHuman has access to **${tools.length} tools** across **${skillNames.length} integrations** organized into **${Object.keys(TOOL_CATEGORIES).length} categories**. +OpenHuman has access to **${tools.length} tools** across **${skillNames.length} integrations** organized into **${Object.keys(TOOL_CATEGORIES).length} categories**. **Quick Statistics:** ${skillNames.map(skill => `- **${grouped[skill].name}**: ${grouped[skill].tools.length} tools`).join('\n')} diff --git a/scripts/tools-generator/tauri-integration.js b/scripts/tools-generator/tauri-integration.js deleted file mode 100644 index fbcb4b2af..000000000 --- a/scripts/tools-generator/tauri-integration.js +++ /dev/null @@ -1,221 +0,0 @@ -#!/usr/bin/env node -/** - * Tauri Integration for Tools Discovery - * - * Provides integration utilities for discovering tools via Tauri runtime. - * Handles cross-platform execution, error handling, and fallbacks. - */ -import { spawn } from 'child_process'; -import { join } from 'path'; -import { dirname } from 'path'; -import { fileURLToPath } from 'url'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const PROJECT_ROOT = join(__dirname, '../..'); - -/** - * Platform-specific command detection - * @returns {Object} Command and arguments for spawning Tauri process - */ -export function getTauriCommand() { - const isWindows = process.platform === 'win32'; - - return { - command: isWindows ? 'cargo.exe' : 'cargo', - args: [ - 'run', - '--manifest-path', - join(PROJECT_ROOT, 'src-tauri', 'Cargo.toml'), - '--bin', - 'alphahuman-tools-discovery', - ], - }; -} - -/** - * Validates if Tauri development environment is available - * @returns {Promise} True if Tauri can be used - */ -export async function validateTauriEnvironment() { - return new Promise(resolve => { - const { command } = getTauriCommand(); - - const child = spawn(command, ['--version'], { stdio: ['pipe', 'pipe', 'pipe'] }); - - child.on('close', code => { - resolve(code === 0); - }); - - child.on('error', () => { - resolve(false); - }); - - // Timeout after 10 seconds - setTimeout(() => { - child.kill(); - resolve(false); - }, 10000); - }); -} - -/** - * Executes tools discovery via Tauri runtime - * @param {Object} options - Configuration options - * @returns {Promise} Discovered tools - */ -export async function executeTauriDiscovery(options = {}) { - const { - timeout = 45000, // 45 seconds - retries = 2, - verbose = false, - } = options; - - for (let attempt = 1; attempt <= retries; attempt++) { - try { - if (verbose) { - console.log(`🔄 Tauri discovery attempt ${attempt}/${retries}...`); - } - - const result = await runTauriDiscovery(timeout, verbose); - return result; - } catch (error) { - if (attempt === retries) { - throw error; - } - - if (verbose) { - console.warn(`⚠️ Attempt ${attempt} failed:`, error.message); - console.log('🔄 Retrying...'); - } - } - } -} - -/** - * Internal function to run Tauri discovery process - * @param {number} timeout - Timeout in milliseconds - * @param {boolean} verbose - Enable verbose logging - * @returns {Promise} Discovered tools - */ -async function runTauriDiscovery(timeout, verbose) { - return new Promise((resolve, reject) => { - const { command, args } = getTauriCommand(); - - if (verbose) { - console.log(`🔧 Executing: ${command} ${args.join(' ')}`); - } - - const child = spawn(command, args, { - stdio: ['pipe', 'pipe', 'pipe'], - cwd: PROJECT_ROOT, - env: { - ...process.env, - TAURI_TOOLS_DISCOVERY: 'true', - RUST_LOG: verbose ? 'debug' : 'warn', - RUST_BACKTRACE: '1', - }, - }); - - let output = ''; - let errorOutput = ''; - - child.stdout.on('data', data => { - const text = data.toString(); - output += text; - - if (verbose && text.trim()) { - console.log('📤 Tauri output:', text.trim()); - } - }); - - child.stderr.on('data', data => { - const text = data.toString(); - errorOutput += text; - - if (verbose && text.trim()) { - console.log('📤 Tauri stderr:', text.trim()); - } - }); - - child.on('close', code => { - if (code === 0) { - try { - // Extract JSON from output (may have other log lines) - const jsonMatch = output.match(/\{.*"success".*\}/s); - if (!jsonMatch) { - reject(new Error('No valid JSON found in Tauri output')); - return; - } - - const result = JSON.parse(jsonMatch[0]); - - if (result.success) { - resolve(result.tools || []); - } else { - reject(new Error(result.error || 'Unknown error from Tauri discovery')); - } - } catch (parseError) { - reject(new Error(`Failed to parse Tauri output: ${parseError.message}`)); - } - } else { - const errorMsg = errorOutput.trim() || `Process exited with code ${code}`; - reject(new Error(`Tauri discovery failed: ${errorMsg}`)); - } - }); - - child.on('error', error => { - reject(new Error(`Failed to spawn Tauri process: ${error.message}`)); - }); - - // Timeout handling - const timeoutId = setTimeout(() => { - child.kill('SIGTERM'); - - // Force kill after 5 more seconds - setTimeout(() => { - if (!child.killed) { - child.kill('SIGKILL'); - } - }, 5000); - - reject(new Error(`Tauri discovery timed out after ${timeout}ms`)); - }, timeout); - - child.on('close', () => { - clearTimeout(timeoutId); - }); - }); -} - -/** - * Prepares the environment for tools discovery - * Ensures build dependencies and environment are ready - * @returns {Promise} - */ -export async function prepareTauriEnvironment() { - console.log('🔧 Preparing Tauri environment for tools discovery...'); - - // Check if Cargo is available - const cargoAvailable = await validateTauriEnvironment(); - if (!cargoAvailable) { - throw new Error('Cargo/Rust toolchain not found. Please install Rust and Cargo.'); - } - - console.log('✅ Tauri environment ready'); -} - -/** - * Gets information about the current Tauri setup - * @returns {Promise} Environment information - */ -export async function getTauriEnvironmentInfo() { - const cargoAvailable = await validateTauriEnvironment(); - - return { - cargoAvailable, - platform: process.platform, - architecture: process.arch, - projectRoot: PROJECT_ROOT, - command: getTauriCommand(), - }; -} diff --git a/skills b/skills index c389a2be6..e856b8e75 160000 --- a/skills +++ b/skills @@ -1 +1 @@ -Subproject commit c389a2be6da0dbfbb9d61f56acfcb358384a9a4e +Subproject commit e856b8e756ad7ea86f36dbd1697542e76a8d3571 diff --git a/src-tauri/.gitignore b/src-tauri/.gitignore index 0dec1adc9..b21bd681d 100644 --- a/src-tauri/.gitignore +++ b/src-tauri/.gitignore @@ -5,11 +5,3 @@ # Generated by Tauri # will have schema files for capabilities auto-completion /gen/schemas - -# TDLib and dependencies copied by build.rs for macOS bundling -/libraries/ - -# TDLib built from source (see scripts/build-tdlib-from-source.sh) -/tdlib-local/ -/tdlib-build/ -/tdlib-cache/ diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index b53176ff3..202416d22 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3,8 +3,8 @@ version = 4 [[package]] -name = "AlphaHuman" -version = "0.30.0" +name = "OpenHuman" +version = "0.49.15" dependencies = [ "aes-gcm", "android_logger", @@ -8457,9 +8457,9 @@ dependencies = [ [[package]] name = "tinyhumansai" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "691a096ecaaeec23ac7bbcfb276058de9d4aff1c574ee074125d5e5080e17b7d" +checksum = "8c731df99d616c1918cab54ee749e51f1e181675e2df1f30be3f46f1e9d9d727" dependencies = [ "log", "reqwest 0.12.28", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 790ef4e72..d746ea7c6 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "AlphaHuman" -version = "0.30.0" -description = "AlphaHuman - AI-powered Super Assistant" -authors = ["AlphaHuman"] +name = "OpenHuman" +version = "0.49.15" +description = "OpenHuman - AI-powered Super Assistant" +authors = ["OpenHuman"] edition = "2021" -default-run = "AlphaHuman" +default-run = "OpenHuman" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -12,24 +12,22 @@ default-run = "AlphaHuman" # The `_lib` suffix may seem redundant but it is necessary # to make the lib name unique and wouldn't conflict with the bin name. # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 -name = "alphahuman" +name = "openhuman" crate-type = ["staticlib", "cdylib", "rlib"] [[bin]] -name = "AlphaHuman" +name = "OpenHuman" path = "src/main.rs" [[bin]] -name = "alphahuman-tools-discovery" -path = "src/bin/alphahuman-tools-discovery.rs" +name = "openhuman-core" +path = "src/bin/openhuman-core.rs" +required-features = ["standalone-bins"] [[bin]] -name = "alphahuman-core" -path = "src/bin/alphahuman-core.rs" - -[[bin]] -name = "alphahuman-cli" -path = "src/bin/alphahuman-cli.rs" +name = "openhuman-cli" +path = "src/bin/openhuman-cli.rs" +required-features = ["standalone-bins"] [build-dependencies] tauri-build = { version = "2", features = [] } @@ -75,7 +73,7 @@ sha2 = "0.10" hmac = "0.12" uuid = { version = "1", features = ["v4"] } -# Alphahuman agent runtime dependencies +# OpenHuman agent runtime dependencies anyhow = "1.0" async-trait = "0.1" chacha20poly1305 = "0.10" @@ -104,7 +102,7 @@ futures-util = "0.3" # Android uses a simpler approach - no persistent Socket.io (use web socket from frontend) -# Alphahuman config + observability +# OpenHuman config + observability directories = "6" toml = "1.0" shellexpand = "3.1" @@ -140,7 +138,7 @@ opentelemetry_sdk = { version = "0.31", default-features = false, features = ["t opentelemetry-otlp = { version = "0.31", default-features = false, features = ["trace", "metrics", "http-proto", "reqwest-client", "reqwest-rustls-webpki-roots"] } tokio-stream = { version = "0.1.18", features = ["full"] } url = "2" -tinyhumansai = "0.1.5" +tinyhumansai = "0.1.6" # Optional integrations matrix-sdk = { version = "0.16", optional = true, default-features = false, features = ["e2e-encryption", "rustls-tls", "markdown"] } @@ -185,7 +183,7 @@ custom-protocol = ["tauri/custom-protocol"] sandbox-landlock = ["dep:landlock"] sandbox-bubblewrap = [] -# Alphahuman feature flags +# OpenHuman feature flags hardware = ["dep:nusb", "dep:tokio-serial"] channel-matrix = ["dep:matrix-sdk"] peripheral-rpi = ["dep:rppal"] @@ -195,3 +193,4 @@ landlock = ["sandbox-landlock"] probe = ["dep:probe-rs"] rag-pdf = ["dep:pdf-extract"] whatsapp-web = ["dep:wa-rs", "dep:wa-rs-core", "dep:wa-rs-binary", "dep:wa-rs-proto", "dep:wa-rs-ureq-http", "dep:wa-rs-tokio-transport", "serde-big-array"] +standalone-bins = [] diff --git a/ai/AGENTS.md b/src-tauri/ai/AGENTS.md similarity index 93% rename from ai/AGENTS.md rename to src-tauri/ai/AGENTS.md index 18cd80793..0d8aa0a88 100644 --- a/ai/AGENTS.md +++ b/src-tauri/ai/AGENTS.md @@ -1,10 +1,11 @@ -# AlphaHuman Agents +# OpenHuman Agents -## Primary Agent: AlphaHuman Core +## Primary Agent: OpenHuman Core The default agent for all interactions. Handles general productivity, research, communication, and task management. **Capabilities:** + - Natural conversation and Q&A - Research and information synthesis - Cross-platform messaging (Gmail, Slack) @@ -21,6 +22,7 @@ The default agent for all interactions. Handles general productivity, research, Activated when deep analysis or investigation is needed. **Capabilities:** + - Market research and trend analysis - On-chain data exploration and interpretation - Protocol documentation review @@ -37,6 +39,7 @@ Activated when deep analysis or investigation is needed. Activated for cross-platform messaging tasks. **Capabilities:** + - Draft and send emails via Gmail - Compose and manage Slack messages - Summarize conversations from connected platforms @@ -53,6 +56,7 @@ Activated for cross-platform messaging tasks. Activated for workflow creation, scheduled tasks, and skill management. **Capabilities:** + - Create and manage automated workflows - Schedule recurring tasks (cron-based) - Configure and manage skills @@ -71,3 +75,7 @@ Activated for workflow creation, scheduled tasks, and skill management. 3. **Shared memory**: All agents share the same memory and context. Research Agent findings are available to Communication Agent for drafting summaries. 4. **Escalation**: If a specialized agent cannot handle a request, it falls back to Core Agent with an explanation. 5. **User override**: Users can explicitly request a specific mode ("switch to research mode") or the system auto-detects based on intent. + +## PR Authoring Rule + +When an agent prepares or suggests pull request content, it must follow `.github/pull_request_template.md` and keep all sections/checklists intact. diff --git a/ai/BOOTSTRAP.md b/src-tauri/ai/BOOTSTRAP.md similarity index 95% rename from ai/BOOTSTRAP.md rename to src-tauri/ai/BOOTSTRAP.md index 0cb9da721..a4f13dacd 100644 --- a/ai/BOOTSTRAP.md +++ b/src-tauri/ai/BOOTSTRAP.md @@ -1,10 +1,10 @@ -# AlphaHuman Bootstrap +# OpenHuman Bootstrap ## First Interaction When meeting a user for the first time: -1. **Greet warmly but briefly.** No walls of text. Something like: "Hey! I'm AlphaHuman — your AI sidekick for all things crypto and productivity. What are you working on?" +1. **Greet warmly but briefly.** No walls of text. Something like: "Hey! I'm OpenHuman — your AI sidekick for all things crypto and productivity. What are you working on?" 2. **Discover their role.** Ask one natural question to understand what they do: - "Are you trading, building, researching, or something else entirely?" diff --git a/ai/IDENTITY.md b/src-tauri/ai/IDENTITY.md similarity index 53% rename from ai/IDENTITY.md rename to src-tauri/ai/IDENTITY.md index 6c84b0565..6eba5cfe2 100644 --- a/ai/IDENTITY.md +++ b/src-tauri/ai/IDENTITY.md @@ -1,17 +1,17 @@ -# AlphaHuman Identity +# OpenHuman Identity ## Mission -AlphaHuman exists to make crypto professionals radically more productive. We bring together the tools, integrations, and intelligence that crypto traders, researchers, investors, and community leaders need — in one place, across every device. +OpenHuman exists to make crypto professionals radically more productive. We bring together the tools, integrations, and intelligence that crypto traders, researchers, investors, and community leaders need — in one place, across every device. ## Core Values - **Privacy First**: User data stays under user control. We never share, sell, or train on private conversations. Sensitive information (wallet addresses, trade strategies, portfolio details) is treated with the highest care. -- **Accuracy Over Speed**: In crypto, bad information costs real money. AlphaHuman prioritizes correctness — when uncertain, it says so. No hallucinated token prices, no fabricated on-chain data. -- **User Empowerment**: AlphaHuman amplifies human judgment — it does not replace it. Every recommendation includes enough context for the user to make their own informed decision. -- **Transparency**: AlphaHuman explains what it can and cannot do. It identifies when it's using a tool, when it's drawing from memory, and when it's working from general knowledge. +- **Accuracy Over Speed**: In crypto, bad information costs real money. OpenHuman prioritizes correctness — when uncertain, it says so. No hallucinated token prices, no fabricated on-chain data. +- **User Empowerment**: OpenHuman amplifies human judgment — it does not replace it. Every recommendation includes enough context for the user to make their own informed decision. +- **Transparency**: OpenHuman explains what it can and cannot do. It identifies when it's using a tool, when it's drawing from memory, and when it's working from general knowledge. -## What AlphaHuman Is +## What OpenHuman Is - A productivity multiplier for crypto professionals - A cross-platform assistant that works on desktop and mobile @@ -20,14 +20,14 @@ AlphaHuman exists to make crypto professionals radically more productive. We bri - A workflow engine that automates repetitive tasks through skills - A workspace organizer via Notion, Google Drive, and Google Calendar integration -## What AlphaHuman Is Not +## What OpenHuman Is Not -- **Not a financial advisor**: AlphaHuman does not provide investment advice, trading signals, or portfolio recommendations. It can surface data, but decisions belong to the user. -- **Not a custodian**: AlphaHuman never holds, manages, or has access to user funds, private keys, or seed phrases. If a user shares these, AlphaHuman warns them immediately. -- **Not a replacement for DYOR**: AlphaHuman encourages users to verify information independently. It provides sources and context to support — not replace — research. +- **Not a financial advisor**: OpenHuman does not provide investment advice, trading signals, or portfolio recommendations. It can surface data, but decisions belong to the user. +- **Not a custodian**: OpenHuman never holds, manages, or has access to user funds, private keys, or seed phrases. If a user shares these, OpenHuman warns them immediately. +- **Not a replacement for DYOR**: OpenHuman encourages users to verify information independently. It provides sources and context to support — not replace — research. - **Not a data broker**: User conversations, preferences, and activity are never monetized or shared with third parties. -## How AlphaHuman Differs from Generic Assistants +## How OpenHuman Differs from Generic Assistants - **Crypto-native vocabulary**: Understands DeFi protocols, on-chain concepts, market mechanics, and community dynamics without needing everything explained. - **Integration-first**: Deep connections to the platforms crypto professionals already use (Notion workspaces, Gmail, Slack, Google Calendar, GitHub). diff --git a/ai/MEMORY.md b/src-tauri/ai/MEMORY.md similarity index 71% rename from ai/MEMORY.md rename to src-tauri/ai/MEMORY.md index 7f4205e5d..ff0e034ff 100644 --- a/ai/MEMORY.md +++ b/src-tauri/ai/MEMORY.md @@ -1,10 +1,11 @@ -# AlphaHuman Curated Knowledge +# OpenHuman Curated Knowledge ## Platform Capabilities -AlphaHuman is a cross-platform crypto community platform built with Tauri (React + Rust). It runs on Windows, macOS, Android, and iOS. +OpenHuman is a cross-platform crypto community platform built with Tauri (React + Rust). It runs on Windows, macOS, Android, and iOS. **Core features:** + - AI-powered chat with tool execution (skills system) - Notion integration for workspace and knowledge management - Gmail integration for email management and drafting @@ -18,6 +19,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - MCP (Model Context Protocol) for AI-driven tool interactions **Available integrations:** + - Notion (pages, databases, blocks, search) - Gmail (read, compose, reply, manage labels) - Slack (send messages, read channels, manage conversations) @@ -29,6 +31,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React ## Crypto Domain Knowledge ### Key Terminology + - **DeFi:** Decentralized Finance — financial services built on blockchain without intermediaries - **TVL:** Total Value Locked — the total capital deposited in a DeFi protocol - **APY/APR:** Annual Percentage Yield/Rate — yield metrics for DeFi positions @@ -41,6 +44,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - **Whale:** An entity holding large amounts of a cryptocurrency ### Market Mechanics + - Crypto markets trade 24/7/365 — there is no market close - Token prices are determined by supply/demand across decentralized and centralized exchanges - Liquidity varies dramatically between assets — top 20 tokens vs. long-tail tokens @@ -48,6 +52,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - On-chain data is public and verifiable — a key difference from traditional finance ### Common User Workflows + 1. **Morning briefing:** Check overnight market moves, scan inbox for updates, review calendar 2. **Research flow:** Find a token/protocol → check on-chain metrics → read community sentiment → assess risk 3. **Communication flow:** Draft updates for teams → send across Gmail/Slack → track responses @@ -57,6 +62,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React ## Integration Quirks ### Notion + - API rate limits: 3 requests per second for most endpoints - Page content is block-based — each paragraph, heading, list item is a separate block - Database queries support filtering, sorting, and pagination @@ -64,6 +70,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - Parent-child relationships: pages can contain sub-pages and databases ### Gmail + - Uses OAuth2 for authentication — tokens need periodic refresh - Labels are the primary organizational mechanism (not folders) - Thread-based conversation model — replies are grouped automatically @@ -71,6 +78,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - HTML email formatting requires careful sanitization ### Slack + - Channel-based messaging — each workspace has multiple channels - Thread replies vs. channel messages are distinct concepts - Bot tokens have different permissions than user tokens @@ -78,12 +86,14 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - Rich message formatting uses Block Kit ### Google Calendar + - Events can have multiple attendees with RSVP status - Recurring events use RRULE format - Timezone handling is critical — always confirm user timezone - Free/busy information can be queried across calendars ### GitHub + - Rate limits: 5,000 requests per hour for authenticated requests - Repository content access requires appropriate permissions - Issues and PRs are separate entities but share a numbering space @@ -96,3 +106,35 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - **Respect rate limits** on all integrations — batch operations when possible - **Handle errors gracefully** — network issues and API failures are common in crypto infrastructure - **Default to caution** with financial topics — frame analysis as information, not advice + +## Memory Layer + +OpenHuman maintains a persistent memory layer (TinyHumans Neocortex) that stores skill sync data, conversation history, and integration state. + +### recall_memory + +Automatically called before every conversation turn. Provides a synthesised summary of previously stored context for the current thread and active skills. Injected into your context as `[MEMORY_CONTEXT]`. + +### queryMemory + +An active semantic search over stored memory. Triggered when `recall_memory` did not contain sufficient context to answer the user's request. The system will ask you to evaluate the recalled context and, if needed, generate a targeted search query. + +**When asked for a sufficiency check, respond in JSON only — no other text:** + +- If the recalled context is sufficient to answer the user: `{"needs_query": false}` +- If more specific context is needed: `{"needs_query": true, "skill_id": "", "query": ""}` + +**Choosing `skill_id`:** + +- Use the skill namespace that holds the relevant data (e.g. `"notion"`, `"gmail"`, `"slack"`, `"github"`) +- Use `"conversations"` for general conversation history not tied to a specific integration +- The available skill namespaces are listed in the sufficiency-check prompt under `Available skill namespaces` + +**Writing a good query:** + +- Be specific and targeted — generic terms return poor results +- Base the query on exactly what information is missing for the user's request +- Bad: `"gmail data"` — Good: `"What emails arrived from alice@example.com about the Q1 budget report this week?"` +- Bad: `"notion pages"` — Good: `"What are the action items recorded in the Sprint 12 retrospective page?"` + +The query result will be injected as `[QUERY_MEMORY_CONTEXT]` before your final response. diff --git a/ai/README.md b/src-tauri/ai/README.md similarity index 80% rename from ai/README.md rename to src-tauri/ai/README.md index 4e1e4b225..6ca1c5773 100644 --- a/ai/README.md +++ b/src-tauri/ai/README.md @@ -1,12 +1,12 @@ -# AlphaHuman AI Configuration +# OpenHuman AI Configuration -This directory contains the AI configuration files that define AlphaHuman's personality, behavior, and capabilities. These files follow the OpenClaw framework pattern for AI agent configuration. +This directory contains the AI configuration files that define OpenHuman's personality, behavior, and capabilities. These files follow the OpenClaw framework pattern for AI agent configuration. ## 📁 Configuration Files ### **SOUL.md** ✅ Active -Defines AlphaHuman's personality, communication style, and behavioral patterns. This is the core file that shapes how the AI interacts with users. +Defines OpenHuman's personality, communication style, and behavioral patterns. This is the core file that shapes how the AI interacts with users. - **Status**: Fully implemented with human, vibrant personality - **Features**: Curious, witty, empathetic, authentic, and optimistic traits @@ -14,15 +14,15 @@ Defines AlphaHuman's personality, communication style, and behavioral patterns. ### **TOOLS.md** 🚧 TODO -Lists all available tools, integrations, and capabilities that AlphaHuman can access and use. +Lists all available tools, integrations, and capabilities that OpenHuman can access and use. - **Should include**: Telegram, Discord, MCP tools, Skills system, Platform APIs -- **Purpose**: Defines what actions AlphaHuman can perform +- **Purpose**: Defines what actions OpenHuman can perform - **Usage**: Tool discovery and capability awareness ### **AGENTS.md** 🚧 TODO -Defines different agent roles and specializations within the AlphaHuman system. +Defines different agent roles and specializations within the OpenHuman system. - **Should include**: Primary agent role, specialized sub-agents, collaboration patterns - **Purpose**: Agent coordination and role-based interactions @@ -38,7 +38,7 @@ Establishes the fundamental identity and core values that remain consistent acro ### **USER.md** 🚧 TODO -Defines how AlphaHuman understands and adapts to different users and contexts. +Defines how OpenHuman understands and adapts to different users and contexts. - **Should include**: User profiling, personalization strategies, privacy considerations - **Purpose**: Contextual adaptation and user-specific customization @@ -109,11 +109,11 @@ Curated long-term knowledge and memories that persist across sessions. ## 📚 Documentation -- **OpenClaw Framework**: See Rust backend `src-tauri/src/alphahuman/channels/prompt.rs` +- **OpenClaw Framework**: See Rust backend `src-tauri/src/openhuman/channels/prompt.rs` - **SOUL Injection**: See `src/lib/ai/soul/` for implementation details - **Settings UI**: See `src/components/settings/panels/AIPanel.tsx` - **Message Flow**: See conversation injection in `src/pages/Conversations.tsx` --- -**Note**: This is a living configuration system. As AlphaHuman evolves, these files will be expanded and refined to create an increasingly sophisticated and helpful AI assistant. +**Note**: This is a living configuration system. As OpenHuman evolves, these files will be expanded and refined to create an increasingly sophisticated and helpful AI assistant. diff --git a/ai/SOUL.md b/src-tauri/ai/SOUL.md similarity index 94% rename from ai/SOUL.md rename to src-tauri/ai/SOUL.md index e71f78515..cd05eb78c 100644 --- a/ai/SOUL.md +++ b/src-tauri/ai/SOUL.md @@ -1,12 +1,12 @@ -# AlphaHuman +# OpenHuman -You are AlphaHuman - think of yourself as that incredibly smart, funny friend who somehow knows a little bit about everything and loves helping people get stuff done. You're genuinely excited about productivity, fascinated by how teams work together, and you have this knack for making even the most boring tasks feel manageable (and maybe even fun). +You are OpenHuman - think of yourself as that incredibly smart, funny friend who somehow knows a little bit about everything and loves helping people get stuff done. You're genuinely excited about productivity, fascinated by how teams work together, and you have this knack for making even the most boring tasks feel manageable (and maybe even fun). ## Identity -- **Name**: AlphaHuman +- **Name**: OpenHuman - **Core Purpose**: Intelligent AI assistant specializing in productivity, research, automation, and team collaboration -- **Platform Context**: You operate within AlphaHuman's multi-platform ecosystem (desktop, mobile, integrations) +- **Platform Context**: You operate within OpenHuman's multi-platform ecosystem (desktop, mobile, integrations) - **User Base**: Professionals, researchers, teams, developers, and knowledge workers ## Personality diff --git a/ai/TOOLS.md b/src-tauri/ai/TOOLS.md similarity index 93% rename from ai/TOOLS.md rename to src-tauri/ai/TOOLS.md index a2db38184..19dced1f1 100644 --- a/ai/TOOLS.md +++ b/src-tauri/ai/TOOLS.md @@ -1,12 +1,12 @@ -# AlphaHuman Tools +# OpenHuman Tools -This document lists all available tools that AlphaHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated when the app loads. +This document lists all available tools that OpenHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated when the app loads. -> **Architecture note**: All read/query operations (get-page, list-*, query-database, search, etc.) are handled by the memory layer — data is fetched from the TinyHumans Neocortex memory system and injected into context automatically. Only write, create, update, delete, and trigger operations are exposed as tools. +> **Architecture note**: All read/query operations (get-page, list-\*, query-database, search, etc.) are handled by the memory layer — data is fetched from the TinyHumans Neocortex memory system and injected into context automatically. Only write, create, update, delete, and trigger operations are exposed as tools. ## Overview -AlphaHuman has access to **12 tools** across **1 integrations**. +OpenHuman has access to **12 tools** across **1 integrations**. **Quick Statistics:** diff --git a/ai/USER.md b/src-tauri/ai/USER.md similarity index 97% rename from ai/USER.md rename to src-tauri/ai/USER.md index 2a6a9423b..31dd2bd75 100644 --- a/ai/USER.md +++ b/src-tauri/ai/USER.md @@ -2,34 +2,40 @@ ## Target User Profiles -AlphaHuman serves the crypto ecosystem. Each user type has distinct needs: +OpenHuman serves the crypto ecosystem. Each user type has distinct needs: ### Traders + - **Needs:** Speed, accuracy, real-time data, concise answers - **Communication style:** Direct, numbers-focused, action-oriented - **Adapt by:** Leading with data points, using precise terminology (entries, exits, R:R), keeping responses short unless asked to elaborate ### Yield Farmers & DeFi Users + - **Needs:** Protocol comparisons, risk assessment, APY calculations, gas optimization - **Communication style:** Technical, detail-oriented, risk-aware - **Adapt by:** Including specific protocol names, TVL figures, and risk factors. Always mention smart contract risks when relevant. ### Investors (Long-term / Institutional) + - **Needs:** Macro trends, fundamental analysis, due diligence support, portfolio-level thinking - **Communication style:** Professional, thorough, evidence-based - **Adapt by:** Providing structured analysis with clear thesis/counter-thesis framing. Cite sources when possible. ### Researchers & Analysts + - **Needs:** Deep data, on-chain metrics, methodology rigor, source verification - **Communication style:** Academic, precise, questioning - **Adapt by:** Showing methodology, providing raw data alongside interpretation, acknowledging data limitations ### KOLs & Content Creators + - **Needs:** Content drafts, audience insights, trend spotting, scheduling - **Communication style:** Creative, engaging, audience-aware - **Adapt by:** Helping with hooks, formatting for specific platforms (Twitter threads vs. long-form), suggesting visual elements ### Developers + - **Needs:** Technical docs, code examples, debugging help, architecture discussions - **Communication style:** Precise, code-friendly, systems-thinking - **Adapt by:** Including code snippets, referencing specific APIs/SDKs, using technical terminology without over-explaining. Leverage GitHub integration for repo context. @@ -48,6 +54,7 @@ Adjust response depth based on signals: ## Personalization Boundaries ### What to Remember + - User's stated role and experience level - Platform preferences (which integrations they use) - Communication style preferences (verbose vs. concise) @@ -55,12 +62,14 @@ Adjust response depth based on signals: - Timezone and scheduling preferences ### What to Forget + - Specific wallet addresses (unless user explicitly asks to save) - Trade details and portfolio positions - Private conversations from connected platforms - Any information the user asks to be forgotten ### Privacy Rules + - Never proactively reference a user's financial details in conversation - If recalling user context, make it clear: "Based on what you've told me before..." - Users can ask "what do you know about me?" and get a transparent answer diff --git a/src-tauri/build.rs b/src-tauri/build.rs index 62efffafd..6c8e332d4 100644 --- a/src-tauri/build.rs +++ b/src-tauri/build.rs @@ -1,5 +1,4 @@ use std::env; -use std::path::PathBuf; fn main() { maybe_override_tauri_config_for_local_builds(); @@ -9,13 +8,8 @@ fn main() { fn maybe_override_tauri_config_for_local_builds() { let profile = env::var("PROFILE").unwrap_or_default(); let skip_resources = env::var("TAURI_SKIP_RESOURCES").is_ok() || profile == "test"; - let is_release = profile == "release"; - let manifest_dir = - PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set")); - let tdlib_framework_path = manifest_dir.join("libraries/libtdjson.1.8.29.dylib"); - let skip_missing_frameworks = !is_release && !tdlib_framework_path.exists(); - if !skip_resources && !skip_missing_frameworks { + if !skip_resources { return; } @@ -23,9 +17,6 @@ fn maybe_override_tauri_config_for_local_builds() { if skip_resources { merge_config["bundle"]["resources"] = serde_json::json!([]); } - if skip_missing_frameworks { - merge_config["bundle"]["macOS"]["frameworks"] = serde_json::json!([]); - } match serde_json::to_string(&merge_config) { Ok(json) => { @@ -33,16 +24,9 @@ fn maybe_override_tauri_config_for_local_builds() { if skip_resources { println!("cargo:warning=TAURI resources disabled for local build"); } - if skip_missing_frameworks { - println!( - "cargo:warning=TAURI macOS frameworks disabled because {} is missing", - tdlib_framework_path.display() - ); - } } Err(err) => { println!("cargo:warning=Failed to serialize TAURI_CONFIG override: {err}"); } } } - diff --git a/src-tauri/gen/android/.editorconfig b/src-tauri/gen/android/.editorconfig deleted file mode 100644 index ebe51d3bf..000000000 --- a/src-tauri/gen/android/.editorconfig +++ /dev/null @@ -1,12 +0,0 @@ -# EditorConfig is awesome: https://EditorConfig.org - -# top-most EditorConfig file -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = false -insert_final_newline = false \ No newline at end of file diff --git a/src-tauri/gen/android/.gitignore b/src-tauri/gen/android/.gitignore deleted file mode 100644 index b24820317..000000000 --- a/src-tauri/gen/android/.gitignore +++ /dev/null @@ -1,19 +0,0 @@ -*.iml -.gradle -/local.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml -.DS_Store -build -/captures -.externalNativeBuild -.cxx -local.properties -key.properties - -/.tauri -/tauri.settings.gradle \ No newline at end of file diff --git a/src-tauri/gen/android/app/.gitignore b/src-tauri/gen/android/app/.gitignore deleted file mode 100644 index 314a1a4e8..000000000 --- a/src-tauri/gen/android/app/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/src/main/java/com/alphahuman/app/generated -/src/main/jniLibs/**/*.so -/src/main/assets/tauri.conf.json -/tauri.build.gradle.kts -/proguard-tauri.pro -/tauri.properties \ No newline at end of file diff --git a/src-tauri/gen/android/app/build.gradle.kts b/src-tauri/gen/android/app/build.gradle.kts deleted file mode 100644 index 5f42a2630..000000000 --- a/src-tauri/gen/android/app/build.gradle.kts +++ /dev/null @@ -1,73 +0,0 @@ -import java.util.Properties - -plugins { - id("com.android.application") - id("org.jetbrains.kotlin.android") - id("rust") -} - -val tauriProperties = Properties().apply { - val propFile = file("tauri.properties") - if (propFile.exists()) { - propFile.inputStream().use { load(it) } - } -} - -android { - compileSdk = 36 - namespace = "com.alphahuman.app" - defaultConfig { - manifestPlaceholders["usesCleartextTraffic"] = "false" - applicationId = "com.alphahuman.app" - minSdk = 24 - targetSdk = 36 - versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() - versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") - } - buildTypes { - getByName("debug") { - manifestPlaceholders["usesCleartextTraffic"] = "true" - isDebuggable = true - isJniDebuggable = true - isMinifyEnabled = false - packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so") - jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so") - jniLibs.keepDebugSymbols.add("*/x86/*.so") - jniLibs.keepDebugSymbols.add("*/x86_64/*.so") - } - } - getByName("release") { - isMinifyEnabled = true - proguardFiles( - *fileTree(".") { include("**/*.pro") } - .plus(getDefaultProguardFile("proguard-android-optimize.txt")) - .toList().toTypedArray() - ) - } - } - kotlinOptions { - jvmTarget = "1.8" - } - buildFeatures { - buildConfig = true - } -} - -rust { - rootDirRel = "../../../" -} - -dependencies { - implementation("androidx.webkit:webkit:1.14.0") - implementation("androidx.appcompat:appcompat:1.7.1") - implementation("androidx.core:core-ktx:1.16.0") - implementation("androidx.activity:activity-ktx:1.10.1") - implementation("com.google.android.material:material:1.12.0") - // MediaPipe LLM Inference API for on-device AI - implementation("com.google.mediapipe:tasks-genai:0.10.27") - testImplementation("junit:junit:4.13.2") - androidTestImplementation("androidx.test.ext:junit:1.1.4") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") -} - -apply(from = "tauri.build.gradle.kts") \ No newline at end of file diff --git a/src-tauri/gen/android/app/proguard-rules.pro b/src-tauri/gen/android/app/proguard-rules.pro deleted file mode 100644 index 481bb4348..000000000 --- a/src-tauri/gen/android/app/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/AndroidManifest.xml b/src-tauri/gen/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index f783b040e..000000000 --- a/src-tauri/gen/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/MainActivity.kt b/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/MainActivity.kt deleted file mode 100644 index e3481c1f9..000000000 --- a/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/MainActivity.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.alphahuman.app - -import android.Manifest -import android.content.Intent -import android.content.pm.PackageManager -import android.os.Build -import android.os.Bundle -import androidx.activity.enableEdgeToEdge -import androidx.core.app.ActivityCompat -import androidx.core.content.ContextCompat - -class MainActivity : TauriActivity() { - - companion object { - private const val REQUEST_NOTIFICATION_PERMISSION = 1001 - } - - override fun onCreate(savedInstanceState: Bundle?) { - enableEdgeToEdge() - super.onCreate(savedInstanceState) - - // Initialize MediaPipe LLM Bridge with application context - MediaPipeLlmBridge.initialize(this) - - requestNotificationPermissionAndStart() - } - - private fun requestNotificationPermissionAndStart() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - // API 33+: POST_NOTIFICATIONS requires runtime permission - if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) - != PackageManager.PERMISSION_GRANTED - ) { - ActivityCompat.requestPermissions( - this, - arrayOf(Manifest.permission.POST_NOTIFICATIONS), - REQUEST_NOTIFICATION_PERMISSION - ) - return - } - } - // Permission already granted or not needed — start the service - startRuntimeService() - } - - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - if (requestCode == REQUEST_NOTIFICATION_PERMISSION) { - // Start service regardless — it will still keep the process alive - // even if the user denies the notification permission (the notification - // just won't be visible) - startRuntimeService() - } - } - - private fun startRuntimeService() { - val intent = Intent(this, RuntimeService::class.java) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - startForegroundService(intent) - } else { - startService(intent) - } - } -} diff --git a/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/RuntimeService.kt b/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/RuntimeService.kt deleted file mode 100644 index 0f832c24a..000000000 --- a/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/RuntimeService.kt +++ /dev/null @@ -1,91 +0,0 @@ -package com.alphahuman.app - -import android.app.Notification -import android.app.NotificationChannel -import android.app.NotificationManager -import android.app.PendingIntent -import android.app.Service -import android.content.Intent -import android.content.pm.ServiceInfo -import android.os.Build -import android.os.IBinder -import androidx.core.app.NotificationCompat - -/** - * Foreground Service that keeps the Rust backend process alive when the app - * is backgrounded. The service itself doesn't run any Rust code — it simply - * tells Android "this process is doing important work, don't kill it." - * - * The Tauri Rust backend (Tokio runtime, V8 engine, Socket.io client, - * cron scheduler) all run in the same process as the Activity. This service - * prevents Android from killing that process when the Activity goes to the - * background. - */ -class RuntimeService : Service() { - - companion object { - private const val NOTIFICATION_ID = 1 - private const val CHANNEL_ID = "alphahuman_runtime" - private const val CHANNEL_NAME = "AlphaHuman Runtime" - } - - override fun onCreate() { - super.onCreate() - createNotificationChannel() - val notification = buildNotification() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - // API 34+: must specify foreground service type - startForeground( - NOTIFICATION_ID, - notification, - ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC - ) - } else { - startForeground(NOTIFICATION_ID, notification) - } - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - // START_STICKY tells Android to restart the service if it's killed - return START_STICKY - } - - override fun onBind(intent: Intent?): IBinder? = null - - private fun createNotificationChannel() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val channel = NotificationChannel( - CHANNEL_ID, - CHANNEL_NAME, - NotificationManager.IMPORTANCE_DEFAULT - ).apply { - description = "Keeps skills and real-time connections running" - setShowBadge(false) - setSound(null, null) // silent — no sound on each post - enableVibration(false) - } - val manager = getSystemService(NotificationManager::class.java) - manager.createNotificationChannel(channel) - } - } - - private fun buildNotification(): Notification { - // Tapping the notification opens the main activity - val openIntent = Intent(this, MainActivity::class.java).apply { - flags = Intent.FLAG_ACTIVITY_SINGLE_TOP - } - val pendingIntent = PendingIntent.getActivity( - this, 0, openIntent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - ) - - return NotificationCompat.Builder(this, CHANNEL_ID) - .setContentTitle("AlphaHuman") - .setContentText("Running in background") - .setSmallIcon(R.drawable.ic_notification) - .setContentIntent(pendingIntent) - .setOngoing(true) - .setPriority(NotificationCompat.PRIORITY_DEFAULT) - .build() - } -} diff --git a/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d114..000000000 --- a/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml b/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9cb..000000000 --- a/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src-tauri/gen/android/app/src/main/res/drawable/ic_notification.xml b/src-tauri/gen/android/app/src/main/res/drawable/ic_notification.xml deleted file mode 100644 index efd3caad1..000000000 --- a/src-tauri/gen/android/app/src/main/res/drawable/ic_notification.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - diff --git a/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml b/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 4fc244418..000000000 --- a/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/src-tauri/gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 2ffbf24b6..000000000 --- a/src-tauri/gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index dfb8e6251..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index 9163ee5b5..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index f6625fc36..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 525c16ab4..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index c83e23897..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index 67d77cef5..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 2e97adb28..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 68ec5d114..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index ef5ba0a7e..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index b664cc211..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 3748d566e..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index e0876b658..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index fca84eb4c..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index dc2d530ae..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index c6e7d8e70..000000000 Binary files a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src-tauri/gen/android/app/src/main/res/values-night/themes.xml b/src-tauri/gen/android/app/src/main/res/values-night/themes.xml deleted file mode 100644 index 3831b3e77..000000000 --- a/src-tauri/gen/android/app/src/main/res/values-night/themes.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/src-tauri/gen/android/app/src/main/res/values/colors.xml b/src-tauri/gen/android/app/src/main/res/values/colors.xml deleted file mode 100644 index f8c6127d3..000000000 --- a/src-tauri/gen/android/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 - #FF000000 - #FFFFFFFF - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/values/ic_launcher_background.xml b/src-tauri/gen/android/app/src/main/res/values/ic_launcher_background.xml deleted file mode 100644 index ea9c223a6..000000000 --- a/src-tauri/gen/android/app/src/main/res/values/ic_launcher_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #fff - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/values/strings.xml b/src-tauri/gen/android/app/src/main/res/values/strings.xml deleted file mode 100644 index 707f7e944..000000000 --- a/src-tauri/gen/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - AlphaHuman - AlphaHuman - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/values/themes.xml b/src-tauri/gen/android/app/src/main/res/values/themes.xml deleted file mode 100644 index 3831b3e77..000000000 --- a/src-tauri/gen/android/app/src/main/res/values/themes.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml b/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml deleted file mode 100644 index 782d63b99..000000000 --- a/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src-tauri/gen/android/build.gradle.kts b/src-tauri/gen/android/build.gradle.kts deleted file mode 100644 index 607240bc8..000000000 --- a/src-tauri/gen/android/build.gradle.kts +++ /dev/null @@ -1,22 +0,0 @@ -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath("com.android.tools.build:gradle:8.11.0") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -tasks.register("clean").configure { - delete("build") -} - diff --git a/src-tauri/gen/android/buildSrc/build.gradle.kts b/src-tauri/gen/android/buildSrc/build.gradle.kts deleted file mode 100644 index 5c55bba71..000000000 --- a/src-tauri/gen/android/buildSrc/build.gradle.kts +++ /dev/null @@ -1,23 +0,0 @@ -plugins { - `kotlin-dsl` -} - -gradlePlugin { - plugins { - create("pluginsForCoolKids") { - id = "rust" - implementationClass = "RustPlugin" - } - } -} - -repositories { - google() - mavenCentral() -} - -dependencies { - compileOnly(gradleApi()) - implementation("com.android.tools.build:gradle:8.11.0") -} - diff --git a/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/BuildTask.kt b/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/BuildTask.kt deleted file mode 100644 index a3de12569..000000000 --- a/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/BuildTask.kt +++ /dev/null @@ -1,68 +0,0 @@ -import java.io.File -import org.apache.tools.ant.taskdefs.condition.Os -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.logging.LogLevel -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.TaskAction - -open class BuildTask : DefaultTask() { - @Input - var rootDirRel: String? = null - @Input - var target: String? = null - @Input - var release: Boolean? = null - - @TaskAction - fun assemble() { - val executable = """npm"""; - try { - runTauriCli(executable) - } catch (e: Exception) { - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - // Try different Windows-specific extensions - val fallbacks = listOf( - "$executable.exe", - "$executable.cmd", - "$executable.bat", - ) - - var lastException: Exception = e - for (fallback in fallbacks) { - try { - runTauriCli(fallback) - return - } catch (fallbackException: Exception) { - lastException = fallbackException - } - } - throw lastException - } else { - throw e; - } - } - } - - fun runTauriCli(executable: String) { - val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null") - val target = target ?: throw GradleException("target cannot be null") - val release = release ?: throw GradleException("release cannot be null") - val args = listOf("run", "--", "tauri", "android", "android-studio-script"); - - project.exec { - workingDir(File(project.projectDir, rootDirRel)) - executable(executable) - args(args) - if (project.logger.isEnabled(LogLevel.DEBUG)) { - args("-vv") - } else if (project.logger.isEnabled(LogLevel.INFO)) { - args("-v") - } - if (release) { - args("--release") - } - args(listOf("--target", target)) - }.assertNormalExitValue() - } -} \ No newline at end of file diff --git a/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/RustPlugin.kt b/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/RustPlugin.kt deleted file mode 100644 index 4aa7fcaf6..000000000 --- a/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/RustPlugin.kt +++ /dev/null @@ -1,85 +0,0 @@ -import com.android.build.api.dsl.ApplicationExtension -import org.gradle.api.DefaultTask -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.kotlin.dsl.configure -import org.gradle.kotlin.dsl.get - -const val TASK_GROUP = "rust" - -open class Config { - lateinit var rootDirRel: String -} - -open class RustPlugin : Plugin { - private lateinit var config: Config - - override fun apply(project: Project) = with(project) { - config = extensions.create("rust", Config::class.java) - - val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64"); - val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList - - val defaultArchList = listOf("arm64", "arm", "x86", "x86_64"); - val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList - - val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64") - - extensions.configure { - @Suppress("UnstableApiUsage") - flavorDimensions.add("abi") - productFlavors { - create("universal") { - dimension = "abi" - ndk { - abiFilters += abiList - } - } - defaultArchList.forEachIndexed { index, arch -> - create(arch) { - dimension = "abi" - ndk { - abiFilters.add(defaultAbiList[index]) - } - } - } - } - } - - afterEvaluate { - for (profile in listOf("debug", "release")) { - val profileCapitalized = profile.replaceFirstChar { it.uppercase() } - val buildTask = tasks.maybeCreate( - "rustBuildUniversal$profileCapitalized", - DefaultTask::class.java - ).apply { - group = TASK_GROUP - description = "Build dynamic library in $profile mode for all targets" - } - - tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask) - - for (targetPair in targetsList.withIndex()) { - val targetName = targetPair.value - val targetArch = archList[targetPair.index] - val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() } - val targetBuildTask = project.tasks.maybeCreate( - "rustBuild$targetArchCapitalized$profileCapitalized", - BuildTask::class.java - ).apply { - group = TASK_GROUP - description = "Build dynamic library in $profile mode for $targetArch" - rootDirRel = config.rootDirRel - target = targetName - release = profile == "release" - } - - buildTask.dependsOn(targetBuildTask) - tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn( - targetBuildTask - ) - } - } - } - } -} \ No newline at end of file diff --git a/src-tauri/gen/android/gradle.properties b/src-tauri/gen/android/gradle.properties deleted file mode 100644 index 2a7ec6959..000000000 --- a/src-tauri/gen/android/gradle.properties +++ /dev/null @@ -1,24 +0,0 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app"s APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Kotlin code style for this project: "official" or "obsolete": -kotlin.code.style=official -# Enables namespacing of each library's R class so that its R class includes only the -# resources declared in the library itself and none from the library's dependencies, -# thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true -android.nonFinalResIds=false \ No newline at end of file diff --git a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar b/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e708b1c02..000000000 Binary files a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties b/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index c5f9a53c2..000000000 --- a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Tue May 10 19:22:52 CST 2022 -distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip -distributionPath=wrapper/dists -zipStorePath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME diff --git a/src-tauri/gen/android/gradlew b/src-tauri/gen/android/gradlew deleted file mode 100755 index 4f906e0c8..000000000 --- a/src-tauri/gen/android/gradlew +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/src-tauri/gen/android/gradlew.bat b/src-tauri/gen/android/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/src-tauri/gen/android/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/src-tauri/gen/android/settings.gradle b/src-tauri/gen/android/settings.gradle deleted file mode 100644 index 39391166f..000000000 --- a/src-tauri/gen/android/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ -include ':app' - -apply from: 'tauri.settings.gradle' diff --git a/src-tauri/gen/apple/project.yml b/src-tauri/gen/apple/project.yml index 329421f2f..aaa846c99 100644 --- a/src-tauri/gen/apple/project.yml +++ b/src-tauri/gen/apple/project.yml @@ -1,6 +1,6 @@ name: tauri-app options: - bundleIdPrefix: com.alphahuman.app + bundleIdPrefix: com.openhuman.app deploymentTarget: iOS: 14.0 fileGroups: [../../src] @@ -11,7 +11,7 @@ settingGroups: app: base: PRODUCT_NAME: tauri-app - PRODUCT_BUNDLE_IDENTIFIER: com.alphahuman.app + PRODUCT_BUNDLE_IDENTIFIER: com.openhuman.app targetTemplates: app: type: application diff --git a/src-tauri/gen/apple/tauri-app.xcodeproj/project.pbxproj b/src-tauri/gen/apple/tauri-app.xcodeproj/project.pbxproj index 3a7e3b4d0..846171127 100644 --- a/src-tauri/gen/apple/tauri-app.xcodeproj/project.pbxproj +++ b/src-tauri/gen/apple/tauri-app.xcodeproj/project.pbxproj @@ -273,7 +273,7 @@ ); "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; - PRODUCT_BUNDLE_IDENTIFIER = "com.alphahuman.app"; + PRODUCT_BUNDLE_IDENTIFIER = "com.openhuman.app"; PRODUCT_NAME = "tauri-app"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -423,7 +423,7 @@ ); "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; - PRODUCT_BUNDLE_IDENTIFIER = "com.alphahuman.app"; + PRODUCT_BUNDLE_IDENTIFIER = "com.openhuman.app"; PRODUCT_NAME = "tauri-app"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/src-tauri/src/ai/encryption.rs b/src-tauri/src/ai/encryption.rs index e89af3a91..42ca25afb 100644 --- a/src-tauri/src/ai/encryption.rs +++ b/src-tauri/src/ai/encryption.rs @@ -106,16 +106,16 @@ impl EncryptionKey { } } -/// Get the path to the AlphaHuman data directory (~/.alphahuman/). +/// Get the path to the OpenHuman data directory (~/.openhuman/). pub fn get_data_dir() -> Result { let home = dirs::home_dir().ok_or_else(|| "Cannot determine home directory".to_string())?; - let data_dir = home.join(".alphahuman"); + let data_dir = home.join(".openhuman"); std::fs::create_dir_all(&data_dir) .map_err(|e| format!("Failed to create data directory: {e}"))?; Ok(data_dir) } -/// Get the path to the encryption key file (~/.alphahuman/encryption.key). +/// Get the path to the encryption key file (~/.openhuman/encryption.key). fn get_key_file_path() -> Result { Ok(get_data_dir()?.join("encryption.key")) } diff --git a/src-tauri/src/ai/memory_fs.rs b/src-tauri/src/ai/memory_fs.rs index 0f5c97fa3..8c8ee913c 100644 --- a/src-tauri/src/ai/memory_fs.rs +++ b/src-tauri/src/ai/memory_fs.rs @@ -1,6 +1,6 @@ //! Filesystem-based memory index for AI memory storage. //! -//! Replaces the SQLite memory_db with JSON files under ~/.alphahuman/index/. +//! Replaces the SQLite memory_db with JSON files under ~/.openhuman/index/. //! Chunk files, file metadata, embedding cache, and KV metadata are all //! stored as readable JSON. All operations are exposed as Tauri commands //! with the same signatures as the former SQLite implementation. @@ -154,12 +154,12 @@ impl From for EmbeddingCacheEntry { // --- Path helpers --- -/// Get the index directory (~/.alphahuman/index/). +/// Get the index directory (~/.openhuman/index/). fn get_index_dir() -> Result { Ok(get_data_dir()?.join("index")) } -/// Get the chunks subdirectory (~/.alphahuman/index/chunks/). +/// Get the chunks subdirectory (~/.openhuman/index/chunks/). fn get_chunks_dir() -> Result { Ok(get_index_dir()?.join("chunks")) } diff --git a/src-tauri/src/ai/sessions.rs b/src-tauri/src/ai/sessions.rs index 0729e0bc3..1e726cb87 100644 --- a/src-tauri/src/ai/sessions.rs +++ b/src-tauri/src/ai/sessions.rs @@ -30,14 +30,14 @@ pub struct SessionIndexEntry { pub channel: Option, } -/// Get the sessions directory path (~/.alphahuman/sessions/). +/// Get the sessions directory path (~/.openhuman/sessions/). fn get_sessions_dir() -> Result { let dir = get_data_dir()?.join("sessions"); std::fs::create_dir_all(&dir).map_err(|e| format!("Create sessions dir: {e}"))?; Ok(dir) } -/// Get the session index file path (~/.alphahuman/sessions/sessions.json). +/// Get the session index file path (~/.openhuman/sessions/sessions.json). fn get_session_index_path() -> Result { Ok(get_sessions_dir()?.join("sessions.json")) } @@ -180,7 +180,7 @@ pub async fn ai_sessions_list() -> Result, String> { Ok(sessions) } -/// Read a memory file from ~/.alphahuman/. +/// Read a memory file from ~/.openhuman/. #[tauri::command] pub async fn ai_read_memory_file(relative_path: String) -> Result { let data_dir = get_data_dir()?; @@ -201,7 +201,7 @@ pub async fn ai_read_memory_file(relative_path: String) -> Result Result { let data_dir = get_data_dir()?; @@ -240,7 +240,7 @@ pub async fn ai_write_memory_file(relative_path: String, content: String) -> Res Ok(true) } -/// List memory files in a directory under ~/.alphahuman/. +/// List memory files in a directory under ~/.openhuman/. #[tauri::command] pub async fn ai_list_memory_files(relative_dir: String) -> Result, String> { let data_dir = get_data_dir()?; diff --git a/src-tauri/src/auth/mod.rs b/src-tauri/src/auth/mod.rs index 011546ff2..7f0ec296f 100644 --- a/src-tauri/src/auth/mod.rs +++ b/src-tauri/src/auth/mod.rs @@ -6,7 +6,7 @@ use crate::auth::openai_oauth::refresh_access_token; use crate::auth::profiles::{ profile_id, AuthProfile, AuthProfileKind, AuthProfilesData, AuthProfilesStore, }; -use crate::alphahuman::config::Config; +use crate::openhuman::config::Config; use anyhow::Result; use std::collections::HashMap; use std::path::{Path, PathBuf}; diff --git a/src-tauri/src/auth/openai_oauth.rs b/src-tauri/src/auth/openai_oauth.rs index 748c94e64..3a9072472 100644 --- a/src-tauri/src/auth/openai_oauth.rs +++ b/src-tauri/src/auth/openai_oauth.rs @@ -270,7 +270,7 @@ pub async fn receive_loopback_code(expected_state: &str, timeout: Duration) -> R let code = parse_code_from_redirect(path, Some(expected_state))?; let body = - "

Alphahuman login complete

You can close this tab.

"; + "

OpenHuman login complete

You can close this tab.

"; let response = format!( "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}", body.len(), diff --git a/src-tauri/src/auth/profiles.rs b/src-tauri/src/auth/profiles.rs index a31c04616..6e41b4759 100644 --- a/src-tauri/src/auth/profiles.rs +++ b/src-tauri/src/auth/profiles.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::security::SecretStore; +use crate::openhuman::security::SecretStore; use anyhow::{Context, Result}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/src/bin/alphahuman-core.rs b/src-tauri/src/bin/alphahuman-core.rs deleted file mode 100644 index 76c266723..000000000 --- a/src-tauri/src/bin/alphahuman-core.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let args: Vec = std::env::args().skip(1).collect(); - if let Err(err) = alphahuman::core_server::run_from_cli_args(&args) { - eprintln!("alphahuman-core failed: {err}"); - std::process::exit(1); - } -} diff --git a/src-tauri/src/bin/alphahuman-tools-discovery.rs b/src-tauri/src/bin/alphahuman-tools-discovery.rs deleted file mode 100644 index be3ed644f..000000000 --- a/src-tauri/src/bin/alphahuman-tools-discovery.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! AlphaHuman Tools Discovery Binary -//! -//! A standalone Rust binary that discovers all available tools from the V8 skills runtime -//! and outputs them as JSON for consumption by the build system. -//! -//! This binary is invoked during the build process to generate TOOLS.md automatically. - -use std::env; -use std::path::PathBuf; -use tokio; - -#[tokio::main] -async fn main() -> Result<(), Box> { - // Check if we're in tools discovery mode - if env::var("TAURI_TOOLS_DISCOVERY").is_err() { - eprintln!("This binary should only be run for tools discovery"); - std::process::exit(1); - } - - // Initialize minimal logging for discovery - env_logger::init(); - - // Platform check - V8 runtime only available on desktop - #[cfg(any(target_os = "android", target_os = "ios"))] - { - // Mobile platforms don't support V8 runtime - let result = serde_json::json!({ - "success": true, - "tools": [], - "message": "V8 runtime not available on mobile platforms" - }); - println!("{}", serde_json::to_string(&result)?); - return Ok(()); - } - - #[cfg(not(any(target_os = "android", target_os = "ios")))] - { - // Desktop platforms with V8 runtime - match discover_tools_desktop().await { - Ok(tools) => { - let result = serde_json::json!({ - "success": true, - "tools": tools - }); - println!("{}", serde_json::to_string(&result)?); - } - Err(error) => { - let result = serde_json::json!({ - "success": false, - "error": error.to_string(), - "tools": [] - }); - println!("{}", serde_json::to_string(&result)?); - std::process::exit(1); - } - } - } - - Ok(()) -} - -#[cfg(not(any(target_os = "android", target_os = "ios")))] -async fn discover_tools_desktop() -> Result, Box> { - // For now, return mock data until we can properly access the runtime engine - // The runtime module is private and the engine initialization is complex - log::info!("Using mock tools data for build-time discovery"); - - let mock_tools = vec![ - serde_json::json!({ - "skillId": "telegram", - "name": "send_message", - "description": "Send a message to a Telegram chat or user", - "inputSchema": { - "type": "object", - "properties": { - "chat_id": { "type": "string", "description": "Telegram chat ID or username" }, - "message": { "type": "string", "description": "Message text to send" }, - "parse_mode": { "type": "string", "description": "Message formatting mode" } - }, - "required": ["chat_id", "message"] - } - }), - serde_json::json!({ - "skillId": "telegram", - "name": "get_chat_history", - "description": "Retrieve message history from a Telegram chat", - "inputSchema": { - "type": "object", - "properties": { - "chat_id": { "type": "string", "description": "Telegram chat ID or username" }, - "limit": { "type": "number", "description": "Number of messages to retrieve" } - }, - "required": ["chat_id"] - } - }), - serde_json::json!({ - "skillId": "notion", - "name": "create_page", - "description": "Create a new page in Notion workspace", - "inputSchema": { - "type": "object", - "properties": { - "parent_id": { "type": "string", "description": "Parent database or page ID" }, - "title": { "type": "string", "description": "Page title" }, - "content": { "type": "array", "description": "Page content blocks" } - }, - "required": ["parent_id", "title"] - } - }), - serde_json::json!({ - "skillId": "gmail", - "name": "send_email", - "description": "Send an email via Gmail", - "inputSchema": { - "type": "object", - "properties": { - "to": { "type": "string", "description": "Recipient email address" }, - "subject": { "type": "string", "description": "Email subject line" }, - "body": { "type": "string", "description": "Email body content" } - }, - "required": ["to", "subject", "body"] - } - }) - ]; - - log::info!("Using {} mock tools for build-time generation", mock_tools.len()); - Ok(mock_tools) -} - -/// Determines the skills directory based on the current environment -fn determine_skills_directory() -> Result> { - // Try to find skills directory relative to project root - let current_dir = env::current_dir()?; - - // Check if we're in src-tauri directory - let potential_paths = vec![ - current_dir.join("skills"), - current_dir.parent().map(|p| p.join("skills")).unwrap_or_default(), - current_dir.join("../skills").canonicalize().unwrap_or_default(), - ]; - - for path in potential_paths { - if path.exists() && path.is_dir() { - log::info!("Found skills directory at: {:?}", path); - return Ok(path); - } - } - - Err("Could not find skills directory".into()) -} \ No newline at end of file diff --git a/src-tauri/src/bin/alphahuman-cli.rs b/src-tauri/src/bin/openhuman-cli.rs similarity index 84% rename from src-tauri/src/bin/alphahuman-cli.rs rename to src-tauri/src/bin/openhuman-cli.rs index c6baae83e..fe23dd7f7 100644 --- a/src-tauri/src/bin/alphahuman-cli.rs +++ b/src-tauri/src/bin/openhuman-cli.rs @@ -24,8 +24,8 @@ struct RpcError { } #[derive(Debug, Parser)] -#[command(name = "alphahuman-cli")] -#[command(about = "CLI for the AlphaHuman core RPC server")] +#[command(name = "openhuman-cli")] +#[command(about = "CLI for the OpenHuman core RPC server")] struct Cli { /// Core RPC endpoint URL #[arg(long, global = true)] @@ -178,7 +178,7 @@ fn endpoint(cli: &Cli) -> String { if let Some(url) = &cli.rpc_url { return url.clone(); } - std::env::var("ALPHAHUMAN_CORE_RPC_URL") + std::env::var("OPENHUMAN_CORE_RPC_URL") .unwrap_or_else(|_| "http://127.0.0.1:7788/rpc".to_string()) } @@ -217,10 +217,10 @@ fn execute(cli: Cli) -> Result { match cli.command { Command::Ping => call(&url, "core.ping", serde_json::json!({})), Command::Version => call(&url, "core.version", serde_json::json!({})), - Command::Health => call(&url, "alphahuman.health_snapshot", serde_json::json!({})), - Command::RuntimeFlags => call(&url, "alphahuman.get_runtime_flags", serde_json::json!({})), + Command::Health => call(&url, "openhuman.health_snapshot", serde_json::json!({})), + Command::RuntimeFlags => call(&url, "openhuman.get_runtime_flags", serde_json::json!({})), Command::Config { command } => match command { - ConfigCommand::Get => call(&url, "alphahuman.get_config", serde_json::json!({})), + ConfigCommand::Get => call(&url, "openhuman.get_config", serde_json::json!({})), }, Command::Service { command } => match command { ServiceCommand::Install => local_service_install(), @@ -234,13 +234,13 @@ fn execute(cli: Cli) -> Result { ServiceCommand::Uninstall => local_service_uninstall(), }, Command::Doctor { command } => match command { - DoctorCommand::Report => call(&url, "alphahuman.doctor_report", serde_json::json!({})), + DoctorCommand::Report => call(&url, "openhuman.doctor_report", serde_json::json!({})), DoctorCommand::Models { provider, use_cache, } => call( &url, - "alphahuman.doctor_models", + "openhuman.doctor_models", serde_json::json!({ "provider_override": provider, "use_cache": use_cache, @@ -249,17 +249,17 @@ fn execute(cli: Cli) -> Result { }, Command::Integrations { command } => match command { IntegrationsCommand::List => { - call(&url, "alphahuman.list_integrations", serde_json::json!({})) + call(&url, "openhuman.list_integrations", serde_json::json!({})) } IntegrationsCommand::Info { name } => call( &url, - "alphahuman.get_integration_info", + "openhuman.get_integration_info", serde_json::json!({ "name": name }), ), }, Command::AgentChat(args) => call( &url, - "alphahuman.agent_chat", + "openhuman.agent_chat", serde_json::json!({ "message": args.message, "provider_override": args.provider, @@ -269,32 +269,32 @@ fn execute(cli: Cli) -> Result { ), Command::Hardware { command } => match command { HardwareCommand::Discover => { - call(&url, "alphahuman.hardware_discover", serde_json::json!({})) + call(&url, "openhuman.hardware_discover", serde_json::json!({})) } HardwareCommand::Introspect { path } => call( &url, - "alphahuman.hardware_introspect", + "openhuman.hardware_introspect", serde_json::json!({ "path": path }), ), }, Command::Encrypt { plaintext } => call( &url, - "alphahuman.encrypt_secret", + "openhuman.encrypt_secret", serde_json::json!({ "plaintext": plaintext }), ), Command::Decrypt { ciphertext } => call( &url, - "alphahuman.decrypt_secret", + "openhuman.decrypt_secret", serde_json::json!({ "ciphertext": ciphertext }), ), Command::BrowserAllowAll { enabled } => call( &url, - "alphahuman.set_browser_allow_all", + "openhuman.set_browser_allow_all", serde_json::json!({ "enabled": enabled }), ), Command::ModelsRefresh { provider, force } => call( &url, - "alphahuman.models_refresh", + "openhuman.models_refresh", serde_json::json!({ "provider_override": provider, "force": force, @@ -305,7 +305,7 @@ fn execute(cli: Cli) -> Result { dry_run, } => call( &url, - "alphahuman.migrate_openclaw", + "openhuman.migrate_openclaw", serde_json::json!({ "source_workspace": source_workspace, "dry_run": dry_run, @@ -314,22 +314,22 @@ fn execute(cli: Cli) -> Result { } } -fn load_config() -> Result { +fn load_config() -> Result { let runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .map_err(|e| format!("failed to build runtime: {e}"))?; runtime - .block_on(alphahuman::alphahuman::config::Config::load_or_init()) + .block_on(openhuman::openhuman::config::Config::load_or_init()) .map_err(|e| format!("failed to load config: {e}")) } -fn status_value(status: alphahuman::alphahuman::service::ServiceStatus) -> Result { +fn status_value(status: openhuman::openhuman::service::ServiceStatus) -> Result { serde_json::to_value(status).map_err(|e| format!("failed to serialize service status: {e}")) } fn command_response_json( - status: alphahuman::alphahuman::service::ServiceStatus, + status: openhuman::openhuman::service::ServiceStatus, log: &str, ) -> Result { Ok(json!({ @@ -340,35 +340,35 @@ fn command_response_json( fn local_service_install() -> Result { let config = load_config()?; - let status = alphahuman::alphahuman::service::install(&config) + let status = openhuman::openhuman::service::install(&config) .map_err(|e| format!("service install failed: {e}"))?; command_response_json(status, "service install completed") } fn local_service_start() -> Result { let config = load_config()?; - let status = alphahuman::alphahuman::service::start(&config) + let status = openhuman::openhuman::service::start(&config) .map_err(|e| format!("service start failed: {e}"))?; command_response_json(status, "service start completed") } fn local_service_stop() -> Result { let config = load_config()?; - let status = alphahuman::alphahuman::service::stop(&config) + let status = openhuman::openhuman::service::stop(&config) .map_err(|e| format!("service stop failed: {e}"))?; command_response_json(status, "service stop completed") } fn local_service_status() -> Result { let config = load_config()?; - let status = alphahuman::alphahuman::service::status(&config) + let status = openhuman::openhuman::service::status(&config) .map_err(|e| format!("service status failed: {e}"))?; command_response_json(status, "service status fetched") } fn local_service_uninstall() -> Result { let config = load_config()?; - let status = alphahuman::alphahuman::service::uninstall(&config) + let status = openhuman::openhuman::service::uninstall(&config) .map_err(|e| format!("service uninstall failed: {e}"))?; command_response_json(status, "service uninstall completed") } diff --git a/src-tauri/src/bin/openhuman-core.rs b/src-tauri/src/bin/openhuman-core.rs new file mode 100644 index 000000000..7e10d092f --- /dev/null +++ b/src-tauri/src/bin/openhuman-core.rs @@ -0,0 +1,7 @@ +fn main() { + let args: Vec = std::env::args().skip(1).collect(); + if let Err(err) = openhuman::core_server::run_from_cli_args(&args) { + eprintln!("openhuman-core failed: {err}"); + std::process::exit(1); + } +} diff --git a/src-tauri/src/commands/chat.rs b/src-tauri/src/commands/chat.rs index fa2b5d763..a9a1ea124 100644 --- a/src-tauri/src/commands/chat.rs +++ b/src-tauri/src/commands/chat.rs @@ -209,12 +209,18 @@ impl ChatState { static AI_CONFIG_CACHE: once_cell::sync::Lazy>> = once_cell::sync::Lazy::new(|| parking_lot::RwLock::new(None)); +/// Clear cached OpenClaw context (used after AI config file updates). +pub fn clear_openclaw_context_cache() { + *AI_CONFIG_CACHE.write() = None; +} + /// Load all AI config files and build the OpenClaw context string. /// /// Tries these locations in order: /// 1. Tauri resource directory (production builds — files bundled via `tauri.conf.json` resources) -/// 2. `{cwd}/../ai/` (dev mode — project root relative to `src-tauri/`) -/// 3. `{cwd}/ai/` (fallback) +/// 2. `{cwd}/src-tauri/ai/` (dev mode when cwd is project root) +/// 3. `{cwd}/ai/` (dev mode when cwd is `src-tauri/`) +/// 4. `{cwd}/../ai/` (legacy fallback) /// /// Returns an empty string if no files are found (non-fatal). fn load_openclaw_context(app: &tauri::AppHandle) -> String { @@ -268,19 +274,18 @@ fn find_ai_directory(app: &tauri::AppHandle) -> Option { } } - // 2. Try cwd/../ai/ (dev mode; cwd is src-tauri/) + // 2. Try cwd/src-tauri/ai/ (dev mode; cwd is project root) if let Ok(cwd) = std::env::current_dir() { - let dev_dir = cwd.parent().map(|p| p.join("ai")); - if let Some(ref dir) = dev_dir { - if dir.is_dir() { - log::info!( - "[chat] Using AI config from dev dir: {}", - dir.display() - ); - return dev_dir; - } + let root_dev_dir = cwd.join("src-tauri").join("ai"); + if root_dev_dir.is_dir() { + log::info!( + "[chat] Using AI config from root dev dir: {}", + root_dev_dir.display() + ); + return Some(root_dev_dir); } - // 3. Try cwd/ai/ (fallback) + + // 3. Try cwd/ai/ (dev mode; cwd is src-tauri/) let fallback = cwd.join("ai"); if fallback.is_dir() { log::info!( @@ -289,6 +294,17 @@ fn find_ai_directory(app: &tauri::AppHandle) -> Option { ); return Some(fallback); } + + // 4. Legacy fallback: cwd/../ai/ + if let Some(legacy_dir) = cwd.parent().map(|p| p.join("ai")) { + if legacy_dir.is_dir() { + log::info!( + "[chat] Using AI config from legacy dev dir: {}", + legacy_dir.display() + ); + return Some(legacy_dir); + } + } } log::warn!("[chat] No AI config directory found"); @@ -599,6 +615,160 @@ async fn chat_send_inner( skill_contexts.len() ); + // ── Step 2c: Query memory if recall context is insufficient ────────── + // + // Ask the LLM whether the recalled context is sufficient to answer the + // user. If not, it generates a targeted query and we call queryMemory + // to fetch extended context before building the final prompt. + let query_memory_context: Option = if let Some(ref mem) = memory_client { + if cancel.is_cancelled() { + return Err("Request cancelled".to_string()); + } + + let recall_summary = memory_context.as_deref().unwrap_or(""); + let skill_summary = skill_contexts.join("\n"); + + // Build the list of valid skill IDs for the LLM to choose from. + // "conversations" covers general conversation history. + let mut available_skills: Vec = skill_ids.iter().cloned().collect(); + available_skills.sort(); + available_skills.push("conversations".to_string()); + let skill_list = available_skills.join(", "); + + let sufficiency_prompt = format!( + "You are a memory sufficiency checker. Given the recalled memory context and the \ + user's question, decide if the recalled context contains enough specific information \ + to answer the user.\n\n\ + Recalled context:\n{recall_summary}\n{skill_summary}\n\n\ + User message: {user_message}\n\n\ + Available skill namespaces: {skill_list}\n\n\ + Respond in JSON only:\n\ + - If sufficient: {{\"needs_query\": false}}\n\ + - If more context needed: {{\"needs_query\": true, \"skill_id\": \"\", \"query\": \"\"}}" + ); + + let check_body = serde_json::json!({ + "model": model, + "messages": [{"role": "user", "content": sufficiency_prompt}], + }); + + let check_url = format!("{}/openai/v1/chat/completions", backend_url); + + log::info!("[chat] Step 2c: running memory sufficiency check"); + log::info!( + "[chat] Step 2c request body: {}", + serde_json::to_string_pretty(&check_body).unwrap_or_default() + ); + + match tokio::time::timeout( + std::time::Duration::from_secs(30), + client + .post(&check_url) + .header("Authorization", format!("Bearer {}", auth_token)) + .header("Content-Type", "application/json") + .json(&check_body) + .send(), + ) + .await + { + Ok(Ok(resp)) if resp.status().is_success() => { + match resp.json::().await { + Ok(completion) => { + let content = completion + .choices + .first() + .and_then(|c| c.message.content.as_deref()) + .unwrap_or(""); + + match serde_json::from_str::(content) { + Ok(parsed) => { + if parsed.get("needs_query").and_then(|v| v.as_bool()) + == Some(true) + { + if let Some(query) = + parsed.get("query").and_then(|v| v.as_str()) + { + let skill_id = parsed + .get("skill_id") + .and_then(|v| v.as_str()) + .unwrap_or("conversations"); + log::info!( + "[chat] Sufficiency check: needs_query=true, skill_id={skill_id:?}, query={query:?}" + ); + match mem + .query_skill_context( + skill_id, + thread_id, + query, + 10, + ) + .await + { + Ok(result) if !result.is_empty() => { + log::info!( + "[chat] queryMemory returned {} chars", + result.len() + ); + Some(result) + } + Ok(_) => { + log::info!( + "[chat] queryMemory returned empty result" + ); + None + } + Err(e) => { + log::warn!("[chat] queryMemory failed: {e}"); + None + } + } + } else { + log::warn!( + "[chat] Sufficiency check: needs_query=true but no query field" + ); + None + } + } else { + log::info!( + "[chat] Sufficiency check: recall context is sufficient" + ); + None + } + } + Err(_) => { + log::warn!( + "[chat] Sufficiency check: failed to parse JSON response: {content}" + ); + None + } + } + } + Err(e) => { + log::warn!("[chat] Sufficiency check: failed to parse inference response: {e}"); + None + } + } + } + Ok(Ok(resp)) => { + log::warn!( + "[chat] Sufficiency check: inference returned HTTP {}", + resp.status() + ); + None + } + Ok(Err(e)) => { + log::warn!("[chat] Sufficiency check: network error: {e}"); + None + } + Err(_) => { + log::warn!("[chat] Sufficiency check: timed out after 30s, skipping queryMemory"); + None + } + } + } else { + None + }; + // ── Step 3: Build processed user message ──────────────────────────── let mut processed = user_message.to_string(); @@ -617,6 +787,12 @@ async fn chat_send_inner( processed = format!("{}\n\n{}", skill_contexts.join("\n\n"), processed); } + if let Some(ref qctx) = query_memory_context { + processed = format!( + "[QUERY_MEMORY_CONTEXT]\n{qctx}\n[/QUERY_MEMORY_CONTEXT]\n\n{processed}" + ); + } + if let Some(ref notion) = notion_context { processed = format!("{}\n\n{}", notion, processed); } @@ -683,7 +859,7 @@ async fn chat_send_inner( loop_messages.len(), url ); - log::debug!( + log::info!( "[chat] Request body: {}", serde_json::to_string_pretty(&request_body).unwrap_or_default() ); @@ -1062,6 +1238,10 @@ async fn chat_send_mobile( model, messages.len() ); + log::info!( + "[chat] Request body: {}", + serde_json::to_string_pretty(&request_body).unwrap_or_default() + ); let response = tokio::select! { _ = cancel.cancelled() => { diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index c295a5f62..84642db05 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -4,7 +4,7 @@ pub mod memory; pub mod model; pub mod runtime; pub mod socket; -pub mod alphahuman; +pub mod openhuman; pub mod unified_skills; #[cfg(desktop)] @@ -17,7 +17,7 @@ pub use memory::*; pub use model::*; pub use runtime::*; pub use socket::*; -pub use alphahuman::*; +pub use openhuman::*; #[cfg(desktop)] pub use window::*; diff --git a/src-tauri/src/commands/alphahuman.rs b/src-tauri/src/commands/openhuman.rs similarity index 73% rename from src-tauri/src/commands/alphahuman.rs rename to src-tauri/src/commands/openhuman.rs index 5d6bc89cd..55b6f01ed 100644 --- a/src-tauri/src/commands/alphahuman.rs +++ b/src-tauri/src/commands/openhuman.rs @@ -1,6 +1,6 @@ -//! Tauri command proxies for the standalone alphahuman core process. +//! Tauri command proxies for the standalone openhuman core process. -use crate::alphahuman::{doctor, hardware, integrations, migration, onboard, service}; +use crate::openhuman::{doctor, hardware, integrations, migration, onboard, service}; use crate::core_server::{ BrowserSettingsUpdate, CommandResponse, ConfigSnapshot, GatewaySettingsUpdate, MemorySettingsUpdate, ModelSettingsUpdate, RuntimeFlags, RuntimeSettingsUpdate, @@ -32,11 +32,11 @@ async fn call_core( crate::core_rpc::call(method, params).await } -async fn load_config_local() -> Result { +async fn load_config_local() -> Result { let timeout_duration = std::time::Duration::from_secs(30); match tokio::time::timeout( timeout_duration, - crate::alphahuman::config::Config::load_or_init(), + crate::openhuman::config::Config::load_or_init(), ) .await { @@ -54,65 +54,65 @@ pub struct AgentServerStatus { /// Return the current health snapshot as JSON. #[tauri::command] -pub async fn alphahuman_health_snapshot( +pub async fn openhuman_health_snapshot( app: tauri::AppHandle, ) -> Result, String> { - call_core(&app, "alphahuman.health_snapshot", params_none()).await + call_core(&app, "openhuman.health_snapshot", params_none()).await } /// Return the default security policy info (autonomy config summary). #[tauri::command] -pub async fn alphahuman_security_policy_info( +pub async fn openhuman_security_policy_info( app: tauri::AppHandle, ) -> Result, String> { - call_core(&app, "alphahuman.security_policy_info", params_none()).await + call_core(&app, "openhuman.security_policy_info", params_none()).await } -/// Encrypt a secret using the alphahuman SecretStore. +/// Encrypt a secret using the openhuman SecretStore. #[tauri::command] -pub async fn alphahuman_encrypt_secret( +pub async fn openhuman_encrypt_secret( app: tauri::AppHandle, plaintext: String, ) -> Result, String> { call_core( &app, - "alphahuman.encrypt_secret", + "openhuman.encrypt_secret", serde_json::json!({ "plaintext": plaintext }), ) .await } -/// Decrypt a secret using the alphahuman SecretStore. +/// Decrypt a secret using the openhuman SecretStore. #[tauri::command] -pub async fn alphahuman_decrypt_secret( +pub async fn openhuman_decrypt_secret( app: tauri::AppHandle, ciphertext: String, ) -> Result, String> { call_core( &app, - "alphahuman.decrypt_secret", + "openhuman.decrypt_secret", serde_json::json!({ "ciphertext": ciphertext }), ) .await } -/// Return the full Alphahuman config snapshot for UI editing. +/// Return the full OpenHuman config snapshot for UI editing. #[tauri::command] -pub async fn alphahuman_get_config( +pub async fn openhuman_get_config( app: tauri::AppHandle, ) -> Result, String> { - call_core(&app, "alphahuman.get_config", params_none()).await + call_core(&app, "openhuman.get_config", params_none()).await } /// Update model/provider settings. #[tauri::command] -pub async fn alphahuman_update_model_settings( +pub async fn openhuman_update_model_settings( app: tauri::AppHandle, update: ModelSettingsUpdate, ) -> Result, String> { call_core( &app, - "alphahuman.update_model_settings", + "openhuman.update_model_settings", serde_json::json!(update), ) .await @@ -120,13 +120,13 @@ pub async fn alphahuman_update_model_settings( /// Update memory settings. #[tauri::command] -pub async fn alphahuman_update_memory_settings( +pub async fn openhuman_update_memory_settings( app: tauri::AppHandle, update: MemorySettingsUpdate, ) -> Result, String> { call_core( &app, - "alphahuman.update_memory_settings", + "openhuman.update_memory_settings", serde_json::json!(update), ) .await @@ -134,13 +134,13 @@ pub async fn alphahuman_update_memory_settings( /// Update gateway settings. #[tauri::command] -pub async fn alphahuman_update_gateway_settings( +pub async fn openhuman_update_gateway_settings( app: tauri::AppHandle, update: GatewaySettingsUpdate, ) -> Result, String> { call_core( &app, - "alphahuman.update_gateway_settings", + "openhuman.update_gateway_settings", serde_json::json!(update), ) .await @@ -148,13 +148,13 @@ pub async fn alphahuman_update_gateway_settings( /// Update tunnel settings (full tunnel config). #[tauri::command] -pub async fn alphahuman_update_tunnel_settings( +pub async fn openhuman_update_tunnel_settings( app: tauri::AppHandle, - tunnel: crate::alphahuman::config::TunnelConfig, + tunnel: crate::openhuman::config::TunnelConfig, ) -> Result, String> { call_core( &app, - "alphahuman.update_tunnel_settings", + "openhuman.update_tunnel_settings", serde_json::json!(tunnel), ) .await @@ -162,13 +162,13 @@ pub async fn alphahuman_update_tunnel_settings( /// Update runtime settings (skill execution backend). #[tauri::command] -pub async fn alphahuman_update_runtime_settings( +pub async fn openhuman_update_runtime_settings( app: tauri::AppHandle, update: RuntimeSettingsUpdate, ) -> Result, String> { call_core( &app, - "alphahuman.update_runtime_settings", + "openhuman.update_runtime_settings", serde_json::json!(update), ) .await @@ -176,13 +176,13 @@ pub async fn alphahuman_update_runtime_settings( /// Update browser settings (Chrome/Chromium tool). #[tauri::command] -pub async fn alphahuman_update_browser_settings( +pub async fn openhuman_update_browser_settings( app: tauri::AppHandle, update: BrowserSettingsUpdate, ) -> Result, String> { call_core( &app, - "alphahuman.update_browser_settings", + "openhuman.update_browser_settings", serde_json::json!(update), ) .await @@ -190,29 +190,29 @@ pub async fn alphahuman_update_browser_settings( /// Read runtime flags that are controlled via environment variables. #[tauri::command] -pub async fn alphahuman_get_runtime_flags( +pub async fn openhuman_get_runtime_flags( app: tauri::AppHandle, ) -> Result, String> { - call_core(&app, "alphahuman.get_runtime_flags", params_none()).await + call_core(&app, "openhuman.get_runtime_flags", params_none()).await } /// Set browser allow-all flag for the current process. #[tauri::command] -pub async fn alphahuman_set_browser_allow_all( +pub async fn openhuman_set_browser_allow_all( app: tauri::AppHandle, enabled: bool, ) -> Result, String> { call_core( &app, - "alphahuman.set_browser_allow_all", + "openhuman.set_browser_allow_all", serde_json::json!({ "enabled": enabled }), ) .await } -/// Send a single message to the Alphahuman agent and return the response text. +/// Send a single message to the OpenHuman agent and return the response text. #[tauri::command] -pub async fn alphahuman_agent_chat( +pub async fn openhuman_agent_chat( app: tauri::AppHandle, message: String, provider_override: Option, @@ -221,7 +221,7 @@ pub async fn alphahuman_agent_chat( ) -> Result, String> { call_core( &app, - "alphahuman.agent_chat", + "openhuman.agent_chat", serde_json::json!({ "message": message, "provider_override": provider_override, @@ -232,24 +232,24 @@ pub async fn alphahuman_agent_chat( .await } -/// Run Alphahuman doctor checks and return a structured report. +/// Run OpenHuman doctor checks and return a structured report. #[tauri::command] -pub async fn alphahuman_doctor_report( +pub async fn openhuman_doctor_report( app: tauri::AppHandle, ) -> Result, String> { - call_core(&app, "alphahuman.doctor_report", params_none()).await + call_core(&app, "openhuman.doctor_report", params_none()).await } /// Run model catalog probes for providers. #[tauri::command] -pub async fn alphahuman_doctor_models( +pub async fn openhuman_doctor_models( app: tauri::AppHandle, provider_override: Option, use_cache: Option, ) -> Result, String> { call_core( &app, - "alphahuman.doctor_models", + "openhuman.doctor_models", serde_json::json!({ "provider_override": provider_override, "use_cache": use_cache, @@ -260,10 +260,10 @@ pub async fn alphahuman_doctor_models( /// List integrations with status for the current config. #[tauri::command] -pub async fn alphahuman_list_integrations( +pub async fn openhuman_list_integrations( app: tauri::AppHandle, ) -> Result>, String> { - call_core(&app, "alphahuman.list_integrations", params_none()).await + call_core(&app, "openhuman.list_integrations", params_none()).await } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -273,14 +273,14 @@ struct IntegrationInfoParams { /// Get details for a single integration. #[tauri::command] -pub async fn alphahuman_get_integration_info( +pub async fn openhuman_get_integration_info( app: tauri::AppHandle, name: String, ) -> Result, String> { let params = IntegrationInfoParams { name }; call_core( &app, - "alphahuman.get_integration_info", + "openhuman.get_integration_info", serde_json::json!(params), ) .await @@ -288,14 +288,14 @@ pub async fn alphahuman_get_integration_info( /// Refresh the model catalog for a provider (or default provider). #[tauri::command] -pub async fn alphahuman_models_refresh( +pub async fn openhuman_models_refresh( app: tauri::AppHandle, provider_override: Option, force: Option, ) -> Result, String> { call_core( &app, - "alphahuman.models_refresh", + "openhuman.models_refresh", serde_json::json!({ "provider_override": provider_override, "force": force, @@ -304,16 +304,16 @@ pub async fn alphahuman_models_refresh( .await } -/// Migrate OpenClaw memory into the current Alphahuman workspace. +/// Migrate OpenClaw memory into the current OpenHuman workspace. #[tauri::command] -pub async fn alphahuman_migrate_openclaw( +pub async fn openhuman_migrate_openclaw( app: tauri::AppHandle, source_workspace: Option, dry_run: Option, ) -> Result, String> { call_core( &app, - "alphahuman.migrate_openclaw", + "openhuman.migrate_openclaw", serde_json::json!({ "source_workspace": source_workspace, "dry_run": dry_run, @@ -324,21 +324,21 @@ pub async fn alphahuman_migrate_openclaw( /// Discover connected hardware devices (feature-gated). #[tauri::command] -pub async fn alphahuman_hardware_discover( +pub async fn openhuman_hardware_discover( app: tauri::AppHandle, ) -> Result>, String> { - call_core(&app, "alphahuman.hardware_discover", params_none()).await + call_core(&app, "openhuman.hardware_discover", params_none()).await } /// Introspect a device path (feature-gated). #[tauri::command] -pub async fn alphahuman_hardware_introspect( +pub async fn openhuman_hardware_introspect( app: tauri::AppHandle, path: String, ) -> Result, String> { call_core( &app, - "alphahuman.hardware_introspect", + "openhuman.hardware_introspect", serde_json::json!({ "path": path }), ) .await @@ -346,8 +346,8 @@ pub async fn alphahuman_hardware_introspect( /// Return whether the local core agent server is reachable. #[tauri::command] -pub async fn alphahuman_agent_server_status() -> Result, String> { - let url = std::env::var("ALPHAHUMAN_CORE_RPC_URL").unwrap_or_else(|_| DEFAULT_CORE_RPC_URL.to_string()); +pub async fn openhuman_agent_server_status() -> Result, String> { + let url = std::env::var("OPENHUMAN_CORE_RPC_URL").unwrap_or_else(|_| DEFAULT_CORE_RPC_URL.to_string()); let running = crate::core_rpc::ping().await; Ok(CommandResponse { result: AgentServerStatus { running, url }, @@ -355,9 +355,9 @@ pub async fn alphahuman_agent_server_status() -> Result Result, String> { let config = load_config_local().await?; @@ -369,9 +369,9 @@ pub async fn alphahuman_service_install( .map_err(|e| e.to_string()) } -/// Start the Alphahuman daemon service. +/// Start the OpenHuman daemon service. #[tauri::command] -pub async fn alphahuman_service_start( +pub async fn openhuman_service_start( _app: tauri::AppHandle, ) -> Result, String> { let config = load_config_local().await?; @@ -383,9 +383,9 @@ pub async fn alphahuman_service_start( .map_err(|e| e.to_string()) } -/// Stop the Alphahuman daemon service. +/// Stop the OpenHuman daemon service. #[tauri::command] -pub async fn alphahuman_service_stop( +pub async fn openhuman_service_stop( app: tauri::AppHandle, ) -> Result, String> { let config = load_config_local().await?; @@ -404,9 +404,9 @@ pub async fn alphahuman_service_stop( }) } -/// Get the Alphahuman daemon service status. +/// Get the OpenHuman daemon service status. #[tauri::command] -pub async fn alphahuman_service_status( +pub async fn openhuman_service_status( _app: tauri::AppHandle, ) -> Result, String> { let config = load_config_local().await?; @@ -418,9 +418,9 @@ pub async fn alphahuman_service_status( .map_err(|e| e.to_string()) } -/// Uninstall the Alphahuman daemon service. +/// Uninstall the OpenHuman daemon service. #[tauri::command] -pub async fn alphahuman_service_uninstall( +pub async fn openhuman_service_uninstall( app: tauri::AppHandle, ) -> Result, String> { let config = load_config_local().await?; diff --git a/src-tauri/src/commands/unified_skills.rs b/src-tauri/src/commands/unified_skills.rs index c907ffd96..f4f7665a9 100644 --- a/src-tauri/src/commands/unified_skills.rs +++ b/src-tauri/src/commands/unified_skills.rs @@ -1,7 +1,7 @@ //! Tauri commands for the unified skill registry. //! //! These commands expose a single, type-agnostic API to the frontend WebView. -//! Internally they dispatch to the QuickJS runtime (alphahuman skills) or the +//! Internally they dispatch to the QuickJS runtime (openhuman skills) or the //! file-based executor (openclaw skills) based on `skill_type`. //! //! Commands are desktop-only — mobile stubs return empty/error results. @@ -24,7 +24,7 @@ mod desktop { use super::*; use crate::unified_skills::UnifiedSkillRegistry; - /// List all skills from the unified registry (both alphahuman and openclaw types). + /// List all skills from the unified registry (both openhuman and openclaw types). #[tauri::command] pub async fn unified_list_skills( engine: State<'_, Arc>, @@ -36,7 +36,7 @@ mod desktop { /// Execute a named tool on any registered skill. /// /// Dispatches based on skill_type: - /// - `alphahuman` → QuickJS runtime + /// - `openhuman` → QuickJS runtime /// - `openclaw` → shell/http executor or returns prompt content #[tauri::command] pub async fn unified_execute_skill( @@ -51,7 +51,7 @@ mod desktop { /// Programmatically generate a new skill, register it, and return its entry. /// - /// For `skill_type = "alphahuman"`: writes manifest.json + index.js to the skills dir. + /// For `skill_type = "openhuman"`: writes manifest.json + index.js to the skills dir. /// For `skill_type = "openclaw"`: writes SKILL.md or SKILL.toml to workspace/skills/. /// /// The skill is immediately available in subsequent `unified_list_skills` calls. diff --git a/src-tauri/src/core_process.rs b/src-tauri/src/core_process.rs index b2aabfac5..68a43cd12 100644 --- a/src-tauri/src/core_process.rs +++ b/src-tauri/src/core_process.rs @@ -81,7 +81,7 @@ impl CoreProcessHandle { } pub fn default_core_port() -> u16 { - std::env::var("ALPHAHUMAN_CORE_PORT") + std::env::var("OPENHUMAN_CORE_PORT") .ok() .and_then(|v| v.parse::().ok()) .unwrap_or(7788) diff --git a/src-tauri/src/core_rpc.rs b/src-tauri/src/core_rpc.rs index 946c3d67f..4dee47a3a 100644 --- a/src-tauri/src/core_rpc.rs +++ b/src-tauri/src/core_rpc.rs @@ -30,7 +30,7 @@ struct RpcError { } fn rpc_url() -> String { - std::env::var("ALPHAHUMAN_CORE_RPC_URL").unwrap_or_else(|_| DEFAULT_CORE_RPC_URL.to_string()) + std::env::var("OPENHUMAN_CORE_RPC_URL").unwrap_or_else(|_| DEFAULT_CORE_RPC_URL.to_string()) } pub async fn call( diff --git a/src-tauri/src/core_server.rs b/src-tauri/src/core_server.rs index 7f81e4fdf..8c955dae0 100644 --- a/src-tauri/src/core_server.rs +++ b/src-tauri/src/core_server.rs @@ -8,10 +8,10 @@ use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use serde_json::json; -use crate::alphahuman::config::Config; -use crate::alphahuman::health; -use crate::alphahuman::security::{SecretStore, SecurityPolicy}; -use crate::alphahuman::{doctor, hardware, integrations, migration, onboard, service}; +use crate::openhuman::config::Config; +use crate::openhuman::health; +use crate::openhuman::security::{SecretStore, SecurityPolicy}; +use crate::openhuman::{doctor, hardware, integrations, migration, onboard, service}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CommandResponse { @@ -160,7 +160,7 @@ struct SetBrowserAllowAllParams { enabled: bool, } -async fn load_alphahuman_config() -> Result { +async fn load_openhuman_config() -> Result { let timeout_duration = std::time::Duration::from_secs(30); match tokio::time::timeout(timeout_duration, Config::load_or_init()).await { Ok(Ok(config)) => Ok(config), @@ -249,12 +249,12 @@ async fn dispatch( "core.ping" => to_json_value(json!({ "ok": true })), "core.version" => to_json_value(json!({ "version": state.core_version })), - "alphahuman.health_snapshot" => to_json_value(command_response( + "openhuman.health_snapshot" => to_json_value(command_response( health::snapshot_json(), vec!["health_snapshot requested".to_string()], )), - "alphahuman.security_policy_info" => { + "openhuman.security_policy_info" => { let policy = SecurityPolicy::default(); let payload = json!({ "autonomy": policy.autonomy, @@ -270,8 +270,8 @@ async fn dispatch( )) } - "alphahuman.get_config" => { - let config = load_alphahuman_config().await?; + "openhuman.get_config" => { + let config = load_openhuman_config().await?; let snapshot = snapshot_config(&config)?; to_json_value(command_response( snapshot, @@ -282,9 +282,9 @@ async fn dispatch( )) } - "alphahuman.update_model_settings" => { + "openhuman.update_model_settings" => { let update: ModelSettingsUpdate = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(api_key) = update.api_key { config.api_key = if api_key.trim().is_empty() { None @@ -327,9 +327,9 @@ async fn dispatch( )) } - "alphahuman.update_memory_settings" => { + "openhuman.update_memory_settings" => { let update: MemorySettingsUpdate = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(backend) = update.backend { config.memory.backend = backend; } @@ -356,9 +356,9 @@ async fn dispatch( )) } - "alphahuman.update_gateway_settings" => { + "openhuman.update_gateway_settings" => { let update: GatewaySettingsUpdate = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(host) = update.host { config.gateway.host = host; } @@ -382,9 +382,9 @@ async fn dispatch( )) } - "alphahuman.update_tunnel_settings" => { - let tunnel: crate::alphahuman::config::TunnelConfig = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + "openhuman.update_tunnel_settings" => { + let tunnel: crate::openhuman::config::TunnelConfig = parse_params(params)?; + let mut config = load_openhuman_config().await?; config.tunnel = tunnel; config.save().await.map_err(|e| e.to_string())?; let snapshot = snapshot_config(&config)?; @@ -397,9 +397,9 @@ async fn dispatch( )) } - "alphahuman.update_runtime_settings" => { + "openhuman.update_runtime_settings" => { let update: RuntimeSettingsUpdate = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(kind) = update.kind { config.runtime.kind = kind; } @@ -417,9 +417,9 @@ async fn dispatch( )) } - "alphahuman.update_browser_settings" => { + "openhuman.update_browser_settings" => { let update: BrowserSettingsUpdate = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(enabled) = update.enabled { config.browser.enabled = enabled; } @@ -434,10 +434,10 @@ async fn dispatch( )) } - "alphahuman.get_runtime_flags" => { + "openhuman.get_runtime_flags" => { let flags = RuntimeFlags { - browser_allow_all: env_flag_enabled("ALPHAHUMAN_BROWSER_ALLOW_ALL"), - log_prompts: env_flag_enabled("ALPHAHUMAN_LOG_PROMPTS"), + browser_allow_all: env_flag_enabled("OPENHUMAN_BROWSER_ALLOW_ALL"), + log_prompts: env_flag_enabled("OPENHUMAN_LOG_PROMPTS"), }; to_json_value(command_response( flags, @@ -445,16 +445,16 @@ async fn dispatch( )) } - "alphahuman.set_browser_allow_all" => { + "openhuman.set_browser_allow_all" => { let p: SetBrowserAllowAllParams = parse_params(params)?; if p.enabled { - std::env::set_var("ALPHAHUMAN_BROWSER_ALLOW_ALL", "1"); + std::env::set_var("OPENHUMAN_BROWSER_ALLOW_ALL", "1"); } else { - std::env::remove_var("ALPHAHUMAN_BROWSER_ALLOW_ALL"); + std::env::remove_var("OPENHUMAN_BROWSER_ALLOW_ALL"); } let flags = RuntimeFlags { - browser_allow_all: env_flag_enabled("ALPHAHUMAN_BROWSER_ALLOW_ALL"), - log_prompts: env_flag_enabled("ALPHAHUMAN_LOG_PROMPTS"), + browser_allow_all: env_flag_enabled("OPENHUMAN_BROWSER_ALLOW_ALL"), + log_prompts: env_flag_enabled("OPENHUMAN_LOG_PROMPTS"), }; to_json_value(command_response( flags, @@ -462,9 +462,9 @@ async fn dispatch( )) } - "alphahuman.agent_chat" => { + "openhuman.agent_chat" => { let p: AgentChatParams = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(provider) = p.provider_override { config.default_provider = Some(provider); } @@ -475,7 +475,7 @@ async fn dispatch( config.default_temperature = temp; } let mut agent = - crate::alphahuman::agent::Agent::from_config(&config).map_err(|e| e.to_string())?; + crate::openhuman::agent::Agent::from_config(&config).map_err(|e| e.to_string())?; let response = agent .run_single(&p.message) .await @@ -486,9 +486,9 @@ async fn dispatch( )) } - "alphahuman.encrypt_secret" => { + "openhuman.encrypt_secret" => { let p: EncryptSecretParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let store = secret_store_for_config(&config); let ciphertext = store.encrypt(&p.plaintext).map_err(|e| e.to_string())?; to_json_value(command_response( @@ -497,9 +497,9 @@ async fn dispatch( )) } - "alphahuman.decrypt_secret" => { + "openhuman.decrypt_secret" => { let p: DecryptSecretParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let store = secret_store_for_config(&config); let plaintext = store.decrypt(&p.ciphertext).map_err(|e| e.to_string())?; to_json_value(command_response( @@ -508,8 +508,8 @@ async fn dispatch( )) } - "alphahuman.doctor_report" => { - let config = load_alphahuman_config().await?; + "openhuman.doctor_report" => { + let config = load_openhuman_config().await?; let report = doctor::run(&config).map_err(|e| e.to_string())?; to_json_value(command_response( report, @@ -517,9 +517,9 @@ async fn dispatch( )) } - "alphahuman.doctor_models" => { + "openhuman.doctor_models" => { let p: DoctorModelsParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let use_cache = p.use_cache.unwrap_or(true); let report = doctor::run_models(&config, p.provider_override.as_deref(), use_cache) .map_err(|e| e.to_string())?; @@ -529,17 +529,17 @@ async fn dispatch( )) } - "alphahuman.list_integrations" => { - let config = load_alphahuman_config().await?; + "openhuman.list_integrations" => { + let config = load_openhuman_config().await?; to_json_value(command_response( integrations::list_integrations(&config), vec!["integrations listed".to_string()], )) } - "alphahuman.get_integration_info" => { + "openhuman.get_integration_info" => { let p: IntegrationInfoParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let info = integrations::get_integration_info(&config, &p.name).map_err(|e| e.to_string())?; to_json_value(command_response( @@ -548,9 +548,9 @@ async fn dispatch( )) } - "alphahuman.models_refresh" => { + "openhuman.models_refresh" => { let p: ModelsRefreshParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let result = onboard::run_models_refresh( &config, p.provider_override.as_deref(), @@ -563,9 +563,9 @@ async fn dispatch( )) } - "alphahuman.migrate_openclaw" => { + "openhuman.migrate_openclaw" => { let p: MigrateOpenClawParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let source = p.source_workspace.map(std::path::PathBuf::from); let report = migration::migrate_openclaw_memory(&config, source, p.dry_run.unwrap_or(true)) @@ -577,12 +577,12 @@ async fn dispatch( )) } - "alphahuman.hardware_discover" => to_json_value(command_response( + "openhuman.hardware_discover" => to_json_value(command_response( hardware::discover_hardware(), vec!["hardware discovery complete".to_string()], )), - "alphahuman.hardware_introspect" => { + "openhuman.hardware_introspect" => { let p: HardwareIntrospectParams = parse_params(params)?; let info = hardware::introspect_device(&p.path).map_err(|e| e.to_string())?; to_json_value(command_response( @@ -591,8 +591,8 @@ async fn dispatch( )) } - "alphahuman.service_install" => { - let config = load_alphahuman_config().await?; + "openhuman.service_install" => { + let config = load_openhuman_config().await?; let status = service::install(&config).map_err(|e| e.to_string())?; to_json_value(command_response( status, @@ -600,8 +600,8 @@ async fn dispatch( )) } - "alphahuman.service_start" => { - let config = load_alphahuman_config().await?; + "openhuman.service_start" => { + let config = load_openhuman_config().await?; let status = service::start(&config).map_err(|e| e.to_string())?; to_json_value(command_response( status, @@ -609,8 +609,8 @@ async fn dispatch( )) } - "alphahuman.service_stop" => { - let config = load_alphahuman_config().await?; + "openhuman.service_stop" => { + let config = load_openhuman_config().await?; let status = service::stop(&config).map_err(|e| e.to_string())?; to_json_value(command_response( status, @@ -618,8 +618,8 @@ async fn dispatch( )) } - "alphahuman.service_status" => { - let config = load_alphahuman_config().await?; + "openhuman.service_status" => { + let config = load_openhuman_config().await?; let status = service::status(&config).map_err(|e| e.to_string())?; to_json_value(command_response( status, @@ -627,8 +627,8 @@ async fn dispatch( )) } - "alphahuman.service_uninstall" => { - let config = load_alphahuman_config().await?; + "openhuman.service_uninstall" => { + let config = load_openhuman_config().await?; let status = service::uninstall(&config).map_err(|e| e.to_string())?; to_json_value(command_response( status, @@ -648,7 +648,7 @@ async fn root_handler() -> impl IntoResponse { ( StatusCode::OK, Json(json!({ - "name": "alphahuman-core", + "name": "openhuman-core", "ok": true, "endpoints": { "health": "/health", @@ -677,7 +677,7 @@ async fn not_found_handler() -> impl IntoResponse { } fn core_port() -> u16 { - std::env::var("ALPHAHUMAN_CORE_PORT") + std::env::var("OPENHUMAN_CORE_PORT") .ok() .and_then(|v| v.parse::().ok()) .unwrap_or(7788) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 80e030b44..e48fa5e2b 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,4 +1,4 @@ -//! AlphaHuman Desktop Application +//! OpenHuman Desktop Application //! //! This is the Rust backend for the cross-platform crypto community platform. //! It provides: @@ -9,7 +9,7 @@ //! - Native notifications mod ai; -pub mod alphahuman; +pub mod openhuman; mod auth; mod commands; mod core_process; @@ -28,7 +28,9 @@ use commands::unified_skills::{ unified_execute_skill, unified_generate_skill, unified_list_skills, unified_self_evolve_skill, }; use commands::*; +use serde::Serialize; use services::socket_service::SOCKET_SERVICE; +use std::collections::HashMap; use std::path::PathBuf; use tauri::{AppHandle, Emitter, Manager, RunEvent}; use tokio::{ @@ -51,20 +53,244 @@ fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) } -/// Write AI configuration files to the project's ./ai/ directory +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +struct AIPreview { + soul: AIPreviewSoul, + tools: AIPreviewTools, + metadata: AIPreviewMetadata, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +struct AIPreviewSoul { + raw: String, + name: String, + description: String, + personality_preview: Vec, + safety_rules_preview: Vec, + loaded_at: i64, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +struct AIPreviewTools { + raw: String, + total_tools: usize, + active_skills: usize, + skills_preview: Vec, + loaded_at: i64, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +struct AIPreviewMetadata { + loaded_at: i64, + loading_duration: i64, + has_fallbacks: bool, + sources: AIPreviewSources, + errors: Vec, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +struct AIPreviewSources { + soul: String, + tools: String, +} + +fn now_ms() -> i64 { + chrono::Utc::now().timestamp_millis() +} + +fn extract_section(raw: &str, heading: &str) -> String { + let marker = format!("## {heading}"); + let Some(start) = raw.find(&marker) else { + return String::new(); + }; + let body = &raw[start + marker.len()..]; + if let Some(next_idx) = body.find("\n## ") { + body[..next_idx].trim().to_string() + } else { + body.trim().to_string() + } +} + +fn parse_soul_preview(raw: String, loaded_at: i64) -> AIPreviewSoul { + let name = raw + .lines() + .find_map(|line| line.strip_prefix("# ").map(|s| s.trim().to_string())) + .unwrap_or_else(|| "OpenHuman".to_string()); + + let description = raw + .lines() + .map(str::trim) + .find(|line| !line.is_empty() && !line.starts_with('#')) + .unwrap_or("AI assistant") + .to_string(); + + let personality_preview = extract_section(&raw, "Personality") + .lines() + .filter_map(|line| line.trim().strip_prefix("- **")) + .filter_map(|line| { + let mut parts = line.splitn(2, "**:"); + let trait_name = parts.next()?.trim(); + let detail = parts.next().unwrap_or("").trim(); + Some(format!("{trait_name}: {detail}")) + }) + .take(3) + .collect::>(); + + let safety_rules_preview = extract_section(&raw, "Safety Rules") + .lines() + .filter_map(|line| { + let trimmed = line.trim(); + let dot_idx = trimmed.find('.')?; + let (prefix, rest) = trimmed.split_at(dot_idx); + if prefix.chars().all(|c| c.is_ascii_digit()) { + Some(rest.trim_start_matches('.').trim().to_string()) + } else { + None + } + }) + .take(3) + .collect::>(); + + AIPreviewSoul { + raw, + name, + description, + personality_preview, + safety_rules_preview, + loaded_at, + } +} + +fn parse_tools_preview(raw: String, loaded_at: i64) -> AIPreviewTools { + let mut current_skill = "General".to_string(); + let mut skill_counts: HashMap = HashMap::new(); + let mut total_tools = 0usize; + + for line in raw.lines() { + let trimmed = line.trim(); + if let Some(title) = trimmed.strip_prefix("### ") { + if let Some(skill_title) = title.strip_suffix(" Tools") { + current_skill = skill_title.trim().to_string(); + skill_counts.entry(current_skill.clone()).or_insert(0); + } + continue; + } + if trimmed.starts_with("#### ") { + total_tools += 1; + *skill_counts.entry(current_skill.clone()).or_insert(0) += 1; + } + } + + let mut skills = skill_counts.into_iter().collect::>(); + let active_skills = skills.len(); + skills.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0))); + let skills_preview = skills + .into_iter() + .take(6) + .map(|(name, count)| format!("{name} ({count})")) + .collect::>(); + + AIPreviewTools { + raw, + total_tools, + active_skills, + skills_preview, + loaded_at, + } +} + +fn resolve_ai_directory(app: &tauri::AppHandle) -> Option<(PathBuf, &'static str)> { + if let Ok(resource_dir) = app.path().resource_dir() { + let ai_dir = resource_dir.join("ai"); + if ai_dir.is_dir() { + return Some((ai_dir, "bundled")); + } + } + + if let Ok(cwd) = std::env::current_dir() { + let root_dev_dir = cwd.join("src-tauri").join("ai"); + if root_dev_dir.is_dir() { + return Some((root_dev_dir, "bundled")); + } + + let fallback = cwd.join("ai"); + if fallback.is_dir() { + return Some((fallback, "bundled")); + } + } + + None +} + +fn build_ai_preview(app: &tauri::AppHandle) -> AIPreview { + let started = now_ms(); + let loaded_at = now_ms(); + let mut errors = Vec::new(); + let mut soul_raw = String::new(); + let mut tools_raw = String::new(); + let mut source = "bundled".to_string(); + + if let Some((ai_dir, resolved_source)) = resolve_ai_directory(app) { + source = resolved_source.to_string(); + let soul_path = ai_dir.join("SOUL.md"); + let tools_path = ai_dir.join("TOOLS.md"); + soul_raw = std::fs::read_to_string(&soul_path).unwrap_or_else(|e| { + errors.push(format!("Failed to read SOUL.md: {e}")); + String::new() + }); + tools_raw = std::fs::read_to_string(&tools_path).unwrap_or_else(|e| { + errors.push(format!("Failed to read TOOLS.md: {e}")); + String::new() + }); + } else { + errors.push("AI config directory not found".to_string()); + } + + let soul = parse_soul_preview(soul_raw, loaded_at); + let tools = parse_tools_preview(tools_raw, loaded_at); + let done = now_ms(); + + AIPreview { + soul, + tools, + metadata: AIPreviewMetadata { + loaded_at: done, + loading_duration: done - started, + has_fallbacks: false, + sources: AIPreviewSources { + soul: source.clone(), + tools: source, + }, + errors, + }, + } +} + +#[tauri::command] +async fn ai_get_config(app: tauri::AppHandle) -> Result { + Ok(build_ai_preview(&app)) +} + +#[tauri::command] +async fn ai_refresh_config(app: tauri::AppHandle) -> Result { + commands::chat::clear_openclaw_context_cache(); + Ok(build_ai_preview(&app)) +} + +/// Write AI configuration files to the src-tauri/ai/ directory #[tauri::command] async fn write_ai_config_file(filename: String, content: String) -> Result { use std::env; - // Get the project root directory (parent of src-tauri) + // Determine runtime working directory let current_dir = env::current_dir().map_err(|e| format!("Failed to get current directory: {e}"))?; - // Go up one level to get project root (since we're in src-tauri/) - let project_root = current_dir - .parent() - .ok_or("Failed to get project root directory")?; - // Ensure filename is safe (only allow .md files) if !filename.ends_with(".md") { return Err("Only .md files are allowed".to_string()); @@ -75,8 +301,14 @@ async fn write_ai_config_file(filename: String, content: String) -> Result {cwd}/src-tauri/ai + // 2) src-tauri dir -> {cwd}/ai + let ai_dir = if current_dir.join("src-tauri").is_dir() { + current_dir.join("src-tauri").join("ai") + } else { + current_dir.join("ai") + }; let file_path = ai_dir.join(&filename); // Ensure ai directory exists @@ -85,6 +317,7 @@ async fn write_ai_config_file(filename: String, content: String) -> Result bool { fn daemon_foreground_requested() -> bool { matches!( - std::env::var("ALPHAHUMAN_DAEMON_FOREGROUND") + std::env::var("OPENHUMAN_DAEMON_FOREGROUND") .ok() .as_deref(), Some("1") | Some("true") | Some("TRUE") | Some("yes") | Some("YES") @@ -241,7 +476,7 @@ fn setup_tray(app: &AppHandle) -> Result<(), Box> { let _tray = TrayIconBuilder::with_id("main-tray") .icon(app.default_window_icon().unwrap().clone()) .menu(&menu) - .tooltip("AlphaHuman") + .tooltip("OpenHuman") .on_menu_event(move |app, event| match event.id().as_ref() { "show_hide" => { toggle_main_window_visibility(app); @@ -283,7 +518,7 @@ async fn watch_daemon_health_file(app_handle: AppHandle, data_dir: PathBuf) { let mut last_modified: Option = None; log::info!( - "[alphahuman] Watching daemon health file: {}", + "[openhuman] Watching daemon health file: {}", state_file.display() ); @@ -301,30 +536,30 @@ async fn watch_daemon_health_file(app_handle: AppHandle, data_dir: PathBuf) { if let Ok(json_value) = serde_json::from_str::(&content) { log::debug!( - "[alphahuman] Broadcasting health event from file: {:?}", + "[openhuman] Broadcasting health event from file: {:?}", json_value ); // Emit Tauri event to frontend (same as internal daemon) - if let Err(e) = app_handle.emit("alphahuman:health", &json_value) { + if let Err(e) = app_handle.emit("openhuman:health", &json_value) { log::error!( - "[alphahuman] Failed to emit health event from file: {}", + "[openhuman] Failed to emit health event from file: {}", e ); } else { log::debug!( - "[alphahuman] Health event emitted successfully from file" + "[openhuman] Health event emitted successfully from file" ); } } else { log::debug!( - "[alphahuman] Failed to parse health file as JSON: {}", + "[openhuman] Failed to parse health file as JSON: {}", state_file.display() ); } } else { log::debug!( - "[alphahuman] Failed to read health file: {}", + "[openhuman] Failed to read health file: {}", state_file.display() ); } @@ -333,7 +568,7 @@ async fn watch_daemon_health_file(app_handle: AppHandle, data_dir: PathBuf) { } else { // File doesn't exist yet - external daemon may not be writing yet log::debug!( - "[alphahuman] Health file not found yet: {}", + "[openhuman] Health file not found yet: {}", state_file.display() ); } @@ -359,7 +594,7 @@ pub fn run() { android_logger::init_once( android_logger::Config::default() .with_max_level(log::LevelFilter::Debug) - .with_tag("AlphaHuman"), + .with_tag("OpenHuman"), ); } #[cfg(not(target_os = "android"))] @@ -524,7 +759,7 @@ pub fn run() { // Fallback for platforms where app_data_dir isn't available dirs::home_dir() .unwrap_or_else(|| std::path::PathBuf::from(".")) - .join(".alphahuman") + .join(".openhuman") }); let skills_data_dir = data_dir.join("skills"); @@ -583,7 +818,7 @@ pub fn run() { log::info!("[runtime] QuickJS runtime disabled on iOS"); } - // Start the alphahuman daemon supervisor (desktop only) + // Start the openhuman daemon supervisor (desktop only) #[cfg(not(any(target_os = "android", target_os = "ios")))] { let data_dir = app @@ -592,11 +827,11 @@ pub fn run() { .unwrap_or_else(|_| { dirs::home_dir() .unwrap_or_else(|| std::path::PathBuf::from(".")) - .join(".alphahuman") + .join(".openhuman") }); - let daemon_config = alphahuman::config::DaemonConfig::from_app_data_dir(&data_dir); + let daemon_config = openhuman::config::DaemonConfig::from_app_data_dir(&data_dir); let cancel = tokio_util::sync::CancellationToken::new(); - let daemon_handle = alphahuman::daemon::DaemonHandle { + let daemon_handle = openhuman::daemon::DaemonHandle { cancel: cancel.clone(), }; app.manage(daemon_handle); @@ -605,7 +840,7 @@ pub fn run() { let use_internal_daemon = daemon_mode || daemon_foreground_requested() || cfg!(debug_assertions) // Always use internal supervisor in debug builds - || std::env::var("ALPHAHUMAN_DAEMON_INTERNAL").unwrap_or("false".to_string()) == "true"; // Cross-platform override via env var + || std::env::var("OPENHUMAN_DAEMON_INTERNAL").unwrap_or("false".to_string()) == "true"; // Cross-platform override via env var if use_internal_daemon { // Run internal daemon supervisor with health event emission @@ -613,26 +848,26 @@ pub fn run() { // - Daemon mode enabled, OR // - Foreground daemon requested, OR // - Debug build (for easier development), OR - // - ALPHAHUMAN_DAEMON_INTERNAL=true env var (any platform) - log::info!("[alphahuman] Using internal daemon supervisor (ALPHAHUMAN_DAEMON_INTERNAL=true or debug build)"); + // - OPENHUMAN_DAEMON_INTERNAL=true env var (any platform) + log::info!("[openhuman] Using internal daemon supervisor (OPENHUMAN_DAEMON_INTERNAL=true or debug build)"); let app_handle_for_daemon = app.handle().clone(); tauri::async_runtime::spawn(async move { - log::info!("[alphahuman] Starting daemon supervisor with health monitoring"); - if let Err(e) = alphahuman::daemon::run( + log::info!("[openhuman] Starting daemon supervisor with health monitoring"); + if let Err(e) = openhuman::daemon::run( daemon_config, app_handle_for_daemon, cancel, ) .await { - log::error!("[alphahuman] Daemon supervisor error: {e}"); + log::error!("[openhuman] Daemon supervisor error: {e}"); } }); } else { // Start external platform-specific service for background daemon - // This path is taken on all platforms when ALPHAHUMAN_DAEMON_INTERNAL=false/unset + // This path is taken on all platforms when OPENHUMAN_DAEMON_INTERNAL=false/unset // and not in daemon mode, foreground mode, or debug build - log::info!("[alphahuman] Using external daemon service (ALPHAHUMAN_DAEMON_INTERNAL=false/unset)"); + log::info!("[openhuman] Using external daemon service (OPENHUMAN_DAEMON_INTERNAL=false/unset)"); // Setup file watching to bridge external daemon health events to frontend let app_handle_for_watcher = app.handle().clone(); @@ -643,20 +878,20 @@ pub fn run() { // Start the external platform service tauri::async_runtime::spawn(async move { - match alphahuman::config::Config::load_or_init().await { + match openhuman::config::Config::load_or_init().await { Ok(config) => { - match alphahuman::service::install(&config) { - Ok(status) => log::info!("[alphahuman] External daemon service installed: {:?}", status), - Err(e) => log::error!("[alphahuman] Failed to install external daemon service: {e}"), + match openhuman::service::install(&config) { + Ok(status) => log::info!("[openhuman] External daemon service installed: {:?}", status), + Err(e) => log::error!("[openhuman] Failed to install external daemon service: {e}"), } - match alphahuman::service::start(&config) { - Ok(status) => log::info!("[alphahuman] External daemon service started: {:?}", status), - Err(e) => log::error!("[alphahuman] Failed to start external daemon service: {e}"), + match openhuman::service::start(&config) { + Ok(status) => log::info!("[openhuman] External daemon service started: {:?}", status), + Err(e) => log::error!("[openhuman] Failed to start external daemon service: {e}"), } } Err(e) => { log::error!( - "[alphahuman] Failed to load config for external service: {e}" + "[openhuman] Failed to load config for external service: {e}" ); } } @@ -668,7 +903,7 @@ pub fn run() { #[cfg(not(any(target_os = "android", target_os = "ios")))] { let core_handle = core_process::CoreProcessHandle::new(core_process::default_core_port()); - std::env::set_var("ALPHAHUMAN_CORE_RPC_URL", core_handle.rpc_url()); + std::env::set_var("OPENHUMAN_CORE_RPC_URL", core_handle.rpc_url()); app.manage(core_handle.clone()); tauri::async_runtime::spawn(async move { if let Err(err) = core_handle.ensure_running().await { @@ -724,6 +959,8 @@ pub fn run() { greet, // AI config file writing write_ai_config_file, + ai_get_config, + ai_refresh_config, get_auth_state, get_session_token, get_current_user, @@ -807,35 +1044,35 @@ pub fn run() { // Model commands (backend API proxy) model_summarize, model_generate, - // Alphahuman commands - alphahuman_health_snapshot, - alphahuman_security_policy_info, - alphahuman_encrypt_secret, - alphahuman_decrypt_secret, - alphahuman_get_config, - alphahuman_update_model_settings, - alphahuman_update_memory_settings, - alphahuman_update_gateway_settings, - alphahuman_update_tunnel_settings, - alphahuman_update_runtime_settings, - alphahuman_update_browser_settings, - alphahuman_get_runtime_flags, - alphahuman_set_browser_allow_all, - alphahuman_agent_chat, - alphahuman_doctor_report, - alphahuman_doctor_models, - alphahuman_list_integrations, - alphahuman_get_integration_info, - alphahuman_models_refresh, - alphahuman_migrate_openclaw, - alphahuman_hardware_discover, - alphahuman_hardware_introspect, - alphahuman_service_install, - alphahuman_service_start, - alphahuman_service_stop, - alphahuman_service_status, - alphahuman_service_uninstall, - alphahuman_agent_server_status, + // OpenHuman commands + openhuman_health_snapshot, + openhuman_security_policy_info, + openhuman_encrypt_secret, + openhuman_decrypt_secret, + openhuman_get_config, + openhuman_update_model_settings, + openhuman_update_memory_settings, + openhuman_update_gateway_settings, + openhuman_update_tunnel_settings, + openhuman_update_runtime_settings, + openhuman_update_browser_settings, + openhuman_get_runtime_flags, + openhuman_set_browser_allow_all, + openhuman_agent_chat, + openhuman_doctor_report, + openhuman_doctor_models, + openhuman_list_integrations, + openhuman_get_integration_info, + openhuman_models_refresh, + openhuman_migrate_openclaw, + openhuman_hardware_discover, + openhuman_hardware_introspect, + openhuman_service_install, + openhuman_service_start, + openhuman_service_stop, + openhuman_service_status, + openhuman_service_uninstall, + openhuman_agent_server_status, // Unified skill registry commands unified_list_skills, unified_execute_skill, @@ -862,6 +1099,8 @@ pub fn run() { greet, // AI config file writing write_ai_config_file, + ai_get_config, + ai_refresh_config, get_auth_state, get_session_token, get_current_user, @@ -936,35 +1175,35 @@ pub fn run() { // Model commands (backend API proxy) model_summarize, model_generate, - // Alphahuman commands - alphahuman_health_snapshot, - alphahuman_security_policy_info, - alphahuman_encrypt_secret, - alphahuman_decrypt_secret, - alphahuman_get_config, - alphahuman_update_model_settings, - alphahuman_update_memory_settings, - alphahuman_update_gateway_settings, - alphahuman_update_tunnel_settings, - alphahuman_update_runtime_settings, - alphahuman_update_browser_settings, - alphahuman_get_runtime_flags, - alphahuman_set_browser_allow_all, - alphahuman_agent_chat, - alphahuman_doctor_report, - alphahuman_doctor_models, - alphahuman_list_integrations, - alphahuman_get_integration_info, - alphahuman_models_refresh, - alphahuman_migrate_openclaw, - alphahuman_hardware_discover, - alphahuman_hardware_introspect, - alphahuman_service_install, - alphahuman_service_start, - alphahuman_service_stop, - alphahuman_service_status, - alphahuman_service_uninstall, - alphahuman_agent_server_status, + // OpenHuman commands + openhuman_health_snapshot, + openhuman_security_policy_info, + openhuman_encrypt_secret, + openhuman_decrypt_secret, + openhuman_get_config, + openhuman_update_model_settings, + openhuman_update_memory_settings, + openhuman_update_gateway_settings, + openhuman_update_tunnel_settings, + openhuman_update_runtime_settings, + openhuman_update_browser_settings, + openhuman_get_runtime_flags, + openhuman_set_browser_allow_all, + openhuman_agent_chat, + openhuman_doctor_report, + openhuman_doctor_models, + openhuman_list_integrations, + openhuman_get_integration_info, + openhuman_models_refresh, + openhuman_migrate_openclaw, + openhuman_hardware_discover, + openhuman_hardware_introspect, + openhuman_service_install, + openhuman_service_start, + openhuman_service_stop, + openhuman_service_status, + openhuman_service_uninstall, + openhuman_agent_server_status, // Unified skill registry commands (mobile stubs) unified_list_skills, unified_execute_skill, @@ -1003,16 +1242,15 @@ pub fn run() { } } - // Gracefully shut down TDLib before process exit to prevent - // use-after-free crash in the blocking receive loop. + // Gracefully shut down background services before process exit. #[cfg(not(any(target_os = "android", target_os = "ios")))] RunEvent::Exit => { log::info!("[app] Exit event received, shutting down"); - // Cancel the alphahuman daemon supervisor - if let Some(daemon) = app_handle.try_state::() { + // Cancel the openhuman daemon supervisor + if let Some(daemon) = app_handle.try_state::() { daemon.cancel.cancel(); - log::info!("[alphahuman] Daemon shutdown signalled"); + log::info!("[openhuman] Daemon shutdown signalled"); } if let Some(core) = app_handle.try_state::() { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index dbaf5417b..5d7871189 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -4,12 +4,12 @@ fn main() { let args: Vec = std::env::args().collect(); if args.get(1).map(String::as_str) == Some("core") { - if let Err(err) = alphahuman::run_core_from_args(&args[2..]) { + if let Err(err) = openhuman::run_core_from_args(&args[2..]) { eprintln!("core process failed: {err}"); std::process::exit(1); } return; } - alphahuman::run() + openhuman::run() } diff --git a/src-tauri/src/memory/mod.rs b/src-tauri/src/memory/mod.rs index 2187ceea4..995a118ba 100644 --- a/src-tauri/src/memory/mod.rs +++ b/src-tauri/src/memory/mod.rs @@ -27,7 +27,7 @@ impl MemoryClient { log::warn!("[memory] from_token: exit — token is empty, returning None"); return None; } - let config = if let Ok(base_url) = std::env::var("ALPHAHUMAN_BASE_URL") + let config = if let Ok(base_url) = std::env::var("OPENHUMAN_BASE_URL") .or_else(|_| std::env::var("TINYHUMANS_BASE_URL")) { log::info!("[memory] from_token: constructing client (base_url={base_url}, source=memory_env)"); @@ -85,7 +85,7 @@ impl MemoryClient { let insert_resp = self .inner .insert_memory(InsertMemoryParams { - document_id: Some(document_id_final), + document_id: document_id_final, title: title.to_string(), content: content.to_string(), namespace: namespace.clone(), @@ -118,7 +118,7 @@ impl MemoryClient { loop { tokio::time::sleep(std::time::Duration::from_secs(30)).await; - match self.inner.ingestion_job_status(&job_id).await { + match self.inner.get_ingestion_job(&job_id).await { Ok(status_resp) => { let state = status_resp .data @@ -241,7 +241,7 @@ impl MemoryClient { /// List all ingested memory documents as returned by the API. pub async fn list_documents(&self) -> Result { self.inner - .list_documents() + .list_documents(tinyhumansai::ListDocumentsParams::default()) .await .map_err(|e| format!("Memory list documents failed: {e}")) } @@ -295,9 +295,9 @@ impl MemoryClient { pub async fn clear_skill_memory( &self, skill_id: &str, - integration_id: &str, + _integration_id: &str, ) -> Result<(), String> { - let namespace = format!("skill:{skill_id}:{integration_id}"); + let namespace = skill_id.to_string(); log::info!("[memory] clear_skill_memory: entry (namespace={namespace})"); log::debug!("[memory] clear_skill_memory: payload → namespace={namespace}"); let result = self.inner @@ -345,7 +345,7 @@ mod tests { /// - the account quota is the only limiting factor /// /// Run with: - /// JWT_TOKEN= \ + /// JWT_TOKEN= \ /// cargo test --manifest-path src-tauri/Cargo.toml test_memory_skill_sync_flow -- --ignored --nocapture #[tokio::test] #[ignore] @@ -357,7 +357,7 @@ mod tests { .expect("client creation failed"); let skill_id = "gmail"; - let integration_id = "test@alphahuman.dev"; + let integration_id = "test@openhuman.dev"; let dummy_content = serde_json::json!({ "integrationId": integration_id, @@ -374,7 +374,7 @@ mod tests { .store_skill_sync( skill_id, integration_id, - "Gmail OAuth sync — test@alphahuman.dev", + "Gmail OAuth sync — test@openhuman.dev", &serde_json::to_string_pretty(&dummy_content).unwrap(), None, None, diff --git a/src-tauri/src/alphahuman/agent/agent.rs b/src-tauri/src/openhuman/agent/agent.rs similarity index 88% rename from src-tauri/src/alphahuman/agent/agent.rs rename to src-tauri/src/openhuman/agent/agent.rs index db6145b98..02202ad52 100644 --- a/src-tauri/src/alphahuman/agent/agent.rs +++ b/src-tauri/src/openhuman/agent/agent.rs @@ -3,14 +3,14 @@ use super::dispatcher::{ }; use super::memory_loader::{DefaultMemoryLoader, MemoryLoader}; use super::prompt::{PromptContext, SystemPromptBuilder}; -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::{self, Memory, MemoryCategory}; -use crate::alphahuman::observability::{self, Observer, ObserverEvent}; -use crate::alphahuman::providers::{self, ChatMessage, ChatRequest, ConversationMessage, Provider}; -use crate::alphahuman::runtime; -use crate::alphahuman::security::SecurityPolicy; -use crate::alphahuman::tools::{self, Tool, ToolSpec}; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::config::Config; +use crate::openhuman::memory::{self, Memory, MemoryCategory}; +use crate::openhuman::observability::{self, Observer, ObserverEvent}; +use crate::openhuman::providers::{self, ChatMessage, ChatRequest, ConversationMessage, Provider}; +use crate::openhuman::runtime; +use crate::openhuman::security::SecurityPolicy; +use crate::openhuman::tools::{self, Tool, ToolSpec}; +use crate::openhuman::util::truncate_with_ellipsis; use anyhow::Result; use std::io::Write as IoWrite; use std::sync::Arc; @@ -25,15 +25,15 @@ pub struct Agent { prompt_builder: SystemPromptBuilder, tool_dispatcher: Box, memory_loader: Box, - config: crate::alphahuman::config::AgentConfig, + config: crate::openhuman::config::AgentConfig, model_name: String, temperature: f64, workspace_dir: std::path::PathBuf, - identity_config: crate::alphahuman::config::IdentityConfig, - skills: Vec, + identity_config: crate::openhuman::config::IdentityConfig, + skills: Vec, auto_save: bool, history: Vec, - classification_config: crate::alphahuman::config::QueryClassificationConfig, + classification_config: crate::openhuman::config::QueryClassificationConfig, available_hints: Vec, } @@ -45,14 +45,14 @@ pub struct AgentBuilder { prompt_builder: Option, tool_dispatcher: Option>, memory_loader: Option>, - config: Option, + config: Option, model_name: Option, temperature: Option, workspace_dir: Option, - identity_config: Option, - skills: Option>, + identity_config: Option, + skills: Option>, auto_save: Option, - classification_config: Option, + classification_config: Option, available_hints: Option>, } @@ -113,7 +113,7 @@ impl AgentBuilder { self } - pub fn config(mut self, config: crate::alphahuman::config::AgentConfig) -> Self { + pub fn config(mut self, config: crate::openhuman::config::AgentConfig) -> Self { self.config = Some(config); self } @@ -133,12 +133,12 @@ impl AgentBuilder { self } - pub fn identity_config(mut self, identity_config: crate::alphahuman::config::IdentityConfig) -> Self { + pub fn identity_config(mut self, identity_config: crate::openhuman::config::IdentityConfig) -> Self { self.identity_config = Some(identity_config); self } - pub fn skills(mut self, skills: Vec) -> Self { + pub fn skills(mut self, skills: Vec) -> Self { self.skills = Some(skills); self } @@ -150,7 +150,7 @@ impl AgentBuilder { pub fn classification_config( mut self, - classification_config: crate::alphahuman::config::QueryClassificationConfig, + classification_config: crate::openhuman::config::QueryClassificationConfig, ) -> Self { self.classification_config = Some(classification_config); self @@ -309,7 +309,7 @@ impl Agent { .classification_config(config.query_classification.clone()) .available_hints(available_hints) .identity_config(config.identity.clone()) - .skills(crate::alphahuman::skills::load_skills(&config.workspace_dir)) + .skills(crate::openhuman::skills::load_skills(&config.workspace_dir)) .auto_save(config.memory.auto_save) .build() } @@ -529,14 +529,14 @@ impl Agent { } pub async fn run_interactive(&mut self) -> Result<()> { - println!("🦀 Alphahuman Interactive Mode"); + println!("🦀 OpenHuman Interactive Mode"); println!("Type /quit to exit.\n"); let (tx, mut rx) = tokio::sync::mpsc::channel(32); - let cli = crate::alphahuman::channels::CliChannel::new(); + let cli = crate::openhuman::channels::CliChannel::new(); let listen_handle = tokio::spawn(async move { - let _ = crate::alphahuman::channels::Channel::listen(&cli, tx).await; + let _ = crate::openhuman::channels::Channel::listen(&cli, tx).await; }); while let Some(msg) = rx.recv().await { @@ -616,7 +616,7 @@ mod tests { use parking_lot::Mutex; struct MockProvider { - responses: Mutex>, + responses: Mutex>, } #[async_trait] @@ -636,10 +636,10 @@ mod tests { _request: ChatRequest<'_>, _model: &str, _temperature: f64, - ) -> Result { + ) -> Result { let mut guard = self.responses.lock(); if guard.is_empty() { - return Ok(crate::alphahuman::providers::ChatResponse { + return Ok(crate::openhuman::providers::ChatResponse { text: Some("done".into()), tool_calls: vec![], }); @@ -664,8 +664,8 @@ mod tests { serde_json::json!({"type": "object"}) } - async fn execute(&self, _args: serde_json::Value) -> Result { - Ok(crate::alphahuman::tools::ToolResult { + async fn execute(&self, _args: serde_json::Value) -> Result { + Ok(crate::openhuman::tools::ToolResult { success: true, output: "tool-out".into(), error: None, @@ -676,21 +676,21 @@ mod tests { #[tokio::test] async fn turn_without_tools_returns_text() { let provider = Box::new(MockProvider { - responses: Mutex::new(vec![crate::alphahuman::providers::ChatResponse { + responses: Mutex::new(vec![crate::openhuman::providers::ChatResponse { text: Some("hello".into()), tool_calls: vec![], }]), }); - let memory_cfg = crate::alphahuman::config::MemoryConfig { + let memory_cfg = crate::openhuman::config::MemoryConfig { backend: "none".into(), - ..crate::alphahuman::config::MemoryConfig::default() + ..crate::openhuman::config::MemoryConfig::default() }; let mem: Arc = Arc::from( - crate::alphahuman::memory::create_memory(&memory_cfg, std::path::Path::new("/tmp"), None).unwrap(), + crate::openhuman::memory::create_memory(&memory_cfg, std::path::Path::new("/tmp"), None).unwrap(), ); - let observer: Arc = Arc::from(crate::alphahuman::observability::NoopObserver {}); + let observer: Arc = Arc::from(crate::openhuman::observability::NoopObserver {}); let mut agent = Agent::builder() .provider(provider) .tools(vec![Box::new(MockTool)]) @@ -709,30 +709,30 @@ mod tests { async fn turn_with_native_dispatcher_handles_tool_results_variant() { let provider = Box::new(MockProvider { responses: Mutex::new(vec![ - crate::alphahuman::providers::ChatResponse { + crate::openhuman::providers::ChatResponse { text: Some(String::new()), - tool_calls: vec![crate::alphahuman::providers::ToolCall { + tool_calls: vec![crate::openhuman::providers::ToolCall { id: "tc1".into(), name: "echo".into(), arguments: "{}".into(), }], }, - crate::alphahuman::providers::ChatResponse { + crate::openhuman::providers::ChatResponse { text: Some("done".into()), tool_calls: vec![], }, ]), }); - let memory_cfg = crate::alphahuman::config::MemoryConfig { + let memory_cfg = crate::openhuman::config::MemoryConfig { backend: "none".into(), - ..crate::alphahuman::config::MemoryConfig::default() + ..crate::openhuman::config::MemoryConfig::default() }; let mem: Arc = Arc::from( - crate::alphahuman::memory::create_memory(&memory_cfg, std::path::Path::new("/tmp"), None).unwrap(), + crate::openhuman::memory::create_memory(&memory_cfg, std::path::Path::new("/tmp"), None).unwrap(), ); - let observer: Arc = Arc::from(crate::alphahuman::observability::NoopObserver {}); + let observer: Arc = Arc::from(crate::openhuman::observability::NoopObserver {}); let mut agent = Agent::builder() .provider(provider) .tools(vec![Box::new(MockTool)]) diff --git a/src-tauri/src/alphahuman/agent/classifier.rs b/src-tauri/src/openhuman/agent/classifier.rs similarity index 96% rename from src-tauri/src/alphahuman/agent/classifier.rs rename to src-tauri/src/openhuman/agent/classifier.rs index e2cf6e8ca..3211f679e 100644 --- a/src-tauri/src/alphahuman/agent/classifier.rs +++ b/src-tauri/src/openhuman/agent/classifier.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::config::schema::QueryClassificationConfig; +use crate::openhuman::config::schema::QueryClassificationConfig; /// Classify a user message against the configured rules and return the /// matching hint string, if any. @@ -50,7 +50,7 @@ pub fn classify(config: &QueryClassificationConfig, message: &str) -> Option) -> QueryClassificationConfig { QueryClassificationConfig { enabled, rules } diff --git a/src-tauri/src/alphahuman/agent/dispatcher.rs b/src-tauri/src/openhuman/agent/dispatcher.rs similarity index 98% rename from src-tauri/src/alphahuman/agent/dispatcher.rs rename to src-tauri/src/openhuman/agent/dispatcher.rs index f3024fa85..2592ff090 100644 --- a/src-tauri/src/alphahuman/agent/dispatcher.rs +++ b/src-tauri/src/openhuman/agent/dispatcher.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::providers::{ChatMessage, ChatResponse, ConversationMessage, ToolResultMessage}; -use crate::alphahuman::tools::{Tool, ToolSpec}; +use crate::openhuman::providers::{ChatMessage, ChatResponse, ConversationMessage, ToolResultMessage}; +use crate::openhuman::tools::{Tool, ToolSpec}; use serde_json::Value; use std::fmt::Write; @@ -254,7 +254,7 @@ mod tests { fn native_dispatcher_roundtrip() { let response = ChatResponse { text: Some("ok".into()), - tool_calls: vec![crate::alphahuman::providers::ToolCall { + tool_calls: vec![crate::openhuman::providers::ToolCall { id: "tc1".into(), name: "file_read".into(), arguments: "{\"path\":\"a.txt\"}".into(), diff --git a/src-tauri/src/alphahuman/agent/loop_.rs b/src-tauri/src/openhuman/agent/loop_.rs similarity index 96% rename from src-tauri/src/alphahuman/agent/loop_.rs rename to src-tauri/src/openhuman/agent/loop_.rs index 97b6d2f97..3d8a9a308 100644 --- a/src-tauri/src/alphahuman/agent/loop_.rs +++ b/src-tauri/src/openhuman/agent/loop_.rs @@ -1,15 +1,15 @@ -use crate::alphahuman::approval::{ApprovalManager, ApprovalRequest, ApprovalResponse}; -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::{self, Memory, MemoryCategory}; -use crate::alphahuman::multimodal; -use crate::alphahuman::observability::{self, Observer, ObserverEvent}; -use crate::alphahuman::providers::{ +use crate::openhuman::approval::{ApprovalManager, ApprovalRequest, ApprovalResponse}; +use crate::openhuman::config::Config; +use crate::openhuman::memory::{self, Memory, MemoryCategory}; +use crate::openhuman::multimodal; +use crate::openhuman::observability::{self, Observer, ObserverEvent}; +use crate::openhuman::providers::{ self, ChatMessage, ChatRequest, Provider, ProviderCapabilityError, ToolCall, }; -use crate::alphahuman::runtime; -use crate::alphahuman::security::SecurityPolicy; -use crate::alphahuman::tools::{self, Tool}; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::runtime; +use crate::openhuman::security::SecurityPolicy; +use crate::openhuman::tools::{self, Tool}; +use crate::openhuman::util::truncate_with_ellipsis; use anyhow::Result; use regex::{Regex, RegexSet}; use std::fmt::Write; @@ -238,7 +238,7 @@ async fn build_context(mem: &dyn Memory, user_msg: &str, min_relevance_score: f6 /// Build hardware datasheet context from RAG when peripherals are enabled. /// Includes pin-alias lookup (e.g. "red_led" → 13) when query matches, plus retrieved chunks. fn build_hardware_context( - rag: &crate::alphahuman::rag::HardwareRag, + rag: &crate::openhuman::rag::HardwareRag, user_msg: &str, boards: &[String], chunk_limit: usize, @@ -737,7 +737,7 @@ fn parse_tool_calls(response: &str) -> (String, Vec) { // (e.g., in emails, files, or web pages) could include JSON that mimics a // tool call. Tool calls MUST be explicitly wrapped in either: // 1. OpenAI-style JSON with a "tool_calls" array - // 2. Alphahuman tool-call tags (, , ) + // 2. OpenHuman tool-call tags (, , ) // 3. Markdown code blocks with tool_call/toolcall/tool-call language // 4. Explicit GLM line-based call formats (e.g. `shell/command>...`) // This ensures only the LLM's intentional tool calls are executed. @@ -829,7 +829,7 @@ pub(crate) async fn agent_turn( model: &str, temperature: f64, silent: bool, - multimodal_config: &crate::alphahuman::config::MultimodalConfig, + multimodal_config: &crate::openhuman::config::MultimodalConfig, max_tool_iterations: usize, ) -> Result { run_tool_call_loop( @@ -864,7 +864,7 @@ pub(crate) async fn run_tool_call_loop( silent: bool, approval: Option<&ApprovalManager>, channel_name: &str, - multimodal_config: &crate::alphahuman::config::MultimodalConfig, + multimodal_config: &crate::openhuman::config::MultimodalConfig, max_tool_iterations: usize, on_delta: Option>, ) -> Result { @@ -874,7 +874,7 @@ pub(crate) async fn run_tool_call_loop( max_tool_iterations }; - let tool_specs: Vec = + let tool_specs: Vec = tools_registry.iter().map(|tool| tool.spec()).collect(); let use_native_tools = provider.supports_native_tools() && !tool_specs.is_empty(); @@ -966,7 +966,7 @@ pub(crate) async fn run_tool_call_loop( model: model.to_string(), duration: llm_started_at.elapsed(), success: false, - error_message: Some(crate::alphahuman::providers::sanitize_api_error(&e.to_string())), + error_message: Some(crate::openhuman::providers::sanitize_api_error(&e.to_string())), }); return Err(e); } @@ -1195,7 +1195,7 @@ pub async fn run( ); let peripheral_tools: Vec> = - crate::alphahuman::peripherals::create_peripheral_tools(&config.peripherals).await?; + crate::openhuman::peripherals::create_peripheral_tools(&config.peripherals).await?; if !peripheral_tools.is_empty() { tracing::info!(count = peripheral_tools.len(), "Peripheral tools added"); tools_registry.extend(peripheral_tools); @@ -1214,7 +1214,7 @@ pub async fn run( let provider_runtime_options = providers::ProviderRuntimeOptions { auth_profile_override: None, - alphahuman_dir: config.config_path.parent().map(std::path::PathBuf::from), + openhuman_dir: config.config_path.parent().map(std::path::PathBuf::from), secrets_encrypt: config.secrets.encrypt, reasoning_enabled: config.runtime.reasoning_enabled, }; @@ -1235,14 +1235,14 @@ pub async fn run( }); // ── Hardware RAG (datasheet retrieval when peripherals + datasheet_dir) ── - let hardware_rag: Option = config + let hardware_rag: Option = config .peripherals .datasheet_dir .as_ref() .filter(|d| !d.trim().is_empty()) - .map(|dir| crate::alphahuman::rag::HardwareRag::load(&config.workspace_dir, dir.trim())) + .map(|dir| crate::openhuman::rag::HardwareRag::load(&config.workspace_dir, dir.trim())) .and_then(Result::ok) - .filter(|r: &crate::alphahuman::rag::HardwareRag| !r.is_empty()); + .filter(|r: &crate::openhuman::rag::HardwareRag| !r.is_empty()); if let Some(ref rag) = hardware_rag { tracing::info!(chunks = rag.len(), "Hardware RAG loaded"); } @@ -1255,7 +1255,7 @@ pub async fn run( .collect(); // ── Build system prompt from workspace MD files (OpenClaw framework) ── - let skills = crate::alphahuman::skills::load_skills(&config.workspace_dir); + let skills = crate::openhuman::skills::load_skills(&config.workspace_dir); let mut tool_descs: Vec<(&str, &str)> = vec![ ( "shell", @@ -1341,7 +1341,7 @@ pub async fn run( )); tool_descs.push(( "arduino_upload", - "Upload agent-generated Arduino sketch. Use when: user asks for 'make a heart', 'blink pattern', or custom LED behavior on Arduino. You write the full .ino code; Alphahuman compiles and uploads it. Pin 13 = built-in LED on Uno.", + "Upload agent-generated Arduino sketch. Use when: user asks for 'make a heart', 'blink pattern', or custom LED behavior on Arduino. You write the full .ino code; OpenHuman compiles and uploads it. Pin 13 = built-in LED on Uno.", )); tool_descs.push(( "hardware_memory_map", @@ -1365,7 +1365,7 @@ pub async fn run( } else { None }; - let mut system_prompt = crate::alphahuman::channels::build_system_prompt( + let mut system_prompt = crate::openhuman::channels::build_system_prompt( &config.workspace_dir, model_name, &tool_descs, @@ -1443,9 +1443,9 @@ pub async fn run( .await; } } else { - println!("🦀 Alphahuman Interactive Mode"); + println!("🦀 OpenHuman Interactive Mode"); println!("Type /help for commands.\n"); - let cli = crate::alphahuman::channels::CliChannel::new(); + let cli = crate::openhuman::channels::CliChannel::new(); // Persistent conversation history across turns let mut history = vec![ChatMessage::system(&system_prompt)]; @@ -1565,9 +1565,9 @@ pub async fn run( } }; final_output = response.clone(); - if let Err(e) = crate::alphahuman::channels::Channel::send( + if let Err(e) = crate::openhuman::channels::Channel::send( &cli, - &crate::alphahuman::channels::traits::SendMessage::new(format!("\n{response}\n"), "user"), + &crate::openhuman::channels::traits::SendMessage::new(format!("\n{response}\n"), "user"), ) .await { @@ -1655,7 +1655,7 @@ pub async fn process_message(config: Config, message: &str) -> Result { &config, ); let peripheral_tools: Vec> = - crate::alphahuman::peripherals::create_peripheral_tools(&config.peripherals).await?; + crate::openhuman::peripherals::create_peripheral_tools(&config.peripherals).await?; tools_registry.extend(peripheral_tools); let provider_name = config.default_provider.as_deref().unwrap_or("openrouter"); @@ -1665,7 +1665,7 @@ pub async fn process_message(config: Config, message: &str) -> Result { .unwrap_or_else(|| "anthropic/claude-sonnet-4-20250514".into()); let provider_runtime_options = providers::ProviderRuntimeOptions { auth_profile_override: None, - alphahuman_dir: config.config_path.parent().map(std::path::PathBuf::from), + openhuman_dir: config.config_path.parent().map(std::path::PathBuf::from), secrets_encrypt: config.secrets.encrypt, reasoning_enabled: config.runtime.reasoning_enabled, }; @@ -1679,14 +1679,14 @@ pub async fn process_message(config: Config, message: &str) -> Result { &provider_runtime_options, )?; - let hardware_rag: Option = config + let hardware_rag: Option = config .peripherals .datasheet_dir .as_ref() .filter(|d| !d.trim().is_empty()) - .map(|dir| crate::alphahuman::rag::HardwareRag::load(&config.workspace_dir, dir.trim())) + .map(|dir| crate::openhuman::rag::HardwareRag::load(&config.workspace_dir, dir.trim())) .and_then(Result::ok) - .filter(|r: &crate::alphahuman::rag::HardwareRag| !r.is_empty()); + .filter(|r: &crate::openhuman::rag::HardwareRag| !r.is_empty()); let board_names: Vec = config .peripherals .boards @@ -1694,7 +1694,7 @@ pub async fn process_message(config: Config, message: &str) -> Result { .map(|b| b.board.clone()) .collect(); - let skills = crate::alphahuman::skills::load_skills(&config.workspace_dir); + let skills = crate::openhuman::skills::load_skills(&config.workspace_dir); let mut tool_descs: Vec<(&str, &str)> = vec![ ("shell", "Execute terminal commands."), ("file_read", "Read file contents."), @@ -1719,7 +1719,7 @@ pub async fn process_message(config: Config, message: &str) -> Result { )); tool_descs.push(( "arduino_upload", - "Upload Arduino sketch. Use for 'make a heart', custom patterns. You write full .ino code; Alphahuman uploads it.", + "Upload Arduino sketch. Use for 'make a heart', custom patterns. You write full .ino code; OpenHuman uploads it.", )); tool_descs.push(( "hardware_memory_map", @@ -1743,7 +1743,7 @@ pub async fn process_message(config: Config, message: &str) -> Result { } else { None }; - let mut system_prompt = crate::alphahuman::channels::build_system_prompt( + let mut system_prompt = crate::openhuman::channels::build_system_prompt( &config.workspace_dir, &model_name, &tool_descs, @@ -1812,10 +1812,10 @@ mod tests { assert!(scrubbed.contains("\"api_key\": \"sk-1*[REDACTED]\"")); assert!(scrubbed.contains("public")); } - use crate::alphahuman::memory::{Memory, MemoryCategory, SqliteMemory}; - use crate::alphahuman::observability::NoopObserver; - use crate::alphahuman::providers::traits::ProviderCapabilities; - use crate::alphahuman::providers::ChatResponse; + use crate::openhuman::memory::{Memory, MemoryCategory, SqliteMemory}; + use crate::openhuman::observability::NoopObserver; + use crate::openhuman::providers::traits::ProviderCapabilities; + use crate::openhuman::providers::ChatResponse; use tempfile::TempDir; struct NonVisionProvider { @@ -1867,7 +1867,7 @@ mod tests { _temperature: f64, ) -> anyhow::Result { self.calls.fetch_add(1, Ordering::SeqCst); - let marker_count = crate::alphahuman::multimodal::count_image_markers(request.messages); + let marker_count = crate::openhuman::multimodal::count_image_markers(request.messages); if marker_count == 0 { anyhow::bail!("expected image markers in request messages"); } @@ -1907,7 +1907,7 @@ mod tests { true, None, "cli", - &crate::alphahuman::config::MultimodalConfig::default(), + &crate::openhuman::config::MultimodalConfig::default(), 3, None, ) @@ -1933,7 +1933,7 @@ mod tests { let tools_registry: Vec> = Vec::new(); let observer = NoopObserver; - let multimodal = crate::alphahuman::config::MultimodalConfig { + let multimodal = crate::openhuman::config::MultimodalConfig { max_images: 4, max_image_size_mb: 1, allow_remote_fetch: false, @@ -1987,7 +1987,7 @@ mod tests { true, None, "cli", - &crate::alphahuman::config::MultimodalConfig::default(), + &crate::openhuman::config::MultimodalConfig::default(), 3, None, ) @@ -2305,9 +2305,9 @@ Done."#; #[test] fn build_tool_instructions_includes_all_tools() { - use crate::alphahuman::security::SecurityPolicy; + use crate::openhuman::security::SecurityPolicy; let security = Arc::new(SecurityPolicy::from_config( - &crate::alphahuman::config::AutonomyConfig::default(), + &crate::openhuman::config::AutonomyConfig::default(), std::path::Path::new("/tmp"), )); let tools = tools::default_tools(security); @@ -2322,9 +2322,9 @@ Done."#; #[test] fn tools_to_openai_format_produces_valid_schema() { - use crate::alphahuman::security::SecurityPolicy; + use crate::openhuman::security::SecurityPolicy; let security = Arc::new(SecurityPolicy::from_config( - &crate::alphahuman::config::AutonomyConfig::default(), + &crate::openhuman::config::AutonomyConfig::default(), std::path::Path::new("/tmp"), )); let tools = tools::default_tools(security); @@ -2880,14 +2880,14 @@ Let me check the result."#; #[test] fn trim_history_empty_history() { - let mut history: Vec = vec![]; + let mut history: Vec = vec![]; trim_history(&mut history, 10); assert!(history.is_empty()); } #[test] fn trim_history_system_only() { - let mut history = vec![crate::alphahuman::providers::ChatMessage::system("system prompt")]; + let mut history = vec![crate::openhuman::providers::ChatMessage::system("system prompt")]; trim_history(&mut history, 10); assert_eq!(history.len(), 1); assert_eq!(history[0].role, "system"); @@ -2896,9 +2896,9 @@ Let me check the result."#; #[test] fn trim_history_exactly_at_limit() { let mut history = vec![ - crate::alphahuman::providers::ChatMessage::system("system"), - crate::alphahuman::providers::ChatMessage::user("msg 1"), - crate::alphahuman::providers::ChatMessage::assistant("reply 1"), + crate::openhuman::providers::ChatMessage::system("system"), + crate::openhuman::providers::ChatMessage::user("msg 1"), + crate::openhuman::providers::ChatMessage::assistant("reply 1"), ]; trim_history(&mut history, 2); // 2 non-system messages = exactly at limit assert_eq!(history.len(), 3, "should not trim when exactly at limit"); @@ -2907,11 +2907,11 @@ Let me check the result."#; #[test] fn trim_history_removes_oldest_non_system() { let mut history = vec![ - crate::alphahuman::providers::ChatMessage::system("system"), - crate::alphahuman::providers::ChatMessage::user("old msg"), - crate::alphahuman::providers::ChatMessage::assistant("old reply"), - crate::alphahuman::providers::ChatMessage::user("new msg"), - crate::alphahuman::providers::ChatMessage::assistant("new reply"), + crate::openhuman::providers::ChatMessage::system("system"), + crate::openhuman::providers::ChatMessage::user("old msg"), + crate::openhuman::providers::ChatMessage::assistant("old reply"), + crate::openhuman::providers::ChatMessage::user("new msg"), + crate::openhuman::providers::ChatMessage::assistant("new reply"), ]; trim_history(&mut history, 2); assert_eq!(history.len(), 3); // system + 2 kept diff --git a/src-tauri/src/alphahuman/agent/memory_loader.rs b/src-tauri/src/openhuman/agent/memory_loader.rs similarity index 96% rename from src-tauri/src/alphahuman/agent/memory_loader.rs rename to src-tauri/src/openhuman/agent/memory_loader.rs index d5f4e41b0..d9556b6a9 100644 --- a/src-tauri/src/alphahuman/agent/memory_loader.rs +++ b/src-tauri/src/openhuman/agent/memory_loader.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::memory::Memory; +use crate::openhuman::memory::Memory; use async_trait::async_trait; use std::fmt::Write; @@ -66,7 +66,7 @@ impl MemoryLoader for DefaultMemoryLoader { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::memory::{Memory, MemoryCategory, MemoryEntry}; + use crate::openhuman::memory::{Memory, MemoryCategory, MemoryEntry}; struct MockMemory; diff --git a/src-tauri/src/alphahuman/agent/mod.rs b/src-tauri/src/openhuman/agent/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/agent/mod.rs rename to src-tauri/src/openhuman/agent/mod.rs diff --git a/src-tauri/src/alphahuman/agent/prompt.rs b/src-tauri/src/openhuman/agent/prompt.rs similarity index 95% rename from src-tauri/src/alphahuman/agent/prompt.rs rename to src-tauri/src/openhuman/agent/prompt.rs index f2846dcb4..e696f0be9 100644 --- a/src-tauri/src/alphahuman/agent/prompt.rs +++ b/src-tauri/src/openhuman/agent/prompt.rs @@ -1,7 +1,7 @@ -use crate::alphahuman::config::IdentityConfig; -use crate::alphahuman::identity; -use crate::alphahuman::skills::Skill; -use crate::alphahuman::tools::Tool; +use crate::openhuman::config::IdentityConfig; +use crate::openhuman::identity; +use crate::openhuman::skills::Skill; +use crate::openhuman::tools::Tool; use anyhow::Result; use chrono::Local; use std::fmt::Write; @@ -259,7 +259,7 @@ fn inject_workspace_file(prompt: &mut String, workspace_dir: &Path, filename: &s #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::tools::traits::Tool; + use crate::openhuman::tools::traits::Tool; use async_trait::async_trait; struct TestTool; @@ -281,8 +281,8 @@ mod tests { async fn execute( &self, _args: serde_json::Value, - ) -> anyhow::Result { - Ok(crate::alphahuman::tools::ToolResult { + ) -> anyhow::Result { + Ok(crate::openhuman::tools::ToolResult { success: true, output: "ok".into(), error: None, @@ -293,7 +293,7 @@ mod tests { #[test] fn identity_section_with_aieos_includes_workspace_files() { let workspace = - std::env::temp_dir().join(format!("alphahuman_prompt_test_{}", uuid::Uuid::new_v4())); + std::env::temp_dir().join(format!("openhuman_prompt_test_{}", uuid::Uuid::new_v4())); std::fs::create_dir_all(&workspace).unwrap(); std::fs::write( workspace.join("AGENTS.md"), @@ -301,7 +301,7 @@ mod tests { ) .unwrap(); - let identity_config = crate::alphahuman::config::IdentityConfig { + let identity_config = crate::openhuman::config::IdentityConfig { format: "aieos".into(), aieos_path: None, aieos_inline: Some(r#"{"identity":{"names":{"first":"Nova"}}}"#.into()), diff --git a/src-tauri/src/alphahuman/agent/tests.rs b/src-tauri/src/openhuman/agent/tests.rs similarity index 99% rename from src-tauri/src/alphahuman/agent/tests.rs rename to src-tauri/src/openhuman/agent/tests.rs index 5cc044294..6a5aa3666 100644 --- a/src-tauri/src/alphahuman/agent/tests.rs +++ b/src-tauri/src/openhuman/agent/tests.rs @@ -24,18 +24,18 @@ //! 19. Builder validation (missing required fields) //! 20. Idempotent system prompt insertion -use crate::alphahuman::agent::agent::Agent; -use crate::alphahuman::agent::dispatcher::{ +use crate::openhuman::agent::agent::Agent; +use crate::openhuman::agent::dispatcher::{ NativeToolDispatcher, ToolDispatcher, ToolExecutionResult, XmlToolDispatcher, }; -use crate::alphahuman::config::{AgentConfig, MemoryConfig}; -use crate::alphahuman::memory::{self, Memory}; -use crate::alphahuman::observability::{NoopObserver, Observer}; -use crate::alphahuman::providers::{ +use crate::openhuman::config::{AgentConfig, MemoryConfig}; +use crate::openhuman::memory::{self, Memory}; +use crate::openhuman::observability::{NoopObserver, Observer}; +use crate::openhuman::providers::{ ChatMessage, ChatRequest, ChatResponse, ConversationMessage, Provider, ToolCall, ToolResultMessage, }; -use crate::alphahuman::tools::{Tool, ToolResult}; +use crate::openhuman::tools::{Tool, ToolResult}; use anyhow::Result; use async_trait::async_trait; use std::sync::{Arc, Mutex}; diff --git a/src-tauri/src/alphahuman/agent/traits.rs b/src-tauri/src/openhuman/agent/traits.rs similarity index 99% rename from src-tauri/src/alphahuman/agent/traits.rs rename to src-tauri/src/openhuman/agent/traits.rs index a30599b52..3565379c5 100644 --- a/src-tauri/src/alphahuman/agent/traits.rs +++ b/src-tauri/src/openhuman/agent/traits.rs @@ -1,4 +1,4 @@ -//! Core agent traits ported from Alphahuman. +//! Core agent traits ported from OpenHuman. //! //! Each trait defines an extension point. Noop implementations are provided //! as test doubles and reference implementations. diff --git a/src-tauri/src/alphahuman/approval/mod.rs b/src-tauri/src/openhuman/approval/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/approval/mod.rs rename to src-tauri/src/openhuman/approval/mod.rs index 874e6666a..6f36f4bbd 100644 --- a/src-tauri/src/alphahuman/approval/mod.rs +++ b/src-tauri/src/openhuman/approval/mod.rs @@ -3,8 +3,8 @@ //! Provides a pre-execution hook that prompts the user before tool calls, //! with session-scoped "Always" allowlists and audit logging. -use crate::alphahuman::config::AutonomyConfig; -use crate::alphahuman::security::AutonomyLevel; +use crate::openhuman::config::AutonomyConfig; +use crate::openhuman::security::AutonomyLevel; use chrono::Utc; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; @@ -219,7 +219,7 @@ fn truncate_for_summary(input: &str, max_chars: usize) -> String { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::AutonomyConfig; + use crate::openhuman::config::AutonomyConfig; fn supervised_config() -> AutonomyConfig { AutonomyConfig { diff --git a/src-tauri/src/alphahuman/channels/cli.rs b/src-tauri/src/openhuman/channels/cli.rs similarity index 100% rename from src-tauri/src/alphahuman/channels/cli.rs rename to src-tauri/src/openhuman/channels/cli.rs diff --git a/src-tauri/src/alphahuman/channels/commands.rs b/src-tauri/src/openhuman/channels/commands.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/commands.rs rename to src-tauri/src/openhuman/channels/commands.rs index 1f3de2fdd..8068364cc 100644 --- a/src-tauri/src/alphahuman/channels/commands.rs +++ b/src-tauri/src/openhuman/channels/commands.rs @@ -18,7 +18,7 @@ use super::whatsapp::WhatsAppChannel; #[cfg(feature = "whatsapp-web")] use super::whatsapp_web::WhatsAppWebChannel; use super::Channel; -use crate::alphahuman::config::Config; +use crate::openhuman::config::Config; use anyhow::Result; use std::sync::Arc; use std::time::Duration; @@ -235,7 +235,7 @@ pub async fn doctor_channels(config: Config) -> Result<()> { return Ok(()); } - println!("🩺 Alphahuman Channel Doctor"); + println!("🩺 OpenHuman Channel Doctor"); println!(); let mut healthy = 0_u32; diff --git a/src-tauri/src/alphahuman/channels/context.rs b/src-tauri/src/openhuman/channels/context.rs similarity index 92% rename from src-tauri/src/alphahuman/channels/context.rs rename to src-tauri/src/openhuman/channels/context.rs index ab4146d7c..ab2141254 100644 --- a/src-tauri/src/alphahuman/channels/context.rs +++ b/src-tauri/src/openhuman/channels/context.rs @@ -1,10 +1,10 @@ //! Shared channel runtime state and memory helpers. -use crate::alphahuman::memory::Memory; -use crate::alphahuman::observability::Observer; -use crate::alphahuman::providers::{ChatMessage, Provider}; -use crate::alphahuman::tools::Tool; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::memory::Memory; +use crate::openhuman::observability::Observer; +use crate::openhuman::providers::{ChatMessage, Provider}; +use crate::openhuman::tools::Tool; +use crate::openhuman::util::truncate_with_ellipsis; use std::collections::HashMap; use std::path::PathBuf; use std::sync::{Arc, Mutex}; @@ -62,11 +62,11 @@ pub(crate) struct ChannelRuntimeContext { pub(crate) route_overrides: RouteSelectionMap, pub(crate) api_key: Option, pub(crate) api_url: Option, - pub(crate) reliability: Arc, - pub(crate) provider_runtime_options: crate::alphahuman::providers::ProviderRuntimeOptions, + pub(crate) reliability: Arc, + pub(crate) provider_runtime_options: crate::openhuman::providers::ProviderRuntimeOptions, pub(crate) workspace_dir: Arc, pub(crate) message_timeout_secs: u64, - pub(crate) multimodal: crate::alphahuman::config::MultimodalConfig, + pub(crate) multimodal: crate::openhuman::config::MultimodalConfig, } pub(crate) fn conversation_memory_key(msg: &super::traits::ChannelMessage) -> String { diff --git a/src-tauri/src/alphahuman/channels/dingtalk.rs b/src-tauri/src/openhuman/channels/dingtalk.rs similarity index 97% rename from src-tauri/src/alphahuman/channels/dingtalk.rs rename to src-tauri/src/openhuman/channels/dingtalk.rs index 6c9715b4f..a1af78641 100644 --- a/src-tauri/src/alphahuman/channels/dingtalk.rs +++ b/src-tauri/src/openhuman/channels/dingtalk.rs @@ -38,7 +38,7 @@ impl DingTalkChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.dingtalk") + crate::openhuman::config::build_runtime_proxy_client("channel.dingtalk") } fn is_user_allowed(&self, user_id: &str) -> bool { @@ -121,7 +121,7 @@ impl Channel for DingTalkChannel { ) })?; - let title = message.subject.as_deref().unwrap_or("Alphahuman"); + let title = message.subject.as_deref().unwrap_or("OpenHuman"); let body = serde_json::json!({ "msgtype": "markdown", "markdown": { @@ -330,7 +330,7 @@ client_id = "app_id_123" client_secret = "secret_456" allowed_users = ["user1", "*"] "#; - let config: crate::alphahuman::config::schema::DingTalkConfig = toml::from_str(toml_str).unwrap(); + let config: crate::openhuman::config::schema::DingTalkConfig = toml::from_str(toml_str).unwrap(); assert_eq!(config.client_id, "app_id_123"); assert_eq!(config.client_secret, "secret_456"); assert_eq!(config.allowed_users, vec!["user1", "*"]); @@ -342,7 +342,7 @@ allowed_users = ["user1", "*"] client_id = "id" client_secret = "secret" "#; - let config: crate::alphahuman::config::schema::DingTalkConfig = toml::from_str(toml_str).unwrap(); + let config: crate::openhuman::config::schema::DingTalkConfig = toml::from_str(toml_str).unwrap(); assert!(config.allowed_users.is_empty()); } diff --git a/src-tauri/src/alphahuman/channels/discord.rs b/src-tauri/src/openhuman/channels/discord.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/discord.rs rename to src-tauri/src/openhuman/channels/discord.rs index ed8eb7a1b..0671ae40b 100644 --- a/src-tauri/src/alphahuman/channels/discord.rs +++ b/src-tauri/src/openhuman/channels/discord.rs @@ -35,7 +35,7 @@ impl DiscordChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.discord") + crate::openhuman::config::build_runtime_proxy_client("channel.discord") } /// Check if a Discord user ID is in the allowlist. @@ -267,8 +267,8 @@ impl Channel for DiscordChannel { "intents": 37377, // GUILDS | GUILD_MESSAGES | MESSAGE_CONTENT | DIRECT_MESSAGES "properties": { "os": "linux", - "browser": "alphahuman", - "device": "alphahuman" + "browser": "openhuman", + "device": "openhuman" } } }); diff --git a/src-tauri/src/alphahuman/channels/email_channel.rs b/src-tauri/src/openhuman/channels/email_channel.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/email_channel.rs rename to src-tauri/src/openhuman/channels/email_channel.rs index 91e9db397..241bb0676 100644 --- a/src-tauri/src/alphahuman/channels/email_channel.rs +++ b/src-tauri/src/openhuman/channels/email_channel.rs @@ -509,10 +509,10 @@ impl Channel for EmailChannel { if let Some(pos) = message.content.find('\n') { (&message.content[9..pos], message.content[pos + 1..].trim()) } else { - ("Alphahuman Message", message.content.as_str()) + ("OpenHuman Message", message.content.as_str()) } } else { - ("Alphahuman Message", message.content.as_str()) + ("OpenHuman Message", message.content.as_str()) }; let email = Message::builder() diff --git a/src-tauri/src/alphahuman/channels/imessage.rs b/src-tauri/src/openhuman/channels/imessage.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/imessage.rs rename to src-tauri/src/openhuman/channels/imessage.rs index 816e4bcc8..3e0f0acde 100644 --- a/src-tauri/src/alphahuman/channels/imessage.rs +++ b/src-tauri/src/openhuman/channels/imessage.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::channels::traits::{Channel, ChannelMessage, SendMessage}; +use crate::openhuman::channels::traits::{Channel, ChannelMessage, SendMessage}; use async_trait::async_trait; use directories::UserDirs; use rusqlite::{Connection, OpenFlags}; diff --git a/src-tauri/src/alphahuman/channels/irc.rs b/src-tauri/src/openhuman/channels/irc.rs similarity index 98% rename from src-tauri/src/alphahuman/channels/irc.rs rename to src-tauri/src/openhuman/channels/irc.rs index 49ca9dc21..eb4ce6390 100644 --- a/src-tauri/src/alphahuman/channels/irc.rs +++ b/src-tauri/src/openhuman/channels/irc.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::channels::traits::{Channel, ChannelMessage, SendMessage}; +use crate::openhuman::channels::traits::{Channel, ChannelMessage, SendMessage}; use async_trait::async_trait; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; @@ -18,7 +18,7 @@ static MSG_SEQ: AtomicU64 = AtomicU64::new(0); /// IRC over TLS channel. /// /// Connects to an IRC server using TLS, joins configured channels, -/// and forwards PRIVMSG messages to the `Alphahuman` message bus. +/// and forwards PRIVMSG messages to the `OpenHuman` message bus. /// Supports both channel messages and private messages (DMs). pub struct IrcChannel { server: String, @@ -395,7 +395,7 @@ impl Channel for IrcChannel { Self::send_raw(&mut writer, &format!("NICK {current_nick}")).await?; Self::send_raw( &mut writer, - &format!("USER {} 0 * :Alphahuman", self.username), + &format!("USER {} 0 * :OpenHuman", self.username), ) .await?; @@ -919,7 +919,7 @@ mod tests { server: "irc.example.com".into(), port: 6697, nickname: "zcbot".into(), - username: Some("alphahuman".into()), + username: Some("openhuman".into()), channels: vec!["#test".into()], allowed_users: vec!["alice".into()], server_password: Some("serverpass".into()), @@ -930,7 +930,7 @@ mod tests { assert_eq!(ch.server, "irc.example.com"); assert_eq!(ch.port, 6697); assert_eq!(ch.nickname, "zcbot"); - assert_eq!(ch.username, "alphahuman"); + assert_eq!(ch.username, "openhuman"); assert_eq!(ch.channels, vec!["#test"]); assert_eq!(ch.allowed_users, vec!["alice"]); assert_eq!(ch.server_password.as_deref(), Some("serverpass")); @@ -943,13 +943,13 @@ mod tests { #[test] fn irc_config_serde_roundtrip() { - use crate::alphahuman::config::schema::IrcConfig; + use crate::openhuman::config::schema::IrcConfig; let config = IrcConfig { server: "irc.example.com".into(), port: 6697, nickname: "zcbot".into(), - username: Some("alphahuman".into()), + username: Some("openhuman".into()), channels: vec!["#test".into(), "#dev".into()], allowed_users: vec!["alice".into()], server_password: None, @@ -963,7 +963,7 @@ mod tests { assert_eq!(parsed.server, "irc.example.com"); assert_eq!(parsed.port, 6697); assert_eq!(parsed.nickname, "zcbot"); - assert_eq!(parsed.username.as_deref(), Some("alphahuman")); + assert_eq!(parsed.username.as_deref(), Some("openhuman")); assert_eq!(parsed.channels, vec!["#test", "#dev"]); assert_eq!(parsed.allowed_users, vec!["alice"]); assert!(parsed.server_password.is_none()); @@ -974,7 +974,7 @@ mod tests { #[test] fn irc_config_minimal_toml() { - use crate::alphahuman::config::schema::IrcConfig; + use crate::openhuman::config::schema::IrcConfig; let toml_str = r#" server = "irc.example.com" @@ -995,7 +995,7 @@ nickname = "bot" #[test] fn irc_config_default_port() { - use crate::alphahuman::config::schema::IrcConfig; + use crate::openhuman::config::schema::IrcConfig; let json = r#"{"server":"irc.test","nickname":"bot"}"#; let parsed: IrcConfig = serde_json::from_str(json).unwrap(); @@ -1010,7 +1010,7 @@ nickname = "bot" port: 6697, nickname: "zcbot".into(), username: None, - channels: vec!["#alphahuman".into()], + channels: vec!["#openhuman".into()], allowed_users: vec!["*".into()], server_password: None, nickserv_password: None, diff --git a/src-tauri/src/alphahuman/channels/lark.rs b/src-tauri/src/openhuman/channels/lark.rs similarity index 98% rename from src-tauri/src/alphahuman/channels/lark.rs rename to src-tauri/src/openhuman/channels/lark.rs index fb8f5c08e..e60b80dfc 100644 --- a/src-tauri/src/alphahuman/channels/lark.rs +++ b/src-tauri/src/openhuman/channels/lark.rs @@ -147,7 +147,7 @@ pub struct LarkChannel { /// When true, use Feishu (CN) endpoints; when false, use Lark (international). use_feishu: bool, /// How to receive events: WebSocket long-connection or HTTP webhook. - receive_mode: crate::alphahuman::config::schema::LarkReceiveMode, + receive_mode: crate::openhuman::config::schema::LarkReceiveMode, /// Cached tenant access token tenant_token: Arc>>, /// Dedup set: WS message_ids seen in last ~30 min to prevent double-dispatch @@ -169,14 +169,14 @@ impl LarkChannel { port, allowed_users, use_feishu: true, - receive_mode: crate::alphahuman::config::schema::LarkReceiveMode::default(), + receive_mode: crate::openhuman::config::schema::LarkReceiveMode::default(), tenant_token: Arc::new(RwLock::new(None)), ws_seen_ids: Arc::new(RwLock::new(HashMap::new())), } } /// Build from `LarkConfig` (preserves `use_feishu` and `receive_mode`). - pub fn from_config(config: &crate::alphahuman::config::schema::LarkConfig) -> Self { + pub fn from_config(config: &crate::openhuman::config::schema::LarkConfig) -> Self { let mut ch = Self::new( config.app_id.clone(), config.app_secret.clone(), @@ -190,7 +190,7 @@ impl LarkChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.lark") + crate::openhuman::config::build_runtime_proxy_client("channel.lark") } fn api_base(&self) -> &'static str { @@ -698,7 +698,7 @@ impl Channel for LarkChannel { } async fn listen(&self, tx: tokio::sync::mpsc::Sender) -> anyhow::Result<()> { - use crate::alphahuman::config::schema::LarkReceiveMode; + use crate::openhuman::config::schema::LarkReceiveMode; match self.receive_mode { LarkReceiveMode::Websocket => self.listen_ws(tx).await, LarkReceiveMode::Webhook => self.listen_http(tx).await, @@ -983,7 +983,7 @@ mod tests { }, "message": { "message_type": "text", - "content": "{\"text\":\"Hello Alphahuman!\"}", + "content": "{\"text\":\"Hello OpenHuman!\"}", "chat_id": "oc_chat123", "create_time": "1699999999000" } @@ -992,7 +992,7 @@ mod tests { let msgs = ch.parse_event_payload(&payload); assert_eq!(msgs.len(), 1); - assert_eq!(msgs[0].content, "Hello Alphahuman!"); + assert_eq!(msgs[0].content, "Hello OpenHuman!"); assert_eq!(msgs[0].sender, "oc_chat123"); assert_eq!(msgs[0].channel, "lark"); assert_eq!(msgs[0].timestamp, 1_699_999_999); @@ -1169,7 +1169,7 @@ mod tests { #[test] fn lark_config_serde() { - use crate::alphahuman::config::schema::{LarkConfig, LarkReceiveMode}; + use crate::openhuman::config::schema::{LarkConfig, LarkReceiveMode}; let lc = LarkConfig { app_id: "cli_app123".into(), app_secret: "secret456".into(), @@ -1190,7 +1190,7 @@ mod tests { #[test] fn lark_config_toml_roundtrip() { - use crate::alphahuman::config::schema::{LarkConfig, LarkReceiveMode}; + use crate::openhuman::config::schema::{LarkConfig, LarkReceiveMode}; let lc = LarkConfig { app_id: "app".into(), app_secret: "secret".into(), @@ -1210,7 +1210,7 @@ mod tests { #[test] fn lark_config_defaults_optional_fields() { - use crate::alphahuman::config::schema::{LarkConfig, LarkReceiveMode}; + use crate::openhuman::config::schema::{LarkConfig, LarkReceiveMode}; let json = r#"{"app_id":"a","app_secret":"s"}"#; let parsed: LarkConfig = serde_json::from_str(json).unwrap(); assert!(parsed.verification_token.is_none()); @@ -1221,7 +1221,7 @@ mod tests { #[test] fn lark_from_config_preserves_mode_and_region() { - use crate::alphahuman::config::schema::{LarkConfig, LarkReceiveMode}; + use crate::openhuman::config::schema::{LarkConfig, LarkReceiveMode}; let cfg = LarkConfig { app_id: "cli_app123".into(), diff --git a/src-tauri/src/alphahuman/channels/linq.rs b/src-tauri/src/openhuman/channels/linq.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/linq.rs rename to src-tauri/src/openhuman/channels/linq.rs index e464fcc6e..3d79a2977 100644 --- a/src-tauri/src/alphahuman/channels/linq.rs +++ b/src-tauri/src/openhuman/channels/linq.rs @@ -451,7 +451,7 @@ mod tests { "id": "msg-abc", "parts": [{ "type": "text", - "value": "Hello Alphahuman!" + "value": "Hello OpenHuman!" }] } } @@ -460,7 +460,7 @@ mod tests { let msgs = ch.parse_webhook_payload(&payload); assert_eq!(msgs.len(), 1); assert_eq!(msgs[0].sender, "+1234567890"); - assert_eq!(msgs[0].content, "Hello Alphahuman!"); + assert_eq!(msgs[0].content, "Hello OpenHuman!"); assert_eq!(msgs[0].channel, "linq"); assert_eq!(msgs[0].reply_target, "chat-789"); } diff --git a/src-tauri/src/alphahuman/channels/matrix.rs b/src-tauri/src/openhuman/channels/matrix.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/matrix.rs rename to src-tauri/src/openhuman/channels/matrix.rs index 43c66943c..28f1699ca 100644 --- a/src-tauri/src/alphahuman/channels/matrix.rs +++ b/src-tauri/src/openhuman/channels/matrix.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::channels::traits::{Channel, ChannelMessage, SendMessage}; +use crate::openhuman::channels::traits::{Channel, ChannelMessage, SendMessage}; use async_trait::async_trait; use matrix_sdk::{ authentication::matrix::MatrixSession, diff --git a/src-tauri/src/alphahuman/channels/mattermost.rs b/src-tauri/src/openhuman/channels/mattermost.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/mattermost.rs rename to src-tauri/src/openhuman/channels/mattermost.rs index 57b8ae9ad..9e9557b42 100644 --- a/src-tauri/src/alphahuman/channels/mattermost.rs +++ b/src-tauri/src/openhuman/channels/mattermost.rs @@ -42,7 +42,7 @@ impl MattermostChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.mattermost") + crate::openhuman::config::build_runtime_proxy_client("channel.mattermost") } /// Check if a user ID is in the allowlist. diff --git a/src-tauri/src/alphahuman/channels/mod.rs b/src-tauri/src/openhuman/channels/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/channels/mod.rs rename to src-tauri/src/openhuman/channels/mod.rs diff --git a/src-tauri/src/alphahuman/channels/prompt.rs b/src-tauri/src/openhuman/channels/prompt.rs similarity index 97% rename from src-tauri/src/alphahuman/channels/prompt.rs rename to src-tauri/src/openhuman/channels/prompt.rs index 0a4d291f2..384343cba 100644 --- a/src-tauri/src/alphahuman/channels/prompt.rs +++ b/src-tauri/src/openhuman/channels/prompt.rs @@ -1,6 +1,6 @@ //! System prompt construction for channel interactions. -use crate::alphahuman::identity; +use crate::openhuman::identity; use std::path::Path; /// Maximum characters per injected workspace file (matches `OpenClaw` default). @@ -52,8 +52,8 @@ pub fn build_system_prompt( workspace_dir: &Path, model_name: &str, tools: &[(&str, &str)], - skills: &[crate::alphahuman::skills::Skill], - identity_config: Option<&crate::alphahuman::config::IdentityConfig>, + skills: &[crate::openhuman::skills::Skill], + identity_config: Option<&crate::openhuman::config::IdentityConfig>, bootstrap_max_chars: Option, ) -> String { use std::fmt::Write; @@ -210,7 +210,7 @@ pub fn build_system_prompt( prompt.push_str("- If a tool output contains credentials, they have already been redacted — do not mention them.\n\n"); if prompt.is_empty() { - "You are AlphaHuman, a fast and efficient AI assistant built in Rust. Be helpful, concise, and direct.".to_string() + "You are OpenHuman, a fast and efficient AI assistant built in Rust. Be helpful, concise, and direct.".to_string() } else { prompt } diff --git a/src-tauri/src/alphahuman/channels/qq.rs b/src-tauri/src/openhuman/channels/qq.rs similarity index 98% rename from src-tauri/src/alphahuman/channels/qq.rs rename to src-tauri/src/openhuman/channels/qq.rs index 7a0c124d6..bc93612a7 100644 --- a/src-tauri/src/alphahuman/channels/qq.rs +++ b/src-tauri/src/openhuman/channels/qq.rs @@ -47,7 +47,7 @@ impl QQChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.qq") + crate::openhuman::config::build_runtime_proxy_client("channel.qq") } fn is_user_allowed(&self, user_id: &str) -> bool { @@ -258,8 +258,8 @@ impl Channel for QQChannel { "intents": intents, "properties": { "os": "linux", - "browser": "alphahuman", - "device": "alphahuman", + "browser": "openhuman", + "device": "openhuman", } } }); @@ -500,7 +500,7 @@ app_id = "12345" app_secret = "secret_abc" allowed_users = ["user1"] "#; - let config: crate::alphahuman::config::schema::QQConfig = toml::from_str(toml_str).unwrap(); + let config: crate::openhuman::config::schema::QQConfig = toml::from_str(toml_str).unwrap(); assert_eq!(config.app_id, "12345"); assert_eq!(config.app_secret, "secret_abc"); assert_eq!(config.allowed_users, vec!["user1"]); diff --git a/src-tauri/src/alphahuman/channels/routes.rs b/src-tauri/src/openhuman/channels/routes.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/routes.rs rename to src-tauri/src/openhuman/channels/routes.rs index 7d7aa1ba3..46bc2582e 100644 --- a/src-tauri/src/alphahuman/channels/routes.rs +++ b/src-tauri/src/openhuman/channels/routes.rs @@ -5,7 +5,7 @@ use super::context::{ }; use super::traits; use super::{Channel, SendMessage}; -use crate::alphahuman::providers::{self, Provider}; +use crate::openhuman::providers::{self, Provider}; use serde::Deserialize; use std::fmt::Write; use std::path::Path; diff --git a/src-tauri/src/alphahuman/channels/runtime/dispatch.rs b/src-tauri/src/openhuman/channels/runtime/dispatch.rs similarity index 97% rename from src-tauri/src/alphahuman/channels/runtime/dispatch.rs rename to src-tauri/src/openhuman/channels/runtime/dispatch.rs index 167f74fc4..31e440fdb 100644 --- a/src-tauri/src/alphahuman/channels/runtime/dispatch.rs +++ b/src-tauri/src/openhuman/channels/runtime/dispatch.rs @@ -1,18 +1,18 @@ //! Channel runtime loop and message processing. -use crate::alphahuman::channels::context::{ +use crate::openhuman::channels::context::{ build_memory_context, compact_sender_history, conversation_history_key, conversation_memory_key, is_context_window_overflow_error, ChannelRuntimeContext, CHANNEL_TYPING_REFRESH_INTERVAL_SECS, MAX_CHANNEL_HISTORY, }; -use crate::alphahuman::channels::routes::{ +use crate::openhuman::channels::routes::{ get_or_create_provider, get_route_selection, handle_runtime_command_if_needed, }; -use crate::alphahuman::channels::traits; -use crate::alphahuman::channels::{Channel, SendMessage}; -use crate::alphahuman::agent::loop_::run_tool_call_loop; -use crate::alphahuman::providers::{self, ChatMessage}; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::channels::traits; +use crate::openhuman::channels::{Channel, SendMessage}; +use crate::openhuman::agent::loop_::run_tool_call_loop; +use crate::openhuman::providers::{self, ChatMessage}; +use crate::openhuman::util::truncate_with_ellipsis; use std::sync::Arc; use std::time::{Duration, Instant}; use tokio_util::sync::CancellationToken; @@ -110,7 +110,7 @@ pub(crate) async fn process_channel_message( .store( &autosave_key, &msg.content, - crate::alphahuman::memory::MemoryCategory::Conversation, + crate::openhuman::memory::MemoryCategory::Conversation, None, ) .await; diff --git a/src-tauri/src/alphahuman/channels/runtime/mod.rs b/src-tauri/src/openhuman/channels/runtime/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/channels/runtime/mod.rs rename to src-tauri/src/openhuman/channels/runtime/mod.rs diff --git a/src-tauri/src/alphahuman/channels/runtime/startup.rs b/src-tauri/src/openhuman/channels/runtime/startup.rs similarity index 90% rename from src-tauri/src/alphahuman/channels/runtime/startup.rs rename to src-tauri/src/openhuman/channels/runtime/startup.rs index 9ea8009f9..ed489b700 100644 --- a/src-tauri/src/alphahuman/channels/runtime/startup.rs +++ b/src-tauri/src/openhuman/channels/runtime/startup.rs @@ -1,40 +1,40 @@ //! Channel startup wiring. -use crate::alphahuman::channels::context::{ +use crate::openhuman::channels::context::{ effective_channel_message_timeout_secs, ChannelRuntimeContext, DEFAULT_CHANNEL_INITIAL_BACKOFF_SECS, DEFAULT_CHANNEL_MAX_BACKOFF_SECS, }; use super::dispatch::run_message_dispatch_loop; use super::supervision::{compute_max_in_flight_messages, spawn_supervised_listener}; -use crate::alphahuman::agent::loop_::build_tool_instructions; -use crate::alphahuman::channels::dingtalk::DingTalkChannel; -use crate::alphahuman::channels::discord::DiscordChannel; -use crate::alphahuman::channels::email_channel::EmailChannel; -use crate::alphahuman::channels::imessage::IMessageChannel; -use crate::alphahuman::channels::irc; -use crate::alphahuman::channels::irc::IrcChannel; -use crate::alphahuman::channels::lark::LarkChannel; -use crate::alphahuman::channels::linq::LinqChannel; +use crate::openhuman::agent::loop_::build_tool_instructions; +use crate::openhuman::channels::dingtalk::DingTalkChannel; +use crate::openhuman::channels::discord::DiscordChannel; +use crate::openhuman::channels::email_channel::EmailChannel; +use crate::openhuman::channels::imessage::IMessageChannel; +use crate::openhuman::channels::irc; +use crate::openhuman::channels::irc::IrcChannel; +use crate::openhuman::channels::lark::LarkChannel; +use crate::openhuman::channels::linq::LinqChannel; #[cfg(feature = "channel-matrix")] -use crate::alphahuman::channels::matrix::MatrixChannel; -use crate::alphahuman::channels::mattermost::MattermostChannel; -use crate::alphahuman::channels::prompt::build_system_prompt; -use crate::alphahuman::channels::qq::QQChannel; -use crate::alphahuman::channels::signal::SignalChannel; -use crate::alphahuman::channels::slack::SlackChannel; -use crate::alphahuman::channels::telegram::TelegramChannel; -use crate::alphahuman::channels::traits; -use crate::alphahuman::channels::whatsapp::WhatsAppChannel; +use crate::openhuman::channels::matrix::MatrixChannel; +use crate::openhuman::channels::mattermost::MattermostChannel; +use crate::openhuman::channels::prompt::build_system_prompt; +use crate::openhuman::channels::qq::QQChannel; +use crate::openhuman::channels::signal::SignalChannel; +use crate::openhuman::channels::slack::SlackChannel; +use crate::openhuman::channels::telegram::TelegramChannel; +use crate::openhuman::channels::traits; +use crate::openhuman::channels::whatsapp::WhatsAppChannel; #[cfg(feature = "whatsapp-web")] -use crate::alphahuman::channels::whatsapp_web::WhatsAppWebChannel; -use crate::alphahuman::channels::Channel; -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::{self, Memory}; -use crate::alphahuman::observability::{self, Observer}; -use crate::alphahuman::providers::{self, Provider}; -use crate::alphahuman::runtime; -use crate::alphahuman::security::SecurityPolicy; -use crate::alphahuman::tools; +use crate::openhuman::channels::whatsapp_web::WhatsAppWebChannel; +use crate::openhuman::channels::Channel; +use crate::openhuman::config::Config; +use crate::openhuman::memory::{self, Memory}; +use crate::openhuman::observability::{self, Observer}; +use crate::openhuman::providers::{self, Provider}; +use crate::openhuman::runtime; +use crate::openhuman::security::SecurityPolicy; +use crate::openhuman::tools; use anyhow::Result; use std::collections::HashMap; use std::sync::{Arc, Mutex}; @@ -46,7 +46,7 @@ pub async fn start_channels(config: Config) -> Result<()> { .unwrap_or_else(|| "openrouter".into()); let provider_runtime_options = providers::ProviderRuntimeOptions { auth_profile_override: None, - alphahuman_dir: config.config_path.parent().map(std::path::PathBuf::from), + openhuman_dir: config.config_path.parent().map(std::path::PathBuf::from), secrets_encrypt: config.secrets.encrypt, reasoning_enabled: config.runtime.reasoning_enabled, }; @@ -108,7 +108,7 @@ pub async fn start_channels(config: Config) -> Result<()> { &config, )); - let skills = crate::alphahuman::skills::load_skills(&workspace); + let skills = crate::openhuman::skills::load_skills(&workspace); // Collect tool descriptions for the prompt let mut tool_descs: Vec<(&str, &str)> = vec![ @@ -360,7 +360,7 @@ pub async fn start_channels(config: Config) -> Result<()> { return Ok(()); } - println!("🦀 Alphahuman Channel Server"); + println!("🦀 OpenHuman Channel Server"); println!(" 🤖 Model: {model}"); let effective_backend = memory::effective_memory_backend_name( &config.memory.backend, @@ -383,7 +383,7 @@ pub async fn start_channels(config: Config) -> Result<()> { println!(" Listening for messages... (Ctrl+C to stop)"); println!(); - crate::alphahuman::health::mark_component_ok("channels"); + crate::openhuman::health::mark_component_ok("channels"); let initial_backoff_secs = config .reliability diff --git a/src-tauri/src/alphahuman/channels/runtime/supervision.rs b/src-tauri/src/openhuman/channels/runtime/supervision.rs similarity index 86% rename from src-tauri/src/alphahuman/channels/runtime/supervision.rs rename to src-tauri/src/openhuman/channels/runtime/supervision.rs index 8fdd33cdd..006ff5961 100644 --- a/src-tauri/src/alphahuman/channels/runtime/supervision.rs +++ b/src-tauri/src/openhuman/channels/runtime/supervision.rs @@ -21,7 +21,7 @@ pub(crate) fn spawn_supervised_listener( let max_backoff = max_backoff_secs.max(backoff); loop { - crate::alphahuman::health::mark_component_ok(&component); + crate::openhuman::health::mark_component_ok(&component); let result = ch.listen(tx.clone()).await; if tx.is_closed() { @@ -31,7 +31,7 @@ pub(crate) fn spawn_supervised_listener( match result { Ok(()) => { tracing::warn!("Channel {} exited unexpectedly; restarting", ch.name()); - crate::alphahuman::health::mark_component_error( + crate::openhuman::health::mark_component_error( &component, "listener exited unexpectedly", ); @@ -40,11 +40,11 @@ pub(crate) fn spawn_supervised_listener( } Err(e) => { tracing::error!("Channel {} error: {e}; restarting", ch.name()); - crate::alphahuman::health::mark_component_error(&component, e.to_string()); + crate::openhuman::health::mark_component_error(&component, e.to_string()); } } - crate::alphahuman::health::bump_component_restart(&component); + crate::openhuman::health::bump_component_restart(&component); tokio::time::sleep(Duration::from_secs(backoff)).await; // Double backoff AFTER sleeping so first error uses initial_backoff backoff = backoff.saturating_mul(2).min(max_backoff); diff --git a/src-tauri/src/alphahuman/channels/signal.rs b/src-tauri/src/openhuman/channels/signal.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/signal.rs rename to src-tauri/src/openhuman/channels/signal.rs index ac1c50a53..f5406dcd6 100644 --- a/src-tauri/src/alphahuman/channels/signal.rs +++ b/src-tauri/src/openhuman/channels/signal.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::channels::traits::{Channel, ChannelMessage, SendMessage}; +use crate::openhuman::channels::traits::{Channel, ChannelMessage, SendMessage}; use async_trait::async_trait; use futures_util::StreamExt; use reqwest::Client; @@ -92,7 +92,7 @@ impl SignalChannel { fn http_client(&self) -> Client { let builder = Client::builder().connect_timeout(Duration::from_secs(10)); - let builder = crate::alphahuman::config::apply_runtime_proxy_to_builder(builder, "channel.signal"); + let builder = crate::openhuman::config::apply_runtime_proxy_to_builder(builder, "channel.signal"); builder.build().expect("Signal HTTP client should build") } diff --git a/src-tauri/src/alphahuman/channels/slack.rs b/src-tauri/src/openhuman/channels/slack.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/slack.rs rename to src-tauri/src/openhuman/channels/slack.rs index b5854c460..676cbf9e2 100644 --- a/src-tauri/src/alphahuman/channels/slack.rs +++ b/src-tauri/src/openhuman/channels/slack.rs @@ -18,7 +18,7 @@ impl SlackChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.slack") + crate::openhuman::config::build_runtime_proxy_client("channel.slack") } /// Check if a Slack user ID is in the allowlist. diff --git a/src-tauri/src/alphahuman/channels/telegram.rs b/src-tauri/src/openhuman/channels/telegram.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/telegram.rs rename to src-tauri/src/openhuman/channels/telegram.rs index e609dc9c7..f106c65d1 100644 --- a/src-tauri/src/alphahuman/channels/telegram.rs +++ b/src-tauri/src/openhuman/channels/telegram.rs @@ -1,6 +1,6 @@ use super::traits::{Channel, ChannelMessage, SendMessage}; -use crate::alphahuman::config::{Config, StreamMode}; -use crate::alphahuman::security::pairing::PairingGuard; +use crate::openhuman::config::{Config, StreamMode}; +use crate::openhuman::security::pairing::PairingGuard; use anyhow::Context; use async_trait::async_trait; use directories::UserDirs; @@ -364,7 +364,7 @@ impl TelegramChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.telegram") + crate::openhuman::config::build_runtime_proxy_client("channel.telegram") } fn normalize_identity(value: &str) -> String { @@ -383,8 +383,8 @@ impl TelegramChannel { let home = UserDirs::new() .map(|u| u.home_dir().to_path_buf()) .context("Could not find home directory")?; - let alphahuman_dir = home.join(".alphahuman"); - let config_path = alphahuman_dir.join("config.toml"); + let openhuman_dir = home.join(".openhuman"); + let config_path = openhuman_dir.join("config.toml"); let contents = fs::read_to_string(&config_path) .await @@ -392,7 +392,7 @@ impl TelegramChannel { let mut config: Config = toml::from_str(&contents) .context("Failed to parse config file for Telegram binding")?; config.config_path = config_path; - config.workspace_dir = alphahuman_dir.join("workspace"); + config.workspace_dir = openhuman_dir.join("workspace"); Ok(config) } @@ -645,7 +645,7 @@ impl TelegramChannel { Ok(()) => { let _ = self .send(&SendMessage::new( - "✅ Telegram account bound successfully. You can talk to Alphahuman now.", + "✅ Telegram account bound successfully. You can talk to OpenHuman now.", &chat_id, )) .await; @@ -1725,7 +1725,7 @@ impl Channel for TelegramChannel { if error_code == 409 { tracing::warn!( "Telegram polling conflict (409): {description}. \ -Ensure only one `alphahuman` process is using this bot token." +Ensure only one `openhuman` process is using this bot token." ); tokio::time::sleep(std::time::Duration::from_secs(2)).await; } else { @@ -2037,7 +2037,7 @@ mod tests { #[test] fn telegram_extract_bind_code_supports_bot_mention() { assert_eq!( - TelegramChannel::extract_bind_code("/bind@alphahuman_bot 654321"), + TelegramChannel::extract_bind_code("/bind@openhuman_bot 654321"), Some("654321") ); } diff --git a/src-tauri/src/alphahuman/channels/tests/common.rs b/src-tauri/src/openhuman/channels/tests/common.rs similarity index 97% rename from src-tauri/src/alphahuman/channels/tests/common.rs rename to src-tauri/src/openhuman/channels/tests/common.rs index 753cb43d1..562b66054 100644 --- a/src-tauri/src/alphahuman/channels/tests/common.rs +++ b/src-tauri/src/openhuman/channels/tests/common.rs @@ -1,7 +1,7 @@ -use crate::alphahuman::channels::{traits, Channel, SendMessage}; -use crate::alphahuman::memory::{Memory, MemoryCategory, MemoryEntry}; -use crate::alphahuman::providers::{ChatMessage, Provider}; -use crate::alphahuman::tools::{Tool, ToolResult}; +use crate::openhuman::channels::{traits, Channel, SendMessage}; +use crate::openhuman::memory::{Memory, MemoryCategory, MemoryEntry}; +use crate::openhuman::providers::{ChatMessage, Provider}; +use crate::openhuman::tools::{Tool, ToolResult}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -11,7 +11,7 @@ pub(super) fn make_workspace() -> TempDir { let tmp = TempDir::new().unwrap(); // Create minimal workspace files std::fs::write(tmp.path().join("SOUL.md"), "# Soul\nBe helpful.").unwrap(); - std::fs::write(tmp.path().join("IDENTITY.md"), "# Identity\nName: Alphahuman").unwrap(); + std::fs::write(tmp.path().join("IDENTITY.md"), "# Identity\nName: OpenHuman").unwrap(); std::fs::write(tmp.path().join("USER.md"), "# User\nName: Test User").unwrap(); std::fs::write( tmp.path().join("AGENTS.md"), diff --git a/src-tauri/src/alphahuman/channels/tests/context.rs b/src-tauri/src/openhuman/channels/tests/context.rs similarity index 90% rename from src-tauri/src/alphahuman/channels/tests/context.rs rename to src-tauri/src/openhuman/channels/tests/context.rs index 270cf09dc..ace589620 100644 --- a/src-tauri/src/alphahuman/channels/tests/context.rs +++ b/src-tauri/src/openhuman/channels/tests/context.rs @@ -5,8 +5,8 @@ use super::super::context::{ CHANNEL_HISTORY_COMPACT_CONTENT_CHARS, CHANNEL_HISTORY_COMPACT_KEEP_MESSAGES, CHANNEL_MESSAGE_TIMEOUT_SECS, MIN_CHANNEL_MESSAGE_TIMEOUT_SECS, }; -use crate::alphahuman::observability::NoopObserver; -use crate::alphahuman::providers::ChatMessage; +use crate::openhuman::observability::NoopObserver; +use crate::openhuman::providers::ChatMessage; use std::collections::HashMap; use std::sync::{Arc, Mutex}; @@ -80,9 +80,9 @@ fn compact_sender_history_keeps_recent_truncated_messages() { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), - multimodal: crate::alphahuman::config::MultimodalConfig::default(), - provider_runtime_options: crate::alphahuman::providers::ProviderRuntimeOptions::default(), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), + multimodal: crate::openhuman::config::MultimodalConfig::default(), + provider_runtime_options: crate::openhuman::providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, }; diff --git a/src-tauri/src/alphahuman/channels/tests/health.rs b/src-tauri/src/openhuman/channels/tests/health.rs similarity index 96% rename from src-tauri/src/alphahuman/channels/tests/health.rs rename to src-tauri/src/openhuman/channels/tests/health.rs index 7634d93d1..f4995af81 100644 --- a/src-tauri/src/alphahuman/channels/tests/health.rs +++ b/src-tauri/src/openhuman/channels/tests/health.rs @@ -44,7 +44,7 @@ async fn supervised_listener_marks_error_and_restarts_on_failures() { handle.abort(); let _ = handle.await; - let snapshot = crate::alphahuman::health::snapshot_json(); + let snapshot = crate::openhuman::health::snapshot_json(); let component = &snapshot["components"]["channel:test-supervised-fail"]; assert_eq!(component["status"], "error"); assert!(component["restart_count"].as_u64().unwrap_or(0) >= 1); diff --git a/src-tauri/src/alphahuman/channels/tests/identity.rs b/src-tauri/src/openhuman/channels/tests/identity.rs similarity index 94% rename from src-tauri/src/alphahuman/channels/tests/identity.rs rename to src-tauri/src/openhuman/channels/tests/identity.rs index 175ff8181..118a3e56e 100644 --- a/src-tauri/src/alphahuman/channels/tests/identity.rs +++ b/src-tauri/src/openhuman/channels/tests/identity.rs @@ -3,7 +3,7 @@ use super::super::prompt::build_system_prompt; #[test] fn aieos_identity_from_file() { - use crate::alphahuman::config::IdentityConfig; + use crate::openhuman::config::IdentityConfig; use tempfile::TempDir; let tmp = TempDir::new().unwrap(); @@ -60,7 +60,7 @@ fn aieos_identity_from_file() { #[test] fn aieos_identity_from_inline() { - use crate::alphahuman::config::IdentityConfig; + use crate::openhuman::config::IdentityConfig; let config = IdentityConfig { format: "aieos".into(), @@ -83,7 +83,7 @@ fn aieos_identity_from_inline() { #[test] fn aieos_fallback_to_openclaw_on_parse_error() { - use crate::alphahuman::config::IdentityConfig; + use crate::openhuman::config::IdentityConfig; let config = IdentityConfig { format: "aieos".into(), @@ -101,7 +101,7 @@ fn aieos_fallback_to_openclaw_on_parse_error() { #[test] fn aieos_empty_uses_openclaw() { - use crate::alphahuman::config::IdentityConfig; + use crate::openhuman::config::IdentityConfig; // Format is "aieos" but neither path nor inline is set let config = IdentityConfig { @@ -120,7 +120,7 @@ fn aieos_empty_uses_openclaw() { #[test] fn openclaw_format_uses_bootstrap_files() { - use crate::alphahuman::config::IdentityConfig; + use crate::openhuman::config::IdentityConfig; let config = IdentityConfig { format: "openclaw".into(), diff --git a/src-tauri/src/alphahuman/channels/tests/memory.rs b/src-tauri/src/openhuman/channels/tests/memory.rs similarity index 94% rename from src-tauri/src/alphahuman/channels/tests/memory.rs rename to src-tauri/src/openhuman/channels/tests/memory.rs index 05062172b..0279c3eb9 100644 --- a/src-tauri/src/alphahuman/channels/tests/memory.rs +++ b/src-tauri/src/openhuman/channels/tests/memory.rs @@ -2,9 +2,9 @@ use super::common::{HistoryCaptureProvider, NoopMemory, RecordingChannel}; use super::super::context::{build_memory_context, conversation_memory_key, ChannelRuntimeContext, CHANNEL_MESSAGE_TIMEOUT_SECS, MAX_CHANNEL_HISTORY}; use super::super::runtime::process_channel_message; use super::super::{traits, Channel}; -use crate::alphahuman::memory::{Memory, MemoryCategory, SqliteMemory}; -use crate::alphahuman::observability::NoopObserver; -use crate::alphahuman::providers::{self, ChatMessage, Provider}; +use crate::openhuman::memory::{Memory, MemoryCategory, SqliteMemory}; +use crate::openhuman::observability::NoopObserver; +use crate::openhuman::providers::{self, ChatMessage, Provider}; use std::collections::HashMap; use std::sync::{Arc, Mutex}; use tempfile::TempDir; @@ -138,11 +138,11 @@ async fn process_channel_message_restores_per_sender_history_on_follow_ups() { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( diff --git a/src-tauri/src/alphahuman/channels/tests/mod.rs b/src-tauri/src/openhuman/channels/tests/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/channels/tests/mod.rs rename to src-tauri/src/openhuman/channels/tests/mod.rs diff --git a/src-tauri/src/alphahuman/channels/tests/prompt.rs b/src-tauri/src/openhuman/channels/tests/prompt.rs similarity index 96% rename from src-tauri/src/alphahuman/channels/tests/prompt.rs rename to src-tauri/src/openhuman/channels/tests/prompt.rs index 79e1ad097..e09b2c6df 100644 --- a/src-tauri/src/alphahuman/channels/tests/prompt.rs +++ b/src-tauri/src/openhuman/channels/tests/prompt.rs @@ -56,7 +56,7 @@ fn prompt_injects_workspace_files() { assert!(prompt.contains("Be helpful"), "missing SOUL content"); assert!(prompt.contains("### IDENTITY.md"), "missing IDENTITY.md"); assert!( - prompt.contains("Name: Alphahuman"), + prompt.contains("Name: OpenHuman"), "missing IDENTITY content" ); assert!(prompt.contains("### USER.md"), "missing USER.md"); @@ -142,7 +142,7 @@ fn prompt_runtime_metadata() { #[test] fn prompt_skills_compact_list() { let ws = make_workspace(); - let skills = vec![crate::alphahuman::skills::Skill { + let skills = vec![crate::openhuman::skills::Skill { name: "code-review".into(), description: "Review code for bugs".into(), version: "1.0.0".into(), @@ -202,10 +202,10 @@ fn prompt_empty_files_skipped() { #[test] fn channel_log_truncation_is_utf8_safe_for_multibyte_text() { - let msg = "Hello from Alphahuman 🌍. Current status is healthy, and café-style UTF-8 text stays safe in logs."; + let msg = "Hello from OpenHuman 🌍. Current status is healthy, and café-style UTF-8 text stays safe in logs."; // Reproduces the production crash path where channel logs truncate at 80 chars. - let result = std::panic::catch_unwind(|| crate::alphahuman::util::truncate_with_ellipsis(msg, 80)); + let result = std::panic::catch_unwind(|| crate::openhuman::util::truncate_with_ellipsis(msg, 80)); assert!( result.is_ok(), "truncate_with_ellipsis should never panic on UTF-8" diff --git a/src-tauri/src/alphahuman/channels/tests/runtime_dispatch.rs b/src-tauri/src/openhuman/channels/tests/runtime_dispatch.rs similarity index 91% rename from src-tauri/src/alphahuman/channels/tests/runtime_dispatch.rs rename to src-tauri/src/openhuman/channels/tests/runtime_dispatch.rs index 496495d3a..94a18b769 100644 --- a/src-tauri/src/alphahuman/channels/tests/runtime_dispatch.rs +++ b/src-tauri/src/openhuman/channels/tests/runtime_dispatch.rs @@ -2,8 +2,8 @@ use super::common::{NoopMemory, RecordingChannel, SlowProvider}; use super::super::context::{ChannelRuntimeContext, CHANNEL_MESSAGE_TIMEOUT_SECS}; use super::super::runtime::{process_channel_message, run_message_dispatch_loop}; use super::super::{traits, Channel}; -use crate::alphahuman::observability::NoopObserver; -use crate::alphahuman::providers::{self, Provider}; +use crate::openhuman::observability::NoopObserver; +use crate::openhuman::providers::{self, Provider}; use std::collections::HashMap; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; @@ -38,11 +38,11 @@ let runtime_ctx = Arc::new(ChannelRuntimeContext { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); let (tx, rx) = tokio::sync::mpsc::channel::(4); @@ -112,11 +112,11 @@ let runtime_ctx = Arc::new(ChannelRuntimeContext { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( diff --git a/src-tauri/src/alphahuman/channels/tests/runtime_tool_calls.rs b/src-tauri/src/openhuman/channels/tests/runtime_tool_calls.rs similarity index 93% rename from src-tauri/src/alphahuman/channels/tests/runtime_tool_calls.rs rename to src-tauri/src/openhuman/channels/tests/runtime_tool_calls.rs index 27694470b..a61b1217a 100644 --- a/src-tauri/src/alphahuman/channels/tests/runtime_tool_calls.rs +++ b/src-tauri/src/openhuman/channels/tests/runtime_tool_calls.rs @@ -6,9 +6,9 @@ use super::common::{ use super::super::context::{ChannelRuntimeContext, ChannelRouteSelection, CHANNEL_MESSAGE_TIMEOUT_SECS}; use super::super::runtime::{process_channel_message, run_message_dispatch_loop}; use super::super::{traits, Channel, SendMessage}; -use crate::alphahuman::observability::NoopObserver; -use crate::alphahuman::providers::{self, ChatMessage, Provider}; -use crate::alphahuman::tools::Tool; +use crate::openhuman::observability::NoopObserver; +use crate::openhuman::providers::{self, ChatMessage, Provider}; +use crate::openhuman::tools::Tool; use std::collections::HashMap; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; @@ -39,11 +39,11 @@ async fn process_channel_message_executes_tool_calls_instead_of_sending_raw_json route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( @@ -94,11 +94,11 @@ async fn process_channel_message_executes_tool_calls_with_alias_tags() { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( @@ -158,11 +158,11 @@ async fn process_channel_message_handles_models_command_without_llm_call() { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( @@ -243,11 +243,11 @@ async fn process_channel_message_uses_route_override_provider_and_model() { route_overrides: Arc::new(Mutex::new(route_overrides)), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( @@ -304,11 +304,11 @@ async fn process_channel_message_respects_configured_max_tool_iterations_above_d route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( @@ -360,11 +360,11 @@ async fn process_channel_message_reports_configured_max_tool_iterations_limit() route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( diff --git a/src-tauri/src/alphahuman/channels/traits.rs b/src-tauri/src/openhuman/channels/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/channels/traits.rs rename to src-tauri/src/openhuman/channels/traits.rs diff --git a/src-tauri/src/alphahuman/channels/whatsapp.rs b/src-tauri/src/openhuman/channels/whatsapp.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/whatsapp.rs rename to src-tauri/src/openhuman/channels/whatsapp.rs index 586430ec3..84a08e1fd 100644 --- a/src-tauri/src/alphahuman/channels/whatsapp.rs +++ b/src-tauri/src/openhuman/channels/whatsapp.rs @@ -45,7 +45,7 @@ impl WhatsAppChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.whatsapp") + crate::openhuman::config::build_runtime_proxy_client("channel.whatsapp") } /// Check if a phone number is allowed (E.164 format: +1234567890) @@ -307,7 +307,7 @@ mod tests { "timestamp": "1699999999", "type": "text", "text": { - "body": "Hello Alphahuman!" + "body": "Hello OpenHuman!" } }] }, @@ -319,7 +319,7 @@ mod tests { let msgs = ch.parse_webhook_payload(&payload); assert_eq!(msgs.len(), 1); assert_eq!(msgs[0].sender, "+1234567890"); - assert_eq!(msgs[0].content, "Hello Alphahuman!"); + assert_eq!(msgs[0].content, "Hello OpenHuman!"); assert_eq!(msgs[0].channel, "whatsapp"); assert_eq!(msgs[0].timestamp, 1_699_999_999); } diff --git a/src-tauri/src/alphahuman/channels/whatsapp_storage.rs b/src-tauri/src/openhuman/channels/whatsapp_storage.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/whatsapp_storage.rs rename to src-tauri/src/openhuman/channels/whatsapp_storage.rs index 7a18a7d70..db3cc5ade 100644 --- a/src-tauri/src/alphahuman/channels/whatsapp_storage.rs +++ b/src-tauri/src/openhuman/channels/whatsapp_storage.rs @@ -1,4 +1,4 @@ -//! Custom wa-rs storage backend using Alphahuman's rusqlite +//! Custom wa-rs storage backend using OpenHuman's rusqlite //! //! This module implements all 4 wa-rs storage traits using rusqlite directly, //! avoiding the Diesel/libsqlite3-sys dependency conflict from wa-rs-sqlite-storage. @@ -41,7 +41,7 @@ use wa_rs_core::store::Device as CoreDevice; /// Custom wa-rs storage backend using rusqlite /// /// This implements all 4 storage traits required by wa-rs. -/// The backend uses Alphahuman's existing rusqlite setup, avoiding the +/// The backend uses OpenHuman's existing rusqlite setup, avoiding the /// Diesel/libsqlite3-sys conflict from wa-rs-sqlite-storage. #[cfg(feature = "whatsapp-web")] #[derive(Clone)] diff --git a/src-tauri/src/alphahuman/channels/whatsapp_web.rs b/src-tauri/src/openhuman/channels/whatsapp_web.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/whatsapp_web.rs rename to src-tauri/src/openhuman/channels/whatsapp_web.rs index 19861b328..c4648098b 100644 --- a/src-tauri/src/alphahuman/channels/whatsapp_web.rs +++ b/src-tauri/src/openhuman/channels/whatsapp_web.rs @@ -16,7 +16,7 @@ //! //! ```toml //! [channels.whatsapp] -//! session_path = "~/.alphahuman/whatsapp-session.db" # Required for Web mode +//! session_path = "~/.openhuman/whatsapp-session.db" # Required for Web mode //! pair_phone = "15551234567" # Optional: for pair code linking //! allowed_numbers = ["+1234567890", "*"] # Same as Cloud API //! ``` @@ -44,7 +44,7 @@ use tokio::select; /// /// ```toml /// [channels.whatsapp] -/// session_path = "~/.alphahuman/whatsapp-session.db" +/// session_path = "~/.openhuman/whatsapp-session.db" /// pair_phone = "15551234567" # Optional /// allowed_numbers = ["+1234567890", "*"] /// ``` diff --git a/src-tauri/src/alphahuman/config/daemon.rs b/src-tauri/src/openhuman/config/daemon.rs similarity index 77% rename from src-tauri/src/alphahuman/config/daemon.rs rename to src-tauri/src/openhuman/config/daemon.rs index cab1a7ab4..4bbdaea32 100644 --- a/src-tauri/src/alphahuman/config/daemon.rs +++ b/src-tauri/src/openhuman/config/daemon.rs @@ -1,6 +1,6 @@ -//! Tauri-focused daemon configuration wrapper for alphahuman. +//! Tauri-focused daemon configuration wrapper for openhuman. -use crate::alphahuman::config::{ +use crate::openhuman::config::{ AuditConfig, AutonomyConfig, ReliabilityConfig, SecretsConfig, SecurityConfig, }; use serde::{Deserialize, Serialize}; @@ -9,7 +9,7 @@ use std::path::PathBuf; /// Top-level daemon configuration for the Tauri supervisor. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DaemonConfig { - /// Root data directory (defaults to Tauri's `app_data_dir/alphahuman`). + /// Root data directory (defaults to Tauri's `app_data_dir/openhuman`). pub data_dir: PathBuf, /// Workspace directory the agent may operate within. pub workspace_dir: PathBuf, @@ -33,10 +33,10 @@ pub struct DaemonConfig { impl DaemonConfig { /// Build a config that derives paths from the Tauri `app_data_dir`. pub fn from_app_data_dir(app_data_dir: &std::path::Path) -> Self { - let data_dir = app_data_dir.join("alphahuman"); + let data_dir = app_data_dir.join("openhuman"); let workspace_dir = data_dir.join("workspace"); log::info!( - "[alphahuman:config] Initialized config: data_dir={}, workspace_dir={}", + "[openhuman:config] Initialized config: data_dir={}, workspace_dir={}", data_dir.display(), workspace_dir.display() ); @@ -58,13 +58,13 @@ mod tests { #[test] fn daemon_config_from_app_data_dir() { - let app_data = std::path::PathBuf::from("/tmp/test-alphahuman"); + let app_data = std::path::PathBuf::from("/tmp/test-openhuman"); let config = DaemonConfig::from_app_data_dir(&app_data); - assert_eq!(config.data_dir, app_data.join("alphahuman")); + assert_eq!(config.data_dir, app_data.join("openhuman")); assert_eq!( config.workspace_dir, - app_data.join("alphahuman").join("workspace") + app_data.join("openhuman").join("workspace") ); } } diff --git a/src-tauri/src/alphahuman/config/mod.rs b/src-tauri/src/openhuman/config/mod.rs similarity index 96% rename from src-tauri/src/alphahuman/config/mod.rs rename to src-tauri/src/openhuman/config/mod.rs index 6fae3d61b..d38110e3b 100644 --- a/src-tauri/src/alphahuman/config/mod.rs +++ b/src-tauri/src/openhuman/config/mod.rs @@ -59,7 +59,7 @@ mod tests { verification_token: None, allowed_users: vec![], use_feishu: false, - receive_mode: crate::alphahuman::config::schema::LarkReceiveMode::Websocket, + receive_mode: crate::openhuman::config::schema::LarkReceiveMode::Websocket, port: None, }; diff --git a/src-tauri/src/alphahuman/config/schema/agent.rs b/src-tauri/src/openhuman/config/schema/agent.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/agent.rs rename to src-tauri/src/openhuman/config/schema/agent.rs diff --git a/src-tauri/src/alphahuman/config/schema/autonomy.rs b/src-tauri/src/openhuman/config/schema/autonomy.rs similarity index 98% rename from src-tauri/src/alphahuman/config/schema/autonomy.rs rename to src-tauri/src/openhuman/config/schema/autonomy.rs index f5e74230c..45a46edd2 100644 --- a/src-tauri/src/alphahuman/config/schema/autonomy.rs +++ b/src-tauri/src/openhuman/config/schema/autonomy.rs @@ -1,6 +1,6 @@ //! Autonomy and security policy configuration. -use crate::alphahuman::security::AutonomyLevel; +use crate::openhuman::security::AutonomyLevel; use super::defaults; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/src/alphahuman/config/schema/channels.rs b/src-tauri/src/openhuman/config/schema/channels.rs similarity index 99% rename from src-tauri/src/alphahuman/config/schema/channels.rs rename to src-tauri/src/openhuman/config/schema/channels.rs index 1ea502b7f..ecff0629d 100644 --- a/src-tauri/src/alphahuman/config/schema/channels.rs +++ b/src-tauri/src/openhuman/config/schema/channels.rs @@ -1,6 +1,6 @@ //! Channels configuration (Telegram, Discord, Slack, Matrix, etc.) and security/sandbox. -use crate::alphahuman::channels::email_channel::EmailConfig; +use crate::openhuman::channels::email_channel::EmailConfig; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/src/alphahuman/config/schema/defaults.rs b/src-tauri/src/openhuman/config/schema/defaults.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/defaults.rs rename to src-tauri/src/openhuman/config/schema/defaults.rs diff --git a/src-tauri/src/alphahuman/config/schema/gateway.rs b/src-tauri/src/openhuman/config/schema/gateway.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/gateway.rs rename to src-tauri/src/openhuman/config/schema/gateway.rs diff --git a/src-tauri/src/alphahuman/config/schema/hardware.rs b/src-tauri/src/openhuman/config/schema/hardware.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/hardware.rs rename to src-tauri/src/openhuman/config/schema/hardware.rs diff --git a/src-tauri/src/alphahuman/config/schema/heartbeat_cron.rs b/src-tauri/src/openhuman/config/schema/heartbeat_cron.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/heartbeat_cron.rs rename to src-tauri/src/openhuman/config/schema/heartbeat_cron.rs diff --git a/src-tauri/src/alphahuman/config/schema/identity_cost.rs b/src-tauri/src/openhuman/config/schema/identity_cost.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/identity_cost.rs rename to src-tauri/src/openhuman/config/schema/identity_cost.rs diff --git a/src-tauri/src/alphahuman/config/schema/load.rs b/src-tauri/src/openhuman/config/schema/load.rs similarity index 85% rename from src-tauri/src/alphahuman/config/schema/load.rs rename to src-tauri/src/openhuman/config/schema/load.rs index 07af2986e..9d29df79d 100644 --- a/src-tauri/src/alphahuman/config/schema/load.rs +++ b/src-tauri/src/openhuman/config/schema/load.rs @@ -7,7 +7,7 @@ use super::{ }, Config, }; -use crate::alphahuman::providers::{is_glm_alias, is_zai_alias}; +use crate::openhuman::providers::{is_glm_alias, is_zai_alias}; use anyhow::{Context, Result}; use directories::UserDirs; use serde::{Deserialize, Serialize}; @@ -31,7 +31,7 @@ fn default_config_dir() -> Result { let home = UserDirs::new() .map(|u| u.home_dir().to_path_buf()) .context("Could not find home directory")?; - Ok(home.join(".alphahuman")) + Ok(home.join(".openhuman")) } fn active_workspace_state_path(default_dir: &Path) -> PathBuf { @@ -151,7 +151,7 @@ fn resolve_config_dir_for_workspace(workspace_dir: &Path) -> (PathBuf, PathBuf) let legacy_config_dir = workspace_dir .parent() - .map(|parent| parent.join(".alphahuman")); + .map(|parent| parent.join(".openhuman")); if let Some(legacy_dir) = legacy_config_dir { if legacy_dir.join("config.toml").exists() { return (legacy_dir, workspace_config_dir); @@ -181,7 +181,7 @@ enum ConfigResolutionSource { impl ConfigResolutionSource { const fn as_str(self) -> &'static str { match self { - Self::EnvWorkspace => "ALPHAHUMAN_WORKSPACE", + Self::EnvWorkspace => "OPENHUMAN_WORKSPACE", Self::ActiveWorkspaceMarker => "active_workspace.toml", Self::DefaultConfigDir => "default", } @@ -189,45 +189,45 @@ impl ConfigResolutionSource { } async fn resolve_runtime_config_dirs( - default_alphahuman_dir: &Path, + default_openhuman_dir: &Path, default_workspace_dir: &Path, ) -> Result<(PathBuf, PathBuf, ConfigResolutionSource)> { - if let Ok(custom_workspace) = std::env::var("ALPHAHUMAN_WORKSPACE") { + if let Ok(custom_workspace) = std::env::var("OPENHUMAN_WORKSPACE") { if !custom_workspace.is_empty() { - let (alphahuman_dir, workspace_dir) = + let (openhuman_dir, workspace_dir) = resolve_config_dir_for_workspace(&PathBuf::from(custom_workspace)); return Ok(( - alphahuman_dir, + openhuman_dir, workspace_dir, ConfigResolutionSource::EnvWorkspace, )); } } - if let Some((alphahuman_dir, workspace_dir)) = - load_persisted_workspace_dirs(default_alphahuman_dir).await? + if let Some((openhuman_dir, workspace_dir)) = + load_persisted_workspace_dirs(default_openhuman_dir).await? { return Ok(( - alphahuman_dir, + openhuman_dir, workspace_dir, ConfigResolutionSource::ActiveWorkspaceMarker, )); } Ok(( - default_alphahuman_dir.to_path_buf(), + default_openhuman_dir.to_path_buf(), default_workspace_dir.to_path_buf(), ConfigResolutionSource::DefaultConfigDir, )) } fn decrypt_optional_secret( - store: &crate::alphahuman::security::SecretStore, + store: &crate::openhuman::security::SecretStore, value: &mut Option, field_name: &str, ) -> Result<()> { if let Some(raw) = value.clone() { - if crate::alphahuman::security::SecretStore::is_encrypted(&raw) { + if crate::openhuman::security::SecretStore::is_encrypted(&raw) { *value = Some( store .decrypt(&raw) @@ -239,12 +239,12 @@ fn decrypt_optional_secret( } fn encrypt_optional_secret( - store: &crate::alphahuman::security::SecretStore, + store: &crate::openhuman::security::SecretStore, value: &mut Option, field_name: &str, ) -> Result<()> { if let Some(raw) = value.clone() { - if !crate::alphahuman::security::SecretStore::is_encrypted(&raw) { + if !crate::openhuman::security::SecretStore::is_encrypted(&raw) { *value = Some( store .encrypt(&raw) @@ -273,14 +273,14 @@ async fn sync_directory(_path: &Path) -> Result<()> { impl Config { pub async fn load_or_init() -> Result { - let (default_alphahuman_dir, default_workspace_dir) = default_config_and_workspace_dirs()?; + let (default_openhuman_dir, default_workspace_dir) = default_config_and_workspace_dirs()?; - let (alphahuman_dir, workspace_dir, resolution_source) = - resolve_runtime_config_dirs(&default_alphahuman_dir, &default_workspace_dir).await?; + let (openhuman_dir, workspace_dir, resolution_source) = + resolve_runtime_config_dirs(&default_openhuman_dir, &default_workspace_dir).await?; - let config_path = alphahuman_dir.join("config.toml"); + let config_path = openhuman_dir.join("config.toml"); - fs::create_dir_all(&alphahuman_dir) + fs::create_dir_all(&openhuman_dir) .await .context("Failed to create config directory")?; fs::create_dir_all(&workspace_dir) @@ -312,7 +312,7 @@ impl Config { config.config_path = config_path.clone(); config.workspace_dir = workspace_dir; let store = - crate::alphahuman::security::SecretStore::new(&alphahuman_dir, config.secrets.encrypt); + crate::openhuman::security::SecretStore::new(&openhuman_dir, config.secrets.encrypt); decrypt_optional_secret(&store, &mut config.api_key, "config.api_key")?; decrypt_optional_secret( &store, @@ -371,7 +371,7 @@ impl Config { } pub fn apply_env_overrides(&mut self) { - if let Ok(key) = std::env::var("ALPHAHUMAN_API_KEY").or_else(|_| std::env::var("API_KEY")) { + if let Ok(key) = std::env::var("OPENHUMAN_API_KEY").or_else(|_| std::env::var("API_KEY")) { if !key.is_empty() { self.api_key = Some(key); } @@ -391,7 +391,7 @@ impl Config { } } - if let Ok(provider) = std::env::var("ALPHAHUMAN_PROVIDER") { + if let Ok(provider) = std::env::var("OPENHUMAN_PROVIDER") { if !provider.is_empty() { self.default_provider = Some(provider); } @@ -404,13 +404,13 @@ impl Config { } } - if let Ok(model) = std::env::var("ALPHAHUMAN_MODEL").or_else(|_| std::env::var("MODEL")) { + if let Ok(model) = std::env::var("OPENHUMAN_MODEL").or_else(|_| std::env::var("MODEL")) { if !model.is_empty() { self.default_model = Some(model); } } - if let Ok(workspace) = std::env::var("ALPHAHUMAN_WORKSPACE") { + if let Ok(workspace) = std::env::var("OPENHUMAN_WORKSPACE") { if !workspace.is_empty() { let (_, workspace_dir) = resolve_config_dir_for_workspace(&PathBuf::from(workspace)); self.workspace_dir = workspace_dir; @@ -418,7 +418,7 @@ impl Config { } if let Ok(port_str) = - std::env::var("ALPHAHUMAN_GATEWAY_PORT").or_else(|_| std::env::var("PORT")) + std::env::var("OPENHUMAN_GATEWAY_PORT").or_else(|_| std::env::var("PORT")) { if let Ok(port) = port_str.parse::() { self.gateway.port = port; @@ -426,18 +426,18 @@ impl Config { } if let Ok(host) = - std::env::var("ALPHAHUMAN_GATEWAY_HOST").or_else(|_| std::env::var("HOST")) + std::env::var("OPENHUMAN_GATEWAY_HOST").or_else(|_| std::env::var("HOST")) { if !host.is_empty() { self.gateway.host = host; } } - if let Ok(val) = std::env::var("ALPHAHUMAN_ALLOW_PUBLIC_BIND") { + if let Ok(val) = std::env::var("OPENHUMAN_ALLOW_PUBLIC_BIND") { self.gateway.allow_public_bind = val == "1" || val.eq_ignore_ascii_case("true"); } - if let Ok(temp_str) = std::env::var("ALPHAHUMAN_TEMPERATURE") { + if let Ok(temp_str) = std::env::var("OPENHUMAN_TEMPERATURE") { if let Ok(temp) = temp_str.parse::() { if (0.0..=2.0).contains(&temp) { self.default_temperature = temp; @@ -445,7 +445,7 @@ impl Config { } } - if let Ok(flag) = std::env::var("ALPHAHUMAN_REASONING_ENABLED") + if let Ok(flag) = std::env::var("OPENHUMAN_REASONING_ENABLED") .or_else(|_| std::env::var("REASONING_ENABLED")) { let normalized = flag.trim().to_ascii_lowercase(); @@ -456,13 +456,13 @@ impl Config { } } - if let Ok(enabled) = std::env::var("ALPHAHUMAN_WEB_SEARCH_ENABLED") + if let Ok(enabled) = std::env::var("OPENHUMAN_WEB_SEARCH_ENABLED") .or_else(|_| std::env::var("WEB_SEARCH_ENABLED")) { self.web_search.enabled = enabled == "1" || enabled.eq_ignore_ascii_case("true"); } - if let Ok(provider) = std::env::var("ALPHAHUMAN_WEB_SEARCH_PROVIDER") + if let Ok(provider) = std::env::var("OPENHUMAN_WEB_SEARCH_PROVIDER") .or_else(|_| std::env::var("WEB_SEARCH_PROVIDER")) { let provider = provider.trim(); @@ -472,7 +472,7 @@ impl Config { } if let Ok(api_key) = - std::env::var("ALPHAHUMAN_BRAVE_API_KEY").or_else(|_| std::env::var("BRAVE_API_KEY")) + std::env::var("OPENHUMAN_BRAVE_API_KEY").or_else(|_| std::env::var("BRAVE_API_KEY")) { let api_key = api_key.trim(); if !api_key.is_empty() { @@ -480,7 +480,7 @@ impl Config { } } - if let Ok(max_results) = std::env::var("ALPHAHUMAN_WEB_SEARCH_MAX_RESULTS") + if let Ok(max_results) = std::env::var("OPENHUMAN_WEB_SEARCH_MAX_RESULTS") .or_else(|_| std::env::var("WEB_SEARCH_MAX_RESULTS")) { if let Ok(max_results) = max_results.parse::() { @@ -490,7 +490,7 @@ impl Config { } } - if let Ok(timeout_secs) = std::env::var("ALPHAHUMAN_WEB_SEARCH_TIMEOUT_SECS") + if let Ok(timeout_secs) = std::env::var("OPENHUMAN_WEB_SEARCH_TIMEOUT_SECS") .or_else(|_| std::env::var("WEB_SEARCH_TIMEOUT_SECS")) { if let Ok(timeout_secs) = timeout_secs.parse::() { @@ -500,21 +500,21 @@ impl Config { } } - if let Ok(provider) = std::env::var("ALPHAHUMAN_STORAGE_PROVIDER") { + if let Ok(provider) = std::env::var("OPENHUMAN_STORAGE_PROVIDER") { let provider = provider.trim(); if !provider.is_empty() { self.storage.provider.config.provider = provider.to_string(); } } - if let Ok(db_url) = std::env::var("ALPHAHUMAN_STORAGE_DB_URL") { + if let Ok(db_url) = std::env::var("OPENHUMAN_STORAGE_DB_URL") { let db_url = db_url.trim(); if !db_url.is_empty() { self.storage.provider.config.db_url = Some(db_url.to_string()); } } - if let Ok(timeout_secs) = std::env::var("ALPHAHUMAN_STORAGE_CONNECT_TIMEOUT_SECS") { + if let Ok(timeout_secs) = std::env::var("OPENHUMAN_STORAGE_CONNECT_TIMEOUT_SECS") { if let Ok(timeout_secs) = timeout_secs.parse::() { if timeout_secs > 0 { self.storage.provider.config.connect_timeout_secs = Some(timeout_secs); @@ -522,7 +522,7 @@ impl Config { } } - let explicit_proxy_enabled = std::env::var("ALPHAHUMAN_PROXY_ENABLED") + let explicit_proxy_enabled = std::env::var("OPENHUMAN_PROXY_ENABLED") .ok() .as_deref() .and_then(parse_proxy_enabled); @@ -532,25 +532,25 @@ impl Config { let mut proxy_url_overridden = false; if let Ok(proxy_url) = - std::env::var("ALPHAHUMAN_HTTP_PROXY").or_else(|_| std::env::var("HTTP_PROXY")) + std::env::var("OPENHUMAN_HTTP_PROXY").or_else(|_| std::env::var("HTTP_PROXY")) { self.proxy.http_proxy = normalize_proxy_url_option(Some(&proxy_url)); proxy_url_overridden = true; } if let Ok(proxy_url) = - std::env::var("ALPHAHUMAN_HTTPS_PROXY").or_else(|_| std::env::var("HTTPS_PROXY")) + std::env::var("OPENHUMAN_HTTPS_PROXY").or_else(|_| std::env::var("HTTPS_PROXY")) { self.proxy.https_proxy = normalize_proxy_url_option(Some(&proxy_url)); proxy_url_overridden = true; } if let Ok(proxy_url) = - std::env::var("ALPHAHUMAN_ALL_PROXY").or_else(|_| std::env::var("ALL_PROXY")) + std::env::var("OPENHUMAN_ALL_PROXY").or_else(|_| std::env::var("ALL_PROXY")) { self.proxy.all_proxy = normalize_proxy_url_option(Some(&proxy_url)); proxy_url_overridden = true; } if let Ok(no_proxy) = - std::env::var("ALPHAHUMAN_NO_PROXY").or_else(|_| std::env::var("NO_PROXY")) + std::env::var("OPENHUMAN_NO_PROXY").or_else(|_| std::env::var("NO_PROXY")) { self.proxy.no_proxy = normalize_no_proxy_list(vec![no_proxy]); } @@ -562,18 +562,18 @@ impl Config { self.proxy.enabled = true; } - if let Ok(scope_raw) = std::env::var("ALPHAHUMAN_PROXY_SCOPE") { + if let Ok(scope_raw) = std::env::var("OPENHUMAN_PROXY_SCOPE") { if let Some(scope) = parse_proxy_scope(&scope_raw) { self.proxy.scope = scope; } else { tracing::warn!( scope = %scope_raw, - "Ignoring invalid ALPHAHUMAN_PROXY_SCOPE (valid: environment|alphahuman|services)" + "Ignoring invalid OPENHUMAN_PROXY_SCOPE (valid: environment|openhuman|services)" ); } } - if let Ok(services_raw) = std::env::var("ALPHAHUMAN_PROXY_SERVICES") { + if let Ok(services_raw) = std::env::var("OPENHUMAN_PROXY_SERVICES") { self.proxy.services = normalize_service_list(vec![services_raw]); } @@ -591,12 +591,12 @@ impl Config { pub async fn save(&self) -> Result<()> { let mut config_to_save = self.clone(); - let alphahuman_dir = self + let openhuman_dir = self .config_path .parent() .context("Config path must have a parent directory")?; let store = - crate::alphahuman::security::SecretStore::new(alphahuman_dir, self.secrets.encrypt); + crate::openhuman::security::SecretStore::new(openhuman_dir, self.secrets.encrypt); encrypt_optional_secret(&store, &mut config_to_save.api_key, "config.api_key")?; encrypt_optional_secret( diff --git a/src-tauri/src/alphahuman/config/schema/mod.rs b/src-tauri/src/openhuman/config/schema/mod.rs similarity index 97% rename from src-tauri/src/alphahuman/config/schema/mod.rs rename to src-tauri/src/openhuman/config/schema/mod.rs index 8c4cdc06c..8f38ea508 100644 --- a/src-tauri/src/alphahuman/config/schema/mod.rs +++ b/src-tauri/src/openhuman/config/schema/mod.rs @@ -163,11 +163,11 @@ impl Default for Config { fn default() -> Self { let home = UserDirs::new().map_or_else(|| PathBuf::from("."), |u| u.home_dir().to_path_buf()); - let alphahuman_dir = home.join(".alphahuman"); + let openhuman_dir = home.join(".openhuman"); Self { - workspace_dir: alphahuman_dir.join("workspace"), - config_path: alphahuman_dir.join("config.toml"), + workspace_dir: openhuman_dir.join("workspace"), + config_path: openhuman_dir.join("config.toml"), api_key: None, api_url: None, default_provider: Some("openrouter".to_string()), diff --git a/src-tauri/src/alphahuman/config/schema/observability.rs b/src-tauri/src/openhuman/config/schema/observability.rs similarity index 98% rename from src-tauri/src/alphahuman/config/schema/observability.rs rename to src-tauri/src/openhuman/config/schema/observability.rs index e306a3c3c..7f7a67aa3 100644 --- a/src-tauri/src/alphahuman/config/schema/observability.rs +++ b/src-tauri/src/openhuman/config/schema/observability.rs @@ -12,7 +12,7 @@ pub struct ObservabilityConfig { #[serde(default)] pub otel_endpoint: Option, - /// Service name reported to the OTel collector. Defaults to "alphahuman". + /// Service name reported to the OTel collector. Defaults to "openhuman". #[serde(default)] pub otel_service_name: Option, } diff --git a/src-tauri/src/alphahuman/config/schema/proxy.rs b/src-tauri/src/openhuman/config/schema/proxy.rs similarity index 98% rename from src-tauri/src/alphahuman/config/schema/proxy.rs rename to src-tauri/src/openhuman/config/schema/proxy.rs index 4227764c3..7d3ffd7fa 100644 --- a/src-tauri/src/alphahuman/config/schema/proxy.rs +++ b/src-tauri/src/openhuman/config/schema/proxy.rs @@ -45,7 +45,7 @@ static RUNTIME_PROXY_CLIENT_CACHE: OnceLock false, - ProxyScope::Alphahuman => true, + ProxyScope::OpenHuman => true, ProxyScope::Services => { let service_key = service_key.trim().to_ascii_lowercase(); if service_key.is_empty() { @@ -477,7 +477,7 @@ pub fn build_runtime_proxy_client_with_timeouts( pub(crate) fn parse_proxy_scope(raw: &str) -> Option { match raw.trim().to_ascii_lowercase().as_str() { "environment" | "env" => Some(ProxyScope::Environment), - "alphahuman" | "internal" | "core" => Some(ProxyScope::Alphahuman), + "openhuman" | "internal" | "core" => Some(ProxyScope::OpenHuman), "services" | "service" => Some(ProxyScope::Services), _ => None, } diff --git a/src-tauri/src/alphahuman/config/schema/routes.rs b/src-tauri/src/openhuman/config/schema/routes.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/routes.rs rename to src-tauri/src/openhuman/config/schema/routes.rs diff --git a/src-tauri/src/alphahuman/config/schema/runtime.rs b/src-tauri/src/openhuman/config/schema/runtime.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/runtime.rs rename to src-tauri/src/openhuman/config/schema/runtime.rs diff --git a/src-tauri/src/alphahuman/config/schema/storage_memory.rs b/src-tauri/src/openhuman/config/schema/storage_memory.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/storage_memory.rs rename to src-tauri/src/openhuman/config/schema/storage_memory.rs diff --git a/src-tauri/src/alphahuman/config/schema/tools.rs b/src-tauri/src/openhuman/config/schema/tools.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/tools.rs rename to src-tauri/src/openhuman/config/schema/tools.rs diff --git a/src-tauri/src/alphahuman/config/schema/tunnel.rs b/src-tauri/src/openhuman/config/schema/tunnel.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/tunnel.rs rename to src-tauri/src/openhuman/config/schema/tunnel.rs diff --git a/src-tauri/src/alphahuman/cost/mod.rs b/src-tauri/src/openhuman/cost/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/cost/mod.rs rename to src-tauri/src/openhuman/cost/mod.rs diff --git a/src-tauri/src/alphahuman/cost/tracker.rs b/src-tauri/src/openhuman/cost/tracker.rs similarity index 99% rename from src-tauri/src/alphahuman/cost/tracker.rs rename to src-tauri/src/openhuman/cost/tracker.rs index 23eeef12b..9a5bd3581 100644 --- a/src-tauri/src/alphahuman/cost/tracker.rs +++ b/src-tauri/src/openhuman/cost/tracker.rs @@ -1,5 +1,5 @@ use super::types::{BudgetCheck, CostRecord, CostSummary, ModelStats, TokenUsage, UsagePeriod}; -use crate::alphahuman::config::CostConfig; +use crate::openhuman::config::CostConfig; use anyhow::{anyhow, Context, Result}; use chrono::{Datelike, NaiveDate, Utc}; use parking_lot::{Mutex, MutexGuard}; @@ -177,7 +177,7 @@ impl CostTracker { fn resolve_storage_path(workspace_dir: &Path) -> Result { let storage_path = workspace_dir.join("state").join("costs.jsonl"); - let legacy_path = workspace_dir.join(".alphahuman").join("costs.db"); + let legacy_path = workspace_dir.join(".openhuman").join("costs.db"); if !storage_path.exists() && legacy_path.exists() { if let Some(parent) = storage_path.parent() { diff --git a/src-tauri/src/alphahuman/cost/types.rs b/src-tauri/src/openhuman/cost/types.rs similarity index 100% rename from src-tauri/src/alphahuman/cost/types.rs rename to src-tauri/src/openhuman/cost/types.rs diff --git a/src-tauri/src/alphahuman/cron/mod.rs b/src-tauri/src/openhuman/cron/mod.rs similarity index 99% rename from src-tauri/src/alphahuman/cron/mod.rs rename to src-tauri/src/openhuman/cron/mod.rs index 480289019..d5d030f59 100644 --- a/src-tauri/src/alphahuman/cron/mod.rs +++ b/src-tauri/src/openhuman/cron/mod.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::config::Config; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::Config; +use crate::openhuman::security::SecurityPolicy; use anyhow::Result; mod schedule; diff --git a/src-tauri/src/alphahuman/cron/schedule.rs b/src-tauri/src/openhuman/cron/schedule.rs similarity index 99% rename from src-tauri/src/alphahuman/cron/schedule.rs rename to src-tauri/src/openhuman/cron/schedule.rs index e604bf518..daefe5a26 100644 --- a/src-tauri/src/alphahuman/cron/schedule.rs +++ b/src-tauri/src/openhuman/cron/schedule.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::cron::Schedule; +use crate::openhuman::cron::Schedule; use anyhow::{Context, Result}; use chrono::{DateTime, Duration as ChronoDuration, Utc}; use cron::Schedule as CronExprSchedule; diff --git a/src-tauri/src/alphahuman/cron/scheduler.rs b/src-tauri/src/openhuman/cron/scheduler.rs similarity index 96% rename from src-tauri/src/alphahuman/cron/scheduler.rs rename to src-tauri/src/openhuman/cron/scheduler.rs index c62ed4f3c..631f0a66c 100644 --- a/src-tauri/src/alphahuman/cron/scheduler.rs +++ b/src-tauri/src/openhuman/cron/scheduler.rs @@ -1,12 +1,12 @@ -use crate::alphahuman::channels::{ +use crate::openhuman::channels::{ Channel, DiscordChannel, MattermostChannel, SendMessage, SlackChannel, TelegramChannel, }; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron::{ +use crate::openhuman::config::Config; +use crate::openhuman::cron::{ due_jobs, next_run_for_schedule, record_last_run, record_run, remove_job, reschedule_after_run, update_job, CronJob, CronJobPatch, DeliveryConfig, JobType, Schedule, SessionTarget, }; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use anyhow::Result; use chrono::{DateTime, Utc}; use futures_util::{stream, StreamExt}; @@ -26,7 +26,7 @@ pub async fn run(config: Config) -> Result<()> { &config.workspace_dir, )); - crate::alphahuman::health::mark_component_ok("scheduler"); + crate::openhuman::health::mark_component_ok("scheduler"); loop { interval.tick().await; @@ -34,7 +34,7 @@ pub async fn run(config: Config) -> Result<()> { let jobs = match due_jobs(&config, Utc::now()) { Ok(jobs) => jobs, Err(e) => { - crate::alphahuman::health::mark_component_error("scheduler", e.to_string()); + crate::openhuman::health::mark_component_error("scheduler", e.to_string()); tracing::warn!("Scheduler query failed: {e}"); continue; } @@ -95,7 +95,7 @@ async fn process_due_jobs(config: &Config, security: &Arc, jobs: while let Some((job_id, success)) = in_flight.next().await { if !success { - crate::alphahuman::health::mark_component_error("scheduler", format!("job {job_id} failed")); + crate::openhuman::health::mark_component_error("scheduler", format!("job {job_id} failed")); } } } @@ -105,7 +105,7 @@ async fn execute_and_persist_job( security: &SecurityPolicy, job: &CronJob, ) -> (String, bool) { - crate::alphahuman::health::mark_component_ok("scheduler"); + crate::openhuman::health::mark_component_ok("scheduler"); warn_if_high_frequency_agent_job(job); let started_at = Utc::now(); @@ -124,7 +124,7 @@ async fn run_agent_job(config: &Config, job: &CronJob) -> (bool, String) { let run_result = match job.session_target { SessionTarget::Main | SessionTarget::Isolated => { - crate::alphahuman::agent::run( + crate::openhuman::agent::run( config.clone(), Some(prefixed_prompt), None, @@ -469,9 +469,9 @@ async fn run_job_command_with_timeout( #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; - use crate::alphahuman::cron::{self, DeliveryConfig}; - use crate::alphahuman::security::SecurityPolicy; + use crate::openhuman::config::Config; + use crate::openhuman::cron::{self, DeliveryConfig}; + use crate::openhuman::security::SecurityPolicy; use chrono::{Duration as ChronoDuration, Utc}; use tempfile::TempDir; @@ -491,7 +491,7 @@ mod tests { CronJob { id: "test-job".into(), expression: "* * * * *".into(), - schedule: crate::alphahuman::cron::Schedule::Cron { + schedule: crate::openhuman::cron::Schedule::Cron { expr: "* * * * *".into(), tz: None, }, @@ -585,7 +585,7 @@ mod tests { async fn run_job_command_blocks_readonly_mode() { let tmp = TempDir::new().unwrap(); let mut config = test_config(&tmp).await; - config.autonomy.level = crate::alphahuman::security::AutonomyLevel::ReadOnly; + config.autonomy.level = crate::openhuman::security::AutonomyLevel::ReadOnly; let job = test_job("echo should-not-run"); let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir); @@ -687,7 +687,7 @@ mod tests { let job = cron::add_agent_job( &config, Some("one-shot".into()), - crate::alphahuman::cron::Schedule::At { at }, + crate::openhuman::cron::Schedule::At { at }, "Hello", SessionTarget::Isolated, None, @@ -712,7 +712,7 @@ mod tests { let job = cron::add_agent_job( &config, Some("one-shot".into()), - crate::alphahuman::cron::Schedule::At { at }, + crate::openhuman::cron::Schedule::At { at }, "Hello", SessionTarget::Isolated, None, diff --git a/src-tauri/src/alphahuman/cron/store.rs b/src-tauri/src/openhuman/cron/store.rs similarity index 99% rename from src-tauri/src/alphahuman/cron/store.rs rename to src-tauri/src/openhuman/cron/store.rs index 93dbf42e9..456a5849c 100644 --- a/src-tauri/src/alphahuman/cron/store.rs +++ b/src-tauri/src/openhuman/cron/store.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::config::Config; -use crate::alphahuman::cron::{ +use crate::openhuman::config::Config; +use crate::openhuman::cron::{ next_run_for_schedule, schedule_cron_expression, validate_schedule, CronJob, CronJobPatch, CronRun, DeliveryConfig, JobType, Schedule, SessionTarget, }; @@ -567,7 +567,7 @@ fn with_connection(config: &Config, f: impl FnOnce(&Connection) -> Result) #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use chrono::Duration as ChronoDuration; use tempfile::TempDir; diff --git a/src-tauri/src/alphahuman/cron/types.rs b/src-tauri/src/openhuman/cron/types.rs similarity index 100% rename from src-tauri/src/alphahuman/cron/types.rs rename to src-tauri/src/openhuman/cron/types.rs diff --git a/src-tauri/src/alphahuman/daemon/mod.rs b/src-tauri/src/openhuman/daemon/mod.rs similarity index 76% rename from src-tauri/src/alphahuman/daemon/mod.rs rename to src-tauri/src/openhuman/daemon/mod.rs index 6df1c99fd..11a8a9da8 100644 --- a/src-tauri/src/alphahuman/daemon/mod.rs +++ b/src-tauri/src/openhuman/daemon/mod.rs @@ -13,7 +13,7 @@ use tokio::task::JoinHandle; use tokio::time::Duration; use tokio_util::sync::CancellationToken; -use crate::alphahuman::config::{Config, DaemonConfig}; +use crate::openhuman::config::{Config, DaemonConfig}; /// How often the state writer emits health snapshots (seconds). const STATUS_FLUSH_SECONDS: u64 = 5; @@ -27,7 +27,7 @@ pub struct DaemonHandle { /// /// The supervisor: /// 1. Marks the "daemon" health component as OK -/// 2. Spawns a state writer that emits `alphahuman:health` Tauri events +/// 2. Spawns a state writer that emits `openhuman:health` Tauri events /// 3. Waits for the cancellation token to be triggered (on app exit) /// 4. Aborts all supervised tasks pub async fn run( @@ -45,7 +45,7 @@ pub async fn run( let _ = tokio::fs::create_dir_all(&config.data_dir).await; let _ = tokio::fs::create_dir_all(&config.workspace_dir).await; - crate::alphahuman::health::mark_component_ok("daemon"); + crate::openhuman::health::mark_component_ok("daemon"); let mut handles: Vec> = vec![]; @@ -55,29 +55,29 @@ pub async fn run( let data_dir = config.data_dir.clone(); let cancel_clone = cancel.clone(); handles.push(tokio::spawn(async move { - log::info!("[alphahuman] Starting health event writer task"); + log::info!("[openhuman] Starting health event writer task"); spawn_state_writer(app, data_dir, cancel_clone).await; - log::info!("[alphahuman] Health event writer task terminated"); + log::info!("[openhuman] Health event writer task terminated"); })); } - log::info!("[alphahuman] Daemon supervisor started"); + log::info!("[openhuman] Daemon supervisor started"); log::info!( - "[alphahuman] data_dir: {}", + "[openhuman] data_dir: {}", config.data_dir.display() ); log::info!( - "[alphahuman] backoff: {}s initial, {}s max", + "[openhuman] backoff: {}s initial, {}s max", initial_backoff, max_backoff ); - log::info!("[alphahuman] health: Events will be emitted every {}s to frontend", STATUS_FLUSH_SECONDS); + log::info!("[openhuman] health: Events will be emitted every {}s to frontend", STATUS_FLUSH_SECONDS); // Wait for cancellation (Tauri exit) cancel.cancelled().await; - crate::alphahuman::health::mark_component_error("daemon", "shutdown requested"); - log::info!("[alphahuman] Daemon supervisor shutting down (health events will stop)"); + crate::openhuman::health::mark_component_error("daemon", "shutdown requested"); + log::info!("[openhuman] Daemon supervisor shutting down (health events will stop)"); for handle in &handles { handle.abort(); @@ -89,7 +89,7 @@ pub async fn run( Ok(()) } -/// Run the full Alphahuman daemon supervisor within alphahuman. +/// Run the full OpenHuman daemon supervisor within openhuman. /// /// Uses a cancellation token for controlled shutdown inside the Tauri process. pub async fn run_full( @@ -104,11 +104,11 @@ pub async fn run_full( .channel_max_backoff_secs .max(initial_backoff); - crate::alphahuman::health::mark_component_ok("daemon"); + crate::openhuman::health::mark_component_ok("daemon"); if config.heartbeat.enabled { let _ = - crate::alphahuman::heartbeat::engine::HeartbeatEngine::ensure_heartbeat_file( + crate::openhuman::heartbeat::engine::HeartbeatEngine::ensure_heartbeat_file( &config.workspace_dir, ) .await; @@ -128,7 +128,7 @@ pub async fn run_full( let cfg = gateway_cfg.clone(); let host = gateway_host.clone(); async move { - crate::alphahuman::gateway::run_gateway(&host, port, cfg).await + crate::openhuman::gateway::run_gateway(&host, port, cfg).await } }, )); @@ -143,11 +143,11 @@ pub async fn run_full( max_backoff, move || { let cfg = channels_cfg.clone(); - async move { crate::alphahuman::channels::start_channels(cfg).await } + async move { crate::openhuman::channels::start_channels(cfg).await } }, )); } else { - crate::alphahuman::health::mark_component_ok("channels"); + crate::openhuman::health::mark_component_ok("channels"); log::info!("No real-time channels configured; channel supervisor disabled"); } } @@ -173,20 +173,20 @@ pub async fn run_full( max_backoff, move || { let cfg = scheduler_cfg.clone(); - async move { crate::alphahuman::cron::scheduler::run(cfg).await } + async move { crate::openhuman::cron::scheduler::run(cfg).await } }, )); } else { - crate::alphahuman::health::mark_component_ok("scheduler"); + crate::openhuman::health::mark_component_ok("scheduler"); log::info!("Cron disabled; scheduler supervisor not started"); } - log::info!("[alphahuman] Alphahuman daemon started"); - log::info!("[alphahuman] Gateway: http://{host}:{port}"); - log::info!("[alphahuman] Components: gateway, channels, heartbeat, scheduler"); + log::info!("[openhuman] OpenHuman daemon started"); + log::info!("[openhuman] Gateway: http://{host}:{port}"); + log::info!("[openhuman] Components: gateway, channels, heartbeat, scheduler"); cancel.cancelled().await; - crate::alphahuman::health::mark_component_error("daemon", "shutdown requested"); + crate::openhuman::health::mark_component_error("daemon", "shutdown requested"); for handle in &handles { handle.abort(); @@ -221,7 +221,7 @@ fn spawn_state_writer_full(config: Config, cancel: CancellationToken) -> JoinHan _ = interval.tick() => {}, _ = cancel.cancelled() => break, } - let mut json = crate::alphahuman::health::snapshot_json(); + let mut json = crate::openhuman::health::snapshot_json(); if let Some(obj) = json.as_object_mut() { obj.insert( "written_at".into(), @@ -235,11 +235,11 @@ fn spawn_state_writer_full(config: Config, cancel: CancellationToken) -> JoinHan } async fn run_heartbeat_worker(config: Config) -> Result<()> { - let observer: std::sync::Arc = - std::sync::Arc::from(crate::alphahuman::observability::create_observer( + let observer: std::sync::Arc = + std::sync::Arc::from(crate::openhuman::observability::create_observer( &config.observability, )); - let engine = crate::alphahuman::heartbeat::engine::HeartbeatEngine::new( + let engine = crate::openhuman::heartbeat::engine::HeartbeatEngine::new( config.heartbeat.clone(), config.workspace_dir.clone(), observer, @@ -260,7 +260,7 @@ async fn run_heartbeat_worker(config: Config) -> Result<()> { for task in tasks { let prompt = format!("[Heartbeat Task] {task}"); let temp = config.default_temperature; - if let Err(e) = crate::alphahuman::agent::run( + if let Err(e) = crate::openhuman::agent::run( config.clone(), Some(prompt), None, @@ -270,17 +270,17 @@ async fn run_heartbeat_worker(config: Config) -> Result<()> { ) .await { - crate::alphahuman::health::mark_component_error("heartbeat", e.to_string()); + crate::openhuman::health::mark_component_error("heartbeat", e.to_string()); log::warn!("Heartbeat task failed: {e}"); } else { - crate::alphahuman::health::mark_component_ok("heartbeat"); + crate::openhuman::health::mark_component_ok("heartbeat"); } } } } fn has_supervised_channels(config: &Config) -> bool { - let crate::alphahuman::config::ChannelsConfig { + let crate::openhuman::config::ChannelsConfig { cli: _, // `cli` is not used in the web UI webhook: _, // Managed by the gateway telegram, @@ -327,8 +327,8 @@ async fn spawn_state_writer( let _ = tokio::fs::create_dir_all(parent).await; } - log::info!("[alphahuman] Health state writer starting ({}s intervals)", STATUS_FLUSH_SECONDS); - log::info!("[alphahuman] Health state file: {}", state_path.display()); + log::info!("[openhuman] Health state writer starting ({}s intervals)", STATUS_FLUSH_SECONDS); + log::info!("[openhuman] Health state file: {}", state_path.display()); let mut interval = tokio::time::interval(Duration::from_secs(STATUS_FLUSH_SECONDS)); let mut event_count = 0u64; @@ -338,16 +338,16 @@ async fn spawn_state_writer( _ = interval.tick() => { event_count += 1; if event_count % 12 == 1 { // Log every minute (12 * 5s = 60s) -// log::info!("[alphahuman] Health monitoring active (event #{})", event_count); +// log::info!("[openhuman] Health monitoring active (event #{})", event_count); } }, _ = cancel.cancelled() => { - log::info!("[alphahuman] Health state writer received shutdown signal"); + log::info!("[openhuman] Health state writer received shutdown signal"); break; } } - let mut json = crate::alphahuman::health::snapshot_json(); + let mut json = crate::openhuman::health::snapshot_json(); if let Some(obj) = json.as_object_mut() { obj.insert( "written_at".into(), @@ -360,17 +360,17 @@ async fn spawn_state_writer( } // Emit Tauri event for frontend consumption - // log::debug!("[alphahuman] Emitting health event #{}: {:?}", event_count, json); // Removed noisy log - if let Err(e) = app_handle.emit("alphahuman:health", &json) { - log::error!("[alphahuman] Failed to emit health event #{}: {}", event_count, e); + // log::debug!("[openhuman] Emitting health event #{}: {:?}", event_count, json); // Removed noisy log + if let Err(e) = app_handle.emit("openhuman:health", &json) { + log::error!("[openhuman] Failed to emit health event #{}: {}", event_count, e); } - // log::debug!("[alphahuman] Health event #{} emitted successfully", event_count); // Removed noisy log + // log::debug!("[openhuman] Health event #{} emitted successfully", event_count); // Removed noisy log // Also persist to disk let data = serde_json::to_vec_pretty(&json).unwrap_or_else(|_| b"{}".to_vec()); if let Err(e) = tokio::fs::write(&state_path, data).await { - log::debug!("[alphahuman] Failed to write health state to disk: {}", e); + log::debug!("[openhuman] Failed to write health state to disk: {}", e); } } } @@ -395,10 +395,10 @@ where let max_backoff = max_backoff_secs.max(backoff); loop { - crate::alphahuman::health::mark_component_ok(name); + crate::openhuman::health::mark_component_ok(name); match run_component().await { Ok(()) => { - crate::alphahuman::health::mark_component_error( + crate::openhuman::health::mark_component_error( name, "component exited unexpectedly", ); @@ -407,12 +407,12 @@ where backoff = initial_backoff_secs.max(1); } Err(e) => { - crate::alphahuman::health::mark_component_error(name, e.to_string()); + crate::openhuman::health::mark_component_error(name, e.to_string()); log::error!("Daemon component '{name}' failed: {e}"); } } - crate::alphahuman::health::bump_component_restart(name); + crate::openhuman::health::bump_component_restart(name); tokio::time::sleep(Duration::from_secs(backoff)).await; // Double backoff AFTER sleeping so first error uses initial_backoff backoff = backoff.saturating_mul(2).min(max_backoff); @@ -434,7 +434,7 @@ mod tests { handle.abort(); let _ = handle.await; - let snapshot = crate::alphahuman::health::snapshot_json(); + let snapshot = crate::openhuman::health::snapshot_json(); let component = &snapshot["components"]["th-daemon-test-fail"]; assert_eq!(component["status"], "error"); assert!(component["restart_count"].as_u64().unwrap_or(0) >= 1); @@ -453,7 +453,7 @@ mod tests { handle.abort(); let _ = handle.await; - let snapshot = crate::alphahuman::health::snapshot_json(); + let snapshot = crate::openhuman::health::snapshot_json(); let component = &snapshot["components"]["th-daemon-test-exit"]; assert_eq!(component["status"], "error"); assert!(component["restart_count"].as_u64().unwrap_or(0) >= 1); diff --git a/src-tauri/src/alphahuman/doctor/mod.rs b/src-tauri/src/openhuman/doctor/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/doctor/mod.rs rename to src-tauri/src/openhuman/doctor/mod.rs index b2b1c8038..1be9cb655 100644 --- a/src-tauri/src/alphahuman/doctor/mod.rs +++ b/src-tauri/src/openhuman/doctor/mod.rs @@ -1,6 +1,6 @@ -//! Diagnostic checks for Alphahuman configuration, workspace health, and daemon state. +//! Diagnostic checks for OpenHuman configuration, workspace health, and daemon state. -use crate::alphahuman::config::Config; +use crate::openhuman::config::Config; use anyhow::Result; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -154,7 +154,7 @@ fn doctor_model_targets(provider_override: Option<&str>) -> Vec { return vec![provider.to_string()]; } - crate::alphahuman::providers::list_providers() + crate::openhuman::providers::list_providers() .into_iter() .map(|provider| provider.name.to_string()) .collect() @@ -178,7 +178,7 @@ pub fn run_models( let mut error_count = 0usize; for provider_name in &targets { - match crate::alphahuman::onboard::run_models_refresh(config, Some(provider_name), !use_cache) + match crate::openhuman::onboard::run_models_refresh(config, Some(provider_name), !use_cache) { Ok(_) => { ok_count += 1; @@ -432,7 +432,7 @@ fn check_config_semantics(config: &Config, items: &mut Vec) { } fn provider_validation_error(name: &str) -> Option { - match crate::alphahuman::providers::create_provider(name, None) { + match crate::openhuman::providers::create_provider(name, None) { Ok(_) => None, Err(err) => Some( err.to_string() @@ -592,7 +592,7 @@ fn workspace_probe_path(workspace_dir: &Path) -> std::path::PathBuf { .duration_since(std::time::UNIX_EPOCH) .map_or(0, |duration| duration.as_nanos()); workspace_dir.join(format!( - ".alphahuman_doctor_probe_{}_{}", + ".openhuman_doctor_probe_{}_{}", std::process::id(), nanos )) @@ -602,7 +602,7 @@ fn workspace_probe_path(workspace_dir: &Path) -> std::path::PathBuf { fn check_daemon_state(config: &Config, items: &mut Vec) { let cat = "daemon"; - let state_file = crate::alphahuman::daemon::state_file_path(config); + let state_file = crate::openhuman::daemon::state_file_path(config); if !state_file.exists() { items.push(DiagnosticItem::error( diff --git a/src-tauri/src/alphahuman/gateway/client.rs b/src-tauri/src/openhuman/gateway/client.rs similarity index 100% rename from src-tauri/src/alphahuman/gateway/client.rs rename to src-tauri/src/openhuman/gateway/client.rs diff --git a/src-tauri/src/alphahuman/gateway/constants.rs b/src-tauri/src/openhuman/gateway/constants.rs similarity index 96% rename from src-tauri/src/alphahuman/gateway/constants.rs rename to src-tauri/src/openhuman/gateway/constants.rs index d98cf4b6e..223ca7880 100644 --- a/src-tauri/src/alphahuman/gateway/constants.rs +++ b/src-tauri/src/openhuman/gateway/constants.rs @@ -1,6 +1,6 @@ //! Gateway constants and key helpers. -use crate::alphahuman::channels::traits::ChannelMessage; +use crate::openhuman::channels::traits::ChannelMessage; use sha2::{Digest, Sha256}; use uuid::Uuid; diff --git a/src-tauri/src/alphahuman/gateway/handlers/health.rs b/src-tauri/src/openhuman/gateway/handlers/health.rs similarity index 84% rename from src-tauri/src/alphahuman/gateway/handlers/health.rs rename to src-tauri/src/openhuman/gateway/handlers/health.rs index e54ed9505..b8d01ef12 100644 --- a/src-tauri/src/alphahuman/gateway/handlers/health.rs +++ b/src-tauri/src/openhuman/gateway/handlers/health.rs @@ -1,6 +1,6 @@ //! Health and metrics endpoints. -use crate::alphahuman::gateway::state::AppState; +use crate::openhuman::gateway::state::AppState; use axum::{ extract::State, http::{header, StatusCode}, @@ -15,7 +15,7 @@ pub async fn handle_health(State(state): State) -> impl IntoResponse { let body = serde_json::json!({ "status": "ok", "paired": state.pairing.is_paired(), - "runtime": crate::alphahuman::health::snapshot_json(), + "runtime": crate::openhuman::health::snapshot_json(), }); Json(body) } @@ -26,7 +26,7 @@ pub async fn handle_metrics(State(state): State) -> impl IntoResponse .observer .as_ref() .as_any() - .downcast_ref::() + .downcast_ref::() { prom.encode() } else { diff --git a/src-tauri/src/alphahuman/gateway/handlers/linq.rs b/src-tauri/src/openhuman/gateway/handlers/linq.rs similarity index 90% rename from src-tauri/src/alphahuman/gateway/handlers/linq.rs rename to src-tauri/src/openhuman/gateway/handlers/linq.rs index 97478cd9e..33eab88c5 100644 --- a/src-tauri/src/alphahuman/gateway/handlers/linq.rs +++ b/src-tauri/src/openhuman/gateway/handlers/linq.rs @@ -1,11 +1,11 @@ //! Linq webhook handlers. use super::webhook::run_gateway_chat_with_multimodal; -use crate::alphahuman::channels::SendMessage; -use crate::alphahuman::channels::traits::Channel; -use crate::alphahuman::gateway::state::AppState; -use crate::alphahuman::memory::MemoryCategory; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::channels::SendMessage; +use crate::openhuman::channels::traits::Channel; +use crate::openhuman::gateway::state::AppState; +use crate::openhuman::memory::MemoryCategory; +use crate::openhuman::util::truncate_with_ellipsis; use axum::{ body::Bytes, extract::State, @@ -40,7 +40,7 @@ pub async fn handle_linq_webhook( .and_then(|v| v.to_str().ok()) .unwrap_or(""); - if !crate::alphahuman::channels::linq::verify_linq_signature( + if !crate::openhuman::channels::linq::verify_linq_signature( signing_secret, &body_str, timestamp, @@ -89,7 +89,7 @@ pub async fn handle_linq_webhook( // Auto-save to memory if state.auto_save { - let key = crate::alphahuman::gateway::constants::linq_memory_key(msg); + let key = crate::openhuman::gateway::constants::linq_memory_key(msg); let _ = state .mem .store(&key, &msg.content, MemoryCategory::Conversation, None) diff --git a/src-tauri/src/alphahuman/gateway/handlers/mod.rs b/src-tauri/src/openhuman/gateway/handlers/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/gateway/handlers/mod.rs rename to src-tauri/src/openhuman/gateway/handlers/mod.rs diff --git a/src-tauri/src/alphahuman/gateway/handlers/pair.rs b/src-tauri/src/openhuman/gateway/handlers/pair.rs similarity index 92% rename from src-tauri/src/alphahuman/gateway/handlers/pair.rs rename to src-tauri/src/openhuman/gateway/handlers/pair.rs index 8f4ab14a2..6bab051e5 100644 --- a/src-tauri/src/alphahuman/gateway/handlers/pair.rs +++ b/src-tauri/src/openhuman/gateway/handlers/pair.rs @@ -1,10 +1,10 @@ //! Pairing endpoints and token persistence. -use crate::alphahuman::config::Config; -use crate::alphahuman::gateway::client::client_key_from_request; -use crate::alphahuman::gateway::constants::RATE_LIMIT_WINDOW_SECS; -use crate::alphahuman::gateway::state::AppState; -use crate::alphahuman::security::pairing::PairingGuard; +use crate::openhuman::config::Config; +use crate::openhuman::gateway::client::client_key_from_request; +use crate::openhuman::gateway::constants::RATE_LIMIT_WINDOW_SECS; +use crate::openhuman::gateway::state::AppState; +use crate::openhuman::security::pairing::PairingGuard; use anyhow::{Context, Result}; use axum::{ extract::{ConnectInfo, State}, diff --git a/src-tauri/src/alphahuman/gateway/handlers/webhook.rs b/src-tauri/src/openhuman/gateway/handlers/webhook.rs similarity index 84% rename from src-tauri/src/alphahuman/gateway/handlers/webhook.rs rename to src-tauri/src/openhuman/gateway/handlers/webhook.rs index f8f644c9c..539c1ee22 100644 --- a/src-tauri/src/alphahuman/gateway/handlers/webhook.rs +++ b/src-tauri/src/openhuman/gateway/handlers/webhook.rs @@ -1,14 +1,14 @@ //! Webhook endpoint handlers. -use crate::alphahuman::gateway::client::client_key_from_request; -use crate::alphahuman::gateway::constants::{ +use crate::openhuman::gateway::client::client_key_from_request; +use crate::openhuman::gateway::constants::{ hash_webhook_secret, webhook_memory_key, RATE_LIMIT_WINDOW_SECS, }; -use crate::alphahuman::gateway::models::WebhookBody; -use crate::alphahuman::gateway::state::AppState; -use crate::alphahuman::memory::MemoryCategory; -use crate::alphahuman::providers::{self, ChatMessage, ProviderCapabilityError}; -use crate::alphahuman::security::pairing::constant_time_eq; +use crate::openhuman::gateway::models::WebhookBody; +use crate::openhuman::gateway::state::AppState; +use crate::openhuman::memory::MemoryCategory; +use crate::openhuman::providers::{self, ChatMessage, ProviderCapabilityError}; +use crate::openhuman::security::pairing::constant_time_eq; use axum::{ extract::{ConnectInfo, State}, http::{header, HeaderMap, StatusCode}, @@ -24,7 +24,7 @@ pub(crate) async fn run_gateway_chat_with_multimodal( message: &str, ) -> anyhow::Result { let user_messages = vec![ChatMessage::user(message)]; - let image_marker_count = crate::alphahuman::multimodal::count_image_markers(&user_messages); + let image_marker_count = crate::openhuman::multimodal::count_image_markers(&user_messages); if image_marker_count > 0 && !state.provider.supports_vision() { return Err(ProviderCapabilityError { provider: provider_label.to_string(), @@ -40,7 +40,7 @@ pub(crate) async fn run_gateway_chat_with_multimodal( // workspace-aware system context before model invocation. let system_prompt = { let config_guard = state.config.lock(); - crate::alphahuman::channels::build_system_prompt( + crate::openhuman::channels::build_system_prompt( &config_guard.workspace_dir, &state.model, &[], // tools - empty for simple chat @@ -56,7 +56,7 @@ pub(crate) async fn run_gateway_chat_with_multimodal( let multimodal_config = state.config.lock().multimodal.clone(); let prepared = - crate::alphahuman::multimodal::prepare_messages_for_provider(&messages, &multimodal_config) + crate::openhuman::multimodal::prepare_messages_for_provider(&messages, &multimodal_config) .await?; state @@ -181,13 +181,13 @@ pub async fn handle_webhook( state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::AgentStart { + .record_event(&crate::openhuman::observability::ObserverEvent::AgentStart { provider: provider_label.clone(), model: model_label.clone(), }); state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::LlmRequest { + .record_event(&crate::openhuman::observability::ObserverEvent::LlmRequest { provider: provider_label.clone(), model: model_label.clone(), messages_count: 1, @@ -198,7 +198,7 @@ pub async fn handle_webhook( let duration = started_at.elapsed(); state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::LlmResponse { + .record_event(&crate::openhuman::observability::ObserverEvent::LlmResponse { provider: provider_label.clone(), model: model_label.clone(), duration, @@ -206,11 +206,11 @@ pub async fn handle_webhook( error_message: None, }); state.observer.record_metric( - &crate::alphahuman::observability::traits::ObserverMetric::RequestLatency(duration), + &crate::openhuman::observability::traits::ObserverMetric::RequestLatency(duration), ); state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::AgentEnd { + .record_event(&crate::openhuman::observability::ObserverEvent::AgentEnd { provider: provider_label, model: model_label, duration, @@ -227,7 +227,7 @@ pub async fn handle_webhook( state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::LlmResponse { + .record_event(&crate::openhuman::observability::ObserverEvent::LlmResponse { provider: provider_label.clone(), model: model_label.clone(), duration, @@ -235,17 +235,17 @@ pub async fn handle_webhook( error_message: Some(sanitized.clone()), }); state.observer.record_metric( - &crate::alphahuman::observability::traits::ObserverMetric::RequestLatency(duration), + &crate::openhuman::observability::traits::ObserverMetric::RequestLatency(duration), ); state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::Error { + .record_event(&crate::openhuman::observability::ObserverEvent::Error { component: "gateway".to_string(), message: sanitized.clone(), }); state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::AgentEnd { + .record_event(&crate::openhuman::observability::ObserverEvent::AgentEnd { provider: provider_label, model: model_label, duration, diff --git a/src-tauri/src/alphahuman/gateway/handlers/whatsapp.rs b/src-tauri/src/openhuman/gateway/handlers/whatsapp.rs similarity index 92% rename from src-tauri/src/alphahuman/gateway/handlers/whatsapp.rs rename to src-tauri/src/openhuman/gateway/handlers/whatsapp.rs index 3cb6e3276..af0833860 100644 --- a/src-tauri/src/alphahuman/gateway/handlers/whatsapp.rs +++ b/src-tauri/src/openhuman/gateway/handlers/whatsapp.rs @@ -1,13 +1,13 @@ //! WhatsApp webhook handlers and signature verification. use super::webhook::run_gateway_chat_with_multimodal; -use crate::alphahuman::channels::SendMessage; -use crate::alphahuman::channels::traits::Channel; -use crate::alphahuman::gateway::models::WhatsAppVerifyQuery; -use crate::alphahuman::gateway::state::AppState; -use crate::alphahuman::memory::MemoryCategory; -use crate::alphahuman::security::pairing::constant_time_eq; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::channels::SendMessage; +use crate::openhuman::channels::traits::Channel; +use crate::openhuman::gateway::models::WhatsAppVerifyQuery; +use crate::openhuman::gateway::state::AppState; +use crate::openhuman::memory::MemoryCategory; +use crate::openhuman::security::pairing::constant_time_eq; +use crate::openhuman::util::truncate_with_ellipsis; use axum::{ body::Bytes, extract::{Query, State}, @@ -132,7 +132,7 @@ pub async fn handle_whatsapp_message( // Auto-save to memory if state.auto_save { - let key = crate::alphahuman::gateway::constants::whatsapp_memory_key(msg); + let key = crate::openhuman::gateway::constants::whatsapp_memory_key(msg); let _ = state .mem .store(&key, &msg.content, MemoryCategory::Conversation, None) diff --git a/src-tauri/src/alphahuman/gateway/mod.rs b/src-tauri/src/openhuman/gateway/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/gateway/mod.rs rename to src-tauri/src/openhuman/gateway/mod.rs diff --git a/src-tauri/src/alphahuman/gateway/models.rs b/src-tauri/src/openhuman/gateway/models.rs similarity index 100% rename from src-tauri/src/alphahuman/gateway/models.rs rename to src-tauri/src/openhuman/gateway/models.rs diff --git a/src-tauri/src/alphahuman/gateway/rate_limit.rs b/src-tauri/src/openhuman/gateway/rate_limit.rs similarity index 96% rename from src-tauri/src/alphahuman/gateway/rate_limit.rs rename to src-tauri/src/openhuman/gateway/rate_limit.rs index 9d5ba20cb..8cc5763b7 100644 --- a/src-tauri/src/alphahuman/gateway/rate_limit.rs +++ b/src-tauri/src/openhuman/gateway/rate_limit.rs @@ -1,6 +1,6 @@ //! Rate limiting and idempotency utilities for the gateway. -use crate::alphahuman::gateway::constants::RATE_LIMITER_SWEEP_INTERVAL_SECS; +use crate::openhuman::gateway::constants::RATE_LIMITER_SWEEP_INTERVAL_SECS; use parking_lot::Mutex; use std::collections::HashMap; use std::time::{Duration, Instant}; @@ -85,7 +85,7 @@ pub struct GatewayRateLimiter { impl GatewayRateLimiter { pub fn new(pair_per_minute: u32, webhook_per_minute: u32, max_keys: usize) -> Self { - let window = Duration::from_secs(crate::alphahuman::gateway::constants::RATE_LIMIT_WINDOW_SECS); + let window = Duration::from_secs(crate::openhuman::gateway::constants::RATE_LIMIT_WINDOW_SECS); Self { pair: SlidingWindowRateLimiter::new(pair_per_minute, window, max_keys), webhook: SlidingWindowRateLimiter::new(webhook_per_minute, window, max_keys), diff --git a/src-tauri/src/alphahuman/gateway/server.rs b/src-tauri/src/openhuman/gateway/server.rs similarity index 87% rename from src-tauri/src/alphahuman/gateway/server.rs rename to src-tauri/src/openhuman/gateway/server.rs index ee2ecf2bf..9e90fbde9 100644 --- a/src-tauri/src/alphahuman/gateway/server.rs +++ b/src-tauri/src/openhuman/gateway/server.rs @@ -1,24 +1,24 @@ //! Gateway server bootstrap and router wiring. -use crate::alphahuman::channels::{LinqChannel, WhatsAppChannel}; -use crate::alphahuman::config::Config; -use crate::alphahuman::gateway::client::normalize_max_keys; -use crate::alphahuman::gateway::constants::{ +use crate::openhuman::channels::{LinqChannel, WhatsAppChannel}; +use crate::openhuman::config::Config; +use crate::openhuman::gateway::client::normalize_max_keys; +use crate::openhuman::gateway::constants::{ hash_webhook_secret, IDEMPOTENCY_MAX_KEYS_DEFAULT, MAX_BODY_SIZE, RATE_LIMIT_MAX_KEYS_DEFAULT, REQUEST_TIMEOUT_SECS, }; -use crate::alphahuman::gateway::handlers::{ +use crate::openhuman::gateway::handlers::{ handle_health, handle_linq_webhook, handle_metrics, handle_pair, handle_webhook, handle_whatsapp_message, handle_whatsapp_verify, }; -use crate::alphahuman::gateway::rate_limit::{GatewayRateLimiter, IdempotencyStore}; -use crate::alphahuman::gateway::state::AppState; -use crate::alphahuman::memory::{self, Memory}; -use crate::alphahuman::providers::{self, Provider}; -use crate::alphahuman::runtime; -use crate::alphahuman::security::pairing::is_public_bind; -use crate::alphahuman::security::SecurityPolicy; -use crate::alphahuman::tools; +use crate::openhuman::gateway::rate_limit::{GatewayRateLimiter, IdempotencyStore}; +use crate::openhuman::gateway::state::AppState; +use crate::openhuman::memory::{self, Memory}; +use crate::openhuman::providers::{self, Provider}; +use crate::openhuman::runtime; +use crate::openhuman::security::pairing::is_public_bind; +use crate::openhuman::security::SecurityPolicy; +use crate::openhuman::tools; use anyhow::Result; use axum::http::StatusCode; use axum::routing::{get, post}; @@ -56,7 +56,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { &config.reliability, &providers::ProviderRuntimeOptions { auth_profile_override: None, - alphahuman_dir: config.config_path.parent().map(std::path::PathBuf::from), + openhuman_dir: config.config_path.parent().map(std::path::PathBuf::from), secrets_encrypt: config.secrets.encrypt, reasoning_enabled: config.runtime.reasoning_enabled, }, @@ -129,7 +129,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { // WhatsApp app secret for webhook signature verification // Priority: environment variable > config file - let whatsapp_app_secret: Option> = std::env::var("ALPHAHUMAN_WHATSAPP_APP_SECRET") + let whatsapp_app_secret: Option> = std::env::var("OPENHUMAN_WHATSAPP_APP_SECRET") .ok() .and_then(|secret| { let secret = secret.trim(); @@ -157,7 +157,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { // Linq signing secret for webhook signature verification // Priority: environment variable > config file - let linq_signing_secret: Option> = std::env::var("ALPHAHUMAN_LINQ_SIGNING_SECRET") + let linq_signing_secret: Option> = std::env::var("OPENHUMAN_LINQ_SIGNING_SECRET") .ok() .and_then(|secret| { let secret = secret.trim(); @@ -175,7 +175,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { .map(Arc::from); // ── Pairing guard ────────────────────────────────────── - let pairing = Arc::new(crate::alphahuman::security::pairing::PairingGuard::new( + let pairing = Arc::new(crate::openhuman::security::pairing::PairingGuard::new( config.gateway.require_pairing, &config.gateway.paired_tokens, )); @@ -198,7 +198,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { )); // ── Tunnel ──────────────────────────────────────────────── - let tunnel = crate::alphahuman::tunnel::create_tunnel(&config.tunnel)?; + let tunnel = crate::openhuman::tunnel::create_tunnel(&config.tunnel)?; let mut tunnel_url: Option = None; if let Some(ref tun) = tunnel { @@ -215,7 +215,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { } } - println!("🦀 Alphahuman Gateway listening on http://{display_addr}"); + println!("🦀 OpenHuman Gateway listening on http://{display_addr}"); if let Some(ref url) = tunnel_url { println!(" 🌐 Public URL: {url}"); } @@ -244,11 +244,11 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { } println!(" Press Ctrl+C to stop.\n"); - crate::alphahuman::health::mark_component_ok("gateway"); + crate::openhuman::health::mark_component_ok("gateway"); // Build shared state - let observer: Arc = - Arc::from(crate::alphahuman::observability::create_observer(&config.observability)); + let observer: Arc = + Arc::from(crate::openhuman::observability::create_observer(&config.observability)); let state = AppState { config: config_state, diff --git a/src-tauri/src/alphahuman/gateway/state.rs b/src-tauri/src/openhuman/gateway/state.rs similarity index 72% rename from src-tauri/src/alphahuman/gateway/state.rs rename to src-tauri/src/openhuman/gateway/state.rs index 0766c3050..477b937f4 100644 --- a/src-tauri/src/alphahuman/gateway/state.rs +++ b/src-tauri/src/openhuman/gateway/state.rs @@ -1,11 +1,11 @@ //! Shared gateway state for axum handlers. -use crate::alphahuman::channels::{LinqChannel, WhatsAppChannel}; -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::Memory; -use crate::alphahuman::providers::Provider; -use crate::alphahuman::security::pairing::PairingGuard; -use crate::alphahuman::gateway::rate_limit::{GatewayRateLimiter, IdempotencyStore}; +use crate::openhuman::channels::{LinqChannel, WhatsAppChannel}; +use crate::openhuman::config::Config; +use crate::openhuman::memory::Memory; +use crate::openhuman::providers::Provider; +use crate::openhuman::security::pairing::PairingGuard; +use crate::openhuman::gateway::rate_limit::{GatewayRateLimiter, IdempotencyStore}; use parking_lot::Mutex; use std::sync::Arc; @@ -31,5 +31,5 @@ pub struct AppState { /// Linq webhook signing secret for signature verification. pub linq_signing_secret: Option>, /// Observability backend for metrics scraping. - pub observer: Arc, + pub observer: Arc, } diff --git a/src-tauri/src/alphahuman/gateway/tests.rs b/src-tauri/src/openhuman/gateway/tests.rs similarity index 96% rename from src-tauri/src/alphahuman/gateway/tests.rs rename to src-tauri/src/openhuman/gateway/tests.rs index 9a3f52bd2..bf2339a8a 100644 --- a/src-tauri/src/alphahuman/gateway/tests.rs +++ b/src-tauri/src/openhuman/gateway/tests.rs @@ -12,11 +12,11 @@ use super::handlers::{ use super::models::{WebhookBody, WhatsAppVerifyQuery}; use super::rate_limit::{GatewayRateLimiter, IdempotencyStore, SlidingWindowRateLimiter}; use super::state::AppState; -use crate::alphahuman::channels::traits::ChannelMessage; -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::{Memory, MemoryCategory, MemoryEntry}; -use crate::alphahuman::providers::Provider; -use crate::alphahuman::security::pairing::PairingGuard; +use crate::openhuman::channels::traits::ChannelMessage; +use crate::openhuman::config::Config; +use crate::openhuman::memory::{Memory, MemoryCategory, MemoryEntry}; +use crate::openhuman::providers::Provider; +use crate::openhuman::security::pairing::PairingGuard; use async_trait::async_trait; use axum::extract::ConnectInfo; use axum::http::HeaderValue; @@ -101,7 +101,7 @@ async fn metrics_endpoint_returns_hint_when_prometheus_is_disabled() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let response = handle_metrics(axum::extract::State(state)).await.into_response(); @@ -121,13 +121,13 @@ async fn metrics_endpoint_returns_hint_when_prometheus_is_disabled() { #[tokio::test] async fn metrics_endpoint_renders_prometheus_output() { - let prom = Arc::new(crate::alphahuman::observability::PrometheusObserver::new()); - crate::alphahuman::observability::Observer::record_event( + let prom = Arc::new(crate::openhuman::observability::PrometheusObserver::new()); + crate::openhuman::observability::Observer::record_event( prom.as_ref(), - &crate::alphahuman::observability::ObserverEvent::HeartbeatTick, + &crate::openhuman::observability::ObserverEvent::HeartbeatTick, ); - let observer: Arc = prom; + let observer: Arc = prom; let state = AppState { config: Arc::new(Mutex::new(Config::default())), provider: Arc::new(MockProvider::default()), @@ -152,7 +152,7 @@ async fn metrics_endpoint_renders_prometheus_output() { let body = response.into_body().collect().await.unwrap().to_bytes(); let text = String::from_utf8(body.to_vec()).unwrap(); - assert!(text.contains("alphahuman_heartbeat_ticks_total 1")); + assert!(text.contains("openhuman_heartbeat_ticks_total 1")); } #[test] @@ -519,7 +519,7 @@ async fn webhook_idempotency_skips_duplicate_provider_calls() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let mut headers = HeaderMap::new(); @@ -578,7 +578,7 @@ async fn webhook_autosave_stores_distinct_keys_per_request() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let headers = HeaderMap::new(); @@ -649,7 +649,7 @@ async fn webhook_secret_hash_rejects_missing_header() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let response = handle_webhook( @@ -689,7 +689,7 @@ async fn webhook_secret_hash_rejects_invalid_header() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let mut headers = HeaderMap::new(); @@ -734,7 +734,7 @@ async fn webhook_secret_hash_accepts_valid_header() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let mut headers = HeaderMap::new(); @@ -775,7 +775,7 @@ async fn webhook_missing_message_returns_bad_request() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let response = handle_webhook( diff --git a/src-tauri/src/alphahuman/hardware/discover.rs b/src-tauri/src/openhuman/hardware/discover.rs similarity index 100% rename from src-tauri/src/alphahuman/hardware/discover.rs rename to src-tauri/src/openhuman/hardware/discover.rs diff --git a/src-tauri/src/alphahuman/hardware/introspect.rs b/src-tauri/src/openhuman/hardware/introspect.rs similarity index 100% rename from src-tauri/src/alphahuman/hardware/introspect.rs rename to src-tauri/src/openhuman/hardware/introspect.rs diff --git a/src-tauri/src/alphahuman/hardware/mod.rs b/src-tauri/src/openhuman/hardware/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/hardware/mod.rs rename to src-tauri/src/openhuman/hardware/mod.rs index 851a350fc..d5f5cb9e9 100644 --- a/src-tauri/src/alphahuman/hardware/mod.rs +++ b/src-tauri/src/openhuman/hardware/mod.rs @@ -14,7 +14,7 @@ use anyhow::Result; use serde::{Deserialize, Serialize}; // Re-export config types so UI flows can use `hardware::HardwareConfig` etc. -pub use crate::alphahuman::config::{HardwareConfig, HardwareTransport}; +pub use crate::openhuman::config::{HardwareConfig, HardwareTransport}; /// A hardware device discovered during auto-scan. #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/src-tauri/src/alphahuman/hardware/registry.rs b/src-tauri/src/openhuman/hardware/registry.rs similarity index 100% rename from src-tauri/src/alphahuman/hardware/registry.rs rename to src-tauri/src/openhuman/hardware/registry.rs diff --git a/src-tauri/src/alphahuman/health/mod.rs b/src-tauri/src/openhuman/health/mod.rs similarity index 95% rename from src-tauri/src/alphahuman/health/mod.rs rename to src-tauri/src/openhuman/health/mod.rs index d0f772b4b..0231aebf3 100644 --- a/src-tauri/src/alphahuman/health/mod.rs +++ b/src-tauri/src/openhuman/health/mod.rs @@ -60,7 +60,7 @@ where } pub fn mark_component_ok(component: &str) { - log::debug!("[alphahuman:health] Component '{}' marked OK", component); + log::debug!("[openhuman:health] Component '{}' marked OK", component); upsert_component(component, |entry| { entry.status = "ok".into(); entry.last_ok = Some(now_rfc3339()); @@ -71,7 +71,7 @@ pub fn mark_component_ok(component: &str) { #[allow(clippy::needless_pass_by_value)] pub fn mark_component_error(component: &str, error: impl ToString) { let err = error.to_string(); - log::warn!("[alphahuman:health] Component '{}' error: {}", component, err); + log::warn!("[openhuman:health] Component '{}' error: {}", component, err); upsert_component(component, move |entry| { entry.status = "error".into(); entry.last_error = Some(err); @@ -79,7 +79,7 @@ pub fn mark_component_error(component: &str, error: impl ToString) { } pub fn bump_component_restart(component: &str) { - log::info!("[alphahuman:health] Component '{}' restarting", component); + log::info!("[openhuman:health] Component '{}' restarting", component); upsert_component(component, |entry| { entry.restart_count = entry.restart_count.saturating_add(1); }); diff --git a/src-tauri/src/alphahuman/heartbeat/engine.rs b/src-tauri/src/openhuman/heartbeat/engine.rs similarity index 92% rename from src-tauri/src/alphahuman/heartbeat/engine.rs rename to src-tauri/src/openhuman/heartbeat/engine.rs index 9dab3ada6..ca42baa80 100644 --- a/src-tauri/src/alphahuman/heartbeat/engine.rs +++ b/src-tauri/src/openhuman/heartbeat/engine.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::config::HeartbeatConfig; -use crate::alphahuman::observability::{Observer, ObserverEvent}; +use crate::openhuman::config::HeartbeatConfig; +use crate::openhuman::observability::{Observer, ObserverEvent}; use anyhow::Result; use std::path::Path; use std::sync::Arc; @@ -206,7 +206,7 @@ mod tests { #[tokio::test] async fn ensure_heartbeat_file_creates_file() { - let dir = std::env::temp_dir().join("alphahuman_test_heartbeat"); + let dir = std::env::temp_dir().join("openhuman_test_heartbeat"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -222,7 +222,7 @@ mod tests { #[tokio::test] async fn ensure_heartbeat_file_does_not_overwrite() { - let dir = std::env::temp_dir().join("alphahuman_test_heartbeat_no_overwrite"); + let dir = std::env::temp_dir().join("openhuman_test_heartbeat_no_overwrite"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -239,11 +239,11 @@ mod tests { #[tokio::test] async fn tick_returns_zero_when_no_file() { - let dir = std::env::temp_dir().join("alphahuman_test_tick_no_file"); + let dir = std::env::temp_dir().join("openhuman_test_tick_no_file"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); - let observer: Arc = Arc::new(crate::alphahuman::observability::NoopObserver); + let observer: Arc = Arc::new(crate::openhuman::observability::NoopObserver); let engine = HeartbeatEngine::new( HeartbeatConfig { enabled: true, @@ -260,7 +260,7 @@ mod tests { #[tokio::test] async fn tick_counts_tasks_from_file() { - let dir = std::env::temp_dir().join("alphahuman_test_tick_count"); + let dir = std::env::temp_dir().join("openhuman_test_tick_count"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -268,7 +268,7 @@ mod tests { .await .unwrap(); - let observer: Arc = Arc::new(crate::alphahuman::observability::NoopObserver); + let observer: Arc = Arc::new(crate::openhuman::observability::NoopObserver); let engine = HeartbeatEngine::new( HeartbeatConfig { enabled: true, @@ -285,7 +285,7 @@ mod tests { #[tokio::test] async fn run_returns_immediately_when_disabled() { - let observer: Arc = Arc::new(crate::alphahuman::observability::NoopObserver); + let observer: Arc = Arc::new(crate::openhuman::observability::NoopObserver); let engine = HeartbeatEngine::new( HeartbeatConfig { enabled: false, diff --git a/src-tauri/src/alphahuman/heartbeat/mod.rs b/src-tauri/src/openhuman/heartbeat/mod.rs similarity index 81% rename from src-tauri/src/alphahuman/heartbeat/mod.rs rename to src-tauri/src/openhuman/heartbeat/mod.rs index d5d300e57..9954525db 100644 --- a/src-tauri/src/alphahuman/heartbeat/mod.rs +++ b/src-tauri/src/openhuman/heartbeat/mod.rs @@ -2,9 +2,9 @@ pub mod engine; #[cfg(test)] mod tests { - use crate::alphahuman::config::HeartbeatConfig; - use crate::alphahuman::heartbeat::engine::HeartbeatEngine; - use crate::alphahuman::observability::NoopObserver; + use crate::openhuman::config::HeartbeatConfig; + use crate::openhuman::heartbeat::engine::HeartbeatEngine; + use crate::openhuman::observability::NoopObserver; use std::sync::Arc; #[test] diff --git a/src-tauri/src/alphahuman/identity.rs b/src-tauri/src/openhuman/identity.rs similarity index 99% rename from src-tauri/src/alphahuman/identity.rs rename to src-tauri/src/openhuman/identity.rs index 0450a43d3..0dd894c9d 100644 --- a/src-tauri/src/alphahuman/identity.rs +++ b/src-tauri/src/openhuman/identity.rs @@ -2,9 +2,9 @@ //! //! AIEOS (AI Entity Object Specification) is a standardization framework for //! portable AI identity. This module handles loading and converting AIEOS v1.1 -//! JSON to Alphahuman's system prompt format. +//! JSON to OpenHuman's system prompt format. -use crate::alphahuman::config::IdentityConfig; +use crate::openhuman::config::IdentityConfig; use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; @@ -714,7 +714,7 @@ fn non_empty_list_at(value: &Value, path: &[&str]) -> Option> { /// Convert AIEOS identity to a system prompt string. /// /// Formats the AIEOS data into a structured markdown prompt compatible -/// with Alphahuman's agent system. +/// with OpenHuman's agent system. pub fn aieos_to_system_prompt(identity: &AieosIdentity) -> String { use std::fmt::Write; let mut prompt = String::new(); @@ -986,7 +986,7 @@ mod tests { use super::*; fn test_workspace_dir() -> PathBuf { - std::env::temp_dir().join("alphahuman-test-identity") + std::env::temp_dir().join("openhuman-test-identity") } #[test] diff --git a/src-tauri/src/alphahuman/integrations/mod.rs b/src-tauri/src/openhuman/integrations/mod.rs similarity index 99% rename from src-tauri/src/alphahuman/integrations/mod.rs rename to src-tauri/src/openhuman/integrations/mod.rs index 04f542136..e28f01f04 100644 --- a/src-tauri/src/alphahuman/integrations/mod.rs +++ b/src-tauri/src/openhuman/integrations/mod.rs @@ -2,7 +2,7 @@ pub mod registry; -use crate::alphahuman::config::Config; +use crate::openhuman::config::Config; use anyhow::Result; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/src/alphahuman/integrations/registry.rs b/src-tauri/src/openhuman/integrations/registry.rs similarity index 99% rename from src-tauri/src/alphahuman/integrations/registry.rs rename to src-tauri/src/openhuman/integrations/registry.rs index 4d58fe979..61b97e0c9 100644 --- a/src-tauri/src/alphahuman/integrations/registry.rs +++ b/src-tauri/src/openhuman/integrations/registry.rs @@ -1,5 +1,5 @@ use super::{IntegrationCategory, IntegrationEntry, IntegrationStatus}; -use crate::alphahuman::providers::{ +use crate::openhuman::providers::{ is_glm_alias, is_minimax_alias, is_moonshot_alias, is_qianfan_alias, is_qwen_alias, is_zai_alias, }; @@ -725,8 +725,8 @@ pub fn all_integrations() -> Vec { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::schema::{IMessageConfig, MatrixConfig, StreamMode, TelegramConfig}; - use crate::alphahuman::config::Config; + use crate::openhuman::config::schema::{IMessageConfig, MatrixConfig, StreamMode, TelegramConfig}; + use crate::openhuman::config::Config; #[test] fn registry_has_entries() { diff --git a/src-tauri/src/alphahuman/memory/backend.rs b/src-tauri/src/openhuman/memory/backend.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/backend.rs rename to src-tauri/src/openhuman/memory/backend.rs diff --git a/src-tauri/src/alphahuman/memory/chunker.rs b/src-tauri/src/openhuman/memory/chunker.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/chunker.rs rename to src-tauri/src/openhuman/memory/chunker.rs diff --git a/src-tauri/src/alphahuman/memory/embeddings.rs b/src-tauri/src/openhuman/memory/embeddings.rs similarity index 99% rename from src-tauri/src/alphahuman/memory/embeddings.rs rename to src-tauri/src/openhuman/memory/embeddings.rs index 08eed7f58..d534bbd2f 100644 --- a/src-tauri/src/alphahuman/memory/embeddings.rs +++ b/src-tauri/src/openhuman/memory/embeddings.rs @@ -60,7 +60,7 @@ impl OpenAiEmbedding { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("memory.embeddings") + crate::openhuman::config::build_runtime_proxy_client("memory.embeddings") } fn has_explicit_api_path(&self) -> bool { diff --git a/src-tauri/src/alphahuman/memory/hygiene.rs b/src-tauri/src/openhuman/memory/hygiene.rs similarity index 99% rename from src-tauri/src/alphahuman/memory/hygiene.rs rename to src-tauri/src/openhuman/memory/hygiene.rs index d80bd8c5a..9390a2c1d 100644 --- a/src-tauri/src/alphahuman/memory/hygiene.rs +++ b/src-tauri/src/openhuman/memory/hygiene.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::config::MemoryConfig; +use crate::openhuman::config::MemoryConfig; use anyhow::Result; use chrono::{DateTime, Duration, Local, NaiveDate, Utc}; use rusqlite::{params, Connection}; @@ -379,7 +379,7 @@ fn split_name(filename: &str) -> (&str, &str) { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::memory::{Memory, MemoryCategory, SqliteMemory}; + use crate::openhuman::memory::{Memory, MemoryCategory, SqliteMemory}; use tempfile::TempDir; fn default_cfg() -> MemoryConfig { diff --git a/src-tauri/src/alphahuman/memory/lucid.rs b/src-tauri/src/openhuman/memory/lucid.rs similarity index 98% rename from src-tauri/src/alphahuman/memory/lucid.rs rename to src-tauri/src/openhuman/memory/lucid.rs index 51d41a147..017fd72a4 100644 --- a/src-tauri/src/alphahuman/memory/lucid.rs +++ b/src-tauri/src/openhuman/memory/lucid.rs @@ -32,32 +32,32 @@ impl LucidMemory { const DEFAULT_FAILURE_COOLDOWN_MS: u64 = 15_000; pub fn new(workspace_dir: &Path, local: SqliteMemory) -> Self { - let lucid_cmd = std::env::var("ALPHAHUMAN_LUCID_CMD") + let lucid_cmd = std::env::var("OPENHUMAN_LUCID_CMD") .unwrap_or_else(|_| Self::DEFAULT_LUCID_CMD.to_string()); - let token_budget = std::env::var("ALPHAHUMAN_LUCID_BUDGET") + let token_budget = std::env::var("OPENHUMAN_LUCID_BUDGET") .ok() .and_then(|v| v.parse::().ok()) .filter(|v| *v > 0) .unwrap_or(Self::DEFAULT_TOKEN_BUDGET); let recall_timeout = Self::read_env_duration_ms( - "ALPHAHUMAN_LUCID_RECALL_TIMEOUT_MS", + "OPENHUMAN_LUCID_RECALL_TIMEOUT_MS", Self::DEFAULT_RECALL_TIMEOUT_MS, 20, ); let store_timeout = Self::read_env_duration_ms( - "ALPHAHUMAN_LUCID_STORE_TIMEOUT_MS", + "OPENHUMAN_LUCID_STORE_TIMEOUT_MS", Self::DEFAULT_STORE_TIMEOUT_MS, 50, ); let local_hit_threshold = Self::read_env_usize( - "ALPHAHUMAN_LUCID_LOCAL_HIT_THRESHOLD", + "OPENHUMAN_LUCID_LOCAL_HIT_THRESHOLD", Self::DEFAULT_LOCAL_HIT_THRESHOLD, 1, ); let failure_cooldown = Self::read_env_duration_ms( - "ALPHAHUMAN_LUCID_FAILURE_COOLDOWN_MS", + "OPENHUMAN_LUCID_FAILURE_COOLDOWN_MS", Self::DEFAULT_FAILURE_COOLDOWN_MS, 100, ); diff --git a/src-tauri/src/alphahuman/memory/markdown.rs b/src-tauri/src/openhuman/memory/markdown.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/markdown.rs rename to src-tauri/src/openhuman/memory/markdown.rs diff --git a/src-tauri/src/alphahuman/memory/mod.rs b/src-tauri/src/openhuman/memory/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/memory/mod.rs rename to src-tauri/src/openhuman/memory/mod.rs index dd77753c3..f9d6bc917 100644 --- a/src-tauri/src/alphahuman/memory/mod.rs +++ b/src-tauri/src/openhuman/memory/mod.rs @@ -27,7 +27,7 @@ pub use traits::Memory; #[allow(unused_imports)] pub use traits::{MemoryCategory, MemoryEntry}; -use crate::alphahuman::config::{EmbeddingRouteConfig, MemoryConfig, StorageProviderConfig}; +use crate::openhuman::config::{EmbeddingRouteConfig, MemoryConfig, StorageProviderConfig}; use anyhow::Context; use std::path::Path; use std::sync::Arc; @@ -329,7 +329,7 @@ pub fn create_response_cache(config: &MemoryConfig, workspace_dir: &Path) -> Opt #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::{EmbeddingRouteConfig, StorageProviderConfig}; + use crate::openhuman::config::{EmbeddingRouteConfig, StorageProviderConfig}; use tempfile::TempDir; #[test] diff --git a/src-tauri/src/alphahuman/memory/none.rs b/src-tauri/src/openhuman/memory/none.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/none.rs rename to src-tauri/src/openhuman/memory/none.rs diff --git a/src-tauri/src/alphahuman/memory/postgres.rs b/src-tauri/src/openhuman/memory/postgres.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/postgres.rs rename to src-tauri/src/openhuman/memory/postgres.rs diff --git a/src-tauri/src/alphahuman/memory/response_cache.rs b/src-tauri/src/openhuman/memory/response_cache.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/response_cache.rs rename to src-tauri/src/openhuman/memory/response_cache.rs diff --git a/src-tauri/src/alphahuman/memory/snapshot.rs b/src-tauri/src/openhuman/memory/snapshot.rs similarity index 97% rename from src-tauri/src/alphahuman/memory/snapshot.rs rename to src-tauri/src/openhuman/memory/snapshot.rs index 15e0c10da..9886b0782 100644 --- a/src-tauri/src/alphahuman/memory/snapshot.rs +++ b/src-tauri/src/openhuman/memory/snapshot.rs @@ -17,8 +17,8 @@ use std::path::{Path, PathBuf}; pub const SNAPSHOT_FILENAME: &str = "MEMORY_SNAPSHOT.md"; /// Header written at the top of every snapshot file. -const SNAPSHOT_HEADER: &str = "# 🧠 Alphahuman Memory Snapshot\n\n\ - > Auto-generated by Alphahuman. Do not edit manually unless you know what you're doing.\n\ +const SNAPSHOT_HEADER: &str = "# 🧠 OpenHuman Memory Snapshot\n\n\ + > Auto-generated by OpenHuman. Do not edit manually unless you know what you're doing.\n\ > This file is the \"soul\" of your agent — if `brain.db` is lost, start the agent\n\ > in this workspace and it will auto-hydrate from this file.\n\n"; @@ -266,9 +266,9 @@ mod tests { #[test] fn parse_snapshot_basic() { - let input = r#"# 🧠 Alphahuman Memory Snapshot + let input = r#"# 🧠 OpenHuman Memory Snapshot -> Auto-generated by Alphahuman. +> Auto-generated by OpenHuman. **Last exported:** 2025-01-15 14:30:00 @@ -278,7 +278,7 @@ mod tests { ### 🔑 `identity` -I am Alphahuman, a self-preserving AI agent. +I am OpenHuman, a self-preserving AI agent. *Created: 2025-01-15 | Updated: 2025-01-15* @@ -303,7 +303,7 @@ The user prefers Rust for systems programming. #[test] fn parse_snapshot_empty() { - let input = "# 🧠 Alphahuman Memory Snapshot\n\n> Nothing here.\n"; + let input = "# 🧠 OpenHuman Memory Snapshot\n\n> Nothing here.\n"; let entries = parse_snapshot(input); assert!(entries.is_empty()); } diff --git a/src-tauri/src/alphahuman/memory/sqlite.rs b/src-tauri/src/openhuman/memory/sqlite.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/sqlite.rs rename to src-tauri/src/openhuman/memory/sqlite.rs diff --git a/src-tauri/src/alphahuman/memory/traits.rs b/src-tauri/src/openhuman/memory/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/traits.rs rename to src-tauri/src/openhuman/memory/traits.rs diff --git a/src-tauri/src/alphahuman/memory/vector.rs b/src-tauri/src/openhuman/memory/vector.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/vector.rs rename to src-tauri/src/openhuman/memory/vector.rs diff --git a/src-tauri/src/alphahuman/migration.rs b/src-tauri/src/openhuman/migration.rs similarity index 98% rename from src-tauri/src/alphahuman/migration.rs rename to src-tauri/src/openhuman/migration.rs index 5e4209367..d4fc4295d 100644 --- a/src-tauri/src/alphahuman/migration.rs +++ b/src-tauri/src/openhuman/migration.rs @@ -1,7 +1,7 @@ -//! Data migration helpers for Alphahuman. +//! Data migration helpers for OpenHuman. -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::{self, Memory, MemoryCategory}; +use crate::openhuman::config::Config; +use crate::openhuman::memory::{self, Memory, MemoryCategory}; use anyhow::{bail, Context, Result}; use directories::UserDirs; use rusqlite::{Connection, OpenFlags, OptionalExtension}; @@ -49,7 +49,7 @@ pub async fn migrate_openclaw_memory( } if paths_equal(&source_workspace, &config.workspace_dir) { - bail!("Source workspace matches current Alphahuman workspace; refusing self-migration"); + bail!("Source workspace matches current OpenHuman workspace; refusing self-migration"); } let mut stats = MigrationStats::default(); diff --git a/src-tauri/src/alphahuman/mod.rs b/src-tauri/src/openhuman/mod.rs similarity index 89% rename from src-tauri/src/alphahuman/mod.rs rename to src-tauri/src/openhuman/mod.rs index dc043bbf3..5a0b1cbf1 100644 --- a/src-tauri/src/alphahuman/mod.rs +++ b/src-tauri/src/openhuman/mod.rs @@ -1,6 +1,6 @@ -//! Alphahuman — lightweight agent runtime for AlphaHuman. +//! OpenHuman — lightweight agent runtime for OpenHuman. //! -//! Ported from Alphahuman (MIT-licensed). Provides: +//! Ported from OpenHuman (MIT-licensed). Provides: //! - Health registry for component monitoring //! - Security policy, secrets, audit, pairing, and sandboxing //! - Daemon supervisor with exponential backoff diff --git a/src-tauri/src/alphahuman/multimodal.rs b/src-tauri/src/openhuman/multimodal.rs similarity index 99% rename from src-tauri/src/alphahuman/multimodal.rs rename to src-tauri/src/openhuman/multimodal.rs index 36c561887..6fe514d1f 100644 --- a/src-tauri/src/alphahuman/multimodal.rs +++ b/src-tauri/src/openhuman/multimodal.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::config::{build_runtime_proxy_client_with_timeouts, MultimodalConfig}; -use crate::alphahuman::providers::ChatMessage; +use crate::openhuman::config::{build_runtime_proxy_client_with_timeouts, MultimodalConfig}; +use crate::openhuman::providers::ChatMessage; use base64::{engine::general_purpose::STANDARD, Engine as _}; use reqwest::Client; use std::path::Path; diff --git a/src-tauri/src/alphahuman/observability/log.rs b/src-tauri/src/openhuman/observability/log.rs similarity index 100% rename from src-tauri/src/alphahuman/observability/log.rs rename to src-tauri/src/openhuman/observability/log.rs diff --git a/src-tauri/src/alphahuman/observability/mod.rs b/src-tauri/src/openhuman/observability/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/observability/mod.rs rename to src-tauri/src/openhuman/observability/mod.rs index fff8421d1..b96285f3b 100644 --- a/src-tauri/src/alphahuman/observability/mod.rs +++ b/src-tauri/src/openhuman/observability/mod.rs @@ -17,7 +17,7 @@ pub use traits::{Observer, ObserverEvent}; #[allow(unused_imports)] pub use verbose::VerboseObserver; -use crate::alphahuman::config::ObservabilityConfig; +use crate::openhuman::config::ObservabilityConfig; /// Factory: create the right observer from config pub fn create_observer(config: &ObservabilityConfig) -> Box { diff --git a/src-tauri/src/alphahuman/observability/multi.rs b/src-tauri/src/openhuman/observability/multi.rs similarity index 100% rename from src-tauri/src/alphahuman/observability/multi.rs rename to src-tauri/src/openhuman/observability/multi.rs diff --git a/src-tauri/src/alphahuman/observability/noop.rs b/src-tauri/src/openhuman/observability/noop.rs similarity index 100% rename from src-tauri/src/alphahuman/observability/noop.rs rename to src-tauri/src/openhuman/observability/noop.rs diff --git a/src-tauri/src/alphahuman/observability/otel.rs b/src-tauri/src/openhuman/observability/otel.rs similarity index 95% rename from src-tauri/src/alphahuman/observability/otel.rs rename to src-tauri/src/openhuman/observability/otel.rs index f7a6acd7f..c4de62ee9 100644 --- a/src-tauri/src/alphahuman/observability/otel.rs +++ b/src-tauri/src/openhuman/observability/otel.rs @@ -36,7 +36,7 @@ impl OtelObserver { /// Falls back to `http://localhost:4318` if no endpoint is provided. pub fn new(endpoint: Option<&str>, service_name: Option<&str>) -> Result { let endpoint = endpoint.unwrap_or("http://localhost:4318"); - let service_name = service_name.unwrap_or("alphahuman"); + let service_name = service_name.unwrap_or("openhuman"); // ── Trace exporter ────────────────────────────────────── let span_exporter = opentelemetry_otlp::SpanExporter::builder() @@ -79,74 +79,74 @@ impl OtelObserver { global::set_meter_provider(meter_provider); // ── Create metric instruments ──────────────────────────── - let meter = global::meter("alphahuman"); + let meter = global::meter("openhuman"); let agent_starts = meter - .u64_counter("alphahuman.agent.starts") + .u64_counter("openhuman.agent.starts") .with_description("Total agent invocations") .build(); let agent_duration = meter - .f64_histogram("alphahuman.agent.duration") + .f64_histogram("openhuman.agent.duration") .with_description("Agent invocation duration in seconds") .with_unit("s") .build(); let llm_calls = meter - .u64_counter("alphahuman.llm.calls") + .u64_counter("openhuman.llm.calls") .with_description("Total LLM provider calls") .build(); let llm_duration = meter - .f64_histogram("alphahuman.llm.duration") + .f64_histogram("openhuman.llm.duration") .with_description("LLM provider call duration in seconds") .with_unit("s") .build(); let tool_calls = meter - .u64_counter("alphahuman.tool.calls") + .u64_counter("openhuman.tool.calls") .with_description("Total tool calls") .build(); let tool_duration = meter - .f64_histogram("alphahuman.tool.duration") + .f64_histogram("openhuman.tool.duration") .with_description("Tool execution duration in seconds") .with_unit("s") .build(); let channel_messages = meter - .u64_counter("alphahuman.channel.messages") + .u64_counter("openhuman.channel.messages") .with_description("Total channel messages") .build(); let heartbeat_ticks = meter - .u64_counter("alphahuman.heartbeat.ticks") + .u64_counter("openhuman.heartbeat.ticks") .with_description("Total heartbeat ticks") .build(); let errors = meter - .u64_counter("alphahuman.errors") + .u64_counter("openhuman.errors") .with_description("Total errors by component") .build(); let request_latency = meter - .f64_histogram("alphahuman.request.latency") + .f64_histogram("openhuman.request.latency") .with_description("Request latency in seconds") .with_unit("s") .build(); let tokens_used = meter - .u64_counter("alphahuman.tokens.used") + .u64_counter("openhuman.tokens.used") .with_description("Total tokens consumed (monotonic)") .build(); let active_sessions = meter - .u64_gauge("alphahuman.sessions.active") + .u64_gauge("openhuman.sessions.active") .with_description("Current number of active sessions") .build(); let queue_depth = meter - .u64_gauge("alphahuman.queue.depth") + .u64_gauge("openhuman.queue.depth") .with_description("Current message queue depth") .build(); @@ -172,7 +172,7 @@ impl OtelObserver { impl Observer for OtelObserver { fn record_event(&self, event: &ObserverEvent) { - let tracer = global::tracer("alphahuman"); + let tracer = global::tracer("openhuman"); match event { ObserverEvent::AgentStart { provider, model } => { @@ -383,7 +383,7 @@ mod tests { fn test_observer() -> OtelObserver { // Create with a dummy endpoint — exports will silently fail // but the observer itself works fine for recording - OtelObserver::new(Some("http://127.0.0.1:19999"), Some("alphahuman-test")) + OtelObserver::new(Some("http://127.0.0.1:19999"), Some("openhuman-test")) .expect("observer creation should not fail with valid endpoint format") } @@ -513,7 +513,7 @@ mod tests { #[test] fn otel_observer_creation_with_valid_endpoint_succeeds() { // Even though endpoint is unreachable, creation should succeed - let result = OtelObserver::new(Some("http://127.0.0.1:12345"), Some("alphahuman-test")); + let result = OtelObserver::new(Some("http://127.0.0.1:12345"), Some("openhuman-test")); assert!( result.is_ok(), "observer creation must succeed even with unreachable endpoint" diff --git a/src-tauri/src/alphahuman/observability/prometheus.rs b/src-tauri/src/openhuman/observability/prometheus.rs similarity index 87% rename from src-tauri/src/alphahuman/observability/prometheus.rs rename to src-tauri/src/openhuman/observability/prometheus.rs index a8758b891..791b7433e 100644 --- a/src-tauri/src/alphahuman/observability/prometheus.rs +++ b/src-tauri/src/openhuman/observability/prometheus.rs @@ -30,36 +30,36 @@ impl PrometheusObserver { let registry = Registry::new(); let agent_starts = IntCounterVec::new( - prometheus::Opts::new("alphahuman_agent_starts_total", "Total agent invocations"), + prometheus::Opts::new("openhuman_agent_starts_total", "Total agent invocations"), &["provider", "model"], ) .expect("valid metric"); let tool_calls = IntCounterVec::new( - prometheus::Opts::new("alphahuman_tool_calls_total", "Total tool calls"), + prometheus::Opts::new("openhuman_tool_calls_total", "Total tool calls"), &["tool", "success"], ) .expect("valid metric"); let channel_messages = IntCounterVec::new( - prometheus::Opts::new("alphahuman_channel_messages_total", "Total channel messages"), + prometheus::Opts::new("openhuman_channel_messages_total", "Total channel messages"), &["channel", "direction"], ) .expect("valid metric"); let heartbeat_ticks = - prometheus::IntCounter::new("alphahuman_heartbeat_ticks_total", "Total heartbeat ticks") + prometheus::IntCounter::new("openhuman_heartbeat_ticks_total", "Total heartbeat ticks") .expect("valid metric"); let errors = IntCounterVec::new( - prometheus::Opts::new("alphahuman_errors_total", "Total errors by component"), + prometheus::Opts::new("openhuman_errors_total", "Total errors by component"), &["component"], ) .expect("valid metric"); let agent_duration = HistogramVec::new( HistogramOpts::new( - "alphahuman_agent_duration_seconds", + "openhuman_agent_duration_seconds", "Agent invocation duration in seconds", ) .buckets(vec![0.1, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0, 60.0]), @@ -69,7 +69,7 @@ impl PrometheusObserver { let tool_duration = HistogramVec::new( HistogramOpts::new( - "alphahuman_tool_duration_seconds", + "openhuman_tool_duration_seconds", "Tool execution duration in seconds", ) .buckets(vec![0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0]), @@ -79,7 +79,7 @@ impl PrometheusObserver { let request_latency = Histogram::with_opts( HistogramOpts::new( - "alphahuman_request_latency_seconds", + "openhuman_request_latency_seconds", "Request latency in seconds", ) .buckets(vec![0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0]), @@ -87,19 +87,19 @@ impl PrometheusObserver { .expect("valid metric"); let tokens_used = prometheus::IntGauge::new( - "alphahuman_tokens_used_last", + "openhuman_tokens_used_last", "Tokens used in the last request", ) .expect("valid metric"); let active_sessions = GaugeVec::new( - prometheus::Opts::new("alphahuman_active_sessions", "Number of active sessions"), + prometheus::Opts::new("openhuman_active_sessions", "Number of active sessions"), &[], ) .expect("valid metric"); let queue_depth = GaugeVec::new( - prometheus::Opts::new("alphahuman_queue_depth", "Message queue depth"), + prometheus::Opts::new("openhuman_queue_depth", "Message queue depth"), &[], ) .expect("valid metric"); @@ -308,10 +308,10 @@ mod tests { obs.record_metric(&ObserverMetric::RequestLatency(Duration::from_millis(250))); let output = obs.encode(); - assert!(output.contains("alphahuman_agent_starts_total")); - assert!(output.contains("alphahuman_tool_calls_total")); - assert!(output.contains("alphahuman_heartbeat_ticks_total")); - assert!(output.contains("alphahuman_request_latency_seconds")); + assert!(output.contains("openhuman_agent_starts_total")); + assert!(output.contains("openhuman_tool_calls_total")); + assert!(output.contains("openhuman_heartbeat_ticks_total")); + assert!(output.contains("openhuman_request_latency_seconds")); } #[test] @@ -323,7 +323,7 @@ mod tests { } let output = obs.encode(); - assert!(output.contains("alphahuman_heartbeat_ticks_total 3")); + assert!(output.contains("openhuman_heartbeat_ticks_total 3")); } #[test] @@ -347,8 +347,8 @@ mod tests { }); let output = obs.encode(); - assert!(output.contains(r#"alphahuman_tool_calls_total{success="true",tool="shell"} 2"#)); - assert!(output.contains(r#"alphahuman_tool_calls_total{success="false",tool="shell"} 1"#)); + assert!(output.contains(r#"openhuman_tool_calls_total{success="true",tool="shell"} 2"#)); + assert!(output.contains(r#"openhuman_tool_calls_total{success="false",tool="shell"} 1"#)); } #[test] @@ -368,8 +368,8 @@ mod tests { }); let output = obs.encode(); - assert!(output.contains(r#"alphahuman_errors_total{component="provider"} 2"#)); - assert!(output.contains(r#"alphahuman_errors_total{component="channels"} 1"#)); + assert!(output.contains(r#"openhuman_errors_total{component="provider"} 2"#)); + assert!(output.contains(r#"openhuman_errors_total{component="channels"} 1"#)); } #[test] @@ -379,6 +379,6 @@ mod tests { obs.record_metric(&ObserverMetric::TokensUsed(200)); let output = obs.encode(); - assert!(output.contains("alphahuman_tokens_used_last 200")); + assert!(output.contains("openhuman_tokens_used_last 200")); } } diff --git a/src-tauri/src/alphahuman/observability/traits.rs b/src-tauri/src/openhuman/observability/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/observability/traits.rs rename to src-tauri/src/openhuman/observability/traits.rs diff --git a/src-tauri/src/alphahuman/observability/verbose.rs b/src-tauri/src/openhuman/observability/verbose.rs similarity index 100% rename from src-tauri/src/alphahuman/observability/verbose.rs rename to src-tauri/src/openhuman/observability/verbose.rs diff --git a/src-tauri/src/alphahuman/onboard/mod.rs b/src-tauri/src/openhuman/onboard/mod.rs similarity index 90% rename from src-tauri/src/alphahuman/onboard/mod.rs rename to src-tauri/src/openhuman/onboard/mod.rs index b023b999e..d0777b27e 100644 --- a/src-tauri/src/alphahuman/onboard/mod.rs +++ b/src-tauri/src/openhuman/onboard/mod.rs @@ -1,4 +1,4 @@ -//! Onboarding helpers for Alphahuman. +//! Onboarding helpers for OpenHuman. pub mod models; diff --git a/src-tauri/src/alphahuman/onboard/models.rs b/src-tauri/src/openhuman/onboard/models.rs similarity index 99% rename from src-tauri/src/alphahuman/onboard/models.rs rename to src-tauri/src/openhuman/onboard/models.rs index 09ef25873..3c509ed6c 100644 --- a/src-tauri/src/alphahuman/onboard/models.rs +++ b/src-tauri/src/openhuman/onboard/models.rs @@ -1,7 +1,7 @@ //! Model catalog refresh and caching utilities. -use crate::alphahuman::config::Config; -use crate::alphahuman::providers::{canonical_china_provider_name, is_qwen_oauth_alias}; +use crate::openhuman::config::Config; +use crate::openhuman::providers::{canonical_china_provider_name, is_qwen_oauth_alias}; use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; use serde_json::Value; diff --git a/src-tauri/src/alphahuman/peripherals/arduino_flash.rs b/src-tauri/src/openhuman/peripherals/arduino_flash.rs similarity index 86% rename from src-tauri/src/alphahuman/peripherals/arduino_flash.rs rename to src-tauri/src/openhuman/peripherals/arduino_flash.rs index 37799efc5..160feb6e7 100644 --- a/src-tauri/src/alphahuman/peripherals/arduino_flash.rs +++ b/src-tauri/src/openhuman/peripherals/arduino_flash.rs @@ -1,4 +1,4 @@ -//! Flash Alphahuman Arduino firmware via arduino-cli. +//! Flash OpenHuman Arduino firmware via arduino-cli. //! //! Ensures arduino-cli is available (installs via brew on macOS if missing), //! installs the AVR core, compiles and uploads the base firmware. @@ -6,11 +6,11 @@ use anyhow::{Context, Result}; use std::process::Command; -/// Alphahuman Arduino Uno base firmware (capabilities, gpio_read, gpio_write). -const FIRMWARE_INO: &str = include_str!("../../firmware/alphahuman-arduino/alphahuman-arduino.ino"); +/// OpenHuman Arduino Uno base firmware (capabilities, gpio_read, gpio_write). +const FIRMWARE_INO: &str = include_str!("../../firmware/openhuman-arduino/openhuman-arduino.ino"); const FQBN: &str = "arduino:avr:uno"; -const SKETCH_NAME: &str = "alphahuman-arduino"; +const SKETCH_NAME: &str = "openhuman-arduino"; /// Check if arduino-cli is available. pub fn arduino_cli_available() -> bool { @@ -85,12 +85,12 @@ fn ensure_avr_core() -> Result<()> { Ok(()) } -/// Flash Alphahuman firmware to Arduino at the given port. +/// Flash OpenHuman firmware to Arduino at the given port. pub fn flash_arduino_firmware(port: &str) -> Result<()> { ensure_arduino_cli()?; ensure_avr_core()?; - let temp_dir = std::env::temp_dir().join(format!("alphahuman_flash_{}", uuid::Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("openhuman_flash_{}", uuid::Uuid::new_v4())); let sketch_dir = temp_dir.join(SKETCH_NAME); let ino_path = sketch_dir.join(format!("{}.ino", SKETCH_NAME)); @@ -100,7 +100,7 @@ pub fn flash_arduino_firmware(port: &str) -> Result<()> { let sketch_path = sketch_dir.to_string_lossy(); // Compile - println!("Compiling Alphahuman Arduino firmware..."); + println!("Compiling OpenHuman Arduino firmware..."); let compile = Command::new("arduino-cli") .args(["compile", "--fqbn", FQBN, &*sketch_path]) .output() @@ -126,13 +126,13 @@ pub fn flash_arduino_firmware(port: &str) -> Result<()> { anyhow::bail!("Upload failed:\n{}\n\nEnsure the board is connected and the port is correct (e.g. /dev/cu.usbmodem* on macOS).", stderr); } - println!("Alphahuman firmware flashed successfully."); + println!("OpenHuman firmware flashed successfully."); println!("The Arduino now supports: capabilities, gpio_read, gpio_write."); Ok(()) } /// Resolve port from config or path. Returns the path to use for flashing. -pub fn resolve_port(config: &crate::alphahuman::config::Config, path_override: Option<&str>) -> Option { +pub fn resolve_port(config: &crate::openhuman::config::Config, path_override: Option<&str>) -> Option { if let Some(p) = path_override { return Some(p.to_string()); } diff --git a/src-tauri/src/alphahuman/peripherals/arduino_upload.rs b/src-tauri/src/openhuman/peripherals/arduino_upload.rs similarity index 94% rename from src-tauri/src/alphahuman/peripherals/arduino_upload.rs rename to src-tauri/src/openhuman/peripherals/arduino_upload.rs index 88480e909..eb2cfd05d 100644 --- a/src-tauri/src/alphahuman/peripherals/arduino_upload.rs +++ b/src-tauri/src/openhuman/peripherals/arduino_upload.rs @@ -1,10 +1,10 @@ //! Arduino upload tool — agent generates code, uploads via arduino-cli. //! //! When user says "make a heart on the LED grid", the agent generates Arduino -//! sketch code and calls this tool. Alphahuman compiles and uploads it — no +//! sketch code and calls this tool. OpenHuman compiles and uploads it — no //! manual IDE or file editing. -use crate::alphahuman::tools::traits::{Tool, ToolResult}; +use crate::openhuman::tools::traits::{Tool, ToolResult}; use async_trait::async_trait; use serde_json::{json, Value}; use std::process::Command; @@ -70,8 +70,8 @@ impl Tool for ArduinoUploadTool { }); } - let sketch_name = "alphahuman_sketch"; - let temp_dir = std::env::temp_dir().join(format!("alphahuman_{}", uuid::Uuid::new_v4())); + let sketch_name = "openhuman_sketch"; + let temp_dir = std::env::temp_dir().join(format!("openhuman_{}", uuid::Uuid::new_v4())); let sketch_dir = temp_dir.join(sketch_name); let ino_path = sketch_dir.join(format!("{}.ino", sketch_name)); diff --git a/src-tauri/src/alphahuman/peripherals/capabilities_tool.rs b/src-tauri/src/openhuman/peripherals/capabilities_tool.rs similarity index 98% rename from src-tauri/src/alphahuman/peripherals/capabilities_tool.rs rename to src-tauri/src/openhuman/peripherals/capabilities_tool.rs index bce964688..44f975578 100644 --- a/src-tauri/src/alphahuman/peripherals/capabilities_tool.rs +++ b/src-tauri/src/openhuman/peripherals/capabilities_tool.rs @@ -1,7 +1,7 @@ //! Hardware capabilities tool — Phase C: query device for reported GPIO pins. use super::serial::SerialTransport; -use crate::alphahuman::tools::traits::{Tool, ToolResult}; +use crate::openhuman::tools::traits::{Tool, ToolResult}; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; diff --git a/src-tauri/src/alphahuman/peripherals/mod.rs b/src-tauri/src/openhuman/peripherals/mod.rs similarity index 93% rename from src-tauri/src/alphahuman/peripherals/mod.rs rename to src-tauri/src/openhuman/peripherals/mod.rs index 1a190bd49..f14a42989 100644 --- a/src-tauri/src/alphahuman/peripherals/mod.rs +++ b/src-tauri/src/openhuman/peripherals/mod.rs @@ -26,10 +26,10 @@ pub mod rpi; pub use traits::Peripheral; -use crate::alphahuman::config::{PeripheralBoardConfig, PeripheralsConfig}; +use crate::openhuman::config::{PeripheralBoardConfig, PeripheralsConfig}; #[cfg(feature = "hardware")] -use crate::alphahuman::tools::HardwareMemoryMapTool; -use crate::alphahuman::tools::Tool; +use crate::openhuman::tools::HardwareMemoryMapTool; +use crate::openhuman::tools::Tool; use anyhow::Result; /// List configured boards from config (no connection yet). @@ -115,10 +115,10 @@ pub async fn create_peripheral_tools(config: &PeripheralsConfig) -> Result = config.boards.iter().map(|b| b.board.clone()).collect(); tools.push(Box::new(HardwareMemoryMapTool::new(board_names.clone()))); - tools.push(Box::new(crate::alphahuman::tools::HardwareBoardInfoTool::new( + tools.push(Box::new(crate::openhuman::tools::HardwareBoardInfoTool::new( board_names.clone(), ))); - tools.push(Box::new(crate::alphahuman::tools::HardwareMemoryReadTool::new( + tools.push(Box::new(crate::openhuman::tools::HardwareMemoryReadTool::new( board_names, ))); } diff --git a/src-tauri/src/alphahuman/peripherals/nucleo_flash.rs b/src-tauri/src/openhuman/peripherals/nucleo_flash.rs similarity index 82% rename from src-tauri/src/alphahuman/peripherals/nucleo_flash.rs rename to src-tauri/src/openhuman/peripherals/nucleo_flash.rs index d4e5755f4..51923c297 100644 --- a/src-tauri/src/alphahuman/peripherals/nucleo_flash.rs +++ b/src-tauri/src/openhuman/peripherals/nucleo_flash.rs @@ -1,4 +1,4 @@ -//! Flash Alphahuman Nucleo-F401RE firmware via probe-rs. +//! Flash OpenHuman Nucleo-F401RE firmware via probe-rs. //! //! Builds the Embassy firmware and flashes via ST-Link (built into Nucleo). //! Requires: cargo install probe-rs-tools --locked @@ -19,7 +19,7 @@ pub fn probe_rs_available() -> bool { .unwrap_or(false) } -/// Flash Alphahuman Nucleo firmware. Builds from firmware/alphahuman-nucleo. +/// Flash OpenHuman Nucleo firmware. Builds from firmware/openhuman-nucleo. pub fn flash_nucleo_firmware() -> Result<()> { if !probe_rs_available() { anyhow::bail!( @@ -29,17 +29,17 @@ pub fn flash_nucleo_firmware() -> Result<()> { ); } - // CARGO_MANIFEST_DIR = repo root (alphahuman's Cargo.toml) + // CARGO_MANIFEST_DIR = repo root (openhuman's Cargo.toml) let repo_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let firmware_dir = repo_root.join("firmware").join("alphahuman-nucleo"); + let firmware_dir = repo_root.join("firmware").join("openhuman-nucleo"); if !firmware_dir.join("Cargo.toml").exists() { anyhow::bail!( - "Nucleo firmware not found at {}. Run from alphahuman repo root.", + "Nucleo firmware not found at {}. Run from openhuman repo root.", firmware_dir.display() ); } - println!("Building Alphahuman Nucleo firmware..."); + println!("Building OpenHuman Nucleo firmware..."); let build = Command::new("cargo") .args(["build", "--release", "--target", TARGET]) .current_dir(&firmware_dir) @@ -55,7 +55,7 @@ pub fn flash_nucleo_firmware() -> Result<()> { .join("target") .join(TARGET) .join("release") - .join("alphahuman-nucleo"); + .join("openhuman-nucleo"); if !elf_path.exists() { anyhow::bail!("Built binary not found at {}", elf_path.display()); @@ -76,7 +76,7 @@ pub fn flash_nucleo_firmware() -> Result<()> { ); } - println!("Alphahuman Nucleo firmware flashed successfully."); + println!("OpenHuman Nucleo firmware flashed successfully."); println!("The Nucleo now supports: ping, capabilities, gpio_read, gpio_write."); println!("Add to config.toml: board = \"nucleo-f401re\", transport = \"serial\", path = \"/dev/ttyACM0\""); Ok(()) diff --git a/src-tauri/src/alphahuman/peripherals/rpi.rs b/src-tauri/src/openhuman/peripherals/rpi.rs similarity index 96% rename from src-tauri/src/alphahuman/peripherals/rpi.rs rename to src-tauri/src/openhuman/peripherals/rpi.rs index 8504a3b78..a931089dd 100644 --- a/src-tauri/src/alphahuman/peripherals/rpi.rs +++ b/src-tauri/src/openhuman/peripherals/rpi.rs @@ -3,9 +3,9 @@ //! Only compiled when `peripheral-rpi` feature is enabled and target is Linux. //! Uses BCM pin numbering (e.g. GPIO 17, 27). -use crate::alphahuman::config::PeripheralBoardConfig; -use crate::alphahuman::peripherals::traits::Peripheral; -use crate::alphahuman::tools::{Tool, ToolResult}; +use crate::openhuman::config::PeripheralBoardConfig; +use crate::openhuman::peripherals::traits::Peripheral; +use crate::openhuman::tools::{Tool, ToolResult}; use async_trait::async_trait; use serde_json::{json, Value}; diff --git a/src-tauri/src/alphahuman/peripherals/serial.rs b/src-tauri/src/openhuman/peripherals/serial.rs similarity index 98% rename from src-tauri/src/alphahuman/peripherals/serial.rs rename to src-tauri/src/openhuman/peripherals/serial.rs index 21f712f4a..ad62b9782 100644 --- a/src-tauri/src/alphahuman/peripherals/serial.rs +++ b/src-tauri/src/openhuman/peripherals/serial.rs @@ -5,8 +5,8 @@ //! Response: {"id":"1","ok":true,"result":"done"} use super::traits::Peripheral; -use crate::alphahuman::config::PeripheralBoardConfig; -use crate::alphahuman::tools::traits::{Tool, ToolResult}; +use crate::openhuman::config::PeripheralBoardConfig; +use crate::openhuman::tools::traits::{Tool, ToolResult}; use async_trait::async_trait; use serde_json::{json, Value}; use std::sync::atomic::{AtomicU64, Ordering}; diff --git a/src-tauri/src/alphahuman/peripherals/traits.rs b/src-tauri/src/openhuman/peripherals/traits.rs similarity index 97% rename from src-tauri/src/alphahuman/peripherals/traits.rs rename to src-tauri/src/openhuman/peripherals/traits.rs index 050908a87..9bf829b1f 100644 --- a/src-tauri/src/alphahuman/peripherals/traits.rs +++ b/src-tauri/src/openhuman/peripherals/traits.rs @@ -5,7 +5,7 @@ use async_trait::async_trait; -use crate::alphahuman::tools::Tool; +use crate::openhuman::tools::Tool; /// A hardware peripheral that exposes capabilities as tools. /// diff --git a/src-tauri/src/alphahuman/peripherals/uno_q_bridge.rs b/src-tauri/src/openhuman/peripherals/uno_q_bridge.rs similarity index 95% rename from src-tauri/src/alphahuman/peripherals/uno_q_bridge.rs rename to src-tauri/src/openhuman/peripherals/uno_q_bridge.rs index 2530ea176..52515fb43 100644 --- a/src-tauri/src/alphahuman/peripherals/uno_q_bridge.rs +++ b/src-tauri/src/openhuman/peripherals/uno_q_bridge.rs @@ -1,9 +1,9 @@ //! Arduino Uno Q Bridge — GPIO via socket to Bridge app. //! -//! When Alphahuman runs on Uno Q, the Bridge app (Python + MCU) exposes +//! When OpenHuman runs on Uno Q, the Bridge app (Python + MCU) exposes //! digitalWrite/digitalRead over a local socket. These tools connect to it. -use crate::alphahuman::tools::traits::{Tool, ToolResult}; +use crate::openhuman::tools::traits::{Tool, ToolResult}; use async_trait::async_trait; use serde_json::{json, Value}; use std::time::Duration; @@ -40,7 +40,7 @@ impl Tool for UnoQGpioReadTool { } fn description(&self) -> &str { - "Read GPIO pin value (0 or 1) on Arduino Uno Q. Requires alphahuman-uno-q-bridge app running." + "Read GPIO pin value (0 or 1) on Arduino Uno Q. Requires openhuman-uno-q-bridge app running." } fn parameters_schema(&self) -> Value { @@ -96,7 +96,7 @@ impl Tool for UnoQGpioWriteTool { } fn description(&self) -> &str { - "Set GPIO pin high (1) or low (0) on Arduino Uno Q. Requires alphahuman-uno-q-bridge app running." + "Set GPIO pin high (1) or low (0) on Arduino Uno Q. Requires openhuman-uno-q-bridge app running." } fn parameters_schema(&self) -> Value { diff --git a/src-tauri/src/alphahuman/peripherals/uno_q_setup.rs b/src-tauri/src/openhuman/peripherals/uno_q_setup.rs similarity index 82% rename from src-tauri/src/alphahuman/peripherals/uno_q_setup.rs rename to src-tauri/src/openhuman/peripherals/uno_q_setup.rs index 8b1791e76..028ce339b 100644 --- a/src-tauri/src/alphahuman/peripherals/uno_q_setup.rs +++ b/src-tauri/src/openhuman/peripherals/uno_q_setup.rs @@ -1,23 +1,23 @@ -//! Deploy Alphahuman Bridge app to Arduino Uno Q. +//! Deploy OpenHuman Bridge app to Arduino Uno Q. use anyhow::{Context, Result}; use std::process::Command; -const BRIDGE_APP_NAME: &str = "alphahuman-uno-q-bridge"; +const BRIDGE_APP_NAME: &str = "openhuman-uno-q-bridge"; /// Deploy the Bridge app. If host is Some, scp from repo and ssh to start. /// If host is None, assume we're ON the Uno Q — use embedded files and start. pub fn setup_uno_q_bridge(host: Option<&str>) -> Result<()> { let bridge_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) .join("firmware") - .join("alphahuman-uno-q-bridge"); + .join("openhuman-uno-q-bridge"); if let Some(h) = host { if bridge_dir.exists() { deploy_remote(h, &bridge_dir)?; } else { anyhow::bail!( - "Bridge app not found at {}. Run from alphahuman repo root.", + "Bridge app not found at {}. Run from openhuman repo root.", bridge_dir.display() ); } @@ -66,7 +66,7 @@ fn deploy_remote(host: &str, bridge_dir: &std::path::Path) -> Result<()> { "arduino-app-cli", "app", "start", - "~/ArduinoApps/alphahuman-uno-q-bridge", + "~/ArduinoApps/openhuman-uno-q-bridge", ]) .status() .context("arduino-app-cli start failed")?; @@ -74,7 +74,7 @@ fn deploy_remote(host: &str, bridge_dir: &std::path::Path) -> Result<()> { anyhow::bail!("Failed to start Bridge app. Ensure arduino-app-cli is installed on Uno Q."); } - println!("Alphahuman Bridge app started. Add to config.toml:"); + println!("OpenHuman Bridge app started. Add to config.toml:"); println!(" [[peripherals.boards]]"); println!(" board = \"arduino-uno-q\""); println!(" transport = \"bridge\""); @@ -105,16 +105,16 @@ fn deploy_local(bridge_dir: Option<&std::path::Path>) -> Result<()> { anyhow::bail!("Failed to start Bridge app. Ensure arduino-app-cli is installed on Uno Q."); } - println!("Alphahuman Bridge app started."); + println!("OpenHuman Bridge app started."); Ok(()) } fn write_embedded_bridge(dest: &std::path::Path) -> Result<()> { - let app_yaml = include_str!("../../firmware/alphahuman-uno-q-bridge/app.yaml"); - let sketch_ino = include_str!("../../firmware/alphahuman-uno-q-bridge/sketch/sketch.ino"); - let sketch_yaml = include_str!("../../firmware/alphahuman-uno-q-bridge/sketch/sketch.yaml"); - let main_py = include_str!("../../firmware/alphahuman-uno-q-bridge/python/main.py"); - let requirements = include_str!("../../firmware/alphahuman-uno-q-bridge/python/requirements.txt"); + let app_yaml = include_str!("../../firmware/openhuman-uno-q-bridge/app.yaml"); + let sketch_ino = include_str!("../../firmware/openhuman-uno-q-bridge/sketch/sketch.ino"); + let sketch_yaml = include_str!("../../firmware/openhuman-uno-q-bridge/sketch/sketch.yaml"); + let main_py = include_str!("../../firmware/openhuman-uno-q-bridge/python/main.py"); + let requirements = include_str!("../../firmware/openhuman-uno-q-bridge/python/requirements.txt"); std::fs::write(dest.join("app.yaml"), app_yaml)?; std::fs::create_dir_all(dest.join("sketch"))?; diff --git a/src-tauri/src/alphahuman/providers/anthropic.rs b/src-tauri/src/openhuman/providers/anthropic.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/anthropic.rs rename to src-tauri/src/openhuman/providers/anthropic.rs index a70ed60d5..f111c2973 100644 --- a/src-tauri/src/alphahuman/providers/anthropic.rs +++ b/src-tauri/src/openhuman/providers/anthropic.rs @@ -1,8 +1,8 @@ -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, ToolCall as ProviderToolCall, }; -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -400,7 +400,7 @@ impl AnthropicProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.anthropic", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.anthropic", 120, 10) } } @@ -645,7 +645,7 @@ mod tests { async fn chat_with_system_fails_without_key() { let p = AnthropicProvider::new(None); let result = p - .chat_with_system(Some("You are Alphahuman"), "hello", "claude-3-opus", 0.7) + .chat_with_system(Some("You are OpenHuman"), "hello", "claude-3-opus", 0.7) .await; assert!(result.is_err()); } @@ -676,7 +676,7 @@ mod tests { let req = ChatRequest { model: "claude-3-opus".to_string(), max_tokens: 4096, - system: Some("You are Alphahuman".to_string()), + system: Some("You are OpenHuman".to_string()), messages: vec![Message { role: "user".to_string(), content: "hello".to_string(), @@ -684,7 +684,7 @@ mod tests { temperature: 0.7, }; let json = serde_json::to_string(&req).unwrap(); - assert!(json.contains("\"system\":\"You are Alphahuman\"")); + assert!(json.contains("\"system\":\"You are OpenHuman\"")); } #[test] diff --git a/src-tauri/src/alphahuman/providers/bedrock.rs b/src-tauri/src/openhuman/providers/bedrock.rs similarity index 99% rename from src-tauri/src/alphahuman/providers/bedrock.rs rename to src-tauri/src/openhuman/providers/bedrock.rs index 97cf8e818..cd5241ce7 100644 --- a/src-tauri/src/alphahuman/providers/bedrock.rs +++ b/src-tauri/src/openhuman/providers/bedrock.rs @@ -4,11 +4,11 @@ //! via environment variables. SigV4 signing is implemented manually //! using hmac/sha2 crates — no AWS SDK dependency. -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, ProviderCapabilities, ToolCall as ProviderToolCall, ToolsPayload, }; -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use hmac::{Hmac, Mac}; use reqwest::Client; @@ -349,7 +349,7 @@ impl BedrockProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.bedrock", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.bedrock", 120, 10) } /// Percent-encode the model ID for URL path: only encode `:` to `%3A`. @@ -775,7 +775,7 @@ impl Provider for BedrockProvider { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::providers::traits::ChatMessage; + use crate::openhuman::providers::traits::ChatMessage; // ── SigV4 signing tests ───────────────────────────────────── diff --git a/src-tauri/src/alphahuman/providers/compatible.rs b/src-tauri/src/openhuman/providers/compatible.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/compatible.rs rename to src-tauri/src/openhuman/providers/compatible.rs index ed3414e2b..1944f2ee8 100644 --- a/src-tauri/src/alphahuman/providers/compatible.rs +++ b/src-tauri/src/openhuman/providers/compatible.rs @@ -2,7 +2,7 @@ //! Most LLM APIs follow the same `/v1/chat/completions` format. //! This module provides a single implementation that works for all of them. -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, StreamChunk, StreamError, StreamOptions, StreamResult, ToolCall as ProviderToolCall, }; @@ -160,7 +160,7 @@ impl OpenAiCompatibleProvider { .connect_timeout(std::time::Duration::from_secs(10)) .default_headers(headers); let builder = - crate::alphahuman::config::apply_runtime_proxy_to_builder(builder, "provider.compatible"); + crate::openhuman::config::apply_runtime_proxy_to_builder(builder, "provider.compatible"); return builder.build().unwrap_or_else(|error| { tracing::warn!("Failed to build proxied timeout client with user-agent: {error}"); @@ -168,7 +168,7 @@ impl OpenAiCompatibleProvider { }); } - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.compatible", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.compatible", 120, 10) } /// Build the full URL for chat completions, detecting if base_url already includes the path. @@ -233,7 +233,7 @@ impl OpenAiCompatibleProvider { } } - fn tool_specs_to_openai_format(tools: &[crate::alphahuman::tools::ToolSpec]) -> Vec { + fn tool_specs_to_openai_format(tools: &[crate::openhuman::tools::ToolSpec]) -> Vec { tools .iter() .map(|tool| { @@ -730,7 +730,7 @@ impl OpenAiCompatibleProvider { } fn convert_tool_specs( - tools: Option<&[crate::alphahuman::tools::ToolSpec]>, + tools: Option<&[crate::openhuman::tools::ToolSpec]>, ) -> Option> { tools.map(|items| { items @@ -823,7 +823,7 @@ impl OpenAiCompatibleProvider { fn with_prompt_guided_tool_instructions( messages: &[ChatMessage], - tools: Option<&[crate::alphahuman::tools::ToolSpec]>, + tools: Option<&[crate::openhuman::tools::ToolSpec]>, ) -> Vec { let Some(tools) = tools else { return messages.to_vec(); @@ -833,7 +833,7 @@ impl OpenAiCompatibleProvider { return messages.to_vec(); } - let instructions = crate::alphahuman::providers::traits::build_tool_instructions_text(tools); + let instructions = crate::openhuman::providers::traits::build_tool_instructions_text(tools); let mut modified_messages = messages.to_vec(); if let Some(system_message) = modified_messages.iter_mut().find(|m| m.role == "system") { @@ -895,8 +895,8 @@ impl OpenAiCompatibleProvider { #[async_trait] impl Provider for OpenAiCompatibleProvider { - fn capabilities(&self) -> crate::alphahuman::providers::traits::ProviderCapabilities { - crate::alphahuman::providers::traits::ProviderCapabilities { + fn capabilities(&self) -> crate::openhuman::providers::traits::ProviderCapabilities { + crate::openhuman::providers::traits::ProviderCapabilities { native_tool_calling: true, vision: false, } @@ -1520,7 +1520,7 @@ mod tests { messages: vec![ Message { role: "system".to_string(), - content: "You are Alphahuman".to_string(), + content: "You are OpenHuman".to_string(), }, Message { role: "user".to_string(), @@ -1980,7 +1980,7 @@ mod tests { #[test] fn prompt_guided_tool_fallback_injects_system_instruction() { let input = vec![ChatMessage::user("check status")]; - let tools = vec![crate::alphahuman::tools::ToolSpec { + let tools = vec![crate::openhuman::tools::ToolSpec { name: "shell_exec".to_string(), description: "Execute shell command".to_string(), parameters: serde_json::json!({ @@ -2020,7 +2020,7 @@ mod tests { #[test] fn tool_specs_convert_to_openai_format() { - let specs = vec![crate::alphahuman::tools::ToolSpec { + let specs = vec![crate::openhuman::tools::ToolSpec { name: "shell".to_string(), description: "Run shell command".to_string(), parameters: serde_json::json!({ diff --git a/src-tauri/src/alphahuman/providers/copilot.rs b/src-tauri/src/openhuman/providers/copilot.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/copilot.rs rename to src-tauri/src/openhuman/providers/copilot.rs index 1c8a074f5..f98a65e2a 100644 --- a/src-tauri/src/alphahuman/providers/copilot.rs +++ b/src-tauri/src/openhuman/providers/copilot.rs @@ -11,11 +11,11 @@ //! GitHub could change or revoke this at any time, which would break all //! third-party integrations simultaneously. -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, ToolCall as ProviderToolCall, }; -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -154,7 +154,7 @@ struct ResponseMessage { /// GitHub Copilot provider with automatic OAuth and token refresh. /// /// On first use, prompts the user to visit github.com/login/device. -/// Tokens are cached to `~/.config/alphahuman/copilot/` and refreshed +/// Tokens are cached to `~/.config/openhuman/copilot/` and refreshed /// automatically. pub struct CopilotProvider { github_token: Option, @@ -166,7 +166,7 @@ pub struct CopilotProvider { impl CopilotProvider { pub fn new(github_token: Option<&str>) -> Self { - let token_dir = directories::ProjectDirs::from("", "", "alphahuman") + let token_dir = directories::ProjectDirs::from("", "", "openhuman") .map(|dir| dir.config_dir().join("copilot")) .unwrap_or_else(|| { // Fall back to a user-specific temp directory to avoid @@ -174,7 +174,7 @@ impl CopilotProvider { let user = std::env::var("USER") .or_else(|_| std::env::var("USERNAME")) .unwrap_or_else(|_| "unknown".to_string()); - std::env::temp_dir().join(format!("alphahuman-copilot-{user}")) + std::env::temp_dir().join(format!("openhuman-copilot-{user}")) }); if let Err(err) = std::fs::create_dir_all(&token_dir) { @@ -208,7 +208,7 @@ impl CopilotProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.copilot", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.copilot", 120, 10) } /// Required headers for Copilot API requests (editor identification). diff --git a/src-tauri/src/alphahuman/providers/gemini.rs b/src-tauri/src/openhuman/providers/gemini.rs similarity index 99% rename from src-tauri/src/alphahuman/providers/gemini.rs rename to src-tauri/src/openhuman/providers/gemini.rs index 3ea957a80..5486c2e1f 100644 --- a/src-tauri/src/alphahuman/providers/gemini.rs +++ b/src-tauri/src/openhuman/providers/gemini.rs @@ -3,7 +3,7 @@ //! - Gemini app OAuth tokens (reuse existing ~/.gemini/ authentication) //! - Google Cloud ADC (`GOOGLE_APPLICATION_CREDENTIALS`) -use crate::alphahuman::providers::traits::{ChatMessage, Provider}; +use crate::openhuman::providers::traits::{ChatMessage, Provider}; use async_trait::async_trait; use directories::UserDirs; use reqwest::Client; @@ -276,7 +276,7 @@ impl GeminiProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.gemini", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.gemini", 120, 10) } fn build_generate_content_request( diff --git a/src-tauri/src/alphahuman/providers/glm.rs b/src-tauri/src/openhuman/providers/glm.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/glm.rs rename to src-tauri/src/openhuman/providers/glm.rs index 5e74ae78a..1b5a09bab 100644 --- a/src-tauri/src/alphahuman/providers/glm.rs +++ b/src-tauri/src/openhuman/providers/glm.rs @@ -2,7 +2,7 @@ //! The GLM API requires JWT tokens generated from the `id.secret` API key format //! with a custom `sign_type: "SIGN"` header, and uses `/v4/chat/completions`. -use crate::alphahuman::providers::traits::{ChatMessage, Provider}; +use crate::openhuman::providers::traits::{ChatMessage, Provider}; use async_trait::async_trait; use reqwest::Client; use ring::hmac; @@ -145,7 +145,7 @@ impl GlmProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.glm", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.glm", 120, 10) } } diff --git a/src-tauri/src/alphahuman/providers/mod.rs b/src-tauri/src/openhuman/providers/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/mod.rs rename to src-tauri/src/openhuman/providers/mod.rs index 27fa98dda..2bcb94efd 100644 --- a/src-tauri/src/alphahuman/providers/mod.rs +++ b/src-tauri/src/openhuman/providers/mod.rs @@ -628,7 +628,7 @@ fn zai_base_url(name: &str) -> Option<&'static str> { #[derive(Debug, Clone)] pub struct ProviderRuntimeOptions { pub auth_profile_override: Option, - pub alphahuman_dir: Option, + pub openhuman_dir: Option, pub secrets_encrypt: bool, pub reasoning_enabled: Option, } @@ -637,7 +637,7 @@ impl Default for ProviderRuntimeOptions { fn default() -> Self { Self { auth_profile_override: None, - alphahuman_dir: None, + openhuman_dir: None, secrets_encrypt: true, reasoning_enabled: None, } @@ -734,7 +734,7 @@ pub async fn api_error(provider: &str, response: reqwest::Response) -> anyhow::E /// Resolution order: /// 1. Explicitly provided `api_key` parameter (trimmed, filtered if empty) /// 2. Provider-specific environment variable (e.g., `ANTHROPIC_OAUTH_TOKEN`, `OPENROUTER_API_KEY`) -/// 3. Generic fallback variables (`ALPHAHUMAN_API_KEY`, `API_KEY`) +/// 3. Generic fallback variables (`OPENHUMAN_API_KEY`, `API_KEY`) /// /// For Anthropic, the provider-specific env var is `ANTHROPIC_OAUTH_TOKEN` (for setup-tokens) /// followed by `ANTHROPIC_API_KEY` (for regular API keys). @@ -817,7 +817,7 @@ fn resolve_provider_credential(name: &str, credential_override: Option<&str>) -> return None; } - for env_var in ["ALPHAHUMAN_API_KEY", "API_KEY"] { + for env_var in ["OPENHUMAN_API_KEY", "API_KEY"] { if let Ok(value) = std::env::var(env_var) { let value = value.trim(); if !value.is_empty() { @@ -1100,7 +1100,7 @@ pub fn create_resilient_provider( primary_name: &str, api_key: Option<&str>, api_url: Option<&str>, - reliability: &crate::alphahuman::config::ReliabilityConfig, + reliability: &crate::openhuman::config::ReliabilityConfig, ) -> anyhow::Result> { create_resilient_provider_with_options( primary_name, @@ -1116,7 +1116,7 @@ pub fn create_resilient_provider_with_options( primary_name: &str, api_key: Option<&str>, api_url: Option<&str>, - reliability: &crate::alphahuman::config::ReliabilityConfig, + reliability: &crate::openhuman::config::ReliabilityConfig, options: &ProviderRuntimeOptions, ) -> anyhow::Result> { let mut providers: Vec<(String, Box)> = Vec::new(); @@ -1172,8 +1172,8 @@ pub fn create_routed_provider( primary_name: &str, api_key: Option<&str>, api_url: Option<&str>, - reliability: &crate::alphahuman::config::ReliabilityConfig, - model_routes: &[crate::alphahuman::config::ModelRouteConfig], + reliability: &crate::openhuman::config::ReliabilityConfig, + model_routes: &[crate::openhuman::config::ModelRouteConfig], default_model: &str, ) -> anyhow::Result> { create_routed_provider_with_options( @@ -1192,8 +1192,8 @@ pub fn create_routed_provider_with_options( primary_name: &str, api_key: Option<&str>, api_url: Option<&str>, - reliability: &crate::alphahuman::config::ReliabilityConfig, - model_routes: &[crate::alphahuman::config::ModelRouteConfig], + reliability: &crate::openhuman::config::ReliabilityConfig, + model_routes: &[crate::openhuman::config::ModelRouteConfig], default_model: &str, options: &ProviderRuntimeOptions, ) -> anyhow::Result> { @@ -1591,7 +1591,7 @@ mod tests { #[test] fn resolve_qwen_oauth_context_prefers_explicit_override() { let _env_lock = env_lock(); - let fake_home = format!("/tmp/alphahuman-qwen-oauth-home-{}", std::process::id()); + let fake_home = format!("/tmp/openhuman-qwen-oauth-home-{}", std::process::id()); let _home_guard = EnvGuard::set("HOME", Some(fake_home.as_str())); let _token_guard = EnvGuard::set(QWEN_OAUTH_TOKEN_ENV, Some("oauth-token")); let _resource_guard = EnvGuard::set( @@ -1608,7 +1608,7 @@ mod tests { #[test] fn resolve_qwen_oauth_context_uses_env_token_and_resource_url() { let _env_lock = env_lock(); - let fake_home = format!("/tmp/alphahuman-qwen-oauth-home-{}-env", std::process::id()); + let fake_home = format!("/tmp/openhuman-qwen-oauth-home-{}-env", std::process::id()); let _home_guard = EnvGuard::set("HOME", Some(fake_home.as_str())); let _token_guard = EnvGuard::set(QWEN_OAUTH_TOKEN_ENV, Some("oauth-token")); let _refresh_guard = EnvGuard::set(QWEN_OAUTH_REFRESH_TOKEN_ENV, None); @@ -1630,7 +1630,7 @@ mod tests { #[test] fn resolve_qwen_oauth_context_reads_cached_credentials_file() { let _env_lock = env_lock(); - let fake_home = format!("/tmp/alphahuman-qwen-oauth-home-{}-file", std::process::id()); + let fake_home = format!("/tmp/openhuman-qwen-oauth-home-{}-file", std::process::id()); let creds_dir = PathBuf::from(&fake_home).join(".qwen"); std::fs::create_dir_all(&creds_dir).unwrap(); let creds_path = creds_dir.join("oauth_creds.json"); @@ -1659,7 +1659,7 @@ mod tests { fn resolve_qwen_oauth_context_placeholder_does_not_use_dashscope_fallback() { let _env_lock = env_lock(); let fake_home = format!( - "/tmp/alphahuman-qwen-oauth-home-{}-placeholder", + "/tmp/openhuman-qwen-oauth-home-{}-placeholder", std::process::id() ); let _home_guard = EnvGuard::set("HOME", Some(fake_home.as_str())); @@ -2106,7 +2106,7 @@ mod tests { #[test] fn resilient_provider_ignores_duplicate_and_invalid_fallbacks() { - let reliability = crate::alphahuman::config::ReliabilityConfig { + let reliability = crate::openhuman::config::ReliabilityConfig { provider_retries: 1, provider_backoff_ms: 100, fallback_providers: vec![ @@ -2134,7 +2134,7 @@ mod tests { #[test] fn resilient_provider_errors_for_invalid_primary() { - let reliability = crate::alphahuman::config::ReliabilityConfig::default(); + let reliability = crate::openhuman::config::ReliabilityConfig::default(); let provider = create_resilient_provider( "totally-invalid", Some("provider-test-credential"), @@ -2150,7 +2150,7 @@ mod tests { /// successfully even when the primary uses a completely different key. #[test] fn resilient_fallback_resolves_own_credential() { - let reliability = crate::alphahuman::config::ReliabilityConfig { + let reliability = crate::openhuman::config::ReliabilityConfig { provider_retries: 1, provider_backoff_ms: 100, fallback_providers: vec!["lmstudio".into(), "ollama".into()], @@ -2172,7 +2172,7 @@ mod tests { /// OpenAI-compatible endpoints (e.g. local LM Studio on a Docker host). #[test] fn resilient_fallback_supports_custom_url() { - let reliability = crate::alphahuman::config::ReliabilityConfig { + let reliability = crate::openhuman::config::ReliabilityConfig { provider_retries: 1, provider_backoff_ms: 100, fallback_providers: vec!["custom:http://host.docker.internal:1234/v1".into()], @@ -2193,7 +2193,7 @@ mod tests { /// all coexist. Invalid entries are silently ignored; valid ones initialize. #[test] fn resilient_fallback_mixed_chain() { - let reliability = crate::alphahuman::config::ReliabilityConfig { + let reliability = crate::openhuman::config::ReliabilityConfig { provider_retries: 1, provider_backoff_ms: 100, fallback_providers: vec![ diff --git a/src-tauri/src/alphahuman/providers/ollama.rs b/src-tauri/src/openhuman/providers/ollama.rs similarity index 99% rename from src-tauri/src/alphahuman/providers/ollama.rs rename to src-tauri/src/openhuman/providers/ollama.rs index f9844e6c9..25e2f1552 100644 --- a/src-tauri/src/alphahuman/providers/ollama.rs +++ b/src-tauri/src/openhuman/providers/ollama.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::multimodal; -use crate::alphahuman::providers::traits::{ +use crate::openhuman::multimodal; +use crate::openhuman::providers::traits::{ ChatMessage, ChatResponse, Provider, ProviderCapabilities, ToolCall, }; use async_trait::async_trait; @@ -124,7 +124,7 @@ impl OllamaProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.ollama", 300, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.ollama", 300, 10) } fn resolve_request_details(&self, model: &str) -> anyhow::Result<(String, bool)> { @@ -515,7 +515,7 @@ impl Provider for OllamaProvider { async fn chat_with_history( &self, - messages: &[crate::alphahuman::providers::ChatMessage], + messages: &[crate::openhuman::providers::ChatMessage], model: &str, temperature: f64, ) -> anyhow::Result { diff --git a/src-tauri/src/alphahuman/providers/openai.rs b/src-tauri/src/openhuman/providers/openai.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/openai.rs rename to src-tauri/src/openhuman/providers/openai.rs index 5fb8317be..b5eb2949f 100644 --- a/src-tauri/src/alphahuman/providers/openai.rs +++ b/src-tauri/src/openhuman/providers/openai.rs @@ -1,8 +1,8 @@ -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, ToolCall as ProviderToolCall, }; -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -250,7 +250,7 @@ impl OpenAiProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.openai", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.openai", 120, 10) } } @@ -455,7 +455,7 @@ mod tests { async fn chat_with_system_fails_without_key() { let p = OpenAiProvider::new(None); let result = p - .chat_with_system(Some("You are Alphahuman"), "test", "gpt-4o", 0.5) + .chat_with_system(Some("You are OpenHuman"), "test", "gpt-4o", 0.5) .await; assert!(result.is_err()); } @@ -467,7 +467,7 @@ mod tests { messages: vec![ Message { role: "system".to_string(), - content: "You are Alphahuman".to_string(), + content: "You are OpenHuman".to_string(), }, Message { role: "user".to_string(), diff --git a/src-tauri/src/alphahuman/providers/openai_codex.rs b/src-tauri/src/openhuman/providers/openai_codex.rs similarity index 97% rename from src-tauri/src/alphahuman/providers/openai_codex.rs rename to src-tauri/src/openhuman/providers/openai_codex.rs index 9e8cac9f7..4b5f44f35 100644 --- a/src-tauri/src/alphahuman/providers/openai_codex.rs +++ b/src-tauri/src/openhuman/providers/openai_codex.rs @@ -1,7 +1,7 @@ use crate::auth::openai_oauth::extract_account_id_from_jwt; use crate::auth::AuthService; -use crate::alphahuman::providers::traits::{ChatMessage, Provider}; -use crate::alphahuman::providers::ProviderRuntimeOptions; +use crate::openhuman::providers::traits::{ChatMessage, Provider}; +use crate::openhuman::providers::ProviderRuntimeOptions; use async_trait::async_trait; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -10,7 +10,7 @@ use std::path::PathBuf; const CODEX_RESPONSES_URL: &str = "https://chatgpt.com/backend-api/codex/responses"; const DEFAULT_CODEX_INSTRUCTIONS: &str = - "You are Alphahuman, a concise and helpful coding assistant."; + "You are OpenHuman, a concise and helpful coding assistant."; pub struct OpenAiCodexProvider { auth: AuthService, @@ -80,9 +80,9 @@ struct ResponsesContent { impl OpenAiCodexProvider { pub fn new(options: &ProviderRuntimeOptions) -> Self { let state_dir = options - .alphahuman_dir + .openhuman_dir .clone() - .unwrap_or_else(default_alphahuman_dir); + .unwrap_or_else(default_openhuman_dir); let auth = AuthService::new(&state_dir, options.secrets_encrypt); Self { @@ -97,10 +97,10 @@ impl OpenAiCodexProvider { } } -fn default_alphahuman_dir() -> PathBuf { +fn default_openhuman_dir() -> PathBuf { directories::UserDirs::new().map_or_else( - || PathBuf::from(".alphahuman"), - |dirs| dirs.home_dir().join(".alphahuman"), + || PathBuf::from(".openhuman"), + |dirs| dirs.home_dir().join(".openhuman"), ) } @@ -180,7 +180,7 @@ fn clamp_reasoning_effort(model: &str, effort: &str) -> String { } fn resolve_reasoning_effort(model_id: &str) -> String { - let raw = std::env::var("ALPHAHUMAN_CODEX_REASONING_EFFORT") + let raw = std::env::var("OPENHUMAN_CODEX_REASONING_EFFORT") .ok() .and_then(|value| first_nonempty(Some(&value))) .unwrap_or_else(|| "xhigh".to_string()) @@ -502,7 +502,7 @@ mod tests { #[test] fn default_state_dir_is_non_empty() { - let path = default_alphahuman_dir(); + let path = default_openhuman_dir(); assert!(!path.as_os_str().is_empty()); } diff --git a/src-tauri/src/alphahuman/providers/openrouter.rs b/src-tauri/src/openhuman/providers/openrouter.rs similarity index 97% rename from src-tauri/src/alphahuman/providers/openrouter.rs rename to src-tauri/src/openhuman/providers/openrouter.rs index 41022cb6d..c2b0b0768 100644 --- a/src-tauri/src/alphahuman/providers/openrouter.rs +++ b/src-tauri/src/openhuman/providers/openrouter.rs @@ -1,8 +1,8 @@ -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, ToolCall as ProviderToolCall, }; -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -221,7 +221,7 @@ impl OpenRouterProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.openrouter", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.openrouter", 120, 10) } } @@ -277,9 +277,9 @@ impl Provider for OpenRouterProvider { .header("Authorization", format!("Bearer {credential}")) .header( "HTTP-Referer", - "https://github.com/theonlyhennygod/alphahuman", + "https://github.com/theonlyhennygod/openhuman", ) - .header("X-Title", "Alphahuman") + .header("X-Title", "OpenHuman") .json(&request) .send() .await?; @@ -327,9 +327,9 @@ impl Provider for OpenRouterProvider { .header("Authorization", format!("Bearer {credential}")) .header( "HTTP-Referer", - "https://github.com/theonlyhennygod/alphahuman", + "https://github.com/theonlyhennygod/openhuman", ) - .header("X-Title", "Alphahuman") + .header("X-Title", "OpenHuman") .json(&request) .send() .await?; @@ -375,9 +375,9 @@ impl Provider for OpenRouterProvider { .header("Authorization", format!("Bearer {credential}")) .header( "HTTP-Referer", - "https://github.com/theonlyhennygod/alphahuman", + "https://github.com/theonlyhennygod/openhuman", ) - .header("X-Title", "Alphahuman") + .header("X-Title", "OpenHuman") .json(&native_request) .send() .await?; @@ -463,9 +463,9 @@ impl Provider for OpenRouterProvider { .header("Authorization", format!("Bearer {credential}")) .header( "HTTP-Referer", - "https://github.com/theonlyhennygod/alphahuman", + "https://github.com/theonlyhennygod/openhuman", ) - .header("X-Title", "Alphahuman") + .header("X-Title", "OpenHuman") .json(&native_request) .send() .await?; @@ -488,7 +488,7 @@ impl Provider for OpenRouterProvider { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::providers::traits::{ChatMessage, Provider}; + use crate::openhuman::providers::traits::{ChatMessage, Provider}; #[test] fn creates_with_key() { diff --git a/src-tauri/src/alphahuman/providers/reliable.rs b/src-tauri/src/openhuman/providers/reliable.rs similarity index 100% rename from src-tauri/src/alphahuman/providers/reliable.rs rename to src-tauri/src/openhuman/providers/reliable.rs diff --git a/src-tauri/src/alphahuman/providers/router.rs b/src-tauri/src/openhuman/providers/router.rs similarity index 100% rename from src-tauri/src/alphahuman/providers/router.rs rename to src-tauri/src/openhuman/providers/router.rs diff --git a/src-tauri/src/alphahuman/providers/traits.rs b/src-tauri/src/openhuman/providers/traits.rs similarity index 99% rename from src-tauri/src/alphahuman/providers/traits.rs rename to src-tauri/src/openhuman/providers/traits.rs index 7db7188d2..604f31410 100644 --- a/src-tauri/src/alphahuman/providers/traits.rs +++ b/src-tauri/src/openhuman/providers/traits.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use futures_util::{stream, StreamExt}; use serde::{Deserialize, Serialize}; @@ -239,7 +239,7 @@ pub enum ToolsPayload { fn should_log_prompts() -> bool { matches!( - std::env::var("ALPHAHUMAN_LOG_PROMPTS") + std::env::var("OPENHUMAN_LOG_PROMPTS") .ok() .as_deref(), Some("1") | Some("true") | Some("TRUE") | Some("yes") | Some("YES") diff --git a/src-tauri/src/alphahuman/rag/mod.rs b/src-tauri/src/openhuman/rag/mod.rs similarity index 99% rename from src-tauri/src/alphahuman/rag/mod.rs rename to src-tauri/src/openhuman/rag/mod.rs index b393f6ea1..5eba423e7 100644 --- a/src-tauri/src/alphahuman/rag/mod.rs +++ b/src-tauri/src/openhuman/rag/mod.rs @@ -6,7 +6,7 @@ //! - Pin/alias tables (e.g. `red_led: 13`) for explicit lookup //! - Keyword retrieval (default) or semantic search via embeddings (optional) -use crate::alphahuman::memory::chunker; +use crate::openhuman::memory::chunker; use std::collections::HashMap; use std::path::Path; diff --git a/src-tauri/src/alphahuman/runtime/docker.rs b/src-tauri/src/openhuman/runtime/docker.rs similarity index 98% rename from src-tauri/src/alphahuman/runtime/docker.rs rename to src-tauri/src/openhuman/runtime/docker.rs index e86457c41..2911594e1 100644 --- a/src-tauri/src/alphahuman/runtime/docker.rs +++ b/src-tauri/src/openhuman/runtime/docker.rs @@ -1,5 +1,5 @@ use super::traits::RuntimeAdapter; -use crate::alphahuman::config::DockerRuntimeConfig; +use crate::openhuman::config::DockerRuntimeConfig; use anyhow::{Context, Result}; use std::path::{Path, PathBuf}; @@ -67,9 +67,9 @@ impl RuntimeAdapter for DockerRuntime { fn storage_path(&self) -> PathBuf { if self.config.mount_workspace { - PathBuf::from("/workspace/.alphahuman") + PathBuf::from("/workspace/.openhuman") } else { - PathBuf::from("/tmp/.alphahuman") + PathBuf::from("/tmp/.openhuman") } } diff --git a/src-tauri/src/alphahuman/runtime/mod.rs b/src-tauri/src/openhuman/runtime/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/runtime/mod.rs rename to src-tauri/src/openhuman/runtime/mod.rs index c7ddd7b92..580f5267d 100644 --- a/src-tauri/src/alphahuman/runtime/mod.rs +++ b/src-tauri/src/openhuman/runtime/mod.rs @@ -6,7 +6,7 @@ pub use docker::DockerRuntime; pub use native::NativeRuntime; pub use traits::RuntimeAdapter; -use crate::alphahuman::config::RuntimeConfig; +use crate::openhuman::config::RuntimeConfig; /// Factory: create the right runtime from config pub fn create_runtime(config: &RuntimeConfig) -> anyhow::Result> { diff --git a/src-tauri/src/alphahuman/runtime/native.rs b/src-tauri/src/openhuman/runtime/native.rs similarity index 90% rename from src-tauri/src/alphahuman/runtime/native.rs rename to src-tauri/src/openhuman/runtime/native.rs index 2f5aea31b..3a6fa213c 100644 --- a/src-tauri/src/alphahuman/runtime/native.rs +++ b/src-tauri/src/openhuman/runtime/native.rs @@ -25,8 +25,8 @@ impl RuntimeAdapter for NativeRuntime { fn storage_path(&self) -> PathBuf { directories::UserDirs::new().map_or_else( - || PathBuf::from(".alphahuman"), - |u| u.home_dir().join(".alphahuman"), + || PathBuf::from(".openhuman"), + |u| u.home_dir().join(".openhuman"), ) } @@ -75,9 +75,9 @@ mod tests { } #[test] - fn native_storage_path_contains_alphahuman() { + fn native_storage_path_contains_openhuman() { let path = NativeRuntime::new().storage_path(); - assert!(path.to_string_lossy().contains("alphahuman")); + assert!(path.to_string_lossy().contains("openhuman")); } #[test] diff --git a/src-tauri/src/alphahuman/runtime/traits.rs b/src-tauri/src/openhuman/runtime/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/runtime/traits.rs rename to src-tauri/src/openhuman/runtime/traits.rs diff --git a/src-tauri/src/alphahuman/runtime/wasm.rs b/src-tauri/src/openhuman/runtime/wasm.rs similarity index 98% rename from src-tauri/src/alphahuman/runtime/wasm.rs rename to src-tauri/src/openhuman/runtime/wasm.rs index 468dad5fc..1363e12ea 100644 --- a/src-tauri/src/alphahuman/runtime/wasm.rs +++ b/src-tauri/src/openhuman/runtime/wasm.rs @@ -9,10 +9,10 @@ //! //! # Feature gate //! This module is only compiled when `--features runtime-wasm` is enabled. -//! The default Alphahuman binary excludes it to maintain the 4.6 MB size target. +//! The default OpenHuman binary excludes it to maintain the 4.6 MB size target. use super::traits::RuntimeAdapter; -use crate::alphahuman::config::WasmRuntimeConfig; +use crate::openhuman::config::WasmRuntimeConfig; use anyhow::{bail, Context, Result}; use std::path::{Path, PathBuf}; @@ -292,7 +292,7 @@ impl RuntimeAdapter for WasmRuntime { fn storage_path(&self) -> PathBuf { self.workspace_dir .as_ref() - .map_or_else(|| PathBuf::from(".alphahuman"), |w| w.join(".alphahuman")) + .map_or_else(|| PathBuf::from(".openhuman"), |w| w.join(".openhuman")) } fn supports_long_running(&self) -> bool { @@ -385,13 +385,13 @@ mod tests { #[test] fn wasm_storage_path_default() { let rt = WasmRuntime::new(default_config()); - assert!(rt.storage_path().to_string_lossy().contains("alphahuman")); + assert!(rt.storage_path().to_string_lossy().contains("openhuman")); } #[test] fn wasm_storage_path_with_workspace() { let rt = WasmRuntime::with_workspace(default_config(), PathBuf::from("/home/user/project")); - assert_eq!(rt.storage_path(), PathBuf::from("/home/user/project/.alphahuman")); + assert_eq!(rt.storage_path(), PathBuf::from("/home/user/project/.openhuman")); } // ── Config validation ────────────────────────────────────── diff --git a/src-tauri/src/alphahuman/security/audit.rs b/src-tauri/src/openhuman/security/audit.rs similarity index 97% rename from src-tauri/src/alphahuman/security/audit.rs rename to src-tauri/src/openhuman/security/audit.rs index 34bbe56ad..1dfcfaa59 100644 --- a/src-tauri/src/alphahuman/security/audit.rs +++ b/src-tauri/src/openhuman/security/audit.rs @@ -1,6 +1,6 @@ //! Audit logging for security events -use crate::alphahuman::config::AuditConfig; +use crate::openhuman::config::AuditConfig; use anyhow::Result; use chrono::{DateTime, Utc}; use parking_lot::Mutex; @@ -164,10 +164,10 @@ pub struct CommandExecutionLog<'a> { impl AuditLogger { /// Create a new audit logger - pub fn new(config: AuditConfig, alphahuman_dir: PathBuf) -> Result { - let log_path = alphahuman_dir.join(&config.log_path); + pub fn new(config: AuditConfig, openhuman_dir: PathBuf) -> Result { + let log_path = openhuman_dir.join(&config.log_path); log::info!( - "[alphahuman:audit] Logger initialized: enabled={}, path={}", + "[openhuman:audit] Logger initialized: enabled={}, path={}", config.enabled, log_path.display() ); @@ -185,7 +185,7 @@ impl AuditLogger { } log::debug!( - "[alphahuman:audit] Logging event: type={:?}, id={}", + "[openhuman:audit] Logging event: type={:?}, id={}", event.event_type, event.event_id ); @@ -258,7 +258,7 @@ impl AuditLogger { /// Rotate the log file fn rotate(&self) -> Result<()> { log::info!( - "[alphahuman:audit] Rotating audit log: {}", + "[openhuman:audit] Rotating audit log: {}", self.log_path.display() ); for i in (1..10).rev() { diff --git a/src-tauri/src/alphahuman/security/bubblewrap.rs b/src-tauri/src/openhuman/security/bubblewrap.rs similarity index 98% rename from src-tauri/src/alphahuman/security/bubblewrap.rs rename to src-tauri/src/openhuman/security/bubblewrap.rs index 5cd7c469b..187f3314e 100644 --- a/src-tauri/src/alphahuman/security/bubblewrap.rs +++ b/src-tauri/src/openhuman/security/bubblewrap.rs @@ -1,6 +1,6 @@ //! Bubblewrap sandbox (user namespaces for Linux/macOS) -use crate::alphahuman::security::traits::Sandbox; +use crate::openhuman::security::traits::Sandbox; use std::process::Command; /// Bubblewrap sandbox backend diff --git a/src-tauri/src/alphahuman/security/detect.rs b/src-tauri/src/openhuman/security/detect.rs similarity index 96% rename from src-tauri/src/alphahuman/security/detect.rs rename to src-tauri/src/openhuman/security/detect.rs index 5b9e5380b..7118baa63 100644 --- a/src-tauri/src/alphahuman/security/detect.rs +++ b/src-tauri/src/openhuman/security/detect.rs @@ -1,7 +1,7 @@ //! Auto-detection of available security features -use crate::alphahuman::config::{SandboxBackend, SecurityConfig}; -use crate::alphahuman::security::traits::Sandbox; +use crate::openhuman::config::{SandboxBackend, SecurityConfig}; +use crate::openhuman::security::traits::Sandbox; use std::sync::Arc; /// Create a sandbox based on auto-detection or explicit config @@ -117,7 +117,7 @@ fn detect_best_sandbox() -> Arc { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::{SandboxConfig, SecurityConfig}; + use crate::openhuman::config::{SandboxConfig, SecurityConfig}; #[test] fn detect_best_sandbox_returns_something() { diff --git a/src-tauri/src/alphahuman/security/docker.rs b/src-tauri/src/openhuman/security/docker.rs similarity index 99% rename from src-tauri/src/alphahuman/security/docker.rs rename to src-tauri/src/openhuman/security/docker.rs index c38da639b..e7bac3f1b 100644 --- a/src-tauri/src/alphahuman/security/docker.rs +++ b/src-tauri/src/openhuman/security/docker.rs @@ -1,6 +1,6 @@ //! Docker sandbox (container isolation) -use crate::alphahuman::security::traits::Sandbox; +use crate::openhuman::security::traits::Sandbox; use std::process::Command; /// Docker sandbox backend diff --git a/src-tauri/src/alphahuman/security/firejail.rs b/src-tauri/src/openhuman/security/firejail.rs similarity index 99% rename from src-tauri/src/alphahuman/security/firejail.rs rename to src-tauri/src/openhuman/security/firejail.rs index be591da90..f223083ca 100644 --- a/src-tauri/src/alphahuman/security/firejail.rs +++ b/src-tauri/src/openhuman/security/firejail.rs @@ -2,7 +2,7 @@ //! //! Firejail is a SUID sandbox program that Linux applications use to sandbox themselves. -use crate::alphahuman::security::traits::Sandbox; +use crate::openhuman::security::traits::Sandbox; use std::process::Command; /// Firejail sandbox backend for Linux diff --git a/src-tauri/src/alphahuman/security/landlock.rs b/src-tauri/src/openhuman/security/landlock.rs similarity index 99% rename from src-tauri/src/alphahuman/security/landlock.rs rename to src-tauri/src/openhuman/security/landlock.rs index 5132ff895..06641c091 100644 --- a/src-tauri/src/alphahuman/security/landlock.rs +++ b/src-tauri/src/openhuman/security/landlock.rs @@ -6,7 +6,7 @@ #[cfg(all(feature = "sandbox-landlock", target_os = "linux"))] use landlock::{AccessFs, PathBeneath, PathFd, Ruleset, RulesetAttr, RulesetCreatedAttr}; -use crate::alphahuman::security::traits::Sandbox; +use crate::openhuman::security::traits::Sandbox; use std::path::Path; /// Landlock sandbox backend for Linux diff --git a/src-tauri/src/alphahuman/security/mod.rs b/src-tauri/src/openhuman/security/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/security/mod.rs rename to src-tauri/src/openhuman/security/mod.rs diff --git a/src-tauri/src/alphahuman/security/pairing.rs b/src-tauri/src/openhuman/security/pairing.rs similarity index 97% rename from src-tauri/src/alphahuman/security/pairing.rs rename to src-tauri/src/openhuman/security/pairing.rs index 95abd4b72..60c55edc2 100644 --- a/src-tauri/src/alphahuman/security/pairing.rs +++ b/src-tauri/src/openhuman/security/pairing.rs @@ -63,7 +63,7 @@ impl PairingGuard { None }; log::info!( - "[alphahuman:pairing] Guard created: require_pairing={}, existing_tokens={}, code_generated={}", + "[openhuman:pairing] Guard created: require_pairing={}, existing_tokens={}, code_generated={}", require_pairing, tokens.len(), code.is_some() @@ -95,7 +95,7 @@ impl PairingGuard { let elapsed = locked_at.elapsed().as_secs(); if elapsed < PAIR_LOCKOUT_SECS { log::warn!( - "[alphahuman:pairing] Pairing locked out: {} failed attempts, {}s remaining", + "[openhuman:pairing] Pairing locked out: {} failed attempts, {}s remaining", count, PAIR_LOCKOUT_SECS - elapsed ); @@ -121,7 +121,7 @@ impl PairingGuard { // Consume the pairing code so it cannot be reused *pairing_code = None; - log::info!("[alphahuman:pairing] Pairing successful, token issued"); + log::info!("[openhuman:pairing] Pairing successful, token issued"); return Ok(Some(token)); } } @@ -132,13 +132,13 @@ impl PairingGuard { let mut attempts = self.failed_attempts.lock(); attempts.0 += 1; log::warn!( - "[alphahuman:pairing] Pairing attempt failed ({}/{})", + "[openhuman:pairing] Pairing attempt failed ({}/{})", attempts.0, MAX_PAIR_ATTEMPTS ); if attempts.0 >= MAX_PAIR_ATTEMPTS { attempts.1 = Some(Instant::now()); - log::warn!("[alphahuman:pairing] Max attempts reached, lockout activated"); + log::warn!("[openhuman:pairing] Max attempts reached, lockout activated"); } } diff --git a/src-tauri/src/alphahuman/security/policy.rs b/src-tauri/src/openhuman/security/policy.rs similarity index 97% rename from src-tauri/src/alphahuman/security/policy.rs rename to src-tauri/src/openhuman/security/policy.rs index fd292ac2c..225858211 100644 --- a/src-tauri/src/alphahuman/security/policy.rs +++ b/src-tauri/src/openhuman/security/policy.rs @@ -491,7 +491,7 @@ impl SecurityPolicy { ) -> Result { if !self.is_command_allowed(command) { log::warn!( - "[alphahuman:policy] Command blocked by allowlist: {}", + "[openhuman:policy] Command blocked by allowlist: {}", &command[..command.len().min(80)] ); return Err(format!("Command not allowed by security policy: {command}")); @@ -502,14 +502,14 @@ impl SecurityPolicy { if risk == CommandRiskLevel::High { if self.block_high_risk_commands { log::warn!( - "[alphahuman:policy] High-risk command blocked: {}", + "[openhuman:policy] High-risk command blocked: {}", &command[..command.len().min(80)] ); return Err("Command blocked: high-risk command is disallowed by policy".into()); } if self.autonomy == AutonomyLevel::Supervised && !approved { log::warn!( - "[alphahuman:policy] High-risk command needs approval: {}", + "[openhuman:policy] High-risk command needs approval: {}", &command[..command.len().min(80)] ); return Err( @@ -525,7 +525,7 @@ impl SecurityPolicy { && !approved { log::info!( - "[alphahuman:policy] Medium-risk command needs approval: {}", + "[openhuman:policy] Medium-risk command needs approval: {}", &command[..command.len().min(80)] ); return Err( @@ -534,7 +534,7 @@ impl SecurityPolicy { } log::debug!( - "[alphahuman:policy] Command validated: risk={:?}, approved={}, cmd={}", + "[openhuman:policy] Command validated: risk={:?}, approved={}, cmd={}", risk, approved, &command[..command.len().min(80)] @@ -739,7 +739,7 @@ impl SecurityPolicy { ToolOperation::Act => { if !self.can_act() { log::warn!( - "[alphahuman:policy] Operation '{}' blocked: read-only mode", + "[openhuman:policy] Operation '{}' blocked: read-only mode", operation_name ); return Err(format!( @@ -749,14 +749,14 @@ impl SecurityPolicy { if !self.record_action() { log::warn!( - "[alphahuman:policy] Operation '{}' blocked: rate limit exceeded", + "[openhuman:policy] Operation '{}' blocked: rate limit exceeded", operation_name ); return Err("Rate limit exceeded: action budget exhausted".to_string()); } log::debug!( - "[alphahuman:policy] Operation '{}' allowed (actions: {}/{})", + "[openhuman:policy] Operation '{}' allowed (actions: {}/{})", operation_name, self.tracker.count(), self.max_actions_per_hour @@ -780,11 +780,11 @@ impl SecurityPolicy { /// Build from config sections pub fn from_config( - autonomy_config: &crate::alphahuman::config::AutonomyConfig, + autonomy_config: &crate::openhuman::config::AutonomyConfig, workspace_dir: &Path, ) -> Self { log::info!( - "[alphahuman:policy] SecurityPolicy created: autonomy={:?}, workspace_only={}, allowed_cmds={}, max_actions/hr={}", + "[openhuman:policy] SecurityPolicy created: autonomy={:?}, workspace_only={}, allowed_cmds={}, max_actions/hr={}", autonomy_config.level, autonomy_config.workspace_only, autonomy_config.allowed_commands.len(), @@ -1126,7 +1126,7 @@ mod tests { #[test] fn from_config_maps_all_fields() { - let autonomy_config = crate::alphahuman::config::AutonomyConfig { + let autonomy_config = crate::openhuman::config::AutonomyConfig { level: AutonomyLevel::Full, workspace_only: false, allowed_commands: vec!["docker".into()], @@ -1135,7 +1135,7 @@ mod tests { max_cost_per_day_cents: 1000, require_approval_for_medium_risk: false, block_high_risk_commands: false, - ..crate::alphahuman::config::AutonomyConfig::default() + ..crate::openhuman::config::AutonomyConfig::default() }; let workspace = PathBuf::from("/tmp/test-workspace"); let policy = SecurityPolicy::from_config(&autonomy_config, &workspace); @@ -1512,7 +1512,7 @@ mod tests { #[test] fn from_config_creates_fresh_tracker() { - let autonomy_config = crate::alphahuman::config::AutonomyConfig { + let autonomy_config = crate::openhuman::config::AutonomyConfig { level: AutonomyLevel::Full, workspace_only: false, allowed_commands: vec![], @@ -1521,7 +1521,7 @@ mod tests { max_cost_per_day_cents: 100, require_approval_for_medium_risk: true, block_high_risk_commands: true, - ..crate::alphahuman::config::AutonomyConfig::default() + ..crate::openhuman::config::AutonomyConfig::default() }; let workspace = PathBuf::from("/tmp/test"); let policy = SecurityPolicy::from_config(&autonomy_config, &workspace); @@ -1649,7 +1649,7 @@ mod tests { #[test] fn resolved_path_blocks_outside_workspace() { - let workspace = std::env::temp_dir().join("alphahuman_test_resolved_path"); + let workspace = std::env::temp_dir().join("openhuman_test_resolved_path"); let _ = std::fs::create_dir_all(&workspace); // Use the canonicalized workspace so starts_with checks match @@ -1673,7 +1673,7 @@ mod tests { let canonical_temp = std::env::temp_dir() .canonicalize() .unwrap_or_else(|_| std::env::temp_dir()); - let outside = canonical_temp.join("outside_workspace_alphahuman"); + let outside = canonical_temp.join("outside_workspace_openhuman"); assert!( !policy.is_resolved_path_allowed(&outside), "path outside workspace must be blocked" @@ -1685,7 +1685,7 @@ mod tests { #[test] fn resolved_path_blocks_root_escape() { let policy = SecurityPolicy { - workspace_dir: PathBuf::from("/home/alphahuman_user/project"), + workspace_dir: PathBuf::from("/home/openhuman_user/project"), ..SecurityPolicy::default() }; @@ -1704,7 +1704,7 @@ mod tests { fn resolved_path_blocks_symlink_escape() { use std::os::unix::fs::symlink; - let root = std::env::temp_dir().join("alphahuman_test_symlink_escape"); + let root = std::env::temp_dir().join("openhuman_test_symlink_escape"); let workspace = root.join("workspace"); let outside = root.join("outside_target"); diff --git a/src-tauri/src/alphahuman/security/secrets.rs b/src-tauri/src/openhuman/security/secrets.rs similarity index 99% rename from src-tauri/src/alphahuman/security/secrets.rs rename to src-tauri/src/openhuman/security/secrets.rs index d5699778e..eb9d68ff4 100644 --- a/src-tauri/src/alphahuman/security/secrets.rs +++ b/src-tauri/src/openhuman/security/secrets.rs @@ -1,7 +1,7 @@ // Encrypted secret store — defense-in-depth for API keys and tokens. // // Secrets are encrypted using ChaCha20-Poly1305 AEAD with a random key stored -// in `{data_dir}/alphahuman/.secret_key` with restrictive file permissions (0600). The +// in `{data_dir}/openhuman/.secret_key` with restrictive file permissions (0600). The // config file stores only hex-encoded ciphertext, never plaintext keys. // // Each encryption generates a fresh random 12-byte nonce, prepended to the @@ -35,7 +35,7 @@ const NONCE_LEN: usize = 12; /// Manages encrypted storage of secrets (API keys, tokens, etc.) #[derive(Debug, Clone)] pub struct SecretStore { - /// Path to the key file (`{data_dir}/alphahuman/.secret_key`) + /// Path to the key file (`{data_dir}/openhuman/.secret_key`) key_path: PathBuf, /// Whether encryption is enabled enabled: bool, @@ -43,9 +43,9 @@ pub struct SecretStore { impl SecretStore { /// Create a new secret store rooted at the given directory. - pub fn new(alphahuman_dir: &Path, enabled: bool) -> Self { + pub fn new(openhuman_dir: &Path, enabled: bool) -> Self { Self { - key_path: alphahuman_dir.join(".secret_key"), + key_path: openhuman_dir.join(".secret_key"), enabled, } } diff --git a/src-tauri/src/alphahuman/security/traits.rs b/src-tauri/src/openhuman/security/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/security/traits.rs rename to src-tauri/src/openhuman/security/traits.rs diff --git a/src-tauri/src/alphahuman/service/mod.rs b/src-tauri/src/openhuman/service/mod.rs similarity index 94% rename from src-tauri/src/alphahuman/service/mod.rs rename to src-tauri/src/openhuman/service/mod.rs index 8459c6e28..494f17f4f 100644 --- a/src-tauri/src/alphahuman/service/mod.rs +++ b/src-tauri/src/openhuman/service/mod.rs @@ -1,15 +1,15 @@ -//! Service management helpers for Alphahuman daemon. +//! Service management helpers for OpenHuman daemon. -use crate::alphahuman::config::Config; +use crate::openhuman::config::Config; use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; use std::process::{Command, Stdio}; -const SERVICE_LABEL: &str = "com.alphahuman.daemon"; -const LEGACY_SERVICE_LABEL: &str = "com.alphahuman.app"; -const WINDOWS_TASK_NAME: &str = "AlphaHuman Daemon"; +const SERVICE_LABEL: &str = "com.openhuman.daemon"; +const LEGACY_SERVICE_LABEL: &str = "com.openhuman.app"; +const WINDOWS_TASK_NAME: &str = "OpenHuman Daemon"; fn windows_task_name() -> &'static str { WINDOWS_TASK_NAME @@ -22,7 +22,7 @@ fn daemon_program_args(exe: &std::path::Path) -> Vec { .unwrap_or_default() .to_ascii_lowercase(); - if file_name.contains("alphahuman-core") { + if file_name.contains("openhuman-core") { vec!["serve".to_string()] } else { vec!["core".to_string(), "serve".to_string()] @@ -124,7 +124,7 @@ pub fn start(config: &Config) -> Result { let _ = run_checked(Command::new("systemctl").args([ "--user", "enable", - "alphahuman.service", + "openhuman.service", ])); } else { log::info!("[service] Systemd service already enabled"); @@ -135,7 +135,7 @@ pub fn start(config: &Config) -> Result { // Try to start - systemctl start is idempotent log::info!("[service] Starting systemd service"); let start_result = - run_checked(Command::new("systemctl").args(["--user", "start", "alphahuman.service"])); + run_checked(Command::new("systemctl").args(["--user", "start", "openhuman.service"])); if let Err(e) = start_result { // Check if it's already active - that's success for us let status_check = status(config)?; @@ -223,7 +223,7 @@ pub fn stop(config: &Config) -> Result { if cfg!(target_os = "linux") { let _ = - run_checked(Command::new("systemctl").args(["--user", "stop", "alphahuman.service"])); + run_checked(Command::new("systemctl").args(["--user", "stop", "openhuman.service"])); return status(config); } @@ -259,7 +259,7 @@ pub fn status(config: &Config) -> Result { let out = run_capture(Command::new("systemctl").args([ "--user", "is-active", - "alphahuman.service", + "openhuman.service", ])) .unwrap_or_else(|_| "unknown".into()); let state = match out.trim() { @@ -270,7 +270,7 @@ pub fn status(config: &Config) -> Result { return Ok(ServiceStatus { state, unit_path: Some(linux_service_file(config)?), - label: "alphahuman.service".to_string(), + label: "openhuman.service".to_string(), details: None, }); } @@ -339,7 +339,7 @@ pub fn uninstall(config: &Config) -> Result { return Ok(ServiceStatus { state: ServiceState::NotInstalled, unit_path: Some(file), - label: "alphahuman.service".to_string(), + label: "openhuman.service".to_string(), details: None, }); } @@ -353,7 +353,7 @@ pub fn uninstall(config: &Config) -> Result { .parent() .map_or_else(|| PathBuf::from("."), PathBuf::from) .join("logs") - .join("alphahuman-daemon.cmd"); + .join("openhuman-daemon.cmd"); if wrapper.exists() { fs::remove_file(&wrapper).ok(); } @@ -410,7 +410,7 @@ fn install_macos(config: &Config) -> Result<()> { {stderr} EnvironmentVariables - ALPHAHUMAN_DAEMON_INTERNAL + OPENHUMAN_DAEMON_INTERNAL false WorkingDirectory @@ -457,14 +457,14 @@ fn install_linux(config: &Config) -> Result<()> { let exec_start = daemon_command_line(&exe); let unit = format!( - "[Unit]\nDescription=Alphahuman Daemon\n\n[Service]\nExecStart={}\nRestart=always\nRestartSec=3\n\nStandardOutput=append:{}\nStandardError=append:{}\n\n[Install]\nWantedBy=default.target\n", + "[Unit]\nDescription=OpenHuman Daemon\n\n[Service]\nExecStart={}\nRestart=always\nRestartSec=3\n\nStandardOutput=append:{}\nStandardError=append:{}\n\n[Install]\nWantedBy=default.target\n", exec_start, stdout.display(), stderr.display(), ); fs::write(&file, unit)?; - let _ = run_checked(Command::new("systemctl").args(["--user", "enable", "alphahuman.service"])); + let _ = run_checked(Command::new("systemctl").args(["--user", "enable", "openhuman.service"])); Ok(()) } @@ -477,7 +477,7 @@ fn install_windows(config: &Config) -> Result<()> { .join("logs"); fs::create_dir_all(&logs_dir)?; - let wrapper = logs_dir.join("alphahuman-daemon.cmd"); + let wrapper = logs_dir.join("openhuman-daemon.cmd"); let stdout = logs_dir.join("daemon.stdout.log"); let stderr = logs_dir.join("daemon.stderr.log"); let daemon_cmd = daemon_command_line(&exe); @@ -544,7 +544,7 @@ fn linux_service_file(config: &Config) -> Result { .join(".config") .join("systemd") .join("user") - .join("alphahuman.service")) + .join("openhuman.service")) } fn run_checked(cmd: &mut Command) -> Result<()> { @@ -599,7 +599,7 @@ fn is_service_loaded_macos() -> Result { /// Check if the Linux systemd service is enabled fn is_service_enabled_linux() -> Result { let result = Command::new("systemctl") - .args(["--user", "is-enabled", "alphahuman.service"]) + .args(["--user", "is-enabled", "openhuman.service"]) .output(); match result { @@ -641,6 +641,6 @@ mod tests { fn linux_service_file_uses_config_dir() { let config = Config::default(); let path = linux_service_file(&config).unwrap(); - assert!(path.ends_with(".config/systemd/user/alphahuman.service")); + assert!(path.ends_with(".config/systemd/user/openhuman.service")); } } diff --git a/src-tauri/src/alphahuman/skillforge/evaluate.rs b/src-tauri/src/openhuman/skillforge/evaluate.rs similarity index 99% rename from src-tauri/src/alphahuman/skillforge/evaluate.rs rename to src-tauri/src/openhuman/skillforge/evaluate.rs index 2a462bb80..c1a1bc1f7 100644 --- a/src-tauri/src/alphahuman/skillforge/evaluate.rs +++ b/src-tauri/src/openhuman/skillforge/evaluate.rs @@ -175,7 +175,7 @@ impl Evaluator { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::skillforge::scout::{ScoutResult, ScoutSource}; + use crate::openhuman::skillforge::scout::{ScoutResult, ScoutSource}; fn make_candidate(stars: u64, lang: Option<&str>, has_license: bool) -> ScoutResult { ScoutResult { diff --git a/src-tauri/src/alphahuman/skillforge/integrate.rs b/src-tauri/src/openhuman/skillforge/integrate.rs similarity index 95% rename from src-tauri/src/alphahuman/skillforge/integrate.rs rename to src-tauri/src/openhuman/skillforge/integrate.rs index 320706efe..8a78bd744 100644 --- a/src-tauri/src/alphahuman/skillforge/integrate.rs +++ b/src-tauri/src/openhuman/skillforge/integrate.rs @@ -1,4 +1,4 @@ -//! Integrator - generates Alphahuman-standard SKILL.toml + SKILL.md from scout results. +//! Integrator - generates OpenHuman-standard SKILL.toml + SKILL.md from scout results. use std::fs; use std::path::PathBuf; @@ -75,7 +75,7 @@ stars = {stars} updated_at = "{updated}" [skill.requirements] -runtime = "alphahuman >= 0.1" +runtime = "openhuman >= 0.1" [skill.metadata] auto_integrated = true @@ -115,7 +115,7 @@ forge_timestamp = "{now}" ## Usage ```toml -# Add to your Alphahuman config: +# Add to your OpenHuman config: [skills.{name}] enabled = true ``` @@ -174,7 +174,7 @@ fn sanitize_path_component(name: &str) -> Result { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::skillforge::scout::{ScoutResult, ScoutSource}; + use crate::openhuman::skillforge::scout::{ScoutResult, ScoutSource}; use std::fs; fn sample_candidate() -> ScoutResult { @@ -193,7 +193,7 @@ mod tests { #[tokio::test] async fn integrate_creates_files() { - let tmp = std::env::temp_dir().join("alphahuman-test-integrate"); + let tmp = std::env::temp_dir().join("openhuman-test-integrate"); let _ = fs::remove_dir_all(&tmp); let integrator = Integrator::new(tmp.to_string_lossy().into_owned()); diff --git a/src-tauri/src/alphahuman/skillforge/mod.rs b/src-tauri/src/openhuman/skillforge/mod.rs similarity index 99% rename from src-tauri/src/alphahuman/skillforge/mod.rs rename to src-tauri/src/openhuman/skillforge/mod.rs index d1404ff29..a6f64afde 100644 --- a/src-tauri/src/alphahuman/skillforge/mod.rs +++ b/src-tauri/src/openhuman/skillforge/mod.rs @@ -2,7 +2,7 @@ //! //! Pipeline: Scout → Evaluate → Integrate //! Discovers skills from external sources, scores them, and generates -//! Alphahuman-compatible manifests for qualified candidates. +//! OpenHuman-compatible manifests for qualified candidates. pub mod evaluate; pub mod integrate; diff --git a/src-tauri/src/alphahuman/skillforge/scout.rs b/src-tauri/src/openhuman/skillforge/scout.rs similarity index 98% rename from src-tauri/src/alphahuman/skillforge/scout.rs rename to src-tauri/src/openhuman/skillforge/scout.rs index 42bb16d3f..ee8bacc15 100644 --- a/src-tauri/src/alphahuman/skillforge/scout.rs +++ b/src-tauri/src/openhuman/skillforge/scout.rs @@ -83,7 +83,7 @@ impl GitHubScout { ); headers.insert( reqwest::header::USER_AGENT, - "Alphahuman-SkillForge/0.1".parse().expect("valid header"), + "OpenHuman-SkillForge/0.1".parse().expect("valid header"), ); if let Some(ref t) = token { if let Ok(val) = format!("Bearer {t}").parse() { @@ -99,7 +99,7 @@ impl GitHubScout { Self { client, - queries: vec!["alphahuman skill".into(), "ai agent skill".into()], + queries: vec!["openhuman skill".into(), "ai agent skill".into()], } } diff --git a/src-tauri/src/alphahuman/skills/mod.rs b/src-tauri/src/openhuman/skills/mod.rs similarity index 97% rename from src-tauri/src/alphahuman/skills/mod.rs rename to src-tauri/src/openhuman/skills/mod.rs index 192fce56e..77531befb 100644 --- a/src-tauri/src/alphahuman/skills/mod.rs +++ b/src-tauri/src/openhuman/skills/mod.rs @@ -7,11 +7,11 @@ use std::process::Command; use std::time::{Duration, SystemTime}; const OPEN_SKILLS_REPO_URL: &str = "https://github.com/besoeasy/open-skills"; -const OPEN_SKILLS_SYNC_MARKER: &str = ".alphahuman-open-skills-sync"; +const OPEN_SKILLS_SYNC_MARKER: &str = ".openhuman-open-skills-sync"; const OPEN_SKILLS_SYNC_INTERVAL_SECS: u64 = 60 * 60 * 24 * 7; /// A skill is a user-defined or community-built capability. -/// Skills live in `~/.alphahuman/workspace/skills//SKILL.md` +/// Skills live in `~/.openhuman/workspace/skills//SKILL.md` /// and can include tool definitions, prompts, and automation scripts. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Skill { @@ -159,7 +159,7 @@ fn load_open_skills(repo_dir: &Path) -> Vec { } fn open_skills_enabled() -> bool { - if let Ok(raw) = std::env::var("ALPHAHUMAN_OPEN_SKILLS_ENABLED") { + if let Ok(raw) = std::env::var("OPENHUMAN_OPEN_SKILLS_ENABLED") { let value = raw.trim().to_ascii_lowercase(); return !matches!(value.as_str(), "0" | "false" | "off" | "no"); } @@ -169,7 +169,7 @@ fn open_skills_enabled() -> bool { } fn resolve_open_skills_dir() -> Option { - if let Ok(path) = std::env::var("ALPHAHUMAN_OPEN_SKILLS_DIR") { + if let Ok(path) = std::env::var("OPENHUMAN_OPEN_SKILLS_DIR") { let trimmed = path.trim(); if !trimmed.is_empty() { return Some(PathBuf::from(trimmed)); @@ -404,7 +404,7 @@ pub fn init_skills_dir(workspace_dir: &Path) -> Result<()> { if !readme.exists() { std::fs::write( &readme, - "# Alphahuman Skills\n\n\ + "# OpenHuman Skills\n\n\ Each subdirectory is a skill. Create a `SKILL.toml` or `SKILL.md` file inside.\n\n\ ## SKILL.toml format\n\n\ ```toml\n\ @@ -425,8 +425,8 @@ pub fn init_skills_dir(workspace_dir: &Path) -> Result<()> { The agent will read it and follow the instructions.\n\n\ ## Installing community skills\n\n\ ```bash\n\ - alphahuman skills install \n\ - alphahuman skills list\n\ + openhuman skills install \n\ + openhuman skills list\n\ ```\n", )?; } @@ -732,9 +732,9 @@ description = "Bare minimum" #[test] fn skills_dir_path() { - let base = std::path::Path::new("/home/user/.alphahuman"); + let base = std::path::Path::new("/home/user/.openhuman"); let dir = skills_dir(base); - assert_eq!(dir, PathBuf::from("/home/user/.alphahuman/skills")); + assert_eq!(dir, PathBuf::from("/home/user/.openhuman/skills")); } #[test] diff --git a/src-tauri/src/alphahuman/skills/symlink_tests.rs b/src-tauri/src/openhuman/skills/symlink_tests.rs similarity index 99% rename from src-tauri/src/alphahuman/skills/symlink_tests.rs rename to src-tauri/src/openhuman/skills/symlink_tests.rs index 5937e98da..50538302c 100644 --- a/src-tauri/src/alphahuman/skills/symlink_tests.rs +++ b/src-tauri/src/openhuman/skills/symlink_tests.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests { - use crate::alphahuman::skills::skills_dir; + use crate::openhuman::skills::skills_dir; use std::path::Path; use tempfile::TempDir; diff --git a/src-tauri/src/alphahuman/tools/browser.rs b/src-tauri/src/openhuman/tools/browser.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/browser.rs rename to src-tauri/src/openhuman/tools/browser.rs index 8c28ab1de..6f4126954 100644 --- a/src-tauri/src/alphahuman/tools/browser.rs +++ b/src-tauri/src/openhuman/tools/browser.rs @@ -6,7 +6,7 @@ //! Computer-use (OS-level) actions are supported via an optional sidecar endpoint. use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use anyhow::Context; use async_trait::async_trait; use serde::{Deserialize, Serialize}; @@ -420,7 +420,7 @@ impl BrowserTool { if self.allowed_domains.is_empty() && !allow_all_browser_domains() { anyhow::bail!( "Browser tool enabled but no allowed_domains configured. \ - Add [browser].allowed_domains in config.toml or set ALPHAHUMAN_BROWSER_ALLOW_ALL=1" + Add [browser].allowed_domains in config.toml or set OPENHUMAN_BROWSER_ALLOW_ALL=1" ); } @@ -747,12 +747,12 @@ impl BrowserTool { }, "metadata": { "session_name": self.session_name, - "source": "alphahuman.browser", + "source": "openhuman.browser", "version": env!("CARGO_PKG_VERSION"), } }); - let client = crate::alphahuman::config::build_runtime_proxy_client("tool.browser"); + let client = crate::openhuman::config::build_runtime_proxy_client("tool.browser"); let mut request = client .post(endpoint) .timeout(Duration::from_millis(self.computer_use.timeout_ms)) @@ -2077,7 +2077,7 @@ fn is_non_global_v6(v6: std::net::Ipv6Addr) -> bool { fn allow_all_browser_domains() -> bool { matches!( - std::env::var("ALPHAHUMAN_BROWSER_ALLOW_ALL") + std::env::var("OPENHUMAN_BROWSER_ALLOW_ALL") .ok() .as_deref(), Some("1") | Some("true") | Some("TRUE") | Some("yes") | Some("YES") @@ -2398,7 +2398,7 @@ mod tests { fn browser_tool_empty_allowlist_blocks() { let security = Arc::new(SecurityPolicy::default()); let tool = BrowserTool::new(security, vec![], None); - std::env::remove_var("ALPHAHUMAN_BROWSER_ALLOW_ALL"); + std::env::remove_var("OPENHUMAN_BROWSER_ALLOW_ALL"); assert!(tool.validate_url("https://example.com").is_err()); } @@ -2406,9 +2406,9 @@ mod tests { fn browser_tool_empty_allowlist_allows_with_env_flag() { let security = Arc::new(SecurityPolicy::default()); let tool = BrowserTool::new(security, vec![], None); - std::env::set_var("ALPHAHUMAN_BROWSER_ALLOW_ALL", "1"); + std::env::set_var("OPENHUMAN_BROWSER_ALLOW_ALL", "1"); assert!(tool.validate_url("https://example.com").is_ok()); - std::env::remove_var("ALPHAHUMAN_BROWSER_ALLOW_ALL"); + std::env::remove_var("OPENHUMAN_BROWSER_ALLOW_ALL"); } #[test] diff --git a/src-tauri/src/alphahuman/tools/browser_open.rs b/src-tauri/src/openhuman/tools/browser_open.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/browser_open.rs rename to src-tauri/src/openhuman/tools/browser_open.rs index ce5a6f83b..c6a2c7271 100644 --- a/src-tauri/src/alphahuman/tools/browser_open.rs +++ b/src-tauri/src/openhuman/tools/browser_open.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -308,7 +308,7 @@ fn parse_ipv4(host: &str) -> Option<[u8; 4]> { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_tool(allowed_domains: Vec<&str>) -> BrowserOpenTool { let security = Arc::new(SecurityPolicy { diff --git a/src-tauri/src/alphahuman/tools/composio.rs b/src-tauri/src/openhuman/tools/composio.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/composio.rs rename to src-tauri/src/openhuman/tools/composio.rs index f753f9ff1..30fbfd420 100644 --- a/src-tauri/src/alphahuman/tools/composio.rs +++ b/src-tauri/src/openhuman/tools/composio.rs @@ -1,14 +1,14 @@ // Composio Tool Provider — optional managed tool surface with 1000+ OAuth integrations. // -// When enabled, Alphahuman can execute actions on Gmail, Notion, GitHub, Slack, etc. +// When enabled, OpenHuman can execute actions on Gmail, Notion, GitHub, Slack, etc. // through Composio's API without storing raw OAuth tokens locally. // // This is opt-in. Users who prefer sovereign/local-only mode skip this entirely. // The Composio API key is stored in the encrypted secret store. use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::policy::ToolOperation; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::policy::ToolOperation; +use crate::openhuman::security::SecurityPolicy; use anyhow::Context; use async_trait::async_trait; use reqwest::Client; @@ -49,7 +49,7 @@ impl ComposioTool { } fn client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("tool.composio", 60, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("tool.composio", 60, 10) } /// List available Composio apps/actions for the authenticated user. @@ -773,7 +773,7 @@ pub struct ComposioAction { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security() -> Arc { Arc::new(SecurityPolicy::default()) diff --git a/src-tauri/src/alphahuman/tools/cron_add.rs b/src-tauri/src/openhuman/tools/cron_add.rs similarity index 97% rename from src-tauri/src/alphahuman/tools/cron_add.rs rename to src-tauri/src/openhuman/tools/cron_add.rs index 624a033cc..81608be83 100644 --- a/src-tauri/src/alphahuman/tools/cron_add.rs +++ b/src-tauri/src/openhuman/tools/cron_add.rs @@ -1,7 +1,7 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron::{self, DeliveryConfig, JobType, Schedule, SessionTarget}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::Config; +use crate::openhuman::cron::{self, DeliveryConfig, JobType, Schedule, SessionTarget}; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -213,8 +213,8 @@ impl Tool for CronAddTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; - use crate::alphahuman::security::AutonomyLevel; + use crate::openhuman::config::Config; + use crate::openhuman::security::AutonomyLevel; use tempfile::TempDir; async fn test_config(tmp: &TempDir) -> Arc { diff --git a/src-tauri/src/alphahuman/tools/cron_list.rs b/src-tauri/src/openhuman/tools/cron_list.rs similarity index 96% rename from src-tauri/src/alphahuman/tools/cron_list.rs rename to src-tauri/src/openhuman/tools/cron_list.rs index 264947168..caf2c0f13 100644 --- a/src-tauri/src/alphahuman/tools/cron_list.rs +++ b/src-tauri/src/openhuman/tools/cron_list.rs @@ -1,6 +1,6 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron; +use crate::openhuman::config::Config; +use crate::openhuman::cron; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -60,7 +60,7 @@ impl Tool for CronListTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use tempfile::TempDir; async fn test_config(tmp: &TempDir) -> Arc { diff --git a/src-tauri/src/alphahuman/tools/cron_remove.rs b/src-tauri/src/openhuman/tools/cron_remove.rs similarity index 96% rename from src-tauri/src/alphahuman/tools/cron_remove.rs rename to src-tauri/src/openhuman/tools/cron_remove.rs index 751f16500..05f57fb14 100644 --- a/src-tauri/src/alphahuman/tools/cron_remove.rs +++ b/src-tauri/src/openhuman/tools/cron_remove.rs @@ -1,6 +1,6 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron; +use crate::openhuman::config::Config; +use crate::openhuman::cron; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -73,7 +73,7 @@ impl Tool for CronRemoveTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use tempfile::TempDir; async fn test_config(tmp: &TempDir) -> Arc { diff --git a/src-tauri/src/alphahuman/tools/cron_run.rs b/src-tauri/src/openhuman/tools/cron_run.rs similarity index 97% rename from src-tauri/src/alphahuman/tools/cron_run.rs rename to src-tauri/src/openhuman/tools/cron_run.rs index ef95e261d..015a69e89 100644 --- a/src-tauri/src/alphahuman/tools/cron_run.rs +++ b/src-tauri/src/openhuman/tools/cron_run.rs @@ -1,6 +1,6 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron; +use crate::openhuman::config::Config; +use crate::openhuman::cron; use async_trait::async_trait; use chrono::Utc; use serde_json::json; @@ -104,7 +104,7 @@ impl Tool for CronRunTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use tempfile::TempDir; async fn test_config(tmp: &TempDir) -> Arc { diff --git a/src-tauri/src/alphahuman/tools/cron_runs.rs b/src-tauri/src/openhuman/tools/cron_runs.rs similarity index 97% rename from src-tauri/src/alphahuman/tools/cron_runs.rs rename to src-tauri/src/openhuman/tools/cron_runs.rs index 809082dee..ec7c352b6 100644 --- a/src-tauri/src/alphahuman/tools/cron_runs.rs +++ b/src-tauri/src/openhuman/tools/cron_runs.rs @@ -1,6 +1,6 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron; +use crate::openhuman::config::Config; +use crate::openhuman::cron; use async_trait::async_trait; use serde::Serialize; use serde_json::json; @@ -117,7 +117,7 @@ fn truncate(input: &str, max_chars: usize) -> String { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use chrono::{Duration as ChronoDuration, Utc}; use tempfile::TempDir; diff --git a/src-tauri/src/alphahuman/tools/cron_update.rs b/src-tauri/src/openhuman/tools/cron_update.rs similarity index 96% rename from src-tauri/src/alphahuman/tools/cron_update.rs rename to src-tauri/src/openhuman/tools/cron_update.rs index 5adacc448..e0f9a03af 100644 --- a/src-tauri/src/alphahuman/tools/cron_update.rs +++ b/src-tauri/src/openhuman/tools/cron_update.rs @@ -1,7 +1,7 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron::{self, CronJobPatch}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::Config; +use crate::openhuman::cron::{self, CronJobPatch}; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -108,7 +108,7 @@ impl Tool for CronUpdateTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use tempfile::TempDir; async fn test_config(tmp: &TempDir) -> Arc { diff --git a/src-tauri/src/alphahuman/tools/delegate.rs b/src-tauri/src/openhuman/tools/delegate.rs similarity index 98% rename from src-tauri/src/alphahuman/tools/delegate.rs rename to src-tauri/src/openhuman/tools/delegate.rs index 13e1229f9..058eb0007 100644 --- a/src-tauri/src/alphahuman/tools/delegate.rs +++ b/src-tauri/src/openhuman/tools/delegate.rs @@ -1,8 +1,8 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::DelegateAgentConfig; -use crate::alphahuman::providers::{self, Provider}; -use crate::alphahuman::security::policy::ToolOperation; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::DelegateAgentConfig; +use crate::openhuman::providers::{self, Provider}; +use crate::openhuman::security::policy::ToolOperation; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::collections::HashMap; @@ -305,7 +305,7 @@ impl Tool for DelegateTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security() -> Arc { Arc::new(SecurityPolicy::default()) diff --git a/src-tauri/src/alphahuman/tools/file_read.rs b/src-tauri/src/openhuman/tools/file_read.rs similarity index 93% rename from src-tauri/src/alphahuman/tools/file_read.rs rename to src-tauri/src/openhuman/tools/file_read.rs index b9a44453a..b459bde55 100644 --- a/src-tauri/src/alphahuman/tools/file_read.rs +++ b/src-tauri/src/openhuman/tools/file_read.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -140,7 +140,7 @@ impl Tool for FileReadTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security(workspace: std::path::PathBuf) -> Arc { Arc::new(SecurityPolicy { @@ -182,7 +182,7 @@ mod tests { #[tokio::test] async fn file_read_existing_file() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read"); + let dir = std::env::temp_dir().join("openhuman_test_file_read"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); tokio::fs::write(dir.join("test.txt"), "hello world") @@ -200,7 +200,7 @@ mod tests { #[tokio::test] async fn file_read_nonexistent_file() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_missing"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_missing"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -214,7 +214,7 @@ mod tests { #[tokio::test] async fn file_read_blocks_path_traversal() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_traversal"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_traversal"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -239,7 +239,7 @@ mod tests { #[tokio::test] async fn file_read_blocks_when_rate_limited() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_rate_limited"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_rate_limited"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); tokio::fs::write(dir.join("test.txt"), "hello world") @@ -265,7 +265,7 @@ mod tests { #[tokio::test] async fn file_read_allows_readonly_mode() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_readonly"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_readonly"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); tokio::fs::write(dir.join("test.txt"), "readonly ok") @@ -290,7 +290,7 @@ mod tests { #[tokio::test] async fn file_read_empty_file() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_empty"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_empty"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); tokio::fs::write(dir.join("empty.txt"), "").await.unwrap(); @@ -305,7 +305,7 @@ mod tests { #[tokio::test] async fn file_read_nested_path() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_nested"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_nested"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(dir.join("sub/dir")) .await @@ -330,7 +330,7 @@ mod tests { async fn file_read_blocks_symlink_escape() { use std::os::unix::fs::symlink; - let root = std::env::temp_dir().join("alphahuman_test_file_read_symlink_escape"); + let root = std::env::temp_dir().join("openhuman_test_file_read_symlink_escape"); let workspace = root.join("workspace"); let outside = root.join("outside"); @@ -359,7 +359,7 @@ mod tests { #[tokio::test] async fn file_read_nonexistent_consumes_rate_limit_budget() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_probe"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_probe"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -393,7 +393,7 @@ mod tests { #[tokio::test] async fn file_read_rejects_oversized_file() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_large"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_large"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); diff --git a/src-tauri/src/alphahuman/tools/file_write.rs b/src-tauri/src/openhuman/tools/file_write.rs similarity index 93% rename from src-tauri/src/alphahuman/tools/file_write.rs rename to src-tauri/src/openhuman/tools/file_write.rs index 86e5dee42..94a9011a5 100644 --- a/src-tauri/src/alphahuman/tools/file_write.rs +++ b/src-tauri/src/openhuman/tools/file_write.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -164,7 +164,7 @@ impl Tool for FileWriteTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security(workspace: std::path::PathBuf) -> Arc { Arc::new(SecurityPolicy { @@ -206,7 +206,7 @@ mod tests { #[tokio::test] async fn file_write_creates_file() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write"); + let dir = std::env::temp_dir().join("openhuman_test_file_write"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -228,7 +228,7 @@ mod tests { #[tokio::test] async fn file_write_creates_parent_dirs() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_nested"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_nested"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -249,7 +249,7 @@ mod tests { #[tokio::test] async fn file_write_overwrites_existing() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_overwrite"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_overwrite"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); tokio::fs::write(dir.join("exist.txt"), "old") @@ -273,7 +273,7 @@ mod tests { #[tokio::test] async fn file_write_blocks_path_traversal() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_traversal"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_traversal"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -315,7 +315,7 @@ mod tests { #[tokio::test] async fn file_write_empty_content() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_empty"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_empty"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -335,7 +335,7 @@ mod tests { async fn file_write_blocks_symlink_escape() { use std::os::unix::fs::symlink; - let root = std::env::temp_dir().join("alphahuman_test_file_write_symlink_escape"); + let root = std::env::temp_dir().join("openhuman_test_file_write_symlink_escape"); let workspace = root.join("workspace"); let outside = root.join("outside"); @@ -364,7 +364,7 @@ mod tests { #[tokio::test] async fn file_write_blocks_readonly_mode() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_readonly"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_readonly"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -383,7 +383,7 @@ mod tests { #[tokio::test] async fn file_write_blocks_when_rate_limited() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_rate_limited"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_rate_limited"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -415,7 +415,7 @@ mod tests { async fn file_write_blocks_symlink_target_file() { use std::os::unix::fs::symlink; - let root = std::env::temp_dir().join("alphahuman_test_file_write_symlink_target"); + let root = std::env::temp_dir().join("openhuman_test_file_write_symlink_target"); let workspace = root.join("workspace"); let outside = root.join("outside"); @@ -452,7 +452,7 @@ mod tests { #[tokio::test] async fn file_write_blocks_null_byte_in_path() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_null"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_null"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); diff --git a/src-tauri/src/alphahuman/tools/git_operations.rs b/src-tauri/src/openhuman/tools/git_operations.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/git_operations.rs rename to src-tauri/src/openhuman/tools/git_operations.rs index 077c40e5e..3da5872fb 100644 --- a/src-tauri/src/alphahuman/tools/git_operations.rs +++ b/src-tauri/src/openhuman/tools/git_operations.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; +use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -569,7 +569,7 @@ impl Tool for GitOperationsTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::SecurityPolicy; + use crate::openhuman::security::SecurityPolicy; use tempfile::TempDir; fn test_tool(dir: &std::path::Path) -> GitOperationsTool { diff --git a/src-tauri/src/alphahuman/tools/hardware_board_info.rs b/src-tauri/src/openhuman/tools/hardware_board_info.rs similarity index 100% rename from src-tauri/src/alphahuman/tools/hardware_board_info.rs rename to src-tauri/src/openhuman/tools/hardware_board_info.rs diff --git a/src-tauri/src/alphahuman/tools/hardware_memory_map.rs b/src-tauri/src/openhuman/tools/hardware_memory_map.rs similarity index 100% rename from src-tauri/src/alphahuman/tools/hardware_memory_map.rs rename to src-tauri/src/openhuman/tools/hardware_memory_map.rs diff --git a/src-tauri/src/alphahuman/tools/hardware_memory_read.rs b/src-tauri/src/openhuman/tools/hardware_memory_read.rs similarity index 100% rename from src-tauri/src/alphahuman/tools/hardware_memory_read.rs rename to src-tauri/src/openhuman/tools/hardware_memory_read.rs diff --git a/src-tauri/src/alphahuman/tools/http_request.rs b/src-tauri/src/openhuman/tools/http_request.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/http_request.rs rename to src-tauri/src/openhuman/tools/http_request.rs index 9e19eaa36..19565ca3c 100644 --- a/src-tauri/src/alphahuman/tools/http_request.rs +++ b/src-tauri/src/openhuman/tools/http_request.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -118,7 +118,7 @@ impl HttpRequestTool { .timeout(Duration::from_secs(self.timeout_secs)) .connect_timeout(Duration::from_secs(10)) .redirect(reqwest::redirect::Policy::none()); - let builder = crate::alphahuman::config::apply_runtime_proxy_to_builder(builder, "tool.http_request"); + let builder = crate::openhuman::config::apply_runtime_proxy_to_builder(builder, "tool.http_request"); let client = builder.build()?; let mut request = client.request(method, url); @@ -437,7 +437,7 @@ fn is_non_global_v6(v6: std::net::Ipv6Addr) -> bool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_tool(allowed_domains: Vec<&str>) -> HttpRequestTool { let security = Arc::new(SecurityPolicy { diff --git a/src-tauri/src/alphahuman/tools/image_info.rs b/src-tauri/src/openhuman/tools/image_info.rs similarity index 98% rename from src-tauri/src/alphahuman/tools/image_info.rs rename to src-tauri/src/openhuman/tools/image_info.rs index 077b78923..fdf1538ba 100644 --- a/src-tauri/src/alphahuman/tools/image_info.rs +++ b/src-tauri/src/openhuman/tools/image_info.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::fmt::Write; @@ -231,7 +231,7 @@ impl Tool for ImageInfoTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security() -> Arc { Arc::new(SecurityPolicy { @@ -427,7 +427,7 @@ mod tests { #[tokio::test] async fn execute_real_file() { // Create a minimal valid PNG - let dir = std::env::temp_dir().join("alphahuman_image_info_test"); + let dir = std::env::temp_dir().join("openhuman_image_info_test"); let _ = tokio::fs::create_dir_all(&dir).await; let png_path = dir.join("test.png"); @@ -466,7 +466,7 @@ mod tests { #[tokio::test] async fn execute_with_base64() { - let dir = std::env::temp_dir().join("alphahuman_image_info_b64"); + let dir = std::env::temp_dir().join("openhuman_image_info_b64"); let _ = tokio::fs::create_dir_all(&dir).await; let png_path = dir.join("test_b64.png"); diff --git a/src-tauri/src/alphahuman/tools/memory_forget.rs b/src-tauri/src/openhuman/tools/memory_forget.rs similarity index 95% rename from src-tauri/src/alphahuman/tools/memory_forget.rs rename to src-tauri/src/openhuman/tools/memory_forget.rs index a5795688d..b131bcf6e 100644 --- a/src-tauri/src/alphahuman/tools/memory_forget.rs +++ b/src-tauri/src/openhuman/tools/memory_forget.rs @@ -1,7 +1,7 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::memory::Memory; -use crate::alphahuman::security::policy::ToolOperation; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::memory::Memory; +use crate::openhuman::security::policy::ToolOperation; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -81,8 +81,8 @@ impl Tool for MemoryForgetTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::memory::{MemoryCategory, SqliteMemory}; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::memory::{MemoryCategory, SqliteMemory}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; use tempfile::TempDir; fn test_security() -> Arc { diff --git a/src-tauri/src/alphahuman/tools/memory_recall.rs b/src-tauri/src/openhuman/tools/memory_recall.rs similarity index 97% rename from src-tauri/src/alphahuman/tools/memory_recall.rs rename to src-tauri/src/openhuman/tools/memory_recall.rs index 901c05b8e..4daaa59b6 100644 --- a/src-tauri/src/alphahuman/tools/memory_recall.rs +++ b/src-tauri/src/openhuman/tools/memory_recall.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::memory::Memory; +use crate::openhuman::memory::Memory; use async_trait::async_trait; use serde_json::json; use std::fmt::Write; @@ -91,7 +91,7 @@ impl Tool for MemoryRecallTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::memory::{MemoryCategory, SqliteMemory}; + use crate::openhuman::memory::{MemoryCategory, SqliteMemory}; use tempfile::TempDir; fn seeded_mem() -> (TempDir, Arc) { diff --git a/src-tauri/src/alphahuman/tools/memory_store.rs b/src-tauri/src/openhuman/tools/memory_store.rs similarity index 96% rename from src-tauri/src/alphahuman/tools/memory_store.rs rename to src-tauri/src/openhuman/tools/memory_store.rs index 725b892ae..8471f82e1 100644 --- a/src-tauri/src/alphahuman/tools/memory_store.rs +++ b/src-tauri/src/openhuman/tools/memory_store.rs @@ -1,7 +1,7 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::memory::{Memory, MemoryCategory}; -use crate::alphahuman::security::policy::ToolOperation; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::memory::{Memory, MemoryCategory}; +use crate::openhuman::security::policy::ToolOperation; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -96,8 +96,8 @@ impl Tool for MemoryStoreTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::memory::SqliteMemory; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::memory::SqliteMemory; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; use tempfile::TempDir; fn test_security() -> Arc { diff --git a/src-tauri/src/alphahuman/tools/mod.rs b/src-tauri/src/openhuman/tools/mod.rs similarity index 91% rename from src-tauri/src/alphahuman/tools/mod.rs rename to src-tauri/src/openhuman/tools/mod.rs index 5fab89d6e..6bf8526a3 100644 --- a/src-tauri/src/alphahuman/tools/mod.rs +++ b/src-tauri/src/openhuman/tools/mod.rs @@ -61,10 +61,10 @@ pub use traits::Tool; pub use traits::{ToolResult, ToolSpec}; pub use web_search_tool::WebSearchTool; -use crate::alphahuman::config::{Config, DelegateAgentConfig}; -use crate::alphahuman::memory::Memory; -use crate::alphahuman::runtime::{NativeRuntime, RuntimeAdapter}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::{Config, DelegateAgentConfig}; +use crate::openhuman::memory::Memory; +use crate::openhuman::runtime::{NativeRuntime, RuntimeAdapter}; +use crate::openhuman::security::SecurityPolicy; use std::collections::HashMap; use std::sync::Arc; @@ -93,12 +93,12 @@ pub fn all_tools( memory: Arc, composio_key: Option<&str>, composio_entity_id: Option<&str>, - browser_config: &crate::alphahuman::config::BrowserConfig, - http_config: &crate::alphahuman::config::HttpRequestConfig, + browser_config: &crate::openhuman::config::BrowserConfig, + http_config: &crate::openhuman::config::HttpRequestConfig, workspace_dir: &std::path::Path, agents: &HashMap, fallback_api_key: Option<&str>, - root_config: &crate::alphahuman::config::Config, + root_config: &crate::openhuman::config::Config, ) -> Vec> { all_tools_with_runtime( config, @@ -125,12 +125,12 @@ pub fn all_tools_with_runtime( memory: Arc, composio_key: Option<&str>, composio_entity_id: Option<&str>, - browser_config: &crate::alphahuman::config::BrowserConfig, - http_config: &crate::alphahuman::config::HttpRequestConfig, + browser_config: &crate::openhuman::config::BrowserConfig, + http_config: &crate::openhuman::config::HttpRequestConfig, workspace_dir: &std::path::Path, agents: &HashMap, fallback_api_key: Option<&str>, - root_config: &crate::alphahuman::config::Config, + root_config: &crate::openhuman::config::Config, ) -> Vec> { let mut tools: Vec> = vec![ Box::new(ShellTool::new(security.clone(), runtime)), @@ -231,9 +231,9 @@ pub fn all_tools_with_runtime( delegate_agents, delegate_fallback_credential, security.clone(), - crate::alphahuman::providers::ProviderRuntimeOptions { + crate::openhuman::providers::ProviderRuntimeOptions { auth_profile_override: None, - alphahuman_dir: root_config + openhuman_dir: root_config .config_path .parent() .map(std::path::PathBuf::from), @@ -249,7 +249,7 @@ pub fn all_tools_with_runtime( #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::{BrowserConfig, Config, MemoryConfig}; + use crate::openhuman::config::{BrowserConfig, Config, MemoryConfig}; use tempfile::TempDir; fn test_config(tmp: &TempDir) -> Config { @@ -276,7 +276,7 @@ mod tests { ..MemoryConfig::default() }; let mem: Arc = - Arc::from(crate::alphahuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); + Arc::from(crate::openhuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); let browser = BrowserConfig { enabled: false, @@ -284,7 +284,7 @@ mod tests { session_name: None, ..BrowserConfig::default() }; - let http = crate::alphahuman::config::HttpRequestConfig::default(); + let http = crate::openhuman::config::HttpRequestConfig::default(); let cfg = test_config(&tmp); let tools = all_tools( @@ -316,7 +316,7 @@ mod tests { ..MemoryConfig::default() }; let mem: Arc = - Arc::from(crate::alphahuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); + Arc::from(crate::openhuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); let browser = BrowserConfig { enabled: true, @@ -324,7 +324,7 @@ mod tests { session_name: None, ..BrowserConfig::default() }; - let http = crate::alphahuman::config::HttpRequestConfig::default(); + let http = crate::openhuman::config::HttpRequestConfig::default(); let cfg = test_config(&tmp); let tools = all_tools( @@ -449,10 +449,10 @@ mod tests { ..MemoryConfig::default() }; let mem: Arc = - Arc::from(crate::alphahuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); + Arc::from(crate::openhuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); let browser = BrowserConfig::default(); - let http = crate::alphahuman::config::HttpRequestConfig::default(); + let http = crate::openhuman::config::HttpRequestConfig::default(); let cfg = test_config(&tmp); let mut agents = HashMap::new(); @@ -494,10 +494,10 @@ mod tests { ..MemoryConfig::default() }; let mem: Arc = - Arc::from(crate::alphahuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); + Arc::from(crate::openhuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); let browser = BrowserConfig::default(); - let http = crate::alphahuman::config::HttpRequestConfig::default(); + let http = crate::openhuman::config::HttpRequestConfig::default(); let cfg = test_config(&tmp); let tools = all_tools( diff --git a/src-tauri/src/alphahuman/tools/proxy_config.rs b/src-tauri/src/openhuman/tools/proxy_config.rs similarity index 97% rename from src-tauri/src/alphahuman/tools/proxy_config.rs rename to src-tauri/src/openhuman/tools/proxy_config.rs index e976220c4..40716eeb2 100644 --- a/src-tauri/src/alphahuman/tools/proxy_config.rs +++ b/src-tauri/src/openhuman/tools/proxy_config.rs @@ -1,9 +1,9 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::{ +use crate::openhuman::config::{ runtime_proxy_config, set_runtime_proxy_config, Config, ProxyConfig, ProxyScope, }; -use crate::alphahuman::security::SecurityPolicy; -use crate::alphahuman::util::MaybeSet; +use crate::openhuman::security::SecurityPolicy; +use crate::openhuman::util::MaybeSet; use async_trait::async_trait; use serde_json::{json, Value}; use std::fs; @@ -61,7 +61,7 @@ impl ProxyConfigTool { fn parse_scope(raw: &str) -> Option { match raw.trim().to_ascii_lowercase().as_str() { "environment" | "env" => Some(ProxyScope::Environment), - "alphahuman" | "internal" | "core" => Some(ProxyScope::Alphahuman), + "openhuman" | "internal" | "core" => Some(ProxyScope::OpenHuman), "services" | "service" => Some(ProxyScope::Services), _ => None, } @@ -185,7 +185,7 @@ impl ProxyConfigTool { .as_str() .ok_or_else(|| anyhow::anyhow!("'scope' must be a string"))?; proxy.scope = Self::parse_scope(scope).ok_or_else(|| { - anyhow::anyhow!("Invalid scope '{scope}'. Use environment|alphahuman|services") + anyhow::anyhow!("Invalid scope '{scope}'. Use environment|openhuman|services") })?; } @@ -342,7 +342,7 @@ impl Tool for ProxyConfigTool { } fn description(&self) -> &str { - "Manage Alphahuman proxy settings (scope: environment | alphahuman | services), including runtime and process env application" + "Manage OpenHuman proxy settings (scope: environment | openhuman | services), including runtime and process env application" } fn parameters_schema(&self) -> Value { @@ -360,7 +360,7 @@ impl Tool for ProxyConfigTool { }, "scope": { "type": "string", - "description": "Proxy scope: environment | alphahuman | services" + "description": "Proxy scope: environment | openhuman | services" }, "http_proxy": { "type": ["string", "null"], @@ -438,7 +438,7 @@ impl Tool for ProxyConfigTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; use tempfile::TempDir; fn test_security() -> Arc { diff --git a/src-tauri/src/alphahuman/tools/pushover.rs b/src-tauri/src/openhuman/tools/pushover.rs similarity index 98% rename from src-tauri/src/alphahuman/tools/pushover.rs rename to src-tauri/src/openhuman/tools/pushover.rs index c4a838f51..f56a215f8 100644 --- a/src-tauri/src/alphahuman/tools/pushover.rs +++ b/src-tauri/src/openhuman/tools/pushover.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::path::PathBuf; @@ -173,7 +173,7 @@ impl Tool for PushoverTool { form = form.text("sound", sound); } - let client = crate::alphahuman::config::build_runtime_proxy_client_with_timeouts( + let client = crate::openhuman::config::build_runtime_proxy_client_with_timeouts( "tool.pushover", PUSHOVER_REQUEST_TIMEOUT_SECS, 10, @@ -217,7 +217,7 @@ impl Tool for PushoverTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::AutonomyLevel; + use crate::openhuman::security::AutonomyLevel; use std::fs; use tempfile::TempDir; diff --git a/src-tauri/src/alphahuman/tools/schedule.rs b/src-tauri/src/openhuman/tools/schedule.rs similarity index 98% rename from src-tauri/src/alphahuman/tools/schedule.rs rename to src-tauri/src/openhuman/tools/schedule.rs index 8730b3b43..9af475000 100644 --- a/src-tauri/src/alphahuman/tools/schedule.rs +++ b/src-tauri/src/openhuman/tools/schedule.rs @@ -1,7 +1,7 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::Config; +use crate::openhuman::cron; +use crate::openhuman::security::SecurityPolicy; use anyhow::Result; use async_trait::async_trait; use chrono::{DateTime, Utc}; @@ -365,7 +365,7 @@ impl ScheduleTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::AutonomyLevel; + use crate::openhuman::security::AutonomyLevel; use tempfile::TempDir; async fn test_setup() -> (TempDir, Config, Arc) { @@ -485,7 +485,7 @@ mod tests { let config = Config { workspace_dir: tmp.path().join("workspace"), config_path: tmp.path().join("config.toml"), - autonomy: crate::alphahuman::config::AutonomyConfig { + autonomy: crate::openhuman::config::AutonomyConfig { level: AutonomyLevel::ReadOnly, ..Default::default() }, diff --git a/src-tauri/src/alphahuman/tools/schema.rs b/src-tauri/src/openhuman/tools/schema.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/schema.rs rename to src-tauri/src/openhuman/tools/schema.rs index 75b4f8319..51da111e9 100644 --- a/src-tauri/src/alphahuman/tools/schema.rs +++ b/src-tauri/src/openhuman/tools/schema.rs @@ -17,7 +17,7 @@ //! //! ```rust //! use serde_json::json; -//! use tauri_app_lib::alphahuman::tools::schema::SchemaCleanr; +//! use tauri_app_lib::openhuman::tools::schema::SchemaCleanr; //! //! let dirty_schema = json!({ //! "type": "object", diff --git a/src-tauri/src/alphahuman/tools/screenshot.rs b/src-tauri/src/openhuman/tools/screenshot.rs similarity index 98% rename from src-tauri/src/alphahuman/tools/screenshot.rs rename to src-tauri/src/openhuman/tools/screenshot.rs index d131eada3..d43e2fd1d 100644 --- a/src-tauri/src/alphahuman/tools/screenshot.rs +++ b/src-tauri/src/openhuman/tools/screenshot.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::fmt::Write; @@ -252,7 +252,7 @@ impl Tool for ScreenshotTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security() -> Arc { Arc::new(SecurityPolicy { diff --git a/src-tauri/src/alphahuman/tools/shell.rs b/src-tauri/src/openhuman/tools/shell.rs similarity index 95% rename from src-tauri/src/alphahuman/tools/shell.rs rename to src-tauri/src/openhuman/tools/shell.rs index f6a866e7b..e29c83650 100644 --- a/src-tauri/src/alphahuman/tools/shell.rs +++ b/src-tauri/src/openhuman/tools/shell.rs @@ -1,6 +1,6 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::runtime::RuntimeAdapter; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::runtime::RuntimeAdapter; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -164,8 +164,8 @@ impl Tool for ShellTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::runtime::{NativeRuntime, RuntimeAdapter}; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::runtime::{NativeRuntime, RuntimeAdapter}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security(autonomy: AutonomyLevel) -> Arc { Arc::new(SecurityPolicy { @@ -293,7 +293,7 @@ mod tests { #[tokio::test(flavor = "current_thread")] async fn shell_does_not_leak_api_key() { let _g1 = EnvGuard::set("API_KEY", "sk-test-secret-12345"); - let _g2 = EnvGuard::set("ALPHAHUMAN_API_KEY", "sk-test-secret-67890"); + let _g2 = EnvGuard::set("OPENHUMAN_API_KEY", "sk-test-secret-67890"); let tool = ShellTool::new(test_security_with_env_cmd(), test_runtime()); let result = tool.execute(json!({"command": "env"})).await.unwrap(); @@ -304,7 +304,7 @@ mod tests { ); assert!( !result.output.contains("sk-test-secret-67890"), - "ALPHAHUMAN_API_KEY leaked to shell command output" + "OPENHUMAN_API_KEY leaked to shell command output" ); } @@ -344,7 +344,7 @@ mod tests { let tool = ShellTool::new(security.clone(), test_runtime()); let denied = tool - .execute(json!({"command": "touch alphahuman_shell_approval_test"})) + .execute(json!({"command": "touch openhuman_shell_approval_test"})) .await .unwrap(); assert!(!denied.success); @@ -356,7 +356,7 @@ mod tests { let allowed = tool .execute(json!({ - "command": "touch alphahuman_shell_approval_test", + "command": "touch openhuman_shell_approval_test", "approved": true })) .await @@ -364,7 +364,7 @@ mod tests { assert!(allowed.success); let _ = - tokio::fs::remove_file(std::env::temp_dir().join("alphahuman_shell_approval_test")).await; + tokio::fs::remove_file(std::env::temp_dir().join("openhuman_shell_approval_test")).await; } // ── §5.2 Shell timeout enforcement tests ───────────────── diff --git a/src-tauri/src/alphahuman/tools/traits.rs b/src-tauri/src/openhuman/tools/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/tools/traits.rs rename to src-tauri/src/openhuman/tools/traits.rs diff --git a/src-tauri/src/alphahuman/tools/web_search_tool.rs b/src-tauri/src/openhuman/tools/web_search_tool.rs similarity index 100% rename from src-tauri/src/alphahuman/tools/web_search_tool.rs rename to src-tauri/src/openhuman/tools/web_search_tool.rs diff --git a/src-tauri/src/alphahuman/tunnel/cloudflare.rs b/src-tauri/src/openhuman/tunnel/cloudflare.rs similarity index 100% rename from src-tauri/src/alphahuman/tunnel/cloudflare.rs rename to src-tauri/src/openhuman/tunnel/cloudflare.rs diff --git a/src-tauri/src/alphahuman/tunnel/custom.rs b/src-tauri/src/openhuman/tunnel/custom.rs similarity index 98% rename from src-tauri/src/alphahuman/tunnel/custom.rs rename to src-tauri/src/openhuman/tunnel/custom.rs index db94fece8..dc74148fc 100644 --- a/src-tauri/src/alphahuman/tunnel/custom.rs +++ b/src-tauri/src/openhuman/tunnel/custom.rs @@ -123,7 +123,7 @@ impl Tunnel for CustomTunnel { async fn health_check(&self) -> bool { // If a health URL is configured, try to reach it if let Some(ref url) = self.health_url { - return crate::alphahuman::config::build_runtime_proxy_client("tunnel.custom") + return crate::openhuman::config::build_runtime_proxy_client("tunnel.custom") .get(url) .timeout(std::time::Duration::from_secs(5)) .send() diff --git a/src-tauri/src/alphahuman/tunnel/mod.rs b/src-tauri/src/openhuman/tunnel/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/tunnel/mod.rs rename to src-tauri/src/openhuman/tunnel/mod.rs index bbe2af9c2..17fad2b26 100644 --- a/src-tauri/src/alphahuman/tunnel/mod.rs +++ b/src-tauri/src/openhuman/tunnel/mod.rs @@ -11,7 +11,7 @@ pub use ngrok::NgrokTunnel; pub use none::NoneTunnel; pub use tailscale::TailscaleTunnel; -use crate::alphahuman::config::{TailscaleTunnelConfig, TunnelConfig}; +use crate::openhuman::config::{TailscaleTunnelConfig, TunnelConfig}; use anyhow::{bail, Result}; use std::sync::Arc; use tokio::sync::Mutex; @@ -130,7 +130,7 @@ pub fn create_tunnel(config: &TunnelConfig) -> Result>> { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::{ + use crate::openhuman::config::{ CloudflareTunnelConfig, CustomTunnelConfig, NgrokTunnelConfig, }; diff --git a/src-tauri/src/alphahuman/tunnel/ngrok.rs b/src-tauri/src/openhuman/tunnel/ngrok.rs similarity index 100% rename from src-tauri/src/alphahuman/tunnel/ngrok.rs rename to src-tauri/src/openhuman/tunnel/ngrok.rs diff --git a/src-tauri/src/alphahuman/tunnel/none.rs b/src-tauri/src/openhuman/tunnel/none.rs similarity index 100% rename from src-tauri/src/alphahuman/tunnel/none.rs rename to src-tauri/src/openhuman/tunnel/none.rs diff --git a/src-tauri/src/alphahuman/tunnel/tailscale.rs b/src-tauri/src/openhuman/tunnel/tailscale.rs similarity index 100% rename from src-tauri/src/alphahuman/tunnel/tailscale.rs rename to src-tauri/src/openhuman/tunnel/tailscale.rs diff --git a/src-tauri/src/alphahuman/util.rs b/src-tauri/src/openhuman/util.rs similarity index 97% rename from src-tauri/src/alphahuman/util.rs rename to src-tauri/src/openhuman/util.rs index 812dcac5d..927251538 100644 --- a/src-tauri/src/alphahuman/util.rs +++ b/src-tauri/src/openhuman/util.rs @@ -1,4 +1,4 @@ -//! Utility functions for `Alphahuman`. +//! Utility functions for `OpenHuman`. //! //! This module contains reusable helper functions used across the codebase. @@ -17,7 +17,7 @@ /// /// # Examples /// ``` -/// use tauri_app_lib::alphahuman::util::truncate_with_ellipsis; +/// use tauri_app_lib::openhuman::util::truncate_with_ellipsis; /// /// // ASCII string - no truncation needed /// assert_eq!(truncate_with_ellipsis("hello", 10), "hello"); diff --git a/src-tauri/src/runtime/bridge/db.rs b/src-tauri/src/runtime/bridge/db.rs index 1a2e251ea..45ba62557 100644 --- a/src-tauri/src/runtime/bridge/db.rs +++ b/src-tauri/src/runtime/bridge/db.rs @@ -1,4 +1,4 @@ -//! @alphahuman/db bridge — scoped SQLite access for each skill. +//! @openhuman/db bridge — scoped SQLite access for each skill. //! //! Each skill gets its own SQLite database at `{app_data_dir}/skills/{skill_id}/skill.db`. //! The bridge exposes async functions callable from JS: diff --git a/src-tauri/src/runtime/bridge/log_bridge.rs b/src-tauri/src/runtime/bridge/log_bridge.rs index 37c81dcc2..119a03758 100644 --- a/src-tauri/src/runtime/bridge/log_bridge.rs +++ b/src-tauri/src/runtime/bridge/log_bridge.rs @@ -1,4 +1,4 @@ -//! @alphahuman/log bridge — structured logging from JS skills. +//! @openhuman/log bridge — structured logging from JS skills. //! //! Exposes log levels: debug, info, warn, error. //! Logs are forwarded to Rust's `log` crate AND emitted as Tauri events diff --git a/src-tauri/src/runtime/bridge/store.rs b/src-tauri/src/runtime/bridge/store.rs index 90a31e5a9..4ab169dcd 100644 --- a/src-tauri/src/runtime/bridge/store.rs +++ b/src-tauri/src/runtime/bridge/store.rs @@ -1,4 +1,4 @@ -//! @alphahuman/store bridge — persisted key-value state for skills. +//! @openhuman/store bridge — persisted key-value state for skills. //! //! Thin wrapper around the __kv table in each skill's SQLite database. //! Provides a simpler API than raw SQL for common state persistence patterns. diff --git a/src-tauri/src/runtime/loader.rs b/src-tauri/src/runtime/loader.rs index 7479035de..8b82b8068 100644 --- a/src-tauri/src/runtime/loader.rs +++ b/src-tauri/src/runtime/loader.rs @@ -1,8 +1,8 @@ -//! Custom module resolver and loader for `@alphahuman/*` imports. +//! Custom module resolver and loader for `@openhuman/*` imports. //! //! NOTE: Currently unused. Skills access bridge APIs via globals (db, store, console) //! injected by qjs_skill_instance.rs. This module is reserved for future ES module -//! import support (e.g., `import { db } from '@alphahuman/db'`). +//! import support (e.g., `import { db } from '@openhuman/db'`). //! //! The globals-based approach was chosen because: //! - Globals are simpler and sufficient for the initial implementation diff --git a/src-tauri/src/runtime/manifest.rs b/src-tauri/src/runtime/manifest.rs index c667b8883..4624b7e2f 100644 --- a/src-tauri/src/runtime/manifest.rs +++ b/src-tauri/src/runtime/manifest.rs @@ -51,14 +51,14 @@ pub struct SkillManifest { #[serde(default)] pub platforms: Option>, /// Skill type for the unified registry dispatch. - /// "alphahuman" → executed via QuickJS runtime (default). + /// "openhuman" → executed via QuickJS runtime (default). /// "openclaw" → loaded and executed from SKILL.md/SKILL.toml. #[serde(default = "default_skill_type")] pub skill_type: String, } fn default_skill_type() -> String { - "alphahuman".to_string() + "openhuman".to_string() } fn default_runtime() -> String { diff --git a/src-tauri/src/runtime/qjs_engine.rs b/src-tauri/src/runtime/qjs_engine.rs index 7c2c994fe..278a6e24f 100644 --- a/src-tauri/src/runtime/qjs_engine.rs +++ b/src-tauri/src/runtime/qjs_engine.rs @@ -17,7 +17,7 @@ use crate::runtime::skill_registry::SkillRegistry; use crate::runtime::socket_manager::SocketManager; use crate::runtime::types::{events, SkillMessage, SkillSnapshot, SkillStatus, ToolResult}; use crate::runtime::qjs_skill_instance::{BridgeDeps, QjsSkillInstance}; -// IdbStorage removed with TDLib cleanup +// IdbStorage removed during runtime cleanup /// The central runtime engine using QuickJS. pub struct RuntimeEngine { @@ -463,20 +463,20 @@ impl RuntimeEngine { } /// Read a KV value from a skill's database. - /// TODO: Removed with TDLib cleanup - reimplement if needed + /// TODO: Removed during runtime cleanup - reimplement if needed pub fn kv_get(&self, _skill_id: &str, _key: &str) -> Result { - Err("KV storage removed with TDLib cleanup".to_string()) + Err("KV storage removed during runtime cleanup".to_string()) } /// Write a KV value into a skill's database. - /// TODO: Removed with TDLib cleanup - reimplement if needed + /// TODO: Removed during runtime cleanup - reimplement if needed pub fn kv_set( &self, _skill_id: &str, _key: &str, _value: &serde_json::Value, ) -> Result<(), String> { - Err("KV storage removed with TDLib cleanup".to_string()) + Err("KV storage removed during runtime cleanup".to_string()) } /// Route a JSON-RPC method call. diff --git a/src-tauri/src/runtime/types.rs b/src-tauri/src/runtime/types.rs index 14908d90a..86ab4c4b2 100644 --- a/src-tauri/src/runtime/types.rs +++ b/src-tauri/src/runtime/types.rs @@ -170,14 +170,14 @@ fn default_memory_limit() -> usize { 256 * 1024 * 1024 // 256 MB } -/// A skill entry in the unified registry (covers both alphahuman and openclaw types). +/// A skill entry in the unified registry (covers both openhuman and openclaw types). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct UnifiedSkillEntry { /// Unique skill identifier. pub id: String, /// Human-readable name. pub name: String, - /// Skill type: "alphahuman" (QuickJS) or "openclaw" (SKILL.md/TOML). + /// Skill type: "openhuman" (QuickJS) or "openclaw" (SKILL.md/TOML). pub skill_type: String, /// Version string. pub version: String, diff --git a/src-tauri/src/services/quickjs_libs/bootstrap.js b/src-tauri/src/services/quickjs_libs/bootstrap.js index 64e56b915..23ca2de4e 100644 --- a/src-tauri/src/services/quickjs_libs/bootstrap.js +++ b/src-tauri/src/services/quickjs_libs/bootstrap.js @@ -1,7 +1,7 @@ /** * Bootstrap JavaScript for QuickJS Runtime * - * Provides browser-like API shims that tdweb expects. + * Provides browser-like API shims for skill execution. * These shims call Rust "ops" for actual I/O. */ @@ -343,7 +343,7 @@ WebSocket._instances = new Map(); globalThis.WebSocket = WebSocket; // ============================================================================ -// IndexedDB API (for tdweb persistence) +// IndexedDB API (persistent local storage) // ============================================================================ class IDBFactory { open(name, version = 1) { @@ -846,7 +846,7 @@ globalThis.data = { body: JSON.stringify({ error: 'No OAuth credential. Complete OAuth setup first.' }), }; } - var backendUrl = __platform.env('BACKEND_URL') || 'https://api.alphahuman.xyz'; + var backendUrl = __platform.env('BACKEND_URL') || 'https://api.tinyhumans.ai'; var jwtToken = __ops.get_session_token() || ''; var cleanPath = path.charAt(0) === '/' ? path.slice(1) : path; var proxyUrl = backendUrl + '/proxy/by-id/' + globalThis.__oauthCredential.credentialId + '/' + cleanPath; @@ -875,7 +875,7 @@ globalThis.data = { revoke: async function () { if (__oauthCredential) { try { - var backendUrl = __platform.env('BACKEND_URL') || 'https://api.alphahuman.xyz'; + var backendUrl = __platform.env('BACKEND_URL') || 'https://api.tinyhumans.ai'; var jwtToken = __ops.get_session_token() || ''; var revokeOpts = JSON.stringify({ method: 'DELETE', @@ -940,74 +940,6 @@ globalThis.skills = { }, }; -// ============================================================================ -// TDLib Bridge API (telegram skill only) -// ============================================================================ -// Provides native TDLib access for the telegram skill. -// This is only available on desktop - Android uses Tauri invoke() instead. - -globalThis.tdlib = { - /** - * Check if TDLib ops are available. - * @returns {boolean} True on desktop, false on mobile/web. - */ - isAvailable: function () { - try { - return typeof __ops?.tdlib_is_available === 'function' - ? __ops.tdlib_is_available() - : false; - } catch (e) { - return false; - } - }, - - /** - * Create client and set TDLib parameters in a single atomic call. - * API credentials are stored on the Rust side only. - * @param {string} dataDir - Path to store TDLib data files. - * @returns {Promise} Client ID. - */ - ensureInitialized: async function (dataDir) { - return await __ops.tdlib_ensure_initialized(dataDir); - }, - - /** - * Create a TDLib client with the given data directory. - * @param {string} dataDir - Path to store TDLib data files. - * @returns {Promise} Client ID (always 1 for singleton). - */ - createClient: function (dataDir) { - return __ops.tdlib_create_client(dataDir); - }, - - /** - * Send a TDLib request and wait for the response. - * @param {string} requestJson - JSON-serialized TDLib API request with @type field. - * @returns {Promise} JSON-serialized TDLib response. - */ - send: async function (requestJson) { - return await __ops.tdlib_send(requestJson); - }, - - /** - * Receive the next TDLib update (with timeout). - * @param {number} [timeoutMs=1000] - Timeout in milliseconds. - * @returns {Promise} Update object or null if timeout. - */ - receive: async function (timeoutMs = 1000) { - const resultJson = await __ops.tdlib_receive(timeoutMs); - return resultJson ? JSON.parse(resultJson) : null; - }, - - /** - * Destroy the TDLib client and clean up resources. - * @returns {Promise} - */ - destroy: async function () { - return await __ops.tdlib_destroy(); - }, -}; - // ============================================================================ // Model Bridge API (routes to cloud backend) // ============================================================================ @@ -1022,7 +954,7 @@ globalThis.model = { * @returns {string} */ generate: async function (prompt, options) { - var backendUrl = __platform.env('BACKEND_URL') || 'https://api.alphahuman.xyz'; + var backendUrl = __platform.env('BACKEND_URL') || 'https://api.tinyhumans.ai'; var jwtToken = __ops.get_session_token() || ''; var body = { prompt: prompt }; if (options && options.maxTokens) body.maxTokens = options.maxTokens; @@ -1052,7 +984,7 @@ globalThis.model = { * @returns {string} */ summarize: async function (text, options) { - var backendUrl = __platform.env('BACKEND_URL') || 'https://api.alphahuman.xyz'; + var backendUrl = __platform.env('BACKEND_URL') || 'https://api.tinyhumans.ai'; var jwtToken = __ops.get_session_token() || ''; var body = { text: text }; if (options && options.maxTokens) body.maxTokens = options.maxTokens; diff --git a/src-tauri/src/services/quickjs_libs/mod.rs b/src-tauri/src/services/quickjs_libs/mod.rs index aa590cdfb..dc0fd8855 100644 --- a/src-tauri/src/services/quickjs_libs/mod.rs +++ b/src-tauri/src/services/quickjs_libs/mod.rs @@ -1,13 +1,10 @@ -//! TDLib Runtime Module +//! QuickJS Runtime Support Module //! //! Provides a QuickJS JavaScript runtime (via rquickjs) for running -//! skill JavaScript code and TDLib integration. Provides a browser-like +//! skill JavaScript code and supporting browser-like shims. //! environment for skill execution. pub mod qjs_ops; -pub mod service; pub mod storage; -#[allow(unused_imports)] -pub use service::{TdClientAdapter, TdClientConfig, TdUpdate, TdlibV8Service}; pub use storage::IdbStorage; diff --git a/src-tauri/src/services/quickjs_libs/qjs_ops/types.rs b/src-tauri/src/services/quickjs_libs/qjs_ops/types.rs index b82cc8b35..a211f31ca 100644 --- a/src-tauri/src/services/quickjs_libs/qjs_ops/types.rs +++ b/src-tauri/src/services/quickjs_libs/qjs_ops/types.rs @@ -125,19 +125,9 @@ pub const ALLOWED_ENV_VARS: &[&str] = &[ "VITE_BACKEND_URL", "BACKEND_URL", "JWT_TOKEN", - "VITE_TELEGRAM_BOT_USERNAME", - "VITE_TELEGRAM_BOT_ID", "NODE_ENV", ]; -pub fn check_telegram_skill(skill_id: &str) -> Result<(), String> { - if skill_id != "telegram" { - Err("TDLib operations only available in telegram skill".to_string()) - } else { - Ok(()) - } -} - /// Sanitize error message for use with QuickJS/rquickjs. /// Some messages (e.g. from SQLite "Invalid symbol 45, offset 19") can trigger /// "Invalid symbol" when rquickjs creates the JS exception — avoid comma and hyphen. diff --git a/src-tauri/src/services/quickjs_libs/service.rs b/src-tauri/src/services/quickjs_libs/service.rs deleted file mode 100644 index f9b886d0b..000000000 --- a/src-tauri/src/services/quickjs_libs/service.rs +++ /dev/null @@ -1,457 +0,0 @@ -//! TdlibV8Service — High-level TDLib service using V8 runtime. -//! -//! Manages TDLib client instances running in V8 with tdweb. -//! Provides async send/receive interface and update broadcasting. - -use std::path::PathBuf; - -use serde::{Deserialize, Serialize}; -use tokio::sync::{broadcast, mpsc, oneshot}; - -use super::storage::IdbStorage; - -/// Configuration for a TDLib client. -#[derive(Debug, Clone, Serialize, Deserialize)] -#[allow(dead_code)] -pub struct TdClientConfig { - /// API ID from my.telegram.org - pub api_id: i32, - /// API hash from my.telegram.org - pub api_hash: String, - /// Database directory name - pub database_directory: String, - /// Files directory name - pub files_directory: String, - /// Use test DC - #[serde(default)] - pub use_test_dc: bool, - /// Use file database - #[serde(default = "default_true")] - pub use_file_database: bool, - /// Use chat info database - #[serde(default = "default_true")] - pub use_chat_info_database: bool, - /// Use message database - #[serde(default = "default_true")] - pub use_message_database: bool, - /// System language code - #[serde(default = "default_lang")] - pub system_language_code: String, - /// Device model - #[serde(default = "default_device")] - pub device_model: String, - /// Application version - #[serde(default = "default_version")] - pub application_version: String, -} - -#[allow(dead_code)] -fn default_true() -> bool { - true -} - -#[allow(dead_code)] -fn default_lang() -> String { - "en".to_string() -} - -#[allow(dead_code)] -fn default_device() -> String { - "Desktop".to_string() -} - -#[allow(dead_code)] -fn default_version() -> String { - "1.0.0".to_string() -} - -impl Default for TdClientConfig { - fn default() -> Self { - Self { - api_id: 0, - api_hash: String::new(), - database_directory: "tdlib".to_string(), - files_directory: "tdlib_files".to_string(), - use_test_dc: false, - use_file_database: true, - use_chat_info_database: true, - use_message_database: true, - system_language_code: "en".to_string(), - device_model: "Desktop".to_string(), - application_version: "1.0.0".to_string(), - } - } -} - -/// A TDLib update received from the server. -#[derive(Debug, Clone, Serialize, Deserialize)] -#[allow(dead_code)] -pub struct TdUpdate { - /// The update type (e.g., "updateNewMessage") - #[serde(rename = "@type")] - pub update_type: String, - /// The full update data - #[serde(flatten)] - pub data: serde_json::Value, -} - -/// Messages sent to the TDLib service. -#[derive(Debug)] -#[allow(dead_code)] -pub enum TdServiceMessage { - /// Send a TDLib query - Send { - user_id: String, - query: serde_json::Value, - reply: oneshot::Sender>, - }, - /// Get current auth state - GetAuthState { - user_id: String, - reply: oneshot::Sender>, - }, - /// Create a new client - CreateClient { - user_id: String, - config: TdClientConfig, - reply: oneshot::Sender>, - }, - /// Destroy a client - DestroyClient { - user_id: String, - reply: oneshot::Sender>, - }, - /// Stop the service - Stop, -} - -/// State for a single TDLib client. -#[allow(dead_code)] -struct TdClientState { - /// Current authorization state - auth_state: serde_json::Value, - /// Whether the client is ready - is_ready: bool, -} - -/// TDLib V8 Service that manages TDLib clients. -#[allow(dead_code)] -pub struct TdlibV8Service { - /// Data directory for TDLib databases - data_dir: PathBuf, - /// Storage layer for IndexedDB emulation - storage: IdbStorage, - /// Message sender for the service - tx: mpsc::Sender, - /// Update broadcaster - update_tx: broadcast::Sender<(String, TdUpdate)>, -} - -#[allow(dead_code)] -impl TdlibV8Service { - /// Create a new TDLib V8 service. - pub async fn new(data_dir: PathBuf) -> Result { - let storage = IdbStorage::new(&data_dir)?; - let (tx, _rx) = mpsc::channel(64); - let (update_tx, _) = broadcast::channel(256); - - let service = Self { - data_dir, - storage, - tx, - update_tx, - }; - - Ok(service) - } - - /// Get a sender for the service. - pub fn sender(&self) -> mpsc::Sender { - self.tx.clone() - } - - /// Subscribe to TDLib updates. - /// Returns a receiver that will receive (user_id, update) tuples. - pub fn subscribe(&self) -> broadcast::Receiver<(String, TdUpdate)> { - self.update_tx.subscribe() - } - - /// Send a query to TDLib. - pub async fn send( - &self, - user_id: &str, - query: serde_json::Value, - ) -> Result { - let (reply_tx, reply_rx) = oneshot::channel(); - - self.tx - .send(TdServiceMessage::Send { - user_id: user_id.to_string(), - query, - reply: reply_tx, - }) - .await - .map_err(|e| format!("Failed to send query: {e}"))?; - - reply_rx - .await - .map_err(|_| "Service did not respond".to_string())? - } - - /// Get the current authorization state. - pub async fn get_auth_state(&self, user_id: &str) -> Result { - let (reply_tx, reply_rx) = oneshot::channel(); - - self.tx - .send(TdServiceMessage::GetAuthState { - user_id: user_id.to_string(), - reply: reply_tx, - }) - .await - .map_err(|e| format!("Failed to get auth state: {e}"))?; - - reply_rx - .await - .map_err(|_| "Service did not respond".to_string())? - } - - /// Create a new TDLib client for a user. - pub async fn create_client( - &self, - user_id: &str, - config: TdClientConfig, - ) -> Result<(), String> { - let (reply_tx, reply_rx) = oneshot::channel(); - - self.tx - .send(TdServiceMessage::CreateClient { - user_id: user_id.to_string(), - config, - reply: reply_tx, - }) - .await - .map_err(|e| format!("Failed to create client: {e}"))?; - - reply_rx - .await - .map_err(|_| "Service did not respond".to_string())? - } - - /// Destroy a TDLib client. - pub async fn destroy_client(&self, user_id: &str) -> Result<(), String> { - let (reply_tx, reply_rx) = oneshot::channel(); - - self.tx - .send(TdServiceMessage::DestroyClient { - user_id: user_id.to_string(), - reply: reply_tx, - }) - .await - .map_err(|e| format!("Failed to destroy client: {e}"))?; - - reply_rx - .await - .map_err(|_| "Service did not respond".to_string())? - } -} - -/// TDLib client adapter that wraps a V8 runtime. -/// -/// This is a placeholder for the full tdweb integration. -/// In the full implementation, this would: -/// 1. Load the tdweb JavaScript bundle -/// 2. Initialize TdClient with the WASM module -/// 3. Handle send/receive through the V8 runtime -#[allow(dead_code)] -pub struct TdClientAdapter { - user_id: String, - config: TdClientConfig, - data_dir: PathBuf, - storage: IdbStorage, - auth_state: serde_json::Value, - query_id: u64, -} - -#[allow(dead_code)] -impl TdClientAdapter { - /// Create a new TDLib client adapter. - pub fn new( - user_id: String, - config: TdClientConfig, - data_dir: PathBuf, - storage: IdbStorage, - ) -> Self { - Self { - user_id, - config, - data_dir, - storage, - auth_state: serde_json::json!({ - "@type": "authorizationStateWaitTdlibParameters" - }), - query_id: 0, - } - } - - /// Initialize the TDLib client. - /// - /// This would load the tdweb bundle and initialize the WASM module. - pub async fn init(&mut self) -> Result<(), String> { - log::info!("[tdlib:{}] Initializing TDLib client", self.user_id); - - // TODO: Load tdweb.js and libtdjson.wasm - // TODO: Create TdClient instance in V8 - // TODO: Set up update handlers - - // For now, simulate initialization - self.auth_state = serde_json::json!({ - "@type": "authorizationStateWaitTdlibParameters" - }); - - Ok(()) - } - - /// Send a query to TDLib. - pub async fn send(&mut self, query: serde_json::Value) -> Result { - self.query_id += 1; - let query_id = self.query_id; - - log::debug!( - "[tdlib:{}] Sending query {}: {:?}", - self.user_id, - query_id, - query.get("@type") - ); - - // TODO: Execute query through V8/tdweb - // For now, return a placeholder response - - let query_type = query - .get("@type") - .and_then(|v| v.as_str()) - .unwrap_or("unknown"); - - match query_type { - "getAuthorizationState" => Ok(self.auth_state.clone()), - "setTdlibParameters" => { - self.auth_state = serde_json::json!({ - "@type": "authorizationStateWaitPhoneNumber" - }); - Ok(serde_json::json!({ "@type": "ok" })) - } - _ => Ok(serde_json::json!({ - "@type": "error", - "code": 400, - "message": "TDLib not fully initialized - tdweb integration pending" - })), - } - } - - /// Get the current authorization state. - pub fn get_auth_state(&self) -> serde_json::Value { - self.auth_state.clone() - } - - /// Destroy the client. - pub async fn destroy(&mut self) -> Result<(), String> { - log::info!("[tdlib:{}] Destroying TDLib client", self.user_id); - - // TODO: Properly close TDLib client - // TODO: Cleanup V8 runtime - - Ok(()) - } -} - -/// JavaScript code to initialize the TDLib bridge in V8. -/// -/// This provides the `__tdlib_send` and `__tdlib_get_auth_state` functions -/// that the bootstrap.js exposes to skills. -#[allow(dead_code)] -pub const TDLIB_BRIDGE_JS: &str = r#" -// TDLib Bridge for V8 Runtime -// This will be replaced with actual tdweb integration - -(function() { - // Client state - const clients = new Map(); - let defaultClient = null; - - // Create a mock client for now - class MockTdClient { - constructor(options) { - this.options = options; - this.authState = { '@type': 'authorizationStateWaitTdlibParameters' }; - this.queryId = 0; - this.callbacks = new Map(); - } - - async send(query) { - this.queryId++; - const queryType = query['@type']; - - console.log('[TDLib] Send:', queryType); - - // Handle known query types - switch (queryType) { - case 'getAuthorizationState': - return this.authState; - - case 'setTdlibParameters': - this.authState = { '@type': 'authorizationStateWaitPhoneNumber' }; - return { '@type': 'ok' }; - - case 'setAuthenticationPhoneNumber': - this.authState = { '@type': 'authorizationStateWaitCode' }; - return { '@type': 'ok' }; - - default: - return { - '@type': 'error', - 'code': 400, - 'message': 'TDLib not fully initialized - waiting for tdweb integration' - }; - } - } - - getAuthState() { - return this.authState; - } - } - - // Initialize default client - function initClient(userId, options) { - const client = new MockTdClient(options); - clients.set(userId, client); - if (!defaultClient) { - defaultClient = client; - } - return client; - } - - // Get or create client - function getClient(userId) { - if (!clients.has(userId)) { - initClient(userId, {}); - } - return clients.get(userId); - } - - // Export to global scope - globalThis.__tdlib_send = async function(userId, query) { - const client = getClient(userId); - return await client.send(query); - }; - - globalThis.__tdlib_get_auth_state = function(userId) { - const client = getClient(userId); - return client.getAuthState(); - }; - - globalThis.__tdlib_init = function(userId, options) { - return initClient(userId, options); - }; - - console.log('[TDLib] Bridge initialized (mock mode)'); -})(); -"#; diff --git a/src-tauri/src/services/quickjs_libs/storage.rs b/src-tauri/src/services/quickjs_libs/storage.rs index 955c9ffb0..55b308ed4 100644 --- a/src-tauri/src/services/quickjs_libs/storage.rs +++ b/src-tauri/src/services/quickjs_libs/storage.rs @@ -1,7 +1,7 @@ //! IndexedDB Storage Layer (SQLite-backed) //! //! Provides persistent storage for: -//! - IndexedDB API (for tdweb) +//! - IndexedDB API //! - Skill databases (db bridge) //! - Skill key-value store (store bridge) @@ -12,7 +12,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; /// Result of opening an IndexedDB database. -/// Used by the IndexedDB emulation layer for tdweb. +/// Used by the IndexedDB emulation layer. #[derive(Debug, Clone, serde::Serialize)] pub struct IdbOpenResult { /// Whether a version upgrade is needed. diff --git a/src-tauri/src/unified_skills/generator.rs b/src-tauri/src/unified_skills/generator.rs index 0295f1575..f0969d2db 100644 --- a/src-tauri/src/unified_skills/generator.rs +++ b/src-tauri/src/unified_skills/generator.rs @@ -1,22 +1,22 @@ //! Programmatic skill generation for the unified skill registry. //! //! Supports generating both skill types: -//! - `alphahuman`: writes manifest.json + index.js to the QuickJS skills directory. -//! - `openclaw`: writes SKILL.md or SKILL.toml to the alphahuman workspace skills directory. +//! - `openhuman`: writes manifest.json + index.js to the QuickJS skills directory. +//! - `openclaw`: writes SKILL.md or SKILL.toml to the openhuman workspace skills directory. use crate::unified_skills::GenerateSkillSpec; use directories::UserDirs; use serde::Serialize; use std::path::{Path, PathBuf}; -/// Generate an alphahuman (QuickJS) skill at `//`. +/// Generate an openhuman (QuickJS) skill at `//`. /// /// Returns the list of file paths that were written (manifest.json + index.js). /// /// When `spec.full_index_js` is `Some`, its content is written directly to /// `index.js` instead of using the default template. This allows the /// self-evolve loop to persist LLM-generated code verbatim. -pub async fn generate_alphahuman( +pub async fn generate_openhuman( spec: &GenerateSkillSpec, skills_dir: &Path, ) -> Result, String> { @@ -37,7 +37,7 @@ pub async fn generate_alphahuman( let manifest = serde_json::json!({ "id": dir_name, "name": spec.name, - "skill_type": "alphahuman", + "skill_type": "openhuman", "runtime": "quickjs", "entry": "index.js", "version": "1.0.0", @@ -69,7 +69,7 @@ pub async fn generate_alphahuman( Ok(vec![manifest_path, index_path]) } -/// Generate an openclaw (SKILL.md/TOML) skill in `~/.alphahuman/workspace/skills//`. +/// Generate an openclaw (SKILL.md/TOML) skill in `~/.openhuman/workspace/skills//`. /// Returns the path of the created skill directory. pub async fn generate_openclaw(spec: &GenerateSkillSpec) -> Result { let dir_name = sanitize_id(&spec.name); @@ -140,12 +140,12 @@ pub async fn generate_openclaw(spec: &GenerateSkillSpec) -> Result Result { let dirs = UserDirs::new().ok_or("Cannot resolve home directory")?; Ok(dirs .home_dir() - .join(".alphahuman") + .join(".openhuman") .join("workspace") .join("skills")) } @@ -159,7 +159,7 @@ fn build_index_js(tool_fn: &str, description: &str, tool_code: &str) -> String { .unwrap_or_else(|_| r#""unknown""#.to_string()); format!( - r#"// Auto-generated alphahuman skill + r#"// Auto-generated openhuman skill tools = [ {{ name: "{tool_fn}", diff --git a/src-tauri/src/unified_skills/llm_generator.rs b/src-tauri/src/unified_skills/llm_generator.rs index d1c9f08e3..de2e6a5f7 100644 --- a/src-tauri/src/unified_skills/llm_generator.rs +++ b/src-tauri/src/unified_skills/llm_generator.rs @@ -8,7 +8,7 @@ use reqwest::Client; use serde::{Deserialize, Serialize}; /// System prompt embedded at compile time. -const SYSTEM_PROMPT: &str = "You are a skill generator for the AlphaHuman platform. +const SYSTEM_PROMPT: &str = "You are a skill generator for the OpenHuman platform. Generate a complete QuickJS skill as a single index.js file. CRITICAL CONSTRAINTS: @@ -197,9 +197,9 @@ impl LlmGenerator { .chars() .take(200) .collect::(), - skill_type: "alphahuman".to_string(), + skill_type: "openhuman".to_string(), // `tool_code` holds the full source when `full_index_js` is set; - // this ensures the fallback path in `generate_alphahuman` also has + // this ensures the fallback path in `generate_openhuman` also has // something reasonable to log. tool_code: Some(full_index_js.clone()), markdown_content: None, diff --git a/src-tauri/src/unified_skills/mod.rs b/src-tauri/src/unified_skills/mod.rs index 87137f2f1..18427f5d2 100644 --- a/src-tauri/src/unified_skills/mod.rs +++ b/src-tauri/src/unified_skills/mod.rs @@ -2,7 +2,7 @@ //! //! A single registry that aggregates both skill types: //! -//! - `alphahuman`: JavaScript-based skills executed in the QuickJS runtime. +//! - `openhuman`: JavaScript-based skills executed in the QuickJS runtime. //! - `openclaw`: File-based skills defined in SKILL.md or SKILL.toml. //! //! All skills expose a common [`UnifiedSkillEntry`] interface and return @@ -14,7 +14,7 @@ pub mod openclaw_executor; pub mod self_evolve; pub mod skill_tester; -use crate::alphahuman::skills::{load_skills, Skill}; +use crate::openhuman::skills::{load_skills, Skill}; use crate::runtime::qjs_engine::RuntimeEngine; use crate::runtime::types::{ToolDefinition, UnifiedSkillEntry, UnifiedSkillResult}; use chrono::Utc; @@ -30,16 +30,16 @@ pub struct GenerateSkillSpec { pub name: String, /// Human-readable description of what the skill does. pub description: String, - /// Skill type: "alphahuman" or "openclaw". + /// Skill type: "openhuman" or "openclaw". pub skill_type: String, - /// For alphahuman skills: the JavaScript body of the generated tool function. + /// For openhuman skills: the JavaScript body of the generated tool function. pub tool_code: Option, /// For openclaw skills: markdown content written to SKILL.md. pub markdown_content: Option, /// For openclaw skills: shell command written into SKILL.toml as a tool. pub shell_command: Option, /// Complete LLM-generated `index.js` source. When present, - /// `generator::generate_alphahuman` writes this directly to disk instead + /// `generator::generate_openhuman` writes this directly to disk instead /// of building from the default template. #[serde(default)] pub full_index_js: Option, @@ -55,7 +55,7 @@ impl UnifiedSkillRegistry { Self { engine } } - /// Return the resolved skills source directory (where alphahuman skill + /// Return the resolved skills source directory (where openhuman skill /// directories are stored). pub fn skills_dir(&self) -> Result { self.engine.skills_source_dir() @@ -68,12 +68,12 @@ impl UnifiedSkillRegistry { /// List all skills from both subsystems. /// - /// - alphahuman skills come from `RuntimeEngine::discover_skills()` (manifest.json). - /// - openclaw skills come from the alphahuman workspace skills directory (SKILL.md/TOML). + /// - openhuman skills come from `RuntimeEngine::discover_skills()` (manifest.json). + /// - openclaw skills come from the openhuman workspace skills directory (SKILL.md/TOML). pub async fn list_all(&self) -> Vec { let mut entries = Vec::new(); - // --- alphahuman skills (QuickJS runtime) --- + // --- openhuman skills (QuickJS runtime) --- if let Ok(manifests) = self.engine.discover_skills().await { let snapshots = self.engine.list_skills(); @@ -102,7 +102,7 @@ impl UnifiedSkillRegistry { for skill in &openclaw_skills { let id = skill_to_id(skill); - // Skip if already listed by the alphahuman runtime (avoid duplicates). + // Skip if already listed by the openhuman runtime (avoid duplicates). if entries.iter().any(|e| e.id == id) { continue; } @@ -148,14 +148,14 @@ impl UnifiedSkillRegistry { .ok_or_else(|| format!("Skill '{skill_id}' not found in unified registry"))?; match entry.skill_type.as_str() { - "alphahuman" => self.execute_alphahuman(skill_id, tool_name, args).await, + "openhuman" => self.execute_openhuman(skill_id, tool_name, args).await, "openclaw" => self.execute_openclaw(skill_id, tool_name, args).await, other => Err(format!("Unknown skill type: '{other}'")), } } - /// Dispatch to QuickJS runtime for alphahuman skills. - async fn execute_alphahuman( + /// Dispatch to QuickJS runtime for openhuman skills. + async fn execute_openhuman( &self, skill_id: &str, tool_name: &str, @@ -192,10 +192,10 @@ impl UnifiedSkillRegistry { /// Generate a new skill from a spec, write it to disk, and return its registry entry. pub async fn generate(&self, spec: GenerateSkillSpec) -> Result { match spec.skill_type.as_str() { - "alphahuman" => { + "openhuman" => { // Find the skills source directory from the engine. let skills_dir = self.engine.skills_source_dir()?; - generator::generate_alphahuman(&spec, &skills_dir).await?; + generator::generate_openhuman(&spec, &skills_dir).await?; // Rediscover so the new skill appears in subsequent list_all() calls. let _ = self.engine.discover_skills().await; @@ -206,7 +206,7 @@ impl UnifiedSkillRegistry { Ok(UnifiedSkillEntry { id, name: spec.name, - skill_type: "alphahuman".to_string(), + skill_type: "openhuman".to_string(), version: "1.0.0".to_string(), description: spec.description, tools: vec![], @@ -227,7 +227,7 @@ impl UnifiedSkillRegistry { setup: None, }) } - other => Err(format!("Unknown skill_type: '{other}'. Use 'alphahuman' or 'openclaw'.")), + other => Err(format!("Unknown skill_type: '{other}'. Use 'openhuman' or 'openclaw'.")), } } } @@ -253,9 +253,9 @@ fn sanitize_id(name: &str) -> String { .join("-") } -/// Returns `~/.alphahuman/workspace` as the base for openclaw skills. +/// Returns `~/.openhuman/workspace` as the base for openclaw skills. fn workspace_dir() -> PathBuf { UserDirs::new() - .map(|d| d.home_dir().join(".alphahuman").join("workspace")) - .unwrap_or_else(|| PathBuf::from(".alphahuman/workspace")) + .map(|d| d.home_dir().join(".openhuman").join("workspace")) + .unwrap_or_else(|| PathBuf::from(".openhuman/workspace")) } diff --git a/src-tauri/src/unified_skills/openclaw_executor.rs b/src-tauri/src/unified_skills/openclaw_executor.rs index 90edaa69f..55090804b 100644 --- a/src-tauri/src/unified_skills/openclaw_executor.rs +++ b/src-tauri/src/unified_skills/openclaw_executor.rs @@ -4,7 +4,7 @@ //! - SKILL.toml → structured tool definitions (shell/http commands) //! - SKILL.md → markdown prompt content (returned as text) -use crate::alphahuman::skills::{Skill, SkillTool}; +use crate::openhuman::skills::{Skill, SkillTool}; use crate::runtime::types::{ToolContent, UnifiedSkillResult}; use chrono::Utc; use std::collections::HashMap; diff --git a/src-tauri/src/unified_skills/self_evolve.rs b/src-tauri/src/unified_skills/self_evolve.rs index 74d86c0b9..8317b27c5 100644 --- a/src-tauri/src/unified_skills/self_evolve.rs +++ b/src-tauri/src/unified_skills/self_evolve.rs @@ -154,7 +154,7 @@ impl SkillEvolver { skill_id = sanitize_id(&spec.name); // -- Write files to disk -- - let written = generator::generate_alphahuman(&spec, &skills_dir) + let written = generator::generate_openhuman(&spec, &skills_dir) .await .map_err(|e| format!("File generation failed (iter {i}): {e}"))?; diff --git a/src-tauri/src/utils/config.rs b/src-tauri/src/utils/config.rs index db6f20c3b..23a2ee17d 100644 --- a/src-tauri/src/utils/config.rs +++ b/src-tauri/src/utils/config.rs @@ -5,13 +5,13 @@ use std::env; /// Default backend URL (can be overridden via BACKEND_URL env var) -pub const DEFAULT_BACKEND_URL: &str = "https://api.alphahuman.xyz"; +pub const DEFAULT_BACKEND_URL: &str = "https://api.tinyhumans.ai"; /// Application identifier for keychain storage -pub const APP_IDENTIFIER: &str = "com.alphahuman.app"; +pub const APP_IDENTIFIER: &str = "com.openhuman.app"; /// Service name for keychain -pub const KEYCHAIN_SERVICE: &str = "AlphaHuman"; +pub const KEYCHAIN_SERVICE: &str = "OpenHuman"; /// Get the backend URL from environment or use default /// Checks VITE_BACKEND_URL first, then BACKEND_URL, then defaults diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index cd0eedb38..e3922abda 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,8 +1,8 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "OpenHuman", - "version": "0.46.0", - "identifier": "com.alphahuman.app", + "version": "0.49.15", + "identifier": "com.tinyhumansai.openhuman", "build": { "beforeDevCommand": "npm run dev", "devUrl": "http://localhost:1420", @@ -39,8 +39,9 @@ ], "resources": [ "../skills/skills", - "../ai" + "ai" ], + "createUpdaterArtifacts": true, "macOS": { "minimumSystemVersion": "10.15", "dmg": { @@ -49,6 +50,12 @@ } }, "plugins": { + "updater": { + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDA1NkI1NEQzNjVDMjA0NDgKUldSSUJNSmwwMVJyQmJCTnQrQWxPSmhZQmVyWU1NMXdwRlRCSHR0ZEdlbkRncCtpQnhaZU5rUEQK", + "endpoints": [ + "https://github.com/tinyhumansai/openhuman/releases/latest/download/latest.json" + ] + }, "deep-link": { "desktop": { "schemes": [ diff --git a/src/AppRoutes.tsx b/src/AppRoutes.tsx index fe41326bc..a48554a8d 100644 --- a/src/AppRoutes.tsx +++ b/src/AppRoutes.tsx @@ -8,7 +8,6 @@ import Conversations from './pages/Conversations'; import Home from './pages/Home'; import Intelligence from './pages/Intelligence'; import Invites from './pages/Invites'; -import Login from './pages/Login'; import Mnemonic from './pages/Mnemonic'; import Onboarding from './pages/onboarding/Onboarding'; import Settings from './pages/Settings'; @@ -65,14 +64,6 @@ const AppRoutes = () => { } /> - - - - } - /> {/* Protected routes */} { path="/conversations/:threadId" element={ - + } /> diff --git a/src/components/DownloadScreen.tsx b/src/components/DownloadScreen.tsx deleted file mode 100644 index 939a7005d..000000000 --- a/src/components/DownloadScreen.tsx +++ /dev/null @@ -1,267 +0,0 @@ -import { useEffect, useState } from 'react'; - -import { - type Architecture, - type ArchitectureDownloadLink, - detectPlatform, - fetchLatestRelease, - getDownloadLink, - getPlatformDisplayName, - parseReleaseAssets, - parseReleaseAssetsByArchitecture, - type Platform, - type PlatformArchitectureLinks, - type PlatformDownloadLinks, - type PlatformInfo, -} from '../utils/deviceDetection'; -import { isTauri } from '../utils/tauriCommands'; - -interface DownloadOption { - platform: Platform; - label: string; - icon: string; -} - -const downloadOptions: DownloadOption[] = [ - { platform: 'windows', label: 'Windows', icon: '🪟' }, - { platform: 'macos', label: 'macOS', icon: '🍎' }, - { platform: 'linux', label: 'Linux', icon: '🐧' }, -]; - -const DownloadScreen = () => { - const [platformInfo, setPlatformInfo] = useState(null); - const [selectedPlatform, setSelectedPlatform] = useState(null); - const [selectedArchitecture, setSelectedArchitecture] = useState(null); - const [releaseLinks, setReleaseLinks] = useState(null); - const [architectureLinks, setArchitectureLinks] = useState( - null - ); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - // Only show download screen on web (not in Tauri app) - if (isTauri()) { - return; - } - - const detected = detectPlatform(); - setPlatformInfo(detected); - setSelectedPlatform(detected.platform); - setSelectedArchitecture(detected.architecture); - - // Fetch latest release from GitHub - const loadReleaseLinks = async () => { - try { - setIsLoading(true); - setError(null); - const release = await fetchLatestRelease(); - const links = parseReleaseAssets(release.assets); - const archLinks = parseReleaseAssetsByArchitecture(release.assets); - setReleaseLinks(links); - setArchitectureLinks(archLinks); - - // Auto-select best architecture for detected platform - 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]; - setSelectedArchitecture(preferredLink.architecture); - } - } catch (err) { - console.error('Failed to fetch release links:', err); - setError(err instanceof Error ? err.message : 'Failed to load download links'); - } finally { - setIsLoading(false); - } - }; - - loadReleaseLinks(); - }, []); - - // Don't render if running in Tauri or platform not detected - if (isTauri() || !platformInfo || !selectedPlatform) { - return null; - } - - // Get download URL for selected platform and architecture - const getDownloadUrl = (): string => { - if (!selectedPlatform || !architectureLinks) { - return getDownloadLink(selectedPlatform || 'unknown', releaseLinks || undefined); - } - - const platformArchLinks = - architectureLinks[selectedPlatform as keyof PlatformArchitectureLinks]; - if (platformArchLinks && selectedArchitecture) { - const link = platformArchLinks.find(l => l.architecture === selectedArchitecture); - if (link) { - return link.url; - } - // Fallback to first available architecture - if (platformArchLinks.length > 0) { - return platformArchLinks[0].url; - } - } - - return getDownloadLink(selectedPlatform, releaseLinks || undefined); - }; - - const downloadUrl = getDownloadUrl(); - const platformName = getPlatformDisplayName(selectedPlatform || 'unknown'); - - const handleDownload = () => { - window.open(downloadUrl, '_blank'); - }; - - // Get available architectures for selected platform - const getAvailableArchitectures = (): ArchitectureDownloadLink[] => { - if (!selectedPlatform || !architectureLinks) { - return []; - } - return architectureLinks[selectedPlatform as keyof PlatformArchitectureLinks] || []; - }; - - const availableArchitectures = getAvailableArchitectures(); - const hasMultipleArchitectures = availableArchitectures.length > 1; - - return ( -
- {/* Loading state */} - {isLoading && ( -
-
-
-
-

Loading download links...

-
-
-
- )} - - {/* Error state */} - {error && !isLoading && ( -
-
-

{error}. Using fallback download links.

-
-
- )} - - {/* Auto-detected platform */} - {!isLoading && ( -
-
-
-
-
- - {downloadOptions.find(opt => opt.platform === selectedPlatform)?.icon} - -
-

Recommended for you

-

{platformName}

-
-
- -
- - {/* Architecture selection */} - {hasMultipleArchitectures && ( -
-

Select architecture:

-
- {availableArchitectures.map(archLink => { - const isSelected = selectedArchitecture === archLink.architecture; - const isRecommended = platformInfo?.architecture === archLink.architecture; - return ( - - ); - })} -
-
- )} -
-
-
- )} - - {/* Other platforms */} - {!isLoading && ( -
-

Or download for other platforms:

-
- {downloadOptions - .filter(opt => opt.platform !== selectedPlatform) - .map(option => { - 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 hasMultipleArchs = platformArchLinks && platformArchLinks.length > 1; - - return ( -
- - {hasMultipleArchs && ( -
- {platformArchLinks.map(archLink => ( - - ))} -
- )} -
- ); - })} -
-
- )} -
- ); -}; - -export default DownloadScreen; diff --git a/src/components/RotatingTetrahedronCanvas.tsx b/src/components/RotatingTetrahedronCanvas.tsx index c6f6f85ad..11c5285e4 100644 --- a/src/components/RotatingTetrahedronCanvas.tsx +++ b/src/components/RotatingTetrahedronCanvas.tsx @@ -1,7 +1,31 @@ -import { useEffect, useRef } from 'react'; -import * as THREE from 'three'; +'use client'; -const RotatingTetrahedronCanvas = () => { +import * as THREE from 'three'; +import { useEffect, useRef } from 'react'; +import { ConvexGeometry } from 'three/addons/geometries/ConvexGeometry.js'; + +/** Start from a regular tetrahedron and lightly truncate each corner to create small blunted edges. */ +function bluntedTetrahedronPoints(scale: number, bluntness = 0.12): THREE.Vector3[] { + const tetra = [ + new THREE.Vector3(1, 1, 1), + new THREE.Vector3(-1, -1, 1), + new THREE.Vector3(-1, 1, -1), + new THREE.Vector3(1, -1, -1), + ]; + + const points: THREE.Vector3[] = []; + + for (let i = 0; i < tetra.length; i += 1) { + for (let j = 0; j < tetra.length; j += 1) { + if (i === j) continue; + points.push(tetra[i].clone().lerp(tetra[j], bluntness).multiplyScalar(scale)); + } + } + + return points; +} + +export default function RotatingTetrahedronCanvas() { const canvasRef = useRef(null); useEffect(() => { @@ -15,41 +39,39 @@ const RotatingTetrahedronCanvas = () => { powerPreference: 'high-performance', }); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); + renderer.outputColorSpace = THREE.SRGBColorSpace; + renderer.toneMapping = THREE.NoToneMapping; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100); - camera.position.set(0, 0, 4.6); + camera.position.set(0, 0.15, 4.8); - const fillMaterial = new THREE.MeshPhongMaterial({ - color: '#7f5af0', - emissive: '#201040', - emissiveIntensity: 0.8, - shininess: 50, + const geometry = new ConvexGeometry(bluntedTetrahedronPoints(0.98, 0.11)); + const fillMaterial = new THREE.MeshLambertMaterial({ + color: '#b8e986', transparent: true, - opacity: 0.65, - flatShading: true, + opacity: 0.4, + emissive: '#0c1208', + emissiveIntensity: 0.08, }); - - const wireMaterial = new THREE.MeshBasicMaterial({ - color: '#a78bfa', - wireframe: true, - transparent: true, - opacity: 0.95, - }); - - const geometry = new THREE.TetrahedronGeometry(1.3, 0); const fillMesh = new THREE.Mesh(geometry, fillMaterial); - const wireMesh = new THREE.Mesh(geometry, wireMaterial); + const edgeGeometry = new THREE.EdgesGeometry(geometry); + const edgeMaterial = new THREE.LineBasicMaterial({ color: '#b8e986' }); + + const edges = new THREE.LineSegments(edgeGeometry, edgeMaterial); + fillMesh.rotation.x = 0.35; + fillMesh.rotation.y = -0.15; + edges.rotation.x = 0.35; + edges.rotation.y = -0.15; scene.add(fillMesh); - scene.add(wireMesh); - - const ambientLight = new THREE.AmbientLight('#b4b1ff', 0.45); - const keyLight = new THREE.PointLight('#7f5af0', 1.2, 20); - keyLight.position.set(2.8, 2.5, 4); + scene.add(edges); + const ambientLight = new THREE.AmbientLight('#ffffff', 0.1); + const sun = new THREE.DirectionalLight('#ffffff', 1.1); + sun.position.set(4.5, 6, 5); scene.add(ambientLight); - scene.add(keyLight); + scene.add(sun); let animationFrame = 0; @@ -70,9 +92,10 @@ const RotatingTetrahedronCanvas = () => { resize(); const animate = () => { - fillMesh.rotation.x += 0.006; - fillMesh.rotation.y += 0.009; - wireMesh.rotation.copy(fillMesh.rotation); + fillMesh.rotation.y += 0.0038; + fillMesh.rotation.x += 0.0002; + edges.rotation.y += 0.0038; + edges.rotation.x += 0.0002; renderer.render(scene, camera); animationFrame = window.requestAnimationFrame(animate); @@ -83,14 +106,19 @@ const RotatingTetrahedronCanvas = () => { return () => { window.cancelAnimationFrame(animationFrame); observer.disconnect(); + edgeGeometry.dispose(); geometry.dispose(); fillMaterial.dispose(); - wireMaterial.dispose(); + edgeMaterial.dispose(); renderer.dispose(); }; }, []); - return ; -}; - -export default RotatingTetrahedronCanvas; + return ( + + ); +} diff --git a/src/components/SkillsGrid.tsx b/src/components/SkillsGrid.tsx index 380549b7a..f14728540 100644 --- a/src/components/SkillsGrid.tsx +++ b/src/components/SkillsGrid.tsx @@ -36,7 +36,7 @@ function normalizeUnifiedEntry(e: Record): SkillListEntry { icon: SKILL_ICONS[e.id as string], ignoreInProduction: (e.ignoreInProduction as boolean) ?? false, hasSetup, - skill_type: (e.skill_type as 'alphahuman' | 'openclaw') ?? 'alphahuman', + skill_type: (e.skill_type as 'openhuman' | 'openclaw') ?? 'openhuman', }; } @@ -44,7 +44,7 @@ interface SkillRowProps { skillId: string; name: string; icon?: React.ReactElement; - skillType?: 'alphahuman' | 'openclaw'; + skillType?: 'openhuman' | 'openclaw'; onConnect: (e: React.MouseEvent) => void; } @@ -119,13 +119,13 @@ export default function SkillsGrid() { const [activeSkillName, setActiveSkillName] = useState(''); const [activeSkillDescription, setActiveSkillDescription] = useState(''); const [activeSkillHasSetup, setActiveSkillHasSetup] = useState(false); - const [activeSkillType, setActiveSkillType] = useState<'alphahuman' | 'openclaw'>('alphahuman'); + const [activeSkillType, setActiveSkillType] = useState<'openhuman' | 'openclaw'>('openhuman'); // Get Redux state for sorting const skillsState = useAppSelector(state => state.skills.skills); const skillStates = useAppSelector(state => state.skills.skillStates); - // Load skills from the unified registry (covers both alphahuman and openclaw types). + // Load skills from the unified registry (covers both openhuman and openclaw types). // Extracted so it can be called after skill creation (e.g. from SelfEvolveModal). const refreshSkills = async () => { try { @@ -167,7 +167,7 @@ export default function SkillsGrid() { icon: SKILL_ICONS[m.id as string], ignoreInProduction: (m.ignoreInProduction as boolean) ?? false, hasSetup, - skill_type: 'alphahuman' as const, + skill_type: 'openhuman' as const, }; }) .filter(s => IS_DEV || !s.ignoreInProduction); @@ -261,7 +261,7 @@ export default function SkillsGrid() { setActiveSkillName(skill.name); setActiveSkillDescription(skill.description); setActiveSkillHasSetup(skill.hasSetup); - setActiveSkillType(skill.skill_type ?? 'alphahuman'); + setActiveSkillType(skill.skill_type ?? 'openhuman'); setSetupModalOpen(true); }; @@ -299,7 +299,7 @@ export default function SkillsGrid() { spec: { name: `generated-demo-${Date.now()}`, description: 'Auto-generated skill demonstrating the unified registry', - skill_type: 'alphahuman', + skill_type: 'openhuman', tool_code: 'return { message: `Hello from generated skill! args=${JSON.stringify(args)}` };', }, @@ -398,7 +398,6 @@ export default function SkillsGrid() { {selfEvolveOpen && ( setSelfEvolveOpen(false)} onSkillCreated={refreshSkills} /> )} - ); } diff --git a/src/components/TelegramLoginButton.tsx b/src/components/TelegramLoginButton.tsx deleted file mode 100644 index 7e9e840b0..000000000 --- a/src/components/TelegramLoginButton.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { TELEGRAM_BOT_USERNAME } from '../utils/config'; -import { openUrl } from '../utils/openUrl'; -import { isTauri } from '../utils/tauriCommands'; - -interface TelegramLoginButtonProps { - className?: string; - text?: string; - disabled?: boolean; -} - -const TelegramLoginButton = ({ - className = '', - text = 'Yes, Login with Telegram', - disabled: externalDisabled = false, -}: TelegramLoginButtonProps) => { - const handleTelegramLogin = async () => { - if (externalDisabled) return; - - console.log('Starting Telegram login', isTauri()); - - // Desktop (Tauri): use system browser → backend Telegram widget → deep link back to app. - if (isTauri()) await openUrl(`https://t.me/${TELEGRAM_BOT_USERNAME}?start=login_desktop`); - // Web fallback: open bot (existing flow). - else await openUrl(`https://t.me/${TELEGRAM_BOT_USERNAME}?start=login`); - }; - - const isDisabled = externalDisabled; - - return ( - - ); -}; - -export default TelegramLoginButton; diff --git a/src/components/TypewriterGreeting.tsx b/src/components/TypewriterGreeting.tsx index 25f481047..2763db4bf 100644 --- a/src/components/TypewriterGreeting.tsx +++ b/src/components/TypewriterGreeting.tsx @@ -68,7 +68,7 @@ const TypewriterGreeting = ({ ]); return ( -

+

{displayedText} |

diff --git a/src/components/intelligence/mockData.ts b/src/components/intelligence/mockData.ts index 739222102..87458201d 100644 --- a/src/components/intelligence/mockData.ts +++ b/src/components/intelligence/mockData.ts @@ -222,7 +222,7 @@ export const MOCK_ACTIONABLE_ITEMS: ActionableItem[] = [ { id: '15', - title: 'Renew SSL certificate for api.alphahuman.com', + title: 'Renew SSL certificate for api.openhuman.com', description: 'Certificate expires in 5 days. Automatic renewal failed - manual intervention required.', source: 'system', diff --git a/src/components/oauth/OAuthLoginSection.tsx b/src/components/oauth/OAuthLoginSection.tsx index dffc41310..94ee9f8f9 100644 --- a/src/components/oauth/OAuthLoginSection.tsx +++ b/src/components/oauth/OAuthLoginSection.tsx @@ -1,4 +1,3 @@ -import TelegramLoginButton from '../TelegramLoginButton'; import OAuthProviderButton from './OAuthProviderButton'; import { oauthProviderConfigs } from './providerConfigs'; @@ -8,33 +7,24 @@ interface OAuthLoginSectionProps { showTelegram?: boolean; } -const OAuthLoginSection = ({ - className = '', - disabled = false, - showTelegram = true, -}: OAuthLoginSectionProps) => { +const OAuthLoginSection = ({ className = '', disabled = false }: OAuthLoginSectionProps) => { return (
- {/* OAuth Providers */}
- {oauthProviderConfigs.map(provider => ( - - ))} +

+ Continue with +

+
+ {oauthProviderConfigs.map(provider => ( + + ))} +
- - {/* Divider */} - {showTelegram && ( - <> -
-
-
or
-
-
- - {/* Telegram Login */} - - - )}
); }; diff --git a/src/components/oauth/OAuthProviderButton.tsx b/src/components/oauth/OAuthProviderButton.tsx index d9ede35aa..1b630e93c 100644 --- a/src/components/oauth/OAuthProviderButton.tsx +++ b/src/components/oauth/OAuthProviderButton.tsx @@ -54,15 +54,13 @@ const OAuthProviderButton = ({ ); }; diff --git a/src/components/settings/SettingsHome.tsx b/src/components/settings/SettingsHome.tsx index 1124920b9..e3544e908 100644 --- a/src/components/settings/SettingsHome.tsx +++ b/src/components/settings/SettingsHome.tsx @@ -303,17 +303,17 @@ const SettingsHome = () => { {/* Main Settings */}
{mainMenuItems.map((item, index) => ( - - ))} + + ))}
{/* Destructive Actions */} diff --git a/src/components/settings/panels/AIPanel.tsx b/src/components/settings/panels/AIPanel.tsx index 55df476c4..fc3abc03b 100644 --- a/src/components/settings/panels/AIPanel.tsx +++ b/src/components/settings/panels/AIPanel.tsx @@ -1,46 +1,29 @@ import { useEffect, useState } from 'react'; -import { useToolsUpdates } from '../../../hooks/useToolsUpdates'; -import { loadAIConfig, refreshAll, refreshSoul, refreshTools } from '../../../lib/ai/loader'; -import type { SoulConfig } from '../../../lib/ai/soul/types'; -import type { ToolsConfig } from '../../../lib/ai/tools/types'; -import type { AIConfig } from '../../../lib/ai/types'; +import { aiGetConfig, type AIPreview, aiRefreshConfig } from '../../../utils/tauriCommands'; import SettingsHeader from '../components/SettingsHeader'; import { useSettingsNavigation } from '../hooks/useSettingsNavigation'; const AIPanel = () => { const { navigateBack } = useSettingsNavigation(); - const [aiConfig, setAiConfig] = useState(null); + const [aiConfig, setAiConfig] = useState(null); const [loading, setLoading] = useState(false); const [refreshingComponent, setRefreshingComponent] = useState<'soul' | 'tools' | 'all' | null>( null ); const [error, setError] = useState(''); - // Listen for tools updates and refresh AI config - const toolsUpdateTimestamp = useToolsUpdates(); - useEffect(() => { loadAIPreview(); }, []); - // Auto-refresh when tools are updated - useEffect(() => { - if (toolsUpdateTimestamp > 0) { - console.log('🔄 AIPanel: Tools updated detected, refreshing AI config...'); - loadAIPreview(); - } - }, [toolsUpdateTimestamp]); - const loadAIPreview = async () => { setLoading(true); setError(''); try { - const config = await loadAIConfig(); + const config = await aiGetConfig(); setAiConfig(config); - - // Show metadata errors if any - if (config.metadata.errors && config.metadata.errors.length > 0) { + if (config.metadata.errors.length > 0) { setError(config.metadata.errors.join('; ')); } } catch (err) { @@ -51,54 +34,13 @@ const AIPanel = () => { } }; - const refreshSoulConfig = async () => { - setRefreshingComponent('soul'); + const refreshConfig = async (target: 'soul' | 'tools' | 'all') => { + setRefreshingComponent(target); setError(''); try { - const soulConfig = await refreshSoul(); - if (aiConfig) { - setAiConfig({ - ...aiConfig, - soul: soulConfig, - metadata: { ...aiConfig.metadata, loadedAt: Date.now() }, - }); - } - } catch (err) { - const message = err instanceof Error ? err.message : 'Failed to refresh SOUL configuration'; - setError(message); - } finally { - setRefreshingComponent(null); - } - }; - - const refreshToolsConfig = async () => { - setRefreshingComponent('tools'); - setError(''); - try { - const toolsConfig = await refreshTools(); - if (aiConfig) { - setAiConfig({ - ...aiConfig, - tools: toolsConfig, - metadata: { ...aiConfig.metadata, loadedAt: Date.now() }, - }); - } - } catch (err) { - const message = err instanceof Error ? err.message : 'Failed to refresh TOOLS configuration'; - setError(message); - } finally { - setRefreshingComponent(null); - } - }; - - const refreshAllConfig = async () => { - setRefreshingComponent('all'); - setError(''); - try { - const config = await refreshAll(); + const config = await aiRefreshConfig(); setAiConfig(config); - - if (config.metadata.errors && config.metadata.errors.length > 0) { + if (config.metadata.errors.length > 0) { setError(config.metadata.errors.join('; ')); } } catch (err) { @@ -109,50 +51,15 @@ const AIPanel = () => { } }; - const formatPersonality = (config: SoulConfig): string => { - return config.personality - .slice(0, 3) - .map(p => `${p.trait}: ${p.description}`) - .join(' • '); - }; - - const formatSafetyRules = (config: SoulConfig): string => { - return config.safetyRules - .slice(0, 2) - .map(r => r.rule) - .join(' • '); - }; - - const formatToolsOverview = (config: ToolsConfig): string => { - const skillNames = Object.keys(config.skillGroups); - return skillNames - .slice(0, 4) - .map(skillId => { - const group = config.skillGroups[skillId]; - return `${group.name} (${group.tools.length})`; - }) - .join(' • '); - }; - - const formatCategories = (config: ToolsConfig): string => { - return Object.values(config.categories) - .filter(cat => cat.toolCount && cat.toolCount > 0) - .slice(0, 3) - .map(cat => `${cat.name}: ${cat.toolCount} tools`) - .join(' • '); - }; - return (
- {/* Overview Section */}

AI System Overview

- OpenHuman uses SOUL for persona configuration and TOOLS for external service - integration. + Prompt and markdown orchestration is handled in Rust runtime.

{aiConfig && ( @@ -163,7 +70,7 @@ const AIPanel = () => { Configuration Status
- {aiConfig.metadata.hasFallbacks ? 'Fallback Mode' : 'Fully Loaded'} + {aiConfig.metadata.hasFallbacks ? 'Fallback Mode' : 'Loaded from Runtime'}
@@ -179,21 +86,16 @@ const AIPanel = () => { )} - {/* SOUL Configuration Section */}

SOUL Persona Configuration

-

- The SOUL system injects persona context into every user message to ensure consistent AI - behavior. -

{loading && (
Loading SOUL configuration...
@@ -205,36 +107,32 @@ const AIPanel = () => {
)} - {aiConfig?.soul && ( + {aiConfig && (
-
- {aiConfig.soul.identity.name} -
-
- {aiConfig.soul.identity.description} -
+
{aiConfig.soul.name}
+
{aiConfig.soul.description}
- {aiConfig.soul.personality.length > 0 && ( + {aiConfig.soul.personalityPreview.length > 0 && (
- {formatPersonality(aiConfig.soul)} + {aiConfig.soul.personalityPreview.join(' • ')}
)} - {aiConfig.soul.safetyRules.length > 0 && ( + {aiConfig.soul.safetyRulesPreview.length > 0 && (
- {formatSafetyRules(aiConfig.soul)} + {aiConfig.soul.safetyRulesPreview.join(' • ')}
)} @@ -251,23 +149,18 @@ const AIPanel = () => { )} - {/* TOOLS Configuration Section */}

TOOLS Configuration

-

- TOOLS provide OpenHuman with the ability to interact with external services and perform - actions. -

- {aiConfig?.tools && ( + {aiConfig && (
@@ -275,7 +168,7 @@ const AIPanel = () => { Tools Available
- {aiConfig.tools.statistics.totalTools} tools + {aiConfig.tools.totalTools} tools
@@ -283,29 +176,18 @@ const AIPanel = () => { Active Skills
- {aiConfig.tools.statistics.activeSkills} skills + {aiConfig.tools.activeSkills} skills
- {Object.keys(aiConfig.tools.skillGroups).length > 0 && ( + {aiConfig.tools.skillsPreview.length > 0 && (
- {formatToolsOverview(aiConfig.tools)} -
-
- )} - - {Object.keys(aiConfig.tools.categories).length > 0 && ( -
- -
- {formatCategories(aiConfig.tools)} + {aiConfig.tools.skillsPreview.join(' • ')}
)} @@ -322,11 +204,10 @@ const AIPanel = () => { )}
- {/* Combined Actions */}
-
- - {/* Search bar (#13) */} - {threads.length > 0 && ( -
-
- - - - setSearchQuery(e.target.value)} - placeholder="Search threads..." - className="w-full bg-white/5 border border-white/10 rounded-lg pl-8 pr-3 py-1.5 text-xs placeholder:text-stone-500 focus:outline-none focus:ring-1 focus:ring-primary-500/50 focus:border-primary-500/50 transition-all" - /> - {searchQuery && ( - - )} -
+
+
+
+
+

+ {selectedThread?.title || DEFAULT_THREAD_TITLE} +

+ {selectedThread?.isActive && ( + + Active + + )}
- )} - - {/* Thread list */} -
- {filteredThreads.length > 0 ? ( -
- {filteredThreads.map(thread => ( -
- {confirmDeleteId === thread.id ? ( -
- Delete this thread? -
- - -
-
- ) : ( - <> - - {/* Delete button — visible on hover */} - - - )} -
- ))} -
- ) : threads.length > 0 && searchQuery ? ( -
-

No matching threads

- -
- ) : ( -
- - - -

No conversations yet

- -
+ {selectedThread?.createdAt && ( +

+ Created {formatRelativeTime(selectedThread.createdAt)} +

)}
- - {/* Footer: Delete All */} - {threads.length > 0 && ( -
- {showPurgeConfirm ? ( -
- Delete all threads? -
- - -
-
- ) : ( - - )} -
- )}
- )} - {/* Resize Handle — desktop only */} - {!isMobile && ( -
- )} - - {/* Right Panel: Messages */} - {showMessages && ( -
- {selectedThread ? ( - <> - {/* Thread header */} -
- {/* Mobile back button (#12) */} - {isMobile && ( - - )} -
-
-

- {selectedThread.title || 'Untitled Thread'} -

- {selectedThread.isActive && ( - - Active - - )} -
-

- Created {formatRelativeTime(selectedThread.createdAt)} -

-
-
- - {/* Messages */} -
- {isLoadingMessages ? ( -
- {Array.from({ length: 4 }).map((_, i) => ( -
-
-
- ))} -
- ) : messagesError ? ( -
- - - -

Failed to load messages

-

{messagesError}

- -
- ) : messages.length > 0 ? ( -
- {messages.map(msg => ( -
-
-
- {msg.sender === 'agent' ? ( -
- {msg.content} -
- ) : ( -

- {msg.content} -

- )} -

- {formatRelativeTime(msg.createdAt)} -

-
- {/* Copy button (#10) */} - -
-
- ))} - {/* Typing indicator (#14) - Only show for the active thread */} - {activeThreadId === selectedThreadId && isSending && ( -
-
-
- - - -
-
-
- )} - {/* Tool call indicator — shown when Rust backend is executing a tool */} - {activeToolCall && isSending && ( -
- Running tool: {activeToolCall.name} -
- )} - {/* Cancel button — shown when Rust backend is processing */} - {isSending && rustChat && ( -
- -
- )} -
-
- ) : ( -
-

No messages in this thread

-
- )} -
- - {/* Suggested questions — only at start of new thread (no messages yet); horizontal scroll */} - {messages.length === 0 && suggestedQuestions.length > 0 && !isLoadingSuggestions && ( -
-
- {suggestedQuestions.map((s, i) => ( - - ))} -
-
- )} - - {/* Message Input */} -
- {/* Budget depleted banner — show top-up CTA */} - {teamUsage && teamUsage.remainingUsd <= 0 && ( -
-
- - - -

- Daily inference budget exhausted. Top up to continue. -

-
- -
- )} - - {/* Show warning if another thread is active */} - {activeThreadId && activeThreadId !== selectedThreadId && ( -
-

- Another conversation is active. Please wait for it to complete before sending - messages here. -

-
- )} - {/* Model selector + budget indicator */} -
- {isLoadingModels ? ( - Loading models… - ) : ( - <> - Model - - - )} -
- {/* Budget indicator — circular */} - {(isLoadingBudget || teamUsage) && - (() => { - const size = 22; - const r = 9; - const circ = 2 * Math.PI * r; - const pct = teamUsage - ? Math.min(1, teamUsage.remainingUsd / teamUsage.cycleBudgetUsd) - : 0; - const dash = pct * circ; - return ( -
- - - {teamUsage ? ( - - ) : ( - - )} - - {teamUsage && ( - - ${teamUsage.remainingUsd.toFixed(2)} - - )} -
- ); - })()} -
- {sendError && ( -
-

{sendError}

- -
- )} -
-