Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 26 additions & 23 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 9 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,18 @@ categories = ["command-line-utilities", "development-tools"]
# animus-subject-protocol resolves to one source (no duplicate-crate type
# mismatches). animus-plugin-protocol/runtime remain in-tree pending a
# follow-up move.
animus-plugin-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-actor = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-config-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-journal-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-provider-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-session-backend = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-subject-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-plugin-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
animus-actor = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
animus-config-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
animus-journal-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
animus-provider-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
animus-session-backend = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
animus-subject-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
# v0.7: environment plugin kind — EnvironmentSpec/HarnessCommand/ExecRequest wire
# types + prepare/exec/exec_stream/teardown methods. Consumed by the routing
# resolver + the follow-on runtime EnvironmentClient (not yet built).
animus-environment-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6", package = "protocol" }
animus-environment-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7", package = "protocol" }
orchestrator-daemon-runtime = { path = "crates/orchestrator-daemon-runtime" }
orchestrator-logging = { path = "crates/orchestrator-logging" }
orchestrator-plugin-host = { path = "crates/orchestrator-plugin-host" }
Expand Down
10 changes: 5 additions & 5 deletions crates/orchestrator-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "orchestrator-cli"
version = "0.7.0-rc.14"
version = "0.7.0-rc.23"
edition = "2021"
license = "Elastic-2.0"
default-run = "animus"
Expand Down Expand Up @@ -39,9 +39,9 @@ animus-environment-protocol = { workspace = true }
# embed subject-protocol types, so `animus-subject-protocol-wire` MUST match
# control's rev. v0.1.26 additively adds `actor: Option<Actor>` to the control +
# workflow-runner request types relayed by the control surface / plugin_clients.
animus-control-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-log-storage-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-subject-protocol-wire = { package = "animus-subject-protocol", git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-control-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
animus-log-storage-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
animus-subject-protocol-wire = { package = "animus-subject-protocol", git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
animus-actor = { workspace = true }
# Plugin protocol crates used by the plugin-host wrappers in
# `services::plugin_clients` to dispatch `workflow/*` and `queue/*` RPCs through
Expand All @@ -51,7 +51,7 @@ animus-actor = { workspace = true }
# NOT share `animus-subject-protocol-wire`'s rev (cargo forbids two names for one
# package instance), so they stay a distinct rev.
animus-queue-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.5.10" }
animus-workflow-runner-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.6" }
animus-workflow-runner-protocol = { git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.7.0-rc.7" }
animus-subject-protocol-v05 = { package = "animus-subject-protocol", git = "https://github.com/launchapp-dev/animus-protocol", tag = "v0.5.10" }
protocol = { workspace = true }
animus-session-backend = { workspace = true }
Expand Down
5 changes: 5 additions & 0 deletions crates/orchestrator-cli/src/cli_types/output_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ pub(crate) struct OutputRunArgs {
/// Resolve the latest run id recorded for this workflow, then read it.
#[arg(long)]
pub(crate) workflow_id: Option<String>,
/// With --workflow-id, read the transcript of THIS phase's run (from the
/// phase session checkpoint) instead of the workflow's latest run. Lets the
/// UI load logs for a specific/earlier phase, not just the last one.
#[arg(long, requires = "workflow_id")]
pub(crate) phase: Option<String>,
}

#[derive(Debug, Args)]
Expand Down
31 changes: 30 additions & 1 deletion crates/orchestrator-cli/src/services/operations/ops_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,30 @@ fn resolve_run_id_arg(project_root: &str, run_id: Option<String>, workflow_id: O
}
}

/// Resolve the run id for a SPECIFIC `(workflow_id, phase_id)` from the phase
/// session checkpoints (`runs/<workflow_id>/phases/*.session.json`). Lets the UI
/// load one phase's transcript instead of only the workflow's latest run.
fn resolve_run_id_for_workflow_phase(project_root: &str, workflow_id: &str, phase_id: &str) -> Result<String> {
let Some(workflow_run_dir) = resolve_run_dir_for_lookup(project_root, workflow_id)? else {
return Err(not_found_error(format!("no run directory recorded for workflow {workflow_id}")));
};
let phases_dir = workflow_run_dir.join("phases");
if phases_dir.is_dir() {
for entry in fs::read_dir(&phases_dir).with_context(|| format!("read phases dir {}", phases_dir.display()))? {
let path = entry?.path();
if !path.file_name().and_then(|n| n.to_str()).is_some_and(|n| n.ends_with(".session.json")) {
continue;
}
if let Ok(Some(checkpoint)) = phase_session::read_path(&path) {
if checkpoint.phase_id == phase_id {
return Ok(checkpoint.run_id);
}
}
}
}
Err(not_found_error(format!("no run recorded for phase '{phase_id}' of workflow {workflow_id}")))
}

fn extract_timestamp_hint(line: &str) -> Option<String> {
let parsed = serde_json::from_str::<Value>(line).ok()?;
parsed
Expand Down Expand Up @@ -277,7 +301,12 @@ pub(crate) fn get_phase_outputs(
pub(crate) async fn handle_output(command: OutputCommand, project_root: &str, json: bool) -> Result<()> {
match command {
OutputCommand::Read(args) => {
let run_id = resolve_run_id_arg(project_root, args.run_id, args.workflow_id)?;
let run_id = match (&args.phase, &args.workflow_id) {
(Some(phase), Some(workflow_id)) => {
resolve_run_id_for_workflow_phase(project_root, workflow_id, phase)?
}
_ => resolve_run_id_arg(project_root, args.run_id, args.workflow_id)?,
};
let run_dir = resolve_run_dir_for_lookup(project_root, &run_id)?
.ok_or_else(|| not_found_error(format!("run directory not found for {run_id}")))?;
let events_path = run_dir.join("events.jsonl");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ impl WorkflowRouting for WorkflowRoutingImpl {
let query = WorkflowQuery {
filter: WorkflowFilter {
status: request.status.map(wire_status_to_core),
workflow_ref: None,
// v0.7.0-rc.7: the workflow-type filter is now wire-expressible.
workflow_ref: request.workflow_ref.clone(),
task_id: None,
phase_id: None,
search_text: None,
Expand All @@ -181,9 +182,10 @@ impl WorkflowRouting for WorkflowRoutingImpl {
sort: Default::default(),
};
let page: ListPage<OrchestratorWorkflow> = hub.workflows().query(query).await.map_err(internal)?;
let total = page.total as u32;
let runs: Vec<WireRunSummary> = page.items.iter().map(workflow_summary_from_core).collect();
let next_cursor = page.next_offset.map(|n| n.to_string());
Ok(WireListResponse { runs, next_cursor })
Ok(WireListResponse { runs, next_cursor, total: Some(total) })
}

async fn workflow_get(&self, request: WireGetRequest) -> Result<WireWorkflowRun, ControlError> {
Expand Down
Loading
Loading