Skip to content
Open
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
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ version-compare = "0.1"
vte = { git = "https://github.com/warpdotdev/vte.git", rev = "4b399c87b63ba88f45709edaa6383fc519f6c900", default-features = false }
walkdir = "2"
warp-workflows = { git = "https://github.com/warpdotdev/workflows", rev = "793a98ddda6ef19682aed66364faebd2829f0e01" }
warp_multi_agent_api = { git = "https://github.com/warpdotdev/warp-proto-apis.git", rev = "3d26f166b74469d5c12080ef6a3423fadee4d0e3" }
warp_multi_agent_api = { git = "https://github.com/warpdotdev/warp-proto-apis.git", rev = "4f566de018be84b36d1dc9a86c6916ec2a9b7823" }
wasm-bindgen = "0.2.89"
wasm-bindgen-futures = "0.4.42"
web-sys = { version = "0.3.69", features = [
Expand Down
5 changes: 4 additions & 1 deletion app/src/ai/agent/api/convert_to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -804,19 +804,21 @@ fn convert_context(context: &[AIAgentContext]) -> api::InputContext {
api_git_context.head = head;
api_git_context.branch = branch.unwrap_or_default();
}
AIAgentContext::Repository { name, owner } => {
AIAgentContext::Repository { name, owner, host } => {
let api_git_context =
git_context.get_or_insert_with(api::input_context::Git::default);
api_git_context.repository = Some(api::input_context::git::Repository {
name,
owner: owner.unwrap_or_default(),
host: host.unwrap_or_default(),
});
}
AIAgentContext::PullRequest {
number,
state,
draft,
base_branch,
url,
} => {
if number <= 0 {
continue;
Expand All @@ -828,6 +830,7 @@ fn convert_context(context: &[AIAgentContext]) -> api::InputContext {
number,
state: state as i32,
base_branch,
url,
};
let api_git_context =
git_context.get_or_insert_with(api::input_context::Git::default);
Expand Down
9 changes: 9 additions & 0 deletions app/src/ai/agent/api/convert_to_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ fn git_context_converts_repository_and_pull_request_metadata() {
AIAgentContext::Repository {
name: "warp-internal".to_string(),
owner: Some("warpdotdev".to_string()),
host: Some("github.com".to_string()),
},
AIAgentContext::PullRequest {
number: 42,
state: "OPEN".to_string(),
draft: true,
base_branch: "main".to_string(),
url: "https://github.com/warpdotdev/warp-internal/pull/42".to_string(),
},
];

Expand All @@ -36,6 +38,7 @@ fn git_context_converts_repository_and_pull_request_metadata() {
let repository = git.repository.expect("expected repository context");
assert_eq!(repository.name, "warp-internal");
assert_eq!(repository.owner, "warpdotdev");
assert_eq!(repository.host, "github.com");

let pull_request = git.pull_request.expect("expected pull request context");
assert_eq!(pull_request.number, 42);
Expand All @@ -44,6 +47,10 @@ fn git_context_converts_repository_and_pull_request_metadata() {
api::input_context::git::pull_request::State::OpenDraft as i32
);
assert_eq!(pull_request.base_branch, "main");
assert_eq!(
pull_request.url,
"https://github.com/warpdotdev/warp-internal/pull/42"
);
}

#[test]
Expand All @@ -59,6 +66,7 @@ fn git_context_skips_pull_request_metadata_with_invalid_number() {
state: "OPEN".to_string(),
draft: false,
base_branch: "main".to_string(),
url: "https://github.com/warpdotdev/warp-internal/pull/1".to_string(),
},
];

Expand All @@ -82,6 +90,7 @@ fn git_context_skips_pull_request_metadata_with_unknown_state() {
state: "SOMETHING_ELSE".to_string(),
draft: false,
base_branch: "main".to_string(),
url: "https://github.com/warpdotdev/warp-internal/pull/42".to_string(),
},
];

Expand Down
1 change: 1 addition & 0 deletions app/src/ai/agent/conversation_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ fn start_recording_tool_call() -> api::message::tool_call::Tool {
summary: String::new(),
playback_speed_multiplier: 0,
target: None,
description: String::new(),
})
}

Expand Down
5 changes: 5 additions & 0 deletions app/src/ai/agent/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2252,6 +2252,8 @@ pub enum AIAgentContext {
name: String,
/// The repository owner/organization (e.g. "warpdotdev"), if determinable from the remote URL.
owner: Option<String>,
/// The repository host (e.g. "github.com"), if determinable from the remote URL.
host: Option<String>,
},

/// Information about the GitHub pull request associated with the current branch.
Expand All @@ -2268,6 +2270,9 @@ pub enum AIAgentContext {
/// The pull request's base branch.
#[serde(default)]
base_branch: String,
/// The full URL of the pull request (e.g. "https://github.com/owner/repo/pull/123").
#[serde(default)]
url: String,
},

/// List of available skills is provided to the agent during initialization
Expand Down
2 changes: 2 additions & 0 deletions app/src/ai/blocklist/context_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,7 @@ impl BlocklistAIContextModel {
AIAgentContext::Repository {
name: repository_info.name.clone(),
owner: repository_info.owner.clone(),
host: repository_info.host.clone(),
}
}

Expand All @@ -846,6 +847,7 @@ impl BlocklistAIContextModel {
state: pr_info.state.clone(),
draft: pr_info.draft,
base_branch: pr_info.base_branch.clone(),
url: pr_info.url.clone(),
})
}

