fix(grid-agent): keep TUI terminal output isolated
This commit is contained in:
@@ -1892,9 +1892,7 @@ impl AutonomousApprovalReviewer {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
cancellation_bridge.abort();
|
cancellation_bridge.abort();
|
||||||
let message = result.map_err(|error| {
|
let message = result.map_err(|_| ())?;
|
||||||
eprintln!("Mentra approval review failed: {error}");
|
|
||||||
})?;
|
|
||||||
let text = message.text();
|
let text = message.text();
|
||||||
let verdict = text
|
let verdict = text
|
||||||
.trim()
|
.trim()
|
||||||
@@ -1904,10 +1902,6 @@ impl AutonomousApprovalReviewer {
|
|||||||
} else if verdict.eq_ignore_ascii_case("DENY") {
|
} else if verdict.eq_ignore_ascii_case("DENY") {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
} else {
|
} else {
|
||||||
eprintln!(
|
|
||||||
"Mentra approval review returned an invalid verdict ({} bytes)",
|
|
||||||
text.len()
|
|
||||||
);
|
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1976,18 +1970,8 @@ impl mentra::tool::ToolExecutor for MentraGridTool {
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
crate::tool_loop::ToolExecution::Completed(result) => Ok(result.into_inner()),
|
crate::tool_loop::ToolExecution::Completed(result) => Ok(result.into_inner()),
|
||||||
crate::tool_loop::ToolExecution::Rejected(reason) => {
|
crate::tool_loop::ToolExecution::Rejected(reason)
|
||||||
eprintln!(
|
| crate::tool_loop::ToolExecution::Failed(reason) => Err(reason.into_inner()),
|
||||||
"Mentra grid tool rejected: name={} reason={}",
|
|
||||||
self.definition.name.as_str(),
|
|
||||||
reason.as_str()
|
|
||||||
);
|
|
||||||
Err(reason.into_inner())
|
|
||||||
}
|
|
||||||
crate::tool_loop::ToolExecution::Failed(reason) => {
|
|
||||||
eprintln!("Mentra grid tool failed: {}", reason.as_str());
|
|
||||||
Err(reason.into_inner())
|
|
||||||
}
|
|
||||||
crate::tool_loop::ToolExecution::AmbiguousMutation => {
|
crate::tool_loop::ToolExecution::AmbiguousMutation => {
|
||||||
active.mentra_cancellation.cancel();
|
active.mentra_cancellation.cancel();
|
||||||
Err("mutation outcome is ambiguous; stopped without retry".to_owned())
|
Err("mutation outcome is ambiguous; stopped without retry".to_owned())
|
||||||
@@ -2383,10 +2367,7 @@ impl InteractionResponder for PolicyLlmResponder {
|
|||||||
.lock()
|
.lock()
|
||||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||||
.remove(&agent_id);
|
.remove(&agent_id);
|
||||||
let message = result.map_err(|error| {
|
let message = result.map_err(|error| mentra_interaction_error(&error))?;
|
||||||
eprintln!("Mentra inference failed: {error}");
|
|
||||||
mentra_interaction_error(&error)
|
|
||||||
})?;
|
|
||||||
mentra_visible_text(&message)
|
mentra_visible_text(&message)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,58 @@ impl fmt::Display for CliError {
|
|||||||
|
|
||||||
impl Error for CliError {}
|
impl Error for CliError {}
|
||||||
|
|
||||||
|
#[cfg(feature = "live-grid")]
|
||||||
|
struct SilentLogger;
|
||||||
|
|
||||||
|
#[cfg(feature = "live-grid")]
|
||||||
|
impl libremetaverse::logging::ILogger for SilentLogger {
|
||||||
|
fn is_enabled(&self, _level: libremetaverse::logging::LogLevel) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
fn log(
|
||||||
|
&self,
|
||||||
|
_level: libremetaverse::logging::LogLevel,
|
||||||
|
_message: &libremetaverse_types::compat::Object,
|
||||||
|
_exception: Option<&libremetaverse_types::compat::ExternalError>,
|
||||||
|
_client_name: Option<&str>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
fn begin_scope(
|
||||||
|
&self,
|
||||||
|
_state: libremetaverse_types::compat::Object,
|
||||||
|
) -> Box<dyn libremetaverse_types::compat::Close> {
|
||||||
|
Box::new(SilentScope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "live-grid")]
|
||||||
|
struct SilentScope;
|
||||||
|
|
||||||
|
#[cfg(feature = "live-grid")]
|
||||||
|
impl libremetaverse_types::compat::Close for SilentScope {
|
||||||
|
fn close(&mut self) -> Result<(), libremetaverse_types::compat::ExternalError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "live-grid")]
|
||||||
|
struct SilentLoggerFactory;
|
||||||
|
|
||||||
|
#[cfg(feature = "live-grid")]
|
||||||
|
impl libremetaverse::logging::ILoggerFactory for SilentLoggerFactory {
|
||||||
|
fn create_logger(&self, _name: &str) -> Arc<dyn libremetaverse::logging::ILogger> {
|
||||||
|
Arc::new(SilentLogger)
|
||||||
|
}
|
||||||
|
fn shutdown(&self) -> Result<(), libremetaverse_types::compat::ExternalError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "live-grid")]
|
||||||
|
fn install_silent_grid_logger() -> Result<(), libremetaverse::Error> {
|
||||||
|
libremetaverse::Logger::set_logger_factory(Box::new(SilentLoggerFactory), "tui".into())
|
||||||
|
}
|
||||||
|
|
||||||
fn color_disabled() -> bool {
|
fn color_disabled() -> bool {
|
||||||
std::env::var_os("NO_COLOR").is_some()
|
std::env::var_os("NO_COLOR").is_some()
|
||||||
|| std::env::var_os("TERM").is_some_and(|value| value == "dumb")
|
|| std::env::var_os("TERM").is_some_and(|value| value == "dumb")
|
||||||
@@ -278,6 +330,10 @@ async fn run_live(
|
|||||||
SessionSupervisor, TcpControlConfig, TcpControlServer, WorldSnapshotSource,
|
SessionSupervisor, TcpControlConfig, TcpControlServer, WorldSnapshotSource,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if tui {
|
||||||
|
install_silent_grid_logger()?;
|
||||||
|
}
|
||||||
|
|
||||||
let connection = config.grid.clone().ok_or_else(|| {
|
let connection = config.grid.clone().ok_or_else(|| {
|
||||||
CliError("validated live configuration did not contain a grid connection".into())
|
CliError("validated live configuration did not contain a grid connection".into())
|
||||||
})?;
|
})?;
|
||||||
@@ -335,6 +391,7 @@ async fn run_live(
|
|||||||
.timeouts
|
.timeouts
|
||||||
.startup
|
.startup
|
||||||
.saturating_sub(Duration::from_secs(5)),
|
.saturating_sub(Duration::from_secs(5)),
|
||||||
|
!tui,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
@@ -472,7 +529,9 @@ async fn run_live(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("grid agent session supervisor started; press Ctrl-C to stop");
|
if !tui {
|
||||||
|
println!("grid agent session supervisor started; press Ctrl-C to stop");
|
||||||
|
}
|
||||||
let mut signal_error = None;
|
let mut signal_error = None;
|
||||||
let mut control_failure = None;
|
let mut control_failure = None;
|
||||||
let mut active_interactions = 0_usize;
|
let mut active_interactions = 0_usize;
|
||||||
@@ -496,7 +555,9 @@ async fn run_live(
|
|||||||
&framework_readiness,
|
&framework_readiness,
|
||||||
status.generation,
|
status.generation,
|
||||||
config.timeouts.startup.saturating_sub(Duration::from_secs(5)),
|
config.timeouts.startup.saturating_sub(Duration::from_secs(5)),
|
||||||
|
!tui,
|
||||||
).await
|
).await
|
||||||
|
&& !tui
|
||||||
{
|
{
|
||||||
eprintln!("framework initialization failed: {error}");
|
eprintln!("framework initialization failed: {error}");
|
||||||
}
|
}
|
||||||
@@ -524,14 +585,14 @@ async fn run_live(
|
|||||||
component: "session".into(),
|
component: "session".into(),
|
||||||
state: status.state.as_str().into(),
|
state: status.state.as_str().into(),
|
||||||
});
|
});
|
||||||
println!(
|
if !tui {
|
||||||
"grid session state={} generation={} transport_connected={} agent_ready={} reason={reason:?} retry_in={retry_in:?}",
|
println!(
|
||||||
status.state.as_str(),
|
"grid session state={} generation={} transport_connected={} agent_ready={} reason={reason:?} retry_in={retry_in:?}",
|
||||||
status.generation,
|
status.state.as_str(), status.generation,
|
||||||
status.transport_connected,
|
status.transport_connected, status.agent_ready,
|
||||||
status.agent_ready,
|
);
|
||||||
);
|
}
|
||||||
if status.agent_ready {
|
if status.agent_ready && !tui {
|
||||||
print_ready(&live, status.generation);
|
print_ready(&live, status.generation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -551,12 +612,12 @@ async fn run_live(
|
|||||||
pause.conversation = active_interactions != 0;
|
pause.conversation = active_interactions != 0;
|
||||||
});
|
});
|
||||||
record_interaction_observation(&live.observability, &event);
|
record_interaction_observation(&live.observability, &event);
|
||||||
println!("grid interaction event={event:?}");
|
if !tui { println!("grid interaction event={event:?}"); }
|
||||||
}
|
}
|
||||||
event = live.perception_observations.recv() => {
|
event = live.perception_observations.recv() => {
|
||||||
let Some(event) = event else { break; };
|
let Some(event) = event else { break; };
|
||||||
record_perception_observation(&live.observability, &event);
|
record_perception_observation(&live.observability, &event);
|
||||||
println!("grid perception event={event:?}");
|
if !tui { println!("grid perception event={event:?}"); }
|
||||||
}
|
}
|
||||||
event = live.behavior.next_observation() => {
|
event = live.behavior.next_observation() => {
|
||||||
let Some(event) = event else { break; };
|
let Some(event) = event else { break; };
|
||||||
@@ -568,7 +629,7 @@ async fn run_live(
|
|||||||
state: format!("{to:?}").to_ascii_lowercase(),
|
state: format!("{to:?}").to_ascii_lowercase(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
println!("grid behavior event={event:?}");
|
if !tui { println!("grid behavior event={event:?}"); }
|
||||||
}
|
}
|
||||||
command = control_commands.recv() => {
|
command = control_commands.recv() => {
|
||||||
let Some(command) = command else { break; };
|
let Some(command) = command else { break; };
|
||||||
@@ -639,7 +700,9 @@ async fn run_live(
|
|||||||
if let Some(error) = control_failure {
|
if let Some(error) = control_failure {
|
||||||
return Err(CliError(format!("control command failed: {error}")).into());
|
return Err(CliError(format!("control command failed: {error}")).into());
|
||||||
}
|
}
|
||||||
println!("grid agent stopped cleanly");
|
if !tui {
|
||||||
|
println!("grid agent stopped cleanly");
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,8 +712,13 @@ async fn prepare_live_framework(
|
|||||||
readiness: &metacrate_grid_agent::FrameworkReadiness,
|
readiness: &metacrate_grid_agent::FrameworkReadiness,
|
||||||
generation: u64,
|
generation: u64,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
|
print_status: bool,
|
||||||
) -> Result<(), CliError> {
|
) -> Result<(), CliError> {
|
||||||
println!("INITIALIZING generation={generation} waiting_for=world_state,viewport target_fps=10");
|
if print_status {
|
||||||
|
println!(
|
||||||
|
"INITIALIZING generation={generation} waiting_for=world_state,viewport target_fps=10"
|
||||||
|
);
|
||||||
|
}
|
||||||
tokio::time::timeout(timeout, async {
|
tokio::time::timeout(timeout, async {
|
||||||
loop {
|
loop {
|
||||||
let world_ready = live
|
let world_ready = live
|
||||||
@@ -689,13 +757,15 @@ async fn prepare_live_framework(
|
|||||||
.map_err(|_| CliError("timed out waiting for stable world state and viewport".into()))?;
|
.map_err(|_| CliError("timed out waiting for stable world state and viewport".into()))?;
|
||||||
readiness.mark_ready(generation);
|
readiness.mark_ready(generation);
|
||||||
let stats = live.vision.viewport_stats().unwrap_or_default();
|
let stats = live.vision.viewport_stats().unwrap_or_default();
|
||||||
println!(
|
if print_status {
|
||||||
"INITIALIZED generation={} viewport_frames={} last_render_ms={} warmup_missed_deadlines={} world_state=stable viewport_state=stable",
|
println!(
|
||||||
generation,
|
"INITIALIZED generation={} viewport_frames={} last_render_ms={} warmup_missed_deadlines={} world_state=stable viewport_state=stable",
|
||||||
stats.completed_frames,
|
generation,
|
||||||
stats.last_render.as_millis(),
|
stats.completed_frames,
|
||||||
stats.missed_frame_deadlines,
|
stats.last_render.as_millis(),
|
||||||
);
|
stats.missed_frame_deadlines,
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user