mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
This commit is contained in:
@@ -366,7 +366,13 @@ pub struct MemoryTreeConfig {
|
||||
}
|
||||
|
||||
fn default_memory_tree_spacy_enabled() -> bool {
|
||||
true
|
||||
// Opt-in (#5056). Default OFF so a fresh install never provisions the spaCy
|
||||
// venv + `en_core_web_sm` model on first launch, and the runtime Python
|
||||
// server is not spawned on every boot when no local NLP is configured.
|
||||
// Query-entity extraction degrades to the in-Rust regex+LLM extractor
|
||||
// (`score::extract`); operators opt in via config or
|
||||
// `OPENHUMAN_MEMORY_TREE_SPACY_ENABLED=1`.
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns `None` so that existing installs that never opted into Phase 4
|
||||
@@ -513,6 +519,15 @@ mod tests {
|
||||
assert_eq!(DEFAULT_CLOUD_LLM_MODEL, "summarization-v1");
|
||||
}
|
||||
|
||||
/// #5056: spaCy is opt-in — a fresh install must never provision the
|
||||
/// spaCy venv / `en_core_web_sm` model, nor spawn the runtime Python
|
||||
/// server, without an explicit config or env-var opt-in.
|
||||
#[test]
|
||||
fn spacy_enabled_defaults_to_false() {
|
||||
assert!(!MemoryTreeConfig::default().spacy_enabled);
|
||||
assert!(!default_memory_tree_spacy_enabled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn memory_tree_config_default_content_dir_is_none() {
|
||||
let cfg = MemoryTreeConfig::default();
|
||||
|
||||
@@ -5,9 +5,15 @@
|
||||
//! orchestrates and reports; it does not reimplement any download logic.
|
||||
//!
|
||||
//! Current steps (all non-required — failure degrades to a fallback):
|
||||
//! 1. `python_runtime` — managed CPython (prerequisite for spaCy).
|
||||
//! 2. `spacy` — spaCy venv + `en_core_web_sm` model.
|
||||
//! 3. `runtime_python_server` — long-running Python backend host.
|
||||
//! 1. `python_runtime` — managed CPython. Only provisions eagerly when a
|
||||
//! Python backend is actually enabled (`enabled_backends` non-empty);
|
||||
//! otherwise it is a no-op and lazy consumers (Python tools / skills)
|
||||
//! resolve the interpreter on first use (#5056).
|
||||
//! 2. `spacy` — spaCy venv + `en_core_web_sm` model. Opt-in
|
||||
//! (`memory_tree.spacy_enabled`, default OFF) so a fresh install does not
|
||||
//! provision it — nor spawn the runtime Python server — on launch.
|
||||
//! 3. `runtime_python_server` — long-running Python backend host. Derived:
|
||||
//! launches only when `enabled_backends` is non-empty.
|
||||
//! 4. `node_runtime` — managed Node.js (skills / MCP).
|
||||
//!
|
||||
//! Voice models (Whisper, Piper) and Ollama stay lazy/opt-in and are
|
||||
@@ -73,9 +79,20 @@ fn python_runtime_step() -> HarnessInitStep {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the managed interpreter must be provisioned **eagerly at boot**.
|
||||
/// True only when Python is enabled AND a Python backend (spaCy / Kompress)
|
||||
/// actually needs it. When no backend is enabled we skip the speculative
|
||||
/// managed-CPython download entirely (#5056) — lazy consumers (Python tools /
|
||||
/// skills, Python MCP servers) still resolve the interpreter on first use.
|
||||
fn python_needed_eagerly(config: &Config) -> bool {
|
||||
config.runtime_python.enabled
|
||||
&& !crate::openhuman::runtime_python_server::enabled_backends(config).is_empty()
|
||||
}
|
||||
|
||||
async fn python_is_done(config: &Config) -> bool {
|
||||
if !config.runtime_python.enabled {
|
||||
// Disabled → nothing to provision; treat as satisfied.
|
||||
if !python_needed_eagerly(config) {
|
||||
// Nothing at boot needs the interpreter → treat as satisfied. Never
|
||||
// downloads CPython speculatively.
|
||||
return true;
|
||||
}
|
||||
// Durable on-disk probe: survives restarts (unlike the process-local
|
||||
@@ -89,7 +106,7 @@ async fn python_is_done(config: &Config) -> bool {
|
||||
}
|
||||
|
||||
async fn python_run(config: &Config) -> Result<(), String> {
|
||||
if !config.runtime_python.enabled {
|
||||
if !python_needed_eagerly(config) {
|
||||
return Ok(());
|
||||
}
|
||||
use crate::openhuman::runtime_python::PythonBootstrap;
|
||||
@@ -301,6 +318,46 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// #5056: on a fresh install (`Config::default()`) `runtime_python.enabled`
|
||||
/// is `true` but no Python backend (spaCy/Kompress) is on, so the
|
||||
/// `python_runtime` step must report itself already `Done` and `run` must
|
||||
/// be a no-op — proving the eager managed-CPython download is skipped
|
||||
/// when nothing at boot needs it. This is a pure gating check
|
||||
/// (`python_needed_eagerly` returns `false`): it never touches disk or
|
||||
/// resolves a real interpreter, so it stays hermetic.
|
||||
#[tokio::test]
|
||||
async fn python_runtime_step_is_done_by_default_with_no_backend_enabled() {
|
||||
let config = Config::default();
|
||||
assert!(
|
||||
!python_needed_eagerly(&config),
|
||||
"default config should not need Python eagerly (no backend enabled)"
|
||||
);
|
||||
assert!(
|
||||
python_is_done(&config).await,
|
||||
"python_runtime step should be Done without provisioning when no backend is enabled"
|
||||
);
|
||||
assert!(
|
||||
python_run(&config).await.is_ok(),
|
||||
"python_runtime run should no-op when no backend is enabled"
|
||||
);
|
||||
}
|
||||
|
||||
/// Inverse of the above: once a backend (spaCy) is enabled, the step must
|
||||
/// no longer be trivially `Done` via the eager-skip branch — proving the
|
||||
/// gate still allows provisioning when a backend genuinely needs Python.
|
||||
/// We only assert the gating predicate here (not `is_done`/`run`), so the
|
||||
/// test never attempts a real interpreter probe/download.
|
||||
#[test]
|
||||
fn python_needed_eagerly_true_when_spacy_backend_enabled() {
|
||||
let mut config = Config::default();
|
||||
config.runtime_python.enabled = true;
|
||||
config.memory_tree.spacy_enabled = true;
|
||||
assert!(
|
||||
python_needed_eagerly(&config),
|
||||
"python should be needed eagerly once a Python backend is enabled"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn disabled_runtimes_report_done_without_work() {
|
||||
let mut config = Config::default();
|
||||
|
||||
@@ -35,6 +35,19 @@ pub fn enabled_backends(config: &Config) -> Vec<RuntimePythonBackend> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// #5056: a fresh install (`Config::default()`) must not enable any
|
||||
/// Python backend, so the runtime Python server never launches — and the
|
||||
/// managed CPython interpreter is never speculatively downloaded — on a
|
||||
/// default boot.
|
||||
#[test]
|
||||
fn enabled_backends_is_empty_by_default() {
|
||||
let config = Config::default();
|
||||
assert!(
|
||||
enabled_backends(&config).is_empty(),
|
||||
"default config must not enable any runtime Python backend"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_respects_runtime_and_spacy_flags() {
|
||||
let mut config = Config::default();
|
||||
|
||||
Reference in New Issue
Block a user