Expand Down
8 changes: 7 additions & 1 deletion app/src/ai/blocklist/context_model_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ fn repository_context_reads_github_repo_model() {
Some(RepositoryInfo {
name: "warp-internal".to_owned(),
owner: Some("warpdotdev".to_owned()),
host: Some("github.com".to_owned()),
}),
ctx,
);
Expand All @@ -205,6 +206,7 @@ fn repository_context_reads_github_repo_model() {
Some(AIAgentContext::Repository {
name: "warp-internal".to_owned(),
owner: Some("warpdotdev".to_owned()),
host: Some("github.com".to_owned()),
})
);
});
Expand Down Expand Up @@ -382,19 +384,21 @@ fn repository_context_from_repository_info_converts_to_agent_context() {
let repository_info = RepositoryInfo {
name: "warp-internal".to_owned(),
owner: Some("warpdotdev".to_owned()),
host: Some("github.com".to_owned()),
};

assert_eq!(
BlocklistAIContextModel::repository_context_from_repository_info(&repository_info),
AIAgentContext::Repository {
name: "warp-internal".to_owned(),
owner: Some("warpdotdev".to_owned()),
host: Some("github.com".to_owned()),
}
);
}

#[test]
fn pull_request_context_from_pr_info_excludes_url() {
fn pull_request_context_from_pr_info_includes_url() {
let pr_info = PrInfo {
number: 123,
url: "https://github.com/warpdotdev/warp/pull/123".to_owned(),
Expand All @@ -410,6 +414,7 @@ fn pull_request_context_from_pr_info_excludes_url() {
state: "OPEN".to_owned(),
draft: true,
base_branch: "main".to_owned(),
url: "https://github.com/warpdotdev/warp/pull/123".to_owned(),
})
);
}
Expand Down Expand Up @@ -475,6 +480,7 @@ fn pull_request_context_reads_github_repo_model() {
state: "OPEN".to_owned(),
draft: false,
base_branch: "main".to_owned(),
url: "https://github.com/warpdotdev/warp/pull/123".to_owned(),
})
);
});
Expand Down
1 change: 1 addition & 0 deletions app/src/code_review/github_repo_model/local_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ fn repository_info() -> RepositoryInfo {
RepositoryInfo {
name: "warp".to_string(),
owner: Some("warpdotdev".to_string()),
host: Some("github.com".to_string()),
}
}

