gptr runs a language model agent
inside your R session. It computes on objects you already loaded and
keeps named results available for the next iteration. A dataset around 4
GB can stay in R while the model sees a bounded description and the
results its tools report. You can revise one analysis step without
exporting and reloading the dataset for each turn. The same function,
peter(), is an interactive chat at the console and a
programmable call in scripts, loops and if statements.
Names, shapes, previews, printed results and plots can reach the provider. R memory, copies and calculation time still matter, as does each model request’s latency. The execution guide explains those boundaries; the examples here use only small objects.
Peter’s name commemorates Peter Naur and Peter Cathcart Wason. The Why Peter? guide connects their work on programs and reasoning to gptr.
This vignette runs without a network connection or a key. Every call
uses gptr_fake_provider(), a scripted model that ships with
the package, so the output is reproducible. Start with this example
before connecting an API, subscription command-line tool or local Ollama
model through the language-model
guide.
A fake provider plays a script in which each element is one model
reply. A reply can call a tool: the r tool runs R code in
the environment you give to peter().
library(gptr)
fake = gptr_fake_provider(list(
list(tool = "r", input = list(code = paste(
"fit = lm(mpg ~ wt, data = cars)", "gptr_return(coef(fit))", sep = "\n"
))),
"Each additional 1000 lb of weight lowers fuel economy by about 5.3 miles per gallon.",
list(tool = "r", input = list(code = "predicted = predict(fit)\ngptr_return(head(predicted))")),
"The first six predictions are ready."
))
work = new.env()
work$cars = mtcars
s = peter("Fit mpg on wt in cars and return the coefficients.", cars = work$cars,
model = fake, envir = work, mode = auto)
s$text
#> [1] "Each additional 1000 lb of weight lowers fuel economy by about 5.3 miles per gallon."
s$value
#> (Intercept) wt
#> 37.285126 -5.344472Prompts are always quoted strings. Identifiers such as the mode can
be bare names, the way library(gptr) needs no quotes:
mode = auto and mode = "auto" are the same.
The auto mode lets ordinary agent actions run without
asking, while retaining the critical and secret guards. This vignette
needs it because nobody is there to answer. At the console the default
mode, manual, asks before changes unless a permission rule
already allows them. The fake provider supplies the tool code
explicitly; a real model chooses its own code from the prompt.
s$text is the final answer, and s$value is
the value the tool selected with gptr_return(). The object
the agent created is in work, like any object you created
yourself:
Reuse that fitted object in the next turn. No data file or repeated fit is needed:
s |> peter("Reuse fit to predict mpg and return the first six predictions.")
#> The first six predictions are ready.
#> idle . fake/fake-1 . 2 turns . 6.6k tokens . $0.0000 . s9e10ebe7d9
s$value
#> Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive
#> 23.28261 21.91977 24.88595 20.10265
#> Hornet Sportabout Valiant
#> 18.90014 18.79325
head(work$predicted)
#> Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive
#> 23.28261 21.91977 24.88595 20.10265
#> Hornet Sportabout Valiant
#> 18.90014 18.79325peter() returned a session object. It holds the
conversation, the model, the status and the token usage:
Piping a session into peter() adds a turn to the same
session: the same history, the same model and the same workspace. This
continuation does not duplicate the dataset; ordinary R code can still
allocate copies when it modifies objects or computes new results.
fake2 = gptr_fake_provider(list(
list(tool = "r", input = list(code = "cyl_mpg = tapply(cars$mpg, cars$cyl, mean)")),
"The mean fuel economy per number of cylinders is stored in `cyl_mpg`.",
"Four-cylinder cars are the most economical, at about 26.7 miles per gallon.",
"Four."
))
s2 = peter("Compute the mean mpg for each number of cylinders.", model = fake2, envir = work,
mode = auto)
s3 = s2 |> peter("Which group is the most economical?")
identical(s2, s3)
#> [1] TRUE
s2$turns
#> [1] 2
s2$text
#> [1] "Four-cylinder cars are the most economical, at about 26.7 miles per gallon."A branch is always explicit. gptr_fork() copies the
conversation into a new session whose workspace sees the original
objects without copying them and keeps its own changes:
branch = gptr_fork(s2)
branch |> peter("Answer in one word.")
#> Four.
#> idle . fake/fake-1 . 3 turns . 1.7k tokens . $0.0000 . sda7d4cca6a
c(original = s2$turns, branch = branch$turns)
#> original branch
#> 2 3The overlay separates ordinary bindings, rather than making a full data snapshot. Reference objects and arbitrary side effects require their usual care; see the execution guide.
In manual mode a change needs approval unless an allow
rule already permits it. When nobody can answer (an Rscript
job, a knitted report), the run stops with a classed condition that says
how to allow the action:
careful = gptr_fake_provider(list(
list(tool = "r", input = list(code = "mtcars$kpl = mtcars$mpg * 0.425")),
"Added the column kpl."
))
res = tryCatch(
peter("Add fuel economy in km per liter to mtcars.", model = careful, envir = new.env(),
mode = manual),
gptr_error_permission = function(e) e
)
class(res)[1]
#> [1] "gptr_error_permission"
res$session$status
#> [1] "blocked"mode = plan inspects and proposes while preserving the
user workspace; level-1 R exploration can create intermediate objects in
its scratch environment. mode = edits allows file edits
inside the project, and gptr_permissions() adds rules such
as "r(level<=1)" that allow low-risk code without a
question.
Called without a prompt in an interactive console,
peter() opens a chat. Piping a session into it continues
that session, and /exit returns the session. Inside chat,
/help lists commands, @name attaches an object
and !code runs your own R immediately. The console guide explains input syntax,
permissions and interrupts.
Choose a route explicitly. API providers use their named environment
variables, which you can load from a private file with
gptr_env(). Subscription CLI routes use the executable’s
own sign-in; Ollama uses an already-running local server and an
installed model. The language-model
guide gives setup examples for each route.
gptr_env("~/keys/.env")
gptr_providers()
gptr_models(provider = "openai")
gptr_config(model = "openai/gpt-6-sol", .scope = "user")
res = peter("Describe the mpg and wt columns.", mtcars)
res$textThe first time a provider is used interactively, gptr shows what is
sent to it and records your acknowledgment; ?gptr_egress
lists what a request contains. For persistent storage, call
gptr_init("/path/to/project") to create a
.gptr/ workspace and review its separate trust decision.
Without a project workspace, session storage is temporary. Defaults and
storage policy are covered in the configuration guide.
if, for and while.?gptr_security, ?gptr_egress and
?gptr_options.