Manages the Copilot CLI subprocess in ACP (Agent Client Protocol) mode and handles JSON-RPC 2.0 communication over NDJSON stdio. This is the low-level transport layer – most users should use HalChat instead.
The client spawns the Copilot CLI with --acp, which starts it as a
JSON-RPC server. Authentication uses ambient Copilot credentials from
any editor (VS Code, Positron, JetBrains).
Value
An R6 object of class HalClient. Methods return
values as documented per method; construct with HalClient$new().
See also
HalChat for the high-level chat interface,
hal_available() to check CLI availability.
Methods
HalClient$new()
Create a new Copilot SDK client.
Usage
HalClient$new(
model = NULL,
cli_path = NULL,
permission_policy = "auto-allow",
on_text = NULL,
on_tool_call = NULL,
on_thought = NULL,
quiet = FALSE
)Arguments
modelModel identifier (e.g.,
"claude-sonnet-5","gpt-5.2"). Passed as--modelto the CLI at startup. IfNULL, falls back to theCOPILOT_MODELenvironment variable, then the server default.cli_pathPath to the Copilot CLI binary. If
NULL, searchesPATHand common install locations.permission_policyHow to handle tool permission requests:
"auto-allow"(default) auto-approves all,"auto-deny"auto-denies, or a function receiving the permission params and returning an option ID.on_textCallback function receiving each text chunk as it streams. Signature:
function(chunk). Called for eachagent_message_chunk.on_tool_callCallback function receiving tool call events. Signature:
function(tool_call). Called ontool_callandtool_call_updateevents with ahal_tool_callobject.on_thoughtCallback function receiving thought chunks. Signature:
function(chunk). Called for eachagent_thought_chunk.quietLogical; suppress informational messages during init, handshake, and session creation (default: FALSE).
HalClient$register_tools()
Register tools to expose via MCP server.
Tools must be registered before the first $prompt() call (before the
CLI subprocess starts). The tools are passed via --additional-mcp-config
at startup. Registering tools after the CLI is running triggers a warning.
Tools are merged into the existing set by name. Call multiple times to accumulate tools from different sources.
HalClient$handshake()
Perform the ACP initialize handshake.
Sends the initialize request and initialized notification.
Called automatically on first use if needed.
HalClient$new_session()
Create a new ACP session.
Sends session/new to create a session. The session holds conversation
state server-side. Automatically performs the handshake if needed.
Custom tools are configured via --additional-mcp-config at CLI startup
(not via mcpServers in this call, which is broken per CLI issue #1040).
Usage
HalClient$new_session(cwd = getwd(), timeout = 15)HalClient$prompt()
Send a prompt and collect the streamed response.
Sends session/prompt and reads session/update notifications until
the final response arrives. Automatically creates a session if needed.
HalClient$request()
Send a JSON-RPC request and wait for a response.
Usage
HalClient$request(method, params = list(), timeout = 60)HalClient$notify()
Send a JSON-RPC notification (no response expected).
Usage
HalClient$notify(method, params = list())HalClient$switch_model()
Switch models mid-session.
Changes the active model without losing conversation context.
Use hal_models() to see available model IDs.
HalClient$set_mode()
Set the session mode.
Switches between Agent, Plan, and Autopilot modes.
Agent: Default conversational mode.
Plan: Multi-step planning mode with structured output.
Autopilot: Autonomous mode that runs until task completion without user interaction (experimental).
Usage
HalClient$set_mode(mode = c("agent", "plan", "autopilot"), timeout = 10)HalClient$swap_session()
Create a temporary new session, saving the current one.
Used internally by disposable verbs (hal_ask) to get history isolation
on the same CLI process. Call restore_session() to switch back.
HalClient$cancel()
Cancel the current in-flight prompt.
Signals the streaming loop to stop and return a partial response with
stop_reason = "interrupted". Safe to call from callbacks, Shiny
observers, or a second thread. Does nothing if no prompt is active.
For interactive use, pressing Ctrl+C (ESC in RStudio) during a prompt achieves the same effect automatically.
HalClient$set_ipc()
Configure IPC for live eval_r execution.
When set, the polling loop checks for eval_r requests from the MCP
subprocess and executes them in the user's R session via eval_fn.
Arguments
ipc_dirPath to the IPC directory for request/response files.
eval_fnFunction taking a code string and returning
list(result = "...", error = NULL)orlist(result = NULL, error = "...").permission_fnOptional handler for permission requests (used by the Claude permission_prompt bridge). Takes the parsed request object and returns the same
list(result, error)shape aseval_fn.
Examples
if (FALSE) { # \dontrun{
# Preferred: use hal_client()
client <- hal_client()
client$handshake()
session <- client$new_session()
client$stop()
} # }
