feat(grid-agent): add structured observability and replay (#127)
This commit is contained in:
@@ -7,7 +7,7 @@ use std::path::PathBuf;
|
||||
#[cfg(feature = "live-grid")]
|
||||
use std::sync::Arc;
|
||||
#[cfg(feature = "live-grid")]
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
const MAX_ARGUMENTS: usize = 8;
|
||||
|
||||
@@ -184,22 +184,28 @@ async fn run_live(
|
||||
let readiness = tokio::time::timeout(config.timeouts.startup, async {
|
||||
loop {
|
||||
match handle.next_observation().await {
|
||||
Some(SessionObservation::Transition { status, .. }) if status.agent_ready => {
|
||||
Some(event @ SessionObservation::Transition { status, .. })
|
||||
if status.agent_ready =>
|
||||
{
|
||||
record_session_observation(&live.observability, &event);
|
||||
return Ok::<(), CliError>(());
|
||||
}
|
||||
Some(SessionObservation::Transition {
|
||||
status:
|
||||
metacrate_grid_agent::SessionStatus {
|
||||
state: SessionState::AuthenticationBlocked,
|
||||
..
|
||||
},
|
||||
..
|
||||
}) => {
|
||||
Some(
|
||||
event @ SessionObservation::Transition {
|
||||
status:
|
||||
metacrate_grid_agent::SessionStatus {
|
||||
state: SessionState::AuthenticationBlocked,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
) => {
|
||||
record_session_observation(&live.observability, &event);
|
||||
return Err(CliError(
|
||||
"grid authentication/configuration requires operator action".into(),
|
||||
));
|
||||
}
|
||||
Some(_) => {}
|
||||
Some(event) => record_session_observation(&live.observability, &event),
|
||||
None => {
|
||||
return Err(CliError(
|
||||
"session supervisor stopped before readiness".into(),
|
||||
@@ -239,6 +245,7 @@ async fn run_live(
|
||||
live.behavior.ingress(),
|
||||
config.limits.control_queue,
|
||||
)?;
|
||||
control_target.attach_observability(live.observability.clone());
|
||||
control_target.update_session(handle.status());
|
||||
let erased_target: Arc<dyn ControlTarget> = control_target.clone();
|
||||
let (control_plane, _integrated_client, control_server) = match config.mode {
|
||||
@@ -292,6 +299,7 @@ async fn run_live(
|
||||
}
|
||||
event = handle.next_observation() => {
|
||||
let Some(event) = event else { break; };
|
||||
record_session_observation(&live.observability, &event);
|
||||
if let SessionObservation::Transition { status, reason, retry_in } = event {
|
||||
control_target.update_session(status);
|
||||
control_plane.publish(ControlEventKind::StateChanged {
|
||||
@@ -309,14 +317,17 @@ async fn run_live(
|
||||
}
|
||||
event = live.interaction.next_observation() => {
|
||||
let Some(event) = event else { break; };
|
||||
record_interaction_observation(&live.observability, &event);
|
||||
println!("grid interaction event={event:?}");
|
||||
}
|
||||
event = live.perception_observations.recv() => {
|
||||
let Some(event) = event else { break; };
|
||||
record_perception_observation(&live.observability, &event);
|
||||
println!("grid perception event={event:?}");
|
||||
}
|
||||
event = live.behavior.next_observation() => {
|
||||
let Some(event) = event else { break; };
|
||||
record_behavior_observation(&live.observability, &event);
|
||||
if let BehaviorObservation::Transition { to, .. } = &event {
|
||||
control_target.update_behavior(*to);
|
||||
control_plane.publish(ControlEventKind::StateChanged {
|
||||
@@ -358,6 +369,14 @@ async fn run_live(
|
||||
}
|
||||
}
|
||||
}
|
||||
let shutdown_event = metacrate_grid_agent::EventDraft::new(
|
||||
metacrate_grid_agent::EventFamily::Shutdown,
|
||||
metacrate_grid_agent::EventSeverity::Info,
|
||||
"service",
|
||||
metacrate_grid_agent::EventOrigin::Service,
|
||||
)?
|
||||
.result_code("requested")?;
|
||||
let _ = live.observability.record(shutdown_event);
|
||||
control_target.mark_stopping();
|
||||
let session_result = handle.shutdown().await;
|
||||
let interaction_result = live.interaction.shutdown().await;
|
||||
@@ -391,6 +410,7 @@ struct LiveInteractions {
|
||||
conversations: Arc<metacrate_grid_agent::ConversationStore>,
|
||||
policy: Arc<metacrate_grid_agent::PolicyGateway>,
|
||||
audit: Arc<metacrate_grid_agent::MemoryPolicyAudit>,
|
||||
observability: Arc<metacrate_grid_agent::Observability>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
@@ -402,8 +422,9 @@ fn start_live_interactions(
|
||||
use metacrate_grid_agent::{
|
||||
AuthorizedBackendRouter, AuthorizedToolBackend, BehaviorBackend, BehaviorController,
|
||||
ConversationStore, InteractionCoordinator, LlmClient, LlmTransportLimits,
|
||||
MemoryPolicyAudit, PerceptionBackend, PolicyGateway, PolicyLimits, PolicyLlmResponder,
|
||||
ToolLoopLimits, behavior_policy_tools, perception_policy_tools,
|
||||
MemoryPolicyAudit, Observability, ObservabilityLimits, PerceptionBackend, PolicyAuditSink,
|
||||
PolicyGateway, PolicyLimits, PolicyLlmResponder, ToolLoopLimits, UnifiedPolicyAudit,
|
||||
behavior_policy_tools, perception_policy_tools,
|
||||
};
|
||||
|
||||
let transport_limits = LlmTransportLimits {
|
||||
@@ -435,6 +456,16 @@ fn start_live_interactions(
|
||||
let behavior_ingress = behavior.ingress();
|
||||
let client = Arc::new(LlmClient::new(config.llm.clone(), transport_limits)?);
|
||||
let audit = Arc::new(MemoryPolicyAudit::new(config.limits.observable_queue)?);
|
||||
let observability = Observability::memory(ObservabilityLimits {
|
||||
ring_events: config.limits.observable_queue,
|
||||
subscriber_queue: config.limits.observable_queue.min(512),
|
||||
journal_queue: config.limits.observable_queue,
|
||||
..ObservabilityLimits::default()
|
||||
})?;
|
||||
let audit_sink: Arc<dyn PolicyAuditSink> = Arc::new(UnifiedPolicyAudit::new(
|
||||
audit.clone(),
|
||||
observability.clone(),
|
||||
));
|
||||
let mut tools = perception_policy_tools()?;
|
||||
tools.extend(behavior_policy_tools(&config.behavior)?);
|
||||
let routes = tools
|
||||
@@ -453,7 +484,7 @@ fn start_live_interactions(
|
||||
config.authorized_avatar_uuids.clone(),
|
||||
tools,
|
||||
PolicyLimits::default(),
|
||||
audit.clone(),
|
||||
audit_sink,
|
||||
)?);
|
||||
let loop_limits = ToolLoopLimits {
|
||||
max_tool_calls_per_turn: config.limits.max_tool_calls,
|
||||
@@ -500,5 +531,497 @@ fn start_live_interactions(
|
||||
conversations: conversation,
|
||||
policy: gateway,
|
||||
audit,
|
||||
observability,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
fn record_session_observation(
|
||||
observer: &metacrate_grid_agent::Observability,
|
||||
observation: &metacrate_grid_agent::SessionObservation,
|
||||
) {
|
||||
use metacrate_grid_agent::{
|
||||
EventDraft, EventFamily, EventOrigin, EventSeverity, SessionObservation,
|
||||
};
|
||||
let SessionObservation::Transition {
|
||||
status,
|
||||
reason,
|
||||
retry_in,
|
||||
} = observation
|
||||
else {
|
||||
return;
|
||||
};
|
||||
observer.metrics().set_ready(status.agent_ready);
|
||||
if matches!(
|
||||
reason,
|
||||
metacrate_grid_agent::SessionReason::TransientTransport
|
||||
| metacrate_grid_agent::SessionReason::Maintenance
|
||||
| metacrate_grid_agent::SessionReason::Kicked
|
||||
| metacrate_grid_agent::SessionReason::SimulatorDisconnected
|
||||
| metacrate_grid_agent::SessionReason::ServerFailure
|
||||
| metacrate_grid_agent::SessionReason::OperatorForceReconnect
|
||||
) {
|
||||
observer.metrics().record_reconnect();
|
||||
}
|
||||
let event = EventDraft::new(
|
||||
EventFamily::LifecycleTransition,
|
||||
if status.agent_ready {
|
||||
EventSeverity::Info
|
||||
} else {
|
||||
EventSeverity::Warning
|
||||
},
|
||||
"session",
|
||||
EventOrigin::Grid,
|
||||
)
|
||||
.and_then(|event| event.reason_code(session_reason_code(*reason)))
|
||||
.and_then(|event| {
|
||||
event
|
||||
.retry_count(status.consecutive_failures)
|
||||
.code_field("to", status.state.as_str())
|
||||
})
|
||||
.and_then(|event| event.field("generation", serde_json::Value::from(status.generation)))
|
||||
.and_then(|event| event.field("ready", serde_json::Value::from(status.agent_ready)))
|
||||
.and_then(|event| {
|
||||
event.field(
|
||||
"transport_connected",
|
||||
serde_json::Value::from(status.transport_connected),
|
||||
)
|
||||
})
|
||||
.and_then(|event| {
|
||||
event.field(
|
||||
"retry_millis",
|
||||
serde_json::Value::from(retry_in.map_or(0, |duration| {
|
||||
u64::try_from(duration.as_millis()).unwrap_or(u64::MAX)
|
||||
})),
|
||||
)
|
||||
});
|
||||
if let Ok(event) = event {
|
||||
let _ = observer.record(event);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn record_interaction_observation(
|
||||
observer: &metacrate_grid_agent::Observability,
|
||||
observation: &metacrate_grid_agent::InteractionObservation,
|
||||
) {
|
||||
use metacrate_grid_agent::{
|
||||
CorrelationIds, EventDraft, EventFamily, EventOrigin, EventSeverity, InferenceOutcome,
|
||||
InteractionObservation, MemoryReason, OutcomeCode,
|
||||
};
|
||||
let event = match observation {
|
||||
InteractionObservation::SessionMemory { event } => {
|
||||
let (family, state) = match event.reason {
|
||||
MemoryReason::SessionCreated => (EventFamily::SessionCreated, "created"),
|
||||
MemoryReason::PublicExpired
|
||||
| MemoryReason::DirectImExpired
|
||||
| MemoryReason::SessionLimitEviction
|
||||
| MemoryReason::TotalByteEviction
|
||||
| MemoryReason::OperatorDeleted
|
||||
| MemoryReason::OperatorExpired => (EventFamily::SessionExpired, "expired"),
|
||||
MemoryReason::TurnCompacted
|
||||
| MemoryReason::ByteCompacted
|
||||
| MemoryReason::ToolResultCompacted => {
|
||||
(EventFamily::LifecycleTransition, "compacted")
|
||||
}
|
||||
MemoryReason::CorruptSnapshotQuarantined
|
||||
| MemoryReason::UnsupportedSnapshotQuarantined
|
||||
| MemoryReason::SnapshotTooLargeQuarantined
|
||||
| MemoryReason::PermissionsNotVerified => {
|
||||
(EventFamily::LifecycleTransition, "quarantined")
|
||||
}
|
||||
};
|
||||
EventDraft::new(
|
||||
family,
|
||||
EventSeverity::Info,
|
||||
"conversation",
|
||||
EventOrigin::Service,
|
||||
)
|
||||
.and_then(|draft| {
|
||||
draft.correlation(CorrelationIds {
|
||||
avatar_id: event.avatar_id.map(|id| id.to_string()),
|
||||
session_id: event.session_id.as_ref().map(|id| id.as_str().to_owned()),
|
||||
..CorrelationIds::default()
|
||||
})
|
||||
})
|
||||
.and_then(|draft| draft.reason_code(memory_reason_code(event.reason)))
|
||||
.and_then(|draft| draft.code_field("state", state))
|
||||
}
|
||||
InteractionObservation::Suppressed {
|
||||
delivery_id,
|
||||
reason,
|
||||
} => EventDraft::new(
|
||||
EventFamily::InboundMessage,
|
||||
EventSeverity::Info,
|
||||
"interaction",
|
||||
EventOrigin::Grid,
|
||||
)
|
||||
.and_then(|event| {
|
||||
event.correlation(CorrelationIds {
|
||||
request_id: Some(delivery_id.as_str().to_owned()),
|
||||
..CorrelationIds::default()
|
||||
})
|
||||
})
|
||||
.and_then(|event| event.result_code("suppressed"))
|
||||
.and_then(|event| event.reason_code(suppression_reason_code(*reason)))
|
||||
.and_then(|event| event.redacted("message_content")),
|
||||
InteractionObservation::IntentRouted {
|
||||
delivery_id,
|
||||
session_id,
|
||||
origin,
|
||||
intent,
|
||||
} => EventDraft::new(
|
||||
EventFamily::InboundMessage,
|
||||
EventSeverity::Info,
|
||||
"interaction",
|
||||
EventOrigin::Grid,
|
||||
)
|
||||
.and_then(|event| {
|
||||
event.correlation(CorrelationIds {
|
||||
session_id: Some(session_id.as_str().to_owned()),
|
||||
request_id: Some(delivery_id.as_str().to_owned()),
|
||||
..CorrelationIds::default()
|
||||
})
|
||||
})
|
||||
.and_then(|event| event.result_code("routed"))
|
||||
.and_then(|event| event.code_field("origin", interaction_origin_code(*origin)))
|
||||
.and_then(|event| event.code_field("intent", interaction_intent_code(*intent)))
|
||||
.and_then(|event| event.redacted("message_content")),
|
||||
InteractionObservation::AttentionRequested {
|
||||
delivery_id,
|
||||
avatar_id,
|
||||
} => EventDraft::new(
|
||||
EventFamily::ModelActionSummary,
|
||||
EventSeverity::Info,
|
||||
"behavior",
|
||||
EventOrigin::Service,
|
||||
)
|
||||
.and_then(|event| {
|
||||
event.correlation(CorrelationIds {
|
||||
avatar_id: Some(avatar_id.to_string()),
|
||||
request_id: Some(delivery_id.as_str().to_owned()),
|
||||
..CorrelationIds::default()
|
||||
})
|
||||
})
|
||||
.and_then(|event| event.code_field("summary", "face_speaker")),
|
||||
InteractionObservation::InferenceStarted {
|
||||
delivery_id,
|
||||
session_id,
|
||||
prompt_messages,
|
||||
} => EventDraft::new(
|
||||
EventFamily::InferenceRequest,
|
||||
EventSeverity::Info,
|
||||
"llm",
|
||||
EventOrigin::Service,
|
||||
)
|
||||
.and_then(|event| {
|
||||
event.correlation(CorrelationIds {
|
||||
session_id: Some(session_id.as_str().to_owned()),
|
||||
request_id: Some(delivery_id.as_str().to_owned()),
|
||||
..CorrelationIds::default()
|
||||
})
|
||||
})
|
||||
.and_then(|event| event.field("prompt_messages", serde_json::Value::from(*prompt_messages)))
|
||||
.and_then(|event| event.redacted("prompt_content")),
|
||||
InteractionObservation::InferenceFinished {
|
||||
delivery_id,
|
||||
session_id,
|
||||
outcome,
|
||||
duration_millis,
|
||||
} => {
|
||||
observer
|
||||
.metrics()
|
||||
.record_inference_latency(Duration::from_millis(*duration_millis));
|
||||
let (severity, result, metric) = match outcome {
|
||||
InferenceOutcome::Completed => {
|
||||
(EventSeverity::Info, "completed", OutcomeCode::Completed)
|
||||
}
|
||||
InferenceOutcome::Cancelled => {
|
||||
(EventSeverity::Warning, "cancelled", OutcomeCode::Cancelled)
|
||||
}
|
||||
InferenceOutcome::TimedOut => {
|
||||
(EventSeverity::Warning, "timed_out", OutcomeCode::Failed)
|
||||
}
|
||||
InferenceOutcome::Failed => (EventSeverity::Error, "failed", OutcomeCode::Failed),
|
||||
InferenceOutcome::PolicyRejected => (
|
||||
EventSeverity::Warning,
|
||||
"policy_rejected",
|
||||
OutcomeCode::Denied,
|
||||
),
|
||||
};
|
||||
observer.metrics().record_inference_outcome(metric);
|
||||
EventDraft::new(
|
||||
EventFamily::InferenceResult,
|
||||
severity,
|
||||
"llm",
|
||||
EventOrigin::Model,
|
||||
)
|
||||
.and_then(|event| {
|
||||
event.correlation(CorrelationIds {
|
||||
session_id: Some(session_id.as_str().to_owned()),
|
||||
request_id: Some(delivery_id.as_str().to_owned()),
|
||||
..CorrelationIds::default()
|
||||
})
|
||||
})
|
||||
.map(|event| event.duration_millis(*duration_millis))
|
||||
.and_then(|event| event.result_code(result))
|
||||
.and_then(|event| event.redacted("response_content"))
|
||||
}
|
||||
InteractionObservation::Delivery {
|
||||
delivery_id,
|
||||
session_id,
|
||||
channel,
|
||||
outcome,
|
||||
delivered_parts,
|
||||
} => EventDraft::new(
|
||||
EventFamily::OutboundMessage,
|
||||
EventSeverity::Info,
|
||||
"interaction",
|
||||
EventOrigin::Service,
|
||||
)
|
||||
.and_then(|event| {
|
||||
event.correlation(CorrelationIds {
|
||||
session_id: Some(session_id.as_str().to_owned()),
|
||||
request_id: Some(delivery_id.as_str().to_owned()),
|
||||
..CorrelationIds::default()
|
||||
})
|
||||
})
|
||||
.and_then(|event| event.result_code(delivery_outcome_code(*outcome)))
|
||||
.and_then(|event| event.code_field("channel", interaction_channel_code(*channel)))
|
||||
.and_then(|event| event.field("delivered_parts", serde_json::Value::from(*delivered_parts)))
|
||||
.and_then(|event| event.redacted("message_content")),
|
||||
};
|
||||
if let Ok(event) = event {
|
||||
let _ = observer.record(event);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
fn record_perception_observation(
|
||||
observer: &metacrate_grid_agent::Observability,
|
||||
observation: &metacrate_grid_agent::PerceptionObservation,
|
||||
) {
|
||||
use metacrate_grid_agent::{
|
||||
CorrelationIds, EventDraft, EventFamily, EventOrigin, EventSeverity, PerceptionOutcome,
|
||||
};
|
||||
observer
|
||||
.metrics()
|
||||
.record_tool_latency(Duration::from_millis(observation.duration_millis));
|
||||
let result = match observation.outcome {
|
||||
PerceptionOutcome::Completed => "completed",
|
||||
PerceptionOutcome::Rejected => "rejected",
|
||||
};
|
||||
let event = EventDraft::new(
|
||||
EventFamily::ToolResult,
|
||||
EventSeverity::Info,
|
||||
"perception",
|
||||
EventOrigin::Service,
|
||||
)
|
||||
.and_then(|event| {
|
||||
event.correlation(CorrelationIds {
|
||||
action_id: Some(observation.call_id.as_str().to_owned()),
|
||||
..CorrelationIds::default()
|
||||
})
|
||||
})
|
||||
.map(|event| event.duration_millis(observation.duration_millis))
|
||||
.and_then(|event| event.result_code(result))
|
||||
.and_then(|event| event.identifier_field("tool", observation.tool.as_str()))
|
||||
.and_then(|event| {
|
||||
event.field(
|
||||
"result_bytes",
|
||||
serde_json::Value::from(observation.result_bytes),
|
||||
)
|
||||
})
|
||||
.and_then(|event| event.field("cache_hit", serde_json::Value::from(observation.cache_hit)))
|
||||
.and_then(|event| event.redacted("tool_result"));
|
||||
if let Ok(event) = event {
|
||||
let _ = observer.record(event);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
fn record_behavior_observation(
|
||||
observer: &metacrate_grid_agent::Observability,
|
||||
observation: &metacrate_grid_agent::BehaviorObservation,
|
||||
) {
|
||||
use metacrate_grid_agent::{
|
||||
BehaviorObservation, CorrelationIds, EventDraft, EventFamily, EventOrigin, EventSeverity,
|
||||
};
|
||||
let event = match observation {
|
||||
BehaviorObservation::Transition { from, to, .. } => EventDraft::new(
|
||||
EventFamily::BehaviorTransition,
|
||||
EventSeverity::Info,
|
||||
"behavior",
|
||||
EventOrigin::Service,
|
||||
)
|
||||
.and_then(|event| event.code_field("from", behavior_mode_code(*from)))
|
||||
.and_then(|event| event.code_field("to", behavior_mode_code(*to))),
|
||||
BehaviorObservation::Action {
|
||||
action_id,
|
||||
generation,
|
||||
action,
|
||||
duration_millis,
|
||||
outcome,
|
||||
..
|
||||
} => EventDraft::new(
|
||||
EventFamily::ToolResult,
|
||||
EventSeverity::Info,
|
||||
"behavior",
|
||||
EventOrigin::Service,
|
||||
)
|
||||
.and_then(|event| {
|
||||
event.correlation(CorrelationIds {
|
||||
action_id: Some(action_id.clone()),
|
||||
..CorrelationIds::default()
|
||||
})
|
||||
})
|
||||
.map(|event| event.duration_millis(*duration_millis))
|
||||
.and_then(|event| event.result_code(behavior_outcome_code(*outcome)))
|
||||
.and_then(|event| event.identifier_field("tool", action))
|
||||
.and_then(|event| {
|
||||
event.field(
|
||||
"generation",
|
||||
serde_json::Value::from(generation.unwrap_or(0)),
|
||||
)
|
||||
}),
|
||||
};
|
||||
if let Ok(event) = event {
|
||||
let _ = observer.record(event);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
const fn session_reason_code(reason: metacrate_grid_agent::SessionReason) -> &'static str {
|
||||
use metacrate_grid_agent::SessionReason;
|
||||
match reason {
|
||||
SessionReason::Startup => "startup",
|
||||
SessionReason::LoginSucceeded => "login_succeeded",
|
||||
SessionReason::AgentReady => "agent_ready",
|
||||
SessionReason::ReadinessLost => "readiness_lost",
|
||||
SessionReason::TransientTransport => "transient_transport",
|
||||
SessionReason::Maintenance => "maintenance",
|
||||
SessionReason::Kicked => "kicked",
|
||||
SessionReason::SimulatorDisconnected => "simulator_disconnected",
|
||||
SessionReason::ServerFailure => "server_failure",
|
||||
SessionReason::InvalidCredentials => "invalid_credentials",
|
||||
SessionReason::InvalidConfiguration => "invalid_configuration",
|
||||
SessionReason::StableSessionReset => "stable_session_reset",
|
||||
SessionReason::OperatorPause => "operator_pause",
|
||||
SessionReason::OperatorResume => "operator_resume",
|
||||
SessionReason::OperatorForceReconnect => "operator_force_reconnect",
|
||||
SessionReason::OperatorLogout => "operator_logout",
|
||||
SessionReason::ShutdownRequested => "shutdown_requested",
|
||||
SessionReason::ShutdownComplete => "shutdown_complete",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
const fn memory_reason_code(reason: metacrate_grid_agent::MemoryReason) -> &'static str {
|
||||
use metacrate_grid_agent::MemoryReason;
|
||||
match reason {
|
||||
MemoryReason::SessionCreated => "session_created",
|
||||
MemoryReason::PublicExpired => "public_expired",
|
||||
MemoryReason::DirectImExpired => "direct_im_expired",
|
||||
MemoryReason::TurnCompacted => "turn_compacted",
|
||||
MemoryReason::ByteCompacted => "byte_compacted",
|
||||
MemoryReason::ToolResultCompacted => "tool_result_compacted",
|
||||
MemoryReason::SessionLimitEviction => "session_limit_eviction",
|
||||
MemoryReason::TotalByteEviction => "total_byte_eviction",
|
||||
MemoryReason::OperatorDeleted => "operator_deleted",
|
||||
MemoryReason::OperatorExpired => "operator_expired",
|
||||
MemoryReason::CorruptSnapshotQuarantined => "corrupt_snapshot_quarantined",
|
||||
MemoryReason::UnsupportedSnapshotQuarantined => "unsupported_snapshot_quarantined",
|
||||
MemoryReason::SnapshotTooLargeQuarantined => "snapshot_too_large_quarantined",
|
||||
MemoryReason::PermissionsNotVerified => "permissions_not_verified",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
const fn suppression_reason_code(reason: metacrate_grid_agent::SuppressionReason) -> &'static str {
|
||||
use metacrate_grid_agent::SuppressionReason;
|
||||
match reason {
|
||||
SuppressionReason::SelfEcho => "self_echo",
|
||||
SuppressionReason::Duplicate => "duplicate",
|
||||
SuppressionReason::Muted => "muted",
|
||||
SuppressionReason::UnsupportedSource => "unsupported_source",
|
||||
SuppressionReason::UnsupportedDialog => "unsupported_dialog",
|
||||
SuppressionReason::AmbientPublicChat => "ambient_public_chat",
|
||||
SuppressionReason::SenderQueueFull => "sender_queue_full",
|
||||
SuppressionReason::SenderLimit => "sender_limit",
|
||||
SuppressionReason::Disconnected => "disconnected",
|
||||
SuppressionReason::UnsafeResponse => "unsafe_response",
|
||||
SuppressionReason::Cancelled => "cancelled",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
const fn interaction_origin_code(origin: metacrate_grid_agent::InteractionOrigin) -> &'static str {
|
||||
use metacrate_grid_agent::InteractionOrigin;
|
||||
match origin {
|
||||
InteractionOrigin::Public => "public",
|
||||
InteractionOrigin::UnprivilegedIm => "unprivileged_im",
|
||||
InteractionOrigin::AuthorizedIm => "authorized_im",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
const fn interaction_intent_code(intent: metacrate_grid_agent::InteractionIntent) -> &'static str {
|
||||
use metacrate_grid_agent::InteractionIntent;
|
||||
match intent {
|
||||
InteractionIntent::Informational => "informational",
|
||||
InteractionIntent::PublicCommandDenied => "public_command_denied",
|
||||
InteractionIntent::PolicyGatedCommand => "policy_gated_command",
|
||||
InteractionIntent::PolicyGatedLslRequest => "policy_gated_lsl_request",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
const fn delivery_outcome_code(outcome: metacrate_grid_agent::DeliveryOutcome) -> &'static str {
|
||||
use metacrate_grid_agent::DeliveryOutcome;
|
||||
match outcome {
|
||||
DeliveryOutcome::Succeeded => "succeeded",
|
||||
DeliveryOutcome::Failed => "failed",
|
||||
DeliveryOutcome::TimedOut => "timed_out",
|
||||
DeliveryOutcome::PolicyDenied => "policy_denied",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
const fn interaction_channel_code(
|
||||
channel: metacrate_grid_agent::InteractionChannel,
|
||||
) -> &'static str {
|
||||
use metacrate_grid_agent::InteractionChannel;
|
||||
match channel {
|
||||
InteractionChannel::PublicChat => "public_chat",
|
||||
InteractionChannel::DirectIm => "direct_im",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
const fn behavior_mode_code(mode: metacrate_grid_agent::BehaviorMode) -> &'static str {
|
||||
use metacrate_grid_agent::BehaviorMode;
|
||||
match mode {
|
||||
BehaviorMode::Offline => "offline",
|
||||
BehaviorMode::Settling => "settling",
|
||||
BehaviorMode::Available => "available",
|
||||
BehaviorMode::Engaged => "engaged",
|
||||
BehaviorMode::Executing => "executing",
|
||||
BehaviorMode::Roaming => "roaming",
|
||||
BehaviorMode::Paused => "paused",
|
||||
BehaviorMode::Recovering => "recovering",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
const fn behavior_outcome_code(outcome: metacrate_grid_agent::BehaviorOutcome) -> &'static str {
|
||||
use metacrate_grid_agent::BehaviorOutcome;
|
||||
match outcome {
|
||||
BehaviorOutcome::Completed => "completed",
|
||||
BehaviorOutcome::Cancelled => "cancelled",
|
||||
BehaviorOutcome::TimedOut => "timed_out",
|
||||
BehaviorOutcome::Stuck => "stuck",
|
||||
BehaviorOutcome::Rejected => "rejected",
|
||||
BehaviorOutcome::Preempted => "preempted",
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user