Expand Down
2 changes: 2 additions & 0 deletions app/src/remote_server/git_status_proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ impl From<&proto::RepositoryInfo> for RepositoryInfo {
RepositoryInfo {
name: info.name.clone(),
owner: info.owner.clone(),
host: info.host.clone(),
}
}
}
Expand All @@ -27,6 +28,7 @@ impl From<&RepositoryInfo> for proto::RepositoryInfo {
proto::RepositoryInfo {
name: info.name.clone(),
owner: info.owner.clone(),
host: info.host.clone(),
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion app/src/util/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,8 @@ pub struct PrInfo {
pub struct RepositoryInfo {
pub name: String,
pub owner: Option<String>,
/// The repository host (e.g. "github.com"), parsed from the repo URL.
pub host: Option<String>,
}

#[cfg(feature = "local_fs")]
Expand All @@ -753,9 +755,15 @@ fn repository_info_from_gh_output(output: &str) -> Result<RepositoryInfo> {
.filter(|owner| !owner.is_empty())
.ok_or_else(|| anyhow!("Missing 'owner.login' in gh output"))?
.to_string();
// The host is best-effort: parsed from the repo URL when present.
let host = parsed["url"]
.as_str()
.and_then(|u| url::Url::parse(u).ok())
.and_then(|u| u.host_str().map(|host| host.to_string()));
Ok(RepositoryInfo {
name,
owner: Some(owner),
host,
})
}

Expand All @@ -773,7 +781,7 @@ pub async fn get_repository_info(

match run_gh_command(
repo_path,
&["repo", "view", "--json", "name,owner"],
&["repo", "view", "--json", "name,owner,url"],
path_env,
)
.await
Expand Down
19 changes: 19 additions & 0 deletions app/src/util/git_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ async fn git(repo: &Path, args: &[&str]) -> String {
#[cfg(feature = "local_fs")]
#[test]
fn repository_info_from_gh_output_parses_name_and_owner() {
// No url in the output => host is absent.
assert_eq!(
super::repository_info_from_gh_output(
r#"{"name":"warp-internal","owner":{"login":"warpdotdev"}}"#
Expand All @@ -33,6 +34,23 @@ fn repository_info_from_gh_output_parses_name_and_owner() {
RepositoryInfo {
name: "warp-internal".to_owned(),
owner: Some("warpdotdev".to_owned()),
host: None,
}
);
}

#[cfg(feature = "local_fs")]
#[test]
fn repository_info_from_gh_output_parses_host_from_url() {
assert_eq!(
super::repository_info_from_gh_output(
r#"{"name":"warp-internal","owner":{"login":"warpdotdev"},"url":"https://github.com/warpdotdev/warp-internal"}"#
)
.unwrap(),
RepositoryInfo {
name: "warp-internal".to_owned(),
owner: Some("warpdotdev".to_owned()),
host: Some("github.com".to_owned()),
}
);
}
Expand Down Expand Up @@ -146,6 +164,7 @@ async fn get_repository_info_reads_gh_repo_view() {
Some(RepositoryInfo {
name: "warp-internal".to_owned(),
owner: Some("warpdotdev".to_owned()),
host: None,
})
);
}
Expand Down
1 change: 1 addition & 0 deletions crates/ai/src/agent/action/convert_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ fn start_recording(
summary: String::new(),
playback_speed_multiplier: 0,
target,
description: String::new(),
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/remote_server/proto/diff_state.proto
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ message GitGenerateCommitMessageResponse {
message RepositoryInfo {
string name = 1;
optional string owner = 2;
// The repository host (e.g. "github.com"), parsed from the repo URL.
optional string host = 3;
}

// Mirrors GitStatusMetadata in Rust (code_review/git_repo_model/mod.rs).
Expand Down
Loading