Language: English | 简体中文
Standard, WEAR, and protected-data paths
codeagent has two general data-exploration experiences and a separate safe metadata path for protected data:
| Standard session | WEAR session (wear_explore()) |
Data Shield DescribeData
|
|
|---|---|---|---|
| Entry point |
codeagent_app() / codeagent_console()
|
wear_explore(data = ...) |
codeagent_client(data_shield = ...) |
| Tool |
ExploreData is registered by default |
Re-registers ExploreData for data, adds
GenerateReport
|
DescribeData for registered protected datasets |
| Model behavior | General-purpose agent | WEAR prompt requires a Next steps section | Filtered schema/metadata only; no arbitrary query code |
| Typical use | Data questions among coding tasks | Focused, stateful EDA | Discovering protected schema without exposing rows |
Rule of thumb: use wear_explore() when
exploration is the task. Use a standard session when data questions are
one part of broader work. For protected data, use Data Shield and
DescribeData; ExploreData is not a security
boundary.
Standard sessions: ExploreData is on by default
A normally constructed client registers ExploreData
unless explore_data is explicitly set to false
in settings. It reads named data.frames from .GlobalEnv by
default. Calling
register_explore_data_tool(chat, envir = ...) explicitly
remains useful to install it on a bare chat or bind it to another
environment.
library(codeagent)
client <- codeagent_client(permission_mode = "bypass", btw_groups = NULL)
register_explore_data_tool(client$chat)
codeagent(client, "How many rows are in mtcars and what are the columns?")
codeagent(client, "What is the average mpg per cylinder count?")To opt out globally or per project:
explore_data_tool(envir = .GlobalEnv) exposes three
model arguments: data_name (required),
question (optional), and code (optional).
Without code, it returns
ellmer::df_schema(df). With code, it parses
and evaluates the expression and returns a table artifact for a
data.frame or text for other results.
The tool is annotated as read-only and is currently classified as a read tool by the central permission gate, so it is allowed without prompting unless a host adds a tool override. That classification describes intended use; it is not an R sandbox guarantee. See Security and execution limits.
WEAR sessions: dedicated exploration
wear_explore(data = NULL, client = NULL, mode = c("repl", "shiny"), ...)
starts a Write/Execute/Analyze/Regroup session. The default mode is
"repl". When client is NULL, it
creates one with permission_mode = "bypass".
data = NULL uses .GlobalEnv; an environment is
used directly; another list-like value is converted with
list2env(as.list(data), parent = .GlobalEnv). Use a named
list so every data.frame has a stable tool-visible name.
The function then:
- registers
ExploreDataagainst that environment; - registers the model-callable
GenerateReporttool; - appends the WEAR system prompt if it is not already present; and
- enters
codeagent_console()orcodeagent_app().
For each user question the prompt instructs the model to:
- W — Write: generate dplyr/base R code;
-
E — Execute: call
ExploreData; - A — Analyze: interpret patterns, outliers, and unexpected findings; and
- R — Regroup: end every response with exactly three numbered suggestions under Next steps.
wear_explore(data = ...)
- resolve data into an environment
- register ExploreData for that environment
- register GenerateReport
- append the WEAR system prompt
- enter codeagent_console() or codeagent_app()
Each turn is prompted to follow W-E-A-R:
W Write model writes dplyr/base R code
E Execute ExploreData evaluates code in a new child environment
- code supplied -> table artifact or printed value
- no code -> ellmer::df_schema(df)
A Analyze model interprets the result
R Regroup model ends with "Next steps" and exactly 3 suggestions
|
v repeat until the user stops
/report -> model is instructed to call GenerateReport
# CLI session (blocks until you type /exit or Ctrl+C)
wear_explore(data = list(mtcars = mtcars))
# Shiny UI
wear_explore(
data = list(sales = sales_df, products = products_df),
mode = "shiny"
)wear_explore() invisibly returns the client after the
interactive frontend ends.
Exporting to Quarto
In a WEAR session, /report is locally recognized as the
built-in report skill. The REPL/Shiny skill path expands
that skill into a model prompt, which instructs the model to call the
registered GenerateReport tool; it does not invoke the
exporter directly in local command dispatch. Asking to save or export
the analysis should invoke the same tool. You can also call
generate_wear_report() directly.
# Capture the client to generate the report after the session ends
client <- wear_explore(data = list(mtcars = mtcars))
path <- generate_wear_report(
client,
path = "mtcars-analysis.qmd",
title = "Motor Trend Car Analysis"
)
# Render with the quarto CLI
system(paste("quarto render", path))generate_wear_report(client, path = ..., title = "Data Exploration Report")
reads the chat turns and writes YAML with code-fold: true,
toc: true, and
execute: {echo: true, eval: false}. User text becomes
## headings and assistant text becomes prose. Tool-result
text that does not begin with [ is written as a
blockquote.
The exporter writes an R code chunk only when a
ContentToolResult contains extra$code. The
current ExploreData implementation returns typed artifacts
but does not attach extra$code, so
ordinary WEAR sessions do not currently preserve the generated query
code in the .qmd. Consequently, treat the export as a
conversation report, not a fully reproducible analysis script, unless
the recorded tool results were produced by a tool that supplies
extra$code.
DescribeData for protected datasets
DescribeData is distinct from ExploreData.
It is installed by an active Data Shield when the describe strategy is
enabled, and it only describes data.frames registered on that shield. It
accepts an optional data_name; omission is allowed when
exactly one protected dataset is registered.
shield <- DataShield$new(strategies = list(
shield_describe(k_anon = 5),
shield_egress(max_rows = 0),
shield_regex(on_fail = "redact")
))
shield$register_data(mtcars, name = "cars")
client <- codeagent_client(data_shield = shield)
# The model can call DescribeData(data_name = "cars").With shield_describe() defaults
(distributions = "off", k_anon = 5,
category_max = 20, category_ratio = 0.2),
DescribeData returns filtered schema information,
sensitivity classes, missingness presence, safe numeric/date ranges, and
sufficiently supported low-cardinality labels. It returns no rows,
free-text examples, distributions, or category counts. Identifier and
quasi-identifier values are suppressed and rare labels become
<rare suppressed>.
distributions = "on" explicitly enables real
per-category counts. distributions = "dp" emits
Laplace-noised category counts and consumes the per-dataset budget
(dp_epsilon = 1, dp_budget = 5 by default),
then silently degrades to labels-only output after exhaustion.
Numeric/date summaries are unchanged by these distribution modes.
When a shield is supplied to codeagent_client(),
filtered schemas for datasets registered before client construction are
also placed in the system prompt. Building that schema block uses the
same DP describe path: in "dp" mode it consumes and
persists dp_epsilon for each eligible categorical column.
Consequently, initial prompt construction and repeated
refresh_data_shield_context(client) calls can exhaust the
dataset budget. After registering runtime uploads, call
refresh_data_shield_context(client) to refresh that prompt
context. DescribeData remains the live authoritative
fallback.
Do not register protected data only with ExploreData: it
can execute arbitrary R and can return row-level values. Data Shield
wraps tool egress and adds the protected-data metadata path, but the
shield must be configured and the dataset must be registered before
relying on those controls.
Environment context injection
This independent setting adds .GlobalEnv object names
and data.frame schemas to the first system reminder so the model knows
what exists without first calling a tool:
It does not register data with Data Shield and does not change
ExploreData execution semantics.
Security and execution limits
ExploreData evaluates model-generated R with
eval(parse(...)) in a new environment whose parent is the
supplied data environment. It binds the selected data.frame in that
child. Ordinary replacement such as df$x <- ... uses the
child binding/copy-on-modify and is tested not to change the source
data.frame.
However, this is namespace isolation, not a security
sandbox. The evaluated code can resolve functions through
parent environments and can potentially use explicit parent assignment,
mutable/reference objects, filesystem functions, process execution, or
network functions available in the R process. The tool therefore
advertises read_only_hint = FALSE,
destructive_hint = TRUE, and
open_world_hint = TRUE; these annotations are risk signals,
not enforcement. Use only with a trusted model and environment, add an
explicit permission override if required by the host, and use Data
Shield/ DescribeData rather than ExploreData
for protected data. The general RunR tool remains
separately classified as execution-capable and goes through its own
permission decision.