Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

220 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Portal

HippoX

A reliable, autonomous LLM runtime and driver orchestration engine.
Capable of processing natural language and automatically executing OS-native drivers, fundamentally enabling the LLM to truly take over the computer.

License Crates.io Downloads

简体中文 | English

🔗 Quick Links

Resource Link
🌐 Website https://hippox.vercel.app/
📖 Documentation https://hippox-docs-en.vercel.app/
📦 Crates.io https://crates.io/crates/hippox
💻 GitHub https://github.com/0xhappyboy/hippo

Basic Usage

Instantiate

// =================== Method 1 ===================
let hippox = Hippox::builder(ModelProvider::OpenAI)
    .api_key("sk-xxx")
    .lang("zh")
    .identity(|id| {
        id.name = Some("agent".to_string());
        id.role = Some("assistant".to_string());
        id.personality = Some("friendly".to_string());
    })
    .build()
    .await?;

// =================== Method 2 ===================
let mut config = HippoxConfig::default();
config.lang = "zh".to_string();
config.identity_information = IdentityInformation {
    name: Some("agent".to_string()),
    role: Some("assistant".to_string()),
    personality: Some("friendly".to_string()),
    ..Default::default()
};
let hippox = Hippox::new(
    ModelProvider::OpenAI,
    Some("sk-xxx".to_string()),
    None,
    Some(config),
).await?;

// =================== Simple Method ===================
let hippox = Hippox::new(
    ModelProvider::OpenAI,
    Some("sk-xxx".to_string()),
    None,
    Some(HippoxConfig::default()),
).await?;

// builder
let hippox = Hippox::builder(ModelProvider::OpenAI)
    .api_key("sk-xxx")
    .build()
    .await?;

Task Execution

Submit

1. Execution mode
  • Asynchronous non-blocking submission. Task goes to background pool, returns task_id immediately. Result must be obtained via polling.
2. How it works
  • Call submit() method
  • NaturalLanguageTask is created and pushed to global TASK_POOL
  • Background execution engine processes tasks automatically
  • Method returns task_id immediately (does NOT wait for completion)
  • Caller repeatedly queries get_task(task_id) to check status
  • When task.status == TaskStatus::Completed, extract result from task.final_output
3. Use when
  • You don't need immediate results, or want to run multiple tasks concurrently.
use hippox::{Hippox, TaskStatus};
use langhub::types::ModelProvider;
use std::time::Duration;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let hippox = Hippox::builder(ModelProvider::OpenAI)
        .api_key("sk-xxx")
        .build()
        .await?;
    // Submit task, returns task_id immediately
    let task_id = hippox.submit("Calculate 15 * 3", None);
    let result = hippox.wait_task(&task_id).await?;
    println!("Result: {}", result);
    Ok(())
}

Execute - Direct execution

1. Execution mode
  • Synchronous blocking call. The function waits until the task completes and returns the result directly.
2. How it works
  • Call execute() method
  • Task starts immediately in the current thread
  • Code pauses and waits for completion
  • Returns HippoxStringResult result directly
3. Use when
  • You need the result immediately and don't want to manage task state.
use hippox::Hippox;
use langhub::types::ModelProvider;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let hippox = Hippox::builder(ModelProvider::OpenAI)
        .api_key("sk-xxx")
        .build()
        .await?;
    // Execute and wait for result
    let result = hippox.execute("Calculate 15 * 3", None).await;
    println!("Result: {}", result);
    Ok(())
}

Custom Drivers and Driver Classification

use hippox_drivers::{
    Driver, DriverCallback, DriverCategory, DriverContext, DriverError, DriverResult,
    DriverParameter, register_driver,
};
use serde_json::{json, Value};
use std::collections::HashMap;
use std::sync::Arc;

const CATEGORY_WEATHER: DriverCategory = DriverCategory::Custom("weather_ops");

#[derive(Debug)]
pub struct WeatherDriver;

