Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
c5940bc
build(cargo): define the default-ON `flows` feature (#4797)
oxoxDev Jul 15, 2026
1271a41
refactor(flows): gate the flows/tinyflows/rhai_workflows module decls…
oxoxDev Jul 15, 2026
1f5bb0f
refactor(core): gate flows controller, subscriber, and boot reconcile…
oxoxDev Jul 15, 2026
99da254
refactor(tools): gate the flows + rhai_workflows agent tools (#4797)
oxoxDev Jul 15, 2026
f7d557b
refactor(agent_registry): gate the workflow_builder + flow_discovery …
oxoxDev Jul 15, 2026
1970c9b
test(flows): gate flows-asserting tests + add directional coverage (#…
oxoxDev Jul 15, 2026
8997359
build(tauri): enable the flows feature in the desktop shell (#4797)
oxoxDev Jul 15, 2026
b25121b
docs(agents): document the flows leaf-gate + dep-shed scope (#4797)
oxoxDev Jul 15, 2026
76336d1
Merge remote-tracking branch 'upstream/main' into feat/4797-flows-fea…
oxoxDev Jul 15, 2026
f14c34b
test(flows): gate flows JSON-RPC E2E tests behind the flows feature (…
oxoxDev Jul 15, 2026
26ee61d
Merge remote-tracking branch 'upstream/main' into pr/4912
senamakel Jul 15, 2026
87ab7c4
Merge remote-tracking branch 'upstream/main' into feat/4797-flows-fea…
oxoxDev Jul 16, 2026
3af7725
Merge branch 'main' into pr/4912
M3gA-Mind Jul 16, 2026
3717f30
fix(flows): classify all flow-owned tools as DomainGroup::Flows
M3gA-Mind Jul 16, 2026
b1114dd
Merge branch 'main' into pr/4912
M3gA-Mind Jul 16, 2026
da5c867
Merge branch 'main' into pr/4912
M3gA-Mind Jul 16, 2026
73b3493
Merge branch 'main' into pr/4912 — resolve flows+skills feature-gate …
M3gA-Mind Jul 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-lite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ jobs:
cache-on-failure: true
shared-key: pr-rust-feature-gate-smoke

- name: Check core builds with the voice + media gates disabled
- name: Check core builds with the default domain gates disabled
run: bash scripts/ci-cancel-aware.sh cargo check --manifest-path Cargo.toml --no-default-features --features tokenjuice-treesitter

rust-core-coverage:
Expand Down
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ GGML_NATIVE=OFF cargo check --manifest-path Cargo.toml \
| `media` | ON | `openhuman::media_generation` (the `media_generate_*` agent tools) + `openhuman::image` scaffold | none (surface-only) |
| `meet` | ON | `openhuman::meet` (join-URL validation) + `openhuman::meet_agent` (live STT/LLM/TTS loop) + `openhuman::agent_meetings` (backend-delegated Meet bot over Socket.IO) | none — see note |
| `skills` | ON | `openhuman::skills` + `openhuman::skill_runtime` + `openhuman::skill_registry` domains — SKILL.md discovery/parse/install, workflow execution + run logs, remote catalogs, the `skill_setup` / `skill_executor` builtin agents, and the 16 skill agent tools | none (see below) |
| `flows` | ON | `openhuman::flows` (saved automation graphs — create/run/schedule, the `workflow_builder` + `flow_discovery` agents), `openhuman::tinyflows` (engine seam), `openhuman::rhai_workflows` (`.ragsh` language-workflow tool) | `tinyflows`, `jaq-core`, `jaq-std`, `jaq-json`, `rhai` |

**Facade pattern (pathfinder for the other gates).** `pub mod voice;` is **always compiled** as a facade: the real submodules are `#[cfg(feature = "voice")]`, and a `#[cfg(not(feature = "voice"))] mod stub;` (`src/openhuman/voice/stub.rs`) re-exposes the same public surface that always-on / other-gated callers use (`server`, `dictation_listener`, `streaming`, `reply_speech`, `cloud_transcribe`, `cli`, `create_stt_provider`, `effective_stt_provider`, `publish_ptt_transcript_committed`) with no-op / `None` / disabled-error bodies. Callers therefore do **not** need per-call `#[cfg]`. When voice is off: the voice/audio controllers are unregistered (unknown-method over `/rpc`, absent from `/schema`), the `audio_generate_podcast` agent tools are absent, and `openhuman voice` returns a "voice disabled" error. Stub signatures must match the real ones exactly — the disabled build (`--no-default-features --features tokenjuice-treesitter`) is the **only** thing that catches drift, so run it before pushing any change to the voice surface.

Expand Down Expand Up @@ -276,6 +277,12 @@ Two places the carve-out doesn't reach, and why they are `#[cfg]` at the call si

When skills are off: the `skills` / `skill_runtime` / `skill_registry` controllers are unregistered (unknown-method over `/rpc`, absent from `/schema`), the 16 skill agent tools (incl. `run_workflow` / `await_workflow`) are **absent** from the tool list rather than degraded to an error, the `skill_setup` / `skill_executor` builtin agents are gone, and the boot-time remote catalog refresh is skipped. Composes with the runtime `DomainSet::skills` flag (#4796) — that axis needed no change here; #4798 is compile-time only.

**Leaf-gate pattern (`flows`).** Where `voice` needs a stub facade, `flows` needs **none** — and deliberately so. Every symbol reached from outside the gate is a *registration site* (controller push in `src/core/all.rs`, the `FlowTriggerSubscriber` in `src/core/jsonrpc.rs`, boot reconcile in `src/core/runtime/services.rs`, agent-tool `vec!` elements in `src/openhuman/tools/ops.rs`, `BuiltinAgent` entries in `agent_registry/agents/loader.rs`). Registration sites want **absence**: a stub that registered a controller returning `Err("flows disabled")` would make `flows.*` a *known* method that fails at runtime — the opposite of the intended "unknown method / omitted tool". So the three modules are `#[cfg(feature = "flows")]` at their `pub mod` declaration and each call site carries its own `#[cfg]`. Nothing inside `flows/`, `tinyflows/`, or `rhai_workflows/` is modified. There is no `openhuman flows` CLI subcommand, so no CLI stub is needed either. When flows is off: the `flows.*` controllers are unregistered (unknown-method over `/rpc`, absent from `/schema`), all 25 flow agent tools + `rhai_workflows` are absent, and the `workflow_builder` / `flow_discovery` built-in agents are not advertised.

**Scope note (`flows` deps):** the gate sheds `tinyflows` + its `jaq-core` / `jaq-std` / `jaq-json` JSON-query stack, and `rhai`. It does **not** shed `tinyagents` — 26+ domains consume that crate. The issue-level DoD line reading "sheds the rhai scripting engine" is therefore true only at the **feature** level: `rhai` arrives via `tinyagents/repl`, which the root `Cargo.toml` no longer enables directly — the `flows` feature turns it on. Dropping `flows` drops `repl`, which drops `rhai`; `tinyagents` itself stays. Verify a claimed shed with `cargo tree -i <crate> --no-default-features --features tokenjuice-treesitter` (must return nothing) — compiling clean is **not** proof that a dep was dropped.

**Testing gotcha (applies to every gate).** The CI smoke lane runs `cargo check` only — it never runs `cargo test --no-default-features`, so CI stays green while the disabled-build **test** suite is broken. Tests that hard-assert a gated family (`.expect("a flows.* method exists")`, `assert!(full_ns.contains("flows"))`, `group_for_namespace("flows")`, built-in-agent id lists) must be `#[cfg]`-gated in lockstep with the feature. Run `GGML_NATIVE=OFF cargo test --lib --no-default-features --features tokenjuice-treesitter core::` locally before pushing any gate change.

### Event bus (`src/core/event_bus/`)

Typed pub/sub + native request/response. Both singletons — use module-level functions.
Expand Down
28 changes: 23 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ tinyplace = "2.0"
# deterministic in-memory capability bundle the flows `dry_run_workflow` agent
# tool (Phase 5b) runs a *draft* graph against so the workflow-builder agent can
# self-verify a proposal without any real side effects (no real LLM/tool/HTTP/code).
tinyflows = { version = "0.5", features = ["mock"] }
#
# Optional: exclusive to the default-ON `flows` feature (#4797). A slim build
# without `flows` drops this crate and its `jaq-*` JSON-query stack entirely.
tinyflows = { version = "0.5", features = ["mock"], optional = true }
# TinyJuice — host-agnostic TokenJuice compression engine. OpenHuman keeps
# config/RPC/tool/runtime adapters in `src/openhuman/tokenjuice/` and patches
# this dependency to the vendored submodule below.
Expand All @@ -77,9 +80,12 @@ tinyjuice = { version = "0.2.1", default-features = false }
# aligned to 0.40, avoiding duplicate `links = "sqlite3"` native bindings.
# Durable graph checkpoints still use `SqlRunLedgerCheckpointer` until the
# migration re-points those rows to the crate checkpointer.
# The `repl` feature adds the embedded Rhai `.ragsh` session runtime powering
# the `rhai_workflows` language-workflow tool (`src/openhuman/rhai_workflows/`).
tinyagents = { version = "1.7", features = ["sqlite", "repl"] }
# The `repl` feature (embedded Rhai `.ragsh` session runtime powering the
# `rhai_workflows` language-workflow tool, `src/openhuman/rhai_workflows/`) is
# NOT enabled here — the default-ON `flows` feature turns it on via
# `tinyagents/repl` (#4797), so a slim build without `flows` sheds `rhai`.
# The crate itself can never be dropped: 26+ domains consume tinyagents.
tinyagents = { version = "1.7", features = ["sqlite"] }
# TinyCortex — Rust core for the memory engine (store/chunks/tree/retrieval/
# queue/ingest/score + long tail), vendored as a git submodule and patched
# below to `vendor/tinycortex`. OpenHuman's memory subsystem migrates onto this
Expand Down Expand Up @@ -341,7 +347,7 @@ tokio = { version = "1", features = ["test-util"] }
proptest = "1"

[features]
default = ["tokenjuice-treesitter", "voice", "web3", "media", "meet", "skills"]
default = ["tokenjuice-treesitter", "voice", "web3", "media", "meet", "skills", "flows"]
# AST-aware code compression (tree-sitter Rust/TS/Python grammars; C build).
# On by default; disable to fall back to the brace-depth heuristic.
tokenjuice-treesitter = [
Expand Down Expand Up @@ -384,6 +390,18 @@ web3 = ["dep:bitcoin", "dep:curve25519-dalek"]
# controllers / stores / subscribers tagged `Media` (agent tools only), and
# `openhuman::image` is currently unwired scaffold (added #2997).
media = []
# Flows domains: the `flows::` automation surface (saved tinyflows graphs —
# create/run/schedule + the workflow_builder / flow_discovery agents), the
# `tinyflows::` adapter seam, and the `rhai_workflows::` language-workflow tool.
# Default-ON — the desktop app always ships with Workflows. Slim / headless
# builds opt out via `--no-default-features --features "<list without flows>"`,
# which drops `tinyflows` + its `jaq-core`/`jaq-std`/`jaq-json` JSON-query stack
# and, via `tinyagents/repl`, the `rhai` scripting engine. Composes with the
# runtime `DomainSet::flows` flag (#4796): the feature narrows the compile-time
# surface, `DomainSet` gates it at runtime.
# NOTE: this gate does NOT drop `tinyagents` itself — 26+ domains consume it.
# Only its `repl` feature (⇒ `rhai`) is exclusive to flows.
flows = ["dep:tinyflows", "tinyagents/repl"]
# Meet domains: `meet` (join-URL validation), `meet_agent` (live STT/LLM/TTS
# loop over an open call), and `agent_meetings` (backend-delegated Meet bot via
# Socket.IO). Default-ON — the desktop app always ships with Meet. Slim /
Expand Down
1 change: 1 addition & 0 deletions app/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ openhuman_core = { path = "../..", package = "openhuman", default-features = fal
"voice",
"tokenjuice-treesitter",
"web3",
"flows",
"meet",
"skills",
] }
Expand Down
2 changes: 2 additions & 0 deletions src/core/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ fn build_registered_controllers() -> Vec<GroupedController> {
crate::openhuman::cron::all_cron_registered_controllers(),
);
// Saved automation workflows (tinyflows graphs): create/get/list/update/delete/run
// (gated with flows).
#[cfg(feature = "flows")]
push(
Comment thread
M3gA-Mind marked this conversation as resolved.
&mut controllers,
DomainGroup::Flows,
Expand Down
47 changes: 46 additions & 1 deletion src/core/all_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,7 @@ async fn harness_excludes_gated_namespaces() {
.iter()
.map(|s| s.namespace)
.collect();
#[cfg(feature = "flows")]
assert!(full_ns.contains("flows"), "full() must expose flows");
assert!(full_ns.contains("voice"), "full() must expose voice");

Expand Down Expand Up @@ -859,6 +860,12 @@ async fn harness_excludes_gated_namespaces() {
);
}

// Uses a `flows.*` method as its gated-family vehicle, so the whole test is
// `#[cfg(feature = "flows")]`: without the feature there is no flows controller
// in the registry at all and the `.expect()` below would panic. The runtime
// gating this proves is orthogonal to the compile-time gate, and CI runs the
// test suite on default features (flows ON), so no coverage is lost there.
#[cfg(feature = "flows")]
#[tokio::test]
async fn dispatch_returns_none_for_gated_method() {
// A method whose group is gated OFF under the ambient DomainSet must
Expand Down Expand Up @@ -890,6 +897,8 @@ async fn dispatch_returns_none_for_gated_method() {
);
}

// Same flows-vehicle reasoning as `dispatch_returns_none_for_gated_method`.
#[cfg(feature = "flows")]
#[tokio::test]
async fn schema_lookup_is_gated_in_lockstep_with_dispatch() {
// #4808 review: `schema_for_rpc_method` must gate identically to
Expand Down Expand Up @@ -939,7 +948,10 @@ fn group_mapping_smoke() {
assert_eq!(group_for_namespace("config"), Some(DomainGroup::Config));
assert_eq!(group_for_namespace("security"), Some(DomainGroup::Security));
assert_eq!(group_for_namespace("agent"), Some(DomainGroup::Agent));
// …and a representative gated one maps to its gate group.
// …and a representative gated one maps to its gate group. `group_for_namespace`
// reads the real controller registry, so a compile-time-gated family has no
// entry to map when its feature is off.
#[cfg(feature = "flows")]
assert_eq!(group_for_namespace("flows"), Some(DomainGroup::Flows));
// `group_for_namespace` is registry-derived, so a compile-time-gated domain
// has no controller to map. Skip when its Cargo feature is off.
Expand All @@ -956,6 +968,39 @@ fn group_mapping_smoke() {
assert_eq!(group_for_namespace("mcp_audit"), Some(DomainGroup::Mcp));
}

// --- #4797: `flows` compile-time gate (directional proof) -------------------
//
// One namespace, not three: `tinyflows` registers no controllers, and
// `rhai_workflows` is `scope() = AgentOnly` (no controller schemas in v1), so
// `flows` is the gate's entire controller surface.

#[cfg(feature = "flows")]
#[test]
fn flows_controllers_registered_when_feature_on() {
let namespaces: Vec<&str> = all_controller_schemas()
.iter()
.map(|s| s.namespace)
.collect();
assert!(
namespaces.contains(&"flows"),
"with the `flows` feature ON the flows controllers must be registered"
);
}

#[cfg(not(feature = "flows"))]
#[test]
fn flows_controllers_absent_when_feature_off() {
let namespaces: Vec<&str> = all_controller_schemas()
.iter()
.map(|s| s.namespace)
.collect();
assert!(
!namespaces.contains(&"flows"),
"with the `flows` feature OFF the flows controllers must be absent \
(unknown-method over /rpc, omitted from /schema)"
);
}

/// All three Meet namespaces register when the `meet` feature is on (#4800).
///
/// Paired with `meet_controllers_absent_when_feature_off` below: together they
Expand Down
8 changes: 8 additions & 0 deletions src/core/jsonrpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2024,6 +2024,10 @@ fn register_domain_subscribers(
// runs `flows::ops::flows_run`, so schedule/app-event workflows still
// dispatch when no realtime channel is configured or
// `OPENHUMAN_DISABLE_CHANNEL_LISTENERS` short-circuits `start_channels`.
// The `plan.flows` runtime guard cannot stand in for the compile-time gate:
// the `flows::bus::FlowTriggerSubscriber` type path below must still resolve
// for this to compile, so the whole block is `#[cfg]`-gated too.
#[cfg(feature = "flows")]
if plan.flows {
if group_first_time(DomainGroup::Flows) {
if let Some(handle) = crate::core::event_bus::subscribe_global(Arc::new(
Expand All @@ -2039,6 +2043,10 @@ fn register_domain_subscribers(
} else {
log::debug!("[event_bus] flows trigger subscriber SKIPPED — Flows domain disabled");
}
#[cfg(not(feature = "flows"))]
log::debug!(
"[event_bus] flows trigger subscriber SKIPPED — flows feature disabled at compile time"
);

// Memory: conversation-persistence + sync-stage bridge.
if plan.memory {
Expand Down
5 changes: 5 additions & 0 deletions src/core/jsonrpc_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ async fn invoke_doctor_models_rejects_unknown_param() {
assert!(err.contains("unknown param 'invalid'"));
}

// Uses a `flows.*` method as its gated-family vehicle: without the `flows`
// feature there is no flows controller in the registry and the `.expect()`
// below would panic. The transport-layer gating it proves is orthogonal to the
// compile-time gate (#4797).
#[cfg(feature = "flows")]
#[tokio::test]
async fn gated_method_is_unknown_at_transport_even_with_malformed_params() {
// #4808 review (CodeRabbit): prove the schema-gate fix at the JSON-RPC
Expand Down
2 changes: 2 additions & 0 deletions src/core/runtime/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ pub fn spawn_cron_service() {
// flow (issue B2) — idempotent, so a flow whose binding
// predates this feature (or was otherwise lost) gets its
// schedule re-registered without the user re-toggling it.
// Gated with flows — absent entirely from a slim build.
#[cfg(feature = "flows")]
if let Err(e) =
crate::openhuman::flows::ops::reconcile_schedule_triggers_on_boot(&config).await
{
Expand Down
3 changes: 3 additions & 0 deletions src/openhuman/agent/harness/builtin_definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,10 @@ mod tests {
"critic",
"archivist",
"summarizer",
// Gated with `flows` (#4797) — absent from a slim build.
#[cfg(feature = "flows")]
"workflow_builder",
#[cfg(feature = "flows")]
"flow_discovery",
] {
assert!(ids.contains(&expected.to_string()), "missing {expected}");
Expand Down
3 changes: 3 additions & 0 deletions src/openhuman/agent/harness/definition_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,10 @@ fn all_builtin_agent_definitions_have_expected_effective_max_iterations() {
("skill_creator", 50),
("task_manager_agent", 50),
("tools_agent", 50),
// Gated with `flows` (#4797) — absent from a slim build.
#[cfg(feature = "flows")]
("flow_discovery", 50),
#[cfg(feature = "flows")]
("workflow_builder", 50),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
// Compiled out with the `skills` gate — see `openhuman::skills::stub`.
#[cfg(feature = "skills")]
Expand Down
11 changes: 10 additions & 1 deletion src/openhuman/agent_registry/agents/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ pub const BUILTINS: &[BuiltinAgent] = &[
// Workflow-authoring specialist (Phase 5a): builds tinyflows automation
// graphs from natural language and returns a validated PROPOSAL — it never
// persists or enables a flow. Deliberately narrow propose-or-read tool belt.
// Gated with `flows`: a slim build must not advertise an agent whose entire
// tool belt is absent, so the entry (and its `include_str!`) is stripped.
#[cfg(feature = "flows")]
BuiltinAgent {
id: "workflow_builder",
toml: include_str!("../../flows/agents/workflow_builder/agent.toml"),
Expand All @@ -306,7 +309,9 @@ pub const BUILTINS: &[BuiltinAgent] = &[
// `suggest_workflows` to record concrete, buildable automation ideas for
// the Flows page "Suggested for you" section. It never persists or enables
// a flow — the read-only counterpart to `workflow_builder`, which turns a
// picked suggestion into a real graph proposal.
// picked suggestion into a real graph proposal. Gated with `flows` (same
// reasoning as `workflow_builder` above).
#[cfg(feature = "flows")]
BuiltinAgent {
id: "flow_discovery",
toml: include_str!("../../flows/agents/flow_discovery/agent.toml"),
Expand Down Expand Up @@ -1005,6 +1010,9 @@ mod tests {
assert!(matches!(def.tools, ToolScope::Wildcard));
}

// Both flows agents are `#[cfg(feature = "flows")]` entries in `BUILTINS`
// (#4797), so these tests only apply when the gate is on.
#[cfg(feature = "flows")]
#[test]
fn workflow_builder_is_registered_worker_with_bounded_authoring_scope() {
// Phase 5a/5b: the workflow-builder must be a Worker-tier leaf whose
Expand Down Expand Up @@ -1135,6 +1143,7 @@ mod tests {
);
}

#[cfg(feature = "flows")]
#[test]
fn flow_discovery_is_registered_readonly_reasoning_scout() {
// The Flow Scout must be a read-only reasoning leaf: it reads the
Expand Down
3 changes: 3 additions & 0 deletions src/openhuman/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub mod emergency_stop;
pub mod encryption;
pub mod file_state;
pub mod file_storage;
#[cfg(feature = "flows")]
pub mod flows;
pub mod harness_init;
pub mod health;
Expand Down Expand Up @@ -102,6 +103,7 @@ pub mod provider_surfaces;
pub mod recall_calendar;
pub mod redirect_links;
pub mod referral;
#[cfg(feature = "flows")]
pub mod rhai_workflows;
pub mod routing;
pub mod runtime_node;
Expand Down Expand Up @@ -131,6 +133,7 @@ pub mod thread_goals;
pub mod threads;
pub mod tinyagents;
pub mod tinycortex;
#[cfg(feature = "flows")]
pub mod tinyflows;
pub mod tinyplace;
pub mod tls;
Expand Down
4 changes: 4 additions & 0 deletions src/openhuman/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ pub use crate::openhuman::credentials::tools::*;
pub use crate::openhuman::cron::tools::*;
pub use crate::openhuman::dashboard::tools::*;
pub use crate::openhuman::doctor::tools::*;
#[cfg(feature = "flows")]
pub use crate::openhuman::flows::builder_tools::*;
#[cfg(feature = "flows")]
pub use crate::openhuman::flows::discovery_tools::*;
#[cfg(feature = "flows")]
pub use crate::openhuman::flows::tools::*;
pub use crate::openhuman::health::tools::*;
pub use crate::openhuman::integrations::tools::*;
Expand All @@ -41,6 +44,7 @@ pub use crate::openhuman::monitor::tools::*;
pub use crate::openhuman::orchestration::tools::*;
pub use crate::openhuman::people::tools::*;
pub use crate::openhuman::referral::tools::*;
#[cfg(feature = "flows")]
pub use crate::openhuman::rhai_workflows::tools::*;
pub use crate::openhuman::screen_intelligence::tools::*;
pub use crate::openhuman::search::tools::*;
Expand Down
Loading
Loading