mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
refactor: remove Tauri integration and update tools discovery mechanism
- Eliminated the Tauri integration files and related functions to streamline the tools discovery process. - Updated the tools discovery logic to utilize a mock registry instead of relying on Tauri, enhancing compatibility and simplifying the workflow. - Adjusted comments in the release workflow to reflect the changes in tools discovery and removed references to the now-removed Tauri binary.
This commit is contained in:
@@ -313,9 +313,9 @@ jobs:
|
||||
WITH_UPDATER: 'true'
|
||||
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }}
|
||||
with:
|
||||
# `openhuman-tools-discovery` is feature-gated in Cargo.toml so it
|
||||
# does not get bundled into release app packages and break macOS
|
||||
# codesign as an unsigned subcomponent.
|
||||
# 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.
|
||||
args: -c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}
|
||||
includeDebug: false
|
||||
includeRelease: true
|
||||
|
||||
@@ -12,12 +12,6 @@ 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, '../..');
|
||||
@@ -42,39 +36,7 @@ const ENVIRONMENTS = {
|
||||
* @returns {Promise<Array>} 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`
|
||||
@@ -195,77 +157,9 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to discover tools from a running Tauri process
|
||||
* @returns {Promise<Array>} 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',
|
||||
'openhuman-tools-discovery',
|
||||
'--features',
|
||||
'tools-discovery-bin',
|
||||
];
|
||||
|
||||
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 };
|
||||
|
||||
@@ -1,223 +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',
|
||||
'openhuman-tools-discovery',
|
||||
'--features',
|
||||
'tools-discovery-bin',
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if Tauri development environment is available
|
||||
* @returns {Promise<boolean>} 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<Array>} 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<Array>} 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<void>}
|
||||
*/
|
||||
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<Object>} Environment information
|
||||
*/
|
||||
export async function getTauriEnvironmentInfo() {
|
||||
const cargoAvailable = await validateTauriEnvironment();
|
||||
|
||||
return {
|
||||
cargoAvailable,
|
||||
platform: process.platform,
|
||||
architecture: process.arch,
|
||||
projectRoot: PROJECT_ROOT,
|
||||
command: getTauriCommand(),
|
||||
};
|
||||
}
|
||||
@@ -19,11 +19,6 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
name = "OpenHuman"
|
||||
path = "src/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "openhuman-tools-discovery"
|
||||
path = "src/bin/openhuman-tools-discovery.rs"
|
||||
required-features = ["tools-discovery-bin"]
|
||||
|
||||
[[bin]]
|
||||
name = "openhuman-core"
|
||||
path = "src/bin/openhuman-core.rs"
|
||||
@@ -185,7 +180,6 @@ tempfile = "3"
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
sandbox-landlock = ["dep:landlock"]
|
||||
sandbox-bubblewrap = []
|
||||
tools-discovery-bin = []
|
||||
|
||||
# OpenHuman feature flags
|
||||
hardware = ["dep:nusb", "dep:tokio-serial"]
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
//! OpenHuman 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<dyn std::error::Error>> {
|
||||
// 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<Vec<serde_json::Value>, Box<dyn std::error::Error>> {
|
||||
// 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<PathBuf, Box<dyn std::error::Error>> {
|
||||
// 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())
|
||||
}
|
||||
Reference in New Issue
Block a user