use std::time::Duration;
use serde_json::{Value, json};
use crate::agents::{DEFAULT_PROMPT_TIMEOUT, DEFAULT_SIZE, PromptOptions, bedrock};
use crate::control::artifact::WrapOptions;
use crate::control::ensure::EnsureImageRequest;
use crate::control::{CreateImageRequest, DEFAULT_AGENT_PORT};
use crate::cost::DEFAULT_RESIDENCY_CYCLES;
use crate::sandbox::{
DEFAULT_LIFECYCLE_TIMEOUT, LIFECYCLE_POLL_INTERVAL, RunRequest, TeardownOpts,
};
use crate::session::{DEFAULT_CLIENT_GRACE, DEFAULT_EXEC_WAIT, StreamOptions};
use crate::sizing::SizeClass;
pub fn client_defaults() -> Value {
let launch = RunRequest::default();
let start = protocol::exec::StartRequest::new(String::new(), Vec::new());
let stream = StreamOptions::default();
let teardown = TeardownOpts::default();
let prompt = PromptOptions::default();
let image = CreateImageRequest::new(String::new(), Vec::new(), String::new(), String::new());
let ensured = EnsureImageRequest::new(
String::new(),
Vec::new(),
String::new(),
String::new(),
String::new(),
);
json!({
"sizeMib": SizeClass::DEFAULT.baseline_mib(),
"agentSizeMib": DEFAULT_SIZE.baseline_mib(),
"agentPort": DEFAULT_AGENT_PORT,
"execWaitSeconds": seconds(DEFAULT_EXEC_WAIT),
"readyTimeoutSeconds": seconds(crate::session::DEFAULT_BOOTSTRAP_TIMEOUT),
"launchTimeoutSeconds": seconds(crate::sandbox::DEFAULT_RUNNING_TIMEOUT),
"lifecycleTimeoutSeconds": seconds(DEFAULT_LIFECYCLE_TIMEOUT),
"lifecyclePollIntervalSeconds": seconds(LIFECYCLE_POLL_INTERVAL),
"promptTimeoutSeconds": seconds(DEFAULT_PROMPT_TIMEOUT),
"clientGraceSeconds": seconds(DEFAULT_CLIENT_GRACE),
"bedrockTokenTtlHours": bedrock::MAX_LIFETIME.as_secs() / 3600,
"residencyCycles": DEFAULT_RESIDENCY_CYCLES,
"keepAwakeToleratedErrors": crate::session::keepalive::DEFAULT_TOLERATED_ERRORS,
"syncDeleteTimeoutSeconds": seconds(crate::workspace::DEFAULT_SYNC_DELETE_TIMEOUT),
"launch": {
"maxIdleSeconds": launch.max_idle_sec,
"suspendedSeconds": launch.suspended_sec,
"maxDurationSeconds": launch.max_duration_sec,
"autoResume": launch.auto_resume,
"egress": launch.egress,
"denyEgress": launch.deny_egress,
"identity": launch.identity,
"shell": launch.shell,
"wait": launch.wait,
"loggingDisabled": matches!(
launch.logging,
Some(crate::control::ops::Logging::Disabled { .. })
),
},
"exec": {
"shell": matches!(start.shell, protocol::exec::Shell::Flag(true)),
"stdin": start.stdin,
"reapGroupOnExit": start.reap_group_on_exit,
"inheritImageEnv": start.inherit_image_env,
},
"stream": {
"reconnect": stream.reconnect,
"errorOnGap": stream.error_on_gap,
},
"teardown": {
"deleteImage": teardown.delete_image,
"deleteLogGroup": teardown.delete_log_group,
"waitForTerminated": teardown.wait_for_terminated.is_some(),
},
"prompt": {
"reapGroupOnExit": prompt.reap_group_on_exit,
},
"image": {
"inheritWorkdir": WrapOptions::default().inherit_workdir,
"repairGuestIdentity": image.repair_guest_identity,
"force": ensured.force,
},
})
}
fn seconds(duration: Duration) -> f64 {
duration.as_secs_f64()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_client_defaults_are_cores_own_values() {
let defaults = client_defaults();
assert_eq!(
defaults["execWaitSeconds"],
DEFAULT_EXEC_WAIT.as_secs_f64(),
"execWaitSeconds"
);
assert_eq!(defaults["agentPort"], DEFAULT_AGENT_PORT);
assert_eq!(defaults["sizeMib"], SizeClass::DEFAULT.baseline_mib());
let launch = RunRequest::default();
assert_eq!(defaults["launch"]["maxIdleSeconds"], launch.max_idle_sec);
assert_eq!(defaults["launch"]["wait"], launch.wait);
let start = protocol::exec::StartRequest::new("x", vec!["true".into()]);
assert_eq!(defaults["exec"]["stdin"], start.stdin);
assert_eq!(defaults["exec"]["shell"], false);
assert_eq!(
defaults["syncDeleteTimeoutSeconds"],
crate::workspace::DEFAULT_SYNC_DELETE_TIMEOUT.as_secs_f64()
);
}
}