Files
openhuman/src/core/cli.rs
T
Steven EnamakelandGitHub c1a3ae1cfe Refactor controller registration into domain schemas and generic registry (#53)
* Refactor core server helpers and enhance REPL dotenv loading

- Removed unused functions for extracting namespaces and filtering documents by namespace from `helpers.rs`, streamlining the codebase.
- Introduced dotenv loading functionality in `repl.rs`, allowing for environment variable management from a specified `.env` file.
- Added utility functions for parsing dotenv values and resolving the dotenv file path, improving configuration handling in the REPL.
- Enhanced logging for dotenv loading to provide better visibility into the process and any issues encountered.

* Add AI RPC module and enhance core server dispatch functionality

- Introduced a new `rpc` module within the `ai` namespace to handle various AI-related commands, including memory file operations and session management.
- Updated the core server's dispatch logic to integrate the new AI RPC functionality, improving modularity and maintainability.
- Removed outdated memory dispatch implementation and streamlined the overall dispatch structure for better performance and clarity.
- Enhanced error handling and logging throughout the new functionalities to improve maintainability and user feedback.

* Refactor project structure and enhance RPC functionality

- Introduced a new `rpc` module to streamline JSON-RPC handling across various domains, improving code organization and maintainability.
- Updated the core server and API modules to utilize the new `rpc` structure, enhancing modularity and reducing code duplication.
- Added new models for authentication and socket management, improving the overall functionality of the API.
- Removed outdated references to the previous `openhuman` RPC structure, ensuring a cleaner and more efficient codebase.

* Update architecture documentation and refactor AI prompt paths

- Updated references in architecture documentation to reflect the new directory structure for AI prompts, changing paths from `src/ai/prompts` to `src/openhuman/agent/prompts`.
- Enhanced clarity in command documentation by aligning AI-related commands with the updated prompt paths.
- Removed obsolete AI module and streamlined memory management references to improve code organization and maintainability.
- Introduced new markdown files for agent prompts, establishing a foundation for OpenHuman's AI capabilities.

* Update AI prompt paths and configuration references

- Changed all references from `src/ai/prompts` to `src/openhuman/agent/prompts` in documentation and code files to reflect the new directory structure.
- Updated Tauri configuration to include the new resource paths for AI prompts, ensuring proper access and functionality.
- Enhanced the AI configuration commands to align with the updated paths, improving clarity and maintainability across the project.

* Enhance core structure and introduce new RPC functionality

- Added a new `core` module to centralize shared schemas and contracts for controllers, improving code organization and maintainability.
- Introduced `jsonrpc` and `cli` modules within the `core` structure to handle JSON-RPC requests and command-line interactions, enhancing modularity.
- Defined a `ControllerSchema` for transport-agnostic function contracts, allowing for consistent handling across RPC and CLI layers.
- Established a new `all` module to manage registered controllers and their schemas, streamlining the invocation process.
- Updated documentation in `CLAUDE.md` to reflect new controller schema contracts and module organization, improving clarity for developers.

* Refactor core server structure and enhance RPC functionality

- Removed the `core_server` module and integrated its functionalities into the `core` module, improving code organization and maintainability.
- Introduced a new `dispatch` module to handle RPC requests, streamlining the invocation process for various commands.
- Updated the CLI to utilize the new core structure, enhancing command handling and modularity.
- Added comprehensive logging for RPC interactions, improving visibility and debugging capabilities.
- Enhanced error handling across the core server, ensuring consistent feedback for users and developers.

* Refactor CLI command handling and enhance JSON-RPC integration

- Consolidated CLI command structure by removing the `CoreCli` and directly implementing command functions for `run`, `call`, and `namespace`.
- Improved argument parsing for server commands, including port specification and help options, enhancing user experience.
- Streamlined the invocation of JSON-RPC methods, ensuring consistent error handling and response formatting across commands.
- Introduced a new `run_namespace_command` function to manage namespace-specific operations, improving modularity and clarity in command execution.

* Refactor SkillsPanel and TauriCommandsPanel for improved integration handling

- Removed unused integration-related functions and state management from SkillsPanel, simplifying the component's logic.
- Updated TauriCommandsPanel to eliminate integration name input and associated commands, streamlining the user interface.
- Introduced a new local AI memory management module to handle session and memory operations, enhancing overall functionality.
- Refactored core RPC client to integrate local AI method dispatching, improving command handling consistency across the application.
- Cleaned up tauriCommands utility functions to align with the new command structure, enhancing maintainability.

* Refactor TauriCommandsPanel to streamline command handling

- Removed the `openhumanModelsRefresh` function and replaced its usage with `openhumanDoctorReport`, simplifying the command logic.
- Eliminated unused model refresh buttons from the UI, enhancing the user interface and reducing clutter.
- Updated related utility functions in `tauriCommands.ts` to reflect the removal of model refresh functionality, improving maintainability.

* Refactor JSON-RPC server integration and remove legacy server module

- Updated the CLI to invoke the JSON-RPC server directly, enhancing command execution flow.
- Introduced a new HTTP router in the `jsonrpc` module, consolidating route handling for health checks and RPC requests.
- Removed the deprecated `server` module, streamlining the codebase and improving maintainability.
- Adjusted tests to reflect the new routing structure, ensuring continued functionality and integration.

* Remove submodule and update CLAUDE.md documentation

- Deleted the `.gitmodules` file and removed the `skills` submodule, simplifying the project structure.
- Updated the description in `CLAUDE.md` to reflect a broader focus on community assistance rather than just crypto, enhancing clarity.
- Added sections on coding philosophy and controller migration checklist to improve developer guidance and maintainability.

* Refactor controller registration and enhance schema management

- Introduced a centralized registry for registered controllers, improving the organization and validation of controller schemas.
- Updated the `all_registered_controllers` and `all_controller_schemas` functions across various modules to streamline controller management.
- Added comprehensive validation for controller registration to ensure consistency and prevent duplicate entries.
- Enhanced the CLI and JSON-RPC integration to utilize the new registry structure, improving command handling and modularity.
- Updated documentation in `CLAUDE.md` to reflect changes in the skills registry and controller management processes, enhancing clarity for contributors.

* Enhance autocomplete, config, and credentials modules with new schemas and controller registrations

- Added support for autocomplete, config, and credentials functionalities by introducing new schemas and registered controllers.
- Updated the `build_registered_controllers` and `build_declared_controller_schemas` functions to include new entries for autocomplete, config, and credentials.
- Implemented new JSON-RPC tests for autocomplete and config methods, ensuring proper validation and error handling.
- Refactored CLI tests to include checks for new commands related to autocomplete and configuration management, improving test coverage and reliability.
- Introduced new modules for schemas in autocomplete, config, and credentials, enhancing code organization and maintainability.

* Add local AI and migration modules with schemas and controller registrations

- Introduced local AI and migration functionalities by adding new schemas and registered controllers.
- Updated the `build_registered_controllers` and `build_declared_controller_schemas` functions to include entries for local AI and migration.
- Implemented JSON-RPC tests for local AI and migration methods, ensuring proper validation and error handling.
- Enhanced CLI tests to verify new commands related to local AI and migration, improving test coverage and reliability.
- Organized code by creating dedicated modules for schemas in local AI and migration, enhancing maintainability.

* Refactor controller schemas for config and auth modules

- Updated controller schemas for config and auth functionalities, aligning namespaces and function names for consistency.
- Changed function names in the JSON-RPC tests to reflect the new schema structure, ensuring proper invocation.
- Enhanced CLI tests to verify updated commands related to config and auth, improving test coverage and reliability.
- Organized code by consolidating related functionalities under appropriate namespaces, enhancing maintainability.

* Add agent and screen intelligence modules with schemas and controller registrations

- Introduced agent and screen intelligence functionalities by adding new schemas and registered controllers.
- Updated the `build_registered_controllers` and `build_declared_controller_schemas` functions to include entries for agent and screen intelligence.
- Created dedicated modules for schemas in agent, screen intelligence, skills, tools, tray, and workspace, enhancing code organization and maintainability.
- Implemented initial controller schemas for agent and screen intelligence, providing a foundation for future functionality.
- Enhanced the overall structure of the core module to accommodate new integrations, improving modularity and clarity.

* Enhance autocomplete and namespace descriptions in core modules

- Added a new function `namespace_description` to provide descriptions for various namespaces, improving user guidance in CLI commands.
- Updated the CLI help output to include namespace descriptions, enhancing clarity for users.
- Introduced a new `core` module for autocomplete functionalities, including various operations and structures related to inline autocomplete.
- Refactored the `autocomplete` module to improve organization and maintainability, consolidating related functionalities under appropriate namespaces.
- Implemented initial JSON-RPC operations for autocomplete, ensuring a robust interface for managing autocomplete features.

* Refactor and clean up code across multiple modules

- Removed unnecessary whitespace in `TauriCommandsPanel.tsx`, improving code readability.
- Cleaned up imports and reorganized code structure in `localCoreAiMemory.ts`, enhancing maintainability.
- Streamlined module imports in `mod.rs` files across various directories, ensuring consistency and clarity.
- Deleted the obsolete `rpc.rs` file in the `cron` module, consolidating functionality and reducing clutter.
- Updated function definitions in `ops.rs` to improve formatting and readability, enhancing overall code quality.

* Refactor session management and enhance module organization

- Changed `sessionIndex` from a mutable variable to a constant in `localCoreAiMemory.ts`, improving code clarity and immutability.
- Introduced new `ops.rs` files in the `approval`, `providers`, `skills`, and `quickjs_libs` modules, consolidating related functionalities and enhancing code organization.
- Streamlined module imports in `mod.rs` files across various directories, ensuring consistency and clarity in module structure.
- Removed obsolete code and unnecessary comments, improving overall code readability and maintainability.

* Refactor configuration schema organization and module structure

- Moved the configuration schema definitions from `mod.rs` to a new `types.rs` file, enhancing modularity and clarity.
- Updated module imports across various files to reflect the new structure, ensuring consistency in the codebase.
- Cleaned up obsolete code and comments, improving overall readability and maintainability.

* Remove obsolete configuration schema file and its associated modules

- Deleted the `types.rs` file from the configuration schema, consolidating the codebase and removing unused components.
- This change enhances maintainability by eliminating redundant code and streamlining the overall structure of the configuration management.

* Fix config schema module exports

* Add configuration schema types and enhance module exports

- Introduced a new `types.rs` file to define the top-level configuration structure for `config.toml`, improving modularity and clarity.
- Updated `mod.rs` to re-export all public types and configurations, ensuring a streamlined interface for the configuration schema.
- Enhanced the organization of configuration components, making it easier to manage and extend in the future.

* Update import path for AuthProfile and AuthProfileKind in tests module

- Changed the import statement for `AuthProfile` and `AuthProfileKind` to use the correct path, ensuring proper module resolution and consistency in the codebase.

* Refactor import statements in test files for consistency

- Cleaned up import statements across multiple test files by removing unnecessary components and ensuring uniformity in module imports.
- This change enhances code readability and maintainability by streamlining the import structure.

* Add agent chat and REPL session handling with schemas

- Introduced new schemas for agent chat and REPL session management, enhancing the functionality of the agent module.
- Implemented handlers for chat and REPL session operations, allowing for more interactive and persistent user sessions.
- Updated the memory store to include category handling for memory entries, improving data organization and retrieval.
- Refactored memory query methods to support ranked results and category storage, enhancing the memory management capabilities.
- Improved error handling in memory recall tools to ensure non-empty parameters, increasing robustness and user feedback.

* Refactor JSON-RPC method names for consistency and clarity

- Updated JSON-RPC method names in tests to follow a consistent naming convention, improving readability and maintainability.
- Adjusted parameter names in the JSON payload to align with the updated method names, ensuring proper functionality and clarity in the API interactions.
- Enhanced overall code organization by streamlining method calls in the test suite.
2026-03-29 15:59:34 -07:00

301 lines
10 KiB
Rust

use anyhow::Result;
use serde_json::{Map, Value};
use std::collections::BTreeMap;
use crate::core::all;
use crate::core::jsonrpc::{default_state, invoke_method, parse_json_params};
use crate::core::{ControllerSchema, TypeSchema};
const CLI_BANNER: &str = r#"
▗▄▖ ▄▄▄▄ ▗▞▀▚▖▄▄▄▄ ▗▖ ▗▖█ ▐▌▄▄▄▄ ▗▞▀▜▌▄▄▄▄
▐▌ ▐▌█ █ ▐▛▀▀▘█ █ ▐▌ ▐▌▀▄▄▞▘█ █ █ ▝▚▄▟▌█ █
▐▌ ▐▌█▄▄▄▀ ▝▚▄▄▖█ █ ▐▛▀▜▌ █ █ █ █
▝▚▄▞▘█ ▐▌ ▐▌
Contribute & Star us on GitHub: https://github.com/tinyhumansai/openhuman
"#;
pub fn run_from_cli_args(args: &[String]) -> Result<()> {
eprint!("{CLI_BANNER}");
let grouped = grouped_schemas();
if args.is_empty() || is_help(&args[0]) {
print_general_help(&grouped);
return Ok(());
}
match args[0].as_str() {
"run" | "serve" => run_server_command(&args[1..]),
"call" => run_call_command(&args[1..]),
namespace => run_namespace_command(namespace, &args[1..], &grouped),
}
}
fn run_server_command(args: &[String]) -> Result<()> {
let mut port: Option<u16> = None;
let mut i = 0usize;
while i < args.len() {
match args[i].as_str() {
"--port" => {
let raw = args
.get(i + 1)
.ok_or_else(|| anyhow::anyhow!("missing value for --port"))?;
port = Some(
raw.parse::<u16>()
.map_err(|e| anyhow::anyhow!("invalid --port: {e}"))?,
);
i += 2;
}
"-h" | "--help" => {
println!("Usage: openhuman run [--port <u16>]");
return Ok(());
}
other => return Err(anyhow::anyhow!("unknown run arg: {other}")),
}
}
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()?;
rt.block_on(async { crate::core::jsonrpc::run_server(port).await })?;
Ok(())
}
fn run_call_command(args: &[String]) -> Result<()> {
let mut method: Option<String> = None;
let mut params = "{}".to_string();
let mut i = 0usize;
while i < args.len() {
match args[i].as_str() {
"--method" => {
method = Some(
args.get(i + 1)
.ok_or_else(|| anyhow::anyhow!("missing value for --method"))?
.clone(),
);
i += 2;
}
"--params" => {
params = args
.get(i + 1)
.ok_or_else(|| anyhow::anyhow!("missing value for --params"))?
.clone();
i += 2;
}
"-h" | "--help" => {
println!("Usage: openhuman call --method <name> [--params '<json>']");
return Ok(());
}
other => return Err(anyhow::anyhow!("unknown call arg: {other}")),
}
}
let method = method.ok_or_else(|| anyhow::anyhow!("--method is required"))?;
let params = parse_json_params(&params).map_err(anyhow::Error::msg)?;
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()?;
let value = rt
.block_on(async { invoke_method(default_state(), &method, params).await })
.map_err(anyhow::Error::msg)?;
println!("{}", serde_json::to_string_pretty(&value)?);
Ok(())
}
fn run_namespace_command(
namespace: &str,
args: &[String],
grouped: &BTreeMap<String, Vec<ControllerSchema>>,
) -> Result<()> {
let Some(schemas) = grouped.get(namespace) else {
return Err(anyhow::anyhow!(
"unknown namespace '{namespace}'. Run `openhuman --help` to see available namespaces."
));
};
if args.is_empty() || is_help(&args[0]) {
print_namespace_help(namespace, schemas);
return Ok(());
}
let function = args[0].as_str();
let Some(schema) = schemas.iter().find(|s| s.function == function).cloned() else {
return Err(anyhow::anyhow!(
"unknown function '{namespace} {function}'. Run `openhuman {namespace} --help`."
));
};
if args.len() > 1 && is_help(&args[1]) {
print_function_help(namespace, &schema);
return Ok(());
}
let params = parse_function_params(&schema, &args[1..]).map_err(anyhow::Error::msg)?;
let method = all::rpc_method_from_parts(namespace, function)
.ok_or_else(|| anyhow::anyhow!("unregistered controller '{namespace}.{function}'"))?;
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()?;
let value = rt
.block_on(async { invoke_method(default_state(), &method, Value::Object(params)).await })
.map_err(anyhow::Error::msg)?;
println!("{}", serde_json::to_string_pretty(&value)?);
Ok(())
}
fn parse_function_params(
schema: &ControllerSchema,
args: &[String],
) -> Result<Map<String, Value>, String> {
let mut out = Map::new();
let mut i = 0usize;
while i < args.len() {
let raw = &args[i];
if !raw.starts_with("--") {
return Err(format!("invalid arg '{raw}', expected --<param> <value>"));
}
let key = raw.trim_start_matches("--").replace('-', "_");
let Some(spec) = schema.inputs.iter().find(|input| input.name == key) else {
return Err(format!(
"unknown param '{key}' for {}.{}",
schema.namespace, schema.function
));
};
let raw_value = args
.get(i + 1)
.ok_or_else(|| format!("missing value for --{key}"))?;
let value = parse_input_value(&spec.ty, raw_value)?;
out.insert(key, value);
i += 2;
}
all::validate_params(schema, &out)?;
Ok(out)
}
fn parse_input_value(ty: &TypeSchema, raw: &str) -> Result<Value, String> {
match ty {
TypeSchema::String => Ok(Value::String(raw.to_string())),
TypeSchema::Bool => raw
.parse::<bool>()
.map(Value::Bool)
.map_err(|e| format!("expected bool, got '{raw}': {e}")),
TypeSchema::I64 => raw
.parse::<i64>()
.map(|n| Value::Number(n.into()))
.map_err(|e| format!("expected i64, got '{raw}': {e}")),
TypeSchema::U64 => raw
.parse::<u64>()
.map(|n| Value::Number(n.into()))
.map_err(|e| format!("expected u64, got '{raw}': {e}")),
TypeSchema::F64 => {
let n = raw
.parse::<f64>()
.map_err(|e| format!("expected f64, got '{raw}': {e}"))?;
serde_json::Number::from_f64(n)
.map(Value::Number)
.ok_or_else(|| format!("invalid f64 '{raw}'"))
}
TypeSchema::Option(inner) => parse_input_value(inner, raw),
TypeSchema::Enum { .. } => Ok(Value::String(raw.to_string())),
TypeSchema::Json
| TypeSchema::Array(_)
| TypeSchema::Map(_)
| TypeSchema::Object { .. }
| TypeSchema::Ref(_)
| TypeSchema::Bytes => parse_json_params(raw),
}
}
fn grouped_schemas() -> BTreeMap<String, Vec<ControllerSchema>> {
let mut grouped: BTreeMap<String, Vec<ControllerSchema>> = BTreeMap::new();
for schema in all::all_controller_schemas() {
grouped
.entry(schema.namespace.to_string())
.or_default()
.push(schema);
}
for schemas in grouped.values_mut() {
schemas.sort_by_key(|s| s.function);
}
grouped
}
fn print_general_help(grouped: &BTreeMap<String, Vec<ControllerSchema>>) {
println!("OpenHuman core CLI\n");
println!("Usage:");
println!(" openhuman run [--port <u16>]");
println!(" openhuman call --method <name> [--params '<json>']");
println!(" openhuman <namespace> <function> [--param value ...]\n");
println!("Available namespaces:");
for namespace in grouped.keys() {
let description = all::namespace_description(namespace.as_str())
.unwrap_or("No namespace description available.");
println!(" {namespace} - {description}");
}
println!("\nUse `openhuman <namespace> --help` to see functions.");
}
fn print_namespace_help(namespace: &str, schemas: &[ControllerSchema]) {
println!("Namespace: {namespace}\n");
if let Some(description) = all::namespace_description(namespace) {
println!("{description}\n");
}
println!("Functions:");
for schema in schemas {
println!(" {} - {}", schema.function, schema.description);
}
println!("\nUse `openhuman {namespace} <function> --help` for parameters.");
}
fn print_function_help(namespace: &str, schema: &ControllerSchema) {
println!("{} {}\n", namespace, schema.function);
println!("{}", schema.description);
println!("\nParameters:");
if schema.inputs.is_empty() {
println!(" none");
} else {
for input in &schema.inputs {
let required = if input.required {
"required"
} else {
"optional"
};
println!(" --{} ({}) - {}", input.name, required, input.comment);
}
}
}
fn is_help(value: &str) -> bool {
matches!(value, "-h" | "--help" | "help")
}
#[cfg(test)]
mod tests {
use super::grouped_schemas;
#[test]
fn grouped_schemas_contains_migrated_namespaces() {
let grouped = grouped_schemas();
assert!(grouped.contains_key("health"));
assert!(grouped.contains_key("doctor"));
assert!(grouped.contains_key("encrypt"));
assert!(grouped.contains_key("decrypt"));
assert!(grouped.contains_key("autocomplete"));
assert!(grouped.contains_key("config"));
assert!(grouped.contains_key("auth"));
assert!(grouped.contains_key("service"));
assert!(grouped.contains_key("migrate"));
assert!(grouped.contains_key("local_ai"));
}
}