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
)Nonblank business logic for the new model.
An ellmer Chat object (ellmer >= 0.4.0). Generation uses a fresh empty-history clone.
Local data frame containing a column named Date of class
Date, the target, series keys and declared drivers. Supply this or 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.
Series-key column names. For raw input, omission is allowed only with unique dates and no varying undeclared non-driver columns.
Numeric target column name; required for raw input.
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.
Positive integer periods to forecast; required for raw input.
Explicit driver column names; otherwise inherited from prepared metadata or empty. Drivers are never selected automatically.
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.
Optional safe model name, preserved in the confirmed rule.
Unique subset of c("local", "global"). Defaults to
local; pooled/global behavior requires explicit compatible settings.
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.
"manual" (default) or "automatic". Manual approval needs
an interactive R session. Automatic explicitly authorizes generated-code
execution without review.
Advanced settings created by custom_model_control(). Omit
for defaults.
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.
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.
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.
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.
custom_model_examples_template(), custom_model_control(),
custom_model_feedback(), prep_models(). See
vignette("best-model-selection", package = "finnts") for workflow examples,
automatic defaults, protocol details and model enrollment.
# 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)
} # }