Skip to contents

rlmstudio (development version)

  • lms_load() now checks the shape of a status-200 load reply before it reads it. The reply must be a JSON object whose status is the string "loaded". With echo_load_config = TRUE, its load_config must also be a JSON object, and the call returns it as a list. Any other reply aborts with rlmstudio_bad_response, and the message names the field that broke the rule. Fields are read by their exact names. Before, {} and a status such as "pending" aborted with rlmstudio_api_error and status 200. A body such as "x" failed with an unclassed error. A field such as statusX was read in place of status. With echo_load_config = TRUE, a reply with no load_config returned NULL.

  • lms_download() now checks the shape of a status-200 reply before it reads it. The reply must be a JSON object whose status is a string. If the status is "already_downloaded", the call returns "already_downloaded" invisibly, as before. Otherwise the reply’s job_id must be a string, and the call returns it. Any other reply aborts with rlmstudio_bad_response, and the message names the field that broke the rule. The call no longer returns TRUE. Before, {}, [], and null returned TRUE, a job_id of 1 returned 1L, and a job_id that was an array returned a list.

  • lms_download_status() now checks the shape of a status-200 reply before it reads it. The reply must be a JSON object whose job_id and status are strings. Its total_size_bytes, downloaded_bytes, and bytes_per_second must each be a number, or absent, or null. Any other reply aborts with rlmstudio_bad_response, and the message names the field that broke the rule. Before, {} returned an empty status object, and printing it failed with “EXPR must be a length 1 vector”.

  • print() on a download status now reads each field by its exact name. Before, a field such as bytes_per_secondX was read in place of an absent bytes_per_second. A string there made print() fail with “non-numeric argument to binary operator”. print() also shows the status as text now. Before, braces in the status were run as R code, so a status of "{1 + 1}" printed as 2.

  • list_models() now checks the shape of a status-200 model list before it reads it. A model list that breaks a rule aborts with rlmstudio_bad_response, and the message names the field or entry that broke it. The body must be a JSON object whose models is an array. Each model must be a JSON object whose type and key are strings and whose loaded_instances is an array. A size_bytes must be a number when it is present and not null. Each loaded instance must be a JSON object whose id is a string that is not empty or blank. Fields are read by their exact names. The check covers every entry, also the entries that the type and loaded filters drop. lms_unload_all(), and lms_load() without force = TRUE, raise the condition through list_models() and send no other request. Before, {} gave an empty data frame, a field such as modelsX was read in place of models, and some bad fields, such as a missing key or type, were read without error. Some other bodies failed with a base R error, such as “$ operator is invalid for atomic vectors” or “missing value where TRUE/FALSE needed”.

  • list_models() no longer fails on a model list with no models in it, which is what a server with nothing downloaded returns. It returns an empty data frame and, unless quiet = TRUE, says that no models were found on the host. Before, it failed with “missing value where TRUE/FALSE needed”. Through it, lms_unload_all() failed the same way, and so did lms_load() without force = TRUE. Now lms_unload_all() reports that no models are loaded, and lms_load() loads the model.

  • lms_unload_all() now reads each loaded instance by its id field alone. Before, it read an identifier field first, then id, then the first field, and it skipped an id that was NA or empty.

  • lms_server_ready() now returns TRUE only for a model list that list_models() can read. It applies the same rules. Before, it accepted any array of JSON objects under models, such as models without a type or a key.

  • A reply body is now read as JSON text and nothing else. Before, the package fetched a body whose text was a URL that starts with http:// or https://. It read a body whose text was the path of an existing file from disk. For a file that held a valid reply, list_models(), lms_embed(), and the chat functions returned the content of that file. If the reply header said application/json, lms_load(), lms_download(), and lms_download_status() did the same. Now such a body does not parse, so the functions that read a status-200 body abort with rlmstudio_bad_response, and lms_server_ready() returns FALSE. An error body of that kind is shown as its own text in the rlmstudio_api_error message.

  • A status-200 body that does not parse as JSON now aborts with rlmstudio_bad_response in list_models(), lms_load(), lms_download(), and lms_download_status(). lms_unload_all() raises it through list_models(), and so does lms_load() unless force = TRUE. The condition’s status is 200L. After a label, the message says what the message of the chat functions says. The label is the function’s own. If the model list is the body that fails, lms_unload_all() and lms_load() show the label of list_models(), “API List Failed”. Before, such a body failed with an unclassed error from httr2 or jsonlite.

  • lms_load(), lms_download(), and lms_download_status() now read a status-200 body by its content, not by its Content-Type header. Valid JSON under text/plain now gives the same result as under application/json. Before, it failed with an unclassed httr2 error. lms_server_ready() now returns TRUE for a model list sent as text/plain, where before it returned FALSE. An rlmstudio_api_error whose JSON body comes as text/plain now shows the error text from the body, where before it showed the whole body.

  • A status-200 reply body that does not parse as JSON now aborts with rlmstudio_bad_response in lms_chat_native(), lms_chat_openresponses(), and lms_chat_openai(). Examples are an HTML page from a proxy, JSON text that stops part way, and an empty body. The abort happens with simplify = TRUE and with simplify = FALSE. The condition’s status is 200L. The message says that the body did not parse as JSON. It also says that something other than LM Studio can be answering on the host. It does not hold the body text. On the OpenAI route, the condition’s content and finish_reason fields are NULL. Before, such a body failed with an unclassed error from httr2 or jsonlite. In lms_chat_batch(), that error ended the batch and lost every reply so far. Now that input fails alone, and the batch stores the failure and warns once, as for other failed inputs.

  • The three chat functions now parse a status-200 body by its content, not by its Content-Type header. Valid JSON under text/plain now gives the same result as under application/json. Before, it failed with an unclassed httr2 error. lms_embed() already worked this way, and its behavior does not change.

  • With api_type = "openresponses" or api_type = "openai" and format = "data.frame", lms_chat_batch() now returns four more columns at the end of the data frame: response_id, input_tokens, total_output_tokens, and reasoning_output_tokens. They carry the names of the first four native columns, so batches from the three routes share them. response_id is the reply’s id. The counts come from the reply’s usage object. The OpenResponses route reads input_tokens, output_tokens, and output_tokens_details.reasoning_tokens. The OpenAI route reads prompt_tokens, completion_tokens, and completion_tokens_details.reasoning_tokens. The columns are there with logprobs = TRUE and with a schema too. response_id is character, and the counts are double. If a field is absent or is not one value of the column type, its cell is NA, with no warning. If usage is not a JSON object, all three count cells are NA. The row of an input that failed holds NA in all four columns. Apart from the bare-value change below, the answer columns, the vector and list formats, and single calls return what they did before.

  • A 200 response body can be a bare JSON value, such as 5, "s", or true. With simplify = TRUE, such a body now aborts with rlmstudio_bad_response in lms_chat_native(), lms_chat_openresponses(), and lms_chat_openai(). The message says that the body is not a JSON object. Before, such a body failed with the base R error “subscript out of bounds”. In lms_chat_batch(), that error ended the batch and lost every reply so far. Now the batch stores the failure and goes on. With simplify = FALSE, the body comes back unchanged, as before.

  • With api_type = "native" and format = "data.frame", lms_chat_batch() now returns seven more columns at the end of the data frame. The first is response_id, the id of the reply on the server. The other six come from the stats object of the reply. They are input_tokens, total_output_tokens, reasoning_output_tokens, tokens_per_second, time_to_first_token_seconds, and model_load_time_seconds. response_id is character, and the other six are double. If a field is absent or has the wrong type, its cell is NA, with no warning. The answer in output is kept. The row of an input that failed holds NA in all seven columns. If every input failed, the columns are still there. The other routes, the other formats, and single calls return what they did before.

  • With simplify = TRUE and logprobs = TRUE, lms_chat_openresponses() now checks the logprobs value of each "output_text" part before it builds the data frame. The value must be an array of JSON objects. In each object, token must be a string and logprob must be a number. Its top_logprobs must be an array of objects whose token and logprob follow the same two rules. Each of these fields, and the logprobs value itself, can also be null or absent. A null step or candidate breaks a rule. A value that breaks a rule aborts with rlmstudio_bad_response, and the message names the first rule it breaks. The parts, the steps of a part, and the candidates of a step are checked one at a time, in order. Within a step, token, logprob, and the array test of top_logprobs come before the candidates. A bad text in any part is reported before any logprobs fault. Before, a value such as [5] failed with the bare R error “$ operator is invalid for atomic vectors”. Parts of other types, such as a refusal, are not checked. With logprobs = FALSE, the call returns the text as before. lms_chat_batch() stores this failure as it stores other failed inputs.

  • The fields of each step and candidate are now read by their exact names. Before, a step with a tokenX field and no token field gave the value of tokenX as its token. Now it gives NA, as a null or absent field does. A readable logprobs value gives the same data frame as before.

  • lms_chat_native() and lms_chat_openresponses() now read the answer from the reply items of type "message". Before, they read the first item of the output array. A reasoning model puts a reasoning item first, so the call returned the reasoning in place of the answer. The text of every message item is now pasted together in order, and reasoning items, tool calls, and other items are skipped. On the OpenResponses route, the text comes from each part of type "output_text", and a part of another type, such as a refusal, is skipped. With logprobs = TRUE, the log probabilities come from every such part in order.

  • With simplify = TRUE, those two functions now abort with rlmstudio_bad_response when a reply holds no readable answer text. That covers an output field that is missing, empty, or not an array, and a reply with no message item, such as one that holds only reasoning or a tool call. It also covers message text that is not one string. Before, some of these replies failed with a bare R error such as “subscript out of bounds”. Others returned NULL or a value that was not a string. simplify = FALSE still returns the body unchanged.

  • With simplify = TRUE, lms_chat_openai() now aborts with rlmstudio_bad_response when the reply content is not one string. That includes null content, which a reply that holds only a tool call has. The condition carries the content and the finish reason in its content and finish_reason fields. Before, null content returned NULL, and with logprobs = TRUE it failed with an unclassed error. Content such as a number or an array was returned as it was.

  • lms_chat_batch() stores these failures as it stores other failed inputs, and warns once. With format = "data.frame" and simplify = FALSE, it now aborts before it sends any request. Before, it sent every request first and then aborted, and the replies were lost.

  • lms_chat_openai() has a new schema argument for structured output. Give it a JSON Schema written as a named list. The request then asks the server for a reply that matches the schema. With simplify = TRUE, the call returns the reply parsed into an R value, for example list(score = 3L), rather than a string. With simplify = FALSE or logprobs = TRUE, the reply stays a string. A plain vector of length one is sent as a single value. Write a JSON array of one item as a list, such as required = list("score").

  • lms_chat() takes schema too and passes it to lms_chat_openai(). It needs api_type = "openai", because LM Studio documents structured output on that endpoint only. Any other api_type with a schema aborts before the request. lms_chat_batch() passes schema on through .... When simplify = TRUE and logprobs = FALSE, the reply is parsed. In that case, format = "list" returns one parsed reply per input. With format = "data.frame", the output column is a list of parsed replies. With format = "vector", the call warns and returns the list.

  • A schema must be a named list, an empty list, or NULL. Any other value aborts before the request, and so does a schema given together with a response_format in .... An empty object nested in the schema, such as properties, is written setNames(list(), character()), because list() is sent as the empty array [].

  • The reply is parsed only with a schema, simplify = TRUE, and logprobs = FALSE. There, reply content that is not one string of valid JSON aborts with the condition class rlmstudio_bad_response. lms_chat_openai() now raises it, as lms_embed() does, and lms_chat() passes it on. The condition carries the reply content in a content field and the server’s finish reason in a finish_reason field. You can therefore read what the model wrote without a second request. If the finish reason is "length", the message says that the token limit cut the reply off and names max_tokens.

  • With simplify = TRUE, a chat completions response from lms_chat_openai() whose choices field is missing, empty, or not an array, or whose first element is not a JSON object with a message object in it, also aborts with rlmstudio_bad_response, with or without a schema. Before, an empty choices list failed with the bare error subscript out of bounds. Without a schema and with logprobs = FALSE, a missing choices field returned NULL. The condition’s content and finish_reason fields are NULL. Without a schema, lms_chat_batch() now stores such a response as a failed input, as the next entry says. Before, a missing choices field gave NULL for that input. With format = "vector", the result was then shorter than the input.

  • lms_chat_batch() no longer stops at an input that fails with rlmstudio_api_error or rlmstudio_bad_response, whatever its settings. It goes on to the next input. In a returned list, and in the output list-column that a schema gives, the element for that input holds the condition. Where the result is text, the element holds NA. That is the case for format = "vector" when it returns a vector, and for a data frame whose replies are not parsed. In such a data frame, the logprobs column holds NULL for a failed input. A reply with no readable answer text, such as one whose content is null, fails in the same way, so the result stays as long as inputs. With format = "data.frame" and logprobs = TRUE, the logprobs column is now always there, even when no reply carried log probabilities. Before, it was left out in that case. The call gives one warning that names the count and the positions of the failed inputs. quiet = TRUE does not silence it. Where the result holds NA, the warning names format = "list" as the way to keep the conditions.

  • An rlmstudio_no_server from one input still aborts lms_chat_batch(), but the replies so far are no longer lost. The condition carries them in a new results field, with any failures stored so far. It is a list as long as inputs, with NULL from the lost input on. This covers a server that the check before each input finds gone. A connection that fails during a request still aborts with an httr2_failure error and no results field.

  • lms_server_start() now waits for the REST API to answer before it returns. The CLI reports success as soon as it asks for the server. The REST API accepts a request some time after that. A script that called the API on the next line therefore reported a missing server on a healthy machine. The call now asks lms_server_ready() again and again until it reports TRUE. It pauses a quarter of a second between requests. Once the wait passes it starts no new request. After the first TRUE it sends no further request.

  • A new wait argument on lms_server_start() sets how many seconds that lasts. It defaults to 10. It is not a hard cap. No new request starts once the wait passes, but a request already in flight is allowed one second to finish. With no host and no port, the call first asks the CLI which port the server uses, and that read runs before the wait starts to count. With wait = 0 the call sends no readiness request and returns as soon as the CLI does, which is what every earlier version did. A wait that is not one number, zero or more, aborts before the CLI runs. NULL, a string, a vector of two, NA, NaN, Inf, and a negative number all abort. The message names the argument and the rule the value broke.

  • A wait that runs out raises a warning rather than an error, and the call still returns the CLI exit code. Aborting cannot undo a server that already started. The warning names the host it asked and the wait argument. The rlmstudio.quiet option does not silence it.

  • A new host argument on lms_server_start() says where to look for the server that was started. It does not change where the CLI starts it, which only port does. When you give no host, the host is http://localhost: plus the port you gave. When you give neither, the port that lms_server_status(json = TRUE) reports is read instead. A call that reaches that last case and finds no usable port sends no readiness request. It raises its own warning instead. That warning names the failed port read, the host argument, and the port argument.

  • A new token argument on lms_server_start() is sent on the readiness request. It serves a server that requires authentication. With token = NULL, the request reads the rlmstudio.token option and then the RLMSTUDIO_API_TOKEN environment variable.

  • lms_server_start() now checks host and token before the CLI runs. A fault in either one therefore aborts before any server starts. A token that is not one character string and not NULL aborts. A host that the readiness request cannot be built from also aborts. The message names host and quotes the reason from httr2 or curl. Some examples are a vector of two strings, NA, an empty string, and a number. A URL with a space in it and "localhost:1234", which lacks http://, abort too. Both checks also run with wait = 0.

  • If the readiness check aborts during the wait, lms_server_start() raises one warning and returns the CLI exit code. The warning names the host and quotes the abort message.

  • The help page of lms_server_ready() now names the call faults that abort it rather than returning FALSE. There are six. A host of NULL. A host of more than one string. A host that is a character NA. A host that cannot be parsed as a URL. A timeout below one millisecond. A timeout that is not one number. The page says which package each message comes from. The httr2 messages name url and seconds rather than host and timeout, and the page says so. The curl message for a host that cannot be parsed as a URL names no argument. It names the parse reason instead. The page also says that those six are not the whole list, because any host that is not one string aborts the same way. The token fault the page already named is unchanged.

  • A model name or a job id that the server cannot use now aborts before the request goes out. The message names the argument and the rule the value broke. The check covers model on lms_chat(), lms_chat_batch(), lms_chat_native(), lms_chat_openai(), lms_chat_openresponses(), lms_download(), lms_embed(), lms_load(), and lms_unload(). It covers job_id on lms_download_status(). Each of these must be one name, given as a single string. These all abort: a vector of two names, an empty character vector, NA, an empty string, and a string of whitespace only. So do a one-by-one matrix, NULL, and any value that is not a character string. Before, eight of these functions had no check on model at all. A vector of two names went to those as a JSON array of two. The error that came back named neither the argument nor the mistake. lms_load() was the one exception. If a model was already loaded, it raised a bare R error from its already-loaded test instead.

  • A missing value inside a text argument now aborts. lms_embed(input) and lms_chat_batch(inputs) must hold at least one value and no NA. On lms_chat(), lms_chat_native(), and lms_chat_openresponses(), a character input must hold no NA. A value of any other type still passes through to the server on those three. The structured input form that the OpenResponses endpoint accepts therefore still works. Two things stay unchecked. lms_chat_openai(messages) takes a list, which no rule here reaches. On the three chat wrappers above, a character input of length zero still goes out as an empty JSON array. Before, an NA went out as JSON null. The server then answered with an error or a count that named neither the NA nor its position.

  • Two of these messages changed text. lms_download() and lms_download_status() used to say “You must provide a valid model identifier or URL.” and “You must provide a valid job_id.”. Those two checks also raised a bare R error, rather than their own message, when the argument held more than one value.

  • A new function, lms_embed(), turns text into the vectors that an embedding model produces for it. Give it a loaded embedding model and a character vector of texts. The whole vector goes out in one request to the server. By default the return is a numeric matrix. It has one row per input text and one column per embedding dimension, so it goes straight to dist() or prcomp(). The matrix carries no row or column names, so rows pair with inputs by position. The row at each position holds the vector that the response reported for the text at that position, whatever order the server answered in. With simplify = FALSE the return is the parsed response body instead. A token argument works as it does on the other functions that reach the REST API. The ... argument forwards any other field to the request body.

  • lms_embed() reads the response before it builds the matrix, and aborts rather than returning a matrix it cannot trust. It aborts on each of these. The response body is not JSON at all. The response body is a plain value rather than an object or an array. The response carries no list of vectors, which is also what a body sent as a bare array reports, because such a body can carry no named field. The list of vectors is a plain value rather than a list. The list of vectors arrived as a JSON object rather than an array. It carries a different number of vectors than there were texts. A vector carries no position, or a position that is not a whole number. Two vectors carry the same position. A position falls outside the range of the texts. A vector is not a list of numbers. A vector is an empty list. An entry in the list of vectors is not an object at all. The vectors are of unequal length. These aborts carry the new condition class rlmstudio_bad_response and a status field holding the HTTP status as an integer. Every message but one names simplify = FALSE, which returns the body unchanged so you can read what arrived. The exception is a body that is not JSON: the parse runs before simplify is read, so that message instead tells you to check what is answering on the host.

  • The help pages now document a third condition class. rlmstudio_bad_response has its own section on the rlmstudio-conditions page and its own alias, so ?rlmstudio_bad_response reaches it. The same section appears on the lms_embed() page. The class means a response that the server did not report as a failure and that the package still cannot read. That is a different thing from rlmstudio_api_error.

  • A new function, lms_server_ready(), reports whether a host answers as an LM Studio server you can use. It sends one GET request to the model list endpoint and returns TRUE only for an HTTP 200 whose body carries a list of models. An empty list counts, because a fresh install has nothing downloaded and its server still works. Every other answer returns FALSE: a refused connection, a listener that never replies, a rejected token, a failed status, and a body that is not a model list. The function raises nothing of its own for any of these, so a caller can branch on the value directly. A timeout argument sets how many seconds to wait, and defaults to 2. A token argument works as it does on the other functions that reach the REST API. A token that is not one character string and not NULL still aborts.

  • The help page for the error conditions now says what the server check actually reads. Functions that call the REST API open a TCP connection to the host and port. Any process holding that port accepts the connection, so rlmstudio_no_server is not raised even though no LM Studio server is there. The call then fails later as an rlmstudio_api_error or as a raw parse error. The page names lms_server_ready() as the stronger test. The same section appears on the help page of every exported function that can raise the condition.

  • Both vignettes now ask whether the server answers before they call it. A host that does not answer makes them skip their REST examples. Before, a server that was not usable made the vignette fail to build.

  • The package can now authenticate to an LM Studio server that requires an API token. Eleven functions take a token argument. They are list_models(), lms_load(), lms_unload(), lms_unload_all(), lms_download(), lms_download_status(), lms_chat(), lms_chat_batch(), lms_chat_openresponses(), lms_chat_openai(), and lms_chat_native(). Each one sends the value as a bearer token in the Authorization header of every request it makes. When token is not given, the package reads the rlmstudio.token option, and then the RLMSTUDIO_API_TOKEN environment variable. When none of the three holds a value, the request carries no Authorization header. A new help topic, rlmstudio_token, is the source. On the nine of these functions that take ..., token sits after the dots. It is therefore matched by name alone, and no existing argument moved position.

  • A printed request shows the Authorization header as <REDACTED> rather than showing the token. The package never puts the token into the message of a failed REST call. That message does repeat the text the server sent. An R backtrace also repeats your own calling line. Neither one is under the package’s control.

  • A token argument that is not one character string and not NULL now aborts. Before, a value such as a vector of two strings was discarded without a message. The call then fell through to the option and the environment variable.

  • A REST response with HTTP status 401 or 403 now adds a hint to the abort. If the request carried no token, the hint names RLMSTUDIO_API_TOKEN and the token argument. If the request carried a token, the hint says that the server rejected it. Other statuses gain no hint.

  • The help pages now document the error condition classes that this package raises. A new help topic, rlmstudio-conditions, is the source. It names the situation that raises rlmstudio_no_server and the situation that raises rlmstudio_api_error. It states that an rlmstudio_api_error condition carries a status field, which holds the HTTP status as an integer. It shows how to catch each class with tryCatch(). The same two sections now appear on the help page of every exported function that can raise one of these classes. The pages of lms_chat(), lms_chat_batch(), and lms_unload_all() also name the function that they reach the abort through.

  • Every failed REST response now aborts through one path. This affects lms_load(), lms_unload(), lms_download(), lms_download_status(), lms_chat_openresponses(), lms_chat_openai(), and lms_chat_native(). All seven now report the same message text for the same response body. Every one of these aborts carries the condition class rlmstudio_api_error. It also carries a status field, which holds the HTTP status as an integer. lms_unload_all() and lms_chat_batch() call these functions, so their failures change in the same way. The aborts from lms_download() and lms_download_status() no longer print the call that raised them. The other five already suppressed it.

  • Some failure messages changed as a result. A JSON body whose error field is a plain string now reports that string. Before, lms_load(), lms_unload(), lms_download(), and lms_download_status() printed the whole raw body, and lms_chat_openresponses() and lms_chat_openai() printed the status. A JSON body that carries no readable message now reports HTTP Status <n>. Before, such a body gave the raw body text, a fragment of the error object, or a crash, depending on the function and the shape. A body that is not JSON and holds text now reports that text at all seven functions. Before, the three chat functions printed the status instead. An empty body still reports HTTP Status <n>. If lms_load() gets a successful response that does not report the model as loaded, it now reports the response body.

  • Response bodies that used to crash now abort with a message. Before, all seven functions raised a raw R error on at least one body shape. An error field holding an empty object, an empty array, or an array of strings raised errors such as argument is of length zero. At lms_load(), lms_unload(), lms_download(), and lms_download_status(), an empty response body raised Can't retrieve empty body.

  • list_models() now reports a failed REST response through that same path. Before, it raised the raw httr2 error, such as HTTP 400 Bad Request. It now aborts with the message API List Failed: followed by the text read out of the response body. The abort carries the condition class rlmstudio_api_error. It also carries a status field, which holds the HTTP status as an integer. If the status is 400 or above and the body carries no readable message, the abort reports HTTP Status <n>. Below status 400 it reports the body text instead. The call now aborts on every status other than 200. Before, only status 400 and above raised an error, so a status such as 201 or 302 reached the parser.

  • The server probe now honors the host argument. This affects list_models(), lms_load(), lms_unload(), lms_unload_all(), lms_download(), lms_download_status(), lms_chat_openai(), lms_chat_openresponses(), lms_chat_native(), and lms_chat_batch(). Before, the probe always tried localhost:1234, so a server on another hostname or port was reported as not running.

  • If the server is not running, list_models(), lms_download(), and lms_download_status() now abort instead of returning an empty data frame or NULL. Every server-down abort carries the condition class rlmstudio_no_server.

  • has_lms() now uses the same lookup as lms_path(): the RLMSTUDIO_LMS_PATH environment variable, then the system PATH, then common installation directories. Before, it checked only the PATH, so the two functions did not always agree.

rlmstudio 0.2.2

CRAN release: 2026-05-05

  • Fix CRAN issues

rlmstudio 0.2.1

  • Submit to CRAN

rlmstudio 0.2.0

  • Improve list–load interaction
  • Handle repeat model loading elegantly
  • Add first set of unit testing
  • Add headless vignette
  • Add pkgdown website
  • Add codecov and lifecycle badges

rlmstudio 0.1.0

  • Initial development version.