Skip to content

feat(agent): add ironrdp-agent CLI + daemon for agentic / LLM control#1339

Draft
Benoît Cortier (CBenoit) wants to merge 1 commit into
refactor/client-splitfrom
feat/agent
Draft

feat(agent): add ironrdp-agent CLI + daemon for agentic / LLM control#1339
Benoît Cortier (CBenoit) wants to merge 1 commit into
refactor/client-splitfrom
feat/agent

Conversation

@CBenoit
Copy link
Copy Markdown
Member

ironrdp-agent is a new headless client built on top of ironrdp-client. It's designed to be driven by an LLM or a test harness rather than a human, and is provably free of the viewer's heavy deps (cpal, native cliprdr, ironrdp-mstsgu, reqwest, winit, softbuffer).

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new ironrdp-agent crate (CLI + long-running daemon) intended for programmatic/LLM-driven control of IronRDP sessions via a custom binary IPC protocol, and adds a Windows GitHub Actions workflow + PowerShell harness to exercise an end-to-end “agentic RDP” scenario.

Changes:

  • Add ironrdp-agent daemon/client implementation with custom length-prefixed IPC framing and request/response types.
  • Add credential redaction utilities and property descriptions for dump-properties.
  • Add GitHub Actions workflow plus PowerShell scripts to automate a localhost RDP scenario and collect artifacts.

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
crates/ironrdp-agent/tests/ipc.rs Integration test for IPC framing round-trips over an in-memory duplex stream.
crates/ironrdp-agent/src/redact.rs Sensitive-key detection + value redaction and unit tests.
crates/ironrdp-agent/src/main.rs Main agent implementation: CLI client mode, daemon, session management, screenshot encoding, IPC server/client plumbing.
crates/ironrdp-agent/src/lib.rs Library crate surface for the agent modules.
crates/ironrdp-agent/src/ipc.rs Binary IPC wire format, framing helpers, and encode/decode implementations + unit tests.
crates/ironrdp-agent/src/help.rs Long-form --help-agent text describing usage and IPC model.
crates/ironrdp-agent/src/descriptions.rs Human-readable .rdp/agent:* property descriptions for dump-properties.
crates/ironrdp-agent/src/cli.rs Clap CLI argument model and .rdp payload generation for connect.
crates/ironrdp-agent/Cargo.toml New crate manifest (features, deps, bin/lib split).
Cargo.lock Lockfile update to include the new crate and dependencies.
.github/workflows/agentic-rdp.yml CI workflow to build ironrdp-agent and run the agentic RDP scenario on Windows runners.
.github/agentic-rdp/Start-InteractivePSHostServer.ps1 Registers/starts/waits for an interactive PSHostServer for GUI/interactive validation.
.github/agentic-rdp/Start-AgentDaemon.ps1 Starts the ironrdp-agent daemon for the CI scenario and writes state/log paths.
.github/agentic-rdp/Invoke-InteractiveCommand.ps1 Verifies interactive remoting by launching/closing a GUI process (Notepad).
.github/agentic-rdp/Invoke-AgenticRdpTest.ps1 Orchestrates the full scenario stages, artifacts, and cleanup.
.github/agentic-rdp/Invoke-AgenticDesktopScenario.ps1 Runs a desktop interaction scenario and validates screenshot properties.
.github/agentic-rdp/Enable-LocalRdp.ps1 Enables local RDP on the runner, creates temporary password, and restores settings on cleanup.
.github/agentic-rdp/Connect-AgentSession.ps1 Connects an RDP session via ironrdp-agent and validates negotiated framebuffer size.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +5 to +6
//! the variant, followed by a `u32` request id (for correlation), followed by
//! the variant payload.
Comment on lines +905 to +909
let mut body = vec![0u8; usize::try_from(len).context("frame length exceeds usize")?];
reader.read_exact(&mut body).await.context("read frame body")?;
let mut cursor = ReadCursor::new(&body);
let pdu = P::decode(&mut cursor).context("decode PDU")?;
Ok(pdu)
Comment on lines +924 to +931
async fn print_response(response: Response, screenshot_output: Option<PathBuf>) -> anyhow::Result<()> {
match response {
Response::Ok | Response::Health => Ok(()),
Response::Error { message } => anyhow::bail!("{message}"),
Response::Connect { session_id } => {
println!("{session_id}");
Ok(())
}
Comment on lines +754 to +760
Command::Mouse(cmd) => (
Request::Mouse {
session_id: cmd.session,
action: cli_mouse_to_ipc(cmd.action),
},
None,
),
})])
.await
}
MouseAction::Position => Ok(()),
Comment on lines +443 to +448
let server = ServerOptions::new()
.access_inbound(true)
.access_outbound(true)
.pipe_mode(PipeMode::Byte)
.create(&path)
.with_context(|| format!("failed to create named pipe {path}"))?;
Comment on lines +80 to +85
--desktop-size $DesktopSize `
--no-credssp `
--autologon `
--compression-enabled false `
--color-depth 16 `
--no-server-pointer
Comment on lines +86 to +90
$connectJson | Set-Content -Path (Join-Path $ArtifactsDir 'agent-connect.json') -Encoding utf8NoBOM

$connect = $connectJson | ConvertFrom-Json
$sessionId = [string] $connect.session_id

Comment on lines +28 to +29
$statusJson = Invoke-Agent status --session $SessionId
return ($statusJson | ConvertFrom-Json)
Comment on lines +36 to +44
function Get-SessionStatus {
param(
[Parameter(Mandatory)]
[string] $SessionId
)

$statusJson = Invoke-Agent status --session $SessionId
$statusJson | Set-Content -Path (Join-Path $ArtifactsDir 'agent-session-status.json') -Encoding utf8NoBOM
return ($statusJson | ConvertFrom-Json)
`ironrdp-agent` is a new headless client built on top of
`ironrdp-client`. It's designed to be driven by an LLM or a test harness
rather than a human, and is provably free of the viewer's heavy deps
(cpal, native cliprdr, ironrdp-mstsgu, reqwest, winit, softbuffer).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants