Turn plain-language business logic into a reusable custom model. Use custom_model_examples_template() to write worked examples of the forecasts you expect, and custom_model_control() for advanced settings.

create_custom_model(
  instructions = NULL,
  llm = NULL,
  input_data = NULL,
  run_info = NULL,
  combo_variables = NULL,
  target_variable = NULL,
  date_type = NULL,
  forecast_horizon = NULL,
  external_regressors = NULL,
  hist_start_date = NULL,
  hist_end_date = NULL,
  name = NULL,
  model_type = NULL,
  validation_examples = NULL,
  approval = "manual",
  control = NULL
)

Arguments

instructions

Nonblank business logic for the new model.

llm

An ellmer Chat object (ellmer >= 0.4.0). Generation uses a fresh empty-history clone.

input_data

Local data frame containing a column named Date of class Date, the target, series keys and declared drivers. Supply this or run_info.

run_info

Compatible prepared run that includes the raw C1 recipe, read without changes. Its metadata is inherited; explicitly supplied metadata must agree with it.

combo_variables

Series-key column names. For raw input, omission is allowed only with unique dates and no varying undeclared non-driver columns.

target_variable

Numeric target column name; required for raw input.

date_type

One of "day", "week", "month", "quarter", "year". Omission requires at least three actual dates per series matching exactly one shared complete cadence. Fiscal calendars are not inferred.

forecast_horizon

Positive integer periods to forecast; required for raw input.

external_regressors

Explicit driver column names; otherwise inherited from prepared metadata or empty. Drivers are never selected automatically.

hist_start_date, hist_end_date

Optional inclusive Date period labels. For first-of-month data, August 2026 is as.Date("2026-08-01"). Bounds select authoring history, not a permanent cutoff for later model fits.

name

Optional safe model name, preserved in the confirmed rule.

model_type

Unique subset of c("local", "global"). Defaults to local; pooled/global behavior requires explicit compatible settings.

validation_examples

Recommended data frame of two to eight independently calculated worked examples, including at least one edge case, in the format returned by custom_model_examples_template(). Its expected values, errors and tolerances are mandatory during repair.

approval

"manual" (default) or "automatic". Manual approval needs an interactive R session. Automatic explicitly authorizes generated-code execution without review.

control

Advanced settings created by custom_model_control(). Omit for defaults.

Value

An approved, passive finnts_custom_model usable by prep_models(). It embeds no fitted state, training data or Chat. Cancellation and failed gates raise errors; use custom_model_feedback() on a returned model or captured error for bounded status and next-action details.

Inputs and Validation

Every series needs finite targets on a complete common historical grid. Declared drivers must cover that history and every future forecast date. Gaps and duplicate keys fail; authoring does not fill or infer business values. Without hist_end_date, series must share their last finite target date. This does not certify business close: specify a cutoff when later rows contain partial actuals, plans or prior forecasts. Driver holdout scores are conditional on supplied values; historical plan vintages/publication lags are not verified.

Raw input is privately prepared; existing runs and Chat objects are unchanged. Prepared runs must include the raw C1 recipe; built-in transformations such as differencing, Box-Cox, outlier cleaning and multistep never alter C1. Local sampling retains up to three series or raw hierarchy leaves. Explicit global calls validate a deterministic representative sample of at most 100 series: extreme-scale, zero-heavy, negative, flattest and shortest series are always kept, multi-variable combo levels are covered when they fit, and remaining series fill in hash order. Every series still passes the full-panel input checks, and forecasting fits the authored model on the complete cohort. All paths retain at most 10000 historical node rows. Prepared hierarchies retain all nodes. Hierarchy rules must be local and univariate; forecast execution requires a mixed custom/FinnTS pool and reconciliation. New global contracts separately declare per-series, per-group or full-cohort prediction. Required peers and complete horizons are checked before prediction. The LLM still writes pooling, regression, transformations and allocation logic; portable calendar/key helpers and prompts do not choose formulas or fit models.