#[async_trait::async_trait]
impl Driver for WeatherDriver {
    fn name(&self) -> &str { "weather_query" }
    fn description(&self) -> &str { "Query weather for a city" }
    fn category(&self) -> DriverCategory { CATEGORY_WEATHER }
    fn parameters(&self) -> Vec<DriverParameter> {
        vec![DriverParameter {
            name: "city".to_string(),
            param_type: "string".to_string(),
            description: "City name".to_string(),
            required: true,
            default: None,
            example: Some(Value::String("Beijing".to_string())),
            enum_values: None,
        }]
    }
    fn example_call(&self) -> DriverResult<Value> {
        Ok(json!({"action": "weather_query", "parameters": {"city": "Beijing"}}))
    }
    fn example_output(&self) -> String {
        "Weather for Beijing: 25°C, Sunny".to_string()
    }
    async fn execute(
        &self,
        parameters: &HashMap<String, Value>,
        _callback: Option<&dyn DriverCallback>,
        _context: Option<&DriverContext>,
    ) -> DriverResult<String> {
        let city = parameters.get("city").and_then(|v| v.as_str())
            .ok_or_else(|| DriverError::missing_parameter("city"))?;
        Ok(format!("Weather for {}: 25°C, Sunny", city))
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Register custom driver
    register_driver(
        CATEGORY_WEATHER,
        "weather_query".to_string(),
        Arc::new(WeatherDriver),
    );
    // Verify: get driver and execute
    use hippox_drivers::get_driver_by_name;
    let driver = get_driver_by_name("weather_query").unwrap();
    let mut params = HashMap::new();
    params.insert("city".to_string(), json!("Shanghai"));
    let result = driver.execute(&params, None, None).await?;
    println!("{}", result); // Weather for Shanghai: 25°C, Sunny
    // Verify custom category is registered
    use hippox_drivers::get_all_categorys;
    println!("All categories: {:?}", get_all_categorys()); // includes "weather_ops"
    Ok(())
}

Configuration

1. HippoxConfig

/// Hippox global configuration
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct HippoxConfig {
    /// Language setting: "en" or "zh"
    pub lang: String,
    /// AI identity information (name, role, personality, etc.)
    pub identity_information: IdentityInformation,
}

2. IdentityInformation

/// AI identity configuration
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct IdentityInformation {
    /// AI name, e.g., "Assistant", "Hippox"
    pub name: Option<String>,
    /// Gender, e.g., "male", "female", "neutral"
    pub sex: Option<String>,
    /// Age, e.g., "25", "young"
    pub age: Option<String>,
    /// Species, e.g., "AI", "human", "robot"
    pub species: Option<String>,
    /// Role, e.g., "assistant", "teacher", "life coach"
    pub role: Option<String>,
    /// Personality, e.g., "friendly", "humorous", "professional"
    pub personality: Option<String>,
    /// Tone style, e.g., "casual", "formal", "poetic"
    pub tone_style: Option<String>,
    /// Knowledge scope, e.g., "general", "medical", "programming"
    pub knowledge_scope: Option<String>,
    /// Catchphrase, e.g., "Haha", "I see", "Let's go"
    pub catchphrase: Option<String>,
    /// Prohibited topics, e.g., "no politics", "no medical advice"
    pub taboos: Option<String>,
}

Hippox Core Working Principle

┌─────────────────────────────────────────────────────────────────────────────┐
│                        Hippox Core Working Principle                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │ 1. Task Submission (Non-blocking)                                     │ │
│  │    hippox.submit(input) → NaturalLanguageTask → TASK_POOL            │ │
│  │    → TASK_NOTIFIER.notify_one() → return task_id                     │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                      │                                      │
│                                      ▼                                      │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │ 2. Intent Analysis (Step 1)                                           │ │
│  │    build_intent_parser_prompt() → LLM.generate() → parse              │ │
│  │    Output: clean_intent, skill_categories                             │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                      │                                      │
│                                      ▼                                      │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │ 3. Workflow Execution (Step 2) using clean_intent                     │ │
│  │    ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────────┐        │ │
│  │    │  ReAct   │ │  Batch   │ │  Chain   │ │ PlanAndExecute  │        │ │
│  │    └────┬─────┘ └────┬─────┘ └────┬─────┘ └───────┬─────────┘        │ │
│  │         └────────────┴────────────┴──────────────┘                   │ │
│  │    LLM generates SkillCall → Executor.execute() → raw_json           │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                      │                                      │
│                                      ▼                                      │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │ 4. Response Formatting (Step 3)                                       │ │
│  │    needs_format_conversion(original_input)?                           │ │
│  │    ┌─────────┐      ┌─────────────────────────────────────────────┐  │ │
│  │    │  false  │ ──▶ │  return raw_json directly                    │  │ │
│  │    └─────────┘      └─────────────────────────────────────────────┘  │ │
│  │    ┌─────────┐      ┌─────────────────────────────────────────────┐  │ │
│  │    │  true   │ ──▶ │  build_format_conversion_prompt()            │  │ │
│  │    └─────────┘      │  → LLM.generate() → formatted output        │  │ │
│  │                     └─────────────────────────────────────────────┘  │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                      │                                      │
│                                      ▼                                      │
│                              final_output                                   │
└─────────────────────────────────────────────────────────────────────────────┘

Pipe Line

User Input
    │
    ▼
┌─────────────┐
│   Step 1    │ → Intent Analysis
│   Analysis  │   build_intent_parser_prompt() → LLM
└──────┬──────┘   Output: clean_intent, skill_categories
       │
       ▼
┌─────────────┐
│   Step 2    │ → Workflow Execution
│  Execution  │   Execute skills using clean_intent
└──────┬──────┘   Output: raw_json
       │
       ▼
┌─────────────┐      ┌─────────────┐
│ Need Format │ ──Yes──▶│   Step 3    │ → Response Formatting
│ Conversion? │      │ Formatting  │   build_format_conversion_prompt() → LLM
└──────┬──────┘      └──────┬──────┘
       │                    │
       └──────────┬─────────┘
                  ▼
            Final Output

Task Pool

State Machine

Pending ──► Running ──► Completed
    │           │
    │           ├──► Paused ──► Running (resume)
    │           │
    │           └──► Cancelled
    │
    └──► Cancelled
              │
              └──► Failed ──► Pending (retry)

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                      Global Static (Auto-Start)                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │                    GLOBAL_TASK_POOL                        │  │
│  │              (Initialized at program load)                │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                        Hippox Instance                          │
├─────────────────────────────────────────────────────────────────┤
│  ┌───────────────────────────────────────────────────────────┐  │
│  │                    TaskPool (Global)                       │  │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐                   │  │
│  │  │Task A   │  │Task B   │  │Task C   │                   │  │
│  │  │Pending  │  │Running  │  │Pending  │                   │  │
│  │  └────┬────┘  └────┬────┘  └────┬────┘                   │  │
│  │       └────────────┼────────────┘                         │  │
│  │                    ▼                                      │  │
│  │         ┌─────────────────────┐                          │  │
│  │         │    Priority Queue   │                          │  │
│  │         │  [Task A, Task C]   │                          │  │
│  │         └──────────┬──────────┘                          │  │
│  │                    │                                      │  │
│  │                    ▼                                      │  │
│  │         ┌─────────────────────┐                          │  │
│  │         │  Execution Engine   │  (max: 10 workers)      │  │
│  │         │  ┌────┐ ┌────┐ ┌────┐                         │  │
│  │         │  │ W1 │ │ W2 │ │ W3 │  ...                    │  │
│  │         │  └──┬─┘ └──┬─┘ └──┬─┘                         │  │
│  │         │     └──────┼──────┘                           │  │
│  │         │           ▼                                   │  │
│  │         │  ┌─────────────────┐                          │  │
│  │         │  │ ExecutableTask  │                          │  │
│  │         │  │   .execute()    │                          │  │
│  │         │  └─────────────────┘                          │  │
│  │         └─────────────────────┘                          │  │
│  │                    ▲                                      │  │
│  │         ┌──────────┴──────────┐                          │  │
│  │         │  Notifier (wakeup)  │                          │  │
│  │         └─────────────────────┘                          │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                  │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │              ExecutableTask Implementation                │  │
│  │  ┌─────────────────────────────────────────────────────┐  │  │
│  │  │                  NaturalLanguageTask                │  │  │
│  │  │  • input: String                                    │  │  │
│  │  │  • workflow_executor: WorkflowExecutor              │  │  │
│  │  │  • scheduler: SkillScheduler                        │  │  │
│  │  └─────────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                         External APIs                           │
├─────────────────────────────────────────────────────────────────┤
│  handle_natural_language()  → task_id  (non-blocking)          │
│  get_task_status() / cancel() / pause() / resume() / retry()   │
└─────────────────────────────────────────────────────────────────┘

Workflow Model

Mode Enum Value Core Features LLM Calls Use Cases
ReAct WorkflowMode::ReAct Think → Act → Observe loop, LLM decides next step after each execution 1 per skill + 1 final response Open-ended tasks, dynamic decision making, error recovery
Batch WorkflowMode::Batch Execute multiple independent skills in parallel 1 (generates batch plan) Independent operations, bulk processing
Chain WorkflowMode::Chain Sequential execution with variable passing ({{variable}} syntax) 1 (generates chain) Linear pipelines, data transformation chains
PlanAndExecute WorkflowMode::PlanAndExecute One-time planning with conditional branching, variable references ({"$ref":"var"}), error handling (retry/skip/fail) 1 plan + optional dynamic decisions Complex workflows, conditional logic, deterministic tasks

Chain

Batch

ReAct

PlanAndExecute

Workflow Atomic Skill Retry Strategy

ReAct

PlanAndExecute

Chain

Batch

Atomic Skill Registry

💡 Hint:In Hippox, an atomic skill represents a smallest indivisible unit of execution, This is a different concept from "Skill" in user business.

Working Principle

┌─────────────────────────────────────────────────────────────┐
│                      SKILL REGISTRY                        │
│                                                           │
│  SkillRegistryMap = HashMap<SkillCategory,               │
│                      HashMap<String, Arc<dyn Skill>>>    │
│                                                           │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐              │
│  │ File     │  │ Math     │  │ Net      │              │
│  ├──────────┤  ├──────────┤  ├──────────┤              │
│  │ read     │  │ calc     │  │ http     │              │
│  │ write    │  │ power    │  │ ping     │              │
│  │ delete   │  │ stats    │  │ dns      │              │
│  │ ...      │  │ ...      │  │ ...      │              │
│  └──────────┘  └──────────┘  └──────────┘              │
└─────────────────────────────────────────────────────────────┘

Registration:

