mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-14 23:22:51 +00:00
Move the supplied-content packager next to its collector
ServerWorkflowVersionPackager was a pure adapter over fabro_manifest::collect_supplied_workflow_versions that touched no server state, yet it lived in fabro-server and was imported from there by the standalone MCP server and the CLI run worker. fabro-manifest can depend on fabro-tool without a cycle, so the adapter now lives beside the collector as SuppliedWorkflowVersionPackager and fabro-server no longer exports a non-server module for it. The adapter also cloned every version's file map out of a closure it already owned. CollectedWorkflowClosure::into_versions hands the versions over by value inside the blocking task instead. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
44dccfa3d2
commit
e6eb59537a
8 changed files with 46 additions and 25 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -2754,12 +2754,14 @@ name = "fabro-manifest"
|
|||
version = "0.354.0-nightly.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"fabro-api",
|
||||
"fabro-config",
|
||||
"fabro-github",
|
||||
"fabro-graphviz",
|
||||
"fabro-template",
|
||||
"fabro-test",
|
||||
"fabro-tool",
|
||||
"fabro-types",
|
||||
"fabro-util",
|
||||
"fabro-workflow",
|
||||
|
|
@ -2770,7 +2772,9 @@ dependencies = [
|
|||
"temp-env",
|
||||
"tempfile",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"toml 0.8.23",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ use fabro_interview::{
|
|||
WORKER_CONTROL_WS_PING_INTERVAL, WorkerControlDeliveryFrame, WorkerControlEnvelope,
|
||||
WorkerControlMessage,
|
||||
};
|
||||
use fabro_manifest::SuppliedWorkflowVersionPackager;
|
||||
use fabro_server::run_tool_manifest;
|
||||
use fabro_server::workflow_version_tool::ServerWorkflowVersionPackager;
|
||||
use fabro_store::{EventEnvelope, RunProjection, RunProjectionReducer};
|
||||
use fabro_tool::fabro_client::ClientBackend;
|
||||
use fabro_types::settings::run::{RunMode, RunNamespace};
|
||||
|
|
@ -238,7 +238,7 @@ fn build_fabro_run_tool_services(
|
|||
}
|
||||
let backend = ClientBackend::new(Arc::new(client))
|
||||
.with_manifest_builder(Arc::new(WorkerRunManifestBuilder))
|
||||
.with_workflow_version_packager(Arc::new(ServerWorkflowVersionPackager));
|
||||
.with_workflow_version_packager(Arc::new(SuppliedWorkflowVersionPackager));
|
||||
Some(FabroRunToolServices {
|
||||
backend: Arc::new(backend),
|
||||
current_run_id,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use fabro_server::workflow_version_tool::ServerWorkflowVersionPackager;
|
||||
use fabro_manifest::SuppliedWorkflowVersionPackager;
|
||||
use fabro_tool::fabro_client::ClientBackend;
|
||||
use fabro_tool::{self as run_tools, FabroToolBackend};
|
||||
use fabro_util::version::FABRO_VERSION;
|
||||
|
|
@ -277,7 +277,7 @@ impl FabroMcpServer {
|
|||
ClientBackend::new(Arc::new(client))
|
||||
.with_manifest_builder(Arc::new(McpRunManifestBuilder))
|
||||
.with_workflow_version_packager(Arc::new(
|
||||
ServerWorkflowVersionPackager,
|
||||
SuppliedWorkflowVersionPackager,
|
||||
)),
|
||||
) as Arc<dyn FabroToolBackend>
|
||||
})
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ pub mod web_auth;
|
|||
mod worker_control;
|
||||
mod worker_runtime;
|
||||
mod worker_token;
|
||||
pub mod workflow_version_tool;
|
||||
|
||||
pub use error::{ApiError, Error, Result};
|
||||
pub use run_manifest::workflow_bundle_from_manifest;
|
||||
|
|
|
|||
|
|
@ -14,18 +14,22 @@ workspace = true
|
|||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
async-trait.workspace = true
|
||||
fabro-api = { path = "../../foundation/fabro-api" }
|
||||
fabro-config = { path = "../../foundation/fabro-config" }
|
||||
fabro-github = { path = "../fabro-github" }
|
||||
fabro-graphviz = { path = "../fabro-graphviz" }
|
||||
fabro-template = { path = "../../foundation/fabro-template" }
|
||||
fabro-tool = { path = "../fabro-tool" }
|
||||
fabro-types = { path = "../../foundation/fabro-types" }
|
||||
fabro-workflow = { path = "../fabro-workflow" }
|
||||
fabro-workflow-version = { path = "../fabro-workflow-version" }
|
||||
git2.workspace = true
|
||||
tempfile = "3"
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
toml.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
fabro-test.workspace = true
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ mod local_workflow_package;
|
|||
mod supplied_workflow;
|
||||
mod workflow_bundler;
|
||||
mod workflow_version_collector;
|
||||
mod workflow_version_packager;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
|
@ -41,6 +42,7 @@ pub use crate::workflow_version_collector::{
|
|||
CollectedWorkflowClosure, WorkflowVersionCollectError, collect_workflow_versions,
|
||||
collect_workflow_versions_at_location,
|
||||
};
|
||||
pub use crate::workflow_version_packager::SuppliedWorkflowVersionPackager;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ManifestBuildInput {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,16 @@ impl CollectedWorkflowClosure {
|
|||
) -> impl Iterator<Item = (WorkflowVersionId, &ValidatedWorkflowVersion)> + '_ {
|
||||
self.versions.iter().map(|(id, version)| (*id, version))
|
||||
}
|
||||
|
||||
/// Consume the closure, yielding every version with dependencies before
|
||||
/// parents, for callers that hand the versions on without cloning.
|
||||
#[must_use]
|
||||
pub fn into_versions(self) -> Vec<WorkflowVersion> {
|
||||
self.versions
|
||||
.into_iter()
|
||||
.map(|(_, version)| version.into_version())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
//! Application adapter that packages caller-supplied workflow contents for
|
||||
//! the `fabro_workflow_version_create` tool.
|
||||
|
||||
use async_trait::async_trait;
|
||||
use fabro_tool::{
|
||||
PackagedWorkflowVersions, ToolError, ValidatedWorkflowVersionCreate, WorkflowVersionPackager,
|
||||
|
|
@ -7,35 +10,34 @@ use tracing::warn;
|
|||
|
||||
/// Packages supplied workflow contents for standalone MCP and capable run
|
||||
/// workers; the backend that owns the API client performs registration.
|
||||
pub struct ServerWorkflowVersionPackager;
|
||||
pub struct SuppliedWorkflowVersionPackager;
|
||||
|
||||
const PACKAGING_FAILED: &str = "workflow source could not be packaged; check configuration, \
|
||||
syntax, local references, and package limits";
|
||||
|
||||
#[async_trait]
|
||||
impl WorkflowVersionPackager for ServerWorkflowVersionPackager {
|
||||
impl WorkflowVersionPackager for SuppliedWorkflowVersionPackager {
|
||||
async fn package(
|
||||
&self,
|
||||
source: ValidatedWorkflowVersionCreate,
|
||||
) -> anyhow::Result<PackagedWorkflowVersions> {
|
||||
let closure = task::spawn_blocking(move || {
|
||||
fabro_manifest::collect_supplied_workflow_versions(&source.entrypoint, &source.files)
|
||||
task::spawn_blocking(move || {
|
||||
let closure =
|
||||
crate::collect_supplied_workflow_versions(&source.entrypoint, &source.files)
|
||||
.map_err(|err| {
|
||||
// Parser diagnostics may quote supplied source, so the
|
||||
// chain stays in the log and only a generic message
|
||||
// crosses the tool boundary.
|
||||
warn!(error = %format!("{err:#}"), "workflow version packaging failed");
|
||||
ToolError::message(PACKAGING_FAILED)
|
||||
})?;
|
||||
Ok(PackagedWorkflowVersions {
|
||||
root_id: closure.root_id(),
|
||||
versions: closure.into_versions(),
|
||||
})
|
||||
})
|
||||
.await
|
||||
.map_err(|err| anyhow::anyhow!("workflow packaging task failed: {err}"))?
|
||||
.map_err(|err| {
|
||||
// Parser diagnostics may quote supplied source, so the chain stays
|
||||
// in the log and only a generic message crosses the tool boundary.
|
||||
warn!(error = %format!("{err:#}"), "workflow version packaging failed");
|
||||
ToolError::message(PACKAGING_FAILED)
|
||||
})?;
|
||||
Ok(PackagedWorkflowVersions {
|
||||
root_id: closure.root_id(),
|
||||
versions: closure
|
||||
.versions()
|
||||
.map(|(_, version)| version.version().clone())
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +72,7 @@ mod tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn packager_returns_dependencies_before_root() {
|
||||
let packaged = ServerWorkflowVersionPackager
|
||||
let packaged = SuppliedWorkflowVersionPackager
|
||||
.package(fixture())
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
@ -112,7 +114,7 @@ mod tests {
|
|||
"PRIVATE_CONTENT invalid source",
|
||||
)]),
|
||||
] {
|
||||
let error = ServerWorkflowVersionPackager
|
||||
let error = SuppliedWorkflowVersionPackager
|
||||
.package(input)
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
|
@ -129,7 +131,7 @@ mod tests {
|
|||
.files
|
||||
.insert("Prompt.md".parse().unwrap(), prompt);
|
||||
assert!(
|
||||
ServerWorkflowVersionPackager
|
||||
SuppliedWorkflowVersionPackager
|
||||
.package(wrong_case)
|
||||
.await
|
||||
.is_err(),
|
||||
Loading…
Add table
Reference in a new issue