run container as host uid:gid, robust /stop, project paths as full agent paths
Nightly Build / build (push) Successful in 6m31s
Nightly Build / build (push) Successful in 6m31s
This commit is contained in:
@@ -1,34 +1,70 @@
|
||||
use crate::db::projects::Project;
|
||||
use crate::run_context::RunContext;
|
||||
|
||||
/// Builds the runtime `RunContext` for working on `project`, layering the project's
|
||||
/// working directory + a context header over an optional pre-resolved `base` RC (which
|
||||
/// carries static config set at creation time, e.g. `security_group`).
|
||||
/// A project member's display info for the system-prompt block.
|
||||
///
|
||||
/// `working_directory` is the **agent path** `projects/{owner_username}/{slug}` — the
|
||||
/// same namespace the fs-tools and `execute_cmd` route through (the host/container
|
||||
/// mapping is handled by `UserFs`). Writes there are auto-allowed by the seeded
|
||||
/// `projects/*` approval rule and physically gated by the per-member read-only mount,
|
||||
/// so no host-path `allow_fs_writes` grant is needed (that was the old single-user
|
||||
/// model, which predated per-user containers).
|
||||
pub fn build_runtime_run_context(
|
||||
/// The display name is what the user usually goes by (fallback to the username);
|
||||
/// the username is the unique handle. Both are shown so the agent can refer to a
|
||||
/// member either way the user does in conversation.
|
||||
pub struct ProjectMemberView {
|
||||
pub display_name: String,
|
||||
pub username: String,
|
||||
}
|
||||
|
||||
/// Builds the runtime `RunContext` for working on `project`, layering a project
|
||||
/// context block over an optional pre-resolved `base` RC (which carries static
|
||||
/// config set at creation time, e.g. `security_group`).
|
||||
///
|
||||
/// The session working directory is **always** the user's home (`~`); project
|
||||
/// files are referenced by their absolute agent path `projects/{owner}/{slug}`,
|
||||
/// which `UserFs` routes to the per-member bind mount. This keeps the working
|
||||
/// directory stable across sessions (so MCP servers running in the container see
|
||||
/// a consistent cwd) and avoids silent path rewriting inside tool calls.
|
||||
///
|
||||
/// Writes under `projects/*` are auto-allowed by the seeded approval rule and
|
||||
/// physically gated by the per-member read-only mount, so no host-path
|
||||
/// `allow_fs_writes` grant is needed.
|
||||
pub fn build_project_run_context(
|
||||
project: &Project,
|
||||
owner_username: &str,
|
||||
members: &[ProjectMemberView],
|
||||
base: Option<RunContext>,
|
||||
) -> RunContext {
|
||||
let mut rc = base.unwrap_or_default();
|
||||
|
||||
rc.working_directory = Some(format!("projects/{owner_username}/{}", project.slug));
|
||||
let project_path = format!("projects/{owner_username}/{}", project.slug);
|
||||
rc.project_root = Some(project_path.clone());
|
||||
|
||||
let project_header = if project.description.is_empty() {
|
||||
format!("You are working on project \"{}\".", project.name)
|
||||
let mut block = vec![
|
||||
format!("You are working on project \"{}\".", project.name),
|
||||
format!("Project folder: {project_path}"),
|
||||
];
|
||||
if !project.description.is_empty() {
|
||||
block.insert(1, format!("Description: {}", project.description));
|
||||
}
|
||||
// Sharing line: list members other than the owner, or note the project is private.
|
||||
// The owner is implicit (they are the user the agent is talking to), so they are
|
||||
// excluded from the list. Display name first, username in parentheses.
|
||||
let others: Vec<String> = members
|
||||
.iter()
|
||||
.filter(|m| m.username != owner_username)
|
||||
.map(|m| {
|
||||
if m.display_name.is_empty() || m.display_name == m.username {
|
||||
m.username.clone()
|
||||
} else {
|
||||
format!("{} ({})", m.display_name, m.username)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let sharing = if others.is_empty() {
|
||||
"Shared with: not shared with anyone yet.".to_string()
|
||||
} else {
|
||||
format!(
|
||||
"You are working on project \"{}\". Description: {}",
|
||||
project.name, project.description
|
||||
)
|
||||
format!("Shared with: {}.", others.join(", "))
|
||||
};
|
||||
let mut injected = vec![project_header];
|
||||
block.push(sharing);
|
||||
|
||||
// Prepend the project block to any existing system_prompt fragments.
|
||||
let mut injected = block;
|
||||
injected.extend(std::mem::take(&mut rc.system_prompt));
|
||||
rc.system_prompt = injected;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user