Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ summary 전에는 model call·plan commit·effect·verification 같은 redacted
strict JSON Schema response와 응답의 exact model ID를 지원하는 서버다. 설치·검증·삭제와 OS별 제약은
[시작하기](docs/getting-started.md)와 [모델 온보딩](docs/development/model-onboarding.md)을 따른다.

Unix headless `run`의 goal은 최대 65,536 UTF-8 바이트입니다. Windows는 OS command-line
한도 때문에 기존 16,384 바이트를 유지하며 도움말에도 실제 한도를 표시합니다. 호스트는 모델 호출 없는
`run --help`의 `XGENY_MAX_GOAL_BYTES=65536` 표기로 설치된 실행기의 한도를 확인할 수
있습니다. 이 표기가 없는 이전 실행기는 16,384 바이트로 취급하세요. 초과 입력은 잘라내지
않고 실행 전에 거절합니다. 모델 context·호출 예산·도구 권한은 확장하지 않으며, 대화형
REPL의 한 줄/합성 goal 한도는 기존 16 KiB를 유지합니다.

Project, Cargo dependency, Rust standard library, Linux musl과 LLVM libunwind의 배포 고지는
binary에 포함되어 있어 network나 별도 파일 없이 `xgeny licenses`로 확인할 수 있다.

Expand Down
26 changes: 25 additions & 1 deletion crates/xgeny-cli/src/composition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,13 @@ use crate::run_layout::{RunLayout, discover_state_root, generate_run_id};
const WORKSPACE_ID: &str = "primary";
const WORKSPACE_IDENTITY_PROFILE: &str = "xgeny.fs.workspace-root-identity.v1";
const DEFAULT_PLANNER_ID: &str = "xgeny.cli.openai";
const MAX_GOAL_BYTES: usize = 16 * 1024;
/// Maximum UTF-8 goal size for headless runs. Independent of the planner's
/// bounded context, model-call budget, and capability permissions.
#[cfg(not(windows))]
pub const MAX_GOAL_BYTES: usize = 64 * 1024;
/// Windows command lines have a lower OS bound; retain the legacy allowance.
#[cfg(windows)]
pub const MAX_GOAL_BYTES: usize = 16 * 1024;
const MAX_TICKS: u32 = 1_024;
const MODEL_CHECK_TIMEOUT: Duration = Duration::from_secs(10);
const LOCAL_EXECUTION_PROFILE_DOMAIN: &str = "xgeny.cli.local-execution-profile/v1";
Expand Down Expand Up @@ -2658,6 +2664,24 @@ mod tests {

use super::*;

#[test]
fn goal_bound_counts_utf8_bytes_without_truncation() {
for unit in ["a", "한", "🧪"] {
let mut goal = unit.repeat(MAX_GOAL_BYTES / unit.len());
goal.push_str(&"x".repeat(MAX_GOAL_BYTES - goal.len()));
let original = goal.clone();
assert!(validate_goal(&goal).is_ok());
assert_eq!(goal, original);
goal.push('x');
assert!(matches!(
validate_goal(&goal),
Err(PublicRunError::Configuration)
));
}
assert!(validate_goal("").is_err());
assert!(validate_goal("valid\0invalid").is_err());
}

#[test]
fn local_route_profile_gate_accepts_new_occurrences_and_legacy_resume_profiles() {
assert!(local_profile_matches_effect_kind(
Expand Down
1 change: 1 addition & 0 deletions crates/xgeny-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ struct RunArgs {
#[command(flatten)]
request_options: RequestOptionArgs,
/// Goal sent to the bounded planner.
#[arg(help = format!("Goal sent to the bounded planner. XGENY_MAX_GOAL_BYTES={}", xgeny_cli::MAX_GOAL_BYTES))]
goal: String,
/// Workspace root opened as the local filesystem capability.
#[arg(long, default_value = ".")]
Expand Down
62 changes: 62 additions & 0 deletions crates/xgeny-cli/tests/environment_onboarding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,68 @@ fn non_utf8_https_credential_is_rejected_before_any_run_state_is_created() {
assert_configuration_before_state(&output, &state);
}

#[test]
fn extended_utf8_goal_reaches_provider_intact_with_unchanged_approval_boundary() {
for unit in ["classification evidence ", "회귀 근거 🧪 "] {
let fixture = tempdir().unwrap();
let workspace = fixture.path().join("workspace");
let state = fixture.path().join("state");
fs::create_dir(&workspace).unwrap();
fs::write(workspace.join("README.md"), "fixture").unwrap();
let mut goal = unit.repeat(xgeny_cli::MAX_GOAL_BYTES / unit.len());
goal.push_str(&"x".repeat(xgeny_cli::MAX_GOAL_BYTES - goal.len()));
let server = CompletionServer::spawn();
let output = xgeny(&state)
.current_dir(&workspace)
.env("XGENY_OPENAI_BASE_URL", &server.base_url)
.env("XGENY_OPENAI_MODEL", MODEL)
.args([
"run",
"--allow-file",
"README.md",
"--allow-remote-model-egress",
&goal,
])
.output()
.unwrap();
assert_read_approval_pause(&output);
let request = server.handle.join().unwrap();
let body = request_body(&request);
assert!(body["messages"].as_array().unwrap().iter().any(|message| {
message["content"]
.as_str()
.is_some_and(|content| content.contains(&goal))
}));
}
}

#[test]
fn advertised_goal_bound_matches_validation_and_oversize_creates_no_state() {
let fixture = tempdir().unwrap();
let state = fixture.path().join("state");
let help = xgeny(&state).args(["run", "--help"]).output().unwrap();
assert!(help.status.success());
assert!(String::from_utf8(help.stdout).unwrap().contains(&format!(
"XGENY_MAX_GOAL_BYTES={}",
xgeny_cli::MAX_GOAL_BYTES
)));
let goal = "x".repeat(xgeny_cli::MAX_GOAL_BYTES + 1);
let output = xgeny(&state)
.current_dir(fixture.path())
.env("XGENY_OPENAI_BASE_URL", "http://127.0.0.1:1/v1")
.env("XGENY_OPENAI_MODEL", MODEL)
.args([
"run",
"--allow-dir",
".",
"--allow-remote-model-egress",
&goal,
])
.output()
.unwrap();
assert_configuration_before_state(&output, &state);
}

fn xgeny(state: &Path) -> Command {
let mut command = Command::new(env!("CARGO_BIN_EXE_xgeny"));
command
Expand Down