Execution model

gptr logo

Peter combines a model with your current R workspace. A language model requests tools and returns a session; a decision model returns a typed vector. peter() handles both. An inline agent can compute on a multi-GB object already loaded in R, keep intermediate variables, and reuse them across turns. This guide explains where that computation happens, what the model receives, and where memory or file transfers still occur.

One language model turn

  1. peter() captures the prompt and context expressions and selects the model and permission mode.
  2. It describes the workspace and attached objects within a token budget, then builds the request.
  3. The provider streams a reply. Each gptr tool request passes through the permission gate.
  4. R code runs in the selected environment; file and external tools use their own documented paths.
  5. Tool results return to the model until it finishes, is interrupted, or reaches a limit.
  6. The session retains the conversation, status, usage and a designated result, if there is one.

For an ordinary interactive call, start with a prompt and the data:

library(gptr)

session = peter("Fit fuel economy against weight.", mtcars)
session |> peter("Plot the fitted relationship.")

The executed example below uses a scripted fake provider. It runs offline and requests the same R code each time; its setup is hidden. An explicit environment keeps the fitted object.

work = new.env()
work$d = mtcars

session = peter("Fit fuel economy against weight.", d = work$d, model = fake,
                envir = work, mode = auto)

session$text
#> [1] "The regression is ready."
session$status
#> [1] "idle"
coef(session$value)
#> (Intercept)          wt
#>   37.285126   -5.344472

gptr_return(fit) designates fit as the result. The final model text is session$text; it does not automatically become the fitted object. The result also remains available as work$fit.

Where objects live

The default envir is the calling frame. At the console that is usually the global workspace; inside a function it is that function’s frame. Supply an environment when you want the work to persist in a particular place. Named context such as d = work$d labels an attachment; it does not create a binding called d in a different evaluation environment.

gptr_describe(work$d, budget = 60)
#> [1] "<data.frame> 32 x 11, 7 KB"
#> [2] "  mpg:dbl cyl:dbl disp:dbl hp:dbl drat:dbl wt:dbl qsec:dbl vs:dbl am:dbl gear:dbl carb:dbl"
ls(work)
#> [1] "d"   "fit"
identical(session$value, work$fit)
#> [1] TRUE

The inline r tool evaluates against those actual bindings. It does not need to write a dataset to a file or reload it before the next tool call. Attach a large object as a plain name visible in that environment; gptr captures that name without retaining another copy of the object in the conversation. An expression such as subset(d, ...) still performs ordinary R work when evaluated, and may allocate a new object.

Workspace context lists names, classes, shapes and sizes within a budget. Attached objects get compact descriptions that can include schema, sample values and summaries. The full local object remains available to R code. Printed tool output is bounded, with an output handle for long results, and captured plots can be sent as images. Those previews and results may contain data values; the permission and egress controls still apply. System 1 decisions instead send encoded input states under their own size rules; see System 1 decisions.

context = "names" reduces workspace context to names and attachments to headers; context = "none" omits both built-in workspace and attached-object descriptions. These settings leave R objects available to the tools and do not suppress prompt text, tool results or every other context block. See Configuration and Token efficiency.

Ordinary R copy-on-modify rules still apply. Modifying an object, keeping aliases, fitting a model or calling a package can allocate substantial memory. Checkpoints retain supported pre-images for undo, and workers, bridges and artifact snapshots have their own transfer or copy costs. An overlay lets reads find the parent object’s binding while keeping ordinary assignments local; it does not isolate changes to reference objects or external resources.

A continued session reuses its kept home environment unless you explicitly supply a new envir. When the default environment is a function call frame, gptr uses it during the active run and does not retain it as the session’s home afterward. An explicit working environment can retain named results. An explicit gptr_fork(session) branches the conversation and uses a workspace overlay. Restoring a session from disk restores its conversation; it does not restore all of your R objects.

Each model request has provider and transport latency. R evaluation takes the time and memory its code needs; memory pressure can slow work or make an allocation fail. A file-backed matrix, Arrow dataset or database connection may read from disk through its package even when its R handle is already loaded. Use those packages’ normal subset and compute operations rather than assuming every object is a fully resident data frame.

What the session retains

session$id
#> [1] "s44c24d5f4d"
session$model
#> [1] "fake/fake-1"
session$turns
#> [1] 1
gptr_usage(session)
#>   group        requests  input  output  cache_read  cache_write  cost
#> 1 s44c24d5f4d  2         3265   20      0           0            0
#>
#> # 1 row
#> 2 requests, 3.3k tokens in, $0.0000
Interface Use
session$text, session$value, session$status Inspect the answer, R result and state
session$messages, session$history, session$usage Inspect conversation, history and usage
session |> peter("next question") Add a turn to the same conversation
gptr_step(), gptr_wait(), gptr_steer(), gptr_cancel() Drive or control a session
gptr_sessions(), gptr_resume(), gptr_last() Find stored or live sessions
gptr_on() Attach a session event handler
gptr_fork(), gptr_checkpoints(), gptr_rewind() Branch or recover supported state

Printing session$history or summary(session) shows eight recent messages and session details without a model request. The underlying table keeps every message; unknown token counts stay unknown.

session$history
#>   turn  role         preview                   tools  tokens
#> 1 1     user         Fit fuel economy agai...         8
#> 2 1     assistant                              r      1644
#> 3 1     tool_result  + fit <lm length 12>      r      5
#> 4 1     assistant    The regression is ready.         1641
#> # 4 recorded messages
#> idle . fake/fake-1 . 1 turn . 3.3k tokens . $0.0000 . s44c24d5f4d
as.data.frame(session$history)
#>   turn        role                          preview tools tokens
#> 1    1        user Fit fuel economy against weight.            8
#> 2    1   assistant                                      r   1644
#> 3    1 tool_result             + fit <lm length 12>     r      5
#> 4    1   assistant         The regression is ready.         1641

Without an initialized project workspace, session files use a temporary directory. gptr_init() creates .gptr/ for project storage. Recording an R document is a separate choice; see Script as history.

A history document records executed code, decisions and bounded output. It does not automatically archive the full input dataset. Replay runs the recorded R procedure again; provide its input objects, packages and required files in a fresh session. Answer caches, checkpoints and artifact data snapshots are separate storage mechanisms.

Permissions and concurrency

manual is the default: actions classified as read-only can run, while changes require approval. plan is for inspection and proposals; edits allows approved classes of project file edits; auto allows ordinary tool work without prompting. Critical, secret and control guards remain separate. A permission gate is not an isolation boundary. External CLIs also have their own sandbox and tool controls; live R requests still pass through gptr’s MCP gate. Use Configuration and ?gptr_security to choose a mode and understand its limits.

HTTP requests, CLI processes, MCP connections and workers share one event loop. Multiple requests can wait for I/O together. Inline R code runs serially in the owning R process and pauses event-loop callbacks until evaluation returns. A worker is a separate R process and receives serializable context; it does not share the parent workspace. See Teams and background work.

Agent code draws from its own random-number stream, so your .Random.seed is preserved, except after a deliberate RNGkind() change or a callback R runs while idle.