Approved envelopes are reusable by default: save the complete returned object with saveRDS(), read it back and supply it to later standard or Agent runs. The authoring horizon describes validation examples, not a future horizon whitelist. Each fresh fit uses its current horizon, history, cutoff and drivers. Positive whole-number horizons are supported subject to the fixed rule's history, driver-type, cadence, mode and business constraints. Finite validation cases do not prove correctness at every horizon. Same-run restarts still require unchanged inputs/settings; reuse does not advance an old fitted object.

Examples must forecast the next complete horizon immediately after their own history and include enough history for the rule. Supplied answers are never computed from the candidate or changed to make it pass. If examples are omitted, LLM-generated numerical comparisons are diagnostic: mismatches warn, while technical, required-property and coded-error checks remain mandatory. Fixed examples, chronological holdouts and fitted RDS round-trips provide evidence, not proof of arbitrary business correctness or guaranteed forecast accuracy.

Review and Execution

Manual calls show the rule, examples, candidate and execution warning, then ask Create model?. yes authorizes that exact source and conditionally approves it only if required validation passes. no, blank or EOF declines. details shows source without execution; edit requests a new candidate. Every repaired source version needs fresh consent. Noninteractive manual calls raise an error. Automatic mode skips manual review, not validation, and raises an error when essential business context is unresolved.

Generated R runs in the current session with the account's filesystem/network permissions. There is no sandbox, crash isolation or hard timeout. The elapsed validation budget is checked after evaluation returns; stuck code can require restarting R. Ordinary options, RNG, working directory and library paths are restored on normal return/error, but arbitrary global or external side effects cannot be rolled back. Syntax checks and approval receipts do not authenticate a human or make arbitrary code safe. No packages are installed by authoring.

Input instructions, including accumulated review edits, are limited to 1048576 UTF-8 bytes (1 MiB), without truncation. This accommodates thousands of words and hundreds of code lines. The selected provider's context limit still applies to instructions plus schema, examples and conversation history. Separate generated-response and reviewed-source size limits are unchanged.

Instructions, examples, source and diagnostics may be confidential. Provider calls receive instructions, schema and supplied examples, not automatically actual series values. Chat objects are never saved. Feedback is advisory and never grants consent or extra retries.

Development Artifacts

This unreleased feature supports one current creation contract. Advanced settings belong only in custom_model_control(). Older development artifacts or argument forms must be recreated, not silently migrated.

See also

Examples

# Worked examples: history rows hold the target, future rows hold the
# independently calculated expected forecast.
examples <- custom_model_examples_template(forecast_horizon = 2)
examples
#>              example       Date Target expected                             how
#> 1         last_value 2024-01-01    100       NA Repeat the last observed value.
#> 2         last_value 2024-02-01    110       NA Repeat the last observed value.
#> 3         last_value 2024-03-01    120       NA Repeat the last observed value.
#> 4         last_value 2024-04-01     NA      120 Repeat the last observed value.
#> 5         last_value 2024-05-01     NA      120 Repeat the last observed value.
#> 6  edge_zero_history 2024-01-01      0       NA  All-zero history repeats zero.
#> 7  edge_zero_history 2024-02-01      0       NA  All-zero history repeats zero.
#> 8  edge_zero_history 2024-03-01      0       NA  All-zero history repeats zero.
#> 9  edge_zero_history 2024-04-01     NA        0  All-zero history repeats zero.
#> 10 edge_zero_history 2024-05-01     NA        0  All-zero history repeats zero.
if (FALSE) { # \dontrun{
model <- create_custom_model(
  instructions = "Forecast every future period as the last observed value.",
  llm = ellmer::chat_openai(),
  input_data = data.frame(Date = seq(as.Date("2021-01-01"),
    by = "month",
    length.out = 12
  ), id = "one", value = 15),
  combo_variables = "id", target_variable = "value",
  date_type = "month", forecast_horizon = 2,
  validation_examples = examples,
  approval = "automatic",
  control = custom_model_control(package_policy = "base_only")
)
custom_model_feedback(model)
} # }