The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Extending gptr

gptr logo

Add a tool, a policy or a hook when an existing capability needs a small change. These features, providers, commands and prompt sections share the extension registry with gptr’s built-ins. gptr_api()$features lists the supported extension kinds and services.

For reusable instructions and packaged extensions, see Skills and plugins. For existing helpers, see Tools and artifacts; choose a model in Language models. The displayed responses below are scripted offline, so building this guide needs no credentials or network.

library(gptr)
gptr_api()$version
#> [1] '1.0'
head(grep("^kind[.]", gptr_api()$features, value = TRUE))
#> [1] "kind.adapter"       "kind.agent"         "kind.artifact_type"
#> [4] "kind.backend"       "kind.cache_policy"  "kind.checkpointer"

A tool the model calls as an R function

Most capabilities are members of the peter$ namespace rather than separate model-visible tools: the model calls them from R code, which costs a few tokens per tool instead of a full schema. gptr_check() runs the conformance checks on a spec before you register it.

add_tool = gptr_tool(
  "add", "Add two numbers",
  parameters = list(
    type = "object", required = I(c("a", "b")),
    properties = list(a = list(type = "number"), b = list(type = "number"))
  ),
  fun = function(a, b) a + b,
  exposure = "r", namespace = "demo"
)
gptr_check(add_tool)
#> <gptr_check> 4 check(s), 0 failed
#>   ok    tool:add  spec.class
#>   ok    tool:add  spec.fields
#>   ok    tool:add  tool.schema
#>   ok    tool:add  tool.empty_input: empty input fails schema validation before execute()
off_tool = gptr_register(add_tool)
peter$demo$add(2, 3)
#> [1] 5

Ask Peter to use it:

session = peter("Add 40 and 2 with the demo tool.")
session$text
#> [1] "The sum is 42."
off_tool()

gptr_register() returns a function that unregisters the record. To add a tool to one session only, pass it as peter(..., tools = list(add_tool)).

exposure = "r" makes a callable peter$demo$add() member. A "direct" tool goes into the model’s tool declarations; give it an execute = function(input, ctx) handler. A "deferred" tool is found through peter$search(), while "hidden" omits it from the model’s catalog. An R package’s tools should use the package name as their namespace. Use peter$help("demo/add") to inspect a registered member’s schema.

An R helper runs in the current R process and can compute on already-loaded objects without a file export. Its allocations follow ordinary R rules; an external backend may need its own serialization. See Execution model for these boundaries.

Choose execution = "sequential" for handlers that evaluate R or change files. A tool’s risk = function(input, ctx) classifies its actions; its result still passes the active permission policies. A custom tool does not grant permission to run its own side effects.

A permission policy

A policy sees every tool call before it runs and can deny, ask, modify or allow it. The strictest answer of all policies wins, and a policy that throws an error denies.

keep_data = gptr_policy("keep_data", check = function(call, ctx) {
  if (identical(call$name, "r") && grepl("rm(", call$input$code, fixed = TRUE)) {
    list(decision = "deny", reason = "removing objects is not allowed in this session")
  } else {
    NULL
  }
})
off_policy = gptr_register(keep_data)
session = peter("Remove the session's objects.", envir = new.env(), mode = auto)
session$text

The offline example requests rm(list = ls()), which this policy denies:

#> [1] "I was not allowed to remove the objects."
off_policy()

The denial reached the model as an error result, even in auto mode. This text match illustrates the callback; it is not a general R code security filter. See Configuration for modes, trust and permission rules.

A hook on a session

gptr_on() attaches a handler to one session’s events; gptr_hook() specs registered with gptr_register() apply to every session.

This example uses an offline provider so the event sequence is reproducible:

fake = gptr_fake_provider(list("hello"))
session = peter("Say hello.", model = fake, .run = FALSE)
seen = new.env()
seen$roles = character()
off_hook = gptr_on(session, "message_end", function(event, ctx) {
  seen$roles = c(seen$roles, event$message$role)
  NULL
})
gptr_step(session)
off_hook()
seen$roles
#> [1] "user"      "assistant"

Prompt sections, context blocks and commands

A prompt section adds text to the system prompt of new sessions; a context block adds data to the first message or to every turn; a command adds a slash command to the console.

rules = gptr_prompt_section(
  "house_rules", "Report every quantity with its unit.", tier = "T1", order = 780L
)
notebook = gptr_context_block(
  "lab_notebook", function(ctx, budget) "Experiment 12: cohort B.",
  placement = "first", order = 650L
)
rows = gptr_command(
  "rows", function(args, ctx) paste("rows:", nrow(mtcars)),
  description = "Show the rows of mtcars"
)
offs = lapply(list(rules, notebook, rows), gptr_register)
reg = gptr_registry(c("prompt_section", "context_block", "command"))
reg[reg$name %in% c("house_rules", "lab_notebook", "rows"), c("kind", "name", "source")]
#> <gptr_registry> 3 record(s)
#>            kind         name source
#>  prompt_section  house_rules   user
#>   context_block lab_notebook   user
#>         command         rows   user
for (off in offs) off()

gptr_prompt() shows what a new session would freeze, section by section, with token estimates. The command’s optional complete callback is metadata for frontend integrations; the built-in console does not currently invoke it for Tab completion.

Other kinds

The eleven exported constructors cover the common kinds: gptr_tool(), gptr_provider(), gptr_adapter(), gptr_router(), gptr_hook(), gptr_policy(), gptr_agent(), gptr_command(), gptr_prompt_section(), gptr_context_block() and gptr_backend(). Every other kind uses gptr_spec():

gptr_spec("env_alias", "SLACK_BOT_TOKEN", aliases = "slack-token")
#> <gptr_env_alias SLACK_BOT_TOKEN>
#>   aliases: slack-token
#>   api_version: 1.0

A provider for an OpenAI-compatible endpoint is data:

gptr_register(gptr_provider(
  "corp", api = "openai-completions",
  base_url = "https://llm.corp.example/v1", auth = "CORP_LLM_KEY",
  models = list(list(id = "corp-large", context = 128000))
))
peter("Summarize this table.", mtcars, model = "corp/corp-large")

Extensions and plugins

An extension is a function of the extension API object. It registers records with gptr$register() and can be passed to one call with extensions =, or saved in .gptr/extensions/ of a trusted project.

lab_rules = function(gptr) {
  gptr$register(gptr_prompt_section(
    "lab_rules", "Report concentrations in mmol/L.", tier = "T1", order = 790L
  ))
}
peter("Summarize the assay results.", assay, extensions = lab_rules)

In an extension file, the last expression must be this factory function. Review the whole file: earlier expressions are evaluated when it loads. The API object has $register(spec), $on(event, handler, matcher = NULL), $require(">= 1.0, < 2") and $has(feature), along with plugin-local $state. Check a factory with gptr_check(lab_rules) before enabling it.

Use gptr_registry(kind = NULL, diagnostics = FALSE) to inspect records, or gptr_registry(diagnostics = TRUE) to see validation and collision messages. For the same kind and name, session records win over trusted project records, user records, plugins and built-ins, in that order. A tie keeps the first registration and reports a collision. Additive kinds such as hooks keep multiple records. Removing a user record exposes the next matching record.

gptr_reload() rereads configuration and extensions for later use; existing sessions keep their frozen prompt. Plugin manifests, activation and compatibility are covered in Skills and plugins.

Packages can teach gptr about their classes through methods for gptr_describe() (compact object descriptions) and gptr_preimage() (undo support). These are separate from a tool registration.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.