  Compile-time: file_register() / math_register() / net_register()
  Runtime: register_skill(category, name, skill)

Query:

  get_skill_by_name("read") → Skill impl → execute()

Core Type

pub type SkillRegistryMap = HashMap<SkillCategory, HashMap<String, Arc<dyn Skill>>>;

Main Functions

Function Description
get_registry() Get read lock on the registry
get_registry_mut() Get write lock on the registry
register_skill(category, name, skill) Dynamically register a skill
get_all_skills() Get all registered skills
get_skill_by_name(name) Find a skill by name
get_skill_by_name_and_category(name, category) Find a skill by name and category
has_skill(name) Check if a skill exists
list_skills_names() List all skill names
list_skills_name_by_category(category) List skill names in a category
get_skills_by_category(category) Get skills by category string
get_skills_by_category_list(categories) Get skills by multiple categories
list_skills_name_by_category_list(categories) List skill names by multiple categories
get_all_categorys() Get all category names
get_skill_category() Get categories with skill counts
get_skill_category_names() Get all category names
get_skill_category_name_and_describe() Get category names with descriptions
generate_skill_registry_table_json_str() Generate registry JSON string

SkillCategory Methods

Method Description
from_str(s) Convert string to enum
name() Convert enum to string (lowercase)
display_name() Get human-readable display name
description() Get category description
icon() Get category icon/emoji
priority() Get display priority (lower = first)
metadata() Get complete category metadata
all_categories() Get metadata for all categories

About

🦛A reliable, autonomous LLM runtime and driver orchestration engine. Capable of processing natural language and automatically executing OS-native drivers, fundamentally enabling the LLM to truly take over the computer.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages