use runx_contracts::{JsonObject, JsonValue, ThreadOutboxProviderOperation};
use crate::adapter::{CREDENTIAL_DELIVERY_OBSERVATIONS_METADATA, InvocationStatus, SkillOutput};
use crate::outbox_provider::ThreadOutboxProviderProcessOutcome;
use super::{ThreadOutboxProviderSkillAdapterError, json_error};
const OBSERVATION_METADATA: &str = "thread_outbox_provider_observation";
const OPERATION_METADATA: &str = "thread_outbox_provider_operation";
const PROVIDER_LOCATOR_METADATA: &str = "thread_outbox_provider_locator";
const PROVIDER_EVENT_HASH_METADATA: &str = "thread_outbox_provider_event_hash";
pub(super) fn skill_output_from_outcome(
outcome: ThreadOutboxProviderProcessOutcome,
) -> Result<SkillOutput, ThreadOutboxProviderSkillAdapterError> {
let observation_value = contract_json_value(&outcome.observation, "serializing observation")?;
let stdout = stdout_from_outcome(&outcome, observation_value.clone())?;
let mut metadata = JsonObject::new();
metadata.insert(OBSERVATION_METADATA.to_owned(), observation_value);
metadata.insert(
OPERATION_METADATA.to_owned(),
JsonValue::String(operation_label(&outcome.observation.operation).to_owned()),
);
if let Some(locator) = &outcome.observation.provider_locator {
metadata.insert(
PROVIDER_LOCATOR_METADATA.to_owned(),
JsonValue::String(locator.locator.to_string()),
);
}
if let Some(event_hash) = &outcome.observation.provider_event_id_hash {
metadata.insert(
PROVIDER_EVENT_HASH_METADATA.to_owned(),
JsonValue::String(event_hash.to_string()),
);
}
if let Some(delivery_observations) = &outcome.observation.delivery_observations {
metadata.insert(
CREDENTIAL_DELIVERY_OBSERVATIONS_METADATA.to_owned(),
contract_json_value(delivery_observations, "serializing delivery observations")?,
);
}
Ok(SkillOutput {
status: InvocationStatus::Success,
stdout,
stderr: outcome.redacted_stderr,
exit_code: outcome.process_exit_code,
duration_ms: outcome.duration_ms,
metadata,
})
}
fn stdout_from_outcome(
outcome: &ThreadOutboxProviderProcessOutcome,
observation_value: JsonValue,
) -> Result<String, ThreadOutboxProviderSkillAdapterError> {
let value = match outcome.provider_output.clone() {
Some(mut output) => {
output.insert(OBSERVATION_METADATA.to_owned(), observation_value);
JsonValue::Object(output)
}
None => observation_value,
};
serde_json::to_string(&value)
.map_err(|source| json_error("serializing thread-outbox-provider adapter stdout", source))
}
fn operation_label(operation: &ThreadOutboxProviderOperation) -> &'static str {
match operation {
ThreadOutboxProviderOperation::Push => "push",
ThreadOutboxProviderOperation::Fetch => "fetch",
}
}
fn contract_json_value(
value: &impl serde::Serialize,
context: &'static str,
) -> Result<JsonValue, ThreadOutboxProviderSkillAdapterError> {
let value = serde_json::to_value(value).map_err(|source| json_error(context, source))?;
serde_json::from_value(value).map_err(|source| json_error(context, source))
}