chore: merge standalone feature into companion integration

# Conflicts:
#	crates/client/src/target.rs
#	crates/client/src/ticket_role.rs
#	crates/manifest/src/profile.rs
#	crates/tui/src/dashboard/tests.rs
#	crates/tui/src/worker_list.rs
#	crates/workspace-server/src/hosts.rs
#	crates/yoi/src/main.rs
This commit is contained in:
2026-08-31 02:01:38 +09:00
49 changed files with 4418 additions and 19803 deletions
+229
View File
@@ -0,0 +1,229 @@
use std::path::PathBuf;
use agen::llm_client::client::LlmClient;
use session_store::{Store, WorkerMetadataStore};
use thiserror::Error;
use workdir::WorkdirSessionHandle;
use crate::PromptCatalogSource;
use crate::controller::{
ShutdownReceiver, WorkerController, WorkerControllerTransport, WorkerHandle,
};
use crate::worker::{Worker, WorkerError, WorkerFilesystemAuthority, WorkerWorkspaceContext};
use manifest::WorkerManifest;
/// Filesystem layout used by a Worker controller started through the reusable
/// bootstrap boundary.
#[derive(Debug, Clone)]
pub enum WorkerBootstrapLayout {
/// A direct Worker rooted below the supplied runtime base directory.
Direct { runtime_base: PathBuf },
/// A runtime-managed Worker with an exact persisted run directory.
RuntimeManagedRun { run_dir: PathBuf },
}
/// Construction and controller inputs that are stable for one Worker launch.
pub struct WorkerBootstrap<St> {
manifest: WorkerManifest,
store: St,
prompt_catalog: PromptCatalogSource,
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
layout: WorkerBootstrapLayout,
transport: WorkerControllerTransport,
model_client: Option<Box<dyn LlmClient>>,
workdir_session: Option<WorkdirSessionHandle>,
}
/// A constructed Worker whose host-owned live bindings can still be installed
/// before Feature installation and controller exposure.
pub struct PreparedWorker<C: LlmClient, St: Store> {
worker: Worker<C, St>,
layout: WorkerBootstrapLayout,
transport: WorkerControllerTransport,
}
/// Live controller returned only after Worker construction and feature
/// installation have completed successfully.
pub struct BootstrappedWorker {
pub handle: WorkerHandle,
pub shutdown: ShutdownReceiver,
}
#[derive(Debug, Error)]
pub enum WorkerBootstrapError {
#[error("worker construction failed")]
Worker(#[source] WorkerError),
#[error("worker controller startup failed")]
Controller {
#[source]
source: std::io::Error,
cleanup_failed: bool,
},
}
impl<St> WorkerBootstrap<St>
where
St: Store + WorkerMetadataStore + Clone + Send + Sync + 'static,
{
#[allow(clippy::too_many_arguments)]
pub fn new(
manifest: WorkerManifest,
store: St,
prompt_catalog: PromptCatalogSource,
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
layout: WorkerBootstrapLayout,
transport: WorkerControllerTransport,
) -> Self {
Self {
manifest,
store,
prompt_catalog,
workspace_context,
filesystem_authority,
layout,
transport,
model_client: None,
workdir_session: None,
}
}
/// Inject a process-owned model client. This is primarily useful for
/// embedded hosts and deterministic tests that must not start an external
/// model server.
pub fn with_model_client<C>(mut self, model_client: C) -> Self
where
C: LlmClient + 'static,
{
self.model_client = Some(Box::new(model_client));
self
}
/// Bind an already materialized Workdir session instead of asking the
/// Worker to derive one from filesystem authority.
pub fn with_workdir_session(mut self, workdir_session: WorkdirSessionHandle) -> Self {
self.workdir_session = Some(workdir_session);
self
}
/// Construct the Worker without exposing a controller handle. Runtime hosts
/// use this seam to bind Workdir, observation, Flow, and other live services
/// before [`PreparedWorker::start`] performs Feature installation.
pub async fn prepare(
self,
) -> Result<PreparedWorker<Box<dyn LlmClient>, St>, WorkerBootstrapError> {
let mut worker = Worker::from_manifest_with_context_and_model_client(
self.manifest,
self.store,
self.prompt_catalog,
self.workspace_context,
self.filesystem_authority,
self.model_client,
)
.await
.map_err(WorkerBootstrapError::Worker)?;
if let Some(workdir_session) = self.workdir_session {
worker.bind_workdir_session(Some(workdir_session));
}
Ok(PreparedWorker::new(worker, self.layout, self.transport))
}
pub async fn prepare_restored(
self,
worker_name: &str,
) -> Result<PreparedWorker<Box<dyn LlmClient>, St>, WorkerBootstrapError> {
let mut worker =
Worker::restore_pending_from_worker_metadata_with_context_and_model_client(
worker_name,
self.manifest,
self.store,
self.prompt_catalog,
self.workspace_context,
self.filesystem_authority,
self.model_client,
)
.await
.map_err(WorkerBootstrapError::Worker)?;
if let Some(workdir_session) = self.workdir_session {
worker.bind_workdir_session(Some(workdir_session));
}
Ok(PreparedWorker::new(worker, self.layout, self.transport))
}
pub async fn start(self) -> Result<BootstrappedWorker, WorkerBootstrapError> {
self.prepare().await?.start().await
}
}
impl<C, St> PreparedWorker<C, St>
where
C: LlmClient + Clone + 'static,
St: Store + WorkerMetadataStore + Clone + Send + Sync + 'static,
{
/// Wrap a restored Worker in the same pre-exposure lifecycle used by fresh
/// bootstraps.
pub fn new(
worker: Worker<C, St>,
layout: WorkerBootstrapLayout,
transport: WorkerControllerTransport,
) -> Self {
Self {
worker,
layout,
transport,
}
}
pub fn worker(&self) -> &Worker<C, St> {
&self.worker
}
pub fn worker_mut(&mut self) -> &mut Worker<C, St> {
&mut self.worker
}
pub async fn start(self) -> Result<BootstrappedWorker, WorkerBootstrapError> {
start_worker_controller(self.worker, self.layout, self.transport).await
}
}
/// Start the shared direct/runtime-managed controller lifecycle for an already
/// constructed Worker. Restore paths use this after replaying durable state;
/// fresh hosts normally use [`WorkerBootstrap::start`].
pub async fn start_worker_controller<C, St>(
worker: Worker<C, St>,
layout: WorkerBootstrapLayout,
transport: WorkerControllerTransport,
) -> Result<BootstrappedWorker, WorkerBootstrapError>
where
C: LlmClient + Clone + 'static,
St: Store + WorkerMetadataStore + Clone + Send + Sync + 'static,
{
let cleanup_session = worker.workdir_session().cloned();
let controller = match layout {
WorkerBootstrapLayout::Direct { runtime_base } => {
WorkerController::spawn_with_transport(worker, &runtime_base, transport).await
}
WorkerBootstrapLayout::RuntimeManagedRun { run_dir } => {
WorkerController::spawn_runtime_managed_run_with_transport(worker, &run_dir, transport)
.await
}
};
match controller {
Ok((handle, shutdown)) => Ok(BootstrappedWorker { handle, shutdown }),
Err(source) => {
let cleanup_failed = match cleanup_session {
Some(session) => session.close().await.is_err(),
None => false,
};
Err(WorkerBootstrapError::Controller {
source,
cleanup_failed,
})
}
}
}
+14
View File
@@ -237,6 +237,20 @@ impl WorkerController {
.await
}
/// Spawn a direct Worker while letting an in-process host select the
/// controller transport explicitly.
pub async fn spawn_with_transport<C, St>(
worker: Worker<C, St>,
runtime_base: &Path,
transport: WorkerControllerTransport,
) -> Result<(WorkerHandle, ShutdownReceiver), std::io::Error>
where
C: LlmClient + Clone + 'static,
St: Store + WorkerMetadataStore + Clone + Send + Sync + 'static,
{
Self::spawn_inner(worker, runtime_base, false, None, transport).await
}
/// Spawn a Worker owned by `worker-runtime`.
///
/// The controller still uses an ephemeral directory for Unix sockets and
+1 -1
View File
@@ -14,9 +14,9 @@ use std::process::Stdio;
use std::sync::Arc;
use std::time::Duration;
use crate::runtime_command::WorkerRuntimeCommand;
use agen::tool::{Tool, ToolDefinition, ToolError, ToolMeta, ToolOutput};
use async_trait::async_trait;
use client::WorkerRuntimeCommand;
use manifest::{Permission, ScopeRule};
use protocol::stream::JsonLineReader;
use protocol::{Event, Method, WorkerStatus};
+18 -8
View File
@@ -3,8 +3,8 @@ use std::path::{Path, PathBuf};
use std::process::ExitCode;
use crate::{
PromptCatalogSource, Worker, WorkerController, WorkerFilesystemAuthority,
WorkerWorkspaceContext,
PromptCatalogSource, Worker, WorkerBootstrapLayout, WorkerControllerTransport,
WorkerFilesystemAuthority, WorkerWorkspaceContext, start_worker_controller,
};
use clap::{CommandFactory, FromArgMatches, Parser};
use manifest::{Permission, ScopeConfig, ScopeRule, WorkerManifest, WorkerManifestConfig, paths};
@@ -184,15 +184,16 @@ fn load_spawn_config_json(
) -> Result<(WorkerManifest, PromptCatalogSource), String> {
let config = serde_json::from_str::<WorkerManifestConfig>(config_json)
.map_err(|e| format!("failed to parse --spawn-config-json: {e}"))?;
let manifest = WorkerManifest::try_from(WorkerManifestConfig::builtin_defaults().merge(config))
.map_err(|e| format!("failed to resolve --spawn-config-json: {e}"))?;
let manifest =
WorkerManifest::try_from(WorkerManifestConfig::resolution_defaults().merge(config))
.map_err(|e| format!("failed to resolve --spawn-config-json: {e}"))?;
Ok((manifest, PromptCatalogSource::builtins_only()))
}
fn load_builtin_default_manifest(
worker_name: &str,
) -> Result<(WorkerManifest, PromptCatalogSource), String> {
let mut config = WorkerManifestConfig::builtin_defaults();
let mut config = WorkerManifestConfig::resolution_defaults();
config.worker.name = Some(worker_name.to_string());
let manifest = WorkerManifest::try_from(config)
.map_err(|e| format!("failed to resolve builtin worker defaults: {e}"))?;
@@ -259,7 +260,7 @@ fn load_single_manifest(
absolute_path.display()
)
})?;
let mut config = WorkerManifestConfig::builtin_defaults().merge(
let mut config = WorkerManifestConfig::resolution_defaults().merge(
WorkerManifestConfig::from_toml(&toml)
.map_err(|e| format!("failed to parse manifest {}: {e}", path.display()))?
.resolve_paths(base_dir),
@@ -633,13 +634,22 @@ async fn run_cli_inner(cli: Cli) -> ExitCode {
return ExitCode::FAILURE;
}
};
let (handle, shutdown_rx) = match WorkerController::spawn(worker, &runtime_base).await {
Ok(pair) => pair,
let started = match start_worker_controller(
worker,
WorkerBootstrapLayout::Direct {
runtime_base: runtime_base.clone(),
},
WorkerControllerTransport::UnixSocket,
)
.await
{
Ok(started) => started,
Err(e) => {
eprintln!("error: failed to start worker controller: {e}");
return ExitCode::FAILURE;
}
};
let (handle, shutdown_rx) = (started.handle, started.shutdown);
let socket_path = handle.runtime_dir.socket_path();
// Machine-readable ready line for parents that spawned this Worker
+6
View File
@@ -1,3 +1,4 @@
pub mod bootstrap;
pub mod compact;
pub mod controller;
pub mod discovery;
@@ -10,6 +11,7 @@ pub mod ipc;
pub mod model_client;
pub mod prompt;
pub mod runtime;
pub mod runtime_command;
pub mod segment_log_sink;
mod session_capture;
mod session_history;
@@ -23,6 +25,10 @@ mod interrupt_prep;
mod permission;
mod worker;
pub use bootstrap::{
BootstrappedWorker, PreparedWorker, WorkerBootstrap, WorkerBootstrapError,
WorkerBootstrapLayout, start_worker_controller,
};
pub use compact::token_counter::{EstimateSource, SplitPoint, TokenEstimate};
pub use controller::{ShutdownReceiver, WorkerController, WorkerControllerTransport, WorkerHandle};
pub use hook::{Hook, HookEventKind, HookRegistryBuilder};
+165
View File
@@ -0,0 +1,165 @@
use std::ffi::OsString;
use std::fmt;
use std::io;
use std::path::{Path, PathBuf};
const POD_RUNTIME_COMMAND_ENV: &str = "YOI_POD_RUNTIME_COMMAND";
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct WorkerRuntimeCommand {
pub program: PathBuf,
pub prefix_args: Vec<OsString>,
}
impl WorkerRuntimeCommand {
pub fn new(program: impl Into<PathBuf>, prefix_args: Vec<OsString>) -> Self {
Self {
program: program.into(),
prefix_args,
}
}
pub fn for_current_exe() -> io::Result<Self> {
Ok(Self::for_executable(std::env::current_exe()?))
}
pub fn for_executable(program: impl Into<PathBuf>) -> Self {
Self::new(program, vec![OsString::from("worker")])
}
/// Resolve the Worker runtime command used for subprocess launches.
///
/// The default launch path is always the current `yoi` executable plus
/// the unified `worker` prefix argument. During development, a non-empty
/// `YOI_POD_RUNTIME_COMMAND` value replaces only the executable path;
/// the `worker` prefix is still added here and the env value is not parsed as a
/// shell command.
pub fn resolve() -> io::Result<Self> {
Self::resolve_from_env_value(
std::env::var_os(POD_RUNTIME_COMMAND_ENV),
std::env::current_exe,
)
}
fn resolve_from_env_value<F>(
override_program: Option<OsString>,
current_exe: F,
) -> io::Result<Self>
where
F: FnOnce() -> io::Result<PathBuf>,
{
if let Some(program) = override_program.filter(|program| !program.as_os_str().is_empty()) {
return Ok(Self::for_executable(program));
}
Ok(Self::for_executable(current_exe()?))
}
pub fn program(&self) -> &Path {
&self.program
}
pub fn prefix_args(&self) -> &[OsString] {
&self.prefix_args
}
pub fn argv_with<I, S>(&self, args: I) -> Vec<OsString>
where
I: IntoIterator<Item = S>,
S: Into<OsString>,
{
let mut argv = self.prefix_args.clone();
argv.extend(args.into_iter().map(Into::into));
argv
}
}
impl fmt::Display for WorkerRuntimeCommand {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.program.display())?;
for arg in &self.prefix_args {
write!(f, " {}", arg.to_string_lossy())?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn yoi_binary_defaults_to_worker_prefix() {
let command = WorkerRuntimeCommand::for_executable("/opt/yoi/bin/yoi");
assert_eq!(command.program(), Path::new("/opt/yoi/bin/yoi"));
assert_eq!(command.prefix_args(), [OsString::from("worker")]);
assert_eq!(
command.argv_with(["--worker", "agent"]),
vec!["worker", "--worker", "agent"]
.into_iter()
.map(OsString::from)
.collect::<Vec<_>>()
);
}
#[test]
fn any_runtime_executable_gets_worker_prefix() {
let command = WorkerRuntimeCommand::for_executable("/opt/yoi/bin/custom-runtime");
assert_eq!(command.program(), Path::new("/opt/yoi/bin/custom-runtime"));
assert_eq!(command.prefix_args(), [OsString::from("worker")]);
assert_eq!(
command.argv_with(["--worker", "agent"]),
vec!["worker", "--worker", "agent"]
.into_iter()
.map(OsString::from)
.collect::<Vec<_>>()
);
}
#[test]
fn resolve_uses_current_exe_when_override_is_unset() {
let command = WorkerRuntimeCommand::resolve_from_env_value(None, || {
Ok(PathBuf::from("/opt/yoi/bin/yoi"))
})
.unwrap();
assert_eq!(
command,
WorkerRuntimeCommand::for_executable("/opt/yoi/bin/yoi")
);
}
#[test]
fn resolve_uses_current_exe_when_override_is_empty() {
let command = WorkerRuntimeCommand::resolve_from_env_value(Some(OsString::new()), || {
Ok(PathBuf::from("/opt/yoi/bin/yoi"))
})
.unwrap();
assert_eq!(
command,
WorkerRuntimeCommand::for_executable("/opt/yoi/bin/yoi")
);
}
#[test]
fn resolve_override_replaces_only_program_and_keeps_worker_prefix() {
let command = WorkerRuntimeCommand::resolve_from_env_value(
Some(OsString::from("/tmp/rebuilt yoi")),
|| panic!("override must not inspect current_exe"),
)
.unwrap();
assert_eq!(command.program(), Path::new("/tmp/rebuilt yoi"));
assert_eq!(command.prefix_args(), [OsString::from("worker")]);
assert_eq!(
command.argv_with(["--worker", "agent"]),
vec!["worker", "--worker", "agent"]
.into_iter()
.map(OsString::from)
.collect::<Vec<_>>()
);
}
}
+20 -17
View File
@@ -403,11 +403,10 @@ impl Tool for SubWorkerSpawnTool {
allow: scope_allow.clone(),
deny: Vec::new(),
};
let mut child_manifest =
WorkerManifest::try_from(WorkerManifestConfig::builtin_defaults().merge(child_config))
.map_err(|error| {
ToolError::ExecutionFailed(format!("resolve child manifest: {error}"))
})?;
let mut child_manifest = WorkerManifest::try_from(
WorkerManifestConfig::resolution_defaults().merge(child_config),
)
.map_err(|error| ToolError::ExecutionFailed(format!("resolve child manifest: {error}")))?;
// Delegated children stay bound to their scoped session and cannot use
// Workspace attachment tools to replace it with parent-level authority.
child_manifest.feature.manage_workdir.enabled = false;
@@ -1625,7 +1624,7 @@ max_tokens = 3333
Some(true)
);
let manifest: WorkerManifest = WorkerManifestConfig::builtin_defaults()
let manifest: WorkerManifest = WorkerManifestConfig::resolution_defaults()
.merge(parsed)
.try_into()
.unwrap();
@@ -1845,7 +1844,7 @@ max_tokens = 3333
}
#[test]
fn invalid_ambiguous_and_no_default_diagnostics_include_available_selectors() {
fn invalid_and_ambiguous_diagnostics_include_available_selectors() {
let tmp = TempDir::new().unwrap();
let project = tmp.path().join("project");
std::fs::create_dir_all(&project).unwrap();
@@ -1863,17 +1862,21 @@ max_tokens = 3333
assert!(invalid.contains("Use `default`, `inherit`"));
assert!(invalid.contains("`project:coder`"));
let default_error = build_spawn_config_json_for_profile(
&parent,
&available,
&project,
"child",
None,
&scope,
SpawnProfileSelector::Default,
let default_config: serde_json::Value = serde_json::from_str(
&build_spawn_config_json_for_profile(
&parent,
&available,
&project,
"child",
None,
&scope,
SpawnProfileSelector::Default,
)
.unwrap(),
)
.unwrap_err();
assert!(default_error.contains("no default profile is configured"));
.unwrap();
assert_eq!(default_config["feature"]["sub_worker"]["enabled"], true);
assert_eq!(default_config["feature"]["ticket"]["enabled"], false);
let user_config = tmp.path().join("user-profiles.toml");
std::fs::write(&user_config, "[profile]\ncoder = \"user-coder.toml\"\n").unwrap();
+97 -5
View File
@@ -5127,15 +5127,35 @@ where
loader: PromptCatalogSource,
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
) -> Result<Self, WorkerError> {
Self::from_manifest_with_context_and_model_client(
manifest,
store,
loader,
workspace_context,
filesystem_authority,
None,
)
.await
}
pub(crate) async fn from_manifest_with_context_and_model_client(
manifest: WorkerManifest,
store: St,
loader: PromptCatalogSource,
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
model_client: Option<Box<dyn LlmClient>>,
) -> Result<Self, WorkerError> {
validate_workspace_memory_snapshot(&manifest.worker.name, &manifest, &workspace_context)?;
let common = prepare_worker_common_with_context(
let common = prepare_worker_common_with_context_and_model_client(
&manifest,
&loader,
/* parse_template */ true,
workspace_context,
filesystem_authority,
manifest.scope.clone(),
model_client,
)?;
// Segment creation is deferred to the first run (see
@@ -5515,6 +5535,27 @@ where
loader: PromptCatalogSource,
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
) -> Result<Self, WorkerError> {
Self::restore_pending_from_worker_metadata_with_context_and_model_client(
worker_name,
fallback,
store,
loader,
workspace_context,
filesystem_authority,
None,
)
.await
}
pub(crate) async fn restore_pending_from_worker_metadata_with_context_and_model_client(
worker_name: &str,
fallback: WorkerManifest,
store: St,
loader: PromptCatalogSource,
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
model_client: Option<Box<dyn LlmClient>>,
) -> Result<Self, WorkerError> {
let metadata =
store
@@ -5535,7 +5576,7 @@ where
worker_name: worker_name.to_string(),
})?;
if let Some(segment_id) = active.segment_id {
return Self::restore_from_manifest_with_context(
return Self::restore_from_manifest_with_context_and_model_client(
active.session_id,
segment_id,
restore_manifest_from_worker_metadata_snapshot(
@@ -5547,6 +5588,7 @@ where
loader,
workspace_context,
filesystem_authority,
model_client,
)
.await;
}
@@ -5557,12 +5599,13 @@ where
})?;
let manifest =
restore_manifest_from_worker_metadata_snapshot(worker_name, Some(snapshot), fallback)?;
Self::from_manifest_with_context(
Self::from_manifest_with_context_and_model_client(
manifest,
store,
loader,
workspace_context,
filesystem_authority,
model_client,
)
.await
}
@@ -5614,6 +5657,29 @@ where
loader: PromptCatalogSource,
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
) -> Result<Self, WorkerError> {
Self::restore_from_manifest_with_context_and_model_client(
session_id,
segment_id,
manifest,
store,
loader,
workspace_context,
filesystem_authority,
None,
)
.await
}
pub(crate) async fn restore_from_manifest_with_context_and_model_client(
session_id: SessionId,
segment_id: SegmentId,
manifest: WorkerManifest,
store: St,
loader: PromptCatalogSource,
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
model_client: Option<Box<dyn LlmClient>>,
) -> Result<Self, WorkerError> {
// Read raw entries once so we can both reconstruct state and
// seed the broadcast sink's mirror with the same prefix that
@@ -5629,13 +5695,14 @@ where
let mirror_entries: Vec<LogEntry> = raw_entries.clone();
let scope_config = effective_restore_scope_config(&store, &manifest)?;
let common = prepare_worker_common_with_context(
let common = prepare_worker_common_with_context_and_model_client(
&manifest,
&loader,
/* parse_template */ false,
workspace_context,
filesystem_authority,
scope_config,
model_client,
)?;
// Atomic: register_worker inside install_top_level rejects when
@@ -6610,6 +6677,26 @@ fn prepare_worker_common_with_context(
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
scope_config: ScopeConfig,
) -> Result<WorkerCommon, WorkerError> {
prepare_worker_common_with_context_and_model_client(
manifest,
loader,
parse_template,
workspace_context,
filesystem_authority,
scope_config,
None,
)
}
fn prepare_worker_common_with_context_and_model_client(
manifest: &WorkerManifest,
loader: &PromptCatalogSource,
parse_template: bool,
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
scope_config: ScopeConfig,
model_client: Option<Box<dyn LlmClient>>,
) -> Result<WorkerCommon, WorkerError> {
let filesystem_authority = match filesystem_authority {
WorkerFilesystemAuthority::None => WorkerFilesystemAuthority::None,
@@ -6645,6 +6732,7 @@ fn prepare_worker_common_with_context(
workspace_context,
filesystem_authority,
scope,
model_client,
)
}
@@ -6655,6 +6743,7 @@ fn prepare_worker_common_from_scope(
workspace_context: WorkerWorkspaceContext,
filesystem_authority: WorkerFilesystemAuthority,
scope: Scope,
model_client: Option<Box<dyn LlmClient>>,
) -> Result<WorkerCommon, WorkerError> {
if let Some(local) = filesystem_authority.as_local() {
if !scope.is_readable(&local.root) {
@@ -6671,7 +6760,10 @@ fn prepare_worker_common_from_scope(
let delegation_scope =
DelegationScope::from_config(&manifest.delegation_scope).map_err(WorkerError::Scope)?;
let client = crate::model_client::build_client(&manifest.model)?;
let client = match model_client {
Some(client) => client,
None => crate::model_client::build_client(&manifest.model)?,
};
let prompts = Arc::new(ArcSwap::from(PromptCatalog::load(loader)?));
let system_prompt_template = if parse_template {
Some(